(root)/
glibc-2.38/
resolv/
getaddrinfo_a.c
       1  /* Copyright (C) 2001-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <errno.h>
      19  #include <netdb.h>
      20  #include <pthread.h>
      21  #include <stdlib.h>
      22  #include <unistd.h>
      23  
      24  #include <gai_misc.h>
      25  
      26  
      27  /* We need this special structure to handle asynchronous I/O.  */
      28  struct async_waitlist
      29    {
      30      unsigned int counter;
      31      struct sigevent sigev;
      32      struct waitlist list[0];
      33    };
      34  
      35  
      36  int
      37  __getaddrinfo_a (int mode, struct gaicb *list[], int ent, struct sigevent *sig)
      38  {
      39    struct sigevent defsigev;
      40    struct requestlist *requests[ent];
      41    int cnt;
      42    volatile unsigned int total = 0;
      43    int result = 0;
      44  
      45    /* Check arguments.  */
      46    if (mode != GAI_WAIT && mode != GAI_NOWAIT)
      47      {
      48        __set_errno (EINVAL);
      49        return EAI_SYSTEM;
      50      }
      51  
      52    if (sig == NULL)
      53      {
      54        defsigev.sigev_notify = SIGEV_NONE;
      55        sig = &defsigev;
      56      }
      57  
      58    /* Request the mutex.  */
      59    __pthread_mutex_lock (&__gai_requests_mutex);
      60  
      61    /* Now we can enqueue all requests.  Since we already acquired the
      62       mutex the enqueue function need not do this.  */
      63    for (cnt = 0; cnt < ent; ++cnt)
      64      if (list[cnt] != NULL)
      65        {
      66  	requests[cnt] = __gai_enqueue_request (list[cnt]);
      67  
      68  	if (requests[cnt] != NULL)
      69  	  /* Successfully enqueued.  */
      70  	  ++total;
      71  	else
      72  	  /* Signal that we've seen an error.  `errno' and the error code
      73  	     of the gaicb will tell more.  */
      74  	  result = EAI_SYSTEM;
      75        }
      76      else
      77        requests[cnt] = NULL;
      78  
      79    if (total == 0)
      80      {
      81        /* We don't have anything to do except signalling if we work
      82  	 asynchronously.  */
      83  
      84        /* Release the mutex.  We do this before raising a signal since the
      85  	 signal handler might do a `siglongjmp' and then the mutex is
      86  	 locked forever.  */
      87        __pthread_mutex_unlock (&__gai_requests_mutex);
      88  
      89        if (mode == GAI_NOWAIT)
      90  	__gai_notify_only (sig,
      91  			   sig->sigev_notify == SIGEV_SIGNAL ? getpid () : 0);
      92  
      93        return result;
      94      }
      95    else if (mode == GAI_WAIT)
      96      {
      97  #ifndef DONT_NEED_GAI_MISC_COND
      98        pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
      99  #endif
     100        struct waitlist waitlist[ent];
     101        int oldstate;
     102  
     103        total = 0;
     104        for (cnt = 0; cnt < ent; ++cnt)
     105  	if (requests[cnt] != NULL)
     106  	  {
     107  #ifndef DONT_NEED_GAI_MISC_COND
     108  	    waitlist[cnt].cond = &cond;
     109  #endif
     110  	    waitlist[cnt].next = requests[cnt]->waiting;
     111  	    waitlist[cnt].counterp = &total;
     112  	    waitlist[cnt].sigevp = NULL;
     113  	    waitlist[cnt].caller_pid = 0;	/* Not needed.  */
     114  	    requests[cnt]->waiting = &waitlist[cnt];
     115  	    ++total;
     116  	  }
     117  
     118        /* Since `pthread_cond_wait'/`pthread_cond_timedwait' are cancelation
     119  	 points we must be careful.  We added entries to the waiting lists
     120  	 which we must remove.  So defer cancelation for now.  */
     121        __pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &oldstate);
     122  
     123        while (total > 0)
     124  	{
     125  #ifdef DONT_NEED_GAI_MISC_COND
     126  	  int not_used __attribute__ ((unused));
     127  	  GAI_MISC_WAIT (not_used, total, NULL, 1);
     128  #else
     129  	  pthread_cond_wait (&cond, &__gai_requests_mutex);
     130  #endif
     131  	}
     132  
     133        /* Now it's time to restore the cancelation state.  */
     134        __pthread_setcancelstate (oldstate, NULL);
     135  
     136  #ifndef DONT_NEED_GAI_MISC_COND
     137        /* Release the conditional variable.  */
     138        if (pthread_cond_destroy (&cond) != 0)
     139  	/* This must never happen.  */
     140  	abort ();
     141  #endif
     142      }
     143    else
     144      {
     145        struct async_waitlist *waitlist;
     146  
     147        waitlist = (struct async_waitlist *)
     148  	malloc (sizeof (struct async_waitlist)
     149  		+ (ent * sizeof (struct waitlist)));
     150  
     151        if (waitlist == NULL)
     152  	result = EAI_AGAIN;
     153        else
     154  	{
     155  	  pid_t caller_pid = sig->sigev_notify == SIGEV_SIGNAL ? getpid () : 0;
     156  	  total = 0;
     157  
     158  	  for (cnt = 0; cnt < ent; ++cnt)
     159  	    if (requests[cnt] != NULL)
     160  	      {
     161  #ifndef DONT_NEED_GAI_MISC_COND
     162  		waitlist->list[cnt].cond = NULL;
     163  #endif
     164  		waitlist->list[cnt].next = requests[cnt]->waiting;
     165  		waitlist->list[cnt].counterp = &waitlist->counter;
     166  		waitlist->list[cnt].sigevp = &waitlist->sigev;
     167  		waitlist->list[cnt].caller_pid = caller_pid;
     168  		requests[cnt]->waiting = &waitlist->list[cnt];
     169  		++total;
     170  	      }
     171  
     172  	  waitlist->counter = total;
     173  	  waitlist->sigev = *sig;
     174  	}
     175      }
     176  
     177    /* Release the mutex.  */
     178    __pthread_mutex_unlock (&__gai_requests_mutex);
     179  
     180    return result;
     181  }
     182  #if PTHREAD_IN_LIBC
     183  versioned_symbol (libc, __getaddrinfo_a, getaddrinfo_a, GLIBC_2_34);
     184  
     185  # if OTHER_SHLIB_COMPAT (libanl, GLIBC_2_2_3, GLIBC_2_34)
     186  compat_symbol (libanl, __getaddrinfo_a, getaddrinfo_a, GLIBC_2_2_3);
     187  # endif
     188  #else /* !PTHREAD_IN_LIBC */
     189  strong_alias (__getaddrinfo_a, getaddrinfo_a)
     190  #endif /* !PTHREAD_IN_LIBC */