#include #include #include #include #include #include #include #include #include using boost::asio::ip::tcp; const int max_length = 1000000; typedef boost::shared_ptr socket_ptr; unsigned short analyze_user_request(std::string& user_request, short unsigned* ID, std::string* request_value) { // function returns: // 0: if user request is incorrect // 1: if user requests "PUT" operation // 2: if user requests "GET" operation // Furthermore, if request is correct, its value (i.e. ID number and/or string) is saved to short unsigned and string values passed by pointers. boost::regex exp("^[[:space:]]*(PUT|GET)[[:space:]]+([[:digit:]]{1,2})(?:[[:space:]]+(.*))?$"); boost::smatch what; if (regex_match(user_request, what, exp, boost::match_extra)) { short unsigned id_number = boost::lexical_cast(what[2]); if (what[1] == "PUT") { boost::regex exp1("^[a-zA-Z0-9]+$"); std::string value = boost::lexical_cast(what[3]); if (value.length() > 4095) return 0; if (!regex_match(value, exp1)) return 0; else { *request_value = value; *ID = id_number; return 1; } } if (what[1] == "GET") { *ID = id_number; return 2; } } if (!regex_match(user_request, what, exp, boost::match_extra)) return 0; } class Session { public: void handleRequest(socket_ptr sock) { try { for (;;) { char data[max_length]; boost::system::error_code error; size_t length = sock->read_some(boost::asio::buffer(data), error); if (error == boost::asio::error::eof) break; // Connection closed cleanly by peer. else if (error) throw boost::system::system_error(error); // Some other error. // convert buffer data to string for further procession std::string line(boost::asio::buffers_begin(boost::asio::buffer(data)), boost::asio::buffers_begin(boost::asio::buffer(data)) + length); std::string reply; // will be "QK", "INVALID", or "OK " unsigned short vID; unsigned short* ID = &vID; std::string vrequest_value; std::string* request_value = &vrequest_value; unsigned short output = analyze_user_request(line, ID, request_value); if (output == 1) { // PUT reply = "OK"; user_array[*ID] = *request_value; } else if (output == 2) { // GET reply = user_array[*ID]; if (reply == "") reply = "EMPTY"; } else reply = "INVALID"; boost::system::error_code ignored_error; size_t ans_len=reply.length(); boost::asio::write(*sock, boost::asio::buffer(reply)); } } catch (std::exception& e) { std::cerr << "Exception in thread: " << e.what() << "\n"; } } private: std::string user_array[100]; }; typedef boost::shared_ptr SessionPtr; void server(boost::asio::io_service& io_service, short port) { tcp::acceptor a(io_service, tcp::endpoint(tcp::v4(), port)); for (;;) { socket_ptr sock(new tcp::socket(io_service)); a.accept(*sock); SessionPtr newSession(new Session()); boost::thread acceptThread(boost::bind(&Session::handleRequest, newSession, sock)); } } int main(int argc, char* argv[]) { try { if (argc != 2) { std::cerr << "Usage: blocking_tcp_echo_server \n"; return 1; } boost::asio::io_service io_service; using namespace std; // For atoi. server(io_service, atoi(argv[1])); } catch (std::exception& e) { std::cerr << "Exception: " << e.what() << "\n"; } return 0; }