core: Handle response to outbound contact requests

This commit is contained in:
John Brooks 2016-10-28 09:50:04 -06:00
parent b6fd295ac1
commit 6f7e030811
2 changed files with 90 additions and 29 deletions

View File

@ -33,6 +33,8 @@ type Contact struct {
connChannel chan *protocol.OpenConnection connChannel chan *protocol.OpenConnection
connClosedChannel chan struct{} connClosedChannel chan struct{}
outboundConnAuthKnown bool
conversation *Conversation conversation *Conversation
} }
@ -247,10 +249,9 @@ func (c *Contact) connectOutbound(ctx context.Context, connChannel chan *protoco
oc, err := protocol.Open(conn, hostname[0:16]) oc, err := protocol.Open(conn, hostname[0:16])
if err != nil { if err != nil {
log.Printf("Contact connection protocol failure: %s", err) log.Printf("Contact connection protocol failure: %s", err)
if oc != nil {
oc.Close() oc.Close()
// XXX These failures are probably not worth retrying so much, }
// but that would need to be investigated. For now, just do the
// same backoff behavior.
if err := connector.Backoff(ctx); err != nil { if err := connector.Backoff(ctx); err != nil {
return return
} }
@ -303,6 +304,14 @@ func (c *Contact) setConnection(conn *protocol.OpenConnection) error {
return fmt.Errorf("Connection hostname %s doesn't match contact hostname %s when assigning connection", conn.OtherHostname, c.data.Hostname[0:16]) return fmt.Errorf("Connection hostname %s doesn't match contact hostname %s when assigning connection", conn.OtherHostname, c.data.Hostname[0:16])
} }
if conn.Client && !c.outboundConnAuthKnown && !c.data.Request.Pending {
log.Printf("Outbound connection to contact says we are not a known contact for %v", c)
// XXX Should move to rejected status, stop attempting connections.
c.mutex.Unlock()
conn.Close()
return fmt.Errorf("Outbound connection says we are not a known contact")
}
if c.connection != nil { if c.connection != nil {
if c.shouldReplaceConnection(conn) { if c.shouldReplaceConnection(conn) {
// XXX Signal state change for connection loss? // XXX Signal state change for connection loss?
@ -324,17 +333,17 @@ func (c *Contact) setConnection(conn *protocol.OpenConnection) error {
log.Printf("Assigned connection %v to contact %v", c.connection, c) log.Printf("Assigned connection %v to contact %v", c.connection, c)
if c.data.Request.Pending { if c.data.Request.Pending {
if conn.Client { if conn.Client && !c.outboundConnAuthKnown {
// XXX Need to check knownContact flag in authentication and implicit accept also
// Outbound connection for contact request; send request message // Outbound connection for contact request; send request message
// XXX hardcoded channel ID // XXX hardcoded channel ID
log.Printf("Sending outbound contact request to %v", c) log.Printf("Sending outbound contact request to %v", c)
conn.SendContactRequest(5, c.data.Request.MyNickname, c.data.Request.Message) conn.SendContactRequest(5, c.data.Request.MyNickname, c.data.Request.Message)
} else { } else {
// Inbound connection for contact request; implicitly accept request // Inbound connection or outbound connection with a positive
// and continue as contact // 'isKnownContact' response implicitly accepts the contact request
log.Printf("Contact request implicitly accepted by incoming connection for contact %v", c) // and can continue as a contact
c.requestAccepted() log.Printf("Contact request implicitly accepted by contact %v", c)
c.updateContactRequest("Accepted")
} }
} else { } else {
c.status = ricochet.Contact_ONLINE c.status = ricochet.Contact_ONLINE
@ -428,22 +437,72 @@ func (c *Contact) shouldReplaceConnection(conn *protocol.OpenConnection) bool {
return false return false
} }
// Assumes mutex is held, and assumes the caller will send the UPDATE event // Update the status of a contact request from a protocol event. Returns
func (c *Contact) requestAccepted() { // true if the contact request channel should remain open.
config := c.core.Config.OpenWrite() func (c *Contact) UpdateContactRequest(status string) bool {
c.data.Request = ConfigContactRequest{} c.mutex.Lock()
config.Contacts[strconv.Itoa(c.id)] = c.data defer c.mutex.Unlock()
config.Save()
if !c.data.Request.Pending {
return false
}
re := c.updateContactRequest(status)
event := ricochet.ContactEvent{
Type: ricochet.ContactEvent_UPDATE,
Subject: &ricochet.ContactEvent_Contact{
Contact: c.Data(),
},
}
c.events.Publish(event)
return re
}
// Same as above, but assumes the mutex is already held and that the caller
// will send an UPDATE event
func (c *Contact) updateContactRequest(status string) bool {
config := c.core.Config.OpenWrite()
now := time.Now().Format(time.RFC3339)
// Whether to keep the channel open
var re bool
switch status {
case "Pending":
c.data.Request.WhenDelivered = now
re = true
case "Accepted":
c.data.Request = ConfigContactRequest{}
if c.connection != nil { if c.connection != nil {
c.status = ricochet.Contact_ONLINE c.status = ricochet.Contact_ONLINE
} else { } else {
c.status = ricochet.Contact_UNKNOWN c.status = ricochet.Contact_UNKNOWN
} }
case "Rejected":
c.data.Request.WhenRejected = now
case "Error":
c.data.Request.WhenRejected = now
c.data.Request.RemoteError = "error occurred"
default:
log.Printf("Unknown contact request status '%s'", status)
}
config.Contacts[strconv.Itoa(c.id)] = c.data
config.Save()
return re
} }
// XXX also will go away during protocol API rework // XXX also will go away during protocol API rework
func (c *Contact) OnConnectionAuthenticated(conn *protocol.OpenConnection) { func (c *Contact) OnConnectionAuthenticated(conn *protocol.OpenConnection, knownContact bool) {
// XXX this is ugly
if conn.Client {
c.outboundConnAuthKnown = knownContact
}
c.connChannel <- conn c.connChannel <- conn
} }

View File

@ -73,7 +73,7 @@ func (pc *ProtocolConnection) OnAuthenticationProof(channelID int32, publicKey [
log.Printf("protocol: OnAuthenticationProof, result: %v, contact: %v", result, pc.Contact) log.Printf("protocol: OnAuthenticationProof, result: %v, contact: %v", result, pc.Contact)
if result && pc.Contact != nil { if result && pc.Contact != nil {
pc.Contact.OnConnectionAuthenticated(pc.Conn) pc.Contact.OnConnectionAuthenticated(pc.Conn, true)
} }
} }
@ -87,16 +87,9 @@ func (pc *ProtocolConnection) OnAuthenticationResult(channelID int32, result boo
return return
} }
// XXX Contact request, removed cases
if !isKnownContact {
log.Printf("protocol: Outbound connection authentication to %s succeeded, but we are not a known contact", pc.Conn.OtherHostname)
pc.Conn.Close()
return
}
log.Printf("protocol: Outbound connection to %s authenticated", pc.Conn.OtherHostname) log.Printf("protocol: Outbound connection to %s authenticated", pc.Conn.OtherHostname)
if pc.Contact != nil { if pc.Contact != nil {
pc.Contact.OnConnectionAuthenticated(pc.Conn) pc.Contact.OnConnectionAuthenticated(pc.Conn, isKnownContact)
} }
} }
@ -105,6 +98,15 @@ func (pc *ProtocolConnection) OnContactRequest(channelID int32, nick string, mes
} }
func (pc *ProtocolConnection) OnContactRequestAck(channelID int32, status string) { func (pc *ProtocolConnection) OnContactRequestAck(channelID int32, status string) {
if !pc.Conn.Client || pc.Contact == nil {
pc.Conn.CloseChannel(channelID)
return
}
if !pc.Contact.UpdateContactRequest(status) {
pc.Conn.CloseChannel(channelID)
return
}
} }
// Managing Channels // Managing Channels