libutp

package
v0.0.0-...-b6b3a0d Latest Latest
Warning

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

Go to latest
Published: Mar 9, 2024 License: MIT Imports: 15 Imported by: 0

Documentation

Index

Constants

View Source
const (

	// DynamicPacketSizeEnabled controls whether this µTP endpoint will limit
	// outgoing packets to a maximum of getMaxPacketSize() bytes. It is very
	// unclear why this would be necessary, because packets are already limited
	// to a maximum of GetUDPMTU() bytes, and the result of that function is
	// always less than the result of getMaxPacketSize() bytes.
	//
	// Really, this parameter is probably vestigial and has no current purpose.
	DynamicPacketSizeEnabled = true
	// DynamicPacketSizeFactor is entirely unused and is also probably
	// vestigial, related to DynamicPacketSizeEnabled.
	DynamicPacketSizeFactor = 2
)
View Source
const (
	// StateConnect is the state wherein a socket has received syn-ack
	// (notification only for outgoing connection completion) (although I don't
	// know exactly what the previous parenthetical means). This state implies
	// writability.
	StateConnect State = 1
	// StateWritable is the state wherein a socket is able to send more data.
	StateWritable = 2
	// StateEOF is the state used for a socket when its connection is closed.
	StateEOF = 3
	// StateDestroying indicates that the socket is being destroyed, meaning
	// all data has been sent if possible. It is not valid to refer to the
	// socket after this state change occurs.
	StateDestroying = 4
)
View Source
const SO_UTPVERSION = 99

SO_UTPVERSION is the option name used to set the version of µTP to use in outgoing connections. This can only be called before the µTP socket is connected.

Example:

conn := base.Create(sendToCallback, sendToUserdata, destAddr)
conn.SetSockopt(libutp.SO_UTPVERSION, 1)  // µTP version 1
View Source
const (
	UdpTeredoMTU = teredoMTU - ipv6HeaderSize - udpHeaderSize
)

Variables

This section is empty.

Functions

func GetUDPMTU

func GetUDPMTU(addr *net.UDPAddr) uint16

GetUDPMTU returns a best guess as to the MTU (maximum transmission unit) on the network to which the specified address belongs (IPv4 or IPv6).

func RandomUint16

func RandomUint16() uint32

func RandomUint32

func RandomUint32() uint32

Types

type BandwidthType

type BandwidthType int

BandwidthType represents different classes of data which may be exchanged in the course of µTP connections. Every byte in a µTP packet is classified using one of these, and every byte that is not PayloadBandwidth is a form of overhead. A base.OnOverhead callback can be used with Socket objects to keep track of how much overhead of each type is getting used.

const (
	// PayloadBandwidth is the class of data which was directly specified by
	// the application layer. That is to say, this is application data.
	PayloadBandwidth BandwidthType = iota
	// ConnectOverhead is the class of data used for bytes which are used to
	// negotiate connections with a remote peer.
	ConnectOverhead
	// CloseOverhead is the class of data used for bytes which are used to
	// indicate that a connection should be closed.
	CloseOverhead
	// AckOverhead is the class of data used to communicate acknowledgement
	// of data received.
	AckOverhead
	// HeaderOverhead is the class of data used for bytes in µTP packet
	// headers.
	HeaderOverhead
	// RetransmitOverhead is the class of data used for bytes that are
	// retransmissions of data previously sent as PayloadBandwidth.
	RetransmitOverhead
)

type CallbackTable

type CallbackTable struct {
	// OnRead is the OnReadCallback to be used by this socket.
	OnRead OnReadCallback
	// OnWrite is the OnWriteCallback to be used by this socket.
	OnWrite OnWriteCallback
	// GetRBSize is the GetRBSizeCallback to be used by this socket.
	GetRBSize GetRBSizeCallback
	// OnState is the OnStateChangeCallback to be used by this socket.
	OnState OnStateChangeCallback
	// OnError is the OnErrorCallback to be used by this socket.
	OnError OnErrorCallback
	// OnOverhead is the OnOverheadCallback to be used by this socket.
	OnOverhead OnOverheadCallback
}

CallbackTable contains a table of callbacks to be used by a Socket. Each Socket can have a different set of callbacks to call, if needed. Any members of the table can be left as nil, if you do not need that callback to be made.

