Endil

cn-lab5-server-except

Mar 15th, 2016
81
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.48 KB | None | 0 0
  1. #include "stdafx.h"
  2. #include <chrono>
  3. #include <exception>
  4. #include <iostream>
  5. #include <map>
  6. #include <regex>
  7. #include <string>
  8. #include <thread>
  9. #include <vector>
  10. #include <winsock2.h>
  11.  
  12. #pragma comment(lib, "ws2_32.lib")
  13.  
  14. using namespace std;
  15. using namespace std::chrono;
  16.  
  17. typedef long long ll;
  18. typedef unsigned long long ull;
  19. typedef time_point<system_clock, milliseconds> timepoint;
  20.  
  21. vector<thread> connected_clients_list;
  22.  
  23. timepoint str_to_tp(const string _tp) {
  24.     milliseconds tp_m(stoull(_tp));
  25.     timepoint tp(tp_m);
  26.     return tp;
  27. }
  28.  
  29. class wsa_exception : public exception {
  30. private:
  31.     static map<const string, const string> description_list;
  32.     const int error_code;
  33.     const string error_message;
  34. public:
  35.     wsa_exception(string s)
  36.         : error_code(WSAGetLastError()), error_message(s) {};
  37.     int code() const {
  38.         return error_code;
  39.     }
  40.     string message() const {
  41.         return error_message;
  42.     }
  43.     virtual const char * what() const override {
  44.         try {
  45.             return description_list.at(error_message).c_str() + ' ' + error_code;
  46.         }
  47.         catch (out_of_range) {
  48.             return "unkwown WSA error" + ' ' + error_code;
  49.         }
  50.     }
  51. };
  52.  
  53. map<const string, const string> wsa_exception::description_list = {
  54.     { "&wsa_error_accept", "accept error " },
  55.     { "&wsa_error_recv", "recv error " } };
  56.  
  57. class Message {
  58. private:
  59.     timepoint tp;
  60.     string dest_num;
  61.     string text;
  62.     bool deletable;
  63. public:
  64.     Message(const timepoint &_tp, const string &_dest_num, const string &_text, const bool &_deletable)
  65.         : tp(_tp), dest_num(_dest_num), text(_text), deletable(_deletable) {};
  66.     string get_dest_number() const {
  67.         return dest_num;
  68.     }
  69.     bool is_deletable() const {
  70.         return deletable;
  71.     }
  72.     timepoint get_tp() const {
  73.         return tp;
  74.     }
  75. };
  76.  
  77. class MessageList {
  78. private:
  79.     vector<Message> messages;
  80. public:
  81.     void add(const string &_tp, const string &_dest_number, const string &_text, const bool &_deletable = false) {
  82.         timepoint tp = str_to_tp(_tp);
  83.         messages.emplace_back(tp, _dest_number, _text, _deletable);
  84.     }
  85.     void remove(const string &_timepoint, const string &_dest_number) {
  86.         for (auto i = messages.rbegin(); i != messages.rend(); i++)
  87.             if (i->get_dest_number() == _dest_number) {
  88.                 if (i->is_deletable() == true) {
  89.                     timepoint tp = str_to_tp(_timepoint);
  90.                     milliseconds period(60000);
  91.                     if (duration_cast<milliseconds>(tp - i->get_tp()) <= period) {
  92.                         messages.erase(next(i).base());
  93.                         return;
  94.                     }
  95.                     throw exception("&del_fail_too_late");
  96.                 }
  97.                 throw exception("&del_fail_not_deletable");
  98.             }
  99.         throw exception("&del_fail_no_such_addressee");
  100.     }
  101. };
  102.  
  103. map<const string, MessageList> client_message_list;
  104.  
  105. class Network {
  106. private:
  107.     SOCKET main_sock;
  108.     map<string, pair<sockaddr_in, SOCKET>> client_list;
  109.     string receive(const SOCKET sock) const {
  110.         char recv_buff[65536];
  111.         int len = recv(sock, &recv_buff[0], sizeof(recv_buff) - 1, 0);
  112.         if (len == -1)
  113.             throw wsa_exception("&wsa_error_recv");
  114.         recv_buff[len] = 0;
  115.         string s = recv_buff;
  116.         return s;
  117.     }
  118. public:
  119.     Network() {
  120.         WSAData wsadata;
  121.         WSAStartup(0x0202, &wsadata);
  122.         cout << "WinSock2 initialized" << endl;
  123.     }
  124.     ~Network() {
  125.         WSACleanup();
  126.     }
  127.     void start(const int &port) {
  128.         main_sock = socket(AF_INET, SOCK_STREAM, 0);
  129.         cout << "Main socket created successfully" << endl;
  130.         sockaddr_in addr_local;
  131.         addr_local.sin_family = AF_INET;
  132.         addr_local.sin_addr.S_un.S_addr = 0;
  133.         addr_local.sin_port = htons(port);
  134.         ::bind(main_sock, (sockaddr *)&addr_local, sizeof(addr_local));
  135.         cout << "Port " << ntohs(addr_local.sin_port) << " bound successful" << endl;
  136.         listen(main_sock, SOMAXCONN);
  137.         cout << "Listening port 5005" << endl;
  138.     }
  139.     void stop() {
  140.         for (auto pair : client_list) {
  141.             send(pair.first, "&server_stop");
  142.             closesocket(pair.second.second);
  143.         }
  144.         closesocket(main_sock);
  145.     }
  146.     void send(const string &num, const string &s) const {
  147.         ::send(client_list.at(num).second, s.c_str(), s.length(), 0);
  148.     }
  149.     string receive(const string &num) const {
  150.         char recv_buff[65536];
  151.         int len = recv(client_list.at(num).second, &recv_buff[0], sizeof(recv_buff) - 1, 0);
  152.         if (len == -1)
  153.             throw wsa_exception("&wsa_error_recv");
  154.         recv_buff[len] = 0;
  155.         string s = recv_buff;
  156.         return s;
  157.     }
  158.     string accept() {
  159.         sockaddr_in client_addr;
  160.         int client_addr_size = sizeof(client_addr);
  161.         SOCKET client_sock = ::accept(main_sock, (sockaddr *)&client_addr, &client_addr_size);
  162.         if (client_sock == INVALID_SOCKET)
  163.             throw wsa_exception("&wsa_error_accept");
  164.         string num;
  165.         try {
  166.             num = receive(client_sock);
  167.         }
  168.         catch (...) {
  169.             rethrow_exception;
  170.         }
  171.         cout << num << " connected" << endl;
  172.         client_list.try_emplace(num, make_pair(client_addr, client_sock));
  173.         return num;
  174.     }
  175. }network;
  176.  
  177. class Commands {
  178. private:
  179.     map<string, void(Commands::*)(const smatch &, const string &) const> command_list;
  180.     void sms(const smatch &input, const string &num) const {
  181.         if (input.str(3) == "-d") {
  182.             client_message_list.at(num).add(input.str(1), input.str(4), input.str(5), true);
  183.             cout << "Message from " << num << " to " << input.str(4) << " send success" << endl;
  184.         }
  185.         else {
  186.             client_message_list.at(num).add(input.str(1), input.str(3), input.str(4));
  187.             cout << "Message from " << num << " to " << input.str(3) << " send success" << endl;
  188.         }
  189.         network.send(num, "&sms_success");
  190.     }
  191.     void del(const smatch &input, const string &num) const {
  192.         try {
  193.             client_message_list.at(num).remove(input.str(1), input.str(3));
  194.         }
  195.         catch (exception e) {
  196.             cout << "Message from " << num << " to " << input.str(3) << " delete failed: " << e.what() << endl;
  197.             network.send(num, e.what());
  198.             return;
  199.         }
  200.         cout << "Message from " << num << " to " << input.str(3) << " delete success" << endl;
  201.         network.send(num, "&del_success");
  202.     }
  203. public:
  204.     Commands() {
  205.         command_list.emplace("sms", &Commands::sms);
  206.         command_list.emplace("del", &Commands::del);
  207.     }
  208.     void exec(const smatch &input, const string &num) const {
  209.         (this->*command_list.at(input.str(2)))(input, num);
  210.     }
  211. }commands;
  212.  
  213. void client_process(const string &num) {
  214.     client_message_list.try_emplace(num);
  215.     while (true) {
  216.         string s;
  217.         try {
  218.             s = network.receive(num);
  219.         }
  220.         catch (wsa_exception e) {
  221.             auto error = WSAGetLastError();
  222.             if (error == 0)
  223.                 break;
  224.             if (error != 10004 && error != 10053)
  225.                 cout << e.what() << error << endl;
  226.             return;
  227.         }
  228.         regex pattern(R"(^(\d+)\s(".+"|[.\S]+)\s*(".*"|[.\S]*)\s*(".*"|[.\S]*)\s*(".*"|[.\S]*)\s*$)");
  229.         smatch match_results;
  230.         regex_match(s, match_results, pattern);
  231.         commands.exec(match_results, num);
  232.     }
  233.     cout << num << " disconnected" << endl;
  234. }
  235.  
  236. void port_listen() {
  237.     while (true) {
  238.         string num;
  239.         try {
  240.             num = network.accept();
  241.         }
  242.         catch (wsa_exception e) {
  243.             if (e.code() != 0 && e.code() != 10004 && e.code() != 10053)
  244.                 cout << e.what() << endl;
  245.             return;
  246.         }
  247.         catch (exception e) {
  248.             cout << e.what() << endl;
  249.             return;
  250.         }
  251.         catch (...) {
  252.             cout << "exception was thrown" << endl;
  253.             return;
  254.         }
  255.         connected_clients_list.emplace_back(client_process, num);
  256.     }
  257. }
  258.  
  259. int main()
  260. {
  261.     cout << "cn-lab5 var10 server was started" << endl;
  262.     network.start(5005);
  263.     thread listen(port_listen);
  264.     string s;
  265.     do {
  266.         cin >> s;
  267.     } while (s != "stop" && s != "exit");
  268.  
  269.     network.stop();
  270.     if (listen.joinable())
  271.         listen.join();
  272.     for (auto i = 0; i < connected_clients_list.size(); i++)
  273.         if (connected_clients_list.at(i).joinable())
  274.             connected_clients_list.at(i).join();
  275.     cout << "cn-lab5 var10 server was stopped" << endl;
  276.     return 0;
  277. }
Advertisement
Add Comment
Please, Sign In to add comment