952
|
1 /*****************************************************************************/
|
|
2 /* socket-connect-getaddrinfo.c - uses getaddrinfo for connections */
|
|
3 /* Copyright (C) 1998-2008 Brian Masney <masneyb@gftp.org> */
|
|
4 /* */
|
|
5 /* This program is free software; you can redistribute it and/or modify */
|
|
6 /* it under the terms of the GNU General Public License as published by */
|
|
7 /* the Free Software Foundation; either version 2 of the License, or */
|
|
8 /* (at your option) any later version. */
|
|
9 /* */
|
|
10 /* This program is distributed in the hope that it will be useful, */
|
|
11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
|
|
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
|
|
13 /* GNU General Public License for more details. */
|
|
14 /* */
|
|
15 /* You should have received a copy of the GNU General Public License */
|
|
16 /* along with this program; if not, write to the Free Software */
|
|
17 /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA */
|
|
18 /*****************************************************************************/
|
|
19
|
|
20 #include "gftp.h"
|
|
21 static const char cvsid[] = "$Id: protocols.c 952 2008-01-24 23:31:26Z masneyb $";
|
|
22
|
|
23 #if defined (HAVE_GETADDRINFO) && defined (HAVE_GAI_STRERROR)
|
|
24
|
|
25 static int
|
|
26 get_port (struct addrinfo *addr)
|
|
27 {
|
|
28 struct sockaddr_in * saddr;
|
|
29 int port;
|
|
30
|
|
31 if (addr->ai_family == AF_INET)
|
|
32 {
|
|
33 saddr = (struct sockaddr_in *) addr->ai_addr;
|
|
34 port = ntohs (saddr->sin_port);
|
|
35 }
|
|
36 else
|
|
37 port = 0;
|
|
38
|
|
39 return (port);
|
|
40 }
|
|
41
|
|
42
|
|
43 struct addrinfo *
|
|
44 lookup_host_with_getaddrinfo (gftp_request *request, char *service,
|
|
45 char *proxy_hostname, int proxy_port)
|
|
46 {
|
|
47 struct addrinfo hints, *hostp;
|
|
48 intptr_t enable_ipv6;
|
|
49 char serv[8], *connect_host;
|
|
50 int ret, connect_port;
|
|
51
|
|
52 if (request->use_proxy)
|
|
53 {
|
|
54 connect_host = proxy_hostname;
|
|
55 connect_port = proxy_port;
|
|
56 }
|
|
57 else
|
|
58 {
|
|
59 connect_host = request->hostname;
|
|
60 connect_port = request->port;
|
|
61 }
|
|
62
|
|
63 gftp_lookup_request_option (request, "enable_ipv6", &enable_ipv6);
|
|
64
|
|
65 memset (&hints, 0, sizeof (hints));
|
|
66 hints.ai_flags = AI_CANONNAME;
|
|
67
|
|
68 hints.ai_family = enable_ipv6 ? PF_UNSPEC : AF_INET;
|
|
69 hints.ai_socktype = SOCK_STREAM;
|
|
70
|
|
71 if (connect_port == 0)
|
|
72 strcpy (serv, service);
|
|
73 else
|
|
74 snprintf (serv, sizeof (serv), "%d", connect_port);
|
|
75
|
|
76 request->logging_function (gftp_logging_misc, request,
|
|
77 _("Looking up %s\n"), connect_host);
|
|
78 if ((ret = getaddrinfo (connect_host, serv, &hints,
|
|
79 &hostp)) != 0)
|
|
80 {
|
|
81 request->logging_function (gftp_logging_error, request,
|
|
82 _("Cannot look up hostname %s: %s\n"),
|
|
83 connect_host, gai_strerror (ret));
|
|
84 return (NULL);
|
|
85 }
|
|
86
|
|
87 return (hostp);
|
|
88 }
|
|
89
|
|
90
|
|
91 int
|
|
92 gftp_connect_server_with_getaddrinfo (gftp_request * request, char *service,
|
|
93 char *proxy_hostname,
|
|
94 unsigned int proxy_port)
|
|
95 {
|
|
96 struct addrinfo *res, *hostp, *current_hostp;
|
|
97 unsigned int port;
|
|
98 int sock = -1;
|
|
99
|
|
100 hostp = lookup_host_with_getaddrinfo (request, service, proxy_hostname,
|
|
101 proxy_port);
|
|
102 if (hostp == NULL)
|
|
103 return (GFTP_ERETRYABLE);
|
|
104
|
|
105 for (res = hostp; res != NULL; res = res->ai_next)
|
|
106 {
|
|
107 port = get_port (res);
|
|
108 if (!request->use_proxy)
|
|
109 request->port = port;
|
|
110
|
|
111 if ((sock = socket (res->ai_family, res->ai_socktype,
|
|
112 res->ai_protocol)) < 0)
|
|
113 {
|
|
114 request->logging_function (gftp_logging_error, request,
|
|
115 _("Failed to create a socket: %s\n"),
|
|
116 g_strerror (errno));
|
|
117 continue;
|
|
118 }
|
|
119
|
|
120 request->logging_function (gftp_logging_misc, request,
|
|
121 _("Trying %s:%d\n"), res[0].ai_canonname,
|
|
122 port);
|
|
123
|
|
124 if (connect (sock, res->ai_addr, res->ai_addrlen) == -1)
|
|
125 {
|
|
126 request->logging_function (gftp_logging_error, request,
|
|
127 _("Cannot connect to %s: %s\n"),
|
|
128 res[0].ai_canonname, g_strerror (errno));
|
|
129 close (sock);
|
|
130 continue;
|
|
131 }
|
|
132
|
|
133 current_hostp = res;
|
|
134 request->ai_family = res->ai_family;
|
|
135 break;
|
|
136 }
|
|
137
|
|
138 if (res == NULL)
|
|
139 {
|
|
140 if (hostp != NULL)
|
|
141 freeaddrinfo (hostp);
|
|
142
|
|
143 return (GFTP_ERETRYABLE);
|
|
144 }
|
|
145
|
|
146 request->remote_addr_len = current_hostp->ai_addrlen;
|
|
147 request->remote_addr = g_malloc0 (request->remote_addr_len);
|
|
148 memcpy (request->remote_addr, &((struct sockaddr_in *) current_hostp->ai_addr)->sin_addr,
|
|
149 request->remote_addr_len);
|
|
150
|
|
151 request->logging_function (gftp_logging_misc, request,
|
|
152 _("Connected to %s:%d\n"), res[0].ai_canonname,
|
|
153 port);
|
|
154
|
|
155 return (sock);
|
|
156 }
|
|
157
|
|
158 #endif
|