Importing starttls 0.4+.
[elisp/starttls.git] / getaddrinfo.c
1 /*
2  * getaddrinfo(2) emulation.
3  * Copyright (C) 1988, 1989, 1992, 1993 Free Software Foundation, Inc.
4
5  * Author: Daiki Ueno <daiki@kiss.kake.info.waseda.ac.jp>
6
7 This file is not part of any package.
8
9 GNU Emacs is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
13
14 GNU Emacs is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with GNU Emacs; see the file COPYING.  If not, write to
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA.
23  */
24
25 #ifndef HAVE_GETADDRINFO
26
27 #include <stdlib.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <netdb.h>
31 #include <netinet/in.h>
32
33 #ifdef HAVE_NETINET6_IN6_H
34 # include <netinet6/in6.h>
35 #endif /* HAVE_NETINET6_IN6_H */
36
37 #include "getaddrinfo.h"
38
39 int getaddrinfo (hostname, servname, hints, res)
40   const char *hostname;
41   const char *servname;
42   const struct addrinfo *hints;
43   struct addrinfo **res;
44 {
45   struct hostent *host = NULL;
46   struct servent *serv = NULL;
47   struct protoent *proto;
48   int port = 0;
49
50 #if (defined (HAVE_SOCKADDR_IN6) && defined (INET6))
51   struct sockaddr_in6 *sin =
52     (struct sockaddr_in6 *) calloc (1, sizeof (struct sockaddr_in6));
53 #else /* (defined (HAVE_SOCKADDR_IN6) && defined (INET6)) */
54   struct sockaddr_in *sin =
55     (struct sockaddr_in *) calloc (1, sizeof (struct sockaddr_in));
56 #endif /* !(defined (HAVE_SOCKADDR_IN6) && defined (INET6)) */
57
58   struct addrinfo *ai = *res = 
59     (struct addrinfo *) calloc (1, sizeof (struct addrinfo));
60   
61   if ((~ hints->ai_flags & AI_PASSIVE) && hostname && 
62       (host = gethostbyname (hostname)) == NULL) {
63     perror ("gethostbyname");
64     return EAI_NONAME;
65   }
66
67   if (hints->ai_protocol && 
68       (proto = getprotobynumber (hints->ai_protocol)) == NULL) {
69     perror ("getprotobynumber");
70     return EAI_NONAME;
71   }
72
73   if (servname) 
74     if (isdigit (servname[0]))
75       port = atoi (servname);
76     else {
77       if ((serv = getservbyname (servname, proto->p_name)) == NULL) {
78         perror ("getservbyname");
79         return EAI_NONAME;
80       }
81       port = serv->s_port;
82     }
83   
84 #if (defined (HAVE_SOCKADDR_IN6) && defined (INET6))
85   if (host)
86     memcpy (&sin->sin6_addr, host->h_addr, host->h_length);
87   sin->sin6_port = htons (port);
88 #else /* (defined (HAVE_SOCKADDR_IN6) && defined (INET6)) */
89   if (host)
90     memcpy (&sin->sin_addr, host->h_addr, host->h_length);
91   sin->sin_port = htons (port);
92 #endif /* !(defined (HAVE_SOCKADDR_IN6) && defined (INET6)) */
93
94   if (hints->ai_family == AF_UNSPEC)
95     ai->ai_family = host->h_addrtype;
96   else
97     ai->ai_family = hints->ai_family;
98 #if (defined (HAVE_SOCKADDR_IN6) && defined (INET6))
99   sin->sin6_family = ai->ai_family;
100 #else /* (defined (HAVE_SOCKADDR_IN6) && defined (INET6)) */
101   sin->sin_family = ai->ai_family;
102 #endif /* !(defined (HAVE_SOCKADDR_IN6) && defined (INET6)) */
103
104   ai->ai_protocol = hints->ai_protocol;
105   ai->ai_socktype = hints->ai_socktype;
106   ai->ai_addrlen = sizeof (*sin);
107   ai->ai_addr = (struct sockaddr *)sin;
108
109   return 0;
110 }
111
112 void freeaddrinfo (ai)
113      struct addrinfo *ai;
114 {
115   struct addrinfo *p;
116
117   while (ai != NULL) {
118     p = ai;
119     ai = ai->ai_next;
120     free (p);
121   }
122 }
123
124 #endif /* HAVE_GETADDRINFO */