Mercurial > gftp.yaz
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 |