go_goutils/netx/inetcksum/funcs_inetchecksumsimple.go
brent saner 965657d1b2
v1.10.1
FIXED:
* Missed a Reset on the inetcksum.InetChecksumSimple.
2025-09-05 18:55:01 -04:00

173 lines
3.9 KiB
Go

package inetcksum
/*
Aligned returns true if the current checksum for an InetChecksumSimple is
aligned to the algorithm's requirement for an even number of bytes.
Note that if Aligned returns false, a single null pad byte will be applied
to the underlying data buffer at time of a Sum* call.
*/
func (i *InetChecksumSimple) Aligned() (aligned bool) {
aligned = i.aligned
return
}
// BlockSize returns the number of bytes at a time that InetChecksumSimple operates on. (It will always return 1.)
func (i *InetChecksumSimple) BlockSize() (blockSize int) {
blockSize = 1
return
}
// Reset resets the state of an InetChecksumSimple.
func (i *InetChecksumSimple) Reset() {
i.last = 0x00
i.sum = 0
i.last = 0x00
}
// Size returns how many bytes a checksum is. (It will always return 2.)
func (i *InetChecksumSimple) Size() (bufSize int) {
bufSize = 2
return
}
// Sum computes the checksum cksum of the current buffer and appends it as big-endian bytes to b.
func (i *InetChecksumSimple) Sum(b []byte) (cksumAppended []byte) {
var sum16 []byte = i.Sum16Bytes()
cksumAppended = append(b, sum16...)
return
}
/*
Sum16 computes the checksum of the current buffer and returns it as a uint16.
This is the native number used in the IPv4 header.
All other Sum* methods wrap this method.
If the underlying buffer is empty or nil, cksum will be 0xffff (65535)
in line with common implementations.
*/
func (i *InetChecksumSimple) Sum16() (cksum uint16) {
var thisSum uint32
thisSum = i.sum
if !i.aligned {
/*
"Pad" at the end of the additive ops - a bitshift is used on the sum integer itself
instead of a binary.Append() or append() or such to avoid additional memory allocation.
*/
thisSum += uint32(i.last) << padShift
}
// Fold the "carried ones".
for thisSum > cksumMask {
thisSum = (thisSum & cksumMask) + (thisSum >> cksumShift)
}
cksum = ^uint16(thisSum)
return
}
/*
Sum16Bytes is a convenience wrapper around [InetChecksumSimple.Sum16]
which returns a slice of the uint16 as a 2-byte-long slice instead.
*/
func (i *InetChecksumSimple) Sum16Bytes() (cksum []byte) {
var sum16 uint16 = i.Sum16()
cksum = make([]byte, 2)
ord.PutUint16(cksum, sum16)
return
}
/*
Write writes data to the underlying InetChecksumSimple buffer. It conforms to [io.Writer].
p may be nil or empty; no error will be returned and n will be 0 if so.
A copy of p is made first and all hashing operations are performed on that copy.
*/
func (i *InetChecksumSimple) Write(p []byte) (n int, err error) {
var idx int
var bufLen int
var buf []byte
var iter int
if p == nil || len(p) == 0 {
return
}
// The TL;DR here is the checksum boils down to:
// cksum = cksum + ((high << 8) | low)
bufLen = len(p)
buf = make([]byte, bufLen)
copy(buf, p)
if !i.aligned {
// Last write was unaligned, so pair i.last in.
i.sum += (uint32(i.last) << padShift) | uint32(buf[0])
i.aligned = true
idx = 1
}
// Operate on bytepairs.
// Note that idx is set to either 0 or 1 depending on if
// buf[0] has already been summed in.
for iter = idx; iter < bufLen; iter += 2 {
if iter+1 < bufLen {
// Technically could use "i.sum += uint32(ord.Uint16(buf[iter:iter+2))" here instead.
i.sum += (uint32(buf[iter]) << padShift) | uint32(buf[iter+1])
} else {
i.last = buf[iter]
i.aligned = false
break
}
}
return
}
// WriteByte checksums a single byte. It conforms to [io.ByteWriter].
func (i *InetChecksumSimple) WriteByte(c byte) (err error) {
if i.aligned {
// Since it's a single byte, we just set i.last and unalign.
i.last = c
i.aligned = false
} else {
// It's unaligned, so join with i.last and align.
i.sum += (uint32(i.last) << padShift) | uint32(c)
i.aligned = true
}
return
}
// WriteString checksums a string. It conforms to [io.StringWriter].
func (i *InetChecksumSimple) WriteString(s string) (n int, err error) {
if n, err = i.Write([]byte(s)); err != nil {
return
}
return
}