برنامه نویسی

بازی با اتصالات جنینی در جاوا با تابع خارجی

امروز ما از تابع خارجی در جاوا 22 برای فراخوانی یک کد بومی با هدف شروع اتصالات جنینی علیه هر سروری استفاده خواهیم کرد.

💡نمونه‌ای برای اجرا در فضای github.com/ulrich من موجود در مخزن آماده است: https://github.com/ulrich/java-rawsocket

اتصالات جنینی چیست؟ 🎓

برای مثال زمانی که می خواهیم یک دست دادن سه طرفه TCP لغو شده را آغاز کنیم، از قابلیت های اتصالات جنینی استفاده می کنیم. اگر دوره های شبکه خود را در دانشکده (coucou Paris 8 ❤️) به خاطر دارید، چند سال (برای من) وجود دارد، در حالی که TCP-IP تلاش می کند یک اتصال شبکه را باز کند، دنباله های زیر را به خاطر می آورید:

1️⃣              SYN (seq 1000) -> |
2️⃣                                | <- SYN / ACK (seq 2000, ACK 1001)
3️⃣    ACK (seq 1001, ACK 2001) -> |
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

هنگامی که فرآیند به دست آمد، میزبان ها می توانند با هم صحبت کنند. اگر ما نیازی به ایجاد یک ارتباط خوب بین میزبان ها نداریم، می توانیم با ارسال یک دستورالعمل بازنشانی (RST) در انتهای دست دادن سه طرفه TCP، دنباله را لغو کنیم، مانند این:

1️⃣              SYN (seq 1000) -> |
2️⃣                                | <- SYN / ACK (seq 2000, ACK 1001)
3️⃣                        RST ->  X
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

دلایل مختلفی برای ایجاد اتصالات جنینی وجود دارد و از طرف من مجبور شدم این ویژگی را برای یک مشتری پیاده کنم، چند سالی است…

به هر حال، اگر می‌خواهید اتصال جنینی را کاوش کنید، به صفحه اختصاصی ویکی‌پدیا بروید: https://en.wikipedia.org/wiki/TCP_half-open

عملکرد خارجی در جاوا؟ 🎓

بهترین راه برای از سرگیری FFI در جاوا ذکر تعریف رسمی از شرکت اوراکل است: The Foreign Function and Memory (FFM) API enables Java programs to interoperate with code and data outside the Java runtime.

به عبارت دیگر، ما می خواهیم “بازی را خم کنیم” و راه های اجدادی (JNI، JNA، JNR…) را برای استفاده از کد بومی خارج از ماشین مجازی جاوا فراموش کرده ایم.

وعده FFI این است که موارد استفاده را در زمانی که جاوا نیاز به فراخوانی (پایین) و (بالا) برنامه یا کتابخانه بومی دارد، آسان کند.

این مقاله مقدمه ای در مورد FFI نیست و بهترین چیز برای یادگیری در مورد آن این است که مستندات Oracle را در اینجا دنبال کنید: https://docs.oracle.com/en/java/javase/22/core/foreign-function-and-memory -api.html

FFI برای اتصال جنینی؟ 🚀

فکر می کنم حدس زده اید که چرا برای ایجاد یک ارتباط جنینی به برنامه بومی نیاز داریم. در واقع، در جاوا متاسفانه ما توانایی ایجاد بسته های شبکه سطح پایین را نداریم. بنابراین استفاده از netinet/tcp.h کتابخانه برای زبان های سطح پایین تر مانند C (مثال ما) رزرو شده است و بنابراین FFI به کمک می آید!

لطفاً با من در کد SocketTester.java عمیق فرو بروید 🔍

public int run() throws Throwable {
    log.info("Running SocketTester for destination address {}:{}", destinationAddress, destinationPort);

1️⃣    try (Arena confinedArena = Arena.ofConfined()) {
        SymbolLookup symbolLookup =
                    SymbolLookup.libraryLookup(Config.getNativeLibraryFile(), confinedArena);

2️⃣        MemorySegment function =
                    symbolLookup.find(Config.getNativeFunctionName())
                            .orElseThrow(() -> new IllegalStateException("Unable to find the native function: " + Config.getNativeFunctionName()));

3️⃣       MethodHandle methodHandle = Linker.nativeLinker()
                .downcallHandle(
                            function,
                            Config.getNativeFunctionDescriptor());

4️⃣       return (int) methodHandle.invoke(
                    confinedArena.allocateFrom(sourceAddress),
                    confinedArena.allocateFrom(destinationAddress),
                    confinedArena.allocateFrom(ValueLayout.OfInt.JAVA_INT, destinationPort),
                    confinedArena.allocateFrom(ValueLayout.OfInt.JAVA_INT, readTimeout),
                    confinedArena.allocateFrom(ValueLayout.OfInt.JAVA_INT, writeTimeout));
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در نقطه 1️⃣ اعلام می کنیم که می خواهیم از Arena محدود شده فقط برای رشته ای که Arena را ایجاد می کند در دسترس است استفاده کنیم. می‌توانیم Arena را با یک جعبه بسته که وظیفه کنترل چرخه حیات بخش‌های حافظه بومی را بر عهده دارد، مقایسه کنیم. در حال حاضر FFI دامنه های زیر را مجاز می کند: جهانی، خودکار، محدود و اشتراکی. لطفاً به Javadoc نگاهی بیندازید: https://docs.oracle.com/en/java/javase/22/docs/api/java.base/java/lang/foreign/Arena.html

در نقطه 2️⃣ باید کتابخانه بومی را تحت فرم .so بارگذاری کنیم.

در نقطه 3️⃣ یک کنترل کننده downcall را که برای برقراری ارتباط از جاوا به کد Native استفاده می شود، مقداردهی اولیه می کنیم. FFI اجازه می دهد تا از خرد کنترل کننده تماس upcall استفاده کنید که به شما امکان می دهد کد جاوا را به عنوان نشانگر تابع به یک تابع خارجی منتقل کنید.

در نقطه 4️⃣ کد بومی را با پاس دادن پارامترهای مورد انتظاری که قبلا توسط متفاوت ایجاد شده بود فراخوانی می کنیم. اختصاص از مواد و روش ها.

برای تست اتصال جنینی با کد خارجی Function می توانید از پروژه فوقانی ذکر شده استفاده کنید.

اگر تمام مراحل با موفقیت انجام شود، ما ردیابی زیر را در ترمینال شما به دست خواهیم آورد:

[INFO (java)] Running SocketTester for destination address 127.0.0.1:8080
[INFO (native)] Selected source port number: 35940
[INFO (native)] TCP header sequence number: 272214228
[INFO (native)] Successfully sent 60 bytes SYN!
[INFO (native)] Received bytes: 40
[INFO (native)] Destination port: 35940
[INFO (native)] Successfully received 40 bytes
[INFO (native)] Received syn: 0, ack: 1, rst: 1
[INFO (native)] TCP header sequence number response: 0
[INFO (native)] TCP header ack sequence number response: 272214229
[INFO (native)] tcph->syn: 0
[INFO (native)] tcph->ack: 16777216
[INFO (native)] SYN ACK received -> Success
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

روز خوبی داشته باشید.

تصویر ژاکلین ماکو از Pixabay

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا