2018-03-11 18:49:10 +00:00
|
|
|
package connections
|
|
|
|
|
|
|
|
import (
|
2018-06-29 19:20:07 +00:00
|
|
|
"cwtch.im/cwtch/model"
|
2018-05-28 18:05:06 +00:00
|
|
|
"cwtch.im/cwtch/peer/peer"
|
|
|
|
"cwtch.im/cwtch/protocol"
|
2018-06-23 16:15:36 +00:00
|
|
|
"git.openprivacy.ca/openprivacy/libricochet-go"
|
2018-10-29 19:19:30 +00:00
|
|
|
"git.openprivacy.ca/openprivacy/libricochet-go/application"
|
2018-06-23 16:15:36 +00:00
|
|
|
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
|
|
|
"git.openprivacy.ca/openprivacy/libricochet-go/connection"
|
2018-11-10 22:14:12 +00:00
|
|
|
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
|
2018-06-23 16:15:36 +00:00
|
|
|
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
2018-05-01 21:36:03 +00:00
|
|
|
"log"
|
2018-03-14 22:23:35 +00:00
|
|
|
"time"
|
2018-03-11 18:49:10 +00:00
|
|
|
)
|
|
|
|
|
2018-10-06 03:50:55 +00:00
|
|
|
// PeerPeerConnection encapsulates a single outgoing cwtchPeer->cwtchPeer connection
|
2018-03-11 18:49:10 +00:00
|
|
|
type PeerPeerConnection struct {
|
|
|
|
connection.AutoConnectionHandler
|
|
|
|
PeerHostname string
|
|
|
|
state ConnectionState
|
2018-05-20 18:29:46 +00:00
|
|
|
connection *connection.Connection
|
2018-03-14 22:23:35 +00:00
|
|
|
profile *model.Profile
|
2018-10-04 19:15:03 +00:00
|
|
|
dataHandler func(string, []byte) []byte
|
2018-10-27 08:49:30 +00:00
|
|
|
aif application.ApplicationInstanceFactory
|
2018-11-21 23:10:02 +00:00
|
|
|
mn connectivity.ACN
|
2018-03-11 18:49:10 +00:00
|
|
|
}
|
|
|
|
|
2018-05-16 21:31:06 +00:00
|
|
|
// NewPeerPeerConnection creates a new peer connection for the given hostname and profile.
|
2018-11-21 23:10:02 +00:00
|
|
|
func NewPeerPeerConnection(mn connectivity.ACN, peerhostname string, profile *model.Profile, dataHandler func(string, []byte) []byte, aif application.ApplicationInstanceFactory) *PeerPeerConnection {
|
2018-03-11 18:49:10 +00:00
|
|
|
ppc := new(PeerPeerConnection)
|
2018-11-10 22:14:12 +00:00
|
|
|
ppc.mn = mn
|
2018-03-11 18:49:10 +00:00
|
|
|
ppc.PeerHostname = peerhostname
|
2018-03-11 19:05:35 +00:00
|
|
|
ppc.profile = profile
|
2018-10-04 19:15:03 +00:00
|
|
|
ppc.dataHandler = dataHandler
|
2018-10-27 08:49:30 +00:00
|
|
|
ppc.aif = aif
|
2018-03-11 18:49:10 +00:00
|
|
|
ppc.Init()
|
|
|
|
return ppc
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetState returns the current connection state
|
|
|
|
func (ppc *PeerPeerConnection) GetState() ConnectionState {
|
|
|
|
return ppc.state
|
|
|
|
}
|
|
|
|
|
2018-05-16 21:31:06 +00:00
|
|
|
// HandleGroupInvite passes the given group invite tothe profile
|
2018-03-12 18:43:51 +00:00
|
|
|
func (ppc *PeerPeerConnection) HandleGroupInvite(gci *protocol.GroupChatInvite) {
|
2018-03-15 20:53:22 +00:00
|
|
|
ppc.profile.ProcessInvite(gci, ppc.PeerHostname)
|
2018-03-12 18:43:51 +00:00
|
|
|
}
|
|
|
|
|
2018-10-04 19:15:03 +00:00
|
|
|
// HandlePacket handles data packets on the optional data channel
|
|
|
|
func (ppc *PeerPeerConnection) HandlePacket(data []byte) []byte {
|
|
|
|
return ppc.dataHandler(ppc.PeerHostname, data)
|
|
|
|
}
|
|
|
|
|
|
|
|
// SendPacket sends data packets on the optional data channel
|
|
|
|
func (ppc *PeerPeerConnection) SendPacket(data []byte) {
|
|
|
|
ppc.WaitTilAuthenticated()
|
|
|
|
ppc.connection.Do(func() error {
|
|
|
|
channel := ppc.connection.Channel("im.cwtch.peer.data", channels.Outbound)
|
|
|
|
if channel != nil {
|
|
|
|
peerchannel, ok := channel.Handler.(*peer.CwtchPeerDataChannel)
|
|
|
|
if ok {
|
|
|
|
log.Printf("Sending packet\n")
|
|
|
|
peerchannel.SendMessage(data)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-10-29 19:19:30 +00:00
|
|
|
// DoOnChannel performs an operation on the requested channel
|
2018-10-27 08:49:30 +00:00
|
|
|
func (ppc *PeerPeerConnection) DoOnChannel(ctype string, direction channels.Direction, doSomethingWith func(channel *channels.Channel)) {
|
|
|
|
ppc.WaitTilAuthenticated()
|
|
|
|
ppc.connection.Do(func() error {
|
|
|
|
channel := ppc.connection.Channel(ctype, direction)
|
|
|
|
if channel != nil {
|
|
|
|
doSomethingWith(channel)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-05-16 21:31:06 +00:00
|
|
|
// SendGroupInvite sends the given serialized invite packet to the Peer
|
2018-03-12 18:43:51 +00:00
|
|
|
func (ppc *PeerPeerConnection) SendGroupInvite(invite []byte) {
|
2018-10-04 19:15:03 +00:00
|
|
|
ppc.WaitTilAuthenticated()
|
2018-03-14 22:23:35 +00:00
|
|
|
ppc.connection.Do(func() error {
|
|
|
|
channel := ppc.connection.Channel("im.cwtch.peer", channels.Outbound)
|
|
|
|
if channel != nil {
|
|
|
|
peerchannel, ok := channel.Handler.(*peer.CwtchPeerChannel)
|
|
|
|
if ok {
|
2018-05-01 21:36:03 +00:00
|
|
|
log.Printf("Sending group invite packet\n")
|
2018-03-14 22:23:35 +00:00
|
|
|
peerchannel.SendMessage(invite)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
2018-03-11 19:05:35 +00:00
|
|
|
}
|
|
|
|
|
2018-10-04 19:15:03 +00:00
|
|
|
// WaitTilAuthenticated waits until the underlying connection is authenticated
|
|
|
|
func (ppc *PeerPeerConnection) WaitTilAuthenticated() {
|
|
|
|
for {
|
|
|
|
if ppc.GetState() == AUTHENTICATED {
|
|
|
|
break
|
|
|
|
}
|
2018-10-10 21:59:38 +00:00
|
|
|
time.Sleep(time.Second * 1)
|
2018-10-04 19:15:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-11 18:49:10 +00:00
|
|
|
// Run manages the setup and teardown of a peer->peer connection
|
|
|
|
func (ppc *PeerPeerConnection) Run() error {
|
2018-05-01 20:44:45 +00:00
|
|
|
ppc.state = CONNECTING
|
2018-11-10 22:14:12 +00:00
|
|
|
rc, err := goricochet.Open(ppc.mn, ppc.PeerHostname)
|
2018-03-11 18:49:10 +00:00
|
|
|
if err == nil {
|
2018-05-01 20:44:45 +00:00
|
|
|
rc.TraceLog(false)
|
2018-05-20 18:29:46 +00:00
|
|
|
ppc.connection = rc
|
2018-03-11 18:49:10 +00:00
|
|
|
ppc.state = CONNECTED
|
2018-10-05 03:18:34 +00:00
|
|
|
_, err := connection.HandleOutboundConnection(ppc.connection).ProcessAuthAsV3Client(identity.InitializeV3(ppc.profile.Name, &ppc.profile.Ed25519PrivateKey, &ppc.profile.Ed25519PublicKey))
|
2018-03-11 19:05:35 +00:00
|
|
|
if err == nil {
|
|
|
|
ppc.state = AUTHENTICATED
|
|
|
|
go func() {
|
|
|
|
ppc.connection.Do(func() error {
|
|
|
|
ppc.connection.RequestOpenChannel("im.cwtch.peer", &peer.CwtchPeerChannel{Handler: ppc})
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
2018-10-04 19:15:03 +00:00
|
|
|
if ppc.dataHandler != nil {
|
|
|
|
ppc.connection.Do(func() error {
|
|
|
|
ppc.connection.RequestOpenChannel("im.cwtch.peer.data", &peer.CwtchPeerDataChannel{Handler: ppc})
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-10-27 08:49:30 +00:00
|
|
|
handlers := ppc.aif.GetHandlers()
|
|
|
|
for i := range handlers {
|
|
|
|
ppc.connection.Do(func() error {
|
|
|
|
ppc.connection.RequestOpenChannel(handlers[i], ppc.aif.GetHandler(handlers[i])(ppc.aif.GetApplicationInstance(ppc.connection))())
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
2018-03-11 19:05:35 +00:00
|
|
|
}()
|
|
|
|
|
|
|
|
ppc.connection.Process(ppc)
|
|
|
|
}
|
2018-03-11 18:49:10 +00:00
|
|
|
}
|
2018-03-15 20:53:22 +00:00
|
|
|
ppc.state = FAILED
|
2018-03-11 18:49:10 +00:00
|
|
|
return err
|
|
|
|
}
|
2018-05-30 17:41:02 +00:00
|
|
|
|
2018-05-30 18:42:17 +00:00
|
|
|
// Close closes the connection
|
|
|
|
func (ppc *PeerPeerConnection) Close() {
|
2018-05-30 17:41:02 +00:00
|
|
|
ppc.state = KILLED
|
2018-06-05 22:06:38 +00:00
|
|
|
ppc.connection.Conn.Close()
|
2018-05-30 17:41:02 +00:00
|
|
|
}
|