udpt

package module
v0.0.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 6, 2022 License: MIT Imports: 20 Imported by: 0

README

udpt

UDP Transport

Go Report Card godoc

Compresses, encrypts and transfers data between a sender and receiver using UDP protocol.

Features and Design Aims:

  • Avoid the overhead of establishing a TCP or TCP+TLS handshake.
  • Reliable transfer of data using an unreliable UDP connection.
  • Uses AES-256 symmetric cipher for encryption.
  • Uses zlib library for data compression.
  • No third-party dependencies. Only uses the standard library.
  • Readable, understandable code with explanatory comments.

Installation:

    go get github.com/balacode/udpt

Hello World:

This demo starts a Receiver which listens for incoming data, then sends a "Hello World" to the receiver using Sender.SendString().

package main

import (
    "fmt"

    "github.com/balacode/udpt"
)

// main demo
func main() {
    // secret encryption key shared by the Sender and Receiver
    cryptoKey := []byte("aA2Xh41FiC4Wtj3e5b2LbytMdn6on7P0")
    //
    // set-up and run the receiver
    rc := udpt.Receiver{Port: 9876, CryptoKey: cryptoKey,
        Receive: func(k string, v []byte) error {
            fmt.Println("Received k:", k, "v:", string(v))
            return nil
        }}
    go func() { _ = rc.Run() }()
    //
    // send a message to the receiver
    err := udpt.SendString("127.0.0.1:9876", "main", "Hello World!", cryptoKey)
    if err != nil {
        fmt.Println("failed sending:", err)
    }
    rc.Stop()
} //                                                                        main

Security Notice:

This is a new project and its use of cryptography has not been reviewed by experts. While I make use of established crypto algorithms available in the standard Go library and would not "roll my own" encryption, there may be weaknesses in my application of the algorithms. Please use caution and do your own security asessment of the code. At present, this library uses AES-256 in Galois Counter Mode to encrypt each packet of data, including its headers, and SHA-256 for hashing binary resources that are being transferred.

Version History:

This project is in its DRAFT stage: very unstable. At this point it works, but the API may change rapidly.

Ideas:

  • Create a drop-in replacement for TCP and TLS connections
  • Implement some form of transfer control
  • Improve performance

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func MakeLogWriter

func MakeLogWriter(printMsg bool, logFile string) io.Writer

MakeLogWriter is a convenience function that creates and returns a Writer to use for logging during developing or debugging.

You can assign this function to Config.LogFunc: E.g. sender.Config.LogWriter = MakeLogWriter(true, "udpt.log")

printMsg determines if each log entry should be printed to standard output.

logFile specifies the log file into which to append.

func Receive

func Receive(
	ctx context.Context,
	port int,
	cryptoKey []byte,
	receive func(k string, v []byte) error,
) error

Receive sets up and runs a Receiver.

Once it starts running, this function will only exit if the context is done or cancelled.

It will only return an error if it fails to start because the port or cryptoKey is invalid.

func Send

func Send(addr, k string, v, cryptoKey []byte, config ...*Configuration) error

Send creates a Sender and uses it to transfer a key-value pair to the Receiver specified by address 'addr'.

addr specifies the host and port number of the Receiver, for example "website.com:9876" or "127.0.0.1:9876"

k is any string you want to use as the key. It can be blank if not needed. It could be a filename, timestamp, UUID, or some other metadata that gives context to the value being sent.

v is the value being sent as a sequence of bytes. It can be as large as the free memory available on the Sender's and Receiver's machine.

cryptoKey is the symmetric encryption key shared by the Sender and Receiver and used to encrypt the sent message.

config is an optional Configuration you can customize. If you leave it out, Send() will use the configuration returned by NewDefaultConfig().

func SendString

func SendString(addr, k, v string, cryptoKey []byte, config ...*Configuration,
) error

SendString creates a Sender and uses it to transfer a key-value pair of strings to the Receiver specified by address 'addr'.

addr specifies the host and port number of the Receiver, for example "website.com:9876" or "127.0.0.1:9876"

k is any string you want to use as the key. It can be blank if not needed. It could be a filename, timestamp, UUID, or some other metadata that gives context to the value being sent.

v is the value being sent as a string. It can be as large as the free memory available on the Sender's and Receiver's machine.

cryptoKey is the symmetric encryption key shared by the Sender and Receiver and used to encrypt the sent message.

