欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

curl上传文件调试:A libcurl function was given a bad argument

程序员文章站 2024-03-15 23:01:30
...

使用的libcurl版本为:android7.1–0x073201 android4.4–0x073000

事情缘由

需将android4.4上的日志上传功能移植到android7.1上,但是移植好后出现了如下截图的问题
curl上传文件调试:A libcurl function was given a bad argument

过程

7.1和4.4有一点的区别很重要,那就是参数类型的位数不一样,7.1使用的是64位,4.4用的是32位的。在相同的源码情况下,4.4正常使用,7.1出现了如上截图的问题,那就必须是libcurl库的问题了,使用grep命令找到错误信息出现的位置加上fprintf(stderr,"…")相应的函数名。发现如下图SIZEOF_SIZE_T未定义、CURL_SIZEOF_CURL_OFF_T为8,andoird4.4上的SIZEOF_SIZE_T为4、CURL_SIZEOF_CURL_OFF_T也为4,归根到底就是默认配置的位数不配置导致出错。因此#if (8 < CURL_SIZEOF_CURL_OFF_T)就可以解决问题了,如下图为成功的消息打印。
curl上传文件调试:A libcurl function was given a bad argumentcurl上传文件调试:A libcurl function was given a bad argument
附上正常使用的源码:

/***************************************************************************
 *                                  _   _ ____  _
 *  Project                     ___| | | |  _ \| |
 *                             / __| | | | |_) | |
 *                            | (__| |_| |  _ <| |___
 *                             \___|\___/|_| \_\_____|
 *
 * Copyright (C) 1998 - 2015, Daniel Stenberg, <aaa@qq.com>, et al.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution. The terms
 * are also available at https://curl.haxx.se/docs/copyright.html.
 *
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
 * copies of the Software, and permit persons to whom the Software is
 * furnished to do so, under the terms of the COPYING file.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ***************************************************************************/
/* <DESC>
 * Upload to a file:// URL
 * </DESC>
 */
#include <stdio.h>
#include <curl/curl.h>
#include <sys/stat.h>
#include <fcntl.h>

int upload_result;
int upload_progress;
char append_zip_file_name[32] = {0};
#define CURL_WRITE_BUFFER_SIZE 1024
size_t callback_get_head(void *ptr, size_t size, size_t nmemb, void *userp) 
 {  
	 int left = CURL_WRITE_BUFFER_SIZE-strlen(userp);
	 if(left > size * nmemb)
	 {
         strcat(userp,ptr);
	 }
	 else if(left > 0)
	 {
         strncat(userp,ptr,left);
	 }
     
    return size * nmemb;     //必须返回这个大小, 否则只回调一次, 不清楚为何. 
 } 

static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *stream)
{
  size_t retcode;
  curl_off_t nread;

  /* in real-world cases, this would probably get this data differently
     as this fread() stuff is exactly what the library already would do
     by default internally */
  retcode = fread(ptr, size, nmemb, stream);

  nread = (curl_off_t)retcode;

  printf("*** We read %d bytes from file\n", nread);

  return retcode;
}

#define STOP_DOWNLOAD_AFTER_THIS_MANY_BYTES         6000
#define MINIMAL_PROGRESS_FUNCTIONALITY_INTERVAL     3

struct myprogress {
  double lastruntime;
  CURL *curl;
};

/* this is how the CURLOPT_XFERINFOFUNCTION callback works */
static int xferinfo(void *p,
                    curl_off_t dltotal, curl_off_t dlnow,
                    curl_off_t ultotal, curl_off_t ulnow)
{
  struct myprogress *myp = (struct myprogress *)p;
  CURL *curl = myp->curl;
  double curtime = 0;

  curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &curtime);

  /* under certain circumstances it may be desirable for certain functionality
     to only run every N seconds, in order to do this the transaction time can
     be used */
  if((curtime - myp->lastruntime) >= MINIMAL_PROGRESS_FUNCTIONALITY_INTERVAL) {
    myp->lastruntime = curtime;
    printf("TOTAL TIME: %f \r\n", curtime);
  }

  printf("UP: %" CURL_FORMAT_CURL_OFF_T " of %" CURL_FORMAT_CURL_OFF_T
          "  DOWN: %" CURL_FORMAT_CURL_OFF_T " of %" CURL_FORMAT_CURL_OFF_T,
          ulnow, ultotal, dlnow, dltotal);
  
  if(ultotal){
      upload_result = 100;
      upload_progress = (int)((float)ulnow/ultotal*100);
    //  msg(M_INFO,"UP progress: %d%",upload_progress);         
  } 
  //if(dltotal) msg(M_INFO,"DOWN progress: %3.0f%%",((float)dlnow/dltotal*100));

  if(dlnow > STOP_DOWNLOAD_AFTER_THIS_MANY_BYTES)
    return 1;
  return 0;
}

/* for libcurl older than 7.32.0 (CURLOPT_PROGRESSFUNCTION) */
static int older_progress(void *p,
                          double dltotal, double dlnow,
                          double ultotal, double ulnow)
{
  return xferinfo(p,
                  (curl_off_t)dltotal,
                  (curl_off_t)dlnow,
                  (curl_off_t)ultotal,
                  (curl_off_t)ulnow);
}

static int http_post_file(char *url, const char *filename)
{
    CURL *curl = NULL;
    CURLcode res = CURLE_OK; //CURL API返回值
    long errcode = 0; //HTTP错误码
    char buffer[CURL_WRITE_BUFFER_SIZE+1] = {0};
    int ret = 0;
    FILE *fd;   
    static struct stat file_info;        
    static const char buf[] = "Expect:";
    
    struct curl_httppost *post=NULL;
    struct curl_httppost *last=NULL;
    struct curl_slist *headerlist=NULL;

    struct myprogress prog;
    
    prog.lastruntime = 0;
    prog.curl = curl;

    if(filename == NULL || url == NULL)
        return -1;
    
    fd = fopen(filename, "rb"); /* open file to upload */
    if(!fd) {
        printf("open file error");
        return -1;
    }
    
    /* to get the file size */
    if(fstat(fileno(fd), &file_info) != 0) {
        printf("get file length error");
        fclose(fd); 
        return -1;
    }
    
    printf("upload_url: %s\n", url);
    printf("upload_filename: %s\n", filename);    

    curl_formadd(&post, &last,
        CURLFORM_COPYNAME, "file",
        CURLFORM_FILE, filename,
        CURLFORM_CONTENTTYPE, "application/zip",
        CURLFORM_END);

    curl_formadd(&post,&last,
        CURLFORM_CONTENTTYPE, "multipart/form-data",
        CURLFORM_END);

    curl_global_init(CURL_GLOBAL_ALL);
    curl = curl_easy_init();
    if(curl == NULL)
    {
        printf("curl_easy_init() error.");
        ret = -1;
        goto out;
    }   
    
    headerlist = curl_slist_append(headerlist, buf);

    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);

    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 300L);
    
    curl_easy_setopt(curl, CURLOPT_URL, url); /*Set URL*/
    curl_easy_setopt(curl, CURLOPT_HTTPPOST, post);

    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callback_get_head); //设置下载数据的回调函数 
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, buffer);
    
    /* set where to read from (on Windows you need to use READFUNCTION too) */        
    curl_easy_setopt(curl, CURLOPT_READDATA, fd);
    /* we want to use our own read function */
    curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);

    curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, xferinfo);
    curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &prog);
    curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
    /*upload progress end*/

    /* enable verbose for easier tracing */
    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
      
    res = curl_easy_perform(curl);
        
    printf("ret:buffer[%s]\n", buffer);  

    //获取返回码
    if( res == CURLE_OK)
    {
        res = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE , &errcode);
    }
 
    printf("---curl getinfo return res: %d - %s,post return : %d",res,curl_easy_strerror(res),errcode);
    //处理返回结果
    if( res == CURLE_OK ) 
    {            
        if(errcode == 200)//SUCCESS
        {
            ret = 0;
        }
        else if(errcode == 412)//文件上传/请求下载时,指定请求的服务器已经达到上限,由服务器返回新的地址再次请求。
        {
            ret = -1;
        }
        else if(errcode == 503)//服务器繁忙,稍后再次请求
        {
            sleep(30);

            ret = -1;
        }
        else
        {
            ret = -1;
        }
    }
    else if( (res == CURLE_COULDNT_CONNECT) || //7: couldn't connect to server 
            (res == CURLE_OPERATION_TIMEOUTED) )  //28: a timeout was reached  
    {
        ret = -1;
    }
    else
    {
        ret = -1;
    }

out:
    curl_easy_cleanup(curl);
    curl_formfree(post);
    curl_global_cleanup();
    fclose(fd); 
    return ret;
}

int main(int argc, char **argv)
{
  http_post_file(argv[1], argv[2]);
  return 0;
}