POST diagnose_log/set HTTP/1.1
Host: 192.168.137.101
Cache-control: no-cache
User-Agent: Camera
First-Login: 0
tapo_tag: 31DCA30558E8599A84A377E6B3FDB3FAC1511C2778BAF29F42D91F21EE158469
seq: 746
Device-Mac: 8C902D3F996D
Content-Length: 2834
Connection: keep-alive
X-If-Encrypt: 1
X-Nonce: ac7f66701c102a5f56a02bcecf6793c4
Content-Type: application/json
{"method":"securePassthrough","params":{"request":"F6bRsXD9GbxQ\/v8tsF+\/uo3s\/09JHiW0GNJWvueS6TnSixXb+c\/jcxseW7Y3xAuEzp\/tyZRoz\/hr0BmYJO2P1X5Pr8c9ISQa6o5FhoqAZE64xaz7ShxguFeEgdEbPfk6mbzXiw39TXkwzcb+bJxJnenQmoGIUpSLwNQ2DaJ3MbuRnQGNORqH\/ttnAlKaIoDHXZ2Pl3vaPgbasSzyCxGHIa30tpw57JC9IKpnpokvgnqCOCYLBf1Ow6LDiAl2luXTum8gzLnqfOh8b5Kb4PgU0EaawAkQs6JPMeWMdSd971iLYio2I\/DckzgPwvhllqB4kHjz5noaGOWPYfqYHc\/3hLFV1ZXe+XOVPkWhK0TBbYh\/\/FwLd7yraHLhrVhEX2kHSDcxhEWuLFG2N+7OkOwhKl2xElzbTa6hIShVs2+BF3bro2ag+isfbCnIzXqwN2mVrT9DZVIaTcmjt7gfVmRCs9WZvo2+JPjGMXCeNCKelrr927m+GPRYh9giI\/qkjBDfFyaTXwf5WVcEs66XXDQv66Rl8C67380fqLt3owT\/WqQLPD0cQCWnQ5hlWFlwp3Yv6VBg7U0caFOFOqQzaBeBY5wTuTiMTAOMLWrEOtl8P2aFGhWPOug8oT1QUPFnDyOXOcTyqcY8iDvuZYycvNIKt6Qpvpac3upSrqvs1CWXTXhkIQ4yzI0S4rBgFmp+mAkD4Adaf8r8SVOo97SuasTQihk26a1DGLtVyLhztZ0AvIxMBmRA6PNnmhUJ0C2YaVCJRIs6LL71JCHEvjI4CnynC0vYbZsxNNvqwY\/WMMd95qt1FROgu7tI1LwP60RAEqZxAad\/NEcHPSC5n4LSleECjXgVAsIbY5ONbBFEs5QivPDKlTm1bnzhV5M3dDwUyZynkwYSzXI1yoYnU6VZt8413Pe\/mVqLiaywUOyCGtRedPMNyCDX54O+25GEJTN0LWb2oZh2DpTgCcxpGn6SXhXGaKp3oIoZPgWebIYd7WJfhOmgjv+WvAov7XAbWPNKZ247jFuR70oQeKrljWpg\/p4Y5iqcABuuMQXR3BAcjP1TZAjPdkFjlPye7NBayxBC86FntJ1QFMNv1oGSV+ygta2sJahiPH9VJB+oHozhS6j+x68Ktlw+9Fn8stJIHaXcvdCuEs47kCimaYgtzSvo4T5oYLqGYdEL6eReZwT8YmTe1qYAg1Ubisb6JVf0KQBoGbnWOvmTb3aZFzLrDP24Kl\/XVGBSiCa61PPDXUweregBUllpHoBQfT31Z0fcAZ1Fmxv+uU\/vcfFO1im0mQu4912fuFJ\/Wo4hcPY8XicZ5Pic9qazgoS59K49TtnnKLVoK2aGYkwndeHbmiRLcFwfA2PUn4ngOSZAhnZZaS+zZs0+Q5H+Eqiva95gGhQ\/rjLgtOlqEqQYX6CXMy1wJW9K8GRm5e+NtfOxNAakLUnlv9Z3PKM536cFVgU3qm5KoyxP3NrGOP0a6YFR2l3uvEAAB7NSl4tGkTXe8NF\/GNse8j1fm0P0T9p4J5Y7\/wXpkk5JUmqeLV42uDYm2DAvG6a2Evg2WAI0q5aMigzdzXHveUI0KL4\/LqBFXWCa\/cai0Te3ErV8HP4H9W31iy9CaTwyQccvxHzernSfd6lG9Y1tHp3opV3TtLN3Zpd5K1gNMz3cZo8jOHammK4cVGMagp39HIlQe4aABH9AhpuRixxpD7zXjWMc6bCYODrrij2+GbJU2zozlD1iZ\/faKkAM71HCO\/yKrfUnzAJoIQ5pFKX79uG\/fY5XYVpwJp+7l5H1Jo8kskQjkuxl4liSX6seu8sFYaSIPPwcvn3m\/vmOOAZsHTLPg4yQhZ\/wIkTZtoVxen6M5iVd\/DqIMXSm1iVvi6EYfL8oXR5SBwG42FSKJeheYarrkR8noN2qR\/g1aK7pWs1iQxby7WzFPYqAYbTEvb1o\/5r6wKKZUrR4V8mkJoGAmt8EysOWygg+NikWquOeN8xOnDMplqZOyQKxmahz5TEN60DSgVvwIqCDeKBUjk2K\/Ah4QKyoFp7fogymozW43lk+Z5+lWnoGbGD6j08huAYb0WWDUWA\/SSh6p5JRtp\/FWWQ+TcCMjR0RCiBoTJVOPSOW36KezgWffoYR6filwLhXOa3YgNEawmxavf5f\/fQyh1eyJQRg9v\/pKqmB92kj8qz4zqRw2DZEUSQLPReiJQr0A3uAnjNsB\/Jb8dCKoqUNteHzFHekaRuqnfki4c7\/+hfzH0gvv2lsFmIFsvAXzEhs6fOwO628rjNtZm0NSJXvgXXLqZ6k+i9NgBhODwS11872cE5vWf9RAuPUyd27EmIBTzYSWcFFwrU5idv\/R4pkqv2fBrQumFNDblXPcMpRwa5YjCYAZP\/IeBf6b6ZMS7NdpfdPyggOyMgtEb\/gGRYq4QO+T3PyFuniSyt0xK+e3FtDOiguRmHQimJDHRTdTUQpn+whwbtQTvChrVw4SLQzILD6fnvDoPC17l1E9wmJRbFpSflWnCIHhfKpNH\/IJyhCC7aUjWpHwiAbbpSATw4AEVPbQunbhanp5n+mn\/aOj8b0\/8UOyMa0oU595zWMUGuHrEhEAsirUs8YBdVNgkkTpDdCiuSQ1E8KY4Xp6hnE7idiLtytLlSszqzQT4t82QHsrldfy1CLfKJx8eesTI8OzQW8qKTYLKhbCeaLpC9U0bb8Jiz688jXXbNpX2sllTJuKFWOCes9PL+ZQd1VsN1nADpRigk="}}这是camera发来的报文,帮我解析拿到base64编码的信息。bool tpsocket_event_filelog_to_hub(struct tpsocket_handler *handler, struct list_head *buf, int event)
{
struct tpsocket_fd *sock = container_of(handler, struct tpsocket_fd, handler);
FileLogSession *session = handler->priv;
if(!session){
return false;
}
int decrypt_flag = session->decrypt_flag;
struct tpsocket_buf *nbuf = NULL;
FILE *fp = session->fp;
int remaining = session->remaining;
char *filepath = session->filepath;
DBG_ERR("sock=%p, event=%s\n", sock, tpsocket_event_name(event));
switch(event) {
case TPSOCKET_EVENT_LISTEN:
DBG_ERR("TPSOCKET_EVENT_LISTEN: %s:%s Listen\n", sock->addr, sock->port);
break;
case TPSOCKET_EVENT_SHUTDOWN:
DBG_ERR("TPSOCKET_EVENT_LISTEN: %s:%s Shutdown\n", sock->addr, sock->port);
break;
case TPSOCKET_EVENT_ACCEPT:
DBG_ERR("TPSOCKET_EVENT_LISTEN: %s:%s Accepted\n", sock->addr, sock->port);
break;
case TPSOCKET_EVENT_CONNECTED:
DBG_ERR("TPSOCKET_EVENT_LISTEN: %s:%s connected\n", sock->addr, sock->port);
break;
case TPSOCKET_EVENT_REQ_HEAD:
DBG_ERR("TPSOCKET_EVENT_LISTEN: %s Requested path: %s\n", sock->path, sock->parser.http.url);
break;
case TPSOCKET_EVENT_RSP_HEAD:
break;
case TPSOCKET_EVENT_SUB_HEAD:
break;
case TPSOCKET_EVENT_UPGRADE:
break;
case TPSOCKET_EVENT_STREAM:
return true;
case TPSOCKET_EVENT_MESSAGE:
nbuf = tpsocket_merge_buf(buf);
if (!nbuf) {
DBG_ERR("Failed to merge buffer\n");
break;
}
if (!fp)
{
DBG_ERR("File pointer is NULL, cannot write\n");
break;
}
unsigned char *input_data = tpbuf_data(nbuf);
int input_len = tpbuf_data_len(nbuf);
DBG_ERR("input_len:%d", input_len);
bool error = false;
if (decrypt_flag)
{
DBG_ERR("+++++++++++++++++++++++++++++");
int decoded_len = tpsocket_base64_decode(input_data, input_len, input_data);
if (decoded_len < 0)
{
DBG_ERR("Base64 decoding failed\n");
error = true;
}
DBG_ERR("tpsocket_base64_decode\n");
int plain_len = decoded_len;
if (remaining > decoded_len)
{
remaining = decoded_len;
DBG_ERR("decode session->remaining:%d\n", remaining);
}
unsigned char *plain_data = calloc(plain_len, sizeof(unsigned char));
DBG_ERR("plain_data:%s\n", plain_data);
work_tapo_log_decrypt(tpbuf_data(nbuf), decoded_len, plain_data, &plain_len);
DBG_ERR("plain_len:%d\n",plain_len);
// 写入解密后的内容
if (fwrite(plain_data, 1, plain_len, fp) < plain_len)
{
DBG_ERR("File write error after decryption: %s\n", strerror(errno));
error = true;
}
else
{
const char newline = '\n';
if (fwrite(&newline, 1, 1, fp) != 1) {
DBG_ERR("Failed to write newline character: %s\n", strerror(errno));
}
remaining -= plain_len;
}
}
else
{
if (fwrite(input_data, 1, input_len, fp) < input_len) {
DBG_ERR("File write error: %s\n", strerror(errno));
error = true;
} else {
const char newline = '\n';
if (fwrite(&newline, 1, 1, fp) != 1) {
DBG_ERR("Failed to write newline character: %s\n", strerror(errno));
}
remaining -= input_len;
}
}
DBG_ERR("session->remaining: %d\n", remaining);
// 传输完成处理
if (remaining <= 0 || error) {
if (fp) {
fclose(fp);
session->fp = NULL;
}
// char resp[256];
if (error) {
// snprintf(resp, sizeof(resp),
// "HTTP/1.1 500 Internal Error\r\n"
// "Connection: close\r\n"
// "{\"error_code\":0}"
// "\r\n");
tpsocket_write(sock,tpbuf_snprintf(256,
"HTTP/1.1 %d %s\r\n"
"Content-Length: %d\r\n"
"Cache-Control: no-cache\r\n"
"Connection: %s\r\n"
"\r\n"
"{\"error_code\":0}",
500, "", strlen("{\"error_code\":0}"), "keep-alive"));
} else {
// snprintf(resp, sizeof(resp),
// "HTTP/1.1 200 OK\r\n"
// "Content-Type: text/plain\r\n"
// "Content-Length: 0\r\n"
// "Connection: close\r\n"
// "\r\n");
tpsocket_write(sock,tpbuf_snprintf(256,
"HTTP/1.1 %d %s\r\n"
"Content-Length: %d\r\n"
"Cache-Control: no-cache\r\n"
"Connection: %s\r\n"
"\r\n"
"{\"error_code\":0}",
200, "", strlen("{\"error_code\":0}"), "keep-alive"));
}
// struct tpsocket_buf *resp_buf = tpbuf_snprintf(strlen(resp) + 1, resp);
// if (resp_buf) tpsocket_write(sock, resp_buf);
// if (error) unlink(filepath);
if(session){
free(session);
handler->priv = NULL;
}
// tpsocket_close(sock);
}
break;
case TPSOCKET_EVENT_RESET:
break;
case TPSOCKET_EVENT_TIMEOUT:
break;
case TPSOCKET_EVENT_CLOSED:
DBG_ERR("TPSOCKET_EVENT_CLOSED\n");
if (session != NULL) {
// 异常关闭时清理资源
DBG_ERR("entering TPSOCKET_EVENT_CLOSED\n");
if (session->fp) {
fclose(session->fp);
session->fp = NULL;
}
unlink(filepath);
free(session);
handler->priv = NULL;
}
break;
case TPSOCKET_EVENT_ERROR:
default:
break;
}
tpsocket_free_buf(buf, tpsocket_event_name(event), 0);
return true;
}bool worker_file_log_set_handle(WORKER_CTX *worker_ctx, struct tpsocket_fd *sock, struct list_head *buf)
{
// 1. 获取设备MAC地址
char *mac = common_find_key_from_buf(buf, "Device-Mac");
if (!mac || strlen(mac) < 12) {
DBG_ERR("Invalid MAC address\n");
return false;
}
DBG_ERR("mac: %s\n", mac);
// 2. MAC格式化处理(冒号转下划线)
char processed_mac[18] = {0};
strncpy(processed_mac, mac, sizeof(processed_mac)-1);
for (char *p = processed_mac; *p; p++) {
if (*p == ':') *p = '_';
}
DBG_ERR("processed_mac: %s\n", processed_mac);
// 3. 创建目标目录
char dirpath[128];
snprintf(dirpath, sizeof(dirpath), "%s/%s", FILELOG_PATH , processed_mac);
// 检创建父目录(/mnt/sd_card)
if (access(FILELOG_PATH, F_OK) != 0) {
if (mkdir(FILELOG_PATH,0755) != 0) {
DBG_ERR("SD card mount failed: %s\n", strerror(errno));
return false;
}
}
// 创建设备目录(/mnt/sd_card/<processed_mac>)
if (access(dirpath, F_OK) != 0) {
if (mkdir(dirpath, 0755) != 0) {
DBG_ERR("Device dir '%s' creation failed: %s\n",
dirpath, strerror(errno));
return false;
}
}
// 4. 构建文件路径
char filepath[256];
snprintf(filepath, sizeof(filepath), "%s/log.txt", dirpath);
DBG_ERR("filepath: %s\n", filepath);
// 5. 获取内容长度(
char *content_length_str = common_find_key_from_buf(buf, "Content-Length");
if (!content_length_str || *content_length_str == '\0') {
DBG_ERR("Missing Content-Length header\n");
return false;
}
size_t content_len = atol(content_length_str);
if (content_len <= 0) {
DBG_ERR("Invalid content length: %s\n", content_length_str);
return false;
}
DBG_ERR("Content-Length: %zu\n", content_len);
// 滚动写入
FILE *fp = fopen(filepath, "ab+");
if (!fp) { /* 错误处理 */ }
fseek(fp, 0, SEEK_END);
long file_size = ftell(fp);
// 处理超大数据特殊情况
if (content_len > MAX_FILELOG_DIR_SIZE) {
DBG_ERR("Unable to free sufficient space\n");
const char *resp = "HTTP/1.1 507 Insufficient Storage\r\n\r\n";
struct tpsocket_buf *resp_buf = tpbuf_snprintf(strlen(resp)+1, resp);
if (resp_buf) tpsocket_write(sock, resp_buf);
return false;
}
// 循环删除行直到空间足够
while (file_size > 0 && file_size + content_len > MAX_FILELOG_DIR_SIZE) {
rewind(fp);
long line_start = 0;
long line_end = 0;
// 增强行定位:逐字符扫描换行符
int ch;
while ((ch = fgetc(fp)) != EOF) {
line_end = ftell(fp);
if (ch == '\n') {
// 找到完整行边界
line_start = line_end;
// 检查剩余空间
if (file_size - line_start + content_len <= MAX_FILELOG_DIR_SIZE)
break;
}
}
// 截断并移位(避免大内存分配)
if (line_start > 0) {
FILE *temp = tmpfile(); // 创建临时文件
fseek(fp, line_start, SEEK_SET);
// 流式复制保留内容
char buffer[1024];
size_t bytes;
while ((bytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) {
fwrite(buffer, 1, bytes, temp);
}
// 原子替换原文件
ftruncate(fileno(fp), 0);
rewind(fp);
rewind(temp);
while ((bytes = fread(buffer, 1, sizeof(buffer), temp)) > 0) {
fwrite(buffer, 1, bytes, fp);
}
fclose(temp);
file_size = ftell(fp);
} else {
ftruncate(fileno(fp), 0);
file_size = 0;
break;
}
}
// fclose(fp);
//session
FileLogSession *session = calloc(1, sizeof(FileLogSession));
if (!session) return false;
// session->fp = fopen(filepath, "ab");
session->fp = fp;
if (!session->fp) {
free(session);
return false;
}
session->remaining = content_len;
session->total_size = content_len;
char *if_encrypt = common_find_key_from_buf(buf, "X-If-Encrypt");
DBG_ERR("if_encrypt:%s\n",if_encrypt);
if (if_encrypt)
{
session->decrypt_flag = atoi(if_encrypt);
DBG_ERR("session->decrypt_flagt:%d\n",session->decrypt_flag);
char *nonce = NULL;
if ((nonce = common_find_key_from_buf(buf, "X-Nonce")))
{
DBG_ERR("nonce:%s\n",nonce);
work_tapo_log_refresh_nonce(nonce);
free(nonce);
}
}
else
{
session->decrypt_flag = 0;
}
free(if_encrypt);
snprintf(session->filepath,sizeof(session->filepath),"%s",filepath);
sock->handler.cb = tpsocket_event_filelog_to_hub;
sock->handler.priv = session;
return sock->handler.cb;
}
bool worker_file_log_read_handle(WORKER_CTX *worker_ctx, struct tpsocket_fd *sock, struct list_head *buf)
{
char *mac = common_find_key_from_buf(buf, "Device-Mac");
if (!mac || strlen(mac) < 12) {
DBG_ERR("Invalid MAC address\n");
const char *resp = "HTTP/1.1 400 Bad Request\r\n\r\n";
struct tpsocket_buf *resp_buf = tpbuf_snprintf(strlen(resp)+1, resp);
if (resp_buf) tpsocket_write(sock, resp_buf);
return false;
}
DBG_ERR("mac: %s\n", mac);
char processed_mac[18] = {0};
strncpy(processed_mac, mac, sizeof(processed_mac)-1);
for (char *p = processed_mac; *p; p++) if (*p == ':') *p = '_';
// 1. 构建日志文件路径
char filepath[256];
snprintf(filepath, sizeof(filepath), "%s/%s/log.txt", FILELOG_PATH, processed_mac);
DBG_ERR("filepath: %s\n", filepath);
// 2. 检查文件是否存在
if (access(filepath, F_OK) != 0) {
DBG_ERR("Log file not found: %s\n", filepath);
const char *resp = "HTTP/1.1 404 Not Found file\r\n\r\n";
struct tpsocket_buf *resp_buf = tpbuf_snprintf(strlen(resp)+1, resp);
if (resp_buf) tpsocket_write(sock, resp_buf);
return false;
}
// 3. 打开日志文件
FILE *fp = fopen(filepath, "rb");
if (!fp) {
DBG_ERR("Failed to open log file: %s\n", strerror(errno));
const char *resp = "HTTP/1.1 500 Internal Error\r\n\r\n";
struct tpsocket_buf *resp_buf = tpbuf_snprintf(strlen(resp)+1, resp);
if (resp_buf) tpsocket_write(sock, resp_buf);
return false;
}
DBG_ERR("[SUCCESS] File opened successfully\n");
// 4. 获取文件大小 (假设最大5MB)
struct stat st;
if (fstat(fileno(fp), &st) != 0) {
DBG_ERR("Failed to get file size: %s\n", strerror(errno));
fclose(fp);
const char *resp = "HTTP/1.1 500 Internal Error\r\n\r\n";
struct tpsocket_buf *resp_buf = tpbuf_snprintf(strlen(resp)+1, resp);
if (resp_buf) tpsocket_write(sock, resp_buf);
return false;
}
size_t file_size = st.st_size;
DBG_ERR("[DEBUG] File size: %zu bytes\n", file_size);
// 5. 读取整个文件内容
char *content = malloc(file_size + 1);
if (!content) {
DBG_ERR("Failed to allocate memory for log content\n");
fclose(fp);
const char *resp = "HTTP/1.1 507 Insufficient Storage\r\n\r\n";
struct tpsocket_buf *resp_buf = tpbuf_snprintf(strlen(resp)+1, resp);
if (resp_buf) tpsocket_write(sock, resp_buf);
return false;
}
size_t bytes_read = fread(content, 1, file_size, fp);
content[file_size] = '\0'; // Null-terminate for text safety
fclose(fp);
DBG_ERR("[DEBUG] Bytes read: %zu/%zu\n", bytes_read, file_size);
if (bytes_read != file_size) {
DBG_ERR("Failed to read entire file: expected %zu, got %zu\n", file_size, bytes_read);
free(content);
const char *resp = "HTTP/1.1 500 Internal Error\r\n\r\n";
struct tpsocket_buf *resp_buf = tpbuf_snprintf(strlen(resp)+1, resp);
if (resp_buf) tpsocket_write(sock, resp_buf);
return false;
}
// 6. 构建并发送 HTTP 响应头
char header[512];
int header_len = snprintf(header, sizeof(header),
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain; charset=utf-8\r\n"
"Content-Length: %zu\r\n"
"Connection: close\r\n\r\n",
file_size);
if (header_len < 0 || header_len >= (int)sizeof(header)) {
DBG_ERR("Header buffer overflow\n");
free(content);
const char *resp = "HTTP/1.1 500 Internal Error\r\n\r\n";
struct tpsocket_buf *resp_buf = tpbuf_snprintf(strlen(resp)+1, resp);
if (resp_buf) tpsocket_write(sock, resp_buf);
return false;
}
// 7.创建复合缓冲区:头部 + 内容
struct tpsocket_buf *full_resp = tpbuf_new(header_len + file_size);
if (!full_resp) {
free(content);
DBG_ERR("Failed to create full response buffer\n");
return false;
}
// 8.按顺序填充数据
memcpy(tpbuf_tail(full_resp), header, header_len); // 头部
tpbuf_put(full_resp, header_len);
memcpy(tpbuf_tail(full_resp), content, file_size); // 内容
tpbuf_put(full_resp, file_size);
// 9.写入
tpsocket_write_force(sock, full_resp, true);
free(content);
tpsocket_close(sock);
return true;
}帮我修改代码,解析请求中的数据再进行处理。
最新发布