initial commit
This commit is contained in:
13
LICENSE.txt
Normal file
13
LICENSE.txt
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||||
|
Version 2, December 2004
|
||||||
|
|
||||||
|
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||||
|
|
||||||
|
Everyone is permitted to copy and distribute verbatim or modified
|
||||||
|
copies of this license document, and changing it is allowed as long
|
||||||
|
as the name is changed.
|
||||||
|
|
||||||
|
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. You just DO WHAT THE FUCK YOU WANT TO.
|
6
README.txt
Normal file
6
README.txt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
yagsl
|
||||||
|
=====
|
||||||
|
|
||||||
|
This is experimental and expect lots of breaking changes.
|
||||||
|
|
||||||
|
Do not use this in production or at all.
|
74
sambridge/naming.go
Normal file
74
sambridge/naming.go
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
package sambridge
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
resultOk string = "OK"
|
||||||
|
invalidKey string = "INVALID_KEY"
|
||||||
|
keyNotFound string = "KEY_NOT_FOUND"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errKeyNotFound = errors.New("Key not found")
|
||||||
|
errUnknownNamingLookup = errors.New("Unknown naming lookup error")
|
||||||
|
)
|
||||||
|
|
||||||
|
type reply struct {
|
||||||
|
name string
|
||||||
|
value string
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
type namingHandler struct {
|
||||||
|
incoming chan reply
|
||||||
|
m sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *SAMBridge) Lookup(name string) (string, error) {
|
||||||
|
var lookupReply reply
|
||||||
|
m.newNamingHandler()
|
||||||
|
|
||||||
|
go m.Send(fmt.Sprintf("NAMING LOOKUP NAME=%s\n", name))
|
||||||
|
for reply := range m.namingHandler.incoming {
|
||||||
|
lookupReply = reply
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if lookupReply.err != nil {
|
||||||
|
return name, lookupReply.err
|
||||||
|
}
|
||||||
|
return lookupReply.value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *SAMBridge) namingReply(line string) {
|
||||||
|
reply := reply{}
|
||||||
|
|
||||||
|
fields := strings.Fields(line)
|
||||||
|
m.namingHandler.m.Lock()
|
||||||
|
reply.name = strings.SplitN(fields[3], "=", 2)[1]
|
||||||
|
switch strings.SplitN(fields[2], "=", 2)[1] { // result
|
||||||
|
case resultOk:
|
||||||
|
reply.err = nil
|
||||||
|
reply.value = strings.SplitN(fields[4], "=", 2)[1]
|
||||||
|
case invalidKey:
|
||||||
|
reply.err = errInvalidKey
|
||||||
|
case keyNotFound:
|
||||||
|
reply.err = errKeyNotFound
|
||||||
|
default:
|
||||||
|
reply.err = errUnknownNamingLookup
|
||||||
|
}
|
||||||
|
m.namingHandler.incoming <- reply
|
||||||
|
m.namingHandler.m.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *SAMBridge) newNamingHandler() {
|
||||||
|
if m.namingHandler == nil {
|
||||||
|
t := new(namingHandler)
|
||||||
|
t.incoming = make(chan reply)
|
||||||
|
m.namingHandler = t
|
||||||
|
}
|
||||||
|
}
|
96
sambridge/sambridge.go
Normal file
96
sambridge/sambridge.go
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
package sambridge
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SAMBridge struct {
|
||||||
|
Options SamOptions
|
||||||
|
Conn net.Conn
|
||||||
|
namingHandler *namingHandler
|
||||||
|
destHandler *destHandler
|
||||||
|
|
||||||
|
SessionReply chan SessionReply
|
||||||
|
StreamReply chan StreamReply
|
||||||
|
}
|
||||||
|
|
||||||
|
type SamOptions struct {
|
||||||
|
Address string
|
||||||
|
User string
|
||||||
|
Password string
|
||||||
|
}
|
||||||
|
|
||||||
|
const handshakeReply string = "HELLO VERSION MIN=3.0 MAX=3.3\n"
|
||||||
|
|
||||||
|
func (s *SAMBridge) Start() {
|
||||||
|
s.Options.Address = "127.0.0.1:7656"
|
||||||
|
err := s.dialSAMBridge()
|
||||||
|
if err != nil {
|
||||||
|
panic(err.Error())
|
||||||
|
}
|
||||||
|
r := bufio.NewReader(s.Conn)
|
||||||
|
for {
|
||||||
|
line, _ := r.ReadString('\n')
|
||||||
|
if line != "" {
|
||||||
|
log.Printf("DEBUG line: %s", line)
|
||||||
|
}
|
||||||
|
if strings.Contains(line, " ") {
|
||||||
|
first := strings.Fields(line)[0]
|
||||||
|
switch first {
|
||||||
|
case "HELLO":
|
||||||
|
go s.handshakeReply(line)
|
||||||
|
case "SESSION":
|
||||||
|
s.sessionReply(line)
|
||||||
|
case "STREAM":
|
||||||
|
// TODO: Wait for an "OK" STREAM result and as soon as that happens break out of the loop so we can panic on unknown sam lines
|
||||||
|
s.streamReply(line)
|
||||||
|
case "DEST":
|
||||||
|
s.destReply(line)
|
||||||
|
case "NAMING":
|
||||||
|
s.namingReply(line)
|
||||||
|
case "PING":
|
||||||
|
go s.pingReply(line)
|
||||||
|
default:
|
||||||
|
//panic("Unknown SAM line encountered")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SAMBridge) dialSAMBridge() error {
|
||||||
|
c, err := net.Dial("tcp", s.Options.Address)
|
||||||
|
s.Conn = c
|
||||||
|
s.sendHandshake()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SAMBridge) Send(line string) error {
|
||||||
|
if s.Conn != nil {
|
||||||
|
var sb strings.Builder
|
||||||
|
sb.WriteString(line)
|
||||||
|
if !strings.HasSuffix(line, "\n") {
|
||||||
|
sb.WriteString("\n")
|
||||||
|
}
|
||||||
|
w := bufio.NewWriter(s.Conn)
|
||||||
|
_, err := w.WriteString(sb.String())
|
||||||
|
|
||||||
|
err = w.Flush()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return errors.New("Conn was closed")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SAMBridge) sendHandshake() error {
|
||||||
|
return s.Send(handshakeReply)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SAMBridge) handshakeReply(reply string) error {
|
||||||
|
if !strings.HasPrefix(reply, "HELLO REPLY RESULT=OK") {
|
||||||
|
return errHandshakeFailed
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
57
sambridge/sessionreply.go
Normal file
57
sambridge/sessionreply.go
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package sambridge
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SessionReply struct {
|
||||||
|
Destination string
|
||||||
|
Err error
|
||||||
|
ID string
|
||||||
|
Message string
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
duplicatedDest = "DUPLICATED_DEST"
|
||||||
|
duplicatedID = "DUPLICATED_ID"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errHandshakeFailed = errors.New("Handshake failed")
|
||||||
|
errInvalidKey = errors.New("invalid key error")
|
||||||
|
errDuplicatedDest = errors.New("the destination is not a valid private destination key")
|
||||||
|
errDuplicatedID = errors.New("the destination is already in use")
|
||||||
|
|
||||||
|
errUnknownSession = errors.New("Unknown session error")
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s SAMBridge) sessionReply(line string) {
|
||||||
|
reply := SessionReply{}
|
||||||
|
fields := strings.Fields(line)
|
||||||
|
|
||||||
|
switch strings.SplitN(fields[2], "=", 2)[1] { // result
|
||||||
|
case resultOk:
|
||||||
|
reply.Err = nil
|
||||||
|
if strings.HasPrefix(fields[3], "DESTINATION") {
|
||||||
|
reply.Destination = strings.SplitN(fields[3], "=", 2)[1]
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(fields[3], "ID") {
|
||||||
|
reply.ID = strings.SplitN(fields[3], "=", 2)[1]
|
||||||
|
}
|
||||||
|
if len(fields) > 4 {
|
||||||
|
if strings.HasPrefix(fields[4], "MESSAGE") {
|
||||||
|
reply.Message = strings.SplitN(fields[4], "=", 2)[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case duplicatedID:
|
||||||
|
reply.Err = errDuplicatedID
|
||||||
|
case duplicatedDest:
|
||||||
|
reply.Err = errDuplicatedDest
|
||||||
|
case invalidKey:
|
||||||
|
reply.Err = errInvalidKey
|
||||||
|
default:
|
||||||
|
reply.Err = errUnknownSession
|
||||||
|
}
|
||||||
|
s.SessionReply <- reply
|
||||||
|
}
|
58
sambridge/streamreply.go
Normal file
58
sambridge/streamreply.go
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package sambridge
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StreamReply struct {
|
||||||
|
Err error
|
||||||
|
Message string
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
invalidID = "INVALID_ID"
|
||||||
|
i2pErr = "I2P_ERROR"
|
||||||
|
cantReachPeer = "CANT_REACH_PEER"
|
||||||
|
timeout = "TIMEOUT"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errInvalidID = errors.New("invalid ID")
|
||||||
|
errI2PErr = errors.New("generic I2P error")
|
||||||
|
errCantReachPeer = errors.New("can't reach peer")
|
||||||
|
errTimeout = errors.New("timeout")
|
||||||
|
errUnknownStream = errors.New("unknown stream error")
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s SAMBridge) streamReply(line string) {
|
||||||
|
log.Printf("DEBUG STREAMREPLY: %s", line)
|
||||||
|
reply := StreamReply{}
|
||||||
|
fields := strings.Fields(line)
|
||||||
|
|
||||||
|
switch strings.SplitN(fields[2], "=", 2)[1] { // result
|
||||||
|
case resultOk:
|
||||||
|
reply.Err = nil
|
||||||
|
case invalidID:
|
||||||
|
reply.Err = errInvalidID
|
||||||
|
case i2pErr:
|
||||||
|
reply.Err = errI2PErr
|
||||||
|
case cantReachPeer:
|
||||||
|
reply.Err = errCantReachPeer
|
||||||
|
case invalidKey:
|
||||||
|
reply.Err = errInvalidKey
|
||||||
|
case timeout:
|
||||||
|
reply.Err = errTimeout
|
||||||
|
default:
|
||||||
|
reply.Err = errUnknownStream
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(fields) > 3 {
|
||||||
|
if strings.HasPrefix(fields[3], "MESSAGE") {
|
||||||
|
reply.Message = strings.SplitN(fields[3], "=", 2)[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s.StreamReply <- reply
|
||||||
|
}
|
65
sambridge/utilitycommands.go
Normal file
65
sambridge/utilitycommands.go
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
package sambridge
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DestReply struct {
|
||||||
|
Pub string
|
||||||
|
Priv string
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
type destHandler struct {
|
||||||
|
incoming chan DestReply
|
||||||
|
m sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m SAMBridge) DestGenerate(signatureType string) (DestReply, error) {
|
||||||
|
var destReply DestReply
|
||||||
|
m.newDestHandler()
|
||||||
|
|
||||||
|
if signatureType == "" {
|
||||||
|
signatureType = "DSA_SHA1"
|
||||||
|
}
|
||||||
|
m.Send(fmt.Sprintf("DEST GENERATE SIGNATURE_TYPE=%s", signatureType))
|
||||||
|
for reply := range m.destHandler.incoming {
|
||||||
|
destReply = reply
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if destReply.err != nil {
|
||||||
|
return destReply, destReply.err
|
||||||
|
}
|
||||||
|
return destReply, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m SAMBridge) destReply(reply string) {
|
||||||
|
dest := DestReply{}
|
||||||
|
fields := strings.Fields(reply)
|
||||||
|
m.destHandler.m.Lock()
|
||||||
|
if fields[2] != "RESULT=OK" {
|
||||||
|
dest.err = errors.New(strings.TrimRight(strings.TrimLeft(strings.Join(fields[3:], " "), "MESSAGE=\""), "\""))
|
||||||
|
} else {
|
||||||
|
dest.Pub = strings.TrimPrefix(fields[2], "PUB=")
|
||||||
|
dest.Priv = strings.TrimPrefix(fields[3], "PRIV=")
|
||||||
|
dest.err = nil
|
||||||
|
}
|
||||||
|
m.destHandler.incoming <- dest
|
||||||
|
m.destHandler.m.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SAMBridge) pingReply(reply string) error {
|
||||||
|
s.Send(fmt.Sprintf("PONG %s", strings.TrimLeft(reply, "PING ")))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *SAMBridge) newDestHandler() {
|
||||||
|
if m.destHandler == nil {
|
||||||
|
dh := destHandler{}
|
||||||
|
dh.incoming = make(chan DestReply)
|
||||||
|
m.destHandler = &dh
|
||||||
|
}
|
||||||
|
}
|
104
session/master.go
Normal file
104
session/master.go
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
package session
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"yagsl/sambridge"
|
||||||
|
)
|
||||||
|
|
||||||
|
const masterSessionStyle string = "MASTER"
|
||||||
|
|
||||||
|
var errMasterSessionFailed = errors.New("Failed to start MasterSession")
|
||||||
|
|
||||||
|
type MasterSession struct {
|
||||||
|
Style string
|
||||||
|
ID string
|
||||||
|
Destination string
|
||||||
|
Transient bool
|
||||||
|
|
||||||
|
Sam *sambridge.SAMBridge
|
||||||
|
*Session
|
||||||
|
|
||||||
|
Ready chan bool
|
||||||
|
|
||||||
|
Subsessions []Subsession
|
||||||
|
|
||||||
|
// i2cp and streaming options go here
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMasterSession(destination string) (MasterSession, error) {
|
||||||
|
sb := new(sambridge.SAMBridge)
|
||||||
|
sb.Options.Address = "127.0.0.1:7656"
|
||||||
|
go sb.Start()
|
||||||
|
ms := MasterSession{Style: "MASTER"}
|
||||||
|
ms.Ready = make(chan bool, 1)
|
||||||
|
if destination == "" {
|
||||||
|
destination = "TRANSIENT"
|
||||||
|
ms.Transient = true
|
||||||
|
}
|
||||||
|
ms.Sam = sb
|
||||||
|
ms.Sam.SessionReply = make(chan sambridge.SessionReply)
|
||||||
|
go ms.newSessionHandler()
|
||||||
|
|
||||||
|
ms.Sam.StreamReply = make(chan sambridge.StreamReply)
|
||||||
|
go ms.newStreamHandler()
|
||||||
|
|
||||||
|
ms.ID = "master" + strconv.FormatInt(time.Now().UTC().Unix(), 10)
|
||||||
|
ms.Destination = destination
|
||||||
|
|
||||||
|
time.Sleep(time.Second * 1)
|
||||||
|
ms.Sam.Send(fmt.Sprintf("SESSION CREATE STYLE=MASTER ID=%s DESTINATION=%s\n", ms.ID, ms.Destination))
|
||||||
|
for ready := range ms.Ready {
|
||||||
|
if ready {
|
||||||
|
return ms, nil
|
||||||
|
}
|
||||||
|
return ms, errMasterSessionFailed
|
||||||
|
}
|
||||||
|
return ms, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MasterSession) NewSubsession(fromPort string, toPort string, listenPort string) Subsession {
|
||||||
|
ss := Subsession{}
|
||||||
|
|
||||||
|
ss.ID = "sub" + strconv.FormatInt(time.Now().UTC().Unix(), 10)
|
||||||
|
if listenPort != "" {
|
||||||
|
ms.Sam.Send(fmt.Sprintf("SESSION ADD STYLE=STREAM ID=%s FROM_PORT=%s LISTEN_PORT=%s SILENT=FALSE\n", ss.ID, fromPort, listenPort))
|
||||||
|
} else {
|
||||||
|
ms.Sam.Send(fmt.Sprintf("SESSION ADD STYLE=STREAM ID=%s FROM_PORT=%s SILENT=FALSE\n", ss.ID, fromPort))
|
||||||
|
}
|
||||||
|
|
||||||
|
ms.Subsessions = append(ms.Subsessions, ss)
|
||||||
|
|
||||||
|
return ss
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MasterSession) newSessionHandler() {
|
||||||
|
var sessionReply sambridge.SessionReply
|
||||||
|
for reply := range ms.Sam.SessionReply {
|
||||||
|
sessionReply = reply
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if sessionReply.Err != nil {
|
||||||
|
ms.Ready <- false
|
||||||
|
}
|
||||||
|
ms.Destination = sessionReply.Destination
|
||||||
|
ms.Ready <- true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MasterSession) newStreamHandler() {
|
||||||
|
var streamReply sambridge.StreamReply
|
||||||
|
for reply := range ms.Sam.StreamReply {
|
||||||
|
streamReply = reply
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if streamReply.Err != nil {
|
||||||
|
log.Printf("StreamReply err: %s", streamReply.Err.Error())
|
||||||
|
} else {
|
||||||
|
log.Printf("StreamReply success!")
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
51
session/session.go
Normal file
51
session/session.go
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package session
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Session struct {
|
||||||
|
Style string
|
||||||
|
ID string
|
||||||
|
Destination string
|
||||||
|
Options SessionOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
type SessionOptions struct {
|
||||||
|
Port string
|
||||||
|
Host string
|
||||||
|
FromPort string
|
||||||
|
ToPort string
|
||||||
|
ListenPort string
|
||||||
|
ListenProtcol string
|
||||||
|
Header bool
|
||||||
|
// i2cp and streaming options go here
|
||||||
|
}
|
||||||
|
|
||||||
|
type sessionHandler struct {
|
||||||
|
incoming chan reply
|
||||||
|
m sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
type reply struct {
|
||||||
|
full string
|
||||||
|
|
||||||
|
name string
|
||||||
|
value string
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Session) SessionCreate() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Session) sessionReply(reply string) error {
|
||||||
|
fields := strings.Fields(reply)
|
||||||
|
if strings.HasPrefix(fields[1], "RESULT=") {
|
||||||
|
log.Printf("Session status result: %s", fields[1:])
|
||||||
|
} else {
|
||||||
|
log.Printf("Got SESSION reply: %s", reply)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
77
session/subsession.go
Normal file
77
session/subsession.go
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
package session
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
"yagsl/sambridge"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Subsession struct {
|
||||||
|
*Session
|
||||||
|
ID string
|
||||||
|
Style string
|
||||||
|
Sam *sambridge.SAMBridge
|
||||||
|
Ready chan (bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
errSubSessionFailed = errors.New("the subsession failed :(")
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewStreamConnect(ID string, destination string, fromPort string) (Subsession, error) {
|
||||||
|
sb := new(sambridge.SAMBridge)
|
||||||
|
go sb.Start()
|
||||||
|
ss := Subsession{
|
||||||
|
Style: "STREAM",
|
||||||
|
ID: ID,
|
||||||
|
}
|
||||||
|
ss.Sam = sb
|
||||||
|
ss.Sam.SessionReply = make(chan sambridge.SessionReply)
|
||||||
|
go ss.newSessionHandler()
|
||||||
|
// TODO: Replace this handshake pause with a Ready callback to prevent a data race
|
||||||
|
time.Sleep(time.Second * 1)
|
||||||
|
// TODO: Refactor this sam.Send into a stream package w/a streamHandler and it's own connect message in that section
|
||||||
|
err := ss.Sam.Send(fmt.Sprintf("STREAM CONNECT ID=%s DESTINATION=%s FROM_PORT=%s TO_PORT=0 SILENT=FALSE\n", ID, destination, fromPort))
|
||||||
|
return ss, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStreamAccept(ID string) (Subsession, error) {
|
||||||
|
sb := new(sambridge.SAMBridge)
|
||||||
|
go sb.Start()
|
||||||
|
ss := Subsession{
|
||||||
|
Style: "STREAM",
|
||||||
|
ID: ID,
|
||||||
|
}
|
||||||
|
ss.Sam = sb
|
||||||
|
ss.Sam.SessionReply = make(chan sambridge.SessionReply)
|
||||||
|
go ss.newSessionHandler()
|
||||||
|
// TODO: Replace this handshake pause with a Ready callback to prevent a data race
|
||||||
|
time.Sleep(time.Second * 1)
|
||||||
|
// TODO: Refactor this sam.Send into a stream package w/a streamHandler and it's own connect message in that section
|
||||||
|
err := ss.Sam.Send(fmt.Sprintf("STREAM ACCEPT ID=%s SILENT=FALSE\n", ID))
|
||||||
|
return ss, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ss *Subsession) newSessionHandler() {
|
||||||
|
var sessionReply sambridge.SessionReply
|
||||||
|
for reply := range ss.Sam.SessionReply {
|
||||||
|
sessionReply = reply
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if sessionReply.Err != nil {
|
||||||
|
ss.Ready <- false
|
||||||
|
}
|
||||||
|
ss.Destination = sessionReply.Destination
|
||||||
|
ss.Ready <- true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ss *Subsession) Stop() error {
|
||||||
|
ss.Sam.Send(fmt.Sprintf("SESSION REMOVE ID=%s", ss.ID))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Subsession) Dial(network, addr string) (net.Conn, error) {
|
||||||
|
return s.Sam.Conn, nil
|
||||||
|
}
|
Reference in New Issue
Block a user