卷曲包装的奇怪行为

时间:2016-10-05 21:31:36

标签: c arm x86-64 libcurl

我在用C编写的项目中使用libcurl。这个应用程序向服务器发出不同的请求,所以我决定制作几个帮助函数来配置CURL对象,发出请求和解析响应。这是curl包装器的代码:

typedef struct  {
    char *ptr;
    size_t len;
} curl_str_t;

typedef size_t (*callback_ptr)(void *, size_t, size_t, void *);

typedef struct {
    CURLoption curl_opt;
    union {
        callback_ptr calback;
        void *obj_ptr;
        long opt;
        curl_off_t offset;
    } opt_param;
} curl_opt_t;

int curl_routine_init_curl_str(curl_str_t *cs) {
    cs->len = 0;
    cs->ptr = malloc(cs->len + 1);
    if (cs->ptr == NULL)
        return -ENOMEM;

    cs->ptr[0] = '\0';
    return 0;
}

size_t curl_routine_curl_write_callback(void *ptr, size_t size, size_t nmeb, 
        curl_str_t *s) {
    size_t new_len = s->len + size * nmeb;
    s->ptr = realloc(s->ptr, new_len + 1);
    if (s->ptr == NULL)
        return -ENOMEM;

    memcpy(s->ptr + s->len, ptr, size * nmeb);
    s->ptr[new_len] = '\0';
    s->len = new_len;

    return size * nmeb;
}

size_t curl_routine_curl_read_callback(void *ptr, size_t size, size_t nmemb, 
        void *stream)  {
    curl_off_t nread;
    size_t retcode = fread(ptr, size, nmemb, stream);
    nread = (curl_off_t)retcode;

    return nread;
}


static int curl_routine_curl_process_set_opt(CURL *curl, const curl_opt_t *opt) {

    long option = (long)opt->curl_opt;

    if (option - CURLOPTTYPE_OFF_T > 0)
        return curl_easy_setopt(curl, opt->curl_opt, opt->opt_param.offset);
    else if (option - CURLOPTTYPE_FUNCTIONPOINT > 0)
        return curl_easy_setopt(curl, opt->curl_opt, opt->opt_param.calback);
#ifdef CURLOPTTYPE_STRINGPOINT
    else if (option - CURLOPTTYPE_STRINGPOINT > 0)
        return curl_easy_setopt(curl, opt->curl_opt, opt->opt_param.obj_ptr);
#endif    
    else if (option - CURLOPTTYPE_OBJECTPOINT > 0)
        return curl_easy_setopt(curl, opt->curl_opt, opt->opt_param.obj_ptr);
    else
        return curl_easy_setopt(curl, opt->curl_opt, opt->opt_param.opt);
}

int curl_routine_curl_process(const char *url, int try_num, char **headers,
        int headers_cnt, const curl_opt_t *opts, int opts_cnt, double *load_speed, 
        double *load_time) {
    CURL *curl = NULL;
    CURLcode curl_res = CURLE_OK;
    char errbuf[CURL_ERROR_SIZE] = { '\0' };
    struct curl_slist *http_headers = NULL;
    int rc = EXIT_SUCCESS, delay = 2, i;
    long http_code = 200;

#ifdef CURL_VERBOSE
    curl_opt_t local_opts[8];
#else
    curl_opt_t local_opts[7];
#endif

    curl_routine_create_curl_opts(local_opts, 
            (sizeof(local_opts) / sizeof(curl_opt_t)) * 2
            ,CURLOPT_FAILONERROR, 1L
            ,CURLOPT_FOLLOWLOCATION, 1L
            ,CURLOPT_ERRORBUFFER, errbuf
            ,CURLOPT_SSL_VERIFYPEER, 0L
            ,CURLOPT_SSL_VERIFYHOST, 0L
            ,CURLOPT_TCP_KEEPALIVE, 1L
            ,CURLOPT_URL, url
#ifdef CURL_VERBOSE
            ,CURLOPT_VERBOSE, 1L
#endif       
            );

    curl = curl_easy_init();
    if (curl) {
        if (headers) {
            for (i = 0; i < headers_cnt; i++)
                http_headers = curl_slist_append(http_headers, headers[i]);
            curl_res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, http_headers);
            if (curl_res != CURLE_OK) {
                log_error("cURL return error: %s\n", curl_easy_strerror(curl_res));
                rc = EXIT_FAILURE;
                goto end;
            }
        }

        if (opts)
            for (i = 0; i < opts_cnt; i++) {
                curl_res = curl_routine_curl_process_set_opt(curl, &opts[i]);
                if (curl_res != CURLE_OK) {
                    log_error("cURL return error: %s\n", curl_easy_strerror(curl_res));
                    rc = EXIT_FAILURE;
                    goto end;
                }
            }

        for (i = 0; i < (sizeof (local_opts) / sizeof (curl_opt_t)); i++) {
            curl_res = curl_routine_curl_process_set_opt(curl, &local_opts[i]);
            if (curl_res != CURLE_OK) {
                log_error("cURL return error: %s\n", curl_easy_strerror(curl_res));
                rc = EXIT_FAILURE;
                goto end;
            }
        }

        while (try_num--) {
            memset(errbuf, '\0', CURL_ERROR_SIZE);
            curl_res = curl_easy_perform(curl);

            if (curl_res == CURLE_OK) {
                curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
                if (load_speed)
                    curl_easy_getinfo(curl, CURLINFO_SPEED_UPLOAD, &load_speed);
                if (load_time)
                    curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &load_time);
                log_debug("Request to '%s' returned with %lu code:%s\n", 
                        url, http_code, errbuf);
                if (http_code >= 200 && http_code < 300) {
                    rc = EXIT_SUCCESS;
                    break;
                } else {
                    rc = http_code;
                }
            } else {
                rc = curl_res;
                log_error("Request to '%s' can't be executed: %s (%s)\n", 
                        url, curl_easy_strerror(rc), errbuf);
                break;
            }

            sleep(delay);
            delay += 3;
        }
    } else {
        log_error("Can't initialize curl\n");
        rc = EXIT_FAILURE;
    }

end:
    curl_easy_cleanup(curl);
    curl_slist_free_all(http_headers);

    return rc;
}

int curl_routine_create_curl_opts(curl_opt_t *opts, int size, ...) {
    va_list ap;
    int i;
    long option;

    if (!opts) 
        return 0;

    va_start(ap, size);
    for (i = 0; i < size / 2; i++) {

        opts[i].curl_opt = va_arg(ap, CURLoption);
        option = (long)opts[i].curl_opt;


        if (option - CURLOPTTYPE_OFF_T > 0)
            opts[i].opt_param.offset = va_arg(ap, curl_off_t);
        else if (option - CURLOPTTYPE_FUNCTIONPOINT > 0)
            opts[i].opt_param.calback = va_arg(ap, callback_ptr);
#ifdef CURLOPTTYPE_STRINGPOINT       
        else if (option - CURLOPTTYPE_STRINGPOINT > 0)
            opts[i].opt_param.obj_ptr = va_arg(ap, char *);
#endif        
        else if (option - CURLOPTTYPE_OBJECTPOINT > 0)
            opts[i].opt_param.obj_ptr = va_arg(ap, void *);
        else
            opts[i].opt_param.opt = va_arg(ap, long);
    }
    va_end(ap);

    return EXIT_SUCCESS;
}

以下是我如何使用它:

int communicate_with_server_tell_about_file(const processing_stack_item_t *item,
        const config_t *config) {
    int rc = EXIT_SUCCESS;
    char *url = NULL;
    char postfields[2048] = { '\0' };
    curl_opt_t opts[1];

    /* Some code */

    if ((rc = curl_routine_create_curl_opts(opts, 2,
            CURLOPT_POSTFIELDS, postfields))) 
        goto end;

    rc = curl_routine_curl_process(url, 2, NULL, 0, opts, 1, NULL, NULL);

end:    
    free(url);
    return rc;
}

还有一个

static int func2(const send_item_t *item) {
    int rc = EXIT_SUCCESS;
    char url[256] = { '\0' };
    char *headers[5];
    FILE *fp = NULL;
    curl_opt_t opts[5];
    long http_code;
    double load_speed, load_time;

    /* Some code */

    fp = fopen(item->fpath, "rb");
    if (!fp) {
        rc = errno;
        print_error("Can't open file '%s': %s", item->fpath, strerror(rc));
        goto end;
    }

    if ((rc = curl_routine_create_curl_opts(opts, 10,
            CURLOPT_PUT, 1L
            ,CURLOPT_UPLOAD, 1L
            ,CURLOPT_READDATA, fp
            ,CURLOPT_READFUNCTION, curl_routine_curl_read_callback
            ,CURLOPT_INFILESIZE, (curl_off_t)item->size
            ))) {
        goto end;
    }

    headers[0] = CONT_TYPE_HEADER;
    headers[1] = x_ms_date_h;
    headers[2] = META_M1_HEADER;
    headers[3] = META_M2_HEADER;
    headers[4] = authorization_header;

#define MBs 1024 / 1024    
    rc = curl_routine_curl_process(url, 2, headers, 5, opts, 5, 
            &load_speed, &load_time);

    if (!rc)
        log_info("File '%s' sent. Speed: %.3f MB/s, Time: %.3f s\n",
                item->name, load_speed / MBs, load_time);
    else
        log_error("Can't send file\n");

end:
    free(authorization_header);
    fclose(fp);
    return rc;
}

所以,当我在我的x86_64计算机上运行构建程序时,一切都运行良好,但是当我为我的ARMV5e板func2构建它时,工作非常奇怪:所有上传的文件都是0字节大小,它看起来像那样curl不会使用curl_routine_curl_read_callback调用我传递给它的callback_ptr。我尝试为其附加调试器并查看curl_routine_curl_read_callback的地址和callback_ptr的值 - 它们是相同的。

还有一个。如果我在func2中重写代码,就像libcurl(内联调用curl_easy_setopt)的示例一样,一切都按照我的计划进行。

有谁能告诉我我做错了什么?或许我错过了什么?

提前致谢。

P.S。顺便说一句,我的编译器是gcc v 4.9.2,ARM板的libcurl是4.3.0,ARM板的标准C库是uClib v.0.9.33.2

0 个答案:

没有答案