mirror of
https://github.com/PeernetOfficial/core.git
synced 2026-07-17 02:47:51 +01:00
119 lines
3.5 KiB
Go
119 lines
3.5 KiB
Go
/*
|
|
File Name: Transfer Virtual Connection.go
|
|
Copyright: 2021 Peernet s.r.o.
|
|
Author: Peter Kleissner
|
|
|
|
This file defines a virtual connection between a transfer protocol and Peernet messages.
|
|
If either the downstream transfer protocol or upstream Peernet messages indicate termination, the virtual connection ceases to exist.
|
|
*/
|
|
|
|
package core
|
|
|
|
import (
|
|
"sync"
|
|
|
|
"github.com/PeernetOfficial/core/protocol"
|
|
)
|
|
|
|
// virtualPacketConn is a virtual connection.
|
|
type virtualPacketConn struct {
|
|
peer *PeerInfo
|
|
|
|
// Transfer settings
|
|
transferProtocol uint8 // 0 = UDT
|
|
hash []byte // The requested hash.
|
|
offset uint64 // Offset to start reading.
|
|
limit uint64 // Limit of bytes to read at the offset.
|
|
|
|
// Sequence number from the first outgoing or incoming packet.
|
|
sequenceNumber uint32
|
|
|
|
// data channel
|
|
incomingData chan []byte
|
|
outgoingData chan []byte
|
|
|
|
// internal data
|
|
closed bool
|
|
terminateChan chan struct{}
|
|
reason int // Reason why it was closed
|
|
sync.Mutex
|
|
}
|
|
|
|
// newVirtualPacketConn creates a new virtual connection (both incomign and outgoing).
|
|
func newVirtualPacketConn(peer *PeerInfo, protocol uint8, hash []byte, offset, limit uint64) (v *virtualPacketConn) {
|
|
v = &virtualPacketConn{
|
|
peer: peer,
|
|
transferProtocol: protocol,
|
|
hash: hash,
|
|
offset: offset,
|
|
limit: limit,
|
|
incomingData: make(chan []byte),
|
|
outgoingData: make(chan []byte),
|
|
terminateChan: make(chan struct{}),
|
|
}
|
|
|
|
go v.writeForward()
|
|
|
|
return
|
|
}
|
|
|
|
// writeForward forwards outgoing messages
|
|
func (v *virtualPacketConn) writeForward() {
|
|
for {
|
|
select {
|
|
case data := <-v.outgoingData:
|
|
v.peer.sendTransfer(data, protocol.TransferControlActive, v.transferProtocol, v.hash, v.offset, v.limit, v.sequenceNumber)
|
|
|
|
case <-v.terminateChan:
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// receiveData receives incoming data via an external message. Blocking until a read occurs or the connection is terminated!
|
|
func (v *virtualPacketConn) receiveData(data []byte) {
|
|
if v.IsTerminated() {
|
|
return
|
|
}
|
|
|
|
// pass the data on
|
|
select {
|
|
case v.incomingData <- data:
|
|
case <-v.terminateChan:
|
|
}
|
|
}
|
|
|
|
// Terminate closes the connection. Do not call this function manually. Use the underlying protocol's function to close the connection.
|
|
// Reason: 404 = Remote peer does not store file (upstream), 1 = Transfer Protocol indicated closing (downstream), 2 = Remote termination signal (upstream), 3 = Sequence invalidation or expiration (upstream)
|
|
func (v *virtualPacketConn) Terminate(reason int) (err error) {
|
|
v.Lock()
|
|
defer v.Unlock()
|
|
|
|
if v.closed { // if already closed, take no action
|
|
return
|
|
}
|
|
|
|
v.closed = true
|
|
v.reason = reason
|
|
close(v.terminateChan)
|
|
|
|
return
|
|
}
|
|
|
|
// IsTerminated checks if the connection is terminated
|
|
func (v *virtualPacketConn) IsTerminated() bool {
|
|
return v.closed
|
|
}
|
|
|
|
// sequenceTerminate is a wrapper for sequenece termination (invalidation or expiration)
|
|
func (v *virtualPacketConn) sequenceTerminate() {
|
|
v.Terminate(3)
|
|
}
|
|
|
|
// Close provides a Close function to be called by the underlying transfer protocol.
|
|
// Do not call the function manually; otherwise the underlying transfer protocol may not have time to send a termination message (and the remote peer would subsequently try to reconnect).
|
|
func (v *virtualPacketConn) Close() (err error) {
|
|
networks.Sequences.InvalidateSequence(v.peer.PublicKey, v.sequenceNumber, true)
|
|
return v.Terminate(1)
|
|
}
|