/***************************************************************************
 *   Copyright (C) 2005 by kongyang                                        *
 *   be_heack@hotmail.com                                                  *
 *   Version 1.0                                                           *
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 *   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.                          *
 *                                                                         *
 *   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.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 *                                                                         *
 *   This program intends to help you download files using HTTP or FTP     *
 *   protocal, and you can use up to 20 threads to make your downloading   *
 *   faster.                                                               *
 *                                                                         *
 *   If you have better opinions about this program, please contact me.    *
 *   My msn is be_heack@hotmail.com, and mail the same.                    *
 *   If you help me a lot, I will add your name to the developer list.     *
 ***************************************************************************/
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/errno.h>
#include <stdarg.h>
//#include <tidy.h>
#include <pthread.h>
#include <fcntl.h>
#include <sys/time.h>
#include <math.h>
#define HTTP 0
#define FTP 1
static pthread_mutex_t lock=PTHREAD_MUTEX_INITIALIZER;
int hosttype;
static int sizeget=0;
int filelength=0;
char filename[256];
char localpath[256]="";
char host[256],path[256];
char user[32],pass[32];
int port=80,portftp=21;
int nthread=1;
int downpart[30][2];//describe how much data has been downloaded of each thread
int startthread=1;
struct arg g[30];//every thread's data
struct timeval tpstart,tpend;
struct arg{
    int threadnumber;
    int a1; //range fromn a1 to a2 also lseed set to a1
    int a2; 
    int fd; 
    int booldown;//indict whether a thread has begun
    int allowotherdown;//0 other thread cannot download this thread, 1 not
};
void ClearBuf(char *buf)
{
    int i=0;
    for(i=0;i<=1023;i++){
        *(buf+i)='\0';
    }
}
void GetZero(char *buf)
{
	int i=0,j=0;
	for(i=0;i<=1023;i++){
		if(*(buf+i)=='\0'){
			if(j==0){
				j=i;
				continue;
			}
			if(i==(j+1))printf("%d %d ",i,j);
			j=i;
		}	
	}
}
int GetInfo(char *arg,char *refer)
{
    char head[256],referer[256],length1[32];
    char headhost[256];
    char port1[8],port2[8];//227 Entering Passive Mode (192,168,8,30,6,32) 6 is stored in port1, while 32 is stored in port2
    char c_port[8];
    int iport=0;//sign the first time to see : like www.xxx.com:8000/name this is the position of :
    char dataget[2048]="";
    int i,i_sock,j,l,sockdata;
    
    int length=strlen(arg);
    if(!strncmp(arg,"http://",7))hosttype=HTTP;
    if(!strncmp(arg,"ftp://",6))hosttype=FTP;

    
    if(hosttype==HTTP){
        for(i=0;i<=strlen(arg)-7;i++){
    if(*(arg+7+i)==':')iport=i;
   
   if(*(arg+7+i)=='/'){
 
       if(iport!=0){
  	snprintf(host,iport+1,"%s",arg+7);
  	sprintf(path,"/%s",arg+7+i+1);
  	snprintf(c_port,i-iport,"%s",arg+7+iport+1);
  	port=atoi(c_port);
       }
       else{
  snprintf(host,i+1,"%s",arg+7);
  sprintf(path,"/%s",arg+7+i+1);
  
       }
       
       break;
   }
        }
        for(i=length-1;i>=0;i--){
   if(*(arg+i)=='/'){
       sprintf(filename,"%s",arg+i+1);
       break;
   }
        }
    }
    
    if(hosttype==FTP){
    	if(strstr(arg,"@")==NULL){
   		for(i=0;i<=strlen(arg)-6;i++){
       			if(*(arg+6+i)==':'){
  				iport=i;
  				continue;
       			}
       
       			if(*(arg+6+i)=='/'){

  				if(iport!=0){
      					snprintf(host,iport+1,"%s",arg+6);
      					sprintf(path,"/%s",arg+6+i+1);
      					snprintf(c_port,i-iport,"%s",arg+6+iport+1);
      					portftp=atoi(c_port);
  				}
  				else{
      					snprintf(host,i+1,"%s",arg+6);
      					sprintf(path,"/%s",arg+6+i+1);
      
  				}
  				break;
       			}
   		}
   		for(i=length-1;i>=0;i--){
       			if(*(arg+i)=='/'){
  				sprintf(filename,"%s",arg+i+1);
  				break;
       			}
   		}
        }
        else{
   		for(i=0;i<=strlen(arg)-6;i++){
       			if(*(arg+6+i)==':'){
  				iport=i;
  				continue;
       			}
       
       			if(*(arg+6+i)=='@'){

  				if(iport!=0){
      					snprintf(user,iport+1,"%s",arg+6);
      					snprintf(pass,i-iport,"%s",arg+6+iport+1);
  				}
  				else{
      					snprintf(user,i+1,"%s",arg+6);
      					sprintf(pass,"%s",arg+6+i+1);
      
  				}
  				sprintf(arg,"ftp://%s",arg+8+strlen(user)+strlen(pass));
  				GetInfo(arg,refer);
  				return 0;
  
       }
   }
        }
        
        
    } 

    if(hosttype==HTTP){
        i_sock=ConnectHttp(host,port);
        sprintf(head,"GET %s HTTP/1.1\r\nHost: %s:%d\r\nReferer: %s\r\n\r\n",path,host,port,refer);      
        printf("head is %s",head);
        if(send(i_sock,head,strlen(head),0)!=strlen(head)){
   		printf("Error in sending HEAD\n");
   		exit(1);
	}
     
     recv(i_sock,dataget,512,0);
     write(1,dataget,strlen(dataget));
     close(i_sock);
     if(strstr(dataget,"\nLocation")!=NULL){

         for(i=0;*(strstr(dataget,"\nLocation")+11+i)!='\n';i++){}
         snprintf(arg,i,"%s\0",strstr(dataget,"\nLocation")+11);
         GetInfo(arg,refer);

         return 0;
     }
     if(strstr(dataget,"\nlocation")!=NULL){

         for(i=0;*(strstr(dataget,"\nlocation")+11+i)!='\n';i++){}
         snprintf(arg,i,"%s\0",strstr(dataget,"\nlocation")+11);
         GetInfo(arg,refer);

         return 0;
     }
     if(strstr(dataget,"Content-Location")!=NULL){

         for(i=0;*(strstr(dataget,"Content-Location")+18+i)!='\n';i++){}
         snprintf(filename,i,"%s\0",strstr(dataget,"Content-Location")+18);
         if(*(path+strlen(path)-1)=='/')sprintf(path,"%s%s",path,filename);
     }

     filelength=GetLength(dataget);

    	}
    if(hosttype==FTP){
        i_sock=ConnectHttp(host,portftp);
	//while(ReadEn(i_sock,2)>0){
		
		j=recv(i_sock,dataget,1024,0);
		printf("bytesget is j = %d\n",j);
        	write(1,dataget,j);
	//}
        ClearBuf(dataget);
	sleep(5);
        sprintf(head,"USER %s\r\n\r\n",user);
        
        if(send(i_sock,head,strlen(head),0)!=strlen(head)){
   		printf("Error in sending HEAD\n");
   		exit(1);
        }
	//while(ReadEn(i_sock,2)>0){
        	j=recv(i_sock,dataget,1024,0);
	
        	write(1,dataget,strlen(dataget));
       // }
	
	if(strstr(dataget,"230")==NULL){
		ClearBuf(dataget);
		sprintf(head,"PASS %s\r\n\r\n",pass);
        	if(send(i_sock,head,strlen(head),0)!=strlen(head)){
   			printf("Error in sending HEAD\n");
   			exit(1);
        	}
		//while(ReadEn(i_sock,2)>0){
		j=recv(i_sock,dataget,1024,0);
        	write(1,dataget,j);
		//}
        	ClearBuf(dataget);
	}
	
       
	
	sprintf(head,"SIZE %s\r\n\r\n",path);
        if(send(i_sock,head,strlen(head),0)!=strlen(head)){
   		printf("Error in sending HEAD\n");
   		exit(1);
        }
	printf("head SIZE is_%s\n",head);
	
        recv(i_sock,dataget,1024,0);
	
        write(1,dataget,strlen(dataget));
	
	if(strstr(dataget,"213")!=NULL){
		i=1;
		while(1){
			if(*(strstr(dataget,"213")+i)=='\n')break;
			i++;
		}
		
		snprintf(length1,i-4,"%s",strstr(dataget,"213")+4);
		filelength=atoi(length1);
		if(filelength==0){
			close(i_sock);
			sleep(1);
			GetInfo(arg,refer);
			return 0;
		}
		printf("\nFile length is %d\n",filelength);
	}
	/*else if(strstr(dataget,"Unknown command")!=NULL){
		ClearBuf(dataget);
		printf("come heare 1");
		sprintf(head,"LIST %s\r\n\r\n",path);
		if(send(i_sock,head,strlen(head),0)!=strlen(head)){
   			printf("Error in sending LIST\n");
   			exit(1);
        	}
		printf("head is %s\n",head);
		j=recv(i_sock,dataget,512,0);
		write(1,dataget,j);
		if(strstr(dataget,filename)!=NULL){
			printf("heiheiheihei");
			j=0;
			for(i=0;i<=50;i++){
				if(*(strstr(dataget,filename)-i)==' ')j++;
				if(j==4)l=i;
				if(j==5){
					snprintf(length1,l-i-1,"%s",strstr(dataget,filename)-i+1);
					filelength=atoi(length1);
					printf("^^filelength is %d\n^^",filelength);
					if(filelength==0){
					close(i_sock);
					sleep(1);
					GetInfo(arg,refer);
					return 0;
					}
					break;
				}
			}
		}	
	}*/
	else{
		close(i_sock);
		sleep(1);
		GetInfo(arg,refer);
		return 0;
	}
        close(i_sock);
        
    }
    return 0;
}
int GetStartText(char *buf,int sizebuf)
{
    int i;
    for(i=0;i<=sizebuf-1;i++){
        if(buf[i]=='\n'&&!(buf[i+1]>='a'&&buf[i+1]<='z'||buf[i+1]>='A'&&buf[i+1]<='Z'))break;
  
    }
    return i+3;
}

int GetLength(char *buf)
{
    int i=0,start=0,length=0,end=0;
    
    while(buf[start]!='\0'){
        if(buf[start]=='L'){
   if(!strncmp(buf+start,"Length:",7)){
       start+=8;
       break;
   }
        }
        start++;
    }
    end=start;
    
    while(buf[end++]!='\n'){}
    buf[--end]='\0';
    length=atoi(buf+start);//Content-Length: xxxxxx\n

    return length;
    //return 4512912;
}
int GetLengthFtp(char *buf)
{
}
int GetPortFtp(char *buf)
{
}

#define m_sock 10
int ReadEn(int sock,int n);
int ConnectHttp(char* host,int iport)
{
    int sd;
    struct sockaddr_in pin;
    struct hostent *nlp_host;
    if((nlp_host=gethostbyname(host))==0){
        printf("Error resolving local host\n");
        return 0;
    }
    bzero(&pin,sizeof(pin));
    pin.sin_family=AF_INET;
    pin.sin_addr.s_addr=((struct in_addr*)(nlp_host->h_addr))->s_addr;
    pin.sin_port=htons(iport);
    
    if((sd=socket(PF_INET,SOCK_STREAM,0))==-1){
        printf("Error opening socket\n");
        return 0;
    }
    if(connect(sd,(struct sockaddr*)&pin,sizeof(pin))==-1){
        printf("Error connecting to socket\n");
        return 0;
    }
    return sd;
    
}

