#include "http_server.h" #include #include #include #include #include #include #include #include #include #include #include "shttpd/shttpd.h" #include "storage/StoragePreferences.h" #include "service/BusinessConfig.h" #include "manager/ConfigManager.h" #include "utils/Log.h" #include "shttpd/multipart_reader.h" #include "os/MountMonitor.h" #include "net/NetManager.h" #define ETHERNETMANAGER NETMANAGER->getEthernetManager() namespace srv { class MyThread: public Thread { public: virtual bool readyToRun() { return true; } virtual bool threadLoop() { //检查是否有退出线程的请求,如果有,则返回false,立即退出线程 if (exitPending()) { return false; } //休眠5s usleep(5000 * 1000); lightControl("CALLLED", "000F"); //重启 sync(); reboot(RB_AUTOBOOT); //返回真,继续下次线程循环 return false; } }; static MyThread my_thread; //地址总长 #define ADDRLEN 15 //定义字符串数组保存IP地址、掩码地址、网关地址、首选DNS服务器地址以及备选DNS服务器地址 static std::string addr[5]; /** * 字符长度是否正确 * */ const bool isLengthCorrect(const std::string addr) { return addr.size() <= ADDRLEN; } /** * 检查是不是最多只有3个.字符 * */ const bool noMoreThan3charactor(const std::string addr) { //.字符个数 int count = 0; for(unsigned int level1 = 0; level1 < addr.size(); ++level1) { if('.' == addr[level1]) { ++count; } } return 3 >= count; } /* * 判断所有字符是不是由0~9和.组成 * */ const bool allCharacterIsLegal(const std::string addr) { for(unsigned int level1 = 0; level1 < addr.size(); ++level1) { if(false == (('0' <= addr[level1] && addr[level1] <= '9') || '.' == addr[level1])) { return false; } } return true; } /** * 判断开头是否是1`9 * */ const bool headIsCorrect(std::string addr, unsigned int pos = 0) { //查找到达末尾,直接返回true if(addr.size() == pos) { return true; } //查找.字符 if(std::string::npos == addr.find('.', pos)) { if('0' < addr[pos] && addr[pos] <= '9') { return true; } //如果开头为字符'0'且其后没有字符,那么返回true else if(addr.size()-1 == pos) { return true; } return false; } else { //开头为0~9 if('0' > addr[pos] || addr[pos] > '9') { return false; } //开头为0,后面没有字符返回false if('0' == addr[pos] && addr.size()-1 <= pos) { return false; } //跳过.字符继续查找 return headIsCorrect(addr, addr.find('.', pos)+1); } return true; //默认返回true } /** * 检查地址每一小段的长度,最长为3个字符 * */ const bool partCheractorCorrect(const std::string addr, unsigned int pos = 0) { //查找到达末尾,直接返回true if(addr.size() == pos) { return true; } //查找.字符 if(std::string::npos == addr.find('.', pos)) { if(3 >= addr.size()-pos) { return true; } return false; } else { //由于跳过了.字符进行查找,因此判断条件应该是>3 if(3 < addr.find('.', pos) - pos) { return false; } //跳过.字符继续查找 return partCheractorCorrect(addr, addr.find('.', pos)+1); } return true; //默认返回true } /** * 检测地址是否有误 * */ const bool checkAddr(std::string addr) { return (true == headIsCorrect(addr))? //地址每小段开头是否为0~9 (true == partCheractorCorrect(addr))? //每小段字符串最大长度是否为3 (true == noMoreThan3charactor(addr))? //最多是否只有3个.字符 (true == isLengthCorrect(addr))? //地址最大长度是否为15 (true == allCharacterIsLegal(addr))? //所有的字符是否都由0~9和.组成 true: false: false: false: false: false; } struct NetworkConfiguration { std::string ip; std::string sub_network_mask; std::string gateway; std::string dns1; std::string dns2; }; NetworkConfiguration GetNetworkConfiguration() { char ip[64] = {0}; char mask[64] = {0}; char gateway[64] = {0}; char dns1[64] = {0}; char dns2[64] = {0}; if (ETHERNETMANAGER->isAutoMode()) { ETHERNETMANAGER->getConfigureInfo(ip, mask, gateway, dns1, dns2); } else { ETHERNETMANAGER->getStaticConfigureInfo(ip, mask, gateway, dns1, dns2); } return NetworkConfiguration{ip, mask, gateway, dns1, dns2}; } std::string read_file(const std::string &file) { std::ifstream ifs(file.c_str(), std::ios::binary | std::ios::in); if (!ifs.is_open()) { return ""; } std::stringstream ss; ss << ifs.rdbuf(); ifs.close(); std::string content(ss.str()); return content; } // Content-Type: multipart/form-data; boundary=----WebKitFormBoundary4MxyDJzPWCVPEFFc std::string get_boundary(shttpd_arg *arg) { int len = 0; const char* boundary = shttpd_get_boundary(arg, &len); if (boundary) { return std::string(boundary, len); } return ""; } /* * This callback function is attached to the "/" and "/abc.html" URIs, * thus is acting as "index.html" file. It shows a bunch of links * to other URIs, and allows to change the value of program's * internal variable. The pointer to that variable is passed to the * callback function as arg->user_data. */ static void show_index(struct shttpd_arg *arg) { // int *p = arg->user_data; /* integer passed to us */ char wifi_name[128] = {0}; char wifi_password[128] = {0}; const char *request_method, *query_string; request_method = shttpd_get_env(arg, "REQUEST_METHOD"); // request_uri = shttpd_get_env(arg, "REQUEST_URI"); query_string = shttpd_get_env(arg, "QUERY_STRING"); /* Change the value of integer variable */ if (!strcmp(request_method, "POST")) { /* If not all data is POSTed, wait for the rest */ if (arg->flags & SHTTPD_MORE_POST_DATA) return; shttpd_get_var("wifi_name", arg->in.buf, arg->in.len, wifi_name, sizeof(wifi_name)); shttpd_get_var("wifi_password", arg->in.buf, arg->in.len, wifi_password, sizeof(wifi_password)); // mTextViewSetupNamePtr->setText(wifi_name); // mTextViewSetupPasswordPtr->setText(wifi_password); // StoragePreferences::putString(PROP_WIFI_NAME, wifi_name); // StoragePreferences::putString(PROP_WIFI_PASSWORD, wifi_password); } else if (query_string != NULL) { // GET // (void) shttpd_get_var("name1", query_string, // strlen(query_string), wifi_name, sizeof(wifi_name)); } shttpd_printf(arg, "%s", "HTTP/1.1 200 OK\r\n"); shttpd_printf(arg, "%s", "Content-Type: text/html\r\n\r\n"); std::string content = read_file(CONFIGMANAGER->getResFilePath("html/index.html")); std::string serverIp = StoragePreferences::getString(STORE_GATEWAY, serverIP); content = srv::format(content.c_str(), NETMANAGER->getEthernetManager()->getMacAddr(), NETMANAGER->getEthernetManager()->getIp(), GetNetworkConfiguration().sub_network_mask.c_str(), GetNetworkConfiguration().gateway.c_str(), GetNetworkConfiguration().dns1.c_str(), GetNetworkConfiguration().dns2.c_str(), serverIp.c_str()); std::string html(content); shttpd_printf(arg, "%s", html.c_str()); if (html.empty()) { shttpd_printf(arg, "%s", "read file failed"); } arg->flags |= SHTTPD_END_OF_OUTPUT; } struct state { size_t cl; /* Content-Length */ size_t nread; /* Number of bytes read */ FILE *fp; size_t file_length; multipart_reader *reader; HttpServer* server; bool is_tf_mounted; }; static void on_form_data_receive(const multipart_reader* reader, const char* data, uint64_t data_length) { // LOGD("write form data [%s], filename = [%s] length %lld", reader->form_data_name, reader->form_data_filename, data_length); if (strcmp(reader->form_data_name, "uploadFile") != 0) { return; } if (data_length == 0) { return; } if (reader->user_data == NULL) { return; } struct state* state = (struct state*)reader->user_data; if (state->fp == NULL) { if (!state->is_tf_mounted) { LOGD("未插入SD卡"); return; } state->fp = fopen(srv::format("/mnt/extsd/%s", reader->form_data_filename).c_str(), "wb"); if (state->fp == NULL) { LOGE("创建文件失败"); return; } } state->file_length += data_length; if (data_length != fwrite(data, 1, data_length, state->fp)) { LOGE("write form data failed"); return; } } static void upload_file(struct shttpd_arg *arg) { const char *s; const char* request_method = shttpd_get_env(arg, "REQUEST_METHOD"); if (strcmp(request_method, "POST") != 0) { return; } /* If the connection was broken prematurely, cleanup */ if ((arg->flags & SHTTPD_CONNECTION_ERROR) && arg->state) { struct state* state = (struct state*) arg->state; if (state->fp) { fclose(state->fp); } sync(); multipart_reader_destroy(state->reader); free(state); } else if ((s = shttpd_get_header(arg, "Content-Length")) == NULL) { shttpd_printf(arg, "HTTP/1.0 411 Length Required\n\n"); arg->flags |= SHTTPD_END_OF_OUTPUT; } else if (arg->state == NULL) { /* New request. Allocate a state structure, and open a file */ struct state* state = (struct state*)calloc(1, sizeof(*state)); arg->state = state; state->cl = strtoul(s, NULL, 10); state->server = (HttpServer*)arg->user_data; state->is_tf_mounted = MOUNTMONITOR->isMount(); std::string boundary = get_boundary(arg); if (!boundary.empty()) { LOGD("boundary=%s", boundary.c_str()); } state->reader = multipart_reader_create(boundary.c_str(), on_form_data_receive, state); shttpd_printf(arg, "HTTP/1.0 200 OK\n" "Content-Type: text/plain\n\n"); } else { struct state* state = (struct state*)arg->state; if(0 != multipart_reader_execute(state->reader, arg->in.buf, arg->in.len)) { LOGE("multipart_parser failed"); } state->nread += arg->in.len; /* Tell SHTTPD we have processed all data */ arg->in.num_bytes = arg->in.len; if (state->server->upload_filename_listener()) { state->server->upload_filename_listener()(state->reader->form_data_filename); } if (state->server->upload_progress_listener()) { state->server->upload_progress_listener()( (state->nread > state->cl) ? state->cl : state->nread, state->cl); } /* Data stream finished? Close the file, and free the state */ if (state->nread >= state->cl) { shttpd_printf(arg, "Written %d bytes", state->file_length); if (!state->is_tf_mounted) { shttpd_printf(arg, ", No TF card is mounted!"); } LOGD("file length = %d", state->file_length); if (state->fp) { fflush(state->fp); fclose(state->fp); } sync(); free(state); arg->flags |= SHTTPD_END_OF_OUTPUT; } } } static void setting(struct shttpd_arg *arg){ char dhcp[10] = {0}; char ip[64] = {0}; char netmask[64] = {0}; char gateway[64] = {0}; char dns1[64] = {0}; char dns2[64] = {0}; char serverIp[64] = {0}; const char *s; const char* request_method = shttpd_get_env(arg, "REQUEST_METHOD"); //仅接受post if (strcmp(request_method, "POST") != 0) { return; } /* If the connection was broken prematurely, cleanup */ if ((arg->flags & SHTTPD_CONNECTION_ERROR) && arg->state) { struct state* state = (struct state*) arg->state; if (state->fp) { fclose(state->fp); } sync(); free(state); } else if ((s = shttpd_get_header(arg, "Content-Length")) == NULL) { shttpd_printf(arg, "HTTP/1.0 411 Length Required\n\n"); arg->flags |= SHTTPD_END_OF_OUTPUT; } else if (arg->state == NULL) { /* New request. Allocate a state structure, and open a file */ struct state* state = (struct state*)calloc(1, sizeof(*state)); arg->state = state; state->cl = strtoul(s, NULL, 10); state->server = (HttpServer*)arg->user_data; shttpd_get_var("dhcp", arg->in.buf, arg->in.len, dhcp, sizeof(dhcp)); LOGD(">>>>>>>>>>>>> dhcp %s", dhcp); shttpd_get_var("ip", arg->in.buf, arg->in.len, ip, sizeof(ip)); LOGD(">>>>>>>>>>>>> ip %s", ip); shttpd_get_var("netmask", arg->in.buf, arg->in.len, netmask, sizeof(netmask)); LOGD(">>>>>>>>>>>>> netmask %s", netmask); shttpd_get_var("gateway", arg->in.buf, arg->in.len, gateway, sizeof(gateway)); LOGD(">>>>>>>>>>>>> gateway %s", gateway); shttpd_get_var("dns1", arg->in.buf, arg->in.len, dns1, sizeof(dns1)); LOGD(">>>>>>>>>>>>> dns1 %s", dns1); shttpd_get_var("dns2", arg->in.buf, arg->in.len, dns2, sizeof(dns2)); LOGD(">>>>>>>>>>>>> dns2 %s", dns2); shttpd_get_var("server_ip", arg->in.buf, arg->in.len, serverIp, sizeof(serverIp)); LOGD(">>>>>>>>>>>>> server ip %s", serverIp); std::string content = read_file(CONFIGMANAGER->getResFilePath("html/setting_result.html")); // std::string _ip = ip; // std::string _netmask = netmask; // std::string _gateway = gateway; // std::string _dns1 = dns1; // std::string _dns2 = dns2; // std::string _serverIp = serverIp; std::string msg = "setting ok. rebooting... pls wait."; if (!checkAddr(ip)){ msg = "ip wrong input"; } else if (!checkAddr(netmask)){ msg = "netmask wrong input"; } else if (!checkAddr(gateway)){ msg = "gateway wrong input"; } else if (!checkAddr(serverIp)){ msg = "server_ip wrong input"; } else { std::string _dhcp = dhcp; if (_dhcp == "1"){ ETHERNETMANAGER->setAutoMode(true); } else { ETHERNETMANAGER->setAutoMode(false); ETHERNETMANAGER->configure(ip, netmask, gateway, dns1, dns2); } StoragePreferences::putString(STORE_GATEWAY, serverIp); } content = srv::format(content.c_str(), msg.c_str()); shttpd_printf(arg, "%s", "HTTP/1.1 200 OK\r\n"); shttpd_printf(arg, "%s", "Content-Type: text/html\r\n\r\n"); std::string html(content); shttpd_printf(arg, "%s", html.c_str()); if (html.empty()) { shttpd_printf(arg, "%s", "read file failed"); } arg->flags |= SHTTPD_END_OF_OUTPUT; my_thread.run("reboot"); } else { } } /* * This callback function is used to show how to handle 404 error */ static void show_404(struct shttpd_arg *arg) { shttpd_printf(arg, "%s", "HTTP/1.1 200 OK\r\n"); shttpd_printf(arg, "%s", "Content-Type: text/plain\r\n\r\n"); shttpd_printf(arg, "%s", "Oops. File not found! "); shttpd_printf(arg, "%s", "This is a custom error handler."); arg->flags |= SHTTPD_END_OF_OUTPUT; } /* * Make sure we have ho zombies from CGIs */ static void signal_handler(int sig_num) { switch (sig_num) { #ifndef _WIN32 case SIGCHLD: while (waitpid(-1, &sig_num, WNOHANG) > 0) ; break; #endif /* !_WIN32 */ default: break; } } HttpServer::HttpServer() { stop_ = false; port_ = 80; upload_filename_listener_ = NULL; upload_progress_listener_ = NULL; } HttpServer::~HttpServer() { } bool HttpServer::threadLoop() { stop_ = false; RunSync(port_); return false; } void HttpServer::RunAsync(int port) { port_ = port; stop_ = false; run("shttpd"); } int HttpServer::RunSync(int port) { struct shttpd_ctx *ctx; #ifndef _WIN32 signal(SIGPIPE, SIG_IGN); signal(SIGCHLD, &signal_handler); #endif /* !_WIN32 */ /* * Initialize SHTTPD context. * Start listening on ports 8080 and 8081 */ ctx = shttpd_init(0, NULL); shttpd_set_option(ctx, "ports", format("%d", port).c_str()); /* 注册uri和它的回调函数*/ shttpd_register_uri(ctx, "/", &show_index, NULL); shttpd_register_uri(ctx, "/setting", &setting, this); shttpd_handle_error(ctx, 404, show_404, NULL); /* Serve connections infinitely until someone kills us */ while (!stop_) { shttpd_poll(ctx, 1000); } /* Probably unreached, because we will be killed by a signal */ shttpd_fini(ctx); return 0; } void HttpServer::Stop() { stop_ = true; requestExitAndWait(); stop_ = false; } void HttpServer::set_upload_filename_listener(UploadFilenameListener listener) { upload_filename_listener_ = listener; } void HttpServer::set_upload_progress_listener(UploadProgressListener listener) { upload_progress_listener_ = listener; } HttpServer::UploadFilenameListener HttpServer::upload_filename_listener() { return upload_filename_listener_; } HttpServer::UploadProgressListener HttpServer::upload_progress_listener() { return upload_progress_listener_; } } /* namespace srv */