Advertisement
Guest User

nonblocking multithreaded EPOLLONESHOT

a guest
Aug 21st, 2019
281
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 3.48 KB | None | 0 0
  1. #define _GNU_SOURCE
  2. #include <stdio.h>
  3. #include <errno.h>
  4. #include <string.h>
  5. #include <unistd.h>
  6. #include <pthread.h>
  7. #include <sys/epoll.h>
  8. #include <sys/socket.h>
  9. #include <netinet/in.h>
  10. #include <netinet/tcp.h>
  11. #include <sys/sysinfo.h>
  12.  
  13. #define NUM_EVENTS 64
  14. #define READ_BUFFER (64 * 1024)
  15. #define RESPONSE "HTTP/1.1 200 Ok\r\nContent-Length: 11\r\n\r\nHello World"
  16.  
  17. int find_clrf(const char* buffer, int len) {
  18.     const char* start_buffer = buffer;
  19.     for (; len >= sizeof(int); len--, buffer++)
  20.         if (*((int*)buffer) == *(int*)"\r\n\r\n")
  21.             return buffer - start_buffer;
  22.     return -1;
  23. }
  24.  
  25. int efd, server;
  26. void* worker(void* arg) {
  27.     char buffer[READ_BUFFER];
  28.     struct epoll_event events[NUM_EVENTS];
  29.  
  30.     while (1) {
  31.         int opt, n = epoll_wait(efd, events, NUM_EVENTS, -1);
  32.         for (int i = 0; i < n; i++) {
  33.             int fd = events[i].data.fd;
  34.             if (events[i].events & (EPOLLHUP | EPOLLERR)) {
  35.                 close(events[i].data.fd);
  36.             } else if (fd == server) {
  37.                 while ((fd = accept4(server, NULL, NULL, SOCK_NONBLOCK)) > 0) {
  38.                     opt = 1;
  39.                     events[i].data.fd = fd;
  40.                     events[i].events = EPOLLIN | EPOLLONESHOT;
  41.                     if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) < 0) perror("no delay");
  42.                     if (epoll_ctl(efd, EPOLL_CTL_ADD, fd, &events[i]) < 0) perror("epoll add client");
  43.                 }
  44.                 events[i].data.fd = server;
  45.                 events[i].events = EPOLLIN | EPOLLONESHOT;
  46.                 if (epoll_ctl(efd, EPOLL_CTL_MOD, server, &events[i]) < 0) perror("epoll rearm server");
  47.             } else {
  48.                 int bytes, offset = 0;
  49.                 while ((bytes = read(fd, buffer + offset, READ_BUFFER - offset)) > 0) {
  50.                     int clrf_offset = 0;
  51.                     while ((clrf_offset = find_clrf(buffer + clrf_offset + offset, bytes)) != -1)
  52.                         if (send(fd, RESPONSE, sizeof(RESPONSE) - 1, MSG_NOSIGNAL) == -1)
  53.                             break;
  54.                     offset += bytes;
  55.                 }
  56.                 if (bytes == 0 || (bytes == -1 && errno != EAGAIN)) {
  57.                     close(fd);
  58.                 } else {
  59.                     events[i].data.fd = fd;
  60.                     events[i].events = EPOLLIN | EPOLLONESHOT;
  61.                     if (epoll_ctl(efd, EPOLL_CTL_MOD, fd, &events[i]) < 0) close(fd);
  62.                 }
  63.             }
  64.         }
  65.     }
  66. }
  67.  
  68. int main() {
  69.     int opt = 1;
  70.     server = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
  71.     if (server < 0) perror("socket create");
  72.     if (setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) perror("reuse addr");
  73.  
  74.     struct sockaddr_in addr;
  75.     addr.sin_family = AF_INET;
  76.     addr.sin_port = htons(12345);
  77.     addr.sin_addr.s_addr = htonl(INADDR_ANY);
  78.     if (bind(server, (struct sockaddr*)&addr, sizeof(addr)) < 0) perror("bind");
  79.     if (listen(server, SOMAXCONN) < 0) perror("listen");
  80.  
  81.     efd = epoll_create1(0);
  82.     if (efd < 0) perror("epoll");
  83.     struct epoll_event event;
  84.     event.events = EPOLLIN | EPOLLONESHOT;
  85.     event.data.fd = server;
  86.     if (epoll_ctl(efd, EPOLL_CTL_ADD, server, &event) < 0) perror("epoll add server");
  87.  
  88.     pthread_t thread;
  89.     for (int i = get_nprocs() - 1; i > 0; i--)
  90.         if (pthread_create(&thread, NULL, worker, NULL) != 0)
  91.             perror("create thread");
  92.     worker(NULL);
  93. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement