LinuxC语言实现上传功能(curl)

来源:互联网 发布:mysql最大连接数 编辑:程序博客网 时间:2024/06/04 18:55

该程序是对接阿里云时做得,上传其他平台可能会略有差异,请注意!

直接上代码(注意参数,最好能看懂上传的大致流程,其实也是用curl):

#include <stdio.h>#include <string.h>#include <time.h>#include <fcntl.h>#include <sys/stat.h>#include "curl.h"#include "util.h"static char AccessKeyIdG[64] = {0};static char SecretAccessKeyG[64] = {0};static char Server_addr[64] = {0};static char Bucket[64] = {0};#define CONFIGINI"/mnt/mtd/SystemConfig.ini"time_t start_time,end_time;#define S3_METADATA_HEADER_NAME_PREFIX     "x-amz-meta-"#define S3_MAX_METADATA_COUNT \    (2048 / (sizeof(S3_METADATA_HEADER_NAME_PREFIX "nv") - 1))#define COMPACTED_METADATA_BUFFER_SIZE \(2048 * sizeof(S3_METADATA_HEADER_NAME_PREFIX "n: v"))// Declare a string multibuffer with the given name of the given maximum size#define string_multibuffer(name, size)                                  \    char name[size];                                                    \    int name##Sizetypedef struct _RequestComputedValues{    char host[80];    char uri[128];    int fileLen; // 要传输文件的长度    // All x-amz- headers, in normalized form (i.e. NAME: VALUE, no other ws)    char *amzHeaders[S3_MAX_METADATA_COUNT + 2]; // + 2 for acl and date    // The number of x-amz- headers    int amzHeadersCount;    // Storage for amzHeaders (the +256 is for x-amz-acl and x-amz-date)    char amzHeadersRaw[COMPACTED_METADATA_BUFFER_SIZE + 256 + 1];    // URL-Encoded key    char urlEncodedKey[60];    string_multibuffer(canonicalizedAmzHeaders,                       COMPACTED_METADATA_BUFFER_SIZE + 256 + 1);    // Canonicalized resource    char canonicalizedResource[128];    // Content-Type header (or empty)    char contentTypeHeader[2];    // Content-MD5 header (or empty)    char md5Header[2];    // Authorization header    char authorizationHeader[128];} RequestComputedValues;int Config_Read_String_Params(const char* lpSessionName,const char* lpKeyName,char* lpOutBuff){    int value;    intret;    charszStr[300];    ret = GetProfileString(CONFIGINI,lpSessionName,lpKeyName,szStr,300);    if(ret == -1)    {        ret = GetProfileInteger(CONFIGINI,lpSessionName,lpKeyName,&value);        if(ret == -1)        {            printf("Load [%s] config [%s] error\n",lpSessionName,lpKeyName);            return -1;        }        else        {            sprintf(lpOutBuff,"%d",value);            printf("Load [%s][%s] = [%s]\n",lpSessionName,lpKeyName,lpOutBuff);        }    }    else    {        sprintf(lpOutBuff,"%s",szStr);        printf("Load [%s][%s] = [%s]\n",lpSessionName,lpKeyName,lpOutBuff);    }    return 0;}int checkout_server_addr(){    int ret = 0;    Config_Read_String_Params("Tutk","AccessKeyIdG",AccessKeyIdG);    if(strlen(AccessKeyIdG) == 0)    {        printf("AccessKeyIdG : NULL \n");        return 0;    }    else    {        printf("AccessKeyIdG :%s\n",AccessKeyIdG);    }        Config_Read_String_Params("Tutk","SecretAccessKeyG",SecretAccessKeyG);    if(strlen(SecretAccessKeyG) == 0)    {        printf("SecretAccessKeyG : NULL \n");        return 0;    }    else    {        printf("SecretAccessKeyG :%s\n",SecretAccessKeyG);    }        Config_Read_String_Params("Tutk","Server_addr",Server_addr);    if(strlen(Server_addr) == 0)    {        printf("Server_addr : NULL \n");        return 0;    }    else    {        printf("Server_addr :%s\n",Server_addr);    }        Config_Read_String_Params("Tutk","Bucket",Bucket);    if(strlen(Bucket) == 0)    {        printf("Bucket : NULL \n");        return 0;    }    else    {        printf("Bucket :%s\n",Bucket);    }        return 1;}static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *userp){    printf("[%s:%d] size[%d] nmemb[%d]\n", __FUNCTION__, __LINE__, size, nmemb);    FILE *fp = (FILE *)userp;    if(!fp)    {        printf("[%s:%d] file point fp NULL\n", __FUNCTION__, __LINE__);    }    if(size*nmemb < 1)    {        printf("read_callback error, size[%d] nmemb[%d]\n", size, nmemb);        return 0;    }    end_time = time(NULL);    if((end_time - start_time) > 120)    {        printf("sending overtime:%d   close file...\n", end_time - start_time);        close(fp);        return 0;    }    else    {        printf("sending...:%ld\n", end_time);        size_t retcode = fread(ptr, size, nmemb, fp);        printf("read_callback fread retcode:%d\n", retcode);        return retcode;    }}int init_amz_header(RequestComputedValues *values){    int len = 0;    // Append a header to amzHeaders, trimming whitespace from the end.    // Does NOT trim whitespace from the beginning.#define headers_append(isNewHeader, format, ...)                        \do {                                                                \    if (isNewHeader) {                                              \        values->amzHeaders[values->amzHeadersCount++] =             \            &(values->amzHeadersRaw[len]);                          \    }                                                               \    len += snprintf(&(values->amzHeadersRaw[len]),                  \                    sizeof(values->amzHeadersRaw) - len,            \                    format, __VA_ARGS__);                           \    if (len >= (int) sizeof(values->amzHeadersRaw)) {               \        return -1;                      \    }                                                               \    while ((len > 0) && (values->amzHeadersRaw[len - 1] == ' ')) {  \        len--;                                                      \    }                                                               \    values->amzHeadersRaw[len++] = 0;                               \} while (0)    //headers_append(1, "x-amz-server-side-encryption: %s", "AES256");    // Add the x-amz-date header    time_t now = time(NULL);    char date[64];    struct tm *gmt;    gmt = gmtime(&now);    strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S GMT", gmt);    headers_append(1, "Date: %s", date);}#define  MAX_MSG_LEN 1024static int aws_authorizationHeader(RequestComputedValues *values){    printf("[%s][%s][%d]: \n",__FILE__,__FUNCTION__,__LINE__);    // We allow for:    // 17 bytes for HTTP-Verb + \n    // 129 bytes for Content-MD5 + \n    // 129 bytes for Content-Type + \n    // 1 byte for empty Date + \n    // CanonicalizedAmzHeaders & CanonicalizedResource    char signbuf[17 + 129 + 129 + 1 +                 (sizeof(values->canonicalizedAmzHeaders) - 1) +                 (sizeof(values->canonicalizedResource) - 1) + 1] = {0};    int len = 0;#define signbuf_append(format, ...)                             \    len += snprintf(&(signbuf[len]), sizeof(signbuf) - len,     \                    format, __VA_ARGS__)    signbuf_append("%s\n", "PUT");    // For MD5 and Content-Type, use the value in the actual header, because    // it's already been trimmed    signbuf_append("%s\n", values->md5Header[0] ?                   &(values->md5Header[sizeof("Content-MD5: ") - 1]) : "");    /*    signbuf_append("%s\n", "video/avi");    sprintf(values->contentTypeHeader, "Content-Type: %s", "video/avi");    */    signbuf_append    ("%s\n", values->contentTypeHeader[0] ?     &(values->contentTypeHeader[sizeof("Content-Type:") - 1]) : "");    //signbuf_append("%s", values->canonicalizedAmzHeaders);    char date[128] = {0};    //sprintf(values->canonicalizedAmzHeaders, "Date: %s", date);    memcpy(date, &values->canonicalizedAmzHeaders[sizeof("Date:")-1], sizeof(date));    signbuf_append("%s", date);    signbuf_append("%s", values->canonicalizedResource);    // Generate an HMAC-SHA-1 of the signbuf    unsigned char hmac[20];    OSS_HMAC_SHA1(hmac, (unsigned char *) SecretAccessKeyG,                  strlen(SecretAccessKeyG),                  (unsigned char *) signbuf, len);    //DPRINT("HMAC_SHA1 hmac:[%s]\n", hmac);    // Now base-64 encode the results    char b64[((20 + 1) * 4) / 3];    int b64Len = oss_base64Encode(hmac, 20, b64);    //DPRINT("base64Encode hmac:[%s] b64[%s]\n", hmac, b64);    snprintf(values->authorizationHeader, sizeof(values->authorizationHeader),             "Authorization: OSS %s:%.*s", AccessKeyIdG,             b64Len, b64);    printf("authorizationHeader:[%s]\n", values->authorizationHeader);    printf("signbuf:{\n%s\n}\n", signbuf);    return 1;}// Compose the URI to use for the request given the request parametersstatic int compose_uri(char *buffer, int bufferSize,                       const char *urlEncodedKey){    int len = 0;#define uri_append(fmt, ...)                                                 \    do {                                                                     \        len += snprintf(&(buffer[len]), bufferSize - len, fmt, __VA_ARGS__); \        if (len >= bufferSize) {                                             \            return -1;                                       \        }                                                                    \    } while (0)    //uri_append("http%s://", (bucketContext->protocol == S3ProtocolHTTP) ? "" : "s");    uri_append("http%s://", "");    uri_append("%s.%s", Bucket, Server_addr);    uri_append("%s", "/");    uri_append("%s", urlEncodedKey);    return 1;}// Simple comparison function for comparing two HTTP header names that are// embedded within an HTTP header line, returning true if header1 comes// before header2 alphabetically, false if notstatic int headerle(const char *header1, const char *header2){    while (1)    {        if (*header1 == ':')        {            return (*header2 != ':');        }        else if (*header2 == ':')        {            return 0;        }        else if (*header2 < *header1)        {            return 0;        }        else if (*header2 > *header1)        {            return 1;        }        header1++, header2++;    }}// Replace this with merge sort eventually, it's the best stable sort.  But// since typically the number of elements being sorted is small, it doesn't// matter that much which sort is used, and gnome sort is the world's simplest// stable sort.  Added a slight twist to the standard gnome_sort - don't go// forward +1, go forward to the last highest index considered.  This saves// all the string comparisons that would be done "going forward", and thus// only does the necessary string comparisons to move values back into their// sorted position.static void header_gnome_sort(const char **headers, int size){    int i = 0, last_highest = 0;    while (i < size)    {        if ((i == 0) || headerle(headers[i - 1], headers[i]))        {            i = ++last_highest;        }        else        {            const char *tmp = headers[i];            headers[i] = headers[i - 1];            headers[--i] = tmp;        }    }}static void canonicalize_amz_headers(RequestComputedValues *values){    // Make a copy of the headers that will be sorted    const char *sortedHeaders[S3_MAX_METADATA_COUNT];    memcpy(sortedHeaders, values->amzHeaders,           (values->amzHeadersCount * sizeof(sortedHeaders[0])));    // Now sort these    header_gnome_sort(sortedHeaders, values->amzHeadersCount);    // Now copy this sorted list into the buffer, all the while:    // - folding repeated headers into single lines, and    // - folding multiple lines    // - removing the space after the colon    int lastHeaderLen = 0, i;    char *buffer = values->canonicalizedAmzHeaders;    for (i = 0; i < values->amzHeadersCount; i++)    {        const char *header = sortedHeaders[i];        const char *c = header;        // If the header names are the same, append the next value        if ((i > 0) &&                !strncmp(header, sortedHeaders[i - 1], lastHeaderLen))        {            // Replacing the previous newline with a comma            *(buffer - 1) = ',';            // Skip the header name and space            c += (lastHeaderLen + 1);        }        // Else this is a new header        else        {            // Copy in everything up to the space in the ": "            while (*c != ' ')            {                *buffer++ = *c++;            }            // Save the header len since it's a new header            lastHeaderLen = c - header;            // Skip the space            c++;        }        // Now copy in the value, folding the lines        while (*c)        {            // If c points to a \r\n[whitespace] sequence, then fold            // this newline out            if ((*c == '\r') && (*(c + 1) == '\n') && is_blank(*(c + 2)))            {                c += 3;                while (is_blank(*c))                {                    c++;                }                // Also, what has most recently been copied into buffer amy                // have been whitespace, and since we're folding whitespace                // out around this newline sequence, back buffer up over                // any whitespace it contains                while (is_blank(*(buffer - 1)))                {                    buffer--;                }                continue;            }            *buffer++ = *c++;        }        // Finally, add the newline        *buffer++ = '\n';    }    // Terminate the buffer    *buffer = 0;}void init_header(RequestComputedValues *values, char *filename, int filesize){    if(!filename)    {        printf("filename NULL, error\n");        return ;    }    //memset(&rq_computed, 0, sizeof(rq_computed));    values->fileLen = filesize;    init_amz_header(values);    //set Url    snprintf(values->host, sizeof(values->host),             "%s.%s", Bucket, Server_addr);    printf("init_header values->host[%s]\n", values->host);    //filename    snprintf(values->urlEncodedKey, sizeof(values->urlEncodedKey),             "%s", filename);    printf("init_header values->urlEncodedKey[%s]\n", values->urlEncodedKey);    canonicalize_amz_headers(values);    printf("canonicalize_amz_headers:[%s]\n", values->canonicalizedAmzHeaders);    //设置上传虚拟地址    snprintf(values->canonicalizedResource, sizeof(values->canonicalizedResource),             "/%s/%s", Bucket, values->urlEncodedKey);    aws_authorizationHeader(values);    compose_uri(values->uri, sizeof(values->uri), values->urlEncodedKey);}int setup_url(RequestComputedValues *values, CURL *curl){    printf("[%s][%s][%d]: \n",__FILE__,__FUNCTION__,__LINE__);    int status;#define curl_easy_setopt_safe(opt, val)                                 \if ((status = curl_easy_setopt\ (curl, opt, val)) != CURLE_OK) {\return status;\}    // Ask curl to parse the Last-Modified header.  This is easier than    // parsing it ourselves.    printf("[%s][%s][%d]: \n",__FILE__,__FUNCTION__,__LINE__);    struct curl_slist *headers_slist = 0;    // Append standard headers#define append_standard_header(fieldName)                               \    if (values-> fieldName [0]) {                                       \        headers_slist = curl_slist_append(headers_slist,          \                                             values-> fieldName);       \    }    append_standard_header(contentTypeHeader);    append_standard_header(md5Header);    // Append x-amz- headers    int i;    for (i = 0; i < values->amzHeadersCount; i++)    {        printf("values->amzHeaders[%d]:%s\n", i, values->amzHeaders[i]);        headers_slist =            curl_slist_append(headers_slist, values->amzHeaders[i]);    }    append_standard_header(authorizationHeader);    {        char header[256];        snprintf(header, sizeof(header), "Content-Length: %llu",                 (unsigned long long) values->fileLen);        headers_slist = curl_slist_append(headers_slist, header);        headers_slist = curl_slist_append(headers_slist, "Transfer-Encoding:");        headers_slist = curl_slist_append(headers_slist, "Expect:");    }    // Set the HTTP headers    curl_easy_setopt_safe(CURLOPT_HTTPHEADER, headers_slist);    curl_easy_setopt_safe(CURLOPT_URL, values->uri);    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 120);//设置超时时间    // Set request type.    curl_easy_setopt_safe(CURLOPT_UPLOAD, 1);    printf("[%s][%s][%d]: \n",__FILE__,__FUNCTION__,__LINE__);    return 1;}int _upload(char *avi_filename,char *upload_path){    CURL *curl;    CURLcode res;    struct stat file_info;    char filename[60] = {0};    FILE *out = NULL;    printf("----------avi_filename: %s\n",avi_filename);    printf("----------upload_path: %s\n",upload_path);    if(!checkout_server_addr())    {        printf("checkout_server_addr failed!\n");        return -1;    }    printf("checkout_server_addr successfully!\n");    if(avi_filename != NULL)    {        strcpy(filename, avi_filename);        out = fopen(filename, "rb");        if(!out)        {            printf("fopen filename %s failed\n", filename);            return -1;        }    }    else    {        printf("avi_filename is NULL!\n");        return -1;    }    stat(filename, &file_info);    int uploadsize = file_info.st_size;    /* In windows, this will init the winsock stuff */    res = curl_global_init(CURL_GLOBAL_DEFAULT);    /* Check for errors */    if(res != CURLE_OK)    {        fprintf(stderr, "curl_global_init() failed: %s\n",                curl_easy_strerror(res));        fclose(out);        return -1;    }    RequestComputedValues rq_computed;    memset(&rq_computed, 0, sizeof(rq_computed));    char object_name[128] = {0};    //strcpy(object_name, upload_path);    sprintf(object_name, "%s", upload_path);    printf("----------object_name: %s\n",object_name);    printf("----------uploadsize: %d\n",uploadsize);    init_header(&rq_computed, object_name, uploadsize);    /* get a curl handle */    curl = curl_easy_init();    if(curl)    {        printf("url:%s\n", rq_computed.uri);        /* First set the URL that is about to receive our POST. */        //curl_easy_setopt(curl, CURLOPT_URL, url);        setup_url(&rq_computed, curl);#if 0        /* enable uploading */        curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);        /* HTTP PUT please */        curl_easy_setopt(curl, CURLOPT_PUT, 1L);#endif        /* we want to use our own read function */        curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);        /* pointer to pass to our read function */        curl_easy_setopt(curl, CURLOPT_READDATA, out);        /* get verbose debug output please */        //curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);        /* Perform the request, res will get the return code */        start_time = time(NULL);        printf("start_time:%ld\n", start_time);        res = curl_easy_perform(curl);        /* Check for errors */        if(res != CURLE_OK)                     //传输失败        {            fprintf(stderr, "curl_easy_perform() failed: %s\n",                    curl_easy_strerror(res));            fclose(out);            curl_easy_cleanup(curl);            curl_global_cleanup();                        return -1;                                              }        /* always cleanup */        curl_easy_cleanup(curl);    }    curl_global_cleanup();    printf("send finish at time:%ld\n", time(NULL));    fclose(out);    return 0;}