axel.c 22.2 KB
Newer Older
1 2
/*
  Axel -- A lighter download accelerator for Linux and other Unices
3

4 5 6
  Copyright 2001-2007 Wilmer van der Gaast
  Copyright 2007-2009 Y Giridhar Appaji Nag
  Copyright 2008-2009 Philipp Hagemeister
7
  Copyright 2015-2017 Joao Eriberto Mota Filho
8
  Copyright 2016      Denis Denisov
9
  Copyright 2016      Ivan Gimenez
10 11
  Copyright 2016      Sjjad Hashemian
  Copyright 2016      Stephen Thirlwall
12
  Copyright 2017      Antonio Quartulli
13 14
  Copyright 2017      Ismael Luceno
  Copyright 2017      nemermollon
15

16 17 18 19
  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 2
  of the License, or (at your option) any later version.
20

21 22 23 24 25 26 27 28 29 30 31 32 33 34
  In addition, as a special exception, the copyright holders give
  permission to link the code of portions of this program with the
  OpenSSL library under certain conditions as described in each
  individual source file, and distribute linked combinations including
  the two.

  You must obey the GNU General Public License in all respects for all
  of the code used other than OpenSSL. If you modify file(s) with this
  exception, you may extend this exception to your version of the
  file(s), but you are not obligated to do so. If you do not wish to do
  so, delete this exception statement from your version. If you delete
  this exception statement from all source files in the program, then
  also delete it here.

35 36 37 38 39
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

40 41 42
  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
43 44
*/

45 46
/* Main control */

47
#include "axel.h"
48
#include "assert.h"
49 50 51 52 53 54 55 56 57

/* Axel */
static void save_state( axel_t *axel );
static void *setup_thread( void * );
static void axel_message( axel_t *axel, char *format, ... );
static void axel_divide( axel_t *axel );

static char *buffer = NULL;