A CallbackTable is assigned to a Socket by use of the SetCallbacks() method.

type ConnId

type ConnId struct {
	// contains filtered or unexported fields
}

ConnId holds id to be used to accepted connection by the utp server

func ReceConnId

func ReceConnId(connSeed uint32) *ConnId

func SendCid

func SendCid(connSeed uint32) *ConnId

func (*ConnId) RecvId

func (c *ConnId) RecvId() uint32

RecvId get receive id

func (*ConnId) SendId

func (c *ConnId) SendId() uint32

SendId get send id

type ConnIdGenerator

type ConnIdGenerator interface {
	// GenCid generates a random connection id
	GenCid(peer any, isInitiator bool) *ConnId
}

ConnIdGenerator generates connection id

func NewConnIdGenerator

func NewConnIdGenerator() ConnIdGenerator

NewConnIdGenerator creates a new instance of DefaultConnIdGenerator

type DefaultConnIdGenerator

type DefaultConnIdGenerator struct {
	Cids map[any]bool
	// contains filtered or unexported fields
}

DefaultConnIdGenerator default connection id generator, it will generate random connection id

func (*DefaultConnIdGenerator) GenCid

func (g *DefaultConnIdGenerator) GenCid(p any, isInitiator bool) *ConnId

func (*DefaultConnIdGenerator) Remove

func (g *DefaultConnIdGenerator) Remove(c *ConnId)

Remove removes connection id to be cached

type GetRBSizeCallback

type GetRBSizeCallback func(userdata interface{}) int

GetRBSizeCallback is the type of callback to be used when a socket needs to know the current size of the read buffer (how many bytes have been received by OnReadCallback, but have not yet been processed). This is used to determine the size of the read window (how many bytes our side is willing to accept from the remote all at once). If your OnReadCallback does not buffer any bytes, but instead always processes bytes immediately, this method can simply always return 0. The callback will be provided with the userdata parameter that was given when the callback was set (using (*Socket).SetCallbacks()).

type GlobalStats

type GlobalStats struct {
	// NumRawRecv keeps a total of all packets received in each size bucket.
	NumRawRecv [5]uint32
	// NumRawSend keeps a total of all packets sent in each size bucket.
	NumRawSend [5]uint32
}

GlobalStats encapsulates statistics pertaining to all use of utp-go since the library was loaded. A snapshot of these statistics can be accessed with the libutp.GetGlobalStats() function.

Statistics in this struct are kept as totals for each of 5 different size buckets:

bucket[0] : size > 0 && size <= 23 bytes bucket[1] : size > 23 && size <= 373 bytes bucket[2] : size > 373 && size <= 723 bytes bucket[3] : size > 723 && size <= 1400 bytes bucket[4] : size > 1400 && size < MTU bytes

The size of the packet header is included in the packet size for this purpose. The packet header is either 20 or 23 bytes, depending on the µTP protocol version in use.

func GetGlobalStats

func GetGlobalStats() GlobalStats

GetGlobalStats returns a snapshot of the current GlobalStats counts.

type GotIncomingConnection

type GotIncomingConnection func(userdata interface{}, s *Socket)

GotIncomingConnection is the type of callback to be called when a new incoming µTP connection has been established by the socket layer. The Socket for the new connection is passed as 's'. The new Socket can be considered connected and writable immediately.

The callback will be provided with the userdata parameter that was given along with this callback in the corresponding call to IsIncomingUTP(). The callback is responsible for getting the Socket ready to do work; typically, this involves setting callbacks for it with (*Socket).SetCallbacks().

If you want to reject the new connection, it may be closed immediately with (*Socket).Close().

type OnErrorCallback

type OnErrorCallback func(userdata interface{}, err error)

OnErrorCallback is the type of callback to be used when something goes wrong with a connection. Currently, the possible errors which cause an OnErrorCallback are syscall.ECONNREFUSED, syscall.ECONNRESET, and syscall.ETIMEDOUT. All of these probably need to be considered fatal errors in the context of the connection.

The callback will be provided with the userdata parameter that was given when the callback was set (using (*Socket).SetCallbacks()). The callback is responsible for calling (*Socket).Close() if appropriate to tear down the connection.

type OnOverheadCallback

