comparison lib/socket-connect.c @ 950:c7d7a081cd9c

2008-03-04 Brian Masney <masneyb@gftp.org> * lib/gftp.h lib/socket-connect.c lib/sockutils.c lib/protocols.c lib/Makefile.am lib/charset-conv.c lib/parse-dir-listing.c - split protocols.c into smaller files. No changes were made to the moved functions.
author masneyb
date Tue, 04 Mar 2008 12:28:40 +0000
parents
children a490d94a5b8e
comparison
equal deleted inserted replaced
949:9a6571938f89 950:c7d7a081cd9c
1 /*****************************************************************************/
2 /* socket-connect.c - contains functions for connecting to a server */
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 /* FIXME - clean up this function */
24 static int
25 gftp_need_proxy (gftp_request * request, char *service, char *proxy_hostname,
26 unsigned int proxy_port)
27 {
28 gftp_config_list_vars * proxy_hosts;
29 gftp_proxy_hosts * hostname;
30 size_t hostlen, domlen;
31 unsigned char addy[4];
32 struct sockaddr *addr;
33 GList * templist;
34 gint32 netaddr;
35 char *pos;
36 #if defined (HAVE_GETADDRINFO) && defined (HAVE_GAI_STRERROR)
37 struct addrinfo hints, *hostp;
38 unsigned int port;
39 int errnum;
40 char serv[8];
41 #else
42 struct hostent host, *hostp;
43 #endif
44
45 gftp_lookup_global_option ("dont_use_proxy", &proxy_hosts);
46
47 if (proxy_hostname == NULL || *proxy_hostname == '\0')
48 return (0);
49 else if (proxy_hosts->list == NULL)
50 return (proxy_hostname != NULL &&
51 *proxy_hostname != '\0');
52
53 hostp = NULL;
54 #if defined (HAVE_GETADDRINFO) && defined (HAVE_GAI_STRERROR)
55 memset (&hints, 0, sizeof (hints));
56 hints.ai_flags = AI_CANONNAME;
57 hints.ai_family = PF_UNSPEC;
58 hints.ai_socktype = SOCK_STREAM;
59
60 port = request->use_proxy ? proxy_port : request->port;
61 if (port == 0)
62 strcpy (serv, service);
63 else
64 snprintf (serv, sizeof (serv), "%d", port);
65
66 request->logging_function (gftp_logging_misc, request,
67 _("Looking up %s\n"), request->hostname);
68
69 if ((errnum = getaddrinfo (request->hostname, serv, &hints,
70 &hostp)) != 0)
71 {
72 request->logging_function (gftp_logging_error, request,
73 _("Cannot look up hostname %s: %s\n"),
74 request->hostname, gai_strerror (errnum));
75 return (GFTP_ERETRYABLE);
76 }
77
78 addr = hostp->ai_addr;
79
80 #else /* !HAVE_GETADDRINFO */
81 request->logging_function (gftp_logging_misc, request,
82 _("Looking up %s\n"), request->hostname);
83
84 if (!(hostp = r_gethostbyname (request->hostname, &host, NULL)))
85 {
86 request->logging_function (gftp_logging_error, request,
87 _("Cannot look up hostname %s: %s\n"),
88 request->hostname, g_strerror (errno));
89 return (GFTP_ERETRYABLE);
90 }
91
92 addr = (struct sockaddr *) host.h_addr_list[0];
93
94 #endif /* HAVE_GETADDRINFO */
95
96 templist = proxy_hosts->list;
97 while (templist != NULL)
98 {
99 hostname = templist->data;
100 if (hostname->domain != NULL)
101 {
102 hostlen = strlen (request->hostname);
103 domlen = strlen (hostname->domain);
104 if (hostlen > domlen)
105 {
106 pos = request->hostname + hostlen - domlen;
107 if (strcmp (hostname->domain, pos) == 0)
108 return (0);
109 }
110 }
111
112 if (hostname->ipv4_network_address != 0)
113 {
114 memcpy (addy, addr, sizeof (*addy));
115 netaddr =
116 (((addy[0] & 0xff) << 24) | ((addy[1] & 0xff) << 16) |
117 ((addy[2] & 0xff) << 8) | (addy[3] & 0xff)) &
118 hostname->ipv4_netmask;
119 if (netaddr == hostname->ipv4_network_address)
120 return (0);
121 }
122 templist = templist->next;
123 }
124
125 return (proxy_hostname != NULL && *proxy_hostname != '\0');
126 }
127
128
129 #if defined (HAVE_GETADDRINFO) && defined (HAVE_GAI_STRERROR)
130 static int
131 get_port (struct addrinfo *addr)
132 {
133 struct sockaddr_in * saddr;
134 int port;
135
136 if (addr->ai_family == AF_INET)
137 {
138 saddr = (struct sockaddr_in *) addr->ai_addr;
139 port = ntohs (saddr->sin_port);
140 }
141 else
142 port = 0;
143
144 return (port);
145 }
146
147
148 static int
149 gftp_connect_server_with_getaddr (gftp_request * request, char *service,
150 char *proxy_hostname, unsigned int proxy_port)
151 {
152 struct addrinfo *hostp, *current_hostp;
153 char *connect_host, *disphost;
154 struct addrinfo hints, *res;
155 intptr_t enable_ipv6;
156 unsigned int port;
157 int ret, sock = -1;
158 char serv[8];
159
160 if ((ret = gftp_need_proxy (request, service, proxy_hostname,
161 proxy_port)) < 0)
162 return (ret);
163 else
164 request->use_proxy = ret;
165
166 gftp_lookup_request_option (request, "enable_ipv6", &enable_ipv6);
167
168 memset (&hints, 0, sizeof (hints));
169 hints.ai_flags = AI_CANONNAME;
170
171 hints.ai_family = enable_ipv6 ? PF_UNSPEC : AF_INET;
172 hints.ai_socktype = SOCK_STREAM;
173
174 if (request->use_proxy)
175 {
176 connect_host = proxy_hostname;
177 port = proxy_port;
178 }
179 else
180 {
181 connect_host = request->hostname;
182 port = request->port;
183 }
184
185 if (port == 0)
186 strcpy (serv, service);
187 else
188 snprintf (serv, sizeof (serv), "%d", port);
189
190 request->logging_function (gftp_logging_misc, request,
191 _("Looking up %s\n"), connect_host);
192 if ((ret = getaddrinfo (connect_host, serv, &hints,
193 &hostp)) != 0)
194 {
195 request->logging_function (gftp_logging_error, request,
196 _("Cannot look up hostname %s: %s\n"),
197 connect_host, gai_strerror (ret));
198 return (GFTP_ERETRYABLE);
199 }
200
201 disphost = connect_host;
202 for (res = hostp; res != NULL; res = res->ai_next)
203 {
204 disphost = res->ai_canonname ? res->ai_canonname : connect_host;
205 port = get_port (res);
206 if (!request->use_proxy)
207 request->port = port;
208
209 if ((sock = socket (res->ai_family, res->ai_socktype,
210 res->ai_protocol)) < 0)
211 {
212 request->logging_function (gftp_logging_error, request,
213 _("Failed to create a socket: %s\n"),
214 g_strerror (errno));
215 continue;
216 }
217
218 request->logging_function (gftp_logging_misc, request,
219 _("Trying %s:%d\n"), disphost, port);
220
221 if (connect (sock, res->ai_addr, res->ai_addrlen) == -1)
222 {
223 request->logging_function (gftp_logging_error, request,
224 _("Cannot connect to %s: %s\n"),
225 disphost, g_strerror (errno));
226 close (sock);
227 continue;
228 }
229
230 current_hostp = res;
231 request->ai_family = res->ai_family;
232 break;
233 }
234
235 if (res == NULL)
236 {
237 if (hostp != NULL)
238 freeaddrinfo (hostp);
239
240 return (GFTP_ERETRYABLE);
241 }
242
243 request->remote_addr_len = current_hostp->ai_addrlen;
244 request->remote_addr = g_malloc0 (request->remote_addr_len);
245 memcpy (request->remote_addr, &((struct sockaddr_in *) current_hostp->ai_addr)->sin_addr,
246 request->remote_addr_len);
247
248 request->logging_function (gftp_logging_misc, request,
249 _("Connected to %s:%d\n"), connect_host, port);
250
251 return (sock);
252 }
253 #endif
254
255
256 static int
257 gftp_connect_server_legacy (gftp_request * request, char *service,
258 char *proxy_hostname, unsigned int proxy_port)
259 {
260 struct sockaddr_in remote_address;
261 char *connect_host, *disphost;
262 struct hostent host, *hostp;
263 struct servent serv_struct;
264 int ret, sock, curhost;
265 unsigned int port;
266
267 if ((ret = gftp_need_proxy (request, service, proxy_hostname,
268 proxy_port)) < 0)
269 return (ret);
270
271 request->use_proxy = ret;
272 if (request->use_proxy == 1)
273 hostp = NULL;
274
275 request->ai_family = AF_INET;
276 if ((sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
277 {
278 request->logging_function (gftp_logging_error, request,
279 _("Failed to create a IPv4 socket: %s\n"),
280 g_strerror (errno));
281 return (GFTP_ERETRYABLE);
282 }
283
284 memset (&remote_address, 0, sizeof (remote_address));
285 remote_address.sin_family = AF_INET;
286
287 if (request->use_proxy)
288 {
289 connect_host = proxy_hostname;
290 port = proxy_port;
291 }
292 else
293 {
294 connect_host = request->hostname;
295 port = request->port;
296 }
297
298 if (port == 0)
299 {
300 if (!r_getservbyname (service, "tcp", &serv_struct, NULL))
301 {
302 request->logging_function (gftp_logging_error, request,
303 _("Cannot look up service name %s/tcp. Please check your services file\n"),
304 service);
305 close (sock);
306 return (GFTP_EFATAL);
307 }
308
309 port = ntohs (serv_struct.s_port);
310
311 if (!request->use_proxy)
312 request->port = port;
313 }
314
315 remote_address.sin_port = htons (port);
316
317 request->logging_function (gftp_logging_misc, request,
318 _("Looking up %s\n"), connect_host);
319
320 if (!(hostp = r_gethostbyname (connect_host, &host, NULL)))
321 {
322 request->logging_function (gftp_logging_error, request,
323 _("Cannot look up hostname %s: %s\n"),
324 connect_host, g_strerror (errno));
325 close (sock);
326 return (GFTP_ERETRYABLE);
327 }
328
329 disphost = NULL;
330 for (curhost = 0;
331 host.h_addr_list[curhost] != NULL;
332 curhost++)
333 {
334 disphost = host.h_name;
335 memcpy (&remote_address.sin_addr,
336 host.h_addr_list[curhost],
337 host.h_length);
338 request->logging_function (gftp_logging_misc, request,
339 _("Trying %s:%d\n"),
340 host.h_name, port);
341
342 if (connect (sock, (struct sockaddr *) &remote_address,
343 sizeof (remote_address)) == -1)
344 {
345 request->logging_function (gftp_logging_error, request,
346 _("Cannot connect to %s: %s\n"),
347 connect_host, g_strerror (errno));
348 }
349 break;
350 }
351
352 if (host.h_addr_list[curhost] == NULL)
353 {
354 close (sock);
355 return (GFTP_ERETRYABLE);
356 }
357
358 return (sock);
359 }
360
361
362 int
363 gftp_connect_server (gftp_request * request, char *service,
364 char *proxy_hostname, unsigned int proxy_port)
365 {
366 int sock;
367
368 #if defined (HAVE_GETADDRINFO) && defined (HAVE_GAI_STRERROR)
369 sock = gftp_connect_server_with_getaddr (request, service, proxy_hostname,
370 proxy_port);
371 #else
372 sock = gftp_connect_server_legacy (request, service, proxy_hostname,
373 proxy_port);
374 #endif
375
376 if (sock < 0)
377 return (sock);
378
379 if (fcntl (sock, F_SETFD, 1) == -1)
380 {
381 request->logging_function (gftp_logging_error, request,
382 _("Error: Cannot set close on exec flag: %s\n"),
383 g_strerror (errno));
384 close (sock);
385 return (GFTP_ERETRYABLE);
386 }
387
388 if (gftp_fd_set_sockblocking (request, sock, 1) < 0)
389 {
390 close (sock);
391 return (GFTP_ERETRYABLE);
392 }
393
394 request->datafd = sock;
395
396 if (request->post_connect != NULL)
397 return (request->post_connect (request));
398
399 return (0);
400 }
401