58
/* Create a new axel_t structure */
59
axel_t *axel_new( conf_t *conf, int count, const void *url )
60
{
61
	const search_t *res;
62
	axel_t *axel;
63 64
	int status;
	long delay;
65 66 67
	url_t *u;
	char *s;
	int i;
68

69
	axel = malloc( sizeof( axel_t ) );
70 71 72
	if( !axel )
		goto nomem;

73
	memset( axel, 0, sizeof( axel_t ) );
74
	axel->conf = conf;
75
	axel->conn = malloc( sizeof( conn_t ) * axel->conf->num_connections );
76 77
	if( !axel->conn )
		goto nomem;
78
	memset( axel->conn, 0, sizeof( conn_t ) * axel->conf->num_connections );
79 80 81 82

	for( i = 0; i < axel->conf->num_connections; i ++ )
		pthread_mutex_init( &axel->conn[i].lock, NULL );

83 84 85 86 87 88 89 90
	if( axel->conf->max_speed > 0 )
	{
		if( (float) axel->conf->max_speed / axel->conf->buffer_size < 0.5 )
		{
			if( axel->conf->verbose >= 2 )
				axel_message( axel, _("Buffer resized for this speed.") );
			axel->conf->buffer_size = axel->conf->max_speed;
		}
91 92 93 94 95 96
		delay = (int) ( (float) 1000000000 / axel->conf->max_speed *
				axel->conf->buffer_size *
				axel->conf->num_connections );

		axel->delay_time.tv_sec = delay / 1000000000;
		axel->delay_time.tv_nsec = delay % 1000000000;
97 98
	}
	if( buffer == NULL )
99
	{
100 101
		/* reserve 4 additional bytes for file extension ".st" */
		buffer = malloc( max( MAX_STRING + 4, axel->conf->buffer_size ) );
102 103 104 105 106 107 108 109 110 111
		if( !buffer )
			goto nomem;
	}

	if( !url )
	{
		axel_message( axel, _("Invalid URL") );
		axel_close( axel );
		return( NULL );
	}
112

113 114 115
	if( count == 0 )
	{
		axel->url = malloc( sizeof( url_t ) );
116 117 118
		if( !axel->url )
			goto nomem;

119
		axel->url->next = axel->url;
120
		strncpy( axel->url->text, url, MAX_STRING );
121 122 123
	}
	else
	{
124 125 126 127 128 129
		res = url;
		u = malloc( sizeof( url_t ) * count );
		if( !u )
			goto nomem;
		axel->url = u;

130 131
		for( i = 0; i < count; i ++ )
		{
132 133
			strncpy( u[i].text, res[i].url, MAX_STRING );
			u[i].next = &u[i + 1];
134
		}
135
		u[count - 1].next = u;
136
	}
137

138 139 140 141 142 143 144 145 146 147
	axel->conn[0].conf = axel->conf;
	if( !conn_set( &axel->conn[0], axel->url->text ) )
	{
		axel_message( axel, _("Could not parse URL.\n") );
		axel->ready = -1;
		return( axel );
	}

	axel->conn[0].local_if = axel->conf->interfaces->text;
	axel->conf->interfaces = axel->conf->interfaces->next;
148

149
	strncpy( axel->filename, axel->conn[0].file, MAX_STRING );
150
	http_decode( axel->filename );
151
	if( *axel->filename == 0 )	/* Index page == no fn */
152
		strncpy( axel->filename, axel->conf->default_filename, MAX_STRING );
153
	if( ( s = strchr( axel->filename, '?' ) ) != NULL && axel->conf->strip_cgi_parameters )
154 155
		*s = 0;		/* Get rid of CGI parameters */

156
	if( axel->conf->no_clobber && access( axel->filename, F_OK ) == 0 )
157
	{
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
		char stfile[MAX_STRING + 3];

		sprintf( stfile, "%s.st", axel->filename );
		if( access( stfile, F_OK ) == 0 )
		{
			printf( _("Incomplete download found, ignoring "
				  "no-clobber option\n") );
		}
		else
		{
			printf( _("File '%s' already there; not retrieving.\n"),
				axel->filename );
			axel->ready = -1;
			return( axel );
		}
173
	}
174

175
	do
176
	{
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
		if( !conn_init( &axel->conn[0] ) )
		{
			axel_message( axel, axel->conn[0].message );
			axel->ready = -1;
			return( axel );
		}

		/* This does more than just checking the file size, it all
		 * depends on the protocol used. */
		status = conn_info( &axel->conn[0] );
		if( !status )
		{
			axel_message( axel, axel->conn[0].message );
			axel->ready = -1;
			return( axel );
		}
193
	}
194 195 196 197
	/* re-init in case of protocol change. This can happen only once
	 * because the FTP protocol can't redirect back to HTTP */
	while( status == -1 );

198
	s = conn_url( axel->conn );
199
	strncpy( axel->url->text, s, MAX_STRING );
200
	if( ( axel->size = axel->conn[0].size ) != LLONG_MAX )
201 202
	{
		if( axel->conf->verbose > 0 )
203
			axel_message( axel, _("File size: %lld bytes"), axel->size );
204
	}
205 206

	/* Wildcards in URL --> Get complete filename */
207
	if( strchr( axel->filename, '*' ) || strchr( axel->filename, '?' ) )
208
		strncpy( axel->filename, axel->conn[0].file, MAX_STRING );
209

210 211 212 213
	if( *axel->conn[0].output_filename != 0 ) {
		strncpy( axel->filename, axel->conn[0].output_filename, MAX_STRING );
	}

214
	return( axel );
215 216 217 218
nomem:
	axel_close( axel );
	printf( "%s\n", strerror(errno) );
	return( NULL );
219 220
}