type OnOverheadCallback func(userdata interface{}, send bool, count int, bandwidthType BandwidthType)

OnOverheadCallback is the type of callback to be used when any data is sent over the network. Each byte is accounted by µTP into one of the BandwidthType data classes, and when sent, the use of that class of data is reported to the application using this OnOverheadCallback. The callback will be provided with the userdata parameter that was given when the callback was set (using (*Socket).SetCallbacks()). This callback can be used to maintain statistics about the amount of overhead used to communicate with µTP.

(Use of the PayloadBandwidth BandwidthType is also reported to this callback, although strictly speaking it is not really "overhead".)

type OnReadCallback

type OnReadCallback func(userdata interface{}, bytes []byte)

OnReadCallback is the type of callback to be used when a socket has received application data from the peer. The callback will be provided with the userdata parameter that was given when the callback was set (using (*Socket).SetCallbacks()). The callback is expected to process or buffer all of the data in the 'bytes' slice. Other methods on the Socket object, such as (*Socket).Write(), may be called while the callback is running, if appropriate.

type OnStateChangeCallback

type OnStateChangeCallback func(userdata interface{}, state State)

OnStateChangeCallback is the type of callback to be used when a socket changes its socket state. The callback will be provided with the userdata parameter that was given when the callback was set (using (*Socket).SetCallbacks()). The 'state' parameter will hold the new state of the Socket. It may be important to provide this callback in order to know when a connection is established, and a Socket can accept data, or when a connection has been closed.

type OnWriteCallback

type OnWriteCallback func(userdata interface{}, bytes []byte)

OnWriteCallback is the type of callback to be used when a socket is ready to send more application data to the peer. The application will already have indicated that it _wants_ to send some amount of data using the (*Socket).Write() method, but the data to be sent is not determined until this callback is made. The callback will be provided with the userdata parameter that was given when the callback was set (using (*Socket).SetCallbacks()). The callback is expected to fill in the entire 'bytes' slice. (It should be guaranteed that the slice will not be greater in size than the amount of application that is ready to be sent, as indicated by the last call to (*Socket).Write().)

Once received, the µTP layer takes responsibility for delivering those bytes.

type PacketSendCallback

type PacketSendCallback func(userdata interface{}, p []byte, addr *net.UDPAddr)

PacketSendCallback is the type of callback to be used when the µTP socket layer wants to transmit data over the underlying packet connection (which is probably UDP). The callback will be provided with the userdata parameter that was given along with this callback in the corresponding call to IsIncomingUTP() or Create(). The callback is responsible for actually transmitting the packet to the destination address.

The callback is allowed to buffer the outgoing data instead of transmitting it immediately, if desired, but the data should be transmitted as soon as feasible.

type Socket

type Socket struct {
	ConnSeed uint32
	// Connection ID for packets I receive
	ConnIDRecv uint32
	// Connection ID for packets I send
	ConnIDSend uint32
	// contains filtered or unexported fields
}

Socket represents a µTP socket, which roughly corresponds to one connection to an internet peer. It is important to distinguish µTP sockets from UDP sockets; although µTP may be used over UDP, there is not a 1-1 correlation from µTP sockets to UDP sockets.

Sockets are created using the mx.Create() method (for outgoing connections) or in the course of processing an incoming packet with mx.IsIncomingUTP() (for incoming connections). In the latter case, the socket object will be provided to your code by way of the GotIncomingConnection callback.

Sockets created directly with Create() will need to have the appropriate callbacks registered (with SetCallbacks()) before they can initiate the outgoing connection. To initiate the outgoing connection, use the Connect() method.

Sockets received by way of a GotIncomingConnection callback represent incoming connections, and should not have Connect() called on them.

When your code wants to send data on a Socket, use the Write() method to indicate the amount of data that is ready to be sent. At the appropriate time, the Socket will use the OnWriteCallback to collect the actual data. The OnWriteCallback will only accept a limited amount of data; enough to fill a single packet. If there is more data than that to be sent, it is appropriate to call Write() again with the new total amount (the amount given to Write() is considered the _total_ amount of data which is ready to be written; it is not added to the amount previously indicated).

When data is received from the other end of the connection, the Socket will call its OnReadCallback to pass the received data on to your code.

If a connection times out or is rejected or reset by the peer, the Socket will call its OnErrorCallback.

