2018-03-10 21:26:19 +00:00
|
|
|
package connections
|
|
|
|
|
|
|
|
import (
|
2018-10-05 03:18:34 +00:00
|
|
|
"crypto/rand"
|
2019-05-15 20:12:11 +00:00
|
|
|
"cwtch.im/cwtch/event"
|
2018-05-28 18:05:06 +00:00
|
|
|
"cwtch.im/cwtch/protocol"
|
2019-01-04 21:44:21 +00:00
|
|
|
"cwtch.im/cwtch/protocol/connections/fetch"
|
|
|
|
"cwtch.im/cwtch/protocol/connections/listen"
|
|
|
|
"cwtch.im/cwtch/protocol/connections/send"
|
2018-03-30 21:16:51 +00:00
|
|
|
"errors"
|
2018-06-23 16:15:36 +00:00
|
|
|
"git.openprivacy.ca/openprivacy/libricochet-go"
|
|
|
|
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
|
|
|
"git.openprivacy.ca/openprivacy/libricochet-go/connection"
|
|
|
|
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
2018-12-04 02:52:11 +00:00
|
|
|
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
2018-10-05 03:18:34 +00:00
|
|
|
"golang.org/x/crypto/ed25519"
|
2018-03-10 21:26:19 +00:00
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
2018-05-16 21:31:06 +00:00
|
|
|
// PeerServerConnection encapsulates a single Peer->Server connection
|
2018-03-10 21:26:19 +00:00
|
|
|
type PeerServerConnection struct {
|
|
|
|
connection.AutoConnectionHandler
|
2019-05-15 20:12:11 +00:00
|
|
|
Server string
|
|
|
|
state ConnectionState
|
|
|
|
connection *connection.Connection
|
|
|
|
protocolEngine Engine
|
2018-03-10 22:05:48 +00:00
|
|
|
|
|
|
|
GroupMessageHandler func(string, *protocol.GroupMessage)
|
2018-03-10 21:26:19 +00:00
|
|
|
}
|
|
|
|
|
2018-05-16 21:31:06 +00:00
|
|
|
// NewPeerServerConnection creates a new Peer->Server outbound connection
|
2019-05-15 20:12:11 +00:00
|
|
|
func NewPeerServerConnection(engine Engine, serverhostname string) *PeerServerConnection {
|
2018-03-10 21:26:19 +00:00
|
|
|
psc := new(PeerServerConnection)
|
2019-05-15 20:12:11 +00:00
|
|
|
psc.protocolEngine = engine
|
2018-03-10 21:26:19 +00:00
|
|
|
psc.Server = serverhostname
|
2019-06-21 21:50:43 +00:00
|
|
|
psc.setState(DISCONNECTED)
|
2018-03-10 21:26:19 +00:00
|
|
|
psc.Init()
|
|
|
|
return psc
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetState returns the current connection state
|
|
|
|
func (psc *PeerServerConnection) GetState() ConnectionState {
|
|
|
|
return psc.state
|
|
|
|
}
|
|
|
|
|
2019-05-15 20:12:11 +00:00
|
|
|
func (psc *PeerServerConnection) setState(state ConnectionState) {
|
2019-06-21 21:50:43 +00:00
|
|
|
log.Debugf("Setting State to %v for %v\n", ConnectionStateName[state], psc.Server)
|
2019-05-15 20:12:11 +00:00
|
|
|
psc.state = state
|
|
|
|
psc.protocolEngine.EventManager().Publish(event.NewEvent(event.ServerStateChange, map[event.Field]string{
|
|
|
|
event.GroupServer: string(psc.Server),
|
|
|
|
event.ConnectionState: ConnectionStateName[state],
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
2019-07-19 17:27:50 +00:00
|
|
|
// WaitTilSynced waits until the underlying connection is authenticated
|
|
|
|
func (psc *PeerServerConnection) WaitTilSynced() {
|
2018-10-10 21:59:38 +00:00
|
|
|
for {
|
2019-07-19 17:27:50 +00:00
|
|
|
if psc.GetState() == SYNCED {
|
2018-10-10 21:59:38 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
time.Sleep(time.Second * 1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-10 21:26:19 +00:00
|
|
|
// Run manages the setup and teardown of a peer server connection
|
|
|
|
func (psc *PeerServerConnection) Run() error {
|
2018-12-04 02:52:11 +00:00
|
|
|
log.Infof("Connecting to %v", psc.Server)
|
2019-06-21 21:50:43 +00:00
|
|
|
psc.setState(CONNECTING)
|
|
|
|
|
2019-05-15 20:12:11 +00:00
|
|
|
rc, err := goricochet.Open(psc.protocolEngine.ACN(), psc.Server)
|
2018-03-10 21:26:19 +00:00
|
|
|
if err == nil {
|
2018-05-20 18:29:46 +00:00
|
|
|
psc.connection = rc
|
2019-06-21 21:50:43 +00:00
|
|
|
if psc.GetState() == KILLED {
|
|
|
|
return nil
|
|
|
|
}
|
2019-05-15 20:12:11 +00:00
|
|
|
psc.setState(CONNECTED)
|
2018-11-24 01:58:45 +00:00
|
|
|
pub, priv, err := ed25519.GenerateKey(rand.Reader)
|
2018-03-10 21:26:19 +00:00
|
|
|
if err == nil {
|
2018-10-05 03:18:34 +00:00
|
|
|
_, err := connection.HandleOutboundConnection(psc.connection).ProcessAuthAsV3Client(identity.InitializeV3("cwtchpeer", &priv, &pub))
|
2018-03-10 21:26:19 +00:00
|
|
|
if err == nil {
|
2019-06-21 21:50:43 +00:00
|
|
|
if psc.GetState() == KILLED {
|
|
|
|
return nil
|
|
|
|
}
|
2019-05-15 20:12:11 +00:00
|
|
|
psc.setState(AUTHENTICATED)
|
2018-03-10 22:05:48 +00:00
|
|
|
|
|
|
|
go func() {
|
|
|
|
psc.connection.Do(func() error {
|
|
|
|
psc.connection.RequestOpenChannel("im.cwtch.server.fetch", &fetch.CwtchPeerFetchChannel{Handler: psc})
|
|
|
|
return nil
|
|
|
|
})
|
2018-03-14 22:03:53 +00:00
|
|
|
|
|
|
|
psc.connection.Do(func() error {
|
|
|
|
psc.connection.RequestOpenChannel("im.cwtch.server.listen", &listen.CwtchPeerListenChannel{Handler: psc})
|
|
|
|
return nil
|
|
|
|
})
|
2018-03-10 22:05:48 +00:00
|
|
|
}()
|
2018-03-10 21:26:19 +00:00
|
|
|
psc.connection.Process(psc)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-05-15 20:12:11 +00:00
|
|
|
psc.setState(FAILED)
|
2018-03-10 21:26:19 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Break makes Run() return and prevents processing, but doesn't close the connection.
|
|
|
|
func (psc *PeerServerConnection) Break() error {
|
|
|
|
return psc.connection.Break()
|
|
|
|
}
|
|
|
|
|
2018-05-16 21:31:06 +00:00
|
|
|
// SendGroupMessage sends the given protocol message to the Server.
|
2018-05-09 19:09:00 +00:00
|
|
|
func (psc *PeerServerConnection) SendGroupMessage(gm *protocol.GroupMessage) error {
|
2019-07-19 17:27:50 +00:00
|
|
|
if psc.state != SYNCED {
|
|
|
|
return errors.New("peer is not yet connected & authenticated & synced to server cannot send message")
|
2018-03-30 21:16:51 +00:00
|
|
|
}
|
2018-05-09 19:09:00 +00:00
|
|
|
|
|
|
|
err := psc.connection.Do(func() error {
|
2018-03-10 22:05:48 +00:00
|
|
|
psc.connection.RequestOpenChannel("im.cwtch.server.send", &send.CwtchPeerSendChannel{})
|
|
|
|
return nil
|
|
|
|
})
|
2018-05-09 19:09:00 +00:00
|
|
|
|
|
|
|
errCount := 0
|
|
|
|
for errCount < 5 {
|
2019-03-25 20:01:24 +00:00
|
|
|
time.Sleep(time.Second * time.Duration(errCount+1)) // back off retry
|
2018-05-09 19:09:00 +00:00
|
|
|
err = psc.connection.Do(func() error {
|
|
|
|
channel := psc.connection.Channel("im.cwtch.server.send", channels.Outbound)
|
|
|
|
if channel == nil {
|
|
|
|
return errors.New("no channel found")
|
|
|
|
}
|
|
|
|
sendchannel, ok := channel.Handler.(*send.CwtchPeerSendChannel)
|
|
|
|
if ok {
|
|
|
|
return sendchannel.SendGroupMessage(gm)
|
|
|
|
}
|
|
|
|
return errors.New("channel is not a peer send channel (this should definitely not happen)")
|
|
|
|
})
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
errCount++
|
2018-03-30 21:16:51 +00:00
|
|
|
} else {
|
2018-05-09 19:09:00 +00:00
|
|
|
return nil
|
2018-03-10 22:05:48 +00:00
|
|
|
}
|
2018-03-30 21:16:51 +00:00
|
|
|
}
|
|
|
|
|
2018-05-09 19:09:00 +00:00
|
|
|
return err
|
2018-03-10 21:26:19 +00:00
|
|
|
}
|
|
|
|
|
2018-06-15 16:21:07 +00:00
|
|
|
// Close shuts down the connection (freeing the handler goroutines)
|
2018-05-30 18:42:17 +00:00
|
|
|
func (psc *PeerServerConnection) Close() {
|
2019-05-15 20:12:11 +00:00
|
|
|
psc.setState(KILLED)
|
2018-10-06 03:50:55 +00:00
|
|
|
if psc.connection != nil {
|
2019-01-21 20:37:06 +00:00
|
|
|
psc.connection.Close()
|
2018-10-06 03:50:55 +00:00
|
|
|
}
|
2018-05-30 18:42:17 +00:00
|
|
|
}
|
|
|
|
|
2018-05-16 21:31:06 +00:00
|
|
|
// HandleGroupMessage passes the given group message back to the profile.
|
2018-03-10 22:05:48 +00:00
|
|
|
func (psc *PeerServerConnection) HandleGroupMessage(gm *protocol.GroupMessage) {
|
|
|
|
psc.GroupMessageHandler(psc.Server, gm)
|
2018-03-10 21:26:19 +00:00
|
|
|
}
|
2019-04-23 20:30:50 +00:00
|
|
|
|
|
|
|
// HandleFetchDone calls the supplied callback for when a fetch connection is closed
|
|
|
|
func (psc *PeerServerConnection) HandleFetchDone() {
|
2019-07-19 17:27:50 +00:00
|
|
|
psc.setState(SYNCED)
|
2019-04-23 20:30:50 +00:00
|
|
|
}
|