C   36

p4.c

Guest on 5th May 2022 11:00:27 PM

  1. #define _GNU_SOURCE
  2.  
  3. #include <arpa/inet.h>
  4. #include <netinet/in.h>
  5. #include <stdio.h>
  6. #include <string.h>
  7. #include <sys/epoll.h>
  8. #include <sys/socket.h>
  9. #include <sys/syscall.h>
  10. #include <unistd.h>
  11. #include <pthread.h>
  12. #include "common.h"
  13.  
  14. pid_t tid() {
  15.         return (pid_t)syscall(__NR_gettid) - getpid();
  16. }
  17.  
  18. struct fdinfo {
  19.         enum {
  20.                 LSOCK,
  21.                 CLIENT
  22.         } type;
  23.         int fd;
  24.         struct sockaddr_in sin;
  25. };
  26.  
  27. static void print_event(int fd, struct epoll_event ev) {
  28.         char flags_str[200];
  29.  
  30.         flags_str[0] = 0;
  31.         flags_str[1] = 0; /* dirty */
  32.  
  33.         if (ev.events & EPOLLIN )       strcat(flags_str, "|EPOLLIN");
  34.         if (ev.events & EPOLLOUT)       strcat(flags_str, "|EPOLLOUT");
  35.         if (ev.events & EPOLLERR)       strcat(flags_str, "|EPOLLERR");
  36.         if (ev.events & EPOLLHUP)       strcat(flags_str, "|EPOLLHUP");
  37.         if (ev.events & EPOLLRDHUP)     strcat(flags_str, "|EPOLLRDHUP");
  38.         if (ev.events & EPOLLPRI)       strcat(flags_str, "|EPOLLPRI");
  39.         if (ev.events & EPOLLET)        strcat(flags_str, "|EPOLLET");
  40.         if (ev.events & EPOLLONESHOT)   strcat(flags_str, "|EPOLLONESHOT");
  41.  
  42.         fprintf(stderr, "Event for fd %i. Flags=(%s).\n",
  43.                         fd, flags_str+1);
  44. }
  45.  
  46. int start_listener(int port);
  47. void service(int epfd);
  48.  
  49. void *service_wrap(void *arg) {
  50.         int epfd = *(int*)arg;
  51.  
  52.         service(epfd);
  53.  
  54.         return 0;
  55. }
  56.  
  57. int main () {
  58.         int epfd = epoll_create(1);
  59.         int lsock = start_listener(9000);
  60.         struct epoll_event ev;
  61.         struct fdinfo *fdinfo;
  62.         int ret;
  63.         int nthr = sysconf(_SC_NPROCESSORS_ONLN);
  64.         long i;
  65.         pthread_t *ths;
  66.  
  67.         ths = malloc(nthr * sizeof ths[1]);
  68.  
  69.         fdinfo = malloc(sizeof (struct fdinfo));
  70.         fdinfo->type = LSOCK;
  71.         fdinfo->fd = lsock;
  72.  
  73.         ev.data.ptr = fdinfo;
  74.         ev.events = EPOLLIN;
  75.  
  76.         ret = epoll_ctl(epfd, EPOLL_CTL_ADD, lsock, &ev);
  77.         if (ret < 0)
  78.                 die("epoll_ctl.1");
  79.  
  80.         for (i = 0; i<nthr; i++)
  81.                 pthread_create(&ths[i], NULL, service_wrap, &epfd);
  82.  
  83.         for (i = 0; i<nthr; i++)
  84.                 pthread_join(ths[i], NULL);
  85.  
  86.         close(epfd);
  87.  
  88.         return 0;
  89. }
  90.  
  91. int start_listener(int port) {
  92.         struct sockaddr_in listen_addr;
  93.         int lsock;
  94.         int ret;
  95.  
  96.         lsock = socket(AF_INET, SOCK_STREAM, 0);
  97.         if (lsock < 0)
  98.                 die("socket");
  99.  
  100.         memset(&listen_addr, 0, sizeof listen_addr);
  101.         listen_addr.sin_family = AF_INET;
  102.         listen_addr.sin_port = htons(port);
  103.         listen_addr.sin_addr.s_addr = INADDR_ANY;
  104.  
  105.         ret = bind(lsock, (sad*)&listen_addr, sizeof listen_addr);
  106.         if (ret < 0)
  107.                 die("bind");
  108.  
  109.         ret = listen(lsock, 10);
  110.         if (ret < 0)
  111.                 die("listen");
  112.  
  113.         return lsock;
  114. }
  115.  
  116. void accept_one(int epfd, int lsock) {
  117.         int cli;
  118.         struct fdinfo *fdinfo;
  119.         struct epoll_event ev;
  120.         socklen_t crap = sizeof fdinfo->sin;
  121.         int ret;
  122.  
  123.         fdinfo = malloc(sizeof *fdinfo);
  124.  
  125.         cli = accept4(lsock, (sad*)&fdinfo->sin, &crap, SOCK_NONBLOCK);
  126.         if (cli < 0)
  127.                 die("accept");
  128.  
  129.         fdinfo->fd = cli;
  130.         fdinfo->type = CLIENT;
  131.  
  132.         ev.data.ptr = fdinfo;
  133.         ev.events = EPOLLIN | EPOLLRDHUP | EPOLLET | EPOLLONESHOT;
  134.  
  135.         ret = epoll_ctl(epfd, EPOLL_CTL_ADD, cli, &ev);
  136.         if (ret < 0)
  137.                 die("epoll_ctl.2");
  138. }
  139.  
  140. void handle_cli(struct fdinfo *fdinfo) {
  141.         int fd = fdinfo->fd;
  142.         int t;
  143.         char buf1[101], buf2[101];
  144.  
  145.         inet_ntop(AF_INET, &fdinfo->sin.sin_addr, buf1, sizeof fdinfo->sin);
  146.         /*
  147.          * Leemos y hacemos echo de todo lo que haya,
  148.          * hasta que la lectura falle (EAGAIN)
  149.          */
  150.         do {
  151.                 buf2[0] = 0;
  152.                 t = read(fd, buf2, 100);
  153.                 if (t > 0) {
  154.                         buf2[t] = 0;
  155.                         printf("%s mandĆ³ %s\n"n", buf1, buf2);
  156.                 }
  157.                 write(fd, buf2, t);
  158.         } while (t > 0);
  159. }
  160.  
  161. void kill_cli(int epfd, struct fdinfo *fdinfo) {
  162.         char buf[100];
  163.         int fd = fdinfo->fd;
  164.         free(fdinfo);
  165.  
  166.         inet_ntop(AF_INET, &fdinfo->sin.sin_addr, buf, sizeof fdinfo->sin);
  167.  
  168.         printf("%i: Chau %s!\n", tid(), buf);
  169.  
  170.         epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
  171.         close(fd);
  172. }
  173.  
  174. void handle_event(int epfd, struct epoll_event ev) {
  175.         struct fdinfo *fdinfo = ev.data.ptr;
  176.  
  177.         switch (fdinfo->type) {
  178.         case LSOCK:
  179.                 accept_one(epfd, fdinfo->fd);
  180.                 break;
  181.         case CLIENT:
  182.                 print_event(fdinfo->fd, ev);
  183.                 if (ev.events & EPOLLHUP) {
  184.                         kill_cli(epfd, fdinfo);
  185.                         return;
  186.                 }
  187.  
  188.                 if (ev.events & EPOLLIN) {
  189.                         handle_cli(fdinfo);
  190.                 }
  191.  
  192.                 if (ev.events & EPOLLRDHUP)  {
  193.                         handle_cli(fdinfo);
  194.                         kill_cli(epfd, fdinfo);
  195.                         return;
  196.                 }
  197.  
  198.                 struct epoll_event ev;
  199.                 ev.events = EPOLLIN | EPOLLRDHUP | EPOLLET | EPOLLONESHOT;
  200.                 ev.data.ptr = fdinfo;
  201.                 if (epoll_ctl(epfd, EPOLL_CTL_MOD, fdinfo->fd, &ev) < 0)
  202.                         die("epoll_ctl.3");
  203.  
  204.                 break;
  205.         }
  206. }
  207.  
  208. void service(int epfd) {
  209.         int i, n;
  210.         struct epoll_event evs[10];
  211.  
  212.         for (;;) {
  213.                 n = epoll_wait(epfd, evs, 10, 5000);
  214.  
  215.                 if (n < 0)
  216.                         die("epoll_wait");
  217.  
  218.                 if (n == 0) {
  219.                         printf("%i: Que aburrimiento che....\n", tid());
  220.                         continue;
  221.                 }
  222.  
  223.                 for (i=0; i<n; i++)
  224.                         handle_event(epfd, evs[i]);
  225.         }

Raw Paste


Login or Register to edit or fork this paste. It's free.