From b92a9d2e5b0c0c818774df62089ee4df08ec95b6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ken-H=C3=A5vard=20Lieng?= <kk_998@hotmail.com>
Date: Thu, 30 Jul 2020 09:29:50 +0200
Subject: [PATCH] Update vendor

---
 go.mod                                        |   1 -
 go.sum                                        |   1 -
 vendor/github.com/eyedeekay/goSam/.gitignore  |  24 +
 .../eyedeekay/goSam/CONTRIBUTING.md           | 195 +++++++
 vendor/github.com/eyedeekay/goSam/LICENSE     |  22 +
 vendor/github.com/eyedeekay/goSam/Makefile    |  24 +
 vendor/github.com/eyedeekay/goSam/README.md   |  91 ++++
 vendor/github.com/eyedeekay/goSam/accept.go   |  63 +++
 vendor/github.com/eyedeekay/goSam/client.go   | 233 ++++++++
 vendor/github.com/eyedeekay/goSam/conn.go     |  68 +++
 vendor/github.com/eyedeekay/goSam/dial.go     |  73 +++
 vendor/github.com/eyedeekay/goSam/go.mod      |  11 +
 vendor/github.com/eyedeekay/goSam/go.sum      |   3 +
 vendor/github.com/eyedeekay/goSam/naming.go   |  34 ++
 vendor/github.com/eyedeekay/goSam/options.go  | 507 ++++++++++++++++++
 .../github.com/eyedeekay/goSam/replyParser.go |  64 +++
 vendor/github.com/eyedeekay/goSam/rw.go       | 101 ++++
 vendor/github.com/eyedeekay/goSam/rwc.go      |  80 +++
 vendor/github.com/eyedeekay/goSam/sessions.go |  45 ++
 vendor/github.com/eyedeekay/goSam/stream.go   |  45 ++
 vendor/modules.txt                            |   2 -
 21 files changed, 1683 insertions(+), 4 deletions(-)
 create mode 100644 vendor/github.com/eyedeekay/goSam/.gitignore
 create mode 100644 vendor/github.com/eyedeekay/goSam/CONTRIBUTING.md
 create mode 100644 vendor/github.com/eyedeekay/goSam/LICENSE
 create mode 100644 vendor/github.com/eyedeekay/goSam/Makefile
 create mode 100644 vendor/github.com/eyedeekay/goSam/README.md
 create mode 100644 vendor/github.com/eyedeekay/goSam/accept.go
 create mode 100644 vendor/github.com/eyedeekay/goSam/client.go
 create mode 100644 vendor/github.com/eyedeekay/goSam/conn.go
 create mode 100644 vendor/github.com/eyedeekay/goSam/dial.go
 create mode 100644 vendor/github.com/eyedeekay/goSam/go.mod
 create mode 100644 vendor/github.com/eyedeekay/goSam/go.sum
 create mode 100644 vendor/github.com/eyedeekay/goSam/naming.go
 create mode 100644 vendor/github.com/eyedeekay/goSam/options.go
 create mode 100644 vendor/github.com/eyedeekay/goSam/replyParser.go
 create mode 100644 vendor/github.com/eyedeekay/goSam/rw.go
 create mode 100644 vendor/github.com/eyedeekay/goSam/rwc.go
 create mode 100644 vendor/github.com/eyedeekay/goSam/sessions.go
 create mode 100644 vendor/github.com/eyedeekay/goSam/stream.go

