int http_connect( http_t *conn, int proto, char *proxy, char *host, int port, char *user, char *pass ) { char base64_encode[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz0123456789+/"; char auth[MAX_STRING], pauth[MAX_STRING]; char *ppass, *puser; conn_t tconn[1]; int i; strncpy( conn->host, host, MAX_STRING ); conn->proto = proto; if( proxy != NULL ) { if( *proxy != 0 ) { sprintf( conn->host, "%s:%i", host, port ); if( !conn_set( tconn, proxy ) ) { /* We'll put the message in conn->headers, not in request */ sprintf( conn->headers, _("Invalid proxy string: %s\n"), proxy ); return( 0 ); } host = tconn->host; port = tconn->port; puser = tconn->user; ppass = tconn->pass; conn->proxy = 1; } else { conn->proxy = 0; } } if( ( conn->fd = tcp_connect( host, port, conn->local_if ) ) == -1 ) { /* We'll put the message in conn->headers, not in request */ sprintf( conn->headers, _("Unable to connect to server %s:%i\n"), host, port ); return( 0 ); } if( *user == 0 ) { *conn->auth = 0; } else { memset( auth, 0, MAX_STRING ); snprintf( auth, MAX_STRING, "%s:%s", user, pass ); for( i = 0; auth[i*3]; i ++ ) { conn->auth[i*4] = base64_encode[(auth[i*3]>>2)]; conn->auth[i*4+1] = base64_encode[((auth[i*3]&3)<<4)|(auth[i*3+1]>>4)]; conn->auth[i*4+2] = base64_encode[((auth[i*3+1]&15)<<2)|(auth[i*3+2]>>6)]; conn->auth[i*4+3] = base64_encode[auth[i*3+2]&63]; if( auth[i*3+2] == 0 ) conn->auth[i*4+3] = '='; if( auth[i*3+1] == 0 ) conn->auth[i*4+2] = '='; } } if( *puser == 0 ) { *conn->proxy_auth = 0; } else { memset( pauth, 0, MAX_STRING ); snprintf( pauth, MAX_STRING, "%s:%s", puser, ppass ); for( i = 0; pauth[i*3]; i ++ ) { conn->proxy_auth[i*4] = base64_encode[(pauth[i*3]>>2)]; conn->proxy_auth[i*4+1] = base64_encode[((pauth[i*3]&3)<<4)|(pauth[i*3+1]>>4)]; conn->proxy_auth[i*4+2] = base64_encode[((pauth[i*3+1]&15)<<2)|(pauth[i*3+2]>>6)]; conn->proxy_auth[i*4+3] = base64_encode[pauth[i*3+2]&63]; if( pauth[i*3+2] == 0 ) conn->proxy_auth[i*4+3] = '='; if( pauth[i*3+1] == 0 ) conn->proxy_auth[i*4+2] = '='; } } return( 1 ); }
/* Main 'loop' */ void axel_do( axel_t *axel ) { fd_set fds[1]; int hifd, i, j; long long int size; struct timeval timeval[1]; /* Create statefile if necessary */ if( gettime() > axel->next_state ) { save_state( axel ); axel->next_state = gettime() + axel->conf->save_state_interval; } /* Wait for data on (one of) the connections */ FD_ZERO( fds ); hifd = 0; for( i = 0; i < axel->conf->num_connections; i ++ ) { if( axel->conn[i].enabled ) FD_SET( axel->conn[i].fd, fds ); hifd = max( hifd, axel->conn[i].fd ); } if( hifd == 0 ) { /* No connections yet. Wait... */ usleep( 100000 ); goto conn_check; } else { timeval->tv_sec = 0; timeval->tv_usec = 100000; /* A select() error probably means it was interrupted by a signal, or that something else's very wrong... */ if( select( hifd + 1, fds, NULL, NULL, timeval ) == -1 ) { axel->ready = -1; return; } } /* Handle connections which need attention */ for( i = 0; i < axel->conf->num_connections; i ++ ) if( axel->conn[i].enabled ) { if( FD_ISSET( axel->conn[i].fd, fds ) ) { axel->conn[i].last_transfer = gettime(); size = read( axel->conn[i].fd, buffer, axel->conf->buffer_size ); if( size == -1 ) { if( axel->conf->verbose ) { axel_message( axel, _("Error on connection %i! " "Connection closed"), i ); } axel->conn[i].enabled = 0; conn_disconnect( &axel->conn[i] ); continue; } else if( size == 0 ) { if( axel->conf->verbose ) { /* Only abnormal behaviour if: */ if( axel->conn[i].currentbyte < axel->conn[i].lastbyte && axel->size != INT_MAX ) { axel_message( axel, _("Connection %i unexpectedly closed"), i ); } else { axel_message( axel, _("Connection %i finished"), i ); } } if( !axel->conn[0].supported ) { axel->ready = 1; } axel->conn[i].enabled = 0; conn_disconnect( &axel->conn[i] ); continue; } /* j == Bytes to go */ j = axel->conn[i].lastbyte - axel->conn[i].currentbyte + 1; if( j < size ) { if( axel->conf->verbose ) { axel_message( axel, _("Connection %i finished"), i ); } axel->conn[i].enabled = 0; conn_disconnect( &axel->conn[i] ); size = j; /* Don't terminate, still stuff to write! */ } /* This should always succeed.. */ lseek( axel->outfd, axel->conn[i].currentbyte, SEEK_SET ); if( write( axel->outfd, buffer, size ) != size ) { axel_message( axel, _("Write error!") ); axel->ready = -1; return; } axel->conn[i].currentbyte += size; axel->bytes_done += size; } 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] ); axel->conn[i].enabled = 0; } } } if( axel->ready ) return; conn_check: /* Look for aborted connections and attempt to restart them. */ for( i = 0; i < axel->conf->num_connections; i ++ ) { if( !axel->conn[i].enabled && axel->conn[i].currentbyte < axel->conn[i].lastbyte ) { if( axel->conn[i].state == 0 ) { conn_set( &axel->conn[i], axel->url->text ); axel->url = axel->url->next; /* 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 ); if( pthread_create( axel->conn[i].setup_thread, NULL, setup_thread, &axel->conn[i] ) == 0 ) { axel->conn[i].state = 1; 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 ); axel->conn[i].state = 0; } } } } /* Calculate current average speed and finish_time */ axel->bytes_per_second = (int) ( (double) ( axel->bytes_done - axel->start_byte ) / ( gettime() - axel->start_time ) ); axel->finish_time = (int) ( axel->start_time + (double) ( axel->size - axel->start_byte ) / axel->bytes_per_second ); /* Check speed. If too high, delay for some time to slow things down a bit. I think a 5% deviation should be acceptable. */ if( axel->conf->max_speed > 0 ) { if( (float) axel->bytes_per_second / axel->conf->max_speed > 1.05 ) axel->delay_time += 10000; else if( ( (float) axel->bytes_per_second / axel->conf->max_speed < 0.95 ) && ( axel->delay_time >= 10000 ) ) axel->delay_time -= 10000; else if( ( (float) axel->bytes_per_second / axel->conf->max_speed < 0.95 ) ) axel->delay_time = 0; usleep( axel->delay_time ); } /* Ready? */ if( axel->bytes_done == axel->size ) axel->ready = 1; }
/* Create a new axel_t structure */ axel_t *axel_new(conf_t *conf, int count, void *url) { search_t *res; axel_t *axel; url_t *u; char *s; int i; #if WIN32 WSADATA wsaData; if (0 != WSAStartup(MAKEWORD(2, 2), &wsaData)) { #ifdef DEBUG printf("WSAStartup error\n"); #endif return NULL; } #endif axel = malloc(sizeof(axel_t)); if (NULL == axel) { return NULL; } memset(axel, 0, sizeof(axel_t)); *axel->conf = *conf; axel->conn = malloc(sizeof(conn_t) * axel->conf->num_connections); if (NULL == axel->conn) { return NULL; } memset(axel->conn, 0, sizeof(conn_t) * axel->conf->num_connections); if (0 < axel->conf->max_speed) { if ((float)axel->conf->max_speed / axel->conf->buffer_size < 0.5) { if (2 <= axel->conf->verbose) { axel_message(axel, _("Buffer resized for this speed.")); } axel->conf->buffer_size = axel->conf->max_speed; } axel->delay_time = (int)((float)1000000 / axel->conf->max_speed * axel->conf->buffer_size * axel->conf->num_connections); } if (NULL == buffer) { buffer = malloc(max(MAX_STRING, axel->conf->buffer_size)); if (NULL == buffer) { return NULL; } } if (0 == count) { axel->url = malloc(sizeof(url_t)); if (NULL == axel->url) { return NULL; } axel->url->next = axel->url; strncpy(axel->url->text, (char *)url, MAX_STRING); } else { res = (search_t *)url; u = axel->url = malloc(sizeof(url_t)); for (i = 0; i < count; i++) { strncpy(u->text, res[i].url, MAX_STRING); if (i < count - 1) { u->next = malloc(sizeof(url_t)); u = u->next; } else { u->next = axel->url; } } } 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; strncpy(axel->filename, axel->conn[0].file, MAX_STRING); http_decode(axel->filename); if (0 == *axel->filename) { /* Index page == no fn */ strncpy(axel->filename, axel->conf->default_filename, MAX_STRING); } if ((s = strchr(axel->filename, '?')) != NULL && axel->conf->strip_cgi_parameters) { *s = 0; /* Get rid of CGI parameters */ } 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. */ if (!conn_info(&axel->conn[0])) { axel_message(axel, axel->conn[0].message); axel->ready = -1; return axel; } s = conn_url(axel->conn); strncpy(axel->url->text, s, MAX_STRING); if ((axel->size = axel->conn[0].size) != INT_MAX) { if (axel->conf->verbose > 0) { axel_message(axel, _("File size: %lld bytes"), axel->size); } } /* Wildcards in URL --> Get complete filename */ if (strchr(axel->filename, '*') || strchr(axel->filename, '?')) { strncpy(axel->filename, axel->conn[0].file, MAX_STRING); } return axel; }
int search_makelist( search_t *results, char *url ) { int i, size = 8192, j = 0; char *s, *s1, *s2, *s3; conn_t conn[1]; double t; memset( conn, 0, sizeof( conn_t ) ); conn->conf = results->conf; t = gettime(); if( !conn_set( conn, url ) ) return( -1 ); if( !conn_init( conn ) ) return( -1 ); if( !conn_info( conn ) ) return( -1 ); strcpy( results[0].url, url ); results[0].speed = 1 + 1000 * ( gettime() - t ); results[0].size = conn->size; s = malloc( size ); sprintf( s, "http://www.filesearching.com/cgi-bin/s?q=%s&w=a&l=en&" "t=f&e=on&m=%i&o=n&s1=%lld&s2=%lld&x=15&y=15", conn->file, results->conf->search_amount, conn->size, conn->size ); conn_disconnect( conn ); memset( conn, 0, sizeof( conn_t ) ); conn->conf = results->conf; if( !conn_set( conn, s ) ) { free( s ); return( 1 ); } if( !conn_setup( conn ) ) { free( s ); return( 1 ); } if( !conn_exec( conn ) ) { free( s ); return( 1 ); } while( ( i = read( conn->fd, s + j, size - j ) ) > 0 ) { j += i; if( j + 10 >= size ) { size *= 2; s = realloc( s, size ); memset( s + size / 2, 0, size / 2 ); } } conn_disconnect( conn ); s1 = strstr( s, "<pre class=list" ); s1 = strchr( s1, '\n' ) + 1; if( strstr( s1, "</pre>" ) == NULL ) { /* Incomplete list */ free( s ); return( 1 ); } for( i = 1; strncmp( s1, "</pre>", 6 ) && i < results->conf->search_amount && *s1; i ++ ) { s3 = strchr( s1, '\n' ); *s3 = 0; s2 = strrstr( s1, "<a href=" ) + 8; *s3 = '\n'; s3 = strchr( s2, ' ' ); *s3 = 0; if( strcmp( results[0].url, s2 ) ) { strncpy( results[i].url, s2, MAX_STRING ); results[i].size = results[0].size; results[i].conf = results->conf; } else { /* The original URL might show up */ i --; } for( s1 = s3; *s1 != '\n'; s1 ++ ); s1 ++; } free( s ); return( i ); }
/* Main 'loop' */ void axel_do(axel_t *axel) { #if WIN32 WSAEVENT hEventObject = WSACreateEvent(); DWORD byte; #else fd_set fds[1]; struct timeval timeval[1]; int hifd; #endif int i; long long int remaining, size; /* Create statefile if necessary */ if (axel->next_state < gettime()) { save_state(axel); axel->next_state = gettime() + axel->conf->save_state_interval; } /* Wait for data on (one of) the connections */ #if !WIN32 FD_ZERO(fds); hifd = 0; for (i = 0; i < axel->conf->num_connections; i++) { if (axel->conn[i].enabled) { FD_SET(axel->conn[i].fd, fds); } hifd = max(hifd, axel->conn[i].fd); } if (0 == hifd) { #ifdef DEBUG printf("DEBUG no connection yet. Wait...\n"); #endif /* No connections yet. Wait... */ usleep(100000); goto conn_check; } else { timeval->tv_sec = 0; timeval->tv_usec = 100000; /* A select() error probably means it was interrupted by a signal, or that something else's very wrong... */ if (-1 == select(hifd + 1, fds, NULL, NULL, timeval)) { axel->ready = -1; return; } } #endif /* Handle connections which need attention */ for (i = 0; i < axel->conf->num_connections; i++) { if (axel->conn[i].enabled) { #if WIN32 if (is_readable(axel, axel->conn[i].fd, hEventObject)) #else if (FD_ISSET(axel->conn[i].fd, fds)) #endif { axel->conn[i].last_transfer = gettime(); #if WIN32 memset(buffer, 0, max(MAX_STRING, axel->conf->buffer_size)); size = recv(axel->conn[i].fd, buffer, axel->conf->buffer_size, 0); #else size = read(axel->conn[i].fd, buffer, axel->conf->buffer_size); #endif #if WIN32 if (SOCKET_ERROR == size) #else if (-1 == size) #endif { #if !WIN32 if (axel->conf->verbose) { axel_message( axel, _("Error on connection %i! " "Connection closed"), i ); } #endif axel->conn[i].enabled = 0; conn_disconnect(&axel->conn[i]); continue; } else if (0 == size) { if (axel->conf->verbose) { /* Only abnormal behaviour if: */ if (axel->conn[i].currentbyte < axel->conn[i].lastbyte && axel->size != INT_MAX) { axel_message(axel, _("Connection %i unexpectedly closed"), i); } else { axel_message(axel, _("Connection %i finished"), i); } } if (!axel->conn[0].supported) { axel->ready = 1; } axel->conn[i].enabled = 0; conn_disconnect(&axel->conn[i]); continue; } /* remaining == Bytes to go */ remaining = axel->conn[i].lastbyte - axel->conn[i].currentbyte + 1; if (remaining < size) { if (axel->conf->verbose) { axel_message(axel, _("Connection %i finished"), i); } axel->conn[i].enabled = 0; conn_disconnect(&axel->conn[i]); size = remaining; /* Don't terminate, still stuff to write! */ } /* This should always succeed.. */ #if WIN32 SetFilePointer(axel->outfd, axel->conn[i].currentbyte, NULL, FILE_BEGIN); if (0 == WriteFile(axel->outfd, buffer, size, &byte, NULL)) #else lseek(axel->outfd, axel->conn[i].currentbyte, SEEK_SET); if (write(axel->outfd, buffer, size) != size) #endif { axel_message(axel, _("Write error!")); axel->ready = -1; return; } axel->conn[i].currentbyte += size; axel->bytes_done += size; } 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]); axel->conn[i].enabled = 0; } } } } if (axel->ready) { return; } conn_check: /* Look for aborted connections and attempt to restart them. */ for (i = 0; i < axel->conf->num_connections; i++) { if (!axel->conn[i].enabled && axel->conn[i].currentbyte < axel->conn[i].lastbyte) { if (0 == axel->conn[i].state) { // Wait for termination of this thread #if WIN32 WaitForSingleObject(axel->conn[i].setup_thread, INFINITE); CloseHandle(axel->conn[i].setup_thread); #else pthread_join(*(axel->conn[i].setup_thread), NULL); #endif conn_set(&axel->conn[i], axel->url->text); axel->url = axel->url->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); } axel->conn[i].state = 1; #if WIN32 axel->conn[i].setup_thread = CreateThread(NULL, 0, setup_thread_cb, &axel->conn[i], 0, NULL); if (NULL != axel->conn[i].setup_thread) #else if (pthread_create(axel->conn[i].setup_thread, NULL, setup_thread_cb, &axel->conn[i]) == 0) #endif { axel->conn[i].last_transfer = gettime(); } else { axel_message(axel, _("thread error in axel_do!!!")); axel->ready = -1; } } else { if (gettime() > axel->conn[i].last_transfer + axel->conf->reconnect_delay) { #if WIN32 TerminateThread(axel->conn[i].setup_thread, 0); CloseHandle(axel->conn[i].setup_thread); #else pthread_cancel(*axel->conn[i].setup_thread); #endif axel->conn[i].state = 0; } } } } /* Calculate current average speed and finish_time */ axel->bytes_per_second = (int)((double)(axel->bytes_done - axel->start_byte) / (gettime() - axel->start_time)); axel->finish_time = (int)(axel->start_time + (double)(axel->size - axel->start_byte) / axel->bytes_per_second); /* Check speed. If too high, delay for some time to slow things down a bit. I think a 5% deviation should be acceptable. */ if (0 < axel->conf->max_speed) { if (1.05 < (float) axel->bytes_per_second / axel->conf->max_speed) { axel->delay_time += 10000; } else if (((float)axel->bytes_per_second / axel->conf->max_speed < 0.95) && 10000 <= (axel->delay_time)) { axel->delay_time -= 10000; } else if (((float)axel->bytes_per_second / axel->conf->max_speed < 0.95)) { axel->delay_time = 0; } usleep(axel->delay_time); } /* Ready? */ if (axel->bytes_done == axel->size) { axel->ready = 1; } }
/* Get file size and other information */ int conn_info( conn_t *conn ) { /* It's all a bit messed up.. But it works. */ if( conn->proto == PROTO_FTP && !conn->proxy ) { ftp_command( conn->ftp, "REST %lld", 1 ); if( ftp_wait( conn->ftp ) / 100 == 3 || conn->ftp->status / 100 == 2 ) { conn->supported = 1; ftp_command( conn->ftp, "REST %lld", 0 ); ftp_wait( conn->ftp ); } else { conn->supported = 0; } if( !ftp_cwd( conn->ftp, conn->dir ) ) return( 0 ); conn->size = ftp_size( conn->ftp, conn->file, MAX_REDIR ); if( conn->size < 0 ) conn->supported = 0; if( conn->size == -1 ) return( 0 ); else if( conn->size == -2 ) conn->size = LLONG_MAX; } else { char s[MAX_STRING], *t; long long int i = 0; do { conn->currentbyte = 1; if( !conn_setup( conn ) ) return( 0 ); conn_exec( conn ); conn_disconnect( conn ); /* Code 3xx == redirect */ if( conn->http->status / 100 != 3 ) break; if( ( t = http_header( conn->http, "location:" ) ) == NULL ) return( 0 ); sscanf( t, "%1000s", s ); //this value is related to MAX_STRING if( strstr( s, "://" ) == NULL) { sprintf( conn->http->headers, "%s%s", conn_url( conn ), s ); strncpy( s, conn->http->headers, MAX_STRING ); } else if( s[0] == '/' ) { snprintf( conn->http->headers, MAX_QUERY, "http://%s:%i%s", conn->host, conn->port, s ); strncpy( s, conn->http->headers, MAX_STRING ); } conn_set( conn, s ); i ++; } while( conn->http->status / 100 == 3 && i < MAX_REDIR ); if( i == MAX_REDIR ) { sprintf( conn->message, _("Too many redirects.\n") ); return( 0 ); } conn->size = http_size( conn->http ); if( conn->http->status == 206 && conn->size >= 0 ) { conn->supported = 1; conn->size ++; } else if( conn->http->status == 200 || conn->http->status == 206 ) { conn->supported = 0; conn->size = LLONG_MAX; } else { t = strchr( conn->message, '\n' ); if( t == NULL ) sprintf( conn->message, _("Unknown HTTP error.\n") ); else *t = 0; return( 0 ); } } return( 1 ); }
/* Get file size and other information */ int conn_info(conn_t *conn) { /* It's all a bit messed up.. But it works. */ if (conn->proto == PROTO_FTP && !conn->proxy) { ftp_command(conn->ftp, "REST %lld", 1); if (ftp_wait(conn->ftp) / 100 == 3 || conn->ftp->status / 100 == 2) { conn->supported = 1; ftp_command(conn->ftp, "REST %lld", 0); ftp_wait(conn->ftp); } else { conn->supported = 0; } if (!ftp_cwd(conn->ftp, conn->dir)) { return 0; } conn->size = ftp_size(conn->ftp, conn->file, MAX_REDIR); if (conn->size < 0) { conn->supported = 0; } if (-1 == conn->size) { return 0; } else if (-2 == conn->size) { conn->size = INT_MAX; } } else { char s[MAX_STRING], *t; long long int i = 0; do { conn->currentbyte = 1; if (!conn_setup(conn)) { return 0; } conn_exec(conn); conn_disconnect(conn); /* Code 3xx == redirect */ if (3 != conn->http->status / 100) { break; } if (NULL == (t = http_header(conn->http, "location:"))) { return 0; } sscanf(t, "%255s", s); if (NULL == strstr(s, "://")) { sprintf(conn->http->headers, "%s%s", conn_url(conn), s); strncpy(s, conn->http->headers, MAX_STRING); } else if ('/' == s[0]) { sprintf(conn->http->headers, "http://%s:%i%s", conn->host, conn->port, s); strncpy(s, conn->http->headers, MAX_STRING); } conn_set(conn, s); i++; } while (conn->http->status / 100 == 3 && i < MAX_REDIR); if (i == MAX_REDIR) { sprintf(conn->message, _("Too many redirects.\n")); return 0; } conn->size = http_size(conn->http); if (conn->http->status == 206 && conn->size >= 0) { conn->supported = 1; conn->size ++; } else if (conn->http->status == 200 || conn->http->status == 206) { conn->supported = 0; conn->size = INT_MAX; } else { t = strchr(conn->message, '\n'); if (t == NULL) { sprintf(conn->message, _("Unknown HTTP error.\n")); } else { *t = 0; } return 0; } } return 1; }
/* Create a new axel_t structure */ axel_t *axel_new( conf_t *conf, int count, void *url ) { SSL_library_init(); g_ssl_ctx = SSL_CTX_new(SSLv23_client_method()); search_t *res; axel_t *axel; url_t *u; char *s; int i; axel = malloc( sizeof( axel_t ) ); memset( axel, 0, sizeof( axel_t ) ); *axel->conf = *conf; axel->conn = malloc( sizeof( conn_t ) * axel->conf->num_connections ); memset( axel->conn, 0, sizeof( conn_t ) * axel->conf->num_connections ); 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; } axel->delay_time = (int) ( (float) 1000000 / axel->conf->max_speed * axel->conf->buffer_size * axel->conf->num_connections ); } if( buffer == NULL ) buffer = malloc( max( MAX_STRING, axel->conf->buffer_size ) ); if( count == 0 ) { axel->url = malloc( sizeof( url_t ) ); axel->url->next = axel->url; strncpy( axel->url->text, (char *) url, MAX_STRING ); } else { res = (search_t *) url; u = axel->url = malloc( sizeof( url_t ) ); for( i = 0; i < count; i ++ ) { strncpy( u->text, res[i].url, MAX_STRING ); if( i < count - 1 ) { u->next = malloc( sizeof( url_t ) ); u = u->next; } else { u->next = axel->url; } } } 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; strncpy( axel->filename, axel->conn[0].file, MAX_STRING ); http_decode( axel->filename ); if( *axel->filename == 0 ) /* Index page == no fn */ strncpy( axel->filename, axel->conf->default_filename, MAX_STRING ); if( ( s = strchr( axel->filename, '?' ) ) != NULL && axel->conf->strip_cgi_parameters ) *s = 0; /* Get rid of CGI parameters */ 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. */ if( !conn_info( &axel->conn[0] ) ) { axel_message( axel, axel->conn[0].message ); axel->ready = -1; return( axel ); } s = conn_url( axel->conn ); strncpy( axel->url->text, s, MAX_STRING ); if( ( axel->size = axel->conn[0].size ) != INT_MAX ) { if( axel->conf->verbose > 0 ) axel_message( axel, _("File size: %lld bytes"), axel->size ); } /* Wildcards in URL --> Get complete filename */ if( strchr( axel->filename, '*' ) || strchr( axel->filename, '?' ) ) strncpy( axel->filename, axel->conn[0].file, MAX_STRING ); return( axel ); }
/* Get file size and other information */ int conn_info( conn_t *conn ) { /* It's all a bit messed up.. But it works. */ if( conn->proto == PROTO_FTP && !conn->proxy ) { ftp_command( conn->ftp, "REST %lld", 1 ); if( ftp_wait( conn->ftp ) / 100 == 3 || conn->ftp->status / 100 == 2 ) { conn->supported = 1; ftp_command( conn->ftp, "REST %lld", 0 ); ftp_wait( conn->ftp ); } else { conn->supported = 0; } if( !ftp_cwd( conn->ftp, conn->dir ) ) return( 0 ); conn->size = ftp_size( conn->ftp, conn->file, MAX_REDIR ); if( conn->size < 0 ) conn->supported = 0; if( conn->size == -1 ) return( 0 ); else if( conn->size == -2 ) conn->size = INT_MAX; } else { char s[MAX_STRING], *t; long long int i = 0; // redirections do { conn->currentbyte = 1; if( !conn_setup( conn ) ) return( 0 ); conn_exec( conn ); conn_disconnect( conn ); /* Code 3xx == redirect */ if( conn->http->status / 100 != 3 ) break; if( ( t = http_header( conn->http, "location:" ) ) == NULL ) return( 0 ); // 255 is a little bit small sscanf( t, "%1023s", s ); if( strstr( s, "://" ) == NULL) { sprintf( conn->http->headers, "%s%s", conn_url( conn ), s ); strncpy( s, conn->http->headers, MAX_STRING ); } else if( s[0] == '/' ) { sprintf( conn->http->headers, "http://%s:%i%s", conn->host, conn->port, s ); strncpy( s, conn->http->headers, MAX_STRING ); } conn_set( conn, s ); i ++; //printf("***************** Redirect %d : %s\n", (int)i, s); } while( conn->http->status / 100 == 3 && i < MAX_REDIR ); if( i == MAX_REDIR ) { sprintf( conn->message, _("Too many redirects.\n") ); return( 0 ); } conn->size = http_size( conn->http ); if( conn->http->status == 206 && conn->size >= 0 ) { conn->supported = 1; conn->size ++; } else if( conn->http->status == 200 || conn->http->status == 206 ) { // 在限速的情况下,此处如果supported设为0的话只能起一个线程 // 为了不限速(添加unlimit参数),这里supported改为1 // added by liuyan conn->supported = 1; //conn->supported = 0; //conn->size = INT_MAX; } else { t = strchr( conn->message, '\n' ); if( t == NULL ) sprintf( conn->message, _("Unknown HTTP error.\n") ); else *t = 0; return( 0 ); } } return( 1 ); }