mirror of
https://github.com/jech/galene.git
synced 2024-11-23 00:55:58 +01:00
205 lines
3.8 KiB
Go
205 lines
3.8 KiB
Go
|
// Package packetmap implements remapping of sequence numbers and picture ids.
|
||
|
package packetmap
|
||
|
|
||
|
import (
|
||
|
"sync"
|
||
|
)
|
||
|
|
||
|
const maxEntries = 128
|
||
|
|
||
|
type Map struct {
|
||
|
mu sync.Mutex
|
||
|
next uint16
|
||
|
nextPid uint16
|
||
|
delta uint16
|
||
|
pidDelta uint16
|
||
|
lastEntry uint16
|
||
|
entries []entry
|
||
|
}
|
||
|
|
||
|
type entry struct {
|
||
|
first, count uint16
|
||
|
delta uint16
|
||
|
pidDelta uint16
|
||
|
}
|
||
|
|
||
|
// Map maps a seqno, adding the mapping if required. It returns whether
|
||
|
// the seqno could be mapped, the target seqno, and the pid delta to apply.
|
||
|
func (m *Map) Map(seqno uint16, pid uint16) (bool, uint16, uint16) {
|
||
|
m.mu.Lock()
|
||
|
defer m.mu.Unlock()
|
||
|
|
||
|
if m.delta == 0 && m.entries == nil {
|
||
|
m.next = seqno + 1
|
||
|
m.nextPid = pid
|
||
|
return true, seqno, 0
|
||
|
}
|
||
|
|
||
|
if compare(m.next, seqno) <= 0 {
|
||
|
if uint16(seqno-m.next) > 8*1024 {
|
||
|
m.reset()
|
||
|
m.next = seqno + 1
|
||
|
m.nextPid = pid
|
||
|
return true, seqno, 0
|
||
|
}
|
||
|
addMapping(m, seqno, pid, m.delta, m.pidDelta)
|
||
|
m.next = seqno + 1
|
||
|
m.nextPid = pid
|
||
|
return true, seqno + m.delta, m.pidDelta
|
||
|
}
|
||
|
|
||
|
if uint16(m.next-seqno) > 8*1024 {
|
||
|
m.reset()
|
||
|
m.next = seqno + 1
|
||
|
m.nextPid = pid
|
||
|
return true, seqno, 0
|
||
|
}
|
||
|
|
||
|
return m.direct(seqno)
|
||
|
}
|
||
|
|
||
|
func (m *Map) reset() {
|
||
|
m.next = 0
|
||
|
m.nextPid = 0
|
||
|
m.delta = 0
|
||
|
m.pidDelta = 0
|
||
|
m.lastEntry = 0
|
||
|
m.entries = nil
|
||
|
}
|
||
|
|
||
|
func addMapping(m *Map, seqno, pid uint16, delta, pidDelta uint16) {
|
||
|
if len(m.entries) == 0 {
|
||
|
m.entries = []entry{
|
||
|
entry{
|
||
|
first: seqno,
|
||
|
count: 1,
|
||
|
delta: delta,
|
||
|
pidDelta: pidDelta,
|
||
|
},
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
i := m.lastEntry
|
||
|
if delta == m.entries[i].delta && pidDelta == m.entries[i].pidDelta {
|
||
|
m.entries[m.lastEntry].count = seqno - m.entries[i].first + 1
|
||
|
return
|
||
|
}
|
||
|
|
||
|
e := entry{
|
||
|
first: seqno,
|
||
|
count: 1,
|
||
|
delta: delta,
|
||
|
pidDelta: pidDelta,
|
||
|
}
|
||
|
|
||
|
if len(m.entries) < maxEntries {
|
||
|
m.entries = append(m.entries, e)
|
||
|
m.lastEntry = uint16(len(m.entries) - 1)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
j := (m.lastEntry + 1) % maxEntries
|
||
|
m.entries[j] = e
|
||
|
m.lastEntry = j
|
||
|
}
|
||
|
|
||
|
// direct maps a seqno to a target seqno. It returns true if the seqno
|
||
|
// could be mapped, the target seqno, and the pid delta to apply.
|
||
|
// Called with the m.mu taken.
|
||
|
func (m *Map) direct(seqno uint16) (bool, uint16, uint16) {
|
||
|
if len(m.entries) == 0 {
|
||
|
return false, 0, 0
|
||
|
}
|
||
|
i := m.lastEntry
|
||
|
for {
|
||
|
f := m.entries[i].first
|
||
|
if seqno >= f {
|
||
|
if seqno < f+m.entries[i].count {
|
||
|
return true,
|
||
|
seqno + m.entries[i].delta,
|
||
|
m.entries[i].pidDelta
|
||
|
}
|
||
|
return false, 0, 0
|
||
|
}
|
||
|
if i > 0 {
|
||
|
i--
|
||
|
} else {
|
||
|
i = uint16(len(m.entries) - 1)
|
||
|
}
|
||
|
if i == m.lastEntry {
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
return false, 0, 0
|
||
|
}
|
||
|
|
||
|
// Reverse maps a target seqno to the original seqno. It returns true if
|
||
|
// the seqno could be mapped, the original seqno, and the pid delta to
|
||
|
// apply in reverse.
|
||
|
func (m *Map) Reverse(seqno uint16) (bool, uint16, uint16) {
|
||
|
m.mu.Lock()
|
||
|
defer m.mu.Unlock()
|
||
|
|
||
|
if m.delta == 0 && m.entries == nil {
|
||
|
return true, seqno, 0
|
||
|
}
|
||
|
if m.entries == nil {
|
||
|
if m.delta == 0 {
|
||
|
return true, seqno, 0
|
||
|
}
|
||
|
return false, 0, 0
|
||
|
}
|
||
|
|
||
|
i := m.lastEntry
|
||
|
for {
|
||
|
f := m.entries[i].first + m.entries[i].delta
|
||
|
if seqno >= f {
|
||
|
if seqno < f+m.entries[i].count {
|
||
|
return true,
|
||
|
seqno - m.entries[i].delta,
|
||
|
m.entries[i].pidDelta
|
||
|
}
|
||
|
return false, 0, 0
|
||
|
}
|
||
|
if i > 0 {
|
||
|
i--
|
||
|
} else {
|
||
|
i = uint16(len(m.entries) - 1)
|
||
|
}
|
||
|
if i == m.lastEntry {
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
return false, 0, 0
|
||
|
}
|
||
|
|
||
|
// Drop attempts to record a dropped packet. It returns true if the
|
||
|
// packet is safe to drop.
|
||
|
func (m *Map) Drop(seqno uint16, pid uint16) bool {
|
||
|
m.mu.Lock()
|
||
|
defer m.mu.Unlock()
|
||
|
|
||
|
if seqno != m.next {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
m.pidDelta += pid - m.nextPid
|
||
|
m.nextPid = pid
|
||
|
|
||
|
m.delta--
|
||
|
m.next = seqno + 1
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
// compare performs comparison modulo 2^16.
|
||
|
func compare(s1, s2 uint16) int {
|
||
|
if s1 == s2 {
|
||
|
return 0
|
||
|
}
|
||
|
if ((s2 - s1) & 0x8000) != 0 {
|
||
|
return 1
|
||
|
}
|
||
|
return -1
|
||
|
}
|