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上,但是移植好后出现了如下截图的问题
过程
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)就可以解决问题了,如下图为成功的消息打印。
附上正常使用的源码:
/***************************************************************************
* _ _ ____ _
* 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;
}