When a connection becomes writable (connected enough to accept outgoing data), or a connection is closed, the Socket's OnStateChangeCallback will be called.

Your code must call mx.CheckTimeouts() periodically; as often as desired to give the µTP code a chance to notice that a socket has timed out. No background threads remain running to manage µTP state; µTP code is only run when your code calls into it (usually via mx.IsIncomingUTP(), mx.CheckTimeouts(), or the Socket methods).

See the documentation on the various types of callback to learn more.

func (*Socket) Close

func (s *Socket) Close() error

Close closes the UTP socket.

It is not valid to issue commands for this socket after it is closed. This does not actually destroy the socket until outstanding data is sent, at which point the socket will change to the StateDestroying state.

func (*Socket) Connect

func (s *Socket) Connect()

Connect initiates connection to the associated remote address. The remote address was given when the Socket was created.

Connect should only be called on outgoing connections; Socket objects received by GotIncomingConnection callbacks are incoming connections and do not need to be "connected".

There is no return value indication of success here; the connection will not be fully established until the Socket's OnStateChangeCallback is called with state=StateConnect or state=StateWritable.

func (*Socket) GetDelays

func (s *Socket) GetDelays() (ours int32, theirs int32, age uint32)

GetDelays returns the currently measured delay values for the connection.

func (*Socket) GetOverhead

func (s *Socket) GetOverhead() int

GetOverhead returns the number of bytes of overhead that apply to each µTP packet sent (GetUDPOverhead() plus the size of the µTP packet header for the µTP protocol version in use for this connection).

func (*Socket) GetPacketSize

func (s *Socket) GetPacketSize() int

GetPacketSize returns the max number of bytes of payload the µTP connection is allowed to send at a time.

func (*Socket) GetPeerName

func (s *Socket) GetPeerName() *net.UDPAddr

GetPeerName returns the UDP address of the remote end of the connection.

func (*Socket) GetUDPMTU

func (s *Socket) GetUDPMTU() int

GetUDPMTU returns the maximum size of UDP packets that may be sent using this Socket.

func (*Socket) GetUDPOverhead

func (s *Socket) GetUDPOverhead() int

GetUDPOverhead returns the number of bytes of overhead that apply to each UDP packet sent (the size of a UDP header plus IPv4 or IPv6 overhead).

func (*Socket) RBDrained

func (s *Socket) RBDrained()

RBDrained notifies the Socket that the read buffer has been exhausted. This prompts the sending of an immediate ACK if appropriate, so that more data can arrive as soon as possible.

func (*Socket) SetCallbacks

func (s *Socket) SetCallbacks(funcs *CallbackTable, userdata interface{})

SetCallbacks assigns a table of callbacks to this Socket. If any callbacks were set previously, they are discarded.

This must be called before Connect, or mass hysteria could result.

func (*Socket) SetLogger

func (s *Socket) SetLogger(logger *zap.Logger)

SetLogger sets a new logger for the socket. If logger is nil, a no-op logger will be used.

func (*Socket) SetSockOpt

func (s *Socket) SetSockOpt(opt, val int) bool

SetSockOpt sets certain socket options on this µTP socket. This is intended to work similarly to the setsockopt() system call as used with UDP and TCP sockets, but it is not really the same thing; this only affects send and receive buffer sizes (SO_SNDBUF and SO_RCVBUF), and the µTP version to be used with this Socket (SO_UTPVERSION).

For incoming connections, the µTP version is determined by the initiating host, so setting SO_UTPVERSION only has an effect for outgoing connections before Connect() has been called.

The return value indicates whether or not the setting was valid.

func (*Socket) Write

func (s *Socket) Write(numBytes int) bool

Write indicates that the specified amount of data is ready to be sent.

The actual bytes to be sent are not passed to the socket at this point; the Socket depends on the calling code to keep track of the data buffers until it is ready to assemble packets. This minimizes the amount of copying that must be done, and gives the caller a great deal of control over how data is to be buffered.

As much data as can be sent immediately (subject to window sizes) will be collected with the Socket's OnWriteCallback and passed on in packetized form to the Socket's PacketSendCallback before Write() returns. The caller may need to call Write() again, when the Socket is able to write more, with the new total amount of data ready to be sent. Subsequent calls to Write() are not additive; each call provides a new _total_ amount of data ready to be sent.

