platform: modularize api/gui, add docs-tests-web foundation, and refresh root config
This commit is contained in:
186
selective-vpn-api/app/transport_client_runtime_alloc_slots.go
Normal file
186
selective-vpn-api/app/transport_client_runtime_alloc_slots.go
Normal file
@@ -0,0 +1,186 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func transportRoutingTableForID(id string) string {
|
||||
s := strings.TrimSpace(id)
|
||||
if s == "" {
|
||||
return "agvpn_client"
|
||||
}
|
||||
s = strings.ReplaceAll(s, "-", "_")
|
||||
s = strings.ReplaceAll(s, ".", "_")
|
||||
return normalizeTransportRoutingTable("agvpn_"+s, "agvpn_client")
|
||||
}
|
||||
|
||||
func transportRoutingTableForIfaceID(ifaceID string) string {
|
||||
id := normalizeTransportIfaceID(ifaceID)
|
||||
if id == transportDefaultIfaceID {
|
||||
return "agvpn_shared"
|
||||
}
|
||||
s := strings.ReplaceAll(id, "-", "_")
|
||||
return normalizeTransportRoutingTable("agvpn_if_"+s, "agvpn_client")
|
||||
}
|
||||
|
||||
func transportRoutingTableForIDUnique(id string, used map[string]struct{}) string {
|
||||
base := transportRoutingTableForID(id)
|
||||
if _, ok := used[base]; !ok {
|
||||
used[base] = struct{}{}
|
||||
return base
|
||||
}
|
||||
for i := 2; i < 1000; i++ {
|
||||
suffix := "_" + strconv.Itoa(i)
|
||||
maxBase := 31 - len(suffix)
|
||||
if maxBase < 1 {
|
||||
maxBase = 1
|
||||
}
|
||||
prefix := base
|
||||
if len(prefix) > maxBase {
|
||||
prefix = prefix[:maxBase]
|
||||
}
|
||||
cand := prefix + suffix
|
||||
if _, ok := used[cand]; ok {
|
||||
continue
|
||||
}
|
||||
used[cand] = struct{}{}
|
||||
return cand
|
||||
}
|
||||
used[base] = struct{}{}
|
||||
return base
|
||||
}
|
||||
|
||||
func normalizeTransportRoutingTable(raw string, fallback string) string {
|
||||
table := strings.ToLower(strings.TrimSpace(raw))
|
||||
if table == "" {
|
||||
table = strings.ToLower(strings.TrimSpace(fallback))
|
||||
}
|
||||
if table == "" {
|
||||
return "agvpn_client"
|
||||
}
|
||||
table = strings.ReplaceAll(table, "-", "_")
|
||||
table = strings.ReplaceAll(table, ".", "_")
|
||||
table = strings.ReplaceAll(table, " ", "_")
|
||||
var b strings.Builder
|
||||
b.Grow(len(table))
|
||||
lastUnderscore := false
|
||||
for i := 0; i < len(table); i++ {
|
||||
ch := table[i]
|
||||
isAZ := ch >= 'a' && ch <= 'z'
|
||||
is09 := ch >= '0' && ch <= '9'
|
||||
if isAZ || is09 {
|
||||
b.WriteByte(ch)
|
||||
lastUnderscore = false
|
||||
continue
|
||||
}
|
||||
if !lastUnderscore {
|
||||
b.WriteByte('_')
|
||||
lastUnderscore = true
|
||||
}
|
||||
}
|
||||
table = strings.Trim(b.String(), "_")
|
||||
if table == "" {
|
||||
table = "agvpn_client"
|
||||
}
|
||||
if !strings.HasPrefix(table, "agvpn_") {
|
||||
table = "agvpn_" + table
|
||||
}
|
||||
if len(table) > 31 {
|
||||
table = strings.Trim(table[:31], "_")
|
||||
}
|
||||
if table == "" {
|
||||
return "agvpn_client"
|
||||
}
|
||||
return table
|
||||
}
|
||||
|
||||
func parseTransportMarkHex(raw string) (uint64, bool) {
|
||||
s := strings.ToLower(strings.TrimSpace(raw))
|
||||
if !strings.HasPrefix(s, "0x") {
|
||||
return 0, false
|
||||
}
|
||||
n, err := strconv.ParseUint(strings.TrimPrefix(s, "0x"), 16, 64)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
if !transportMarkAllowed(n) {
|
||||
return 0, false
|
||||
}
|
||||
return n, true
|
||||
}
|
||||
|
||||
func parseTransportPref(raw int) (int, bool) {
|
||||
if !transportPrefAllowed(raw) {
|
||||
return 0, false
|
||||
}
|
||||
return raw, true
|
||||
}
|
||||
|
||||
func transportMarkAllowed(mark uint64) bool {
|
||||
if mark < transportMarkStart || mark > transportMarkEnd {
|
||||
return false
|
||||
}
|
||||
if mark <= transportMarkReserveEnd {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func transportPrefAllowed(pref int) bool {
|
||||
if pref < transportPrefStart || pref > transportPrefEnd {
|
||||
return false
|
||||
}
|
||||
if pref <= transportPrefReserveEnd {
|
||||
return false
|
||||
}
|
||||
if (pref-transportPrefStart)%transportPrefStep != 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func nextTransportMark(used map[uint64]struct{}) uint64 {
|
||||
for v := transportMarkStart; v <= transportMarkEnd; v++ {
|
||||
if !transportMarkAllowed(v) {
|
||||
continue
|
||||
}
|
||||
if _, ok := used[v]; ok {
|
||||
continue
|
||||
}
|
||||
return v
|
||||
}
|
||||
// Fallback: reuse first available from pool even if exhausted.
|
||||
for v := transportMarkStart; v <= transportMarkEnd; v++ {
|
||||
if !transportMarkAllowed(v) {
|
||||
continue
|
||||
}
|
||||
return v
|
||||
}
|
||||
return transportMarkStart
|
||||
}
|
||||
|
||||
func nextTransportPref(used map[int]struct{}) int {
|
||||
for p := transportPrefStart; p <= transportPrefEnd; p += transportPrefStep {
|
||||
if !transportPrefAllowed(p) {
|
||||
continue
|
||||
}
|
||||
if _, ok := used[p]; ok {
|
||||
continue
|
||||
}
|
||||
return p
|
||||
}
|
||||
// Fallback: reuse first available from pool even if exhausted.
|
||||
for p := transportPrefStart; p <= transportPrefEnd; p += transportPrefStep {
|
||||
if !transportPrefAllowed(p) {
|
||||
continue
|
||||
}
|
||||
return p
|
||||
}
|
||||
return transportPrefStart
|
||||
}
|
||||
|
||||
func formatTransportMarkHex(mark uint64) string {
|
||||
return fmt.Sprintf("0x%x", mark)
|
||||
}
|
||||
Reference in New Issue
Block a user