使用/发送POST数据时的libcurl C问题(不是C ++)

时间:2013-12-02 04:00:59

标签: php c http curl libcurl

好的,所以我一直在尝试重现这个PHP脚本的功能:

<?php

function api_query($method, array $req = array()) {
    // API settings
    $key = ''; // your API-key
    $secret = ''; // your Secret-key

    $req['method'] = $method;
    $mt = explode(' ', microtime());
    $req['nonce'] = $mt[1];

    // generate the POST data string
    $post_data = http_build_query($req, '', '&');

    $sign = hash_hmac("sha512", $post_data, $secret);

    // generate the extra headers
    $headers = array(
            'Sign: '.$sign,
            'Key: '.$key,
    );

    // our curl handle (initialize if required)
    static $ch = null;
    if (is_null($ch)) {
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; Cryptsy API PHP client; '.php_uname('s').'; PHP/'.phpversion().')');
    }
    curl_setopt($ch, CURLOPT_URL, 'https://www.cryptsy.com/api');
    curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);

    // run the query
    $res = curl_exec($ch);

    if ($res === false) throw new Exception('Could not get reply: '.curl_error($ch));
    $dec = json_decode($res, true);
    if (!$dec) throw new Exception('Invalid data received, please make sure connection is working and requested API exists');
    return $dec;
}

我(至少我相信我已经)负责创建我自己构建查询的C不具备的http_build_query调用。我使用gettimeofday()在mtStr中有$ mt变量,我使用openSSL的HMAC函数用我的密钥签名post_data。

我发现C中的CURLOPT_HTTPHEADER选项需要一个curl_slist链表而不仅仅是PHP中的数组,但我似乎遇到问题的是Post Data。请求将通过,但有一个错误返回说“检查您的POST数据”。所以我回到了libcurl文档,发现CURLOPT_POSTFIELDS对要发布的数据要求无效*。所以我创建void * pData = post_data(其中post_data只是一个char数组,而不是一个指针,所以我在这里看不到一个探测器)但它仍然说它不能有效我的识别请检查POST数据。所以,如果你能看一看并告诉我哪里出错了,我们将不胜感激......

请注意,我没有显示我的API和密钥,因为我不能自己更改它们,我宁愿不给它们但是我知道这使得很难通过编译自己来检查我的东西没有一个隐藏的帐户但我我现在想保守秘密,但那里有一些虚拟钥匙,所以有一些东西可以散列,这是适当的长度等。

