epoll_socket.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. /* -*- mode:c; c-file-style:"k&r"; c-basic-offset: 4; tab-width:4;
  2. * indent-tabs-mode:nil; mode:auto-fill; fill-column:78; -*- */
  3. /* vim: set ts=4 sw=4 et tw=78 fo=cqt wm=0: */
  4. // Copied from
  5. // https://banu.com/blog/2/how-to-use-epoll-a-complete-example-in-c/epoll-example.c
  6. // Meant to be used for edge triggered epoll
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <sys/types.h>
  11. #include <sys/socket.h>
  12. #include <netdb.h>
  13. #include <unistd.h>
  14. #include <fcntl.h>
  15. #include <sys/epoll.h>
  16. #include <errno.h>
  17. #define MAXEVENTS 64
  18. static int
  19. make_socket_non_blocking (int sfd)
  20. {
  21. int flags, s;
  22. flags = fcntl (sfd, F_GETFL, 0);
  23. if (flags == -1)
  24. {
  25. perror ("fcntl");
  26. return -1;
  27. }
  28. flags |= O_NONBLOCK;
  29. s = fcntl (sfd, F_SETFL, flags);
  30. if (s == -1)
  31. {
  32. perror ("fcntl");
  33. return -1;
  34. }
  35. return 0;
  36. }
  37. static int
  38. create_and_bind (char *port)
  39. {
  40. struct addrinfo hints;
  41. struct addrinfo *result, *rp;
  42. int s, sfd;
  43. memset (&hints, 0, sizeof (struct addrinfo));
  44. hints.ai_family = AF_UNSPEC; /* Return IPv4 and IPv6 choices */
  45. hints.ai_socktype = SOCK_STREAM; /* We want a TCP socket */
  46. hints.ai_flags = AI_PASSIVE; /* All interfaces */
  47. s = getaddrinfo (NULL, port, &hints, &result);
  48. if (s != 0)
  49. {
  50. fprintf (stderr, "getaddrinfo: %s\n", gai_strerror (s));
  51. return -1;
  52. }
  53. for (rp = result; rp != NULL; rp = rp->ai_next)
  54. {
  55. sfd = socket (rp->ai_family, rp->ai_socktype, rp->ai_protocol);
  56. if (sfd == -1)
  57. continue;
  58. s = bind (sfd, rp->ai_addr, rp->ai_addrlen);
  59. if (s == 0)
  60. {
  61. /* We managed to bind successfully! */
  62. break;
  63. }
  64. close (sfd);
  65. }
  66. if (rp == NULL)
  67. {
  68. fprintf (stderr, "Could not bind\n");
  69. return -1;
  70. }
  71. freeaddrinfo (result);
  72. return sfd;
  73. }
  74. int
  75. main (int argc, char *argv[])
  76. {
  77. int sfd, s;
  78. int efd;
  79. struct epoll_event event;
  80. struct epoll_event *events;
  81. if (argc != 2)
  82. {
  83. fprintf (stderr, "Usage: %s [port]\n", argv[0]);
  84. exit (EXIT_FAILURE);
  85. }
  86. sfd = create_and_bind (argv[1]);
  87. if (sfd == -1)
  88. abort ();
  89. s = make_socket_non_blocking (sfd);
  90. if (s == -1)
  91. abort ();
  92. s = listen (sfd, SOMAXCONN);
  93. if (s == -1)
  94. {
  95. perror ("listen");
  96. abort ();
  97. }
  98. efd = epoll_create1 (0);
  99. if (efd == -1)
  100. {
  101. perror ("epoll_create");
  102. abort ();
  103. }
  104. event.data.fd = sfd;
  105. event.events = EPOLLIN | EPOLLET;
  106. s = epoll_ctl (efd, EPOLL_CTL_ADD, sfd, &event);
  107. if (s == -1)
  108. {
  109. perror ("epoll_ctl");
  110. abort ();
  111. }
  112. /* Buffer where events are returned */
  113. events = calloc (MAXEVENTS, sizeof event);
  114. /* The event loop */
  115. while (1)
  116. {
  117. int n, i;
  118. n = epoll_wait (efd, events, MAXEVENTS, -1);
  119. for (i = 0; i < n; i++)
  120. {
  121. if ((events[i].events & EPOLLERR) ||
  122. (events[i].events & EPOLLHUP) ||
  123. (!(events[i].events & EPOLLIN)))
  124. {
  125. /* An error has occured on this fd, or the socket is not
  126. ready for reading (why were we notified then?) */
  127. fprintf (stderr, "epoll error\n");
  128. close (events[i].data.fd);
  129. continue;
  130. }
  131. else if (sfd == events[i].data.fd)
  132. {
  133. /* We have a notification on the listening socket, which
  134. means one or more incoming connections. */
  135. while (1)
  136. {
  137. struct sockaddr in_addr;
  138. socklen_t in_len;
  139. int infd;
  140. char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
  141. in_len = sizeof in_addr;
  142. infd = accept (sfd, &in_addr, &in_len);
  143. if (infd == -1)
  144. {
  145. if ((errno == EAGAIN) ||
  146. (errno == EWOULDBLOCK))
  147. {
  148. /* We have processed all incoming
  149. connections. */
  150. break;
  151. }
  152. else
  153. {
  154. perror ("accept");
  155. break;
  156. }
  157. }
  158. s = getnameinfo (&in_addr, in_len,
  159. hbuf, sizeof hbuf,
  160. sbuf, sizeof sbuf,
  161. NI_NUMERICHOST | NI_NUMERICSERV);
  162. if (s == 0)
  163. {
  164. printf("Accepted connection on descriptor %d "
  165. "(host=%s, port=%s)\n", infd, hbuf, sbuf);
  166. }
  167. /* Make the incoming socket non-blocking and add it to the
  168. list of fds to monitor. */
  169. s = make_socket_non_blocking (infd);
  170. if (s == -1)
  171. abort ();
  172. event.data.fd = infd;
  173. event.events = EPOLLIN | EPOLLET;
  174. s = epoll_ctl (efd, EPOLL_CTL_ADD, infd, &event);
  175. if (s == -1)
  176. {
  177. perror ("epoll_ctl");
  178. abort ();
  179. }
  180. }
  181. continue;
  182. }
  183. else
  184. {
  185. /* We have data on the fd waiting to be read. Read and
  186. display it. We must read whatever data is available
  187. completely, as we are running in edge-triggered mode
  188. and won't get a notification again for the same
  189. data. */
  190. int done = 0;
  191. while (1)
  192. {
  193. ssize_t count;
  194. char buf[512];
  195. count = read (events[i].data.fd, buf, sizeof buf);
  196. if (count == -1)
  197. {
  198. /* If errno == EAGAIN, that means we have read all
  199. data. So go back to the main loop. */
  200. if (errno != EAGAIN)
  201. {
  202. perror ("read");
  203. done = 1;
  204. }
  205. break;
  206. }
  207. else if (count == 0)
  208. {
  209. /* End of file. The remote has closed the
  210. connection. */
  211. done = 1;
  212. break;
  213. }
  214. /* Write the buffer to standard output */
  215. s = write (1, buf, count);
  216. if (s == -1)
  217. {
  218. perror ("write");
  219. abort ();
  220. }
  221. }
  222. if (done)
  223. {
  224. printf ("Closed connection on descriptor %d\n",
  225. events[i].data.fd);
  226. /* Closing the descriptor will make epoll remove it
  227. from the set of descriptors which are monitored. */
  228. close (events[i].data.fd);
  229. }
  230. }
  231. }
  232. }
  233. free (events);
  234. close (sfd);
  235. return EXIT_SUCCESS;
  236. }