Improve the parser, automatically set empty destinations to TRANSIENT when using a dialer, better error handling, when a socket gets closed, increment the ID and re-create it

This commit is contained in:
idk
2020-11-29 16:09:55 -05:00
parent 38ca0d08e7
commit 0d10b5b516
4 changed files with 46 additions and 16 deletions

View File

@ -12,6 +12,7 @@ import (
"net"
"strings"
"sync"
"time"
)
// A Client represents a single Connection to the SAM bridge
@ -83,7 +84,10 @@ func NewClient(addr string) (*Client, error) {
// NewID generates a random number to use as an tunnel name
func (c *Client) NewID() int32 {
return rand.Int31n(math.MaxInt32)
if c.id == 0 {
c.id = rand.Int31n(math.MaxInt32)
}
return c.id
}
// Destination returns the full destination of the local tunnel
@ -127,11 +131,11 @@ func NewClientFromOptions(opts ...func(*Client) error) (*Client, error) {
c.port = "7656"
c.inLength = 3
c.inVariance = 0
c.inQuantity = 1
c.inQuantity = 3
c.inBackups = 1
c.outLength = 3
c.outVariance = 0
c.outQuantity = 1
c.outQuantity = 3
c.outBackups = 1
c.dontPublishLease = true
c.encryptLease = false
@ -139,7 +143,7 @@ func NewClientFromOptions(opts ...func(*Client) error) (*Client, error) {
c.reduceIdleTime = 300000
c.reduceIdleQuantity = 1
c.closeIdle = true
c.closeIdleTime = 600000
c.closeIdleTime = 60000000
c.debug = true
c.sigType = SAMsigTypes[4]
c.id = 0
@ -153,7 +157,7 @@ func NewClientFromOptions(opts ...func(*Client) error) (*Client, error) {
return nil, err
}
}
conn, err := net.Dial("tcp", c.samaddr())
conn, err := net.DialTimeout("tcp", c.samaddr(), 3*time.Minute)
if err != nil {
return nil, err
}

23
dial.go
View File

@ -3,6 +3,7 @@ package goSam
import (
"context"
"fmt"
"log"
"net"
"strings"
)
@ -17,19 +18,14 @@ func (c *Client) DialContext(ctx context.Context, network, addr string) (net.Con
if conn, err := c.Dial(network, addr); err != nil {
errCh <- err
} else if ctx.Err() != nil {
var err error
c, err = c.NewClient()
if err != nil {
conn.Close()
}
log.Println(ctx)
errCh <- ctx.Err()
} else {
connCh <- conn
}
}()
select {
case err := <-errCh:
// var err error
c, err = c.NewClient()
return c.SamConn, err
case conn := <-connCh:
return conn, nil
@ -44,6 +40,7 @@ func (c *Client) dialCheck(addr string) (int32, bool) {
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
}
@ -61,18 +58,24 @@ func (c *Client) Dial(network, addr string) (net.Conn, error) {
return nil, err
}
var test bool
if c.id, test = c.dialCheck(addr); test == true {
c.id, _ = c.dialCheck(addr)
c.destination, err = c.CreateStreamSession(c.id, c.destination)
if err != nil {
c.id += 1
c, err = c.NewClient()
if err != nil {
return nil, err
}
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
}
c.lastaddr = addr
err = c.StreamConnect(c.id, addr)
if err != nil {

View File

@ -44,6 +44,25 @@ func parseReply(line string) (*Reply, error) {
if len(parts) < 3 {
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{
Topic: parts[0],
@ -64,8 +83,9 @@ func parseReply(line string) (*Reply, error) {
kvPair := strings.SplitN(v, "=", 2)
if kvPair != nil {
if len(kvPair) == 1 {
return nil, fmt.Errorf("Malformed key-value-pair len 1.\n%s\n", kvPair)
} else 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]

View File

@ -6,6 +6,9 @@ import (
// 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 {
if dest == "" {
dest = "TRANSIENT"
}
r, err := c.sendCmd("STREAM CONNECT ID=%d DESTINATION=%s %s %s\n", id, dest, c.from(), c.to())
if err != nil {
return err