epoll_socket.c 6.7 KB

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