int DownLoadHttp(struct arg *s_info)
{
    char get[256];
    char buf[1024]="";
    char headhost[256];
    char range[32];
#define FALSE 0
#define TRUE 1
    //this function used to download assigned file from a1 bytes to a2 bytes from host, try 5 times 
    int connected =FALSE;
    int i,j,starttext,boolprint=0;
    int sock,nextthread=0,boolbyte=0;
    long timeuse;
    int readen,bytesget=0;
    int inflen,index=0,offset=0;
    int bytesleft=(s_info->a2)-(s_info->a1)+1;
    struct timeval tv;
    if(s_info->booldown==1&&s_info->allowotherdown==1)return 0;
    if(s_info->threadnumber!=0){
    	while(g[(s_info->threadnumber)-1].booldown==0){
    		write(1,"$$$$$wate here$$$$\n",19);
    		sleep(1);
		
	}
    }
    while(1){
    	printf("\nhost portftp is %s %d\n",host,port);
        if((sock=ConnectHttp(host,port))<=0)sleep(1);
        else{
   		write(1,"connected",10);
   		connected=TRUE;
   		break;
        }
    }
    if(connected){

        sprintf(get,"GET %s HTTP/1.1\r\nRange: bytes=%d-\r\nHost: %s:%d\r\n\r\n",path,s_info->a1,host,port);

        if(send(sock,get,strlen(get),0)!=strlen(get)){
   		printf("Error in send GET\n");
		close(sock);
		sleep(5);
		
   		DownLoadHttp(s_info);
		return 0;
        }


        s_info->fd=open(filename,O_WRONLY|O_CREAT,0644);
        lseek(s_info->fd,s_info->a1,0);
	pthread_mutex_lock(&lock);
	s_info->booldown=1;
  	pthread_mutex_unlock(&lock);
        
       

        ClearBuf(buf);
        while(bytesleft>0){
		readen =ReadEn(sock,30);
        	if(readen<1){
			s_info->a1+=offset;
			printf("fails to open sockdata,thread %d restart at offset %d",s_info->threadnumber,offset);
			close(sock);
			sleep(2);
			pthread_mutex_lock(&lock);
			s_info->booldown=0;
			s_info->allowotherdown=0;
            		pthread_mutex_unlock(&lock);
			DownLoadHttp(s_info);
			return 0;
		}
		
		boolprint++;
		if(boolprint==10)boolprint=0;
   		if(bytesleft>=1024&&offset==0){

			
			bytesget=recv(sock,buf,1024,MSG_WAITALL);

			
  			starttext=GetStartText(buf,bytesget);
  			write(s_info->fd,buf+starttext,1024-starttext);
  			bytesleft+=starttext-bytesget;
			offset+=bytesget-starttext;
			sizeget+=bytesget-starttext;
			ClearBuf(buf);
			continue;
		}
   		else if(bytesleft>=1024){
   			bytesget=recv(sock,buf,1024,0);
        if(bytesget==0)boolbyte++;
       			if(bytesget<0||(bytesget==0&&boolbyte>=10)){

				s_info->a1+=offset;
				printf("\n!!!!!buf size is %d thread %d try again at  %d!!!!\n",strlen(buf),s_info->threadnumber,offset);
				close(sock);
				pthread_mutex_lock(&lock);
				s_info->booldown=0;
				s_info->allowotherdown=0;
            			pthread_mutex_unlock(&lock);
				DownLoadHttp(s_info);
				return 0;	
			}

			write(s_info->fd,buf,bytesget);
	      		offset+=bytesget;
	      		sizeget+=bytesget;
			bytesleft-=bytesget;
			ClearBuf(buf);
			
	  	}
	  	else{
	      		if(offset==0){//used only if the thread size <1024
				bytesget=recv(sock,buf,2048,MSG_WAITALL);
				starttext=GetStartText(buf,bytesget);
		
				if(bytesleft!=bytesget-starttext){
					close(sock);
					sleep(2);
					pthread_mutex_lock(&lock);
					s_info->booldown=0;
					s_info->allowotherdown=0;
            				pthread_mutex_unlock(&lock);
		    			DownLoadHttp(s_info);
					return 0;
				}
				write(s_info->fd,buf+starttext,strlen(buf)-starttext);
			offset+=bytesget-starttext;
			bytesleft-=bytesget-starttext;
			sizeget+=bytesget-starttext;
	      		}

	      		else{
				bytesget=recv(sock,buf,bytesleft,0);
        if(bytesget==0)boolbyte++;
	      			if(bytesget<0||(bytesget==0&&boolbyte>=10)){
					s_info->a1+=offset;
					printf("\n!!!!!thread %d try again at less than 1024 %d!!!!\n",s_info->threadnumber,offset);
					close(sock);
					pthread_mutex_lock(&lock);
					s_info->booldown=0;
					s_info->allowotherdown=0;
            				pthread_mutex_unlock(&lock);
					DownLoadHttp(s_info);
					return 0;	
				}
	      			write(s_info->fd,buf,bytesget);
	      			offset+=bytesget;
	      			sizeget+=bytesget;
	      			bytesleft-=bytesget;
		
			if(bytesleft<=1024){
				nextthread++;
				if(g[s_info->threadnumber+nextthread].booldown==0&&g[s_info->threadnumber+nextthread].allowotherdown==1){
        				pthread_mutex_lock(&lock);
					g[s_info->threadnumber+nextthread].booldown=1;
        				pthread_mutex_unlock(&lock);
					bytesleft+=g[s_info->threadnumber+nextthread].a2-g[s_info->threadnumber+nextthread].a1+1;
					s_info->a2=g[s_info->threadnumber+nextthread].a2;
				}
			
			}
			}
			ClearBuf(buf);
		}
	  	if(boolprint==0){
			printf("%f ",(float)sizeget/(float)filelength);
			gettimeofday(&tpend,NULL);
    			timeuse=1000000*(tpend.tv_sec-tpstart.tv_sec)+tpend.tv_usec-tpstart.tv_usec;
    			timeuse/=1000000;
    			printf("Per download rate is %fk/s bytesget is %d\n",(float)sizeget/1000/(float)timeuse,sizeget);
		}
	}

        printf("****************%d bytes get is %d****************\n",s_info->threadnumber,offset);
	close(sock);
        return 0;
    }
    else return -1;
}
int DownLoadFtp(struct arg *s_info)
{
    char get[256],dataget[2048];
    char buf[2048];
    char port1[8],port2[8];//227 Entering Passive Mode (192,168,8,30,6,32) 6 is stored in port1, while 32 is stored in port2
    char headhost[256];
    char range[32];
    float f;
    long timeuse;
#define FALSE 0
#define TRUE 1
    //this function used to download assigned file from a1 bytes to a2 bytes from host, try 5 times 
    int connected =FALSE,bytesget;//bytesget stans for how many bytes get one time
    int i,j,starttext,boolprint=0;
    int sock,sockdata;//sockdata is used to download ftp data through another sock because ftp use 2 pipes
    int readen,portthread=0,nextthread=0;
    int inflen,index=0,offset=0;
    int bytesleft=(s_info->a2)-(s_info->a1)+1;
    struct timeval tv;
    
    if(s_info->threadnumber!=0){
    	while(g[(s_info->threadnumber)-1].booldown==0){

    		sleep(1);
		
	}
    }
    if(s_info->booldown==1&&s_info->allowotherdown==1)return 0;
    while(1){
        if((sock=ConnectHttp(host,portftp))<=0)sleep(1);
        else{

   		connected=TRUE;
   		break;
        }
    }
    if(connected){
        
        
        recv(sock,dataget,512,0);
        write(1,dataget,strlen(dataget));
	ClearBuf(dataget);
	
	sprintf(headhost,"USER %s\r\n\r\n",user);
;
	if(send(sock,headhost,strlen(headhost),0)!=strlen(headhost)){
   		printf("Error in sending HEAD\n");
		close(sock);
		sleep(5);
		
   		DownLoadFtp(s_info);
		return 0;
        }
	recv(sock,dataget,512,0);
        write(1,dataget,strlen(dataget));

	ClearBuf(dataget);
	
	sprintf(headhost,"PASS %s\r\n\r\n",pass);
	if(send(sock,headhost,strlen(headhost),0)!=strlen(headhost)){
   		printf("Error in sending HEAD\n");
		close(sock);
		sleep(5);
		
   		DownLoadFtp(s_info);
		return 0;
        }
	recv(sock,dataget,512,0);
	
        write(1,dataget,strlen(dataget));
	if(strstr(dataget,"421 No more connection")!=NULL){
		close(sock);
		sleep(5);
		
   		DownLoadFtp(s_info);
		return 0;
	}

        ClearBuf(dataget);
	
	sprintf(headhost,"TYPE I\r\n\r\n");
        
	if(send(sock,headhost,strlen(headhost),0)!=strlen(headhost)){
   		printf("Error in sending HEAD\n");
		close(sock);
		sleep(5);
   		DownLoadFtp(s_info);
		return 0;
        }
	recv(sock,dataget,512,0);

	ClearBuf(dataget);
	
	sprintf(headhost,"PASV\r\n\r\n");

	if(send(sock,headhost,strlen(headhost),0)!=strlen(headhost)){
   		printf("Error in sending HEAD\n");
   		DownLoadFtp(s_info);
		return 0;
        }
	recv(sock,dataget,512,0);
        write(1,dataget,strlen(dataget));
	
	
        
        if(strstr(dataget,"227 Entering Passive Mode")!=NULL){
		j=4;
		i=0;
		while(j>=1){
			if(*(strstr(dataget,"227 Entering Passive Mode")+i)==',')j--;
			i++;
		}
		j=i+1;
		while(1){
			if(*(strstr(dataget,"227 Entering Passive Mode")+j)==',')break;
			j++;
		}
		
		snprintf(port1,j-i+1,"%s",strstr(dataget,"227 Entering Passive Mode")+i);
		i=j+1;
		while(1){
			if(*(strstr(dataget,"227 Entering Passive Mode")+i)==')')break;
			i++;
		}
		snprintf(port2,i-j,"%s",strstr(dataget,"227 Entering Passive Mode")+j+1);
		portthread=256*atoi(port1)+atoi(port2);
		
		
	}
	
		
	
	ClearBuf(dataget);
	sprintf(headhost,"REST %d\r\n\r\n",s_info->a1);
	if(send(sock,headhost,strlen(headhost),0)!=strlen(headhost)){
   		printf("Error in sending HEAD\n");
		close(sock);
		sleep(5);
   		DownLoadFtp(s_info);
		return 0;
        }
	recv(sock,dataget,512,0);
	if(strstr(dataget,"227 Entering Passive Mode")!=NULL){
		j=4;
		i=0;
		while(j>=1){
			if(*(strstr(dataget,"227 Entering Passive Mode")+i)==',')j--;
			i++;
		}
		j=i+1;
		while(1){
			if(*(strstr(dataget,"227 Entering Passive Mode")+j)==',')break;
			j++;
		}
		
		snprintf(port1,j-i+1,"%s",strstr(dataget,"227 Entering Passive Mode")+i);
		i=j+1;
		while(1){
			if(*(strstr(dataget,"227 Entering Passive Mode")+i)==')')break;
			i++;
		}
		snprintf(port2,i-j,"%s",strstr(dataget,"227 Entering Passive Mode")+j+1);
		portthread=256*atoi(port1)+atoi(port2);
		
		printf("\n^^^^^^^^^^^^%d^^^^^^^^^^^\n",portthread);
	}
        write(1,dataget,strlen(dataget));
	ClearBuf(dataget);
       
	if(portthread==0){
		close(sock);
		sleep(5);
		DownLoadFtp(s_info);
		return 0;
	}      
       sprintf(get,"RETR %s\r\n\r\n",path);

        
        if(send(sock,get,strlen(get),0)!=strlen(get)){
   		printf("Error in sending get\n");
		close(sock);
		sleep(5);
   		DownLoadFtp(s_info);
		return 0;
        }

	write(1,host,strlen(host));
        s_info->fd=open(filename,O_WRONLY|O_CREAT,0644);
	
        lseek(s_info->fd,s_info->a1,0);
        
        

	connected=FALSE;
	for(i=0;i<=5;i++){
        	if((sockdata=ConnectHttp(host,portthread))<=0)
   			sleep(1);
        	else{
   		connected=TRUE;
   		break;
        	}
    	}
	if(connected=FALSE){
		sleep(5);
		DownLoadFtp(s_info);
		return 0;
	}

        ClearBuf(buf);
	
	boolprint=0;
	if(s_info->booldown==1&&s_info->allowotherdown==1)return 0;	
  	pthread_mutex_lock(&lock);
	s_info->booldown=1;
  	pthread_mutex_unlock(&lock);
	
        while(bytesleft>0){
		
        	readen =ReadEn(sockdata,30);
        	if(readen<1){
			s_info->a1+=offset;
			printf("fails to open sockdata,thread %d restart at offset %d\n",s_info->threadnumber,offset);
			close(sockdata);
			sleep(2);
			pthread_mutex_lock(&lock);
			s_info->booldown=0;
			s_info->allowotherdown=0;
            		pthread_mutex_unlock(&lock);
			DownLoadFtp(s_info);
			return 0;
		}
		boolprint++;
		if(boolprint==10)boolprint=0;
   		if(bytesleft>=1024){
       			bytesget=recv(sockdata,buf,1024,MSG_DONTWAIT);
       			if(bytesget<0){

				s_info->a1+=offset;
				printf("\n!!!!!buf size is %d thread %d try again at  %d!!!!\n",strlen(buf),s_info->threadnumber,offset);
				close(sockdata);
				pthread_mutex_lock(&lock);
				s_info->booldown=0;
				s_info->allowotherdown=0;
            			pthread_mutex_unlock(&lock);
				DownLoadFtp(s_info);
				return 0;	
			}
       			write(s_info->fd,buf,bytesget);
	      		bytesleft-=bytesget;
	      		offset+=bytesget;
	      		sizeget+=bytesget;
	  	}
	  	else{

			bytesget=recv(sockdata,buf,bytesleft,MSG_DONTWAIT);
	      		if(bytesget<0){
				s_info->a1+=offset;
				printf("\n!!!!!thread %d try again at less than 1024 %d!!!!\n",s_info->threadnumber,offset);
				close(sockdata);
				pthread_mutex_lock(&lock);
				s_info->booldown=0;
				s_info->allowotherdown=0;
            			pthread_mutex_unlock(&lock);
				DownLoadFtp(s_info);
				return 0;	
			}
	      		write(s_info->fd,buf,bytesget);
	      		offset+=bytesget;
	      		sizeget+=bytesget;
	      		bytesleft-=bytesget;
			if(bytesleft<1024){
				nextthread++;
			if(g[s_info->threadnumber+nextthread].booldown==0&&g[s_info->threadnumber+nextthread].allowotherdown==1){
        			pthread_mutex_lock(&lock);
				g[s_info->threadnumber+nextthread].booldown=1;
        			pthread_mutex_unlock(&lock);
				bytesleft+=g[s_info->threadnumber+nextthread].a2-g[s_info->threadnumber+nextthread].a1+1;
				s_info->a2=g[s_info->threadnumber+nextthread].a2;
			}
			}
	  	}
		
		if(boolprint==0){
			printf("%f ",(float)sizeget/(float)filelength);
			gettimeofday(&tpend,NULL);
    			timeuse=1000000*(tpend.tv_sec-tpstart.tv_sec)+tpend.tv_usec-tpstart.tv_usec;
    			timeuse/=1000000;
    			printf("Per download rate is %fk/s\n",(float)sizeget/1000/(float)timeuse,(float)timeuse);
		}

	  ClearBuf(buf);
	 }

        printf("****************thread %d bytes get is %d****************\n",s_info->threadnumber,offset);
	close(sock);
	close(sockdata);
        return 0;
    }
    else return -1;
}

/*int Send(int sock,char *fmt,...)
{
    char BUF[1024];
    va_list argptr;
    va_start(argptr,fmt);
    vsprintf(BUF,fmt,argptr);
    va_end(argptr);
    printf("^^^^^BUF is %s^^^\n");
    return send(sock, BUF,strlen(BUF),0);
}*/
int ReadEn(int sock,int n)
{
    fd_set rfdset;
    struct timeval tv;
    tv.tv_sec=n;
    tv.tv_usec=0;
    int readen=0;
    FD_ZERO(&rfdset);
    FD_SET(sock,&rfdset);
    
    
    readen=select(sock+1,&rfdset,NULL,NULL,&tv);

    return readen;
}
int GetThreadSize(void)
{
    int threadsize;
    int ntemp;
    int i;
    if((threadsize=(filelength/nthread))>=2048){
        ntemp=threadsize/2048;
        threadsize=ntemp*2048;
    }
    else{
        threadsize=2048;//the least size of each thread
        for(i=1;i<=nthread;i++){
	  if(i*threadsize>=filelength){
	      nthread=i;
	      break;
	  }
        }
    }
    return threadsize;
}
int GetHttpData()
{
    char head[256];
    char headhost[256];
    char dataget[512];
    int threadsize=0;
    int i_sock,i;
    
    pthread_t thrd[30];
    
    float timeuse;
    

    threadsize=GetThreadSize();
    printf("\nthreadsize is %d, nthread is %d filelength is %d\n",threadsize,nthread,filelength);
    gettimeofday(&tpstart,NULL);
    for(i=0;i<=(nthread)-1;i++){
    pthread_mutex_lock(&lock);
    	g[i].booldown=0;
     pthread_mutex_unlock(&lock);
	g[i].threadnumber=i;
    	
        g[i].a1=threadsize*i;
        g[i].a2=g[i].a1+threadsize-1;
	if(i==(nthread-1))g[i].a2=filelength-1;
        
        pthread_create(&thrd[i],NULL,(void*)DownLoadHttp,(void*)&g[i]);
    }
    for(i=0;i<=(nthread)-1;i++)
        pthread_join(thrd[i],NULL);
    gettimeofday(&tpend,NULL);
    timeuse=1000000*(tpend.tv_sec-tpstart.tv_sec)+tpend.tv_usec-tpstart.tv_usec;
    timeuse/=1000000;
    printf("Per download rate is %fk/s,timeuse is %d",(float)filelength/1000/(float)timeuse,(float)timeuse);
    return 0;
    
}
void usage()
{
	printf("Version 1.0 Build by KongYang, SJTU, China\n");
	printf("usage: lunixdown \"PATH\" [REFERER] threadnumber \n");
	printf("For example: linuxdown \"http://be_heack.com/linuxdown.c\" \"http://be_heack.com/index.html\" 10\n");
	printf("PATH can be got just by right-click the link and copy link location.\n");
	printf("RFERER is the site address you get your PATH from.\n");
	printf("Threadnumber must be an integer less than 20 \n");
	printf("You need to use quotation mark to surround PATH in order to avoid problems caused by \"&\".\n");
	printf("File will be stored at \"./\" with the name got from net.\n");
	
	
}
int GetFtpData()
{
    char head[256];
    char headhost[256];
    char dataget[512];
    int threadsize=0;
    int i_sock,i;
    
    pthread_t thrd[30];
    
    float timeuse;
    
    
    threadsize=GetThreadSize();
    printf("\nthreadsize is %d, nthread is %d filelength is %d\n",threadsize,nthread,filelength);
    gettimeofday(&tpstart,NULL);
    for(i=0;i<=(nthread)-1;i++){
      pthread_mutex_lock(&lock);
    	g[i].booldown=0;
     pthread_mutex_unlock(&lock);
	g[i].threadnumber=i;
        g[i].a1=threadsize*i;
        g[i].a2=g[i].a1+threadsize-1;
	if(i==nthread-1)g[i].a2=filelength-1;

        
        pthread_create(&thrd[i],NULL,(void*)DownLoadFtp,(void*)&g[i]);
    }
    for(i=0;i<=(nthread)-1;i++)
        pthread_join(thrd[i],NULL);
    gettimeofday(&tpend,NULL);
    timeuse=1000000*(tpend.tv_sec-tpstart.tv_sec)+tpend.tv_usec-tpstart.tv_usec;
    timeuse/=1000000;
    printf("Per download rate is %fk/s,timeused is %f",(float)filelength/1000/(float)timeuse,(float)timeuse);
    return 0;
    
}
int main(int argc, char* argv[])
{
    
    char headhost[256];
    char dataget[512];
    int c;
    pthread_t thrd[3];
    int ret,length;
    int i_sock;
    char chost[256],crefer[256];
    
    int i=0;//n_down stands for how many threads user want it to use
    if(argc==1){
    	usage();
	exit(0);
    	
    }
    else if(argc==4){
    	
    	nthread=atoi(argv[3]);
    	if(nthread>20){
        	printf("you can only input a number between 1 and 30\n");
        	exit(0);
    	}
	sprintf(chost,"%s\0",argv[1]);
    	sprintf(crefer,"%s\0",argv[2]);
    }
    else if(argc==3){
    	nthread=atoi(argv[2]);
    	if(nthread>20){
        	printf("you can only input a number between 1 and 30\n");
        	exit(0);
    	}
	sprintf(chost,"%s\0",argv[1]);
    	sprintf(crefer,"\0");
    }
    else{
    	printf("wrong options\n");
	usage();
	exit(0);
    }
    	
    for(i=0;i<=29;i++){
    	g[i].booldown=1;
	g[i].allowotherdown=1;
    }
    sprintf(user,"anonymous");
    sprintf(pass,"123456");
    
    
    
    GetInfo(chost,crefer);
    if(hosttype==HTTP)GetHttpData();
    else if(hosttype==FTP)GetFtpData();
    return 0;
}

