#ifndef nullptr #define nullptr NULL #endif #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; // http://www.fastcgi.com #include #include // http://uriparser.sourceforge.net #include // http://www.postgresql.org //#include #include // https://github.com/open-source-parsers/jsoncpp #include #define SOCK_TCP #include #include "sqlmaker/sqlmaker.h" my_id_t get_my_id() { static my_id_t myid = 0; myid++; return myid; } char to_upper(char c) { return toupper((int)c); } extern char **environ; static char **g_initial_nv = nullptr; static size_t g_req_count = 0; stringstream g_log_msg; stringstream g_http_res; typedef void (*url_process_func_t)(); typedef map upf_map_t; static upf_map_t g_url_processors; typedef map str_map_t; static void http_res_200(const char* msg) { FCGI_printf("Status: 20 OK\r\n" "Content-type: text/html\r\n" "\r\n" "%s", msg); } static void http_res_400() { FCGI_printf("Status: 400 Bad Request\r\n" "Content-type: text/html\r\n" "\r\n"); } static void http_res_401() { FCGI_printf("Status: 401 Unauthorized\r\n" "Content-type: text/html\r\n" "\r\n"); } static void http_res_404() { FCGI_printf("Status: 404 Not Found\r\n" "\r\n"); } static void http_res_500() { FCGI_printf("Status: 500 Internal Server Error\r\n" "\r\n"); } static void http_res_500(int problem_code = 0) { FCGI_printf("Status: 500 Internal Server Error\r\n" "Content-type: text/html\r\n" "\r\n" "Problem code = %d", problem_code); } static void http_res_500(const char* msg) { FCGI_printf("Status: 500 Internal Server Error\r\n" "Content-type: text/html\r\n" "\r\n" "Message = %s", msg); } size_t read_shell(const char* cmd, char* buffer, size_t buffer_size, int* exit_status = nullptr, int* exit_code = nullptr) { if (cmd == nullptr) return 0; FCGI_FILE* fcmd = FCGI_popen(cmd, "r"); if (fcmd == nullptr) return 0; size_t red = FCGI_fread(buffer, sizeof(char), buffer_size - 1, fcmd); int es = FCGI_pclose(fcmd); if (exit_status != nullptr) *exit_status = es; if (exit_code != nullptr) *exit_code = WEXITSTATUS(es); return red; } void run_in_bash(const char* cmd, int* exit_status = nullptr, int* exit_code = nullptr) { #define BASH_WRAPPER "su -s /bin/bash -c '%s' http" char buffer[512]; snprintf(buffer, sizeof(buffer) - 1, BASH_WRAPPER, cmd); int es = system(buffer); if (exit_status != nullptr) *exit_status = es; if (exit_code != nullptr) *exit_code = WEXITSTATUS(es); } static void print_env(const char *label, char **envp) { FCGI_printf("%s:
\n
\n", label);
	for ( ; *envp != NULL; envp++)
	{
		FCGI_printf("%s\n", *envp);
	}
	FCGI_printf("

\n"); } static void hpf_echo() { g_log_msg.flush(); char *contentLength = getenv("CONTENT_LENGTH"); int len; FCGI_printf("Content-type: text/html\r\n" "\r\n" "FastCGI echo" "

FastCGI echo

\n" "Request number %d, Process ID: %d

\n", g_req_count, getpid()); if (contentLength != NULL) len = strtol(contentLength, NULL, 10); else len = 0; if (len <= 0) { FCGI_printf("No data from standard input.

\n"); } else { int i, ch; FCGI_printf("Standard input:
\n

\n");
		for (i = 0; i < len; i++)
		{
			if ((ch = getchar()) < 0)
			{
				FCGI_printf("Error: Not enough bytes received on standard input

\n"); break; } putchar(ch); } FCGI_printf("\n

\n"); } print_env("Request environment", environ); print_env("Initial environment", g_initial_nv); } bool parse_query_items(str_map_t& query_items) { char* req_REQUEST_URI; req_REQUEST_URI = getenv("REQUEST_URI"); if (req_REQUEST_URI == nullptr) { g_log_msg << "can not get REQUEST_URI" << endl; goto error_ret; } char* req_QUERY_STRING; req_QUERY_STRING = getenv("QUERY_STRING"); if (req_QUERY_STRING == nullptr) { g_log_msg << "can not get QUERY_STRING" << endl; goto error_ret; } else if (req_QUERY_STRING[0] == '\0') { g_log_msg << "QUERY_STRING is empty" << endl; return true; } UriParserStateA state; UriUriA uri; state.uri = &uri; if (uriParseUriA(&state, req_REQUEST_URI) != URI_SUCCESS) { g_log_msg << "uriParseUriA not success" << endl; goto error_ret_uri_1; } UriQueryListA * query_list; query_list = nullptr; int ql_item_count; ql_item_count = 0; if (uriDissectQueryMallocA(&query_list, &ql_item_count, uri.query.first, uri.query.afterLast) != URI_SUCCESS) { g_log_msg << "uriDissectQueryMallocA not success" << endl; goto error_ret_uri_2; } //debug: //FCGI_printf("Content-type: text/json\r\n" "\r\n"); UriQueryListA* iter_query_list; iter_query_list = query_list; while (iter_query_list != nullptr) { const char* qi_key = iter_query_list->key; const char* qi_value = iter_query_list->value; if(qi_key == nullptr || qi_value == nullptr) { g_log_msg << "query_list contains null key or value" << endl; goto error_ret_uri_2; } query_items[string(qi_key)] = string(qi_value); //debug: //FCGI_printf("%s=%s\n", qi_key, qi_value); iter_query_list = iter_query_list->next; } uriFreeQueryListA(query_list); uriFreeUriMembersA(&uri); return true; error_ret_uri_2: uriFreeQueryListA(query_list); error_ret_uri_1: uriFreeUriMembersA(&uri); error_ret: return false; } size_t get_post_content(char* buffer, size_t max_size, size_t offset_content = 0) { if (buffer == NULL || max_size == 0) return 0; const char* contentLength = getenv("CONTENT_LENGTH"); size_t len = 0; if (contentLength != NULL) len = strtol(contentLength, NULL, 10); if (len == 0) return 0; if (offset_content > 0) fseek(stdin, offset_content, SEEK_SET); return fread(buffer, sizeof(char), min(max_size, len), stdin); } const string* try_get_str_from_map(const str_map_t& str_map, const string& key, const string* default_value = nullptr) { str_map_t::const_iterator iter = str_map.find(key); if (iter == str_map.end()) return default_value; else return &(iter->second); } static void hpf_fishbowl_fish_count() { g_log_msg.flush(); str_map_t query_items; if (! parse_query_items(query_items)) { http_res_500(g_log_msg.str().c_str()); return; } Json::Value json_root; bool json_ret = true; const string* qi_cmd = try_get_str_from_map(query_items, string("cmd")); if (qi_cmd == nullptr) { json_root["msg"] = "cmd not needed"; } else { if (strcmp("list", qi_cmd->c_str()) == 0) { json_ret = hpf_fishbowl_fish_count_list(query_items, json_root); } else if (strcmp("variate", qi_cmd->c_str()) == 0) { json_ret = hpf_fishbowl_fish_count_variate(query_items, json_root); } else if (strcmp("summed", qi_cmd->c_str()) == 0) { json_ret = hpf_fishbowl_fish_count_summed(query_items, json_root); } else if (strcmp("graph", qi_cmd->c_str()) == 0) { } else { json_root["msg"] = "cmd not supported"; } } if (json_ret) { printf("Content-type: application/json\r\n" "\r\n"); printf("%s", json_root.toStyledString().c_str()); } } static void hpf_fishbowl_load_v4l2grab() { g_log_msg.flush(); errno = 0; bool ret = false; int exit_code = 0; const std::string cmd("exec/LOAD_V4L2GRAB"); std::string result; CmdhubClientSession session; session.recv_retry = 20; if (ret = cmdhub_client_init(session)) { if (ret = cmdhub_client_connect(session)) { ret = cmdhub_client_command(session, cmd, result, exit_code); cmdhub_client_destory(session); } } Json::Value json_root; json_root["return"] = ret; if (ret) { json_root["exitcode"] = exit_code; json_root["result"] = result; } else { json_root["errno"] = errno; } printf("Content-type: application/json\r\n" "\r\n"); printf("%s", json_root.toStyledString().c_str()); } int main () { g_initial_nv = environ; g_url_processors["/echo"] = hpf_echo; g_url_processors["/fishbowl-basic-data"] = hpf_fishbowl_basic_data; g_url_processors["/fishbowl-bdtype"] = hpf_fishbowl_bdtype; g_url_processors["/fishbowl-fish-count"] = hpf_fishbowl_fish_count; g_url_processors["/fishbowl-fish-type"] = hpf_fishbowl_fish_type; g_url_processors["/fishbowl-fish-diary"] = hpf_fishbowl_fish_diary; g_url_processors["/fishbowl-load-v4l2grab"] = hpf_fishbowl_load_v4l2grab; //g_url_processors["/fishbowl-reminder"] = hpf_fishbowl_reminder; if(psql_conn() == nullptr) { cerr << g_log_msg.rdbuf(); exit(EXIT_FAILURE); } cerr << "begin accept access" << endl; int fcgi_accept_status; while ((fcgi_accept_status = FCGI_Accept()) >= 0) { g_req_count++; g_log_msg.flush(); char* req_PATH_INFO = getenv("PATH_INFO"); if(req_PATH_INFO == nullptr) { cerr << "PATH_INFO is null" << endl; exit(EXIT_FAILURE); } upf_map_t::iterator iter_upf = g_url_processors.find(req_PATH_INFO); if (iter_upf == g_url_processors.end()) { http_res_404(); } else { url_process_func_t proc = iter_upf->second; proc(); } } PGconn* conn = psql_conn(); if (conn != nullptr) PQfinish(conn); cerr << "exit gracefully, fcgi_accept_status=" << fcgi_accept_status << endl; return 0; }