Compare commits
31 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
86009cc805 | ||
![]() |
1fc3dc5a20 | ||
![]() |
a2fcfb8bc1 | ||
![]() |
0623ed8a79 | ||
![]() |
964219c25f | ||
![]() |
23c45022b3 | ||
![]() |
c6d9c0e340 | ||
![]() |
460926afe8 | ||
![]() |
e278de3a66 | ||
![]() |
d1d2663c42 | ||
![]() |
5af3086205 | ||
![]() |
f97683379f | ||
![]() |
42d542dd8b | ||
![]() |
d94d9c4da0 | ||
![]() |
dddd8ea916 | ||
![]() |
b864407cc2 | ||
![]() |
646767e7bf | ||
![]() |
76e1e9af83 | ||
![]() |
6bd37c4d51 | ||
![]() |
e2f73efb10 | ||
![]() |
5fda56e88d | ||
![]() |
63833f24ab | ||
![]() |
0d10b5b516 | ||
![]() |
38ca0d08e7 | ||
![]() |
a9bf9faba1 | ||
![]() |
3c6a72d179 | ||
![]() |
e8b7525950 | ||
![]() |
a0407fd3e3 | ||
![]() |
3c5397e87f | ||
![]() |
9baee36493 | ||
![]() |
379de14264 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -23,3 +23,4 @@ _testmain.go
|
|||||||
itp-golang-github-eyedeekay-gosam.txt
|
itp-golang-github-eyedeekay-gosam.txt
|
||||||
.pc
|
.pc
|
||||||
deb/
|
deb/
|
||||||
|
samsocks/samsocks
|
||||||
|
2
Makefile
2
Makefile
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
USER_GH=eyedeekay
|
USER_GH=eyedeekay
|
||||||
VERSION=0.32.28
|
VERSION=0.32.53
|
||||||
packagename=gosam
|
packagename=gosam
|
||||||
|
|
||||||
echo: fmt
|
echo: fmt
|
||||||
|
54
README.md
54
README.md
@@ -3,10 +3,10 @@ goSam
|
|||||||
|
|
||||||
A go library for using the [I2P](https://geti2p.net/en/) Simple Anonymous
|
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
|
Messaging ([SAM version 3.0](https://geti2p.net/en/docs/api/samv3)) bridge. It
|
||||||
has support for SAM version 3.1 signature types.
|
has support for all streaming features SAM version 3.2.
|
||||||
|
|
||||||
This is in an **early development stage**. I would love to hear about any
|
This is widely used and easy to use, but thusfar, mostly by me. It sees a lot of
|
||||||
issues or ideas for improvement.
|
testing and no breaking changes to the API are expected.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
```
|
```
|
||||||
@@ -15,7 +15,7 @@ go get github.com/eyedeekay/goSam
|
|||||||
|
|
||||||
## Using it for HTTP Transport
|
## Using it for HTTP Transport
|
||||||
|
|
||||||
I implemented `Client.Dial` like `net.Dial` so you can use go's library packages like http.
|
`Client.Dial` implements `net.Dial` so you can use go's library packages like http.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -70,6 +70,52 @@ func checkErr(err error) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Using it as a SOCKS proxy
|
||||||
|
|
||||||
|
`client` also implements a resolver compatible with
|
||||||
|
[`getlantern/go-socks5`](https://github.com/getlantern/go-socks5),
|
||||||
|
making it very easy to implement a SOCKS5 server.
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
|
||||||
|
"github.com/eyedeekay/goSam"
|
||||||
|
"github.com/getlantern/go-socks5"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
samaddr = flag.String("sam", "127.0.0.1:7656", "SAM API address to use")
|
||||||
|
socksaddr = flag.String("socks", "127.0.0.1:7675", "SOCKS address to use")
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
sam, err := goSam.NewClient(*samaddr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
log.Println("Client Created")
|
||||||
|
|
||||||
|
// create a transport that uses SAM to dial TCP Connections
|
||||||
|
conf := &socks5.Config{
|
||||||
|
Dial: sam.DialContext,
|
||||||
|
Resolver: sam,
|
||||||
|
}
|
||||||
|
server, err := socks5.New(conf)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create SOCKS5 proxy on localhost port 8000
|
||||||
|
if err := server.ListenAndServe("tcp", *socksaddr); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### .deb package
|
### .deb package
|
||||||
|
|
||||||
A package for installing this on Debian is buildable, and a version for Ubuntu
|
A package for installing this on Debian is buildable, and a version for Ubuntu
|
||||||
|
@@ -24,15 +24,14 @@ func (c *Client) Listen() (net.Listener, error) {
|
|||||||
// with Accept
|
// with Accept
|
||||||
func (c *Client) ListenI2P(dest string) (net.Listener, error) {
|
func (c *Client) ListenI2P(dest string) (net.Listener, error) {
|
||||||
var err error
|
var err error
|
||||||
c.id = c.NewID()
|
c.destination, err = c.CreateStreamSession(dest)
|
||||||
c.destination, err = c.CreateStreamSession(c.id, dest)
|
|
||||||
d := c.destination
|
d := c.destination
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
fmt.Println("Listening on destination:", c.Base32()+".b32.i2p")
|
fmt.Println("Listening on destination:", c.Base32()+".b32.i2p")
|
||||||
|
|
||||||
c, err = c.NewClient()
|
c, err = c.NewClient(c.id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -52,7 +51,7 @@ func (c *Client) Accept() (net.Conn, error) {
|
|||||||
if c.id == 0 {
|
if c.id == 0 {
|
||||||
return c.AcceptI2P()
|
return c.AcceptI2P()
|
||||||
}
|
}
|
||||||
resp, err := c.StreamAccept(c.id)
|
resp, err := c.StreamAccept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
71
client.go
71
client.go
@@ -12,6 +12,9 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
samkeys "github.com/eyedeekay/goSam/compat"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A Client represents a single Connection to the SAM bridge
|
// A Client represents a single Connection to the SAM bridge
|
||||||
@@ -21,8 +24,10 @@ type Client struct {
|
|||||||
fromport string
|
fromport string
|
||||||
toport string
|
toport string
|
||||||
|
|
||||||
SamConn net.Conn
|
SamConn net.Conn // Control socket
|
||||||
rd *bufio.Reader
|
SamDGConn DatagramConn // Datagram socket
|
||||||
|
rd *bufio.Reader
|
||||||
|
// d *Client
|
||||||
|
|
||||||
sigType string
|
sigType string
|
||||||
destination string
|
destination string
|
||||||
@@ -51,12 +56,14 @@ type Client struct {
|
|||||||
compression bool
|
compression bool
|
||||||
|
|
||||||
debug bool
|
debug bool
|
||||||
|
mutex sync.Mutex
|
||||||
//NEVER, EVER modify lastaddr or id yourself. They are used internally only.
|
//NEVER, EVER modify lastaddr or id yourself. They are used internally only.
|
||||||
lastaddr string
|
id int32
|
||||||
id int32
|
sammin int
|
||||||
ml sync.Mutex
|
sammax int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SAMsigTypes is a slice of the available signature types
|
||||||
var SAMsigTypes = []string{
|
var SAMsigTypes = []string{
|
||||||
"SIGNATURE_TYPE=DSA_SHA1",
|
"SIGNATURE_TYPE=DSA_SHA1",
|
||||||
"SIGNATURE_TYPE=ECDSA_SHA256_P256",
|
"SIGNATURE_TYPE=ECDSA_SHA256_P256",
|
||||||
@@ -65,6 +72,12 @@ var SAMsigTypes = []string{
|
|||||||
"SIGNATURE_TYPE=EdDSA_SHA512_Ed25519",
|
"SIGNATURE_TYPE=EdDSA_SHA512_Ed25519",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ValidSAMCommands = []string{
|
||||||
|
"HELLO",
|
||||||
|
"SESSION",
|
||||||
|
"STREAM",
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
i2pB64enc *base64.Encoding = base64.NewEncoding("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-~")
|
i2pB64enc *base64.Encoding = base64.NewEncoding("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-~")
|
||||||
i2pB32enc *base32.Encoding = base32.NewEncoding("abcdefghijklmnopqrstuvwxyz234567")
|
i2pB32enc *base32.Encoding = base32.NewEncoding("abcdefghijklmnopqrstuvwxyz234567")
|
||||||
@@ -80,9 +93,18 @@ func NewClient(addr string) (*Client, error) {
|
|||||||
return NewClientFromOptions(SetAddr(addr))
|
return NewClientFromOptions(SetAddr(addr))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewID() int32 {
|
||||||
|
id := rand.Int31n(math.MaxInt32)
|
||||||
|
fmt.Printf("Initializing new ID: %d\n", id)
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
// NewID generates a random number to use as an tunnel name
|
// NewID generates a random number to use as an tunnel name
|
||||||
func (c *Client) NewID() int32 {
|
func (c *Client) NewID() int32 {
|
||||||
return rand.Int31n(math.MaxInt32)
|
if c.id == 0 {
|
||||||
|
c.id = NewID()
|
||||||
|
}
|
||||||
|
return c.id
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destination returns the full destination of the local tunnel
|
// Destination returns the full destination of the local tunnel
|
||||||
@@ -126,11 +148,11 @@ func NewClientFromOptions(opts ...func(*Client) error) (*Client, error) {
|
|||||||
c.port = "7656"
|
c.port = "7656"
|
||||||
c.inLength = 3
|
c.inLength = 3
|
||||||
c.inVariance = 0
|
c.inVariance = 0
|
||||||
c.inQuantity = 1
|
c.inQuantity = 3
|
||||||
c.inBackups = 1
|
c.inBackups = 1
|
||||||
c.outLength = 3
|
c.outLength = 3
|
||||||
c.outVariance = 0
|
c.outVariance = 0
|
||||||
c.outQuantity = 1
|
c.outQuantity = 3
|
||||||
c.outBackups = 1
|
c.outBackups = 1
|
||||||
c.dontPublishLease = true
|
c.dontPublishLease = true
|
||||||
c.encryptLease = false
|
c.encryptLease = false
|
||||||
@@ -139,20 +161,22 @@ func NewClientFromOptions(opts ...func(*Client) error) (*Client, error) {
|
|||||||
c.reduceIdleQuantity = 1
|
c.reduceIdleQuantity = 1
|
||||||
c.closeIdle = true
|
c.closeIdle = true
|
||||||
c.closeIdleTime = 600000
|
c.closeIdleTime = 600000
|
||||||
c.debug = true
|
c.debug = false
|
||||||
c.sigType = SAMsigTypes[4]
|
c.sigType = SAMsigTypes[4]
|
||||||
c.id = 0
|
c.id = 0
|
||||||
c.lastaddr = "invalid"
|
|
||||||
c.destination = ""
|
c.destination = ""
|
||||||
c.leaseSetEncType = "4,0"
|
c.leaseSetEncType = "4,0"
|
||||||
c.fromport = ""
|
c.fromport = ""
|
||||||
c.toport = ""
|
c.toport = ""
|
||||||
|
c.sammin = 0
|
||||||
|
c.sammax = 1
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
if err := o(&c); err != nil {
|
if err := o(&c); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
conn, err := net.Dial("tcp", c.samaddr())
|
c.id = c.NewID()
|
||||||
|
conn, err := net.DialTimeout("tcp", c.samaddr(), 15*time.Minute)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -164,12 +188,22 @@ func NewClientFromOptions(opts ...func(*Client) error) (*Client, error) {
|
|||||||
return &c, c.hello()
|
return &c, c.hello()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ID returns a the current ID of the client as a string
|
||||||
func (p *Client) ID() string {
|
func (p *Client) ID() string {
|
||||||
return fmt.Sprintf("%d", p.id)
|
return fmt.Sprintf("%d", p.NewID())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Addr returns the address of the client as a net.Addr
|
||||||
func (p *Client) Addr() net.Addr {
|
func (p *Client) Addr() net.Addr {
|
||||||
return nil
|
keys, err := samkeys.DestToKeys(p.Destination())
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return keys.Addr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Client) LocalAddr() net.Addr {
|
||||||
|
return p.Addr()
|
||||||
}
|
}
|
||||||
|
|
||||||
//return the combined host:port of the SAM bridge
|
//return the combined host:port of the SAM bridge
|
||||||
@@ -179,7 +213,7 @@ func (c *Client) samaddr() string {
|
|||||||
|
|
||||||
// send the initial handshake command and check that the reply is ok
|
// send the initial handshake command and check that the reply is ok
|
||||||
func (c *Client) hello() error {
|
func (c *Client) hello() error {
|
||||||
r, err := c.sendCmd("HELLO VERSION MIN=3.0 MAX=3.2\n")
|
r, err := c.sendCmd("HELLO VERSION MIN=3.%d MAX=3.%d\n", c.sammin, c.sammax)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -215,8 +249,10 @@ func (c *Client) Close() error {
|
|||||||
return c.SamConn.Close()
|
return c.SamConn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClient generates an exact copy of the client with the same options
|
// NewClient generates an exact copy of the client with the same options, but
|
||||||
func (c *Client) NewClient() (*Client, error) {
|
// re-does all the handshaky business so that Dial can pick up right where it
|
||||||
|
// left off, should the need arise.
|
||||||
|
func (c *Client) NewClient(id int32) (*Client, error) {
|
||||||
return NewClientFromOptions(
|
return NewClientFromOptions(
|
||||||
SetHost(c.host),
|
SetHost(c.host),
|
||||||
SetPort(c.port),
|
SetPort(c.port),
|
||||||
@@ -237,7 +273,6 @@ func (c *Client) NewClient() (*Client, error) {
|
|||||||
SetCloseIdle(c.closeIdle),
|
SetCloseIdle(c.closeIdle),
|
||||||
SetCloseIdleTime(c.closeIdleTime),
|
SetCloseIdleTime(c.closeIdleTime),
|
||||||
SetCompression(c.compression),
|
SetCompression(c.compression),
|
||||||
setlastaddr(c.lastaddr),
|
setid(id),
|
||||||
setid(c.id),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
121
client_test.go
121
client_test.go
@@ -1,3 +1,4 @@
|
|||||||
|
//go:build nettest
|
||||||
// +build nettest
|
// +build nettest
|
||||||
|
|
||||||
package goSam
|
package goSam
|
||||||
@@ -6,84 +7,110 @@ import "testing"
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"math/rand"
|
||||||
"time"
|
"time"
|
||||||
//"log"
|
//"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/eyedeekay/sam3"
|
"github.com/eyedeekay/sam3/helper"
|
||||||
|
"github.com/eyedeekay/sam3/i2pkeys"
|
||||||
)
|
)
|
||||||
|
|
||||||
func HelloServer(w http.ResponseWriter, r *http.Request) {
|
func HelloServer(w http.ResponseWriter, r *http.Request) {
|
||||||
fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:])
|
fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:])
|
||||||
}
|
}
|
||||||
|
|
||||||
var client *Client
|
|
||||||
|
|
||||||
func setup(t *testing.T) {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
// these tests expect a running SAM brige on this address
|
|
||||||
client, err = NewClientFromOptions(SetDebug(true))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("NewDefaultClient() Error: %q\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCompositeClient(t *testing.T) {
|
func TestCompositeClient(t *testing.T) {
|
||||||
sam, err := sam3.NewSAM("127.0.0.1:7656")
|
listener, err := sam.I2PListener("testservice"+fmt.Sprintf("%d", rand.Int31n(math.MaxInt32)), "127.0.0.1:7656", "testkeys")
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Listener() Error: %q\n", err)
|
|
||||||
}
|
|
||||||
keys, err := sam.NewKeys()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Listener() Error: %q\n", err)
|
|
||||||
}
|
|
||||||
stream, err := sam.NewStreamSession("serverTun", keys, sam3.Options_Medium)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Listener() Error: %q\n", err)
|
|
||||||
}
|
|
||||||
listener, err := stream.Listen()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Listener() Error: %q\n", err)
|
t.Fatalf("Listener() Error: %q\n", err)
|
||||||
}
|
}
|
||||||
|
defer listener.Close()
|
||||||
http.HandleFunc("/", HelloServer)
|
http.HandleFunc("/", HelloServer)
|
||||||
go http.Serve(listener, nil)
|
go http.Serve(listener, nil)
|
||||||
|
|
||||||
client, err = NewClientFromOptions(SetDebug(true))
|
listener2, err := sam.I2PListener("testservice"+fmt.Sprintf("%d", rand.Int31n(math.MaxInt32)), "127.0.0.1:7656", "testkeys2")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Listener() Error: %q\n", err)
|
||||||
|
}
|
||||||
|
defer listener2.Close()
|
||||||
|
// http.HandleFunc("/", HelloServer)
|
||||||
|
go http.Serve(listener2, nil)
|
||||||
|
|
||||||
|
listener3, err := sam.I2PListener("testservice"+fmt.Sprintf("%d", rand.Int31n(math.MaxInt32)), "127.0.0.1:7656", "testkeys3")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Listener() Error: %q\n", err)
|
||||||
|
}
|
||||||
|
defer listener3.Close()
|
||||||
|
// http.HandleFunc("/", HelloServer)
|
||||||
|
go http.Serve(listener3, nil)
|
||||||
|
|
||||||
|
sam, err := NewClientFromOptions(SetDebug(false))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("NewDefaultClient() Error: %q\n", err)
|
t.Fatalf("NewDefaultClient() Error: %q\n", err)
|
||||||
}
|
}
|
||||||
tr := &http.Transport{
|
tr := &http.Transport{
|
||||||
Dial: client.Dial,
|
Dial: sam.Dial,
|
||||||
}
|
}
|
||||||
client := &http.Client{Transport: tr}
|
client := &http.Client{Transport: tr}
|
||||||
time.Sleep(time.Second * 30)
|
defer sam.Close()
|
||||||
resp, err := client.Get("http://" + keys.Addr().Base32())
|
x := 0
|
||||||
if err != nil {
|
for x < 15 {
|
||||||
t.Fatalf("Get Error: %q\n", err)
|
time.Sleep(time.Second * 2)
|
||||||
|
t.Log("waiting a little while for services to register", (30 - (x * 2)))
|
||||||
|
x++
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
go func() {
|
||||||
t.Log("Get returned ", resp)
|
resp, err := client.Get("http://" + listener.Addr().(i2pkeys.I2PAddr).Base32())
|
||||||
time.Sleep(time.Second * 15)
|
if err != nil {
|
||||||
|
t.Fatalf("Get Error test 1: %q\n", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
}()
|
||||||
|
//time.Sleep(time.Second * 15)
|
||||||
|
go func() {
|
||||||
|
resp, err := client.Get("http://" + listener2.Addr().(i2pkeys.I2PAddr).Base32())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Get Error test 2: %q\n", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
}()
|
||||||
|
//time.Sleep(time.Second * 15)
|
||||||
|
go func() {
|
||||||
|
resp, err := client.Get("http://" + listener3.Addr().(i2pkeys.I2PAddr).Base32())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Get Error test 3: %q\n", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
time.Sleep(time.Second * 45)
|
||||||
}
|
}
|
||||||
|
|
||||||
func teardown(t *testing.T) {
|
func TestClientHello(t *testing.T) {
|
||||||
|
client, err := NewClientFromOptions(SetDebug(false))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewDefaultClient() Error: %q\n", err)
|
||||||
|
}
|
||||||
|
t.Log(client.Base32())
|
||||||
if err := client.Close(); err != nil {
|
if err := client.Close(); err != nil {
|
||||||
t.Fatalf("client.Close() Error: %q\n", err)
|
t.Fatalf("client.Close() Error: %q\n", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestClientHello(t *testing.T) {
|
|
||||||
setup(t)
|
|
||||||
t.Log(client.Base32())
|
|
||||||
teardown(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNewDestination(t *testing.T) {
|
func TestNewDestination(t *testing.T) {
|
||||||
setup(t)
|
client, err := NewClientFromOptions(SetDebug(false))
|
||||||
t.Log(client.Base32())
|
if err != nil {
|
||||||
if _, err := client.NewDestination(SAMsigTypes[3]); err != nil {
|
t.Fatalf("NewDefaultClient() Error: %q\n", err)
|
||||||
t.Error(err)
|
}
|
||||||
|
t.Log(client.Base32())
|
||||||
|
if s, p, err := client.NewDestination(SAMsigTypes[3]); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
} else {
|
||||||
|
t.Log(s, p)
|
||||||
|
}
|
||||||
|
if err := client.Close(); err != nil {
|
||||||
|
t.Fatalf("client.Close() Error: %q\n", err)
|
||||||
}
|
}
|
||||||
teardown(t)
|
|
||||||
}
|
}
|
||||||
|
9
conn.go
9
conn.go
@@ -30,11 +30,14 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Conn Read data from the connection, writes data to te connection
|
||||||
|
// and logs the data in-between.
|
||||||
type Conn struct {
|
type Conn struct {
|
||||||
RWC
|
RWC
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WrapConn wraps a net.Conn in a Conn.
|
||||||
func WrapConn(c net.Conn) *Conn {
|
func WrapConn(c net.Conn) *Conn {
|
||||||
wrap := Conn{
|
wrap := Conn{
|
||||||
conn: c,
|
conn: c,
|
||||||
@@ -45,23 +48,29 @@ func WrapConn(c net.Conn) *Conn {
|
|||||||
return &wrap
|
return &wrap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LocalAddr returns the local address of the connection.
|
||||||
func (c *Conn) LocalAddr() net.Addr {
|
func (c *Conn) LocalAddr() net.Addr {
|
||||||
return c.conn.LocalAddr()
|
return c.conn.LocalAddr()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RemoteAddr returns the remote address of the connection.
|
||||||
func (c *Conn) RemoteAddr() net.Addr {
|
func (c *Conn) RemoteAddr() net.Addr {
|
||||||
return c.conn.RemoteAddr()
|
return c.conn.RemoteAddr()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetDeadline sets the read and write deadlines associated with the connection
|
||||||
func (c *Conn) SetDeadline(t time.Time) error {
|
func (c *Conn) SetDeadline(t time.Time) error {
|
||||||
log.Println("WARNING: SetDeadline() not sure this works")
|
log.Println("WARNING: SetDeadline() not sure this works")
|
||||||
return c.conn.SetDeadline(t)
|
return c.conn.SetDeadline(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetReadDeadline sets the read deadline associated with the connection
|
||||||
func (c *Conn) SetReadDeadline(t time.Time) error {
|
func (c *Conn) SetReadDeadline(t time.Time) error {
|
||||||
log.Println("WARNING: SetReadDeadline() not sure this works")
|
log.Println("WARNING: SetReadDeadline() not sure this works")
|
||||||
return c.conn.SetReadDeadline(t)
|
return c.conn.SetReadDeadline(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetWriteDeadline sets the write deadline associated with the connection
|
||||||
func (c *Conn) SetWriteDeadline(t time.Time) error {
|
func (c *Conn) SetWriteDeadline(t time.Time) error {
|
||||||
log.Println("WARNING: SetWriteDeadline() not sure this works")
|
log.Println("WARNING: SetWriteDeadline() not sure this works")
|
||||||
return c.conn.SetWriteDeadline(t)
|
return c.conn.SetWriteDeadline(t)
|
||||||
|
25
datagram.go
Normal file
25
datagram.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package goSam
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DatagramConn
|
||||||
|
type DatagramConn interface {
|
||||||
|
ReadFrom(p []byte) (n int, addr net.Addr, err error)
|
||||||
|
Read(b []byte) (n int, err error)
|
||||||
|
WriteTo(p []byte, addr net.Addr) (n int, err error)
|
||||||
|
Write(b []byte) (n int, err error)
|
||||||
|
Close() error
|
||||||
|
LocalAddr() net.Addr
|
||||||
|
RemoteAddr() net.Addr
|
||||||
|
SetDeadline(t time.Time) error
|
||||||
|
SetReadDeadline(t time.Time) error
|
||||||
|
SetWriteDeadline(t time.Time) error
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When datagram support is finished, this will compile.
|
||||||
|
* var conn DatagramConn = &Client{}
|
||||||
|
**/
|
17
debian/changelog
vendored
17
debian/changelog
vendored
@@ -1,4 +1,19 @@
|
|||||||
golang-github-eyedeekay-gosam (0.32.27) UNRELEASED; urgency=medium
|
golang-github-eyedeekay-gosam (0.32.30) UNRELEASED; urgency=medium
|
||||||
|
|
||||||
|
* Improve the defaults
|
||||||
|
* Handle errors more correctly
|
||||||
|
* Gracefully handle hangups by creating a new session
|
||||||
|
* Set empty destinations to TRANSIENT when dialing
|
||||||
|
|
||||||
|
-- idk <hankhill19580@gmail.com> Sun, 03 Nov 2020 16:12:04 -0500
|
||||||
|
|
||||||
|
golang-github-eyedeekay-gosam (0.32.29) UNRELEASED; urgency=medium
|
||||||
|
|
||||||
|
* Maintenance updates
|
||||||
|
|
||||||
|
-- idk <hankhill19580@gmail.com> Mon, 23 Nov 2020 20:40:40 -0500
|
||||||
|
|
||||||
|
golang-github-eyedeekay-gosam (0.32.28) UNRELEASED; urgency=medium
|
||||||
|
|
||||||
* Maintenance updates
|
* Maintenance updates
|
||||||
|
|
||||||
|
66
dial.go
66
dial.go
@@ -3,23 +3,23 @@ package goSam
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DialContext implements the net.DialContext function and can be used for http.Transport
|
// 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) {
|
func (c *Client) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
|
c.mutex.Lock()
|
||||||
|
defer c.mutex.Unlock()
|
||||||
errCh := make(chan error, 1)
|
errCh := make(chan error, 1)
|
||||||
connCh := make(chan net.Conn, 1)
|
connCh := make(chan net.Conn, 1)
|
||||||
go func() {
|
go func() {
|
||||||
if conn, err := c.Dial(network, addr); err != nil {
|
if conn, err := c.DialContextFree(network, addr); err != nil {
|
||||||
errCh <- err
|
errCh <- err
|
||||||
} else if ctx.Err() != nil {
|
} else if ctx.Err() != nil {
|
||||||
var err error
|
log.Println(ctx)
|
||||||
c, err = c.NewClient()
|
errCh <- ctx.Err()
|
||||||
if err != nil {
|
|
||||||
conn.Close()
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
connCh <- conn
|
connCh <- conn
|
||||||
}
|
}
|
||||||
@@ -32,48 +32,58 @@ func (c *Client) DialContext(ctx context.Context, network, addr string) (net.Con
|
|||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return nil, ctx.Err()
|
return nil, ctx.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) dialCheck(addr string) (int32, bool) {
|
func (c *Client) Dial(network, addr string) (net.Conn, error) {
|
||||||
if c.lastaddr == "invalid" {
|
return c.DialContext(context.TODO(), network, addr)
|
||||||
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
|
// Dial implements the net.Dial function and can be used for http.Transport
|
||||||
func (c *Client) Dial(network, addr string) (net.Conn, error) {
|
func (c *Client) DialContextFree(network, addr string) (net.Conn, error) {
|
||||||
c.ml.Lock()
|
if network == "tcp" || network == "tcp6" || network == "tcp4" {
|
||||||
defer c.ml.Unlock()
|
return c.DialStreamingContextFree(addr)
|
||||||
|
}
|
||||||
|
if network == "udp" || network == "udp6" || network == "udp4" {
|
||||||
|
return c.DialDatagramContextFree(addr)
|
||||||
|
}
|
||||||
|
if network == "raw" || network == "ip" {
|
||||||
|
return c.DialDatagramContextFree(addr)
|
||||||
|
}
|
||||||
|
return c.DialStreamingContextFree(addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DialDatagramContextFree is a "Dialer" for "Client-Like" Datagram connections.
|
||||||
|
// It is also not finished. If you need datagram support right now, use sam3.
|
||||||
|
func (c *Client) DialDatagramContextFree(addr string) (DatagramConn, error) {
|
||||||
|
return nil, fmt.Errorf("Datagram support is not finished yet, come back later`")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) DialStreamingContextFree(addr string) (net.Conn, error) {
|
||||||
portIdx := strings.Index(addr, ":")
|
portIdx := strings.Index(addr, ":")
|
||||||
if portIdx >= 0 {
|
if portIdx >= 0 {
|
||||||
addr = addr[:portIdx]
|
addr = addr[:portIdx]
|
||||||
}
|
}
|
||||||
addr, err := c.Lookup(addr)
|
addr, err := c.Lookup(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Printf("LOOKUP DIALER ERROR %s %s", addr, err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var test bool
|
if c.destination == "" {
|
||||||
if c.id, test = c.dialCheck(addr); test == true {
|
c.destination, err = c.CreateStreamSession(c.destination)
|
||||||
c.destination, err = c.CreateStreamSession(c.id, c.destination)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
c.lastaddr = addr
|
|
||||||
}
|
|
||||||
c, err = c.NewClient()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.StreamConnect(c.id, addr)
|
d, err := c.NewClient(c.NewID())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return c.SamConn, nil
|
err = d.StreamConnect(addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return d.SamConn, nil
|
||||||
}
|
}
|
||||||
|
8
go.mod
8
go.mod
@@ -1,6 +1,12 @@
|
|||||||
module github.com/eyedeekay/goSam
|
module github.com/eyedeekay/goSam
|
||||||
|
|
||||||
require github.com/eyedeekay/sam3 v0.32.2
|
require (
|
||||||
|
github.com/eyedeekay/sam3 v0.32.32
|
||||||
|
github.com/getlantern/go-socks5 v0.0.0-20171114193258-79d4dd3e2db5
|
||||||
|
github.com/getlantern/golog v0.0.0-20201105130739-9586b8bde3a9 // indirect
|
||||||
|
github.com/getlantern/netx v0.0.0-20190110220209-9912de6f94fd // indirect
|
||||||
|
github.com/getlantern/ops v0.0.0-20200403153110-8476b16edcd6 // indirect
|
||||||
|
)
|
||||||
|
|
||||||
//replace github.com/eyedeekay/gosam v0.1.1-0.20190814195658-27e786578944 => github.com/eyedeekay/goSam ./
|
//replace github.com/eyedeekay/gosam v0.1.1-0.20190814195658-27e786578944 => github.com/eyedeekay/goSam ./
|
||||||
|
|
||||||
|
31
go.sum
31
go.sum
@@ -1,4 +1,35 @@
|
|||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/eyedeekay/ramp v0.0.0-20190429201811-305b382042ab h1:EfTRHxGSbiaEyxNzvKRBWVIDw3mD8xXGxj4gvwFzY7Q=
|
github.com/eyedeekay/ramp v0.0.0-20190429201811-305b382042ab h1:EfTRHxGSbiaEyxNzvKRBWVIDw3mD8xXGxj4gvwFzY7Q=
|
||||||
github.com/eyedeekay/ramp v0.0.0-20190429201811-305b382042ab/go.mod h1:h7mvUAMgZ/rtRDUOkvKTK+8LnDMeUhJSoa5EPdB51fc=
|
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 h1:xODDY5nBVg0oK7KaYk7ofkXFoHPsmI1umhSv1TZlS7s=
|
||||||
github.com/eyedeekay/sam3 v0.32.2/go.mod h1:Y3igFVzN4ybqkkpfUWULGhw7WRp8lieq0ORXbLBbcZM=
|
github.com/eyedeekay/sam3 v0.32.2/go.mod h1:Y3igFVzN4ybqkkpfUWULGhw7WRp8lieq0ORXbLBbcZM=
|
||||||
|
github.com/eyedeekay/sam3 v0.32.31 h1:0fdDAupEQZSETHcyVQAsnFgpYArGJzU+lC2qN6f0GDk=
|
||||||
|
github.com/eyedeekay/sam3 v0.32.32-0.20201122050855-f464873c9350 h1:8R4zcaWsgANiZ4MKKBPUf9Isct2M1IFVUVZdAMqPCmU=
|
||||||
|
github.com/eyedeekay/sam3 v0.32.32-0.20201122050855-f464873c9350/go.mod h1:qRA9KIIVxbrHlkj+ZB+OoxFGFgdKeGp1vSgPw26eOVU=
|
||||||
|
github.com/eyedeekay/sam3 v0.32.32 h1:9Ea1Ere5O8Clx8zYxKnvhrWy7R96Q4FvxlPskYf8VW0=
|
||||||
|
github.com/eyedeekay/sam3 v0.32.32/go.mod h1:qRA9KIIVxbrHlkj+ZB+OoxFGFgdKeGp1vSgPw26eOVU=
|
||||||
|
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 h1:NRUJuo3v3WGC/g5YiyF790gut6oQr5f3FBI88Wv0dx4=
|
||||||
|
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520/go.mod h1:L+mq6/vvYHKjCX2oez0CgEAJmbq1fbb/oNJIWQkBybY=
|
||||||
|
github.com/getlantern/errors v1.0.1 h1:XukU2whlh7OdpxnkXhNH9VTLVz0EVPGKDV5K0oWhvzw=
|
||||||
|
github.com/getlantern/errors v1.0.1/go.mod h1:l+xpFBrCtDLpK9qNjxs+cHU6+BAdlBaxHqikB6Lku3A=
|
||||||
|
github.com/getlantern/go-socks5 v0.0.0-20171114193258-79d4dd3e2db5 h1:RBKofGGMt2k6eGBwX8mky9qunjL+KnAp9JdzXjiRkRw=
|
||||||
|
github.com/getlantern/go-socks5 v0.0.0-20171114193258-79d4dd3e2db5/go.mod h1:kGHRXch95rnGLHjER/GhhFiHvfnqNz7KqWD9kGfATHY=
|
||||||
|
github.com/getlantern/golog v0.0.0-20201105130739-9586b8bde3a9 h1:8MYJU90rB1bsavemKSAuDKBjtAKo5xq95bEPOnzV7CE=
|
||||||
|
github.com/getlantern/golog v0.0.0-20201105130739-9586b8bde3a9/go.mod h1:ZyIjgH/1wTCl+B+7yH1DqrWp6MPJqESmwmEQ89ZfhvA=
|
||||||
|
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 h1:micT5vkcr9tOVk1FiH8SWKID8ultN44Z+yzd2y/Vyb0=
|
||||||
|
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7/go.mod h1:dD3CgOrwlzca8ed61CsZouQS5h5jIzkK9ZWrTcf0s+o=
|
||||||
|
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 h1:XYzSdCbkzOC0FDNrgJqGRo8PCMFOBFL9py72DRs7bmc=
|
||||||
|
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55/go.mod h1:6mmzY2kW1TOOrVy+r41Za2MxXM+hhqTtY3oBKd2AgFA=
|
||||||
|
github.com/getlantern/netx v0.0.0-20190110220209-9912de6f94fd h1:mn98vs69Kqw56iKhR82mjk16Q1q5aDFFW0E89/QbXkQ=
|
||||||
|
github.com/getlantern/netx v0.0.0-20190110220209-9912de6f94fd/go.mod h1:wKdY0ikOgzrWSeB9UyBVKPRhjXQ+vTb+BPeJuypUuNE=
|
||||||
|
github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f h1:wrYrQttPS8FHIRSlsrcuKazukx/xqO/PpLZzZXsF+EA=
|
||||||
|
github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f/go.mod h1:D5ao98qkA6pxftxoqzibIBBrLSUli+kYnJqrgBf9cIA=
|
||||||
|
github.com/getlantern/ops v0.0.0-20200403153110-8476b16edcd6 h1:QthAQCekS1YOeYWSvoHI6ZatlG4B+GBDLxV/2ZkBsTA=
|
||||||
|
github.com/getlantern/ops v0.0.0-20200403153110-8476b16edcd6/go.mod h1:D5ao98qkA6pxftxoqzibIBBrLSUli+kYnJqrgBf9cIA=
|
||||||
|
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
||||||
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
|
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
|
||||||
|
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
13
i2pkeys.go
13
i2pkeys.go
@@ -2,17 +2,14 @@ package goSam
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/eyedeekay/sam3/i2pkeys"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewDestination generates a new I2P destination, creating the underlying
|
// NewDestination generates a new I2P destination, creating the underlying
|
||||||
// public/private keys in the process. The public key can be used to send messages
|
// public/private keys in the process. The public key can be used to send messages
|
||||||
// to the destination, while the private key can be used to reply to messages
|
// to the destination, while the private key can be used to reply to messages
|
||||||
func (c *Client) NewDestination(sigType ...string) (i2pkeys.I2PKeys, error) {
|
func (c *Client) NewDestination(sigType ...string) (string, string, error) {
|
||||||
var (
|
var (
|
||||||
sigtmp string
|
sigtmp string
|
||||||
keys i2pkeys.I2PKeys
|
|
||||||
)
|
)
|
||||||
if len(sigType) > 0 {
|
if len(sigType) > 0 {
|
||||||
sigtmp = sigType[0]
|
sigtmp = sigType[0]
|
||||||
@@ -22,14 +19,14 @@ func (c *Client) NewDestination(sigType ...string) (i2pkeys.I2PKeys, error) {
|
|||||||
sigtmp,
|
sigtmp,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return keys, err
|
return "", "", err
|
||||||
}
|
}
|
||||||
var pub, priv string
|
var pub, priv string
|
||||||
if priv = r.Pairs["PRIV"]; priv == "" {
|
if priv = r.Pairs["PRIV"]; priv == "" {
|
||||||
return keys, errors.New("failed to generate private destination key")
|
return "", "", errors.New("failed to generate private destination key")
|
||||||
}
|
}
|
||||||
if pub = r.Pairs["PUB"]; pub == "" {
|
if pub = r.Pairs["PUB"]; pub == "" {
|
||||||
return keys, errors.New("failed to generate public destination key")
|
return priv, "", errors.New("failed to generate public destination key")
|
||||||
}
|
}
|
||||||
return i2pkeys.NewKeys(i2pkeys.I2PAddr(pub), priv), nil
|
return priv, pub, nil
|
||||||
}
|
}
|
||||||
|
48
naming.go
48
naming.go
@@ -17,7 +17,7 @@ func (c *Client) Lookup(name string) (string, error) {
|
|||||||
|
|
||||||
// TODO: move check into sendCmd()
|
// TODO: move check into sendCmd()
|
||||||
if r.Topic != "NAMING" || r.Type != "REPLY" {
|
if r.Topic != "NAMING" || r.Type != "REPLY" {
|
||||||
return "", fmt.Errorf("Naming Unknown Reply: %+v\n", r)
|
return "", fmt.Errorf("Naming Unknown Reply: %s, %s\n", r.Topic, r.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
result := r.Pairs["RESULT"]
|
result := r.Pairs["RESULT"]
|
||||||
@@ -37,37 +37,39 @@ func (c *Client) Lookup(name string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) forward(client, conn net.Conn) {
|
func (c *Client) forward(client, conn net.Conn) {
|
||||||
|
defer client.Close()
|
||||||
|
defer conn.Close()
|
||||||
go func() {
|
go func() {
|
||||||
defer client.Close()
|
// defer client.Close()
|
||||||
defer conn.Close()
|
// defer conn.Close()
|
||||||
io.Copy(client, conn)
|
io.Copy(client, conn)
|
||||||
}()
|
}()
|
||||||
go func() {
|
go func() {
|
||||||
defer client.Close()
|
// defer client.Close()
|
||||||
defer conn.Close()
|
// defer conn.Close()
|
||||||
io.Copy(conn, client)
|
io.Copy(conn, client)
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) Resolve(ctx context.Context, name string) (context.Context, net.IP, error) {
|
func (c *Client) Resolve(ctx context.Context, name string) (context.Context, net.IP, error) {
|
||||||
if c.lastaddr == "invalid" || c.lastaddr != name {
|
// if c.lastaddr == "invalid" || c.lastaddr != name {
|
||||||
client, err := c.DialContext(ctx, "", name)
|
client, err := c.DialContext(ctx, "", name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx, nil, err
|
return ctx, nil, err
|
||||||
}
|
|
||||||
ln, err := net.Listen("tcp", "127.0.0.1:")
|
|
||||||
if err != nil {
|
|
||||||
return ctx, nil, err
|
|
||||||
}
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
conn, err := ln.Accept()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err.Error())
|
|
||||||
}
|
|
||||||
go c.forward(client, conn)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
|
ln, err := net.Listen("tcp", "127.0.0.1:")
|
||||||
|
if err != nil {
|
||||||
|
return ctx, nil, err
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
conn, err := ln.Accept()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
}
|
||||||
|
go c.forward(client, conn)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
// }
|
||||||
return ctx, nil, nil
|
return ctx, nil, nil
|
||||||
}
|
}
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
//go:build nettest
|
||||||
// +build nettest
|
// +build nettest
|
||||||
|
|
||||||
package goSam
|
package goSam
|
||||||
@@ -10,8 +11,10 @@ import (
|
|||||||
func TestClientLookupInvalid(t *testing.T) {
|
func TestClientLookupInvalid(t *testing.T) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
setup(t)
|
client, err := NewClientFromOptions(SetDebug(false))
|
||||||
defer teardown(t)
|
if err != nil {
|
||||||
|
t.Fatalf("NewDefaultClient() Error: %q\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
addr, err := client.Lookup(`!(@#)`)
|
addr, err := client.Lookup(`!(@#)`)
|
||||||
if addr != "" || err == nil {
|
if addr != "" || err == nil {
|
||||||
@@ -25,6 +28,9 @@ func TestClientLookupInvalid(t *testing.T) {
|
|||||||
if repErr.Result != ResultKeyNotFound {
|
if repErr.Result != ResultKeyNotFound {
|
||||||
t.Errorf("client.Lookup() should throw an ResultKeyNotFound error.\nGot:%+v%s%s\n", repErr, "!=", ResultKeyNotFound)
|
t.Errorf("client.Lookup() should throw an ResultKeyNotFound error.\nGot:%+v%s%s\n", repErr, "!=", ResultKeyNotFound)
|
||||||
}
|
}
|
||||||
|
if err := client.Close(); err != nil {
|
||||||
|
t.Fatalf("client.Close() Error: %q\n", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestClientLookupValid(t *testing.T) {
|
func TestClientLookupValid(t *testing.T) {
|
||||||
|
36
options.go
36
options.go
@@ -62,6 +62,32 @@ func SetHost(s string) func(*Client) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SetSAMMinVersion(i int) func(*Client) error {
|
||||||
|
return func(c *Client) error {
|
||||||
|
if i < 0 {
|
||||||
|
return fmt.Errorf("SAM version must be greater than or equal to 0")
|
||||||
|
}
|
||||||
|
if i > 3 {
|
||||||
|
return fmt.Errorf("SAM version must be less than or equal to 3")
|
||||||
|
}
|
||||||
|
c.sammin = i
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetSAMMaxVersion(i int) func(*Client) error {
|
||||||
|
return func(c *Client) error {
|
||||||
|
if i < 0 {
|
||||||
|
return fmt.Errorf("SAM version must be greater than or equal to 0")
|
||||||
|
}
|
||||||
|
if i > 3 {
|
||||||
|
return fmt.Errorf("SAM version must be less than or equal to 3")
|
||||||
|
}
|
||||||
|
c.sammin = i
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//SetLocalDestination sets the local destination of the tunnel from a private
|
//SetLocalDestination sets the local destination of the tunnel from a private
|
||||||
//key
|
//key
|
||||||
func SetLocalDestination(s string) func(*Client) error {
|
func SetLocalDestination(s string) func(*Client) error {
|
||||||
@@ -71,13 +97,6 @@ func SetLocalDestination(s string) func(*Client) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setlastaddr(s string) func(*Client) error {
|
|
||||||
return func(c *Client) error {
|
|
||||||
c.lastaddr = s
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func setid(s int32) func(*Client) error {
|
func setid(s int32) func(*Client) error {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
c.id = s
|
c.id = s
|
||||||
@@ -166,7 +185,8 @@ func SetToPortInt(i int) func(*Client) error {
|
|||||||
//SetDebug enables debugging messages
|
//SetDebug enables debugging messages
|
||||||
func SetDebug(b bool) func(*Client) error {
|
func SetDebug(b bool) func(*Client) error {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
c.debug = b
|
//c.debug = b
|
||||||
|
c.debug = true
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,9 +1,8 @@
|
|||||||
|
//go:build nettest
|
||||||
// +build nettest
|
// +build nettest
|
||||||
|
|
||||||
package goSam
|
package goSam
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
@@ -33,12 +32,12 @@ func (c *Client) validCmd(str string, args ...interface{}) (string, error) {
|
|||||||
|
|
||||||
func (c *Client) validCreate() (string, error) {
|
func (c *Client) validCreate() (string, error) {
|
||||||
id := rand.Int31n(math.MaxInt32)
|
id := rand.Int31n(math.MaxInt32)
|
||||||
result, err := c.validCmd("SESSION CREATE STYLE=STREAM ID=%d DESTINATION=%s %s\n", id, "abc.i2p", client.allOptions())
|
result, err := c.validCmd("SESSION CREATE STYLE=STREAM ID=%d DESTINATION=%s %s\n", id, "abc.i2p", c.allOptions())
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOptionAddrString(t *testing.T) {
|
func TestOptionAddrString(t *testing.T) {
|
||||||
client, err := NewClientFromOptions(SetAddr("127.0.0.1:7656"), SetDebug(true))
|
client, err := NewClientFromOptions(SetAddr("127.0.0.1:7656"), SetDebug(false))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("NewClientFromOptions() Error: %q\n", err)
|
t.Fatalf("NewClientFromOptions() Error: %q\n", err)
|
||||||
}
|
}
|
||||||
@@ -47,17 +46,17 @@ func TestOptionAddrString(t *testing.T) {
|
|||||||
} else {
|
} else {
|
||||||
t.Log(result)
|
t.Log(result)
|
||||||
}
|
}
|
||||||
dest, _ := client.CreateStreamSession(client.NewID(), "")
|
_, err = client.CreateStreamSession("")
|
||||||
if err := client.Close(); err != nil {
|
if err := client.Close(); err != nil {
|
||||||
t.Fatalf("client.Close() Error: %q\n", err)
|
t.Fatalf("client.Close() Error: %q\n", err)
|
||||||
}
|
}
|
||||||
fmt.Printf("\t destination- %s \n", dest)
|
/* fmt.Printf("\t destination- %s \n", dest)
|
||||||
fmt.Printf("\t address64- %s \t", client.Base64())
|
fmt.Printf("\t address64- %s \t", client.Base64())
|
||||||
fmt.Printf("\t address- %s \t", client.Base32())
|
fmt.Printf("\t address- %s \t", client.Base32())*/
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOptionAddrStringLh(t *testing.T) {
|
func TestOptionAddrStringLh(t *testing.T) {
|
||||||
client, err := NewClientFromOptions(SetAddr("localhost:7656"), SetDebug(true))
|
client, err := NewClientFromOptions(SetAddr("localhost:7656"), SetDebug(false))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("NewClientFromOptions() Error: %q\n", err)
|
t.Fatalf("NewClientFromOptions() Error: %q\n", err)
|
||||||
}
|
}
|
||||||
@@ -66,17 +65,17 @@ func TestOptionAddrStringLh(t *testing.T) {
|
|||||||
} else {
|
} else {
|
||||||
t.Log(result)
|
t.Log(result)
|
||||||
}
|
}
|
||||||
dest, _ := client.CreateStreamSession(client.NewID(), "")
|
_, err = client.CreateStreamSession("")
|
||||||
if err := client.Close(); err != nil {
|
if err := client.Close(); err != nil {
|
||||||
t.Fatalf("client.Close() Error: %q\n", err)
|
t.Fatalf("client.Close() Error: %q\n", err)
|
||||||
}
|
}
|
||||||
fmt.Printf("\t destination- %s \n", dest)
|
/* fmt.Printf("\t destination- %s \n", dest)
|
||||||
fmt.Printf("\t address64- %s \t", client.Base64())
|
fmt.Printf("\t address64- %s \t", client.Base64())
|
||||||
fmt.Printf("\t address- %s \t", client.Base32())
|
fmt.Printf("\t address- %s \t", client.Base32())*/
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOptionAddrSlice(t *testing.T) {
|
func TestOptionAddrSlice(t *testing.T) {
|
||||||
client, err := NewClientFromOptions(SetAddr("127.0.0.1", "7656"), SetDebug(true))
|
client, err := NewClientFromOptions(SetAddr("127.0.0.1", "7656"), SetDebug(false))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("NewClientFromOptions() Error: %q\n", err)
|
t.Fatalf("NewClientFromOptions() Error: %q\n", err)
|
||||||
}
|
}
|
||||||
@@ -85,17 +84,17 @@ func TestOptionAddrSlice(t *testing.T) {
|
|||||||
} else {
|
} else {
|
||||||
t.Log(result)
|
t.Log(result)
|
||||||
}
|
}
|
||||||
dest, _ := client.CreateStreamSession(client.NewID(), "")
|
_, err = client.CreateStreamSession("")
|
||||||
if err := client.Close(); err != nil {
|
if err := client.Close(); err != nil {
|
||||||
t.Fatalf("client.Close() Error: %q\n", err)
|
t.Fatalf("client.Close() Error: %q\n", err)
|
||||||
}
|
}
|
||||||
fmt.Printf("\t destination- %s \n", dest)
|
/* fmt.Printf("\t destination- %s \n", dest)
|
||||||
fmt.Printf("\t address64- %s \t", client.Base64())
|
fmt.Printf("\t address64- %s \t", client.Base64())
|
||||||
fmt.Printf("\t address- %s \t", client.Base32())
|
fmt.Printf("\t address- %s \t", client.Base32())*/
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOptionAddrMixedSlice(t *testing.T) {
|
func TestOptionAddrMixedSlice(t *testing.T) {
|
||||||
client, err := NewClientFromOptions(SetAddrMixed("127.0.0.1", 7656), SetDebug(true))
|
client, err := NewClientFromOptions(SetAddrMixed("127.0.0.1", 7656), SetDebug(false))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("NewClientFromOptions() Error: %q\n", err)
|
t.Fatalf("NewClientFromOptions() Error: %q\n", err)
|
||||||
}
|
}
|
||||||
@@ -104,13 +103,13 @@ func TestOptionAddrMixedSlice(t *testing.T) {
|
|||||||
} else {
|
} else {
|
||||||
t.Log(result)
|
t.Log(result)
|
||||||
}
|
}
|
||||||
dest, _ := client.CreateStreamSession(client.NewID(), "")
|
_, err = client.CreateStreamSession("")
|
||||||
if err := client.Close(); err != nil {
|
if err := client.Close(); err != nil {
|
||||||
t.Fatalf("client.Close() Error: %q\n", err)
|
t.Fatalf("client.Close() Error: %q\n", err)
|
||||||
}
|
}
|
||||||
fmt.Printf("\t destination- %s \n", dest)
|
/* fmt.Printf("\t destination- %s \n", dest)
|
||||||
fmt.Printf("\t address64- %s \t", client.Base64())
|
fmt.Printf("\t address64- %s \t", client.Base64())
|
||||||
fmt.Printf("\t address- %s \t", client.Base32())
|
fmt.Printf("\t address- %s \t", client.Base32())*/
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOptionHost(t *testing.T) {
|
func TestOptionHost(t *testing.T) {
|
||||||
@@ -126,7 +125,7 @@ func TestOptionHost(t *testing.T) {
|
|||||||
SetInBackups(2),
|
SetInBackups(2),
|
||||||
SetOutBackups(2),
|
SetOutBackups(2),
|
||||||
SetEncrypt(true),
|
SetEncrypt(true),
|
||||||
SetDebug(true),
|
SetDebug(false),
|
||||||
SetUnpublished(true),
|
SetUnpublished(true),
|
||||||
SetReduceIdle(true),
|
SetReduceIdle(true),
|
||||||
SetReduceIdleTime(300001),
|
SetReduceIdleTime(300001),
|
||||||
@@ -142,13 +141,13 @@ func TestOptionHost(t *testing.T) {
|
|||||||
} else {
|
} else {
|
||||||
t.Log(result)
|
t.Log(result)
|
||||||
}
|
}
|
||||||
dest, _ := client.CreateStreamSession(client.NewID(), "")
|
_, err = client.CreateStreamSession("")
|
||||||
if err := client.Close(); err != nil {
|
if err := client.Close(); err != nil {
|
||||||
t.Fatalf("client.Close() Error: %q\n", err)
|
t.Fatalf("client.Close() Error: %q\n", err)
|
||||||
}
|
}
|
||||||
fmt.Printf("\t destination- %s \n", dest)
|
/* fmt.Printf("\t destination- %s \n", dest)
|
||||||
fmt.Printf("\t address64- %s \t", client.Base64())
|
fmt.Printf("\t address64- %s \t", client.Base64())
|
||||||
fmt.Printf("\t address- %s \t", client.Base32())
|
fmt.Printf("\t address- %s \t", client.Base32())*/
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOptionPortInt(t *testing.T) {
|
func TestOptionPortInt(t *testing.T) {
|
||||||
@@ -164,7 +163,7 @@ func TestOptionPortInt(t *testing.T) {
|
|||||||
SetInBackups(2),
|
SetInBackups(2),
|
||||||
SetOutBackups(2),
|
SetOutBackups(2),
|
||||||
SetEncrypt(true),
|
SetEncrypt(true),
|
||||||
SetDebug(true),
|
SetDebug(false),
|
||||||
SetUnpublished(true),
|
SetUnpublished(true),
|
||||||
SetReduceIdle(true),
|
SetReduceIdle(true),
|
||||||
SetReduceIdleTime(300001),
|
SetReduceIdleTime(300001),
|
||||||
@@ -180,12 +179,11 @@ func TestOptionPortInt(t *testing.T) {
|
|||||||
} else {
|
} else {
|
||||||
t.Log(result)
|
t.Log(result)
|
||||||
}
|
}
|
||||||
dest, _ := client.CreateStreamSession(client.NewID(), "")
|
_, err = client.CreateStreamSession("")
|
||||||
if err := client.Close(); err != nil {
|
if err := client.Close(); err != nil {
|
||||||
t.Fatalf("client.Close() Error: %q\n", err)
|
t.Fatalf("client.Close() Error: %q\n", err)
|
||||||
}
|
}
|
||||||
fmt.Printf("\t destination- %s \n", dest)
|
/* fmt.Printf("\t destination- %s \n", dest)
|
||||||
fmt.Printf("\t address64- %s \t", client.Base64())
|
fmt.Printf("\t address64- %s \t", client.Base64())
|
||||||
fmt.Printf("\t address- %s \t", client.Base32())
|
fmt.Printf("\t address- %s \t", client.Base32())*/
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
@@ -44,6 +44,25 @@ func parseReply(line string) (*Reply, error) {
|
|||||||
if len(parts) < 3 {
|
if len(parts) < 3 {
|
||||||
return nil, fmt.Errorf("Malformed Reply.\n%s\n", line)
|
return nil, fmt.Errorf("Malformed Reply.\n%s\n", line)
|
||||||
}
|
}
|
||||||
|
preParseReply := func() []string {
|
||||||
|
val := ""
|
||||||
|
quote := false
|
||||||
|
for _, v := range parts {
|
||||||
|
if strings.Contains(v, "=\"") {
|
||||||
|
quote = true
|
||||||
|
}
|
||||||
|
if strings.Contains(v, "\"\n") || strings.Contains(v, "\" ") {
|
||||||
|
quote = false
|
||||||
|
}
|
||||||
|
if quote {
|
||||||
|
val += v + "_"
|
||||||
|
} else {
|
||||||
|
val += v + " "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strings.Split(strings.TrimSuffix(strings.TrimSpace(val), "_"), " ")
|
||||||
|
}
|
||||||
|
parts = preParseReply()
|
||||||
|
|
||||||
r := &Reply{
|
r := &Reply{
|
||||||
Topic: parts[0],
|
Topic: parts[0],
|
||||||
@@ -64,7 +83,7 @@ func parseReply(line string) (*Reply, error) {
|
|||||||
kvPair := strings.SplitN(v, "=", 2)
|
kvPair := strings.SplitN(v, "=", 2)
|
||||||
if kvPair != nil {
|
if kvPair != nil {
|
||||||
if len(kvPair) != 2 {
|
if len(kvPair) != 2 {
|
||||||
return nil, fmt.Errorf("Malformed key-value-pair.\n%s\n", kvPair)
|
return nil, fmt.Errorf("Malformed key-value-pair len != 2.\n%s\n", kvPair)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
r.Pairs[kvPair[0]] = kvPair[len(kvPair)-1]
|
r.Pairs[kvPair[0]] = kvPair[len(kvPair)-1]
|
||||||
|
37
samsocks/main.go
Normal file
37
samsocks/main.go
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
|
||||||
|
"github.com/eyedeekay/goSam"
|
||||||
|
"github.com/getlantern/go-socks5"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
samaddr = flag.String("sam", "127.0.0.1:7656", "SAM API address to use")
|
||||||
|
socksaddr = flag.String("socks", "127.0.0.1:7675", "SOCKS address to use")
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
sam, err := goSam.NewClient(*samaddr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
log.Println("Client Created")
|
||||||
|
|
||||||
|
// create a transport that uses SAM to dial TCP Connections
|
||||||
|
conf := &socks5.Config{
|
||||||
|
Dial: sam.DialContext,
|
||||||
|
Resolver: sam,
|
||||||
|
}
|
||||||
|
server, err := socks5.New(conf)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create SOCKS5 proxy on localhost port 8000
|
||||||
|
if err := server.ListenAndServe("tcp", *socksaddr); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
32
sessions.go
32
sessions.go
@@ -11,16 +11,18 @@ func init() {
|
|||||||
rand.Seed(time.Now().UnixNano())
|
rand.Seed(time.Now().UnixNano())
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateStreamSession creates a new STREAM Session.
|
// CreateSession creates a new Session of type style, with an optional destination.
|
||||||
// Returns the Id for the new Client.
|
// an empty destination is interpreted as "TRANSIENT"
|
||||||
func (c *Client) CreateStreamSession(id int32, dest string) (string, error) {
|
// Returns the destination for the new Client or an error.
|
||||||
|
func (c *Client) CreateSession(style, dest string) (string, error) {
|
||||||
if dest == "" {
|
if dest == "" {
|
||||||
dest = "TRANSIENT"
|
dest = "TRANSIENT"
|
||||||
}
|
}
|
||||||
c.id = id
|
// c.id = id
|
||||||
r, err := c.sendCmd(
|
r, err := c.sendCmd(
|
||||||
"SESSION CREATE STYLE=STREAM ID=%d DESTINATION=%s %s %s %s %s \n",
|
"SESSION CREATE STYLE=%s ID=%s DESTINATION=%s %s %s %s %s \n",
|
||||||
c.id,
|
style,
|
||||||
|
c.ID(),
|
||||||
dest,
|
dest,
|
||||||
c.from(),
|
c.from(),
|
||||||
c.to(),
|
c.to(),
|
||||||
@@ -43,3 +45,21 @@ func (c *Client) CreateStreamSession(id int32, dest string) (string, error) {
|
|||||||
c.destination = r.Pairs["DESTINATION"]
|
c.destination = r.Pairs["DESTINATION"]
|
||||||
return c.destination, nil
|
return c.destination, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateStreamSession creates a new STREAM Session.
|
||||||
|
// Returns the Id for the new Client.
|
||||||
|
func (c *Client) CreateStreamSession(dest string) (string, error) {
|
||||||
|
return c.CreateSession("STREAM", dest)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateDatagramSession creates a new DATAGRAM Session.
|
||||||
|
// Returns the Id for the new Client.
|
||||||
|
func (c *Client) CreateDatagramSession(dest string) (string, error) {
|
||||||
|
return c.CreateSession("DATAGRAM", dest)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateRawSession creates a new RAW Session.
|
||||||
|
// Returns the Id for the new Client.
|
||||||
|
func (c *Client) CreateRawSession(dest string) (string, error) {
|
||||||
|
return c.CreateSession("RAW", dest)
|
||||||
|
}
|
||||||
|
11
stream.go
11
stream.go
@@ -5,8 +5,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// StreamConnect asks SAM for a TCP-Like connection to dest, has to be called on a new Client
|
// 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 {
|
func (c *Client) StreamConnect(dest string) error {
|
||||||
r, err := c.sendCmd("STREAM CONNECT ID=%d DESTINATION=%s %s %s\n", id, dest, c.from(), c.to())
|
if dest == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
r, err := c.sendCmd("STREAM CONNECT ID=%s DESTINATION=%s %s %s\n", c.ID(), dest, c.from(), c.to())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -25,8 +28,8 @@ func (c *Client) StreamConnect(id int32, dest string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// StreamAccept asks SAM to accept a TCP-Like connection
|
// StreamAccept asks SAM to accept a TCP-Like connection
|
||||||
func (c *Client) StreamAccept(id int32) (*Reply, error) {
|
func (c *Client) StreamAccept() (*Reply, error) {
|
||||||
r, err := c.sendCmd("STREAM ACCEPT ID=%d SILENT=false\n", id)
|
r, err := c.sendCmd("STREAM ACCEPT ID=%s SILENT=false\n", c.ID())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user