2017-05-02 23:33:51 +00:00
|
|
|
package application
|
|
|
|
|
|
|
|
import (
|
2018-06-08 21:54:31 +00:00
|
|
|
"git.openprivacy.ca/openprivacy/libricochet-go"
|
|
|
|
"git.openprivacy.ca/openprivacy/libricochet-go/connection"
|
2018-11-09 21:33:35 +00:00
|
|
|
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
|
2018-06-08 21:54:31 +00:00
|
|
|
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
2018-11-30 21:04:38 +00:00
|
|
|
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
2017-07-04 18:29:11 +00:00
|
|
|
"net"
|
2018-01-01 18:06:58 +00:00
|
|
|
"sync"
|
2017-05-02 23:33:51 +00:00
|
|
|
)
|
|
|
|
|
2018-11-09 21:33:35 +00:00
|
|
|
const (
|
|
|
|
// RicochetPort is the default port used by ricochet applications
|
|
|
|
RicochetPort = 9878
|
|
|
|
)
|
|
|
|
|
2017-05-02 23:33:51 +00:00
|
|
|
// RicochetApplication bundles many useful constructs that are
|
|
|
|
// likely standard in a ricochet application
|
|
|
|
type RicochetApplication struct {
|
2018-01-08 00:51:46 +00:00
|
|
|
contactManager ContactManagerInterface
|
2018-09-22 20:12:08 +00:00
|
|
|
v3identity identity.Identity
|
2018-05-30 17:51:40 +00:00
|
|
|
name string
|
2018-11-09 21:33:35 +00:00
|
|
|
ls connectivity.ListenService
|
2018-11-22 06:15:35 +00:00
|
|
|
acn connectivity.ACN
|
2019-01-21 22:52:26 +00:00
|
|
|
instances []*Instance
|
2018-01-08 00:51:46 +00:00
|
|
|
lock sync.Mutex
|
2019-01-21 22:52:26 +00:00
|
|
|
aif InstanceFactory
|
2017-05-02 23:33:51 +00:00
|
|
|
}
|
|
|
|
|
2018-11-09 21:33:35 +00:00
|
|
|
// Init initializes the underlying RicochetApplication datastructure, making it ready for use
|
2019-01-21 22:52:26 +00:00
|
|
|
func (ra *RicochetApplication) Init(acn connectivity.ACN, name string, v3identity identity.Identity, af InstanceFactory, cm ContactManagerInterface) {
|
2018-11-22 06:15:35 +00:00
|
|
|
ra.acn = acn
|
2018-09-22 20:12:08 +00:00
|
|
|
ra.name = name
|
|
|
|
ra.v3identity = v3identity
|
|
|
|
ra.aif = af
|
|
|
|
ra.contactManager = cm
|
|
|
|
}
|
|
|
|
|
2018-01-10 01:31:54 +00:00
|
|
|
// TODO: Reimplement OnJoin, OnLeave Events.
|
2017-07-04 18:29:11 +00:00
|
|
|
func (ra *RicochetApplication) handleConnection(conn net.Conn) {
|
|
|
|
rc, err := goricochet.NegotiateVersionInbound(conn)
|
|
|
|
if err != nil {
|
2018-11-30 21:04:38 +00:00
|
|
|
log.Errorln("There was an error")
|
2017-07-04 18:29:11 +00:00
|
|
|
conn.Close()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ich := connection.HandleInboundConnection(rc)
|
|
|
|
|
2018-11-09 21:33:35 +00:00
|
|
|
err = ich.ProcessAuthAsV3Server(ra.v3identity, ra.contactManager.LookupContactV3)
|
2018-09-22 20:12:08 +00:00
|
|
|
|
2017-07-04 18:29:11 +00:00
|
|
|
if err != nil {
|
2018-11-30 21:04:38 +00:00
|
|
|
log.Errorf("There was an error authenticating the connection: %v", err)
|
2017-07-04 18:29:11 +00:00
|
|
|
conn.Close()
|
|
|
|
return
|
|
|
|
}
|
2018-09-22 20:12:08 +00:00
|
|
|
|
2018-01-08 00:51:46 +00:00
|
|
|
rai := ra.aif.GetApplicationInstance(rc)
|
2018-01-01 18:06:58 +00:00
|
|
|
ra.lock.Lock()
|
|
|
|
ra.instances = append(ra.instances, rai)
|
|
|
|
ra.lock.Unlock()
|
2017-07-04 18:29:11 +00:00
|
|
|
rc.Process(rai)
|
2018-06-23 15:35:51 +00:00
|
|
|
|
|
|
|
// rc.Process ends when the connection ends.
|
|
|
|
// Remove it from the application's list of instances
|
|
|
|
ra.lock.Lock()
|
|
|
|
for i, x := range ra.instances {
|
|
|
|
if x == rai {
|
2018-06-25 16:14:24 +00:00
|
|
|
ra.instances = append(ra.instances[:i], ra.instances[i+1:]...)
|
2018-06-23 15:35:51 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ra.lock.Unlock()
|
2017-07-04 18:29:11 +00:00
|
|
|
}
|
|
|
|
|
2019-01-21 22:52:26 +00:00
|
|
|
// HandleApplicationInstance delegates handling of a given Instance to the Application.
|
|
|
|
func (ra *RicochetApplication) HandleApplicationInstance(rai *Instance) {
|
2018-05-09 19:02:25 +00:00
|
|
|
ra.lock.Lock()
|
|
|
|
ra.instances = append(ra.instances, rai)
|
|
|
|
ra.lock.Unlock()
|
|
|
|
}
|
|
|
|
|
2018-11-30 21:04:38 +00:00
|
|
|
// Open a connection to another Ricochet peer at onionAddress. Infof they are unknown to use, use requestMessage (otherwise can be blank)
|
2019-01-21 22:52:26 +00:00
|
|
|
func (ra *RicochetApplication) Open(onionAddress string, requestMessage string) (*Instance, error) {
|
2018-11-22 06:15:35 +00:00
|
|
|
rc, err := goricochet.Open(ra.acn, onionAddress)
|
2018-05-30 17:51:40 +00:00
|
|
|
if err != nil {
|
2018-11-30 21:04:38 +00:00
|
|
|
log.Errorf("Error in application.Open(): %v\n", err)
|
2018-05-30 17:51:40 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-09-22 20:12:08 +00:00
|
|
|
och := connection.HandleOutboundConnection(rc)
|
|
|
|
|
2019-01-08 19:05:01 +00:00
|
|
|
_, err = och.ProcessAuthAsV3Client(ra.v3identity)
|
2018-09-22 20:12:08 +00:00
|
|
|
|
|
|
|
if err != nil {
|
2018-11-30 21:04:38 +00:00
|
|
|
log.Errorf("There was an error authenticating the connection: %v", err)
|
2018-09-22 20:12:08 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
2018-05-30 17:51:40 +00:00
|
|
|
rai := ra.aif.GetApplicationInstance(rc)
|
|
|
|
go rc.Process(rai)
|
|
|
|
|
|
|
|
ra.HandleApplicationInstance(rai)
|
|
|
|
return rai, nil
|
|
|
|
}
|
|
|
|
|
2019-01-09 22:33:33 +00:00
|
|
|
// Broadcast performs the given function do() over all application instance (all connected peers)
|
2019-01-21 22:52:26 +00:00
|
|
|
func (ra *RicochetApplication) Broadcast(do func(rai *Instance)) {
|
2018-01-02 17:23:20 +00:00
|
|
|
ra.lock.Lock()
|
|
|
|
for _, rai := range ra.instances {
|
2018-01-08 00:51:46 +00:00
|
|
|
do(rai)
|
2018-01-02 17:23:20 +00:00
|
|
|
}
|
|
|
|
ra.lock.Unlock()
|
2018-01-01 18:06:58 +00:00
|
|
|
}
|
|
|
|
|
2018-11-09 21:33:35 +00:00
|
|
|
// Shutdown stops a RicochetApplication, terminating all child processes and resources
|
2017-11-02 23:43:11 +00:00
|
|
|
func (ra *RicochetApplication) Shutdown() {
|
2018-06-23 15:35:51 +00:00
|
|
|
ra.lock.Lock()
|
2018-11-09 21:33:35 +00:00
|
|
|
ra.ls.Close()
|
2018-05-30 17:51:40 +00:00
|
|
|
for _, instance := range ra.instances {
|
2019-01-11 20:28:50 +00:00
|
|
|
instance.Connection.Close()
|
|
|
|
}
|
|
|
|
ra.lock.Unlock()
|
|
|
|
}
|
|
|
|
|
2019-01-21 22:52:26 +00:00
|
|
|
// Close kills a connection by a given Onion Address
|
2019-01-11 20:28:50 +00:00
|
|
|
func (ra *RicochetApplication) Close(onion string) {
|
|
|
|
ra.lock.Lock()
|
|
|
|
for _, instance := range ra.instances {
|
|
|
|
if instance.RemoteHostname == onion {
|
|
|
|
instance.Connection.Close()
|
|
|
|
}
|
2018-05-30 17:51:40 +00:00
|
|
|
}
|
2018-06-23 15:35:51 +00:00
|
|
|
ra.lock.Unlock()
|
|
|
|
}
|
|
|
|
|
2019-01-09 22:33:33 +00:00
|
|
|
// ConnectionCount returns the number of concurrent connections to the application
|
2018-06-23 15:35:51 +00:00
|
|
|
func (ra *RicochetApplication) ConnectionCount() int {
|
|
|
|
return len(ra.instances)
|
2017-07-04 18:39:19 +00:00
|
|
|
}
|
|
|
|
|
2018-11-09 21:33:35 +00:00
|
|
|
// Run handles a Listen object and Accepts and handles new connections
|
|
|
|
func (ra *RicochetApplication) Run(ls connectivity.ListenService) {
|
|
|
|
if !ra.v3identity.Initialized() || ra.contactManager == nil {
|
2017-07-04 18:29:11 +00:00
|
|
|
return
|
|
|
|
}
|
2019-11-08 00:11:14 +00:00
|
|
|
ra.lock.Lock()
|
2018-11-09 21:33:35 +00:00
|
|
|
ra.ls = ls
|
2019-11-08 00:11:14 +00:00
|
|
|
ra.lock.Unlock()
|
2017-11-02 23:43:11 +00:00
|
|
|
var err error
|
2017-07-04 18:39:19 +00:00
|
|
|
for err == nil {
|
2018-11-09 21:33:35 +00:00
|
|
|
conn, err := ra.ls.Accept()
|
2017-07-04 18:29:11 +00:00
|
|
|
if err == nil {
|
|
|
|
go ra.handleConnection(conn)
|
2017-07-04 18:39:19 +00:00
|
|
|
} else {
|
2017-11-02 23:43:11 +00:00
|
|
|
return
|
2017-07-04 18:29:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|