first commit for opensource
first commit for opensource
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is
|
||||
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "qcloud_utils/qcloud_base64.h"
|
||||
|
||||
static const unsigned char base64_enc_map[64] =
|
||||
{
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
|
||||
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
|
||||
'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
|
||||
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
||||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
|
||||
'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', '+', '/'
|
||||
};
|
||||
|
||||
static const unsigned char base64_dec_map[128] =
|
||||
{
|
||||
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
|
||||
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
|
||||
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
|
||||
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
|
||||
127, 127, 127, 62, 127, 127, 127, 63, 52, 53,
|
||||
54, 55, 56, 57, 58, 59, 60, 61, 127, 127,
|
||||
127, 64, 127, 127, 127, 0, 1, 2, 3, 4,
|
||||
5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
|
||||
25, 127, 127, 127, 127, 127, 127, 26, 27, 28,
|
||||
29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
|
||||
39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
|
||||
49, 50, 51, 127, 127, 127, 127, 127
|
||||
};
|
||||
|
||||
#define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
|
||||
|
||||
int qcloud_utils_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
|
||||
const unsigned char *src, size_t slen )
|
||||
{
|
||||
size_t i, n;
|
||||
unsigned char *p;
|
||||
|
||||
if( slen == 0 )
|
||||
{
|
||||
*olen = 0;
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
n = slen / 3 + ( slen % 3 != 0 );
|
||||
|
||||
if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 )
|
||||
{
|
||||
*olen = BASE64_SIZE_T_MAX;
|
||||
return( QCLOUD_ERR_FAILURE );
|
||||
}
|
||||
|
||||
n *= 4;
|
||||
|
||||
if( ( dlen < n + 1 ) || ( NULL == dst ) )
|
||||
{
|
||||
*olen = n + 1;
|
||||
return( QCLOUD_ERR_FAILURE );
|
||||
}
|
||||
|
||||
n = ( slen / 3 ) * 3;
|
||||
|
||||
int C1, C2, C3;
|
||||
for( i = 0, p = dst; i < n; i += 3 )
|
||||
{
|
||||
C1 = *src++;
|
||||
C2 = *src++;
|
||||
C3 = *src++;
|
||||
|
||||
*p++ = base64_enc_map[(C1 >> 2) & 0x3F];
|
||||
*p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
|
||||
*p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
|
||||
*p++ = base64_enc_map[C3 & 0x3F];
|
||||
}
|
||||
|
||||
if( i < slen )
|
||||
{
|
||||
C1 = *src++;
|
||||
C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
|
||||
|
||||
*p++ = base64_enc_map[(C1 >> 2) & 0x3F];
|
||||
*p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
|
||||
|
||||
if( ( i + 1 ) < slen )
|
||||
*p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
|
||||
else *p++ = '=';
|
||||
|
||||
*p++ = '=';
|
||||
}
|
||||
|
||||
*olen = p - dst;
|
||||
*p = 0;
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int qcloud_utils_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
|
||||
const unsigned char *src, size_t slen )
|
||||
{
|
||||
size_t i, n;
|
||||
uint32_t j, x;
|
||||
unsigned char *p;
|
||||
|
||||
/* First pass: check for validity and get output length */
|
||||
for( i = n = j = 0; i < slen; i++ )
|
||||
{
|
||||
/* Skip spaces before checking for EOL */
|
||||
x = 0;
|
||||
while( i < slen && src[i] == ' ' )
|
||||
{
|
||||
++i;
|
||||
++x;
|
||||
}
|
||||
|
||||
/* Spaces at end of buffer are OK */
|
||||
if( i == slen )
|
||||
break;
|
||||
|
||||
if( ( slen - i ) >= 2 &&
|
||||
src[i] == '\r' && src[i + 1] == '\n' )
|
||||
continue;
|
||||
|
||||
if( src[i] == '\n' )
|
||||
continue;
|
||||
|
||||
/* Space inside a line is an error */
|
||||
if( x != 0 )
|
||||
return( QCLOUD_ERR_FAILURE );
|
||||
|
||||
if( src[i] == '=' && ++j > 2 )
|
||||
return( QCLOUD_ERR_FAILURE );
|
||||
|
||||
if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
|
||||
return( QCLOUD_ERR_FAILURE );
|
||||
|
||||
if( base64_dec_map[src[i]] < 64 && j != 0 )
|
||||
return( QCLOUD_ERR_FAILURE );
|
||||
|
||||
n++;
|
||||
}
|
||||
|
||||
if( n == 0 )
|
||||
{
|
||||
*olen = 0;
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
n = ( ( n * 6 ) + 7 ) >> 3;
|
||||
n -= j;
|
||||
|
||||
if( dst == NULL || dlen < n )
|
||||
{
|
||||
*olen = n;
|
||||
return( QCLOUD_ERR_FAILURE );
|
||||
}
|
||||
|
||||
for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
|
||||
{
|
||||
if( *src == '\r' || *src == '\n' || *src == ' ' )
|
||||
continue;
|
||||
|
||||
j -= ( base64_dec_map[*src] == 64 );
|
||||
x = ( x << 6 ) | ( base64_dec_map[*src] & 0x3F );
|
||||
|
||||
if( ++n == 4 )
|
||||
{
|
||||
n = 0;
|
||||
if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
|
||||
if( j > 1 ) *p++ = (unsigned char)( x >> 8 );
|
||||
if( j > 2 ) *p++ = (unsigned char)( x );
|
||||
}
|
||||
}
|
||||
|
||||
*olen = p - dst;
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is
|
||||
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
#include "qcloud.h"
|
||||
|
||||
#define KEY_IOPAD_SIZE 64
|
||||
|
||||
#define MD5_DIGEST_SIZE 16
|
||||
#define SHA1_DIGEST_SIZE 20
|
||||
|
||||
void utils_hmac_md5(const char *msg, int msg_len, char *digest, const char *key, int key_len)
|
||||
{
|
||||
if((NULL == msg) || (NULL == digest) || (NULL == key)) {
|
||||
QCLOUD_LOG_E("parameter is Null,failed!");
|
||||
return;
|
||||
}
|
||||
|
||||
if(key_len > KEY_IOPAD_SIZE) {
|
||||
QCLOUD_LOG_E("key_len > size(%d) of array",KEY_IOPAD_SIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
iot_md5_context context;
|
||||
unsigned char k_ipad[KEY_IOPAD_SIZE]; /* inner padding - key XORd with ipad */
|
||||
unsigned char k_opad[KEY_IOPAD_SIZE]; /* outer padding - key XORd with opad */
|
||||
unsigned char out[MD5_DIGEST_SIZE];
|
||||
int i;
|
||||
|
||||
/* start out by storing key in pads */
|
||||
memset(k_ipad, 0, sizeof(k_ipad));
|
||||
memset(k_opad, 0, sizeof(k_opad));
|
||||
memcpy(k_ipad, key, key_len);
|
||||
memcpy(k_opad, key, key_len);
|
||||
|
||||
/* XOR key with ipad and opad values */
|
||||
for (i = 0; i < KEY_IOPAD_SIZE; i++) {
|
||||
k_ipad[i] ^= 0x36;
|
||||
k_opad[i] ^= 0x5c;
|
||||
}
|
||||
|
||||
/* perform inner MD5 */
|
||||
utils_md5_init(&context); /* init context for 1st pass */
|
||||
utils_md5_starts(&context); /* setup context for 1st pass */
|
||||
utils_md5_update(&context, k_ipad, KEY_IOPAD_SIZE); /* start with inner pad */
|
||||
utils_md5_update(&context, (unsigned char *) msg, msg_len); /* then text of datagram */
|
||||
utils_md5_finish(&context, out); /* finish up 1st pass */
|
||||
|
||||
/* perform outer MD5 */
|
||||
utils_md5_init(&context); /* init context for 2nd pass */
|
||||
utils_md5_starts(&context); /* setup context for 2nd pass */
|
||||
utils_md5_update(&context, k_opad, KEY_IOPAD_SIZE); /* start with outer pad */
|
||||
utils_md5_update(&context, out, MD5_DIGEST_SIZE); /* then results of 1st hash */
|
||||
utils_md5_finish(&context, out); /* finish up 2nd pass */
|
||||
|
||||
for (i = 0; i < MD5_DIGEST_SIZE; ++i) {
|
||||
digest[i * 2] = utils_hb2hex(out[i] >> 4);
|
||||
digest[i * 2 + 1] = utils_hb2hex(out[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void utils_hmac_sha1(const char *msg, int msg_len, char *digest, const char *key, int key_len)
|
||||
{
|
||||
if((NULL == msg) || (NULL == digest) || (NULL == key)) {
|
||||
QCLOUD_LOG_E("parameter is Null,failed!");
|
||||
return;
|
||||
}
|
||||
|
||||
if(key_len > KEY_IOPAD_SIZE) {
|
||||
QCLOUD_LOG_E("key_len > size(%d) of array",KEY_IOPAD_SIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
iot_sha1_context context;
|
||||
unsigned char k_ipad[KEY_IOPAD_SIZE]; /* inner padding - key XORd with ipad */
|
||||
unsigned char k_opad[KEY_IOPAD_SIZE]; /* outer padding - key XORd with opad */
|
||||
unsigned char out[SHA1_DIGEST_SIZE];
|
||||
int i;
|
||||
|
||||
/* start out by storing key in pads */
|
||||
memset(k_ipad, 0, sizeof(k_ipad));
|
||||
memset(k_opad, 0, sizeof(k_opad));
|
||||
memcpy(k_ipad, key, key_len);
|
||||
memcpy(k_opad, key, key_len);
|
||||
|
||||
/* XOR key with ipad and opad values */
|
||||
for (i = 0; i < KEY_IOPAD_SIZE; i++) {
|
||||
k_ipad[i] ^= 0x36;
|
||||
k_opad[i] ^= 0x5c;
|
||||
}
|
||||
|
||||
/* perform inner SHA */
|
||||
utils_sha1_init(&context); /* init context for 1st pass */
|
||||
utils_sha1_starts(&context); /* setup context for 1st pass */
|
||||
utils_sha1_update(&context, k_ipad, KEY_IOPAD_SIZE); /* start with inner pad */
|
||||
utils_sha1_update(&context, (unsigned char *) msg, msg_len); /* then text of datagram */
|
||||
utils_sha1_finish(&context, out); /* finish up 1st pass */
|
||||
|
||||
/* perform outer SHA */
|
||||
utils_sha1_init(&context); /* init context for 2nd pass */
|
||||
utils_sha1_starts(&context); /* setup context for 2nd pass */
|
||||
utils_sha1_update(&context, k_opad, KEY_IOPAD_SIZE); /* start with outer pad */
|
||||
utils_sha1_update(&context, out, SHA1_DIGEST_SIZE); /* then results of 1st hash */
|
||||
utils_sha1_finish(&context, out); /* finish up 2nd pass */
|
||||
|
||||
for (i = 0; i < SHA1_DIGEST_SIZE; ++i) {
|
||||
digest[i * 2] = utils_hb2hex(out[i] >> 4);
|
||||
digest[i * 2 + 1] = utils_hb2hex(out[i]);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,829 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is
|
||||
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "qcloud.h"
|
||||
|
||||
#define HTTP_CLIENT_MIN(x,y) (((x)<(y))?(x):(y))
|
||||
#define HTTP_CLIENT_MAX(x,y) (((x)>(y))?(x):(y))
|
||||
|
||||
#define HTTP_CLIENT_AUTHB_SIZE 128
|
||||
|
||||
#define HTTP_CLIENT_CHUNK_SIZE 1024
|
||||
#define HTTP_CLIENT_SEND_BUF_SIZE 1024
|
||||
|
||||
#define HTTP_CLIENT_MAX_HOST_LEN 64
|
||||
#define HTTP_CLIENT_MAX_URL_LEN 1024
|
||||
|
||||
#define HTTP_RETRIEVE_MORE_DATA (1)
|
||||
|
||||
#if defined(MBEDTLS_DEBUG_C)
|
||||
#define DEBUG_LEVEL 2
|
||||
#endif
|
||||
|
||||
|
||||
static void _http_client_base64enc(char *out, const char *in)
|
||||
{
|
||||
const char code[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||
int i = 0, x = 0, l = 0;
|
||||
|
||||
for (; *in; in++) {
|
||||
x = x << 8 | *in;
|
||||
for (l += 8; l >= 6; l -= 6) {
|
||||
out[i++] = code[(x >> (l - 6)) & 0x3f];
|
||||
}
|
||||
}
|
||||
if (l > 0) {
|
||||
x <<= 6 - l;
|
||||
out[i++] = code[x & 0x3f];
|
||||
}
|
||||
for (; i % 4;) {
|
||||
out[i++] = '=';
|
||||
}
|
||||
out[i] = '\0';
|
||||
}
|
||||
|
||||
static int _http_client_parse_url(const char *url, char *scheme, uint32_t max_scheme_len, char *host, uint32_t maxhost_len,
|
||||
int *port, char *path, uint32_t max_path_len)
|
||||
{
|
||||
char *scheme_ptr = (char *) url;
|
||||
char *host_ptr = (char *) strstr(url, "://");
|
||||
uint32_t host_len = 0;
|
||||
uint32_t path_len;
|
||||
|
||||
char *path_ptr;
|
||||
char *fragment_ptr;
|
||||
|
||||
if (host_ptr == NULL) {
|
||||
QCLOUD_LOG_E("Could not find host");
|
||||
return QCLOUD_ERR_HTTP_PARSE;
|
||||
}
|
||||
|
||||
if (max_scheme_len < host_ptr - scheme_ptr + 1) {
|
||||
QCLOUD_LOG_E("Scheme str is too small (%u >= %u)", max_scheme_len, (uint32_t)(host_ptr - scheme_ptr + 1));
|
||||
return QCLOUD_ERR_HTTP_PARSE;
|
||||
}
|
||||
memcpy(scheme, scheme_ptr, host_ptr - scheme_ptr);
|
||||
scheme[host_ptr - scheme_ptr] = '\0';
|
||||
|
||||
host_ptr += 3;
|
||||
|
||||
*port = 0;
|
||||
|
||||
path_ptr = strchr(host_ptr, '/');
|
||||
if (NULL == path_ptr) {
|
||||
path_ptr = scheme_ptr + (int)strlen(url);
|
||||
host_len = path_ptr - host_ptr;
|
||||
memcpy(host, host_ptr, host_len);
|
||||
host[host_len] = '\0';
|
||||
|
||||
memcpy(path, "/", 1);
|
||||
path[1] = '\0';
|
||||
|
||||
return QCLOUD_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
if (host_len == 0) {
|
||||
host_len = path_ptr - host_ptr;
|
||||
}
|
||||
|
||||
if (maxhost_len < host_len + 1) {
|
||||
QCLOUD_LOG_E("Host str is too long (host_len(%d) >= max_len(%d))", host_len + 1, maxhost_len);
|
||||
return QCLOUD_ERR_HTTP_PARSE;
|
||||
}
|
||||
memcpy(host, host_ptr, host_len);
|
||||
host[host_len] = '\0';
|
||||
|
||||
fragment_ptr = strchr(host_ptr, '#');
|
||||
if (fragment_ptr != NULL) {
|
||||
path_len = fragment_ptr - path_ptr;
|
||||
} else {
|
||||
path_len = strlen(path_ptr);
|
||||
}
|
||||
|
||||
if (max_path_len < path_len + 1) {
|
||||
QCLOUD_LOG_E("Path str is too small (%d >= %d)", max_path_len, path_len + 1);
|
||||
return QCLOUD_ERR_HTTP_PARSE;
|
||||
}
|
||||
|
||||
memcpy(path, path_ptr, path_len);
|
||||
|
||||
path[path_len] = '\0';
|
||||
|
||||
return QCLOUD_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
static int _http_client_parse_host(const char *url, char *host, uint32_t host_max_len)
|
||||
{
|
||||
const char *host_ptr = (const char *) strstr(url, "://");
|
||||
uint32_t host_len = 0;
|
||||
char *path_ptr;
|
||||
|
||||
if (host_ptr == NULL) {
|
||||
QCLOUD_LOG_E("Could not find host");
|
||||
return QCLOUD_ERR_HTTP_PARSE;
|
||||
}
|
||||
host_ptr += 3;
|
||||
|
||||
uint32_t pro_len = 0;
|
||||
pro_len = host_ptr - url;
|
||||
|
||||
path_ptr = strchr(host_ptr, '/');
|
||||
if (path_ptr != NULL)
|
||||
host_len = path_ptr - host_ptr;
|
||||
else
|
||||
host_len = strlen(url) - pro_len;
|
||||
|
||||
if (host_max_len < host_len + 1) {
|
||||
QCLOUD_LOG_E("Host str is too small (%d >= %d)", host_max_len, host_len + 1);
|
||||
return QCLOUD_ERR_HTTP_PARSE;
|
||||
}
|
||||
memcpy(host, host_ptr, host_len);
|
||||
host[host_len] = '\0';
|
||||
|
||||
return QCLOUD_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 拼接发送的数据
|
||||
*
|
||||
* @param client http client
|
||||
* @param send_buf 发送数据buffer
|
||||
* @param send_idx 标志send_buf数据结束的位置
|
||||
* @param buf 需要被发送的数据,拼接到send_buf中
|
||||
* @param len buf的长度
|
||||
* @return 返回QCLOUD_ERR_SUCCESS, 表示设置成功
|
||||
*/
|
||||
static int _http_client_get_info(HTTPClient *client, unsigned char *send_buf, int *send_idx, char *buf, uint32_t len)
|
||||
{
|
||||
int rc = QCLOUD_ERR_SUCCESS;
|
||||
int cp_len;
|
||||
int idx = *send_idx;
|
||||
|
||||
if (len == 0) {
|
||||
len = strlen(buf);
|
||||
}
|
||||
|
||||
do {
|
||||
if ((HTTP_CLIENT_SEND_BUF_SIZE - idx) >= len) {
|
||||
cp_len = len;
|
||||
} else {
|
||||
cp_len = HTTP_CLIENT_SEND_BUF_SIZE - idx;
|
||||
}
|
||||
|
||||
memcpy(send_buf + idx, buf, cp_len);
|
||||
idx += cp_len;
|
||||
len -= cp_len;
|
||||
|
||||
if (idx == HTTP_CLIENT_SEND_BUF_SIZE) {
|
||||
size_t byte_written_len = 0;
|
||||
rc = client->network.write(&(client->network), send_buf, HTTP_CLIENT_SEND_BUF_SIZE, 5000, &byte_written_len);
|
||||
if (byte_written_len) {
|
||||
return (byte_written_len);
|
||||
}
|
||||
}
|
||||
} while (len);
|
||||
|
||||
*send_idx = idx;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int _http_client_send_auth(HTTPClient *client, unsigned char *send_buf, int *send_idx)
|
||||
{
|
||||
char b_auth[(int)((HTTP_CLIENT_AUTHB_SIZE + 3) * 4 / 3 + 1)];
|
||||
char base64buff[HTTP_CLIENT_AUTHB_SIZE + 3];
|
||||
|
||||
_http_client_get_info(client, send_buf, send_idx, "Authorization: Basic ", 0);
|
||||
osal_snprintf(base64buff, sizeof(base64buff), "%s:%s", client->auth_user, client->auth_password);
|
||||
|
||||
_http_client_base64enc(b_auth, base64buff);
|
||||
b_auth[strlen(b_auth) + 1] = '\0';
|
||||
b_auth[strlen(b_auth)] = '\n';
|
||||
|
||||
_http_client_get_info(client, send_buf, send_idx, b_auth, 0);
|
||||
|
||||
return QCLOUD_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 根据请求url和method,拼接请求头
|
||||
*
|
||||
* @param client http client
|
||||
* @param url 请求url
|
||||
* @param method 请求方法
|
||||
* @param client_data http数据负载
|
||||
* @return 返回QCLOUD_ERR_SUCCESS, 表示设置成功
|
||||
*/
|
||||
static int _http_client_send_header(HTTPClient *client, const char *url, HttpMethod method, HTTPClientData *client_data)
|
||||
{
|
||||
char scheme[8] = { 0 };
|
||||
char host[HTTP_CLIENT_MAX_HOST_LEN] = { 0 };
|
||||
char path[HTTP_CLIENT_MAX_URL_LEN] = { 0 };
|
||||
int len;
|
||||
unsigned char send_buf[HTTP_CLIENT_SEND_BUF_SIZE] = { 0 };
|
||||
char buf[HTTP_CLIENT_SEND_BUF_SIZE] = { 0 };
|
||||
char *meth = (method == HTTP_GET) ? "GET" : (method == HTTP_POST) ? "POST" :
|
||||
(method == HTTP_PUT) ? "PUT" : (method == HTTP_DELETE) ? "DELETE" :
|
||||
(method == HTTP_HEAD) ? "HEAD" : "";
|
||||
int rc;
|
||||
int port;
|
||||
|
||||
int res = _http_client_parse_url(url, scheme, sizeof(scheme), host, sizeof(host), &port, path, sizeof(path));
|
||||
if (res != QCLOUD_ERR_SUCCESS) {
|
||||
QCLOUD_LOG_E("httpclient_parse_url returned %d", res);
|
||||
return res;
|
||||
}
|
||||
|
||||
if (strcmp(scheme, "http") == 0) {
|
||||
|
||||
} else if (strcmp(scheme, "https") == 0) {
|
||||
|
||||
}
|
||||
|
||||
memset(send_buf, 0, HTTP_CLIENT_SEND_BUF_SIZE);
|
||||
len = 0;
|
||||
|
||||
osal_snprintf(buf, sizeof(buf), "%s %s HTTP/1.1\r\nHost: %s\r\n", meth, path, host);
|
||||
rc = _http_client_get_info(client, send_buf, &len, buf, strlen(buf));
|
||||
if (rc) {
|
||||
QCLOUD_LOG_E("Could not write request");
|
||||
return QCLOUD_ERR_HTTP_CONN;
|
||||
}
|
||||
|
||||
if (client->auth_user) {
|
||||
_http_client_send_auth(client, send_buf, &len);
|
||||
}
|
||||
|
||||
if (client->header) {
|
||||
_http_client_get_info(client, send_buf, &len, (char *) client->header, strlen(client->header));
|
||||
}
|
||||
|
||||
if (client_data->post_buf != NULL) {
|
||||
osal_snprintf(buf, sizeof(buf), "Content-Length: %d\r\n", client_data->post_buf_len);
|
||||
_http_client_get_info(client, send_buf, &len, buf, strlen(buf));
|
||||
|
||||
if (client_data->post_content_type != NULL) {
|
||||
osal_snprintf(buf, sizeof(buf), "Content-Type: %s\r\n", client_data->post_content_type);
|
||||
_http_client_get_info(client, send_buf, &len, buf, strlen(buf));
|
||||
}
|
||||
}
|
||||
|
||||
_http_client_get_info(client, send_buf, &len, "\r\n", 0);
|
||||
|
||||
//QCLOUD_LOG_D("REQUEST:\n%s", send_buf);
|
||||
|
||||
size_t written_len = 0;
|
||||
rc = client->network.write(&client->network, send_buf, len, 5000, &written_len);
|
||||
if (written_len > 0) {
|
||||
//QCLOUD_LOG_D("Written %lu bytes", written_len);
|
||||
} else if (written_len == 0) {
|
||||
QCLOUD_LOG_E("written_len == 0,Connection was closed by server");
|
||||
return QCLOUD_ERR_HTTP_CLOSED; /* Connection was closed by server */
|
||||
} else {
|
||||
QCLOUD_LOG_E("Connection error (send returned %d)", rc);
|
||||
return QCLOUD_ERR_HTTP_CONN;
|
||||
}
|
||||
|
||||
return QCLOUD_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 发送post的请求体数据
|
||||
*
|
||||
* @param client http client
|
||||
* @param client_data http数据负载
|
||||
* @return 返回QCLOUD_ERR_SUCCESS, 表示设置成功
|
||||
*/
|
||||
static int _http_client_send_userdata(HTTPClient *client, HTTPClientData *client_data)
|
||||
{
|
||||
if (client_data->post_buf && client_data->post_buf_len) {
|
||||
//QCLOUD_LOG_D("client_data->post_buf: %s", client_data->post_buf);
|
||||
{
|
||||
size_t written_len = 0;
|
||||
int rc = client->network.write(&client->network, (unsigned char *)client_data->post_buf, client_data->post_buf_len, 5000, &written_len);
|
||||
if (written_len > 0) {
|
||||
//QCLOUD_LOG_D("Written %d bytes", written_len);
|
||||
} else if (written_len == 0) {
|
||||
QCLOUD_LOG_E("written_len == 0,Connection was closed by server");
|
||||
return QCLOUD_ERR_HTTP_CLOSED;
|
||||
} else {
|
||||
QCLOUD_LOG_E("Connection error (send returned %d)", rc);
|
||||
return QCLOUD_ERR_HTTP_CONN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QCLOUD_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 读取http数据
|
||||
*
|
||||
* @param client http client
|
||||
* @param buf 数据buffer
|
||||
* @param min_len 读取数据的最小长度
|
||||
* @param max_len 读取数据的最大长度
|
||||
* @param p_read_len 成功读取到的数据的长度
|
||||
* @param timeout_ms 超时时间
|
||||
* @param client_data http数据负载
|
||||
* @return 返回QCLOUD_ERR_SUCCESS, 表示设置成功
|
||||
*/
|
||||
static int _http_client_recv(HTTPClient *client, char *buf, int min_len, int max_len, int *p_read_len, uint32_t timeout_ms, HTTPClientData *client_data)
|
||||
{
|
||||
QCLOUD_FUNC_ENTRY;
|
||||
|
||||
int rc = 0;
|
||||
osal_timer_t timer;
|
||||
|
||||
osal_timer_init(&timer);
|
||||
osal_timer_countdown_ms(&timer, (unsigned int)timeout_ms);
|
||||
|
||||
*p_read_len = 0;
|
||||
|
||||
rc = client->network.read(&client->network, (unsigned char *)buf, max_len, (uint32_t)osal_timer_remain(&timer), (size_t *)p_read_len);
|
||||
|
||||
if (rc == QCLOUD_ERR_SSL_NOTHING_TO_READ || rc == QCLOUD_ERR_TCP_NOTHING_TO_READ) {
|
||||
QCLOUD_LOG_D("HTTP read nothing and timeout");
|
||||
rc = QCLOUD_ERR_SUCCESS;
|
||||
}
|
||||
else if (rc == QCLOUD_ERR_SSL_READ_TIMEOUT || rc == QCLOUD_ERR_TCP_READ_TIMEOUT) {
|
||||
if (*p_read_len == client_data->retrieve_len || client_data->retrieve_len == 0)
|
||||
rc = QCLOUD_ERR_SUCCESS;
|
||||
}
|
||||
else if (rc == QCLOUD_ERR_TCP_PEER_SHUTDOWN && *p_read_len > 0) {
|
||||
/* HTTP server give response and close this connection */
|
||||
client->network.disconnect(&client->network);
|
||||
rc = QCLOUD_ERR_SUCCESS;
|
||||
}
|
||||
else if (rc != QCLOUD_ERR_SUCCESS) { // 其他错误
|
||||
QCLOUD_LOG_E("Connection error rc = %d (recv returned %d)", rc, *p_read_len);
|
||||
QCLOUD_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS);
|
||||
}
|
||||
|
||||
static int _http_client_retrieve_content(HTTPClient *client, char *data, int len, uint32_t timeout_ms,
|
||||
HTTPClientData *client_data)
|
||||
{
|
||||
QCLOUD_FUNC_ENTRY;
|
||||
|
||||
int count = 0;
|
||||
int templen = 0;
|
||||
int crlf_pos;
|
||||
osal_timer_t timer;
|
||||
|
||||
osal_timer_init(&timer);
|
||||
osal_timer_countdown_ms(&timer, (unsigned int)timeout_ms);
|
||||
|
||||
client_data->is_more = QCLOUD_TRUE;
|
||||
|
||||
if (client_data->response_content_len == -1 && client_data->is_chunked == QCLOUD_FALSE) {
|
||||
while (1) {
|
||||
int rc, max_len;
|
||||
if (count + len < client_data->response_buf_len - 1) {
|
||||
memcpy(client_data->response_buf + count, data, len);
|
||||
count += len;
|
||||
client_data->response_buf[count] = '\0';
|
||||
} else {
|
||||
memcpy(client_data->response_buf + count, data, client_data->response_buf_len - 1 - count);
|
||||
client_data->response_buf[client_data->response_buf_len - 1] = '\0';
|
||||
return HTTP_RETRIEVE_MORE_DATA;
|
||||
}
|
||||
|
||||
max_len = HTTP_CLIENT_MIN(HTTP_CLIENT_CHUNK_SIZE - 1, client_data->response_buf_len - 1 - count);
|
||||
rc = _http_client_recv(client, data, 1, max_len, &len, (uint32_t)osal_timer_remain(&timer), client_data);
|
||||
|
||||
/* Receive data */
|
||||
//QCLOUD_LOG_D("data len: %d %d", len, count);
|
||||
|
||||
if (rc != QCLOUD_ERR_SUCCESS) {
|
||||
QCLOUD_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
/* read no more data */
|
||||
QCLOUD_LOG_D("no more data, len == 0");
|
||||
client_data->is_more = QCLOUD_FALSE;
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (1) {
|
||||
uint32_t readLen = 0;
|
||||
if (client_data->is_chunked && client_data->retrieve_len <= 0) {
|
||||
/* Read chunk header */
|
||||
bool foundCrlf;
|
||||
int n;
|
||||
do {
|
||||
foundCrlf = QCLOUD_FALSE;
|
||||
crlf_pos = 0;
|
||||
data[len] = 0;
|
||||
if (len >= 2) {
|
||||
for (; crlf_pos < len - 2; crlf_pos++) {
|
||||
if (data[crlf_pos] == '\r' && data[crlf_pos + 1] == '\n') {
|
||||
foundCrlf = QCLOUD_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!foundCrlf) {
|
||||
/* Try to read more */
|
||||
if (len < HTTP_CLIENT_CHUNK_SIZE) {
|
||||
int new_trf_len, rc;
|
||||
rc = _http_client_recv(client,
|
||||
data + len,
|
||||
0,
|
||||
HTTP_CLIENT_CHUNK_SIZE - len - 1,
|
||||
&new_trf_len,
|
||||
osal_timer_remain(&timer),
|
||||
client_data);
|
||||
len += new_trf_len;
|
||||
if (rc != QCLOUD_ERR_SUCCESS) {
|
||||
QCLOUD_FUNC_EXIT_RC(rc);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_HTTP);
|
||||
}
|
||||
}
|
||||
} while (!foundCrlf);
|
||||
data[crlf_pos] = '\0';
|
||||
|
||||
// n = sscanf(data, "%x", &readLen);/* chunk length */
|
||||
readLen = strtoul(data, NULL, 16);
|
||||
n = (0 == readLen) ? 0 : 1;
|
||||
client_data->retrieve_len = readLen;
|
||||
client_data->response_content_len += client_data->retrieve_len;
|
||||
if (readLen == 0) {
|
||||
client_data->is_more = QCLOUD_FALSE;
|
||||
QCLOUD_LOG_D("no more (last chunk)");
|
||||
}
|
||||
|
||||
if (n != 1) {
|
||||
QCLOUD_LOG_E("Could not read chunk length");
|
||||
return QCLOUD_ERR_HTTP_UNRESOLVED_DNS;
|
||||
}
|
||||
|
||||
memmove(data, &data[crlf_pos + 2], len - (crlf_pos + 2));
|
||||
len -= (crlf_pos + 2);
|
||||
|
||||
} else {
|
||||
readLen = client_data->retrieve_len;
|
||||
}
|
||||
|
||||
do {
|
||||
templen = HTTP_CLIENT_MIN(len, readLen);
|
||||
if (count + templen < client_data->response_buf_len - 1) {
|
||||
memcpy(client_data->response_buf + count, data, templen);
|
||||
count += templen;
|
||||
client_data->response_buf[count] = '\0';
|
||||
client_data->retrieve_len -= templen;
|
||||
} else {
|
||||
memcpy(client_data->response_buf + count, data, client_data->response_buf_len - 1 - count);
|
||||
client_data->response_buf[client_data->response_buf_len - 1] = '\0';
|
||||
client_data->retrieve_len -= (client_data->response_buf_len - 1 - count);
|
||||
QCLOUD_FUNC_EXIT_RC(HTTP_RETRIEVE_MORE_DATA);
|
||||
}
|
||||
|
||||
if (len > readLen) {
|
||||
QCLOUD_LOG_D("memmove %d %d %d\n", readLen, len, client_data->retrieve_len);
|
||||
memmove(data, &data[readLen], len - readLen); /* chunk case, read between two chunks */
|
||||
len -= readLen;
|
||||
readLen = 0;
|
||||
client_data->retrieve_len = 0;
|
||||
} else {
|
||||
readLen -= len;
|
||||
}
|
||||
|
||||
if (readLen) {
|
||||
int rc;
|
||||
int max_len = HTTP_CLIENT_MIN(HTTP_CLIENT_CHUNK_SIZE - 1, client_data->response_buf_len - 1 - count);
|
||||
max_len = HTTP_CLIENT_MIN(max_len, readLen);
|
||||
rc = _http_client_recv(client, data, 1, max_len, &len, osal_timer_remain(&timer), client_data);
|
||||
if (rc != QCLOUD_ERR_SUCCESS) {
|
||||
QCLOUD_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
}
|
||||
} while (readLen);
|
||||
|
||||
if (client_data->is_chunked) {
|
||||
if (len < 2) {
|
||||
int new_trf_len, rc;
|
||||
/* Read missing chars to find end of chunk */
|
||||
rc = _http_client_recv(client, data + len, 2 - len, HTTP_CLIENT_CHUNK_SIZE - len - 1, &new_trf_len,
|
||||
osal_timer_remain(&timer), client_data);
|
||||
if (rc != QCLOUD_ERR_SUCCESS) {
|
||||
QCLOUD_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
len += new_trf_len;
|
||||
}
|
||||
|
||||
if ((data[0] != '\r') || (data[1] != '\n')) {
|
||||
QCLOUD_LOG_E("Format error, %s", data); /* after memmove, the beginning of next chunk */
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_HTTP_UNRESOLVED_DNS);
|
||||
}
|
||||
memmove(data, &data[2], len - 2); /* remove the \r\n */
|
||||
len -= 2;
|
||||
} else {
|
||||
//QCLOUD_LOG_D("no more (content-length)");
|
||||
client_data->is_more = QCLOUD_FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 解析response body数据
|
||||
*
|
||||
* @param client HTTPClient数据
|
||||
* @param data 读取到的数据
|
||||
* @param len 读取到的数据的长度
|
||||
* @param timeout_ms 读取数据的超时时间
|
||||
* @param client_data http数据负载
|
||||
* @return 返回QCLOUD_ERR_SUCCESS, 表示成功
|
||||
*/
|
||||
static int _http_client_response_parse(HTTPClient *client, char *data, int len, uint32_t timeout_ms,
|
||||
HTTPClientData *client_data)
|
||||
{
|
||||
QCLOUD_FUNC_ENTRY;
|
||||
|
||||
int crlf_pos;
|
||||
osal_timer_t timer;
|
||||
char *tmp_ptr, *ptr_body_end;
|
||||
|
||||
osal_timer_init(&timer);
|
||||
osal_timer_countdown_ms(&timer, timeout_ms);
|
||||
|
||||
client_data->response_content_len = -1;
|
||||
|
||||
char *crlf_ptr = strstr(data, "\r\n");
|
||||
if (crlf_ptr == NULL) {
|
||||
QCLOUD_LOG_E("\\r\\n not found");
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_HTTP_UNRESOLVED_DNS);
|
||||
}
|
||||
|
||||
crlf_pos = crlf_ptr - data;
|
||||
data[crlf_pos] = '\0';
|
||||
|
||||
#if 0
|
||||
if (sscanf(data, "HTTP/%*d.%*d %d %*[^\r\n]", &(client->response_code)) != 1) {
|
||||
QCLOUD_LOG_E("Not a correct HTTP answer : %s\n", data);
|
||||
return QCLOUD_ERR_HTTP_UNRESOLVED_DNS;
|
||||
}
|
||||
#endif
|
||||
|
||||
client->response_code = atoi(data + 9);
|
||||
|
||||
if ((client->response_code < 200) || (client->response_code >= 400)) {
|
||||
QCLOUD_LOG_W("Response code %d", client->response_code);
|
||||
|
||||
if (client->response_code == 403)
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_HTTP_AUTH);
|
||||
|
||||
if (client->response_code == 404)
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
//QCLOUD_LOG_D("Reading headers : %s", data);
|
||||
|
||||
// 移除null终止字符
|
||||
memmove(data, &data[crlf_pos + 2], len - (crlf_pos + 2) + 1);
|
||||
len -= (crlf_pos + 2);
|
||||
|
||||
client_data->is_chunked = QCLOUD_FALSE;
|
||||
|
||||
if (NULL == (ptr_body_end = strstr(data, "\r\n\r\n"))) {
|
||||
int new_trf_len, rc;
|
||||
rc = _http_client_recv(client, data + len, 1, HTTP_CLIENT_CHUNK_SIZE - len - 1, &new_trf_len, osal_timer_remain(&timer), client_data);
|
||||
if (rc != QCLOUD_ERR_SUCCESS) {
|
||||
QCLOUD_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
len += new_trf_len;
|
||||
data[len] = '\0';
|
||||
if (NULL == (ptr_body_end = strstr(data, "\r\n\r\n"))) {
|
||||
QCLOUD_LOG_E("parse error: no end of the request body");
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL != (tmp_ptr = strstr(data, "Content-Length"))) {
|
||||
client_data->response_content_len = atoi(tmp_ptr + strlen("Content-Length: "));
|
||||
client_data->retrieve_len = client_data->response_content_len;
|
||||
} else if (NULL != (tmp_ptr = strstr(data, "Transfer-Encoding"))) {
|
||||
int len_chunk = strlen("Chunked");
|
||||
char *chunk_value = data + strlen("Transfer-Encoding: ");
|
||||
|
||||
if ((! memcmp(chunk_value, "Chunked", len_chunk))
|
||||
|| (! memcmp(chunk_value, "chunked", len_chunk))) {
|
||||
client_data->is_chunked = QCLOUD_TRUE;
|
||||
client_data->response_content_len = 0;
|
||||
client_data->retrieve_len = 0;
|
||||
}
|
||||
} else {
|
||||
QCLOUD_LOG_E("Could not parse header");
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_HTTP);
|
||||
}
|
||||
|
||||
len = len - (ptr_body_end + 4 - data);
|
||||
memmove(data, ptr_body_end + 4, len + 1);
|
||||
int rc = _http_client_retrieve_content(client, data, len, osal_timer_remain(&timer), client_data);
|
||||
QCLOUD_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
static int _http_client_connect(HTTPClient *client)
|
||||
{
|
||||
if (QCLOUD_ERR_SUCCESS != client->network.connect(&client->network)) {
|
||||
return QCLOUD_ERR_HTTP_CONN;
|
||||
}
|
||||
|
||||
return QCLOUD_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
static int _http_client_send_request(HTTPClient *client, const char *url, HttpMethod method, HTTPClientData *client_data)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = _http_client_send_header(client, url, method, client_data);
|
||||
if (rc != 0) {
|
||||
QCLOUD_LOG_E("httpclient_send_header is error, rc = %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (method == HTTP_POST || method == HTTP_PUT) {
|
||||
rc = _http_client_send_userdata(client, client_data);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 接收http返回的数据
|
||||
*
|
||||
* @param client http client
|
||||
* @param timeout_ms 读取数据的超时时间
|
||||
* @param client_data http数据负载
|
||||
* @return 返回QCLOUD_ERR_SUCCESS, 表示设置成功
|
||||
*/
|
||||
static int _http_client_recv_response(HTTPClient *client, uint32_t timeout_ms, HTTPClientData *client_data)
|
||||
{
|
||||
QCLOUD_FUNC_ENTRY;
|
||||
|
||||
int reclen = 0, rc = QCLOUD_ERR_HTTP_CONN;
|
||||
char buf[HTTP_CLIENT_CHUNK_SIZE] = { 0 };
|
||||
osal_timer_t timer;
|
||||
|
||||
osal_timer_init(&timer);
|
||||
osal_timer_countdown_ms(&timer, timeout_ms);
|
||||
|
||||
if (!client->network.is_connected(&client->network)) {
|
||||
QCLOUD_LOG_E("Connection has not been established");
|
||||
QCLOUD_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
if (client_data->is_more) {
|
||||
client_data->response_buf[0] = '\0';
|
||||
rc = _http_client_retrieve_content(client, buf, reclen, osal_timer_remain(&timer), client_data);
|
||||
} else {
|
||||
client_data->is_more = QCLOUD_TRUE;
|
||||
rc = _http_client_recv(client, buf, 1, HTTP_CLIENT_CHUNK_SIZE - 1, &reclen, osal_timer_remain(&timer), client_data);
|
||||
|
||||
if (rc != QCLOUD_ERR_SUCCESS) {
|
||||
QCLOUD_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
buf[reclen] = '\0';
|
||||
|
||||
if (reclen) {
|
||||
//osal_printf("RESPONSE:\n%s", buf);
|
||||
rc = _http_client_response_parse(client, buf, reclen, osal_timer_remain(&timer), client_data);
|
||||
}
|
||||
}
|
||||
|
||||
QCLOUD_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
static int _http_network_init(qcloud_network_t *network, const char *host, int port, const char *ca_crt_dir)
|
||||
{
|
||||
int rc = QCLOUD_ERR_SUCCESS;
|
||||
if (network == NULL) {
|
||||
return QCLOUD_ERR_INVAL;
|
||||
}
|
||||
#if (QCLOUD_CFG_TLS_EN > 0u)
|
||||
if (ca_crt_dir != NULL) {
|
||||
network->tls_opt.ca_cert = ca_crt_dir;
|
||||
network->tls_opt.ca_cert_len = strlen(network->tls_opt.ca_cert);
|
||||
network->tls_opt.timeout = 10000;
|
||||
}
|
||||
#endif
|
||||
|
||||
memset(network->host, 0, sizeof(network->host));
|
||||
strncpy(network->host, host, sizeof(network->host) - 1);
|
||||
|
||||
network->port = port;
|
||||
|
||||
rc = qcloud_network_tcp_init(network);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int qcloud_http_client_connect(HTTPClient *client, const char *url, int port, const char *ca_crt)
|
||||
{
|
||||
if (!client->network.is_connected(&client->network)) {
|
||||
QCLOUD_LOG_E("http client has connected to host!");
|
||||
return QCLOUD_ERR_HTTP_CONN;
|
||||
}
|
||||
|
||||
int rc;
|
||||
char host[HTTP_CLIENT_MAX_HOST_LEN] = {0};
|
||||
rc = _http_client_parse_host(url, host, sizeof(host));
|
||||
if (rc != QCLOUD_ERR_SUCCESS) return rc;
|
||||
|
||||
rc = _http_network_init(&client->network, host, port, ca_crt);
|
||||
if (rc != QCLOUD_ERR_SUCCESS)
|
||||
return rc;
|
||||
|
||||
rc = _http_client_connect(client);
|
||||
if (rc != QCLOUD_ERR_SUCCESS) {
|
||||
QCLOUD_LOG_E("http_client_connect is error,rc = %d", rc);
|
||||
qcloud_http_client_close(client);
|
||||
} else {
|
||||
/* reduce log print due to frequent log server connect/disconnect */
|
||||
QCLOUD_LOG_D("http client connect success");
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
void qcloud_http_client_close(HTTPClient *client)
|
||||
{
|
||||
if (client->network.is_connected(&client->network)) {
|
||||
client->network.disconnect(&client->network);
|
||||
}
|
||||
}
|
||||
|
||||
int qcloud_http_client_common(HTTPClient *client, const char *url, int port, const char *ca_crt, HttpMethod method, HTTPClientData *client_data)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!client->network.is_connected(&client->network)) {
|
||||
rc = qcloud_http_client_connect(client, url, port, ca_crt);
|
||||
if (rc != QCLOUD_ERR_SUCCESS) return rc;
|
||||
}
|
||||
|
||||
rc = _http_client_send_request(client, url, method, client_data);
|
||||
if (rc != QCLOUD_ERR_SUCCESS) {
|
||||
QCLOUD_LOG_E("http_client_send_request is error,rc = %d", rc);
|
||||
qcloud_http_client_close(client);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return QCLOUD_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
int qcloud_http_recv_data(HTTPClient *client, uint32_t timeout_ms, HTTPClientData *client_data)
|
||||
{
|
||||
QCLOUD_FUNC_ENTRY;
|
||||
|
||||
int rc = QCLOUD_ERR_SUCCESS;
|
||||
osal_timer_t timer;
|
||||
|
||||
osal_timer_init(&timer);
|
||||
osal_timer_countdown_ms(&timer, (unsigned int) timeout_ms);
|
||||
|
||||
if ((NULL != client_data->response_buf)
|
||||
&& (0 != client_data->response_buf_len)) {
|
||||
rc = _http_client_recv_response(client, osal_timer_remain(&timer), client_data);
|
||||
if (rc < 0) {
|
||||
QCLOUD_LOG_E("http_client_recv_response is error,rc = %d", rc);
|
||||
qcloud_http_client_close(client);
|
||||
QCLOUD_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
}
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019 Tencent Group. All rights reserved.
|
||||
* License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "qcloud.h"
|
||||
|
||||
#define json_debug QCLOUD_LOG_D
|
||||
|
||||
typedef struct JSON_NV {
|
||||
int nLen;
|
||||
int vLen;
|
||||
int vType;
|
||||
char *pN;
|
||||
char *pV;
|
||||
} JSON_NV;
|
||||
|
||||
char *json_get_object(int type, char *str)
|
||||
{
|
||||
char *pos = 0;
|
||||
char ch = (type == JSOBJECT) ? '{' : '[';
|
||||
while (str != 0 && *str != 0) {
|
||||
if (*str == ' ') {
|
||||
str++;
|
||||
continue;
|
||||
}
|
||||
pos = (*str == ch) ? str : 0;
|
||||
break;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
char *json_get_next_object(int type, char *str, char **key, int *key_len,
|
||||
char **val, int *val_len, int *val_type)
|
||||
{
|
||||
char JsonMark[JSTYPEMAX][2] = { { '\"', '\"' }, { '{', '}' }, { '[', ']' }, { '0', ' ' } };
|
||||
int iMarkDepth = 0, iValueType = JSNONE, iNameLen = 0, iValueLen = 0;
|
||||
char *p_cName = 0, *p_cValue = 0, *p_cPos = str;
|
||||
|
||||
if (type == JSOBJECT) {
|
||||
/* Get Key */
|
||||
p_cPos = strchr(p_cPos, '"');
|
||||
if (!p_cPos) {
|
||||
return 0;
|
||||
}
|
||||
p_cName = ++p_cPos;
|
||||
p_cPos = strchr(p_cPos, '"');
|
||||
if (!p_cPos) {
|
||||
return 0;
|
||||
}
|
||||
iNameLen = p_cPos - p_cName;
|
||||
|
||||
/* Get Value */
|
||||
p_cPos = strchr(p_cPos, ':');
|
||||
}
|
||||
while (p_cPos && *p_cPos) {
|
||||
if (*p_cPos == '"') {
|
||||
iValueType = JSSTRING;
|
||||
p_cValue = ++p_cPos;
|
||||
break;
|
||||
} else if (*p_cPos == '{') {
|
||||
iValueType = JSOBJECT;
|
||||
p_cValue = p_cPos++;
|
||||
break;
|
||||
} else if (*p_cPos == '[') {
|
||||
iValueType = JSARRAY;
|
||||
p_cValue = p_cPos++;
|
||||
break;
|
||||
} else if ((*p_cPos == '-') || (*p_cPos >= '0' && *p_cPos <= '9')) {
|
||||
iValueType = JSNUMBER;
|
||||
p_cValue = p_cPos++;
|
||||
break;
|
||||
} else if (*p_cPos == 't' || *p_cPos == 'T' || *p_cPos == 'f' || *p_cPos == 'F') {
|
||||
iValueType = JSBOOLEAN;
|
||||
p_cValue = p_cPos;
|
||||
break;
|
||||
}else if (*p_cPos == 'n' || *p_cPos == 'N') {
|
||||
iValueType = JSNULL;
|
||||
p_cValue = p_cPos;
|
||||
break;
|
||||
}
|
||||
p_cPos++;
|
||||
}
|
||||
while (p_cPos && *p_cPos && iValueType > JSNONE) {
|
||||
if (iValueType == JSBOOLEAN) {
|
||||
int len = strlen(p_cValue);
|
||||
|
||||
if ((*p_cValue == 't' || *p_cValue == 'T') && len >= 4
|
||||
&& (!strncmp(p_cValue, "true", 4)
|
||||
|| !strncmp(p_cValue, "TRUE", 4))) {
|
||||
iValueLen = 4;
|
||||
p_cPos = p_cValue + iValueLen;
|
||||
break;
|
||||
} else if ((*p_cValue == 'f' || *p_cValue == 'F') && len >= 5
|
||||
&& (!strncmp(p_cValue, "false", 5)
|
||||
|| !strncmp(p_cValue, "FALSE", 5))) {
|
||||
iValueLen = 5;
|
||||
p_cPos = p_cValue + iValueLen;
|
||||
break;
|
||||
}
|
||||
} else if (iValueType == JSNULL) { //support null/NULL
|
||||
int nlen = strlen(p_cValue);
|
||||
|
||||
if ((*p_cValue == 'n' || *p_cValue == 'N') && nlen >= 4
|
||||
&& (!strncmp(p_cValue, "null", 4)
|
||||
|| !strncmp(p_cValue, "NULL", 4))) {
|
||||
iValueLen = 4;
|
||||
p_cPos = p_cValue + iValueLen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (iValueType == JSNUMBER) {
|
||||
//if (*p_cPos < '0' || *p_cPos > '9') {
|
||||
if ((*p_cPos < '0' || *p_cPos > '9')&&(*p_cPos != '.')) { //support float
|
||||
iValueLen = p_cPos - p_cValue;
|
||||
break;
|
||||
}
|
||||
} else if (*p_cPos == JsonMark[iValueType][1]) {
|
||||
if (iMarkDepth == 0) {
|
||||
iValueLen = p_cPos - p_cValue + (iValueType == JSSTRING ? 0 : 1);
|
||||
p_cPos++;
|
||||
break;
|
||||
} else {
|
||||
iMarkDepth--;
|
||||
}
|
||||
} else if (*p_cPos == JsonMark[iValueType][0]) {
|
||||
iMarkDepth++;
|
||||
}
|
||||
p_cPos++;
|
||||
}
|
||||
|
||||
if (type == JSOBJECT) {
|
||||
*key = p_cName;
|
||||
*key_len = iNameLen;
|
||||
}
|
||||
|
||||
*val = p_cValue;
|
||||
*val_len = iValueLen;
|
||||
*val_type = iValueType;
|
||||
if (iValueType == JSSTRING) {
|
||||
return p_cValue + iValueLen + 1;
|
||||
} else {
|
||||
return p_cValue + iValueLen;
|
||||
}
|
||||
}
|
||||
|
||||
int json_parse_name_value(char *p_cJsonStr, int iStrLen, json_parse_cb pfnCB, void *p_CBData)
|
||||
{
|
||||
char *pos = 0, *key = 0, *val = 0;
|
||||
int klen = 0, vlen = 0, vtype = 0;
|
||||
char last_char = 0;
|
||||
int ret = JSON_RESULT_ERR;
|
||||
|
||||
if (p_cJsonStr == NULL || iStrLen == 0 || pfnCB == NULL) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (iStrLen != strlen(p_cJsonStr)) {
|
||||
QCLOUD_LOG_W("Backup last_char since %d != %d", iStrLen, (int)strlen(p_cJsonStr));
|
||||
backup_json_str_last_char(p_cJsonStr, iStrLen, last_char);
|
||||
}
|
||||
|
||||
json_object_for_each_kv(p_cJsonStr, pos, key, klen, val, vlen, vtype) {
|
||||
if (key && klen && val && vlen) {
|
||||
ret = JSON_RESULT_OK;
|
||||
if (JSON_PARSE_FINISH == pfnCB(key, klen, val, vlen, vtype, p_CBData)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (iStrLen != strlen(p_cJsonStr)) {
|
||||
restore_json_str_last_char(p_cJsonStr, iStrLen, last_char);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int json_get_value_by_name_cb(char *p_cName, int iNameLen, char *p_cValue, int iValueLen, int iValueType,
|
||||
void *p_CBData)
|
||||
{
|
||||
JSON_NV *p_stNameValue = (JSON_NV *)p_CBData;
|
||||
|
||||
#if (JSON_DEBUG == 1)
|
||||
int i;
|
||||
|
||||
if (p_cName) {
|
||||
json_debug("Name:");
|
||||
for (i = 0; i < iNameLen; i++) {
|
||||
json_debug("%c", *(p_cName + i));
|
||||
}
|
||||
}
|
||||
|
||||
if (p_cValue) {
|
||||
json_debug("Value:");
|
||||
for (i = 0; i < iValueLen; i++) {
|
||||
json_debug("%c", *(p_cValue + i));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!strncmp(p_cName, p_stNameValue->pN, p_stNameValue->nLen)) {
|
||||
p_stNameValue->pV = p_cValue;
|
||||
p_stNameValue->vLen = iValueLen;
|
||||
p_stNameValue->vType = iValueType;
|
||||
return JSON_PARSE_FINISH;
|
||||
} else {
|
||||
return JSON_PARSE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
char *json_get_value_by_name(char *p_cJsonStr, int iStrLen, char *p_cName, int *p_iValueLen, int *p_iValueType)
|
||||
{
|
||||
JSON_NV stNV;
|
||||
|
||||
memset(&stNV, 0, sizeof(stNV));
|
||||
stNV.pN = p_cName;
|
||||
stNV.nLen = strlen(p_cName);
|
||||
if (JSON_RESULT_OK == json_parse_name_value(p_cJsonStr, iStrLen, json_get_value_by_name_cb, (void *)&stNV)) {
|
||||
if (p_iValueLen) {
|
||||
*p_iValueLen = stNV.vLen;
|
||||
}
|
||||
if (p_iValueType) {
|
||||
*p_iValueType = stNV.vType;
|
||||
if(JSNULL == stNV.vType){
|
||||
stNV.pV = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return stNV.pV;
|
||||
}
|
||||
|
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019 Tencent Group. All rights reserved.
|
||||
* License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qcloud.h"
|
||||
|
||||
#ifndef SCNi8
|
||||
#define SCNi8 "hhi"
|
||||
#endif
|
||||
|
||||
#ifndef SCNu8
|
||||
#define SCNu8 "hhu"
|
||||
#endif
|
||||
|
||||
#ifndef SCNi16
|
||||
#define SCNi16 "hi"
|
||||
#endif
|
||||
|
||||
#ifndef SCNu16
|
||||
#define SCNu16 "hu"
|
||||
#endif
|
||||
|
||||
#ifndef SCNi32
|
||||
#define SCNi32 "i"
|
||||
#endif
|
||||
|
||||
#ifndef SCNu32
|
||||
#define SCNu32 "u"
|
||||
#endif
|
||||
|
||||
char *LITE_json_value_of(char *key, char *src)
|
||||
{
|
||||
char *value = NULL;
|
||||
int value_len = -1;
|
||||
char *ret = NULL;
|
||||
|
||||
char *delim = NULL;
|
||||
char *key_iter;
|
||||
char *key_next;
|
||||
int key_len;
|
||||
char *src_iter;
|
||||
|
||||
src_iter = src;
|
||||
key_iter = key;
|
||||
|
||||
do {
|
||||
if ((delim = strchr(key_iter, '.')) != NULL) {
|
||||
key_len = delim - key_iter;
|
||||
key_next = osal_malloc(key_len + 1);
|
||||
strncpy(key_next, key_iter, key_len);
|
||||
key_next[key_len] = '\0';
|
||||
value = json_get_value_by_name(src_iter, strlen(src_iter), key_next, &value_len, 0);
|
||||
|
||||
if (value == NULL) {
|
||||
osal_free(key_next);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
src_iter = value;
|
||||
key_iter = delim + 1;
|
||||
osal_free(key_next);
|
||||
}
|
||||
} while (delim);
|
||||
|
||||
value = json_get_value_by_name(src_iter, strlen(src_iter), key_iter, &value_len, 0);
|
||||
if (NULL == value) {
|
||||
return NULL;
|
||||
}
|
||||
ret = osal_malloc((value_len + 1) * sizeof(char));
|
||||
if (NULL == ret) {
|
||||
return NULL;
|
||||
}
|
||||
osal_snprintf(ret, value_len + 1, "%s", value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
list_head_t *LITE_json_keys_of(char *src, char *prefix)
|
||||
{
|
||||
static LIST_HEAD(keylist);
|
||||
|
||||
char *pos = 0, *key = 0, *val = 0;
|
||||
int klen = 0, vlen = 0, vtype = 0;
|
||||
|
||||
if (src == NULL || prefix == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!strcmp("", prefix)) {
|
||||
INIT_LIST_HEAD(&keylist);
|
||||
}
|
||||
|
||||
json_object_for_each_kv(src, pos, key, klen, val, vlen, vtype) {
|
||||
if (key && klen && val && vlen) {
|
||||
|
||||
json_key_t *entry = NULL;
|
||||
|
||||
entry = osal_malloc(sizeof(json_key_t));
|
||||
memset(entry, 0, sizeof(json_key_t));
|
||||
entry->key = LITE_format_string("%s%.*s", prefix, klen, key);
|
||||
list_add_tail(&entry->list, &keylist);
|
||||
|
||||
if (JSOBJECT == vtype) {
|
||||
char *iter_val = LITE_format_string("%.*s", vlen, val);
|
||||
char *iter_pre = LITE_format_string("%s%.*s.", prefix, klen, key);
|
||||
LITE_json_keys_of(iter_val, iter_pre);
|
||||
osal_free(iter_val);
|
||||
osal_free(iter_pre);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!strcmp("", prefix)) {
|
||||
json_key_t *entry = NULL;
|
||||
|
||||
entry = osal_malloc(sizeof(json_key_t));
|
||||
memset(entry, 0, sizeof(json_key_t));
|
||||
list_add_tail(&entry->list, &keylist);
|
||||
|
||||
return &keylist;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void LITE_json_keys_release(list_head_t *keylist)
|
||||
{
|
||||
json_key_t *pos, *tmp;
|
||||
|
||||
list_for_each_entry_safe(pos, tmp, keylist, list, json_key_t) {
|
||||
if (pos->key) {
|
||||
osal_free(pos->key);
|
||||
}
|
||||
list_del(&pos->list);
|
||||
osal_free(pos);
|
||||
}
|
||||
}
|
||||
|
||||
qcloud_err_t LITE_get_int32(int32_t *value, char *src) {
|
||||
return (sscanf(src, "%" SCNi32, value) == 1) ? QCLOUD_ERR_SUCCESS : QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
qcloud_err_t LITE_get_int16(int16_t *value, char *src) {
|
||||
return (sscanf(src, "%" SCNi16, value) == 1) ? QCLOUD_ERR_SUCCESS : QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
qcloud_err_t LITE_get_int8(int8_t *value, char *src) {
|
||||
return (sscanf(src, "%" SCNi8, value) == 1) ? QCLOUD_ERR_SUCCESS : QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
qcloud_err_t LITE_get_uint32(uint32_t *value, char *src) {
|
||||
return (sscanf(src, "%" SCNu32, value) == 1) ? QCLOUD_ERR_SUCCESS : QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
qcloud_err_t LITE_get_uint16(uint16_t *value, char *src) {
|
||||
return (sscanf(src, "%" SCNu16, value) == 1) ? QCLOUD_ERR_SUCCESS : QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
qcloud_err_t LITE_get_uint8(uint8_t *value, char *src) {
|
||||
return (sscanf(src, "%" SCNu8, value) == 1) ? QCLOUD_ERR_SUCCESS : QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
qcloud_err_t LITE_get_float(float *value, char *src) {
|
||||
return (sscanf(src, "%f", value) == 1) ? QCLOUD_ERR_SUCCESS : QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
qcloud_err_t LITE_get_double(double *value, char *src) {
|
||||
return (sscanf(src, "%lf", value) == 1) ? QCLOUD_ERR_SUCCESS : QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
qcloud_err_t LITE_get_boolean(bool *value, char *src) {
|
||||
if (!strcmp(src, "false")) {
|
||||
*value = false;
|
||||
}
|
||||
else {
|
||||
*value = true;
|
||||
}
|
||||
|
||||
return QCLOUD_ERR_SUCCESS;
|
||||
}
|
||||
|
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is
|
||||
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "qcloud.h"
|
||||
|
||||
#define MD5_DIGEST_SIZE 16
|
||||
|
||||
|
||||
/* Implementation that should never be optimized out by the compiler */
|
||||
static void _utils_md5_zeroize(void *v, size_t n)
|
||||
{
|
||||
volatile unsigned char *p = v;
|
||||
while (n--) *p++ = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 32-bit integer manipulation macros (little endian)
|
||||
*/
|
||||
#ifndef IOT_MD5_GET_UINT32_LE
|
||||
#define IOT_MD5_GET_UINT32_LE(n,b,i) \
|
||||
{ \
|
||||
(n) = ( (uint32_t) (b)[(i) ] ) \
|
||||
| ( (uint32_t) (b)[(i) + 1] << 8 ) \
|
||||
| ( (uint32_t) (b)[(i) + 2] << 16 ) \
|
||||
| ( (uint32_t) (b)[(i) + 3] << 24 ); \
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef IOT_MD5_PUT_UINT32_LE
|
||||
#define IOT_MD5_PUT_UINT32_LE(n,b,i) \
|
||||
{ \
|
||||
(b)[(i) ] = (unsigned char) ( ( (n) ) & 0xFF ); \
|
||||
(b)[(i) + 1] = (unsigned char) ( ( (n) >> 8 ) & 0xFF ); \
|
||||
(b)[(i) + 2] = (unsigned char) ( ( (n) >> 16 ) & 0xFF ); \
|
||||
(b)[(i) + 3] = (unsigned char) ( ( (n) >> 24 ) & 0xFF ); \
|
||||
}
|
||||
#endif
|
||||
|
||||
void utils_md5_init(iot_md5_context *ctx)
|
||||
{
|
||||
memset(ctx, 0, sizeof(iot_md5_context));
|
||||
}
|
||||
|
||||
void utils_md5_free(iot_md5_context *ctx)
|
||||
{
|
||||
if (ctx == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
_utils_md5_zeroize(ctx, sizeof(iot_md5_context));
|
||||
}
|
||||
|
||||
void utils_md5_clone(iot_md5_context *dst,
|
||||
const iot_md5_context *src)
|
||||
{
|
||||
*dst = *src;
|
||||
}
|
||||
|
||||
/*
|
||||
* MD5 context setup
|
||||
*/
|
||||
void utils_md5_starts(iot_md5_context *ctx)
|
||||
{
|
||||
ctx->total[0] = 0;
|
||||
ctx->total[1] = 0;
|
||||
|
||||
ctx->state[0] = 0x67452301;
|
||||
ctx->state[1] = 0xEFCDAB89;
|
||||
ctx->state[2] = 0x98BADCFE;
|
||||
ctx->state[3] = 0x10325476;
|
||||
}
|
||||
|
||||
void utils_md5_process(iot_md5_context *ctx, const unsigned char data[64])
|
||||
{
|
||||
uint32_t X[16], A, B, C, D;
|
||||
|
||||
IOT_MD5_GET_UINT32_LE(X[ 0], data, 0);
|
||||
IOT_MD5_GET_UINT32_LE(X[ 1], data, 4);
|
||||
IOT_MD5_GET_UINT32_LE(X[ 2], data, 8);
|
||||
IOT_MD5_GET_UINT32_LE(X[ 3], data, 12);
|
||||
IOT_MD5_GET_UINT32_LE(X[ 4], data, 16);
|
||||
IOT_MD5_GET_UINT32_LE(X[ 5], data, 20);
|
||||
IOT_MD5_GET_UINT32_LE(X[ 6], data, 24);
|
||||
IOT_MD5_GET_UINT32_LE(X[ 7], data, 28);
|
||||
IOT_MD5_GET_UINT32_LE(X[ 8], data, 32);
|
||||
IOT_MD5_GET_UINT32_LE(X[ 9], data, 36);
|
||||
IOT_MD5_GET_UINT32_LE(X[10], data, 40);
|
||||
IOT_MD5_GET_UINT32_LE(X[11], data, 44);
|
||||
IOT_MD5_GET_UINT32_LE(X[12], data, 48);
|
||||
IOT_MD5_GET_UINT32_LE(X[13], data, 52);
|
||||
IOT_MD5_GET_UINT32_LE(X[14], data, 56);
|
||||
IOT_MD5_GET_UINT32_LE(X[15], data, 60);
|
||||
|
||||
#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
|
||||
|
||||
#define P(a,b,c,d,k,s,t) \
|
||||
{ \
|
||||
a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \
|
||||
}
|
||||
|
||||
A = ctx->state[0];
|
||||
B = ctx->state[1];
|
||||
C = ctx->state[2];
|
||||
D = ctx->state[3];
|
||||
|
||||
#define F(x,y,z) (z ^ (x & (y ^ z)))
|
||||
|
||||
P(A, B, C, D, 0, 7, 0xD76AA478);
|
||||
P(D, A, B, C, 1, 12, 0xE8C7B756);
|
||||
P(C, D, A, B, 2, 17, 0x242070DB);
|
||||
P(B, C, D, A, 3, 22, 0xC1BDCEEE);
|
||||
P(A, B, C, D, 4, 7, 0xF57C0FAF);
|
||||
P(D, A, B, C, 5, 12, 0x4787C62A);
|
||||
P(C, D, A, B, 6, 17, 0xA8304613);
|
||||
P(B, C, D, A, 7, 22, 0xFD469501);
|
||||
P(A, B, C, D, 8, 7, 0x698098D8);
|
||||
P(D, A, B, C, 9, 12, 0x8B44F7AF);
|
||||
P(C, D, A, B, 10, 17, 0xFFFF5BB1);
|
||||
P(B, C, D, A, 11, 22, 0x895CD7BE);
|
||||
P(A, B, C, D, 12, 7, 0x6B901122);
|
||||
P(D, A, B, C, 13, 12, 0xFD987193);
|
||||
P(C, D, A, B, 14, 17, 0xA679438E);
|
||||
P(B, C, D, A, 15, 22, 0x49B40821);
|
||||
|
||||
#undef F
|
||||
|
||||
#define F(x,y,z) (y ^ (z & (x ^ y)))
|
||||
|
||||
P(A, B, C, D, 1, 5, 0xF61E2562);
|
||||
P(D, A, B, C, 6, 9, 0xC040B340);
|
||||
P(C, D, A, B, 11, 14, 0x265E5A51);
|
||||
P(B, C, D, A, 0, 20, 0xE9B6C7AA);
|
||||
P(A, B, C, D, 5, 5, 0xD62F105D);
|
||||
P(D, A, B, C, 10, 9, 0x02441453);
|
||||
P(C, D, A, B, 15, 14, 0xD8A1E681);
|
||||
P(B, C, D, A, 4, 20, 0xE7D3FBC8);
|
||||
P(A, B, C, D, 9, 5, 0x21E1CDE6);
|
||||
P(D, A, B, C, 14, 9, 0xC33707D6);
|
||||
P(C, D, A, B, 3, 14, 0xF4D50D87);
|
||||
P(B, C, D, A, 8, 20, 0x455A14ED);
|
||||
P(A, B, C, D, 13, 5, 0xA9E3E905);
|
||||
P(D, A, B, C, 2, 9, 0xFCEFA3F8);
|
||||
P(C, D, A, B, 7, 14, 0x676F02D9);
|
||||
P(B, C, D, A, 12, 20, 0x8D2A4C8A);
|
||||
|
||||
#undef F
|
||||
|
||||
#define F(x,y,z) (x ^ y ^ z)
|
||||
|
||||
P(A, B, C, D, 5, 4, 0xFFFA3942);
|
||||
P(D, A, B, C, 8, 11, 0x8771F681);
|
||||
P(C, D, A, B, 11, 16, 0x6D9D6122);
|
||||
P(B, C, D, A, 14, 23, 0xFDE5380C);
|
||||
P(A, B, C, D, 1, 4, 0xA4BEEA44);
|
||||
P(D, A, B, C, 4, 11, 0x4BDECFA9);
|
||||
P(C, D, A, B, 7, 16, 0xF6BB4B60);
|
||||
P(B, C, D, A, 10, 23, 0xBEBFBC70);
|
||||
P(A, B, C, D, 13, 4, 0x289B7EC6);
|
||||
P(D, A, B, C, 0, 11, 0xEAA127FA);
|
||||
P(C, D, A, B, 3, 16, 0xD4EF3085);
|
||||
P(B, C, D, A, 6, 23, 0x04881D05);
|
||||
P(A, B, C, D, 9, 4, 0xD9D4D039);
|
||||
P(D, A, B, C, 12, 11, 0xE6DB99E5);
|
||||
P(C, D, A, B, 15, 16, 0x1FA27CF8);
|
||||
P(B, C, D, A, 2, 23, 0xC4AC5665);
|
||||
|
||||
#undef F
|
||||
|
||||
#define F(x,y,z) (y ^ (x | ~z))
|
||||
|
||||
P(A, B, C, D, 0, 6, 0xF4292244);
|
||||
P(D, A, B, C, 7, 10, 0x432AFF97);
|
||||
P(C, D, A, B, 14, 15, 0xAB9423A7);
|
||||
P(B, C, D, A, 5, 21, 0xFC93A039);
|
||||
P(A, B, C, D, 12, 6, 0x655B59C3);
|
||||
P(D, A, B, C, 3, 10, 0x8F0CCC92);
|
||||
P(C, D, A, B, 10, 15, 0xFFEFF47D);
|
||||
P(B, C, D, A, 1, 21, 0x85845DD1);
|
||||
P(A, B, C, D, 8, 6, 0x6FA87E4F);
|
||||
P(D, A, B, C, 15, 10, 0xFE2CE6E0);
|
||||
P(C, D, A, B, 6, 15, 0xA3014314);
|
||||
P(B, C, D, A, 13, 21, 0x4E0811A1);
|
||||
P(A, B, C, D, 4, 6, 0xF7537E82);
|
||||
P(D, A, B, C, 11, 10, 0xBD3AF235);
|
||||
P(C, D, A, B, 2, 15, 0x2AD7D2BB);
|
||||
P(B, C, D, A, 9, 21, 0xEB86D391);
|
||||
|
||||
#undef F
|
||||
|
||||
ctx->state[0] += A;
|
||||
ctx->state[1] += B;
|
||||
ctx->state[2] += C;
|
||||
ctx->state[3] += D;
|
||||
}
|
||||
|
||||
/*
|
||||
* MD5 process buffer
|
||||
*/
|
||||
void utils_md5_update(iot_md5_context *ctx, const unsigned char *input, size_t ilen)
|
||||
{
|
||||
size_t fill;
|
||||
uint32_t left;
|
||||
|
||||
if (ilen == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
left = ctx->total[0] & 0x3F;
|
||||
fill = 64 - left;
|
||||
|
||||
ctx->total[0] += (uint32_t) ilen;
|
||||
ctx->total[0] &= 0xFFFFFFFF;
|
||||
|
||||
if (ctx->total[0] < (uint32_t) ilen) {
|
||||
ctx->total[1]++;
|
||||
}
|
||||
|
||||
if (left && ilen >= fill) {
|
||||
memcpy((void *)(ctx->buffer + left), input, fill);
|
||||
utils_md5_process(ctx, ctx->buffer);
|
||||
input += fill;
|
||||
ilen -= fill;
|
||||
left = 0;
|
||||
}
|
||||
|
||||
while (ilen >= 64) {
|
||||
utils_md5_process(ctx, input);
|
||||
input += 64;
|
||||
ilen -= 64;
|
||||
}
|
||||
|
||||
if (ilen > 0) {
|
||||
memcpy((void *)(ctx->buffer + left), input, ilen);
|
||||
}
|
||||
}
|
||||
|
||||
static const unsigned char iot_md5_padding[64] = {
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
/*
|
||||
* MD5 final digest
|
||||
*/
|
||||
void utils_md5_finish(iot_md5_context *ctx, unsigned char output[16])
|
||||
{
|
||||
uint32_t last, padn;
|
||||
uint32_t high, low;
|
||||
unsigned char msglen[8];
|
||||
|
||||
high = (ctx->total[0] >> 29)
|
||||
| (ctx->total[1] << 3);
|
||||
low = (ctx->total[0] << 3);
|
||||
|
||||
IOT_MD5_PUT_UINT32_LE(low, msglen, 0);
|
||||
IOT_MD5_PUT_UINT32_LE(high, msglen, 4);
|
||||
|
||||
last = ctx->total[0] & 0x3F;
|
||||
padn = (last < 56) ? (56 - last) : (120 - last);
|
||||
|
||||
utils_md5_update(ctx, iot_md5_padding, padn);
|
||||
utils_md5_update(ctx, msglen, 8);
|
||||
|
||||
IOT_MD5_PUT_UINT32_LE(ctx->state[0], output, 0);
|
||||
IOT_MD5_PUT_UINT32_LE(ctx->state[1], output, 4);
|
||||
IOT_MD5_PUT_UINT32_LE(ctx->state[2], output, 8);
|
||||
IOT_MD5_PUT_UINT32_LE(ctx->state[3], output, 12);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* output = MD5( input buffer )
|
||||
*/
|
||||
void utils_md5(const unsigned char *input, size_t ilen, unsigned char output[16])
|
||||
{
|
||||
iot_md5_context ctx;
|
||||
|
||||
utils_md5_init(&ctx);
|
||||
utils_md5_starts(&ctx);
|
||||
utils_md5_update(&ctx, input, ilen);
|
||||
utils_md5_finish(&ctx, output);
|
||||
utils_md5_free(&ctx);
|
||||
}
|
||||
|
||||
int8_t utils_hb2hex(uint8_t hb)
|
||||
{
|
||||
hb = hb & 0xF;
|
||||
return (int8_t)(hb < 10 ? '0' + hb : hb - 10 + 'a');
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,335 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is
|
||||
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "qcloud.h"
|
||||
|
||||
/* Implementation that should never be optimized out by the compiler */
|
||||
static void utils_sha1_zeroize(void *v, size_t n)
|
||||
{
|
||||
volatile unsigned char *p = v;
|
||||
while (n--) {
|
||||
*p++ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 32-bit integer manipulation macros (big endian)
|
||||
*/
|
||||
#ifndef IOT_SHA1_GET_UINT32_BE
|
||||
#define IOT_SHA1_GET_UINT32_BE(n,b,i) \
|
||||
{ \
|
||||
(n) = ( (uint32_t) (b)[(i) ] << 24 ) \
|
||||
| ( (uint32_t) (b)[(i) + 1] << 16 ) \
|
||||
| ( (uint32_t) (b)[(i) + 2] << 8 ) \
|
||||
| ( (uint32_t) (b)[(i) + 3] ); \
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef IOT_SHA1_PUT_UINT32_BE
|
||||
#define IOT_SHA1_PUT_UINT32_BE(n,b,i) \
|
||||
{ \
|
||||
(b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
|
||||
(b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
|
||||
(b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
|
||||
(b)[(i) + 3] = (unsigned char) ( (n) ); \
|
||||
}
|
||||
#endif
|
||||
|
||||
void utils_sha1_init(iot_sha1_context *ctx)
|
||||
{
|
||||
memset(ctx, 0, sizeof(iot_sha1_context));
|
||||
}
|
||||
|
||||
void utils_sha1_free(iot_sha1_context *ctx)
|
||||
{
|
||||
if (ctx == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
utils_sha1_zeroize(ctx, sizeof(iot_sha1_context));
|
||||
}
|
||||
|
||||
void utils_sha1_clone(iot_sha1_context *dst,
|
||||
const iot_sha1_context *src)
|
||||
{
|
||||
*dst = *src;
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA-1 context setup
|
||||
*/
|
||||
void utils_sha1_starts(iot_sha1_context *ctx)
|
||||
{
|
||||
ctx->total[0] = 0;
|
||||
ctx->total[1] = 0;
|
||||
|
||||
ctx->state[0] = 0x67452301;
|
||||
ctx->state[1] = 0xEFCDAB89;
|
||||
ctx->state[2] = 0x98BADCFE;
|
||||
ctx->state[3] = 0x10325476;
|
||||
ctx->state[4] = 0xC3D2E1F0;
|
||||
}
|
||||
|
||||
void utils_sha1_process(iot_sha1_context *ctx, const unsigned char data[64])
|
||||
{
|
||||
uint32_t temp, W[16], A, B, C, D, E;
|
||||
|
||||
IOT_SHA1_GET_UINT32_BE(W[ 0], data, 0);
|
||||
IOT_SHA1_GET_UINT32_BE(W[ 1], data, 4);
|
||||
IOT_SHA1_GET_UINT32_BE(W[ 2], data, 8);
|
||||
IOT_SHA1_GET_UINT32_BE(W[ 3], data, 12);
|
||||
IOT_SHA1_GET_UINT32_BE(W[ 4], data, 16);
|
||||
IOT_SHA1_GET_UINT32_BE(W[ 5], data, 20);
|
||||
IOT_SHA1_GET_UINT32_BE(W[ 6], data, 24);
|
||||
IOT_SHA1_GET_UINT32_BE(W[ 7], data, 28);
|
||||
IOT_SHA1_GET_UINT32_BE(W[ 8], data, 32);
|
||||
IOT_SHA1_GET_UINT32_BE(W[ 9], data, 36);
|
||||
IOT_SHA1_GET_UINT32_BE(W[10], data, 40);
|
||||
IOT_SHA1_GET_UINT32_BE(W[11], data, 44);
|
||||
IOT_SHA1_GET_UINT32_BE(W[12], data, 48);
|
||||
IOT_SHA1_GET_UINT32_BE(W[13], data, 52);
|
||||
IOT_SHA1_GET_UINT32_BE(W[14], data, 56);
|
||||
IOT_SHA1_GET_UINT32_BE(W[15], data, 60);
|
||||
|
||||
#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
|
||||
|
||||
#define R(t) \
|
||||
( \
|
||||
temp = W[( t - 3 ) & 0x0F] ^ W[( t - 8 ) & 0x0F] ^ \
|
||||
W[( t - 14 ) & 0x0F] ^ W[ t & 0x0F], \
|
||||
( W[t & 0x0F] = S(temp,1) ) \
|
||||
)
|
||||
|
||||
#define P(a,b,c,d,e,x) \
|
||||
{ \
|
||||
e += S(a,5) + F(b,c,d) + K + x; b = S(b,30); \
|
||||
}
|
||||
|
||||
A = ctx->state[0];
|
||||
B = ctx->state[1];
|
||||
C = ctx->state[2];
|
||||
D = ctx->state[3];
|
||||
E = ctx->state[4];
|
||||
|
||||
#define F(x,y,z) (z ^ (x & (y ^ z)))
|
||||
#define K 0x5A827999
|
||||
|
||||
P(A, B, C, D, E, W[0]);
|
||||
P(E, A, B, C, D, W[1]);
|
||||
P(D, E, A, B, C, W[2]);
|
||||
P(C, D, E, A, B, W[3]);
|
||||
P(B, C, D, E, A, W[4]);
|
||||
P(A, B, C, D, E, W[5]);
|
||||
P(E, A, B, C, D, W[6]);
|
||||
P(D, E, A, B, C, W[7]);
|
||||
P(C, D, E, A, B, W[8]);
|
||||
P(B, C, D, E, A, W[9]);
|
||||
P(A, B, C, D, E, W[10]);
|
||||
P(E, A, B, C, D, W[11]);
|
||||
P(D, E, A, B, C, W[12]);
|
||||
P(C, D, E, A, B, W[13]);
|
||||
P(B, C, D, E, A, W[14]);
|
||||
P(A, B, C, D, E, W[15]);
|
||||
P(E, A, B, C, D, R(16));
|
||||
P(D, E, A, B, C, R(17));
|
||||
P(C, D, E, A, B, R(18));
|
||||
P(B, C, D, E, A, R(19));
|
||||
|
||||
#undef K
|
||||
#undef F
|
||||
|
||||
#define F(x,y,z) (x ^ y ^ z)
|
||||
#define K 0x6ED9EBA1
|
||||
|
||||
P(A, B, C, D, E, R(20));
|
||||
P(E, A, B, C, D, R(21));
|
||||
P(D, E, A, B, C, R(22));
|
||||
P(C, D, E, A, B, R(23));
|
||||
P(B, C, D, E, A, R(24));
|
||||
P(A, B, C, D, E, R(25));
|
||||
P(E, A, B, C, D, R(26));
|
||||
P(D, E, A, B, C, R(27));
|
||||
P(C, D, E, A, B, R(28));
|
||||
P(B, C, D, E, A, R(29));
|
||||
P(A, B, C, D, E, R(30));
|
||||
P(E, A, B, C, D, R(31));
|
||||
P(D, E, A, B, C, R(32));
|
||||
P(C, D, E, A, B, R(33));
|
||||
P(B, C, D, E, A, R(34));
|
||||
P(A, B, C, D, E, R(35));
|
||||
P(E, A, B, C, D, R(36));
|
||||
P(D, E, A, B, C, R(37));
|
||||
P(C, D, E, A, B, R(38));
|
||||
P(B, C, D, E, A, R(39));
|
||||
|
||||
#undef K
|
||||
#undef F
|
||||
|
||||
#define F(x,y,z) ((x & y) | (z & (x | y)))
|
||||
#define K 0x8F1BBCDC
|
||||
|
||||
P(A, B, C, D, E, R(40));
|
||||
P(E, A, B, C, D, R(41));
|
||||
P(D, E, A, B, C, R(42));
|
||||
P(C, D, E, A, B, R(43));
|
||||
P(B, C, D, E, A, R(44));
|
||||
P(A, B, C, D, E, R(45));
|
||||
P(E, A, B, C, D, R(46));
|
||||
P(D, E, A, B, C, R(47));
|
||||
P(C, D, E, A, B, R(48));
|
||||
P(B, C, D, E, A, R(49));
|
||||
P(A, B, C, D, E, R(50));
|
||||
P(E, A, B, C, D, R(51));
|
||||
P(D, E, A, B, C, R(52));
|
||||
P(C, D, E, A, B, R(53));
|
||||
P(B, C, D, E, A, R(54));
|
||||
P(A, B, C, D, E, R(55));
|
||||
P(E, A, B, C, D, R(56));
|
||||
P(D, E, A, B, C, R(57));
|
||||
P(C, D, E, A, B, R(58));
|
||||
P(B, C, D, E, A, R(59));
|
||||
|
||||
#undef K
|
||||
#undef F
|
||||
|
||||
#define F(x,y,z) (x ^ y ^ z)
|
||||
#define K 0xCA62C1D6
|
||||
|
||||
P(A, B, C, D, E, R(60));
|
||||
P(E, A, B, C, D, R(61));
|
||||
P(D, E, A, B, C, R(62));
|
||||
P(C, D, E, A, B, R(63));
|
||||
P(B, C, D, E, A, R(64));
|
||||
P(A, B, C, D, E, R(65));
|
||||
P(E, A, B, C, D, R(66));
|
||||
P(D, E, A, B, C, R(67));
|
||||
P(C, D, E, A, B, R(68));
|
||||
P(B, C, D, E, A, R(69));
|
||||
P(A, B, C, D, E, R(70));
|
||||
P(E, A, B, C, D, R(71));
|
||||
P(D, E, A, B, C, R(72));
|
||||
P(C, D, E, A, B, R(73));
|
||||
P(B, C, D, E, A, R(74));
|
||||
P(A, B, C, D, E, R(75));
|
||||
P(E, A, B, C, D, R(76));
|
||||
P(D, E, A, B, C, R(77));
|
||||
P(C, D, E, A, B, R(78));
|
||||
P(B, C, D, E, A, R(79));
|
||||
|
||||
#undef K
|
||||
#undef F
|
||||
|
||||
ctx->state[0] += A;
|
||||
ctx->state[1] += B;
|
||||
ctx->state[2] += C;
|
||||
ctx->state[3] += D;
|
||||
ctx->state[4] += E;
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA-1 process buffer
|
||||
*/
|
||||
void utils_sha1_update(iot_sha1_context *ctx, const unsigned char *input, size_t ilen)
|
||||
{
|
||||
size_t fill;
|
||||
uint32_t left;
|
||||
|
||||
if (ilen == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
left = ctx->total[0] & 0x3F;
|
||||
fill = 64 - left;
|
||||
|
||||
ctx->total[0] += (uint32_t) ilen;
|
||||
ctx->total[0] &= 0xFFFFFFFF;
|
||||
|
||||
if (ctx->total[0] < (uint32_t) ilen) {
|
||||
ctx->total[1]++;
|
||||
}
|
||||
|
||||
if (left && ilen >= fill) {
|
||||
memcpy((void *)(ctx->buffer + left), input, fill);
|
||||
utils_sha1_process(ctx, ctx->buffer);
|
||||
input += fill;
|
||||
ilen -= fill;
|
||||
left = 0;
|
||||
}
|
||||
|
||||
while (ilen >= 64) {
|
||||
utils_sha1_process(ctx, input);
|
||||
input += 64;
|
||||
ilen -= 64;
|
||||
}
|
||||
|
||||
if (ilen > 0) {
|
||||
memcpy((void *)(ctx->buffer + left), input, ilen);
|
||||
}
|
||||
}
|
||||
|
||||
static const unsigned char iot_sha1_padding[64] = {
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
/*
|
||||
* SHA-1 final digest
|
||||
*/
|
||||
void utils_sha1_finish(iot_sha1_context *ctx, unsigned char output[20])
|
||||
{
|
||||
uint32_t last, padn;
|
||||
uint32_t high, low;
|
||||
unsigned char msglen[8];
|
||||
|
||||
high = (ctx->total[0] >> 29)
|
||||
| (ctx->total[1] << 3);
|
||||
low = (ctx->total[0] << 3);
|
||||
|
||||
IOT_SHA1_PUT_UINT32_BE(high, msglen, 0);
|
||||
IOT_SHA1_PUT_UINT32_BE(low, msglen, 4);
|
||||
|
||||
last = ctx->total[0] & 0x3F;
|
||||
padn = (last < 56) ? (56 - last) : (120 - last);
|
||||
|
||||
utils_sha1_update(ctx, iot_sha1_padding, padn);
|
||||
utils_sha1_update(ctx, msglen, 8);
|
||||
|
||||
IOT_SHA1_PUT_UINT32_BE(ctx->state[0], output, 0);
|
||||
IOT_SHA1_PUT_UINT32_BE(ctx->state[1], output, 4);
|
||||
IOT_SHA1_PUT_UINT32_BE(ctx->state[2], output, 8);
|
||||
IOT_SHA1_PUT_UINT32_BE(ctx->state[3], output, 12);
|
||||
IOT_SHA1_PUT_UINT32_BE(ctx->state[4], output, 16);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* output = SHA-1( input buffer )
|
||||
*/
|
||||
void utils_sha1(const unsigned char *input, size_t ilen, unsigned char output[20])
|
||||
{
|
||||
iot_sha1_context ctx;
|
||||
|
||||
utils_sha1_init(&ctx);
|
||||
utils_sha1_starts(&ctx);
|
||||
utils_sha1_update(&ctx, input, ilen);
|
||||
utils_sha1_finish(&ctx, output);
|
||||
utils_sha1_free(&ctx);
|
||||
}
|
||||
|
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019 Tencent Group. All rights reserved.
|
||||
* License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qcloud.h"
|
||||
|
||||
char *LITE_format_string(const char *fmt, ...)
|
||||
{
|
||||
#define TEMP_STRING_MAXLEN (512)
|
||||
|
||||
va_list ap;
|
||||
char *tmp = NULL;
|
||||
char *dst;
|
||||
int rc = -1;
|
||||
|
||||
va_start(ap, fmt);
|
||||
tmp = osal_malloc(TEMP_STRING_MAXLEN);
|
||||
memset(tmp, 0, TEMP_STRING_MAXLEN);
|
||||
rc = osal_vsnprintf(tmp, TEMP_STRING_MAXLEN, fmt, ap);
|
||||
va_end(ap);
|
||||
LITE_ASSERT(tmp);
|
||||
LITE_ASSERT(rc < 1024);
|
||||
|
||||
dst = LITE_strdup(tmp);
|
||||
osal_free(tmp);
|
||||
|
||||
return dst;
|
||||
|
||||
#undef TEMP_STRING_MAXLEN
|
||||
}
|
||||
|
||||
char *LITE_format_nstring(const int len, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *tmp = NULL;
|
||||
char *dst;
|
||||
int rc = -1;
|
||||
|
||||
va_start(ap, fmt);
|
||||
tmp = osal_malloc(len+2);
|
||||
memset(tmp, 0, len+2);
|
||||
rc = osal_vsnprintf(tmp, len+1, fmt, ap);
|
||||
va_end(ap);
|
||||
LITE_ASSERT(tmp);
|
||||
LITE_ASSERT(rc < 1024);
|
||||
|
||||
dst = osal_malloc(len + 1);
|
||||
osal_snprintf(dst, (len + 1), "%s", tmp);
|
||||
osal_free(tmp);
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
char *LITE_strdup(const char *src)
|
||||
{
|
||||
int len = 0;
|
||||
char *dst = NULL;
|
||||
|
||||
if (!src) {
|
||||
return NULL;
|
||||
}
|
||||
len = strlen(src) + 1;
|
||||
if (len > 1024) {
|
||||
QCLOUD_LOG_E("Too long string to duplicate, abort! len = %d", len);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dst = (char *)osal_malloc(sizeof(char) * len);
|
||||
if (!dst) {
|
||||
return NULL;
|
||||
}
|
||||
strncpy(dst, src, len);
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
void LITE_hexbuf_convert(unsigned char *digest, char *out, int in_len, int uppercase)
|
||||
{
|
||||
static char *zEncode[] = {"0123456789abcdef", "0123456789ABCDEF"};
|
||||
int j = 0;
|
||||
int i = 0;
|
||||
int idx = uppercase ? 1 : 0;
|
||||
|
||||
for (i = 0; i < in_len; i ++) {
|
||||
int a = digest[i];
|
||||
|
||||
out[j++] = zEncode[idx][(a >> 4) & 0xf];
|
||||
out[j++] = zEncode[idx][a & 0xf];
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t _hexval_of_char(char hex)
|
||||
{
|
||||
if (LITE_isdigit(hex)) {
|
||||
return (hex - '0');
|
||||
}
|
||||
if (hex >= 'a' && hex <= 'f') {
|
||||
return (hex - 'a' + 10);
|
||||
}
|
||||
if (hex >= 'A' && hex <= 'F') {
|
||||
return (hex - 'A' + 10);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LITE_hexstr_convert(char *hexstr, uint8_t *out_buf, int in_len)
|
||||
{
|
||||
int i = 0;
|
||||
uint8_t ch0, ch1;
|
||||
|
||||
if (in_len % 2 != 0) {
|
||||
QCLOUD_LOG_E("hexstr length (%d) is not even", in_len);
|
||||
return;
|
||||
}
|
||||
|
||||
while (i < in_len) {
|
||||
ch0 = _hexval_of_char((char)hexstr[2 * i]);
|
||||
ch1 = _hexval_of_char((char)hexstr[2 * i + 1]);
|
||||
out_buf[i] = (ch0 << 4 | ch1);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void LITE_replace_substr(char originalString[], char key[], char swap[])
|
||||
{
|
||||
int lengthOfOriginalString, lengthOfKey, lengthOfSwap, i, j, flag;
|
||||
char tmp[512];
|
||||
|
||||
lengthOfOriginalString = strlen(originalString);
|
||||
lengthOfKey = strlen(key);
|
||||
lengthOfSwap = strlen(swap);
|
||||
|
||||
for (i = 0; i <= lengthOfOriginalString - lengthOfKey; i++) {
|
||||
flag = 1;
|
||||
for (j = 0; j < lengthOfKey; j++) {
|
||||
if (originalString[i + j] != key[j]) {
|
||||
flag = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (flag) {
|
||||
strcpy(tmp, originalString);
|
||||
strcpy(&tmp[i], swap);
|
||||
strcpy(&tmp[i + lengthOfSwap], &originalString[i + lengthOfKey]);
|
||||
strcpy(originalString, tmp);
|
||||
i += lengthOfSwap - 1;
|
||||
lengthOfOriginalString = strlen(originalString);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user