The best way to know when the Socket is writable again appears to be by way of its OnStateChangeCallback. That callback can be called with state= StateWritable many times in succession. Therefore, it might be a good idea to call Write() every time the OnStateChangeCallback is called with StateWritable or StateConnected, if there actually is any data to send.

type SocketMapKey

type SocketMapKey struct {
	// contains filtered or unexported fields
}

type SocketMultiplexer

type SocketMultiplexer struct {
	// contains filtered or unexported fields
}

SocketMultiplexer coordinates µTP sockets that are sharing a single underlying PacketConn.

func NewSocketMultiplexer

func NewSocketMultiplexer(logger *zap.Logger, packetTimeCallback func() time.Duration, maxPacketSize int) *SocketMultiplexer

NewSocketMultiplexer creates a new instance of SocketMultiplexer.

func (*SocketMultiplexer) CheckTimeouts

func (mx *SocketMultiplexer) CheckTimeouts()

CheckTimeouts checks for timeout expiration on all current µTP sockets, and closes connections or causes state transitions as appropriate.

It should be called by the governing code often enough that timeouts can be noticed reasonably quickly. The ideal call frequency will depend on your particular situation, but for development purposes, once every 50ms seems to work well.

func (*SocketMultiplexer) Create

func (mx *SocketMultiplexer) Create(sendToCB PacketSendCallback, sendToUserdata interface{}, addr *net.UDPAddr, cid *ConnId) (*Socket, error)

Create a µTP socket for communication with a peer at the given address. Create a µTP socket for communication with a peer at the given address.

func (*SocketMultiplexer) HandleICMP

func (mx *SocketMultiplexer) HandleICMP(buffer []byte, toAddr *net.UDPAddr) bool

HandleICMP tells the µTP system to "process an ICMP received UDP packet." Why was a UDP packet received with ICMP? I don't know. It looks like the assumption here is that the ICMP packet is indicating an error with a sent UDP packet, so I suppose it is expecting ICMP messages like "Time exceeded" or "Destination unreachable".

func (*SocketMultiplexer) IsIncomingUTP

func (mx *SocketMultiplexer) IsIncomingUTP(incomingCB GotIncomingConnection, sendToCB PacketSendCallback, sendToUserdata interface{}, buffer []byte, toAddr *net.UDPAddr) bool

IsIncomingUTP passes a UDP packet into the µTP processing layer. If the provided packet appears to be µTP traffic, it will be associated with the appropriate existing connection or it will begin negotiation of a new connection.

The packet data should be passed in the 'buffer' parameter, and the source address that sent the data should be given in 'toAddr'.

The returned boolean value indicates whether the provided packet data did indeed appear to be µTP traffic. If it was not, the caller might want to do something else with it.

If a new connection is being initiated, a new Socket object will be created and passed to the provided GotIncomingConnection callback.

func (*SocketMultiplexer) SetPacketTimeCallback

func (mx *SocketMultiplexer) SetPacketTimeCallback(cb func() time.Duration)

SetPacketTimeCallback sets the packet time callback. The callback must return a positive and monotonically increasing time value. it is used to assign timestamps in microseconds and in milliseconds to various packet fields and timers.

This must not be called after any packets have been received or sent on the underlying PacketConn.

type State

type State int

State represents the state of a µTP socket. It is important to distinguish this type from connState, which is the state of a µTP _connection_. State conveys what a socket is prepared to do, while connState indicates a point in the µTP protocol state diagram. For most purposes, code using utp-go will only need to deal with State.

func (State) String

func (s State) String() string

type Stats

type Stats struct {
	NBytesRecv uint64 // total bytes received
	NBytesXmit uint64 // total bytes transmitted
	ReXmit     uint32 // retransmit counter
	FastReXmit uint32 // fast retransmit counter
	NXmit      uint32 // transmit counter
	NRecv      uint32 // receive counter (total)
	NDupRecv   uint32 // duplicate receive counter
}

Stats collects statistics for a particular Socket when utp-go is built with the 'utpstats' build tag. The (*Socket).GetStats() method will be made available when that build tag is present, and it will return a current copy of the Stats table for that socket.

When the utpstats build tag is not used, no per-socket statistics will be collected.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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