diff --git a/bin/uce_fastcgi.debug.linux.bin b/bin/uce_fastcgi.debug.linux.bin index 3456865..48462cc 100755 Binary files a/bin/uce_fastcgi.debug.linux.bin and b/bin/uce_fastcgi.debug.linux.bin differ diff --git a/src/fastcgi/src/fcgicc.cc b/src/fastcgi/src/fcgicc.cc index e02fb4e..6710266 100644 --- a/src/fastcgi/src/fcgicc.cc +++ b/src/fastcgi/src/fcgicc.cc @@ -5,13 +5,13 @@ * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. + * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. * 3. Neither the names of the copyright holders nor the names of contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. + * may be used to endorse or promote products derived from this software + * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -49,17 +49,17 @@ FastCGIServer::RequestInfo::RequestInfo() : - params_closed(false), - in_closed(false), - output_closed(false) + params_closed(false), + in_closed(false), + output_closed(false) { } FastCGIServer::Connection::Connection() : - close_responsibility(false), - close_socket(false) + close_responsibility(false), + close_socket(false) { } @@ -67,14 +67,14 @@ FastCGIServer::Connection::Connection() : int FastCGIServer::HandlerBase::operator()(FastCGIRequest&) { - return 0; + return 0; } FastCGIServer::FastCGIServer() : - handle_request(new HandlerBase), - handle_data(new HandlerBase), - handle_complete(new HandlerBase) + handle_request(new HandlerBase), + handle_data(new HandlerBase), + handle_complete(new HandlerBase) { } @@ -84,432 +84,431 @@ FastCGIServer::~FastCGIServer() if(my_pid != parent_pid) // if we're a child process, we must not close the handles return; - for (std::vector::iterator it = listen_sockets.begin(); - it != listen_sockets.end(); ++it) - close(*it); + for (std::vector::iterator it = listen_sockets.begin(); + it != listen_sockets.end(); ++it) + close(*it); - for (std::vector::iterator it = listen_unlink.begin(); - it != listen_unlink.end(); ++it) - unlink(it->c_str()); + for (std::vector::iterator it = listen_unlink.begin(); + it != listen_unlink.end(); ++it) + unlink(it->c_str()); - for (std::map::iterator it = read_sockets.begin(); - it != read_sockets.end(); ++it) { - close(it->first); - for (RequestList::iterator req_it = it->second->requests.begin(); - req_it != it->second->requests.end(); ++req_it) - delete req_it->second; - delete it->second; - } + for (std::map::iterator it = read_sockets.begin(); + it != read_sockets.end(); ++it) { + close(it->first); + for (RequestList::iterator req_it = it->second->requests.begin(); + req_it != it->second->requests.end(); ++req_it) + delete req_it->second; + delete it->second; + } - delete handle_request; - delete handle_data; - delete handle_complete; + delete handle_request; + delete handle_data; + delete handle_complete; } void FastCGIServer::request_handler(int (* function)(FastCGIRequest&)) { - handle_request = new StaticHandler(function); + handle_request = new StaticHandler(function); } void FastCGIServer::data_handler(int (* function)(FastCGIRequest&)) { - handle_data = new StaticHandler(function); + handle_data = new StaticHandler(function); } void FastCGIServer::complete_handler(int (* function)(FastCGIRequest&)) { - handle_complete = new StaticHandler(function); + handle_complete = new StaticHandler(function); } void FastCGIServer::set_handler(HandlerBase*& handler, HandlerBase* new_handler) { - delete handler; - handler = new_handler; + delete handler; + handler = new_handler; } void FastCGIServer::listen(unsigned tcp_port) { - int listen_socket = socket(PF_INET, SOCK_STREAM, 0); - if (listen_socket == -1) - throw std::runtime_error("socket() failed"); + int listen_socket = socket(PF_INET, SOCK_STREAM, 0); + if (listen_socket == -1) + throw std::runtime_error("socket() failed"); - try { - struct sockaddr_in sa; - bzero(&sa, sizeof(sa)); - sa.sin_family = AF_INET; - sa.sin_port = htons(tcp_port); - sa.sin_addr.s_addr = htonl(INADDR_ANY); - if (bind(listen_socket, (struct sockaddr*)&sa, sizeof(sa)) == -1) - throw std::runtime_error("bind() failed"); + try { + struct sockaddr_in sa; + bzero(&sa, sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons(tcp_port); + sa.sin_addr.s_addr = htonl(INADDR_ANY); + if (bind(listen_socket, (struct sockaddr*)&sa, sizeof(sa)) == -1) + throw std::runtime_error("bind() failed"); - if (::listen(listen_socket, 100)) - throw std::runtime_error("listen() failed"); + if (::listen(listen_socket, 100)) + throw std::runtime_error("listen() failed"); - listen_sockets.push_back(listen_socket); + listen_sockets.push_back(listen_socket); - } catch (...) { - close(listen_socket); - throw; - } + } catch (...) { + close(listen_socket); + throw; + } } void FastCGIServer::listen(const std::string& local_path) { - int listen_socket = socket(PF_UNIX, SOCK_STREAM, 0); - if (listen_socket == -1) - throw std::runtime_error("socket() failed"); + int listen_socket = socket(PF_UNIX, SOCK_STREAM, 0); + if (listen_socket == -1) + throw std::runtime_error("socket() failed"); - try { - struct sockaddr_un sa; - bzero(&sa, sizeof(sa)); - sa.sun_family = AF_LOCAL; + try { + struct sockaddr_un sa; + bzero(&sa, sizeof(sa)); + sa.sun_family = AF_LOCAL; - std::string::size_type size = local_path.size(); - if (size >= sizeof(sa.sun_path)) - throw std::runtime_error("path too long"); - if (local_path.find_first_of('\0') != std::string::npos) - throw std::runtime_error("null character in path"); + std::string::size_type size = local_path.size(); + if (size >= sizeof(sa.sun_path)) + throw std::runtime_error("path too long"); + if (local_path.find_first_of('\0') != std::string::npos) + throw std::runtime_error("null character in path"); - std::memcpy(sa.sun_path, local_path.data(), size); + std::memcpy(sa.sun_path, local_path.data(), size); - unlink(local_path.c_str()); - try { - if (bind(listen_socket, (struct sockaddr*)&sa, - sizeof(sa) - (sizeof(sa.sun_path) - size - 1)) == -1) - throw std::runtime_error("bind() failed"); + unlink(local_path.c_str()); + try { + if (bind(listen_socket, (struct sockaddr*)&sa, + sizeof(sa) - (sizeof(sa.sun_path) - size - 1)) == -1) + throw std::runtime_error("bind() failed"); - if (::listen(listen_socket, 100)) - throw std::runtime_error("listen() failed"); + if (::listen(listen_socket, 100)) + throw std::runtime_error("listen() failed"); - listen_sockets.push_back(listen_socket); - listen_unlink.push_back(local_path); + listen_sockets.push_back(listen_socket); + listen_unlink.push_back(local_path); - } catch (...) { - unlink(local_path.c_str()); - throw; - } + } catch (...) { + unlink(local_path.c_str()); + throw; + } - } catch (...) { - close(listen_socket); - throw; - } + } catch (...) { + close(listen_socket); + throw; + } } void FastCGIServer::abandon_files() { - listen_unlink.clear(); + listen_unlink.clear(); } void FastCGIServer::process(int timeout_ms) { - char buffer[4096]; - fd_set fs_read; - fd_set fs_write; - int nfd = 0; - struct timeval tv = { timeout_ms / 1000, (timeout_ms % 1000) * 1000 }; + char buffer[4096]; + fd_set fs_read; + fd_set fs_write; + int nfd = 0; + struct timeval tv = { timeout_ms / 1000, (timeout_ms % 1000) * 1000 }; - FD_ZERO(&fs_read); - FD_ZERO(&fs_write); + FD_ZERO(&fs_read); + FD_ZERO(&fs_write); - for (std::vector::const_iterator it = listen_sockets.begin(); - it != listen_sockets.end(); ++it) { - FD_SET(*it, &fs_read); - nfd = std::max(nfd, *it); - } + for(auto socket_handle : listen_sockets) + { + FD_SET(socket_handle, &fs_read); + nfd = std::max(nfd, socket_handle); + } - for (std::map::const_iterator it = read_sockets.begin(); - it != read_sockets.end(); ++it) { - FD_SET(it->first, &fs_read); - if (!it->second->output_buffer.empty()) - FD_SET(it->first, &fs_write); - nfd = std::max(nfd, it->first); - } + for(auto con : read_sockets) + { + FD_SET(con.first, &fs_read); + if (!con.second->output_buffer.empty()) + FD_SET(con.first, &fs_write); + nfd = std::max(nfd, con.first); + } - int select_result = select(nfd + 1, &fs_read, &fs_write, NULL, - timeout_ms < 0 ? NULL : &tv); - if (select_result == -1) - if (errno == EINTR) - return; - else - throw std::runtime_error("select() failed"); + int select_result = select(nfd + 1, &fs_read, &fs_write, NULL, + timeout_ms < 0 ? NULL : &tv); + if (select_result == -1) + if (errno == EINTR) + return; + else + throw std::runtime_error("select() failed"); - for (std::vector::const_iterator it = listen_sockets.begin(); - it != listen_sockets.end(); ++it) - if (FD_ISSET(*it, &fs_read)) { - int read_socket = accept(*it, NULL, NULL); - if (read_socket == -1) - throw std::runtime_error("accept() failed"); - Connection* connection = new Connection; - try { - read_sockets.insert(std::map::value_type( - read_socket, connection)); - } catch (...) { - delete connection; - throw; - } - } + for(auto socket_handle : listen_sockets) + if (FD_ISSET(socket_handle, &fs_read)) + { + int posix_con = accept(socket_handle, NULL, NULL); + if (posix_con == -1) + throw std::runtime_error("accept() failed"); + read_sockets[posix_con] = new Connection(); + } - for (std::map::iterator it = read_sockets.begin(); - it != read_sockets.end();) { - int read_socket = it->first; + for (std::map::iterator it = read_sockets.begin(); + it != read_sockets.end();) + { + int read_socket = it->first; - if (FD_ISSET(read_socket, &fs_read)) { - int read_result = read(read_socket, buffer, sizeof(buffer)); - if (read_result == -1) - if (errno == ECONNRESET) - goto close_socket; - else - throw std::runtime_error("read() on socket failed"); - if (read_result == 0) - it->second->close_socket = true; - else { - it->second->input_buffer.append(buffer, read_result); - process_connection_read(*it->second); - } - } + if (FD_ISSET(read_socket, &fs_read)) + { + int read_result = read(read_socket, buffer, sizeof(buffer)); + if (read_result == -1) + if (errno == ECONNRESET) + goto close_socket; + else + throw std::runtime_error("read() on socket failed"); + if (read_result == 0) + it->second->close_socket = true; + else { + it->second->input_buffer.append(buffer, read_result); + process_connection_read(*it->second); + } + } - if (!it->second->output_buffer.empty() && - FD_ISSET(read_socket, &fs_write)) { - process_connection_write(*it->second); - int write_result = write(read_socket, - it->second->output_buffer.data(), - it->second->output_buffer.size()); - if (write_result == -1) - throw std::runtime_error("write() failed"); - it->second->output_buffer.erase(0, write_result); - } + if (!it->second->output_buffer.empty() && + FD_ISSET(read_socket, &fs_write)) + { + process_connection_write(*it->second); + int write_result = write(read_socket, + it->second->output_buffer.data(), + it->second->output_buffer.size()); + if (write_result == -1) + throw std::runtime_error("write() failed"); + it->second->output_buffer.erase(0, write_result); + } - if (it->second->close_socket && it->second->output_buffer.empty()) { - close_socket: - int close_result = close(it->first); - if (close_result == -1 && errno != ECONNRESET) - throw std::runtime_error("close() failed"); - Connection* connection = it->second; - read_sockets.erase(it++); - delete connection; - } else - ++it; - } + if (it->second->close_socket && it->second->output_buffer.empty()) + { + close_socket: + int close_result = close(it->first); + if (close_result == -1 && errno != ECONNRESET) + throw std::runtime_error("close() failed"); + Connection* connection = it->second; + read_sockets.erase(it++); + delete connection; + } else + ++it; + } } void FastCGIServer::process_forever() { - for (;;) - process(); + for (;;) + process(); } void FastCGIServer::process_connection_read(Connection& connection) { - std::string::size_type n = 0; - while (connection.input_buffer.size() - n >= FCGI_HEADER_LEN) { - const FCGI_Header& header = *reinterpret_cast( - connection.input_buffer.data() + n); - if (header.version != FCGI_VERSION_1) { - connection.close_socket = true; - break; - } + std::string::size_type n = 0; + while (connection.input_buffer.size() - n >= FCGI_HEADER_LEN) { + const FCGI_Header& header = *reinterpret_cast( + connection.input_buffer.data() + n); + if (header.version != FCGI_VERSION_1) { + connection.close_socket = true; + break; + } - unsigned content_length = - (header.contentLengthB1 << 8) + header.contentLengthB0; - if (connection.input_buffer.size() - n < - FCGI_HEADER_LEN + content_length + header.paddingLength) - break; - const char* content = - connection.input_buffer.data() + n + FCGI_HEADER_LEN; + unsigned content_length = + (header.contentLengthB1 << 8) + header.contentLengthB0; + if (connection.input_buffer.size() - n < + FCGI_HEADER_LEN + content_length + header.paddingLength) + break; + const char* content = + connection.input_buffer.data() + n + FCGI_HEADER_LEN; - RequestID request_id = (header.requestIdB1 << 8) + header.requestIdB0; + RequestID request_id = (header.requestIdB1 << 8) + header.requestIdB0; - switch (header.type) { - case FCGI_GET_VALUES: { - Pairs pairs = parse_pairs(content, content_length); + switch (header.type) { + case FCGI_GET_VALUES: { + Pairs pairs = parse_pairs(content, content_length); - std::string::size_type base = connection.output_buffer.size(); - connection.output_buffer.push_back(FCGI_VERSION_1); - connection.output_buffer.push_back(FCGI_GET_VALUES_RESULT); - connection.output_buffer.append(FCGI_HEADER_LEN - 2, 0); + std::string::size_type base = connection.output_buffer.size(); + connection.output_buffer.push_back(FCGI_VERSION_1); + connection.output_buffer.push_back(FCGI_GET_VALUES_RESULT); + connection.output_buffer.append(FCGI_HEADER_LEN - 2, 0); - for (Pairs::iterator it = pairs.begin(); it != pairs.end(); ++it) - if (it->first == FCGI_MAX_CONNS) - write_pair(connection.output_buffer, - it->first, std::string("100")); - else if (it->first == FCGI_MAX_REQS) - write_pair(connection.output_buffer, - it->first, std::string("1000")); - else if (it->first == FCGI_MPXS_CONNS) - write_pair(connection.output_buffer, - it->first, std::string("1")); + for (Pairs::iterator it = pairs.begin(); it != pairs.end(); ++it) + if (it->first == FCGI_MAX_CONNS) + write_pair(connection.output_buffer, + it->first, std::string("100")); + else if (it->first == FCGI_MAX_REQS) + write_pair(connection.output_buffer, + it->first, std::string("1000")); + else if (it->first == FCGI_MPXS_CONNS) + write_pair(connection.output_buffer, + it->first, std::string("1")); - std::string::size_type len = connection.output_buffer.size() - base; - connection.output_buffer[base + 4] = (len >> 8) & 0xff; - connection.output_buffer[base + 5] = len & 0xff; - break; - } - case FCGI_BEGIN_REQUEST: { - if (content_length < sizeof(FCGI_BeginRequestBody)) - break; - const FCGI_BeginRequestBody& body = - *reinterpret_cast(content); + std::string::size_type len = connection.output_buffer.size() - base; + connection.output_buffer[base + 4] = (len >> 8) & 0xff; + connection.output_buffer[base + 5] = len & 0xff; + break; + } + case FCGI_BEGIN_REQUEST: { + if (content_length < sizeof(FCGI_BeginRequestBody)) + break; + const FCGI_BeginRequestBody& body = + *reinterpret_cast(content); - if (!(body.flags & FCGI_KEEP_CONN)) - connection.close_responsibility = true; + if (!(body.flags & FCGI_KEEP_CONN)) + connection.close_responsibility = true; - unsigned role = (body.roleB1 << 8) + body.roleB0; - if (role != FCGI_RESPONDER) { - FCGI_EndRequestRecord unknown; - bzero(&unknown, sizeof(unknown)); - unknown.header.version = FCGI_VERSION_1; - unknown.header.type = FCGI_END_REQUEST; - unknown.header.contentLengthB0 = sizeof(unknown.body); - unknown.body.protocolStatus = FCGI_UNKNOWN_ROLE; - connection.output_buffer.append( - reinterpret_cast(&unknown), sizeof(unknown)); - if (connection.close_responsibility) - connection.close_socket = true; - break; - } + unsigned role = (body.roleB1 << 8) + body.roleB0; + if (role != FCGI_RESPONDER) { + FCGI_EndRequestRecord unknown; + bzero(&unknown, sizeof(unknown)); + unknown.header.version = FCGI_VERSION_1; + unknown.header.type = FCGI_END_REQUEST; + unknown.header.contentLengthB0 = sizeof(unknown.body); + unknown.body.protocolStatus = FCGI_UNKNOWN_ROLE; + connection.output_buffer.append( + reinterpret_cast(&unknown), sizeof(unknown)); + if (connection.close_responsibility) + connection.close_socket = true; + break; + } - { - RequestList::iterator it = connection.requests.find(request_id); - if (it != connection.requests.end()) { - delete it->second; - connection.requests.erase(it); - } - } + { + RequestList::iterator it = connection.requests.find(request_id); + if (it != connection.requests.end()) { + delete it->second; + connection.requests.erase(it); + } + } - RequestInfo* new_request = new RequestInfo; - try { - connection.requests.insert(RequestList::value_type( - request_id, new_request)); - } catch (...) { - delete new_request; - throw; - } - break; - } - case FCGI_ABORT_REQUEST: { - RequestList::iterator it = connection.requests.find(request_id); - if (it == connection.requests.end()) - break; + RequestInfo* new_request = new RequestInfo; + try { + connection.requests.insert(RequestList::value_type( + request_id, new_request)); + } catch (...) { + delete new_request; + throw; + } + break; + } + case FCGI_ABORT_REQUEST: { + RequestList::iterator it = connection.requests.find(request_id); + if (it == connection.requests.end()) + break; - FCGI_EndRequestRecord aborted; - bzero(&aborted, sizeof(aborted)); - aborted.header.version = FCGI_VERSION_1; - aborted.header.type = FCGI_END_REQUEST; - aborted.header.contentLengthB0 = sizeof(aborted.body); - aborted.body.appStatusB0 = 1; - aborted.body.protocolStatus = FCGI_REQUEST_COMPLETE; - connection.output_buffer.append( - reinterpret_cast(&aborted), sizeof(aborted)); - if (connection.close_responsibility) - connection.close_socket = true; + FCGI_EndRequestRecord aborted; + bzero(&aborted, sizeof(aborted)); + aborted.header.version = FCGI_VERSION_1; + aborted.header.type = FCGI_END_REQUEST; + aborted.header.contentLengthB0 = sizeof(aborted.body); + aborted.body.appStatusB0 = 1; + aborted.body.protocolStatus = FCGI_REQUEST_COMPLETE; + connection.output_buffer.append( + reinterpret_cast(&aborted), sizeof(aborted)); + if (connection.close_responsibility) + connection.close_socket = true; - delete it->second; - connection.requests.erase(it); - break; - } - case FCGI_PARAMS: { - RequestList::iterator it = connection.requests.find(request_id); - if (it == connection.requests.end()) - break; + delete it->second; + connection.requests.erase(it); + break; + } + case FCGI_PARAMS: { + RequestList::iterator it = connection.requests.find(request_id); + if (it == connection.requests.end()) + break; - RequestInfo& request = *it->second; - if (!request.params_closed) - if (content_length != 0) - request.params_buffer.append(content, content_length); - else { - request.params = parse_pairs(request.params_buffer.data(), - request.params_buffer.size()); - request.params_buffer.clear(); - request.params_closed = true; + RequestInfo& request = *it->second; + if (!request.params_closed) + if (content_length != 0) + request.params_buffer.append(content, content_length); + else { + request.params = parse_pairs(request.params_buffer.data(), + request.params_buffer.size()); + request.params_buffer.clear(); + request.params_closed = true; - request.status = (*handle_request)(request); - if (request.status == 0 && !request.in.empty()) { - request.status = (*handle_data)(request); - if (request.status == 0 && request.in_closed) - request.status = (*handle_complete)(request); - } - process_write_request(connection, request_id, request); - } - break; - } - case FCGI_STDIN: { - RequestList::iterator it = connection.requests.find(request_id); - if (it == connection.requests.end()) - break; + request.status = (*handle_request)(request); + if (request.status == 0 && !request.in.empty()) { + request.status = (*handle_data)(request); + if (request.status == 0 && request.in_closed) + request.status = (*handle_complete)(request); + } + process_write_request(connection, request_id, request); + } + break; + } + case FCGI_STDIN: { + RequestList::iterator it = connection.requests.find(request_id); + if (it == connection.requests.end()) + break; - RequestInfo& request = *it->second; - if (!request.in_closed) - if (content_length != 0) { - request.in.append(content, content_length); - if (request.params_closed && request.status == 0) { - request.status = (*handle_data)(request); - process_write_request(connection, request_id, request); - } - } else { - request.in_closed = true; - if (request.params_closed && request.status == 0) { - request.status = (*handle_complete)(request); - process_write_request(connection, request_id, request); - } - } - break; - } - case FCGI_DATA: - break; - default: { - FCGI_UnknownTypeRecord unknown; - bzero(&unknown, sizeof(unknown)); - unknown.header.version = FCGI_VERSION_1; - unknown.header.type = FCGI_UNKNOWN_TYPE; - unknown.header.contentLengthB0 = sizeof(unknown.body); - unknown.body.type = header.type; - connection.output_buffer.append( - reinterpret_cast(&unknown), sizeof(unknown)); - } - } + RequestInfo& request = *it->second; + if (!request.in_closed) + if (content_length != 0) { + request.in.append(content, content_length); + if (request.params_closed && request.status == 0) { + request.status = (*handle_data)(request); + process_write_request(connection, request_id, request); + } + } else { + request.in_closed = true; + if (request.params_closed && request.status == 0) { + request.status = (*handle_complete)(request); + process_write_request(connection, request_id, request); + } + } + break; + } + case FCGI_DATA: + break; + default: { + FCGI_UnknownTypeRecord unknown; + bzero(&unknown, sizeof(unknown)); + unknown.header.version = FCGI_VERSION_1; + unknown.header.type = FCGI_UNKNOWN_TYPE; + unknown.header.contentLengthB0 = sizeof(unknown.body); + unknown.body.type = header.type; + connection.output_buffer.append( + reinterpret_cast(&unknown), sizeof(unknown)); + } + } - n += FCGI_HEADER_LEN + content_length + header.paddingLength; - } + n += FCGI_HEADER_LEN + content_length + header.paddingLength; + } - connection.input_buffer.erase(0, n); + connection.input_buffer.erase(0, n); } void FastCGIServer::process_write_request(Connection& connection, RequestID id, - RequestInfo& request) + RequestInfo& request) { - if (!request.out.empty()) { - write_data(connection.output_buffer, id, request.out, FCGI_STDOUT); - request.out.clear(); - } - if (!request.err.empty()) { - write_data(connection.output_buffer, id, request.err, FCGI_STDERR); - request.err.clear(); - } - if ((request.in_closed || request.status != 0) && - !request.output_closed) { - + if (!request.out.empty()) + { + write_data(connection.output_buffer, id, request.out, FCGI_STDOUT); + request.out.clear(); + } + if (!request.err.empty()) + { + write_data(connection.output_buffer, id, request.err, FCGI_STDERR); + request.err.clear(); + } + if ((request.in_closed || request.status != 0) && + !request.output_closed) + { request.out = var_dump(request.header, "", "\r\n") + var_dump(request.set_cookies, "", "\r\n") + @@ -522,151 +521,151 @@ FastCGIServer::process_write_request(Connection& connection, RequestID id, } request.ob_stack.clear(); - write_data(connection.output_buffer, id, request.out, FCGI_STDOUT); - write_data(connection.output_buffer, id, request.err, FCGI_STDERR); + write_data(connection.output_buffer, id, request.out, FCGI_STDOUT); + write_data(connection.output_buffer, id, request.err, FCGI_STDERR); - request.time_end = microtime(); + request.stats.time_end = microtime(); printf("(r) pid:%i\t%s\t%0.6fs\t%0.1fkB\n", my_pid, request.params["REQUEST_URI"].c_str(), - request.time_end - request.time_start, + request.stats.time_end - request.stats.time_start, (f32)(request.out.length()/1024) ); - FCGI_EndRequestRecord complete; - bzero(&complete, sizeof(complete)); - complete.header.version = FCGI_VERSION_1; - complete.header.type = FCGI_END_REQUEST; - complete.header.requestIdB1 = (id >> 8) & 0xff; - complete.header.requestIdB0 = id & 0xff; - complete.header.contentLengthB0 = sizeof(complete.body); - complete.body.appStatusB3 = (request.status >> 24) & 0xff; - complete.body.appStatusB2 = (request.status >> 16) & 0xff; - complete.body.appStatusB1 = (request.status >> 8) & 0xff; - complete.body.appStatusB0 = request.status & 0xff; - complete.body.protocolStatus = FCGI_REQUEST_COMPLETE; - connection.output_buffer.append( - reinterpret_cast(&complete), sizeof(complete)); - if (connection.close_responsibility) - connection.close_socket = true; + FCGI_EndRequestRecord complete; + bzero(&complete, sizeof(complete)); + complete.header.version = FCGI_VERSION_1; + complete.header.type = FCGI_END_REQUEST; + complete.header.requestIdB1 = (id >> 8) & 0xff; + complete.header.requestIdB0 = id & 0xff; + complete.header.contentLengthB0 = sizeof(complete.body); + complete.body.appStatusB3 = (request.status >> 24) & 0xff; + complete.body.appStatusB2 = (request.status >> 16) & 0xff; + complete.body.appStatusB1 = (request.status >> 8) & 0xff; + complete.body.appStatusB0 = request.status & 0xff; + complete.body.protocolStatus = FCGI_REQUEST_COMPLETE; + connection.output_buffer.append( + reinterpret_cast(&complete), sizeof(complete)); + if (connection.close_responsibility) + connection.close_socket = true; - request.output_closed = true; - } + request.output_closed = true; + } } void FastCGIServer::process_connection_write(Connection& connection) { - for (RequestList::iterator it = connection.requests.begin(); - it != connection.requests.end();) { - process_write_request(connection, it->first, *it->second); - if (it->second->params_closed && it->second->in_closed) { - RequestInfo* request = it->second; - connection.requests.erase(it++); - delete request; - } else - ++it; - } + for (RequestList::iterator it = connection.requests.begin(); + it != connection.requests.end();) { + process_write_request(connection, it->first, *it->second); + if (it->second->params_closed && it->second->in_closed) { + RequestInfo* request = it->second; + connection.requests.erase(it++); + delete request; + } else + ++it; + } } FastCGIServer::Pairs FastCGIServer::parse_pairs(const char* data, std::string::size_type n) { - Pairs pairs; + Pairs pairs; - const unsigned char* u = reinterpret_cast(data); + const unsigned char* u = reinterpret_cast(data); - for (std::string::size_type m = 0; m < n;) { - std::string::size_type name_length, value_length; + for (std::string::size_type m = 0; m < n;) { + std::string::size_type name_length, value_length; - if (u[m] >> 7) { - if (n - m < 4) - break; - name_length = ((u[m] & 0x7f) << 24) + (u[m + 1] << 16) + - (u[m + 2] << 8) + u[m + 3]; - m += 4; - } else - name_length = u[m++]; - if (m >= n) - break; + if (u[m] >> 7) { + if (n - m < 4) + break; + name_length = ((u[m] & 0x7f) << 24) + (u[m + 1] << 16) + + (u[m + 2] << 8) + u[m + 3]; + m += 4; + } else + name_length = u[m++]; + if (m >= n) + break; - if (u[m] >> 7) { - if (n - m < 4) - break; - value_length = ((u[m] & 0x7f) << 24) + (u[m + 1] << 16) + - (u[m + 2] << 8) + u[m + 3]; - m += 4; - } else - value_length = u[m++]; + if (u[m] >> 7) { + if (n - m < 4) + break; + value_length = ((u[m] & 0x7f) << 24) + (u[m + 1] << 16) + + (u[m + 2] << 8) + u[m + 3]; + m += 4; + } else + value_length = u[m++]; - if (n - m < name_length) - break; - std::string key(data + m, name_length); - m += name_length; + if (n - m < name_length) + break; + std::string key(data + m, name_length); + m += name_length; - if (n - m < value_length) - break; - pairs.insert(Pairs::value_type( - key, std::string(data + m, value_length))); - m += value_length; - } + if (n - m < value_length) + break; + pairs.insert(Pairs::value_type( + key, std::string(data + m, value_length))); + m += value_length; + } - return pairs; + return pairs; } void FastCGIServer::write_pair(std::string& buffer, - const std::string& key, const std::string& value) + const std::string& key, const std::string& value) { - if (key.size() > 0x7f) { - buffer.push_back(0x80 + ((key.size() >> 24) & 0x7f)); - buffer.push_back((key.size() >> 16) & 0xff); - buffer.push_back((key.size() >> 8) & 0xff); - buffer.push_back(key.size() & 0xff); - } else - buffer.push_back(key.size()); + if (key.size() > 0x7f) { + buffer.push_back(0x80 + ((key.size() >> 24) & 0x7f)); + buffer.push_back((key.size() >> 16) & 0xff); + buffer.push_back((key.size() >> 8) & 0xff); + buffer.push_back(key.size() & 0xff); + } else + buffer.push_back(key.size()); - if (value.size() > 0x7f) { - buffer.push_back(0x80 + ((value.size() >> 24) & 0x7f)); - buffer.push_back((value.size() >> 16) & 0xff); - buffer.push_back((value.size() >> 8) & 0xff); - buffer.push_back(value.size() & 0xff); - } else - buffer.push_back(value.size()); + if (value.size() > 0x7f) { + buffer.push_back(0x80 + ((value.size() >> 24) & 0x7f)); + buffer.push_back((value.size() >> 16) & 0xff); + buffer.push_back((value.size() >> 8) & 0xff); + buffer.push_back(value.size() & 0xff); + } else + buffer.push_back(value.size()); - buffer.append(key); - buffer.append(value); + buffer.append(key); + buffer.append(value); } void FastCGIServer::write_data(std::string& buffer, RequestID id, - const std::string& input, unsigned char type) + const std::string& input, unsigned char type) { - FCGI_Header header; - bzero(&header, sizeof(header)); - header.version = FCGI_VERSION_1; - header.type = type; - header.requestIdB1 = (id >> 8) & 0xff; - header.requestIdB0 = id & 0xff; + FCGI_Header header; + bzero(&header, sizeof(header)); + header.version = FCGI_VERSION_1; + header.type = type; + header.requestIdB1 = (id >> 8) & 0xff; + header.requestIdB0 = id & 0xff; - for (std::string::size_type n = 0;;) { - std::string::size_type written = std::min(input.size() - n, - (std::string::size_type)0xffffu); + for (std::string::size_type n = 0;;) { + std::string::size_type written = std::min(input.size() - n, + (std::string::size_type)0xffffu); - header.contentLengthB1 = written >> 8; - header.contentLengthB0 = written & 0xff; - header.paddingLength = (8 - (written % 8)) % 8; - buffer.append( - reinterpret_cast(&header), sizeof(header)); - buffer.append(input.data() + n, written); - buffer.append(header.paddingLength, 0); + header.contentLengthB1 = written >> 8; + header.contentLengthB0 = written & 0xff; + header.paddingLength = (8 - (written % 8)) % 8; + buffer.append( + reinterpret_cast(&header), sizeof(header)); + buffer.append(input.data() + n, written); + buffer.append(header.paddingLength, 0); - n += written; - if (n == input.size()) - break; - } + n += written; + if (n == input.size()) + break; + } } diff --git a/src/fastcgi/src/fcgicc.h b/src/fastcgi/src/fcgicc.h index 31892a0..5d69d38 100644 --- a/src/fastcgi/src/fcgicc.h +++ b/src/fastcgi/src/fcgicc.h @@ -5,18 +5,18 @@ * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. + * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. * 3. Neither the names of the copyright holders nor the names of contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. + * may be used to endorse or promote products derived from this software + * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS @@ -41,110 +41,110 @@ class FastCGIServer { public: - FastCGIServer(); - ~FastCGIServer(); + FastCGIServer(); + ~FastCGIServer(); - // called when the parameters and standard input have been receieved - void request_handler(int (* function)(FastCGIRequest&)); - template - void request_handler(C& object, int (C::* function)(FastCGIRequest&)) { - set_handler(handle_request, new Handler(object, function)); - } + // called when the parameters and standard input have been receieved + void request_handler(int (* function)(FastCGIRequest&)); + template + void request_handler(C& object, int (C::* function)(FastCGIRequest&)) { + set_handler(handle_request, new Handler(object, function)); + } - // called when new data appears on stdin - void data_handler(int (* function)(FastCGIRequest&)); - template - void data_handler(C& object, int (C::* function)(FastCGIRequest&)) { - set_handler(handle_data, new Handler(object, function)); - } + // called when new data appears on stdin + void data_handler(int (* function)(FastCGIRequest&)); + template + void data_handler(C& object, int (C::* function)(FastCGIRequest&)) { + set_handler(handle_data, new Handler(object, function)); + } - // called when the complete request has been received - void complete_handler(int (* function)(FastCGIRequest&)); - template - void complete_handler(C& object, int (C::* function)(FastCGIRequest&)) { - set_handler(handle_complete, new Handler(object, function)); - } + // called when the complete request has been received + void complete_handler(int (* function)(FastCGIRequest&)); + template + void complete_handler(C& object, int (C::* function)(FastCGIRequest&)) { + set_handler(handle_complete, new Handler(object, function)); + } - void listen(unsigned tcp_port); - void listen(const std::string& local_path); - void abandon_files(); + void listen(unsigned tcp_port); + void listen(const std::string& local_path); + void abandon_files(); - void process(int timeout_ms = -1); // timeout_ms<0 blocks forever - void process_forever(); + void process(int timeout_ms = -1); // timeout_ms<0 blocks forever + void process_forever(); protected: - struct RequestInfo : FastCGIRequest { - RequestInfo(); + struct RequestInfo : FastCGIRequest { + RequestInfo(); - std::string params_buffer; - bool params_closed; - bool in_closed; - int status; - bool output_closed; + std::string params_buffer; + bool params_closed; + bool in_closed; + int status; + bool output_closed; - friend class FastCGIServer; - }; + friend class FastCGIServer; + }; - typedef unsigned RequestID; - typedef std::map RequestList; - struct Connection { - Connection(); + typedef unsigned RequestID; + typedef std::map RequestList; + struct Connection { + Connection(); - RequestList requests; - std::string input_buffer; - std::string output_buffer; - bool close_responsibility; - bool close_socket; - }; + RequestList requests; + std::string input_buffer; + std::string output_buffer; + bool close_responsibility; + bool close_socket; + }; - typedef StringMap Pairs; + typedef StringMap Pairs; - std::vector listen_sockets; - std::vector listen_unlink; + std::vector listen_sockets; + std::vector listen_unlink; - std::map read_sockets; + std::map read_sockets; - void process_connection_read(Connection&); - static void process_write_request(Connection&, RequestID, RequestInfo&); - static void process_connection_write(Connection&); - static Pairs parse_pairs(const char*, std::string::size_type); - static void write_pair(std::string& buffer, - const std::string& key, const std::string&); - static void write_data(std::string& buffer, RequestID id, - const std::string& input, unsigned char type); + void process_connection_read(Connection&); + static void process_write_request(Connection&, RequestID, RequestInfo&); + static void process_connection_write(Connection&); + static Pairs parse_pairs(const char*, std::string::size_type); + static void write_pair(std::string& buffer, + const std::string& key, const std::string&); + static void write_data(std::string& buffer, RequestID id, + const std::string& input, unsigned char type); - struct HandlerBase { - virtual int operator()(FastCGIRequest&); - }; + struct HandlerBase { + virtual int operator()(FastCGIRequest&); + }; - struct StaticHandler : public HandlerBase { - StaticHandler(int (* p_function)(FastCGIRequest&)) : - function(p_function) {} - int operator()(FastCGIRequest& request) { - return function(request); - } + struct StaticHandler : public HandlerBase { + StaticHandler(int (* p_function)(FastCGIRequest&)) : + function(p_function) {} + int operator()(FastCGIRequest& request) { + return function(request); + } - int (* function)(FastCGIRequest&); - }; + int (* function)(FastCGIRequest&); + }; - template - struct Handler : public HandlerBase { - Handler(C& p_object, int (C::* p_function)(FastCGIRequest&)) : - object(p_object), function(p_function) {} - int operator()(FastCGIRequest& request) { - return (object.*function)(request); - } + template + struct Handler : public HandlerBase { + Handler(C& p_object, int (C::* p_function)(FastCGIRequest&)) : + object(p_object), function(p_function) {} + int operator()(FastCGIRequest& request) { + return (object.*function)(request); + } - C& object; - int (C::* function)(FastCGIRequest&); - }; + C& object; + int (C::* function)(FastCGIRequest&); + }; - void set_handler(HandlerBase*&, HandlerBase*); + void set_handler(HandlerBase*&, HandlerBase*); - HandlerBase* handle_request; - HandlerBase* handle_data; - HandlerBase* handle_complete; + HandlerBase* handle_request; + HandlerBase* handle_data; + HandlerBase* handle_complete; }; #endif // !FCGICC_H diff --git a/src/lib/functionlib.cpp b/src/lib/functionlib.cpp index e586325..90deed0 100644 --- a/src/lib/functionlib.cpp +++ b/src/lib/functionlib.cpp @@ -397,3 +397,68 @@ String ob_get_close() return(result); } +#define BIT_NOISE1 0xB5297A4D +#define BIT_NOISE2 0x68E31DA4 +#define BIT_NOISE3 0x1B56C4E9 + +// based on Squirrel3 https://www.youtube.com/watch?v=LWFzPP8ZbdU&t=2666s +u32 noise32(u32 index, u32 seed) +{ + u32 r = index; + r *= BIT_NOISE1; + r += seed; + r ^= (r >> 8); + r += BIT_NOISE2; + r ^= (r << 8); + r *= BIT_NOISE3; + r ^= (r >> 8); + return(r); +} + +#define BIT_NOISE61 0x5134811636f8cc8a +#define BIT_NOISE62 0xb8E31DA41B56C4E9 +#define BIT_NOISE63 0x18cd227aaa1168c1 + +u64 noise64(u64 index, u64 seed) +{ + u64 r = index; + r *= BIT_NOISE61; + r += seed; + r ^= (r >> 8); + r += BIT_NOISE62; + r ^= (r << 8); + r *= BIT_NOISE63; + r ^= (r >> 8); + return(r); +} + +#define MAX_64 0xffffffffffffffff + +f64 noise01(u64 index, u64 seed) +{ + return((float)noise64(index, seed)/(float)MAX_64); +} + +u64 generate_int(u64 from, u64 to, u64 index, u64 seed) +{ + u64 b = 1 + to - from; + return(from + (noise64(index, seed) % b)); +} + +#include +f64 generate_float(f64 from, f64 to, u64 index, u64 seed, f64 decimal_precision) +{ + f64 b = to - from; + return(from + fmod( decimal_precision*(f64)noise64(index, seed), b)); +} + +u64 draw_int(u64 from, u64 to) +{ + return(generate_int(from, to, context->random_index++, context->random_seed)); +} + +f64 draw_float(f64 from, f64 to, f64 decimal_precision) +{ + return(generate_float(from, to, context->random_index++, context->random_seed, decimal_precision)); +} + diff --git a/src/lib/functionlib.h b/src/lib/functionlib.h index 10b2e23..1557e36 100644 --- a/src/lib/functionlib.h +++ b/src/lib/functionlib.h @@ -29,3 +29,11 @@ void ob_start(); void ob_clear(); String ob_get_clear(); String ob_get(); + +u32 noise32(u32 index, u32 seed = 0); +u64 noise64(u64 index, u64 seed = 0); +f64 noise01(u64 index, u64 seed = 0); +u64 generate_int(u64 from, u64 to, u64 index, u64 seed = 0); +f64 generate_float(f64 from, f64 to, u64 index, u64 seed = 0, f64 decimal_precision = 0.000000000001); +u64 draw_int(u64 from, u64 to); +f64 draw_float(f64 from, f64 to, f64 decimal_precision = 0.000000000001); diff --git a/src/lib/types.h b/src/lib/types.h index d2e1b2a..15b0870 100644 --- a/src/lib/types.h +++ b/src/lib/types.h @@ -153,7 +153,7 @@ struct ServerSettings { String COMPILER_SYS_PATH = "."; u32 LISTEN_PORT = 9993; u64 SESSION_TIME = 60*60*24*30; - u32 WORKER_COUNT = 4; + u32 WORKER_COUNT = 1; u32 MAX_MEMORY = 1024*1024*16; }; @@ -236,6 +236,9 @@ struct Request { StringMap header; StringList set_cookies; + u64 random_seed; + u64 random_index; + MemoryArena* request_arena; String in; @@ -246,12 +249,11 @@ struct Request { bool is_finished = false; - f64 time_init; - f64 time_start; - f64 time_end; - struct Stats { u32 bytes_written; + f64 time_init; + f64 time_start; + f64 time_end; } stats; struct Resources { diff --git a/src/linux_fastcgi.cpp b/src/linux_fastcgi.cpp index 4da03a8..b872f78 100644 --- a/src/linux_fastcgi.cpp +++ b/src/linux_fastcgi.cpp @@ -11,7 +11,7 @@ int handle_request(FastCGIRequest& request) { // server receives all parameters. There may be more data coming on the // standard input stream. request.request_arena = request_arena; - request.time_init = microtime(); + request.stats.time_init = microtime(); request.ob_start(); // this one is for the headers request.ob_start(); // this one is for the content if (request.params.count("REQUEST_URI")) @@ -45,9 +45,11 @@ int handle_complete(FastCGIRequest& request) { context = &request; request.server = &server_state; - request.time_start = microtime(); + request.stats.time_start = microtime(); request.header["Content-Type"] = context->server->config.CONTENT_TYPE; request.get = parse_query(request.params["QUERY_String"]); + request.random_index = 0; + request.random_seed = noise64(*reinterpret_cast(&request.stats.time_start)); if(request.params["HTTP_COOKIE"].length() > 0) request.cookies = parse_cookies(request.params["HTTP_COOKIE"]); diff --git a/test/index.uce b/test/index.uce index d3ee131..2caa684 100644 --- a/test/index.uce +++ b/test/index.uce @@ -24,6 +24,7 @@ RENDER()
  • Memcached
  • MySQL Connector
  • File I/O
  • +
  • RNG/Noise
  • 
    +		
    +		

    + UCE Test: + Random +

    + + + + + <> + Generate Some Numbers +
    + Draw Some Numbers +
    + Seed random_seed ?> +
    +
    + Params +
    params) ?>
    + + +}