diff --git a/go.mod b/go.mod
index 98ddbd15..949c2667 100644
--- a/go.mod
+++ b/go.mod
@@ -12,7 +12,6 @@ require (
 	github.com/cznic/strutil v0.0.0-20181122101858-275e90344537 // indirect
 	github.com/dsnet/compress v0.0.1
 	github.com/eyedeekay/goSam v0.32.22
-	github.com/eyedeekay/sam3 v0.32.3 // indirect
 	github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 // indirect
 	github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect
 	github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 // indirect
diff --git a/go.sum b/go.sum
index 6add93a1..c63e79cd 100644
--- a/go.sum
+++ b/go.sum
@@ -142,7 +142,6 @@ github.com/eyedeekay/goSam v0.32.22 h1:SD0GEQ8MGJ1wZ4MepSa0mpZjiZAGMSTUhSwAZVrm2
 github.com/eyedeekay/goSam v0.32.22/go.mod h1:YIklxqKiJ3I5JNRgb5pM7VCQOSNDGnVulHnrKBbbECM=
 github.com/eyedeekay/ramp v0.0.0-20190429201811-305b382042ab/go.mod h1:h7mvUAMgZ/rtRDUOkvKTK+8LnDMeUhJSoa5EPdB51fc=
 github.com/eyedeekay/sam3 v0.32.2/go.mod h1:Y3igFVzN4ybqkkpfUWULGhw7WRp8lieq0ORXbLBbcZM=
-github.com/eyedeekay/sam3 v0.32.3/go.mod h1:qRA9KIIVxbrHlkj+ZB+OoxFGFgdKeGp1vSgPw26eOVU=
 github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ=
 github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64=
 github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A=
diff --git a/vendor/github.com/eyedeekay/goSam/.gitignore b/vendor/github.com/eyedeekay/goSam/.gitignore
new file mode 100644
index 00000000..d3bdc127
--- /dev/null
+++ b/vendor/github.com/eyedeekay/goSam/.gitignore
@@ -0,0 +1,24 @@
+# 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
+itp-golang-github-eyedeekay-gosam.txt
+.pc
diff --git a/vendor/github.com/eyedeekay/goSam/CONTRIBUTING.md b/vendor/github.com/eyedeekay/goSam/CONTRIBUTING.md
new file mode 100644
index 00000000..6df463c6
--- /dev/null
+++ b/vendor/github.com/eyedeekay/goSam/CONTRIBUTING.md
@@ -0,0 +1,195 @@
+How to make contributions to goSam
+==================================
+
+Welcome to goSam, the easy-to-use http client for i2p. We're glad you're here
+and interested in contributing. Here's some help getting started.
+
+Table of Contents
+-----------------
+
+  * (1) Environment
+  * (2) Testing
+  * (3) Filing Issues/Reporting Bugs/Making Suggestions
+  * (4) Contributing Code/Style Guide
+    - (a) Adding i2cp and tunnel Options
+    - (b) Writing Tests
+    - (c) Style
+    - (d) Other kinds of modification?
+  * (5) Conduct
+
+### (1) Environment
+
+goSam is a simple go library. You are free to use an IDE if you wish, but all
+that is required to build and test the library are a go compiler and the gofmt
+tool. Git is the version control system. All the files in the library are in a
+single root directory. Invoking go build from this directory not generate any
+files.
+
+### (2) Testing
+
+Tests are implemented using the standard go "testing" library in files named
+"file\_test.go," so tests of the client go in client\_test.go, name lookups
+in naming\_test.go, et cetera. Everything that can be tested, should be tested.
+
+Testing is done by running
+
+        go test
+
+More information about designing tests is below in the
+**Contributing Code/Style Guide** section below.
+
+### (3) Filing issues/Reporting bugs/Making suggestions
+
+If you discover the library doing something you don't think is right, please let
+us know! Just filing an issue here is OK.
+
+If you need to suggest a feature, we're happy to hear from you too. Filing an
+issue will give us a place to discuss how it's implemented openly and publicly.
+
+Please file an issue for your new code contributions in order to provide us with
+a place to discuss them for inclusion.
+
+### (4) Contributing Code/Style Guide
+
+Welcome new coders. We have good news for you, this library is really easy to
+contribute to. The easiest contributions take the form of i2cp and tunnel
+options.
+
+#### (a) Adding i2cp and tunnel Options
+
+First, add a variable to store the state of your new option. For example, the
+existing variables are in the Client class [here:](https://github.com/cryptix/goSam/blob/701d7fcf03ddb354262fe213163dcf6f202a24f1/client.go#L29)
+
+i2cp and tunnel options are added in a highly uniform process of basically three
+steps. First, you create a functional argument in the options.go file, in the
+form:
+
+``` Go
+        // SetOPTION sets $OPTION
+        func SetOPTION(arg type) func(*Client) error {  // arg type
+            return func(c *Client) error {              // pass a client to the inner function and declare error return function
+                if arg == valid {                       // validate the argument
+                    c.option = s                        // set the variable to the argument value
+                    return nil                          // if option is set successfully return nil error
+                }
+                return fmt.Errorf("Invalid argument:" arg) // return a descriptive error if arg is invalid
+            }
+        }
+```
+
+[example](https://github.com/cryptix/goSam/blob/701d7fcf03ddb354262fe213163dcf6f202a24f1/options.go#L187)
+
+Next, you create a getter which prepares the option. Regardless of the type of
+option that is set, these must return strings representing valid i2cp options.
+
+``` Go
+        //return the OPTION as a string.
+        func (c *Client) option() string {
+            return fmt.Sprintf("i2cp.option=%d", c.option)
+        }
+```
+
+[example](https://github.com/cryptix/goSam/blob/701d7fcf03ddb354262fe213163dcf6f202a24f1/options.go#L299)
+
+Lastly, you'll need to add it to the allOptions function and the
+Client.NewClient() function. To add it to allOptions, it looks like this:
+
+``` Go
+        //return all options as string ready for passing to sendcmd
+        func (c *Client) allOptions() string {
+            return c.inlength() + " " +
+                c.outlength() + " " +
+                ... //other options removed from example for brevity
+                c.option()
+        }
+```
+
+``` Go
+        //return all options as string ready for passing to sendcmd
+        func (c *Client) NewClient() (*Client, error) {
+            return NewClientFromOptions(
+                SetHost(c.host),
+                SetPort(c.port),
+                ... //other options removed from example for brevity
+                SetCompression(c.compression),
+                setlastaddr(c.lastaddr),
+                setid(c.id),
+            )
+        }
+```
+
+[example](https://github.com/cryptix/goSam/blob/701d7fcf03ddb354262fe213163dcf6f202a24f1/options.go#L333)
+
+#### (b) Writing Tests
+
+Before the feature can be added, you'll need to add a test for it to
+options_test.go. To do this, just add your new option to the long TestOptions
+functions in options_test.go.
+
+``` Go
+        func TestOptionHost(t *testing.T) {
+            client, err := NewClientFromOptions(
+                SetHost("127.0.0.1"),
+                SetPort("7656"),
+                ... //other options removed from example for brevity
+                SetCloseIdleTime(300001),
+            )
+            if err != nil {
+                t.Fatalf("NewClientFromOptions() Error: %q\n", err)
+            }
+            if result, err := client.validCreate(); err != nil {
+                t.Fatalf(err.Error())
+            } else {
+                t.Log(result)
+            }
+            client.CreateStreamSession("")
+            if err := client.Close(); err != nil {
+                t.Fatalf("client.Close() Error: %q\n", err)
+            }
+        }
+
+        func TestOptionPortInt(t *testing.T) {
+            client, err := NewClientFromOptions(
+                SetHost("127.0.0.1"),
+                SetPortInt(7656),
+                ... //other options removed from example for brevity
+                SetUnpublished(true),
+            )
+            if err != nil {
+                t.Fatalf("NewClientFromOptions() Error: %q\n", err)
+            }
+            if result, err := client.validCreate(); err != nil {
+                t.Fatalf(err.Error())
+            } else {
+                t.Log(result)
+            }
+            client.CreateStreamSession("")
+            if err := client.Close(); err != nil {
+                t.Fatalf("client.Close() Error: %q\n", err)
+            }
+        }
+
+```
+
+If any of these tasks fail, then the test should fail.
+
+#### (c) Style
+
+It's pretty simple to make sure the code style is right, just run gofmt over it
+to adjust the indentation, and golint over it to ensure that your comments are
+of the correct form for the documentation generator.
+
+#### (d) Other kinds of modification?
+
+It may be useful to extend goSam in other ways. Since there's not a
+one-size-fits-all uniform way of dealing with these kinds of changes, open an
+issue for discussion and
+
+### (5) Conduct
+
+This is a small-ish, straightforward library intended to enable a clear
+technical task. We should be able to be civil with eachother, and give and
+accept criticism contructively and respectfully.
+
+This document was drawn from the examples given by Mozilla
+[here](mozillascience.github.io/working-open-workshop/contributing/)
diff --git a/vendor/github.com/eyedeekay/goSam/LICENSE b/vendor/github.com/eyedeekay/goSam/LICENSE
new file mode 100644
index 00000000..e870cb4c
--- /dev/null
+++ b/vendor/github.com/eyedeekay/goSam/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Henry
+
+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.
+
diff --git a/vendor/github.com/eyedeekay/goSam/Makefile b/vendor/github.com/eyedeekay/goSam/Makefile
new file mode 100644
index 00000000..3da96d0a
--- /dev/null
+++ b/vendor/github.com/eyedeekay/goSam/Makefile
@@ -0,0 +1,24 @@
+
+USER_GH=eyedeekay
+VERSION=0.32.22
+packagename=gosam
+
+echo:
+	@echo "type make version to do release $(VERSION)"
+
+version:
+	gothub release -s $(GITHUB_TOKEN) -u $(USER_GH) -r $(packagename) -t v$(VERSION) -d "version $(VERSION)"
+
+del:
+	gothub delete -s $(GITHUB_TOKEN) -u $(USER_GH) -r $(packagename) -t v$(VERSION)
+
+tar:
+	tar --exclude .git \
+		--exclude .go \
+		--exclude bin \
+		--exclude examples \
+		-cJvf ../$(packagename)_$(VERSION).orig.tar.xz .
+
+link:
+	rm -f ../goSam
+	ln -sf . ../goSam
diff --git a/vendor/github.com/eyedeekay/goSam/README.md b/vendor/github.com/eyedeekay/goSam/README.md
new file mode 100644
index 00000000..1ec32ff7
--- /dev/null
+++ b/vendor/github.com/eyedeekay/goSam/README.md
@@ -0,0 +1,91 @@
+goSam
+=====
+
+A go library for using the [I2P](https://geti2p.net/en/) Simple Anonymous
+Messaging ([SAM version 3.0](https://geti2p.net/en/docs/api/samv3)) bridge. It
+has support for SAM version 3.1 signature types.
+
+This is in an **early development stage**. I would love to hear about any
+issues or ideas for improvement.
+
+## Installation
+```
+go get github.com/eyedeekay/goSam
+```
+
+## Using it for HTTP Transport
+
+I implemented `Client.Dial` like `net.Dial` so you can use go's library packages like http.
+
+```go
+package main
+
+import (
+	"io"
+	"log"
+	"net/http"
+	"os"
+
+	"github.com/cryptix/goSam"
+)
+
+func main() {
+	// create a default sam client
+	sam, err := goSam.NewDefaultClient()
+	checkErr(err)
+
+	log.Println("Client Created")
+
+	// create a transport that uses SAM to dial TCP Connections
+	tr := &http.Transport{
+		Dial: sam.Dial,
+	}
+
+	// create  a client using this transport
+	client := &http.Client{Transport: tr}
+
+	// send a get request
+	resp, err := client.Get("http://stats.i2p/")
+	checkErr(err)
+	defer resp.Body.Close()
+
+	log.Printf("Get returned %+v\n", resp)
+
+	// create a file for the response
+	file, err := os.Create("stats.html")
+	checkErr(err)
+	defer file.Close()
+
+	// copy the response to the file
+	_, err = io.Copy(file, resp.Body)
+	checkErr(err)
+
+	log.Println("Done.")
+}
+
+func checkErr(err error) {
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+```
+
+### .deb package
+
+A package for installing this on Debian is buildable, and a version for Ubuntu
+is available as a PPA and mirrored via i2p. To build the deb package, from the
+root of this repository with the build dependencies installed(git, i2p, go,
+debuild) run the command
+
+        debuild -us -uc
+
+to produce an unsigned deb for personal use only. For packagers,
+
+        debuild -S
+
+will produce a viable source package for use with Launchpad PPA's and other
+similar systems.
+### TODO
+
+* Implement `STREAM ACCEPT` and `STREAM FORWARD`
+* Implement datagrams (Repliable and Anon)
diff --git a/vendor/github.com/eyedeekay/goSam/accept.go b/vendor/github.com/eyedeekay/goSam/accept.go
new file mode 100644
index 00000000..95310400
--- /dev/null
+++ b/vendor/github.com/eyedeekay/goSam/accept.go
@@ -0,0 +1,63 @@
+package goSam
+
+import (
+	"fmt"
+	"net"
+)
+
+// AcceptI2P creates a new Client and accepts a connection on it
+func (c *Client) AcceptI2P() (net.Conn, error) {
+	listener, err := c.Listen()
+	if err != nil {
+		return nil, err
+	}
+	return listener.Accept()
+}
+
+// Listen creates a new Client and returns a net.listener which *must* be started
+// with Accept
+func (c *Client) Listen() (net.Listener, error) {
+	return c.ListenI2P(c.destination)
+}
+
+// ListenI2P creates a new Client and returns a net.listener which *must* be started
+// with Accept
+func (c *Client) ListenI2P(dest string) (net.Listener, error) {
+	var err error
+	var id int32
+	c.id = c.NewID()
+	c.destination, err = c.CreateStreamSession(id, dest)
+	if err != nil {
+		return nil, err
+	}
+
+	fmt.Println("destination:", c.destination)
+
+	c, err = c.NewClient()
+	if err != nil {
+		return nil, err
+	}
+
+	if c.debug {
+		c.SamConn = WrapConn(c.SamConn)
+	}
+
+	return c, nil
+}
+
+// Accept accepts a connection on a listening goSam.Client(Implements net.Listener)
+// or, if the connection isn't listening yet, just calls AcceptI2P for compatibility
+// with older versions.
+func (c *Client) Accept() (net.Conn, error) {
+	if c.id == 0 {
+		return c.AcceptI2P()
+	}
+	resp, err := c.StreamAccept(c.id)
+	if err != nil {
+		return nil, err
+	}
+
+	fmt.Println("Accept Resp:", resp)
+
+	return c.SamConn, nil
+}
diff --git a/vendor/github.com/eyedeekay/goSam/client.go b/vendor/github.com/eyedeekay/goSam/client.go
new file mode 100644
index 00000000..d97ac36f
--- /dev/null
+++ b/vendor/github.com/eyedeekay/goSam/client.go
@@ -0,0 +1,233 @@
+package goSam
+
+import (
+	"bufio"
+	"crypto/sha256"
+	"encoding/base32"
+	"encoding/base64"
+	"encoding/binary"
+	"fmt"
+	"math"
+	"math/rand"
+	"net"
+	"strings"
+)
+
+// A Client represents a single Connection to the SAM bridge
+type Client struct {
+	host     string
+	port     string
+	fromport string
+	toport   string
+
+	SamConn net.Conn
+	rd      *bufio.Reader
+
+	sigType     string
+	destination string
+
+	inLength   uint
+	inVariance int
+	inQuantity uint
+	inBackups  uint
+
+	outLength   uint
+	outVariance int
+	outQuantity uint
+	outBackups  uint
+
+	dontPublishLease bool
+	encryptLease     bool
+
+	reduceIdle         bool
+	reduceIdleTime     uint
+	reduceIdleQuantity uint
+
+	closeIdle     bool
+	closeIdleTime uint
+
+	compression bool
+
+	debug bool
+	//NEVER, EVER modify lastaddr or id yourself. They are used internally only.
+	lastaddr string
+	id       int32
+}
+
+var SAMsigTypes = []string{
+	"SIGNATURE_TYPE=DSA_SHA1",
+	"SIGNATURE_TYPE=ECDSA_SHA256_P256",
+	"SIGNATURE_TYPE=ECDSA_SHA384_P384",
+	"SIGNATURE_TYPE=ECDSA_SHA512_P521",
+	"SIGNATURE_TYPE=EdDSA_SHA512_Ed25519",
+}
+
+var (
+	i2pB64enc *base64.Encoding = base64.NewEncoding("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-~")
+	i2pB32enc *base32.Encoding = base32.NewEncoding("abcdefghijklmnopqrstuvwxyz234567")
+)
+
+// NewDefaultClient creates a new client, connecting to the default host:port at localhost:7656
+func NewDefaultClient() (*Client, error) {
+	return NewClient("localhost:7656")
+}
+
+// NewClient creates a new client, connecting to a specified port
+func NewClient(addr string) (*Client, error) {
+	return NewClientFromOptions(SetAddr(addr))
+}
+
+// NewID generates a random number to use as an tunnel name
+func (c *Client) NewID() int32 {
+	return rand.Int31n(math.MaxInt32)
+}
+
+// Destination returns the full destination of the local tunnel
+func (c *Client) Destination() string {
+	return c.destination
+}
+
+// Base32 returns the base32 of the local tunnel
+func (c *Client) Base32() string {
+	hash := sha256.New()
+	b64, err := i2pB64enc.DecodeString(c.Base64())
+	if err != nil {
+		return ""
+	}
+	hash.Write([]byte(b64))
+	return strings.ToLower(strings.Replace(i2pB32enc.EncodeToString(hash.Sum(nil)), "=", "", -1))
+}
+
+func (c *Client) base64() []byte {
+	if c.destination != "" {
+		s, _ := i2pB64enc.DecodeString(c.destination)
+		alen := binary.BigEndian.Uint16(s[385:387])
+		return s[:387+alen]
+	}
+	return []byte("")
+}
+
+// Base64 returns the base64 of the local tunnel
+func (c *Client) Base64() string {
+	return i2pB64enc.EncodeToString(c.base64())
+}
+
+// NewClientFromOptions creates a new client, connecting to a specified port
+func NewClientFromOptions(opts ...func(*Client) error) (*Client, error) {
+	var c Client
+	c.host = "127.0.0.1"
+	c.port = "7656"
+	c.inLength = 3
+	c.inVariance = 0
+	c.inQuantity = 1
+	c.inBackups = 1
+	c.outLength = 3
+	c.outVariance = 0
+	c.outQuantity = 1
+	c.outBackups = 1
+	c.dontPublishLease = true
+	c.encryptLease = false
+	c.reduceIdle = false
+	c.reduceIdleTime = 300000
+	c.reduceIdleQuantity = 1
+	c.closeIdle = true
+	c.closeIdleTime = 600000
+	c.debug = true
+	c.sigType = SAMsigTypes[4]
+	c.id = 0
+	c.lastaddr = "invalid"
+	c.destination = ""
+	for _, o := range opts {
+		if err := o(&c); err != nil {
+			return nil, err
+		}
+	}
+	conn, err := net.Dial("tcp", c.samaddr())
+	if err != nil {
+		return nil, err
+	}
+	if c.debug {
+		conn = WrapConn(conn)
+	}
+	c.SamConn = conn
+	c.rd = bufio.NewReader(conn)
+	return &c, c.hello()
+}
+
+func (p *Client) ID() string {
+	return fmt.Sprintf("%d", p.id)
+}
+
+func (p *Client) Addr() net.Addr {
+	return nil
+}
+
+//return the combined host:port of the SAM bridge
+func (c *Client) samaddr() string {
+	return fmt.Sprintf("%s:%s", c.host, c.port)
+}
+
+// send the initial handshake command and check that the reply is ok
+func (c *Client) hello() error {
+	r, err := c.sendCmd("HELLO VERSION MIN=3.0 MAX=3.2\n")
+	if err != nil {
+		return err
+	}
+
+	if r.Topic != "HELLO" {
+		return fmt.Errorf("Unknown Reply: %+v\n", r)
+	}
+
+	if r.Pairs["RESULT"] != "OK" {
+		return fmt.Errorf("Handshake did not succeed\nReply:%+v\n", r)
+	}
+
+	return nil
+}
+
+// helper to send one command and parse the reply by sam
+func (c *Client) sendCmd(str string, args ...interface{}) (*Reply, error) {
+	if _, err := fmt.Fprintf(c.SamConn, str, args...); err != nil {
+		return nil, err
+	}
+
+	line, err := c.rd.ReadString('\n')
+	if err != nil {
+		return nil, err
+	}
+
+	return parseReply(line)
+}
+
+// Close the underlying socket to SAM
+func (c *Client) Close() error {
+	c.rd = nil
+	return c.SamConn.Close()
+}
+
+// NewClient generates an exact copy of the client with the same options
+func (c *Client) NewClient() (*Client, error) {
+	return NewClientFromOptions(
+		SetHost(c.host),
+		SetPort(c.port),
+		SetDebug(c.debug),
+		SetInLength(c.inLength),
+		SetOutLength(c.outLength),
+		SetInVariance(c.inVariance),
+		SetOutVariance(c.outVariance),
+		SetInQuantity(c.inQuantity),
+		SetOutQuantity(c.outQuantity),
+		SetInBackups(c.inBackups),
+		SetOutBackups(c.outBackups),
+		SetUnpublished(c.dontPublishLease),
+		SetEncrypt(c.encryptLease),
+		SetReduceIdle(c.reduceIdle),
+		SetReduceIdleTime(c.reduceIdleTime),
+		SetReduceIdleQuantity(c.reduceIdleQuantity),
+		SetCloseIdle(c.closeIdle),
+		SetCloseIdleTime(c.closeIdleTime),
+		SetCompression(c.compression),
+		setlastaddr(c.lastaddr),
+		setid(c.id),
+	)
+}
diff --git a/vendor/github.com/eyedeekay/goSam/conn.go b/vendor/github.com/eyedeekay/goSam/conn.go
new file mode 100644
index 00000000..798bb953
--- /dev/null
+++ b/vendor/github.com/eyedeekay/goSam/conn.go
@@ -0,0 +1,68 @@
+/*
+The MIT License (MIT)
+
+Copyright (c) 2014 Henry
+
+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.
+*/
+
+package goSam
+
+import (
+	"log"
+	"net"
+	"time"
+)
+
+type Conn struct {
+	RWC
+	conn net.Conn
+}
+
+func WrapConn(c net.Conn) *Conn {
+	wrap := Conn{
+		conn: c,
+	}
+	wrap.Reader = NewReadLogger("<", c)
+	wrap.Writer = NewWriteLogger(">", c)
+	wrap.RWC.c = c
+	return &wrap
+}
+
+func (c *Conn) LocalAddr() net.Addr {
+	return c.conn.LocalAddr()
+}
+
+func (c *Conn) RemoteAddr() net.Addr {
+	return c.conn.RemoteAddr()
+}
+
+func (c *Conn) SetDeadline(t time.Time) error {
+	log.Println("WARNING: SetDeadline() not sure this works")
+	return c.conn.SetDeadline(t)
+}
+
+func (c *Conn) SetReadDeadline(t time.Time) error {
+	log.Println("WARNING: SetReadDeadline() not sure this works")
+	return c.conn.SetReadDeadline(t)
+}
+func (c *Conn) SetWriteDeadline(t time.Time) error {
+	log.Println("WARNING: SetWriteDeadline() not sure this works")
+	return c.conn.SetWriteDeadline(t)
+}
diff --git a/vendor/github.com/eyedeekay/goSam/dial.go b/vendor/github.com/eyedeekay/goSam/dial.go
new file mode 100644
index 00000000..2e11829a
--- /dev/null
+++ b/vendor/github.com/eyedeekay/goSam/dial.go
@@ -0,0 +1,73 @@
+package goSam
+
+import (
+	"context"
+	"fmt"
+	"net"
+	"strings"
+)
+
+// DialContext implements the net.DialContext function and can be used for http.Transport
+func (c *Client) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
+	errCh := make(chan error, 1)
+	connCh := make(chan net.Conn, 1)
+	go func() {
+		if conn, err := c.Dial(network, addr); err != nil {
+			errCh <- err
+		} else if ctx.Err() != nil {
+			conn.Close()
+		} else {
+			connCh <- conn
+		}
+	}()
+	select {
+	case err := <-errCh:
+		return nil, err
+	case conn := <-connCh:
+		return conn, nil
+	case <-ctx.Done():
+		return nil, ctx.Err()
+	}
+}
+
+func (c Client) dialCheck(addr string) (int32, bool) {
+	if c.lastaddr == "invalid" {
+		fmt.Println("Preparing to dial new address.")
+		return c.NewID(), true
+	} else if c.lastaddr != addr {
+		fmt.Println("Preparing to dial next new address.")
+		return c.NewID(), true
+	}
+	return c.id, false
+}
+
+// Dial implements the net.Dial function and can be used for http.Transport
+func (c *Client) Dial(network, addr string) (net.Conn, error) {
+	portIdx := strings.Index(addr, ":")
+	if portIdx >= 0 {
+		addr = addr[:portIdx]
+	}
+	addr, err := c.Lookup(addr)
+	if err != nil {
+		return nil, err
+	}
+
+	var test bool
+	if c.id, test = c.dialCheck(addr); test == true {
+		c.destination, err = c.CreateStreamSession(c.id, c.destination)
+		if err != nil {
+			return nil, err
+		}
+		c.lastaddr = addr
+	}
+	c, err = c.NewClient()
+	if err != nil {
+		return nil, err
+	}
+
+	err = c.StreamConnect(c.id, addr)
+	if err != nil {
+		return nil, err
+	}
+	return c.SamConn, nil
+}
diff --git a/vendor/github.com/eyedeekay/goSam/go.mod b/vendor/github.com/eyedeekay/goSam/go.mod
new file mode 100644
index 00000000..159bc0aa
--- /dev/null
+++ b/vendor/github.com/eyedeekay/goSam/go.mod
@@ -0,0 +1,11 @@
+module github.com/eyedeekay/goSam
+
+require github.com/eyedeekay/sam3 v0.32.2
+
+//replace github.com/eyedeekay/gosam v0.1.1-0.20190814195658-27e786578944 => github.com/eyedeekay/goSam ./
+
+replace github.com/eyedeekay/gosam v0.32.1 => ./
+
+replace github.com/eyedeekay/goSam v0.32.1 => ./
+
+go 1.13
diff --git a/vendor/github.com/eyedeekay/goSam/go.sum b/vendor/github.com/eyedeekay/goSam/go.sum
new file mode 100644
index 00000000..6f9cf05b
--- /dev/null
+++ b/vendor/github.com/eyedeekay/goSam/go.sum
@@ -0,0 +1,3 @@
+github.com/eyedeekay/ramp v0.0.0-20190429201811-305b382042ab/go.mod h1:h7mvUAMgZ/rtRDUOkvKTK+8LnDMeUhJSoa5EPdB51fc=
+github.com/eyedeekay/sam3 v0.32.2 h1:xODDY5nBVg0oK7KaYk7ofkXFoHPsmI1umhSv1TZlS7s=
+github.com/eyedeekay/sam3 v0.32.2/go.mod h1:Y3igFVzN4ybqkkpfUWULGhw7WRp8lieq0ORXbLBbcZM=
diff --git a/vendor/github.com/eyedeekay/goSam/naming.go b/vendor/github.com/eyedeekay/goSam/naming.go
new file mode 100644
index 00000000..b47f7908
--- /dev/null
+++ b/vendor/github.com/eyedeekay/goSam/naming.go
@@ -0,0 +1,34 @@
+package goSam
+
+import (
+	"fmt"
+	"os"
+)
+
+// Lookup askes SAM for the internal i2p address from name
+func (c *Client) Lookup(name string) (string, error) {
+	r, err := c.sendCmd("NAMING LOOKUP NAME=%s\n", name)
+	if err != nil {
+		return "", nil
+	}
+
+	// TODO: move check into sendCmd()
+	if r.Topic != "NAMING" || r.Type != "REPLY" {
+		return "", fmt.Errorf("Unknown Reply: %+v\n", r)
+	}
+
+	result := r.Pairs["RESULT"]
+	if result != "OK" {
+		return "", ReplyError{result, r}
+	}
+
+	if r.Pairs["NAME"] != name {
+		// somehow different on i2pd
+		if r.Pairs["NAME"] != "ME" {
+			return "", fmt.Errorf("Lookup() Replyed to another name.\nWanted:%s\nGot: %+v\n", name, r)
+		}
+		fmt.Fprintln(os.Stderr, "WARNING: Lookup() Replyed to another name. assuming i2pd c++ fluke")
+	}
+
+	return r.Pairs["VALUE"], nil
+}
diff --git a/vendor/github.com/eyedeekay/goSam/options.go b/vendor/github.com/eyedeekay/goSam/options.go
new file mode 100644
index 00000000..ba2af83e
--- /dev/null
+++ b/vendor/github.com/eyedeekay/goSam/options.go
@@ -0,0 +1,507 @@
+package goSam
+
+import (
+	"fmt"
+	"strconv"
+	"strings"
+)
+
+//Option is a client Option
+type Option func(*Client) error
+
+//SetAddr sets a clients's address in the form host:port or host, port
+func SetAddr(s ...string) func(*Client) error {
+	return func(c *Client) error {
+		if len(s) == 1 {
+			split := strings.SplitN(s[0], ":", 2)
+			if len(split) == 2 {
+				if i, err := strconv.Atoi(split[1]); err == nil {
+					if i < 65536 {
+						c.host = split[0]
+						c.port = split[1]
+						return nil
+					}
+					return fmt.Errorf("Invalid port")
+				}
+				return fmt.Errorf("Invalid port; non-number")
+			}
+			return fmt.Errorf("Invalid address; use host:port %s", split)
+		} else if len(s) == 2 {
+			if i, err := strconv.Atoi(s[1]); err == nil {
+				if i < 65536 {
+					c.host = s[0]
+					c.port = s[1]
+					return nil
+				}
+				return fmt.Errorf("Invalid port")
+			}
+			return fmt.Errorf("Invalid port; non-number")
+		} else {
+			return fmt.Errorf("Invalid address")
+		}
+	}
+}
+
+//SetAddrMixed sets a clients's address in the form host, port(int)
+func SetAddrMixed(s string, i int) func(*Client) error {
+	return func(c *Client) error {
+		if i < 65536 && i > 0 {
+			c.host = s
+			c.port = strconv.Itoa(i)
+			return nil
+		}
+		return fmt.Errorf("Invalid port")
+	}
+}
+
+//SetHost sets the host of the client's SAM bridge
+func SetHost(s string) func(*Client) error {
+	return func(c *Client) error {
+		c.host = s
+		return nil
+	}
+}
+
+//SetLocalDestination sets the local destination of the tunnel from a private
+//key
+func SetLocalDestination(s string) func(*Client) error {
+	return func(c *Client) error {
+		c.destination = s
+		return nil
+	}
+}
+
+func setlastaddr(s string) func(*Client) error {
+	return func(c *Client) error {
+		c.lastaddr = s
+		return nil
+	}
+}
+
+func setid(s int32) func(*Client) error {
+	return func(c *Client) error {
+		c.id = s
+		return nil
+	}
+}
+
+//SetPort sets the port of the client's SAM bridge using a string
+func SetPort(s string) func(*Client) error {
+	return func(c *Client) error {
+		port, err := strconv.Atoi(s)
+		if err != nil {
+			return fmt.Errorf("Invalid port; non-number")
+		}
+		if port < 65536 && port > -1 {
+			c.port = s
+			return nil
+		}
+		return fmt.Errorf("Invalid port")
+	}
+}
+
+//SetPortInt sets the port of the client's SAM bridge using a string
+func SetPortInt(i int) func(*Client) error {
+	return func(c *Client) error {
+		if i < 65536 && i > -1 {
+			c.port = strconv.Itoa(i)
+			return nil
+		}
+		return fmt.Errorf("Invalid port")
+	}
+}
+
+//SetFromPort sets the port of the client's SAM bridge using a string
+func SetFromPort(s string) func(*Client) error {
+	return func(c *Client) error {
+		port, err := strconv.Atoi(s)
+		if err != nil {
+			return fmt.Errorf("Invalid port; non-number")
+		}
+		if port < 65536 && port > -1 {
+			c.fromport = s
+			return nil
+		}
+		return fmt.Errorf("Invalid port")
+	}
+}
+
+//SetFromPortInt sets the port of the client's SAM bridge using a string
+func SetFromPortInt(i int) func(*Client) error {
+	return func(c *Client) error {
+		if i < 65536 && i > -1 {
+			c.fromport = strconv.Itoa(i)
+			return nil
+		}
+		return fmt.Errorf("Invalid port")
+	}
+}
+
+//SetToPort sets the port of the client's SAM bridge using a string
+func SetToPort(s string) func(*Client) error {
+	return func(c *Client) error {
+		port, err := strconv.Atoi(s)
+		if err != nil {
+			return fmt.Errorf("Invalid port; non-number")
+		}
+		if port < 65536 && port > -1 {
+			c.toport = s
+			return nil
+		}
+		return fmt.Errorf("Invalid port")
+	}
+}
+
+//SetToPortInt sets the port of the client's SAM bridge using a string
+func SetToPortInt(i int) func(*Client) error {
+	return func(c *Client) error {
+		if i < 65536 && i > -1 {
+			c.fromport = strconv.Itoa(i)
+			return nil
+		}
+		return fmt.Errorf("Invalid port")
+	}
+}
+
+//SetDebug enables debugging messages
+func SetDebug(b bool) func(*Client) error {
+	return func(c *Client) error {
+		c.debug = b
+		return nil
+	}
+}
+
+//SetInLength sets the number of hops inbound
+func SetInLength(u uint) func(*Client) error {
+	return func(c *Client) error {
+		if u < 7 {
+			c.inLength = u
+			return nil
+		}
+		return fmt.Errorf("Invalid inbound tunnel length")
+	}
+}
+
+//SetOutLength sets the number of hops outbound
+func SetOutLength(u uint) func(*Client) error {
+	return func(c *Client) error {
+		if u < 7 {
+			c.outLength = u
+			return nil
+		}
+		return fmt.Errorf("Invalid outbound tunnel length")
+	}
+}
+
+//SetInVariance sets the variance of a number of hops inbound
+func SetInVariance(i int) func(*Client) error {
+	return func(c *Client) error {
+		if i < 7 && i > -7 {
+			c.inVariance = i
+			return nil
+		}
+		return fmt.Errorf("Invalid inbound tunnel length")
+	}
+}
+
+//SetOutVariance sets the variance of a number of hops outbound
+func SetOutVariance(i int) func(*Client) error {
+	return func(c *Client) error {
+		if i < 7 && i > -7 {
+			c.outVariance = i
+			return nil
+		}
+		return fmt.Errorf("Invalid outbound tunnel variance")
+	}
+}
+
+//SetInQuantity sets the inbound tunnel quantity
+func SetInQuantity(u uint) func(*Client) error {
+	return func(c *Client) error {
+		if u <= 16 {
+			c.inQuantity = u
+			return nil
+		}
+		return fmt.Errorf("Invalid inbound tunnel quantity")
+	}
+}
+
+//SetOutQuantity sets the outbound tunnel quantity
+func SetOutQuantity(u uint) func(*Client) error {
+	return func(c *Client) error {
+		if u <= 16 {
+			c.outQuantity = u
+			return nil
+		}
+		return fmt.Errorf("Invalid outbound tunnel quantity")
+	}
+}
+
+//SetInBackups sets the inbound tunnel backups
+func SetInBackups(u uint) func(*Client) error {
+	return func(c *Client) error {
+		if u < 6 {
+			c.inBackups = u
+			return nil
+		}
+		return fmt.Errorf("Invalid inbound tunnel backup quantity")
+	}
+}
+
+//SetOutBackups sets the inbound tunnel backups
+func SetOutBackups(u uint) func(*Client) error {
+	return func(c *Client) error {
+		if u < 6 {
+			c.outBackups = u
+			return nil
+		}
+		return fmt.Errorf("Invalid outbound tunnel backup quantity")
+	}
+}
+
+//SetUnpublished tells the router to not publish the client leaseset
+func SetUnpublished(b bool) func(*Client) error {
+	return func(c *Client) error {
+		c.dontPublishLease = b
+		return nil
+	}
+}
+
+//SetEncrypt tells the router to use an encrypted leaseset
+func SetEncrypt(b bool) func(*Client) error {
+	return func(c *Client) error {
+		c.encryptLease = b
+		return nil
+	}
+}
+
+//SetReduceIdle sets the created tunnels to be reduced during extended idle time to avoid excessive resource usage
+func SetReduceIdle(b bool) func(*Client) error {
+	return func(c *Client) error {
+		c.reduceIdle = b
+		return nil
+	}
+}
+
+//SetReduceIdleTime sets time to wait before the tunnel quantity is reduced
+func SetReduceIdleTime(u uint) func(*Client) error {
+	return func(c *Client) error {
+		if u > 299999 {
+			c.reduceIdleTime = u
+			return nil
+		}
+		return fmt.Errorf("Invalid reduce idle time %v", u)
+	}
+}
+
+//SetReduceIdleQuantity sets number of tunnels to keep alive during an extended idle period
+func SetReduceIdleQuantity(u uint) func(*Client) error {
+	return func(c *Client) error {
+		if u < 5 {
+			c.reduceIdleQuantity = u
+			return nil
+		}
+		return fmt.Errorf("Invalid reduced tunnel quantity %v", u)
+	}
+}
+
+//SetCloseIdle sets the tunnels to close after a specific amount of time
+func SetCloseIdle(b bool) func(*Client) error {
+	return func(c *Client) error {
+		c.closeIdle = b
+		return nil
+	}
+}
+
+//SetCloseIdleTime sets the time in milliseconds to wait before closing tunnels
+func SetCloseIdleTime(u uint) func(*Client) error {
+	return func(c *Client) error {
+		if u > 299999 {
+			c.closeIdleTime = u
+			return nil
+		}
+		return fmt.Errorf("Invalid close idle time %v", u)
+	}
+}
+
+//SetCompression sets the tunnels to close after a specific amount of time
+func SetCompression(b bool) func(*Client) error {
+	return func(c *Client) error {
+		c.compression = b
+		return nil
+	}
+}
+
+/* SAM v 3.1 Options*/
+
+//SetSignatureType tells gosam to pass SAM a signature_type parameter with one
+// of the following values:
+//    "SIGNATURE_TYPE=DSA_SHA1",
+//    "SIGNATURE_TYPE=ECDSA_SHA256_P256",
+//    "SIGNATURE_TYPE=ECDSA_SHA384_P384",
+//    "SIGNATURE_TYPE=ECDSA_SHA512_P521",
+//    "SIGNATURE_TYPE=EdDSA_SHA512_Ed25519",
+// or an empty string
+func SetSignatureType(s string) func(*Client) error {
+	return func(c *Client) error {
+		if s == "" {
+			c.sigType = ""
+			return nil
+		}
+		for _, valid := range SAMsigTypes {
+			if s == valid {
+				c.sigType = valid
+				return nil
+			}
+		}
+		return fmt.Errorf("Invalid signature type specified at construction time")
+	}
+}
+
+//return the from port as a string.
+func (c *Client) from() string {
+	if c.fromport == "" {
+		return ""
+	}
+	return fmt.Sprintf(" FROM_PORT=%v ", c.fromport)
+}
+
+//return the to port as a string.
+func (c *Client) to() string {
+	if c.toport == "" {
+		return ""
+	}
+	return fmt.Sprintf(" TO_PORT=%v ", c.toport)
+}
+
+//return the signature type as a string.
+func (c *Client) sigtype() string {
+	return fmt.Sprintf(" %s ", c.sigType)
+}
+
+//return the inbound length as a string.
+func (c *Client) inlength() string {
+	return fmt.Sprintf(" inbound.length=%d ", c.inLength)
+}
+
+//return the outbound length as a string.
+func (c *Client) outlength() string {
+	return fmt.Sprintf(" outbound.length=%d ", c.outLength)
+}
+
+//return the inbound length variance as a string.
+func (c *Client) invariance() string {
+	return fmt.Sprintf(" inbound.lengthVariance=%d ", c.inVariance)
+}
+
+//return the outbound length variance as a string.
+func (c *Client) outvariance() string {
+	return fmt.Sprintf(" outbound.lengthVariance=%d ", c.outVariance)
+}
+
+//return the inbound tunnel quantity as a string.
+func (c *Client) inquantity() string {
+	return fmt.Sprintf(" inbound.quantity=%d ", c.inQuantity)
+}
+
+//return the outbound tunnel quantity as a string.
+func (c *Client) outquantity() string {
+	return fmt.Sprintf(" outbound.quantity=%d ", c.outQuantity)
+}
+
+//return the inbound tunnel quantity as a string.
+func (c *Client) inbackups() string {
+	return fmt.Sprintf(" inbound.backupQuantity=%d ", c.inQuantity)
+}
+
+//return the outbound tunnel quantity as a string.
+func (c *Client) outbackups() string {
+	return fmt.Sprintf(" outbound.backupQuantity=%d ", c.outQuantity)
+}
+
+func (c *Client) encryptlease() string {
+	if c.encryptLease {
+		return " i2cp.encryptLeaseSet=true "
+	}
+	return " i2cp.encryptLeaseSet=false "
+}
+
+func (c *Client) dontpublishlease() string {
+	if c.dontPublishLease {
+		return " i2cp.dontPublishLeaseSet=true "
+	}
+	return " i2cp.dontPublishLeaseSet=false "
+}
+
+func (c *Client) closeonidle() string {
+	if c.closeIdle {
+		return " i2cp.closeOnIdle=true "
+	}
+	return " i2cp.closeOnIdle=false "
+}
+
+func (c *Client) closeidletime() string {
+	return fmt.Sprintf(" i2cp.closeIdleTime=%d ", c.closeIdleTime)
+}
+
+func (c *Client) reduceonidle() string {
+	if c.reduceIdle {
+		return " i2cp.reduceOnIdle=true "
+	}
+	return " i2cp.reduceOnIdle=false "
+}
+
+func (c *Client) reduceidletime() string {
+	return fmt.Sprintf(" i2cp.reduceIdleTime=%d ", c.reduceIdleTime)
+}
+
+func (c *Client) reduceidlecount() string {
+	return fmt.Sprintf(" i2cp.reduceIdleQuantity=%d ", c.reduceIdleQuantity)
+}
+
+func (c *Client) compresion() string {
+	if c.compression {
+		return " i2cp.gzip=true "
+	}
+	return " i2cp.gzip=false "
+}
+
+//return all options as string ready for passing to sendcmd
+func (c *Client) allOptions() string {
+	return c.inlength() +
+		c.outlength() +
+		c.invariance() +
+		c.outvariance() +
+		c.inquantity() +
+		c.outquantity() +
+		c.inbackups() +
+		c.outbackups() +
+		c.dontpublishlease() +
+		c.encryptlease() +
+		c.reduceonidle() +
+		c.reduceidletime() +
+		c.reduceidlecount() +
+		c.closeonidle() +
+		c.closeidletime() +
+		c.compresion()
+}
+
+//Print return all options as string
+func (c *Client) Print() string {
+	return c.inlength() +
+		c.outlength() +
+		c.invariance() +
+		c.outvariance() +
+		c.inquantity() +
+		c.outquantity() +
+		c.inbackups() +
+		c.outbackups() +
+		c.dontpublishlease() +
+		c.encryptlease() +
+		c.reduceonidle() +
+		c.reduceidletime() +
+		c.reduceidlecount() +
+		c.closeonidle() +
+		c.closeidletime() +
+		c.compresion()
+}
diff --git a/vendor/github.com/eyedeekay/goSam/replyParser.go b/vendor/github.com/eyedeekay/goSam/replyParser.go
new file mode 100644
index 00000000..70afc9a6
--- /dev/null
+++ b/vendor/github.com/eyedeekay/goSam/replyParser.go
@@ -0,0 +1,64 @@
+package goSam
+
+import (
+	"fmt"
+	"strings"
+)
+
+// The Possible Results send by SAM
+const (
+	ResultOk             = "OK"              //Operation completed successfully
+	ResultCantReachPeer  = "CANT_REACH_PEER" //The peer exists, but cannot be reached
+	ResultDuplicatedID   = "DUPLICATED_ID"   //If the nickname is already associated with a session :
+	ResultDuplicatedDest = "DUPLICATED_DEST" //The specified Destination is already in use
+	ResultI2PError       = "I2P_ERROR"       //A generic I2P error (e.g. I2CP disconnection, etc.)
+	ResultInvalidKey     = "INVALID_KEY"     //The specified key is not valid (bad format, etc.)
+	ResultKeyNotFound    = "KEY_NOT_FOUND"   //The naming system can't resolve the given name
+	ResultPeerNotFound   = "PEER_NOT_FOUND"  //The peer cannot be found on the network
+	ResultTimeout        = "TIMEOUT"         // Timeout while waiting for an event (e.g. peer answer)
+)
+
+// A ReplyError is a custom error type, containing the Result and full Reply
+type ReplyError struct {
+	Result string
+	Reply  *Reply
+}
+
+func (r ReplyError) Error() string {
+	return fmt.Sprintf("ReplyError: Result:%s - Reply:%+v", r.Result, r.Reply)
+}
+
+// Reply is the parsed result of a SAM command, containing a map of all the key-value pairs
+type Reply struct {
+	Topic string
+	Type  string
+
+	Pairs map[string]string
+}
+
+func parseReply(line string) (*Reply, error) {
+	line = strings.TrimSpace(line)
+	parts := strings.Split(line, " ")
+	if len(parts) < 3 {
+		return nil, fmt.Errorf("Malformed Reply.\n%s\n", line)
+	}
+
+	r := &Reply{
+		Topic: parts[0],
+		Type:  parts[1],
+		Pairs: make(map[string]string, len(parts)-2),
+	}
+
+	for _, v := range parts[2:] {
+		kvPair := strings.SplitN(v, "=", 2)
+		if kvPair != nil {
+			if len(kvPair) != 2 {
+				return nil, fmt.Errorf("Malformed key-value-pair.\n%s\n", kvPair)
+			}
+		}
+
+		r.Pairs[kvPair[0]] = kvPair[len(kvPair)-1]
+	}
+
+	return r, nil
+}
diff --git a/vendor/github.com/eyedeekay/goSam/rw.go b/vendor/github.com/eyedeekay/goSam/rw.go
new file mode 100644
index 00000000..18d54609
--- /dev/null
+++ b/vendor/github.com/eyedeekay/goSam/rw.go
@@ -0,0 +1,101 @@
+/*
+The MIT License (MIT)
+
+Copyright (c) 2014 Henry
+
+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.
+*/
+
+package goSam
+
+import (
+	"encoding/hex"
+	"io"
+	"log"
+)
+
+/*
+Copy of testing/iotest Read- and WriteLogger, but using %q instead of %x for printing
+*/
+
+type writeLogger struct {
+	prefix string
+	w      io.Writer
+}
+
+func (l *writeLogger) Write(p []byte) (n int, err error) {
+	n, err = l.w.Write(p)
+	if err != nil {
+		log.Printf("%s %q: %v", l.prefix, string(p[0:n]), err)
+	} else {
+		log.Printf("%s %q", l.prefix, string(p[0:n]))
+	}
+	return
+}
+
+// NewWriteLogger returns a writer that behaves like w except
+// that it logs (using log.Printf) each write to standard error,
+// printing the prefix and the hexadecimal data written.
+func NewWriteLogger(prefix string, w io.Writer) io.Writer {
+	return &writeLogger{prefix, w}
+}
+
+type readLogger struct {
+	prefix string
+	r      io.Reader
+}
+
+func (l *readLogger) Read(p []byte) (n int, err error) {
+	n, err = l.r.Read(p)
+	if err != nil {
+		log.Printf("%s %q: %v", l.prefix, string(p[0:n]), err)
+	} else {
+		log.Printf("%s %q", l.prefix, string(p[0:n]))
+	}
+	return
+}
+
+// NewReadLogger returns a reader that behaves like r except
+// that it logs (using log.Print) each read to standard error,
+// printing the prefix and the hexadecimal data written.
+func NewReadLogger(prefix string, r io.Reader) io.Reader {
+	return &readLogger{prefix, r}
+}
+
+type readHexLogger struct {
+	prefix string
+	r      io.Reader
+}
+
+func (l *readHexLogger) Read(p []byte) (n int, err error) {
+	n, err = l.r.Read(p)
+	if err != nil {
+		log.Printf("%s (%d bytes) Error: %v", l.prefix, n, err)
+	} else {
+		log.Printf("%s (%d bytes)", l.prefix, n)
+	}
+	log.Print("\n" + hex.Dump(p[:n]))
+	return
+}
+
+// NewReadHexLogger returns a reader that behaves like r except
+// that it logs to stderr using ecoding/hex.
+func NewReadHexLogger(prefix string, r io.Reader) io.Reader {
+	return &readHexLogger{prefix, r}
+}
diff --git a/vendor/github.com/eyedeekay/goSam/rwc.go b/vendor/github.com/eyedeekay/goSam/rwc.go
new file mode 100644
index 00000000..4327a0db
--- /dev/null
+++ b/vendor/github.com/eyedeekay/goSam/rwc.go
@@ -0,0 +1,80 @@
+/*
+The MIT License (MIT)
+
+Copyright (c) 2014 Henry
+
+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.
+*/
+
+package goSam
+
+import (
+	"io"
+	//"github.com/miolini/datacounter"
+)
+
+type RWC struct {
+	io.Reader
+	io.Writer
+	c io.Closer
+}
+
+func WrapRWC(c io.ReadWriteCloser) io.ReadWriteCloser {
+	rl := NewReadLogger("<", c)
+	wl := NewWriteLogger(">", c)
+
+	return &RWC{
+		Reader: rl,
+		Writer: wl,
+		c:      c,
+	}
+}
+
+func (c *RWC) Close() error {
+	return c.c.Close()
+}
+
+/*
+type Counter struct {
+	io.Reader
+	io.Writer
+	c io.Closer
+
+	Cr *datacounter.ReaderCounter
+	Cw *datacounter.WriterCounter
+}
+
+func WrapCounter(c io.ReadWriteCloser) *Counter {
+	rc := datacounter.NewReaderCounter(c)
+	wc := datacounter.NewWriterCounter(c)
+
+	return &Counter{
+		Reader: rc,
+		Writer: wc,
+		c:      c,
+
+		Cr: rc,
+		Cw: wc,
+	}
+}
+
+func (c *Counter) Close() error {
+	return c.c.Close()
+}
+*/
diff --git a/vendor/github.com/eyedeekay/goSam/sessions.go b/vendor/github.com/eyedeekay/goSam/sessions.go
new file mode 100644
index 00000000..f5aece4c
--- /dev/null
+++ b/vendor/github.com/eyedeekay/goSam/sessions.go
@@ -0,0 +1,45 @@
+package goSam
+
+import (
+	"fmt"
+	//	"math"
+	"math/rand"
+	"time"
+)
+
+func init() {
+	rand.Seed(time.Now().UnixNano())
+}
+
+// CreateStreamSession creates a new STREAM Session.
+// Returns the Id for the new Client.
+func (c *Client) CreateStreamSession(id int32, dest string) (string, error) {
+	if dest == "" {
+		dest = "TRANSIENT"
+	}
+	c.id = id
+	r, err := c.sendCmd(
+		"SESSION CREATE STYLE=STREAM ID=%d %s %s DESTINATION=%s %s %s\n",
+		c.id,
+		c.from(),
+		c.to(),
+		dest,
+		c.sigtype(),
+		c.allOptions(),
+	)
+	if err != nil {
+		return "", err
+	}
+
+	// TODO: move check into sendCmd()
+	if r.Topic != "SESSION" || r.Type != "STATUS" {
+		return "", fmt.Errorf("Unknown Reply: %+v\n", r)
+	}
+
+	result := r.Pairs["RESULT"]
+	if result != "OK" {
+		return "", ReplyError{ResultKeyNotFound, r}
+	}
+	c.destination = r.Pairs["DESTINATION"]
+	return c.destination, nil
+}
diff --git a/vendor/github.com/eyedeekay/goSam/stream.go b/vendor/github.com/eyedeekay/goSam/stream.go
new file mode 100644
index 00000000..3663a825
--- /dev/null
+++ b/vendor/github.com/eyedeekay/goSam/stream.go
@@ -0,0 +1,45 @@
+package goSam
+
+import (
+	"fmt"
+)
+
+// StreamConnect asks SAM for a TCP-Like connection to dest, has to be called on a new Client
+func (c *Client) StreamConnect(id int32, dest string) error {
+	r, err := c.sendCmd("STREAM CONNECT ID=%d %s %s DESTINATION=%s\n", id, c.from(), c.to(), dest)
+	if err != nil {
+		return err
+	}
+
+	// TODO: move check into sendCmd()
+	if r.Topic != "STREAM" || r.Type != "STATUS" {
+		return fmt.Errorf("Unknown Reply: %+v\n", r)
+	}
+
+	result := r.Pairs["RESULT"]
+	if result != "OK" {
+		return ReplyError{result, r}
+	}
+
+	return nil
+}
+
+// StreamAccept asks SAM to accept a TCP-Like connection
+func (c *Client) StreamAccept(id int32) (*Reply, error) {
+	r, err := c.sendCmd("STREAM ACCEPT ID=%d SILENT=false\n", id)
+	if err != nil {
+		return nil, err
+	}
+
+	// TODO: move check into sendCmd()
+	if r.Topic != "STREAM" || r.Type != "STATUS" {
+		return nil, fmt.Errorf("Unknown Reply: %+v\n", r)
+	}
+
+	result := r.Pairs["RESULT"]
+	if result != "OK" {
+		return nil, ReplyError{result, r}
+	}
+
+	return r, nil
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index c76e9208..6f9a5737 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -84,8 +84,6 @@ github.com/dsnet/compress/internal/errors
 # github.com/eyedeekay/goSam v0.32.22
 ## explicit
 github.com/eyedeekay/goSam
-# github.com/eyedeekay/sam3 v0.32.3
-## explicit
 # github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51
 ## explicit
 # github.com/facebookgo/stack v0.0.0-20160209184415-751773369052