Advertisement
Guest User

Untitled

a guest
Jul 18th, 2017
157
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.66 KB | None | 0 0
  1. #include <sys/mman.h>
  2. #include <sys/types.h>
  3. #include <sys/socket.h>
  4. #include <netinet/in.h>
  5. #include <netinet/tcp.h>
  6. #include <unistd.h>
  7. #include <sched.h>
  8. #include <exception>
  9. #include <string.h>
  10. #include <sys/epoll.h>
  11. #include <iostream>
  12. #include <array>
  13. #include <vector>
  14. #include <openssl/md5.h>
  15.  
  16. #define PCKT_SZ 1024
  17.  
  18. int safe_call(int ret, const char * ctx) {
  19. //   fprintf(stderr, "%s == %d, errno(%d) == %s\n", ctx, ret, errno, strerror(errno));
  20.   if((ret == -1) && (errno != EINPROGRESS)) throw std::runtime_error(std::string(ctx) +  " == " + std::to_string(ret) + ", errno(" + std::to_string(errno) + ')'  + " == " + strerror(errno));
  21.   return ret;
  22. }
  23. #define safe_call(call) safe_call(call, #call)
  24.  
  25. int connect_to(in_addr_t addr, uint16_t port) {
  26.   sockaddr_in saddr{};
  27.   saddr.sin_family = AF_INET;
  28.   saddr.sin_port = htons(port);
  29.   saddr.sin_addr.s_addr = htonl(addr);
  30.   int fd = safe_call(socket(AF_INET, SOCK_NONBLOCK | SOCK_STREAM, 0));
  31.   safe_call(connect(fd, (__CONST_SOCKADDR_ARG)&saddr, sizeof(saddr)));
  32.   return fd;
  33. }
  34.  
  35.  
  36.  
  37.  
  38. class alignas(64) client {
  39. public:
  40.  
  41.  
  42.   void connect(in_addr_t addr, uint16_t port) {
  43. //     fprintf(stderr, "%s\n", __PRETTY_FUNCTION__);
  44.     this->addr = addr;
  45.     this->port = port;
  46.     fd = connect_to(addr, port);
  47.     add_to_epoll();
  48.     ++active_connections;
  49.   }
  50.  
  51.  
  52.  
  53.   void close() {
  54. //     fprintf(stderr, "%s\n", __PRETTY_FUNCTION__);
  55.     remove_from_epoll();
  56.     safe_call(::close(fd));
  57.     --active_connections;
  58.   }
  59.  
  60.   size_t get_rq() {
  61.     return count;
  62.   }
  63.  
  64.   client() = default;
  65.   client(client && o) = delete;
  66.   client(client & o) = delete;
  67.   client & operator=(const client & o) = delete;  
  68.   client & operator=(client && o) = delete;
  69.   ~client() = default;
  70.  
  71.  
  72.   void run() {
  73.     // fprintf(stderr, "%s\n", __PRETTY_FUNCTION__);
  74.     safe_call(write(fd, req_buf, sizeof(req_buf)));
  75.     update_events(EPOLLIN | EPOLLRDHUP | EPOLLET);
  76.   }
  77.  
  78.  
  79. protected:
  80.  
  81.   void add_to_epoll() {
  82.     epoll_event eevent;
  83.     eevent.events = EPOLLIN | EPOLLOUT | EPOLLRDHUP | EPOLLET;
  84.     eevent.data.ptr = (void *)this;
  85.     safe_call(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &eevent));
  86.   }
  87.  
  88.   void update_events(uint32_t ev) {
  89.     epoll_event eevent;
  90.     eevent.events = ev;
  91.     eevent.data.ptr = (void *)this;
  92.     safe_call(epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &eevent));
  93.   }
  94.  
  95.   void remove_from_epoll() {
  96.     safe_call(epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, nullptr));
  97.   }
  98.  
  99.   void update_next() {
  100.     // fprintf(stderr, "%s\n", __PRETTY_FUNCTION__);
  101.     if (memcmp(req_buf_md5, buff, MD5_DIGEST_LENGTH) != 0)
  102.         throw std::runtime_error{"bad data"};
  103.     buff_cur = 0; memset(buff, 0, sizeof(buff)); ++count;
  104.   }
  105.  
  106.   void update_buff() {
  107.     // fprintf(stderr, "%s\n", __PRETTY_FUNCTION__);
  108.     while(ssize_t r = read(fd, buff, (sizeof(buff) - buff_cur))) {
  109.       if(r == -1) return;
  110.       buff_cur += r;
  111.       if(buff_cur == sizeof(buff)) update_next();
  112.     }
  113.   }
  114.  
  115. protected:
  116.   in_addr_t addr;
  117.   uint16_t port;
  118.   int fd;
  119.   size_t buff_cur = 0, count = 0;
  120.   uint8_t buff[PCKT_SZ];
  121.  
  122.   static inline uint8_t req_buf[PCKT_SZ];
  123.   static inline uint8_t req_buf_md5[MD5_DIGEST_LENGTH];
  124. protected:
  125.   static constexpr size_t epoll_size = 1024, epoll_event_size = 1024;
  126.   static inline int epoll_fd = safe_call(epoll_create(epoll_size));
  127.   static inline std::array<epoll_event, epoll_event_size> edata;
  128.   static inline size_t active_connections = 0;
  129.  
  130. public:
  131.  
  132.   static void req_buf_init() {
  133.       srand(time(NULL));
  134.       for (auto & x : req_buf)
  135.           x = (uint8_t)rand();
  136.       MD5(req_buf, sizeof(req_buf), req_buf_md5);
  137.   }
  138.   static void run(size_t timeout) {
  139.    
  140.     while(1) {
  141.       size_t n = safe_call(epoll_wait(epoll_fd, std::begin(edata), edata.size(), timeout));
  142.      
  143.       if(!active_connections) return;
  144.      
  145.       for(auto it = std::begin(edata), end = it + n; it < end; ++it) {
  146.         ((client *)(it->data.ptr))->wait_handler(it->events);
  147.       }
  148.     }
  149.   }
  150. protected:
  151.  
  152.   void wait_handler(uint32_t events) try {
  153. //     fprintf(stderr, "%s, events == %x\n", __PRETTY_FUNCTION__, events);
  154.      
  155.     if(events & EPOLLOUT) run();
  156.     if(events & EPOLLIN) update_buff();  
  157.     if(events & EPOLLRDHUP) close();
  158.   } catch(const std::exception & e) { std::cerr << e.what() << std::endl; std::terminate();}
  159. };
  160.  
  161.  
  162. int main() {
  163.   in_addr_t addr = INADDR_LOOPBACK; uint16_t port = 8888;
  164.   client::req_buf_init();
  165.   std::vector<client> v(10000);
  166.   for(auto & x : v) x.connect(addr, port);
  167.  
  168.  
  169.   client::run(50);
  170.  
  171.   size_t rq = 0;
  172.  
  173.   for(auto & x : v) rq += x.get_rq();
  174.  
  175.   fprintf(stderr, "rq = %lu\n", rq);
  176. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement