ConnectionFisherServer
ConnectionFisherServer بخش سرور ConnectionFisherClient است. منتظر probe ثابت کلاینت میماند، با marker ثابت سرور پاسخ میدهد و تنها پس از آن اجازه میدهد line وارد حالت عادی عبور stream شود.
این node را فقط در مسیری قرار دهید که انتظار دارید ترافیک ConnectionFisherClient را دریافت کند.
جایگاه رایج
چیدمان سادهٔ TCP:
TcpListener -> ConnectionFisherServer -> TcpConnector
کلاینت متناظر:
TcpListener -> ConnectionFisherClient -> TcpConnector
TcpListener -> ConnectionFisherServer -> TcpConnector
همراه با تونلهای stream دیگر در میانه مسیر:
ConnectionFisherClient -> EncryptionClient -> TcpConnector
TcpListener -> EncryptionServer -> ConnectionFisherServer -> TcpConnector
پس از decode شدن داده در هر جفت تونل کلاینت/سرور میانی، سرور باید دقیقاً همان بایتهای FISH? ارسالی کلاینت را ببیند.
این نود چه میکند؟
- با دریافت
Initدر upstream، فقط state محلی line را مقداردهی اولیه میکند. - upstream
Initبهnextرا به تأخیر میاندازد. - بایتهای upstream را تا رسیدن دستکم ۵ بایت buffer میکند.
- نیاز دارد ۵ بایت اول دقیقاً
FISH?باشند. - پاسخ ثابت
FISH!را downstream به client میفرستد. nextرا تنها پس از رسیدن payload بعد از probe مقداردهی اولیه میکند.- پس از کامل شدن مرحله probe، payload را بهصورت عادی عبور میدهد.
- اگر probe نامعتبر باشد یا حجم داده handshake در buffer از حد بگذرد، line را میبندد.
ConnectionFisherServer یک تونل میانی stream است. مستقیماً socket یا packet line نمیسازد.
نمونه تنظیم
{
"name": "fisher-server",
"type": "ConnectionFisherServer",
"next": "service"
}
در نسخه فعلی settings استفاده نمیشود.
فیلدهای اجباری
فیلدهای سطح اصلی:
| فیلد | نوع | توضیح |
|---|---|---|
name | string | نام یکتای node در config. |
type | string | باید دقیقاً "ConnectionFisherServer" باشد. |
next | string | اجباری. node stream بعدی که payload بعد از فاز probe را دریافت میکند. |
ConnectionFisherServer باید node قبلی نیز داشته باشد؛ این node ابتدا یا انتهای chain نیست.
تنظیمات
در حال حاضر هیچ فیلدی از settings خوانده نمیشود.
تبادل Probe
| جهت | Bytes | معنی |
|---|---|---|
| کلاینت به سرور | FISH? | پنج بایت الزامی ابتدای upstream. |
| سرور به کلاینت | FISH! | پس از دریافت probe معتبر ارسال میشود. |
markerها بایتهای ثابت ASCII هستند و سازوکار امنیتی محسوب نمیشوند.
مرحلههای سرور
پیادهسازی از سه فاز استفاده میکند:
| فاز | رفتار |
|---|---|
| wait ping | بایتهای upstream تا رسیدن دستکم ۵ بایت buffer میشوند. |
| wait payload | probe معتبر بوده و FISH! فرستاده شده است؛ با این حال next هنوز مقداردهی نشده، مگر اینکه payload اضافه از قبل در buffer باشد. |
| established | Init سمت next شروع شده است؛ ورودی نگهداشتهشده پیش از بازنشستگی سرور تخلیه میشود. |
جریان Handshake
با دریافت Init در upstream، سرور فقط state محلی line را مقداردهی اولیه میکند و هنوز tunnelNextUpStreamInit() را فراخوانی نمیکند.
پردازش payloadِ upstream پیش از برقراری کامل:
- سرور بایتهای ورودی را buffer میکند.
- probe ناقص حداکثر چهار بایت دارد؛ بدنه پس از probe کامل سقف جداگانه 2 MiB دارد.
- وقتی حداقل ۵ بایت در دسترس باشد، ۵ بایت اول خوانده میشوند.
- اگر دقیقاً
FISH?نباشند، line بسته میشود. - اگر منطبق باشند،
FISH!در جهت downstream به سمت previous فرستاده میشود. - اگر پس از پنج بایت اول payloadی مانده باشد، سرور
nextرا مقداردهی اولیه میکند و payload باقیمانده را در upstream میفرستد. - اگر payload اضافهای نباشد، سرور منتظر payload بعدی upstream میماند؛ سپس
nextرا مقداردهی اولیه و آن payload را ارسال میکند.
مسیر ادامه پیش از فراخوانی Init بعدی منتشر میشود. همه اعلانهای Est مربوط به transport، حتی اعلان تکراری از داخل Init، فوری منتقل میشوند. payload برای Est منتظر نمیماند.
بدنه همراه FISH? و نخستین payload پس از probe، هنگام پاسخ FISH!، Init بعدی و Est re-entrant جای FIFO خود را حفظ میکنند. ترتیب موقت ورودی، شامل بدنه در انتظار بازگشت Init، سقف 2 MiB و 1,024 buffer دارد و در همان dispatch پذیرفتهشده تکمیل میشود. Pause یا Est بهتنهایی صف داده آماده ایجاد نمیکنند. probe ناقص حداکثر چهار بایت دارد و بدنه پس از probe کامل سقف جداگانه 2 MiB دارد. بستهشدن در Init یا Est داده محلی قدیمی را آزاد میکند.
رفتار Lifecycle
قبل از establishment:
Initدر upstream فقط محلی است.- upstream payload بهعنوان probe یا اولین payload بعد از probe در نظر گرفته میشود
- آخرین
Pauseدر upstream برای ارسال پس از Init سمت next نگه داشته میشود؛Resumeآن را لغو میکند، حتی هنگام ورود مجدد در Init. Est،PauseوResumeدر downstream عبور داده نمیشوند.- payloadِ downstream در این مرحله غیرمنتظره است؛ buffer آن برای استفاده مجدد برمیگردد و line بسته میشود.
بعد از establishment:
- payloadِ upstream به
nextفرستاده میشود. - payloadِ downstream به node قبلی میرود.
- Pause و Resume در upstream، از جمله اعلانهای تکراری، به
nextفرستاده میشوند. - Est، Pause و Resume در downstream، از جمله اعلانهای تکراری، به node قبلی میروند.
پس از اتمام Init سمت next، ارسال Pause باقیمانده و تخلیه همه ورودی پذیرفتهشده، سرور state خط را آزاد و کاملاً صفر میکند و روی همان line برای همیشه bypass میشود. این کار برای Est یا Resume منتظر نمیماند. Pause یا Resume تازه هنگام Init، ارسال درخواست قدیمی را لغو میکند. callbackهای بعدی مستقیماً میان همسایهها عبور میکنند.
پیش از bypass، با دریافت Finish در upstream، سرور state محلی را از بین میبرد. تنها در صورتی Finish را در upstream منتشر میکند که next قبلاً مقداردهی اولیه شده باشد. اگر پیش از ایجاد سمت next خطای پروتکل رخ دهد، فقط سمت previous بسته میشود، زیرا هنوز lineای در سمت next وجود ندارد.
محدودیتها
| محدودیت | مقدار | رفتار |
|---|---|---|
| طول probe | 5 بایت | پنج بایت نخست باید FISH? باشند. |
| probe ناقص | 4 بایت | probe کامل پنجبایتی بیدرنگ اعتبارسنجی میشود. |
| داده pending برنامه | 2 MiB / 1,024 buffers | بدنه در انتظار Init نیز شمرده میشود؛ marker از سقف کم نمیکند. |
required_padding_left | 0 | سرور چیزی به bufferهای موجود اضافه نمیکند. |
برای پاسخ FISH! یک buffer کوچک جداگانه گرفته میشود.
نکتهها
- با
ConnectionFisherClientمتناظر استفاده کنید. - آن را پس از هر تونل سمت سرور قرار دهید که transport میان کلاینت و سرور را decode میکند.
- برای chainهای stream طراحی شده است، نه packet-line.
- probe ثابت و عمومی است؛ برای امنیت واقعی از nodeهای دیگر WaterWall استفاده کنید.
- upstream
Estو downstreamInitبرای این node غیرفعال هستند.
پشتیبانی از splice و بازنشستگی state راهاندازی
هر دو node، buffer عادی و payload موجود در pipe خصوصی را میپذیرند. هر delivery که وارد parsing
handshake یا ترتیبدهی هنگام انتخاب child شود، با sbufEnsureOrdinary() کامل به buffer عادی تبدیل
میشود. FIFO برنامه buffer را بدون خواندن محتوا نگه میدارد. marker کامل پنجبایتی میتواند تا 2 MiB
داده برنامه همراه داشته باشد؛ marker از سقف داده برنامه کم نمیکند و marker ناقص حداکثر چهار بایت دارد.
پس از راهاندازی و تخلیه FIFO، client فضای handshake و صف خالی را آزاد میکند، اما نگاشت main به child منتخب و کنترل جریان endpoint برای payload، فشار و Finish باقی میماند. server پس از اتمام Init سمت backend و replay، همه state خط را آزاد و صفر میکند و روی همان line برای همیشه bypass میشود. payload آماده بدون inspection، materialization یا سقف backlog راهاندازی عبور میکند. server همچنان backend را با نخستین payload برنامه مقداردهی میکند؛ childهای بازنده اتصال backend نمیسازند. برای TCP آماده، ترجیح خواندن عادی ثبت نمیشود.
متادیتای نود
metadata برگرفته از کد منبع:
| ویژگی | مقدار |
|---|---|
| node flags | kNodeFlagSupportsSplice |
can_have_prev | true |
can_have_next | true |
layer_group | kNodeLayer4 |
layer_group_prev_node | kNodeLayer4 |
layer_group_next_node | kNodeLayer4 |
required_padding_left | 0 bytes |