2019-07-26 20:51:29 +00:00
|
|
|
// +build !windows
|
|
|
|
|
2019-06-21 21:50:43 +00:00
|
|
|
package bridge
|
|
|
|
|
|
|
|
import (
|
2020-02-03 18:46:15 +00:00
|
|
|
"cwtch.im/cwtch/event"
|
2019-07-10 20:30:24 +00:00
|
|
|
"cwtch.im/cwtch/protocol/connections"
|
2019-07-06 00:46:51 +00:00
|
|
|
"encoding/base64"
|
|
|
|
"encoding/binary"
|
2019-06-21 21:50:43 +00:00
|
|
|
"encoding/json"
|
2020-02-10 22:09:24 +00:00
|
|
|
"git.openprivacy.ca/openprivacy/log"
|
2019-06-21 21:50:43 +00:00
|
|
|
"os"
|
|
|
|
"sync"
|
2020-02-03 18:46:15 +00:00
|
|
|
"syscall"
|
|
|
|
"time"
|
2019-06-21 21:50:43 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
/* pipeBridge creates a pair of named pipes
|
|
|
|
Needs a call to new client and service to fully successfully open
|
|
|
|
*/
|
|
|
|
|
2019-07-10 20:30:24 +00:00
|
|
|
const maxBufferSize = 1000
|
|
|
|
|
2019-09-05 17:59:55 +00:00
|
|
|
const serviceName = "service"
|
|
|
|
const clientName = "client"
|
|
|
|
|
|
|
|
const syn = "SYN"
|
|
|
|
const synack = "SYNACK"
|
|
|
|
const ack = "ACK"
|
|
|
|
|
2019-06-21 21:50:43 +00:00
|
|
|
type pipeBridge struct {
|
2019-07-10 20:30:24 +00:00
|
|
|
infile, outfile string
|
|
|
|
in, out *os.File
|
2019-09-05 17:59:55 +00:00
|
|
|
read chan event.IPCMessage
|
|
|
|
write *InfiniteChannel
|
2019-07-10 20:30:24 +00:00
|
|
|
closedChan chan bool
|
|
|
|
state connections.ConnectionState
|
|
|
|
lock sync.Mutex
|
2019-09-19 23:14:35 +00:00
|
|
|
threeShake func() bool
|
2019-07-19 17:27:50 +00:00
|
|
|
|
|
|
|
// For logging / debugging purposes
|
|
|
|
name string
|
2019-06-21 21:50:43 +00:00
|
|
|
}
|
|
|
|
|
2019-07-10 20:30:24 +00:00
|
|
|
func newPipeBridge(inFilename, outFilename string) *pipeBridge {
|
2019-06-21 21:50:43 +00:00
|
|
|
syscall.Mkfifo(inFilename, 0600)
|
|
|
|
syscall.Mkfifo(outFilename, 0600)
|
2019-07-10 20:30:24 +00:00
|
|
|
pb := &pipeBridge{infile: inFilename, outfile: outFilename, state: connections.DISCONNECTED}
|
|
|
|
pb.read = make(chan event.IPCMessage, maxBufferSize)
|
2019-09-05 17:59:55 +00:00
|
|
|
pb.write = newInfiniteChannel() //make(chan event.IPCMessage, maxBufferSize)
|
2019-07-10 20:30:24 +00:00
|
|
|
return pb
|
|
|
|
}
|
2019-06-21 21:50:43 +00:00
|
|
|
|
2019-07-10 20:30:24 +00:00
|
|
|
// NewPipeBridgeClient returns a pipe backed IPCBridge for a client
|
|
|
|
func NewPipeBridgeClient(inFilename, outFilename string) event.IPCBridge {
|
|
|
|
log.Debugf("Making new PipeBridge Client...\n")
|
|
|
|
pb := newPipeBridge(inFilename, outFilename)
|
2019-09-05 17:59:55 +00:00
|
|
|
pb.name = clientName
|
|
|
|
pb.threeShake = pb.threeShakeClient
|
2019-07-19 17:27:50 +00:00
|
|
|
go pb.connectionManager()
|
2019-07-10 20:30:24 +00:00
|
|
|
|
|
|
|
return pb
|
2019-06-21 21:50:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewPipeBridgeService returns a pipe backed IPCBridge for a service
|
2019-07-19 17:27:50 +00:00
|
|
|
func NewPipeBridgeService(inFilename, outFilename string) event.IPCBridge {
|
2019-06-21 21:50:43 +00:00
|
|
|
log.Debugf("Making new PipeBridge Service...\n")
|
2019-07-10 20:30:24 +00:00
|
|
|
pb := newPipeBridge(inFilename, outFilename)
|
2019-09-05 17:59:55 +00:00
|
|
|
pb.name = serviceName
|
|
|
|
pb.threeShake = pb.threeShakeService
|
2019-06-21 21:50:43 +00:00
|
|
|
|
2019-07-19 17:27:50 +00:00
|
|
|
go pb.connectionManager()
|
2019-06-21 21:50:43 +00:00
|
|
|
|
|
|
|
log.Debugf("Successfully created new PipeBridge Service!\n")
|
2019-07-19 17:27:50 +00:00
|
|
|
return pb
|
2019-06-21 21:50:43 +00:00
|
|
|
}
|
|
|
|
|
2020-02-03 18:46:15 +00:00
|
|
|
func (pb *pipeBridge) setState(state connections.ConnectionState) {
|
|
|
|
pb.lock.Lock()
|
|
|
|
defer pb.lock.Unlock()
|
|
|
|
|
|
|
|
pb.state = state
|
|
|
|
}
|
|
|
|
|
|
|
|
func (pb *pipeBridge) getState() connections.ConnectionState {
|
|
|
|
pb.lock.Lock()
|
|
|
|
defer pb.lock.Unlock()
|
|
|
|
|
|
|
|
return pb.state
|
|
|
|
}
|
|
|
|
|
2019-07-19 17:27:50 +00:00
|
|
|
func (pb *pipeBridge) connectionManager() {
|
2020-02-03 18:46:15 +00:00
|
|
|
for pb.getState() != connections.KILLED {
|
2019-07-19 17:27:50 +00:00
|
|
|
log.Debugf("clientConnManager loop start init\n")
|
2020-02-03 18:46:15 +00:00
|
|
|
pb.setState(connections.CONNECTING)
|
2019-06-21 21:50:43 +00:00
|
|
|
|
2019-07-10 20:30:24 +00:00
|
|
|
var err error
|
2019-07-19 17:27:50 +00:00
|
|
|
log.Debugf("%v open file infile\n", pb.name)
|
|
|
|
pb.in, err = os.OpenFile(pb.infile, os.O_RDWR, 0600)
|
2019-07-06 00:46:51 +00:00
|
|
|
if err != nil {
|
2020-02-03 18:46:15 +00:00
|
|
|
pb.setState(connections.DISCONNECTED)
|
2019-07-10 20:30:24 +00:00
|
|
|
continue
|
2019-07-06 00:46:51 +00:00
|
|
|
}
|
2019-07-10 20:30:24 +00:00
|
|
|
|
2019-07-19 17:27:50 +00:00
|
|
|
log.Debugf("%v open file outfile\n", pb.name)
|
|
|
|
pb.out, err = os.OpenFile(pb.outfile, os.O_RDWR, 0600)
|
2019-07-10 20:30:24 +00:00
|
|
|
if err != nil {
|
2020-02-03 18:46:15 +00:00
|
|
|
pb.setState(connections.DISCONNECTED)
|
2019-07-10 20:30:24 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2019-07-19 17:27:50 +00:00
|
|
|
log.Debugf("Successfully connected PipeBridge %v!\n", pb.name)
|
2019-07-10 20:30:24 +00:00
|
|
|
|
|
|
|
pb.handleConns()
|
2019-07-06 00:46:51 +00:00
|
|
|
}
|
2019-07-19 17:27:50 +00:00
|
|
|
log.Debugf("exiting %v ConnectionManager\n", pb.name)
|
2019-06-21 21:50:43 +00:00
|
|
|
|
2019-07-10 20:30:24 +00:00
|
|
|
}
|
|
|
|
|
2019-09-05 17:59:55 +00:00
|
|
|
// threeShake performs a 3way handshake sync up
|
|
|
|
func (pb *pipeBridge) threeShakeService() bool {
|
|
|
|
synacked := false
|
|
|
|
|
|
|
|
for {
|
|
|
|
resp, err := pb.readString()
|
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if string(resp) == syn {
|
|
|
|
if !synacked {
|
|
|
|
err = pb.writeString([]byte(synack))
|
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
synacked = true
|
|
|
|
}
|
|
|
|
} else if string(resp) == ack {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (pb *pipeBridge) synLoop(stop chan bool) {
|
|
|
|
delay := time.Duration(0)
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-time.After(delay):
|
|
|
|
err := pb.writeString([]byte(syn))
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
delay = time.Second
|
2019-09-19 23:14:35 +00:00
|
|
|
case <-stop:
|
|
|
|
return
|
2019-09-05 17:59:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (pb *pipeBridge) threeShakeClient() bool {
|
|
|
|
stop := make(chan bool)
|
|
|
|
go pb.synLoop(stop)
|
|
|
|
for {
|
|
|
|
resp, err := pb.readString()
|
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if string(resp) == synack {
|
|
|
|
stop <- true
|
|
|
|
err := pb.writeString([]byte(ack))
|
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-10 20:30:24 +00:00
|
|
|
func (pb *pipeBridge) handleConns() {
|
|
|
|
|
2019-09-05 17:59:55 +00:00
|
|
|
if !pb.threeShake() {
|
2020-02-03 18:46:15 +00:00
|
|
|
pb.setState(connections.FAILED)
|
2019-09-05 17:59:55 +00:00
|
|
|
pb.closeReset()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-02-03 18:46:15 +00:00
|
|
|
pb.setState(connections.AUTHENTICATED)
|
2019-07-10 20:30:24 +00:00
|
|
|
|
|
|
|
pb.closedChan = make(chan bool, 5)
|
|
|
|
|
2019-07-19 17:27:50 +00:00
|
|
|
log.Debugf("handleConns authed, %v 2xgo\n", pb.name)
|
2019-07-10 20:30:24 +00:00
|
|
|
|
|
|
|
go pb.handleRead()
|
|
|
|
go pb.handleWrite()
|
|
|
|
|
|
|
|
<-pb.closedChan
|
2019-07-19 17:27:50 +00:00
|
|
|
log.Debugf("handleConns <-closedChan (%v)\n", pb.name)
|
2020-02-03 18:46:15 +00:00
|
|
|
if pb.getState() != connections.KILLED {
|
|
|
|
pb.setState(connections.FAILED)
|
2019-07-06 00:46:51 +00:00
|
|
|
}
|
2019-07-19 17:27:50 +00:00
|
|
|
pb.closeReset()
|
|
|
|
log.Debugf("handleConns done for %v, exit\n", pb.name)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (pb *pipeBridge) closeReset() {
|
2019-07-10 20:30:24 +00:00
|
|
|
pb.in.Close()
|
|
|
|
pb.out.Close()
|
|
|
|
close(pb.read)
|
2019-09-05 17:59:55 +00:00
|
|
|
pb.write.Close()
|
|
|
|
|
2020-02-03 18:46:15 +00:00
|
|
|
if pb.getState() != connections.KILLED {
|
2019-09-05 17:59:55 +00:00
|
|
|
pb.read = make(chan event.IPCMessage, maxBufferSize)
|
|
|
|
pb.write = newInfiniteChannel()
|
|
|
|
}
|
2019-06-21 21:50:43 +00:00
|
|
|
}
|
|
|
|
|
2019-07-10 20:30:24 +00:00
|
|
|
func (pb *pipeBridge) handleWrite() {
|
2019-07-19 17:27:50 +00:00
|
|
|
log.Debugf("handleWrite() %v\n", pb.name)
|
|
|
|
defer log.Debugf("exiting handleWrite() %v\n", pb.name)
|
|
|
|
|
2019-07-10 20:30:24 +00:00
|
|
|
for {
|
|
|
|
select {
|
2019-09-05 17:59:55 +00:00
|
|
|
case messageInf := <-pb.write.output:
|
|
|
|
if messageInf == nil {
|
|
|
|
pb.closedChan <- true
|
|
|
|
return
|
|
|
|
}
|
|
|
|
message := messageInf.(event.IPCMessage)
|
2019-07-19 17:27:50 +00:00
|
|
|
if message.Message.EventType == event.EncryptedGroupMessage || message.Message.EventType == event.SendMessageToGroup || message.Message.EventType == event.NewMessageFromGroup {
|
|
|
|
log.Debugf("handleWrite <- message: %v %v ...\n", message.Dest, message.Message.EventType)
|
|
|
|
} else {
|
|
|
|
log.Debugf("handleWrite <- message: %v\n", message)
|
|
|
|
}
|
2020-02-03 18:46:15 +00:00
|
|
|
if pb.getState() == connections.AUTHENTICATED {
|
2019-07-10 20:30:24 +00:00
|
|
|
encMessage := &event.IPCMessage{Dest: message.Dest, Message: event.Event{EventType: message.Message.EventType, EventID: message.Message.EventID, Data: make(map[event.Field]string)}}
|
|
|
|
for k, v := range message.Message.Data {
|
|
|
|
encMessage.Message.Data[k] = base64.StdEncoding.EncodeToString([]byte(v))
|
|
|
|
}
|
|
|
|
|
|
|
|
messageJSON, _ := json.Marshal(encMessage)
|
2019-09-05 17:59:55 +00:00
|
|
|
err := pb.writeString(messageJSON)
|
|
|
|
if err != nil {
|
|
|
|
pb.closedChan <- true
|
|
|
|
return
|
2019-07-10 20:30:24 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return
|
|
|
|
}
|
2019-07-06 00:46:51 +00:00
|
|
|
}
|
2019-07-10 20:30:24 +00:00
|
|
|
}
|
|
|
|
}
|
2019-07-06 00:46:51 +00:00
|
|
|
|
2019-07-10 20:30:24 +00:00
|
|
|
func (pb *pipeBridge) handleRead() {
|
2019-07-19 17:27:50 +00:00
|
|
|
log.Debugf("handleRead() %v\n", pb.name)
|
|
|
|
defer log.Debugf("exiting handleRead() %v", pb.name)
|
|
|
|
|
2019-07-10 20:30:24 +00:00
|
|
|
for {
|
|
|
|
log.Debugf("Waiting to handleRead()...\n")
|
2019-09-05 17:59:55 +00:00
|
|
|
|
|
|
|
buffer, err := pb.readString()
|
|
|
|
if err != nil {
|
2019-07-10 20:30:24 +00:00
|
|
|
pb.closedChan <- true
|
|
|
|
return
|
|
|
|
}
|
2019-07-06 00:46:51 +00:00
|
|
|
|
2019-07-10 20:30:24 +00:00
|
|
|
var message event.IPCMessage
|
|
|
|
err = json.Unmarshal(buffer, &message)
|
|
|
|
if err != nil {
|
2019-09-05 17:59:55 +00:00
|
|
|
log.Errorf("Read error: '%v', value: '%v'", err, buffer)
|
|
|
|
pb.closedChan <- true
|
|
|
|
return // probably new connection trying to initialize
|
2019-07-10 20:30:24 +00:00
|
|
|
}
|
|
|
|
for k, v := range message.Message.Data {
|
|
|
|
val, _ := base64.StdEncoding.DecodeString(v)
|
|
|
|
message.Message.Data[k] = string(val)
|
|
|
|
}
|
2019-07-19 17:27:50 +00:00
|
|
|
if message.Message.EventType == event.EncryptedGroupMessage || message.Message.EventType == event.SendMessageToGroup || message.Message.EventType == event.NewMessageFromGroup {
|
|
|
|
log.Debugf("handleRead read<-: %v %v ...\n", message.Dest, message.Message.EventType)
|
|
|
|
} else {
|
|
|
|
log.Debugf("handleRead read<-: %v\n", message)
|
|
|
|
}
|
2019-07-10 20:30:24 +00:00
|
|
|
pb.read <- message
|
|
|
|
log.Debugf("handleRead wrote\n")
|
2019-06-21 21:50:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-10 20:30:24 +00:00
|
|
|
func (pb *pipeBridge) Read() (*event.IPCMessage, bool) {
|
2019-07-19 17:27:50 +00:00
|
|
|
log.Debugf("Read() %v...\n", pb.name)
|
2019-09-05 17:59:55 +00:00
|
|
|
var ok = false
|
|
|
|
var message event.IPCMessage
|
2020-02-03 18:46:15 +00:00
|
|
|
for !ok && pb.getState() != connections.KILLED {
|
2019-09-05 17:59:55 +00:00
|
|
|
message, ok = <-pb.read
|
|
|
|
if message.Message.EventType == event.EncryptedGroupMessage || message.Message.EventType == event.SendMessageToGroup || message.Message.EventType == event.NewMessageFromGroup {
|
|
|
|
log.Debugf("Read %v: %v %v ...\n", pb.name, message.Dest, message.Message.EventType)
|
|
|
|
} else {
|
|
|
|
log.Debugf("Read %v: %v\n", pb.name, message)
|
|
|
|
}
|
2019-07-19 17:27:50 +00:00
|
|
|
}
|
2020-02-03 18:46:15 +00:00
|
|
|
return &message, pb.getState() != connections.KILLED
|
2019-07-10 20:30:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (pb *pipeBridge) Write(message *event.IPCMessage) {
|
2019-07-19 17:27:50 +00:00
|
|
|
if message.Message.EventType == event.EncryptedGroupMessage || message.Message.EventType == event.SendMessageToGroup || message.Message.EventType == event.NewMessageFromGroup {
|
|
|
|
log.Debugf("Write %v: %v %v ...\n", pb.name, message.Dest, message.Message.EventType)
|
|
|
|
} else {
|
|
|
|
log.Debugf("Write %v: %v\n", pb.name, message)
|
|
|
|
}
|
2019-09-05 17:59:55 +00:00
|
|
|
pb.write.input <- *message
|
2019-07-10 20:30:24 +00:00
|
|
|
log.Debugf("Wrote\n")
|
|
|
|
}
|
|
|
|
|
2019-06-21 21:50:43 +00:00
|
|
|
func (pb *pipeBridge) Shutdown() {
|
2020-02-03 18:46:15 +00:00
|
|
|
log.Debugf("pb.Shutdown() for %v currently in state: %v\n", pb.name, connections.ConnectionStateName[pb.getState()])
|
2019-07-10 20:30:24 +00:00
|
|
|
pb.state = connections.KILLED
|
|
|
|
pb.closedChan <- true
|
2019-07-19 17:27:50 +00:00
|
|
|
log.Debugf("Done Shutdown for %v\n", pb.name)
|
2019-06-21 21:50:43 +00:00
|
|
|
}
|
2019-09-05 17:59:55 +00:00
|
|
|
|
|
|
|
func (pb *pipeBridge) writeString(message []byte) error {
|
|
|
|
size := make([]byte, 2)
|
|
|
|
binary.LittleEndian.PutUint16(size, uint16(len(message)))
|
|
|
|
pb.out.Write(size)
|
|
|
|
|
|
|
|
for pos := 0; pos < len(message); {
|
|
|
|
n, err := pb.out.Write(message[pos:])
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("Writing out on pipeBridge: %v\n", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
pos += n
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (pb *pipeBridge) readString() ([]byte, error) {
|
|
|
|
var n int
|
|
|
|
size := make([]byte, 2)
|
|
|
|
var err error
|
|
|
|
|
|
|
|
n, err = pb.in.Read(size)
|
|
|
|
if err != nil || n != 2 {
|
|
|
|
log.Errorf("Could not read len int from stream: %v\n", err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
n = int(binary.LittleEndian.Uint16(size))
|
|
|
|
pos := 0
|
|
|
|
buffer := make([]byte, n)
|
|
|
|
for n > 0 {
|
|
|
|
m, err := pb.in.Read(buffer[pos:])
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("Reading into buffer from pipe: %v\n", err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
n -= m
|
|
|
|
pos += m
|
|
|
|
}
|
|
|
|
return buffer, nil
|
|
|
|
}
|