blob: a772c982d503d03f4efd649ce1754c5c0d85bdee [file] [log] [blame]
#include "xml_ubus.h"
static struct blob_buf buf;
static struct ubus_context *ctx;
static char *g_xml_res = NULL;
formvars *start;
static struct upload_ctx upload_obj;
void blobmsg_add_xml_leaf_node(struct blob_buf *b, mxml_node_t * node);
void blobmsg_add_xml_tree(struct blob_buf *b, mxml_node_t * node);
void cgi_init_http_headers(int content_length, char *content_disposition, struct mime_vec *mime);
void cgi_init_xml_headers(int content_length, char *content_disposition);
int send_xml_response(char *xml_res);
int xml_duster_parse(char *filepost);
int get_request_len(char *buf, int buflen);
int comm_ota_init(struct upload_ctx *ota_ctx, int fbf_size, int segment_size);
int send_prepare_msg_ota(struct upload_ctx *ota_ctx);
int connect_to_ota(struct upload_ctx *ota_ctx);
int send_fbf_segment_ota(struct upload_ctx *ota_ctx, char *data, int len);
int upload_fw_fs_init(struct upload_ctx *obj, int file_size);
int upload_fw_fs_write(struct upload_ctx *obj, char *data, int len);
int upload_fw_fs_done(struct upload_ctx *obj);
int upload_fw_ota_init(struct upload_ctx *obj, int file_size, int segmnet_size);
int upload_fw_ota_write(struct upload_ctx *obj, char *data, int len);
int process_upload_request(struct upload_forward_ops *ops);
int download_config_file_init();
int response_download_config_file();
int process_download_request(struct download_ops *ops);
void blobmsg_add_xml_leaf_node(struct blob_buf *b, mxml_node_t * node)
{
mxml_node_t *cur;
char *node_key;
char *node_val;
void *t;
if (node->child && node->child->type != MXML_ELEMENT && node->child->child == NULL && node->child->next == NULL) {
/*This is a leaf node with value */
node_key = node->value.element.name;
node_val = node->child->value.opaque;
blobmsg_add_string(b, node_key, node_val);
return;
} else if (node->type == MXML_ELEMENT && node->child == NULL) {
/*leaf node with no value, do not need to add to blob */
CGI_LOGI("blobmsg_add_xml_leaf_node, leaf node with no value\n");
} else {
/* Not a leaf node
* Proceed further*/
t = blobmsg_open_table(b, node->value.element.name);
for (cur = node->child; cur != NULL; cur = cur->next) {
if (cur->type != MXML_ELEMENT) {
continue;
}
blobmsg_add_xml_leaf_node(b, cur);
}
blobmsg_close_table(b, t);
}
}
void blobmsg_add_xml_tree(struct blob_buf *b, mxml_node_t * node)
{
mxml_node_t *child;
for (child = node->child; child != NULL; child = child->next) {
if (child->type != MXML_ELEMENT) {
continue;
}
blobmsg_add_xml_leaf_node(b, child);
}
return;
}
static int cgi_ubus_init(void)
{
const char *ubus_socket = NULL;
ctx = ubus_connect(ubus_socket);
if (!ctx) {
fprintf(stderr, "Failed to connect to ubus\n");
return -1;
}
return 0;
}
static void cgi_ubus_end(void)
{
ubus_free(ctx);
}
static void cgi_receive_ubus_result_data(struct ubus_request *req, int type, struct blob_attr *msg)
{
mxml_node_t *xml;
mxml_node_t *rgw;
mxml_node_t *cur;
FILE *fp = NULL;
bool array;
if (!msg) {
system("echo \"no msg return\" >> /tmp/my_debug");
return;
}
array = blob_is_extended(msg) && blobmsg_type(msg) == BLOBMSG_TYPE_ARRAY;
xml = mxmlNewXML("1.0");
rgw = mxmlNewElement(xml, "RGW");
cur = rgw;
CGI_LOGI("blob_data(msg) %p, blob_len(msg) %d array %d\n", blob_data(msg), blob_len(msg), array);
blobmsg_format_xml_tree(cur, blob_data(msg), blob_len(msg), array);
fp = fopen(g_xml_res, "wb");
if(!fp)
{
CGI_LOGI("open g_xml_res fail\n");
return;
}
mxmlSaveFile(xml, fp, NULL);
fclose(fp);
mxmlDelete(xml);
}
static void cgi_prepare_response(char *module_name, e_error_cause error_cause, e_error_cause_format format)
{
#define TMP_BUFF_SIZ 256
char buff[TMP_BUFF_SIZ] = { 0 };
FILE *fp = NULL;
int size = 0;
if (!module_name) {
goto END;
}
if (format == ERR_STRING) {
snprintf(buff, TMP_BUFF_SIZ, "<?xml version=\"1.0\" encoding=\"US-ASCII\" ?><RGW><%s>%s</%s></RGW>",
module_name, error_cause_msg[error_cause], module_name);
} else if (format == ERR_NUMBER) {
snprintf(buff, TMP_BUFF_SIZ, "<?xml version=\"1.0\" encoding=\"US-ASCII\" ?><RGW><%s>%d</%s></RGW>",
module_name, (int)error_cause, module_name);
} else
goto END;
fp = fopen(g_xml_res, "wb");
if (!fp) {
goto END;
}
if (strlen(buff) >= TMP_BUFF_SIZ) {
goto END;
}
size = fwrite(buff, strlen(buff), sizeof(char), fp);
if (size != strlen(buff)) {
goto END;
}
END:
if (fp != NULL)
fclose(fp);
}
static void cgi_ubus_send_request(int obj, char *func, const char *sid, struct blob_attr *args, int timeout)
{
struct blob_attr *cur;
static struct blob_buf req;
int rem;
blob_buf_init(&req, 0);
blobmsg_for_each_attr(cur, args, rem) {
if (!strcmp(blobmsg_name(cur), "ubus_rpc_session")) {
//return ubus_error(cl, ERROR_PARAMS);
}
blobmsg_add_blob(&req, cur);
}
blobmsg_add_string(&req, "ubus_rpc_session", sid);
CGI_LOGI("ctx %p, obj %u, func %s, req.head %p\n", ctx, obj, func, req.head);
if (ubus_invoke(ctx, obj, func, req.head, cgi_receive_ubus_result_data, 0, timeout) == UBUS_STATUS_TIMEOUT)
{
cgi_prepare_response(ERROR_CAUSE_TAG, ERR_CGI_FILE, ERR_NUMBER);
}
blob_buf_free(&req);
}
static void cgi_ubus_create_pdp(int obj, char *func, int timeout)
{
struct blob_attr *cur;
static struct blob_buf req;
int status;
blob_buf_init(&req, 0);
CGI_LOGI("ctx %p, obj %u, func %s, req.head %p\n", ctx, obj, func, req.head);
if (status = ubus_invoke(ctx, obj, func, req.head, NULL, 0, timeout))
{
CGI_LOGE("cgi_ubus_create_pdp failed, status %d\n", status);
}
blob_buf_free(&req);
}
static void cgi_ubus_destroy_pdp(int obj, char *func, int timeout, int connection_num, int delete_all)
{
struct blob_attr *cur;
static struct blob_buf req;
int status;
blob_buf_init(&req, 0);
blobmsg_add_u32(&req, "connectionNum", connection_num);
blobmsg_add_u32(&req, "deleteall", delete_all);
CGI_LOGI("ctx %p, obj %u, func %s, req.head %p\n", ctx, obj, func, req.head);
if (status = ubus_invoke(ctx, obj, func, req.head, NULL, 0, timeout))
{
CGI_LOGE("cgi_ubus_destroy_pdp failed, status %d\n", status);
}
blob_buf_free(&req);
}
void cgi_init_http_headers(int content_length, char *content_disposition, struct mime_vec *mime)
{
printf("Content-Type: %s\r\n", mime->str);
printf("Pragma: No-Cache\r\n");
printf("Cache-Control: no-cache,no-store,max-age=0\r\n");
if (content_disposition != NULL)
printf("Content-Disposition: %s\r\n", content_disposition);
printf("Content-Length: %d\r\n", content_length);
printf("\r\n");
}
void cgi_init_xml_headers(int content_length, char *content_disposition)
{
printf("Content-type: text/xml\r\n");
printf("Charset: utf-8\r\n");
printf("Pragma: No-Cache\r\n");
printf("Cache-Control: no-cache,no-store,max-age=0\r\n");
if (content_disposition != NULL)
printf("Content-disposition: %s\r\n", content_disposition);
printf("Content-length: %d\r\n\r\n", content_length);
}
int send_xml_response(char *xml_res)
{
struct stat file_stat;
char *buffer = NULL;
int fd = -1, size = 0;
int ret = 0;
buffer = malloc(XML_GET_BUF_SIZE);
if (!buffer) {
return -1;
}
memset(buffer, 0, XML_GET_BUF_SIZE);
/* init the repsonse header and body */
stat(xml_res, &file_stat);
fd = open(xml_res, O_RDONLY);
if (fd < 0) {
system("echo \"Open xml_res failed\" >> /tmp/my_debug");
ret = -1;
goto end;
}
system("echo \"Prepare to init xml_headers\" >> /tmp/my_debug");
memset(buffer, 0, XML_GET_BUF_SIZE);
cgi_init_xml_headers(file_stat.st_size, NULL);
while ((size = read(fd, buffer, XML_GET_BUF_SIZE)) > 0) {
buffer[size] = '\0';
//Pirnt the buffer to stdout, the stdout now redirect to pipi_wr, connect to parent process(Web Server)
printf("%s", buffer);
}
ret = 0;
end:
if (fd >= 0)
close(fd);
if (buffer)
free(buffer);
return ret;
}
int xml_duster_parse(char *filepost)
{
#define UBUS_PARAM_NUM 4
#define PARAM_LEN 32
#define ERROR_CAUSE_TAG "error_cause"
mxml_node_t *root = NULL;
mxml_node_t *cur = NULL;
mxml_node_t *param_node = NULL;
char param[UBUS_PARAM_NUM][PARAM_LEN];
unsigned int obj_id, cm_obj_id;
int i = 0;
FILE *fp = NULL;
int ret = 0;
int timeout = 0;
blob_buf_init(&buf, 0);
fp = fopen(filepost, "r");
if (fp == NULL) {
perror("Couldn't read file");
ret = -1;
cgi_prepare_response(ERROR_CAUSE_TAG, ERR_CGI_FILE, ERR_NUMBER);
goto END;
}
CGI_LOGI("ctx %p, xml_duster_parse enter\n", ctx);
root = mxmlLoadFile(NULL, fp, MXML_OPAQUE_CALLBACK);
fclose(fp);
CGI_LOGI("ctx %p, mxmlLoadFile success\n", ctx);
cur = mxmlFindElement(root, root, "RGW", NULL, NULL, MXML_DESCEND_FIRST);
if (cur == NULL) {
cgi_prepare_response(ERROR_CAUSE_TAG, ERR_CGI_FORMAT, ERR_NUMBER);
ret = -1;
goto END;
}
cur = cur->child;
for (; cur != NULL; cur = cur->next) {
if (cur->type != MXML_ELEMENT) {
continue;
}
if (!strcmp(cur->value.element.name, "param")) {
param_node = cur->child;
i = 0;
for (; param_node != NULL; param_node = param_node->next) {
if (param_node->type != MXML_ELEMENT) {
continue;
}
if (param_node->child && param_node->child->type != MXML_ELEMENT &&
param_node->child->child == NULL && param_node->child->next == NULL) {
if (param_node->child->value.opaque){
if(i >= UBUS_PARAM_NUM || strlen(param_node->child->value.opaque) > PARAM_LEN){
CGI_LOGE("xml_duster_parse failed i[%d],opaque len[%d]\n", i, strlen(param_node->child->value.opaque));
cgi_prepare_response(ERROR_CAUSE_TAG, ERR_PARAM_INVALID, ERR_NUMBER);
ret = -1;
goto END;
}else{
strcpy(param[i++], param_node->child->value.opaque);
}
}
}
}
} else {
blobmsg_add_xml_tree(&buf, cur);
}
}
if (!strcmp(param[RPC_METHOD], "call")) {
if (strlen(param[RPC_SESSIONID]) == 0 || strlen(param[RPC_OBJPATH]) == 0 ||strlen(param[PRC_OBJMETHOD]) == 0) {
cgi_prepare_response(ERROR_CAUSE_TAG, ERR_PARAM_INVALID, ERR_NUMBER);
ret = -1;
goto END;
}
CGI_LOGI("ctx %p, param[RPC_OBJPATH] %s\n", ctx, param[RPC_OBJPATH]);
if (ubus_lookup_id(ctx, param[RPC_OBJPATH], &obj_id)) {
cgi_prepare_response(ERROR_CAUSE_TAG, ERR_SERVICE_NOT_FOUND, ERR_NUMBER);
ret = -1;
goto END;
}
if (strcmp(param[PRC_OBJMETHOD], "search_network") == 0)
{
timeout = 360*1000;
}
else if (strcmp(param[RPC_OBJPATH], "wireless") == 0)
{
timeout = 60*1000;
}
else if (strcmp(param[RPC_OBJPATH], "cm") == 0)
{
timeout = 120*1000;
}
else
timeout = 30*1000;
CGI_LOGI("ctx %p, obj_id %u, obj_method %s, buf.head %p, invoke timeout %d ms\n", ctx, obj_id, param[PRC_OBJMETHOD],
buf.head, timeout);
if (strcmp(param[PRC_OBJMETHOD], "search_network") == 0)
{
if (ubus_lookup_id(ctx, "cm", &cm_obj_id)) {
cgi_prepare_response(ERROR_CAUSE_TAG, ERR_SERVICE_NOT_FOUND, ERR_NUMBER);
ret = -1;
goto END;
}
cgi_ubus_destroy_pdp(cm_obj_id, "destroy_pdp", 30000, 0, 1);
cgi_ubus_send_request(obj_id, param[PRC_OBJMETHOD], param[RPC_SESSIONID], buf.head, timeout);
cgi_ubus_create_pdp(cm_obj_id, "create_pdp", 30000);
} else {
cgi_ubus_send_request(obj_id, param[PRC_OBJMETHOD], param[RPC_SESSIONID], buf.head, timeout);
}
} else if (!strcmp(param[RPC_METHOD], "list")) {
/*not support yet*/
cgi_prepare_response(ERROR_CAUSE_TAG, ERR_METHOD_NOT_SUPPORT, ERR_NUMBER);
ret = -1;
goto END;
}
END:
if (root)
mxmlDelete(root);
blob_buf_free(&buf);
return ret;
}
int get_request_len(char *buf, int buflen)
{
const char *s, *e;
int len = 0;
for (s = buf, e = s + buflen - 1; len <= 0 && s < e; s++) {
if (!isprint(*(const unsigned char *)s && *s != '\r' && *s != '\n') &&
(*(const unsigned char *)s < 128)) {
len = -1;
} else if (s[0] == '\n' && s[1] == '\n') {
len = (int)(s - buf) + 2;
} else if (s[0] == '\n' && &s[1] < e && s[1] == '\r' && s[2] == '\n') {
len = (int)(s - buf) + 3;
}
}
return len;
}
int comm_ota_init(struct upload_ctx *ota_ctx, int fbf_size, int segment_size)
{
int ret;
ret = ubus_lookup_id(ctx, "ota", &(ota_ctx->id));
if (ret != NO_ERR) {
CGI_LOGE("%s: lookup object ota failed\n", __func__);
ret = ERR_PARAM_INVALID;
goto end;
}
ota_ctx->n_file_total = fbf_size;
ota_ctx->n_file_segmnet = segment_size;
end:
return ret;
}
static void receive_msg_ota_cb(struct ubus_request *req, int type, struct blob_attr *msg)
{
CGI_LOGE("enter %s\n", __func__);
return;
}
int send_prepare_msg_ota(struct upload_ctx *ota_ctx)
{
blob_buf_init(&buf, 0);
blobmsg_add_string(&buf, "url", OTA_UNIX_PATH);
blobmsg_add_u32(&buf, "type", 1);
blobmsg_add_u32(&buf, "size", ota_ctx->n_file_total);
blobmsg_add_u32(&buf, "segment_size", ota_ctx->n_file_segmnet);
ubus_invoke(ctx, ota_ctx->id, "download", buf.head, receive_msg_ota_cb, 0, 5000);
CGI_LOGI("%s: send size %d, segment_size %d\n", __func__, ota_ctx->n_file_total, ota_ctx->n_file_segmnet);
return NO_ERR;
}
enum {
QUERY_RESPONSE,
QUERY_RESPONSE_MAX,
};
const struct blobmsg_policy query_response_policy[QUERY_RESPONSE_MAX] ={
[QUERY_RESPONSE] = { .name = "response", .type = BLOBMSG_TYPE_STRING },
};
static void query_status_msg_ota_cb(struct ubus_request *req, int type, struct blob_attr *msg)
{
UNUSEDPARAM(type);
struct blob_attr *tb[QUERY_RESPONSE_MAX];
int rc;
char *query_response = NULL;
struct upload_ctx *ota_ctx = (struct upload_ctx *)req->priv;
rc = blobmsg_parse(query_response_policy, ARRAY_SIZE(query_response_policy), tb, blob_data(msg), blob_len(msg));
if (rc < 0 || !tb[QUERY_RESPONSE]) {
CGI_LOGE("%s: parse msg failed\n", __func__);
return;
}
query_response = blobmsg_get_string(tb[QUERY_RESPONSE]);
if (!query_response) {
CGI_LOGE("%s: query_response is null \n", __func__);
return;
}
CGI_LOGE("%s: query_response %s \n", __func__, query_response);
if (strstr(query_response, "fail"))
ota_ctx->upload_status = ERR_UPLOAD_FAILED;
return;
}
int query_upgrade_status_msg_ota(struct upload_ctx *ota_ctx)
{
blob_buf_init(&buf, 0);
blobmsg_add_string(&buf, "type", "1");
ubus_invoke(ctx, ota_ctx->id, "query", buf.head, query_status_msg_ota_cb, ota_ctx, 5000);
CGI_LOGI("%s: done\n", __func__);
return NO_ERR;
}
int connect_to_ota(struct upload_ctx *ota_ctx)
{
int waitSeconds = 10, i = 0;
//sleep(1);
while (i++ < waitSeconds) {
ota_ctx->fd = usock(USOCK_UNIX, OTA_UNIX_PATH, NULL);
if (ota_ctx->fd < 0) {
sleep(1);
}
else {
CGI_LOGI("%s: client fd %d", __func__, ota_ctx->fd);
return NO_ERR;
}
}
CGI_LOGE("%s: Failed to connect to server(%s)\n", __func__, strerror(errno));
return ERR_PARAM_INVALID;
}
int send_fbf_segment_ota(struct upload_ctx *ota_ctx, char *data, int len)
{
int n_send;
n_send = write(ota_ctx->fd, data, len);
if (n_send != len) {
CGI_LOGE("%s: size %d actual send %d\n", __func__, len, n_send);
return ERR_PARAM_INVALID;
}
ota_ctx->n_send += n_send;
return NO_ERR;
}
int upload_fw_fs_init(struct upload_ctx *obj, int file_size)
{
char *file_tmp = NULL;
int fd_tmp = 0;
int ret = NO_ERR;
CGI_LOGI("%s: enter\n", __func__);
file_tmp = strdup("/tmp/config.XXXXXX");
if ((fd_tmp = mkstemp(file_tmp)) < 0) {
ret = ERR_PARAM_INVALID;
goto end;
}
close(fd_tmp);
fd_tmp = open(file_tmp, O_WRONLY | O_TRUNC | O_CREAT | O_APPEND, 0);
if (fd_tmp == -1) {
ret = ERR_PARAM_INVALID;
goto end;
}
strncpy(obj->f_name, file_tmp, 31);
obj->fd = fd_tmp;
CGI_LOGI("%s: temp file %s\n", __func__, obj->f_name);
end:
//coverity[check_after_deref:SUPPRESS]
if (file_tmp) {
free(file_tmp);
}
CGI_LOGI("%s: leave\n", __func__);
return ret;
}
int upload_fw_fs_write(struct upload_ctx *obj, char *data, int len)
{
int n_send;
n_send = write(obj->fd, data, len);
if (n_send != len) {
CGI_LOGE("%s: size %d actual send %d\n", __func__, len, n_send);
return ERR_PARAM_INVALID;
}
obj->n_send += n_send;
return NO_ERR;
}
int upload_fw_fs_done(struct upload_ctx *obj)
{
char exec_str[128] = { 0 };
int ret = ERR_PARAM_INVALID;
CGI_LOGI("%s: enter\n", __func__);
if (obj->fd > 0)
close(obj->fd);
if (strlen(obj->f_name) > 0) {
snprintf(exec_str, 127, "tar xzvf %s -C / >/dev/null", obj->f_name);
CGI_LOGI("%s: exec command:%s\n", __func__, exec_str);
ret = system(exec_str);
if (ret < 0)
ret = ERR_PARAM_INVALID;
else
ret = NO_ERR;
}
CGI_LOGI("%s: leave %d\n", __func__, ret);
return ret;
}
int upload_fw_ota_init(struct upload_ctx *obj, int file_size, int segmnet_size)
{
int ret;
ret = comm_ota_init(obj, file_size, segmnet_size);
if (ret != NO_ERR) {
CGI_LOGE("%s: comm_ota_init Failed\n", __func__);
goto end;
}
query_upgrade_status_msg_ota(obj);
if (obj->upload_status == ERR_UPLOAD_FAILED)
{
ret = ERR_PARAM_INVALID;
goto end;
}
ret = send_prepare_msg_ota(obj);
if (ret != NO_ERR) {
CGI_LOGE("%s: send_prepare_msg_ota Failed\n", __func__);
goto end;
}
ret = connect_to_ota(obj);
if (ret != NO_ERR) {
CGI_LOGE("%s: connect_to_ota Failed\n", __func__);
goto end;
}
end:
CGI_LOGI("%s: done with ret %d\n", __func__, ret);
return ret;
}
int upload_fw_ota_write(struct upload_ctx *obj, char *data, int len)
{
return send_fbf_segment_ota(obj, data, len);
}
int upload_fw_ota_done(struct upload_ctx *obj)
{
int ret = ERR_PARAM_INVALID;
if (obj->fd > 0)
ret = close(obj->fd);
CGI_LOGI("%s: leave with %d\n", __func__, ret);
return ret;
}
#define CONTENET_TYPE_OCTECT "application/octet-stream"
int process_upload_request(struct upload_forward_ops *ops)
{
#define MAX_HEADER_OPTION_LEN 256
#define MAX_TCP_BUF_SIZE 1460
#define FORM_HEAD_MAX_SIZE 256
char content_type_buf[MAX_HEADER_OPTION_LEN] = { 0 };
char boundary_buf[MAX_HEADER_OPTION_LEN] = { 0 };
char media_type[MAX_HEADER_OPTION_LEN] = { 0 };
char *env_content_type = getenv("CONTENT_TYPE");
char *env_content_len = getenv("CONTENT_LENGTH");
char *p = NULL, *p1 = NULL;
char buf[2 * MAX_TCP_BUF_SIZE];
char fbf_buf[2 * MAX_TCP_BUF_SIZE];
int n_boundary = 0, n_consumed = 0, content_len = 0, len = 0;
int n_form_head = 0, n_form_tail = 0, n_fbf = 0, n_fbf_total = 0, n_file_size = 0;
int n_read, to_read;
int ret = NO_ERR;
bool boundary_found = true;
CGI_LOGI("%s: enter\n", __func__);
if (!env_content_type) {
/*not found content_type */
CGI_LOGI("%s: no Content-Type in request\n", __func__);
ret = ERR_PARAM_INVALID;
goto end;
}
if (!env_content_len) {
/*not found content_length */
CGI_LOGI("%s: no Content-Length in request\n", __func__);
ret = ERR_PARAM_INVALID;
goto end;
}
if (env_content_type) {
strncpy(content_type_buf, env_content_type, MAX_HEADER_OPTION_LEN - 1);
}
CGI_LOGI("%s: content_type_buf %s\n", __func__, content_type_buf);
p = strstr(content_type_buf, CONTENET_TYPE_OCTECT);
if (!p) {
p = strstr(content_type_buf, "boundary=");
}
else
boundary_found = false;
if (!p) {
/*not found connect type */
CGI_LOGI("%s: content type %s in request is not valid\n", __func__, content_type_buf);
ret = ERR_PARAM_INVALID;
goto end;
}
/*fbf segment size */
content_len = atoi(env_content_len);
CGI_LOGI("%s: content length %d\n", __func__, content_len);
if (boundary_found) {
p += strlen("boundary=");
strncpy(boundary_buf, p, sizeof(boundary_buf) - 1);
CGI_LOGI("%s: boundary=%s\n", __func__, boundary_buf);
n_boundary = strlen("\r\n--") + strlen(boundary_buf);
}
else {
p += strlen(CONTENET_TYPE_OCTECT);
/* find ',' */
if (*p == ',')
{
/* skip ',' and ' ' */
p += 2;
strncpy(boundary_buf, p, sizeof(boundary_buf) - 1);
CGI_LOGI("%s: fbf file size %s, %d\n", __func__, boundary_buf, atoi(boundary_buf));
/*fbf total size */
n_file_size = atoi(boundary_buf);
if (n_file_size == 0)
goto end;
}
}
if (boundary_found) {
/*read first boundary */
if ((n_read = read(0, buf, MAX_TCP_BUF_SIZE)) > 0) {
CGI_LOGI("%s: read size %d n_boundary %d\n", __func__, n_read, n_boundary);
n_form_head = get_request_len(buf + n_boundary, FORM_HEAD_MAX_SIZE);
if (n_form_head > 0) {
n_form_head += n_boundary;
n_fbf = n_read - n_form_head;
memcpy(fbf_buf, buf + n_form_head, n_fbf);
n_fbf_total += n_fbf;
} else {
/*not get full form head */
CGI_LOGI("%s: not get full form head\n", __func__);
buf[n_read] = '\0';
p = strstr(buf, "Content-Type:");
if (!p) {
goto end;
}
p1 = strstr(buf, "\r\n\r\n");
if (!p1) {
goto end;
}
if (p > p1) {
goto end;
}
len = p1 + strlen("\r\n\r\n") - p - strlen("Content-Type:");
if (len < 0) {
goto end;
}
memcpy(media_type, p + strlen("Content-Type:"), len);
media_type[len] = '\0';
CGI_LOGI("%s: len %d media_type %s\n", __func__, len, media_type);
p = strstr(buf, media_type);
if (!p) {
goto end;
}
n_form_head = p - buf + strlen(media_type);
CGI_LOGI("%s: n_form_head %d\n", __func__, n_form_head);
if (n_form_head > n_read)
goto end;
n_fbf = n_read - n_form_head;
memcpy(fbf_buf, buf + n_form_head, n_fbf);
n_fbf_total += n_fbf;
n_file_size = content_len - n_form_head - n_boundary - strlen("\r\n--");
CGI_LOGI("%s: fbf size %d\n", __func__, n_file_size);
}
/**here we should send fbf to OTA service**/
CGI_LOGI("%s: forward file segment, length %d, total length %d\n", __func__, n_fbf, n_fbf_total);
#ifdef TMP_STORE_FBF
fbf_tmp = strdup("/tmp/fbf.XXXXXX");
if ((fd_tmp = mkstemp(fbf_tmp)) < 0)
goto end;
close(fd_tmp);
fd_tmp = open(fbf_tmp, O_WRONLY | O_TRUNC | O_CREAT | O_APPEND, 0);
if (fd_tmp == -1)
goto end;
write(fd_tmp, fbf_buf, n_fbf);
#else
if (!ops->upload_fw_init_cb) {
CGI_LOGE("%s: upload forward init not registered\n", __func__);
goto end;
}
ret = ops->upload_fw_init_cb(&upload_obj, n_file_size, 0);
if (ret != NO_ERR) {
CGI_LOGE("%s: upload forward init Failed\n", __func__);
goto end;
}
if (!ops->upload_fw_write_cb) {
CGI_LOGE("%s: upload forward write not registered \n", __func__);
goto end;
}
ret = ops->upload_fw_write_cb(&upload_obj, fbf_buf, n_fbf);
if (ret != NO_ERR) {
CGI_LOGE("%s: upload forward write Failed\n", __func__);
goto end;
}
#endif
}
n_consumed += n_read;
CGI_LOGI("%s: after first boundary get file len %d\n", __func__, n_fbf_total);
}
else {
if (!ops->upload_fw_init_cb) {
CGI_LOGE("%s: upload forward init not registered\n", __func__);
goto end;
}
if (!ops->upload_fw_write_cb) {
CGI_LOGE("%s: upload forward write not registered \n", __func__);
goto end;
}
ret = ops->upload_fw_init_cb(&upload_obj, n_file_size, content_len);
if (ret != NO_ERR) {
CGI_LOGE("%s: upload forward init Failed\n", __func__);
goto end;
}
}
/*read fbf until done */
//coverity[tainted_data:SUPPRESS]
while (n_consumed < content_len) {
to_read = MAX_TCP_BUF_SIZE;
if (to_read > content_len - n_consumed) {
to_read = content_len - n_consumed;
}
n_read = read(0, buf, to_read);
if (n_read <= 0) {
/**read failed**/
CGI_LOGE("%s: read failed or read end %d\n", __func__, n_read);
goto end;
}
n_consumed += n_read;
CGI_LOGI("%s: read size %d\n", __func__, n_consumed);
if (boundary_found) {
if (content_len - n_consumed < n_boundary) {
/*get tail boundary in this read, should remove it */
CGI_LOGI("%s: tali boundary, %d %d \n", __func__, n_consumed, content_len);
if (n_consumed >= content_len) {
/*get all content done */
CGI_LOGE("%s: get all content done\n", __func__);
memcpy(fbf_buf, buf, n_read);
n_fbf = n_read;
} else {
memcpy(fbf_buf, buf, n_read);
n_fbf = n_read;
/*check until get all content done */
while (n_consumed < content_len) {
to_read = content_len - n_consumed;
n_read = read(0, buf, to_read);
if (n_read <= 0) {
/**read failed**/
CGI_LOGE("%s: read %d failed or read end %d\n", __func__, to_read,
n_read);
goto end;
}
n_consumed += n_read;
n_fbf += n_read;
memcpy(fbf_buf + n_fbf, buf, n_read);
}
/*here we should get all connted done */
}
/** remove last boundary
* "--\r\n" append the tail of boundary
* remove it **/
n_boundary += strlen("--\r\n");
n_form_tail = n_fbf - n_boundary;
n_fbf = n_form_tail;
/*remove '-' '\r''\n' in tail of fbf, if need */
while (1) {
if (fbf_buf[n_fbf - 1] == '-' || fbf_buf[n_fbf - 1] == '\r'
|| fbf_buf[n_fbf - 1] == '\n')
n_fbf--;
else
break;
}
n_fbf_total += n_fbf;
CGI_LOGI("%s: forward file segment, length %d, total length %d\n", __func__, n_fbf,
n_fbf_total);
/** Here should send fbf segment to OTA service
* TODO
**/
#ifdef TMP_STORE_FBF
write(fd_tmp, fbf_buf, n_fbf);
#else
ret = ops->upload_fw_write_cb(&upload_obj, fbf_buf, n_fbf);
if (ret != NO_ERR) {
CGI_LOGE("%s: upload forward write Failed\n", __func__);
goto end;
}
#endif
} else {
n_fbf_total += n_read;
CGI_LOGI("%s: forward file segment, length %d, total length %d\n", __func__, n_read,
n_fbf_total);
/** Here should send fbf segment to OTA service
* TODO
**/
#ifdef TMP_STORE_FBF
write(fd_tmp, buf, n_read);
#else
ret = ops->upload_fw_write_cb(&upload_obj, buf, n_read);
if (ret != NO_ERR) {
CGI_LOGE("%s: upload forward write Failed\n", __func__);
goto end;
}
#endif
}
}
else {
ret = ops->upload_fw_write_cb(&upload_obj, buf, n_read);
if (ret != NO_ERR) {
CGI_LOGE("%s: upload forward write Failed\n", __func__);
goto end;
}
}
}
end:
if (ops->upload_fw_done_cb)
ops->upload_fw_done_cb(&upload_obj);
if (ret == NO_ERR)
{
upload_obj.upload_status = UPLOAD_OK;
} else {
upload_obj.upload_status = ERR_UPLOAD_FAILED;
}
if (ops->upload_response_cb) {
if (ops->upload_response_cb(&upload_obj) != NO_ERR)
CGI_LOGE("%s: upload response Failed\n", __func__);
}
CGI_LOGI("%s: leave with ret %d\n", __func__, ret);
return ret;
}
int download_config_file_init()
{
int ret = ERR_PARAM_INVALID;
char exec_str[128] = { 0 };
CGI_LOGI("%s: enter\n", __func__);
snprintf(exec_str, 127, "tar czvf /tmp/pxa1826_cfg.tar.gz /etc/config/ > /dev/null");
ret = system(exec_str);
if (ret < 0)
ret = ERR_PARAM_INVALID;
else
ret = NO_ERR;
CGI_LOGI("%s: leave %d \n", __func__, ret);
return ret;
}
int response_restore_status(struct upload_ctx *obj)
{
#define CONF_MGR_TAG "configure_management"
#define RESTORE_STATUS_TAG "restore_status"
int ret = NO_ERR;
int text_size;
char *buffer = NULL;
struct mime_vec mime;
CGI_LOGI("%s: enter\n", __func__);
buffer = malloc(XML_GET_BUF_SIZE);
if (!buffer) {
ret = ERR_PARAM_INVALID;
goto end;
}
memset(buffer, 0, XML_GET_BUF_SIZE);
mime.str = "text/xml";
mime.len = strlen("text/xml");
text_size = snprintf(buffer, XML_GET_BUF_SIZE, "<?xml version=\"1.0\" encoding=\"US-ASCII\" ?><RGW><%s><%s>%d</%s></%s></RGW>",
CONF_MGR_TAG, RESTORE_STATUS_TAG, (int)obj->upload_status, RESTORE_STATUS_TAG, CONF_MGR_TAG);
cgi_init_http_headers(text_size, NULL, &mime);
printf("%s",buffer);
end:
if (buffer)
free(buffer);
return ret;
}
int response_firmware_upload(struct upload_ctx *obj)
{
#define FIRMWARE_TAG "firmware"
#define UPLOAD_STATUS_TAG "upload_status"
int ret = NO_ERR;
int text_size;
char *buffer = NULL;
struct mime_vec mime;
CGI_LOGI("%s: enter\n", __func__);
buffer = malloc(XML_GET_BUF_SIZE);
if (!buffer) {
ret = ERR_PARAM_INVALID;
goto end;
}
memset(buffer, 0, XML_GET_BUF_SIZE);
mime.str = "text/xml";
mime.len = strlen("text/xml");
text_size = snprintf(buffer, XML_GET_BUF_SIZE, "<?xml version=\"1.0\" encoding=\"US-ASCII\" ?><RGW><%s><%s>%d</%s></%s></RGW>",
FIRMWARE_TAG, UPLOAD_STATUS_TAG, (int)obj->upload_status, UPLOAD_STATUS_TAG, FIRMWARE_TAG);
cgi_init_http_headers(text_size, NULL, &mime);
printf("%s",buffer);
end:
if (buffer)
free(buffer);
return ret;
}
int response_download_config_file()
{
struct stat file_stat;
char *buffer = NULL;
int fd = -1, size = 0, n_write = 0;
char file_name[128] = "/tmp/pxa1826_cfg.tar.gz";
int ret = NO_ERR;
struct mime_vec mime;
char disposition[128] = { 0 };
CGI_LOGI("%s: enter\n", __func__);
mime.str = "application/octet-stream";
mime.len = strlen("application/octet-stream");
stat(file_name, &file_stat);
if (file_stat.st_size <= 0) {
CGI_LOGE("%s: file size %d invalid\n", __func__, file_stat.st_size);
ret = ERR_PARAM_INVALID;
goto end;
}
buffer = malloc(XML_GET_BUF_SIZE);
if (!buffer) {
ret = ERR_PARAM_INVALID;
goto end;
}
memset(buffer, 0, XML_GET_BUF_SIZE);
/* init the repsonse header and body */
fd = open(file_name, O_RDONLY);
if (fd < 0) {
system("echo \"Open xml_res failed\" >> /tmp/my_debug");
ret = ERR_PARAM_INVALID;
goto end;
}
snprintf(disposition, 127, "attachment; filename=%s", CONFIG_FILE_NAME);
CGI_LOGI("%s: file size %d\n", __func__, file_stat.st_size);
cgi_init_http_headers(file_stat.st_size, disposition, &mime);
while ((size = read(fd, buffer, XML_GET_BUF_SIZE)) > 0) {
CGI_LOGI("%s: read size %d\n", __func__, size);
/*Pirnt the buffer to stdout, the stdout now redirect to pipi_wr, connect to parent process(Web Server) */
fwrite(buffer, size, 1, stdout);
if (n_write == size) {
CGI_LOGI("%s: write size %d done\n", __func__, size);
}
}
end:
CGI_LOGI("%s: leave %d\n", __func__, ret);
if (fd >= 0)
close(fd);
if (buffer)
free(buffer);
return ret;
}
int process_download_request(struct download_ops *ops)
{
int ret = ERR_PARAM_INVALID;
CGI_LOGI("%s: enter\n", __func__);
if (ops->download_init_cb) {
ret = ops->download_init_cb();
if (ret != NO_ERR)
goto end;
}
if (ops->download_response_cb) {
ret = ops->download_response_cb();
if (ret != NO_ERR)
goto end;
}
end:
CGI_LOGI("%s: leave %d\n", __func__, ret);
return ret;
}
int check_rpc_method_no_auth(char *filepost)
{
#define UBUS_PARAM_NUM 4
#define PARAM_LEN 32
#define ERROR_CAUSE_TAG "error_cause"
mxml_node_t *root = NULL;
mxml_node_t *cur = NULL;
mxml_node_t *param_node = NULL;
char param[UBUS_PARAM_NUM][PARAM_LEN];
unsigned int obj_id;
int i = 0;
FILE *fp = NULL;
int ret = -1;
fp = fopen(filepost, "r");
if (fp == NULL) {
CGI_LOGE("%s Couldn't read file\n", __func__);
ret = -1;
goto END;
}
root = mxmlLoadFile(NULL, fp, MXML_OPAQUE_CALLBACK);
fclose(fp);
CGI_LOGI("mxmlLoadFile success\n");
cur = mxmlFindElement(root, root, "RGW", NULL, NULL, MXML_DESCEND_FIRST);
if (cur == NULL) {
CGI_LOGE("%s mxmlFindElement failed\n", __func__);
ret = -1;
goto END;
}
cur = cur->child;
for (; cur != NULL; cur = cur->next) {
if (cur->type != MXML_ELEMENT) {
continue;
}
if (!strcmp(cur->value.element.name, "param")) {
param_node = cur->child;
i = 0;
for (; param_node != NULL; param_node = param_node->next) {
if (param_node->type != MXML_ELEMENT) {
continue;
}
if (param_node->child && param_node->child->type != MXML_ELEMENT &&
param_node->child->child == NULL && param_node->child->next == NULL) {
if (param_node->child->value.opaque){
if(i >= UBUS_PARAM_NUM || strlen(param_node->child->value.opaque) > PARAM_LEN){
CGI_LOGE("check_rpc_method_no_auth failed i[%d],opaque len[%d]\n", i, strlen(param_node->child->value.opaque));
ret = -1;
goto END;
}else{
strcpy(param[i++], param_node->child->value.opaque);
}
}
}
}
}
}
if (!strcmp(param[RPC_METHOD], "call")){
if(!strcmp(param[PRC_OBJMETHOD],"webdav_get_path_info")){
ret = 0;
}
}
END:
if (root)
mxmlDelete(root);
CGI_LOGI("check_rpc_method_no_auth: ret %d\n", ret);
return ret;
}
int main(int argc, char *argv[])
{
char *buffer = NULL;
int size;
int fd1, fd2;
char *xml_set = NULL, *xml_res = NULL;
int save_fd;
int ret = NO_ERR;
int res = NO_ERR;
struct upload_forward_ops ul_ops = { 0 };
struct download_ops dl_ops = { 0 };
set_service_log_tag("XML_ACTION");
prctl(PR_SET_NAME, "xml_action");
cgi_init();
if (cgi_ubus_init() != 0) {
CGI_LOGE("connect to ubus failed\n");
exit(0);
}
system("echo xml_action.lock > /sys/power/wake_lock");
start = cgi_process_form();
#if 0
if (access("/tmp/xml_lock", F_OK) < 0)
{
lock_fd = open("/tmp/xml_lock", O_RDWR|O_CREAT, 0);
if (lock_fd < 0)
{
/* create file failed */
cgi_prepare_response(ERROR_CAUSE_TAG, ERR_CGI_FILE, ERR_NUMBER);
goto cgi_cleanup;
}
}
else
{
/* lock file exist, not allow current request */
cgi_prepare_response(ERROR_CAUSE_TAG, ERR_CGI_FILE, ERR_NUMBER);
goto cgi_cleanup;
}
#endif
/*Generate temp unique get-result files for all request */
xml_set = strdup("/tmp/xml_set.XXXXXX");
xml_res = strdup("/tmp/xml_res.XXXXXX");
if ((fd1 = mkstemp(xml_set)) < 0)
goto cgi_cleanup;
if ((fd2 = mkstemp(xml_res)) < 0)
goto cgi_cleanup;
close(fd1);
close(fd2);
/*re-pointer to xml result temp file*/
g_xml_res = xml_res;
if (cgi_param(ARG_METHOD)) {
/*Open a temporary file in which the body of
*POST request will be stored*/
save_fd = open(xml_set, O_WRONLY | O_TRUNC | O_CREAT, 0);
if (save_fd == -1)
goto cgi_cleanup;
if (!buffer) {
buffer = malloc(XML_GET_BUF_SIZE);
memset(buffer, 0, XML_GET_BUF_SIZE);
}
/*Read the body of the POST request for stdin which has been redirect to pipe_rd*/
if ((size = read(0, buffer, XML_GET_BUF_SIZE)) > 0)
write(save_fd, buffer, size);
close(save_fd);
res=check_rpc_method_no_auth(xml_set);
ret = cgi_session_check();
CGI_LOGE("cgi_session_check ret %d\n", ret);
if (ret != SESS_VALID && res!=0) {
CGI_LOGE("invalid session!\n");
cgi_prepare_response(ERROR_CAUSE_TAG, ERR_SESSION_INVALID, ERR_NUMBER);
} else {
xml_duster_parse(xml_set);
}
send_xml_response(xml_res);
CGI_LOGI("send response done!\n");
}
if (cgi_param(ARG_ACTION)) {
if (cgi_session_check() != SESS_VALID) {
cgi_prepare_response(ERROR_CAUSE_TAG, ERR_SESSION_INVALID, ERR_NUMBER);
goto cgi_cleanup;
}
if (!strcmp(cgi_param(ARG_ACTION), "logout")) {
cgi_session_destroy();
cgi_prepare_response(RESPONSE_TAG, NO_ERR, ERR_STRING);
send_xml_response(xml_res);
} else if (!strcmp(cgi_param(ARG_ACTION), "Upload")) {
if (!strcmp(cgi_param(ARG_FILE), "upgrade")) {
CGI_LOGI("software upgrade!\n");
ul_ops.upload_fw_init_cb = upload_fw_ota_init;
ul_ops.upload_fw_write_cb = upload_fw_ota_write;
ul_ops.upload_fw_done_cb = upload_fw_ota_done;
ul_ops.upload_response_cb = response_firmware_upload;
ret = process_upload_request(&ul_ops);
if (ret != NO_ERR)
{
if (upload_obj.upload_status == ERR_UPLOAD_FAILED)
system("reboot > /dev/null");
else
goto cgi_cleanup;
}
} else if (!strcmp(cgi_param(ARG_FILE), "restore_config")) {
if (cgi_param(ARG_COMMAND)) {
if (!strcmp(cgi_param(ARG_COMMAND), "query_status")) {
CGI_LOGI("query restore config status!\n");
ul_ops.upload_response_cb = response_restore_status;
ul_ops.upload_response_cb(&upload_obj);
if (upload_obj.upload_status == UPLOAD_OK) {
/*reboot here*/
system("reboot > /dev/null");
}
}
goto cgi_cleanup;
}
CGI_LOGI("restore config!\n");
ul_ops.upload_fw_init_cb = upload_fw_fs_init;
ul_ops.upload_fw_write_cb = upload_fw_fs_write;
ul_ops.upload_fw_done_cb = upload_fw_fs_done;
ret = process_upload_request(&ul_ops);
if (ret != NO_ERR) {
upload_obj.upload_status = ERR_UPLOAD_FAILED;
} else
upload_obj.upload_status = UPLOAD_OK;
goto cgi_cleanup;
}
} else if (!strcmp(cgi_param(ARG_ACTION), "Download")) {
if (!strcmp(cgi_param(ARG_FILE), "backup_config")) {
CGI_LOGI("backup config!\n");
dl_ops.download_init_cb = download_config_file_init;
dl_ops.download_response_cb = response_download_config_file;
ret = process_download_request(&dl_ops);
if (ret != NO_ERR)
goto cgi_cleanup;
}
}
}
cgi_cleanup:
cgi_ubus_end();
cgi_end();
if (xml_res)
{
remove(xml_res);
free(xml_res);
}
//coverity[check_after_deref:SUPPRESS]
if (xml_set)
{
remove(xml_set);
free(xml_set);
}
if (buffer) {
free(buffer);
buffer = NULL;
}
#if 0
if (lock_fd != -1)
{
unlink("/tmp/xml_lock");
}
#endif
system("echo xml_action.lock > /sys/power/wake_unlock");
CGI_LOGI("%s: exit\n", __func__);
exit(0);
}