221
/* Open a local file to store the downloaded data */
222 223 224
int axel_open( axel_t *axel )
{
	int i, fd;
225 226
 	ssize_t nread;

227 228
	if( axel->conf->verbose > 0 )
		axel_message( axel, _("Opening output file %s"), axel->filename );
229
	snprintf( buffer, MAX_STRING + 4, "%s.st", axel->filename );
230

231
	axel->outfd = -1;
232

233
	/* Check whether server knows about RESTart and switch back to
234
	   single connection download if necessary */
235 236 237 238 239 240 241 242 243 244
	if( !axel->conn[0].supported )
	{
		axel_message( axel, _("Server unsupported, "
			"starting from scratch with one connection.") );
		axel->conf->num_connections = 1;
		axel->conn = realloc( axel->conn, sizeof( conn_t ) );
		axel_divide( axel );
	}
	else if( ( fd = open( buffer, O_RDONLY ) ) != -1 )
	{
245 246 247 248
		int old_format = 0;
		off_t stsize = lseek(fd,0,SEEK_END);
		lseek(fd,0,SEEK_SET);

249
		nread = read( fd, &axel->conf->num_connections, sizeof( axel->conf->num_connections ) );
250 251 252 253 254 255 256
		if( nread != sizeof( axel->conf->num_connections ) )
		{
			printf( _("%s.st: Error, truncated state file\n"),
				axel->filename );
			close( fd );
			return( 0 );
		}
257

258 259 260
		if(stsize < sizeof( axel->conf->num_connections ) + sizeof( axel->bytes_done )
			+ 2 * axel->conf->num_connections * sizeof( axel->conn[i].currentbyte ))
		{
261 262
			/* FIXME this might be wrong, the file may have been
			 * truncated, we need another way to check. */
263
#ifdef DEBUG
264
			printf( _("State file has old format.\n") );
265 266 267 268
#endif
			old_format = 1;
		}

269 270 271
		axel->conn = realloc( axel->conn, sizeof( conn_t ) * axel->conf->num_connections );
		memset( axel->conn + 1, 0, sizeof( conn_t ) * ( axel->conf->num_connections - 1 ) );

272 273
		if(old_format)
			axel_divide( axel );
274 275 276 277 278 279

		nread = read( fd, &axel->bytes_done, sizeof( axel->bytes_done ) );
		assert( nread == sizeof( axel->bytes_done ) );
		for( i = 0; i < axel->conf->num_connections; i ++ ) {
			nread = read( fd, &axel->conn[i].currentbyte, sizeof( axel->conn[i].currentbyte ) );
			assert( nread == sizeof( axel->conn[i].currentbyte ) );
280 281 282 283
			if( !old_format ) {
				nread = read( fd, &axel->conn[i].lastbyte, sizeof( axel->conn[i].lastbyte ) );
				assert( nread == sizeof( axel->conn[i].lastbyte ) );
			}
284
		}
285

286
		axel_message( axel, _("State file found: %lld bytes downloaded, %lld to go."),
287
			axel->bytes_done, axel->size - axel->bytes_done );
288

289
		close( fd );
290

291 292 293 294 295 296 297
		if( ( axel->outfd = open( axel->filename, O_WRONLY, 0666 ) ) == -1 )
		{
			axel_message( axel, _("Error opening local file") );
			return( 0 );
		}
	}

298
	/* If outfd == -1 we have to start from scrath now */
299 300 301
	if( axel->outfd == -1 )
	{
		axel_divide( axel );
302

303 304 305 306 307
		if( ( axel->outfd = open( axel->filename, O_CREAT | O_WRONLY, 0666 ) ) == -1 )
		{
			axel_message( axel, _("Error opening local file") );
			return( 0 );
		}
308

309 310
		/* And check whether the filesystem can handle seeks to
		   past-EOF areas.. Speeds things up. :) AFAIK this
311
		   should just not happen: */
312 313 314 315
		if( lseek( axel->outfd, axel->size, SEEK_SET ) == -1 && axel->conf->num_connections > 1 )
		{
			/* But if the OS/fs does not allow to seek behind
			   EOF, we have to fill the file with zeroes before
316
			   starting. Slow.. */
317 318 319
			axel_message( axel, _("Crappy filesystem/OS.. Working around. :-(") );
			lseek( axel->outfd, 0, SEEK_SET );
			memset( buffer, 0, axel->conf->buffer_size );
320
			long long int j = axel->size;
321
			while( j > 0 ) {
322 323
				ssize_t nwrite;

324 325 326 327 328 329
				if( ( nwrite = write( axel->outfd, buffer, min( j, axel->conf->buffer_size ) ) ) < 0 ) {
					if ( errno == EINTR || errno == EAGAIN) continue;
					axel_message( axel, _("Error creating local file") );
					return( 0 );
				}
				j -= nwrite;
330 331 332
			}
		}
	}
333

334 335 336
	return( 1 );
}

337 338
void reactivate_connection(axel_t *axel, int thread)
{
339 340
	long long int max_remaining = 0;
	int idx = -1;
341 342 343 344

	if(axel->conn[thread].enabled || axel->conn[thread].currentbyte <= axel->conn[thread].lastbyte)
		return;
	/* find some more work to do */
345
	for( int j = 0; j < axel->conf->num_connections; j ++ )
346
	{
347
		long long int remaining = axel->conn[j].lastbyte - axel->conn[j].currentbyte + 1;
348 349 350 351 352 353 354 355 356 357
		if(remaining > max_remaining)
		{
			max_remaining = remaining;
			idx = j;
		}
	}
	/* do not reactivate for less than 100KB */
	if(max_remaining >= 100 * 1024 && idx != -1)
	{
#ifdef DEBUG
358
		printf( _("\nReactivate connection %d\n"),thread);
359 360 361 362 363 364 365
#endif
		axel->conn[thread].lastbyte = axel->conn[idx].lastbyte;
		axel->conn[idx].lastbyte = axel->conn[idx].currentbyte + max_remaining/2;
		axel->conn[thread].currentbyte = axel->conn[idx].lastbyte + 1;
	}
}

366
/* Start downloading */
367 368 369
void axel_start( axel_t *axel )
{
	int i;
370
	url_t *url_ptr;
371

372
	/* HTTP might've redirected and FTP handles wildcards, so
373
	   re-scan the URL for every conn */
374
	url_ptr = axel->url;
375 376
	for( i = 0; i < axel->conf->num_connections; i ++ )
	{
377 378
		conn_set( &axel->conn[i], url_ptr->text );
		url_ptr = url_ptr->next;
379 380 381
		axel->conn[i].local_if = axel->conf->interfaces->text;
		axel->conf->interfaces = axel->conf->interfaces->next;
		axel->conn[i].conf = axel->conf;
382
		if( i ) axel->conn[i].supported = true;
383
	}
384

385 386
	if( axel->conf->verbose > 0 )
		axel_message( axel, _("Starting download") );
387

388 389 390 391 392 393
	for( i = 0; i < axel->conf->num_connections; i ++ )
	if( axel->conn[i].currentbyte > axel->conn[i].lastbyte )
	{
		reactivate_connection(axel, i);
	}

394 395 396 397
	for( i = 0; i < axel->conf->num_connections; i ++ )
	if( axel->conn[i].currentbyte <= axel->conn[i].lastbyte )
	{
		if( axel->conf->verbose >= 2 )
398
		{
399 400
			axel_message( axel, _("Connection %i downloading from %s:%i using interface %s"),
		        	      i, axel->conn[i].host, axel->conn[i].port, axel->conn[i].local_if );
401
		}
402

403
		axel->conn[i].state = true;
404 405 406 407 408 409
		if( pthread_create( axel->conn[i].setup_thread, NULL, setup_thread, &axel->conn[i] ) != 0 )
		{
			axel_message( axel, _("pthread error!!!") );
			axel->ready = -1;
		}
	}
410 411

	/* The real downloading will start now, so let's start counting */
412 413 414 415
	axel->start_time = gettime();
	axel->ready = 0;
}

