mirror of
https://github.com/ipfs/kubo.git
synced 2025-07-02 12:20:03 +08:00
@ -4,7 +4,7 @@ MAINTAINER Brian Tiger Chow <btc@perfmode.com>
|
||||
COPY . /go/src/github.com/jbenet/go-ipfs
|
||||
RUN cd /go/src/github.com/jbenet/go-ipfs/cmd/ipfs && go install
|
||||
|
||||
EXPOSE 4001 5001
|
||||
EXPOSE 4001 5001 4002/udp
|
||||
|
||||
ENTRYPOINT ["ipfs"]
|
||||
|
||||
@ -12,3 +12,4 @@ CMD ["daemon", "--init"]
|
||||
|
||||
# build: docker build -t go-ipfs .
|
||||
# run: docker run -p 4001:4001 -p 5001:5001 go-ipfs:latest daemon --init
|
||||
# run: docker run -p 4002:4002/udp -p 4001:4001 -p 5001:5001 go-ipfs:latest daemon --init
|
||||
|
22
Godeps/Godeps.json
generated
22
Godeps/Godeps.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"ImportPath": "github.com/jbenet/go-ipfs",
|
||||
"GoVersion": "go1.3.3",
|
||||
"GoVersion": "go1.3",
|
||||
"Packages": [
|
||||
"./..."
|
||||
],
|
||||
@ -73,10 +73,6 @@
|
||||
"ImportPath": "github.com/facebookgo/stackerr",
|
||||
"Rev": "060fbf9364c89acd41bf710e9e92915a90e7a5b5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gonuts/flag",
|
||||
"Rev": "741a6cbd37a30dedc93f817e7de6aaf0ca38a493"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gorilla/context",
|
||||
"Rev": "14f550f51af52180c2eefed15e5fd18d63c0a64a"
|
||||
@ -86,12 +82,12 @@
|
||||
"Rev": "4b8fbc56f3b2400a7c7ea3dba9b3539787c486b6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/inconshreveable/go-update",
|
||||
"Rev": "221d034a558b4c21b0624b2a450c076913854a57"
|
||||
"ImportPath": "github.com/h2so5/utp",
|
||||
"Rev": "654d875bb65e96729678180215cf080fe2810371"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/jbenet/commander",
|
||||
"Rev": "e0cf317891f0ab6f1ac64dfcb754b4fb5e69f7df"
|
||||
"ImportPath": "github.com/inconshreveable/go-update",
|
||||
"Rev": "221d034a558b4c21b0624b2a450c076913854a57"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/jbenet/go-base58",
|
||||
@ -115,8 +111,12 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/jbenet/go-multiaddr",
|
||||
"Comment": "0.1.2-27-g62a88e0",
|
||||
"Rev": "62a88e015e1bf5d6aaca29aec1aba0722f21c8d3"
|
||||
"Comment": "0.1.2-30-g99cf3ed",
|
||||
"Rev": "99cf3edc711751cf7b43505fac0e3913f6b9a75c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/jbenet/go-multiaddr-net",
|
||||
"Rev": "b6265d8119558acf3912db44abb34d97c30c3220"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/jbenet/go-multihash",
|
||||
|
27
Godeps/_workspace/src/github.com/gonuts/flag/LICENSE
generated
vendored
27
Godeps/_workspace/src/github.com/gonuts/flag/LICENSE
generated
vendored
@ -1,27 +0,0 @@
|
||||
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
6
Godeps/_workspace/src/github.com/gonuts/flag/README.md
generated
vendored
6
Godeps/_workspace/src/github.com/gonuts/flag/README.md
generated
vendored
@ -1,6 +0,0 @@
|
||||
flag
|
||||
=======
|
||||
|
||||
[](https://drone.io/github.com/gonuts/flag/latest)
|
||||
|
||||
A fork of the official "flag" package but with the flag.Value interface extended to provide a ``Get() interface{}`` method.
|
83
Godeps/_workspace/src/github.com/gonuts/flag/example_test.go
generated
vendored
83
Godeps/_workspace/src/github.com/gonuts/flag/example_test.go
generated
vendored
@ -1,83 +0,0 @@
|
||||
// Copyright 2012 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.
|
||||
|
||||
// These examples demonstrate more intricate uses of the flag package.
|
||||
package flag_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Example 1: A single string flag called "species" with default value "gopher".
|
||||
var species = flag.String("species", "gopher", "the species we are studying")
|
||||
|
||||
// Example 2: Two flags sharing a variable, so we can have a shorthand.
|
||||
// The order of initialization is undefined, so make sure both use the
|
||||
// same default value. They must be set up with an init function.
|
||||
var gopherType string
|
||||
|
||||
func init() {
|
||||
const (
|
||||
defaultGopher = "pocket"
|
||||
usage = "the variety of gopher"
|
||||
)
|
||||
flag.StringVar(&gopherType, "gopher_type", defaultGopher, usage)
|
||||
flag.StringVar(&gopherType, "g", defaultGopher, usage+" (shorthand)")
|
||||
}
|
||||
|
||||
// Example 3: A user-defined flag type, a slice of durations.
|
||||
type interval []time.Duration
|
||||
|
||||
// String is the method to format the flag's value, part of the flag.Value interface.
|
||||
// The String method's output will be used in diagnostics.
|
||||
func (i *interval) String() string {
|
||||
return fmt.Sprint(*i)
|
||||
}
|
||||
|
||||
// Set is the method to set the flag value, part of the flag.Value interface.
|
||||
// Set's argument is a string to be parsed to set the flag.
|
||||
// It's a comma-separated list, so we split it.
|
||||
func (i *interval) Set(value string) error {
|
||||
// If we wanted to allow the flag to be set multiple times,
|
||||
// accumulating values, we would delete this if statement.
|
||||
// That would permit usages such as
|
||||
// -deltaT 10s -deltaT 15s
|
||||
// and other combinations.
|
||||
if len(*i) > 0 {
|
||||
return errors.New("interval flag already set")
|
||||
}
|
||||
for _, dt := range strings.Split(value, ",") {
|
||||
duration, err := time.ParseDuration(dt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*i = append(*i, duration)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Define a flag to accumulate durations. Because it has a special type,
|
||||
// we need to use the Var function and therefore create the flag during
|
||||
// init.
|
||||
|
||||
var intervalFlag interval
|
||||
|
||||
func init() {
|
||||
// Tie the command-line flag to the intervalFlag variable and
|
||||
// set a usage message.
|
||||
flag.Var(&intervalFlag, "deltaT", "comma-separated list of intervals to use between events")
|
||||
}
|
||||
|
||||
func Example() {
|
||||
// All the interesting pieces are with the variables declared above, but
|
||||
// to enable the flag package to see the flags defined there, one must
|
||||
// execute, typically at the start of main (not init!):
|
||||
// flag.Parse()
|
||||
// We don't run it here because this is not a main function and
|
||||
// the testing suite has already parsed the flags.
|
||||
}
|
22
Godeps/_workspace/src/github.com/gonuts/flag/export_test.go
generated
vendored
22
Godeps/_workspace/src/github.com/gonuts/flag/export_test.go
generated
vendored
@ -1,22 +0,0 @@
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package flag
|
||||
|
||||
import "os"
|
||||
|
||||
// Additional routines compiled into the package only during testing.
|
||||
|
||||
// ResetForTesting clears all flag state and sets the usage function as directed.
|
||||
// After calling ResetForTesting, parse errors in flag handling will not
|
||||
// exit the program.
|
||||
func ResetForTesting(usage func()) {
|
||||
commandLine = NewFlagSet(os.Args[0], ContinueOnError)
|
||||
Usage = usage
|
||||
}
|
||||
|
||||
// CommandLine returns the default FlagSet.
|
||||
func CommandLine() *FlagSet {
|
||||
return commandLine
|
||||
}
|
816
Godeps/_workspace/src/github.com/gonuts/flag/flag.go
generated
vendored
816
Godeps/_workspace/src/github.com/gonuts/flag/flag.go
generated
vendored
@ -1,816 +0,0 @@
|
||||
// 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 flag implements command-line flag parsing.
|
||||
|
||||
Usage:
|
||||
|
||||
Define flags using flag.String(), Bool(), Int(), etc.
|
||||
|
||||
This declares an integer flag, -flagname, stored in the pointer ip, with type *int.
|
||||
import "flag"
|
||||
var ip = flag.Int("flagname", 1234, "help message for flagname")
|
||||
If you like, you can bind the flag to a variable using the Var() functions.
|
||||
var flagvar int
|
||||
func init() {
|
||||
flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname")
|
||||
}
|
||||
Or you can create custom flags that satisfy the Value interface (with
|
||||
pointer receivers) and couple them to flag parsing by
|
||||
flag.Var(&flagVal, "name", "help message for flagname")
|
||||
For such flags, the default value is just the initial value of the variable.
|
||||
|
||||
After all flags are defined, call
|
||||
flag.Parse()
|
||||
to parse the command line into the defined flags.
|
||||
|
||||
Flags may then be used directly. If you're using the flags themselves,
|
||||
they are all pointers; if you bind to variables, they're values.
|
||||
fmt.Println("ip has value ", *ip)
|
||||
fmt.Println("flagvar has value ", flagvar)
|
||||
|
||||
After parsing, the arguments after the flag are available as the
|
||||
slice flag.Args() or individually as flag.Arg(i).
|
||||
The arguments are indexed from 0 up to flag.NArg().
|
||||
|
||||
Command line flag syntax:
|
||||
-flag
|
||||
-flag=x
|
||||
-flag x // non-boolean flags only
|
||||
One or two minus signs may be used; they are equivalent.
|
||||
The last form is not permitted for boolean flags because the
|
||||
meaning of the command
|
||||
cmd -x *
|
||||
will change if there is a file called 0, false, etc. You must
|
||||
use the -flag=false form to turn off a boolean flag.
|
||||
|
||||
Flag parsing stops just before the first non-flag argument
|
||||
("-" is a non-flag argument) or after the terminator "--".
|
||||
|
||||
Integer flags accept 1234, 0664, 0x1234 and may be negative.
|
||||
Boolean flags may be 1, 0, t, f, true, false, TRUE, FALSE, True, False.
|
||||
Duration flags accept any input valid for time.ParseDuration.
|
||||
|
||||
The default set of command-line flags is controlled by
|
||||
top-level functions. The FlagSet type allows one to define
|
||||
independent sets of flags, such as to implement subcommands
|
||||
in a command-line interface. The methods of FlagSet are
|
||||
analogous to the top-level functions for the command-line
|
||||
flag set.
|
||||
*/
|
||||
package flag
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ErrHelp is the error returned if the flag -help is invoked but no such flag is defined.
|
||||
var ErrHelp = errors.New("flag: help requested")
|
||||
|
||||
// -- bool Value
|
||||
type boolValue bool
|
||||
|
||||
func newBoolValue(val bool, p *bool) *boolValue {
|
||||
*p = val
|
||||
return (*boolValue)(p)
|
||||
}
|
||||
|
||||
func (b *boolValue) Set(s string) error {
|
||||
v, err := strconv.ParseBool(s)
|
||||
*b = boolValue(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (b *boolValue) Get() interface{} { return bool(*b) }
|
||||
|
||||
func (b *boolValue) String() string { return fmt.Sprintf("%v", *b) }
|
||||
|
||||
// -- int Value
|
||||
type intValue int
|
||||
|
||||
func newIntValue(val int, p *int) *intValue {
|
||||
*p = val
|
||||
return (*intValue)(p)
|
||||
}
|
||||
|
||||
func (i *intValue) Set(s string) error {
|
||||
v, err := strconv.ParseInt(s, 0, 64)
|
||||
*i = intValue(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (i *intValue) Get() interface{} { return int(*i) }
|
||||
|
||||
func (i *intValue) String() string { return fmt.Sprintf("%v", *i) }
|
||||
|
||||
// -- int64 Value
|
||||
type int64Value int64
|
||||
|
||||
func newInt64Value(val int64, p *int64) *int64Value {
|
||||
*p = val
|
||||
return (*int64Value)(p)
|
||||
}
|
||||
|
||||
func (i *int64Value) Set(s string) error {
|
||||
v, err := strconv.ParseInt(s, 0, 64)
|
||||
*i = int64Value(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (i *int64Value) Get() interface{} { return int64(*i) }
|
||||
|
||||
func (i *int64Value) String() string { return fmt.Sprintf("%v", *i) }
|
||||
|
||||
// -- uint Value
|
||||
type uintValue uint
|
||||
|
||||
func newUintValue(val uint, p *uint) *uintValue {
|
||||
*p = val
|
||||
return (*uintValue)(p)
|
||||
}
|
||||
|
||||
func (i *uintValue) Set(s string) error {
|
||||
v, err := strconv.ParseUint(s, 0, 64)
|
||||
*i = uintValue(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (i *uintValue) Get() interface{} { return uint(*i) }
|
||||
|
||||
func (i *uintValue) String() string { return fmt.Sprintf("%v", *i) }
|
||||
|
||||
// -- uint64 Value
|
||||
type uint64Value uint64
|
||||
|
||||
func newUint64Value(val uint64, p *uint64) *uint64Value {
|
||||
*p = val
|
||||
return (*uint64Value)(p)
|
||||
}
|
||||
|
||||
func (i *uint64Value) Set(s string) error {
|
||||
v, err := strconv.ParseUint(s, 0, 64)
|
||||
*i = uint64Value(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (i *uint64Value) Get() interface{} { return uint64(*i) }
|
||||
|
||||
func (i *uint64Value) String() string { return fmt.Sprintf("%v", *i) }
|
||||
|
||||
// -- string Value
|
||||
type stringValue string
|
||||
|
||||
func newStringValue(val string, p *string) *stringValue {
|
||||
*p = val
|
||||
return (*stringValue)(p)
|
||||
}
|
||||
|
||||
func (s *stringValue) Set(val string) error {
|
||||
*s = stringValue(val)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *stringValue) Get() interface{} { return s.String() }
|
||||
|
||||
func (s *stringValue) String() string { return fmt.Sprintf("%s", *s) }
|
||||
|
||||
// -- float64 Value
|
||||
type float64Value float64
|
||||
|
||||
func newFloat64Value(val float64, p *float64) *float64Value {
|
||||
*p = val
|
||||
return (*float64Value)(p)
|
||||
}
|
||||
|
||||
func (f *float64Value) Set(s string) error {
|
||||
v, err := strconv.ParseFloat(s, 64)
|
||||
*f = float64Value(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *float64Value) Get() interface{} { return float64(*f) }
|
||||
|
||||
func (f *float64Value) String() string { return fmt.Sprintf("%v", *f) }
|
||||
|
||||
// -- time.Duration Value
|
||||
type durationValue time.Duration
|
||||
|
||||
func newDurationValue(val time.Duration, p *time.Duration) *durationValue {
|
||||
*p = val
|
||||
return (*durationValue)(p)
|
||||
}
|
||||
|
||||
func (d *durationValue) Set(s string) error {
|
||||
v, err := time.ParseDuration(s)
|
||||
*d = durationValue(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *durationValue) Get() interface{} { return *(*time.Duration)(d) }
|
||||
|
||||
func (d *durationValue) String() string { return (*time.Duration)(d).String() }
|
||||
|
||||
// Value is the interface to the dynamic value stored in a flag.
|
||||
// (The default value is represented as a string.)
|
||||
type Value interface {
|
||||
String() string
|
||||
Set(string) error
|
||||
Get() interface{}
|
||||
}
|
||||
|
||||
// ErrorHandling defines how to handle flag parsing errors.
|
||||
type ErrorHandling int
|
||||
|
||||
const (
|
||||
ContinueOnError ErrorHandling = iota
|
||||
ExitOnError
|
||||
PanicOnError
|
||||
)
|
||||
|
||||
// A FlagSet represents a set of defined flags.
|
||||
type FlagSet struct {
|
||||
// Usage is the function called when an error occurs while parsing flags.
|
||||
// The field is a function (not a method) that may be changed to point to
|
||||
// a custom error handler.
|
||||
Usage func()
|
||||
|
||||
name string
|
||||
parsed bool
|
||||
actual map[string]*Flag
|
||||
formal map[string]*Flag
|
||||
args []string // arguments after flags
|
||||
exitOnError bool // does the program exit if there's an error?
|
||||
errorHandling ErrorHandling
|
||||
output io.Writer // nil means stderr; use out() accessor
|
||||
}
|
||||
|
||||
// A Flag represents the state of a flag.
|
||||
type Flag struct {
|
||||
Name string // name as it appears on command line
|
||||
Usage string // help message
|
||||
Value Value // value as set
|
||||
DefValue string // default value (as text); for usage message
|
||||
}
|
||||
|
||||
// sortFlags returns the flags as a slice in lexicographical sorted order.
|
||||
func sortFlags(flags map[string]*Flag) []*Flag {
|
||||
list := make(sort.StringSlice, len(flags))
|
||||
i := 0
|
||||
for _, f := range flags {
|
||||
list[i] = f.Name
|
||||
i++
|
||||
}
|
||||
list.Sort()
|
||||
result := make([]*Flag, len(list))
|
||||
for i, name := range list {
|
||||
result[i] = flags[name]
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (f *FlagSet) out() io.Writer {
|
||||
if f.output == nil {
|
||||
return os.Stderr
|
||||
}
|
||||
return f.output
|
||||
}
|
||||
|
||||
// SetOutput sets the destination for usage and error messages.
|
||||
// If output is nil, os.Stderr is used.
|
||||
func (f *FlagSet) SetOutput(output io.Writer) {
|
||||
f.output = output
|
||||
}
|
||||
|
||||
// VisitAll visits the flags in lexicographical order, calling fn for each.
|
||||
// It visits all flags, even those not set.
|
||||
func (f *FlagSet) VisitAll(fn func(*Flag)) {
|
||||
for _, flag := range sortFlags(f.formal) {
|
||||
fn(flag)
|
||||
}
|
||||
}
|
||||
|
||||
// VisitAll visits the command-line flags in lexicographical order, calling
|
||||
// fn for each. It visits all flags, even those not set.
|
||||
func VisitAll(fn func(*Flag)) {
|
||||
commandLine.VisitAll(fn)
|
||||
}
|
||||
|
||||
// Visit visits the flags in lexicographical order, calling fn for each.
|
||||
// It visits only those flags that have been set.
|
||||
func (f *FlagSet) Visit(fn func(*Flag)) {
|
||||
for _, flag := range sortFlags(f.actual) {
|
||||
fn(flag)
|
||||
}
|
||||
}
|
||||
|
||||
// Visit visits the command-line flags in lexicographical order, calling fn
|
||||
// for each. It visits only those flags that have been set.
|
||||
func Visit(fn func(*Flag)) {
|
||||
commandLine.Visit(fn)
|
||||
}
|
||||
|
||||
// Lookup returns the Flag structure of the named flag, returning nil if none exists.
|
||||
func (f *FlagSet) Lookup(name string) *Flag {
|
||||
return f.formal[name]
|
||||
}
|
||||
|
||||
// Lookup returns the Flag structure of the named command-line flag,
|
||||
// returning nil if none exists.
|
||||
func Lookup(name string) *Flag {
|
||||
return commandLine.formal[name]
|
||||
}
|
||||
|
||||
// Set sets the value of the named flag.
|
||||
func (f *FlagSet) Set(name, value string) error {
|
||||
flag, ok := f.formal[name]
|
||||
if !ok {
|
||||
return fmt.Errorf("no such flag -%v", name)
|
||||
}
|
||||
err := flag.Value.Set(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if f.actual == nil {
|
||||
f.actual = make(map[string]*Flag)
|
||||
}
|
||||
f.actual[name] = flag
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set sets the value of the named command-line flag.
|
||||
func Set(name, value string) error {
|
||||
return commandLine.Set(name, value)
|
||||
}
|
||||
|
||||
// PrintDefaults prints, to standard error unless configured
|
||||
// otherwise, the default values of all defined flags in the set.
|
||||
func (f *FlagSet) PrintDefaults() {
|
||||
f.VisitAll(func(flag *Flag) {
|
||||
format := " -%s=%s: %s\n"
|
||||
if _, ok := flag.Value.(*stringValue); ok {
|
||||
// put quotes on the value
|
||||
format = " -%s=%q: %s\n"
|
||||
}
|
||||
fmt.Fprintf(f.out(), format, flag.Name, flag.DefValue, flag.Usage)
|
||||
})
|
||||
}
|
||||
|
||||
// PrintDefaults prints to standard error the default values of all defined command-line flags.
|
||||
func PrintDefaults() {
|
||||
commandLine.PrintDefaults()
|
||||
}
|
||||
|
||||
// defaultUsage is the default function to print a usage message.
|
||||
func defaultUsage(f *FlagSet) {
|
||||
fmt.Fprintf(f.out(), "Usage of %s:\n", f.name)
|
||||
f.PrintDefaults()
|
||||
}
|
||||
|
||||
// NOTE: Usage is not just defaultUsage(commandLine)
|
||||
// because it serves (via godoc flag Usage) as the example
|
||||
// for how to write your own usage function.
|
||||
|
||||
// Usage prints to standard error a usage message documenting all defined command-line flags.
|
||||
// The function is a variable that may be changed to point to a custom function.
|
||||
var Usage = func() {
|
||||
fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
|
||||
PrintDefaults()
|
||||
}
|
||||
|
||||
// NFlag returns the number of flags that have been set.
|
||||
func (f *FlagSet) NFlag() int { return len(f.actual) }
|
||||
|
||||
// NFlag returns the number of command-line flags that have been set.
|
||||
func NFlag() int { return len(commandLine.actual) }
|
||||
|
||||
// Arg returns the i'th argument. Arg(0) is the first remaining argument
|
||||
// after flags have been processed.
|
||||
func (f *FlagSet) Arg(i int) string {
|
||||
if i < 0 || i >= len(f.args) {
|
||||
return ""
|
||||
}
|
||||
return f.args[i]
|
||||
}
|
||||
|
||||
// Arg returns the i'th command-line argument. Arg(0) is the first remaining argument
|
||||
// after flags have been processed.
|
||||
func Arg(i int) string {
|
||||
return commandLine.Arg(i)
|
||||
}
|
||||
|
||||
// NArg is the number of arguments remaining after flags have been processed.
|
||||
func (f *FlagSet) NArg() int { return len(f.args) }
|
||||
|
||||
// NArg is the number of arguments remaining after flags have been processed.
|
||||
func NArg() int { return len(commandLine.args) }
|
||||
|
||||
// Args returns the non-flag arguments.
|
||||
func (f *FlagSet) Args() []string { return f.args }
|
||||
|
||||
// Args returns the non-flag command-line arguments.
|
||||
func Args() []string { return commandLine.args }
|
||||
|
||||
// BoolVar defines a bool flag with specified name, default value, and usage string.
|
||||
// The argument p points to a bool variable in which to store the value of the flag.
|
||||
func (f *FlagSet) BoolVar(p *bool, name string, value bool, usage string) {
|
||||
f.Var(newBoolValue(value, p), name, usage)
|
||||
}
|
||||
|
||||
// BoolVar defines a bool flag with specified name, default value, and usage string.
|
||||
// The argument p points to a bool variable in which to store the value of the flag.
|
||||
func BoolVar(p *bool, name string, value bool, usage string) {
|
||||
commandLine.Var(newBoolValue(value, p), name, usage)
|
||||
}
|
||||
|
||||
// Bool defines a bool flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a bool variable that stores the value of the flag.
|
||||
func (f *FlagSet) Bool(name string, value bool, usage string) *bool {
|
||||
p := new(bool)
|
||||
f.BoolVar(p, name, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Bool defines a bool flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a bool variable that stores the value of the flag.
|
||||
func Bool(name string, value bool, usage string) *bool {
|
||||
return commandLine.Bool(name, value, usage)
|
||||
}
|
||||
|
||||
// IntVar defines an int flag with specified name, default value, and usage string.
|
||||
// The argument p points to an int variable in which to store the value of the flag.
|
||||
func (f *FlagSet) IntVar(p *int, name string, value int, usage string) {
|
||||
f.Var(newIntValue(value, p), name, usage)
|
||||
}
|
||||
|
||||
// IntVar defines an int flag with specified name, default value, and usage string.
|
||||
// The argument p points to an int variable in which to store the value of the flag.
|
||||
func IntVar(p *int, name string, value int, usage string) {
|
||||
commandLine.Var(newIntValue(value, p), name, usage)
|
||||
}
|
||||
|
||||
// Int defines an int flag with specified name, default value, and usage string.
|
||||
// The return value is the address of an int variable that stores the value of the flag.
|
||||
func (f *FlagSet) Int(name string, value int, usage string) *int {
|
||||
p := new(int)
|
||||
f.IntVar(p, name, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Int defines an int flag with specified name, default value, and usage string.
|
||||
// The return value is the address of an int variable that stores the value of the flag.
|
||||
func Int(name string, value int, usage string) *int {
|
||||
return commandLine.Int(name, value, usage)
|
||||
}
|
||||
|
||||
// Int64Var defines an int64 flag with specified name, default value, and usage string.
|
||||
// The argument p points to an int64 variable in which to store the value of the flag.
|
||||
func (f *FlagSet) Int64Var(p *int64, name string, value int64, usage string) {
|
||||
f.Var(newInt64Value(value, p), name, usage)
|
||||
}
|
||||
|
||||
// Int64Var defines an int64 flag with specified name, default value, and usage string.
|
||||
// The argument p points to an int64 variable in which to store the value of the flag.
|
||||
func Int64Var(p *int64, name string, value int64, usage string) {
|
||||
commandLine.Var(newInt64Value(value, p), name, usage)
|
||||
}
|
||||
|
||||
// Int64 defines an int64 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of an int64 variable that stores the value of the flag.
|
||||
func (f *FlagSet) Int64(name string, value int64, usage string) *int64 {
|
||||
p := new(int64)
|
||||
f.Int64Var(p, name, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Int64 defines an int64 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of an int64 variable that stores the value of the flag.
|
||||
func Int64(name string, value int64, usage string) *int64 {
|
||||
return commandLine.Int64(name, value, usage)
|
||||
}
|
||||
|
||||
// UintVar defines a uint flag with specified name, default value, and usage string.
|
||||
// The argument p points to a uint variable in which to store the value of the flag.
|
||||
func (f *FlagSet) UintVar(p *uint, name string, value uint, usage string) {
|
||||
f.Var(newUintValue(value, p), name, usage)
|
||||
}
|
||||
|
||||
// UintVar defines a uint flag with specified name, default value, and usage string.
|
||||
// The argument p points to a uint variable in which to store the value of the flag.
|
||||
func UintVar(p *uint, name string, value uint, usage string) {
|
||||
commandLine.Var(newUintValue(value, p), name, usage)
|
||||
}
|
||||
|
||||
// Uint defines a uint flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a uint variable that stores the value of the flag.
|
||||
func (f *FlagSet) Uint(name string, value uint, usage string) *uint {
|
||||
p := new(uint)
|
||||
f.UintVar(p, name, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Uint defines a uint flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a uint variable that stores the value of the flag.
|
||||
func Uint(name string, value uint, usage string) *uint {
|
||||
return commandLine.Uint(name, value, usage)
|
||||
}
|
||||
|
||||
// Uint64Var defines a uint64 flag with specified name, default value, and usage string.
|
||||
// The argument p points to a uint64 variable in which to store the value of the flag.
|
||||
func (f *FlagSet) Uint64Var(p *uint64, name string, value uint64, usage string) {
|
||||
f.Var(newUint64Value(value, p), name, usage)
|
||||
}
|
||||
|
||||
// Uint64Var defines a uint64 flag with specified name, default value, and usage string.
|
||||
// The argument p points to a uint64 variable in which to store the value of the flag.
|
||||
func Uint64Var(p *uint64, name string, value uint64, usage string) {
|
||||
commandLine.Var(newUint64Value(value, p), name, usage)
|
||||
}
|
||||
|
||||
// Uint64 defines a uint64 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a uint64 variable that stores the value of the flag.
|
||||
func (f *FlagSet) Uint64(name string, value uint64, usage string) *uint64 {
|
||||
p := new(uint64)
|
||||
f.Uint64Var(p, name, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Uint64 defines a uint64 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a uint64 variable that stores the value of the flag.
|
||||
func Uint64(name string, value uint64, usage string) *uint64 {
|
||||
return commandLine.Uint64(name, value, usage)
|
||||
}
|
||||
|
||||
// StringVar defines a string flag with specified name, default value, and usage string.
|
||||
// The argument p points to a string variable in which to store the value of the flag.
|
||||
func (f *FlagSet) StringVar(p *string, name string, value string, usage string) {
|
||||
f.Var(newStringValue(value, p), name, usage)
|
||||
}
|
||||
|
||||
// StringVar defines a string flag with specified name, default value, and usage string.
|
||||
// The argument p points to a string variable in which to store the value of the flag.
|
||||
func StringVar(p *string, name string, value string, usage string) {
|
||||
commandLine.Var(newStringValue(value, p), name, usage)
|
||||
}
|
||||
|
||||
// String defines a string flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a string variable that stores the value of the flag.
|
||||
func (f *FlagSet) String(name string, value string, usage string) *string {
|
||||
p := new(string)
|
||||
f.StringVar(p, name, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// String defines a string flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a string variable that stores the value of the flag.
|
||||
func String(name string, value string, usage string) *string {
|
||||
return commandLine.String(name, value, usage)
|
||||
}
|
||||
|
||||
// Float64Var defines a float64 flag with specified name, default value, and usage string.
|
||||
// The argument p points to a float64 variable in which to store the value of the flag.
|
||||
func (f *FlagSet) Float64Var(p *float64, name string, value float64, usage string) {
|
||||
f.Var(newFloat64Value(value, p), name, usage)
|
||||
}
|
||||
|
||||
// Float64Var defines a float64 flag with specified name, default value, and usage string.
|
||||
// The argument p points to a float64 variable in which to store the value of the flag.
|
||||
func Float64Var(p *float64, name string, value float64, usage string) {
|
||||
commandLine.Var(newFloat64Value(value, p), name, usage)
|
||||
}
|
||||
|
||||
// Float64 defines a float64 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a float64 variable that stores the value of the flag.
|
||||
func (f *FlagSet) Float64(name string, value float64, usage string) *float64 {
|
||||
p := new(float64)
|
||||
f.Float64Var(p, name, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Float64 defines a float64 flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a float64 variable that stores the value of the flag.
|
||||
func Float64(name string, value float64, usage string) *float64 {
|
||||
return commandLine.Float64(name, value, usage)
|
||||
}
|
||||
|
||||
// DurationVar defines a time.Duration flag with specified name, default value, and usage string.
|
||||
// The argument p points to a time.Duration variable in which to store the value of the flag.
|
||||
func (f *FlagSet) DurationVar(p *time.Duration, name string, value time.Duration, usage string) {
|
||||
f.Var(newDurationValue(value, p), name, usage)
|
||||
}
|
||||
|
||||
// DurationVar defines a time.Duration flag with specified name, default value, and usage string.
|
||||
// The argument p points to a time.Duration variable in which to store the value of the flag.
|
||||
func DurationVar(p *time.Duration, name string, value time.Duration, usage string) {
|
||||
commandLine.Var(newDurationValue(value, p), name, usage)
|
||||
}
|
||||
|
||||
// Duration defines a time.Duration flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a time.Duration variable that stores the value of the flag.
|
||||
func (f *FlagSet) Duration(name string, value time.Duration, usage string) *time.Duration {
|
||||
p := new(time.Duration)
|
||||
f.DurationVar(p, name, value, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
// Duration defines a time.Duration flag with specified name, default value, and usage string.
|
||||
// The return value is the address of a time.Duration variable that stores the value of the flag.
|
||||
func Duration(name string, value time.Duration, usage string) *time.Duration {
|
||||
return commandLine.Duration(name, value, usage)
|
||||
}
|
||||
|
||||
// Var defines a flag with the specified name and usage string. The type and
|
||||
// value of the flag are represented by the first argument, of type Value, which
|
||||
// typically holds a user-defined implementation of Value. For instance, the
|
||||
// caller could create a flag that turns a comma-separated string into a slice
|
||||
// of strings by giving the slice the methods of Value; in particular, Set would
|
||||
// decompose the comma-separated string into the slice.
|
||||
func (f *FlagSet) Var(value Value, name string, usage string) {
|
||||
// Remember the default value as a string; it won't change.
|
||||
flag := &Flag{name, usage, value, value.String()}
|
||||
_, alreadythere := f.formal[name]
|
||||
if alreadythere {
|
||||
msg := fmt.Sprintf("%s flag redefined: %s", f.name, name)
|
||||
fmt.Fprintln(f.out(), msg)
|
||||
panic(msg) // Happens only if flags are declared with identical names
|
||||
}
|
||||
if f.formal == nil {
|
||||
f.formal = make(map[string]*Flag)
|
||||
}
|
||||
f.formal[name] = flag
|
||||
}
|
||||
|
||||
// Var defines a flag with the specified name and usage string. The type and
|
||||
// value of the flag are represented by the first argument, of type Value, which
|
||||
// typically holds a user-defined implementation of Value. For instance, the
|
||||
// caller could create a flag that turns a comma-separated string into a slice
|
||||
// of strings by giving the slice the methods of Value; in particular, Set would
|
||||
// decompose the comma-separated string into the slice.
|
||||
func Var(value Value, name string, usage string) {
|
||||
commandLine.Var(value, name, usage)
|
||||
}
|
||||
|
||||
// failf prints to standard error a formatted error and usage message and
|
||||
// returns the error.
|
||||
func (f *FlagSet) failf(format string, a ...interface{}) error {
|
||||
err := fmt.Errorf(format, a...)
|
||||
fmt.Fprintln(f.out(), err)
|
||||
f.usage()
|
||||
return err
|
||||
}
|
||||
|
||||
// usage calls the Usage method for the flag set, or the usage function if
|
||||
// the flag set is commandLine.
|
||||
func (f *FlagSet) usage() {
|
||||
if f == commandLine {
|
||||
Usage()
|
||||
} else if f.Usage == nil {
|
||||
defaultUsage(f)
|
||||
} else {
|
||||
f.Usage()
|
||||
}
|
||||
}
|
||||
|
||||
// parseOne parses one flag. It returns whether a flag was seen.
|
||||
func (f *FlagSet) parseOne() (bool, error) {
|
||||
if len(f.args) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
s := f.args[0]
|
||||
if len(s) == 0 || s[0] != '-' || len(s) == 1 {
|
||||
return false, nil
|
||||
}
|
||||
num_minuses := 1
|
||||
if s[1] == '-' {
|
||||
num_minuses++
|
||||
if len(s) == 2 { // "--" terminates the flags
|
||||
f.args = f.args[1:]
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
name := s[num_minuses:]
|
||||
if len(name) == 0 || name[0] == '-' || name[0] == '=' {
|
||||
return false, f.failf("bad flag syntax: %s", s)
|
||||
}
|
||||
|
||||
// it's a flag. does it have an argument?
|
||||
f.args = f.args[1:]
|
||||
has_value := false
|
||||
value := ""
|
||||
for i := 1; i < len(name); i++ { // equals cannot be first
|
||||
if name[i] == '=' {
|
||||
value = name[i+1:]
|
||||
has_value = true
|
||||
name = name[0:i]
|
||||
break
|
||||
}
|
||||
}
|
||||
m := f.formal
|
||||
flag, alreadythere := m[name] // BUG
|
||||
if !alreadythere {
|
||||
if name == "help" || name == "h" { // special case for nice help message.
|
||||
f.usage()
|
||||
return false, ErrHelp
|
||||
}
|
||||
return false, f.failf("flag provided but not defined: -%s", name)
|
||||
}
|
||||
if fv, ok := flag.Value.(*boolValue); ok { // special case: doesn't need an arg
|
||||
if has_value {
|
||||
if err := fv.Set(value); err != nil {
|
||||
f.failf("invalid boolean value %q for -%s: %v", value, name, err)
|
||||
}
|
||||
} else {
|
||||
fv.Set("true")
|
||||
}
|
||||
} else {
|
||||
// It must have a value, which might be the next argument.
|
||||
if !has_value && len(f.args) > 0 {
|
||||
// value is the next arg
|
||||
has_value = true
|
||||
value, f.args = f.args[0], f.args[1:]
|
||||
}
|
||||
if !has_value {
|
||||
return false, f.failf("flag needs an argument: -%s", name)
|
||||
}
|
||||
if err := flag.Value.Set(value); err != nil {
|
||||
return false, f.failf("invalid value %q for flag -%s: %v", value, name, err)
|
||||
}
|
||||
}
|
||||
if f.actual == nil {
|
||||
f.actual = make(map[string]*Flag)
|
||||
}
|
||||
f.actual[name] = flag
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Parse parses flag definitions from the argument list, which should not
|
||||
// include the command name. Must be called after all flags in the FlagSet
|
||||
// are defined and before flags are accessed by the program.
|
||||
// The return value will be ErrHelp if -help was set but not defined.
|
||||
func (f *FlagSet) Parse(arguments []string) error {
|
||||
f.parsed = true
|
||||
f.args = arguments
|
||||
for {
|
||||
seen, err := f.parseOne()
|
||||
if seen {
|
||||
continue
|
||||
}
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
switch f.errorHandling {
|
||||
case ContinueOnError:
|
||||
return err
|
||||
case ExitOnError:
|
||||
os.Exit(2)
|
||||
case PanicOnError:
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Parsed reports whether f.Parse has been called.
|
||||
func (f *FlagSet) Parsed() bool {
|
||||
return f.parsed
|
||||
}
|
||||
|
||||
// Parse parses the command-line flags from os.Args[1:]. Must be called
|
||||
// after all flags are defined and before flags are accessed by the program.
|
||||
func Parse() {
|
||||
// Ignore errors; commandLine is set for ExitOnError.
|
||||
commandLine.Parse(os.Args[1:])
|
||||
}
|
||||
|
||||
// Parsed returns true if the command-line flags have been parsed.
|
||||
func Parsed() bool {
|
||||
return commandLine.Parsed()
|
||||
}
|
||||
|
||||
// The default set of command-line flags, parsed from os.Args.
|
||||
var commandLine = NewFlagSet(os.Args[0], ExitOnError)
|
||||
|
||||
// NewFlagSet returns a new, empty flag set with the specified name and
|
||||
// error handling property.
|
||||
func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet {
|
||||
f := &FlagSet{
|
||||
name: name,
|
||||
errorHandling: errorHandling,
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
// Init sets the name and error handling property for a flag set.
|
||||
// By default, the zero FlagSet uses an empty name and the
|
||||
// ContinueOnError error handling policy.
|
||||
func (f *FlagSet) Init(name string, errorHandling ErrorHandling) {
|
||||
f.name = name
|
||||
f.errorHandling = errorHandling
|
||||
}
|
288
Godeps/_workspace/src/github.com/gonuts/flag/flag_test.go
generated
vendored
288
Godeps/_workspace/src/github.com/gonuts/flag/flag_test.go
generated
vendored
@ -1,288 +0,0 @@
|
||||
// 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 flag_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
. "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag"
|
||||
)
|
||||
|
||||
var (
|
||||
test_bool = Bool("test_bool", false, "bool value")
|
||||
test_int = Int("test_int", 0, "int value")
|
||||
test_int64 = Int64("test_int64", 0, "int64 value")
|
||||
test_uint = Uint("test_uint", 0, "uint value")
|
||||
test_uint64 = Uint64("test_uint64", 0, "uint64 value")
|
||||
test_string = String("test_string", "0", "string value")
|
||||
test_float64 = Float64("test_float64", 0, "float64 value")
|
||||
test_duration = Duration("test_duration", 0, "time.Duration value")
|
||||
)
|
||||
|
||||
func boolString(s string) string {
|
||||
if s == "0" {
|
||||
return "false"
|
||||
}
|
||||
return "true"
|
||||
}
|
||||
|
||||
func TestEverything(t *testing.T) {
|
||||
m := make(map[string]*Flag)
|
||||
desired := "0"
|
||||
visitor := func(f *Flag) {
|
||||
if len(f.Name) > 5 && f.Name[0:5] == "test_" {
|
||||
m[f.Name] = f
|
||||
ok := false
|
||||
switch {
|
||||
case f.Value.String() == desired:
|
||||
ok = true
|
||||
case f.Name == "test_bool" && f.Value.String() == boolString(desired):
|
||||
ok = true
|
||||
case f.Name == "test_duration" && f.Value.String() == desired+"s":
|
||||
ok = true
|
||||
}
|
||||
if !ok {
|
||||
t.Error("Visit: bad value", f.Value.String(), "for", f.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
VisitAll(visitor)
|
||||
if len(m) != 8 {
|
||||
t.Error("VisitAll misses some flags")
|
||||
for k, v := range m {
|
||||
t.Log(k, *v)
|
||||
}
|
||||
}
|
||||
m = make(map[string]*Flag)
|
||||
Visit(visitor)
|
||||
if len(m) != 0 {
|
||||
t.Errorf("Visit sees unset flags")
|
||||
for k, v := range m {
|
||||
t.Log(k, *v)
|
||||
}
|
||||
}
|
||||
// Now set all flags
|
||||
Set("test_bool", "true")
|
||||
Set("test_int", "1")
|
||||
Set("test_int64", "1")
|
||||
Set("test_uint", "1")
|
||||
Set("test_uint64", "1")
|
||||
Set("test_string", "1")
|
||||
Set("test_float64", "1")
|
||||
Set("test_duration", "1s")
|
||||
desired = "1"
|
||||
Visit(visitor)
|
||||
if len(m) != 8 {
|
||||
t.Error("Visit fails after set")
|
||||
for k, v := range m {
|
||||
t.Log(k, *v)
|
||||
}
|
||||
}
|
||||
// Now test they're visited in sort order.
|
||||
var flagNames []string
|
||||
Visit(func(f *Flag) { flagNames = append(flagNames, f.Name) })
|
||||
if !sort.StringsAreSorted(flagNames) {
|
||||
t.Errorf("flag names not sorted: %v", flagNames)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUsage(t *testing.T) {
|
||||
called := false
|
||||
ResetForTesting(func() { called = true })
|
||||
if CommandLine().Parse([]string{"-x"}) == nil {
|
||||
t.Error("parse did not fail for unknown flag")
|
||||
}
|
||||
if !called {
|
||||
t.Error("did not call Usage for unknown flag")
|
||||
}
|
||||
}
|
||||
|
||||
func testParse(f *FlagSet, t *testing.T) {
|
||||
if f.Parsed() {
|
||||
t.Error("f.Parse() = true before Parse")
|
||||
}
|
||||
boolFlag := f.Bool("bool", false, "bool value")
|
||||
bool2Flag := f.Bool("bool2", false, "bool2 value")
|
||||
intFlag := f.Int("int", 0, "int value")
|
||||
int64Flag := f.Int64("int64", 0, "int64 value")
|
||||
uintFlag := f.Uint("uint", 0, "uint value")
|
||||
uint64Flag := f.Uint64("uint64", 0, "uint64 value")
|
||||
stringFlag := f.String("string", "0", "string value")
|
||||
float64Flag := f.Float64("float64", 0, "float64 value")
|
||||
durationFlag := f.Duration("duration", 5*time.Second, "time.Duration value")
|
||||
extra := "one-extra-argument"
|
||||
args := []string{
|
||||
"-bool",
|
||||
"-bool2=true",
|
||||
"--int", "22",
|
||||
"--int64", "0x23",
|
||||
"-uint", "24",
|
||||
"--uint64", "25",
|
||||
"-string", "hello",
|
||||
"-float64", "2718e28",
|
||||
"-duration", "2m",
|
||||
extra,
|
||||
}
|
||||
if err := f.Parse(args); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !f.Parsed() {
|
||||
t.Error("f.Parse() = false after Parse")
|
||||
}
|
||||
if *boolFlag != true {
|
||||
t.Error("bool flag should be true, is ", *boolFlag)
|
||||
}
|
||||
if *bool2Flag != true {
|
||||
t.Error("bool2 flag should be true, is ", *bool2Flag)
|
||||
}
|
||||
if *intFlag != 22 {
|
||||
t.Error("int flag should be 22, is ", *intFlag)
|
||||
}
|
||||
if *int64Flag != 0x23 {
|
||||
t.Error("int64 flag should be 0x23, is ", *int64Flag)
|
||||
}
|
||||
if *uintFlag != 24 {
|
||||
t.Error("uint flag should be 24, is ", *uintFlag)
|
||||
}
|
||||
if *uint64Flag != 25 {
|
||||
t.Error("uint64 flag should be 25, is ", *uint64Flag)
|
||||
}
|
||||
if *stringFlag != "hello" {
|
||||
t.Error("string flag should be `hello`, is ", *stringFlag)
|
||||
}
|
||||
if *float64Flag != 2718e28 {
|
||||
t.Error("float64 flag should be 2718e28, is ", *float64Flag)
|
||||
}
|
||||
if *durationFlag != 2*time.Minute {
|
||||
t.Error("duration flag should be 2m, is ", *durationFlag)
|
||||
}
|
||||
if len(f.Args()) != 1 {
|
||||
t.Error("expected one argument, got", len(f.Args()))
|
||||
} else if f.Args()[0] != extra {
|
||||
t.Errorf("expected argument %q got %q", extra, f.Args()[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
ResetForTesting(func() { t.Error("bad parse") })
|
||||
testParse(CommandLine(), t)
|
||||
}
|
||||
|
||||
func TestFlagSetParse(t *testing.T) {
|
||||
testParse(NewFlagSet("test", ContinueOnError), t)
|
||||
}
|
||||
|
||||
// Declare a user-defined flag type.
|
||||
type flagVar []string
|
||||
|
||||
func (f *flagVar) String() string {
|
||||
return fmt.Sprint([]string(*f))
|
||||
}
|
||||
|
||||
func (f *flagVar) Set(value string) error {
|
||||
*f = append(*f, value)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *flagVar) Get() interface{} { return []string(*f) }
|
||||
|
||||
func TestUserDefined(t *testing.T) {
|
||||
var flags FlagSet
|
||||
flags.Init("test", ContinueOnError)
|
||||
var v flagVar
|
||||
flags.Var(&v, "v", "usage")
|
||||
if err := flags.Parse([]string{"-v", "1", "-v", "2", "-v=3"}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if len(v) != 3 {
|
||||
t.Fatal("expected 3 args; got ", len(v))
|
||||
}
|
||||
expect := "[1 2 3]"
|
||||
if v.String() != expect {
|
||||
t.Errorf("expected value %q got %q", expect, v.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetOutput(t *testing.T) {
|
||||
var flags FlagSet
|
||||
var buf bytes.Buffer
|
||||
flags.SetOutput(&buf)
|
||||
flags.Init("test", ContinueOnError)
|
||||
flags.Parse([]string{"-unknown"})
|
||||
if out := buf.String(); !strings.Contains(out, "-unknown") {
|
||||
t.Logf("expected output mentioning unknown; got %q", out)
|
||||
}
|
||||
}
|
||||
|
||||
// This tests that one can reset the flags. This still works but not well, and is
|
||||
// superseded by FlagSet.
|
||||
func TestChangingArgs(t *testing.T) {
|
||||
ResetForTesting(func() { t.Fatal("bad parse") })
|
||||
oldArgs := os.Args
|
||||
defer func() { os.Args = oldArgs }()
|
||||
os.Args = []string{"cmd", "-before", "subcmd", "-after", "args"}
|
||||
before := Bool("before", false, "")
|
||||
if err := CommandLine().Parse(os.Args[1:]); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cmd := Arg(0)
|
||||
os.Args = Args()
|
||||
after := Bool("after", false, "")
|
||||
Parse()
|
||||
args := Args()
|
||||
|
||||
if !*before || cmd != "subcmd" || !*after || len(args) != 1 || args[0] != "args" {
|
||||
t.Fatalf("expected true subcmd true [args] got %v %v %v %v", *before, cmd, *after, args)
|
||||
}
|
||||
}
|
||||
|
||||
// Test that -help invokes the usage message and returns ErrHelp.
|
||||
func TestHelp(t *testing.T) {
|
||||
var helpCalled = false
|
||||
fs := NewFlagSet("help test", ContinueOnError)
|
||||
fs.Usage = func() { helpCalled = true }
|
||||
var flag bool
|
||||
fs.BoolVar(&flag, "flag", false, "regular flag")
|
||||
// Regular flag invocation should work
|
||||
err := fs.Parse([]string{"-flag=true"})
|
||||
if err != nil {
|
||||
t.Fatal("expected no error; got ", err)
|
||||
}
|
||||
if !flag {
|
||||
t.Error("flag was not set by -flag")
|
||||
}
|
||||
if helpCalled {
|
||||
t.Error("help called for regular flag")
|
||||
helpCalled = false // reset for next test
|
||||
}
|
||||
// Help flag should work as expected.
|
||||
err = fs.Parse([]string{"-help"})
|
||||
if err == nil {
|
||||
t.Fatal("error expected")
|
||||
}
|
||||
if err != ErrHelp {
|
||||
t.Fatal("expected ErrHelp; got ", err)
|
||||
}
|
||||
if !helpCalled {
|
||||
t.Fatal("help was not called")
|
||||
}
|
||||
// If we define a help flag, that should override.
|
||||
var help bool
|
||||
fs.BoolVar(&help, "help", false, "help flag")
|
||||
helpCalled = false
|
||||
err = fs.Parse([]string{"-help"})
|
||||
if err != nil {
|
||||
t.Fatal("expected no error for defined -help; got ", err)
|
||||
}
|
||||
if helpCalled {
|
||||
t.Fatal("help was called; should not have been for defined help flag")
|
||||
}
|
||||
}
|
26
Godeps/_workspace/src/github.com/h2so5/utp/.gitignore
generated
vendored
Normal file
26
Godeps/_workspace/src/github.com/h2so5/utp/.gitignore
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
||||
|
||||
_ucat_test/libutp
|
7
Godeps/_workspace/src/github.com/h2so5/utp/.travis.yml
generated
vendored
Normal file
7
Godeps/_workspace/src/github.com/h2so5/utp/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
language: go
|
||||
|
||||
script:
|
||||
- GO_UTP_LOGGING=2 go test -v -bench .
|
||||
- go test -v -race
|
||||
- GO_UTP_LOGGING=2 go run benchmark/main.go -h
|
||||
- GO_UTP_LOGGING=2 cd _ucat_test; make test
|
21
Godeps/_workspace/src/github.com/h2so5/utp/LICENSE
generated
vendored
Normal file
21
Godeps/_workspace/src/github.com/h2so5/utp/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Ron Hashimoto
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
57
Godeps/_workspace/src/github.com/h2so5/utp/README.md
generated
vendored
Normal file
57
Godeps/_workspace/src/github.com/h2so5/utp/README.md
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
utp
|
||||
===
|
||||
|
||||
μTP (Micro Transport Protocol) implementation
|
||||
|
||||
[](https://ci.appveyor.com/project/h2so5/utp)
|
||||
[](https://travis-ci.org/h2so5/utp)
|
||||
[](http://godoc.org/github.com/h2so5/utp)
|
||||
|
||||
http://www.bittorrent.org/beps/bep_0029.html
|
||||
|
||||
**warning: This is a buggy alpha version.**
|
||||
|
||||
## Benchmark History
|
||||
|
||||
[]()
|
||||
|
||||
## Installation
|
||||
|
||||
```
|
||||
go get github.com/h2so5/utp
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
Echo server
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/h2so5/utp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ln, _ := utp.Listen("utp", ":11000")
|
||||
defer ln.Close()
|
||||
|
||||
conn, _ := ln.AcceptUTP()
|
||||
conn.SetKeepAlive(time.Minute)
|
||||
defer conn.Close()
|
||||
|
||||
for {
|
||||
var buf [1024]byte
|
||||
l, err := conn.Read(buf[:])
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
_, err = conn.Write(buf[:l])
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
34
Godeps/_workspace/src/github.com/h2so5/utp/addr.go
generated
vendored
Normal file
34
Godeps/_workspace/src/github.com/h2so5/utp/addr.go
generated
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
package utp
|
||||
|
||||
import "net"
|
||||
|
||||
type UTPAddr struct {
|
||||
net.Addr
|
||||
}
|
||||
|
||||
func (a UTPAddr) Network() string { return "utp" }
|
||||
|
||||
func utp2udp(n string) (string, error) {
|
||||
switch n {
|
||||
case "utp":
|
||||
return "udp", nil
|
||||
case "utp4":
|
||||
return "udp4", nil
|
||||
case "utp6":
|
||||
return "udp6", nil
|
||||
default:
|
||||
return "", net.UnknownNetworkError(n)
|
||||
}
|
||||
}
|
||||
|
||||
func ResolveUTPAddr(n, addr string) (*UTPAddr, error) {
|
||||
udpnet, err := utp2udp(n)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
udp, err := net.ResolveUDPAddr(udpnet, addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &UTPAddr{Addr: udp}, nil
|
||||
}
|
276
Godeps/_workspace/src/github.com/h2so5/utp/benchmark/main.go
generated
vendored
Normal file
276
Godeps/_workspace/src/github.com/h2so5/utp/benchmark/main.go
generated
vendored
Normal file
@ -0,0 +1,276 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/davecheney/profile"
|
||||
"github.com/dustin/go-humanize"
|
||||
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/h2so5/utp"
|
||||
)
|
||||
|
||||
type RandReader struct{}
|
||||
|
||||
func (r RandReader) Read(p []byte) (n int, err error) {
|
||||
for i := range p {
|
||||
p[i] = byte(rand.Int())
|
||||
}
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
type ByteCounter struct {
|
||||
n int64
|
||||
mutex sync.RWMutex
|
||||
}
|
||||
|
||||
func (b *ByteCounter) Write(p []byte) (n int, err error) {
|
||||
b.mutex.Lock()
|
||||
defer b.mutex.Unlock()
|
||||
b.n += int64(len(p))
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (b *ByteCounter) Length() int64 {
|
||||
b.mutex.RLock()
|
||||
defer b.mutex.RUnlock()
|
||||
return b.n
|
||||
}
|
||||
|
||||
var h = flag.Bool("h", false, "Human readable")
|
||||
|
||||
func main() {
|
||||
var l = flag.Int("c", 10485760, "Payload length (bytes)")
|
||||
var s = flag.Bool("s", false, "Stream mode(Low memory usage, but Slow)")
|
||||
flag.Parse()
|
||||
|
||||
defer profile.Start(profile.CPUProfile).Stop()
|
||||
|
||||
if *h {
|
||||
fmt.Printf("Payload: %s\n", humanize.IBytes(uint64(*l)))
|
||||
} else {
|
||||
fmt.Printf("Payload: %d\n", *l)
|
||||
}
|
||||
|
||||
c2s := c2s(int64(*l), *s)
|
||||
n, p := humanize.ComputeSI(c2s)
|
||||
if *h {
|
||||
fmt.Printf("C2S: %f%sbps\n", n, p)
|
||||
} else {
|
||||
fmt.Printf("C2S: %f\n", c2s)
|
||||
}
|
||||
|
||||
s2c := s2c(int64(*l), *s)
|
||||
n, p = humanize.ComputeSI(s2c)
|
||||
if *h {
|
||||
fmt.Printf("S2C: %f%sbps\n", n, p)
|
||||
} else {
|
||||
fmt.Printf("S2C: %f\n", s2c)
|
||||
}
|
||||
|
||||
avg := (c2s + s2c) / 2.0
|
||||
n, p = humanize.ComputeSI(avg)
|
||||
|
||||
if *h {
|
||||
fmt.Printf("AVG: %f%sbps\n", n, p)
|
||||
} else {
|
||||
fmt.Printf("AVG: %f\n", avg)
|
||||
}
|
||||
}
|
||||
|
||||
func c2s(l int64, stream bool) float64 {
|
||||
ln, err := utp.Listen("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
raddr, err := utp.ResolveUTPAddr("utp", ln.Addr().String())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
c, err := utp.DialUTPTimeout("utp", nil, raddr, 1000*time.Millisecond)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
s, err := ln.Accept()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer s.Close()
|
||||
ln.Close()
|
||||
|
||||
rch := make(chan int)
|
||||
|
||||
sendHash := md5.New()
|
||||
readHash := md5.New()
|
||||
counter := ByteCounter{}
|
||||
|
||||
var bps float64
|
||||
if stream {
|
||||
go func() {
|
||||
defer c.Close()
|
||||
io.Copy(io.MultiWriter(c, sendHash, &counter), io.LimitReader(RandReader{}, l))
|
||||
}()
|
||||
|
||||
go func() {
|
||||
io.Copy(readHash, s)
|
||||
close(rch)
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-time.After(time.Second):
|
||||
if *h {
|
||||
fmt.Printf("\r <--> %s ", humanize.IBytes(uint64(counter.Length())))
|
||||
} else {
|
||||
fmt.Printf("\r <--> %d ", counter.Length())
|
||||
}
|
||||
case <-rch:
|
||||
fmt.Printf("\r")
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
start := time.Now()
|
||||
<-rch
|
||||
bps = float64(l*8) / (float64(time.Now().Sub(start)) / float64(time.Second))
|
||||
|
||||
} else {
|
||||
var sendBuf, readBuf bytes.Buffer
|
||||
io.Copy(io.MultiWriter(&sendBuf, sendHash), io.LimitReader(RandReader{}, l))
|
||||
|
||||
go func() {
|
||||
defer c.Close()
|
||||
io.Copy(c, &sendBuf)
|
||||
}()
|
||||
|
||||
go func() {
|
||||
io.Copy(&readBuf, s)
|
||||
rch <- 0
|
||||
}()
|
||||
|
||||
start := time.Now()
|
||||
<-rch
|
||||
bps = float64(l*8) / (float64(time.Now().Sub(start)) / float64(time.Second))
|
||||
|
||||
io.Copy(sendHash, &sendBuf)
|
||||
io.Copy(readHash, &readBuf)
|
||||
}
|
||||
|
||||
if !bytes.Equal(sendHash.Sum(nil), readHash.Sum(nil)) {
|
||||
log.Fatal("Broken payload")
|
||||
}
|
||||
|
||||
return bps
|
||||
}
|
||||
|
||||
func s2c(l int64, stream bool) float64 {
|
||||
ln, err := utp.Listen("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
raddr, err := utp.ResolveUTPAddr("utp", ln.Addr().String())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
c, err := utp.DialUTPTimeout("utp", nil, raddr, 1000*time.Millisecond)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
s, err := ln.Accept()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer s.Close()
|
||||
ln.Close()
|
||||
|
||||
rch := make(chan int)
|
||||
|
||||
sendHash := md5.New()
|
||||
readHash := md5.New()
|
||||
counter := ByteCounter{}
|
||||
|
||||
var bps float64
|
||||
|
||||
if stream {
|
||||
go func() {
|
||||
defer s.Close()
|
||||
io.Copy(io.MultiWriter(s, sendHash, &counter), io.LimitReader(RandReader{}, l))
|
||||
}()
|
||||
|
||||
go func() {
|
||||
io.Copy(readHash, c)
|
||||
close(rch)
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-time.After(time.Second):
|
||||
if *h {
|
||||
fmt.Printf("\r <--> %s ", humanize.IBytes(uint64(counter.Length())))
|
||||
} else {
|
||||
fmt.Printf("\r <--> %d ", counter.Length())
|
||||
}
|
||||
case <-rch:
|
||||
fmt.Printf("\r")
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
start := time.Now()
|
||||
<-rch
|
||||
bps = float64(l*8) / (float64(time.Now().Sub(start)) / float64(time.Second))
|
||||
|
||||
} else {
|
||||
var sendBuf, readBuf bytes.Buffer
|
||||
io.Copy(io.MultiWriter(&sendBuf, sendHash), io.LimitReader(RandReader{}, l))
|
||||
|
||||
go func() {
|
||||
defer s.Close()
|
||||
io.Copy(s, &sendBuf)
|
||||
}()
|
||||
|
||||
go func() {
|
||||
io.Copy(&readBuf, c)
|
||||
rch <- 0
|
||||
}()
|
||||
|
||||
start := time.Now()
|
||||
<-rch
|
||||
bps = float64(l*8) / (float64(time.Now().Sub(start)) / float64(time.Second))
|
||||
|
||||
io.Copy(sendHash, &sendBuf)
|
||||
io.Copy(readHash, &readBuf)
|
||||
}
|
||||
|
||||
if !bytes.Equal(sendHash.Sum(nil), readHash.Sum(nil)) {
|
||||
log.Fatal("Broken payload")
|
||||
}
|
||||
|
||||
return bps
|
||||
}
|
230
Godeps/_workspace/src/github.com/h2so5/utp/buffer.go
generated
vendored
Normal file
230
Godeps/_workspace/src/github.com/h2so5/utp/buffer.go
generated
vendored
Normal file
@ -0,0 +1,230 @@
|
||||
package utp
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math"
|
||||
"time"
|
||||
)
|
||||
|
||||
type packetBuffer struct {
|
||||
root *packetBufferNode
|
||||
size int
|
||||
begin int
|
||||
}
|
||||
|
||||
type packetBufferNode struct {
|
||||
p *packet
|
||||
next *packetBufferNode
|
||||
pushed time.Time
|
||||
}
|
||||
|
||||
func newPacketBuffer(size, begin int) *packetBuffer {
|
||||
return &packetBuffer{
|
||||
size: size,
|
||||
begin: begin,
|
||||
}
|
||||
}
|
||||
|
||||
func (b *packetBuffer) push(p *packet) error {
|
||||
if int(p.header.seq) > b.begin+b.size-1 {
|
||||
return errors.New("out of bounds")
|
||||
} else if int(p.header.seq) < b.begin {
|
||||
if int(p.header.seq)+math.MaxUint16 > b.begin+b.size-1 {
|
||||
return errors.New("out of bounds")
|
||||
}
|
||||
}
|
||||
if b.root == nil {
|
||||
b.root = &packetBufferNode{}
|
||||
}
|
||||
n := b.root
|
||||
i := b.begin
|
||||
for {
|
||||
if i == int(p.header.seq) {
|
||||
n.p = p
|
||||
n.pushed = time.Now()
|
||||
return nil
|
||||
} else if n.next == nil {
|
||||
n.next = &packetBufferNode{}
|
||||
}
|
||||
n = n.next
|
||||
i = (i + 1) % (math.MaxUint16 + 1)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *packetBuffer) fetch(id uint16) *packet {
|
||||
for p := b.root; p != nil; p = p.next {
|
||||
if p.p != nil {
|
||||
if p.p.header.seq < id {
|
||||
p.p = nil
|
||||
} else if p.p.header.seq == id {
|
||||
r := p.p
|
||||
p.p = nil
|
||||
return r
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *packetBuffer) compact() {
|
||||
for b.root != nil && b.root.p == nil {
|
||||
b.root = b.root.next
|
||||
b.begin = (b.begin + 1) % (math.MaxUint16 + 1)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *packetBuffer) first() *packet {
|
||||
if b.root == nil || b.root.p == nil {
|
||||
return nil
|
||||
}
|
||||
return b.root.p
|
||||
}
|
||||
|
||||
func (b *packetBuffer) frontPushedTime() (time.Time, error) {
|
||||
if b.root == nil || b.root.p == nil {
|
||||
return time.Time{}, errors.New("no first packet")
|
||||
}
|
||||
return b.root.pushed, nil
|
||||
}
|
||||
|
||||
func (b *packetBuffer) fetchSequence() []*packet {
|
||||
var a []*packet
|
||||
for ; b.root != nil && b.root.p != nil; b.root = b.root.next {
|
||||
a = append(a, b.root.p)
|
||||
b.begin = (b.begin + 1) % (math.MaxUint16 + 1)
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func (b *packetBuffer) sequence() []*packet {
|
||||
var a []*packet
|
||||
n := b.root
|
||||
for ; n != nil && n.p != nil; n = n.next {
|
||||
a = append(a, n.p)
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func (b *packetBuffer) space() int {
|
||||
s := b.size
|
||||
for p := b.root; p != nil; p = p.next {
|
||||
s--
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (b *packetBuffer) empty() bool {
|
||||
return b.root == nil
|
||||
}
|
||||
|
||||
// test use only
|
||||
func (b *packetBuffer) all() []*packet {
|
||||
var a []*packet
|
||||
for p := b.root; p != nil; p = p.next {
|
||||
if p.p != nil {
|
||||
a = append(a, p.p)
|
||||
}
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func (b *packetBuffer) generateSelectiveACK() []byte {
|
||||
if b.empty() {
|
||||
return nil
|
||||
}
|
||||
|
||||
var ack []byte
|
||||
var bit uint
|
||||
var octet byte
|
||||
for p := b.root.next; p != nil; p = p.next {
|
||||
if p.p != nil {
|
||||
octet |= (1 << bit)
|
||||
}
|
||||
bit++
|
||||
if bit == 8 {
|
||||
ack = append(ack, octet)
|
||||
bit = 0
|
||||
octet = 0
|
||||
}
|
||||
}
|
||||
|
||||
if bit != 0 {
|
||||
ack = append(ack, octet)
|
||||
}
|
||||
|
||||
for len(ack) > 0 && ack[len(ack)-1] == 0 {
|
||||
ack = ack[:len(ack)-1]
|
||||
}
|
||||
|
||||
return ack
|
||||
}
|
||||
|
||||
func (b *packetBuffer) processSelectiveACK(ack []byte) {
|
||||
if b.empty() {
|
||||
return
|
||||
}
|
||||
|
||||
p := b.root.next
|
||||
if p == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, a := range ack {
|
||||
for i := 0; i < 8; i++ {
|
||||
acked := (a & 1) != 0
|
||||
a >>= 1
|
||||
if acked {
|
||||
p.p = nil
|
||||
}
|
||||
p = p.next
|
||||
if p == nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type timedBuffer struct {
|
||||
d time.Duration
|
||||
root *timedBufferNode
|
||||
}
|
||||
|
||||
type timedBufferNode struct {
|
||||
val float64
|
||||
next *timedBufferNode
|
||||
pushed time.Time
|
||||
}
|
||||
|
||||
func (b *timedBuffer) push(val float64) {
|
||||
var before *timedBufferNode
|
||||
for n := b.root; n != nil; n = n.next {
|
||||
if time.Now().Sub(n.pushed) >= b.d {
|
||||
if before != nil {
|
||||
before.next = nil
|
||||
} else {
|
||||
b.root = nil
|
||||
}
|
||||
break
|
||||
}
|
||||
before = n
|
||||
}
|
||||
b.root = &timedBufferNode{
|
||||
val: val,
|
||||
next: b.root,
|
||||
pushed: time.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
func (b *timedBuffer) min() float64 {
|
||||
if b.root == nil {
|
||||
return 0
|
||||
}
|
||||
min := b.root.val
|
||||
for n := b.root; n != nil; n = n.next {
|
||||
if min > n.val {
|
||||
min = n.val
|
||||
}
|
||||
}
|
||||
return min
|
||||
}
|
761
Godeps/_workspace/src/github.com/h2so5/utp/conn.go
generated
vendored
Normal file
761
Godeps/_workspace/src/github.com/h2so5/utp/conn.go
generated
vendored
Normal file
@ -0,0 +1,761 @@
|
||||
package utp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"math"
|
||||
"math/rand"
|
||||
"net"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
type UTPConn struct {
|
||||
conn net.PacketConn
|
||||
raddr net.Addr
|
||||
rid, sid, seq, ack, lastAck uint16
|
||||
rtt, rttVar, minRtt, rto, dupAck int64
|
||||
diff, maxWindow uint32
|
||||
rdeadline, wdeadline time.Time
|
||||
|
||||
state state
|
||||
lastTimedOut time.Time
|
||||
|
||||
outch chan *outgoingPacket
|
||||
outchch chan int
|
||||
sendch chan *outgoingPacket
|
||||
sendchch chan int
|
||||
recvch chan *packet
|
||||
recvchch chan int
|
||||
readch chan []byte
|
||||
readchch chan int
|
||||
winch chan uint32
|
||||
quitch chan int
|
||||
activech chan int
|
||||
connch chan error
|
||||
finch chan int
|
||||
closech chan<- uint16
|
||||
eofid uint16
|
||||
keepalivech chan time.Duration
|
||||
|
||||
readbuf bytes.Buffer
|
||||
recvbuf *packetBuffer
|
||||
sendbuf *packetBuffer
|
||||
|
||||
stat statistics
|
||||
}
|
||||
|
||||
type statistics struct {
|
||||
sentPackets int
|
||||
resentPackets int
|
||||
receivedPackets int
|
||||
receivedDuplicatedACKs int
|
||||
packetTimedOuts int
|
||||
sentSelectiveACKs int
|
||||
receivedSelectiveACKs int
|
||||
|
||||
rtoSum int
|
||||
rtoCount int
|
||||
}
|
||||
|
||||
func dial(n string, laddr, raddr *UTPAddr, timeout time.Duration) (*UTPConn, error) {
|
||||
udpnet, err := utp2udp(n)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO extract
|
||||
if laddr == nil {
|
||||
addr, err := net.ResolveUDPAddr(udpnet, ":0")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
laddr = &UTPAddr{Addr: addr}
|
||||
}
|
||||
|
||||
conn, err := net.ListenPacket(udpnet, laddr.Addr.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
id := uint16(rand.Intn(math.MaxUint16))
|
||||
|
||||
c := newUTPConn()
|
||||
c.conn = conn
|
||||
c.raddr = raddr.Addr
|
||||
c.rid = id
|
||||
c.sid = id + 1
|
||||
c.seq = 1
|
||||
c.state = state_syn_sent
|
||||
c.sendbuf = newPacketBuffer(window_size, 1)
|
||||
|
||||
go c.recv()
|
||||
go c.loop()
|
||||
|
||||
select {
|
||||
case c.sendch <- &outgoingPacket{st_syn, nil, nil}:
|
||||
case <-c.sendchch:
|
||||
return nil, errors.New("use of closed network connection")
|
||||
}
|
||||
|
||||
var t <-chan time.Time
|
||||
if timeout != 0 {
|
||||
t = time.After(timeout)
|
||||
}
|
||||
|
||||
select {
|
||||
case err := <-c.connch:
|
||||
if err != nil {
|
||||
c.closed()
|
||||
return nil, err
|
||||
}
|
||||
ulog.Printf(1, "Conn(%v): Connected", c.LocalAddr())
|
||||
return c, nil
|
||||
case <-t:
|
||||
c.quitch <- 0
|
||||
return nil, &timeoutError{}
|
||||
}
|
||||
}
|
||||
|
||||
func newUTPConn() *UTPConn {
|
||||
rto := 60
|
||||
|
||||
return &UTPConn{
|
||||
minRtt: math.MaxInt64,
|
||||
maxWindow: mtu,
|
||||
rto: int64(rto),
|
||||
|
||||
outch: make(chan *outgoingPacket, 1),
|
||||
outchch: make(chan int),
|
||||
sendch: make(chan *outgoingPacket, 1),
|
||||
sendchch: make(chan int),
|
||||
recvch: make(chan *packet, 2),
|
||||
recvchch: make(chan int),
|
||||
winch: make(chan uint32, 1),
|
||||
quitch: make(chan int),
|
||||
activech: make(chan int),
|
||||
readch: make(chan []byte, 1),
|
||||
readchch: make(chan int),
|
||||
connch: make(chan error, 1),
|
||||
finch: make(chan int, 1),
|
||||
|
||||
keepalivech: make(chan time.Duration),
|
||||
|
||||
stat: statistics{
|
||||
rtoSum: rto,
|
||||
rtoCount: 1,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *UTPConn) ok() bool { return c != nil && c.conn != nil }
|
||||
|
||||
func (c *UTPConn) Close() error {
|
||||
if !c.ok() {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
|
||||
select {
|
||||
case <-c.activech:
|
||||
default:
|
||||
c.quitch <- 0
|
||||
ulog.Printf(2, "Conn(%v): Wait for close", c.LocalAddr())
|
||||
<-c.finch
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *UTPConn) LocalAddr() net.Addr {
|
||||
return &UTPAddr{Addr: c.conn.LocalAddr()}
|
||||
}
|
||||
|
||||
func (c *UTPConn) RemoteAddr() net.Addr {
|
||||
return &UTPAddr{Addr: c.raddr}
|
||||
}
|
||||
|
||||
func (c *UTPConn) Read(b []byte) (int, error) {
|
||||
if !c.ok() {
|
||||
return 0, syscall.EINVAL
|
||||
}
|
||||
|
||||
if c.readbuf.Len() == 0 {
|
||||
var timeout <-chan time.Time
|
||||
if !c.rdeadline.IsZero() {
|
||||
timeout = time.After(c.rdeadline.Sub(time.Now()))
|
||||
}
|
||||
|
||||
select {
|
||||
case b := <-c.readch:
|
||||
if b == nil {
|
||||
return 0, io.EOF
|
||||
}
|
||||
_, err := c.readbuf.Write(b)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
case <-c.readchch:
|
||||
loop:
|
||||
for {
|
||||
select {
|
||||
case b := <-c.readch:
|
||||
_, err := c.readbuf.Write(b)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
default:
|
||||
break loop
|
||||
}
|
||||
}
|
||||
if c.readbuf.Len() == 0 {
|
||||
return 0, io.EOF
|
||||
}
|
||||
case <-timeout:
|
||||
return 0, &timeoutError{}
|
||||
}
|
||||
}
|
||||
return c.readbuf.Read(b)
|
||||
}
|
||||
|
||||
func (c *UTPConn) Write(b []byte) (int, error) {
|
||||
if !c.ok() {
|
||||
return 0, syscall.EINVAL
|
||||
}
|
||||
|
||||
var wrote uint64
|
||||
for {
|
||||
l := uint64(len(b)) - wrote
|
||||
if l > mss {
|
||||
l = mss
|
||||
}
|
||||
select {
|
||||
case c.outch <- &outgoingPacket{st_data, nil, b[wrote : wrote+l]}:
|
||||
case <-c.outchch:
|
||||
return 0, errors.New("use of closed network connection")
|
||||
}
|
||||
|
||||
wrote += l
|
||||
ulog.Printf(4, "Conn(%v): Write %d/%d bytes", c.LocalAddr(), wrote, len(b))
|
||||
if l < mss {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
func (c *UTPConn) SetDeadline(t time.Time) error {
|
||||
if !c.ok() {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
if err := c.SetReadDeadline(t); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.SetWriteDeadline(t); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *UTPConn) SetReadDeadline(t time.Time) error {
|
||||
if !c.ok() {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
c.rdeadline = t
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *UTPConn) SetWriteDeadline(t time.Time) error {
|
||||
if !c.ok() {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
c.wdeadline = t
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *UTPConn) SetKeepAlive(d time.Duration) error {
|
||||
if !c.ok() {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
select {
|
||||
case <-c.activech:
|
||||
default:
|
||||
c.keepalivech <- d
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func readPacket(data []byte) (*packet, error) {
|
||||
p := globalPool.get()
|
||||
err := p.UnmarshalBinary(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if p.header.ver != version {
|
||||
return nil, errors.New("unsupported header version")
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (c *UTPConn) recv() {
|
||||
for {
|
||||
var buf [mtu]byte
|
||||
len, addr, err := c.conn.ReadFrom(buf[:])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if addr.String() != c.raddr.String() {
|
||||
continue
|
||||
}
|
||||
p, err := readPacket(buf[:len])
|
||||
if err == nil {
|
||||
select {
|
||||
case c.recvch <- p:
|
||||
case <-c.recvchch:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *UTPConn) loop() {
|
||||
var recvExit, sendExit bool
|
||||
var lastReceived time.Time
|
||||
var keepalive <-chan time.Time
|
||||
|
||||
go func() {
|
||||
var window uint32 = window_size * mtu
|
||||
for {
|
||||
if window >= mtu {
|
||||
select {
|
||||
case b := <-c.outch:
|
||||
select {
|
||||
case c.sendch <- b:
|
||||
window -= mtu
|
||||
case <-c.sendchch:
|
||||
return
|
||||
}
|
||||
case <-c.outchch:
|
||||
return
|
||||
case w := <-c.winch:
|
||||
window = w
|
||||
}
|
||||
} else {
|
||||
window = <-c.winch
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-c.sendchch:
|
||||
sendExit = true
|
||||
default:
|
||||
}
|
||||
select {
|
||||
case <-c.recvchch:
|
||||
recvExit = true
|
||||
default:
|
||||
}
|
||||
select {
|
||||
case p := <-c.recvch:
|
||||
ack := c.processPacket(p)
|
||||
lastReceived = time.Now()
|
||||
if ack {
|
||||
out := &outgoingPacket{st_state, nil, nil}
|
||||
selack := c.sendbuf.generateSelectiveACK()
|
||||
if len(selack) > 0 {
|
||||
out.ext = []extension{
|
||||
extension{
|
||||
typ: ext_selective_ack,
|
||||
payload: selack,
|
||||
},
|
||||
}
|
||||
c.stat.sentSelectiveACKs++
|
||||
}
|
||||
c.sendPacket(out)
|
||||
}
|
||||
|
||||
case b := <-c.sendch:
|
||||
c.sendPacket(b)
|
||||
|
||||
case <-time.After(time.Duration(c.rto) * time.Millisecond):
|
||||
if !c.state.active && time.Now().Sub(lastReceived) > reset_timeout {
|
||||
ulog.Printf(2, "Conn(%v): Connection timed out", c.LocalAddr())
|
||||
c.sendPacket(&outgoingPacket{st_reset, nil, nil})
|
||||
c.close()
|
||||
} else {
|
||||
t, err := c.sendbuf.frontPushedTime()
|
||||
if err == nil && c.lastTimedOut != t && time.Now().Sub(t) > time.Duration(c.rto)*time.Millisecond {
|
||||
c.lastTimedOut = t
|
||||
c.stat.packetTimedOuts++
|
||||
c.maxWindow /= 2
|
||||
if c.maxWindow < mtu {
|
||||
c.maxWindow = mtu
|
||||
}
|
||||
for _, p := range c.sendbuf.sequence() {
|
||||
c.resendPacket(p)
|
||||
}
|
||||
}
|
||||
}
|
||||
case d := <-c.keepalivech:
|
||||
if d <= 0 {
|
||||
keepalive = nil
|
||||
} else {
|
||||
keepalive = time.Tick(d)
|
||||
}
|
||||
case <-keepalive:
|
||||
ulog.Printf(2, "Conn(%v): Send keepalive", c.LocalAddr())
|
||||
c.sendPacket(&outgoingPacket{st_state, nil, nil})
|
||||
|
||||
case <-c.quitch:
|
||||
if c.state.exit != nil {
|
||||
c.state.exit(c)
|
||||
}
|
||||
}
|
||||
if recvExit && sendExit {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *UTPConn) sendPacket(b *outgoingPacket) {
|
||||
p := c.makePacket(b)
|
||||
bin, err := p.MarshalBinary()
|
||||
if err == nil {
|
||||
ulog.Printf(3, "SEND %v -> %v: %v", c.conn.LocalAddr(), c.raddr, p.String())
|
||||
c.stat.sentPackets++
|
||||
_, err = c.conn.WriteTo(bin, c.raddr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if b.typ != st_state {
|
||||
c.sendbuf.push(p)
|
||||
} else {
|
||||
globalPool.put(p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *UTPConn) resendPacket(p *packet) {
|
||||
bin, err := p.MarshalBinary()
|
||||
if err == nil {
|
||||
ulog.Printf(3, "RESEND %v -> %v: %v", c.conn.LocalAddr(), c.raddr, p.String())
|
||||
c.stat.resentPackets++
|
||||
_, err = c.conn.WriteTo(bin, c.raddr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func currentMicrosecond() uint32 {
|
||||
return uint32(time.Now().Nanosecond() / 1000)
|
||||
}
|
||||
|
||||
func (c *UTPConn) processPacket(p *packet) bool {
|
||||
var ack bool
|
||||
|
||||
if p.header.t == 0 {
|
||||
c.diff = 0
|
||||
} else {
|
||||
t := currentMicrosecond()
|
||||
if t > p.header.t {
|
||||
c.diff = t - p.header.t
|
||||
if c.minRtt > int64(c.diff) {
|
||||
c.minRtt = int64(c.diff)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ulog.Printf(3, "RECV %v -> %v: %v", c.raddr, c.conn.LocalAddr(), p.String())
|
||||
c.stat.receivedPackets++
|
||||
|
||||
if p.header.typ == st_state {
|
||||
|
||||
f := c.sendbuf.first()
|
||||
if f != nil && p.header.ack == f.header.seq {
|
||||
for _, e := range p.ext {
|
||||
if e.typ == ext_selective_ack {
|
||||
ulog.Printf(3, "Conn(%v): Receive Selective ACK", c.LocalAddr())
|
||||
c.stat.receivedSelectiveACKs++
|
||||
c.sendbuf.processSelectiveACK(e.payload)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s := c.sendbuf.fetch(p.header.ack)
|
||||
if s != nil {
|
||||
current := currentMicrosecond()
|
||||
if current > s.header.t {
|
||||
e := int64(current-s.header.t) / 1000
|
||||
if c.rtt == 0 {
|
||||
c.rtt = e
|
||||
c.rttVar = e / 2
|
||||
} else {
|
||||
d := c.rtt - e
|
||||
if d < 0 {
|
||||
d = -d
|
||||
}
|
||||
c.rttVar += (d - c.rttVar) / 4
|
||||
c.rtt = c.rtt - c.rtt/8 + e/8
|
||||
}
|
||||
c.rto = c.rtt + c.rttVar*4
|
||||
if c.rto < 60 {
|
||||
c.rto = 60
|
||||
} else if c.rto > 1000 {
|
||||
c.rto = 1000
|
||||
}
|
||||
c.stat.rtoSum += int(c.rto)
|
||||
c.stat.rtoCount++
|
||||
}
|
||||
|
||||
if c.diff != 0 {
|
||||
ourDelay := float64(c.diff)
|
||||
offTarget := 100000.0 - ourDelay
|
||||
windowFactor := float64(mtu) / float64(c.maxWindow)
|
||||
delayFactor := offTarget / 100000.0
|
||||
gain := 3000.0 * delayFactor * windowFactor
|
||||
c.maxWindow = uint32(int(c.maxWindow) + int(gain))
|
||||
if c.maxWindow < mtu {
|
||||
c.maxWindow = mtu
|
||||
}
|
||||
ulog.Printf(4, "Conn(%v): Update maxWindow: %d", c.LocalAddr(), c.maxWindow)
|
||||
}
|
||||
globalPool.put(s)
|
||||
}
|
||||
c.sendbuf.compact()
|
||||
if c.lastAck == p.header.ack {
|
||||
c.dupAck++
|
||||
if c.dupAck >= 2 {
|
||||
ulog.Printf(3, "Conn(%v): Receive 3 duplicated acks: %d", c.LocalAddr(), p.header.ack)
|
||||
c.stat.receivedDuplicatedACKs++
|
||||
p := c.sendbuf.first()
|
||||
if p != nil {
|
||||
c.maxWindow /= 2
|
||||
if c.maxWindow < mtu {
|
||||
c.maxWindow = mtu
|
||||
}
|
||||
ulog.Printf(4, "Conn(%v): Update maxWindow: %d", c.LocalAddr(), c.maxWindow)
|
||||
c.resendPacket(p)
|
||||
}
|
||||
c.dupAck = 0
|
||||
}
|
||||
} else {
|
||||
c.dupAck = 0
|
||||
}
|
||||
c.lastAck = p.header.ack
|
||||
if p.header.ack == c.seq-1 {
|
||||
wnd := p.header.wnd
|
||||
if wnd > c.maxWindow {
|
||||
wnd = c.maxWindow
|
||||
}
|
||||
ulog.Printf(4, "Conn(%v): Reset window: %d", c.LocalAddr(), wnd)
|
||||
go func() {
|
||||
c.winch <- wnd
|
||||
}()
|
||||
}
|
||||
if c.state.state != nil {
|
||||
c.state.state(c, p)
|
||||
}
|
||||
globalPool.put(p)
|
||||
} else if p.header.typ == st_reset {
|
||||
globalPool.put(p)
|
||||
c.close()
|
||||
} else {
|
||||
if c.recvbuf == nil {
|
||||
return false
|
||||
}
|
||||
ack = true
|
||||
c.recvbuf.push(p)
|
||||
for _, s := range c.recvbuf.fetchSequence() {
|
||||
c.ack = s.header.seq
|
||||
switch s.header.typ {
|
||||
case st_data:
|
||||
if c.state.data != nil {
|
||||
c.state.data(c, s)
|
||||
}
|
||||
case st_fin:
|
||||
if c.state.fin != nil {
|
||||
c.state.fin(c, s)
|
||||
}
|
||||
case st_state:
|
||||
if c.state.state != nil {
|
||||
c.state.state(c, s)
|
||||
}
|
||||
}
|
||||
globalPool.put(s)
|
||||
}
|
||||
}
|
||||
return ack
|
||||
}
|
||||
|
||||
func (c *UTPConn) makePacket(b *outgoingPacket) *packet {
|
||||
wnd := window_size * mtu
|
||||
if c.recvbuf != nil {
|
||||
wnd = c.recvbuf.space() * mtu
|
||||
}
|
||||
id := c.sid
|
||||
if b.typ == st_syn {
|
||||
id = c.rid
|
||||
}
|
||||
p := globalPool.get()
|
||||
p.header.typ = b.typ
|
||||
p.header.ver = version
|
||||
p.header.id = id
|
||||
p.header.t = currentMicrosecond()
|
||||
p.header.diff = c.diff
|
||||
p.header.wnd = uint32(wnd)
|
||||
p.header.seq = c.seq
|
||||
p.header.ack = c.ack
|
||||
if b.typ == st_fin {
|
||||
c.eofid = c.seq
|
||||
}
|
||||
if !(b.typ == st_state && len(b.payload) == 0) {
|
||||
c.seq++
|
||||
}
|
||||
p.payload = p.payload[:len(b.payload)]
|
||||
copy(p.payload, b.payload)
|
||||
return p
|
||||
}
|
||||
|
||||
func (c *UTPConn) close() {
|
||||
if !c.state.closed {
|
||||
close(c.outchch)
|
||||
close(c.readchch)
|
||||
close(c.sendchch)
|
||||
close(c.recvchch)
|
||||
close(c.activech)
|
||||
close(c.finch)
|
||||
c.closed()
|
||||
|
||||
// Accepted connection
|
||||
if c.closech != nil {
|
||||
c.closech <- c.sid
|
||||
} else {
|
||||
c.conn.Close()
|
||||
}
|
||||
|
||||
ulog.Printf(1, "Conn(%v): Closed", c.LocalAddr())
|
||||
ulog.Printf(1, "Conn(%v): * SentPackets: %d", c.LocalAddr(), c.stat.sentPackets)
|
||||
ulog.Printf(1, "Conn(%v): * ResentPackets: %d", c.LocalAddr(), c.stat.resentPackets)
|
||||
ulog.Printf(1, "Conn(%v): * ReceivedPackets: %d", c.LocalAddr(), c.stat.receivedPackets)
|
||||
ulog.Printf(1, "Conn(%v): * ReceivedDuplicatedACKs: %d", c.LocalAddr(), c.stat.receivedDuplicatedACKs)
|
||||
ulog.Printf(1, "Conn(%v): * PacketTimedOuts: %d", c.LocalAddr(), c.stat.packetTimedOuts)
|
||||
ulog.Printf(1, "Conn(%v): * SentSelectiveACKs: %d", c.LocalAddr(), c.stat.sentSelectiveACKs)
|
||||
ulog.Printf(1, "Conn(%v): * ReceivedSelectiveACKs: %d", c.LocalAddr(), c.stat.receivedSelectiveACKs)
|
||||
ulog.Printf(1, "Conn(%v): * AverageRTO: %d", c.LocalAddr(), c.stat.rtoSum/c.stat.rtoCount)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *UTPConn) closed() {
|
||||
ulog.Printf(2, "Conn(%v): Change state: CLOSED", c.LocalAddr())
|
||||
c.state = state_closed
|
||||
}
|
||||
|
||||
func (c *UTPConn) closing() {
|
||||
ulog.Printf(2, "Conn(%v): Change state: CLOSING", c.LocalAddr())
|
||||
c.state = state_closing
|
||||
}
|
||||
|
||||
func (c *UTPConn) syn_sent() {
|
||||
ulog.Printf(2, "Conn(%v): Change state: SYN_SENT", c.LocalAddr())
|
||||
c.state = state_syn_sent
|
||||
}
|
||||
|
||||
func (c *UTPConn) connected() {
|
||||
ulog.Printf(2, "Conn(%v): Change state: CONNECTED", c.LocalAddr())
|
||||
c.state = state_connected
|
||||
}
|
||||
|
||||
func (c *UTPConn) fin_sent() {
|
||||
ulog.Printf(2, "Conn(%v): Change state: FIN_SENT", c.LocalAddr())
|
||||
c.state = state_fin_sent
|
||||
}
|
||||
|
||||
type state struct {
|
||||
data func(c *UTPConn, p *packet)
|
||||
fin func(c *UTPConn, p *packet)
|
||||
state func(c *UTPConn, p *packet)
|
||||
exit func(c *UTPConn)
|
||||
active bool
|
||||
closed bool
|
||||
}
|
||||
|
||||
var state_closed state = state{
|
||||
closed: true,
|
||||
}
|
||||
|
||||
var state_closing state = state{
|
||||
data: func(c *UTPConn, p *packet) {
|
||||
select {
|
||||
case c.readch <- append([]byte(nil), p.payload...):
|
||||
case <-c.readchch:
|
||||
}
|
||||
if c.recvbuf.empty() && c.sendbuf.empty() {
|
||||
c.close()
|
||||
}
|
||||
},
|
||||
state: func(c *UTPConn, p *packet) {
|
||||
if c.recvbuf.empty() && c.sendbuf.empty() {
|
||||
c.close()
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
var state_syn_sent state = state{
|
||||
state: func(c *UTPConn, p *packet) {
|
||||
c.recvbuf = newPacketBuffer(window_size, int(p.header.seq))
|
||||
c.connected()
|
||||
c.connch <- nil
|
||||
},
|
||||
exit: func(c *UTPConn) {
|
||||
go func() {
|
||||
select {
|
||||
case c.outch <- &outgoingPacket{st_fin, nil, nil}:
|
||||
case <-c.outchch:
|
||||
}
|
||||
}()
|
||||
c.fin_sent()
|
||||
},
|
||||
active: true,
|
||||
}
|
||||
|
||||
var state_connected state = state{
|
||||
data: func(c *UTPConn, p *packet) {
|
||||
select {
|
||||
case c.readch <- append([]byte(nil), p.payload...):
|
||||
case <-c.readchch:
|
||||
}
|
||||
},
|
||||
fin: func(c *UTPConn, p *packet) {
|
||||
if c.recvbuf.empty() && c.sendbuf.empty() {
|
||||
c.close()
|
||||
} else {
|
||||
c.closing()
|
||||
}
|
||||
},
|
||||
exit: func(c *UTPConn) {
|
||||
go func() {
|
||||
select {
|
||||
case c.outch <- &outgoingPacket{st_fin, nil, nil}:
|
||||
case <-c.outchch:
|
||||
}
|
||||
}()
|
||||
c.fin_sent()
|
||||
},
|
||||
active: true,
|
||||
}
|
||||
|
||||
var state_fin_sent state = state{
|
||||
state: func(c *UTPConn, p *packet) {
|
||||
if p.header.ack == c.eofid {
|
||||
if c.recvbuf.empty() && c.sendbuf.empty() {
|
||||
c.close()
|
||||
} else {
|
||||
c.closing()
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
68
Godeps/_workspace/src/github.com/h2so5/utp/dial.go
generated
vendored
Normal file
68
Godeps/_workspace/src/github.com/h2so5/utp/dial.go
generated
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
package utp
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Dial(n, addr string) (*UTPConn, error) {
|
||||
raddr, err := ResolveUTPAddr(n, addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return DialUTP(n, nil, raddr)
|
||||
}
|
||||
|
||||
func DialUTP(n string, laddr, raddr *UTPAddr) (*UTPConn, error) {
|
||||
return dial(n, laddr, raddr, 0)
|
||||
}
|
||||
|
||||
func DialUTPTimeout(n string, laddr, raddr *UTPAddr, timeout time.Duration) (*UTPConn, error) {
|
||||
return dial(n, laddr, raddr, timeout)
|
||||
}
|
||||
|
||||
// A Dialer contains options for connecting to an address.
|
||||
//
|
||||
// The zero value for each field is equivalent to dialing without
|
||||
// that option. Dialing with the zero value of Dialer is therefore
|
||||
// equivalent to just calling the Dial function.
|
||||
type Dialer struct {
|
||||
// Timeout is the maximum amount of time a dial will wait for
|
||||
// a connect to complete. If Deadline is also set, it may fail
|
||||
// earlier.
|
||||
//
|
||||
// The default is no timeout.
|
||||
//
|
||||
// With or without a timeout, the operating system may impose
|
||||
// its own earlier timeout. For instance, TCP timeouts are
|
||||
// often around 3 minutes.
|
||||
Timeout time.Duration
|
||||
|
||||
// LocalAddr is the local address to use when dialing an
|
||||
// address. The address must be of a compatible type for the
|
||||
// network being dialed.
|
||||
// If nil, a local address is automatically chosen.
|
||||
LocalAddr net.Addr
|
||||
}
|
||||
|
||||
// Dial connects to the address on the named network.
|
||||
//
|
||||
// See func Dial for a description of the network and address parameters.
|
||||
func (d *Dialer) Dial(n, addr string) (*UTPConn, error) {
|
||||
raddr, err := ResolveUTPAddr(n, addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var laddr *UTPAddr
|
||||
if d.LocalAddr != nil {
|
||||
var ok bool
|
||||
laddr, ok = d.LocalAddr.(*UTPAddr)
|
||||
if !ok {
|
||||
return nil, errors.New("Dialer.LocalAddr is not a UTPAddr")
|
||||
}
|
||||
}
|
||||
|
||||
return DialUTPTimeout(n, laddr, raddr, d.Timeout)
|
||||
}
|
329
Godeps/_workspace/src/github.com/h2so5/utp/listener.go
generated
vendored
Normal file
329
Godeps/_workspace/src/github.com/h2so5/utp/listener.go
generated
vendored
Normal file
@ -0,0 +1,329 @@
|
||||
package utp
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math"
|
||||
"math/rand"
|
||||
"net"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
type UTPListener struct {
|
||||
// RawConn represents an out-of-band connection.
|
||||
// This allows a single socket to handle multiple protocols.
|
||||
RawConn net.PacketConn
|
||||
|
||||
conn net.PacketConn
|
||||
conns map[uint16]*UTPConn
|
||||
accept chan (*UTPConn)
|
||||
err chan (error)
|
||||
lasterr error
|
||||
deadline time.Time
|
||||
closech chan int
|
||||
connch chan uint16
|
||||
closed bool
|
||||
}
|
||||
|
||||
func Listen(n, laddr string) (*UTPListener, error) {
|
||||
addr, err := ResolveUTPAddr(n, laddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ListenUTP(n, addr)
|
||||
}
|
||||
|
||||
func ListenUTP(n string, laddr *UTPAddr) (*UTPListener, error) {
|
||||
udpnet, err := utp2udp(n)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn, err := listenPacket(udpnet, laddr.Addr.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
l := UTPListener{
|
||||
RawConn: newRawConn(conn),
|
||||
conn: conn,
|
||||
conns: make(map[uint16]*UTPConn),
|
||||
accept: make(chan (*UTPConn), 10),
|
||||
err: make(chan (error), 1),
|
||||
closech: make(chan int),
|
||||
connch: make(chan uint16),
|
||||
lasterr: nil,
|
||||
}
|
||||
|
||||
l.listen()
|
||||
return &l, nil
|
||||
}
|
||||
|
||||
type incoming struct {
|
||||
p *packet
|
||||
addr net.Addr
|
||||
}
|
||||
|
||||
func (l *UTPListener) listen() {
|
||||
inch := make(chan incoming)
|
||||
raw := l.RawConn.(*rawConn)
|
||||
|
||||
// reads udp packets
|
||||
go func() {
|
||||
for {
|
||||
var buf [mtu]byte
|
||||
len, addr, err := l.conn.ReadFrom(buf[:])
|
||||
if err != nil {
|
||||
l.err <- err
|
||||
return
|
||||
}
|
||||
p, err := readPacket(buf[:len])
|
||||
if err == nil {
|
||||
inch <- incoming{p, addr}
|
||||
} else {
|
||||
select {
|
||||
case <-raw.closed:
|
||||
default:
|
||||
i := rawIncoming{b: buf[:len], addr: addr}
|
||||
select {
|
||||
case raw.in <- i:
|
||||
default:
|
||||
// discard the oldest packet
|
||||
<-raw.in
|
||||
raw.in <- i
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case i := <-inch:
|
||||
l.processPacket(i.p, i.addr)
|
||||
case <-l.closech:
|
||||
ulog.Printf(2, "Listener(%v): Stop listening", l.conn.LocalAddr())
|
||||
close(l.accept)
|
||||
l.closed = true
|
||||
case id := <-l.connch:
|
||||
if _, ok := l.conns[id]; !ok {
|
||||
delete(l.conns, id+1)
|
||||
ulog.Printf(2, "Listener(%v): Connection closed #%d (alive: %d)", l.conn.LocalAddr(), id, len(l.conns))
|
||||
if l.closed && len(l.conns) == 0 {
|
||||
ulog.Printf(2, "Listener(%v): All accepted connections are closed", l.conn.LocalAddr())
|
||||
l.conn.Close()
|
||||
ulog.Printf(1, "Listener(%v): Closed", l.conn.LocalAddr())
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
ulog.Printf(1, "Listener(%v): Start listening", l.conn.LocalAddr())
|
||||
}
|
||||
|
||||
func listenPacket(n, addr string) (net.PacketConn, error) {
|
||||
if n == "mem" {
|
||||
return nil, errors.New("TODO implement in-memory packet connection")
|
||||
}
|
||||
return net.ListenPacket(n, addr)
|
||||
}
|
||||
|
||||
func (l *UTPListener) processPacket(p *packet, addr net.Addr) {
|
||||
switch p.header.typ {
|
||||
case st_data, st_fin, st_state, st_reset:
|
||||
if c, ok := l.conns[p.header.id]; ok {
|
||||
select {
|
||||
case c.recvch <- p:
|
||||
case <-c.recvchch:
|
||||
}
|
||||
}
|
||||
case st_syn:
|
||||
if l.closed {
|
||||
return
|
||||
}
|
||||
sid := p.header.id + 1
|
||||
if _, ok := l.conns[p.header.id]; !ok {
|
||||
seq := rand.Intn(math.MaxUint16)
|
||||
|
||||
c := newUTPConn()
|
||||
c.conn = l.conn
|
||||
c.raddr = addr
|
||||
c.rid = p.header.id + 1
|
||||
c.sid = p.header.id
|
||||
c.seq = uint16(seq)
|
||||
c.ack = p.header.seq
|
||||
c.diff = currentMicrosecond() - p.header.t
|
||||
c.state = state_connected
|
||||
c.closech = l.connch
|
||||
c.recvbuf = newPacketBuffer(window_size, int(p.header.seq))
|
||||
c.sendbuf = newPacketBuffer(window_size, seq)
|
||||
|
||||
go c.loop()
|
||||
select {
|
||||
case c.recvch <- p:
|
||||
case <-c.recvchch:
|
||||
}
|
||||
|
||||
l.conns[sid] = c
|
||||
ulog.Printf(2, "Listener(%v): New incoming connection #%d from %v (alive: %d)", l.conn.LocalAddr(), sid, addr, len(l.conns))
|
||||
|
||||
l.accept <- c
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (l *UTPListener) Accept() (net.Conn, error) {
|
||||
return l.AcceptUTP()
|
||||
}
|
||||
|
||||
func (l *UTPListener) AcceptUTP() (*UTPConn, error) {
|
||||
if l == nil || l.conn == nil {
|
||||
return nil, syscall.EINVAL
|
||||
}
|
||||
if l.lasterr != nil {
|
||||
return nil, l.lasterr
|
||||
}
|
||||
var timeout <-chan time.Time
|
||||
if !l.deadline.IsZero() {
|
||||
timeout = time.After(l.deadline.Sub(time.Now()))
|
||||
}
|
||||
select {
|
||||
case conn := <-l.accept:
|
||||
if conn == nil {
|
||||
return nil, errors.New("use of closed network connection")
|
||||
}
|
||||
return conn, nil
|
||||
case err := <-l.err:
|
||||
l.lasterr = err
|
||||
return nil, err
|
||||
case <-timeout:
|
||||
return nil, &timeoutError{}
|
||||
}
|
||||
}
|
||||
|
||||
func (l *UTPListener) Addr() net.Addr {
|
||||
return &UTPAddr{Addr: l.conn.LocalAddr()}
|
||||
}
|
||||
|
||||
func (l *UTPListener) Close() error {
|
||||
if l == nil || l.conn == nil {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
l.closech <- 0
|
||||
l.RawConn.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *UTPListener) SetDeadline(t time.Time) error {
|
||||
if l == nil || l.conn == nil {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
l.deadline = t
|
||||
return nil
|
||||
}
|
||||
|
||||
type rawIncoming struct {
|
||||
b []byte
|
||||
addr net.Addr
|
||||
}
|
||||
|
||||
type rawConn struct {
|
||||
conn net.PacketConn
|
||||
rdeadline, wdeadline time.Time
|
||||
in chan rawIncoming
|
||||
closed chan int
|
||||
}
|
||||
|
||||
func newRawConn(conn net.PacketConn) *rawConn {
|
||||
return &rawConn{
|
||||
conn: conn,
|
||||
in: make(chan rawIncoming, 100),
|
||||
closed: make(chan int),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *rawConn) ok() bool { return c != nil && c.conn != nil }
|
||||
|
||||
func (c *rawConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) {
|
||||
if !c.ok() {
|
||||
return 0, nil, syscall.EINVAL
|
||||
}
|
||||
select {
|
||||
case <-c.closed:
|
||||
return 0, nil, errors.New("use of closed network connection")
|
||||
default:
|
||||
}
|
||||
var timeout <-chan time.Time
|
||||
if !c.rdeadline.IsZero() {
|
||||
timeout = time.After(c.rdeadline.Sub(time.Now()))
|
||||
}
|
||||
select {
|
||||
case r := <-c.in:
|
||||
return copy(b, r.b), r.addr, nil
|
||||
case <-timeout:
|
||||
return 0, nil, &timeoutError{}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *rawConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
|
||||
if !c.ok() {
|
||||
return 0, syscall.EINVAL
|
||||
}
|
||||
select {
|
||||
case <-c.closed:
|
||||
return 0, errors.New("use of closed network connection")
|
||||
default:
|
||||
}
|
||||
return c.conn.WriteTo(b, addr)
|
||||
}
|
||||
|
||||
func (c *rawConn) Close() error {
|
||||
if !c.ok() {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
select {
|
||||
case <-c.closed:
|
||||
return errors.New("use of closed network connection")
|
||||
default:
|
||||
close(c.closed)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *rawConn) LocalAddr() net.Addr {
|
||||
if !c.ok() {
|
||||
return nil
|
||||
}
|
||||
return c.conn.LocalAddr()
|
||||
}
|
||||
|
||||
func (c *rawConn) SetDeadline(t time.Time) error {
|
||||
if !c.ok() {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
if err := c.SetReadDeadline(t); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.SetWriteDeadline(t); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *rawConn) SetReadDeadline(t time.Time) error {
|
||||
if !c.ok() {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
c.rdeadline = t
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *rawConn) SetWriteDeadline(t time.Time) error {
|
||||
if !c.ok() {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
c.wdeadline = t
|
||||
return nil
|
||||
}
|
50
Godeps/_workspace/src/github.com/h2so5/utp/log.go
generated
vendored
Normal file
50
Godeps/_workspace/src/github.com/h2so5/utp/log.go
generated
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
package utp
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type logger struct {
|
||||
level int
|
||||
}
|
||||
|
||||
var ulog *logger
|
||||
|
||||
func init() {
|
||||
logenv := os.Getenv("GO_UTP_LOGGING")
|
||||
|
||||
var level int
|
||||
if len(logenv) > 0 {
|
||||
l, err := strconv.Atoi(logenv)
|
||||
if err != nil {
|
||||
log.Print("warning: GO_UTP_LOGGING must be numeric")
|
||||
} else {
|
||||
level = l
|
||||
}
|
||||
}
|
||||
|
||||
ulog = &logger{level}
|
||||
}
|
||||
|
||||
func (l *logger) Print(level int, v ...interface{}) {
|
||||
if l.level < level {
|
||||
return
|
||||
}
|
||||
log.Print(v...)
|
||||
}
|
||||
|
||||
func (l *logger) Printf(level int, format string, v ...interface{}) {
|
||||
if l.level < level {
|
||||
return
|
||||
}
|
||||
log.Printf(format, v...)
|
||||
}
|
||||
|
||||
func (l *logger) Println(level int, v ...interface{}) {
|
||||
if l.level < level {
|
||||
return
|
||||
}
|
||||
log.Println(v...)
|
||||
}
|
240
Godeps/_workspace/src/github.com/h2so5/utp/packet.go
generated
vendored
Normal file
240
Godeps/_workspace/src/github.com/h2so5/utp/packet.go
generated
vendored
Normal file
@ -0,0 +1,240 @@
|
||||
package utp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type header struct {
|
||||
typ, ver int
|
||||
id uint16
|
||||
t, diff, wnd uint32
|
||||
seq, ack uint16
|
||||
}
|
||||
|
||||
type extension struct {
|
||||
typ int
|
||||
payload []byte
|
||||
}
|
||||
|
||||
type packet struct {
|
||||
header header
|
||||
ext []extension
|
||||
payload []byte
|
||||
}
|
||||
|
||||
type outgoingPacket struct {
|
||||
typ int
|
||||
ext []extension
|
||||
payload []byte
|
||||
}
|
||||
|
||||
func (p *packet) MarshalBinary() ([]byte, error) {
|
||||
firstExt := ext_none
|
||||
if len(p.ext) > 0 {
|
||||
firstExt = p.ext[0].typ
|
||||
}
|
||||
buf := new(bytes.Buffer)
|
||||
var beforeExt = []interface{}{
|
||||
// | type | ver |
|
||||
uint8(((byte(p.header.typ) << 4) & 0xF0) | (byte(p.header.ver) & 0xF)),
|
||||
// | extension |
|
||||
uint8(firstExt),
|
||||
}
|
||||
var afterExt = []interface{}{
|
||||
// | connection_id |
|
||||
uint16(p.header.id),
|
||||
// | timestamp_microseconds |
|
||||
uint32(p.header.t),
|
||||
// | timestamp_difference_microseconds |
|
||||
uint32(p.header.diff),
|
||||
// | wnd_size |
|
||||
uint32(p.header.wnd),
|
||||
// | seq_nr |
|
||||
uint16(p.header.seq),
|
||||
// | ack_nr |
|
||||
uint16(p.header.ack),
|
||||
}
|
||||
|
||||
for _, v := range beforeExt {
|
||||
err := binary.Write(buf, binary.BigEndian, v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if len(p.ext) > 0 {
|
||||
for i, e := range p.ext {
|
||||
next := ext_none
|
||||
if i < len(p.ext)-1 {
|
||||
next = p.ext[i+1].typ
|
||||
}
|
||||
var ext = []interface{}{
|
||||
// | extension |
|
||||
uint8(next),
|
||||
// | len |
|
||||
uint8(len(e.payload)),
|
||||
}
|
||||
for _, v := range ext {
|
||||
err := binary.Write(buf, binary.BigEndian, v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
_, err := buf.Write(e.payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, v := range afterExt {
|
||||
err := binary.Write(buf, binary.BigEndian, v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
_, err := buf.Write(p.payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func (p *packet) UnmarshalBinary(data []byte) error {
|
||||
p.ext = nil
|
||||
buf := bytes.NewReader(data)
|
||||
var tv, e uint8
|
||||
|
||||
var beforeExt = []interface{}{
|
||||
// | type | ver |
|
||||
(*uint8)(&tv),
|
||||
// | extension |
|
||||
(*uint8)(&e),
|
||||
}
|
||||
for _, v := range beforeExt {
|
||||
err := binary.Read(buf, binary.BigEndian, v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for e != ext_none {
|
||||
currentExt := int(e)
|
||||
var l uint8
|
||||
var ext = []interface{}{
|
||||
// | extension |
|
||||
(*uint8)(&e),
|
||||
// | len |
|
||||
(*uint8)(&l),
|
||||
}
|
||||
for _, v := range ext {
|
||||
err := binary.Read(buf, binary.BigEndian, v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
payload := make([]byte, l)
|
||||
size, err := buf.Read(payload[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if size != len(payload) {
|
||||
return io.EOF
|
||||
}
|
||||
p.ext = append(p.ext, extension{typ: currentExt, payload: payload})
|
||||
}
|
||||
|
||||
var afterExt = []interface{}{
|
||||
// | connection_id |
|
||||
(*uint16)(&p.header.id),
|
||||
// | timestamp_microseconds |
|
||||
(*uint32)(&p.header.t),
|
||||
// | timestamp_difference_microseconds |
|
||||
(*uint32)(&p.header.diff),
|
||||
// | wnd_size |
|
||||
(*uint32)(&p.header.wnd),
|
||||
// | seq_nr |
|
||||
(*uint16)(&p.header.seq),
|
||||
// | ack_nr |
|
||||
(*uint16)(&p.header.ack),
|
||||
}
|
||||
for _, v := range afterExt {
|
||||
err := binary.Read(buf, binary.BigEndian, v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
p.header.typ = int((tv >> 4) & 0xF)
|
||||
p.header.ver = int(tv & 0xF)
|
||||
|
||||
l := buf.Len()
|
||||
if l > 0 {
|
||||
p.payload = p.payload[:l]
|
||||
_, err := buf.Read(p.payload[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p packet) String() string {
|
||||
var s string = fmt.Sprintf("[%d ", p.header.id)
|
||||
switch p.header.typ {
|
||||
case st_data:
|
||||
s += "ST_DATA"
|
||||
case st_fin:
|
||||
s += "ST_FIN"
|
||||
case st_state:
|
||||
s += "ST_STATE"
|
||||
case st_reset:
|
||||
s += "ST_RESET"
|
||||
case st_syn:
|
||||
s += "ST_SYN"
|
||||
}
|
||||
s += fmt.Sprintf(" seq:%d ack:%d len:%d", p.header.seq, p.header.ack, len(p.payload))
|
||||
s += "]"
|
||||
return s
|
||||
}
|
||||
|
||||
var globalPool packetPool
|
||||
|
||||
type packetPool struct {
|
||||
root *packetPoolNode
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
type packetPoolNode struct {
|
||||
p *packet
|
||||
next *packetPoolNode
|
||||
}
|
||||
|
||||
func (o *packetPool) get() *packet {
|
||||
o.mutex.Lock()
|
||||
defer o.mutex.Unlock()
|
||||
r := o.root
|
||||
if r != nil {
|
||||
o.root = o.root.next
|
||||
return r.p
|
||||
} else {
|
||||
return &packet{
|
||||
payload: make([]byte, 0, mss),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (o *packetPool) put(p *packet) {
|
||||
o.mutex.Lock()
|
||||
defer o.mutex.Unlock()
|
||||
o.root = &packetPoolNode{
|
||||
p: p,
|
||||
next: o.root,
|
||||
}
|
||||
}
|
3
Godeps/_workspace/src/github.com/h2so5/utp/ucat/.gitignore
generated
vendored
Normal file
3
Godeps/_workspace/src/github.com/h2so5/utp/ucat/.gitignore
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
ucat
|
||||
random
|
||||
.trash/
|
34
Godeps/_workspace/src/github.com/h2so5/utp/ucat/Makefile
generated
vendored
Normal file
34
Godeps/_workspace/src/github.com/h2so5/utp/ucat/Makefile
generated
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
# Run tests
|
||||
|
||||
testnames=simple
|
||||
tests=$(addprefix test_, $(testnames))
|
||||
trash=.trash/
|
||||
|
||||
all: ucat
|
||||
|
||||
test: clean ucat ${tests}
|
||||
@echo ${tests}
|
||||
@echo "*** tests passed ***"
|
||||
|
||||
# not sue why this doesn't work:
|
||||
# test_%: test_%.sh
|
||||
test_simple: test_simple.sh
|
||||
mkdir -p ${trash}
|
||||
@echo "*** running $@ ***"
|
||||
./$@.sh
|
||||
|
||||
clean:
|
||||
@echo "*** $@ ***"
|
||||
-rm -r ${trash}
|
||||
|
||||
deps: random ucat
|
||||
|
||||
ucat:
|
||||
go build
|
||||
|
||||
random:
|
||||
@echo "*** installing $@ ***"
|
||||
go get github.com/jbenet/go-random/random
|
||||
go build -o random github.com/jbenet/go-random/random
|
||||
|
||||
.PHONY: clean ucat ${tests}
|
49
Godeps/_workspace/src/github.com/h2so5/utp/ucat/test_simple.sh
generated
vendored
Normal file
49
Godeps/_workspace/src/github.com/h2so5/utp/ucat/test_simple.sh
generated
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e # exit on error
|
||||
# set -v # verbose
|
||||
|
||||
log() {
|
||||
echo "--> $1"
|
||||
}
|
||||
|
||||
test_send() {
|
||||
file=$1_
|
||||
count=$2
|
||||
addr=localhost:8765
|
||||
|
||||
# generate random data
|
||||
log "generating $count bytes of random data"
|
||||
./random $count $RANDOM > ${file}expected
|
||||
|
||||
# dialer sends
|
||||
log "sending from dialer"
|
||||
./ucat -v $addr 2>&1 <${file}expected | sed "s/^/ dialer1: /" &
|
||||
./ucat -v -l $addr 2>&1 >${file}actual1 | sed "s/^/listener1: /"
|
||||
diff ${file}expected ${file}actual1
|
||||
if test $? != 0; then
|
||||
log "sending from dialer failed. compare with:\n"
|
||||
log "diff ${file}expected ${file}actual1"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# listener sends
|
||||
log "sending from listener"
|
||||
./ucat -v -l $addr 2>&1 <${file}expected | sed "s/^/listener2: /" &
|
||||
./ucat -v $addr 2>&1 >${file}actual2 | sed "s/^/ dialer2: /"
|
||||
diff ${file}expected ${file}actual2
|
||||
if test $? != 0; then
|
||||
log "sending from listener failed. compare with:\n"
|
||||
log "diff ${file}expected ${file}actual2"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo rm ${file}{expected,actual1,actual2}
|
||||
rm ${file}{expected,actual1,actual2}
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
test_send ".trash/1KB" 1024
|
||||
test_send ".trash/1MB" 1048576
|
||||
test_send ".trash/1GB" 1073741824
|
188
Godeps/_workspace/src/github.com/h2so5/utp/ucat/ucat.go
generated
vendored
Normal file
188
Godeps/_workspace/src/github.com/h2so5/utp/ucat/ucat.go
generated
vendored
Normal file
@ -0,0 +1,188 @@
|
||||
// package ucat provides an implementation of netcat using the go utp package.
|
||||
// It is meant to exercise the utp implementation.
|
||||
// Usage:
|
||||
// ucat [<local address>] <remote address>
|
||||
// ucat -l <local address>
|
||||
//
|
||||
// Address format is: [host]:port
|
||||
//
|
||||
// Note that uTP's congestion control gives priority to tcp flows (web traffic),
|
||||
// so you could use this ucat tool to transfer massive files without hogging
|
||||
// all the bandwidth.
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
utp "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/h2so5/utp"
|
||||
)
|
||||
|
||||
var verbose = false
|
||||
|
||||
// Usage prints out the usage of this module.
|
||||
// Assumes flags use go stdlib flag pacakage.
|
||||
var Usage = func() {
|
||||
text := `ucat - uTP netcat in Go
|
||||
|
||||
Usage:
|
||||
|
||||
listen: %s [<local address>] <remote address>
|
||||
dial: %s -l <local address>
|
||||
|
||||
Address format is Go's: [host]:port
|
||||
`
|
||||
|
||||
fmt.Fprintf(os.Stderr, text, os.Args[0], os.Args[0])
|
||||
flag.PrintDefaults()
|
||||
}
|
||||
|
||||
type args struct {
|
||||
listen bool
|
||||
verbose bool
|
||||
localAddr string
|
||||
remoteAddr string
|
||||
}
|
||||
|
||||
func parseArgs() args {
|
||||
var a args
|
||||
|
||||
// setup + parse flags
|
||||
flag.BoolVar(&a.listen, "listen", false, "listen for connections")
|
||||
flag.BoolVar(&a.listen, "l", false, "listen for connections (short)")
|
||||
flag.BoolVar(&a.verbose, "v", false, "verbose debugging")
|
||||
flag.Usage = Usage
|
||||
flag.Parse()
|
||||
osArgs := flag.Args()
|
||||
|
||||
if len(osArgs) < 1 {
|
||||
exit("")
|
||||
}
|
||||
|
||||
if a.listen {
|
||||
a.localAddr = osArgs[0]
|
||||
} else {
|
||||
if len(osArgs) > 1 {
|
||||
a.localAddr = osArgs[0]
|
||||
a.remoteAddr = osArgs[1]
|
||||
} else {
|
||||
a.remoteAddr = osArgs[0]
|
||||
}
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
func main() {
|
||||
args := parseArgs()
|
||||
verbose = args.verbose
|
||||
|
||||
var err error
|
||||
if args.listen {
|
||||
err = Listen(args.localAddr)
|
||||
} else {
|
||||
err = Dial(args.localAddr, args.remoteAddr)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
exit("%s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func exit(format string, vals ...interface{}) {
|
||||
if format != "" {
|
||||
fmt.Fprintf(os.Stderr, "ucat error: "+format+"\n", vals...)
|
||||
}
|
||||
Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func log(format string, vals ...interface{}) {
|
||||
if verbose {
|
||||
fmt.Fprintf(os.Stderr, "ucat log: "+format+"\n", vals...)
|
||||
}
|
||||
}
|
||||
|
||||
// Listen listens and accepts one incoming uTP connection on a given port,
|
||||
// and pipes all incoming data to os.Stdout.
|
||||
func Listen(localAddr string) error {
|
||||
l, err := utp.Listen("utp", localAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log("listening at %s", l.Addr())
|
||||
|
||||
c, err := l.Accept()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log("accepted connection from %s", c.RemoteAddr())
|
||||
|
||||
// should be able to close listener here, but utp.Listener.Close
|
||||
// closes all open connections.
|
||||
defer l.Close()
|
||||
|
||||
netcat(c)
|
||||
return c.Close()
|
||||
}
|
||||
|
||||
// Dial connects to a remote address and pipes all os.Stdin to the remote end.
|
||||
// If localAddr is set, uses it to Dial from.
|
||||
func Dial(localAddr, remoteAddr string) error {
|
||||
|
||||
var laddr net.Addr
|
||||
var err error
|
||||
if localAddr != "" {
|
||||
laddr, err = utp.ResolveUTPAddr("utp", localAddr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to resolve address %s", localAddr)
|
||||
}
|
||||
}
|
||||
|
||||
if laddr != nil {
|
||||
log("dialing %s from %s", remoteAddr, laddr)
|
||||
} else {
|
||||
log("dialing %s", remoteAddr)
|
||||
}
|
||||
|
||||
d := utp.Dialer{LocalAddr: laddr}
|
||||
c, err := d.Dial("utp", remoteAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log("connected to %s", c.RemoteAddr())
|
||||
|
||||
netcat(c)
|
||||
return c.Close()
|
||||
}
|
||||
|
||||
func netcat(c net.Conn) {
|
||||
log("piping stdio to connection")
|
||||
|
||||
done := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
n, _ := io.Copy(c, os.Stdin)
|
||||
log("sent %d bytes", n)
|
||||
done <- struct{}{}
|
||||
}()
|
||||
go func() {
|
||||
n, _ := io.Copy(os.Stdout, c)
|
||||
log("received %d bytes", n)
|
||||
done <- struct{}{}
|
||||
}()
|
||||
|
||||
// wait until we exit.
|
||||
sigc := make(chan os.Signal, 1)
|
||||
signal.Notify(sigc, syscall.SIGHUP, syscall.SIGINT,
|
||||
syscall.SIGTERM, syscall.SIGQUIT)
|
||||
select {
|
||||
case <-done:
|
||||
case <-sigc:
|
||||
}
|
||||
}
|
29
Godeps/_workspace/src/github.com/h2so5/utp/utp.go
generated
vendored
Normal file
29
Godeps/_workspace/src/github.com/h2so5/utp/utp.go
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
package utp
|
||||
|
||||
import "time"
|
||||
|
||||
const (
|
||||
version = 1
|
||||
|
||||
st_data = 0
|
||||
st_fin = 1
|
||||
st_state = 2
|
||||
st_reset = 3
|
||||
st_syn = 4
|
||||
|
||||
ext_none = 0
|
||||
ext_selective_ack = 1
|
||||
|
||||
header_size = 20
|
||||
mtu = 3200
|
||||
mss = mtu - header_size
|
||||
window_size = 100
|
||||
|
||||
reset_timeout = time.Second
|
||||
)
|
||||
|
||||
type timeoutError struct{}
|
||||
|
||||
func (e *timeoutError) Error() string { return "i/o timeout" }
|
||||
func (e *timeoutError) Timeout() bool { return true }
|
||||
func (e *timeoutError) Temporary() bool { return true }
|
601
Godeps/_workspace/src/github.com/h2so5/utp/utp_test.go
generated
vendored
Normal file
601
Godeps/_workspace/src/github.com/h2so5/utp/utp_test.go
generated
vendored
Normal file
@ -0,0 +1,601 @@
|
||||
package utp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"math/rand"
|
||||
"net"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rand.Seed(time.Now().Unix())
|
||||
}
|
||||
|
||||
func TestReadWrite(t *testing.T) {
|
||||
ln, err := Listen("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
raddr, err := ResolveUTPAddr("utp", ln.Addr().String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c, err := DialUTPTimeout("utp", nil, raddr, 1000*time.Millisecond)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
err = ln.SetDeadline(time.Now().Add(1000 * time.Millisecond))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s, err := ln.Accept()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ln.Close()
|
||||
|
||||
payload := []byte("Hello!")
|
||||
_, err = c.Write(payload)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = s.SetDeadline(time.Now().Add(1000 * time.Millisecond))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var buf [256]byte
|
||||
l, err := s.Read(buf[:])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(payload, buf[:l]) {
|
||||
t.Errorf("expected payload of %v; got %v", payload, buf[:l])
|
||||
}
|
||||
|
||||
payload2 := []byte("World!")
|
||||
_, err = s.Write(payload2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = c.SetDeadline(time.Now().Add(1000 * time.Millisecond))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
l, err = c.Read(buf[:])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(payload2, buf[:l]) {
|
||||
t.Errorf("expected payload of %v; got %v", payload2, buf[:l])
|
||||
}
|
||||
}
|
||||
|
||||
func TestRawReadWrite(t *testing.T) {
|
||||
ln, err := Listen("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ln.Close()
|
||||
|
||||
raddr, err := net.ResolveUDPAddr("udp", ln.Addr().String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c, err := net.DialUDP("udp", nil, raddr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
payload := []byte("Hello!")
|
||||
_, err = c.Write(payload)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var buf [256]byte
|
||||
n, addr, err := ln.RawConn.ReadFrom(buf[:])
|
||||
if !bytes.Equal(payload, buf[:n]) {
|
||||
t.Errorf("expected payload of %v; got %v", payload, buf[:n])
|
||||
}
|
||||
if addr.String() != c.LocalAddr().String() {
|
||||
t.Errorf("expected addr of %v; got %v", c.LocalAddr(), addr.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestLongReadWriteC2S(t *testing.T) {
|
||||
ln, err := Listen("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
raddr, err := ResolveUTPAddr("utp", ln.Addr().String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c, err := DialUTPTimeout("utp", nil, raddr, 1000*time.Millisecond)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
err = ln.SetDeadline(time.Now().Add(1000 * time.Millisecond))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s, err := ln.Accept()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer s.Close()
|
||||
ln.Close()
|
||||
|
||||
var payload [10485760]byte
|
||||
for i := range payload {
|
||||
payload[i] = byte(rand.Int())
|
||||
}
|
||||
|
||||
rch := make(chan []byte)
|
||||
ech := make(chan error, 2)
|
||||
|
||||
go func() {
|
||||
defer c.Close()
|
||||
_, err := c.Write(payload[:])
|
||||
if err != nil {
|
||||
ech <- err
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
b, err := ioutil.ReadAll(s)
|
||||
if err != nil {
|
||||
ech <- err
|
||||
rch <- nil
|
||||
} else {
|
||||
ech <- nil
|
||||
rch <- b
|
||||
}
|
||||
}()
|
||||
|
||||
err = <-ech
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
r := <-rch
|
||||
if r == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !bytes.Equal(r, payload[:]) {
|
||||
t.Errorf("expected payload of %d; got %d", len(payload[:]), len(r))
|
||||
}
|
||||
}
|
||||
|
||||
func TestLongReadWriteS2C(t *testing.T) {
|
||||
ln, err := Listen("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
raddr, err := ResolveUTPAddr("utp", ln.Addr().String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c, err := DialUTPTimeout("utp", nil, raddr, 1000*time.Millisecond)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
err = ln.SetDeadline(time.Now().Add(1000 * time.Millisecond))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s, err := ln.Accept()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer s.Close()
|
||||
ln.Close()
|
||||
|
||||
var payload [10485760]byte
|
||||
for i := range payload {
|
||||
payload[i] = byte(rand.Int())
|
||||
}
|
||||
|
||||
rch := make(chan []byte)
|
||||
ech := make(chan error, 2)
|
||||
|
||||
go func() {
|
||||
defer s.Close()
|
||||
_, err := s.Write(payload[:])
|
||||
if err != nil {
|
||||
ech <- err
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
b, err := ioutil.ReadAll(c)
|
||||
if err != nil {
|
||||
ech <- err
|
||||
rch <- nil
|
||||
} else {
|
||||
ech <- nil
|
||||
rch <- b
|
||||
}
|
||||
}()
|
||||
|
||||
err = <-ech
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
r := <-rch
|
||||
if r == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !bytes.Equal(r, payload[:]) {
|
||||
t.Errorf("expected payload of %d; got %d", len(payload[:]), len(r))
|
||||
}
|
||||
}
|
||||
|
||||
func TestAccept(t *testing.T) {
|
||||
ln, err := Listen("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ln.Close()
|
||||
|
||||
c, err := DialUTPTimeout("utp", nil, ln.Addr().(*UTPAddr), 200*time.Millisecond)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
err = ln.SetDeadline(time.Now().Add(100 * time.Millisecond))
|
||||
_, err = ln.Accept()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAcceptDeadline(t *testing.T) {
|
||||
ln, err := Listen("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ln.Close()
|
||||
err = ln.SetDeadline(time.Now().Add(time.Millisecond))
|
||||
_, err = ln.Accept()
|
||||
if err == nil {
|
||||
t.Fatal("Accept should failed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAcceptClosedListener(t *testing.T) {
|
||||
ln, err := Listen("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = ln.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = ln.Accept()
|
||||
if err == nil {
|
||||
t.Fatal("Accept should failed")
|
||||
}
|
||||
_, err = ln.Accept()
|
||||
if err == nil {
|
||||
t.Fatal("Accept should failed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDialer(t *testing.T) {
|
||||
ln, err := Listen("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ln.Close()
|
||||
|
||||
d := Dialer{}
|
||||
c, err := d.Dial("utp", ln.Addr().String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
}
|
||||
|
||||
func TestDialerAddrs(t *testing.T) {
|
||||
ln, err := Listen("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ln.Close()
|
||||
|
||||
laddr, err := ResolveUTPAddr("utp", "127.0.0.1:45678")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
d := Dialer{LocalAddr: laddr}
|
||||
c1, err := d.Dial("utp", ln.Addr().String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c1.Close()
|
||||
|
||||
c2, err := ln.Accept()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c2.Close()
|
||||
|
||||
eq := func(a, b net.Addr) bool {
|
||||
return a.String() == b.String()
|
||||
}
|
||||
|
||||
if !eq(d.LocalAddr, c2.RemoteAddr()) {
|
||||
t.Fatal("dialer.LocalAddr not equal to c2.RemoteAddr ")
|
||||
}
|
||||
if !eq(c1.LocalAddr(), c2.RemoteAddr()) {
|
||||
t.Fatal("c1.LocalAddr not equal to c2.RemoteAddr ")
|
||||
}
|
||||
if !eq(c2.LocalAddr(), c1.RemoteAddr()) {
|
||||
t.Fatal("c2.LocalAddr not equal to c1.RemoteAddr ")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDialerTimeout(t *testing.T) {
|
||||
timeout := time.Millisecond * 200
|
||||
d := Dialer{Timeout: timeout}
|
||||
done := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
_, err := d.Dial("utp", "127.0.0.1:34567")
|
||||
if err == nil {
|
||||
t.Fatal("should not connect")
|
||||
}
|
||||
done <- struct{}{}
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-time.After(timeout * 2):
|
||||
t.Fatal("should have ended already")
|
||||
case <-done:
|
||||
}
|
||||
}
|
||||
|
||||
func TestPacketBinary(t *testing.T) {
|
||||
h := header{
|
||||
typ: st_fin,
|
||||
ver: version,
|
||||
id: 100,
|
||||
t: 50000,
|
||||
diff: 10000,
|
||||
wnd: 65535,
|
||||
seq: 100,
|
||||
ack: 200,
|
||||
}
|
||||
|
||||
e := []extension{
|
||||
extension{
|
||||
typ: ext_selective_ack,
|
||||
payload: []byte{0, 1, 0, 1},
|
||||
},
|
||||
extension{
|
||||
typ: ext_selective_ack,
|
||||
payload: []byte{100, 0, 200, 0},
|
||||
},
|
||||
}
|
||||
|
||||
p := packet{
|
||||
header: h,
|
||||
ext: e,
|
||||
payload: []byte("abcdefg"),
|
||||
}
|
||||
|
||||
b, err := p.MarshalBinary()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
p2 := packet{payload: make([]byte, 0, mss)}
|
||||
err = p2.UnmarshalBinary(b)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(p, p2) {
|
||||
t.Errorf("expected packet of %v; got %v", p, p2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalShortPacket(t *testing.T) {
|
||||
b := make([]byte, 18)
|
||||
p := packet{}
|
||||
err := p.UnmarshalBinary(b)
|
||||
|
||||
if err == nil {
|
||||
t.Fatal("UnmarshalBinary should fail")
|
||||
} else if err != io.EOF {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteOnClosedChannel(t *testing.T) {
|
||||
ln, err := Listen("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ln.Close()
|
||||
|
||||
c, err := DialUTPTimeout("utp", nil, ln.Addr().(*UTPAddr), 200*time.Millisecond)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
for {
|
||||
_, err := c.Write([]byte{100})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
c.Close()
|
||||
}
|
||||
|
||||
func TestReadOnClosedChannel(t *testing.T) {
|
||||
ln, err := Listen("utp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ln.Close()
|
||||
|
||||
c, err := DialUTPTimeout("utp", nil, ln.Addr().(*UTPAddr), 200*time.Millisecond)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
for {
|
||||
var buf [16]byte
|
||||
_, err := c.Read(buf[:])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
c.Close()
|
||||
}
|
||||
|
||||
func TestPacketBuffer(t *testing.T) {
|
||||
size := 12
|
||||
b := newPacketBuffer(12, 1)
|
||||
|
||||
if b.space() != size {
|
||||
t.Errorf("expected space == %d; got %d", size, b.space())
|
||||
}
|
||||
|
||||
for i := 1; i <= size; i++ {
|
||||
b.push(&packet{header: header{seq: uint16(i)}})
|
||||
}
|
||||
|
||||
if b.space() != 0 {
|
||||
t.Errorf("expected space == 0; got %d", b.space())
|
||||
}
|
||||
|
||||
a := []byte{255, 7}
|
||||
ack := b.generateSelectiveACK()
|
||||
if !bytes.Equal(a, ack) {
|
||||
t.Errorf("expected ack == %v; got %v", a, ack)
|
||||
}
|
||||
|
||||
err := b.push(&packet{header: header{seq: 15}})
|
||||
if err == nil {
|
||||
t.Fatal("push should fail")
|
||||
}
|
||||
|
||||
all := b.all()
|
||||
if len(all) != size {
|
||||
t.Errorf("expected %d packets sequence; got %d", size, len(all))
|
||||
}
|
||||
|
||||
f := b.fetch(6)
|
||||
if f == nil {
|
||||
t.Fatal("fetch should not fail")
|
||||
}
|
||||
|
||||
b.compact()
|
||||
|
||||
err = b.push(&packet{header: header{seq: 15}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = b.push(&packet{header: header{seq: 17}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for i := 7; i <= size; i++ {
|
||||
f := b.fetch(uint16(i))
|
||||
if f == nil {
|
||||
t.Fatal("fetch should not fail")
|
||||
}
|
||||
}
|
||||
|
||||
a = []byte{128, 2}
|
||||
ack = b.generateSelectiveACK()
|
||||
if !bytes.Equal(a, ack) {
|
||||
t.Errorf("expected ack == %v; got %v", a, ack)
|
||||
}
|
||||
|
||||
all = b.all()
|
||||
if len(all) != 2 {
|
||||
t.Errorf("expected 2 packets sequence; got %d", len(all))
|
||||
}
|
||||
|
||||
b.compact()
|
||||
if b.space() != 9 {
|
||||
t.Errorf("expected space == 9; got %d", b.space())
|
||||
}
|
||||
|
||||
ack = b.generateSelectiveACK()
|
||||
b.processSelectiveACK(ack)
|
||||
|
||||
all = b.all()
|
||||
if len(all) != 1 {
|
||||
t.Errorf("expected size == 1; got %d", len(all))
|
||||
}
|
||||
}
|
||||
|
||||
func TestPacketBufferBoundary(t *testing.T) {
|
||||
begin := math.MaxUint16 - 3
|
||||
b := newPacketBuffer(12, begin)
|
||||
for i := begin; i != 5; i = (i + 1) % (math.MaxUint16 + 1) {
|
||||
err := b.push(&packet{header: header{seq: uint16(i)}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimedBufferNode(t *testing.T) {
|
||||
b := timedBuffer{d: time.Millisecond * 100}
|
||||
b.push(100)
|
||||
b.push(200)
|
||||
time.Sleep(time.Millisecond * 200)
|
||||
b.push(300)
|
||||
b.push(400)
|
||||
m := b.min()
|
||||
if m != 300 {
|
||||
t.Errorf("expected min == 300; got %d", m)
|
||||
}
|
||||
}
|
11
Godeps/_workspace/src/github.com/jbenet/commander/AUTHORS
generated
vendored
11
Godeps/_workspace/src/github.com/jbenet/commander/AUTHORS
generated
vendored
@ -1,11 +0,0 @@
|
||||
# This is the official list of Go-Commander authors for copyright purposes.
|
||||
# This file is distinct from the CONTRIBUTORS files.
|
||||
# See the latter for an explanation.
|
||||
|
||||
# Names should be added to this file as
|
||||
# Name or Organization <email address>
|
||||
# The email address is not required for organizations.
|
||||
|
||||
# Please keep the list sorted.
|
||||
|
||||
Google Inc
|
31
Godeps/_workspace/src/github.com/jbenet/commander/CONTRIBUTORS
generated
vendored
31
Godeps/_workspace/src/github.com/jbenet/commander/CONTRIBUTORS
generated
vendored
@ -1,31 +0,0 @@
|
||||
# This is the official list of people who can contribute
|
||||
# (and typically have contributed) code to the Go-Commander repository.
|
||||
# The AUTHORS file lists the copyright holders; this file
|
||||
# lists people. For example, Google employees are listed here
|
||||
# but not in AUTHORS, because Google holds the copyright.
|
||||
#
|
||||
# The submission process automatically checks to make sure
|
||||
# that people submitting code are listed in this file (by email address).
|
||||
#
|
||||
# Names should be added to this file only after verifying that
|
||||
# the individual or the individual's organization has agreed to
|
||||
# the appropriate Contributor License Agreement, found here:
|
||||
#
|
||||
# http://code.google.com/legal/individual-cla-v1.0.html
|
||||
# http://code.google.com/legal/corporate-cla-v1.0.html
|
||||
#
|
||||
# The agreement for individuals can be filled out on the web.
|
||||
#
|
||||
# When adding J Random Contributor's name to this file,
|
||||
# either J's name or J's organization's name should be
|
||||
# added to the AUTHORS file, depending on whether the
|
||||
# individual or corporate CLA was used.
|
||||
|
||||
# Names should be added to this file like so:
|
||||
# Name <email address>
|
||||
|
||||
# Please keep the list sorted.
|
||||
|
||||
Juan Batiz-Benet <juan@benet.ai>
|
||||
Sebastien Binet <seb.binet@gmail.com>
|
||||
Yves Junqueira <yves.junqueira@gmail.com>
|
27
Godeps/_workspace/src/github.com/jbenet/commander/LICENSE
generated
vendored
27
Godeps/_workspace/src/github.com/jbenet/commander/LICENSE
generated
vendored
@ -1,27 +0,0 @@
|
||||
Copyright (c) 2012 The Go-Commander Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
107
Godeps/_workspace/src/github.com/jbenet/commander/README.md
generated
vendored
107
Godeps/_workspace/src/github.com/jbenet/commander/README.md
generated
vendored
@ -1,107 +0,0 @@
|
||||
commander
|
||||
============
|
||||
|
||||
[](https://drone.io/github.com/gonuts/commander/latest)
|
||||
|
||||
``commander`` is a spin off of [golang](http://golang.org) ``go tool`` infrastructure to provide commands and sub-commands.
|
||||
|
||||
A ``commander.Command`` has a ``Subcommands`` field holding ``[]*commander.Command`` subcommands, referenced by name from the command line.
|
||||
|
||||
So a ``Command`` can have sub commands.
|
||||
|
||||
So you can have, _e.g._:
|
||||
```sh
|
||||
$ mycmd action1 [options...]
|
||||
$ mycmd subcmd1 action1 [options...]
|
||||
```
|
||||
|
||||
Example provided by:
|
||||
- [hwaf](https://github.com/hwaf/hwaf)
|
||||
- [examples/my-cmd](examples/my-cmd)
|
||||
|
||||
## Documentation
|
||||
Is available on [godoc](http://godoc.org/github.com/gonuts/commander)
|
||||
|
||||
## Installation
|
||||
Is performed with the usual:
|
||||
```sh
|
||||
$ go get github.com/gonuts/commander
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
See the simple ``my-cmd`` example command for how this all hangs
|
||||
together [there](http://github.com/gonuts/commander/blob/master/examples/my-cmd/main.go):
|
||||
|
||||
```sh
|
||||
$ my-cmd cmd1
|
||||
my-cmd-cmd1: hello from cmd1 (quiet=true)
|
||||
|
||||
$ my-cmd cmd1 -q
|
||||
my-cmd-cmd1: hello from cmd1 (quiet=true)
|
||||
|
||||
$ my-cmd cmd1 -q=0
|
||||
my-cmd-cmd1: hello from cmd1 (quiet=false)
|
||||
|
||||
$ my-cmd cmd2
|
||||
my-cmd-cmd2: hello from cmd2 (quiet=true)
|
||||
|
||||
$ my-cmd subcmd1 cmd1
|
||||
my-cmd-subcmd1-cmd1: hello from subcmd1-cmd1 (quiet=true)
|
||||
|
||||
$ my-cmd subcmd1 cmd2
|
||||
my-cmd-subcmd1-cmd2: hello from subcmd1-cmd2 (quiet=true)
|
||||
|
||||
$ my-cmd subcmd2 cmd1
|
||||
my-cmd-subcmd2-cmd1: hello from subcmd2-cmd1 (quiet=true)
|
||||
|
||||
$ my-cmd subcmd2 cmd2
|
||||
my-cmd-subcmd2-cmd2: hello from subcmd2-cmd2 (quiet=true)
|
||||
|
||||
$ my-cmd help
|
||||
Usage:
|
||||
|
||||
my-cmd command [arguments]
|
||||
|
||||
The commands are:
|
||||
|
||||
cmd1 runs cmd1 and exits
|
||||
cmd2 runs cmd2 and exits
|
||||
subcmd1 subcmd1 subcommand. does subcmd1 thingies
|
||||
subcmd2 subcmd2 subcommand. does subcmd2 thingies
|
||||
|
||||
Use "my-cmd help [command]" for more information about a command.
|
||||
|
||||
Additional help topics:
|
||||
|
||||
|
||||
Use "my-cmd help [topic]" for more information about that topic.
|
||||
|
||||
|
||||
$ my-cmd help subcmd1
|
||||
Usage:
|
||||
|
||||
subcmd1 command [arguments]
|
||||
|
||||
The commands are:
|
||||
|
||||
cmd1 runs cmd1 and exits
|
||||
cmd2 runs cmd2 and exits
|
||||
|
||||
|
||||
Use "subcmd1 help [command]" for more information about a command.
|
||||
|
||||
Additional help topics:
|
||||
|
||||
|
||||
Use "subcmd1 help [topic]" for more information about that topic.
|
||||
|
||||
```
|
||||
|
||||
|
||||
## TODO
|
||||
|
||||
- automatically generate the bash/zsh/csh autocompletion lists
|
||||
- automatically generate Readme examples text
|
||||
- test cases
|
||||
|
358
Godeps/_workspace/src/github.com/jbenet/commander/commands.go
generated
vendored
358
Godeps/_workspace/src/github.com/jbenet/commander/commands.go
generated
vendored
@ -1,358 +0,0 @@
|
||||
// Copyright 2012 The Go-Commander Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
// Based on the original work by The Go Authors:
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
|
||||
// commander helps creating command line programs whose arguments are flags,
|
||||
// commands and subcommands.
|
||||
package commander
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag"
|
||||
)
|
||||
|
||||
// UsageSection differentiates between sections in the usage text.
|
||||
type Listing int
|
||||
|
||||
const (
|
||||
CommandsList = iota
|
||||
HelpTopicsList
|
||||
Unlisted
|
||||
)
|
||||
|
||||
// A Command is an implementation of a subcommand.
|
||||
type Command struct {
|
||||
|
||||
// UsageLine is the short usage message.
|
||||
// The first word in the line is taken to be the command name.
|
||||
UsageLine string
|
||||
|
||||
// Short is the short description line shown in command lists.
|
||||
Short string
|
||||
|
||||
// Long is the long description shown in the 'help <this-command>' output.
|
||||
Long string
|
||||
|
||||
// List reports which list to show this command in Usage and Help.
|
||||
// Choose between {CommandsList (default), HelpTopicsList, Unlisted}
|
||||
List Listing
|
||||
|
||||
// Run runs the command.
|
||||
// The args are the arguments after the command name.
|
||||
Run func(cmd *Command, args []string) error
|
||||
|
||||
// Flag is a set of flags specific to this command.
|
||||
Flag flag.FlagSet
|
||||
|
||||
// CustomFlags indicates that the command will do its own
|
||||
// flag parsing.
|
||||
CustomFlags bool
|
||||
|
||||
// Subcommands are dispatched from this command
|
||||
Subcommands []*Command
|
||||
|
||||
// Parent command, nil for root.
|
||||
Parent *Command
|
||||
|
||||
// UsageTemplate formats the usage (short) information displayed to the user
|
||||
// (leave empty for default)
|
||||
UsageTemplate string
|
||||
|
||||
// HelpTemplate formats the help (long) information displayed to the user
|
||||
// (leave empty for default)
|
||||
HelpTemplate string
|
||||
|
||||
// Stdout and Stderr by default are os.Stdout and os.Stderr, but you can
|
||||
// point them at any io.Writer
|
||||
Stdout io.Writer
|
||||
Stderr io.Writer
|
||||
}
|
||||
|
||||
// Name returns the command's name: the first word in the usage line.
|
||||
func (c *Command) Name() string {
|
||||
name := c.UsageLine
|
||||
i := strings.Index(name, " ")
|
||||
if i >= 0 {
|
||||
name = name[:i]
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
// Usage prints the usage details to the standard error output.
|
||||
func (c *Command) Usage() {
|
||||
c.usage()
|
||||
}
|
||||
|
||||
// FlagOptions returns the flag's options as a string
|
||||
func (c *Command) FlagOptions() string {
|
||||
var buf bytes.Buffer
|
||||
c.Flag.SetOutput(&buf)
|
||||
c.Flag.PrintDefaults()
|
||||
|
||||
str := string(buf.Bytes())
|
||||
if len(str) > 0 {
|
||||
return fmt.Sprintf("\nOptions:\n%s", str)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Runnable reports whether the command can be run; otherwise
|
||||
// it is a documentation pseudo-command such as importpath.
|
||||
func (c *Command) Runnable() bool {
|
||||
return c.Run != nil
|
||||
}
|
||||
|
||||
// Type to allow us to use sort.Sort on a slice of Commands
|
||||
type CommandSlice []*Command
|
||||
|
||||
func (c CommandSlice) Len() int {
|
||||
return len(c)
|
||||
}
|
||||
|
||||
func (c CommandSlice) Less(i, j int) bool {
|
||||
return c[i].Name() < c[j].Name()
|
||||
}
|
||||
|
||||
func (c CommandSlice) Swap(i, j int) {
|
||||
c[i], c[j] = c[j], c[i]
|
||||
}
|
||||
|
||||
// Sort the commands
|
||||
func (c *Command) SortCommands() {
|
||||
sort.Sort(CommandSlice(c.Subcommands))
|
||||
}
|
||||
|
||||
// Init the command
|
||||
func (c *Command) init() {
|
||||
if c.Parent != nil {
|
||||
return // already initialized.
|
||||
}
|
||||
|
||||
// setup strings
|
||||
if len(c.UsageLine) < 1 {
|
||||
c.UsageLine = Defaults.UsageLine
|
||||
}
|
||||
if len(c.UsageTemplate) < 1 {
|
||||
c.UsageTemplate = Defaults.UsageTemplate
|
||||
}
|
||||
if len(c.HelpTemplate) < 1 {
|
||||
c.HelpTemplate = Defaults.HelpTemplate
|
||||
}
|
||||
|
||||
if c.Stderr == nil {
|
||||
c.Stderr = os.Stderr
|
||||
}
|
||||
if c.Stdout == nil {
|
||||
c.Stdout = os.Stdout
|
||||
}
|
||||
|
||||
// init subcommands
|
||||
for _, cmd := range c.Subcommands {
|
||||
cmd.init()
|
||||
}
|
||||
|
||||
// init hierarchy...
|
||||
for _, cmd := range c.Subcommands {
|
||||
cmd.Parent = c
|
||||
}
|
||||
}
|
||||
|
||||
// Dispatch executes the command using the provided arguments.
|
||||
// If a subcommand exists matching the first argument, it is dispatched.
|
||||
// Otherwise, the command's Run function is called.
|
||||
func (c *Command) Dispatch(args []string) error {
|
||||
if c == nil {
|
||||
return fmt.Errorf("Called Run() on a nil Command")
|
||||
}
|
||||
|
||||
// Ensure command is initialized.
|
||||
c.init()
|
||||
|
||||
// First, try a sub-command
|
||||
if len(args) > 0 {
|
||||
for _, cmd := range c.Subcommands {
|
||||
n := cmd.Name()
|
||||
if n == args[0] {
|
||||
return cmd.Dispatch(args[1:])
|
||||
}
|
||||
}
|
||||
|
||||
// help is builtin (but after, to allow overriding)
|
||||
if args[0] == "help" {
|
||||
return c.help(args[1:])
|
||||
}
|
||||
|
||||
// then, try out an external binary (git-style)
|
||||
bin, err := exec.LookPath(c.FullName() + "-" + args[0])
|
||||
if err == nil {
|
||||
cmd := exec.Command(bin, args[1:]...)
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = c.Stdout
|
||||
cmd.Stderr = c.Stderr
|
||||
return cmd.Run()
|
||||
}
|
||||
}
|
||||
|
||||
// then, try running this command
|
||||
if c.Runnable() {
|
||||
if !c.CustomFlags {
|
||||
var err = error(nil)
|
||||
c.Flag.Usage = func() {
|
||||
c.Usage()
|
||||
err = fmt.Errorf("Failed to parse flags.")
|
||||
}
|
||||
c.Flag.Parse(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
args = c.Flag.Args()
|
||||
}
|
||||
return c.Run(c, args)
|
||||
}
|
||||
|
||||
// TODO: try an alias
|
||||
//...
|
||||
|
||||
// Last, print usage
|
||||
if err := c.usage(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Command) usage() error {
|
||||
// c.SortCommands()
|
||||
err := tmpl(c.Stderr, c.UsageTemplate, c)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// help implements the 'help' command.
|
||||
func (c *Command) help(args []string) error {
|
||||
|
||||
// help exactly for this command?
|
||||
if len(args) == 0 {
|
||||
if len(c.Long) > 0 {
|
||||
return tmpl(c.Stdout, c.HelpTemplate, c)
|
||||
} else {
|
||||
return c.usage()
|
||||
}
|
||||
}
|
||||
|
||||
arg := args[0]
|
||||
|
||||
// is this help for a subcommand?
|
||||
for _, cmd := range c.Subcommands {
|
||||
n := cmd.Name()
|
||||
// strip out "<parent>-"" name
|
||||
if strings.HasPrefix(n, c.Name()+"-") {
|
||||
n = n[len(c.Name()+"-"):]
|
||||
}
|
||||
if n == arg {
|
||||
return cmd.help(args[1:])
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("Unknown help topic %#q. Run '%v help'.\n", arg, c.Name())
|
||||
}
|
||||
|
||||
func (c *Command) MaxLen() (res int) {
|
||||
res = 0
|
||||
for _, cmd := range c.Subcommands {
|
||||
i := len(cmd.Name())
|
||||
if i > res {
|
||||
res = i
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ColFormat returns the column header size format for printing in the template
|
||||
func (c *Command) ColFormat() string {
|
||||
sz := c.MaxLen()
|
||||
if sz < 11 {
|
||||
sz = 11
|
||||
}
|
||||
return fmt.Sprintf("%%-%ds", sz)
|
||||
}
|
||||
|
||||
// FullName returns the full name of the command, prefixed with parent commands
|
||||
func (c *Command) FullName() string {
|
||||
n := c.Name()
|
||||
if c.Parent != nil {
|
||||
n = c.Parent.FullName() + "-" + n
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// FullSpacedName returns the full name of the command, with ' ' instead of '-'
|
||||
func (c *Command) FullSpacedName() string {
|
||||
n := c.Name()
|
||||
if c.Parent != nil {
|
||||
n = c.Parent.FullSpacedName() + " " + n
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (c *Command) SubcommandList(list Listing) []*Command {
|
||||
var cmds []*Command
|
||||
for _, cmd := range c.Subcommands {
|
||||
if cmd.List == list {
|
||||
cmds = append(cmds, cmd)
|
||||
}
|
||||
}
|
||||
return cmds
|
||||
}
|
||||
|
||||
var Defaults = Command{
|
||||
UsageTemplate: `{{if .Runnable}}Usage: {{if .Parent}}{{.Parent.FullSpacedName}}{{end}} {{.UsageLine}}
|
||||
|
||||
{{else}}{{.FullSpacedName}} - {{end}}{{.Short}}
|
||||
|
||||
{{if commandList}}Commands:
|
||||
{{range commandList}}
|
||||
{{.Name | printf (colfmt)}} {{.Short}}{{end}}
|
||||
|
||||
Use "{{.Name}} help <command>" for more information about a command.
|
||||
|
||||
{{end}}{{.FlagOptions}}{{if helpList}}
|
||||
Additional help topics:
|
||||
{{range helpList}}
|
||||
{{.Name | printf (colfmt)}} {{.Short}}{{end}}
|
||||
|
||||
Use "{{.Name}} help <topic>" for more information about that topic.
|
||||
|
||||
{{end}}`,
|
||||
|
||||
HelpTemplate: `{{if .Runnable}}Usage: {{if .Parent}}{{.Parent.FullSpacedName}}{{end}} {{.UsageLine}}
|
||||
|
||||
{{end}}{{.Long | trim}}
|
||||
{{.FlagOptions}}
|
||||
`,
|
||||
}
|
||||
|
||||
// tmpl executes the given template text on data, writing the result to w.
|
||||
func tmpl(w io.Writer, text string, data interface{}) error {
|
||||
t := template.New("top")
|
||||
t.Funcs(template.FuncMap{
|
||||
"trim": strings.TrimSpace,
|
||||
"colfmt": func() string { return data.(*Command).ColFormat() },
|
||||
"commandList": func() []*Command { return data.(*Command).SubcommandList(CommandsList) },
|
||||
"helpList": func() []*Command { return data.(*Command).SubcommandList(HelpTopicsList) },
|
||||
})
|
||||
template.Must(t.Parse(text))
|
||||
return t.Execute(w, data)
|
||||
}
|
34
Godeps/_workspace/src/github.com/jbenet/commander/examples/my-cmd/cmd_cmd1.go
generated
vendored
34
Godeps/_workspace/src/github.com/jbenet/commander/examples/my-cmd/cmd_cmd1.go
generated
vendored
@ -1,34 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag"
|
||||
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander"
|
||||
)
|
||||
|
||||
var cmd_cmd1 = &commander.Command{
|
||||
Run: ex_run_cmd_cmd1,
|
||||
UsageLine: "cmd1 [options]",
|
||||
Short: "runs cmd1 and exits",
|
||||
Long: `
|
||||
runs cmd1 and exits.
|
||||
|
||||
ex:
|
||||
$ my-cmd cmd1
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("my-cmd-cmd1", flag.ExitOnError),
|
||||
}
|
||||
|
||||
func init() {
|
||||
cmd_cmd1.Flag.Bool("q", true, "only print error and warning messages, all other output will be suppressed")
|
||||
}
|
||||
|
||||
func ex_run_cmd_cmd1(cmd *commander.Command, args []string) error {
|
||||
name := "my-cmd-" + cmd.Name()
|
||||
quiet := cmd.Flag.Lookup("q").Value.Get().(bool)
|
||||
fmt.Printf("%s: hello from cmd1 (quiet=%v)\n", name, quiet)
|
||||
return nil
|
||||
}
|
||||
|
||||
// EOF
|
34
Godeps/_workspace/src/github.com/jbenet/commander/examples/my-cmd/cmd_cmd2.go
generated
vendored
34
Godeps/_workspace/src/github.com/jbenet/commander/examples/my-cmd/cmd_cmd2.go
generated
vendored
@ -1,34 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag"
|
||||
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander"
|
||||
)
|
||||
|
||||
func ex_make_cmd_cmd2() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: ex_run_cmd_cmd2,
|
||||
UsageLine: "cmd2 [options]",
|
||||
Short: "runs cmd2 and exits",
|
||||
Long: `
|
||||
runs cmd2 and exits.
|
||||
|
||||
ex:
|
||||
$ my-cmd cmd2
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("my-cmd-cmd2", flag.ExitOnError),
|
||||
}
|
||||
cmd.Flag.Bool("q", true, "only print error and warning messages, all other output will be suppressed")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func ex_run_cmd_cmd2(cmd *commander.Command, args []string) error {
|
||||
name := "my-cmd-" + cmd.Name()
|
||||
quiet := cmd.Flag.Lookup("q").Value.Get().(bool)
|
||||
fmt.Printf("%s: hello from cmd2 (quiet=%v)\n", name, quiet)
|
||||
return nil
|
||||
}
|
||||
|
||||
// EOF
|
18
Godeps/_workspace/src/github.com/jbenet/commander/examples/my-cmd/cmd_subcmd1.go
generated
vendored
18
Godeps/_workspace/src/github.com/jbenet/commander/examples/my-cmd/cmd_subcmd1.go
generated
vendored
@ -1,18 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag"
|
||||
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander"
|
||||
)
|
||||
|
||||
var cmd_subcmd1 = &commander.Command{
|
||||
UsageLine: "subcmd1 <command>",
|
||||
Short: "subcmd1 subcommand. does subcmd1 thingies",
|
||||
Subcommands: []*commander.Command{
|
||||
cmd_subcmd1_cmd1,
|
||||
cmd_subcmd1_cmd2,
|
||||
},
|
||||
Flag: *flag.NewFlagSet("my-cmd-subcmd1", flag.ExitOnError),
|
||||
}
|
||||
|
||||
// EOF
|
34
Godeps/_workspace/src/github.com/jbenet/commander/examples/my-cmd/cmd_subcmd1_cmd1.go
generated
vendored
34
Godeps/_workspace/src/github.com/jbenet/commander/examples/my-cmd/cmd_subcmd1_cmd1.go
generated
vendored
@ -1,34 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag"
|
||||
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander"
|
||||
)
|
||||
|
||||
var cmd_subcmd1_cmd1 = &commander.Command{
|
||||
Run: ex_run_cmd_subcmd1_cmd1,
|
||||
UsageLine: "cmd1 [options]",
|
||||
Short: "runs cmd1 and exits",
|
||||
Long: `
|
||||
runs cmd1 and exits.
|
||||
|
||||
ex:
|
||||
$ my-cmd subcmd1 cmd1
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("my-cmd-subcmd1-cmd1", flag.ExitOnError),
|
||||
}
|
||||
|
||||
func init() {
|
||||
cmd_subcmd1_cmd1.Flag.Bool("q", true, "only print error and warning messages, all other output will be suppressed")
|
||||
}
|
||||
|
||||
func ex_run_cmd_subcmd1_cmd1(cmd *commander.Command, args []string) error {
|
||||
name := "my-cmd-subcmd1-" + cmd.Name()
|
||||
quiet := cmd.Flag.Lookup("q").Value.Get().(bool)
|
||||
fmt.Printf("%s: hello from subcmd1-cmd1 (quiet=%v)\n", name, quiet)
|
||||
return nil
|
||||
}
|
||||
|
||||
// EOF
|
34
Godeps/_workspace/src/github.com/jbenet/commander/examples/my-cmd/cmd_subcmd1_cmd2.go
generated
vendored
34
Godeps/_workspace/src/github.com/jbenet/commander/examples/my-cmd/cmd_subcmd1_cmd2.go
generated
vendored
@ -1,34 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag"
|
||||
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander"
|
||||
)
|
||||
|
||||
var cmd_subcmd1_cmd2 = &commander.Command{
|
||||
Run: ex_run_cmd_subcmd1_cmd2,
|
||||
UsageLine: "cmd2 [options]",
|
||||
Short: "runs cmd2 and exits",
|
||||
Long: `
|
||||
runs cmd2 and exits.
|
||||
|
||||
ex:
|
||||
$ my-cmd subcmd1 cmd2
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("my-cmd-subcmd1-cmd2", flag.ExitOnError),
|
||||
}
|
||||
|
||||
func init() {
|
||||
cmd_subcmd1_cmd2.Flag.Bool("q", true, "only print error and warning messages, all other output will be suppressed")
|
||||
}
|
||||
|
||||
func ex_run_cmd_subcmd1_cmd2(cmd *commander.Command, args []string) error {
|
||||
name := "my-cmd-subcmd1-" + cmd.Name()
|
||||
quiet := cmd.Flag.Lookup("q").Value.Get().(bool)
|
||||
fmt.Printf("%s: hello from subcmd1-cmd2 (quiet=%v)\n", name, quiet)
|
||||
return nil
|
||||
}
|
||||
|
||||
// EOF
|
22
Godeps/_workspace/src/github.com/jbenet/commander/examples/my-cmd/cmd_subcmd2.go
generated
vendored
22
Godeps/_workspace/src/github.com/jbenet/commander/examples/my-cmd/cmd_subcmd2.go
generated
vendored
@ -1,22 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag"
|
||||
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander"
|
||||
)
|
||||
|
||||
func ex_make_cmd_subcmd2() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
UsageLine: "subcmd2",
|
||||
Short: "subcmd2 subcommand. does subcmd2 thingies (help list)",
|
||||
List: commander.HelpTopicsList,
|
||||
Subcommands: []*commander.Command{
|
||||
ex_make_cmd_subcmd2_cmd1(),
|
||||
ex_make_cmd_subcmd2_cmd2(),
|
||||
},
|
||||
Flag: *flag.NewFlagSet("my-cmd-subcmd2", flag.ExitOnError),
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
// EOF
|
34
Godeps/_workspace/src/github.com/jbenet/commander/examples/my-cmd/cmd_subcmd2_cmd1.go
generated
vendored
34
Godeps/_workspace/src/github.com/jbenet/commander/examples/my-cmd/cmd_subcmd2_cmd1.go
generated
vendored
@ -1,34 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag"
|
||||
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander"
|
||||
)
|
||||
|
||||
func ex_make_cmd_subcmd2_cmd1() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: ex_run_cmd_subcmd2_cmd1,
|
||||
UsageLine: "cmd1 [options]",
|
||||
Short: "runs cmd1 and exits",
|
||||
Long: `
|
||||
runs cmd1 and exits.
|
||||
|
||||
ex:
|
||||
$ my-cmd subcmd2 cmd1
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("my-cmd-subcmd2-cmd1", flag.ExitOnError),
|
||||
}
|
||||
cmd.Flag.Bool("q", true, "only print error and warning messages, all other output will be suppressed")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func ex_run_cmd_subcmd2_cmd1(cmd *commander.Command, args []string) error {
|
||||
name := "my-cmd-subcmd2-" + cmd.Name()
|
||||
quiet := cmd.Flag.Lookup("q").Value.Get().(bool)
|
||||
fmt.Printf("%s: hello from subcmd2-cmd1 (quiet=%v)\n", name, quiet)
|
||||
return nil
|
||||
}
|
||||
|
||||
// EOF
|
34
Godeps/_workspace/src/github.com/jbenet/commander/examples/my-cmd/cmd_subcmd2_cmd2.go
generated
vendored
34
Godeps/_workspace/src/github.com/jbenet/commander/examples/my-cmd/cmd_subcmd2_cmd2.go
generated
vendored
@ -1,34 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag"
|
||||
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander"
|
||||
)
|
||||
|
||||
func ex_make_cmd_subcmd2_cmd2() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: ex_run_cmd_subcmd2_cmd2,
|
||||
UsageLine: "cmd2 [options]",
|
||||
Short: "runs cmd2 and exits",
|
||||
Long: `
|
||||
runs cmd2 and exits.
|
||||
|
||||
ex:
|
||||
$ my-cmd subcmd2 cmd2
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("my-cmd-subcmd2-cmd2", flag.ExitOnError),
|
||||
}
|
||||
cmd.Flag.Bool("q", true, "only print error and warning messages, all other output will be suppressed")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func ex_run_cmd_subcmd2_cmd2(cmd *commander.Command, args []string) error {
|
||||
name := "my-cmd-subcmd2-" + cmd.Name()
|
||||
quiet := cmd.Flag.Lookup("q").Value.Get().(bool)
|
||||
fmt.Printf("%s: hello from subcmd2-cmd2 (quiet=%v)\n", name, quiet)
|
||||
return nil
|
||||
}
|
||||
|
||||
// EOF
|
33
Godeps/_workspace/src/github.com/jbenet/commander/examples/my-cmd/main.go
generated
vendored
33
Godeps/_workspace/src/github.com/jbenet/commander/examples/my-cmd/main.go
generated
vendored
@ -1,33 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander"
|
||||
)
|
||||
|
||||
var g_cmd = &commander.Command{
|
||||
UsageLine: os.Args[0] + " does cool things",
|
||||
}
|
||||
|
||||
func init() {
|
||||
g_cmd.Subcommands = []*commander.Command{
|
||||
cmd_cmd1,
|
||||
ex_make_cmd_cmd2(),
|
||||
cmd_subcmd1,
|
||||
ex_make_cmd_subcmd2(),
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
err := g_cmd.Dispatch(os.Args[1:])
|
||||
if err != nil {
|
||||
fmt.Printf("%v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// EOF
|
18
Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/Godeps/Godeps.json
generated
vendored
Normal file
18
Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/Godeps/Godeps.json
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"ImportPath": "github.com/jbenet/go-multiaddr-net",
|
||||
"GoVersion": "go1.3",
|
||||
"Packages": [
|
||||
"./..."
|
||||
],
|
||||
"Deps": [
|
||||
{
|
||||
"ImportPath": "github.com/h2so5/utp",
|
||||
"Rev": "654d875bb65e96729678180215cf080fe2810371"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/jbenet/go-multiaddr",
|
||||
"Comment": "0.1.2-30-g99cf3ed",
|
||||
"Rev": "99cf3edc711751cf7b43505fac0e3913f6b9a75c"
|
||||
}
|
||||
]
|
||||
}
|
5
Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/Godeps/Readme
generated
vendored
Normal file
5
Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/Godeps/Readme
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
This directory tree is generated automatically by godep.
|
||||
|
||||
Please do not edit.
|
||||
|
||||
See https://github.com/tools/godep for more information.
|
21
Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/LICENSE
generated
vendored
Normal file
21
Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Juan Batiz-Benet
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
16
Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/Makefile
generated
vendored
Normal file
16
Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/Makefile
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
all: install
|
||||
|
||||
godep:
|
||||
go get github.com/tools/godep
|
||||
|
||||
# saves/vendors third-party dependencies to Godeps/_workspace
|
||||
# -r flag rewrites import paths to use the vendored path
|
||||
# ./... performs operation on all packages in tree
|
||||
vendor: godep
|
||||
godep save -r ./...
|
||||
|
||||
install: dep
|
||||
cd multiaddr && go install
|
||||
|
||||
dep:
|
||||
cd multiaddr && go get ./...
|
@ -1,11 +1,11 @@
|
||||
# multiaddr/net - Multiaddr friendly net
|
||||
|
||||
Package multiaddr/net provides Multiaddr specific versions of common
|
||||
Package multiaddr/net provides [Multiaddr](http://github.com/jbenet/go-multiaddr) specific versions of common
|
||||
functions in stdlib's net package. This means wrappers of
|
||||
standard net symbols like net.Dial and net.Listen, as well
|
||||
as conversion to/from net.Addr.
|
||||
|
||||
Docs:
|
||||
|
||||
- `multiaddr/net`: https://godoc.org/github.com/jbenet/go-multiaddr/net
|
||||
- `multiaddr/net`: https://godoc.org/github.com/jbenet/go-multiaddr-net
|
||||
- `multiaddr`: https://godoc.org/github.com/jbenet/go-multiaddr
|
@ -5,6 +5,7 @@ import (
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
utp "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/h2so5/utp"
|
||||
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
|
||||
)
|
||||
|
||||
@ -55,6 +56,33 @@ func FromNetAddr(a net.Addr) (ma.Multiaddr, error) {
|
||||
// Encapsulate
|
||||
return ipm.Encapsulate(udpm), nil
|
||||
|
||||
case "utp", "utp4", "utp6":
|
||||
acc, ok := a.(*utp.UTPAddr)
|
||||
if !ok {
|
||||
return nil, errIncorrectNetAddr
|
||||
}
|
||||
|
||||
// Get UDP Addr
|
||||
ac, ok := acc.Addr.(*net.UDPAddr)
|
||||
if !ok {
|
||||
return nil, errIncorrectNetAddr
|
||||
}
|
||||
|
||||
// Get IP Addr
|
||||
ipm, err := FromIP(ac.IP)
|
||||
if err != nil {
|
||||
return nil, errIncorrectNetAddr
|
||||
}
|
||||
|
||||
// Get UDP Addr
|
||||
utpm, err := ma.NewMultiaddr(fmt.Sprintf("/udp/%d/utp", ac.Port))
|
||||
if err != nil {
|
||||
return nil, errIncorrectNetAddr
|
||||
}
|
||||
|
||||
// Encapsulate
|
||||
return ipm.Encapsulate(utpm), nil
|
||||
|
||||
case "ip", "ip4", "ip6":
|
||||
ac, ok := a.(*net.IPAddr)
|
||||
if !ok {
|
||||
@ -88,6 +116,8 @@ func ToNetAddr(maddr ma.Multiaddr) (net.Addr, error) {
|
||||
return net.ResolveTCPAddr(network, host)
|
||||
case "udp":
|
||||
return net.ResolveUDPAddr(network, host)
|
||||
case "utp":
|
||||
return utp.ResolveUTPAddr(network, host)
|
||||
case "ip":
|
||||
return net.ResolveIPAddr(network, host)
|
||||
}
|
||||
@ -121,6 +151,10 @@ func DialArgs(m ma.Multiaddr) (string, string, error) {
|
||||
}
|
||||
|
||||
network := parts[2]
|
||||
if parts[2] == "udp" && len(parts) > 4 && parts[4] == "utp" {
|
||||
network = parts[4]
|
||||
}
|
||||
|
||||
var host string
|
||||
switch parts[0] {
|
||||
case "ip4":
|
@ -4,6 +4,7 @@ import (
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
utp "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/h2so5/utp"
|
||||
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
|
||||
)
|
||||
|
||||
@ -88,17 +89,31 @@ func TestFromUDP(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestFromUTP(t *testing.T) {
|
||||
testConvert(t, "/ip4/10.20.30.40/udp/1234/utp", func() (ma.Multiaddr, error) {
|
||||
return FromNetAddr(&utp.UTPAddr{
|
||||
Addr: &net.UDPAddr{
|
||||
IP: net.ParseIP("10.20.30.40"),
|
||||
Port: 1234,
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestThinWaist(t *testing.T) {
|
||||
addrs := map[string]bool{
|
||||
"/ip4/127.0.0.1/udp/1234": true,
|
||||
"/ip4/127.0.0.1/tcp/1234": true,
|
||||
"/ip4/127.0.0.1/udp/1234/utp": true,
|
||||
"/ip4/127.0.0.1/udp/1234/tcp/1234": true,
|
||||
"/ip4/127.0.0.1/tcp/12345/ip4/1.2.3.4": true,
|
||||
"/ip6/::1/tcp/80": true,
|
||||
"/ip6/::1/udp/80": true,
|
||||
"/ip6/::1": true,
|
||||
"/ip6/::1/utp": false,
|
||||
"/tcp/1234/ip4/1.2.3.4": false,
|
||||
"/tcp/1234": false,
|
||||
"/tcp/1234/utp": false,
|
||||
"/tcp/1234/udp/1234": false,
|
||||
"/ip4/1.2.3.4/ip4/2.3.4.5": true,
|
||||
"/ip6/::1/ip4/2.3.4.5": true,
|
||||
@ -117,21 +132,27 @@ func TestThinWaist(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDialArgs(t *testing.T) {
|
||||
m, err := ma.NewMultiaddr("/ip4/127.0.0.1/udp/1234")
|
||||
test := func(e_maddr, e_nw, e_host string) {
|
||||
m, err := ma.NewMultiaddr(e_maddr)
|
||||
if err != nil {
|
||||
t.Fatal("failed to construct", "/ip4/127.0.0.1/udp/1234")
|
||||
t.Fatal("failed to construct", "/ip4/127.0.0.1/udp/1234", e_maddr)
|
||||
}
|
||||
|
||||
nw, host, err := DialArgs(m)
|
||||
if err != nil {
|
||||
t.Fatal("failed to get dial args", "/ip4/127.0.0.1/udp/1234", err)
|
||||
t.Fatal("failed to get dial args", e_maddr, m, err)
|
||||
}
|
||||
|
||||
if nw != "udp" {
|
||||
t.Error("failed to get udp network Dial Arg")
|
||||
if nw != e_nw {
|
||||
t.Error("failed to get udp network Dial Arg", e_nw, nw)
|
||||
}
|
||||
|
||||
if host != "127.0.0.1:1234" {
|
||||
t.Error("failed to get host:port Dial Arg")
|
||||
if host != e_host {
|
||||
t.Error("failed to get host:port Dial Arg", e_host, host)
|
||||
}
|
||||
}
|
||||
|
||||
test("/ip4/127.0.0.1/udp/1234", "udp", "127.0.0.1:1234")
|
||||
test("/ip4/127.0.0.1/tcp/4321", "tcp", "127.0.0.1:4321")
|
||||
test("/ip4/127.0.0.1/udp/1234/utp", "utp", "127.0.0.1:1234")
|
||||
}
|
BIN
Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/multiaddr/multiaddr
generated
vendored
Normal file
BIN
Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/multiaddr/multiaddr
generated
vendored
Normal file
Binary file not shown.
@ -7,7 +7,7 @@ import (
|
||||
"os"
|
||||
|
||||
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
|
||||
manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/net"
|
||||
manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
|
||||
)
|
||||
|
||||
// flags
|
@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
utp "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/h2so5/utp"
|
||||
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
|
||||
)
|
||||
|
||||
@ -68,7 +69,7 @@ func (c *maConn) RemoteMultiaddr() ma.Multiaddr {
|
||||
// and RemoteAddr options are Multiaddrs, instead of net.Addrs.
|
||||
type Dialer struct {
|
||||
|
||||
// Dialer is just an embed net.Dialer, with all its options.
|
||||
// Dialer is just an embedded net.Dialer, with all its options.
|
||||
net.Dialer
|
||||
|
||||
// LocalAddr is the local address to use when dialing an
|
||||
@ -103,10 +104,25 @@ func (d *Dialer) Dial(remote ma.Multiaddr) (Conn, error) {
|
||||
}
|
||||
|
||||
// ok, Dial!
|
||||
nconn, err := d.Dialer.Dial(rnet, rnaddr)
|
||||
var nconn net.Conn
|
||||
switch rnet {
|
||||
case "tcp":
|
||||
nconn, err = d.Dialer.Dial(rnet, rnaddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case "utp":
|
||||
// construct utp dialer, with options on our net.Dialer
|
||||
utpd := utp.Dialer{
|
||||
Timeout: d.Dialer.Timeout,
|
||||
LocalAddr: d.Dialer.LocalAddr,
|
||||
}
|
||||
|
||||
nconn, err = utpd.Dial(rnet, rnaddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// get local address (pre-specified or assigned within net.Conn)
|
||||
local := d.LocalAddr
|
||||
@ -206,7 +222,13 @@ func Listen(laddr ma.Multiaddr) (Listener, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nl, err := net.Listen(lnet, lnaddr)
|
||||
var nl net.Listener
|
||||
switch lnet {
|
||||
case "utp":
|
||||
nl, err = utp.Listen(lnet, lnaddr)
|
||||
default:
|
||||
nl, err = net.Listen(lnet, lnaddr)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
@ -12,7 +12,7 @@ import (
|
||||
func newMultiaddr(t *testing.T, m string) ma.Multiaddr {
|
||||
maddr, err := ma.NewMultiaddr(m)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to construct multiaddr: %s", m)
|
||||
t.Fatal("failed to construct multiaddr:", m, err)
|
||||
}
|
||||
return maddr
|
||||
}
|
||||
@ -138,6 +138,36 @@ func TestListen(t *testing.T) {
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestListenAddrs(t *testing.T) {
|
||||
|
||||
test := func(addr string, succeed bool) {
|
||||
|
||||
maddr := newMultiaddr(t, addr)
|
||||
l, err := Listen(maddr)
|
||||
if !succeed {
|
||||
if err == nil {
|
||||
t.Fatal("succeeded in listening", addr)
|
||||
}
|
||||
return
|
||||
}
|
||||
if succeed && err != nil {
|
||||
t.Fatal("failed to listen", addr, err)
|
||||
}
|
||||
if l == nil {
|
||||
t.Fatal("failed to listen", addr, succeed, err)
|
||||
}
|
||||
|
||||
if err = l.Close(); err != nil {
|
||||
t.Fatal("failed to close listener", addr, err)
|
||||
}
|
||||
}
|
||||
|
||||
test("/ip4/127.0.0.1/tcp/4324", true)
|
||||
test("/ip4/127.0.0.1/udp/4325", false)
|
||||
test("/ip4/127.0.0.1/udp/4326/udt", false)
|
||||
test("/ip4/127.0.0.1/udp/4326/utp", true)
|
||||
}
|
||||
|
||||
func TestListenAndDial(t *testing.T) {
|
||||
|
||||
maddr := newMultiaddr(t, "/ip4/127.0.0.1/tcp/4323")
|
||||
@ -199,6 +229,67 @@ func TestListenAndDial(t *testing.T) {
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestListenAndDialUTP(t *testing.T) {
|
||||
|
||||
maddr := newMultiaddr(t, "/ip4/127.0.0.1/udp/4323/utp")
|
||||
listener, err := Listen(maddr)
|
||||
if err != nil {
|
||||
t.Fatal("failed to listen")
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
|
||||
cB, err := listener.Accept()
|
||||
if err != nil {
|
||||
t.Fatal("failed to accept")
|
||||
}
|
||||
|
||||
if !cB.LocalMultiaddr().Equal(maddr) {
|
||||
t.Fatal("local multiaddr not equal:", maddr, cB.LocalMultiaddr())
|
||||
}
|
||||
|
||||
// echo out
|
||||
buf := make([]byte, 1024)
|
||||
for {
|
||||
_, err := cB.Read(buf)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
cB.Write(buf)
|
||||
}
|
||||
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
cA, err := Dial(newMultiaddr(t, "/ip4/127.0.0.1/udp/4323/utp"))
|
||||
if err != nil {
|
||||
t.Fatal("failed to dial", err)
|
||||
}
|
||||
|
||||
buf := make([]byte, 1024)
|
||||
if _, err := cA.Write([]byte("beep boop")); err != nil {
|
||||
t.Fatal("failed to write:", err)
|
||||
}
|
||||
|
||||
if _, err := cA.Read(buf); err != nil {
|
||||
t.Fatal("failed to read:", buf, err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(buf[:9], []byte("beep boop")) {
|
||||
t.Fatal("failed to echo:", buf)
|
||||
}
|
||||
|
||||
maddr2 := cA.RemoteMultiaddr()
|
||||
if !maddr2.Equal(maddr) {
|
||||
t.Fatal("remote multiaddr not equal:", maddr, maddr2)
|
||||
}
|
||||
|
||||
cA.Close()
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestIPLoopback(t *testing.T) {
|
||||
if IP4Loopback.String() != "/ip4/127.0.0.1" {
|
||||
t.Error("IP4Loopback incorrect:", IP4Loopback)
|
25
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/codec.go
generated
vendored
25
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/codec.go
generated
vendored
@ -28,12 +28,14 @@ func stringToBytes(s string) ([]byte, error) {
|
||||
if p == nil {
|
||||
return nil, fmt.Errorf("no protocol with name %s", sp[0])
|
||||
}
|
||||
b = append(b, byte(p.Code))
|
||||
b = append(b, CodeToVarint(p.Code)...)
|
||||
sp = sp[1:]
|
||||
|
||||
a := addressStringToBytes(p, sp[1])
|
||||
if p.Size > 0 {
|
||||
a := addressStringToBytes(p, sp[0])
|
||||
b = append(b, a...)
|
||||
|
||||
sp = sp[2:]
|
||||
sp = sp[1:]
|
||||
}
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
@ -50,19 +52,23 @@ func bytesToString(b []byte) (ret string, err error) {
|
||||
s := ""
|
||||
|
||||
for len(b) > 0 {
|
||||
p := ProtocolWithCode(int(b[0]))
|
||||
|
||||
code, n := ReadVarintCode(b)
|
||||
b = b[n:]
|
||||
p := ProtocolWithCode(code)
|
||||
if p == nil {
|
||||
return "", fmt.Errorf("no protocol with code %d", b[0])
|
||||
return "", fmt.Errorf("no protocol with code %d", code)
|
||||
}
|
||||
s = strings.Join([]string{s, "/", p.Name}, "")
|
||||
b = b[1:]
|
||||
|
||||
if p.Size > 0 {
|
||||
a := addressBytesToString(p, b[:(p.Size/8)])
|
||||
if len(a) > 0 {
|
||||
s = strings.Join([]string{s, "/", a}, "")
|
||||
}
|
||||
b = b[(p.Size / 8):]
|
||||
}
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
@ -78,12 +84,13 @@ func bytesSplit(b []byte) (ret [][]byte, err error) {
|
||||
|
||||
ret = [][]byte{}
|
||||
for len(b) > 0 {
|
||||
p := ProtocolWithCode(int(b[0]))
|
||||
code, n := ReadVarintCode(b)
|
||||
p := ProtocolWithCode(code)
|
||||
if p == nil {
|
||||
return [][]byte{}, fmt.Errorf("no protocol with code %d", b[0])
|
||||
}
|
||||
|
||||
length := 1 + (p.Size / 8)
|
||||
length := n + (p.Size / 8)
|
||||
ret = append(ret, b[:length])
|
||||
b = b[length:]
|
||||
}
|
||||
|
5
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/multiaddr.go
generated
vendored
5
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/multiaddr.go
generated
vendored
@ -67,14 +67,15 @@ func (m *multiaddr) Protocols() []*Protocol {
|
||||
ps := []*Protocol{}
|
||||
b := m.bytes[:]
|
||||
for len(b) > 0 {
|
||||
p := ProtocolWithCode(int(b[0]))
|
||||
code, n := ReadVarintCode(b)
|
||||
p := ProtocolWithCode(code)
|
||||
if p == nil {
|
||||
// this is a panic (and not returning err) because this should've been
|
||||
// caught on constructing the Multiaddr
|
||||
panic(fmt.Errorf("no protocol with code %d", b[0]))
|
||||
}
|
||||
ps = append(ps, p)
|
||||
b = b[1+(p.Size/8):]
|
||||
b = b[n+(p.Size/8):]
|
||||
}
|
||||
return ps
|
||||
}
|
||||
|
BIN
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/multiaddr/multiaddr
generated
vendored
BIN
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/multiaddr/multiaddr
generated
vendored
Binary file not shown.
8
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/multiaddr_test.go
generated
vendored
8
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/multiaddr_test.go
generated
vendored
@ -68,6 +68,8 @@ func TestStringToBytes(t *testing.T) {
|
||||
}
|
||||
|
||||
testString("/ip4/127.0.0.1/udp/1234", "047f0000011104d2")
|
||||
testString("/ip4/127.0.0.1/tcp/4321", "047f0000010610e1")
|
||||
testString("/ip4/127.0.0.1/udp/1234/ip4/127.0.0.1/tcp/4321", "047f0000011104d2047f0000010610e1")
|
||||
}
|
||||
|
||||
func TestBytesToString(t *testing.T) {
|
||||
@ -89,6 +91,8 @@ func TestBytesToString(t *testing.T) {
|
||||
}
|
||||
|
||||
testString("/ip4/127.0.0.1/udp/1234", "047f0000011104d2")
|
||||
testString("/ip4/127.0.0.1/tcp/4321", "047f0000010610e1")
|
||||
testString("/ip4/127.0.0.1/udp/1234/ip4/127.0.0.1/tcp/4321", "047f0000011104d2047f0000010610e1")
|
||||
}
|
||||
|
||||
func TestBytesSplitAndJoin(t *testing.T) {
|
||||
@ -96,7 +100,7 @@ func TestBytesSplitAndJoin(t *testing.T) {
|
||||
testString := func(s string, res []string) {
|
||||
m, err := NewMultiaddr(s)
|
||||
if err != nil {
|
||||
t.Error("failed to convert", s)
|
||||
t.Fatal("failed to convert", s, err)
|
||||
}
|
||||
|
||||
split := Split(m)
|
||||
@ -132,6 +136,8 @@ func TestBytesSplitAndJoin(t *testing.T) {
|
||||
testString("/ip4/1.2.3.4/udp/1234", []string{"/ip4/1.2.3.4", "/udp/1234"})
|
||||
testString("/ip4/1.2.3.4/tcp/1/ip4/2.3.4.5/udp/2",
|
||||
[]string{"/ip4/1.2.3.4", "/tcp/1", "/ip4/2.3.4.5", "/udp/2"})
|
||||
testString("/ip4/1.2.3.4/utp/ip4/2.3.4.5/udp/2/udt",
|
||||
[]string{"/ip4/1.2.3.4", "/utp", "/ip4/2.3.4.5", "/udp/2", "/udt"})
|
||||
}
|
||||
|
||||
func TestProtocols(t *testing.T) {
|
||||
|
2
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/protocols.csv
generated
vendored
2
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/protocols.csv
generated
vendored
@ -5,5 +5,7 @@ code size name
|
||||
33 16 dccp
|
||||
41 128 ip6
|
||||
132 16 sctp
|
||||
301 0 udt
|
||||
302 0 utp
|
||||
480 0 http
|
||||
443 0 https
|
||||
|
|
44
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/protocols.go
generated
vendored
44
Godeps/_workspace/src/github.com/jbenet/go-multiaddr/protocols.go
generated
vendored
@ -1,10 +1,15 @@
|
||||
package multiaddr
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
// Protocol is a Multiaddr protocol description structure.
|
||||
type Protocol struct {
|
||||
Code int
|
||||
Size int
|
||||
Name string
|
||||
VCode []byte
|
||||
}
|
||||
|
||||
// replicating table here to:
|
||||
@ -18,17 +23,21 @@ const (
|
||||
P_DCCP = 33
|
||||
P_IP6 = 41
|
||||
P_SCTP = 132
|
||||
P_UTP = 301
|
||||
P_UDT = 302
|
||||
)
|
||||
|
||||
// Protocols is the list of multiaddr protocols supported by this module.
|
||||
var Protocols = []*Protocol{
|
||||
&Protocol{P_IP4, 32, "ip4"},
|
||||
&Protocol{P_TCP, 16, "tcp"},
|
||||
&Protocol{P_UDP, 16, "udp"},
|
||||
&Protocol{P_DCCP, 16, "dccp"},
|
||||
&Protocol{P_IP6, 128, "ip6"},
|
||||
&Protocol{P_IP4, 32, "ip4", CodeToVarint(P_IP4)},
|
||||
&Protocol{P_TCP, 16, "tcp", CodeToVarint(P_TCP)},
|
||||
&Protocol{P_UDP, 16, "udp", CodeToVarint(P_UDP)},
|
||||
&Protocol{P_DCCP, 16, "dccp", CodeToVarint(P_DCCP)},
|
||||
&Protocol{P_IP6, 128, "ip6", CodeToVarint(P_IP6)},
|
||||
// these require varint:
|
||||
&Protocol{P_SCTP, 16, "sctp"},
|
||||
&Protocol{P_SCTP, 16, "sctp", CodeToVarint(P_SCTP)},
|
||||
&Protocol{P_UTP, 0, "utp", CodeToVarint(P_UTP)},
|
||||
&Protocol{P_UDT, 0, "udt", CodeToVarint(P_UDT)},
|
||||
// {480, 0, "http"},
|
||||
// {443, 0, "https"},
|
||||
}
|
||||
@ -52,3 +61,26 @@ func ProtocolWithCode(c int) *Protocol {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CodeToVarint converts an integer to a varint-encoded []byte
|
||||
func CodeToVarint(num int) []byte {
|
||||
buf := make([]byte, (num/7)+1) // varint package is uint64
|
||||
n := binary.PutUvarint(buf, uint64(num))
|
||||
return buf[:n]
|
||||
}
|
||||
|
||||
// VarintToCode converts a varint-encoded []byte to an integer protocol code
|
||||
func VarintToCode(buf []byte) int {
|
||||
num, _ := ReadVarintCode(buf)
|
||||
return num
|
||||
}
|
||||
|
||||
// ReadVarintCode reads a varint code from the beginning of buf.
|
||||
// returns the code, and the number of bytes read.
|
||||
func ReadVarintCode(buf []byte) (int, int) {
|
||||
num, n := binary.Uvarint(buf)
|
||||
if n < 0 {
|
||||
panic("varints larger than uint64 not yet supported")
|
||||
}
|
||||
return int(num), n
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
|
||||
manners "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/braintree/manners"
|
||||
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
|
||||
manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/net"
|
||||
manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
|
||||
cmds "github.com/jbenet/go-ipfs/commands"
|
||||
cmdsHttp "github.com/jbenet/go-ipfs/commands/http"
|
||||
core "github.com/jbenet/go-ipfs/core"
|
||||
|
@ -177,9 +177,13 @@ func initConfig(configFilename string, dspathOverride string, nBitsForKeypair in
|
||||
|
||||
conf := &config.Config{
|
||||
|
||||
// setup the node addresses.
|
||||
// setup the node's default addresses.
|
||||
// Note: two swarm listen addrs, one tcp, one utp.
|
||||
Addresses: config.Addresses{
|
||||
Swarm: "/ip4/0.0.0.0/tcp/4001",
|
||||
Swarm: []string{
|
||||
"/ip4/0.0.0.0/tcp/4001",
|
||||
"/ip4/0.0.0.0/udp/4002/utp",
|
||||
},
|
||||
API: "/ip4/127.0.0.1/tcp/5001",
|
||||
},
|
||||
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
// TODO rm direct reference to go-logging
|
||||
logging "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-logging"
|
||||
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
|
||||
manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/net"
|
||||
manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
|
||||
|
||||
cmds "github.com/jbenet/go-ipfs/commands"
|
||||
cmdsCli "github.com/jbenet/go-ipfs/commands/cli"
|
||||
|
@ -36,7 +36,7 @@ type Datastore struct {
|
||||
|
||||
// Addresses stores the (string) multiaddr addresses for the node.
|
||||
type Addresses struct {
|
||||
Swarm string // address for the swarm network
|
||||
Swarm []string // addresses for the swarm network
|
||||
API string // address for the local API (RPC)
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,10 @@ func ReadConfigFile(filename string, cfg interface{}) error {
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
return Decode(f, cfg)
|
||||
if err := Decode(f, cfg); err != nil {
|
||||
return fmt.Errorf("Failure to decode config: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteConfigFile writes the config from `cfg` into `filename`.
|
||||
|
12
core/core.go
12
core/core.go
@ -268,15 +268,15 @@ func initConnections(ctx context.Context, cfg *config.Config, pstore peer.Peerst
|
||||
}
|
||||
|
||||
func listenAddresses(cfg *config.Config) ([]ma.Multiaddr, error) {
|
||||
var listen []ma.Multiaddr
|
||||
|
||||
if len(cfg.Addresses.Swarm) > 0 {
|
||||
maddr, err := ma.NewMultiaddr(cfg.Addresses.Swarm)
|
||||
var err error
|
||||
listen := make([]ma.Multiaddr, len(cfg.Addresses.Swarm))
|
||||
for i, addr := range cfg.Addresses.Swarm {
|
||||
|
||||
listen[i], err = ma.NewMultiaddr(addr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failure to parse config.Addresses.Swarm: %s", cfg.Addresses.Swarm)
|
||||
return nil, fmt.Errorf("Failure to parse config.Addresses.Swarm[%d]: %s", i, cfg.Addresses.Swarm)
|
||||
}
|
||||
|
||||
listen = append(listen, maddr)
|
||||
}
|
||||
|
||||
return listen, nil
|
||||
|
@ -17,7 +17,7 @@ func TestInitialization(t *testing.T) {
|
||||
Type: "memory",
|
||||
},
|
||||
Addresses: config.Addresses{
|
||||
Swarm: "/ip4/0.0.0.0/tcp/4001",
|
||||
Swarm: []string{"/ip4/0.0.0.0/tcp/4001"},
|
||||
API: "/ip4/127.0.0.1/tcp/8000",
|
||||
},
|
||||
},
|
||||
@ -29,7 +29,7 @@ func TestInitialization(t *testing.T) {
|
||||
Path: ".testdb",
|
||||
},
|
||||
Addresses: config.Addresses{
|
||||
Swarm: "/ip4/0.0.0.0/tcp/4001",
|
||||
Swarm: []string{"/ip4/0.0.0.0/tcp/4001"},
|
||||
API: "/ip4/127.0.0.1/tcp/8000",
|
||||
},
|
||||
},
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
|
||||
msgio "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-msgio"
|
||||
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
|
||||
manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/net"
|
||||
manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
|
||||
|
||||
peer "github.com/jbenet/go-ipfs/peer"
|
||||
u "github.com/jbenet/go-ipfs/util"
|
||||
|
@ -1,30 +1,58 @@
|
||||
package conn
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
|
||||
|
||||
manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/net"
|
||||
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
|
||||
manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
|
||||
|
||||
peer "github.com/jbenet/go-ipfs/peer"
|
||||
debugerror "github.com/jbenet/go-ipfs/util/debugerror"
|
||||
)
|
||||
|
||||
// Dial connects to a particular peer, over a given network
|
||||
// Example: d.Dial(ctx, "udp", peer)
|
||||
func (d *Dialer) Dial(ctx context.Context, network string, remote peer.Peer) (Conn, error) {
|
||||
laddr := d.LocalPeer.NetAddress(network)
|
||||
if laddr == nil {
|
||||
return nil, fmt.Errorf("No local address for network %s", network)
|
||||
}
|
||||
|
||||
raddr := remote.NetAddress(network)
|
||||
if raddr == nil {
|
||||
return nil, fmt.Errorf("No remote address for network %s", network)
|
||||
return nil, debugerror.Errorf("No remote address for network %s", network)
|
||||
}
|
||||
return d.DialAddr(ctx, raddr, remote)
|
||||
}
|
||||
|
||||
// DialAddr connects to a peer over a particular address
|
||||
// Ensures raddr is part of peer.Addresses()
|
||||
// Example: d.DialAddr(ctx, peer.Addresses()[0], peer)
|
||||
func (d *Dialer) DialAddr(ctx context.Context, raddr ma.Multiaddr, remote peer.Peer) (Conn, error) {
|
||||
|
||||
found := false
|
||||
for _, addr := range remote.Addresses() {
|
||||
if addr.Equal(raddr) {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return nil, debugerror.Errorf("address %s is not in peer %s", raddr, remote)
|
||||
}
|
||||
|
||||
network, _, err := manet.DialArgs(raddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
laddr := d.LocalPeer.NetAddress(network)
|
||||
if laddr == nil {
|
||||
return nil, debugerror.Errorf("No local address for network %s", network)
|
||||
}
|
||||
|
||||
if strings.HasPrefix(raddr.String(), "/ip4/0.0.0.0") {
|
||||
return nil, debugerror.Errorf("Attempted to connect to zero address: %s", raddr)
|
||||
}
|
||||
|
||||
remote.SetType(peer.Remote)
|
||||
remote, err := d.Peerstore.Add(remote)
|
||||
remote, err = d.Peerstore.Add(remote)
|
||||
if err != nil {
|
||||
log.Errorf("Error putting peer into peerstore: %s", remote)
|
||||
}
|
||||
|
@ -157,3 +157,73 @@ func TestDialer(t *testing.T) {
|
||||
l.Close()
|
||||
cancel()
|
||||
}
|
||||
|
||||
func TestDialAddr(t *testing.T) {
|
||||
// t.Skip("Skipping in favor of another test")
|
||||
|
||||
p1, err := setupPeer("/ip4/127.0.0.1/tcp/4334")
|
||||
if err != nil {
|
||||
t.Fatal("error setting up peer", err)
|
||||
}
|
||||
|
||||
p2, err := setupPeer("/ip4/127.0.0.1/tcp/4335")
|
||||
if err != nil {
|
||||
t.Fatal("error setting up peer", err)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
laddr := p1.NetAddress("tcp")
|
||||
if laddr == nil {
|
||||
t.Fatal("Listen address is nil.")
|
||||
}
|
||||
|
||||
ps1 := peer.NewPeerstore()
|
||||
ps2 := peer.NewPeerstore()
|
||||
ps1.Add(p1)
|
||||
ps2.Add(p2)
|
||||
|
||||
l, err := Listen(ctx, laddr, p1, ps1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
go echoListen(ctx, l)
|
||||
|
||||
d := &Dialer{
|
||||
Peerstore: ps2,
|
||||
LocalPeer: p2,
|
||||
}
|
||||
|
||||
raddr := p1.NetAddress("tcp")
|
||||
if raddr == nil {
|
||||
t.Fatal("Dial address is nil.")
|
||||
}
|
||||
|
||||
c, err := d.DialAddr(ctx, raddr, p1)
|
||||
if err != nil {
|
||||
t.Fatal("error dialing peer", err)
|
||||
}
|
||||
|
||||
// fmt.Println("sending")
|
||||
c.Out() <- []byte("beep")
|
||||
c.Out() <- []byte("boop")
|
||||
|
||||
out := <-c.In()
|
||||
// fmt.Println("recving", string(out))
|
||||
data := string(out)
|
||||
if data != "beep" {
|
||||
t.Error("unexpected conn output", data)
|
||||
}
|
||||
|
||||
out = <-c.In()
|
||||
data = string(out)
|
||||
if string(out) != "boop" {
|
||||
t.Error("unexpected conn output", data)
|
||||
}
|
||||
|
||||
// fmt.Println("closing")
|
||||
c.Close()
|
||||
l.Close()
|
||||
cancel()
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
package conn
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
|
||||
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
|
||||
manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/net"
|
||||
manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
|
||||
|
||||
peer "github.com/jbenet/go-ipfs/peer"
|
||||
ctxc "github.com/jbenet/go-ipfs/util/ctxcloser"
|
||||
@ -73,6 +75,7 @@ func (l *listener) listen() {
|
||||
}
|
||||
|
||||
for {
|
||||
log.Info("swarm listening on %s -- %v\n", l.Multiaddr(), l.Listener)
|
||||
maconn, err := l.Listener.Accept()
|
||||
if err != nil {
|
||||
|
||||
@ -120,7 +123,7 @@ func Listen(ctx context.Context, addr ma.Multiaddr, local peer.Peer, peers peer.
|
||||
|
||||
ml, err := manet.Listen(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("Failed to listen on %s: %s", addr, err)
|
||||
}
|
||||
|
||||
// todo make this a variable
|
||||
|
@ -2,7 +2,7 @@ package swarm
|
||||
|
||||
import (
|
||||
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
|
||||
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/net"
|
||||
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
|
||||
"github.com/jbenet/go-ipfs/util/eventlog"
|
||||
|
||||
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
|
||||
conn "github.com/jbenet/go-ipfs/net/conn"
|
||||
msg "github.com/jbenet/go-ipfs/net/message"
|
||||
peer "github.com/jbenet/go-ipfs/peer"
|
||||
|
||||
context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
|
||||
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
|
||||
@ -95,8 +96,38 @@ func (s *Swarm) handleIncomingConn(nconn conn.Conn) {
|
||||
}
|
||||
}
|
||||
|
||||
// connSetup adds the passed in connection to its peerMap and starts
|
||||
// the fanInSingle routine for that connection
|
||||
// peerMultiConn returns the MultiConn responsible for handling this peer.
|
||||
// if there is none, it creates one and returns it. Note that timeouts
|
||||
// and connection teardowns will remove it.
|
||||
func (s *Swarm) peerMultiConn(p peer.Peer) (*conn.MultiConn, error) {
|
||||
|
||||
s.connsLock.Lock()
|
||||
mc, found := s.conns[p.Key()]
|
||||
if found {
|
||||
s.connsLock.Unlock()
|
||||
return mc, nil
|
||||
}
|
||||
|
||||
// multiconn doesn't exist, make a new one.
|
||||
mc, err := conn.NewMultiConn(s.Context(), s.local, p, nil)
|
||||
if err != nil {
|
||||
s.connsLock.Unlock()
|
||||
log.Errorf("error creating multiconn: %s", err)
|
||||
return nil, err
|
||||
}
|
||||
s.conns[p.Key()] = mc
|
||||
s.connsLock.Unlock()
|
||||
|
||||
// kick off reader goroutine
|
||||
s.Children().Add(1)
|
||||
mc.Children().Add(1) // child of Conn as well.
|
||||
go s.fanInSingle(mc)
|
||||
log.Debugf("added new multiconn: %s", mc)
|
||||
return mc, nil
|
||||
}
|
||||
|
||||
// connSetup takes a new connection, performs the IPFS handshake (handshake3)
|
||||
// and then adds it to the appropriate MultiConn.
|
||||
func (s *Swarm) connSetup(c conn.Conn) (conn.Conn, error) {
|
||||
if c == nil {
|
||||
return nil, errors.New("Tried to start nil connection.")
|
||||
@ -126,35 +157,14 @@ func (s *Swarm) connSetup(c conn.Conn) (conn.Conn, error) {
|
||||
}
|
||||
|
||||
// add to conns
|
||||
s.connsLock.Lock()
|
||||
|
||||
mc, found := s.conns[c.RemotePeer().Key()]
|
||||
if !found {
|
||||
// multiconn doesn't exist, make a new one.
|
||||
conns := []conn.Conn{c}
|
||||
mc, err := conn.NewMultiConn(s.Context(), s.local, c.RemotePeer(), conns)
|
||||
mc, err := s.peerMultiConn(c.RemotePeer())
|
||||
if err != nil {
|
||||
log.Errorf("error creating multiconn: %s", err)
|
||||
c.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.conns[c.RemotePeer().Key()] = mc
|
||||
s.connsLock.Unlock()
|
||||
|
||||
// kick off reader goroutine
|
||||
s.Children().Add(1)
|
||||
mc.Children().Add(1) // child of Conn as well.
|
||||
go s.fanInSingle(mc)
|
||||
log.Debugf("added new multiconn: %s", mc)
|
||||
} else {
|
||||
s.connsLock.Unlock() // unlock before adding new conn
|
||||
|
||||
mc.Add(c)
|
||||
log.Debugf("multiconn found: %s", mc)
|
||||
}
|
||||
|
||||
log.Debugf("multiconn added new conn %s", c)
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,6 @@ package swarm
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
conn "github.com/jbenet/go-ipfs/net/conn"
|
||||
@ -133,17 +132,15 @@ func (s *Swarm) Dial(peer peer.Peer) (conn.Conn, error) {
|
||||
Peerstore: s.peers,
|
||||
}
|
||||
|
||||
// If we are attempting to connect to the zero addr, fail out early
|
||||
raddr := peer.NetAddress("tcp")
|
||||
if raddr == nil {
|
||||
return nil, fmt.Errorf("No remote address for network tcp")
|
||||
// try to connect to one of the peer's known addresses.
|
||||
// for simplicity, we do this sequentially.
|
||||
// A future commit will do this asynchronously.
|
||||
for _, addr := range peer.Addresses() {
|
||||
c, err = d.DialAddr(s.Context(), addr, peer)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
|
||||
if strings.HasPrefix(raddr.String(), "/ip4/0.0.0.0") {
|
||||
return nil, fmt.Errorf("Attempted to connect to loopback address: %s", raddr)
|
||||
}
|
||||
|
||||
c, err = d.Dial(s.Context(), "tcp", peer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
|
||||
mux "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gorilla/mux"
|
||||
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
|
||||
manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/net"
|
||||
manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
|
||||
mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
|
||||
|
||||
core "github.com/jbenet/go-ipfs/core"
|
||||
|
Reference in New Issue
Block a user