123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 |
- // -*- mode: cpp; mode: fold -*-
- // Description /*{{{*/
- // $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 <config.h>
- #include <stdlib.h>
- #include <arpa/inet.h>
- #include <netinet/in.h>
- #include <string.h>
- #include <stdio.h>
- #include "rfc2553emu.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 = res;
- hostent *Addr;
- unsigned int Port;
- int Proto;
- const char *End;
- char **CurAddr;
-
- // Try to convert the service as a number
- Port = htons(strtol(servname,(char **)&End,0));
- Proto = SOCK_STREAM;
-
- if (hints != 0 && hints->ai_socktype != 0)
- Proto = hints->ai_socktype;
-
- // Not a number, must be a name.
- if (End != servname + strlen(servname))
- {
- struct servent *Srv = 0;
-
- // Do a lookup in the service database
- if (hints == 0 || hints->ai_socktype == SOCK_STREAM)
- Srv = getservbyname(servname,"tcp");
- if (hints != 0 && hints->ai_socktype == SOCK_DGRAM)
- Srv = getservbyname(servname,"udp");
- if (Srv == 0)
- return EAI_NONAME;
-
- // Get the right protocol
- Port = Srv->s_port;
- if (strcmp(Srv->s_proto,"tcp") == 0)
- Proto = SOCK_STREAM;
- else
- {
- if (strcmp(Srv->s_proto,"udp") == 0)
- Proto = SOCK_DGRAM;
- else
- return EAI_NONAME;
- }
-
- if (hints != 0 && hints->ai_socktype != Proto &&
- 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 != 0; CurAddr++)
- {
- // New result structure
- *Result = (struct addrinfo *)calloc(sizeof(**Result),1);
- if (*Result == 0)
- {
- freeaddrinfo(*res);
- return EAI_MEMORY;
- }
- if (*res == 0)
- *res = *Result;
-
- (*Result)->ai_family = AF_INET;
- (*Result)->ai_socktype = Proto;
- // If we have the IPPROTO defines we can set the protocol field
- #ifdef IPPROTO_TCP
- if (Proto == SOCK_STREAM)
- (*Result)->ai_protocol = IPPROTO_TCP;
- if (Proto == SOCK_DGRAM)
- (*Result)->ai_protocol = IPPROTO_UDP;
- #endif
- // Allocate space for the address
- (*Result)->ai_addrlen = sizeof(struct sockaddr_in);
- (*Result)->ai_addr = (struct sockaddr *)calloc(sizeof(sockaddr_in),1);
- if ((*Result)->ai_addr == 0)
- {
- freeaddrinfo(*res);
- return EAI_MEMORY;
- }
-
- // Set the address
- ((struct sockaddr_in *)(*Result)->ai_addr)->sin_family = AF_INET;
- ((struct sockaddr_in *)(*Result)->ai_addr)->sin_port = Port;
-
- 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)
- {
- while (ai != 0)
- {
- free(ai->ai_addr);
- ai = ai->ai_next;
- 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
|