

#ifndef MLSSL_H__
#define MLSSL_H__

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <time.h>
#include <stdint.h>

#include "uECC.h"

//Key上传的定时时间间隔，默认是72小时
#define UPLOAD_KEY_DURATION  72 * 60 * 60
//Key上传成功后，旧的Key需要保留的时间，此时新旧Key都可用于解密
#define KEY_MAX_KEEP_TIME 60 * 5
//Key上传错误后，间隔多久再重新上传Key
#define UPLOAD_KEY_ERROR_DURATION 60

#ifdef __cplusplus
extern "C"
{
#endif

/**

 * @brief Http Post函数接口
 * @param url       	http url
 * @param postdata      post的数据内容
 * @param postlen       数据长度
 * @param rdata         返回的数据
 * @param len         	返回的长度
 * @return  1-成功  0-失败
 */
typedef int (* FunHttpPostKey )(const char* url, const uint8_t* postdata, size_t postlen, uint8_t* rdata, size_t len);

typedef void ( * OnReceive )(void *context, const void* data, size_t length, void *arg);

/**
 * @brief 发送消息(XMPP,MQTT)
 * @param user       	发送到的用户，NULL表示发送到所有用户
 * @param data      	发送的数据
 * @param length       	数据长度
 * @return  1-成功  0-失败
 */
typedef int (* FunSendMessage)(void* user, const void* data, size_t length);

typedef struct _ssl_context {
    FunHttpPostKey http_post_key;
    OnReceive on_message;
    FunSendMessage send_message;
    uint8_t secKey[uECC_BYTES];
    uint8_t secKey1[uECC_BYTES];
    time_t keytime;
    const char* SN;
    const char* MAC;
    void *data;							//存储自定义的数据
} ssl_context;

//typedef struct stu_ssl_context {
//	FunHttpPostKey http_post_key;
//	OnReceive on_message;
//	FunSendMessage send_message;
//	uint8_t secKey[uECC_BYTES];
//	uint8_t secKey1[uECC_BYTES];
//	time_t keytime;
//	const char* SN;
//	const char* MAC;
//	void *data;							//存储自定义的数据
//} ssl_context;

/**
 * @brief 初始化上下文
 * @param sn    			设备的SN
 * @param send_message   	实际的发送函数，如xmpp发送
 * @param on_message		实际的接收函数，处理解密后的消息
 * @param http_post_key		http上传函数
 * @return 		上下文
 */
ssl_context *ssl_init_(const char*sn, FunSendMessage send_message,OnReceive on_message,FunHttpPostKey http_post_key);

/**
 * @brief 释放上下文
 * @param context     上下文,由ssl_init返回
 * @return
 */
void ssl_destroy(ssl_context * context);

/**
 * @brief 生成key,并保存在上下中
 * @param context     上下文,由ssl_init返回
 * @param key         用于接收返回Key,长度
 * @return
 */
void ssl_generate_key(ssl_context * context, uint8_t* key);

/**
 * @brief 上传key到服务器
 * @param context     上下文,由ssl_init返回
 * @param key         需要上传的key
 * @return   0成功;  -1失败;   >0剩余的时间
 */
int ssl_upload_key(ssl_context * context, uint8_t* key);

/**
 * @brief 检测key是否满足相应时间，满足时间则上传Key，
 * 	建议在一个线程中循环调用，调用完成后等待返回值n秒后再调用
 * 示例
 *	 	void onthread(void *d) {
			int n = ssl_make_key_chang((ssl_context*)d);
			sleep(n);
		}
 * @param context     上下文,由ssl_init返回
 * @return 下次上传Key的等待时间
 */
int ssl_make_key_change(ssl_context * context);

/**
 * @brief 加密数据,加密后的数据经过Base64处理
 * @param key        加密的Key
 * @param src        发送给的用户
 * @param srclen     src数据长度
 * @param dst        返回的数据
 * @param dstlen     dst数据长度
 * @return  0-失败 n-长度
 */
int ssl_encrypt(const uint8_t *key, const uint8_t *src, size_t srclen, uint8_t *dst, size_t dstlen);

/**
 * @brief 发送数据,可以直接用该函数替换原来xmpp的发送函数
 * @param context     上下文,由ssl_init返回
 * @param user        发送给的用户
 * @param data        数据内容
 * @param length      数据长度
 * @return
 */
int ssl_send(ssl_context * context, const void* user, const uint8_t* data, size_t length);

/**
 * @brief 消息接收函数，有消息返回时调用此函数进行解密处理，如xmpp收到消息后，调用该函数进行解密，解密成功
 *        后会调用context中的on_message回调，可以在此回调中处理原来的请求
 * @param context     上下文,由ssl_init返回
 * @param from        接收来的用户
 * @param data        数据内容
 * @param length      数据长度
 * @return
 */
void ssl_on_message(ssl_context *context, void* from, const uint8_t* data, size_t length, void *arg);


size_t ssl_encryp_data_len(size_t len);

int ssl_decrypt_data(const uint8_t *secKey, const void *data, size_t length, uint8_t *outdata, size_t *size,ssl_context *context);

uint8_t *ssl_get_secKey(ssl_context *context);

void ssl_set_data(ssl_context *context, void*data);


//lhy添加
uint8_t* encrypt_to_hex(const uint8_t *key, const uint8_t *src, size_t srclen) ;
void towidechar(uint8_t *buf, int cmdlen, char *out);

#ifdef __cplusplus
}
#endif

#endif

