欢迎来到虫虫下载站 | 资源下载 资源专辑 关于我们
虫虫下载站

downloadmanager.cpp

这是一个mp3的源代码
CPP
第 1 页 / 共 3 页
字号:
}

bool DownloadManager::HasItem(DownloadItem* item)
{
    return (IndexOf(item) != kInvalidIndex);
}

// Internal functions

inline uint32 DownloadManager::CheckIndex(uint32 index)
{
	// If we're dealing with a bogus index then set it to -1.
	if(index >= CountItems())
    {
		index = kInvalidIndex;
    }

	return index;
}

DownloadItem* DownloadManager::GetNextQueuedItem()
{
    int           i, total = 0;

    if (m_downloadIndex < 0 || m_downloadIndex >= (int)m_itemList.size())
        m_downloadIndex = 0;

    for(i = m_downloadIndex, total = 0; i < (int)m_itemList.size(); 
        i = (i + 1) % m_itemList.size(), total++)
    {
        if (total >= (int)m_itemList.size())
            return NULL;
           
        if (m_itemList[i]->GetState() == kDownloadItemState_Queued)
        {
            m_downloadIndex++;
            return m_itemList[i];
        }
    }
    
    return NULL;
}

static int32 GetContentLengthFromHeader(const char* buffer)
{
    int32 result = -1;

    char* cp = strstr(buffer, "Content-Length:");

    if(cp)
    {
        cp += strlen("Content-Length:") + 1;

        result = atoi(cp);
    }

    return result;
}

const uint8 kHttpPort = 80;
const uint32 kMaxHostNameLen = 64;

static bool IsHTTPHeaderComplete(char* buffer, uint32 length)
{
    bool result = false;

    //if(length >= 4)
    //{
        //if( (buffer[0] == 'H' && buffer[1] == 'T' 
        //       && buffer[2] == 'T' && buffer[3] == 'P'))
        //{
            //cout << "buffer is HTTP" << endl;

            for(char* cp = buffer; cp < buffer + length; cp++)
            {
                if(!strncmp(cp, "\n\n", 2) || !strncmp(cp, "\r\n\r\n", 4))
                {
                    result = true;
                    break;
                }
            }
        //}
    //}

    return result;
}

Error DownloadManager::Download(DownloadItem* item)
{
    Error result = kError_InvalidParam;

    //*m_debug << "Downloading Item: " << item->SourceURL() << endl;
    assert(item);

    if(item)
    {
        char hostname[kMaxHostNameLen + 1];
        char localname[kMaxHostNameLen + 1];
        char proxyname[kMaxHostNameLen + 1];
        unsigned short port;
        struct sockaddr_in  addr;
        struct hostent      host;
        SOCKET s = -1;
        char* file = NULL;
        char* destPath = NULL;
        bool useProxy;

        destPath = new char[_MAX_PATH];
        uint32 length = _MAX_PATH;

        m_context->prefs->GetPrefString(kSaveMusicDirPref, destPath, &length);

        strcat(destPath, DIR_MARKER_STR);
        strcat(destPath, item->DestinationFile().c_str());

        result = kError_ProtocolNotSupported;

        // where should we connect to?
        if(!strncasecmp(item->SourceURL().c_str(), "http://", 7))
        {
            int32 numFields;
            uint32 length;

            result = kError_NoErr;  

            m_context->prefs->GetUseProxyServer(&useProxy);

            length = sizeof(proxyname);
            m_context->prefs->GetProxyServerAddress(proxyname, &length);

            if(useProxy)
            {
                numFields = sscanf(proxyname, 
                                   "http://%[^:/]:%hu", hostname, &port);

                strcpy(proxyname, item->SourceURL().c_str());
                file = proxyname;
            }
            else
            {
                numFields = sscanf(item->SourceURL().c_str(), 
                               "http://%[^:/]:%hu", hostname, &port);

                file = strchr(item->SourceURL().c_str() + 7, '/');
            }

            if(numFields < 1)
            {
                result = kError_InvalidURL;     
            }

            if(numFields < 2)
            {
                port = kHttpPort;
            }            
        }

        if(item->GetState() == kDownloadItemState_Cancelled ||
           item->GetState() == kDownloadItemState_Paused)
            result = kError_UserCancel;

        // get hostname
        if(IsntError(result))
        {
            struct hostent* hostByName;
            struct hostent  hostByIP;

            //*m_debug << "gethostbyname: " << hostname << endl;
            hostByName = gethostbyname(hostname);

            // On some stacks a numeric IP address
            // will not parse with gethostbyname.  
            // If that didn't work try to convert it as a
            // numeric address before giving up.
            if(!hostByName)
            {
                static unsigned long ip;
                static char *addr_ptr[2] = {(char*)&ip, NULL};

                if((ip = inet_addr(hostname)) < 0) 
                    result =  kError_CantFindHost;
                else
                {
                    hostByIP.h_length = sizeof(uint32);
                    hostByIP.h_addrtype = AF_INET;
                    hostByIP.h_addr_list = (char**)&addr_ptr;
                    hostByName = &hostByIP;
                }
            }

            if(IsntError(result))
            {
                memcpy(&host, hostByName, sizeof(struct hostent));
            }

            if(item->GetState() == kDownloadItemState_Cancelled ||
               item->GetState() == kDownloadItemState_Paused)
                result = kError_UserCancel;
        }

        // open socket
        if(IsntError(result))
        {
            memset(&addr, 0x00, sizeof(struct sockaddr_in));
            memcpy(&addr.sin_addr, host.h_addr, host.h_length);
            addr.sin_family= host.h_addrtype;
            addr.sin_port= htons(port); 

            //*m_debug << "socket" << endl;

            s = socket(host.h_addrtype, SOCK_STREAM, 0);

            if(s < 0)
                result = kError_CantCreateSocket;

            if(item->GetState() == kDownloadItemState_Cancelled ||
               item->GetState() == kDownloadItemState_Paused)
                result = kError_UserCancel;
        }

        // connect and send request
        if(IsntError(result))
        {
            //*m_debug << "connect" << endl;

            if(connect(s,(const struct sockaddr*)&addr, sizeof(struct sockaddr)))
                result = kError_CannotBind;

            if(item->GetState() == kDownloadItemState_Cancelled ||
               item->GetState() == kDownloadItemState_Paused)
                result = kError_UserCancel;

            if(IsntError(result))
            {
                gethostname(localname, kMaxHostNameLen);    

                const char* kHTTPQuery = "GET %s HTTP/1.1\n"
                                         "Host: %s\n"
                                         "Accept: */*\n" 
                                         "User-Agent: FreeAmp/%s\n";

                const char* kRange = "Range: %lu-\n"
                                     "If-Range: %s\n";

                const char* kCookie = "Cookie: %s\n";

                // the magic 58 is enough for fixed length time in
                // HTTP time format + 2 terabyte length range numbers.
                // the 2 extra bytes on the end is an extra \n and 0x00 byte
                char* query = new char[ strlen(kHTTPQuery) + 
                                        strlen(file) +
                                        strlen(localname) +
                                        strlen(FREEAMP_VERSION)+
                                        (item->GetBytesReceived() ? (strlen(kRange) + 58): 0 ) +
                                        (item->SourceCookie().size() ? (item->SourceCookie().size() + strlen(kCookie)): 0) +
                                        2];
            
                sprintf(query, kHTTPQuery, file, localname, FREEAMP_VERSION);

                // do we need to request a range?
                if(item->GetBytesReceived())
                { 
                    struct stat st;

                    if(-1 != stat(destPath, &st))
                    {
                        char* range = new char[strlen(kRange) + 58 + 1];
                        char time[32];

                        RFC822GMTTimeString(gmtime(&st.st_mtime), time);

                        sprintf(range, kRange, item->GetBytesReceived(), time);

                        strcat(query, range);

                        delete [] range;
                    }
                    else
                    {
                        item->SetBytesReceived(0);
                    }
                }

                if(item->SourceCookie().size())
                {
                    char* cookie = new char[strlen(kCookie) + item->SourceCookie().size() + 1];

                    sprintf(cookie, kCookie, item->SourceCookie().c_str());

                    strcat(query, cookie);

                    delete [] cookie;
                }
            
                strcat(query, "\n");

                //cout << query << endl;

                int count;

                //*m_debug << "send:" << endl << query;

                count = send(s, query, strlen(query), 0);

                if(count != (int)strlen(query))
                {
                    result = kError_IOError;
                }

                if(item->GetState() == kDownloadItemState_Cancelled ||
                   item->GetState() == kDownloadItemState_Paused)
                    result = kError_UserCancel;

                delete [] query;
            }
        }

        // receive response
        if(IsntError(result))
        {
            uint32 bufferSize = 2048;
            char* buffer = NULL;
            int count;
            uint32 total = 0;

            buffer = (char*)malloc(bufferSize);

            result = kError_OutOfMemory;

            if(buffer)
            {
                result = kError_NoErr;

                do
                {
                    if(total >= bufferSize - 1)
                    {
                        bufferSize *= 2;

                        buffer = (char*) realloc(buffer, bufferSize);

                        if(!buffer)
                        {
                            result = kError_OutOfMemory;
                            break;
                        }
                    }

                    count = recv(s, buffer + total, bufferSize - total - 1, 0);

                    if(count > 0)
                        total += count;
                    else
                    {
                        result = kError_IOError;
                    }

                    if(item->GetState() == kDownloadItemState_Cancelled ||
                       item->GetState() == kDownloadItemState_Paused)
                        result = kError_UserCancel;


                }while(!IsHTTPHeaderComplete(buffer, total) && IsntError(result));
            }

            // parse header
            if(IsntError(result))
            {
                uint32 returnCode = atoi(buffer+9);
                buffer[total] = 0x00;
                //cout << buffer << endl;

                //cout << returnCode << endl;

                switch(buffer[9])
                {
                    // 1xx: Informational - Request received, continuing process
                    case '1':
                    {
                        // not sure what to do here... continue receiving???
                    }    

                    // 2xx: Success - The action was successfully received,
                    // understood, and accepted
                    case '2':
                    {
                        result = kError_UnknownErr;

                        int32 fileSize = GetContentLengthFromHeader(buffer);

                        if(fileSize > 0)
                            item->SetTotalBytes(fileSize);

                        //cout << destPath << endl;

                        int openFlags = O_BINARY|O_CREAT|O_RDWR|O_APPEND;

                        if(returnCode != 206) // server oked partial download
                        {
                            item->SetBytesReceived(0);
                            openFlags |= O_TRUNC;
                        }

                        //*m_debug << "open file:" << destPath<< endl;

                        int fd = open(destPath, openFlags, S_IREAD | S_IWRITE);

                        if(fd >= 0)
                        {
                            result = kError_NoErr;

                            char* cp = strstr(buffer, "\n\n");

                            if(cp)
                                cp += 2;
                            else
                            {
                                cp = strstr(buffer, "\r\n\r\n");

                                if(cp)
                                    cp += 4;
                            }

                            if(cp)
                            {
                                if(cp - buffer < (int)total)
                                {
                                    write(fd, cp, total - (cp - buffer));
                                    item->SetBytesReceived(total - (cp - buffer) + item->GetBytesReceived());
                                    SendProgressMessage(item);
                                }
                            }

                            do
                            {
                                count = recv(s, buffer, bufferSize, 0);

                                if(count > 0)
                                {
                                    write(fd, buffer, count);
                                    item->SetBytesReceived(count + item->GetBytesReceived());
                                    SendProgressMessage(item);
                                }

                                if(count < 0)
                                    result = kError_IOError;
                                
                                if(item->GetState() == kDownloadItemState_Cancelled ||
                                   item->GetState() == kDownloadItemState_Paused)
                                    result = kError_UserCancel;

                            }while(count > 0 && IsntError(result) && m_runDownloadThread &&
                                  item->GetTotalBytes() > item->GetBytesReceived());

                            close(fd);                           
                        }
                        else
                        {
                            //*m_debug << "error opening  file: " <<  endl;

                            switch(errno)
                            {
                                case EEXIST:
                                    result = kError_FileExists;
                                    break;

                                case EACCES:
                                    result = kError_FileNoAccess;
                                    break;

                                case ENOENT:
                                    result = kError_FileNotFound;
                                    break;

                                case EMFILE:
                                    result = kError_FileNoHandles;
                                    break;

                                case EINVAL:
                                    result = kError_FileInvalidArg;
                                    break;
                
                            }
                        }
                        
                        break;
                    }

                    // 3xx: Redirection - Further action must be taken in order to
                    // complete the request
                    case '3':
                    {
                        char* cp = strstr(buffer, "Location:");
                        //int32 length;

                        if(cp)
                        {
                            cp += 9;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -