getaddrinfo_a(3)

الاسم
getaddrinfo_a, gai_suspend, gai_error, gai_cancel - ترجمة غير متزامنة لعنوان الشبكة والخدمة

المكتبة
مكتبة البحث عن الأسماء غير المتزامنة (libanl, -lanl)

موجز
#define _GNU_SOURCE         /* انظر feature_test_macros(7) */
#include <netdb.h>

int getaddrinfo_a(int mode, struct gaicb *list[restrict n],
                  int n, struct sigevent *restrict sevp);
int gai_suspend(const struct gaicb *const list[n], int n,
                  const struct timespec *timeout);

int gai_error(struct gaicb *req);
int gai_cancel(struct gaicb *req);

الوصف
الدالة getaddrinfo_a() تؤدي نفس مهمة getaddrinfo(3)، لكنها تسمح بإجراء عمليات بحث متعددة عن الأسماء بشكل غير متزامن، مع إشعار اختياري عند اكتمال عمليات البحث.

المعامل mode له إحدى القيم التالية:

GAI_WAIT
    إجراء عمليات البحث بشكل متزامن. يُحجَز الاستدعاء حتى تكتمل عمليات البحث.

GAI_NOWAIT
    إجراء عمليات البحث بشكل غير متزامن. يعود الاستدعاء فورًا، وتُحل الطلبات في الخلفية. انظر مناقشة المعامل sevp أدناه.

المصفوفة list تحدد طلبات البحث التي ستُعالج. المعامل n يحدد عدد العناصر في list. تُبدأ عمليات البحث المطلوبة بالتوازي. تُتجاهل العناصر NULL في list. يُوصف كل طلب بهيكل gaicb، المُعرَّف كالتالي:

    struct gaicb {
        const char            *ar_name;
        const char            *ar_service;
        const struct addrinfo *ar_request;
        struct addrinfo       *ar_result;
    };

عناصر هذا الهيكل تتوافق مع معاملات getaddrinfo(3). لذا، ar_name يتوافق مع المعامل node و ar_service مع المعامل service، مُعرِّفًا مضيف إنترنت وخدمة. العنصر ar_request يتوافق مع المعامل hints، مُحددًا معايير اختيار هياكل عنوان المقبس المُعادة. أخيرًا، ar_result يتوافق مع المعامل res؛ لا تحتاج لتهيئة هذا العنصر، سيُضبط آليًا عند حل الطلب. هيكل addrinfo المُشار إليه بالعنصرين الأخيرين موصوف في getaddrinfo(3).

عندما يُحدد mode كـ GAI_NOWAIT، يمكن الحصول على إشعارات حول الطلبات المُحلّة باستخدام هيكل sigevent المُشار إليه بالمعامل sevp. للتعريف والتفاصيل العامة لهذا الهيكل، انظر sigevent(3type). الحقل sevp->sigev_notify يمكن أن يكون له القيم التالية:

SIGEV_NONE
    لا تُقدم أي إشعار.

SIGEV_SIGNAL
    عند اكتمال بحث، يُولَّد الإشارة sigev_signo للعملية. انظر sigevent(3type) للتفاصيل العامة. الحقل si_code من هيكل siginfo_t سيُضبط إلى SI_ASYNCNL.

SIGEV_THREAD
    عند اكتمال بحث، تُستدعى sigev_notify_function كما لو كانت دالة بدء خيط جديد. انظر sigevent(3type) للتفاصيل.

بالنسبة لـ SIGEV_SIGNAL و SIGEV_THREAD، قد يكون من المفيد توجيه sevp->sigev_value.sival_ptr إلى list.

الدالة gai_suspend() تُعلق تنفيذ الخيط المُستدعي، منتظرة اكتمال طلب واحد أو أكثر في المصفوفة list. المعامل n يحدد حجم المصفوفة list. يُحجَز الاستدعاء حتى يحدث أحد التالي:

•   تكتمل عملية أو أكثر من العمليات في list.

•   تُقاطع الاستدعاء بإشارة تم التقاطها.

•   ينقضي الفاصل الزمني المحدد في timeout. تحدد هذه الوسيطة مهلة بالثواني بالإضافة إلى النانوثانية (انظر nanosleep(2) لتفاصيل بنية timespec). إذا كان timeout NULL، فتحجب الاستدعاء إلى أجل غير مسمى (حتى يقع أحد الأحداث أعلاه).