char *handle_url( char *url )
{
CURL *curl;

struct url_data data;
data.size = 0;
data.data = malloc( 4096 );
if ( NULL == data.data )
{
    fprintf( stderr, "failed to allocate memory.\n" );
    return NULL;
}

data.data[0] = '\0';

CURLcode res;

// API settings, API key and secret key for your account
char key[] = "9498fbb723961a42816a10bc559cgda7ded2ed8e";
char secret[] = "687cd29def08a7861446c3b4b9c97996c8472e7dd8922da147d3b1343e52e99125d24ace90729fbb";

// method to use against the API, will make changable later
char *method = "mytrades";

// This is required to replace the microtime()/explode methods to
// generate the nonce value required to use the cryptsy API
struct timeval time;
gettimeofday( &time, NULL );
long mt = ( (unsigned long long)time.tv_sec * 1000000 ) + time.tv_usec;
// C is much morer strict than PHP about types so we create a buffer for the
// string representation of the nonce
char mtStr[ 128 ];

sprintf( mtStr, "%lu", mt );

// C does not have a build_http_query as PHP does so
// we just create the string neccessary with strcpy
// and strcat
char post_data[ strlen("method=") + strlen(method) + strlen("&nonce=") + strlen(mtStr) + 1];
strcpy( post_data, "method=" );
strcat( post_data, method );
strcat( post_data, "&" );
strcat( post_data, "nonce=" );
strcat( post_data, mtStr );

printf( "%s", post_data);
printf( "\n");

void *pData = post_data;

//sha512 needs 128 characters
unsigned char *result;
unsigned int len = 128;

result = (unsigned char *)malloc( sizeof(char) * len );

HMAC_CTX ctx;
HMAC_CTX_init( &ctx );

// using sha512
HMAC_Init_ex( &ctx, secret, strlen(secret), EVP_sha512(), NULL );
HMAC_Update( &ctx, (unsigned char *)&post_data, strlen(post_data) );
HMAC_Final( &ctx, result, &len );
HMAC_CTX_cleanup( &ctx );
/*
printf( "\nHMAC digest: " );

for ( int i = 0; i != len; i++ )
{
    printf( "%02x", (unsigned int)result[i] );
} */
printf("\n");

// This is the start of setting up the $headers array as in the PHP script
const char *header1 = "Sign: ";
size_t PrefixL = strlen(header1);
char resBuffer[PrefixL + 2 * len + 1];
strcpy( resBuffer, header1);
char *p = &resBuffer[PrefixL];

for ( unsigned int i = 0; i < len; i++ )
{
    sprintf( p, "%02x", (unsigned int)result[i]);
    p += 2;
}

printf( "%s\n", resBuffer );

const char *header2 = "Key: ";
size_t PrefixR = strlen(header2);
char keyBuffer[PrefixR + 2 * strlen(key) + 1];
strcpy( keyBuffer, header2);
strcat( keyBuffer, key);

printf( "\n%s\n", keyBuffer );


// So now resBuffer is Sign: <128 character sha512 hash here>
// and keyBuffer is Key: <API key here>

free(result);

//struct curl_httppost *chttppostlist = NULL; //a possibility about sending chunked post data not currently used

// originally I set this up so that Sign and Key would be in the array in the same
// manner as the PHP script but libcurl in C needs a curl_slist 
const char *headerArray[2];
headerArray[0] = resBuffer;
headerArray[1] = keyBuffer;

// So then we just create a curl_slist and add the resBuffer and keyBuffer (headerArray
// [0] and headerArray[1] respectively) to the curl_slist.
struct curl_slist *cslist= NULL;
curl_slist_append(cslist, headerArray[0]);
curl_slist_append(cslist, headerArray[1]);

curl = curl_easy_init();
if ( curl )
{
    curl_easy_setopt( curl, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible Cryptsy API C Client)");
    curl_easy_setopt( curl, CURLOPT_URL, url );
    curl_easy_setopt( curl, CURLOPT_POST, 1 ); // is this necessary? isnt in PHP
    curl_easy_setopt( curl, CURLOPT_POSTFIELDS, pData ); // <--- something wrong here?
    curl_easy_setopt( curl, CURLOPT_HTTPHEADER, cslist );
    curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, write_data );
    curl_easy_setopt( curl, CURLOPT_WRITEDATA, &data );
    curl_easy_setopt( curl, CURLOPT_SSL_VERIFYPEER, 0 );
    res = curl_easy_perform( curl );
    if ( res != CURLE_OK )
    {
        fprintf( stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
    }
    curl_slist_free_all( cslist );
    curl_easy_cleanup( curl );
}
return data.data;
}

1 个答案:

答案 0 :(得分:0)

#include <iostream>
#include <cstdlib>
#include <cstring>
#include "json_parsers.h"
extern "C" {
#include <curl/curl.h>
#include <sys/time.h>
#include <limits.h>
#include <openssl/hmac.h>
#include <openssl/sha.h>
}

#define OK  0
#define NO_INPUT 1
#define TOO_LONG 2

using namespace std;

struct url_data {
size_t size;
char *data;
};

size_t write_data( void *ptr, size_t size, size_t nmemb, struct url_data *data )
{
    size_t index = data->size;
    size_t n = ( size * nmemb );
    char *tmp;

    data->size += ( size * nmemb );

#ifdef DEBUG
    fprintf( stderr, "data at %p size=%ld nmemb=%ld\n", ptr,
        size, nmemb );
#endif

tmp = (char *)realloc( data->data, data->size + 1); // + 1 for \n

if ( tmp )
{
    data->data = tmp;
}
else
{
    if ( data->data )
    {
        free( data->data );
    }
    fprintf( stderr, "Failed to allocate memory.\n" );
    return 0;
}

memcpy( ( data->data + index ), ptr, n );
data->data[ data->size ] = '\0';

return size * nmemb;
}

