]> git.saurik.com Git - apt.git/blobdiff - methods/rfc2553emu.cc
evaluate Acquire::Languages= before LANG= (Closes: #602573)
[apt.git] / methods / rfc2553emu.cc
index 66fe781fb57c814ef7eaaf4ed9edd727b291ca3f..66bc906e9707574c6c646259fc014fde2689bee2 100644 (file)
@@ -1,47 +1,41 @@
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
-// $Id: rfc2553emu.cc,v 1.1 1999/05/25 05:56:24 jgg Exp $
+// $Id: rfc2553emu.cc,v 1.8 2001/02/20 07:03:18 jgg Exp $
 /* ######################################################################
 
    RFC 2553 Emulation - Provides emulation for RFC 2553 getaddrinfo,
                         freeaddrinfo and getnameinfo
+
+   This is really C code, it just has a .cc extensions to play nicer with
+   the rest of APT.
    
    Originally written by Jason Gunthorpe <jgg@debian.org> and placed into
    the Public Domain, do with it what you will.
-   
+
    ##################################################################### */
                                                                        /*}}}*/
 #include "rfc2553emu.h"
 #include <stdlib.h>
 #include <arpa/inet.h>
-#include <iostream.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <stdio.h>
 
 #ifndef HAVE_GETADDRINFO
+// getaddrinfo - Resolve a hostname                                    /*{{{*/
+// ---------------------------------------------------------------------
+/* */
 int getaddrinfo(const char *nodename, const char *servname,
                const struct addrinfo *hints,
                struct addrinfo **res)
 {
-   struct addrinfo **Result;
+   struct addrinfo **Result = res;
    hostent *Addr;
    unsigned int Port;
    int Proto;
    const char *End;
    char **CurAddr;
    
-   Addr = gethostbyname(nodename);
-   if (Addr == 0)
-   {
-      if (h_errno == TRY_AGAIN)
-        return EAI_AGAIN;
-      if (h_errno == NO_RECOVERY)
-        return EAI_FAIL;
-      return EAI_NONAME;
-   }
-   
-   // No A records 
-   if (Addr->h_addr_list[0] == 0)
-      return EAI_NONAME;
-
    // Try to convert the service as a number
    Port = htons(strtol(servname,(char **)&End,0));
    Proto = SOCK_STREAM;
@@ -50,7 +44,7 @@ int getaddrinfo(const char *nodename, const char *servname,
       Proto = hints->ai_socktype;
    
    // Not a number, must be a name.
-   if (End != servname + strlen(End))
+   if (End != servname + strlen(servname))
    {
       struct servent *Srv = 0;
       
@@ -78,10 +72,32 @@ int getaddrinfo(const char *nodename, const char *servname,
          hints->ai_socktype != 0)
         return EAI_SERVICE;
    }
+      
+   // Hostname lookup, only if this is not a listening socket
+   if (hints != 0 && (hints->ai_flags & AI_PASSIVE) != AI_PASSIVE)
+   {
+      Addr = gethostbyname(nodename);
+      if (Addr == 0)
+      {
+        if (h_errno == TRY_AGAIN)
+           return EAI_AGAIN;
+        if (h_errno == NO_RECOVERY)
+           return EAI_FAIL;
+        return EAI_NONAME;
+      }
+   
+      // No A records 
+      if (Addr->h_addr_list[0] == 0)
+        return EAI_NONAME;
+      
+      CurAddr = Addr->h_addr_list;
+   }
+   else
+      CurAddr = (char **)&End;    // Fake!
    
    // Start constructing the linked list
    *res = 0;
-   for (CurAddr = Addr->h_addr_list; *CurAddr != 0; CurAddr++)
+   for (; *CurAddr != 0; CurAddr++)
    {
       // New result structure
       *Result = (struct addrinfo *)calloc(sizeof(**Result),1);
@@ -116,14 +132,24 @@ int getaddrinfo(const char *nodename, const char *servname,
       // Set the address
       ((struct sockaddr_in *)(*Result)->ai_addr)->sin_family = AF_INET;
       ((struct sockaddr_in *)(*Result)->ai_addr)->sin_port = Port;
-      ((struct sockaddr_in *)(*Result)->ai_addr)->sin_addr = *(in_addr *)(*CurAddr);
-
+      
+      if (hints != 0 && (hints->ai_flags & AI_PASSIVE) != AI_PASSIVE)
+        ((struct sockaddr_in *)(*Result)->ai_addr)->sin_addr = *(in_addr *)(*CurAddr);
+      else
+      {
+         // Already zerod by calloc.
+        break;
+      }
+      
       Result = &(*Result)->ai_next;
    }
    
    return 0;
 }
-
+                                                                       /*}}}*/
+// freeaddrinfo - Free the result of getaddrinfo                       /*{{{*/
+// ---------------------------------------------------------------------
+/* */
 void freeaddrinfo(struct addrinfo *ai)
 {
    struct addrinfo *Tmp;
@@ -135,5 +161,85 @@ void freeaddrinfo(struct addrinfo *ai)
       free(ai);
    }
 }
-
+                                                                       /*}}}*/
 #endif // HAVE_GETADDRINFO
+
+#ifndef HAVE_GETNAMEINFO
+// getnameinfo - Convert a sockaddr to a string                        /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+int getnameinfo(const struct sockaddr *sa, socklen_t salen,
+               char *host, size_t hostlen,
+               char *serv, size_t servlen,
+               int flags)
+{
+   struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+   
+   // This routine only supports internet addresses
+   if (sa->sa_family != AF_INET)
+      return EAI_ADDRFAMILY;
+   
+   if (host != 0)
+   {
+      // Try to resolve the hostname
+      if ((flags & NI_NUMERICHOST) != NI_NUMERICHOST)
+      {
+        struct hostent *Ent = gethostbyaddr((char *)&sin->sin_addr,sizeof(sin->sin_addr),
+                                            AF_INET);
+        if (Ent != 0)
+           strncpy(host,Ent->h_name,hostlen);
+        else
+        {
+           if ((flags & NI_NAMEREQD) == NI_NAMEREQD)
+           {
+              if (h_errno == TRY_AGAIN)
+                 return EAI_AGAIN;
+              if (h_errno == NO_RECOVERY)
+                 return EAI_FAIL;
+              return EAI_NONAME;
+           }
+
+           flags |= NI_NUMERICHOST;
+        }
+      }
+      
+      // Resolve as a plain numberic
+      if ((flags & NI_NUMERICHOST) == NI_NUMERICHOST)
+      {
+        strncpy(host,inet_ntoa(sin->sin_addr),hostlen);
+      }
+   }
+   
+   if (serv != 0)
+   {
+      // Try to resolve the hostname
+      if ((flags & NI_NUMERICSERV) != NI_NUMERICSERV)
+      {
+        struct servent *Ent;
+        if ((flags & NI_DATAGRAM) == NI_DATAGRAM)
+           Ent = getservbyport(ntohs(sin->sin_port),"udp");
+        else
+           Ent = getservbyport(ntohs(sin->sin_port),"tcp");
+        
+        if (Ent != 0)
+           strncpy(serv,Ent->s_name,servlen);
+        else
+        {
+           if ((flags & NI_NAMEREQD) == NI_NAMEREQD)
+              return EAI_NONAME;
+
+           flags |= NI_NUMERICSERV;
+        }
+      }
+      
+      // Resolve as a plain numberic
+      if ((flags & NI_NUMERICSERV) == NI_NUMERICSERV)
+      {
+        snprintf(serv,servlen,"%u",ntohs(sin->sin_port));
+      }
+   }
+   
+   return 0;
+}
+                                                                       /*}}}*/
+#endif // HAVE_GETNAMEINFO