/[axel]/branches/3.x-broken/src/conn.c
ViewVC logotype

Contents of /branches/3.x-broken/src/conn.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 79 - (show annotations) (download)
Tue Dec 30 20:13:35 2008 UTC (4 years, 4 months ago) by phihag-guest
File MIME type: text/plain
File size: 9203 byte(s)
Move some stuff around to modularize
1 /********************************************************************\
2 * Axel -- A lighter download accelerator for Linux and other Unices. *
3 * *
4 * Copyright 2001 Wilmer van der Gaast *
5 \********************************************************************/
6
7 /* Connection stuff */
8
9 /*
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License with
21 the Debian GNU/Linux distribution in file /usr/doc/copyright/GPL;
22 if not, write to the Free Software Foundation, Inc., 59 Temple Place,
23 Suite 330, Boston, MA 02111-1307 USA
24 */
25
26 #include "axel.h"
27
28 static void conn_start_threadstart(void* conn);
29
30 void conn_init(conn_t *c, const url_t* url, const axel_t* axel, AXEL_SIZE startbyte, AXEL_SIZE endbyte) {
31 c->axel = axel;
32 c->url = url;
33
34 proto_init(c->proto, url->protoid);
35 c->currentbyte = startbyte;
36 c->endbyte = endbyte;
37 c->cstate = INITIALIZED;
38 }
39
40 // Entry point for a created thread
41 void conn_threadstart(void* conn_void) {
42 int oldstate; // Dummy
43
44 if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate) != 0) ||
45 (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate) != 0)) {
46
47 conn->message = safe_strdup("Thread initialization failed");
48 conn->cstate = ERROR;
49 return;
50 }
51
52 conn_readheaders((conn_t*) conn_void);
53 }
54
55 // Reads all headers, blocks until read. cstate is guaranteed to be either DOWNLOADING or FINISHED afterwards.
56 void conn_readheaders(conn_t* conn);
57 // Read up to bufsize bytes from this connection into buf. Segmantics are same as for the POSIX read() call.
58 ssize_t conn_read(conn_t* conn, char* buf, size_t bufsize);
59 void conn_destroy(conn_t* conn);
60
61
62
63 /* Convert an URL to a conn_t structure */
64 int conn_set( conn_t *conn, char *set_url )
65 {
66 char url[MAX_STRING];
67 char *i, *j;
68
69 /* protocol:// */
70 if( ( i = strstr( set_url, "://" ) ) == NULL )
71 {
72 conn->proto = PROTO_DEFAULT;
73 strncpy( url, set_url, MAX_STRING );
74 }
75 else
76 {
77 if( set_url[0] == 'f' )
78 conn->proto = PROTO_FTP;
79 else if( set_url[0] == 'h' )
80 conn->proto = PROTO_HTTP;
81 else
82 {
83 return( 0 );
84 }
85 strncpy( url, i + 3, MAX_STRING );
86 }
87
88 /* Split */
89 if( ( i = strchr( url, '/' ) ) == NULL )
90 {
91 strcpy( conn->dir, "/" );
92 }
93 else
94 {
95 *i = 0;
96 snprintf( conn->dir, MAX_STRING, "/%s", i + 1 );
97 if( conn->proto == PROTO_HTTP ) {
98 http_encode( conn->dir );
99 }
100 }
101 strncpy( conn->host, url, MAX_STRING );
102 j = strchr( conn->dir, '?' );
103 if( j != NULL )
104 *j = 0;
105 i = strrchr( conn->dir, '/' );
106 *i = 0;
107 if( j != NULL )
108 *j = '?';
109 if( i == NULL )
110 {
111 strncpy( conn->file, conn->dir, MAX_STRING );
112 strcpy( conn->dir, "/" );
113 }
114 else
115 {
116 strncpy( conn->file, i + 1, MAX_STRING );
117 strcat( conn->dir, "/" );
118 }
119
120 /* Check for username in host field */
121 if( strrchr( conn->host, '@' ) != NULL )
122 {
123 strncpy( conn->user, conn->host, MAX_STRING );
124 i = strrchr( conn->user, '@' );
125 *i = 0;
126 strncpy( conn->host, i + 1, MAX_STRING );
127 *conn->pass = 0;
128 }
129 /* If not: Fill in defaults */
130 else
131 {
132 if( PROTO_MAIN(conn->proto) == PROTO_FTP )
133 {
134 /* Dash the password: Save traffic by trying
135 to avoid multi-line responses */
136 strcpy( conn->user, "anonymous" );
137 strcpy( conn->pass, "mailto:axel-devel@lists.alioth.debian.org" );
138 }
139 else
140 {
141 *conn->user = 0;
142 *conn->pass = 0;
143 }
144 }
145
146 /* Password? */
147 if( ( i = strchr( conn->user, ':' ) ) != NULL )
148 {
149 *i = 0;
150 strncpy( conn->pass, i + 1, MAX_STRING );
151 }
152 /* Port number? */
153 if( ( i = strchr( conn->host, ':' ) ) != NULL )
154 {
155 *i = 0;
156 sscanf( i + 1, "%i", &conn->port );
157 }
158 else
159 {
160 conn->port = proto_defport(conn->proto);
161 }
162
163 return( conn->port > 0 );
164 }
165
166
167 /* Simple... */
168 void conn_disconnect( conn_t *conn )
169 {
170 if( conn->proto == PROTO_FTP && !conn->proxy )
171 ftp_disconnect( conn->ftp );
172 else
173 http_disconnect( conn->http );
174 conn->fd = -1;
175 }
176
177 int conn_init( conn_t *conn )
178 {
179 char *proxy = conn->conf->http_proxy, *host = conn->conf->no_proxy;
180 int i;
181
182 if( *conn->conf->http_proxy == 0 )
183 {
184 proxy = NULL;
185 }
186 else if( *conn->conf->no_proxy != 0 )
187 {
188 for( i = 0; ; i ++ )
189 if( conn->conf->no_proxy[i] == 0 )
190 {
191 if( strstr( conn->host, host ) != NULL )
192 proxy = NULL;
193 host = &conn->conf->no_proxy[i+1];
194 if( conn->conf->no_proxy[i+1] == 0 )
195 break;
196 }
197 }
198
199 conn->proxy = proxy != NULL;
200
201 if( conn->proto == PROTO_FTP && !conn->proxy )
202 {
203 conn->ftp->local_if = conn->local_if;
204 conn->ftp->ftp_mode = FTP_PASSIVE;
205 if( !ftp_connect( conn->ftp, conn->host, conn->port, conn->user, conn->pass ) )
206 {
207 conn->message = conn->ftp->message;
208 conn_disconnect( conn );
209 return( 0 );
210 }
211 conn->message = conn->ftp->message;
212 if( !ftp_cwd( conn->ftp, conn->dir ) )
213 {
214 conn_disconnect( conn );
215 return( 0 );
216 }
217 }
218 else
219 {
220 conn->http->local_if = conn->local_if;
221 if( !http_connect( conn->http, conn->proto, proxy, conn->host, conn->port, conn->user, conn->pass ) )
222 {
223 conn->message = conn->http->headers;
224 conn_disconnect( conn );
225 return( 0 );
226 }
227 conn->message = conn->http->headers;
228 conn->fd = conn->http->fd;
229 }
230 return( 1 );
231 }
232
233 int conn_setup( conn_t *conn )
234 {
235 if( conn->ftp->fd <= 0 && conn->http->fd <= 0 )
236 if( !conn_init( conn ) )
237 return( 0 );
238
239 if( conn->proto == PROTO_FTP && !conn->proxy )
240 {
241 if( !ftp_data( conn->ftp ) ) /* Set up data connnection */
242 return( 0 );
243 conn->fd = conn->ftp->data_fd;
244
245 if( conn->currentbyte )
246 {
247 ftp_command( conn->ftp, "REST %lld", conn->currentbyte );
248 if( ftp_wait( conn->ftp ) / 100 != 3 &&
249 conn->ftp->status / 100 != 2 )
250 return( 0 );
251 }
252 }
253 else
254 {
255 char s[MAX_STRING];
256 int i;
257
258 snprintf( s, MAX_STRING, "%s%s", conn->dir, conn->file );
259 conn->http->firstbyte = conn->currentbyte;
260 conn->http->lastbyte = conn->lastbyte;
261 http_get( conn->http, s );
262 http_addheader( conn->http, "User-Agent: %s", conn->conf->user_agent );
263 for( i = 0; i < conn->conf->add_header_count; i++)
264 http_addheader( conn->http, "%s", conn->conf->add_header[i] );
265 }
266 return( 1 );
267 }
268
269 int conn_exec( conn_t *conn )
270 {
271 if( conn->proto == PROTO_FTP && !conn->proxy )
272 {
273 if( !ftp_command( conn->ftp, "RETR %s", conn->file ) )
274 return( 0 );
275 return( ftp_wait( conn->ftp ) / 100 == 1 );
276 }
277 else
278 {
279 if( !http_exec( conn->http ) )
280 return( 0 );
281 return( conn->http->status / 100 == 2 );
282 }
283 }
284
285 /* Get file size and other information */
286 int conn_info( conn_t *conn )
287 {
288 /* It's all a bit messed up.. But it works. */
289 if( conn->proto == PROTO_FTP && !conn->proxy )
290 {
291 ftp_command( conn->ftp, "REST %lld", 1 );
292 if( ftp_wait( conn->ftp ) / 100 == 3 ||
293 conn->ftp->status / 100 == 2 )
294 {
295 conn->supported = 1;
296 ftp_command( conn->ftp, "REST %lld", 0 );
297 ftp_wait( conn->ftp );
298 }
299 else
300 {
301 conn->supported = 0;
302 }
303
304 if( !ftp_cwd( conn->ftp, conn->dir ) ) {
305 return( 0 );
306 }
307 conn->size = ftp_size( conn->ftp, conn->file, MAX_REDIR );
308 if( conn->size < 0 )
309 conn->supported = 0;
310 if( conn->size == -1 ) {
311 return( 0 );
312 }
313 else if( conn->size == -2 )
314 conn->size = INT_MAX;
315 }
316 else
317 {
318 char s[MAX_STRING], *t;
319 long long int i = 0;
320
321 do
322 {
323 conn->currentbyte = 1;
324 if( !conn_setup( conn ) )
325 return( 0 );
326 conn_exec( conn );
327 conn_disconnect( conn );
328 /* Code 3xx == redirect */
329 if( conn->http->status / 100 != 3 )
330 break;
331 if( ( t = http_header( conn->http, "location:" ) ) == NULL )
332 {
333 sprintf( conn->message, _("No location header in HTTP response"));
334 return( 0 );
335 }
336
337 sscanf( t, "%255s", s );
338 if( strstr( s, "://" ) == NULL)
339 {
340 sprintf( conn->http->headers, "%s%s",
341 conn_url( conn ), s );
342 strncpy( s, conn->http->headers, MAX_STRING );
343 }
344 else if( s[0] == '/' )
345 {
346 sprintf( conn->http->headers, "http://%s:%i%s",
347 conn->host, conn->port, s );
348 strncpy( s, conn->http->headers, MAX_STRING );
349 }
350
351 #ifdef DEBUG
352 fprintf( stderr, "Redirecting to %s\n", s );
353 #endif
354
355 conn_set( conn, s );
356 i ++;
357 }
358 while( conn->http->status / 100 == 3 && i < MAX_REDIR );
359
360 if( i == MAX_REDIR )
361 {
362 sprintf( conn->message, _("Too many redirects.\n") );
363 return( 0 );
364 }
365
366 conn->size = http_size( conn->http );
367 if( conn->http->status == 206 && conn->size >= 0 )
368 {
369 conn->supported = 1;
370 conn->size ++;
371 }
372 else if( conn->http->status == 200 || conn->http->status == 206 )
373 {
374 conn->supported = 0;
375 conn->size = INT_MAX;
376 }
377 else
378 {
379 t = strchr( conn->message, '\n' );
380 if( t == NULL ) {
381 sprintf( conn->message, _("Unknown HTTP error.\n") );
382 } else {
383 *t = 0;
384 }
385
386 return( 0 );
387 }
388 }
389
390 return( 1 );
391 }

  ViewVC Help
Powered by ViewVC 1.1.5