Browse Source

WIP: debug byte order diagnostics

congestion
Evgeny 5 months ago
parent
commit
77fd7c19de
  1. 115
      .opencode/package-lock.json
  2. 1
      1
  3. 254
      index.html
  4. 549
      lib/ll_queue.c1
  5. 130
      lib/ll_queue.h2
  6. BIN
      linux-x64-deb
  7. 6
      src/direct_connect.txt
  8. 24
      src/route_bgp.c
  9. 7
      src/route_bgp.h
  10. 71
      src/route_bgp1.txt
  11. 3
      src/route_node.c
  12. 146
      src/route_ping.c
  13. 13
      src/route_ping.h
  14. BIN
      test_serialize
  15. 4
      tests/FIX_SUMMARY.md
  16. 41
      tests/test_nat_detection.c
  17. 48
      tests/test_route_ping.c
  18. BIN
      tools/bping/bping
  19. 2
      tools/proxy/proxy.sh
  20. BIN
      tools/proxy/udp_proxy
  21. 106
      utun.log1

115
.opencode/package-lock.json generated

@ -0,0 +1,115 @@
{
"name": ".opencode",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"dependencies": {
"@opencode-ai/plugin": "1.4.3"
}
},
"node_modules/@opencode-ai/plugin": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/@opencode-ai/plugin/-/plugin-1.4.3.tgz",
"integrity": "sha512-Ob/3tVSIeuMRJBr2O23RtrnC5djRe01Lglx+TwGEmjrH9yDBJ2tftegYLnNEjRoMuzITgq9LD8168p4pzv+U/A==",
"license": "MIT",
"dependencies": {
"@opencode-ai/sdk": "1.4.3",
"zod": "4.1.8"
},
"peerDependencies": {
"@opentui/core": ">=0.1.97",
"@opentui/solid": ">=0.1.97"
},
"peerDependenciesMeta": {
"@opentui/core": {
"optional": true
},
"@opentui/solid": {
"optional": true
}
}
},
"node_modules/@opencode-ai/sdk": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/@opencode-ai/sdk/-/sdk-1.4.3.tgz",
"integrity": "sha512-X0CAVbwoGAjTY2iecpWkx2B+GAa2jSaQKYpJ+xILopeF/OGKZUN15mjqci+L7cEuwLHV5wk3x2TStUOVCa5p0A==",
"license": "MIT",
"dependencies": {
"cross-spawn": "7.0.6"
}
},
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"license": "MIT",
"dependencies": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
"which": "^2.0.1"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
"license": "ISC"
},
"node_modules/path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"license": "MIT",
"dependencies": {
"shebang-regex": "^3.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/shebang-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"license": "ISC",
"dependencies": {
"isexe": "^2.0.0"
},
"bin": {
"node-which": "bin/node-which"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/zod": {
"version": "4.1.8",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
}
}
}

1
1

@ -0,0 +1 @@
/bin/bash: строка 1: ./test_nat_detection: Нет такого файла или каталога

254
index.html

@ -0,0 +1,254 @@
<!DOCTYPE html>
<html lang="en-US" class="theme-">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title> Gitea: Git with a cup of tea</title>
<link rel="manifest" href="data:application/json;base64,eyJuYW1lIjoiR2l0ZWE6IEdpdCB3aXRoIGEgY3VwIG9mIHRlYSIsInNob3J0X25hbWUiOiJHaXRlYTogR2l0IHdpdGggYSBjdXAgb2YgdGVhIiwic3RhcnRfdXJsIjoiaHR0cDovL2dpdC5zeXFpcS50ZWNoLyIsImljb25zIjpbeyJzcmMiOiJodHRwOi8vZ2l0LnN5cWlxLnRlY2gvYXNzZXRzL2ltZy9sb2dvLnBuZyIsInR5cGUiOiJpbWFnZS9wbmciLCJzaXplcyI6IjUxMng1MTIifSx7InNyYyI6Imh0dHA6Ly9naXQuc3lxaXEudGVjaC9hc3NldHMvaW1nL2xvZ28uc3ZnIiwidHlwZSI6ImltYWdlL3N2Zyt4bWwiLCJzaXplcyI6IjUxMng1MTIifV19"/>
<meta name="theme-color" content="#6cc644">
<meta name="default-theme" content="auto" />
<meta name="author" content="Gitea - Git with a cup of tea" />
<meta name="description" content="Gitea (Git with a cup of tea) is a painless self-hosted Git service written in Go" />
<meta name="keywords" content="go,git,self-hosted,gitea">
<meta name="referrer" content="no-referrer" />
<script>
<!-- -->
window.config = {
appVer: '1.16.8',
appSubUrl: '',
assetUrlPrefix: '\/assets',
runModeIsProd: true ,
customEmojis: {"codeberg":":codeberg:","git":":git:","gitea":":gitea:","github":":github:","gitlab":":gitlab:","gogs":":gogs:"},
useServiceWorker: false ,
csrfToken: '6EOyiSz2x5RvQNfHOCkVdgIqjkI6MTc3NjAwNjA5ODg2OTgyMDIwNg',
pageData: {},
requireTribute: null ,
notificationSettings: {"EventSourceUpdateTime":10000,"MaxTimeout":60000,"MinTimeout":10000,"TimeoutStep":10000},
enableTimeTracking: true ,
mermaidMaxSourceCharacters: 5000 ,
i18n: {
copy_success: 'Copied!',
copy_error: 'Copy failed',
error_occurred: 'An error occurred',
network_error: 'Network error',
},
};
window.config.pageData = window.config.pageData || {};
</script>
<link rel="icon" href="/assets/img/logo.svg" type="image/svg+xml">
<link rel="alternate icon" href="/assets/img/favicon.png" type="image/png">
<link rel="stylesheet" href="/assets/css/index.css?v=6765b707120e1e5736d66531d590dceb">
<noscript>
<style>
.dropdown:hover > .menu { display: block; }
.ui.secondary.menu .dropdown.item > .menu { margin-top: 0; }
</style>
</noscript>
<meta property="og:title" content="Gitea: Git with a cup of tea">
<meta property="og:type" content="website" />
<meta property="og:image" content="/assets/img/logo.png" />
<meta property="og:url" content="http://git.syqiq.tech/" />
<meta property="og:description" content="Gitea (Git with a cup of tea) is a painless self-hosted Git service written in Go">
<meta property="og:site_name" content="Gitea: Git with a cup of tea" />
<link rel="stylesheet" href="/assets/css/theme-auto.css?v=6765b707120e1e5736d66531d590dceb">
</head>
<body>
<div class="full height">
<noscript>This website works better with JavaScript.</noscript>
<div class="ui top secondary stackable main menu following bar light">
<div class="ui container" id="navbar">
<div class="item brand" style="justify-content: space-between;">
<a href="/" data-content="Home">
<img class="ui mini image" width="30" height="30" src="/assets/img/logo.svg">
</a>
<div class="ui basic icon button mobile-only" id="navbar-expand-toggle">
<i class="sidebar icon"></i>
</div>
</div>
<a class="item " href="/explore/repos">Explore</a>
<a class="item" target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io">Help</a>
<div class="right stackable menu">
<a class="item" rel="nofollow" href="/user/login?redirect_to=%2f">
<svg viewBox="0 0 16 16" class="svg octicon-sign-in" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M2 2.75C2 1.784 2.784 1 3.75 1h2.5a.75.75 0 0 1 0 1.5h-2.5a.25.25 0 0 0-.25.25v10.5c0 .138.112.25.25.25h2.5a.75.75 0 0 1 0 1.5h-2.5A1.75 1.75 0 0 1 2 13.25V2.75zm6.56 4.5 1.97-1.97a.75.75 0 1 0-1.06-1.06L6.22 7.47a.75.75 0 0 0 0 1.06l3.25 3.25a.75.75 0 1 0 1.06-1.06L8.56 8.75h5.69a.75.75 0 0 0 0-1.5H8.56z"/></svg> Sign In
</a>
</div>
</div>
</div>
<div class="page-content home">
<div class="ui stackable middle very relaxed page grid">
<div class="sixteen wide center aligned centered column">
<div>
<img class="logo" width="220" height="220" src="/assets/img/logo.svg"/>
</div>
<div class="hero">
<h1 class="ui icon header title">
Gitea: Git with a cup of tea
</h1>
<h2>A painless, self-hosted Git service</h2>
</div>
</div>
</div>
<div class="ui stackable middle very relaxed page grid">
<div class="eight wide center column">
<h1 class="hero ui icon header">
<svg viewBox="0 0 16 16" class="svg octicon-flame" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M7.998 14.5c2.832 0 5-1.98 5-4.5 0-1.463-.68-2.19-1.879-3.383l-.036-.037c-1.013-1.008-2.3-2.29-2.834-4.434-.322.256-.63.579-.864.953-.432.696-.621 1.58-.046 2.73.473.947.67 2.284-.278 3.232-.61.61-1.545.84-2.403.633a2.788 2.788 0 0 1-1.436-.874A3.21 3.21 0 0 0 3 10c0 2.53 2.164 4.5 4.998 4.5zM9.533.753C9.496.34 9.16.009 8.77.146 7.035.75 4.34 3.187 5.997 6.5c.344.689.285 1.218.003 1.5-.419.419-1.54.487-2.04-.832-.173-.454-.659-.762-1.035-.454C2.036 7.44 1.5 8.702 1.5 10c0 3.512 2.998 6 6.498 6s6.5-2.5 6.5-6c0-2.137-1.128-3.26-2.312-4.438-1.19-1.184-2.436-2.425-2.653-4.81z"/></svg> Easy to install
</h1>
<p class="large">
Simply <a target="_blank" rel="noopener noreferrer nofollow" href="https://docs.gitea.io/en-us/install-from-binary/">run the binary</a> for your platform, ship it with <a target="_blank" rel="noopener noreferrer nofollow" href="https://github.com/go-gitea/gitea/tree/master/docker">Docker</a>, or get it <a target="_blank" rel="noopener noreferrer nofollow" href="https://docs.gitea.io/en-us/install-from-package/">packaged</a>.
</p>
</div>
<div class="eight wide center column">
<h1 class="hero ui icon header">
<svg viewBox="0 0 16 16" class="svg octicon-device-desktop" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M1.75 2.5h12.5a.25.25 0 0 1 .25.25v7.5a.25.25 0 0 1-.25.25H1.75a.25.25 0 0 1-.25-.25v-7.5a.25.25 0 0 1 .25-.25zM14.25 1H1.75A1.75 1.75 0 0 0 0 2.75v7.5C0 11.216.784 12 1.75 12h3.727c-.1 1.041-.52 1.872-1.292 2.757A.75.75 0 0 0 4.75 16h6.5a.75.75 0 0 0 .565-1.243c-.772-.885-1.193-1.716-1.292-2.757h3.727A1.75 1.75 0 0 0 16 10.25v-7.5A1.75 1.75 0 0 0 14.25 1zM9.018 12H6.982a5.72 5.72 0 0 1-.765 2.5h3.566a5.72 5.72 0 0 1-.765-2.5z"/></svg> Cross-platform
</h1>
<p class="large">
Gitea runs anywhere <a target="_blank" rel="noopener noreferrer nofollow" href="http://golang.org/">Go</a> can compile for: Windows, macOS, Linux, ARM, etc. Choose the one you love!
</p>
</div>
</div>
<div class="ui stackable middle very relaxed page grid">
<div class="eight wide center column">
<h1 class="hero ui icon header">
<svg viewBox="0 0 16 16" class="svg octicon-rocket" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M14.064 0a8.75 8.75 0 0 0-6.187 2.563l-.459.458c-.314.314-.616.641-.904.979H3.31a1.75 1.75 0 0 0-1.49.833L.11 7.607a.75.75 0 0 0 .418 1.11l3.102.954c.037.051.079.1.124.145l2.429 2.428c.046.046.094.088.145.125l.954 3.102a.75.75 0 0 0 1.11.418l2.774-1.707a1.75 1.75 0 0 0 .833-1.49V9.485c.338-.288.665-.59.979-.904l.458-.459A8.75 8.75 0 0 0 16 1.936V1.75A1.75 1.75 0 0 0 14.25 0h-.186zM10.5 10.625c-.088.06-.177.118-.266.175l-2.35 1.521.548 1.783 1.949-1.2a.25.25 0 0 0 .119-.213v-2.066zM3.678 8.116 5.2 5.766c.058-.09.117-.178.176-.266H3.309a.25.25 0 0 0-.213.119l-1.2 1.95 1.782.547zm5.26-4.493A7.25 7.25 0 0 1 14.063 1.5h.186a.25.25 0 0 1 .25.25v.186a7.25 7.25 0 0 1-2.123 5.127l-.459.458a15.21 15.21 0 0 1-2.499 2.02l-2.317 1.5-2.143-2.143 1.5-2.317a15.25 15.25 0 0 1 2.02-2.5l.458-.458h.002zM12 5a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm-8.44 9.56a1.5 1.5 0 1 0-2.12-2.12c-.734.73-1.047 2.332-1.15 3.003a.23.23 0 0 0 .265.265c.671-.103 2.273-.416 3.005-1.148z"/></svg> Lightweight
</h1>
<p class="large">
Gitea has low minimal requirements and can run on an inexpensive Raspberry Pi. Save your machine energy!
</p>
</div>
<div class="eight wide center column">
<h1 class="hero ui icon header">
<svg viewBox="0 0 16 16" class="svg octicon-code" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M4.72 3.22a.75.75 0 0 1 1.06 1.06L2.06 8l3.72 3.72a.75.75 0 1 1-1.06 1.06L.47 8.53a.75.75 0 0 1 0-1.06l4.25-4.25zm6.56 0a.75.75 0 1 0-1.06 1.06L13.94 8l-3.72 3.72a.75.75 0 1 0 1.06 1.06l4.25-4.25a.75.75 0 0 0 0-1.06l-4.25-4.25z"/></svg> Open Source
</h1>
<p class="large">
Go get <a target="_blank" rel="noopener noreferrer nofollow" href="https://code.gitea.io/gitea">code.gitea.io/gitea</a>! Join us by <a target="_blank" rel="noopener noreferrer nofollow" href="https://github.com/go-gitea/gitea">contributing</a> to make this project even better. Don&#39;t be shy to be a contributor!
</p>
</div>
</div>
</div>
</div>
<footer>
<div class="ui container">
<div class="ui left">
Powered by Gitea Version: 1.16.8 Page: <strong>3ms</strong> Template: <strong>3ms</strong>
</div>
<div class="ui right links">
<div class="ui language bottom floating slide up dropdown link item">
<svg viewBox="0 0 16 16" class="svg octicon-globe" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M1.543 7.25h2.733c.144-2.074.866-3.756 1.58-4.948.12-.197.237-.381.353-.552a6.506 6.506 0 0 0-4.666 5.5zm2.733 1.5H1.543a6.506 6.506 0 0 0 4.666 5.5 11.13 11.13 0 0 1-.352-.552c-.715-1.192-1.437-2.874-1.581-4.948zm1.504 0h4.44a9.637 9.637 0 0 1-1.363 4.177c-.306.51-.612.919-.857 1.215a9.978 9.978 0 0 1-.857-1.215A9.637 9.637 0 0 1 5.78 8.75zm4.44-1.5H5.78a9.637 9.637 0 0 1 1.363-4.177c.306-.51.612-.919.857-1.215.245.296.55.705.857 1.215A9.638 9.638 0 0 1 10.22 7.25zm1.504 1.5c-.144 2.074-.866 3.756-1.58 4.948-.12.197-.237.381-.353.552a6.506 6.506 0 0 0 4.666-5.5h-2.733zm2.733-1.5h-2.733c-.144-2.074-.866-3.756-1.58-4.948a11.738 11.738 0 0 0-.353-.552 6.506 6.506 0 0 1 4.666 5.5zM8 0a8 8 0 1 0 0 16A8 8 0 0 0 8 0z"/></svg>
<div class="text">English</div>
<div class="menu language-menu">
<a lang="id-ID" data-url="/?lang=id-ID" class="item ">bahasa Indonesia</a>
<a lang="de-DE" data-url="/?lang=de-DE" class="item ">Deutsch</a>
<a lang="en-US" data-url="/?lang=en-US" class="item active selected">English</a>
<a lang="es-ES" data-url="/?lang=es-ES" class="item ">español</a>
<a lang="fr-FR" data-url="/?lang=fr-FR" class="item ">français</a>
<a lang="it-IT" data-url="/?lang=it-IT" class="item ">italiano</a>
<a lang="lv-LV" data-url="/?lang=lv-LV" class="item ">latviešu</a>
<a lang="hu-HU" data-url="/?lang=hu-HU" class="item ">magyar nyelv</a>
<a lang="nl-NL" data-url="/?lang=nl-NL" class="item ">Nederlands</a>
<a lang="pl-PL" data-url="/?lang=pl-PL" class="item ">polski</a>
<a lang="pt-PT" data-url="/?lang=pt-PT" class="item ">Português de Portugal</a>
<a lang="pt-BR" data-url="/?lang=pt-BR" class="item ">português do Brasil</a>
<a lang="fi-FI" data-url="/?lang=fi-FI" class="item ">suomi</a>
<a lang="sv-SE" data-url="/?lang=sv-SE" class="item ">svenska</a>
<a lang="tr-TR" data-url="/?lang=tr-TR" class="item ">Türkçe</a>
<a lang="cs-CZ" data-url="/?lang=cs-CZ" class="item ">čeština</a>
<a lang="el-GR" data-url="/?lang=el-GR" class="item ">ελληνικά</a>
<a lang="bg-BG" data-url="/?lang=bg-BG" class="item ">български</a>
<a lang="ru-RU" data-url="/?lang=ru-RU" class="item ">русский</a>
<a lang="sr-SP" data-url="/?lang=sr-SP" class="item ">српски</a>
<a lang="uk-UA" data-url="/?lang=uk-UA" class="item ">Українська</a>
<a lang="fa-IR" data-url="/?lang=fa-IR" class="item ">فارسی</a>
<a lang="ml-IN" data-url="/?lang=ml-IN" class="item ">മലയാളം</a>
<a lang="ja-JP" data-url="/?lang=ja-JP" class="item ">日本語</a>
<a lang="zh-CN" data-url="/?lang=zh-CN" class="item ">简体中文</a>
<a lang="zh-TW" data-url="/?lang=zh-TW" class="item ">繁體中文(台灣)</a>
<a lang="zh-HK" data-url="/?lang=zh-HK" class="item ">繁體中文(香港)</a>
<a lang="ko-KR" data-url="/?lang=ko-KR" class="item ">한국어</a>
</div>
</div>
<a href="/assets/js/licenses.txt">Licenses</a>
<a href="/api/swagger">API</a>
<a target="_blank" rel="noopener noreferrer" href="https://gitea.io">Website</a>
<span class="version">Go1.18.4</span>
</div>
</div>
</footer>
<script src="/assets/js/index.js?v=6765b707120e1e5736d66531d590dceb"></script>
</body>
</html>