416
/* Main 'loop' */
417 418 419
void axel_do( axel_t *axel )
{
	fd_set fds[1];
420 421
	int hifd, i;
	long long int remaining,size;
422
	struct timeval timeval[1];
423 424 425
	url_t *url_ptr;
	struct timespec delay = { .tv_sec = 0, .tv_nsec = 100000000 };
	float max_speed_ratio;
426 427

	/* Create statefile if necessary */
428 429 430 431 432
	if( gettime() > axel->next_state )
	{
		save_state( axel );
		axel->next_state = gettime() + axel->conf->save_state_interval;
	}
433 434

	/* Wait for data on (one of) the connections */
435 436 437 438
	FD_ZERO( fds );
	hifd = 0;
	for( i = 0; i < axel->conf->num_connections; i ++ )
	{
439 440 441 442 443 444 445 446
		/* skip connection if setup thread hasn't released the lock yet */
		if( !pthread_mutex_trylock( &axel->conn[i].lock ) )
		{
			if( axel->conn[i].enabled ) {
				FD_SET( axel->conn[i].tcp->fd, fds );
				hifd = max( hifd, axel->conn[i].tcp->fd );
			}
			pthread_mutex_unlock( &axel->conn[i].lock );
447
		}
448 449 450
	}
	if( hifd == 0 )
	{
451
		/* No connections yet. Wait... */
452 453 454 455 456 457 458
		if ( axel_nanosleep( delay ) < 0 )
		{
			axel_message( axel, _("Error while waiting for connection: %s"),
				      strerror( errno ) );
			axel->ready = -1;
			return;
		}
459 460 461 462 463 464 465
		goto conn_check;
	}
	else
	{
		timeval->tv_sec = 0;
		timeval->tv_usec = 100000;
		/* A select() error probably means it was interrupted
466
		   by a signal, or that something else's very wrong... */
467 468 469 470 471 472
		if( select( hifd + 1, fds, NULL, NULL, timeval ) == -1 )
		{
			axel->ready = -1;
			return;
		}
	}
473 474

	/* Handle connections which need attention */
475 476 477 478
	for( i = 0; i < axel->conf->num_connections; i ++ ) {
	/* skip connection if setup thread hasn't released the lock yet */
	if( pthread_mutex_trylock( &axel->conn[i].lock ) )
		continue;
479
	if( axel->conn[i].enabled ) {
480
	if( FD_ISSET( axel->conn[i].tcp->fd, fds ) )
481 482
	{
		axel->conn[i].last_transfer = gettime();
483
		size = tcp_read( axel->conn[i].tcp, buffer, axel->conf->buffer_size );
484 485 486 487 488 489 490 491 492 493 494 495 496 497
		if( size == -1 )
		{
			if( axel->conf->verbose )
			{
				axel_message( axel, _("Error on connection %i! "
					"Connection closed"), i );
			}
			conn_disconnect( &axel->conn[i] );
			continue;
		}
		else if( size == 0 )
		{
			if( axel->conf->verbose )
			{
498
				/* Only abnormal behaviour if: */
499
				if( axel->conn[i].currentbyte < axel->conn[i].lastbyte && axel->size != LLONG_MAX )
500 501 502 503 504 505 506 507 508 509 510 511 512
				{
					axel_message( axel, _("Connection %i unexpectedly closed"), i );
				}
				else
				{
					axel_message( axel, _("Connection %i finished"), i );
				}
			}
			if( !axel->conn[0].supported )
			{
				axel->ready = 1;
			}
			conn_disconnect( &axel->conn[i] );
513
			reactivate_connection(axel,i);
514 515
			continue;
		}
516
		/* remaining == Bytes to go */
517 518
		remaining = axel->conn[i].lastbyte - axel->conn[i].currentbyte + 1;
		if( remaining < size )
519 520 521 522 523 524
		{
			if( axel->conf->verbose )
			{
				axel_message( axel, _("Connection %i finished"), i );
			}
			conn_disconnect( &axel->conn[i] );
525
			size = remaining;
526
			/* Don't terminate, still stuff to write! */
527
		}
528
		/* This should always succeed.. */
529 530 531
		lseek( axel->outfd, axel->conn[i].currentbyte, SEEK_SET );
		if( write( axel->outfd, buffer, size ) != size )
		{
532

533 534 535 536 537 538
			axel_message( axel, _("Write error!") );
			axel->ready = -1;
			return;
		}
		axel->conn[i].currentbyte += size;
		axel->bytes_done += size;
539 540
		if( remaining == size )
			reactivate_connection(axel,i);
541 542 543 544 545 546 547 548 549 550
	}
	else
	{
		if( gettime() > axel->conn[i].last_transfer + axel->conf->connection_timeout )
		{
			if( axel->conf->verbose )
				axel_message( axel, _("Connection %i timed out"), i );
			conn_disconnect( &axel->conn[i] );
		}
	} }
551 552
	pthread_mutex_unlock( &axel->conn[i].lock );
	}
553

554 555
	if( axel->ready )
		return;
556

557
conn_check:
558
	/* Look for aborted connections and attempt to restart them. */
559
	url_ptr = axel->url;
560 561
	for( i = 0; i < axel->conf->num_connections; i ++ )
	{
562 563 564 565
		/* skip connection if setup thread hasn't released the lock yet */
		if( pthread_mutex_trylock( &axel->conn[i].lock ) )
			continue;

566 567
		if( !axel->conn[i].enabled && axel->conn[i].currentbyte < axel->conn[i].lastbyte )
		{
568
			if( !axel->conn[i].state )
569
			{
570 571
				// Wait for termination of this thread
				pthread_join(*(axel->conn[i].setup_thread), NULL);
572

573 574
				conn_set( &axel->conn[i], url_ptr->text );
				url_ptr = url_ptr->next;
575 576 577 578 579
				/* axel->conn[i].local_if = axel->conf->interfaces->text;
				axel->conf->interfaces = axel->conf->interfaces->next; */
				if( axel->conf->verbose >= 2 )
					axel_message( axel, _("Connection %i downloading from %s:%i using interface %s"),
				        	      i, axel->conn[i].host, axel->conn[i].port, axel->conn[i].local_if );
580

581
				axel->conn[i].state = true;
582 583 584 585 586 587 588 589 590 591 592 593 594 595 596
				if( pthread_create( axel->conn[i].setup_thread, NULL, setup_thread, &axel->conn[i] ) == 0 )
				{
					axel->conn[i].last_transfer = gettime();
				}
				else
				{
					axel_message( axel, _("pthread error!!!") );
					axel->ready = -1;
				}
			}
			else
			{
				if( gettime() > axel->conn[i].last_transfer + axel->conf->reconnect_delay )
				{
					pthread_cancel( *axel->conn[i].setup_thread );
597 598
					axel->conn[i].state = false;
					pthread_join( *axel->conn[i].setup_thread, NULL );
599 600 601
				}
			}
		}
602
		pthread_mutex_unlock( &axel->conn[i].lock );
603 604
	}

605
	/* Calculate current average speed and finish_time */
606
	axel->bytes_per_second = (int) ( (double) ( axel->bytes_done - axel->start_byte ) / ( gettime() - axel->start_time ) );
607 608 609 610
	if( axel->bytes_per_second != 0 )
		axel->finish_time = (int) ( axel->start_time + (double) ( axel->size - axel->start_byte ) / axel->bytes_per_second );
	else
		axel->finish_time = INT_MAX;
611 612

	/* Check speed. If too high, delay for some time to slow things
613
	   down a bit. I think a 5% deviation should be acceptable. */
614 615
	if( axel->conf->max_speed > 0 )
	{
616 617 618 619 620 621 622 623 624 625 626 627 628
		max_speed_ratio = (float) axel->bytes_per_second /
					  axel->conf->max_speed;
		if( max_speed_ratio > 1.05 )
			axel->delay_time.tv_nsec += 10000000;
		else if( ( max_speed_ratio < 0.95 ) &&
			 ( axel->delay_time.tv_nsec >= 10000000 ) )
			axel->delay_time.tv_nsec -= 10000000;
		else if( ( max_speed_ratio < 0.95 ) &&
			 ( axel->delay_time.tv_sec > 0 ) )
		{
			axel->delay_time.tv_sec--;
			axel->delay_time.tv_nsec += 999000000;
		}
629
		else if( ( (float) axel->bytes_per_second / axel->conf->max_speed < 0.95 ) )
630 631 632 633 634 635 636 637 638 639 640
		{
			axel->delay_time.tv_sec = 0;
			axel->delay_time.tv_nsec = 0;
		}
		if( axel_nanosleep( axel->delay_time ) < 0 )
		{
			axel_message( axel, _("Error while enforcing throttling: %s"),
				      strerror( errno ) );
			axel->ready = -1;
			return;
		}
641
	}
642 643

	/* Ready? */
644 645 646 647
	if( axel->bytes_done == axel->size )
		axel->ready = 1;
}

648
/* Close an axel connection */
649 650
void axel_close( axel_t *axel )
{
651 652
	if( !axel )
		return;
653

654 655 656 657 658 659 660
	if( axel->conn )
	{
		/* Terminate threads and close connections */
		for( int i = 0; i < axel->conf->num_connections; i ++ )
		{
			/* don't try to kill non existing thread */
			if ( *axel->conn[i].setup_thread != 0 )
661
			{
662
				pthread_cancel( *axel->conn[i].setup_thread );
663 664
				pthread_join( *axel->conn[i].setup_thread, NULL );
			}
665 666 667 668 669
			conn_disconnect( &axel->conn[i] );
		}
	}

	free( axel->url );
670 671

	/* Delete state file if necessary */
672 673
	if( axel->ready == 1 )
	{
674
		snprintf( buffer, MAX_STRING + 4, "%s.st", axel->filename );
675 676
		unlink( buffer );
	}
677
	/* Else: Create it.. */
678 679 680 681 682
	else if( axel->bytes_done > 0 )
	{
		save_state( axel );
	}

683
	print_messages( axel );
684

685
	close( axel->outfd );
686
	free( axel->conn );
687
	free( axel );
688
	free( buffer );
689 690
}

691
/* time() with more precision */
692 693 694
double gettime()
{
	struct timeval time[1];
695

696 697 698 699
	gettimeofday( time, 0 );
	return( (double) time->tv_sec + (double) time->tv_usec / 1000000 );
}

700
/* Save the state of the current download */
701 702 703 704
void save_state( axel_t *axel )
{
	int fd, i;
	char fn[MAX_STRING+4];
705
	ssize_t nwrite;
706 707

	/* No use for such a file if the server doesn't support
708
	   resuming anyway.. */
709 710
	if( !axel->conn[0].supported )
		return;
711

712
	snprintf( fn, sizeof( fn ), "%s.st", axel->filename );
713 714
	if( ( fd = open( fn, O_CREAT | O_TRUNC | O_WRONLY, 0666 ) ) == -1 )
	{
715
		return;		/* Not 100% fatal.. */
716
	}
717 718

        nwrite = write( fd, &axel->conf->num_connections, sizeof( axel->conf->num_connections ) );
719
	assert( nwrite == sizeof( axel->conf->num_connections ) );
720 721

	nwrite = write( fd, &axel->bytes_done, sizeof( axel->bytes_done ) );
722
	assert( nwrite == sizeof( axel->bytes_done ) );
723 724 725 726

	for( i = 0; i < axel->conf->num_connections; i ++ ) {
		nwrite = write( fd, &axel->conn[i].currentbyte, sizeof( axel->conn[i].currentbyte ) );
		assert( nwrite == sizeof( axel->conn[i].currentbyte ) );
727 728
		nwrite = write( fd, &axel->conn[i].lastbyte, sizeof( axel->conn[i].lastbyte ) );
		assert( nwrite == sizeof( axel->conn[i].lastbyte ) );
729 730 731 732
	}
	close( fd );
}

733
/* Thread used to set up a connection */
734 735 736 737
void *setup_thread( void *c )
{
	conn_t *conn = c;
	int oldstate;
738 739

	/* Allow this thread to be killed at any time. */
740 741
	pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &oldstate );
	pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate );
742

743
	pthread_mutex_lock( &conn->lock );
744 745 746 747 748 749
	if( conn_setup( conn ) )
	{
		conn->last_transfer = gettime();
		if( conn_exec( conn ) )
		{
			conn->last_transfer = gettime();
750 751
			conn->enabled = true;
			goto out;
752 753
		}
	}
754

755
	conn_disconnect( conn );
756 757 758 759
out:
	conn->state = false;
	pthread_mutex_unlock( &conn->lock );

760 761 762
	return( NULL );
}

763
/* Add a message to the axel->message structure */
764 765
static void axel_message( axel_t *axel, char *format, ... )
{
766
	message_t *m;
767
	va_list params;
768

769 770 771 772 773 774 775
	if ( !axel )
		goto nomem;

	m = malloc( sizeof( message_t ) );
	if ( !m )
		goto nomem;

776 777 778 779
	memset( m, 0, sizeof( message_t ) );
	va_start( params, format );
	vsnprintf( m->text, MAX_STRING, format, params );
	va_end( params );
780

781 782
	if( axel->message == NULL )
	{
783
		axel->message = axel->last_message = m;
784 785 786
	}
	else
	{
787 788
		axel->last_message->next = m;
		axel->last_message = m;
789
	}
790 791 792 793 794 795 796 797 798

	return;

nomem:
	/* Flush previous messages */
	print_messages( axel );
	va_start( params, format );
	vprintf( format, params );
	va_end( params );
799 800
}

801
/* Divide the file and set the locations for each connection */
802 803 804
static void axel_divide( axel_t *axel )
{
	int i;
805

806 807 808 809 810
	axel->conn[0].currentbyte = 0;
	axel->conn[0].lastbyte = axel->size / axel->conf->num_connections - 1;
	for( i = 1; i < axel->conf->num_connections; i ++ )
	{
#ifdef DEBUG
811
		printf( _("Downloading %lld-%lld using conn. %i\n"), axel->conn[i-1].currentbyte, axel->conn[i-1].lastbyte, i - 1 );
812 813 814 815 816 817
#endif
		axel->conn[i].currentbyte = axel->conn[i-1].lastbyte + 1;
		axel->conn[i].lastbyte = axel->conn[i].currentbyte + axel->size / axel->conf->num_connections;
	}
	axel->conn[axel->conf->num_connections-1].lastbyte = axel->size - 1;
#ifdef DEBUG
818
	printf( _("Downloading %lld-%lld using conn. %i\n"), axel->conn[i-1].currentbyte, axel->conn[i-1].lastbyte, i - 1 );
819 820
#endif
}