char * cryptsy_api(char * url,char * method_in,char * marketid,int limit,char * ordertype,char * quantity,char * price,char * orderid)     {

CURL *curl;

struct url_data data;
data.size = 0;
data.data = (char *)malloc(4096);
if (data.data == NULL)
{
    cerr << "Failed to allocate memory.\n" << endl;
    return NULL;
}

data.data[0] = '\0';

CURLcode res;

char strInt[5];
if (limit != NULL)
{
    sprintf(strInt, "%d", limit);
}

// API settings, API key and secret key for your account
char key[] = "9498fbb723961a42816a10bc559cfda7ded2ed8f";
char secret[] =  "687cd29def08a7861446c3b4b9c97996c8472e7dd8922da147d3b1346e52e99125d24ace90729fb3";

char *method = method_in;

// This is required to replace the microtime()/explode methods to
// generate the nonce value required to use the cryptsy API
struct timeval time;
gettimeofday(&time, NULL);
long mt = (unsigned long long)time.tv_sec;

char mtStr[10];
sprintf(mtStr, "%ul", mt);


// C does not have a build_http_query as PHP does so
// we just create the string neccessary with strcpy
// and strcat
char post_data[ strlen("method=") + strlen(method) + strlen("&nonce=") + strlen(mtStr) + strlen("&marketid=110") + strlen("&limit=1000") + strlen("&ordertype=sell&quantity=1000000&price=0.00000000")+ 1];
strcpy(post_data, "method=");
strcat(post_data, method);
strcat(post_data, "&nonce=");
strcat(post_data, mtStr);
if (marketid != NULL)
{
    strcat(post_data, "&marketid=");
    strcat(post_data, marketid);
}
if (limit != NULL)
{
    strcat(post_data, "&limit=");
    strcat(post_data, strInt);
}
if (ordertype != NULL)
{
    strcat(post_data, "&ordertype=");
    strcat(post_data, ordertype);
}
if (quantity != NULL)
{
    strcat(post_data, "&quantity=");
    strcat(post_data, quantity);
}
if (price != NULL)
{
    strcat(post_data, "&price=");
    strcat(post_data, price);
}
if (orderid != NULL)
{
    strcat(post_data, "&orderid=");
    strcat(post_data, orderid);
}

unsigned char *result;
unsigned int len = SHA512_DIGEST_LENGTH;

result = (unsigned char *)malloc(sizeof(char) * len);

HMAC_CTX ctx;
HMAC_CTX_init( &ctx );

// using SHA512
HMAC_Init_ex( &ctx, secret, strlen(secret), EVP_sha512(), NULL);
HMAC_Update( &ctx, (unsigned char *)&post_data, strlen(post_data));
HMAC_Final( &ctx, result, &len);
HMAC_CTX_cleanup( &ctx );

const char *header1 = "Sign: ";
size_t PrefixL = strlen(header1);
char resBuffer[PrefixL + 2 * len + 1];
strcpy(resBuffer, header1);
char *p = &resBuffer[PrefixL];

for (unsigned int i = 0; i < len; i++)
{
    sprintf(p, "%02x", (unsigned int)result[i]);
    p += 2;
}

const char *header2 = "Key: ";
size_t PrefixR = strlen(header2);
char keyBuffer[PrefixR + 2 * strlen(key) + 1];
strcpy(keyBuffer, header2);
strcat(keyBuffer, key);

free(result);

struct curl_slist *cslist = NULL;
cslist = curl_slist_append(cslist, resBuffer);
cslist = curl_slist_append(cslist, keyBuffer);

curl = curl_easy_init();
if (curl)
{
    curl_easy_setopt(curl, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible Cryptsy API C Client)");
    curl_easy_setopt(curl, CURLOPT_URL, url);
    curl_easy_setopt(curl, CURLOPT_POST, 1L);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, strlen(post_data));
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, cslist);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
    res = curl_easy_perform(curl);
    if (res != CURLE_OK)
    {
        cerr << "curl_easy_perform() failed " << curl_easy_strerror(res) << "\n" <<   endl;
    }
    curl_slist_free_all(cslist);
    curl_easy_cleanup(curl);
}
return data.data;
}

抱歉无法获得格式化的最后一位,但您明白了,是的,我更改了我的API密钥:)