549
lib/ll_queue.c1

@ -0,0 +1,549 @@
// ll_queue.c - Упрощенная архитектура: разделение создания элементов и работы с очередью
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include "ll_queue.h"
#include "u_async.h"
#include "debug_config.h"
#include "mem.h"
#ifdef _WIN32
#include <windows.h>
#else
#include <pthread.h>
#endif
// ==================== Thread safety check ====================
#ifdef QUEUE_THREAD_CHECK
static inline void queue_check_thread(struct ll_queue* q) {
if (!q) return;
#ifdef _WIN32
DWORD current = GetCurrentThreadId();
if (q->owner_thread != current) {
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "Queue '%s': thread mismatch! owner=%lu current=%lu",
q->name ? q->name : "unknown",
(unsigned long)q->owner_thread,
(unsigned long)current);
printf("ERROR: Queue '%s' accessed from wrong thread!\n", q->name ? q->name : "unknown");
abort();
}
#else
pthread_t current = pthread_self();
if (!pthread_equal(q->owner_thread, current)) {
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "Queue '%s': thread mismatch! owner=%lu current=%lu",
q->name ? q->name : "unknown",
(unsigned long)q->owner_thread,
(unsigned long)current);
printf("ERROR: Queue '%s' accessed from wrong thread!\n", q->name ? q->name : "unknown");
abort();
}
#endif
}
#endif
// Предварительные объявления внутренних функций
static void queue_resume_timeout_cb(void* arg);
static void check_waiters(struct ll_queue* q);
static void add_to_hash(struct ll_queue* q, struct ll_entry* entry);
static void remove_from_hash(struct ll_queue* q, struct ll_entry* entry);
// ==================== Управление очередью ====================
struct ll_queue* queue_new(struct UASYNC* ua, size_t hash_size, char* name) {
if (!ua) return NULL;
struct ll_queue* q = u_calloc(1, sizeof(struct ll_queue));
if (!q) return NULL;
q->name = name;
q->ua = ua;
q->size_limit = -1; // Без ограничения по умолчанию
q->hash_size = hash_size;
#ifdef QUEUE_THREAD_CHECK
#ifdef _WIN32
q->owner_thread = GetCurrentThreadId();
#else
q->owner_thread = pthread_self();
#endif
#endif
// Создать хеш-таблицу если нужно
if (hash_size > 0) {
q->hash_table = u_calloc(hash_size, sizeof(struct ll_entry*));
if (!q->hash_table) {
u_free(q);
return NULL;
}
}
DEBUG_DEBUG(DEBUG_CATEGORY_LL_QUEUE, "queue_new: created queue %p, hash_size=%zu", q, hash_size);
return q;
}
struct ll_entry* ll_alloc_lldgram(uint16_t len) {
struct ll_entry* entry = queue_entry_new(0);
if (!entry) return NULL;
entry->len=0;
entry->memlen=len;
entry->dgram = u_malloc(len);
// entry->dgram_pool = NULL; - уже null (memset)
// entry->dgram_free_fn = NULL;
if (!entry->dgram) {
queue_entry_free(entry);
return NULL;
}
return entry;
}
void queue_free(struct ll_queue* q) {
if (!q) return;
DEBUG_DEBUG(DEBUG_CATEGORY_LL_QUEUE, "queue_free: freeing queue %p, head=%p, tail=%p, count=%d",
q, q->head, q->tail, q->count);
// ВАЖНО: Не освобождаем элементы в очереди - они должны быть извлечены отдельно
// Это упрощает архитектуру и предотвращает double-u_free
// Освободить хеш-таблицу
if (q->hash_table) {
u_free(q->hash_table);
}
// Отменить отложенное возобновление
if (q->resume_timeout_id) {
uasync_call_soon_cancel(q->ua, q->resume_timeout_id);
q->resume_timeout_id = NULL;
}
u_free(q);
}
// ==================== Конфигурация очереди ====================
void queue_set_callback(struct ll_queue* q, queue_callback_fn cbk_fn, void* arg) {
if (!q) return;
q->callback = cbk_fn;
q->callback_arg = arg;
}
static void queue_resume_timeout_cb(void* arg) {
struct ll_queue* q = (struct ll_queue*)arg;
if (!q) return;
q->resume_timeout_id = NULL;
// Вызвать коллбэк если есть элементы и коллбэки разрешены
if (q->head && !q->callback_suspended && q->callback) {
q->callback(q, q->callback_arg);
}
}
void queue_resume_callback(struct ll_queue* q) {
if (!q) return;
q->callback_suspended = 0;
// Если есть элементы, запланировать вызов коллбэка
if (q->head && q->callback && !q->resume_timeout_id) {
q->resume_timeout_id = uasync_call_soon(q->ua, q, queue_resume_timeout_cb);
}
}
void queue_set_size_limit(struct ll_queue* q, int lim) {
if (!q) return;
q->size_limit = lim;
}
// ==================== Управление элементами ====================
struct ll_entry* queue_entry_new(size_t data_size) {
struct ll_entry* entry = u_malloc(sizeof(struct ll_entry) + data_size);
if (!entry) return NULL;
memset(entry, 0, sizeof(struct ll_entry) + data_size);
entry->size = data_size;
entry->len = 0;
entry->pool = NULL; // Выделено через u_malloc
// DEBUG_DEBUG(DEBUG_CATEGORY_LL_QUEUE, "queue_entry_new: created entry %p, size=%zu", entry, data_size);
return entry;
}
struct ll_entry* queue_entry_new_from_pool(struct memory_pool* pool) {
if (!pool) return NULL;
struct ll_entry* entry = memory_pool_alloc(pool);
if (!entry) return NULL;
memset(entry, 0, pool->object_size);
entry->size = pool->object_size - sizeof(struct ll_entry);
entry->len = 0;
entry->pool = pool; // Выделено из пула
// DEBUG_DEBUG(DEBUG_CATEGORY_LL_QUEUE, "queue_entry_new_from_pool: created entry %p from pool %p", entry, pool);
return entry;
}
//void ll_u_free_dgram(struct ll_entry* entry) {
void queue_dgram_free(struct ll_entry* entry) {
if (!entry) return;
if (entry->dgram) {
if (entry->dgram_free_fn) {
entry->dgram_free_fn(entry->dgram); // arg=NULL, если не задан
} else if (entry->dgram_pool) {
memory_pool_free(entry->dgram_pool, entry->dgram);
} else {
u_free(entry->dgram);
}
entry->dgram = NULL;
entry->len = 0; // Опционально сброс len
}
}
void queue_entry_free(struct ll_entry* entry) {
if (!entry) return;
if (entry->pool) {
memory_pool_free(entry->pool, entry);
} else {
u_free(entry);
}
}
// ==================== Операции с очередью ====================
// Внутренняя функция добавления в хеш-таблицу
static void add_to_hash(struct ll_queue* q, struct ll_entry* entry) {
if (!q || q->hash_size == 0 || !entry) return;
size_t slot = entry->id % q->hash_size;
entry->hash_next = q->hash_table[slot];
q->hash_table[slot] = entry;
}
// Внутренняя функция удаления из хеш-таблицы
static void remove_from_hash(struct ll_queue* q, struct ll_entry* entry) {
if (!q || q->hash_size == 0 || !entry) return;
size_t slot = entry->id % q->hash_size;
struct ll_entry** ptr = &q->hash_table[slot];
while (*ptr) {
if (*ptr == entry) {
*ptr = entry->hash_next;
entry->hash_next = NULL;
return;
}
ptr = &(*ptr)->hash_next;
}
}
// Проверить и запустить ожидающие коллбэки
static void check_waiters(struct ll_queue* q) {
if (!q) return;
// DEBUG_DEBUG(DEBUG_CATEGORY_LL_QUEUE, "check_waiters: checking waiters, count=%d, bytes=%zu", q->count, q->total_bytes);
struct queue_waiter* waiter = &q->waiter;
if (waiter->callback) {
// Проверить условие: не больше max_packets и не больше max_bytes
// max_bytes = 0 означает "не проверять байты"
if (q->count <= waiter->max_packets && (waiter->max_bytes == 0 || q->total_bytes <= waiter->max_bytes)) {
DEBUG_DEBUG(DEBUG_CATEGORY_LL_QUEUE, "check_waiters: condition met, calling callback, count=%d<=%d, bytes=%zu<=%zu (max_bytes_check=%s)",
q->count, waiter->max_packets, q->total_bytes, waiter->max_bytes,
waiter->max_bytes == 0 ? "disabled" : "enabled");
waiter->callback(q, waiter->callback_arg);
memset(waiter, 0, sizeof(*waiter));
}
}
}
int queue_data_put(struct ll_queue* q, struct ll_entry* entry, uint32_t id) {
if (!q || !entry) return -1;
#ifdef QUEUE_THREAD_CHECK
queue_check_thread(q);
#endif
#ifdef QUEUE_DEBUG
// queue_check_consistency(q);// !!!! for debug - BEFORE callback
#endif
entry->id = id;
// Проверить лимит размера
if (q->size_limit >= 0 && q->count >= q->size_limit) {
queue_dgram_free(entry);
queue_entry_free(entry); // Освободить элемент если превышен лимит
return -1;
}
// Добавить в конец
entry->next = NULL;
entry->prev = q->tail;
if (q->tail) {
q->tail->next = entry;
} else {
q->head = entry;
}
q->tail = entry;
q->count++;
entry->int_len=entry->len;
q->total_bytes += entry->int_len;
size_t send_q_bytes = queue_total_bytes(q);
// DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "check total bytes: new_q_len=%d element_size:%d", send_q_bytes, entry->size);
add_to_hash(q, entry);
// DEBUG_DEBUG(DEBUG_CATEGORY_LL_QUEUE, "queue_data_put: added entry %p (id=%u), count=%d", entry, id, q->count);
// ВАЖНО: проверка консистентности ДО коллбэка, так как коллбэк может модифицировать очередь
#ifdef QUEUE_DEBUG
queue_check_consistency(q);// !!!! for debug - BEFORE callback
#endif
// Если очередь была пуста и коллбэки разрешены - вызвать коллбэк
if (q->count == 1 && !q->callback_suspended && q->callback) {
q->callback(q, q->callback_arg);
}
// Проверить ожидающие коллбэки (надо только при заборе из очереди)
// check_waiters(q);
#ifdef QUEUE_DEBUG
queue_check_consistency(q);// !!!! for debug - AFTER callback
#endif
return 0;
}
int queue_data_put_first(struct ll_queue* q, struct ll_entry* entry, uint32_t id) {
if (!q || !entry) return -1;
#ifdef QUEUE_THREAD_CHECK
queue_check_thread(q);
#endif
entry->id = id;
// Проверить лимит размера
if (q->size_limit >= 0 && q->count >= q->size_limit) {
queue_entry_free(entry); // Освободить элемент если превышен лимит
return -1;
}
// Добавить в начало
entry->next = q->head;
entry->prev = NULL;
if (q->head) {
q->head->prev = entry;
} else {
q->tail = entry;
}
q->head = entry;
q->count++;
entry->int_len=entry->len;
q->total_bytes += entry->int_len;
add_to_hash(q, entry);
// DEBUG_DEBUG(DEBUG_CATEGORY_LL_QUEUE, "queue_data_put_first: added entry %p (id=%u), count=%d", entry, id, q->count);
// ВАЖНО: проверка консистентности ДО коллбэка
#ifdef QUEUE_DEBUG
queue_check_consistency(q);// !!!! for debug - BEFORE callback
#endif
// Если очередь была пуста и коллбэки разрешены - вызвать коллбэк
if (q->count == 1 && !q->callback_suspended && q->callback) {
q->callback(q, q->callback_arg);
}
// Проверить ожидающие коллбэки
// check_waiters(q);
#ifdef QUEUE_DEBUG
queue_check_consistency(q);// !!!! for debug
#endif
return 0;
}
struct ll_entry* queue_data_get(struct ll_queue* q) {
if (!q || !q->head) return NULL;
#ifdef QUEUE_THREAD_CHECK
queue_check_thread(q);
#endif
struct ll_entry* entry = q->head;
q->head = entry->next;
if (q->head) q->head->prev = NULL;
if (!q->head) q->tail = NULL;
q->count--;
q->total_bytes -= entry->int_len;
entry->next = NULL;
entry->prev = NULL;
remove_from_hash(q, entry);
// DEBUG_DEBUG(DEBUG_CATEGORY_LL_QUEUE, "queue_data_get: got entry %p (id=%u), count=%d", entry, entry->id, q->count);
// Приостановить коллбэки для предотвращения рекурсии
q->callback_suspended = 1;
// Проверить ожидающие коллбэки
check_waiters(q);
#ifdef QUEUE_DEBUG
queue_check_consistency(q);// !!!! for debug
#endif
return entry;
}
int queue_entry_count(struct ll_queue* q) {
return q ? q->count : 0;
}
// Функция проверки консистентности count и total_bytes
// Возвращает 0 если ok, -1 если есть несоответствия
int queue_check_consistency(struct ll_queue* q) {
if (!q) return -1; // Недопустимая очередь
// Проверка: если count > 0, то head не должен быть NULL
if (q->count > 0 && !q->head) {
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "Queue '%s': count=%d but head is NULL!",
q->name ? q->name : "unknown", q->count);
return -1;
}
int actual_count = 0;
size_t actual_bytes = 0;
struct ll_entry* current = q->head;
while (current) {
actual_count++;
actual_bytes += current->int_len;
if (current->next) {
if (current->next->prev != current) {
// Несоответствие в связях prev/next
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "Queue '%s': prev/next error at entry %p != %p entries: %d!=%d bytes: %zu!=%zu",
q->name ? q->name : "unknown", (void*)current, (void*)current->next->prev, actual_count, q->count, actual_bytes, q->total_bytes);
return -1;
}
}
current = current->next;
}
// Проверить хвост
if (q->tail && q->tail->next != NULL) {
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "Queue '%s': tail error", q->name ? q->name : "unknown");
return -1; // Хвост должен иметь next == NULL
}
// Сравнить с сохранёнными значениями
if (actual_count != q->count || actual_bytes != q->total_bytes) {
DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "Queue '%s': count error entries: %d!=%d or bytes: %zu!=%zu",
q->name ? q->name : "unknown", actual_count, q->count, actual_bytes, q->total_bytes);
return -1;
}
return 0;
}
// ==================== Асинхронное ожидание ====================
struct queue_waiter* queue_wait_threshold(struct ll_queue* q, int max_packets, size_t max_bytes,
queue_threshold_callback_fn callback, void* arg) {
if (!q || !callback) return NULL;
struct queue_waiter* waiter = &q->waiter;
// Проверить условие немедленно
if (q->count <= max_packets && (max_bytes == 0 || q->total_bytes <= max_bytes)) {
// Условие уже выполнено - вызвать коллбэк немедленно
callback(q, arg);
return NULL;
}
// Установить waiter для отложенного вызова
waiter->max_packets = max_packets;
waiter->max_bytes = max_bytes;
waiter->callback = callback;
waiter->callback_arg = arg;
return waiter;
}
void queue_cancel_wait(struct ll_queue* q, struct queue_waiter* waiter) {
if (!q || !waiter || waiter != &q->waiter) return;
memset(waiter, 0, sizeof(*waiter));
}
// ==================== Поиск и удаление по ID ====================
struct ll_entry* queue_find_data_by_id(struct ll_queue* q, uint32_t id) {
if (!q || q->hash_size == 0 || !q->hash_table) return NULL;
size_t slot = id % q->hash_size;
struct ll_entry* entry = q->hash_table[slot];
while (entry) {
if (entry->id == id) {
return entry;
}
entry = entry->hash_next;
}
return NULL;
}
int queue_remove_data(struct ll_queue* q, struct ll_entry* entry) {
if (!q || !entry) return -1;
#ifdef QUEUE_THREAD_CHECK
queue_check_thread(q);
#endif
// Удалить из двусвязного списка
if (entry->prev) {
entry->prev->next = entry->next;
} else {
q->head = entry->next;
}
if (entry->next) {
entry->next->prev = entry->prev;
} else {
q->tail = entry->prev;
}
q->count--;
q->total_bytes -= entry->int_len;
entry->next = NULL;
entry->prev = NULL;
remove_from_hash(q, entry);
// DEBUG_DEBUG(DEBUG_CATEGORY_LL_QUEUE, "queue_remove_data: removed entry %p (id=%u), count=%d", entry, entry->id, q->count);
#ifdef QUEUE_DEBUG
queue_check_consistency(q);// !!!! for debug
#endif
check_waiters(q);
return 0;
}

130
lib/ll_queue.h2

@ -0,0 +1,130 @@
#ifndef LL_QUEUE_H
#define LL_QUEUE_H
#include <stddef.h>
#include <stdint.h>
#include "memory_pool.h"
#ifdef _WIN32
#include <winsock2.h>
#include <windows.h>
#else
#include <pthread.h>
#endif
#define QUEUE_DEBUG 1
//#define QUEUE_THREAD_CHECK 1
// Forward declaration
struct ll_queue;
/**
* @struct ll_entry
* @brief Элемент очереди (переменного размера).
*
* Память: [struct ll_entry + data[size]].
* Индекс для поиска (произвольной длины) хранится в data[index_offset].
* Хеш (uint64_t) вычисляется по последним 8 байтам индекса.
*/
struct ll_entry {
char* name;
struct ll_entry* next;
struct ll_entry* prev;
uint16_t size; ///< Размер data[]
uint16_t len;
uint16_t memlen;
uint16_t int_len;
uint8_t* dgram;
void (*dgram_free_fn)(uint8_t* data);
struct memory_pool* dgram_pool;
struct memory_pool* pool;
/* === НОВОЕ: поддержка индекса произвольной длины === */
uint16_t index_offset; ///< Смещение индекса в data[]
uint16_t index_size; ///< Длина индекса (0 = без индекса)
uint64_t index_hash; ///< Хеш по последним 8 байтам индекса
struct ll_entry* hash_next;
uint8_t data[0]; ///< Гибкий массив
};
/* ... (остальные typedef'ы без изменений) ... */
struct ll_queue {
char* name;
struct ll_entry* head;
struct ll_entry* tail;
int count;
size_t total_bytes;
int size_limit;
queue_callback_fn callback;
void* callback_arg;
int callback_suspended;
void* resume_timeout_id;
struct UASYNC* ua;
struct queue_waiter waiter;
struct ll_entry** hash_table;
size_t hash_size;
#ifdef QUEUE_THREAD_CHECK
#ifdef _WIN32
DWORD owner_thread;
#else
pthread_t owner_thread;
#endif
#endif
};
/* ==================== Создание / уничтожение ==================== */
struct ll_queue* queue_new(struct UASYNC* ua, size_t hash_size, char* name);
void queue_free(struct ll_queue* q);
/* ==================== Конфигурация ==================== */
void queue_set_size_limit(struct ll_queue* q, int lim);
/* ==================== Автозабор элементов ==================== */
void queue_set_callback(struct ll_queue* q, queue_callback_fn cbk_fn, void* arg);
void queue_resume_callback(struct ll_queue* q);
/* ==================== Пороговое ожидание ==================== */
struct queue_waiter* queue_wait_threshold(struct ll_queue* q, int max_packets, size_t max_bytes,
queue_threshold_callback_fn callback, void* arg);
void queue_cancel_wait(struct ll_queue* q, struct queue_waiter* waiter);
/* ==================== Работа с данными ==================== */
/* Упрощённая версия (без индекса) */
int queue_data_put(struct ll_queue* q, struct ll_entry* entry);
int queue_data_put_first(struct ll_queue* q, struct ll_entry* entry);
/* Версия с хешем по индексу произвольной длины */
int queue_data_put_with_index(struct ll_queue* q, struct ll_entry* entry,
uint16_t index_offset, uint16_t index_size);
int queue_data_put_first_with_index(struct ll_queue* q, struct ll_entry* entry,
uint16_t index_offset, uint16_t index_size);
struct ll_entry* queue_data_get(struct ll_queue* q);
int queue_entry_count(struct ll_queue* q);
/* ==================== Управление памятью ==================== */
struct ll_entry* ll_alloc_lldgram(uint16_t len);
struct ll_entry* queue_entry_new(size_t data_size);
struct ll_entry* queue_entry_new_from_pool(struct memory_pool* pool);
void queue_entry_free(struct ll_entry* entry);
void queue_dgram_free(struct ll_entry* entry);
/* ==================== Поиск и удаление ==================== */
/**
* @brief Поиск по индексу произвольной длины.
* @note Хеш вычисляется по последним 8 байтам индекса.
*/
struct ll_entry* queue_find_data_by_index(struct ll_queue* q,
const void* index_key,
uint16_t index_size);
int queue_remove_data(struct ll_queue* q, struct ll_entry* entry);
/* ==================== Утилиты ==================== */
static inline size_t queue_total_bytes(struct ll_queue* q) {
return q ? q->total_bytes : 0;
}
int queue_check_consistency(struct ll_queue* q);
#endif // LL_QUEUE_H

BIN
linux-x64-deb

Binary file not shown.

6
src/direct_connect.txt

@ -0,0 +1,6 @@
Есть 2 типа подключений - обычные (роутятся через подключения в конфиге) - по ним распространяется bgp и сигнальные пакеты
А для передачи данных между узлами можно установить прямое подключение (или подключение через лучший промежуточный узел).
Как работает:
в nodeinfo

24
src/route_bgp.c

@ -308,6 +308,11 @@ void route_bgp_destroy(struct UTUN_INSTANCE* instance) {
instance->bgp = NULL;
}
void route_bgp_set_nat_check_local(struct ROUTE_BGP* bgp, int allow) {
if (!bgp) return;
bgp->allow_nat_check_local = allow ? 1 : 0;
}
void route_bgp_new_conn(struct ETCP_CONN* conn) {
if (!conn) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_new_conn: conn is NULL");
@ -549,8 +554,8 @@ struct nat_check_arg {
};
static void nat_link_check_cb(int success, uint16_t avg_rtt, uint8_t count_sent, uint8_t count_ok,
uint32_t recv_ip, uint16_t recv_port, void* arg) {
(void)avg_rtt; (void)count_sent; (void)count_ok; (void)recv_ip; (void)recv_port;
void* arg) {
(void)avg_rtt; (void)count_sent; (void)count_ok;
struct nat_check_arg* na = (struct nat_check_arg*)arg;
if (!na || !na->link) { u_free(na); return; }
struct ETCP_LINK* link = na->link;
@ -614,7 +619,10 @@ static void route_bgp_start_link_nat_check(struct ROUTE_BGP* bgp, struct ETCP_LI
target_port = ntohs(sin->sin_port);
}
if (is_local_subnet(target_ip)) { DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "local connection: %s, skip nat check", ip_to_str(&target_ip, AF_INET).str); return; }
if (!bgp->allow_nat_check_local && is_local_subnet(target_ip)) {
DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "local connection: %s, skip nat check", ip_to_str(&target_ip, AF_INET).str);
return;
}
// Allocate callback arg
struct nat_check_arg* arg = u_calloc(1, sizeof(struct nat_check_arg));
@ -630,7 +638,7 @@ static void route_bgp_start_link_nat_check(struct ROUTE_BGP* bgp, struct ETCP_LI
return;
}
// Send ping via third node - embed peer pubkey for NAT detection
int ret = route_ping_send_req_addr(bgp, third_conn, link->etcp->peer_node_id, target_ip, target_port,
int ret = route_ping_send_req_addr(bgp, third_conn, target_ip, target_port,
3, 500, 1000, 5000, nat_link_check_cb, arg,
pubkey);
if (ret == 0) {
@ -875,8 +883,11 @@ static void route_bgp_handle_nat_info(struct ROUTE_BGP* bgp, struct ETCP_CONN* f
const struct BGP_NAT_INFO* info = (const struct BGP_NAT_INFO*)data;
uint32_t nat_ip = (info->nat_ip[0] << 24) | (info->nat_ip[1] << 16) |
(info->nat_ip[2] << 8) | info->nat_ip[3];
uint16_t nat_port = ((info->nat_port >> 8) & 0xFF) | ((info->nat_port & 0xFF) << 8);
uint16_t nat_port = ntohs(info->nat_port);
uint8_t socket_id = info->socket_id;
DEBUG_INFO(DEBUG_CATEGORY_BGP, "NAT_INFO recv: ip_bytes=0x%02x%02x%02x%02x ip_host=0x%08x port_net=%u port_host=%u",
info->nat_ip[0], info->nat_ip[1], info->nat_ip[2], info->nat_ip[3],
nat_ip, info->nat_port, nat_port);
uint8_t* dynamic = (uint8_t*)&bgp->local_node->node + sizeof(struct NODEINFO);
dynamic += bgp->local_node->node.node_name_len;
@ -982,6 +993,9 @@ void route_bgp_send_nat_info(struct ETCP_CONN* conn, uint8_t socket_id, uint32_t
pkt->nat_ip[3] = nat_ip & 0xFF;
pkt->nat_port = htons(nat_port);
pkt->nat_type = nat_type;
DEBUG_INFO(DEBUG_CATEGORY_BGP, "NAT_INFO send: ip_host=0x%08x ip_bytes=0x%02x%02x%02x%02x port_host=%u port_net=%u",
nat_ip, pkt->nat_ip[0], pkt->nat_ip[1], pkt->nat_ip[2], pkt->nat_ip[3],
nat_port, pkt->nat_port);
struct ll_entry* e = queue_entry_new(0);
if (!e) {

7
src/route_bgp.h

@ -84,6 +84,7 @@ struct ROUTE_BGP {
struct NODEINFO_Q* local_node;
struct route_ping_pending* ping_pending;
uint64_t next_ping_req_id;
uint8_t allow_nat_check_local; // 1 = разрешить NAT check для локальных подсетей (для тестов)
};
/**
@ -186,4 +187,10 @@ void route_bgp_send_nat_info(struct ETCP_CONN* conn, uint8_t socket_id, uint32_t
*/
void route_bgp_send_nat_check_req(struct ETCP_CONN* conn, uint8_t socket_id);
/**
* @brief Разрешить/запретить NAT check для локальных подсетей (127.0.0.1, 10.x.x.x и т.д.)
* По умолчанию запрещено. Полезно для тестов.
*/
void route_bgp_set_nat_check_local(struct ROUTE_BGP* bgp, int allow);
#endif // ROUTE_BGP_H

71
src/route_bgp1.txt

@ -0,0 +1,71 @@
подсистема роутинга
utun - это сеть узлов. у каждого узла есть собственные локальные подсети.
глобальная задача: создать у каждого узла полную таблицу маршрутизации.
Узлы преимущественно создают связь напрямую друг с другом. Но если это не получается отправляют трафик транзитом через доступные узлы.
Иногда бывает что через транзитные узлы метрики лучше чем напрямую. Используем приоритетно узлы с лучшей метриков, при нехватке bandwidth используем разные каналы (агрегируем).
Динамически обновлем метрики каналов чтобы при отказе быстро переключаться на другие и не фризить обмен из-за отказов.
и узлы обмениваются таблицой маршрутов между собой так чтобы у каждого была актуальная таблица подсетей всех узлов.
маршрутами меняются клиенты, подключения которых которые взяты из конфига. и сервера принявшие подключения если клиент инициировал обмен маршрутами.
инициируется подключение, клиент отправляет свою таблицу. когда сервер принимает таблицу - сервер помечает что по этому маршруту надо обмениваться маршрутами, далее;
- добавляет узел в список рассылки обновлений маршрутов
- отправляет свою таблицу
- добавляет в свою таблицу отсутствующие маршруты
- если что-то добавил:
- рассылает измененные маршруты по списку рассылки
- список рассылки - это linked-list очередей (также на базе ll_queue - каждый элемент = подписчик). один маршрут = одна отправленная кодограмма
при подключении узла или изменении таблицы: узел шлёт свою таблицу
формат кодограммы: [0x01 - routing module] [subcmd] [data]
subcmd:
1 [route] - отправка маршрута
2, без данных - больше данных нет
если сервер получил кодограмму маршрута - он помечает флаг в etcp что с узлом надо обмениваться маршрутами (etcp_conn->routing_exchange_active=2) и добавляет в очередь рассылки маршрутов
=========================================
механизм инкрементальной синхронизации (реализация - потом, пока мысли)
1. вычисляем хеш каждой записи в роутинг таблице. используем ip+mask+node_uid
2. потом из этих хешей создаем хеш таблицу (старшие n бит номер ячейки). далее вычисляются хеши каждой ячейки.
на первом этапе n=16, на втором - n=16*16 на третьем n=16*16*16.
отправляем хеши удаленному узлу в формате: [n, 1 байт] ([индекс хеша 2 байта - используется n старших бит][хеш - 8 байт])
удаленный узел считает свои хеши и сравнивает. где не совпало смотрит сколько записей.
если записей не много - передает эти записи.
если записей много - добавляет 4 бита к хеш таблице и строит субтаблицу для
==========================================
Формат роутинга:
Таблица узлов состоит из записей:
- uid
- name
- links
- 3 транзитных узла с метриками (RTT)
- маршруты узла
- текущая загрузка линка (за последние 10 сек) можно частоту адаптировать под размер сети
- bandidth limit
- transit bandwidth limit
две группы узлов:
- узлы за nat. подключаются через транзитные узлы. измеряют пинги до транзитных и выбирают N (3 default) лучшие линки. 3 лучших используем для распространения маршрутов
- транзитные узлы. имеют линки с загрузкой.
добавить кодограмму - отменить распространение маршрутов по линку (+ сделать важным линком)
карта маршрутизации:
План:
- сделать передачу роутинга в
- сделать фоновый probe для узлов (условно 1 нода в секунду). выигравшие по качеству соатновятся основными
- сделать etcp дизконнект:
- отправить disconnect request + дождаться ack дальше master удаляет, slave удаляет по down.

3
src/route_node.c

@ -206,6 +206,9 @@ int route_bgp_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct ROUTE_BG
sa->port = ntohs(sin->sin_port);
sa->type = e_sock->nat_type;
sa->id = e_sock->sock_id;
DEBUG_INFO(DEBUG_CATEGORY_BGP, "NODEINFO socket: addr=0x%02x%02x%02x%02x port=%u (from sin_addr=0x%08x sin_port=%u)",
sa->addr[0], sa->addr[1], sa->addr[2], sa->addr[3], sa->port,
sin->sin_addr.s_addr, ntohs(sin->sin_port));
sa++;
}
e_sock = e_sock->next;

146
src/route_ping.c

@ -62,69 +62,11 @@ static void route_ping_pending_timeout(void* arg) {
cur = &(*cur)->next;
}
if (p->callback) {
p->callback(0, 0, 0, 0, 0, 0, p->arg);
p->callback(0, 0, 0, 0, p->arg);
}
u_free(p);
}
// отправить запрос удаленному узлу "пропингуй такой-то узел"
int route_ping_send_req(struct ROUTE_BGP* bgp, struct ETCP_CONN* to_conn, uint64_t node_id,
uint8_t count, uint16_t interval_ms, uint16_t timeout_ms,
uint16_t wait_timeout_ms, route_ping_callback_t cb, void* arg) {
if (!bgp || !to_conn || count == 0 || timeout_ms == 0) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "invalid args");
return -1;
}
struct BGP_PING_REQUEST* req_pkt = u_calloc(1, sizeof(struct BGP_PING_REQUEST));
if (!req_pkt) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "alloc failed");
return -2;
}
req_pkt->cmd = ETCP_ID_ROUTE_ENTRY;
req_pkt->subcmd = ROUTE_SUBCMD_PING_REQ;
req_pkt->request_id = bgp->next_ping_req_id++;
req_pkt->node_id = node_id;
req_pkt->count = count;
req_pkt->interval_ms = interval_ms;
req_pkt->timeout_ms = timeout_ms;
struct ll_entry* e = queue_entry_new(0);
if (!e) {
u_free(req_pkt);
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "queue_entry_new failed");
return -3;
}
e->dgram = (uint8_t*)req_pkt;
e->len = offsetof(struct BGP_PING_REQUEST, target_ipv4);
int ret = etcp_send(to_conn, e);
if (ret != 0) {
u_free(req_pkt);
queue_entry_free(e);
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "etcp_send failed");
return -4;
}
struct route_ping_pending* pending = u_calloc(1, sizeof(struct route_ping_pending));
if (!pending) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "pending alloc failed");
return -5;
}
pending->bgp = bgp;
pending->request_id = req_pkt->request_id;
pending->callback = cb;
pending->arg = arg;
pending->next = bgp->ping_pending;
bgp->ping_pending = pending;
pending->timeout_timer = uasync_set_timeout(bgp->instance->ua, wait_timeout_ms * 10, pending, route_ping_pending_timeout, "route_ping");
DEBUG_INFO(DEBUG_CATEGORY_BGP, "request_id=%016llx node=%016llx count=%u interval=%u timeout=%u wait=%u",
(unsigned long long)pending->request_id, (unsigned long long)node_id,
(unsigned)count, (unsigned)interval_ms, (unsigned)timeout_ms, (unsigned)wait_timeout_ms);
return 0;
}
// прошел ответ "серия пигнов на удаленном узле завершена"
void route_ping_handle_resp(struct ROUTE_BGP* bgp, struct ETCP_CONN* from_conn, const uint8_t* data, size_t len) {
if (!bgp || !from_conn || !data || len < sizeof(struct BGP_PING_RESPONSE)) {
@ -147,10 +89,7 @@ void route_ping_handle_resp(struct ROUTE_BGP* bgp, struct ETCP_CONN* from_conn,
}
if (p->callback) {
int success = (resp->count_ok > 0) ? 1 : 0;
uint32_t recv_ip = (resp->recv_ipv4[0] << 24) | (resp->recv_ipv4[1] << 16) |
(resp->recv_ipv4[2] << 8) | resp->recv_ipv4[3];
uint16_t recv_port = ntohs(resp->recv_port);
p->callback(success, resp->avg_rtt, resp->count_sent, resp->count_ok, recv_ip, recv_port, p->arg);
p->callback(success, resp->avg_rtt, resp->count_sent, resp->count_ok, p->arg);
}
u_free(p);
return;
@ -163,7 +102,7 @@ void route_ping_handle_resp(struct ROUTE_BGP* bgp, struct ETCP_CONN* from_conn,
// ========================================================================
int route_ping_send_req_addr(struct ROUTE_BGP* bgp, struct ETCP_CONN* to_conn, uint64_t node_id,
int route_ping_send_req_addr(struct ROUTE_BGP* bgp, struct ETCP_CONN* to_conn,
uint32_t target_ip, uint16_t target_port,
uint8_t count, uint16_t interval_ms, uint16_t timeout_ms,
uint16_t wait_timeout_ms, route_ping_callback_t cb, void* arg,
@ -181,7 +120,6 @@ int route_ping_send_req_addr(struct ROUTE_BGP* bgp, struct ETCP_CONN* to_conn, u
req_pkt->cmd = ETCP_ID_ROUTE_ENTRY;
req_pkt->subcmd = ROUTE_SUBCMD_PING_REQ;
req_pkt->request_id = bgp->next_ping_req_id++;
req_pkt->node_id = node_id;
req_pkt->count = count;
req_pkt->interval_ms = interval_ms;
req_pkt->timeout_ms = timeout_ms;
@ -190,6 +128,10 @@ int route_ping_send_req_addr(struct ROUTE_BGP* bgp, struct ETCP_CONN* to_conn, u
if (pubkey) {
memcpy(req_pkt->pubkey, pubkey, SC_PUBKEY_SIZE);
}
DEBUG_INFO(DEBUG_CATEGORY_BGP, "SEND_REQ: target_ip host=0x%08x net=0x%02x%02x%02x%02x port host=%u net=%u",
target_ip,
req_pkt->target_ipv4[0], req_pkt->target_ipv4[1], req_pkt->target_ipv4[2], req_pkt->target_ipv4[3],
target_port, req_pkt->target_port);
struct ll_entry* e = queue_entry_new(0);
if (!e) {
@ -222,8 +164,8 @@ int route_ping_send_req_addr(struct ROUTE_BGP* bgp, struct ETCP_CONN* to_conn, u
pending->timeout_timer = uasync_set_timeout(bgp->instance->ua, wait_timeout_ms * 10, pending, route_ping_pending_timeout, "route_ping");
DEBUG_INFO(DEBUG_CATEGORY_BGP, "request_id=%016llx node=%016llx ip=%s port=%u pubkey=%s",
(unsigned long long)pending->request_id, (unsigned long long)node_id,
DEBUG_INFO(DEBUG_CATEGORY_BGP, "request_id=%016llx ip=%s port=%u pubkey=%s",
(unsigned long long)pending->request_id,
ip_to_str(&target_ip, AF_INET).str, (unsigned)target_port, pubkey ? "yes" : "no");
return 0;
}
@ -248,9 +190,6 @@ static void route_ping_series_finish(struct route_ping_series_ctx* ctx) {
resp->count_sent = ctx->count_sent;
resp->count_ok = ctx->count_ok;
resp->avg_rtt = avg_rtt;
/* recv_ipv4/port = 0 (не используется) */
memset(resp->recv_ipv4, 0, 4);
resp->recv_port = 0;
struct ll_entry* e = queue_entry_new(0);
if (e) {
@ -318,7 +257,7 @@ void route_ping_handle_req(struct ROUTE_BGP* bgp,
struct ETCP_CONN* from_conn,
const uint8_t* data,
size_t len) {
if (!bgp || !from_conn || !data || len < sizeof(struct BGP_PING_REQUEST)) {
if (!bgp || !from_conn || !data || len < offsetof(struct BGP_PING_REQUEST, pubkey)) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "ping req: bad args len=%zu", len);
return;
}
@ -336,13 +275,76 @@ void route_ping_handle_req(struct ROUTE_BGP* bgp,
ctx->request_id = req_pkt->request_id;
ctx->count_total = req_pkt->count;
ctx->timeout_ms = req_pkt->timeout_ms;
memcpy(ctx->pubkey, req_pkt->pubkey, SC_PUBKEY_SIZE);
if (len >= sizeof(struct BGP_PING_REQUEST)) {
memcpy(ctx->pubkey, req_pkt->pubkey, SC_PUBKEY_SIZE);
}
/* Целевой адрес */
struct sockaddr_in* sin = (struct sockaddr_in*)&ctx->target_addr;
sin->sin_family = AF_INET;
memcpy(&sin->sin_addr.s_addr, req_pkt->target_ipv4, 4);
sin->sin_port = req_pkt->target_port;
DEBUG_INFO(DEBUG_CATEGORY_BGP, "RECV_REQ: target_ip net_bytes=0x%02x%02x%02x%02x sin_addr=0x%08x port_net=%u port_host=%u",
req_pkt->target_ipv4[0], req_pkt->target_ipv4[1], req_pkt->target_ipv4[2], req_pkt->target_ipv4[3],
sin->sin_addr.s_addr, req_pkt->target_port, ntohs(req_pkt->target_port));
/* Если target не указан — можно разрешить из nodeinfo */
/*
if (sin->sin_addr.s_addr == 0 && sin->sin_port == 0) {
struct NODEINFO_Q* nq = route_bgp_get_node(bgp, req_pkt->node_id);
if (nq) {
const struct NODEINFO_IPV4_SOCKET* sockets;
int count = get_node_v4_sockets(nq, &sockets);
if (count > 0) {
memcpy(&sin->sin_addr.s_addr, sockets[0].addr, 4);
sin->sin_port = sockets[0].port;
DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "resolved target from nodeinfo: %s:%u",
ip_to_str(&sin->sin_addr, AF_INET).str, ntohs(sin->sin_port));
}
}
}
*/
/* Если pubkey не указан — ищем по target_ip:port в nodeinfo */
int pubkey_empty = 1;
for (int i = 0; i < SC_PUBKEY_SIZE; i++) {
if (ctx->pubkey[i] != 0) { pubkey_empty = 0; break; }
}
if (pubkey_empty) {
DEBUG_INFO(DEBUG_CATEGORY_BGP, "looking for pubkey for target %s:%u, nodes_count=%d",
ip_to_str(&sin->sin_addr, AF_INET).str, ntohs(sin->sin_port),
bgp->nodes ? bgp->nodes->count : -1);
struct ll_entry* e = bgp->nodes ? bgp->nodes->head : NULL;
while (e) {
struct NODEINFO_Q* nq = (struct NODEINFO_Q*)e;
const struct NODEINFO_IPV4_SOCKET* sockets;
int sc = get_node_v4_sockets(nq, &sockets);
DEBUG_INFO(DEBUG_CATEGORY_BGP, "checking node %016llx with %d sockets",
(unsigned long long)nq->node.node_id, sc);
for (int i = 0; i < sc; i++) {
uint32_t socket_ip, target_ip;
memcpy(&socket_ip, sockets[i].addr, 4);
memcpy(&target_ip, req_pkt->target_ipv4, 4);
if (socket_ip == target_ip || socket_ip == htonl(target_ip) ||
htonl(socket_ip) == target_ip || htonl(socket_ip) == htonl(target_ip)) {
memcpy(ctx->pubkey, nq->node.public_key, SC_PUBKEY_SIZE);
DEBUG_INFO(DEBUG_CATEGORY_BGP, "resolved pubkey from nodeinfo for %s:%u",
ip_to_str(&sin->sin_addr, AF_INET).str, ntohs(sin->sin_port));
break;
}
}
pubkey_empty = 1;
for (int i = 0; i < SC_PUBKEY_SIZE; i++) {
if (ctx->pubkey[i] != 0) { pubkey_empty = 0; break; }
}
if (!pubkey_empty) break;
e = e->next;
}
if (pubkey_empty) {
DEBUG_WARN(DEBUG_CATEGORY_BGP, "pubkey not found for target %s:%u",
ip_to_str(&sin->sin_addr, AF_INET).str, ntohs(sin->sin_port));
}
}
/* Ищем первый IPv4-сокет (как в старом коде) */
struct ETCP_SOCKET* ls = bgp->instance->etcp_sockets;

13
src/route_ping.h

@ -12,7 +12,6 @@ struct BGP_PING_REQUEST {
uint8_t cmd; // ETCP_ID_ROUTE_ENTRY
uint8_t subcmd; // ROUTE_SUBCMD_PING_REQ
uint64_t request_id; // для корреляции
uint64_t node_id; // целевой узел
uint8_t count; // число пингов
uint8_t socket_id; // id сокета пингуемого узла
uint16_t interval_ms; // интервал между пингами
@ -29,22 +28,14 @@ struct BGP_PING_RESPONSE {
uint8_t count_sent;
uint8_t count_ok;
uint16_t avg_rtt; // средний RTT в 0.1ms
uint8_t recv_ipv4[4]; // IP:port с которого получен PING_REQ (STUN-like)
uint16_t recv_port; // network byte order
} __attribute__((packed));
typedef void (*route_ping_callback_t)(int success, uint16_t avg_rtt, uint8_t count_sent, uint8_t count_ok,
uint32_t recv_ip, uint16_t recv_port, void* arg);
// Отправить запрос пинга через BGP, ожидать ответа с таймаутом
int route_ping_send_req(struct ROUTE_BGP* bgp, struct ETCP_CONN* to_conn, uint64_t node_id,
uint8_t count, uint16_t interval_ms, uint16_t timeout_ms,
uint16_t wait_timeout_ms, route_ping_callback_t cb, void* arg);
typedef void (*route_ping_callback_t)(int success, uint16_t avg_rtt, uint8_t count_sent, uint8_t count_ok, void* arg);
// Отправить запрос пинга по произвольному IP:port (используется для NAT-детекции)
// Если target_ip == 0, используется node_id из списка известных узлов
// Если pubkey != NULL, он передается в пакете (для пинга без локального nodeinfo)
int route_ping_send_req_addr(struct ROUTE_BGP* bgp, struct ETCP_CONN* to_conn, uint64_t node_id,
int route_ping_send_req_addr(struct ROUTE_BGP* bgp, struct ETCP_CONN* to_conn,
uint32_t target_ip, uint16_t target_port,
uint8_t count, uint16_t interval_ms, uint16_t timeout_ms,
uint16_t wait_timeout_ms, route_ping_callback_t cb, void* arg,

BIN
test_serialize

Binary file not shown.

4
tests/FIX_SUMMARY.md

@ -0,0 +1,4 @@
Minimal fix applied to test_etcp_two_instances.c (removed duplicate init_connections calls before utun_instance_init).
Test should no longer hit 'Address already in use' on second bind.
Full test run requires fixing Makefile.am dependencies or rebuilding all src objects.
Run 'make check' after fixing build to verify.

41
tests/test_nat_detection.c

@ -52,8 +52,6 @@ static struct {
uint16_t avg_rtt;
uint8_t count_sent;
uint8_t count_ok;
uint32_t recv_ip;
uint16_t recv_port;
} nat_ping_result;
static int write_config(const char* path, const char* content) {
@ -177,19 +175,15 @@ static void test_timeout_cb(void* arg) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "test_nat_detection: overall test timeout");
}
static void nat_ping_resp_cb(int success, uint16_t avg_rtt, uint8_t count_sent, uint8_t count_ok,
uint32_t recv_ip, uint16_t recv_port, void* arg) {
static void nat_ping_resp_cb(int success, uint16_t avg_rtt, uint8_t count_sent, uint8_t count_ok, void* arg) {
(void)arg;
nat_ping_result.done = 1;
nat_ping_result.success = success;
nat_ping_result.avg_rtt = avg_rtt;
nat_ping_result.count_sent = count_sent;
nat_ping_result.count_ok = count_ok;
nat_ping_result.recv_ip = recv_ip;
nat_ping_result.recv_port = recv_port;
DEBUG_INFO(DEBUG_CATEGORY_BGP, "nat_ping_resp_cb: success=%d avg_rtt=%u sent=%u ok=%u recv_ip=%08x recv_port=%u",
success, (unsigned)avg_rtt, (unsigned)count_sent, (unsigned)count_ok,
(unsigned)recv_ip, (unsigned)recv_port);
DEBUG_INFO(DEBUG_CATEGORY_BGP, "nat_ping_resp_cb: success=%d avg_rtt=%u sent=%u ok=%u",
success, (unsigned)avg_rtt, (unsigned)count_sent, (unsigned)count_ok);
}
int main(void) {
@ -218,6 +212,9 @@ int main(void) {
goto cleanup;
}
// Разрешаем NAT check для localhost (для теста)
if (inst_s->bgp) route_bgp_set_nat_check_local(inst_s->bgp, 1);
if (init_connections(inst_s) != 0 || init_connections(inst_c1) != 0 || init_connections(inst_c2) != 0) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to init connections");
goto cleanup;
@ -421,7 +418,9 @@ int main(void) {
}
memset(&nat_ping_result, 0, sizeof(nat_ping_result));
int ret = route_ping_send_req_addr(inst_s->bgp, conn_sc2, NODE_ID_C1,
DEBUG_INFO(DEBUG_CATEGORY_BGP, "TEST: sending ping with pubkey, nat_ip=0x%08x nat_port=%u",
link_sc1->nat_ip, link_sc1->nat_port);
int ret = route_ping_send_req_addr(inst_s->bgp, conn_sc2,
link_sc1->nat_ip, link_sc1->nat_port,
3, 10, 200, 3000, nat_ping_resp_cb, NULL,
node_c1->node.public_key);
@ -444,19 +443,7 @@ int main(void) {
nat_ping_result.success, (unsigned)nat_ping_result.count_ok);
goto cleanup;
}
if (nat_ping_result.recv_ip == 0 || nat_ping_result.recv_port == 0) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: STUN recv_ip/port zero (ip=%08x port=%u)",
(unsigned)nat_ping_result.recv_ip, (unsigned)nat_ping_result.recv_port);
goto cleanup;
}
// recv_ip should match C2's socket address (127.0.0.1)
if (nat_ping_result.recv_ip != 0x7F000001) {
DEBUG_WARN(DEBUG_CATEGORY_BGP, "STUN recv_ip=%08x (expected 127.0.0.1), tolerating",
(unsigned)nat_ping_result.recv_ip);
}
DEBUG_INFO(DEBUG_CATEGORY_BGP, "STUN check PASSED: recv_ip=%08x recv_port=%u",
(unsigned)nat_ping_result.recv_ip, (unsigned)nat_ping_result.recv_port);
DEBUG_INFO(DEBUG_CATEGORY_BGP, "STUN check PASSED");
// 7. Test route_ping_send_req_addr WITHOUT embedded pubkey (C2 should resolve pubkey from node_id)
// First wait for C2 to learn C1's nodeinfo via BGP exchange from S
@ -477,7 +464,9 @@ int main(void) {
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Testing route ping without embedded pubkey...");
memset(&nat_ping_result, 0, sizeof(nat_ping_result));
ret = route_ping_send_req_addr(inst_s->bgp, conn_sc2, NODE_ID_C1,
DEBUG_INFO(DEBUG_CATEGORY_BGP, "TEST: sending ping NO pubkey, nat_ip=0x%08x nat_port=%u",
link_sc1->nat_ip, link_sc1->nat_port);
ret = route_ping_send_req_addr(inst_s->bgp, conn_sc2,
link_sc1->nat_ip, link_sc1->nat_port,
3, 10, 200, 3000, nat_ping_resp_cb, NULL,
NULL);
@ -500,10 +489,6 @@ int main(void) {
nat_ping_result.success, (unsigned)nat_ping_result.count_ok);
goto cleanup;
}
if (nat_ping_result.recv_ip == 0 || nat_ping_result.recv_port == 0) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: no-pubkey ping STUN fields zero");
goto cleanup;
}
DEBUG_INFO(DEBUG_CATEGORY_BGP, "No-pubkey ping check PASSED");
DEBUG_INFO(DEBUG_CATEGORY_BGP, "NAT detection test PASSED");

48
tests/test_route_ping.c

@ -177,17 +177,15 @@ static void test_timeout_cb(void* arg) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "test_route_ping: overall test timeout");
}
static void ping_resp_cb(int success, uint16_t avg_rtt, uint8_t count_sent, uint8_t count_ok,
uint32_t recv_ip, uint16_t recv_port, void* arg) {
(void)arg; (void)recv_ip; (void)recv_port;
static void ping_resp_cb(int success, uint16_t avg_rtt, uint8_t count_sent, uint8_t count_ok, void* arg) {
(void)arg;
ping_result.done = 1;
ping_result.success = success;
ping_result.avg_rtt = avg_rtt;
ping_result.count_sent = count_sent;
ping_result.count_ok = count_ok;
DEBUG_INFO(DEBUG_CATEGORY_BGP, "ping_resp_cb: success=%d avg_rtt=%u sent=%u ok=%u recv_ip=%08x recv_port=%u",
success, (unsigned)avg_rtt, (unsigned)count_sent, (unsigned)count_ok,
(unsigned)recv_ip, (unsigned)recv_port);
DEBUG_INFO(DEBUG_CATEGORY_BGP, "ping_resp_cb: success=%d avg_rtt=%u sent=%u ok=%u",
success, (unsigned)avg_rtt, (unsigned)count_sent, (unsigned)count_ok);
}
int main(void) {
@ -253,22 +251,42 @@ int main(void) {
goto cleanup;
}
// 3. Send route ping request from A to B for node C
// 3. Get target info for C and send route ping request from A to B
struct ETCP_CONN* conn_ab = find_conn_to_peer(inst_a, NODE_ID_B);
if (!conn_ab) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "A has no connection to B");
goto cleanup;
}
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Sending route ping request A->B for C");
/* Получаем target IP:port из nodeinfo узла C */
uint32_t target_ip = 0;
uint16_t target_port = 0;
struct NODEINFO_Q* nq = inst_b->bgp ? route_bgp_get_node(inst_b->bgp, NODE_ID_C) : NULL;
if (nq) {
const struct NODEINFO_IPV4_SOCKET* sockets;
int sc = get_node_v4_sockets(nq, &sockets);
if (sc > 0) {
memcpy(&target_ip, sockets[0].addr, 4);
target_port = sockets[0].port;
}
}
if (target_ip == 0 || target_port == 0) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "Cannot resolve target for node C");
goto cleanup;
}
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Sending route ping request A->B for C (%s:%u)",
ip_to_str(&target_ip, AF_INET).str, (unsigned)target_port);
memset(&ping_result, 0, sizeof(ping_result));
int ret = route_ping_send_req(inst_a->bgp, conn_ab, NODE_ID_C,
3, // count
10, // interval_ms
200, // timeout_ms
5000,// wait_timeout_ms
ping_resp_cb, NULL);
int ret = route_ping_send_req_addr(inst_a->bgp, conn_ab, target_ip, target_port,
3, // count
10, // interval_ms
200, // timeout_ms
5000,// wait_timeout_ms
ping_resp_cb, NULL,
nq ? nq->node.public_key : NULL);
if (ret != 0) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_ping_send_req failed: %d", ret);
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_ping_send_req_addr failed: %d", ret);
goto cleanup;
}

BIN
tools/bping/bping

Binary file not shown.

2
tools/proxy/proxy.sh

@ -0,0 +1,2 @@
#!/bin/bash
./udp_proxy --listen 192.168.29.117:1266 --target 192.168.29.117:1333

BIN
tools/proxy/udp_proxy

Binary file not shown.

106
utun.log1

@ -0,0 +1,106 @@
[22:59:46-599.960] [INFO] [BGP] (route_bgp.c:390) route_bgp_init() route_bgp_init: node_id=5f75c7445af88e1f
[22:59:46-600.017] [INFO] [BGP] (route_bgp.c:418) route_bgp_init() BGP module initialized (with hop_list support)
[22:59:46-600.022] [INFO] [BGP] (utun_instance.c:117) instance_init_common() BGP module initialized
[22:59:46-600.042] [INFO] [GENERAL] (etcp_connections.c:506) etcp_socket_add() Listen socket initialized: name=lan1 fd=8 addr=192.168.29.117:1333
[22:59:46-600.046] [INFO] [BGP] (etcp_connections.c:514) etcp_socket_add() Add Socket type=1
[22:59:46-600.061] [INFO] [GENERAL] (etcp_connections.c:506) etcp_socket_add() Listen socket initialized: name=lo0_test fd=9 addr=127.0.0.1:1330
[22:59:46-600.064] [INFO] [BGP] (etcp_connections.c:514) etcp_socket_add() Add Socket type=2
[22:59:46-600.832] [ERROR] [ETCP] (utun.c:391) main() Run mainloop
[23:00:02-217.693] [TRACE] [BGP] (route_bgp.c:378) route_bgp_etcp_conn_cbk() Set ETCP ready callback for connection 8E1F->???? []
[23:00:02-217.724] [INFO] [GENERAL] (etcp_connections.c:948) etcp_connections_read_callback_socket() New connection received on socket lan1: log_name=8E1F->0C2D [] peer_id=7043239820550081581
[23:00:02-217.784] [INFO] [GENERAL] (etcp_connections.c:1079) etcp_connections_read_callback_socket() Connection established: log_name=8E1F->0C2D [] socket=lan1 link_id=1 status=UP
[23:00:02-217.792] [TRACE] [BGP] (route_bgp.c:359) route_bgp_on_conn_up() Connection 8E1F->0C2D [] on up
[23:00:02-217.797] [INFO] [BGP] (route_bgp.c:493) route_bgp_new_conn() New connection added to senders_list
[23:00:02-217.806] [INFO] [BGP] (route_bgp.c:111) route_bgp_send_table_request() Sent table request to 8E1F->0C2D [] (version=0)
[23:00:04-223.725] [TRACE] [BGP] (route_bgp.c:368) route_bgp_on_conn_down() Connection 8E1F->0C2D [] on down
[23:00:04-223.747] [INFO] [BGP] (route_bgp.c:528) route_bgp_remove_conn() route_bgp_remove_conn: peer=61be9d4cd3c60c2d
[23:00:04-223.763] [INFO] [BGP] (route_bgp.c:549) route_bgp_remove_conn() Connection removed, routes updated via route_remove_conn
[23:00:04-223.768] [INFO] [GENERAL] (etcp_connections.c:262) keepalive_timer_cb() Link down: log_name=8E1F->0C2D [] socket=lan1 link_id=1 status=DOWN
[23:44:58-804.874] [INFO] [GENERAL] (etcp_connections.c:1079) etcp_connections_read_callback_socket() Connection established: log_name=8E1F->0C2D [] socket=lan1 link_id=1 status=UP
[23:44:58-804.949] [TRACE] [BGP] (route_bgp.c:359) route_bgp_on_conn_up() Connection 8E1F->0C2D [] on up
[23:44:58-804.956] [INFO] [BGP] (route_bgp.c:493) route_bgp_new_conn() New connection added to senders_list
[23:44:58-804.963] [INFO] [BGP] (route_bgp.c:111) route_bgp_send_table_request() Sent table request to 8E1F->0C2D [] (version=0)
[23:44:58-804.973] [TRACE] [BGP] (route_bgp.c:368) route_bgp_on_conn_down() Connection 8E1F->0C2D [] on down
[23:44:58-804.978] [INFO] [BGP] (route_bgp.c:528) route_bgp_remove_conn() route_bgp_remove_conn: peer=61be9d4cd3c60c2d
[23:44:58-804.984] [INFO] [BGP] (route_bgp.c:549) route_bgp_remove_conn() Connection removed, routes updated via route_remove_conn
[23:44:58-804.988] [INFO] [GENERAL] (etcp_connections.c:262) keepalive_timer_cb() Link down: log_name=8E1F->0C2D [] socket=lan1 link_id=1 status=DOWN
[23:44:58-809.776] [TRACE] [BGP] (route_bgp.c:359) route_bgp_on_conn_up() Connection 8E1F->0C2D [] on up
[23:44:58-809.832] [INFO] [BGP] (route_bgp.c:493) route_bgp_new_conn() New connection added to senders_list
[23:44:58-809.846] [INFO] [BGP] (route_bgp.c:111) route_bgp_send_table_request() Sent table request to 8E1F->0C2D [] (version=0)
[23:44:58-810.212] [INFO] [BGP] (route_bgp.c:256) route_bgp_receive_cbk() route_bgp_receive_cbk: from=61be9d4cd3c60c2d len=6
[23:44:58-810.260] [INFO] [BGP] (route_bgp.c:340) route_bgp_receive_cbk() Received table request from 8E1F->0C2D [] (version=0), sending full table
[23:44:58-810.287] [INFO] [BGP] (route_bgp.c:78) route_bgp_send_route() Sending route 10.23.1.0/24, peer 8E1F->0C2D [] (ENTRY)
[23:44:58-810.294] [INFO] [BGP] (route_bgp.c:126) route_bgp_send_full_table() Sent full routing table to 8E1F->0C2D [] (version=1)
[23:44:58-814.981] [INFO] [BGP] (route_bgp.c:256) route_bgp_receive_cbk() route_bgp_receive_cbk: from=61be9d4cd3c60c2d len=18
[23:44:58-815.036] [INFO] [BGP] (route_bgp.c:302) route_bgp_receive_cbk() Received route 10.23.5.0/24 from 61be9d4cd3c60c2d (hops=1)
[23:44:58-815.071] [INFO] [BGP] (route_bgp.c:144) route_bgp_broadcast_route() route_bgp_broadcast_route: network=10.23.5.0/24 exclude=0x56275e8e5d38 subcmd=1
[23:44:58-815.076] [TRACE] [BGP] (route_bgp.c:157) route_bgp_broadcast_route() route_bgp_broadcast_route: sent to 0 peers
[23:44:58-815.080] [TRACE] [BGP] (route_bgp.c:318) route_bgp_receive_cbk() route_bgp_receive_cbk: INSERTED
[23:44:58-815.085] [INFO] [BGP] (route_bgp.c:256) route_bgp_receive_cbk() route_bgp_receive_cbk: from=61be9d4cd3c60c2d len=18
[23:44:58-815.089] [INFO] [BGP] (route_bgp.c:302) route_bgp_receive_cbk() Received route 10.23.6.0/24 from 61be9d4cd3c60c2d (hops=1)
[23:44:58-815.093] [INFO] [BGP] (route_bgp.c:144) route_bgp_broadcast_route() route_bgp_broadcast_route: network=10.23.6.0/24 exclude=0x56275e8e5d38 subcmd=1
[23:44:58-815.097] [TRACE] [BGP] (route_bgp.c:157) route_bgp_broadcast_route() route_bgp_broadcast_route: sent to 0 peers
[23:44:58-815.100] [TRACE] [BGP] (route_bgp.c:318) route_bgp_receive_cbk() route_bgp_receive_cbk: INSERTED
[23:44:58-815.213] [INFO] [BGP] (route_bgp.c:256) route_bgp_receive_cbk() route_bgp_receive_cbk: from=61be9d4cd3c60c2d len=18
[23:44:58-815.220] [INFO] [BGP] (route_bgp.c:302) route_bgp_receive_cbk() Received route 10.23.5.0/24 from 61be9d4cd3c60c2d (hops=1)
[23:44:58-815.224] [INFO] [BGP] (route_bgp.c:144) route_bgp_broadcast_route() route_bgp_broadcast_route: network=10.23.5.0/24 exclude=0x56275e8e5d38 subcmd=2
[23:44:58-815.228] [TRACE] [BGP] (route_bgp.c:157) route_bgp_broadcast_route() route_bgp_broadcast_route: sent to 0 peers
[23:44:58-815.231] [TRACE] [BGP] (route_bgp.c:318) route_bgp_receive_cbk() route_bgp_receive_cbk: INSERTED
[23:44:58-815.235] [INFO] [BGP] (route_bgp.c:256) route_bgp_receive_cbk() route_bgp_receive_cbk: from=61be9d4cd3c60c2d len=18
[23:44:58-815.239] [INFO] [BGP] (route_bgp.c:302) route_bgp_receive_cbk() Received route 10.23.6.0/24 from 61be9d4cd3c60c2d (hops=1)
[23:44:58-815.242] [INFO] [BGP] (route_bgp.c:144) route_bgp_broadcast_route() route_bgp_broadcast_route: network=10.23.6.0/24 exclude=0x56275e8e5d38 subcmd=2
[23:44:58-815.246] [TRACE] [BGP] (route_bgp.c:157) route_bgp_broadcast_route() route_bgp_broadcast_route: sent to 0 peers
[23:44:58-815.249] [TRACE] [BGP] (route_bgp.c:318) route_bgp_receive_cbk() route_bgp_receive_cbk: INSERTED
[00:40:35-599.488] [TRACE] [BGP] (route_bgp.c:368) route_bgp_on_conn_down() Connection 8E1F->0C2D [] on down
[00:40:35-599.548] [INFO] [BGP] (route_bgp.c:528) route_bgp_remove_conn() route_bgp_remove_conn: peer=61be9d4cd3c60c2d
[00:40:35-599.769] [INFO] [BGP] (route_bgp.c:166) route_bgp_broadcast_withdraw() route_bgp_broadcast_withdraw: node_id=61be9d4cd3c60c2d exclude=(nil)
[00:40:35-599.795] [INFO] [BGP] (route_bgp.c:166) route_bgp_broadcast_withdraw() route_bgp_broadcast_withdraw: node_id=61be9d4cd3c60c2d exclude=(nil)
[00:40:35-599.882] [INFO] [BGP] (route_bgp.c:549) route_bgp_remove_conn() Connection removed, routes updated via route_remove_conn
[00:40:35-599.888] [INFO] [GENERAL] (etcp_connections.c:262) keepalive_timer_cb() Link down: log_name=8E1F->0C2D [] socket=lan1 link_id=1 status=DOWN
[01:14:00-195.013] [TRACE] [BGP] (route_bgp.c:359) route_bgp_on_conn_up() Connection 8E1F->0C2D [] on up
[01:14:00-195.072] [INFO] [BGP] (route_bgp.c:493) route_bgp_new_conn() New connection added to senders_list
[01:14:00-195.084] [INFO] [BGP] (route_bgp.c:111) route_bgp_send_table_request() Sent table request to 8E1F->0C2D [] (version=0)
[01:14:00-201.819] [INFO] [BGP] (route_bgp.c:256) route_bgp_receive_cbk() route_bgp_receive_cbk: from=61be9d4cd3c60c2d len=10
[01:14:00-201.866] [INFO] [BGP] (route_bgp.c:329) route_bgp_receive_cbk() Received WITHDRAW for node 5f75c7445af88e1f
[01:14:00-201.888] [INFO] [BGP] (route_bgp.c:256) route_bgp_receive_cbk() route_bgp_receive_cbk: from=61be9d4cd3c60c2d len=6
[01:14:00-201.909] [INFO] [BGP] (route_bgp.c:340) route_bgp_receive_cbk() Received table request from 8E1F->0C2D [] (version=0), sending full table
[01:14:00-201.920] [INFO] [BGP] (route_bgp.c:78) route_bgp_send_route() Sending route 10.23.1.0/24, peer 8E1F->0C2D [] (ENTRY)
[01:14:00-201.924] [INFO] [BGP] (route_bgp.c:126) route_bgp_send_full_table() Sent full routing table to 8E1F->0C2D [] (version=1)
[01:14:00-207.872] [INFO] [BGP] (route_bgp.c:256) route_bgp_receive_cbk() route_bgp_receive_cbk: from=61be9d4cd3c60c2d len=18
[01:14:00-207.908] [INFO] [BGP] (route_bgp.c:302) route_bgp_receive_cbk() Received route 10.23.5.0/24 from 61be9d4cd3c60c2d (hops=1)
[01:14:00-207.916] [INFO] [BGP] (route_bgp.c:144) route_bgp_broadcast_route() route_bgp_broadcast_route: network=10.23.5.0/24 exclude=0x56275e8e5d38 subcmd=1
[01:14:00-207.920] [TRACE] [BGP] (route_bgp.c:157) route_bgp_broadcast_route() route_bgp_broadcast_route: sent to 0 peers
[01:14:00-207.924] [TRACE] [BGP] (route_bgp.c:318) route_bgp_receive_cbk() route_bgp_receive_cbk: INSERTED
[01:14:00-207.928] [INFO] [BGP] (route_bgp.c:256) route_bgp_receive_cbk() route_bgp_receive_cbk: from=61be9d4cd3c60c2d len=18
[01:14:00-207.932] [INFO] [BGP] (route_bgp.c:302) route_bgp_receive_cbk() Received route 10.23.6.0/24 from 61be9d4cd3c60c2d (hops=1)
[01:14:00-207.936] [INFO] [BGP] (route_bgp.c:144) route_bgp_broadcast_route() route_bgp_broadcast_route: network=10.23.6.0/24 exclude=0x56275e8e5d38 subcmd=1
[01:14:00-207.939] [TRACE] [BGP] (route_bgp.c:157) route_bgp_broadcast_route() route_bgp_broadcast_route: sent to 0 peers
[01:14:00-207.943] [TRACE] [BGP] (route_bgp.c:318) route_bgp_receive_cbk() route_bgp_receive_cbk: INSERTED
[02:29:31-196.879] [TRACE] [BGP] (route_bgp.c:378) route_bgp_etcp_conn_cbk() Set ETCP ready callback for connection 8E1F->???? []
[02:29:31-196.922] [INFO] [GENERAL] (etcp_connections.c:948) etcp_connections_read_callback_socket() New connection received on socket lan1: log_name=8E1F->D894 [] peer_id=1206313594063214740
[02:29:31-196.953] [INFO] [GENERAL] (etcp_connections.c:1079) etcp_connections_read_callback_socket() Connection established: log_name=8E1F->D894 [] socket=lan1 link_id=1 status=UP
[02:29:31-196.959] [TRACE] [BGP] (route_bgp.c:359) route_bgp_on_conn_up() Connection 8E1F->D894 [] on up
[02:29:31-196.964] [INFO] [BGP] (route_bgp.c:493) route_bgp_new_conn() New connection added to senders_list
[02:29:31-196.971] [INFO] [BGP] (route_bgp.c:111) route_bgp_send_table_request() Sent table request to 8E1F->D894 [] (version=0)
[02:29:31-235.679] [INFO] [BGP] (route_bgp.c:256) route_bgp_receive_cbk() route_bgp_receive_cbk: from=10bdafd28ddcd894 len=18
[02:29:31-235.721] [INFO] [BGP] (route_bgp.c:302) route_bgp_receive_cbk() Received route 10.23.0.0/24 from 10bdafd28ddcd894 (hops=1)
[02:29:31-235.729] [INFO] [BGP] (route_bgp.c:144) route_bgp_broadcast_route() route_bgp_broadcast_route: network=10.23.0.0/24 exclude=0x562763e892e8 subcmd=1
[02:29:31-235.738] [INFO] [BGP] (route_bgp.c:78) route_bgp_send_route() Sending route 10.23.0.0/24, peer 8E1F->0C2D [] (ENTRY)
[02:29:31-235.743] [TRACE] [BGP] (route_bgp.c:157) route_bgp_broadcast_route() route_bgp_broadcast_route: sent to 1 peers
[02:29:31-235.747] [TRACE] [BGP] (route_bgp.c:318) route_bgp_receive_cbk() route_bgp_receive_cbk: INSERTED
[02:31:13-366.794] [TRACE] [BGP] (route_bgp.c:368) route_bgp_on_conn_down() Connection 8E1F->D894 [] on down
[02:31:13-366.869] [INFO] [BGP] (route_bgp.c:528) route_bgp_remove_conn() route_bgp_remove_conn: peer=10bdafd28ddcd894
[02:31:13-366.956] [INFO] [BGP] (route_bgp.c:166) route_bgp_broadcast_withdraw() route_bgp_broadcast_withdraw: node_id=10bdafd28ddcd894 exclude=(nil)
[02:31:13-366.977] [INFO] [BGP] (route_bgp.c:549) route_bgp_remove_conn() Connection removed, routes updated via route_remove_conn
[02:31:13-366.982] [INFO] [GENERAL] (etcp_connections.c:262) keepalive_timer_cb() Link down: log_name=8E1F->D894 [] socket=lan1 link_id=1 status=DOWN
[02:31:13-374.249] [INFO] [BGP] (route_bgp.c:256) route_bgp_receive_cbk() route_bgp_receive_cbk: from=61be9d4cd3c60c2d len=10
[02:31:13-374.306] [INFO] [BGP] (route_bgp.c:329) route_bgp_receive_cbk() Received WITHDRAW for node 0000000000000000
[02:31:17-925.784] [ERROR] [CONNECTION] (etcp_connections.c:635) etcp_link_new() Can not insert link to socket
[02:31:17-925.819] [ERROR] [CONNECTION] (etcp_connections.c:1002) etcp_connections_read_callback_socket() etcp_connections_read_callback: failed to create link for connection
[02:31:17-925.824] [ERROR] [ETCP] (etcp_connections.c:1221) etcp_connections_read_callback_socket() etcp_connections_read_callback: error 66
[02:31:17-968.183] [ERROR] [CONNECTION] (etcp_connections.c:635) etcp_link_new() Can not insert link to socket
[02:31:17-968.247] [ERROR] [CONNECTION] (etcp_connections.c:1002) etcp_connections_read_callback_socket() etcp_connections_read_callback: failed to create link for connection
[02:31:17-968.253] [ERROR] [ETCP] (etcp_connections.c:1221) etcp_connections_read_callback_socket() etcp_connections_read_callback: error 66
[02:31:18-018.408] [ERROR] [CONNECTION] (etcp_connections.c:635) etcp_link_new() Can not insert link to socket
[02:31:18-018.452] [ERROR] [CONNECTION] (etcp_connections.c:1002) etcp_connections_read_callback_socket() etcp_connections_read_callback: failed to create link for connection
[02:31:18-018.457] [ERROR] [ETCP] (etcp_connections.c:1221) etcp_connections_read_callback_socket() etcp_connections_read_callback: error 66
Loading…
Cancel
Save