لا يُعطى إشارة صريحة عن أي طلب أُكمل؛ يجب عليك تحديد أي الطلبات أُكملت بالتكرار مع gai_error() على قائمة الطلبات.

ترجع الدالة gai_error() حالة الطلب req: إما EAI_INPROGRESS إذا لم يُكمل الطلب بعد، أو 0 إذا عُولج بنجاح، أو رمز خطأ إذا تعذر حل الطلب.

تلغي الدالة gai_cancel() الطلب req. إذا أُلغي الطلب بنجاح، فتُضبط حالة خطأ الطلب إلى EAI_CANCELED ويُجرى الإعلام غير المتزامن العادي. لا يمكن إلغاء الطلب إذا كان يُعالج حاليًا؛ في تلك الحالة، يُعالج كما لو أن gai_cancel() لم تُستدعَ أبدًا. إذا كان req NULL، فتُبذل محاولة لإلغاء جميع الطلبات المعلقة التي قامت بها العملية.

قيمة الإرجاع
ترجع الدالة getaddrinfo_a() 0 إذا صُفت جميع الطلبات في قائمة الانتظار بنجاح، أو أحد رموز الخطأ غير الصفرية التالية:

EAI_AGAIN
    لم تكن الموارد اللازمة لصف طلبات البحث في قائمة الانتظار متاحة. يمكن للتطبيق التحقق من حالة خطأ كل طلب لتحديد أي منها فشل.

EAI_MEMORY
    نفدت الذاكرة.

EAI_SYSTEM
    mode غير صالح.

ترجع الدالة gai_suspend() 0 إذا أُكمل طلب واحد على الأقل من الطلبات المدرجة. وإلا، فترجع أحد رموز الخطأ غير الصفرية التالية:

EAI_AGAIN
    انتهت المهلة المعطاة قبل أن يُكمل أي من الطلبات.

EAI_ALLDONE
    لم تُعطَ أي طلبات فعلية للدالة.

EAI_INTR
    قاطعت إشارة الدالة. لاحظ أن هذا الانقطاع قد يكون ناتجًا عن إعلام إشارة لبعض طلبات البحث المكتملة.

يمكن للدالة gai_error() أن ترجع EAI_INPROGRESS لطلب بحث غير مكتمل، أو 0 لبحث أُكمل بنجاح (كما هو موصوف أعلاه)، أو أحد رموز الخطأ التي قد ترجعها getaddrinfo(3)، أو رمز الخطأ EAI_CANCELED إذا أُلغي الطلب صراحةً قبل أن يُكمل.

يمكن للدالة gai_cancel() أن ترجع إحدى هذه القيم:

EAI_CANCELED
    أُلغي الطلب بنجاح.

EAI_NOTCANCELED
    لم يُلغَ الطلب.

EAI_ALLDONE
    اكتمل الطلب بالفعل.

ترجم الدالة gai_strerror(3) رموز الخطأ هذه إلى سلسلة نصية مقروءة للبشر، مناسبة للإبلاغ عن الأخطاء.

السمات
للاطلاع على شرح للمصطلحات المستخدمة في هذا القسم، انظر attributes(7).
الواجهة | السمة | القيمة
getaddrinfo_a(), gai_suspend(), gai_error(), gai_cancel() | سلامة الخيوط | MT-Safe

المعايير
GNU.

التاريخ
glibc 2.2.3.

صُممت واجهة getaddrinfo_a() على غرار واجهة lio_listio(3).

أمثلة
يُقدَّم مثالان: مثال بسيط يحل عدة طلبات بالتوازي بشكل تزامني، ومثال معقد يُظهر بعض القدرات اللاتزامنية.

  مثال تزامني
يحل البرنامج أدناه ببساطة عدة أسماء مضيفين بالتوازي، مما يُعطي تسريعًا مقارنة بحل أسماء المضيفين تسلسليًا باستخدام getaddrinfo(3). يمكن استخدام البرنامج هكذا:

    $ ./a.out mirrors.kernel.org enoent.linuxfoundation.org gnu.org;
    mirrors.kernel.org: 139.178.88.99
    enoent.linuxfoundation.org: Name or service not known
    gnu.org: 209.51.188.116

