mirror of
https://github.com/PeernetOfficial/core.git
synced 2026-07-16 18:37:51 +01:00
* added upload status * added changes for progress bar with more logs and bug fixes, Documentation yet to be added * huge changes that need more doucmenting * added possibility to get profile using NodeID * added fix profile listing user profile information * removed profile image from the explore reult struct * saving current changes * added filter to search based on NodeID * Monday bug fixing * updates to the profile * changes for tracing the blockchain profile image not shown * added condition to ensure TAG is not sent and removed debug prints * updated webapi docs
200 lines
5.3 KiB
Go
200 lines
5.3 KiB
Go
/*
|
|
File Username: Packet Lite.go
|
|
Copyright: 2021 Peernet s.r.o.
|
|
Author: Peter Kleissner
|
|
|
|
The lite packet header is used for encoding data transfer packets. The regular header is too expensive in terms of CPU consumption due to public key signing.
|
|
Instead, a simple session ID will identify lite packets. The ID is randomized and only valid during the session.
|
|
Unsolicited lite packets are therefore impossible; the receiver must have the ID already whitelisted for the packet to be recognized.
|
|
|
|
Offset Size Info
|
|
0 16 ID
|
|
16 2 Size of data to follow
|
|
|
|
*/
|
|
|
|
package protocol
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"errors"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
// PacketLiteRaw is a decrypted P2P lite packet
|
|
type PacketLiteRaw struct {
|
|
ID uuid.UUID // ID
|
|
Payload []byte // Payload
|
|
Session *LiteID // Session info
|
|
}
|
|
|
|
// Minimum packet size of lite packets.
|
|
const PacketLiteSizeMin = 16 + 2
|
|
|
|
// IsPacketLite identifies a lite packet based on its ID. If the ID is not recognized, it fails.
|
|
func (router *LiteRouter) IsPacketLite(raw []byte) (isLite bool, err error) {
|
|
if len(raw) < PacketLiteSizeMin {
|
|
return false, errors.New("invalid packet size")
|
|
}
|
|
|
|
// Parse the ID and then look it up.
|
|
var id uuid.UUID
|
|
copy(id[:], raw[0:16])
|
|
|
|
return router.LookupLiteID(id) != nil, nil
|
|
}
|
|
|
|
// PacketLiteDecode a lite packet. It will identify the lite packet based on its ID. If the ID is not recognized (which is the case for regular Peernet packets), the function fails.
|
|
// It does not perform any decryption.
|
|
func (router *LiteRouter) PacketLiteDecode(raw []byte) (packet *PacketLiteRaw, err error) {
|
|
if len(raw) < PacketLiteSizeMin {
|
|
return nil, errors.New("invalid packet size")
|
|
}
|
|
|
|
// Parse the ID and look it up. It will contain information about the decryption algorithm to use.
|
|
var id uuid.UUID
|
|
copy(id[:], raw[0:16])
|
|
|
|
session := router.LookupLiteID(id)
|
|
if session == nil {
|
|
return nil, errors.New("packet ID not found")
|
|
}
|
|
|
|
// TODO: Decrypt the data if indicated by the session.
|
|
|
|
sizePayload := binary.LittleEndian.Uint16(raw[16 : 16+2])
|
|
if int(sizePayload) > len(raw)-PacketLiteSizeMin { // invalid size field?
|
|
return nil, errors.New("invalid packet size field")
|
|
}
|
|
|
|
// Valid packet received, extend expiration.
|
|
session.expires = time.Now().Add(session.timeout)
|
|
|
|
return &PacketLiteRaw{Payload: raw[PacketLiteSizeMin:], ID: id, Session: session}, nil
|
|
}
|
|
|
|
// Encodes a lite packet.
|
|
func PacketLiteEncode(id uuid.UUID, data []byte) (raw []byte, err error) {
|
|
raw = make([]byte, PacketLiteSizeMin+len(data))
|
|
|
|
copy(raw[0:16], id[:])
|
|
binary.LittleEndian.PutUint16(raw[16:16+2], uint16(len(data)))
|
|
copy(raw[PacketLiteSizeMin:], data)
|
|
|
|
return raw, nil
|
|
}
|
|
|
|
// ---- Lite packet ID management. This is similar to packet sequences. ----
|
|
|
|
// LiteRouter keeps track of accepted (expected) packet IDs.
|
|
type LiteRouter struct {
|
|
// list of recognized IDs
|
|
ids map[uuid.UUID]*LiteID
|
|
|
|
sync.Mutex // synchronized access to the IDs
|
|
}
|
|
|
|
// LiteID contains session information for a bidirectional transfer of data
|
|
type LiteID struct {
|
|
ID uuid.UUID // ID
|
|
created time.Time // When the ID was created.
|
|
expires time.Time // When the ID expires. This can be extended on the fly!
|
|
Data interface{} // Optional high-level data associated with the ID
|
|
timeout time.Duration // Timeout for receiving the next message
|
|
invalidateFunc func() // Called on expiration.
|
|
}
|
|
|
|
// Creates a new manager to keep track of accepted IDs.
|
|
func NewLiteRouter() (router *LiteRouter) {
|
|
router = &LiteRouter{
|
|
ids: make(map[uuid.UUID]*LiteID),
|
|
}
|
|
|
|
go router.autoDeleteExpired()
|
|
|
|
return
|
|
}
|
|
|
|
// autoDeleteExpired deletes all IDs that are expired.
|
|
func (router *LiteRouter) autoDeleteExpired() {
|
|
for {
|
|
time.Sleep(4 * time.Second)
|
|
now := time.Now()
|
|
|
|
router.Lock()
|
|
for id, info := range router.ids {
|
|
if info.expires.Before(now) {
|
|
delete(router.ids, id)
|
|
|
|
if info.invalidateFunc != nil {
|
|
go info.invalidateFunc()
|
|
}
|
|
}
|
|
}
|
|
router.Unlock()
|
|
}
|
|
}
|
|
|
|
func (router *LiteRouter) LookupLiteID(id uuid.UUID) (info *LiteID) {
|
|
router.Lock()
|
|
info = router.ids[id]
|
|
router.Unlock()
|
|
|
|
return info
|
|
}
|
|
|
|
// Returns a new lite ID to be used.
|
|
func (router *LiteRouter) NewLiteID(data interface{}, timeout time.Duration, invalidateFunc func()) (info *LiteID) {
|
|
info = &LiteID{
|
|
created: time.Now(),
|
|
expires: time.Now().Add(timeout),
|
|
timeout: timeout,
|
|
invalidateFunc: invalidateFunc,
|
|
Data: data,
|
|
ID: uuid.New(),
|
|
}
|
|
|
|
router.Lock()
|
|
router.ids[info.ID] = info
|
|
router.Unlock()
|
|
|
|
return
|
|
}
|
|
|
|
func (router *LiteRouter) RegisterLiteID(id uuid.UUID, data interface{}, timeout time.Duration, invalidateFunc func()) (info *LiteID) {
|
|
info = &LiteID{
|
|
ID: id,
|
|
created: time.Now(),
|
|
expires: time.Now().Add(timeout),
|
|
timeout: timeout,
|
|
invalidateFunc: invalidateFunc,
|
|
Data: data,
|
|
}
|
|
|
|
router.Lock()
|
|
existingInfo := router.ids[info.ID]
|
|
router.ids[info.ID] = info
|
|
router.Unlock()
|
|
|
|
// Call the invalidate function if there is a collision. This should never happen.
|
|
if existingInfo != nil && existingInfo.invalidateFunc != nil {
|
|
go existingInfo.invalidateFunc()
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// Returns all lite sessions
|
|
func (router *LiteRouter) All() (sessions []*LiteID) {
|
|
router.Lock()
|
|
for _, info := range router.ids {
|
|
sessions = append(sessions, info)
|
|
}
|
|
router.Unlock()
|
|
|
|
return sessions
|
|
}
|