server.C 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. /*
  2. This program is free software: you can redistribute it and/or modify
  3. it under the terms of the GNU General Public License as published by
  4. the Free Software Foundation, either version 3 of the License, or
  5. (at your option) any later version.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. GNU General Public License for more details.
  10. You should have received a copy of the GNU General Public License
  11. along with this program. If not, see <http://www.gnu.org/licenses/>.
  12. * */
  13. #include <cpoll/cpoll.H>
  14. #include <unistd.h>
  15. #include <iostream>
  16. #include <signal.h>
  17. #include <cppsp/page.H>
  18. #include <cppsp/cppsp_cpoll.H>
  19. #include <cppsp/common.H>
  20. using namespace std;
  21. using namespace CP;
  22. using namespace cppsp;
  23. using namespace RGC;
  24. #define rmb() /**/
  25. #define wmb() /**/
  26. namespace cppspServer
  27. {
  28. #define CACHELINE_SIZE 64
  29. //currently not used
  30. template<class T> class RingBuffer
  31. {
  32. public:
  33. union {
  34. struct {
  35. T* items;
  36. int length;
  37. };
  38. char padding1[CACHELINE_SIZE];
  39. };
  40. union {
  41. int rpos;
  42. char padding2[CACHELINE_SIZE];
  43. };
  44. union {
  45. int wpos;
  46. char padding3[CACHELINE_SIZE];
  47. };
  48. RingBuffer(int length): length(length),rpos(0), wpos(0) {
  49. items=new T[length];
  50. }
  51. inline int __getlength(int i1, int i2, int wrap)
  52. {
  53. return (i2 < i1 ? i2 + wrap : i2) - i1;
  54. }
  55. inline bool canEnqueue()
  56. {
  57. return __getlength(rpos, wpos, (length*2)) < length;
  58. }
  59. inline bool canDequeue()
  60. {
  61. return __getlength(rpos, wpos, (length*2)) > 0;
  62. }
  63. T* beginEnqueue() {
  64. if(canEnqueue()) return items+(wpos%length);
  65. else return NULL;
  66. }
  67. void endEnqueue() {
  68. wmb();
  69. wpos=(wpos+1)%(length*2);
  70. }
  71. T* beginDequeue() {
  72. if(!canDequeue()) return NULL;
  73. rmb();
  74. return items+(rpos%length);
  75. }
  76. void endDequeue() {
  77. rpos=(rpos+1)%(length*2);
  78. }
  79. };
  80. class Server: public cppsp::Server {
  81. public:
  82. cppspManager* mgr;
  83. String root;
  84. Server(String root):mgr(cppspManager_new()),root(root) {
  85. }
  86. ~Server() {
  87. cppspManager_delete(mgr);
  88. }
  89. void handleStaticRequest(String path, cppsp::Request& req, Response& resp, Delegate<void()> cb) override;
  90. void handleDynamicRequest(String path, cppsp::Request& req, Response& resp, Delegate<void()> cb) override;
  91. void loadPage(CP::Poll& p, String path, RGC::Allocator& a,
  92. Delegate<void(Page*, exception* ex)> cb) override {
  93. string tmp = mapPath(path.toSTDString());
  94. cppsp::loadPage(mgr, p, rootDir(), {tmp.data(), (int) tmp.length()}, &a, cb);
  95. }
  96. void loadPageFromFile(CP::Poll& p, String path, RGC::Allocator& a,
  97. Delegate<void(Page*, exception* ex)> cb) override {
  98. cppsp::loadPage(mgr, p, rootDir(), path, &a, cb);
  99. }
  100. void loadModule(CP::Poll& p, String path,
  101. Delegate<void(void*, exception* ex)> cb) override {
  102. string tmp = mapPath(path.toSTDString());
  103. cppsp::loadModule(mgr, p, this, rootDir(), {tmp.data(), (int) tmp.length()}, cb);
  104. }
  105. void loadModuleFromFile(CP::Poll& p, String path,
  106. Delegate<void(void*, exception* ex)> cb) override {
  107. cppsp::loadModule(mgr, p, this, rootDir(), path, cb);
  108. }
  109. String loadStaticPage(String path) override {
  110. string tmp = mapPath(path.toSTDString());
  111. return cppsp::loadStaticPage(mgr,{tmp.data(), (int) tmp.length()});
  112. }
  113. String loadStaticPageFromFile(String path) override {
  114. return cppsp::loadStaticPage(mgr,path);
  115. }
  116. String rootDir() override {
  117. return root;
  118. }
  119. cppspManager* manager() override {
  120. return mgr;
  121. }
  122. //this function needs to be called periodically to check for file modifications
  123. //otherwise auto re-compile will not work
  124. //generally call it every 2 seconds
  125. void updateTime() {
  126. cppsp::updateTime(mgr);
  127. }
  128. };
  129. class Request:public cppsp::CPollRequest
  130. {
  131. public:
  132. Request(CP::Socket& s, CP::StringPool* sp) :
  133. CPollRequest(s, sp) {
  134. }
  135. void* _handler;
  136. };
  137. //handles a single connection
  138. //just instantiate-and-forget; it will self-destruct when connection is closed
  139. struct handler:public RGC::Object {
  140. Allocator* alloc;
  141. Server& thr;
  142. CP::Poll& p;
  143. Socket& s;
  144. Page* page;
  145. StringPool sp;
  146. Request req;
  147. cppsp::Response resp;
  148. //Page* p;
  149. //MemoryStream ms;
  150. uint8_t* buf;
  151. String path;
  152. iovec iov[2];
  153. bool keepAlive;
  154. handler(Server& thr,CP::Poll& poll,Socket& s):thr(thr),
  155. p(poll),s(s), req(this->s,&sp),resp(this->s,&sp) {
  156. //printf("handler()\n");
  157. req._handler=this;
  158. poll.add(this->s);
  159. s.retain();
  160. if(req.readRequest({&handler::readCB, this})) readCB(true);
  161. }
  162. void readCB(bool success) {
  163. if(!success) {
  164. destruct();
  165. return;
  166. }
  167. auto it=req.headers.find("connection");
  168. if(it!=req.headers.end() && (*it).value=="close")keepAlive=false;
  169. else keepAlive=true;
  170. resp.headers.insert({"Connection", keepAlive?"keep-alive":"close"});
  171. resp.headers.insert({"Date", sp.addString(thr.mgr->curRFCTime)});
  172. thr.handleRequest(req,resp,{&handler::finalize,this});
  173. }
  174. void setPath(String p) {
  175. path.d=sp.beginAdd(p.length()+thr.root.length());
  176. path.len=cppsp::combinePathChroot(thr.root.data(),thr.root.length(),
  177. p.data(),p.length(),path.data());
  178. sp.endAdd(path.len);
  179. }
  180. static inline int itoa(int i, char* b) {
  181. static char const digit[] = "0123456789";
  182. char* p = b;
  183. p += (i==0?0:int(log10f(i))) + 1;
  184. *p = '\0';
  185. int l = p - b;
  186. do { //Move back, inserting digits as u go
  187. *--p = digit[i % 10];
  188. i = i / 10;
  189. } while (i);
  190. return l;
  191. }
  192. void handleStatic(String _path) {
  193. try {
  194. setPath(_path);
  195. String data=cppsp::loadStaticPage(thr.mgr,path);
  196. int bufferL = resp.buffer.length();
  197. {
  198. char* tmps = sp.beginAdd(16);
  199. int l = itoa(data.length(), tmps);
  200. sp.endAdd(l);
  201. resp.headers.insert({"Content-Length", { tmps, l }});
  202. StreamWriter sw(resp.buffer);
  203. resp.serializeHeaders(sw);
  204. }
  205. iov[0]= {resp.buffer.data()+bufferL, (size_t)(resp.buffer.length()-bufferL)};
  206. iov[1]= {data.data(), (size_t)data.length()};
  207. resp.outputStream->writevAll(iov, 2, { &handler::writevCB, this });
  208. } catch(exception& ex) {
  209. cppsp::handleError(&ex,resp,path);
  210. resp.flush( { &handler::flushCB, this });
  211. }
  212. }
  213. void handleDynamic(String _path) {
  214. setPath(_path);
  215. cppsp::loadPage(thr.mgr,p,thr.root,path,&sp,{&handler::loadCB,this});
  216. }
  217. void loadCB(Page* p, exception* ex) {
  218. //printf("loadCB()\n");
  219. if(ex!=NULL) {
  220. cppsp::handleError(ex,resp,path);
  221. resp.flush( { &handler::flushCB, this });
  222. goto doFinish;
  223. }
  224. {
  225. this->page=p;
  226. p->sp=&sp;
  227. //this->p=p;
  228. //p->filePath=path;
  229. p->request=&req;
  230. p->response=&resp;
  231. p->poll=&this->p;
  232. p->server=&thr;
  233. p->handleRequest({&handler::handleRequestCB,this});
  234. return;
  235. }
  236. doFinish:;
  237. }
  238. void sockReadCB(int r) {
  239. if(r<=0) {
  240. free(buf);
  241. destruct();
  242. }
  243. }
  244. void flushCB(Response& resp) {
  245. //s->shutdown(SHUT_WR);
  246. //release();
  247. finalize();
  248. }
  249. void writevCB(int i) {
  250. finalize();
  251. }
  252. void handleRequestCB() {
  253. page->destruct();
  254. page=nullptr;
  255. //s->shutdown(SHUT_WR);
  256. //release();
  257. //s->repeatRead(buf,sizeof(buf),{&handler::sockReadCB,this});
  258. finalize();
  259. }
  260. void finalize() {
  261. if(resp.closed) {
  262. destruct(); return;
  263. }
  264. sp.clear();
  265. if(keepAlive) {
  266. req.reset();
  267. resp.reset();
  268. if(req.readRequest({&handler::readCB,this})) readCB(true);
  269. } else {
  270. s.shutdown(SHUT_WR);
  271. buf=(uint8_t*)malloc(4096);
  272. s.repeatRead(buf,4096,{&handler::sockReadCB,this});
  273. }
  274. }
  275. ~handler() {
  276. //printf("~handler()\n");
  277. s.release();
  278. }
  279. };
  280. void Server::handleStaticRequest(String path, cppsp::Request& req, Response& resp, Delegate<void()> cb) {
  281. cppspServer::Request& r=static_cast<cppspServer::Request&>(req);
  282. (*(handler*)r._handler).handleStatic(path);
  283. }
  284. void Server::handleDynamicRequest(String path, cppsp::Request& req, Response& resp, Delegate<void()> cb) {
  285. cppspServer::Request& r=static_cast<cppspServer::Request&>(req);
  286. (*(handler*)r._handler).handleDynamic(path);
  287. }
  288. }