هذا هو الكود المصدري للبرنامج

    #define _GNU_SOURCE
    #include <err.h>
    #include <netdb.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    #define MALLOC(n, type)  ((type *) reallocarray(NULL, n, sizeof(type)))

    int
    main(int argc, char *argv[])
    {
        int ret;
        struct gaicb *reqs[argc - 1];
        char host[NI_MAXHOST];
        struct addrinfo *res;

        if (argc < 2) {
            fprintf(stderr, "Usage: %s HOST...\n", argv[0]);
            exit(EXIT_FAILURE);
        }

        for (size_t i = 0; i < argc - 1; i++) {
            reqs[i] = MALLOC(1, struct gaicb);
            if (reqs[i] == NULL)
                err(EXIT_FAILURE, "malloc");

            memset(reqs[i], 0, sizeof(*reqs[0]));
            reqs[i]->ar_name = argv[i + 1];
        }

        ret = getaddrinfo_a(GAI_WAIT, reqs, argc - 1, NULL);
        if (ret != 0) {
            fprintf(stderr, "getaddrinfo_a() failed: %s\n",
                    gai_strerror(ret));
            exit(EXIT_FAILURE);
        }

        for (size_t i = 0; i < argc - 1; i++) {
            printf("%s: ", reqs[i]->ar_name);
            ret = gai_error(reqs[i]);
            if (ret == 0) {
                res = reqs[i]->ar_result;

                ret = getnameinfo(res->ai_addr, res->ai_addrlen,
                                  host, sizeof(host),
                                  NULL, 0, NI_NUMERICHOST);
                if (ret != 0) {
                    fprintf(stderr, "getnameinfo() failed: %s\n",
                            gai_strerror(ret));
                    exit(EXIT_FAILURE);
                }
                puts(host);

            } else {
                puts(gai_strerror(ret));
            }
        }
        exit(EXIT_SUCCESS);
    }

  مثال لاتزامني
يُظهر هذا المثال واجهة أمامية تفاعلية بسيطة لـ getaddrinfo_a(). لم يُوضَّح مرفق الإشعار.

قد تبدو جلسة مثال هكذا:

    $ ./a.out;
    > a mirrors.kernel.org enoent.linuxfoundation.org gnu.org
    > c 2
    [2] gnu.org: Request not canceled
    > w 0 1
    [00] mirrors.kernel.org: Finished
    > l
    [00] mirrors.kernel.org: 139.178.88.99
    [01] enoent.linuxfoundation.org: Processing request in progress
    [02] gnu.org: 209.51.188.116
    > l
    [00] mirrors.kernel.org: 139.178.88.99
    [01] enoent.linuxfoundation.org: Name or service not known
    [02] gnu.org: 209.51.188.116

المصدر البرمجي للبرنامج كما يلي:

    #define _GNU_SOURCE
    #include <assert.h>
    #include <err.h>
    #include <netdb.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    #define CALLOC(n, type)  ((type *) calloc(n, sizeof(type)))

    #define REALLOCF(ptr, n, type)                                          \
    ({                                                                      \
        static_assert(__builtin_types_compatible_p(typeof(ptr), type *));   \
                                                                            \
        (type *) reallocarrayf(ptr, n, sizeof(type));                       \
    })

    static struct gaicb **reqs = NULL;
    static size_t nreqs = 0;

    static inline void *
    reallocarrayf(void *p, size_t n, size_t size)
    {
        void  *q;

        q = reallocarray(p, n, size);
        if (q == NULL && n != 0 && size != 0)
            free(p);
        return q;
    }

    static char *
    getcmd(void)
    {
        static char buf[256];

        fputs("> ", stdout);
        fflush(stdout);
        if (fgets(buf, sizeof(buf), stdin) == NULL)
            return NULL;

        if (buf[strlen(buf) - 1] == '\n')
            buf[strlen(buf) - 1] = 0;

        return buf;
    }

    /* Add requests for specified hostnames.  */
    static void
    add_requests(void)
    {
        size_t nreqs_base = nreqs;
        char *host;
        int ret;

        while ((host = strtok(NULL, " "))) {
            nreqs++;
            reqs = REALLOCF(reqs, nreqs, struct gaicb *);
            if (reqs == NULL)
                err(EXIT_FAILURE, "reallocf");

            reqs[nreqs - 1] = CALLOC(1, struct gaicb);
            if (reqs[nreqs - 1] == NULL)
                err(EXIT_FAILURE, "calloc");

            reqs[nreqs - 1]->ar_name = strdup(host);
        }

        /* Queue nreqs_base..nreqs requests.  */

        ret = getaddrinfo_a(GAI_NOWAIT, &reqs[nreqs_base],
                            nreqs - nreqs_base, NULL);
        if (ret) {
            fprintf(stderr, "getaddrinfo_a() failed: %s\n",
                    gai_strerror(ret));
            exit(EXIT_FAILURE);
        }
    }

    /* Wait until at least one of specified requests completes.  */
    static void
    wait_requests(void)
    {
        char *id;
        int ret;
        size_t n;
        struct gaicb const **wait_reqs;

        wait_reqs = CALLOC(nreqs, const struct gaicb *);
        if (wait_reqs == NULL)
            err(EXIT_FAILURE, "calloc");

                    /* NULL elements are ignored by gai_suspend().  */

        while ((id = strtok(NULL, " ")) != NULL) {
            n = atoi(id);

            if (n >= nreqs) {
                printf("Bad request number: %s\n", id);
                return;
            }

            wait_reqs[n] = reqs[n];
        }

        ret = gai_suspend(wait_reqs, nreqs, NULL);
        if (ret) {
            printf("gai_suspend(): %s\n", gai_strerror(ret));
            return;
        }

        for (size_t i = 0; i < nreqs; i++) {
            if (wait_reqs[i] == NULL)
                continue;

            ret = gai_error(reqs[i]);
            if (ret == EAI_INPROGRESS)
                continue;

            printf("[%02zu] %s: %s\n", i, reqs[i]->ar_name,
                   ret == 0 ? "Finished" : gai_strerror(ret));
        }
    }

    /* Cancel specified requests.  */
    static void
    cancel_requests(void)
    {
        char *id;
        int ret;
        size_t n;

        while ((id = strtok(NULL, " ")) != NULL) {
            n = atoi(id);

            if (n >= nreqs) {
                printf("Bad request number: %s\n", id);
                return;
            }

            ret = gai_cancel(reqs[n]);
            printf("[%s] %s: %s\n", id, reqs[atoi(id)]->ar_name,
                   gai_strerror(ret));
        }
    }

    /* List all requests.  */
    static void
    list_requests(void)
    {
        int ret;
        char host[NI_MAXHOST];
        struct addrinfo *res;

        for (size_t i = 0; i < nreqs; i++) {
            printf("[%02zu] %s: ", i, reqs[i]->ar_name);
            ret = gai_error(reqs[i]);

            if (!ret) {
                res = reqs[i]->ar_result;

                ret = getnameinfo(res->ai_addr, res->ai_addrlen,
                                  host, sizeof(host),
                                  NULL, 0, NI_NUMERICHOST);
                if (ret) {
                    fprintf(stderr, "getnameinfo() failed: %s\n",
                            gai_strerror(ret));
                    exit(EXIT_FAILURE);
                }
                puts(host);
            } else {
                puts(gai_strerror(ret));
            }
        }
    }

    int
    main(void)
    {
        char *cmdline;
        char *cmd;

        while ((cmdline = getcmd()) != NULL) {
            cmd = strtok(cmdline, " ");

            if (cmd == NULL) {
                list_requests();
            } else {
                switch (cmd[0]) {
                case 'a':
                    add_requests();
                    break;
                case 'w':
                    wait_requests();
                    break;
                case 'c':
                    cancel_requests();
                    break;
                case 'l':
                    list_requests();
                    break;
                default:
                    fprintf(stderr, "Bad command: %c\n", cmd[0]);
                    break;
                }
            }
        }
        exit(EXIT_SUCCESS);
    }

انظر أيضًا
getaddrinfo(3), inet(3), lio_listio(3), hostname(7), ip(7), sigevent(3type)

ترجمة
تُرجمت هذه الصفحة من الدليل بواسطة زايد السعيدي <zayed.alsaidi@gmail.com>

هذه الترجمة هي وثيقة مجانية؛ راجع رخصة جنو العامة الإصدار 3 (https://www.gnu.org/licenses/gpl-3.0.html) أو ما بعده للاطلاع على شروط حقوق النشر. لا توجد أي ضمانات.

إذا وجدت أي أخطاء في ترجمة صفحة الدليل هذه، يرجى إرسال بريد إلكتروني إلى قائمة بريد المترجمين: kde-l10n-ar@kde.org.