2014-10-28 1 views
3

사용하고 난에합니다 (getinmemory.c libcurl에서 예를을 통합하려고 할 때 성공적으로libcurl에서 : WriteMemoryCallback 내가 C를 사용하여 JSON-RPC 요청을

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <curl/curl.h> 

void post_rpc(CURL *curl_handle) 
{ 
    CURLcode res; 

    char JSONRPC_BASE_URL[] = "https://api.betfair.com/exchange/betting/json-rpc/v1"; 
    char rpc_request[]="{\"jsonrpc\": \"2.0\", \"method\": \"SportsAPING/v1.0/listEventTypes\", \"params\": {\"filter\":{ }}, \"id\": 1}"; 
    char session_token[]= "MY_ACTIVE_SESSION_STRING"; 
    char session_header[100+sizeof(session_token)]; 

    strcpy(session_header, "X-Authentication:"); 
    strcat(session_header, session_token); 

    struct curl_slist * headers = NULL; 
    headers = curl_slist_append(headers, "X-Application: MY_API_KEY"); 
    headers = curl_slist_append(headers, session_header); 
    headers = curl_slist_append(headers, "content-type : application/json"); 

    /* init the curl session */ 
    curl_handle = curl_easy_init(); 

    /* HEADERS */ 
    curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headers); 
    /* POST FIELD : Json-rpc request */ 
    curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, rpc_request); 
    curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, (long)strlen(rpc_request)); 
    /* stdout the header sent */ 
    curl_easy_setopt(curl_handle, CURLOPT_WRITEHEADER, stdout); 
    curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, stdout); 

    /* specify URL to get */ 
    curl_easy_setopt(curl_handle, CURLOPT_URL, JSONRPC_BASE_URL); 

    /* get it! */ 
    res = curl_easy_perform(curl_handle); 
    /* check for errors */ 
    if(res != CURLE_OK) { 
     fprintf(stderr, "curl_easy_perform() failed: %s\n", 
       curl_easy_strerror(res)); 
    } 
} 

int main(){ 

    int res; 
    CURL *curl_handle; 

    curl_global_init(CURL_GLOBAL_DEFAULT); 
    post_rpc(curl_handle); 
    curl_global_cleanup(); 

    return 0; 
} 

그러나 다음 코드를 사용하여 libcurl에 curl_easy_perform에 분할 오류 내가 기본적으로 위의 코드를 추가하는 내 편집)

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

#include <curl/curl.h> 

struct MemoryStruct { 
    char *memory; 
    size_t size; 
}; 


static size_t 
WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) 
{ 
    size_t realsize = size * nmemb; 
    struct MemoryStruct *mem = (struct MemoryStruct *)userp; 

    mem->memory = realloc(mem->memory, mem->size + realsize + 1); 
    if(mem->memory == NULL) { 
    /* out of memory! */ 
    printf("not enough memory (realloc returned NULL)\n"); 
    return 0; 
    } 

    memcpy(&(mem->memory[mem->size]), contents, realsize); 
    mem->size += realsize; 
    mem->memory[mem->size] = 0; 

    return realsize; 
} 


int main(void) 
{ 
    CURL *curl_handle; 
    CURLcode res; 

    struct MemoryStruct chunk; 
    chunk.memory = malloc(1); /* will be grown as needed by the realloc above */ 
    chunk.size = 0; /* no data at this point */ 

    curl_global_init(CURL_GLOBAL_ALL); 

    /* init the curl session */ 
    curl_handle = curl_easy_init(); 


     char JSONRPC_BASE_URL[] = "https://api.betfair.com/exchange/betting/json-rpc/v1"; 
     char rpc_request[]="{\"jsonrpc\": \"2.0\", \"method\": \"SportsAPING/v1.0/listEventTypes\", \"params\": {\"filter\":{ }}, \"id\": 1}"; 
     char session_token[]= "MY_ACTIVE_SESSION_STRING"; 
     char session_header[100+sizeof(session_token)]; 

     strcpy(session_header, "X-Authentication:"); 
     strcat(session_header, session_token); 

     struct curl_slist * headers = NULL; 
     headers = curl_slist_append(headers, "X-Application: MY_API_KEY"); 
     headers = curl_slist_append(headers, session_header); 
     headers = curl_slist_append(headers, "content-type : application/json"); 

     /* HEADERS */ 
     curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headers); 
     /* POST FIELD : Json-rpc request */ 
     curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, rpc_request); 
     curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, (long)strlen(rpc_request)); 
     /* stdout the header sent */ 
     curl_easy_setopt(curl_handle, CURLOPT_WRITEHEADER, stdout); 
     curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, stdout); 

     /* specify URL to get */ 
     curl_easy_setopt(curl_handle, CURLOPT_URL, JSONRPC_BASE_URL); 


    /* send all data to this function */ 
    curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); 

    /* we pass our 'chunk' struct to the callback function */ 
    curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk); 

    /* some servers don't like requests that are made without a user-agent 
    field, so we provide one */ 
    curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0"); 

     printf("THIS IS PRINTED\n"); 
     fflush(stdout); 

    /* get it! */ 
    res = curl_easy_perform(curl_handle); //LINE 114: SEGFAULT 

     printf("THIS IS NOT...\n"); 
     fflush(stdout); 

    /* check for errors */ 
    if(res != CURLE_OK) { 
    fprintf(stderr, "curl_easy_perform() failed: %s\n", 
      curl_easy_strerror(res)); 
    } 
    else { 
    /* 
    * Now, our chunk.memory points to a memory block that is chunk.size 
    * bytes big and contains the remote file. 
    * 
    * Do something nice with it! 
    */ 

    printf("%lu bytes retrieved\n", (long)chunk.size); 
    printf("Chunk:%s\n", chunk.memory); 

    } 

    /* cleanup curl stuff */ 
    curl_easy_cleanup(curl_handle); 

    if(chunk.memory) 
    free(chunk.memory); 

    /* we're done with libcurl, so clean it up */ 
    curl_global_cleanup(); 

    return 0; 
} 
을 들여 한 곳 대신에 표준 출력의 변수)의 출력을 얻기 위해, 따라서 (다음 코드로 올라오고3210

나는 writeMemoryCallback 내부 realloc 호출에 발생

res = curl_easy_perform(curl_handle); 

에서 세그먼트 오류를 ​​얻을.

위의 예에서 stdout에 인쇄 된 헤더는 여기에 인쇄되지 않습니다.

$ valgrind ./dafuq --tool memcheck 
==7002== Memcheck, a memory error detector 
==7002== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al. 
==7002== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info 
==7002== Command: ./dafuq --tool memcheck 
==7002== 
THIS IS PRINTED 
==7002== Invalid free()/delete/delete[]/realloc() 
==7002== at 0x4C2AF2E: realloc (vg_replace_malloc.c:692) 
==7002== by 0x400D27: WriteMemoryCallback (getinmemory.c:44) 
==7002== by 0x4E4BD89: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0) 
==7002== by 0x4E4A353: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0) 
==7002== by 0x4E605AF: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0) 
==7002== by 0x4E6ACE8: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0) 
==7002== by 0x4E6B560: curl_multi_perform (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0) 
==7002== by 0x4E6215A: curl_easy_perform (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.3.0) 
==7002== by 0x401178: main (getinmemory.c:114) 
==7002== Address 0xfbad2a84 is not stack'd, malloc'd or (recently) free'd 
==7002== 
not enough memory (realloc returned NULL) 
THIS IS NOT... 
curl_easy_perform() failed: Failed writing received data to disk/application 
==7002== 
==7002== HEAP SUMMARY: 
==7002==  in use at exit: 238 bytes in 8 blocks 
==7002== total heap usage: 7,171 allocs, 7,163 frees, 67,842,654 bytes allocated 
==7002== 
==7002== LEAK SUMMARY: 
==7002== definitely lost: 16 bytes in 1 blocks 
==7002== indirectly lost: 158 bytes in 5 blocks 
==7002==  possibly lost: 0 bytes in 0 blocks 
==7002== still reachable: 64 bytes in 2 blocks 
==7002==   suppressed: 0 bytes in 0 blocks 
==7002== Rerun with --leak-check=full to see details of leaked memory 
==7002== 
==7002== For counts of detected and suppressed errors, rerun with: -v 
==7002== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0) 

어떤 생각 : 인쇄되어있는 유일한 방법은

$ ./dafuq 
THIS IS PRINTED 
Segmentation fault 

이것은 GDB는 Valgrind의 덤프는

(gdb) break 114 
Breakpoint 1 at 0x40116d: file getinmemory.c, line 114. 
(gdb) break 115 
Breakpoint 2 at 0x40117c: file getinmemory.c, line 115. 
(gdb) run 
Starting program: dafuq 
[Thread debugging using libthread_db enabled] 
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". 
THIS IS PRINTED 

Breakpoint 1, main() at getinmemory.c:114 
114 res = curl_easy_perform(curl_handle); 
(gdb) step 
[New Thread 0x7ffff341e700 (LWP 6774)] 
[Thread 0x7ffff341e700 (LWP 6774) exited] 

Program received signal SIGSEGV, Segmentation fault. 
__GI___libc_realloc (oldmem=0xfbad2a84, bytes=140737354092562) at malloc.c:2977 
2977 malloc.c: No such file or directory. 
(gdb) 

덤프입니다?

추신 : 정확히 같은 행동으로 올라오고 here에서 sth의 코드와 같은 스트림을 사용해 보았습니다.

+0

먼저 (예 : 세션을 만료) * 모든 * 함수의 값을 반환 한 다음 malloc/realloc 호출을 바꾸어보십시오. – 2501

+0

http://curl.haxx.se/libcurl/c/postinmemory.html 예제가 원하는 것보다 훨씬 더 가까울 수도 있습니다 ... –

+0

좋은 지적입니다. 모든 libcurl 함수는 다음을 반환합니다. ''realloc ''을 ''malloc ''으로 바꾸면 (gdb에서) 프로그램 수신 신호 SIGSEGV, 세그먼트 오류가 발생합니다. __memcpy_sse2_unaligned() ../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S:35 ../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S에서 : 해당 파일이나 디렉토리. – chefarov

답변

1

어리석은 실수는 CURLOPT_WRITEDATA이며 chunkstdout입니다. 따라서

curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, stdout); 

을 제거 이 일을 ...

PS : curl_easy_perform에서 분할 오류는 인증 데이터가 false 인 경우에 일어날 것 같다 반환을 확인