server.hpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. #pragma once
  2. #include <nall/service.hpp>
  3. #include <nall/http/role.hpp>
  4. namespace nall::HTTP {
  5. struct Server : Role, service {
  6. inline auto open(uint port = 8080, const string& serviceName = "", const string& command = "") -> bool;
  7. inline auto main(const function<Response (Request&)>& function = {}) -> void;
  8. inline auto scan() -> string;
  9. inline auto close() -> void;
  10. ~Server() { close(); }
  11. private:
  12. function<Response (Request&)> callback;
  13. std::atomic<int> connections{0};
  14. int fd4 = -1;
  15. int fd6 = -1;
  16. struct sockaddr_in addrin4 = {0};
  17. struct sockaddr_in6 addrin6 = {0};
  18. auto ipv4() const -> bool { return fd4 >= 0; }
  19. auto ipv6() const -> bool { return fd6 >= 0; }
  20. auto ipv4_close() -> void { if(fd4 >= 0) ::close(fd4); fd4 = -1; }
  21. auto ipv6_close() -> void { if(fd6 >= 0) ::close(fd6); fd6 = -1; }
  22. auto ipv4_scan() -> bool;
  23. auto ipv6_scan() -> bool;
  24. };
  25. auto Server::open(uint port, const string& serviceName, const string& command) -> bool {
  26. if(serviceName) {
  27. if(!service::command(serviceName, command)) return false;
  28. }
  29. fd4 = socket(AF_INET, SOCK_STREAM, 0);
  30. fd6 = socket(AF_INET6, SOCK_STREAM, 0);
  31. if(!ipv4() && !ipv6()) return false;
  32. {
  33. #if defined(SO_RCVTIMEO)
  34. if(settings.timeoutReceive) {
  35. struct timeval rcvtimeo;
  36. rcvtimeo.tv_sec = settings.timeoutReceive / 1000;
  37. rcvtimeo.tv_usec = settings.timeoutReceive % 1000 * 1000;
  38. if(ipv4()) setsockopt(fd4, SOL_SOCKET, SO_RCVTIMEO, &rcvtimeo, sizeof(struct timeval));
  39. if(ipv6()) setsockopt(fd6, SOL_SOCKET, SO_RCVTIMEO, &rcvtimeo, sizeof(struct timeval));
  40. }
  41. #endif
  42. #if defined(SO_SNDTIMEO)
  43. if(settings.timeoutSend) {
  44. struct timeval sndtimeo;
  45. sndtimeo.tv_sec = settings.timeoutSend / 1000;
  46. sndtimeo.tv_usec = settings.timeoutSend % 1000 * 1000;
  47. if(ipv4()) setsockopt(fd4, SOL_SOCKET, SO_SNDTIMEO, &sndtimeo, sizeof(struct timeval));
  48. if(ipv6()) setsockopt(fd6, SOL_SOCKET, SO_SNDTIMEO, &sndtimeo, sizeof(struct timeval));
  49. }
  50. #endif
  51. #if defined(SO_NOSIGPIPE) //BSD, OSX
  52. int nosigpipe = 1;
  53. if(ipv4()) setsockopt(fd4, SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe, sizeof(int));
  54. if(ipv6()) setsockopt(fd6, SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe, sizeof(int));
  55. #endif
  56. #if defined(SO_REUSEADDR) //BSD, Linux, OSX
  57. int reuseaddr = 1;
  58. if(ipv4()) setsockopt(fd4, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(int));
  59. if(ipv6()) setsockopt(fd6, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(int));
  60. #endif
  61. #if defined(SO_REUSEPORT) //BSD, OSX
  62. int reuseport = 1;
  63. if(ipv4()) setsockopt(fd4, SOL_SOCKET, SO_REUSEPORT, &reuseport, sizeof(int));
  64. if(ipv6()) setsockopt(fd6, SOL_SOCKET, SO_REUSEPORT, &reuseport, sizeof(int));
  65. #endif
  66. }
  67. addrin4.sin_family = AF_INET;
  68. addrin4.sin_addr.s_addr = htonl(INADDR_ANY);
  69. addrin4.sin_port = htons(port);
  70. addrin6.sin6_family = AF_INET6;
  71. addrin6.sin6_addr = in6addr_any;
  72. addrin6.sin6_port = htons(port);
  73. if(bind(fd4, (struct sockaddr*)&addrin4, sizeof(addrin4)) < 0 || listen(fd4, SOMAXCONN) < 0) ipv4_close();
  74. if(bind(fd6, (struct sockaddr*)&addrin6, sizeof(addrin6)) < 0 || listen(fd6, SOMAXCONN) < 0) ipv6_close();
  75. return ipv4() || ipv6();
  76. }
  77. auto Server::main(const function<Response (Request&)>& function) -> void {
  78. callback = function;
  79. }
  80. auto Server::scan() -> string {
  81. if(auto command = service::receive()) return command;
  82. if(connections >= settings.connectionLimit) return "busy";
  83. if(ipv4() && ipv4_scan()) return "ok";
  84. if(ipv6() && ipv6_scan()) return "ok";
  85. return "idle";
  86. }
  87. auto Server::ipv4_scan() -> bool {
  88. struct pollfd query = {0};
  89. query.fd = fd4;
  90. query.events = POLLIN;
  91. poll(&query, 1, 0);
  92. if(query.fd == fd4 && query.revents & POLLIN) {
  93. ++connections;
  94. thread::create([&](uintptr) {
  95. thread::detach();
  96. int clientfd = -1;
  97. struct sockaddr_in settings = {0};
  98. socklen_t socklen = sizeof(sockaddr_in);
  99. clientfd = accept(fd4, (struct sockaddr*)&settings, &socklen);
  100. if(clientfd < 0) return;
  101. uint32_t ip = ntohl(settings.sin_addr.s_addr);
  102. Request request;
  103. request._ipv6 = false;
  104. request._ip = {
  105. (uint8_t)(ip >> 24), ".",
  106. (uint8_t)(ip >> 16), ".",
  107. (uint8_t)(ip >> 8), ".",
  108. (uint8_t)(ip >> 0)
  109. };
  110. if(download(clientfd, request) && callback) {
  111. auto response = callback(request);
  112. upload(clientfd, response);
  113. } else {
  114. upload(clientfd, Response()); //"501 Not Implemented"
  115. }
  116. ::close(clientfd);
  117. --connections;
  118. }, 0, settings.threadStackSize);
  119. return true;
  120. }
  121. return false;
  122. }
  123. auto Server::ipv6_scan() -> bool {
  124. struct pollfd query = {0};
  125. query.fd = fd6;
  126. query.events = POLLIN;
  127. poll(&query, 1, 0);
  128. if(query.fd == fd6 && query.revents & POLLIN) {
  129. ++connections;
  130. thread::create([&](uintptr) {
  131. thread::detach();
  132. int clientfd = -1;
  133. struct sockaddr_in6 settings = {0};
  134. socklen_t socklen = sizeof(sockaddr_in6);
  135. clientfd = accept(fd6, (struct sockaddr*)&settings, &socklen);
  136. if(clientfd < 0) return;
  137. uint8_t* ip = settings.sin6_addr.s6_addr;
  138. uint16_t ipSegment[8];
  139. for(auto n : range(8)) ipSegment[n] = ip[n * 2 + 0] * 256 + ip[n * 2 + 1];
  140. Request request;
  141. request._ipv6 = true;
  142. //RFC5952 IPv6 encoding: the first longest 2+ consecutive zero-sequence is compressed to "::"
  143. int zeroOffset = -1;
  144. int zeroLength = 0;
  145. int zeroCounter = 0;
  146. for(auto n : range(8)) {
  147. uint16_t value = ipSegment[n];
  148. if(value == 0) zeroCounter++;
  149. if(zeroCounter > zeroLength) {
  150. zeroLength = zeroCounter;
  151. zeroOffset = 1 + n - zeroLength;
  152. }
  153. if(value != 0) zeroCounter = 0;
  154. }
  155. if(zeroLength == 1) zeroOffset = -1;
  156. for(uint n = 0; n < 8;) {
  157. if(n == zeroOffset) {
  158. request._ip.append(n == 0 ? "::" : ":");
  159. n += zeroLength;
  160. } else {
  161. uint16_t value = ipSegment[n];
  162. request._ip.append(hex(value), n++ != 7 ? ":" : "");
  163. }
  164. }
  165. if(download(clientfd, request) && callback) {
  166. auto response = callback(request);
  167. upload(clientfd, response);
  168. } else {
  169. upload(clientfd, Response()); //"501 Not Implemented"
  170. }
  171. ::close(clientfd);
  172. --connections;
  173. }, 0, settings.threadStackSize);
  174. return true;
  175. }
  176. return false;
  177. }
  178. auto Server::close() -> void {
  179. ipv4_close();
  180. ipv6_close();
  181. }
  182. }