config is an optional Configuration you can customize. If you leave it out, SendString() will use the configuration returned by NewDefaultConfig().

Types

type Compression

type Compression interface {

	// Compress compresses 'data' and returns the compressed bytes.
	// If there was an error, returns nil and the error instance.
	Compress(data []byte) ([]byte, error)

	// Uncompress uncompresses bytes and returns the uncompressed bytes.
	// If there was an error, returns nil and the error instance.
	Uncompress(comp []byte) ([]byte, error)

} //                                                                 Compression

Compression implements functions to compress and uncompress byte slices.

type Configuration

type Configuration struct {

	// Cipher is the object that handles encryption and decryption.
	//
	// It must implement the SymmetricCipher interface which is defined
	// in this package. If you don't specify Cipher, then encryption will
	// be done using the default AES-256 cipher used in this package.
	//
	Cipher SymmetricCipher

	// Compressor handles compression and uncompression.
	Compressor Compression

	// PacketSizeLimit is the maximum size of a datagram in bytes,
	// including the headers, metadata and data payload.
	//
	// Maximum Transmission Unit (MTU):
	//
	// Internet Protocol requires hosts to process IP datagrams
	// of at least 576 bytes for IPv4 (or 1280 bytes for IPv6).
	// The IPv4 header is 20 bytes (or up to 60 with options).
	// UDP header is 8 bytes. 576 - 60 - 8 = 508 bytes available.
	//
	// The maximum Ethernet (v2) frame size is 1518 bytes, 18
	// of which are overhead, giving a usable size of 1500.
	// (To be on the safe side, we further reduce this by 50 bytes)
	//
	PacketSizeLimit int

	// PacketPayloadSize is the size of a single packet's payload, in bytes.
	// That is the part of the packet that contains actual useful data.
	// PacketPayloadSize must always be smaller that PacketSizeLimit.
	PacketPayloadSize int

	// SendBufferSize is size of the write buffer used by Send(), in bytes.
	SendBufferSize int

	// SendRetries is the number of times for
	// Send() to retry sending lost packets.
	SendRetries int

	// ReplyTimeout is the maximum time to wait for reply
	// datagram(s) to arrive in a UDP connection.
	ReplyTimeout time.Duration

	// SendPacketInterval is the time to wait between sending packets.
	SendPacketInterval time.Duration

	// SendRetryInterval is the time for Sender.Send() to
	// wait before retrying to send undelivered packets.
	SendRetryInterval time.Duration

	// SendWaitInterval is the amount of time Sender() should sleep
	// in the loop, before checking if a confirmation has arrived.
	SendWaitInterval time.Duration

	// WriteTimeout is the maximum time to
	// wait for writing to a UDP connection.
	WriteTimeout time.Duration

	// LogWriter is the writer to which logError() and logInfo() output.
	// If you leave it nil, no logging will be done.
	LogWriter io.Writer

	// VerboseReceiver specifies if Receiver should
	// write informational log messages to LogWriter.
	VerboseReceiver bool

	// VerboseSender specifies if Sender should write
	// informational log messages to LogWriter.
	VerboseSender bool

} //                                                               Configuration

Config contains UDP and other default configuration settings. These settings normally don't need to be changed.

func NewDebugConfig

func NewDebugConfig(logWriter ...io.Writer) *Configuration

NewDebugConfig returns configuration settings for debugging.

You can specify an optional writer used for logging. If you omit it, logError() and logInfo() will print to standard output.

func NewDefaultConfig

func NewDefaultConfig() *Configuration

NewDefaultConfig returns default configuration settings.

func (*Configuration) Validate

func (cf *Configuration) Validate() error

Validate checks if all configuration parameters are set within acceptable limits.

Returns nil if there is no problem, or the error instance.

type Receiver

type Receiver struct {

	// Port is the port number of the listening server.
	// This number must be between 1 and 65535.
	Port int

	// CryptoKey is the secret symmetric encryption key that
	// must be shared by the Sender and the Receiver.
	//
	// The correct size of this key depends
	// on the implementation of SymmetricCipher.
	//
	CryptoKey []byte

	// Config contains UDP and other configuration settings.
	// These settings normally don't need to be changed.
	Config *Configuration

	// Receive is a callback function you must specify. This Receiver
	// will call it when a data item has been fully transferred.
	//
	// 'k' and 'v' will contain the key and value sent
	// by Sender.Send() or Sender.SendString(), etc.
	//
	// The reason there are two parameters is to separate metadata like
	// timestamps or filenames from the content of the transferred resource.
	//
	Receive func(k string, v []byte) error
	// contains filtered or unexported fields

} //                                                                    Receiver

Receiver receives data items sent by Send() or SendString().

func (*Receiver) Run

func (rc *Receiver) Run() error

Run runs the receiver in a loop to process incoming packets.

It calls Receive when a data transfer is complete, after the receiver has received, decrypted and re-assembled a data item.

func (*Receiver) Stop

func (rc *Receiver) Stop()

Stop stops the Receiver from listening and receiving data by closing its connection.

type Sender

type Sender struct {

	// Address is the domain name or IP address of the listening
	// receiver with the port number. For example: "127.0.0.1:9876"
	//
	// The port number must be between 1 and 65535.
	//
	Address string

	// CryptoKey is the secret symmetric encryption key that
	// must be shared by the Sender and the Receiver.
	//
	// The correct size of this key depends on
	// the implementation of SymmetricCipher.
	//
	CryptoKey []byte

	// Config contains UDP and other configuration settings.
	// These settings normally don't need to be changed.
	Config *Configuration
	// contains filtered or unexported fields

} //                                                                      Sender

Sender coordinates sending key-value messages to a listening Receiver.

You can use standalone Send() and SendString() functions to create a single-use Sender to send a message, but it's more efficient to construct a reusable Sender.

func (*Sender) AverageResponseMs

func (sd *Sender) AverageResponseMs() float64

AverageResponseMs is the average response time, in milliseconds, between a packet being sent and its delivery confirmation being received.

func (*Sender) DeliveredAllParts

func (sd *Sender) DeliveredAllParts() bool

DeliveredAllParts returns true if all parts of the sent data item have been delivered. I.e. all packets have been sent, resent if needed, and confirmed.

func (*Sender) LogStats

func (sd *Sender) LogStats(w ...io.Writer)

LogStats prints UDP transfer statistics to the specified writer 'wr', or to Sender.LogWriter. If both are not specified, does nothing.

func (*Sender) Send

func (sd *Sender) Send(k string, v []byte) error

Send transfers a key-value to the Receiver specified by Sender.Address.

'k' is any string you want to use as the key. It can be blank if not needed. It could be a filename, timestamp, UUID, or some other metadata that gives context to the value being sent.

'v' is the value being sent as a sequence of bytes. It can be as large as the free memory available on the Sender's and Receiver's machine.

func (*Sender) SendString

func (sd *Sender) SendString(k string, v string) error

SendString transfers a key and value string to the Receiver specified by Sender.Address.

'k' is any string you want to use as the key. It can be blank if not needed. It could be a filename, timestamp, UUID, or some other metadata that gives context to the value being sent.

'v' is the value being sent as a string. It can be as large as the free memory available on the Sender's and Receiver's machine.

func (*Sender) TransferSpeedKBpS

func (sd *Sender) TransferSpeedKBpS() float64

TransferSpeedKBpS returns the transfer speed of the current Send operation, in Kilobytes (more accurately, Kibibytes) per second.

type SymmetricCipher

type SymmetricCipher interface {

	// ValidateKey checks if 'cryptoKey' is acceptable for use with the cipher.
	// For example it must be of the right size.
	ValidateKey(cryptoKey []byte) error

	// SetKey initializes the cipher with the specified encryption key.
	//
	// If the cipher is already initialized with the given key, does nothing.
	// The same key is used for encryption and decryption.
	//
	SetKey(cryptoKey []byte) error

	// Encrypt encrypts plaintext using the key given to SetKey and
	// returns the encrypted ciphertext, using a symmetric-key cipher.
	//
	// You need to call SetKey at least once before you call Encrypt.
	//
	Encrypt(plaintext []byte) (ciphertext []byte, err error)

	// Decrypt decrypts ciphertext using the key given to SetKey and
	// returns the decrypted plaintext, using a symmetric-key cipher.
	//
	// You need to call SetKey at least once before you call Decrypt.
	//
	Decrypt(ciphertext []byte) (plaintext []byte, err error)

} //                                                             SymmetricCipher

SymmetricCipher interface provides methods to initialize a symmetric-key cipher and use it to encrypt and decrypt plaintext. A symmetric-key cipher uses the same key to encrypt and decrypt.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL