single-threaded.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #define WEB_SERVER_INTERNALS 1
  3. #include "single-threaded.h"
  4. // --------------------------------------------------------------------------------------
  5. // the main socket listener - SINGLE-THREADED
  6. struct web_client *single_threaded_clients[FD_SETSIZE];
  7. static inline int single_threaded_link_client(struct web_client *w, fd_set *ifds, fd_set *ofds, fd_set *efds, int *max) {
  8. if(unlikely(web_client_check_dead(w) || (!web_client_has_wait_receive(w) && !web_client_has_wait_send(w)))) {
  9. return 1;
  10. }
  11. if(unlikely(w->ifd < 0 || w->ifd >= (int)FD_SETSIZE || w->ofd < 0 || w->ofd >= (int)FD_SETSIZE)) {
  12. error("%llu: invalid file descriptor, ifd = %d, ofd = %d (required 0 <= fd < FD_SETSIZE (%d)", w->id, w->ifd, w->ofd, (int)FD_SETSIZE);
  13. return 1;
  14. }
  15. FD_SET(w->ifd, efds);
  16. if(unlikely(*max < w->ifd)) *max = w->ifd;
  17. if(unlikely(w->ifd != w->ofd)) {
  18. if(*max < w->ofd) *max = w->ofd;
  19. FD_SET(w->ofd, efds);
  20. }
  21. if(web_client_has_wait_receive(w)) FD_SET(w->ifd, ifds);
  22. if(web_client_has_wait_send(w)) FD_SET(w->ofd, ofds);
  23. single_threaded_clients[w->ifd] = w;
  24. single_threaded_clients[w->ofd] = w;
  25. return 0;
  26. }
  27. static inline int single_threaded_unlink_client(struct web_client *w, fd_set *ifds, fd_set *ofds, fd_set *efds) {
  28. FD_CLR(w->ifd, efds);
  29. if(unlikely(w->ifd != w->ofd)) FD_CLR(w->ofd, efds);
  30. if(web_client_has_wait_receive(w)) FD_CLR(w->ifd, ifds);
  31. if(web_client_has_wait_send(w)) FD_CLR(w->ofd, ofds);
  32. single_threaded_clients[w->ifd] = NULL;
  33. single_threaded_clients[w->ofd] = NULL;
  34. if(unlikely(web_client_check_dead(w) || (!web_client_has_wait_receive(w) && !web_client_has_wait_send(w)))) {
  35. return 1;
  36. }
  37. return 0;
  38. }
  39. static void socket_listen_main_single_threaded_cleanup(void *data) {
  40. struct netdata_static_thread *static_thread = (struct netdata_static_thread *)data;
  41. static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
  42. info("closing all sockets...");
  43. listen_sockets_close(&api_sockets);
  44. info("freeing web clients cache...");
  45. web_client_cache_destroy();
  46. info("cleanup completed.");
  47. static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
  48. }
  49. void *socket_listen_main_single_threaded(void *ptr) {
  50. netdata_thread_cleanup_push(socket_listen_main_single_threaded_cleanup, ptr);
  51. web_server_mode = WEB_SERVER_MODE_SINGLE_THREADED;
  52. web_server_is_multithreaded = 0;
  53. struct web_client *w;
  54. if(!api_sockets.opened)
  55. fatal("LISTENER: no listen sockets available.");
  56. size_t i;
  57. for(i = 0; i < (size_t)FD_SETSIZE ; i++)
  58. single_threaded_clients[i] = NULL;
  59. fd_set ifds, ofds, efds, rifds, rofds, refds;
  60. FD_ZERO (&ifds);
  61. FD_ZERO (&ofds);
  62. FD_ZERO (&efds);
  63. int fdmax = 0;
  64. for(i = 0; i < api_sockets.opened ; i++) {
  65. if (api_sockets.fds[i] < 0 || api_sockets.fds[i] >= (int)FD_SETSIZE)
  66. fatal("LISTENER: Listen socket %d is not ready, or invalid.", api_sockets.fds[i]);
  67. info("Listening on '%s'", (api_sockets.fds_names[i])?api_sockets.fds_names[i]:"UNKNOWN");
  68. FD_SET(api_sockets.fds[i], &ifds);
  69. FD_SET(api_sockets.fds[i], &efds);
  70. if(fdmax < api_sockets.fds[i])
  71. fdmax = api_sockets.fds[i];
  72. }
  73. while(!netdata_exit) {
  74. debug(D_WEB_CLIENT_ACCESS, "LISTENER: single threaded web server waiting (fdmax = %d)...", fdmax);
  75. struct timeval tv = { .tv_sec = 1, .tv_usec = 0 };
  76. rifds = ifds;
  77. rofds = ofds;
  78. refds = efds;
  79. int retval = select(fdmax+1, &rifds, &rofds, &refds, &tv);
  80. if(unlikely(retval == -1)) {
  81. error("LISTENER: select() failed.");
  82. continue;
  83. }
  84. else if(likely(retval)) {
  85. debug(D_WEB_CLIENT_ACCESS, "LISTENER: got something.");
  86. for(i = 0; i < api_sockets.opened ; i++) {
  87. if (FD_ISSET(api_sockets.fds[i], &rifds)) {
  88. debug(D_WEB_CLIENT_ACCESS, "LISTENER: new connection.");
  89. w = web_client_create_on_listenfd(api_sockets.fds[i]);
  90. if(unlikely(!w))
  91. continue;
  92. if(api_sockets.fds_families[i] == AF_UNIX)
  93. web_client_set_unix(w);
  94. else
  95. web_client_set_tcp(w);
  96. if (single_threaded_link_client(w, &ifds, &ofds, &ifds, &fdmax) != 0) {
  97. web_client_release(w);
  98. }
  99. }
  100. }
  101. for(i = 0 ; i <= (size_t)fdmax ; i++) {
  102. if(likely(!FD_ISSET(i, &rifds) && !FD_ISSET(i, &rofds) && !FD_ISSET(i, &refds)))
  103. continue;
  104. w = single_threaded_clients[i];
  105. if(unlikely(!w)) {
  106. // error("no client on slot %zu", i);
  107. continue;
  108. }
  109. if(unlikely(single_threaded_unlink_client(w, &ifds, &ofds, &efds) != 0)) {
  110. // error("failed to unlink client %zu", i);
  111. web_client_release(w);
  112. continue;
  113. }
  114. if (unlikely(FD_ISSET(w->ifd, &refds) || FD_ISSET(w->ofd, &refds))) {
  115. // error("no input on client %zu", i);
  116. web_client_release(w);
  117. continue;
  118. }
  119. if (unlikely(web_client_has_wait_receive(w) && FD_ISSET(w->ifd, &rifds))) {
  120. if (unlikely(web_client_receive(w) < 0)) {
  121. // error("cannot read from client %zu", i);
  122. web_client_release(w);
  123. continue;
  124. }
  125. if (w->mode != WEB_CLIENT_MODE_FILECOPY) {
  126. debug(D_WEB_CLIENT, "%llu: Processing received data.", w->id);
  127. web_client_process_request(w);
  128. }
  129. }
  130. if (unlikely(web_client_has_wait_send(w) && FD_ISSET(w->ofd, &rofds))) {
  131. if (unlikely(web_client_send(w) < 0)) {
  132. // error("cannot send data to client %zu", i);
  133. debug(D_WEB_CLIENT, "%llu: Cannot send data to client. Closing client.", w->id);
  134. web_client_release(w);
  135. continue;
  136. }
  137. }
  138. if(unlikely(single_threaded_link_client(w, &ifds, &ofds, &efds, &fdmax) != 0)) {
  139. // error("failed to link client %zu", i);
  140. web_client_release(w);
  141. }
  142. }
  143. }
  144. else {
  145. debug(D_WEB_CLIENT_ACCESS, "LISTENER: single threaded web server timeout.");
  146. }
  147. }
  148. netdata_thread_cleanup_pop(1);
  149. return NULL;
  150. }