Browse Source

Compiled resources from various tests

tfb 12 years ago
parent
commit
c75caa1fe6
100 changed files with 14532 additions and 0 deletions
  1. 1 0
      cpoll_cppsp/cppsp_0.2
  2. BIN
      cpoll_cppsp/cppsp_0.2.3.tar.xz
  3. 98 0
      cpoll_cppsp/cppsp_rel0.2.3/CHANGELOG
  4. 43 0
      cpoll_cppsp/cppsp_rel0.2.3/README
  5. 1 0
      cpoll_cppsp/cppsp_rel0.2.3/README.md
  6. 3 0
      cpoll_cppsp/cppsp_rel0.2.3/common_headers/concat.H
  7. 144 0
      cpoll_cppsp/cppsp_rel0.2.3/common_headers/delegate.H
  8. 11 0
      cpoll_cppsp/cppsp_rel0.2.3/common_headers/iallocator.H
  9. 218 0
      cpoll_cppsp/cppsp_rel0.2.3/common_headers/rgc.H
  10. 19 0
      cpoll_cppsp/cppsp_rel0.2.3/common_headers/string_ops.H
  11. BIN
      cpoll_cppsp/cppsp_rel0.2.3/cpoll.o
  12. 167 0
      cpoll_cppsp/cppsp_rel0.2.3/cpoll/.cproject
  13. 83 0
      cpoll_cppsp/cppsp_rel0.2.3/cpoll/.project
  14. 4 0
      cpoll_cppsp/cppsp_rel0.2.3/cpoll/all.C
  15. 2461 0
      cpoll_cppsp/cppsp_rel0.2.3/cpoll/cpoll.C
  16. 41 0
      cpoll_cppsp/cppsp_rel0.2.3/cpoll/cpoll.cbp
  17. 248 0
      cpoll_cppsp/cppsp_rel0.2.3/cpoll/http.C
  18. 175 0
      cpoll_cppsp/cppsp_rel0.2.3/cpoll/include/basictypes.H
  19. 1784 0
      cpoll_cppsp/cppsp_rel0.2.3/cpoll/include/cpoll.H
  20. 110 0
      cpoll_cppsp/cppsp_rel0.2.3/cpoll/include/cpoll_internal.H
  21. 67 0
      cpoll_cppsp/cppsp_rel0.2.3/cpoll/include/http.H
  22. 14 0
      cpoll_cppsp/cppsp_rel0.2.3/cpoll/include/sendfd.H
  23. 408 0
      cpoll_cppsp/cppsp_rel0.2.3/cpoll/include/statemachines.H
  24. 130 0
      cpoll_cppsp/cppsp_rel0.2.3/cpoll/include/threadpool.H
  25. 8 0
      cpoll_cppsp/cppsp_rel0.2.3/cpoll/makefile
  26. 61 0
      cpoll_cppsp/cppsp_rel0.2.3/cpoll/rgctest.C
  27. 90 0
      cpoll_cppsp/cppsp_rel0.2.3/cpoll/sendfd.C
  28. 220 0
      cpoll_cppsp/cppsp_rel0.2.3/cpoll/statemachines.C
  29. 91 0
      cpoll_cppsp/cppsp_rel0.2.3/cpoll/t1.C
  30. BIN
      cpoll_cppsp/cppsp_rel0.2.3/cppsp.o
  31. 179 0
      cpoll_cppsp/cppsp_rel0.2.3/cppsp/.cproject
  32. 27 0
      cpoll_cppsp/cppsp_rel0.2.3/cppsp/.project
  33. 6 0
      cpoll_cppsp/cppsp_rel0.2.3/cppsp/all.C
  34. 865 0
      cpoll_cppsp/cppsp_rel0.2.3/cppsp/common.C
  35. 103 0
      cpoll_cppsp/cppsp_rel0.2.3/cppsp/cppsp_cpoll.C
  36. 31 0
      cpoll_cppsp/cppsp_rel0.2.3/cppsp/include/bitap.H
  37. 241 0
      cpoll_cppsp/cppsp_rel0.2.3/cppsp/include/common.H
  38. 55 0
      cpoll_cppsp/cppsp_rel0.2.3/cppsp/include/cppsp_cpoll.H
  39. 233 0
      cpoll_cppsp/cppsp_rel0.2.3/cppsp/include/headercontainer.H
  40. 252 0
      cpoll_cppsp/cppsp_rel0.2.3/cppsp/include/httpparser.H
  41. 262 0
      cpoll_cppsp/cppsp_rel0.2.3/cppsp/include/mountpointmgr.H
  42. 403 0
      cpoll_cppsp/cppsp_rel0.2.3/cppsp/include/page.H
  43. 56 0
      cpoll_cppsp/cppsp_rel0.2.3/cppsp/include/split.H
  44. 106 0
      cpoll_cppsp/cppsp_rel0.2.3/cppsp/include/stringutils.H
  45. 230 0
      cpoll_cppsp/cppsp_rel0.2.3/cppsp/include/websocket.H
  46. 297 0
      cpoll_cppsp/cppsp_rel0.2.3/cppsp/page.C
  47. 323 0
      cpoll_cppsp/cppsp_rel0.2.3/cppsp/stringutils.C
  48. 94 0
      cpoll_cppsp/cppsp_rel0.2.3/cppsp/websocket.C
  49. 4 0
      cpoll_cppsp/cppsp_rel0.2.3/cppsp_server/.gitignore
  50. 347 0
      cpoll_cppsp/cppsp_rel0.2.3/cppsp_server/cppsp_standalone.C
  51. 5 0
      cpoll_cppsp/cppsp_rel0.2.3/cppsp_server/makefile
  52. 295 0
      cpoll_cppsp/cppsp_rel0.2.3/cppsp_server/server.C
  53. 124 0
      cpoll_cppsp/cppsp_rel0.2.3/cppsp_server/socketd_cppsp.C
  54. BIN
      cpoll_cppsp/cppsp_rel0.2.3/cppsp_standalone
  55. 1 0
      cpoll_cppsp/cppsp_rel0.2.3/include/concat.H
  56. 1 0
      cpoll_cppsp/cppsp_rel0.2.3/include/cpoll
  57. 1 0
      cpoll_cppsp/cppsp_rel0.2.3/include/cpoll.H
  58. 1 0
      cpoll_cppsp/cppsp_rel0.2.3/include/cpoll_internal.H
  59. 1 0
      cpoll_cppsp/cppsp_rel0.2.3/include/cppsp
  60. 1 0
      cpoll_cppsp/cppsp_rel0.2.3/include/delegate.H
  61. 1 0
      cpoll_cppsp/cppsp_rel0.2.3/include/iallocator.H
  62. 1 0
      cpoll_cppsp/cppsp_rel0.2.3/include/rgc.H
  63. 1 0
      cpoll_cppsp/cppsp_rel0.2.3/include/socketd.H
  64. 1 0
      cpoll_cppsp/cppsp_rel0.2.3/include/socketd_client.H
  65. 22 0
      cpoll_cppsp/cppsp_rel0.2.3/makefile
  66. 7 0
      cpoll_cppsp/cppsp_rel0.2.3/run_application
  67. 4 0
      cpoll_cppsp/cppsp_rel0.2.3/run_example
  68. 5 0
      cpoll_cppsp/cppsp_rel0.2.3/run_socketd_example
  69. 624 0
      cpoll_cppsp/cppsp_rel0.2.3/socketd/.cproject
  70. 83 0
      cpoll_cppsp/cppsp_rel0.2.3/socketd/.project
  71. 4 0
      cpoll_cppsp/cppsp_rel0.2.3/socketd/all.C
  72. 365 0
      cpoll_cppsp/cppsp_rel0.2.3/socketd/configparser.C
  73. 43 0
      cpoll_cppsp/cppsp_rel0.2.3/socketd/include/configparser.H
  74. 66 0
      cpoll_cppsp/cppsp_rel0.2.3/socketd/include/socketd.H
  75. 267 0
      cpoll_cppsp/cppsp_rel0.2.3/socketd/include/socketd_client.H
  76. 177 0
      cpoll_cppsp/cppsp_rel0.2.3/socketd/include/socketd_internal.H
  77. 100 0
      cpoll_cppsp/cppsp_rel0.2.3/socketd/main.C
  78. 799 0
      cpoll_cppsp/cppsp_rel0.2.3/socketd/socketd.C
  79. 47 0
      cpoll_cppsp/cppsp_rel0.2.3/socketd/socketd.conf
  80. BIN
      cpoll_cppsp/cppsp_rel0.2.3/socketd_bin
  81. BIN
      cpoll_cppsp/cppsp_rel0.2.3/socketd_cppsp
  82. 32 0
      cpoll_cppsp/cppsp_rel0.2.3/socketd_example.conf
  83. 36 0
      cpoll_cppsp/cppsp_rel0.2.3/socketd_exampleconf
  84. 354 0
      cpoll_cppsp/cppsp_rel0.2.3/socketd_proxy.C
  85. BIN
      cpoll_cppsp/cppsp_rel0.2.3/socketd_proxy.so
  86. 43 0
      cpoll_cppsp/cppsp_rel0.2.3/www/1.cppsp
  87. 1 0
      cpoll_cppsp/cppsp_rel0.2.3/www/100.cppsp
  88. 1 0
      cpoll_cppsp/cppsp_rel0.2.3/www/100.html
  89. 82 0
      cpoll_cppsp/cppsp_rel0.2.3/www/dir_list.cppsm
  90. 6 0
      cpoll_cppsp/cppsp_rel0.2.3/www/errortest.cppsp
  91. 16 0
      cpoll_cppsp/cppsp_rel0.2.3/www/forcestatic.cppsm
  92. 79 0
      cpoll_cppsp/cppsp_rel0.2.3/www/test1.cppsp
  93. 17 0
      cpoll_cppsp/cppsp_rel0.2.3/www/url_rewrite.cppsm
  94. 1 0
      cpoll_cppsp/cppsp_rel0.2.3/www/x.cppsp
  95. BIN
      cpoll_cppsp/www/db.so
  96. 1 0
      cpoll_cppsp/www/db.txt
  97. BIN
      cpoll_cppsp/www/db_pg_async.so
  98. 1 0
      cpoll_cppsp/www/db_pg_async.txt
  99. BIN
      cpoll_cppsp/www/db_pg_threadpool.so
  100. 1 0
      cpoll_cppsp/www/db_pg_threadpool.txt

+ 1 - 0
cpoll_cppsp/cppsp_0.2

@@ -0,0 +1 @@
+cppsp_rel0.2.3

BIN
cpoll_cppsp/cppsp_0.2.3.tar.xz


+ 98 - 0
cpoll_cppsp/cppsp_rel0.2.3/CHANGELOG

@@ -0,0 +1,98 @@
+Version scheme
+================
+	MAJOR.MINOR[.BUGFIX | .rcN]
+	for example, (in order from earliest to latest)
+		rel0.1-rc1: 0.1 initial release candidate
+		rel0.1: release 0.1 initial release
+		rel0.1.1: release 0.1, 1st bugfix release
+		stab0.1.10: release 0.1, 10th bugfix release, stable
+	* A prefix of "rel" means it is a release version (as opposed to development version), and is suitable for testing on non-critical sites. You can consider this the "testing" stage. The "rel" prefix may be omitted in filenames, and is implied when there is no prefix.
+	* Once a release has gone through about 8 cycles of bugfixes, and/or the number and severity of bugs has declined to a very low point, it is considered "stable" and its prefix will be changed to "stab". The bugfix number is not reset, however.
+
+API/ABI stability
+	* For performance reasons, only API compability will be maintained. Expect ABI breakages even between different bugfix numbers of the same release.
+	* For version 1.0 or higher, API compatibility is maintained for all non-rc releases. For versions below 1.0, API compatibility is maintained for stable releases only.
+
+RELEASE OVERVIEW
+================
+(as of 2013/07/23)
+latest stable release: 0.1.12
+latest testing release: 0.2.3
+latest release candidate: none
+"maintained" means API is to be kept unchanged
+
+0.2:
+	* current status: released; maintained
+0.1:
+	* current status: stable; maintained
+
+CHANGELOG
+================
+0.2: (based on cad1a3c8cb8887472c88b93e70ad4eeacf011a81)
+	notable changes included so far (from 0.1):
+		* socketd is now included
+		* static file serving is now supported
+		* added module support; removed "default handler" (superseded by loading a module which does url rewriting)
+		* many optimizations
+		* SO_REUSEPORT support (requires kernel 3.9 or above)
+		* thread pool implementation (in cpoll)
+		* compilation no longer needs to be repeated for every worker thread
+	rel0.2.3: (2013/07/23)
+		* added "date" HTTP response header (as required by http spec)
+	rel0.2.2: (2013/07/08)
+		* switched to NewEPoll for default Poll type because it performed better in many benchmarks
+		* fixed read/writev stall in NewEPoll (bad5745192ee7d5d347e1fa99ffebd7286d2292f)
+	rel0.2.1: (2013/06/03)
+		* expose internal API; check for file existence before allocating data structures to avoid DoS (261486b40386417b2175d47da3220897ef498d01)
+		* API additions (ad0eacf49a7557acdeebe2fb4502b6fbdca067ef)
+		* revert back to EPoll class for default Poll type
+		* added automatic cpu affinity configuration (c12ed66e2873f88fe396c0498213b75bf1bafe1a)
+		* cpoll API additions (String::indexOf, etc) (e1fb9288e43293bd2d32b091996cadf8fee3f095)
+		* completed websocket support (b679ce12a898b68f8ebfa398be3bf268465425cf)
+		* minor bugfix (442a75159185b4284b753eeaca6f7aa143dd0b05)
+		* fixed infinite recursion (6f5f33cc39f87e8b5fdbb07c080e839f8ba66399)
+	rel0.2: (2013/05/24)
+		* sync to tip of git repo (c70bb26a56a3da589a5ce099f1861b0113b734f7)
+	0.2-rc9: (2013/05/20)
+		* 0a74c054fb8940f78515e83a454387fac8645856
+		* 376c9208adbc4de08d6a43402c157b76606e3cd0
+		* 17c7892d98c79f22c5358abe8f59cb29aa7d5648
+	0.2-rc8: (2013/05/19)
+		* ea4f175a2ad6aa0784b80664258496b670bfbb3e
+		* a368b2e786fe9813aa420b76813fdd6c8db96c76
+		* 4a340d50b7e7428efca5a7397ec142a02cf45d9a
+		* eeb74f8d4c148dbf6b54d0936798c28c5de643a6
+		* 1cf4c149832a3132fb6d912341576ba54d11064d
+		* 5f6407cddbe05c52e547bcca81edfff91e1435ed
+	0.2-rc7: (2013/05/17)
+		* 1ec535514582fe8a414b87e233a9d445d39588a0
+		* 809f759e331555ecaa0a2248fd700858ac014532
+		* ad3dbc0eb3b244fd43dfbcadf9d58f6735d9e457
+		* 2d6dbb01581d4f87e1c76064012919f78b6de486
+		* 123746212b2bf85182a45862035c7ae203e1b59c
+	0.2-rc6: (2013/05/15)
+		* 9b0539776d955fad26b377a9628f38f052d0468d
+		* 3276e2abaecc07f258425110ec707a97e724914d
+		* 537e679d2f905d872f19d67ef9fbf6a485b21fb5
+	0.2-rc5: (2013/05/15)
+		* e7fafaa82e767b806edd8373f9abcee6649a1c76
+		* eb2e4e85f278b0b1c3a8ea7421dfd7fb361ce4cd
+		* f3e92cacb6174d8b94357ec6d774cea7e3657d69
+		* 349a1a26ebd799a333e4f3ec770f214ad1382ddc
+		* f87625e51889c374b44892620169bc9ec9c4959b
+		* e23e0e3b032ba53467917f9d401913d400e649c1
+		* ca43ab7cfd2ed9b55ed2fb51bd2d8b6fa55bdcf7
+		* 06f0a4c2f8891e204f477f2cb72ea0f98d008648
+		* 0df5947f2372214b322c884a36be70c73a8343b9
+	0.2-rc4: (2013/05/14)
+		* fe021cd5ca8e27a51c0e9bea4e8ad2395f5aeab7
+	0.2-rc3: (2013/05/12)
+		* f3abae8dd1e68d46028ba5237d8932624f88aefc
+		* 519e710d082a1a03fd4b9609cd4fb4879240dcca
+	0.2-rc2: (2013/05/11)
+		* 26e3705016e16c6e22d5a694a59fa0281abcdc77
+		* 579e5f4cd09b3a620922152c894b02e4bba62fab
+	0.2-rc1: (2013/05/11)
+		* initial release candidate
+
+

+ 43 - 0
cpoll_cppsp/cppsp_rel0.2.3/README

@@ -0,0 +1,43 @@
+CPPSP: C++ Server Pages
+=======================
+CPPSP (C++ Server Pages) is a web application framework similar to ASP and ASP .Net. It features a template parser that parses, compiles, and loads CPPSP pages automatically at runtime. CPPSP pages have a very similar syntax to ASP and ASP .NET, where all code is considered HTML by default, and server-side active code can be embedded using "<% ... %>". 
+
+Features
+================
+* Automatic parsing and compiling of pages. Just copy a .cppsp file into your www directory, and it is instantly accessible. No need to manually compile CPPSP pages. 
+* Automatic re-compilation. Make a modification to a .cppsp file, and the changes will show up in your browser immediately after refresh.
+* Simple syntax and API similar to ASP .Net
+* (0.2 and above) SocketD web server multiplexer allows you to share the same port (usually 80) with multiple cppsp web application hosts, and even between cppsp and another web server (lighttpd, nginx, ...). SocketD supports hostname and request URI matching, but request URI matching does not work well with HTTP keep-alive.
+* (0.2 and above) Modules API allows you to extend the functionality of the web server. The "www" directory included in this tarball includes a few example modules, including one that adds directory listing functionality.
+
+Installing
+================
+
+To compile cppsp, just type:
+	make all -j3
+
+(not needed if you downloaded the binary tarball)
+
+To run cppsp with example scripts, type:
+	./run_example
+
+It will listen on port 16969, and serve files from ./www/
+
+To load modules, specify "-m" on the command line (module path is relative to web root):
+	./run_example -m /dir_list.cppsm
+
+To run cppsp with socketd, type:
+	./run_socketd_example
+
+Then visit http://localhost:16969/ (not 127.0.0.1!) (see socketd_exampleconf)
+
+To install cppsp, just copy the cppsp_standalone file to anywhere you like. You can then simply write a few init scripts if you want it to automatically start on boot.
+
+
+Note: If you plan to benchmark the connections/s performance of cppsp (with keep-alive disabled), make sure you download and compile the Hoard memory allocator:
+
+http://www.hoard.org/
+
+Then, LD_PRELOAD it before running cppsp. There is a possible bug in glibc where if large chunks of memory are malloc()'d and free()'d, glibc repeatedly calls mprotect(), which is very expensive.
+
+

+ 1 - 0
cpoll_cppsp/cppsp_rel0.2.3/README.md

@@ -0,0 +1 @@
+README

+ 3 - 0
cpoll_cppsp/cppsp_rel0.2.3/common_headers/concat.H

@@ -0,0 +1,3 @@
+#ifndef CONCAT
+#define CONCAT(X) (((stringstream&)(stringstream()<<X)).str())
+#endif

+ 144 - 0
cpoll_cppsp/cppsp_rel0.2.3/common_headers/delegate.H

@@ -0,0 +1,144 @@
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * */
+#ifndef DELEGATE_H
+#define DELEGATE_H
+#include <functional>
+#ifndef NULL
+#define NULL ((void*)0)
+#endif
+
+struct GenericDelegate
+{
+	void* func;
+	void* data;
+	template<class R, class... P> R operator()(P && ...p) {
+		return ((R (*)(void* data, P...))func)(data,std::forward<P>(p)...);
+	}
+	
+	void* operator=(void* func) {
+		return this->func=func;
+	}
+};
+
+template<class SIGNATURE> struct DelegateBase;
+template<class R, class... P>
+struct DelegateBase<R(P...)>:public GenericDelegate
+{
+	/*R (*func)(void* data, P...);
+	void* data;*/
+	template<class... P2>
+	R operator() (P2 && ...p) const {
+		return ((R (*)(void* data, P...))func)(data,std::forward<P2>(p)...);
+	}
+	
+	R (*operator=(R (*func)(void* data, P...)))(void* data, P...) {
+		this->func=(void*)func;
+		return func;
+	}
+	bool operator==(void* other) {
+		return (void*)func == other;
+	}
+	bool operator==(const DelegateBase<R(P...)>& other) {
+		return func == other.func && data==other.data;
+	}
+	bool operator!=(void* other) {
+		return (void*)func != other;
+	}
+	bool operator!=(const DelegateBase<R(P...)>& other) {
+		return func != other.func && data==other.data;
+	}
+};
+
+template<class SIGNATURE> struct Delegate;
+template<class R, class... P>
+struct Delegate<R(P...)>:public DelegateBase<R(P...)>
+{
+	Delegate() {
+		this->func=NULL;
+	}
+	Delegate(R (*func)(void* data, P... p...), void* data): DelegateBase<R(P...)>(func,data) {}
+	template<class X>Delegate(R (*func)(X*,P...), X* th) {
+		this->func=(void*)(R(*)(void*,P...))func;
+		this->data=th;
+	}
+	template<class X>Delegate(R (X::*func)(P...), X* th) {
+		this->func=(void*)(R(*)(void*,P...))func;
+		this->data=th;
+	}
+	Delegate(R (*func)(void*, P...)) {
+		this->func=(void*)func;
+		this->data=NULL;
+	}
+	explicit Delegate(const GenericDelegate& other) {
+		this->func=other.func;
+		this->data=other.data;
+	}
+	template<class X>Delegate(X* th) {
+		this->func=(void*)(R(*)(void*,P...))&X::operator();
+		this->data=th;
+	}
+	Delegate(std::nullptr_t n) {
+		this->func=NULL;
+	};
+	R (*operator=(R (*func)(void* data, P...)))(void* data, P...) {
+		this->func=(void*)func;
+		return func;
+	}
+};
+template<class R, class... P> static Delegate<R(P...)> nullDelegate() {
+	struct {
+		R operator()(P... p...) {
+			return R();
+		}
+	} tmp;
+	return &tmp;
+}
+
+template<class SIGNATURE> class DelegateChain;
+template<class R, class ... P>
+class DelegateChain<R(P...)>
+{
+public:
+	struct item
+	{
+		Delegate<R(P...)> func;
+		item* prev;
+		item* next;
+		template<class ... P2>
+		inline R operator()(P2 && ...p) const {
+			func(std::forward<P2>(p)...);
+		}
+	};
+	item* last = NULL;
+	DelegateChain() {
+
+	}
+	item* attach(Delegate<R(P...)> func) {
+		item* it = new item { func, last, NULL };
+		if (last != NULL) last->next = it;
+		last = it;
+		return it;
+	}
+	void detach(item* it) {
+		if (it->next != NULL) it->next->prev = it->prev;
+		if (it->prev != NULL) it->prev->next = it->next;
+		if (last == it) last = it->prev;
+		delete it;
+	}
+	inline R operator()(P... p) const {
+		if (last != NULL) (*last)(std::forward<P>(p)...);
+	}
+};
+#endif

+ 11 - 0
cpoll_cppsp/cppsp_rel0.2.3/common_headers/iallocator.H

@@ -0,0 +1,11 @@
+#include <rgc.H>
+class IAllocator: virtual public RGC::Object
+{
+	//returns NULL if failed
+	virtual void* allocate(int32_t len);
+	virtual void free(void* obj);
+	//if failed, returns NULL and leaves original object untouched
+	virtual void* reallocate(void* obj, int32_t len);
+	virtual ~IAllocator();
+};
+

+ 218 - 0
cpoll_cppsp/cppsp_rel0.2.3/common_headers/rgc.H

@@ -0,0 +1,218 @@
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * */
+
+//RGC: simple reference counting based garbage collection framework
+#ifndef __RGC_H
+#define __RGC_H
+#include <cstddef>
+#include <utility>
+#include <stdlib.h>
+
+namespace RGC
+{
+	typedef volatile int atomic_t;
+#define atomic_read(v)                  v
+#define atomic_set(v,i)                 v = i
+#define atomic_add(i,v)                 v += i
+#define atomic_sub(i,v)                 v -= i
+#define atomic_sub_and_test(i,v)        (v -= i) == 0
+#define atomic_inc(v)                   v++
+#define atomic_dec(v)                   v--
+#define atomic_dec_and_test(v)          --v == 0
+#define atomic_inc_and_test(v)          ++v == 0
+#define atomic_add_negative(i,v)        (v += i) < 0
+	//static int objs=0;
+	class Allocator;
+	class Object
+	{
+	public:
+		Allocator* allocator;
+		atomic_t refCount; //reference counter
+		Object() {
+			allocator = NULL;
+			refCount = 1;
+			/*objs++;
+			 cout << objs << " objects" << endl;*/
+		}
+		Object(const Object& other) {
+			refCount = 1;
+		}
+		virtual ~Object() {
+			/*objs--;
+			 cout << objs << " objects" << endl;*/
+		}
+		inline void retain(int n=1) {
+			atomic_add(n,refCount);
+		}
+		inline void destruct();
+		inline bool release(int n=1) { //returns whether or not destruction occurred
+			atomic_sub(n,refCount);
+			if (refCount <= 0) {
+				destruct();
+				return true;
+			}
+			return false;
+		}
+		/*Object& operator=(const Object& other)
+		 {
+		 //refCount = 1;
+		 return *this;
+		 }*/
+	};
+	class Allocator: public virtual Object
+	{
+	public:
+		virtual void* alloc(int s)=0;
+		virtual void dealloc(void* obj)=0;
+		template<class T>
+		void del(T* obj) {
+			obj->~T();
+			dealloc(obj);
+		}
+	};
+	class DefaultAllocator: public Allocator
+	{
+		void* alloc(int s) override final {
+			return malloc(s);
+		}
+		void dealloc(void* obj) override final {
+			return free(obj);
+		}
+	};
+	static DefaultAllocator defaultAllocator;
+	void Object::destruct() {
+		if(allocator==NULL) delete this;
+		else allocator->del(this);
+	}
+	//template<class T> struct Ref;
+	template<class T> struct Ref
+	{
+		T* obj;
+		inline Ref() :
+				obj(NULL) {
+		}
+		//inline Ref(const Ref<T>& other);
+		inline Ref(T* obj) :
+				obj(obj) {
+			if (obj != NULL) obj->retain();
+		}
+		inline Ref(T& obj) :
+				obj(&obj) {
+			if (&obj != NULL) obj.retain();
+		}
+		/*template<class ... ARGS> inline Ref(ARGS&& ... args)
+		 :obj(new T(std::forward<ARGS>(args)...))
+		 {
+		 }*/
+		inline ~Ref() {
+			if (this->obj != NULL) this->obj->release();
+		}
+		Ref(const Ref<T>& other) :
+				obj(other.obj) {
+			if (obj != NULL) obj->retain();
+		}
+		T* operator=(T* obj) {
+			if (this->obj != NULL) this->obj->release();
+			this->obj = obj;
+			if (obj != NULL) obj->retain();
+			return obj;
+		}
+		T* operator=(T& obj) {
+			return operator=(*obj);
+		}
+		Ref& operator=(const Ref& other) {
+			if (this->obj != NULL) this->obj->release();
+			this->obj = other.obj;
+			if (obj != NULL) obj->retain();
+			return *this;
+		}
+		inline T* operator()() const {
+			return obj;
+		}
+		inline T& operator*() const {
+			return *obj;
+		}
+		inline T* operator->() const {
+			return obj;
+		}
+		inline T* get() const {
+			return obj;
+		}
+		template<class A> Ref<A> staticCast() {
+			return Ref<A>(static_cast<A*>(obj));
+		}
+		template<class A> Ref<A> dynamicCast() {
+			return Ref<A>(dynamic_cast<A*>(obj));
+		}
+		template<class A> Ref<A> reinterpretCast() {
+			return Ref<A>(reinterpret_cast<A*>(obj));
+		}
+	};
+	//creates a new instance, but disowns it
+	template<class T, class ... ARGS> inline T* newObj(ARGS&&... args)
+	{
+		T* tmp = new T(std::forward<ARGS>(args)...);
+		tmp->refCount--;
+		return tmp;
+	}
+/*template<class T> struct Ref
+ {
+ T* obj;
+ template<class ... ARGS> inline Ref(ARGS&& ... args)
+ :obj(new T(std::forward<ARGS>(args)...))
+ {
+ }
+ Ref(const Property<T>& prop):obj(prop.obj)
+ {
+ obj->retain();
+ }
+ ~Ref()
+ {
+ obj->release();
+ }
+ inline T* operator()() const
+ {
+ return obj;
+ }
+ inline T* operator->() const
+ {
+ return obj;
+ }
+ inline T& operator*() const
+ {
+ return *obj;
+ }
+ inline T* get() const
+ {
+ return obj;
+ }
+ };*/
+
+//callback mechanism similar to .NET events
+			/*template<class funcType> class Event
+			 {
+			 public:
+			 vector<funcType> callbacks;
+			 void operator()() {
+			 for(int i=0;i<callbacks.size();i++)
+			 callbacks[i]();
+			 }
+			 void operator+=(const funcType& cb) {
+			 callbacks.push_back(cb);
+			 }
+
+			 };*/
+			}
+#endif

+ 19 - 0
cpoll_cppsp/cppsp_rel0.2.3/common_headers/string_ops.H

@@ -0,0 +1,19 @@
+#ifndef STRING_OPS_H
+#define STRING_OPS_H
+
+namespace string_ops
+{
+	struct STRING
+	{
+		char* data;
+		int length;
+	};
+	struct CONST_STRING
+	{
+		const char* data;
+		int length;
+	};
+
+}
+#endif
+

BIN
cpoll_cppsp/cppsp_rel0.2.3/cpoll.o


+ 167 - 0
cpoll_cppsp/cppsp_rel0.2.3/cpoll/.cproject

@@ -0,0 +1,167 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?fileVersion 4.0.0?>
+
+<cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
+	<storageModule moduleId="org.eclipse.cdt.core.settings">
+		<cconfiguration id="cdt.managedbuild.config.gnu.cross.exe.debug.317623061">
+			<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.cross.exe.debug.317623061" moduleId="org.eclipse.cdt.core.settings" name="Debug">
+				<externalSettings/>
+				<extensions>
+					<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
+					<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+				</extensions>
+			</storageModule>
+			<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+				<configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.debug.317623061" name="Debug" parent="cdt.managedbuild.config.gnu.cross.exe.debug">
+					<folderInfo id="cdt.managedbuild.config.gnu.cross.exe.debug.317623061." name="/" resourcePath="">
+						<toolChain id="cdt.managedbuild.toolchain.gnu.cross.exe.debug.1612288781" name="Cross GCC" superClass="cdt.managedbuild.toolchain.gnu.cross.exe.debug">
+							<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="cdt.managedbuild.targetPlatform.gnu.cross.1245303854" isAbstract="false" osList="all" superClass="cdt.managedbuild.targetPlatform.gnu.cross"/>
+							<builder arguments="-j3" buildPath="${workspace_loc:/cpoll/Debug}" command="make" id="cdt.managedbuild.builder.gnu.cross.758976803" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" superClass="cdt.managedbuild.builder.gnu.cross"/>
+							<tool id="cdt.managedbuild.tool.gnu.cross.c.compiler.879901365" name="Cross GCC Compiler" superClass="cdt.managedbuild.tool.gnu.cross.c.compiler">
+								<option defaultValue="gnu.c.optimization.level.none" id="gnu.c.compiler.option.optimization.level.1587657173" name="Optimization Level" superClass="gnu.c.compiler.option.optimization.level" valueType="enumerated"/>
+								<option id="gnu.c.compiler.option.debugging.level.1837759657" name="Debug Level" superClass="gnu.c.compiler.option.debugging.level" value="gnu.c.debugging.level.max" valueType="enumerated"/>
+								<option id="gnu.c.compiler.option.include.paths.1274264717" name="Include paths (-I)" superClass="gnu.c.compiler.option.include.paths" valueType="includePath">
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/include}&quot;"/>
+								</option>
+								<option id="gnu.c.compiler.option.misc.pic.1262142257" name="Position Independent Code (-fPIC)" superClass="gnu.c.compiler.option.misc.pic" value="true" valueType="boolean"/>
+								<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1660037459" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.cross.cpp.compiler.269481599" name="Cross G++ Compiler" superClass="cdt.managedbuild.tool.gnu.cross.cpp.compiler">
+								<option id="gnu.cpp.compiler.option.optimization.level.1315275034" name="Optimization Level" superClass="gnu.cpp.compiler.option.optimization.level" value="gnu.cpp.compiler.optimization.level.none" valueType="enumerated"/>
+								<option id="gnu.cpp.compiler.option.debugging.level.1266485147" name="Debug Level" superClass="gnu.cpp.compiler.option.debugging.level" value="gnu.cpp.compiler.debugging.level.max" valueType="enumerated"/>
+								<option id="gnu.cpp.compiler.option.include.paths.2018574203" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" valueType="includePath">
+									<listOptionValue builtIn="false" value="../../include"/>
+								</option>
+								<option id="gnu.cpp.compiler.option.other.other.142870301" name="Other flags" superClass="gnu.cpp.compiler.option.other.other" value="-c -fmessage-length=0 --std=c++0x -Wno-pmf-conversions -fno-omit-frame-pointer" valueType="string"/>
+								<option id="gnu.cpp.compiler.option.other.pic.1456659329" name="Position Independent Code (-fPIC)" superClass="gnu.cpp.compiler.option.other.pic" value="true" valueType="boolean"/>
+								<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.224156660" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.cross.c.linker.170069979" name="Cross GCC Linker" superClass="cdt.managedbuild.tool.gnu.cross.c.linker"/>
+							<tool id="cdt.managedbuild.tool.gnu.cross.cpp.linker.2104656420" name="Cross G++ Linker" superClass="cdt.managedbuild.tool.gnu.cross.cpp.linker">
+								<option id="gnu.cpp.link.option.shared.1573746654" name="Shared (-shared)" superClass="gnu.cpp.link.option.shared" value="true" valueType="boolean"/>
+								<option id="gnu.cpp.link.option.soname.243344932" name="Shared object name (-Wl,-soname=)" superClass="gnu.cpp.link.option.soname" value="" valueType="string"/>
+								<option id="gnu.cpp.link.option.flags.1485719014" name="Linker flags" superClass="gnu.cpp.link.option.flags" value="-fPIC" valueType="string"/>
+								<option id="gnu.cpp.link.option.paths.1343058210" name="Library search path (-L)" superClass="gnu.cpp.link.option.paths" valueType="libPaths">
+									<listOptionValue builtIn="false" value="../../lib/"/>
+								</option>
+								<option id="gnu.cpp.link.option.libs.1289669082" name="Libraries (-l)" superClass="gnu.cpp.link.option.libs" valueType="libs">
+									<listOptionValue builtIn="false" value="curl"/>
+								</option>
+								<inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.1863145494" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
+									<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+									<additionalInput kind="additionalinput" paths="$(LIBS)"/>
+								</inputType>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.cross.archiver.1705905565" name="Cross GCC Archiver" superClass="cdt.managedbuild.tool.gnu.cross.archiver"/>
+							<tool id="cdt.managedbuild.tool.gnu.cross.assembler.1886492915" name="Cross GCC Assembler" superClass="cdt.managedbuild.tool.gnu.cross.assembler">
+								<inputType id="cdt.managedbuild.tool.gnu.assembler.input.161397032" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
+							</tool>
+						</toolChain>
+					</folderInfo>
+					<fileInfo id="cdt.managedbuild.config.gnu.cross.exe.debug.317623061.290209944" name="all.C" rcbsApplicability="disable" resourcePath="all.C" toolsToInvoke="cdt.managedbuild.tool.gnu.cross.cpp.compiler.269481599.1483916567">
+						<tool id="cdt.managedbuild.tool.gnu.cross.cpp.compiler.269481599.1483916567" name="Cross G++ Compiler" superClass="cdt.managedbuild.tool.gnu.cross.cpp.compiler.269481599"/>
+					</fileInfo>
+					<sourceEntries>
+						<entry excluding="all.C|rgctest.C|t1.C" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
+					</sourceEntries>
+				</configuration>
+			</storageModule>
+			<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+			<storageModule moduleId="packages"/>
+		</cconfiguration>
+		<cconfiguration id="cdt.managedbuild.config.gnu.cross.exe.release.1045629552">
+			<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.cross.exe.release.1045629552" moduleId="org.eclipse.cdt.core.settings" name="Release">
+				<externalSettings/>
+				<extensions>
+					<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
+					<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+				</extensions>
+			</storageModule>
+			<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+				<configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.release.1045629552" name="Release" parent="cdt.managedbuild.config.gnu.cross.exe.release">
+					<folderInfo id="cdt.managedbuild.config.gnu.cross.exe.release.1045629552." name="/" resourcePath="">
+						<toolChain id="cdt.managedbuild.toolchain.gnu.cross.exe.release.398517666" name="Cross GCC" superClass="cdt.managedbuild.toolchain.gnu.cross.exe.release">
+							<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="cdt.managedbuild.targetPlatform.gnu.cross.950830184" isAbstract="false" osList="all" superClass="cdt.managedbuild.targetPlatform.gnu.cross"/>
+							<builder arguments="-j3" buildPath="${workspace_loc:/cpoll/Release}" command="make" id="cdt.managedbuild.builder.gnu.cross.420489040" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" superClass="cdt.managedbuild.builder.gnu.cross"/>
+							<tool id="cdt.managedbuild.tool.gnu.cross.c.compiler.1696552579" name="Cross GCC Compiler" superClass="cdt.managedbuild.tool.gnu.cross.c.compiler">
+								<option defaultValue="gnu.c.optimization.level.most" id="gnu.c.compiler.option.optimization.level.691904295" name="Optimization Level" superClass="gnu.c.compiler.option.optimization.level" valueType="enumerated"/>
+								<option id="gnu.c.compiler.option.debugging.level.249111321" name="Debug Level" superClass="gnu.c.compiler.option.debugging.level" value="gnu.c.debugging.level.none" valueType="enumerated"/>
+								<option id="gnu.c.compiler.option.optimization.flags.1338584672" name="Other optimization flags" superClass="gnu.c.compiler.option.optimization.flags" value="-Ofast" valueType="string"/>
+								<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1212703011" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.cross.cpp.compiler.1079844465" name="Cross G++ Compiler" superClass="cdt.managedbuild.tool.gnu.cross.cpp.compiler">
+								<option id="gnu.cpp.compiler.option.optimization.level.2137352707" name="Optimization Level" superClass="gnu.cpp.compiler.option.optimization.level" value="gnu.cpp.compiler.optimization.level.most" valueType="enumerated"/>
+								<option id="gnu.cpp.compiler.option.debugging.level.1807185716" name="Debug Level" superClass="gnu.cpp.compiler.option.debugging.level" value="gnu.cpp.compiler.debugging.level.none" valueType="enumerated"/>
+								<option id="gnu.cpp.compiler.option.include.paths.1619156733" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" valueType="includePath">
+									<listOptionValue builtIn="false" value="../../include"/>
+								</option>
+								<option id="gnu.cpp.compiler.option.other.other.308236905" name="Other flags" superClass="gnu.cpp.compiler.option.other.other" value="-c -fmessage-length=0 --std=c++0x -Wno-pmf-conversions -fno-omit-frame-pointer -march=native" valueType="string"/>
+								<option id="gnu.cpp.compiler.option.other.pic.1491174781" name="Position Independent Code (-fPIC)" superClass="gnu.cpp.compiler.option.other.pic" value="true" valueType="boolean"/>
+								<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1689339885" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.cross.c.linker.2109293881" name="Cross GCC Linker" superClass="cdt.managedbuild.tool.gnu.cross.c.linker"/>
+							<tool id="cdt.managedbuild.tool.gnu.cross.cpp.linker.419932455" name="Cross G++ Linker" superClass="cdt.managedbuild.tool.gnu.cross.cpp.linker">
+								<option id="gnu.cpp.link.option.flags.198589648" name="Linker flags" superClass="gnu.cpp.link.option.flags" value="-fPIC -march=native" valueType="string"/>
+								<option id="gnu.cpp.link.option.shared.1004219451" name="Shared (-shared)" superClass="gnu.cpp.link.option.shared" value="true" valueType="boolean"/>
+								<option id="gnu.cpp.link.option.paths.1028458235" name="Library search path (-L)" superClass="gnu.cpp.link.option.paths" valueType="libPaths">
+									<listOptionValue builtIn="false" value="../../lib/"/>
+								</option>
+								<inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.1121523546" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
+									<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+									<additionalInput kind="additionalinput" paths="$(LIBS)"/>
+								</inputType>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.cross.archiver.1755526938" name="Cross GCC Archiver" superClass="cdt.managedbuild.tool.gnu.cross.archiver"/>
+							<tool id="cdt.managedbuild.tool.gnu.cross.assembler.1127505743" name="Cross GCC Assembler" superClass="cdt.managedbuild.tool.gnu.cross.assembler">
+								<inputType id="cdt.managedbuild.tool.gnu.assembler.input.942916331" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
+							</tool>
+						</toolChain>
+					</folderInfo>
+					<fileInfo id="cdt.managedbuild.config.gnu.cross.exe.release.1045629552.1047610922" name="all.C" rcbsApplicability="disable" resourcePath="all.C" toolsToInvoke="cdt.managedbuild.tool.gnu.cross.cpp.compiler.1079844465.958761479">
+						<tool id="cdt.managedbuild.tool.gnu.cross.cpp.compiler.1079844465.958761479" name="Cross G++ Compiler" superClass="cdt.managedbuild.tool.gnu.cross.cpp.compiler.1079844465"/>
+					</fileInfo>
+					<sourceEntries>
+						<entry excluding="all.C|rgctest.C|t1.C" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
+					</sourceEntries>
+				</configuration>
+			</storageModule>
+			<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+		</cconfiguration>
+	</storageModule>
+	<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+		<project id="cpoll.cdt.managedbuild.target.gnu.cross.exe.1693737036" name="Executable" projectType="cdt.managedbuild.target.gnu.cross.exe"/>
+	</storageModule>
+	<storageModule moduleId="scannerConfiguration">
+		<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.cross.exe.release.1045629552;cdt.managedbuild.config.gnu.cross.exe.release.1045629552.;cdt.managedbuild.tool.gnu.cross.c.compiler.1696552579;cdt.managedbuild.tool.gnu.c.compiler.input.1212703011">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.cross.exe.debug.317623061;cdt.managedbuild.config.gnu.cross.exe.debug.317623061.;cdt.managedbuild.tool.gnu.cross.cpp.compiler.269481599;cdt.managedbuild.tool.gnu.cpp.compiler.input.224156660">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.cross.exe.release.1045629552;cdt.managedbuild.config.gnu.cross.exe.release.1045629552.;cdt.managedbuild.tool.gnu.cross.cpp.compiler.1079844465;cdt.managedbuild.tool.gnu.cpp.compiler.input.1689339885">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.cross.exe.debug.317623061;cdt.managedbuild.config.gnu.cross.exe.debug.317623061.;cdt.managedbuild.tool.gnu.cross.c.compiler.879901365;cdt.managedbuild.tool.gnu.c.compiler.input.1660037459">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
+		</scannerConfigBuildInfo>
+	</storageModule>
+	<storageModule moduleId="refreshScope" versionNumber="2">
+		<configuration configurationName="Release">
+			<resource resourceType="PROJECT" workspacePath="/cpoll"/>
+		</configuration>
+		<configuration configurationName="Debug">
+			<resource resourceType="PROJECT" workspacePath="/cpoll"/>
+		</configuration>
+	</storageModule>
+	<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
+	<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
+</cproject>

+ 83 - 0
cpoll_cppsp/cppsp_rel0.2.3/cpoll/.project

@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>cpoll</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
+			<triggers>clean,full,incremental,</triggers>
+			<arguments>
+				<dictionary>
+					<key>?name?</key>
+					<value></value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.append_environment</key>
+					<value>true</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.autoBuildTarget</key>
+					<value>all</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.buildArguments</key>
+					<value></value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.buildCommand</key>
+					<value>make</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.buildLocation</key>
+					<value>${workspace_loc:/cpoll/Debug}</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.cleanBuildTarget</key>
+					<value>clean</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.contents</key>
+					<value>org.eclipse.cdt.make.core.activeConfigSettings</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.enableAutoBuild</key>
+					<value>false</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.enableCleanBuild</key>
+					<value>true</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.enableFullBuild</key>
+					<value>true</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.fullBuildTarget</key>
+					<value>all</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.stopOnError</key>
+					<value>true</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.useDefaultBuildCmd</key>
+					<value>true</value>
+				</dictionary>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
+			<triggers>full,incremental,</triggers>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.cdt.core.cnature</nature>
+		<nature>org.eclipse.cdt.core.ccnature</nature>
+		<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
+		<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
+	</natures>
+</projectDescription>

+ 4 - 0
cpoll_cppsp/cppsp_rel0.2.3/cpoll/all.C

@@ -0,0 +1,4 @@
+#include "cpoll.C"
+#include "statemachines.C"
+#include "sendfd.C"
+

+ 2461 - 0
cpoll_cppsp/cppsp_rel0.2.3/cpoll/cpoll.C

@@ -0,0 +1,2461 @@
+/*
+ * cpoll.C
+ *
+ *  Created on: 2012-09-14
+ *      Author: xaxaxa
+ */
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * */
+#include "include/cpoll.H"
+#include "include/cpoll_internal.H"
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdexcept>
+#include "include/statemachines.H"
+#include <dirent.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <sstream>
+#include <sys/timerfd.h>
+#include <algorithm>
+
+namespace CP
+{
+	//CPollException
+
+	CPollException::CPollException() :
+			message(strerror(errno)), number(errno) {
+	}
+	CPollException::CPollException(int32_t number) :
+			message(strerror(number)), number(number) {
+	}
+	CPollException::CPollException(string message, int32_t number) :
+			message(message), number(number) {
+	}
+	CPollException::~CPollException() throw () {
+	}
+	const char* CPollException::what() const throw () {
+		return message.c_str();
+	}
+
+	AbortException::AbortException() {
+	}
+	AbortException::~AbortException() throw () {
+	}
+	const char* AbortException::what() const throw () {
+		return "aborting cpoll loop";
+	}
+
+	CancelException::CancelException() {
+	}
+	CancelException::~CancelException() throw () {
+	}
+	const char* CancelException::what() const throw () {
+		return "cancelling current cpoll operation";
+	}
+
+	vector<RGC::Ref<EndPoint> > EndPoint::lookupHost(const char* hostname, const char* port,
+			int32_t family, int32_t socktype, int32_t proto, int32_t flags) {
+		vector<RGC::Ref<EndPoint> > tmp;
+		addrinfo hints, *result, *rp;
+		memset(&hints, 0, sizeof(struct addrinfo));
+		hints.ai_family = family; /* Allow IPv4 or IPv6 */
+		hints.ai_socktype = socktype;
+		hints.ai_flags = flags;
+		hints.ai_protocol = proto;
+
+		int32_t s = getaddrinfo(hostname, port, &hints, &result);
+		if (s != 0) {
+			throw CPollException(gai_strerror(s));
+		}
+		for (rp = result; rp != NULL; rp = rp->ai_next) {
+			EndPoint* ep = fromSockAddr(rp->ai_addr);
+			tmp.push_back(ep);
+			ep->release();
+		}
+		freeaddrinfo(result);
+		return tmp;
+	}
+	EndPoint* EndPoint::fromSockAddr(const sockaddr* addr) {
+		switch (addr->sa_family) {
+			case AF_INET:
+				return new IPEndPoint(*((sockaddr_in*) addr));
+			case AF_INET6:
+				return new IPv6EndPoint(*((sockaddr_in6*) addr));
+			case AF_UNIX:
+				return new UNIXEndPoint(*((sockaddr_un*) addr));
+			default:
+				return NULL;
+		}
+	}
+	EndPoint* EndPoint::create(int32_t addressFamily) {
+		switch (addressFamily) {
+			case AF_INET:
+				return new IPEndPoint();
+			case AF_INET6:
+				return new IPv6EndPoint();
+			case AF_UNIX:
+				return new UNIXEndPoint();
+			default:
+				return NULL;
+		}
+	}
+	int EndPoint::getSize(int32_t addressFamily) {
+		switch (addressFamily) {
+			case AF_INET:
+				return sizeof(IPEndPoint);
+			case AF_INET6:
+				return sizeof(IPv6EndPoint);
+			case AF_UNIX:
+				return sizeof(UNIXEndPoint);
+			default:
+				return 0;
+		}
+	}
+	EndPoint* EndPoint::construct(void* mem, int32_t addressFamily) {
+		switch (addressFamily) {
+			case AF_INET:
+				return new (mem) IPEndPoint;
+			case AF_INET6:
+				return new (mem) IPv6EndPoint;
+			case AF_UNIX:
+				return new (mem) UNIXEndPoint;
+			default:
+				return NULL;
+		}
+	}
+
+	//IPEndPoint
+
+	IPEndPoint::IPEndPoint() {
+		this->addressFamily = AF_INET;
+	}
+	IPEndPoint::IPEndPoint(IPAddress address, in_port_t port) {
+		this->addressFamily = AF_INET;
+		this->address = address;
+		this->port = port;
+	}
+	void IPEndPoint::set_addr(const sockaddr_in& addr) {
+		this->addressFamily = AF_INET;
+		this->address = IPAddress(addr.sin_addr);
+		this->port = ntohs(addr.sin_port);
+	}
+	void IPEndPoint::setSockAddr(const sockaddr* addr) {
+		if (addr->sa_family != AF_INET) throw CPollException(
+				"attemting to set the address of an IPEndPoint to a sockaddr that is not AF_INET");
+		set_addr(*(sockaddr_in*) addr);
+	}
+	IPEndPoint::IPEndPoint(const sockaddr_in& addr) {
+		set_addr(addr);
+	}
+	void IPEndPoint::getSockAddr(sockaddr* addr) const {
+		sockaddr_in* addr_in = (sockaddr_in*) addr;
+		addr_in->sin_family = AF_INET;
+		addr_in->sin_port = htons(port);
+		addr_in->sin_addr = address.a;
+	}
+	int32_t IPEndPoint::getSockAddrSize() const {
+		return sizeof(sockaddr_in);
+	}
+	void IPEndPoint::clone(EndPoint& to) const {
+		if (to.addressFamily != addressFamily) throw CPollException(
+				"attempting to clone an EndPoint to another EndPoint with a different addressFamily");
+		IPEndPoint& tmp((IPEndPoint&) to);
+		tmp.address = address;
+		tmp.port = port;
+	}
+	string IPEndPoint::toStr() const {
+		stringstream s;
+		s << address.toStr() << ':' << port;
+		return s.str();
+	}
+
+	//IPv6EndPoint
+
+	IPv6EndPoint::IPv6EndPoint() {
+		this->addressFamily = AF_INET6;
+	}
+	IPv6EndPoint::IPv6EndPoint(IPv6Address address, in_port_t port) {
+		this->addressFamily = AF_INET6;
+		this->address = address;
+		this->port = port;
+	}
+	void IPv6EndPoint::set_addr(const sockaddr_in6& addr) {
+		this->addressFamily = AF_INET6;
+		this->address = IPv6Address(addr.sin6_addr);
+		this->port = ntohs(addr.sin6_port);
+		flowInfo = addr.sin6_flowinfo;
+		scopeID = addr.sin6_scope_id;
+	}
+	IPv6EndPoint::IPv6EndPoint(const sockaddr_in6& addr) {
+		set_addr(addr);
+	}
+	void IPv6EndPoint::setSockAddr(const sockaddr* addr) {
+		if (addr->sa_family != AF_INET6) throw CPollException(
+				"attemting to set the address of an IPv6EndPoint to a sockaddr that is not AF_INET6");
+		set_addr(*(sockaddr_in6*) addr);
+	}
+	void IPv6EndPoint::getSockAddr(sockaddr* addr) const {
+		sockaddr_in6* addr_in = (sockaddr_in6*) addr;
+		addr_in->sin6_family = AF_INET6;
+		addr_in->sin6_port = htons(port);
+		addr_in->sin6_addr = address.a;
+		addr_in->sin6_flowinfo = flowInfo;
+		addr_in->sin6_scope_id = scopeID;
+	}
+	int32_t IPv6EndPoint::getSockAddrSize() const {
+		return sizeof(sockaddr_in);
+	}
+	void IPv6EndPoint::clone(EndPoint& to) const {
+		if (to.addressFamily != addressFamily) throw CPollException(
+				"attempting to clone an EndPoint to another EndPoint with a different addressFamily");
+		IPv6EndPoint& tmp((IPv6EndPoint&) to);
+		tmp.address = address;
+		tmp.port = port;
+		tmp.flowInfo = flowInfo;
+		tmp.scopeID = scopeID;
+	}
+	string IPv6EndPoint::toStr() const {
+		stringstream s;
+		s << '[' << address.toStr() << "]:" << port;
+		return s.str();
+	}
+
+	//UNIXEndPoint
+	UNIXEndPoint::UNIXEndPoint() {
+		this->addressFamily = AF_UNIX;
+	}
+	UNIXEndPoint::UNIXEndPoint(string name) {
+		this->addressFamily = AF_UNIX;
+		this->name = name;
+	}
+	void UNIXEndPoint::set_addr(const sockaddr_un& addr) {
+		this->addressFamily = AF_UNIX;
+		this->name = addr.sun_path;
+	}
+	UNIXEndPoint::UNIXEndPoint(const sockaddr_un& addr) {
+		set_addr(addr);
+	}
+	void UNIXEndPoint::setSockAddr(const sockaddr* addr) {
+		if (addr->sa_family != AF_UNIX) throw CPollException(
+				"attemting to set the address of an UNIXEndPoint to a sockaddr that is not AF_UNIX");
+		set_addr(*(sockaddr_un*) addr);
+	}
+	void UNIXEndPoint::getSockAddr(sockaddr* addr) const {
+		sockaddr_un* a = (sockaddr_un*) addr;
+		a->sun_family = AF_UNIX;
+		strncpy(a->sun_path, name.c_str(), name.length());
+		a->sun_path[name.length()] = '\0';
+	}
+	int32_t UNIXEndPoint::getSockAddrSize() const {
+		return sizeof(sa_family_t) + name.length() + 1;
+	}
+	void UNIXEndPoint::clone(EndPoint& to) const {
+		if (to.addressFamily != addressFamily) throw CPollException(
+				"attempting to clone an EndPoint to another EndPoint with a different addressFamily");
+		UNIXEndPoint& tmp((UNIXEndPoint&) to);
+		tmp.name = name;
+	}
+	string UNIXEndPoint::toStr() const {
+		return name;
+		//XXX
+	}
+
+	static void Stream_readCB(Stream* This, int i);
+	static void Stream_beginRead(Stream* This) {
+		auto& tmp = This->_readToEnd;
+		auto* out = tmp.out;
+		if (out->bufferSize - out->bufferPos < tmp.bufSize) out->flushBuffer(tmp.bufSize);
+		This->read(out->buffer + out->bufferPos, out->bufferSize - out->bufferPos, { &Stream_readCB,
+				This });
+	}
+	static void Stream_readCB(Stream* This, int i) {
+		auto& tmp = This->_readToEnd;
+		if (i <= 0) {
+			tmp.cb(tmp.br);
+			return;
+		}
+		tmp.out->bufferPos += i;
+		tmp.br += i;
+		Stream_beginRead(This);
+	}
+
+	static void Stream_readCB1(Stream* This, int i);
+	static void Stream_beginRead1(Stream* This) {
+		auto& tmp = This->_readChunked;
+		auto* out = tmp.out;
+		int x = (tmp.len - tmp.br) > tmp.bufSize ? tmp.bufSize : (tmp.len - tmp.br);
+		if (x <= 0) {
+			tmp.cb(tmp.br);
+			return;
+		}
+		if (out->bufferSize - out->bufferPos < x) out->flushBuffer(x);
+		This->read(out->buffer + out->bufferPos, x, { &Stream_readCB1, This });
+	}
+	static void Stream_readCB1(Stream* This, int i) {
+		auto& tmp = This->_readChunked;
+		if (i <= 0) {
+			tmp.cb(tmp.br);
+			return;
+		}
+		tmp.out->bufferPos += i;
+		tmp.br += i;
+		Stream_beginRead1(This);
+	}
+
+	static inline void Stream_beginReadv(Stream* This) {
+		if (This->_readvAll.i < This->_readvAll.iovcnt) This->readv(
+				This->_readvAll.iov + This->_readvAll.i, This->_readvAll.iovcnt - This->_readvAll.i, {
+						&Stream::_readvCB, This });
+		else {
+			This->_readvAll.cb(This->_readvAll.br);
+		}
+	}
+	static inline void Stream_beginReadAll(Stream* This) {
+		if (This->_readAll.i < This->_readAll.len) This->read(This->_readAll.buf + This->_readAll.i,
+				This->_readAll.len - This->_readAll.i, { &Stream::_readAllCB, This });
+		else {
+			This->_readAll.cb(This->_readAll.i);
+		}
+	}
+	void Stream::_readvCB(int r) {
+		if (r <= 0) {
+			_readvAll.cb(_readvAll.br);
+			return;
+		}
+		_readvAll.br += r;
+		while (r > 0 && _readvAll.i < _readvAll.iovcnt) {
+			if ((int) _readvAll.iov[_readvAll.i].iov_len > r) {
+				_readvAll.iov[_readvAll.i].iov_base = ((uint8_t*) _readvAll.iov[_readvAll.i].iov_base)
+						+ r;
+				_readvAll.iov[_readvAll.i].iov_len -= r;
+				break;
+			} else {
+				r -= _readvAll.iov[_readvAll.i].iov_len;
+				_readvAll.i++;
+			}
+		}
+		Stream_beginReadv(this);
+	}
+	void Stream::_readAllCB(int r) {
+		if (r <= 0) {
+			_readAll.cb(_readAll.i);
+			return;
+		}
+		_readAll.i += r;
+		Stream_beginReadAll(this);
+	}
+	static inline void Stream_beginWritev(Stream* This) {
+		if (This->_writevAll.i < This->_writevAll.iovcnt) This->writev(
+				This->_writevAll.iov + This->_writevAll.i, This->_writevAll.iovcnt - This->_writevAll.i,
+				{ &Stream::_writevCB, This });
+		else {
+			This->_writevAll.cb(This->_writevAll.br);
+		}
+	}
+	static inline void Stream_beginWriteAll(Stream* This) {
+		if (This->_writeAll.i < This->_writeAll.len) This->write(
+				This->_writeAll.buf + This->_writeAll.i, This->_writeAll.len - This->_writeAll.i, {
+						&Stream::_writeAllCB, This });
+		else {
+			This->_writeAll.cb(This->_writeAll.i);
+		}
+	}
+	void Stream::_writevCB(int r) {
+		if (r <= 0) {
+			_writevAll.cb(_writevAll.br);
+			return;
+		}
+		_writevAll.br += r;
+		while (r > 0 && _writevAll.i < _writevAll.iovcnt) {
+			if ((int) _writevAll.iov[_writevAll.i].iov_len > r) {
+				_writevAll.iov[_writevAll.i].iov_base =
+						((uint8_t*) _writevAll.iov[_writevAll.i].iov_base) + r;
+				_writevAll.iov[_writevAll.i].iov_len -= r;
+				break;
+			} else {
+				r -= _writevAll.iov[_writevAll.i].iov_len;
+				_writevAll.i++;
+			}
+		}
+		Stream_beginWritev(this);
+	}
+	void Stream::_writeAllCB(int r) {
+		if (r <= 0) {
+			_writeAll.cb(_writeAll.i);
+			return;
+		}
+		_writeAll.i += r;
+		Stream_beginWriteAll(this);
+	}
+
+	int Stream::readToEnd(BufferedOutput& out, int32_t bufSize) {
+		int r = 0;
+		while (true) {
+			if (out.bufferSize - out.bufferPos < bufSize) out.flushBuffer(bufSize);
+			int i = read(out.buffer + out.bufferPos, out.bufferSize - out.bufferPos);
+			if (i <= 0) return r;
+			out.bufferPos += i;
+			r += i;
+		}
+	}
+	int Stream::readChunked(BufferedOutput& out, int32_t len, int32_t bufSize) {
+		int r = 0;
+		while (true) {
+			int x = (len - r) > bufSize ? bufSize : (len - r);
+			if (x <= 0) return r;
+			if (out.bufferSize - out.bufferPos < x) out.flushBuffer(x);
+			int i = read(out.buffer + out.bufferPos, x);
+			if (i <= 0) return r;
+			out.bufferPos += i;
+			r += i;
+		}
+	}
+
+	void Stream::readToEnd(BufferedOutput& out, const Callback& cb, int32_t bufSize) {
+		_readToEnd.cb = cb;
+		_readToEnd.bufSize = bufSize;
+		_readToEnd.out = &out;
+		_readToEnd.br = 0;
+		Stream_beginRead(this);
+	}
+	void Stream::readChunked(BufferedOutput& out, int32_t len, const Callback& cb, int32_t bufSize) {
+		_readChunked.cb = cb;
+		_readChunked.bufSize = bufSize;
+		_readChunked.out = &out;
+		_readChunked.len = len;
+		_readChunked.br = 0;
+		Stream_beginRead1(this);
+	}
+	BufferedOutput* Stream::getBufferedOutput() {
+		return NULL;
+	}
+	void Stream::readvAll(iovec* iov, int iovcnt, const Callback& cb) {
+		_readvAll= {cb,iov,iovcnt,0,0};
+		Stream_beginReadv(this);
+	}
+	void Stream::readAll(void* buf, int32_t len, const Callback& cb) {
+		_readAll= {cb,(uint8_t*)buf,len,0};
+		Stream_beginReadAll(this);
+	}
+	void Stream::writevAll(iovec* iov, int iovcnt, const Callback& cb) {
+		_writevAll= {cb,iov,iovcnt,0,0};
+		Stream_beginWritev(this);
+	}
+	void Stream::writeAll(const void* buf, int32_t len, const Callback& cb) {
+		_writeAll= {cb,(const uint8_t*)buf,len,0};
+		Stream_beginWriteAll(this);
+	}
+
+	StreamWriter::StreamWriter(BufferedOutput& s) :
+			outp(&s), buffer(&s), sb(*(StreamBuffer*) nullptr) {
+
+	}
+	StreamWriter::StreamWriter(Stream& s) :
+			outp(&s), buffer(s.getBufferedOutput()),
+					sb(buffer == NULL ? *(new (_sb) StreamBuffer(s)) : *(StreamBuffer*) nullptr) {
+		if (buffer == NULL) buffer = &sb;
+	}
+	StreamWriter::StreamWriter(MemoryStream& s) :
+			outp(&s), buffer(&s), sb(*(StreamBuffer*) nullptr) {
+	}
+	StreamWriter::StreamWriter(StringStream& s) :
+			outp(&s), buffer(&s), sb(*(StreamBuffer*) nullptr) {
+	}
+	StreamWriter::~StreamWriter() {
+		flush();
+		if (buffer == &sb) sb.~StreamBuffer();
+	}
+
+	StreamBuffer::StreamBuffer() {
+		this->buffer = NULL;
+	}
+	StreamBuffer::StreamBuffer(Stream& s, int bufsize) :
+			BufferedOutput((uint8_t*) malloc(bufsize), 0, bufsize), output(s) {
+		if (this->buffer == NULL) throw bad_alloc();
+	}
+	void StreamBuffer::flushBuffer(int minBufferAllocation) {
+		if (bufferPos <= 0) return;
+		if (minBufferAllocation > bufferSize) {
+			int bs = bufferSize;
+			do {
+				bs *= 2;
+			} while (minBufferAllocation > bs);
+			void* newbuffer = realloc(buffer, bs);
+			if (newbuffer == NULL) throw bad_alloc();
+			buffer = (uint8_t*) newbuffer;
+			bufferSize = bs;
+		}
+		output->write(buffer, bufferPos);
+		bufferPos = 0;
+	}
+
+	StreamReader::StreamReader(Stream& input, int bufsize) :
+			input(&input), _sr(malloc(bufsize), bufsize), deletionFlag(NULL), bufSize(bufsize),
+					eof(false) {
+		//sr = malloc(streamReader_getSize() + bufsize);
+		if (_sr.buffer == NULL) throw bad_alloc();
+	}
+	StreamReader::~StreamReader() {
+		if (deletionFlag != NULL) *deletionFlag = true;
+		free(_sr.buffer);
+	}
+	void StreamReader_checkReading1(StreamReader* This) {
+		//if (This->shouldRead) throw CPollException("StreamReader is already reading");
+	}
+	void StreamReader_checkReading(StreamReader* This) {
+		//StreamReader_checkReading1(This);
+		//This->shouldRead = true;
+	}
+	void StreamReader_prepareAsyncRead(StreamReader* This, const StreamReader::Callback& cb) {
+		This->cb = cb;
+		This->out_s = NULL;
+		StreamReader_checkReading(This);
+	}
+	void StreamReader_prepareSyncRead(StreamReader* This) {
+		This->cb = nullptr;
+		This->out_s = NULL;
+		This->tmp.clear();
+		StreamReader_checkReading(This);
+	}
+	void StreamReader_prepareAsyncReadStream(StreamReader* This, Stream& s,
+			const StreamReader::StreamCallback& cb) {
+		This->cb_s = cb;
+		This->out_s = &s;
+		This->tmp_i = 0;
+		StreamReader_checkReading(This);
+	}
+	void StreamReader_prepareSyncReadStream(StreamReader* This, Stream& s) {
+		This->cb_s = nullptr;
+		This->out_s = &s;
+		This->tmp_i = 0;
+		StreamReader_checkReading(This);
+	}
+
+	void StreamReader::readTo(char delim, const Callback& cb) {
+		StreamReader_prepareAsyncRead(this, cb);
+		_sr.readUntilChar(delim);
+		_loop(true);
+	}
+	void StreamReader::readTo(const char* delim, int delimLen, const Callback& cb) {
+		StreamReader_prepareAsyncRead(this, cb);
+		_sr.readUntilString(delim, delimLen);
+		_loop(true);
+	}
+	void StreamReader::readTo(string delim, const Callback& cb) {
+		StreamReader_prepareAsyncRead(this, cb);
+		tmp_delim = delim;
+		_sr.readUntilString(tmp_delim.data(), tmp_delim.length());
+		_loop(true);
+	}
+	void StreamReader::readLine(const Callback& cb) {
+		readTo('\n', cb);
+	}
+	string StreamReader::readTo(char delim) {
+		StreamReader_prepareSyncRead(this);
+		_sr.readUntilChar(delim);
+		_doSyncRead();
+		return this->tmp;
+	}
+	string StreamReader::readTo(const char* delim, int delimLen) {
+		StreamReader_prepareSyncRead(this);
+		_sr.readUntilString(delim, delimLen);
+		_doSyncRead();
+		return this->tmp;
+	}
+	string StreamReader::readTo(string delim) {
+		StreamReader_prepareSyncRead(this);
+		_sr.readUntilString(delim.data(), delim.length());
+		_doSyncRead();
+		return this->tmp;
+	}
+	string StreamReader::readLine() {
+		return readTo('\n');
+	}
+	int StreamReader::readTo(char delim, Stream& s) {
+		StreamReader_prepareSyncReadStream(this, s);
+		_sr.readUntilChar(delim);
+		_doSyncRead();
+		return this->tmp_i;
+	}
+	int StreamReader::readTo(const char* delim, int delimLen, Stream& s) {
+		StreamReader_prepareSyncReadStream(this, s);
+		_sr.readUntilString(delim, delimLen);
+		_doSyncRead();
+		return this->tmp_i;
+	}
+	int StreamReader::readTo(string delim, Stream& s) {
+		StreamReader_prepareSyncReadStream(this, s);
+		tmp_delim = delim;
+		_sr.readUntilString(tmp_delim.data(), tmp_delim.length());
+		_doSyncRead();
+		return this->tmp_i;
+	}
+	int StreamReader::readLine(Stream& s) {
+		return readTo('\n', s);
+	}
+	void StreamReader::readTo(char delim, Stream& s, const StreamCallback& cb) {
+		StreamReader_prepareAsyncReadStream(this, s, cb);
+		_sr.readUntilChar(delim);
+		_loop(true);
+	}
+	void StreamReader::readTo(const char* delim, int delimLen, Stream& s, const StreamCallback& cb) {
+		StreamReader_prepareAsyncReadStream(this, s, cb);
+		_sr.readUntilString(delim, delimLen);
+		_loop(true);
+	}
+	void StreamReader::readTo(string delim, Stream& s, const StreamCallback& cb) {
+		StreamReader_prepareAsyncReadStream(this, s, cb);
+		tmp_delim = delim;
+		_sr.readUntilString(tmp_delim.data(), tmp_delim.length());
+		_loop(true);
+	}
+	void StreamReader::readLine(Stream& s, const StreamCallback& cb) {
+		readTo('\n', s, cb);
+	}
+	int32_t StreamReader::read(void* buf, int32_t len) {
+		void* tmp;
+		int l = readBuffer(tmp, len);
+		if (l <= 0) {
+			freeBuffer(tmp, l);
+			return input->read(buf, len);
+		}
+		memcpy(buf, tmp, l);
+		freeBuffer(tmp, l);
+		return l;
+	}
+	void StreamReader::read(void* buf, int32_t len, const CP::Callback& cb, bool repeat) {
+		void* tmp;
+		int l = readBuffer(tmp, len);
+		if (l <= 0) {
+			freeBuffer(tmp, l);
+			return input->read(buf, len, cb, repeat);
+		}
+		memcpy(buf, tmp, l);
+		freeBuffer(tmp, l);
+		cb(l);
+	}
+	void StreamReader::readAll(void* buf, int32_t len, const CP::Callback& cb) {
+		void* tmp;
+		int l = readBuffer(tmp, len);
+		if (l < len) {
+			freeBuffer(tmp, l);
+			return input->readAll(((uint8_t*) buf) + l, len - l, cb);
+		}
+		memcpy(buf, tmp, l);
+		cb(l);
+		freeBuffer(tmp, l);
+	}
+	void StreamReader::close() {
+		input->close();
+	}
+	void StreamReader::flush() {
+		input->flush();
+	}
+	void StreamReader::close(const CP::Callback& cb) {
+		input->close(cb);
+	}
+	void StreamReader::flush(const CP::Callback& cb) {
+		input->flush(cb);
+	}
+	int32_t StreamReader::readBuffer(void*& buf, int32_t maxlen) {
+		StreamReader_checkReading1(this);
+		String tmp = _sr.getBufferData();
+		if (tmp.len > maxlen) tmp.len = maxlen;
+		if (tmp.len <= 0) return 0;
+		buf = tmp.data();
+		return tmp.len;
+	}
+	void StreamReader::freeBuffer(void* buf, int32_t len) {
+		_sr.skip(len);
+	}
+
+	bool StreamReader::_loop(bool async) {
+		newStreamReader::item it;
+		bool delFlag = false;
+		deletionFlag = &delFlag;
+		while (_sr.process(it)) {
+			if (out_s != NULL) {
+				out_s->write(it.data.data(), it.data.length());
+				tmp_i += it.data.length();
+			} else tmp.append(it.data.data(), it.data.length());
+			if (it.delimReached) {
+				if (out_s == NULL) {
+					if (cb == nullptr) goto skipRead;
+					bool* delFlag = deletionFlag;
+					cb(tmp);
+					if (*delFlag) goto skipRead;
+					tmp.clear();
+				} else {
+					if (cb_s == nullptr) goto skipRead;
+					cb_s(tmp_i);
+				}
+				return false;
+			}
+		}
+		if (async) {
+			_beginRead();
+			deletionFlag = NULL;
+			return true;
+		}
+		skipRead: if (!delFlag) deletionFlag = NULL;
+		return false;
+	}
+	void StreamReader::_beginRead() {
+		String buf = _sr.beginPutData();
+		if (buf.data() == NULL) return;
+		input->read(buf.data(), buf.length(), CP::Callback(&StreamReader::_readCB, this));
+	}
+	void StreamReader::_doSyncRead() {
+		while (_loop(false)) {
+			String buf = _sr.beginPutData();
+			//if (get < 1 > (buf) <= 0) return;
+			int r = input->read(buf.data(), buf.length());
+			if (r <= 0) {
+				String tmp = _sr.getBufferData();
+				if (out_s == NULL) {
+					string tmps = tmp.toSTDString();
+					eof = true;
+					_sr.reset();
+					cb(tmps);
+				} else {
+					out_s->write(tmp.data(), tmp.length());
+					tmp_i += tmp.length();
+					_sr.reset();
+					cb_s(tmp_i);
+				}
+				return;
+			} else {
+				_sr.endPutData(r);
+			}
+		}
+	}
+	void StreamReader::_readCB(int i) {
+		if (i <= 0) {
+			String tmp = _sr.getBufferData();
+			eof = true;
+			if (out_s == NULL) {
+				string tmps = tmp.toSTDString();
+				_sr.reset();
+				cb(tmps);
+			} else {
+				out_s->write(tmp.data(), tmp.length());
+				tmp_i += tmp.length();
+				_sr.reset();
+				cb_s(tmp_i);
+			}
+		} else {
+			_sr.endPutData(i);
+			_loop(true);
+		}
+	}
+	void StreamReader::cancelRead() {
+		input->cancelRead();
+	}
+	void StreamReader::cancelWrite() {
+		input->cancelWrite();
+	}
+
+	Handle::Handle() {
+		deinit();
+	}
+	Handle::Handle(HANDLE handle) {
+		init(handle);
+	}
+	void Handle::init(HANDLE handle) {
+		this->handle = checkError(handle);
+	}
+	void Handle::deinit() {
+		_supportsEPoll = true;
+		handle = -1;
+	}
+	Events Handle::dispatchMultiple(Events events, Events confident, const EventData& evtd) {
+		//cout << (int32_t)events << endl;
+		Events ret = Events::none;
+		for (int32_t i = 0; i < numEvents; i++) {
+			Events e = indexToEvent(i);
+			//cout << (int32_t)e << " " << (((event_t)e)&((event_t)events)) << endl;
+			if ((((event_t) e) & ((event_t) events)) == (event_t) e) {
+				if (dispatch(e, evtd, (confident & e) == e)) ret |= e;
+			}
+		}
+		//cout << ret << endl;
+		return ret;
+	}
+	Events Handle::wait(EventData& evtd) { //since this is single-file, poll() will be used.
+		//Events events=Events::none;
+		Events w = getEvents();
+		pollfd pfd;
+		pfd.fd = handle;
+		pfd.events = eventsToPoll(w);
+		if (pfd.events == 0) return Events::none;
+		poll(&pfd, 1, -1);
+		evtd.hungUp = (pfd.revents & POLLHUP);
+		evtd.error = (pfd.revents & POLLERR);
+		/*for(int32_t i=0;i<numEvents;i++) {
+		 Events e=indexToEvent(i);
+		 short p=eventToPoll(e);
+		 if(p&pfd.revents!=0) events=(Events)((event_t)events | (event_t)e);
+		 }*/
+		return pollToEvents(pfd.revents);
+	}
+	Events Handle::waitAndDispatch() {
+		EventData evtd;
+		Events e = wait(evtd);
+		if (e == Events::none) return e;
+		return dispatchMultiple(e, e, evtd);
+	}
+	void Handle::loop() {
+		try {
+			while (waitAndDispatch() != Events::none)
+				;
+		} catch (const AbortException& ex) {
+
+		}
+	}
+	/*void Handle::close() {
+	 ::close(handle);
+	 }*/
+	Handle::~Handle() {
+		//if (onClose != nullptr) onClose();
+		//::close(handle);
+	}
+
+	static inline bool isWouldBlock() {
+		return errno == EWOULDBLOCK || errno == EAGAIN;
+	}
+//File
+	File::File() :
+			deletionFlag(NULL), dispatching(false) {
+	}
+	File::File(HANDLE handle) :
+			deletionFlag(NULL), dispatching(false) {
+		init(handle);
+	}
+	void File::init(HANDLE handle) {
+		Handle::init(handle);
+	}
+	Events File::_getEvents() {
+		if (dispatching) return preDispatchEvents;
+		Events e = Events::none;
+		for (int32_t i = 0; i < numEvents; i++)
+			if (eventData[i].state != EventHandlerData::States::invalid) (event_t&) e |=
+					(event_t) indexToEvent(i);
+
+		//cout << "_getEvents: " << (int32_t)e << endl;
+		return e;
+	}
+///only accepts one event
+	EventHandlerData* File::beginAddEvent(Events event) {
+		int i = eventToIndex(event);
+		EventHandlerData *ed = &eventData[i];
+		if (ed->state != EventHandlerData::States::invalid) throw CPollException(
+				"Already listening for the specified event on the specified file. "
+						"For example, you may not read() and recv() on one socket at the same time.");
+		eventData[i].opcb = nullptr;
+		return ed;
+	}
+	void File::endAddEvent(Events event, bool repeat) {
+		Events old_events = _getEvents();
+		int i = eventToIndex(event);
+		eventData[i].state =
+				repeat ? (EventHandlerData::States::repeat) : (EventHandlerData::States::once);
+		if (onEventsChange != nullptr && !dispatching) onEventsChange(*this, old_events);
+	}
+	void File::cancel(Events event) {
+		Events old_events = _getEvents();
+		eventData[eventToIndex(event)].state = EventHandlerData::States::invalid;
+		if (onEventsChange != nullptr && !dispatching) onEventsChange(*this, old_events);
+	}
+	int32_t File::read(void* buf, int32_t len) {
+		return ::read(handle, buf, len);
+	}
+	int32_t File::write(const void* buf, int32_t len) {
+		return ::write(handle, buf, len);
+	}
+	/*int32_t File::writeAll(const void* buf, int32_t len) {
+	 int32_t bw = 0, bw1 = 0;
+	 while (bw < len && (bw1 = write(((char*) buf) + bw, len - bw)) > 0)
+	 bw += bw1;
+	 return (bw1 < 0 && bw <= 0) ? -1 : bw;
+	 }*/
+	int32_t File::send(const void* buf, int32_t len, int32_t flags) {
+		return ::send(handle, buf, len, flags);
+	}
+	int32_t File::sendAll(const void* buf, int32_t len, int32_t flags) {
+		int32_t bw = 0, bw1 = 0;
+		while (bw < len && (bw1 = send(((char*) buf) + bw, len - bw, flags)) > 0)
+			bw += bw1;
+		return (bw1 < 0 && bw <= 0) ? -1 : bw;
+	}
+	int32_t File::recv(void* buf, int32_t len, int32_t flags) {
+		return ::recv(handle, buf, len, flags);
+	}
+	int32_t File::recvAll(void* buf, int32_t len, int32_t flags) {
+		int32_t bw = 0, bw1 = 0;
+		while (bw < len && (bw1 = recv(((char*) buf) + bw, len - bw, flags)) > 0)
+			bw += bw1;
+		return (bw1 < 0 && bw <= 0) ? -1 : bw;
+	}
+	Events File::checkEvents(Events events) {
+		pollfd pfd;
+		pfd.fd = handle;
+		pfd.events = eventsToPoll(events);
+		poll(&pfd, 1, 0);
+		return pollToEvents(pfd.revents);
+	}
+	bool File::doOperation(Events event, EventHandlerData& ed, const EventData& evtd,
+			EventHandlerData::States oldstate, bool confident) {
+		Operations op = ed.op;
+		int32_t r;
+		redo: r = 0;
+		if (unlikely(handle<0)) {
+			r = -1;
+			goto asdf;
+		}
+		switch (op) {
+			case Operations::read:
+				r = read(ed.misc.bufferIO.buf, ed.misc.bufferIO.len);
+				break;
+			case Operations::readv:
+				r = readv(ed.misc.bufferIOv.iov, ed.misc.bufferIOv.iovcnt);
+				break;
+			case Operations::readAll:
+				r = read(((char*) ed.misc.bufferIO.buf) + ed.misc.bufferIO.len_done,
+						ed.misc.bufferIO.len - ed.misc.bufferIO.len_done);
+				if (r <= 0) {
+					if (r < 0 && isWouldBlock()) return false;
+					ed.state = EventHandlerData::States::invalid;
+					if (ed.cb != nullptr) ed.cb(
+							ed.misc.bufferIO.len_done == 0 ? r : ed.misc.bufferIO.len_done);
+					return true;
+				}
+				ed.misc.bufferIO.len_done += r;
+				if (ed.misc.bufferIO.len_done >= ed.misc.bufferIO.len) {
+					ed.state = EventHandlerData::States::invalid;
+					if (ed.cb != nullptr) ed.cb(ed.misc.bufferIO.len_done);
+				}
+				return true;
+			case Operations::write:
+				r = write(ed.misc.bufferIO.buf, ed.misc.bufferIO.len);
+				break;
+			case Operations::writev:
+				r = writev(ed.misc.bufferIOv.iov, ed.misc.bufferIOv.iovcnt);
+				break;
+			case Operations::writeAll:
+				r = write(((char*) ed.misc.bufferIO.buf) + ed.misc.bufferIO.len_done,
+						ed.misc.bufferIO.len - ed.misc.bufferIO.len_done);
+				//cout << "wrote " << r << " bytes on fd " << handle << endl;
+				if (r <= 0) {
+					if (r < 0 && isWouldBlock()) return false;
+					ed.state = EventHandlerData::States::invalid;
+					if (ed.cb != nullptr) ed.cb(
+							ed.misc.bufferIO.len_done == 0 ? r : ed.misc.bufferIO.len_done);
+					return true;
+				}
+				ed.misc.bufferIO.len_done += r;
+				//cout << "len_done = " << ed.misc.bufferIO.len_done
+				//		<< " of " << ed.misc.bufferIO.len << endl;
+				if (ed.misc.bufferIO.len_done >= ed.misc.bufferIO.len) {
+					ed.state = EventHandlerData::States::invalid;
+					if (ed.cb != nullptr) ed.cb(ed.misc.bufferIO.len_done);
+				}
+				return true;
+			case Operations::recv:
+				r = recv(ed.misc.bufferIO.buf, ed.misc.bufferIO.len, ed.misc.bufferIO.flags);
+				break;
+			case Operations::recvAll:
+				r = recv(((char*) ed.misc.bufferIO.buf) + ed.misc.bufferIO.len_done,
+						ed.misc.bufferIO.len - ed.misc.bufferIO.len_done, ed.misc.bufferIO.flags);
+				if (r <= 0) {
+					if (r < 0 && isWouldBlock()) return false;
+					ed.state = EventHandlerData::States::invalid;
+					if (ed.cb != nullptr) ed.cb(
+							ed.misc.bufferIO.len_done == 0 ? r : ed.misc.bufferIO.len_done);
+					return true;
+				}
+				ed.misc.bufferIO.len_done += r;
+				if (ed.misc.bufferIO.len_done >= ed.misc.bufferIO.len) {
+					ed.state = EventHandlerData::States::invalid;
+					if (ed.cb != nullptr) ed.cb(ed.misc.bufferIO.len_done);
+				}
+				return true;
+			case Operations::send:
+				r = send(ed.misc.bufferIO.buf, ed.misc.bufferIO.len, ed.misc.bufferIO.flags);
+				break;
+			case Operations::sendAll:
+				r = send(((char*) ed.misc.bufferIO.buf) + ed.misc.bufferIO.len_done,
+						ed.misc.bufferIO.len - ed.misc.bufferIO.len_done, ed.misc.bufferIO.flags);
+				if (r <= 0) {
+					if (r < 0 && isWouldBlock()) return false;
+					ed.state = EventHandlerData::States::invalid;
+					if (ed.cb != nullptr) ed.cb(
+							ed.misc.bufferIO.len_done == 0 ? -1 : ed.misc.bufferIO.len_done);
+					return true;
+				}
+				ed.misc.bufferIO.len_done += r;
+				if (ed.misc.bufferIO.len_done >= ed.misc.bufferIO.len) {
+					ed.state = EventHandlerData::States::invalid;
+					if (ed.cb != nullptr) ed.cb(ed.misc.bufferIO.len_done);
+				}
+				return true;
+			case Operations::close:
+				if (!confident && (checkEvents(event) & event) != event) return false;
+				close();
+				break;
+			case Operations::none:
+				if (!confident && (checkEvents(event) & event) != event) return false;
+				if (evtd.error || evtd.hungUp) r = -1;
+				break;
+			default:
+				break;
+		}
+		if (r < 0 && isWouldBlock()) return false;
+		//micro-optimization: assume that the above syscalls will return -1 if there is
+		//an error or hang-up condition
+		if ((r <= 0 && op != Operations::none) /*|| evtd.error || evtd.hungUp*/) {
+			//invalidate the current event listener
+			asdf: ed.state = EventHandlerData::States::invalid;
+		}
+		bool* del = deletionFlag;
+		if (ed.cb != nullptr) ed.cb(r);
+		if (*del) return true;
+		if (ed.state == EventHandlerData::States::repeat) {
+			confident = false;
+			goto redo;
+		}
+		return true;
+	}
+	bool File::dispatch(Events event, const EventData& evtd, bool confident, bool& deletionFlag) {
+		//cout << (int32_t)event << " dispatched" << endl;
+		EventHandlerData& ed = eventData[eventToIndex(event)];
+		if (ed.state == EventHandlerData::States::invalid) return true;
+		EventHandlerData::States oldstate = ed.state;
+		if (ed.state == EventHandlerData::States::once) ed.state = EventHandlerData::States::invalid;
+		dispatching = true;
+		try {
+			if (!doOperation(event, ed, evtd, oldstate, confident)) {
+				dispatching = false;
+				ed.state = oldstate;
+				return false;
+			}
+		} catch (const CancelException& ex) {
+			ed.state = EventHandlerData::States::invalid;
+		}
+		if (deletionFlag) return true;
+		dispatching = false;
+		return true;
+	}
+	Events File::dispatchMultiple(Events events, Events confident, const EventData& evtd) {
+		preDispatchEvents = _getEvents();
+		dispatching = true;
+		Events ret = Events::none;
+		bool d = false;
+		this->deletionFlag = &d;
+		for (int32_t i = 0; i < numEvents; i++) {
+			Events e = indexToEvent(i);
+			//cout << (int32_t)e << " " << (((event_t)e)&((event_t)events)) << endl;
+			if ((((event_t) e) & ((event_t) events)) == (event_t) e) {
+				EventHandlerData& ed = eventData[i];
+				if (ed.state == EventHandlerData::States::invalid) continue;
+				if (ed.opcb != nullptr) {
+					if (ed.opcb(e, ed, evtd, (confident & e) == e)) ret |= e;
+					if (d) break;
+					continue;
+				}
+				EventHandlerData::States oldstate = ed.state;
+				if (ed.state == EventHandlerData::States::once) ed.state =
+						EventHandlerData::States::invalid;
+				try {
+					if (doOperation(e, ed, evtd, oldstate, (confident & e) == e)) {
+						ret |= e;
+						if (d) break;
+					} else {
+						if (d) break;
+						ed.state = oldstate;
+					}
+				} catch (const CancelException& ex) {
+					if (d) break;
+					ed.state = EventHandlerData::States::invalid;
+				}
+				//if (dispatch(e, evtd, (confident & e) == e, d)) ret |= e;
+			}
+		}
+		if (d) return ret;
+		this->deletionFlag = NULL;
+		dispatching = false;
+		return ret;
+	}
+	void File::fillIOEventHandlerData(EventHandlerData* ed, void* buf, int32_t len,
+			const Callback& cb, Events e, Operations op) {
+		ed->cb = cb;
+		ed->misc.bufferIO.buf = buf;
+		ed->misc.bufferIO.len = len;
+		ed->op = op;
+	}
+	void File::fillIOEventHandlerData(EventHandlerData* ed, iovec* iov, int iovcnt,
+			const Callback& cb, Events e, Operations op) {
+		ed->cb = cb;
+		ed->misc.bufferIOv.iov = iov;
+		ed->misc.bufferIOv.iovcnt = iovcnt;
+		ed->op = op;
+	}
+	bool File_doRead(File* This, Events event, EventHandlerData& ed, const EventData& evtd,
+			bool confident) {
+		int r = ::read(This->handle, ed.misc.bufferIO.buf, ed.misc.bufferIO.len);
+		if (r < 0 && isWouldBlock()) return false;
+		if (ed.state == EventHandlerData::States::once || r <= 0) ed.state =
+				EventHandlerData::States::invalid;
+		ed.cb(r);
+		return true;
+	}
+	bool File_doWritev(File* This, Events event, EventHandlerData& ed, const EventData& evtd,
+			bool confident) {
+		int r = ::writev(This->handle, ed.misc.bufferIOv.iov, ed.misc.bufferIOv.iovcnt);
+		if (r < 0 && isWouldBlock()) return false;
+		if (ed.state == EventHandlerData::States::once || r <= 0) ed.state =
+				EventHandlerData::States::invalid;
+		ed.cb(r);
+		return true;
+	}
+	void File::read(void* buf, int32_t len, const Callback& cb, bool repeat) {
+		if (!_supportsEPoll) {
+			asdfg: int32_t r = read(buf, len);
+			cb(r);
+			if (repeat && r > 0) goto asdfg;
+			return;
+		}
+		static const Events e = Events::in;
+		EventHandlerData* ed = beginAddEvent(e);
+		fillIOEventHandlerData(ed, buf, len, cb, e, Operations::read);
+		ed->opcb= {&File_doRead,this};
+		endAddEvent(e, repeat);
+	}
+	void File::readAll(void* buf, int32_t len, const Callback& cb) {
+		if (!_supportsEPoll) {
+			int32_t r = Stream::readAll(buf, len);
+			cb(r);
+			return;
+		}
+		static const Events e = Events::in;
+		EventHandlerData* ed = beginAddEvent(e);
+		fillIOEventHandlerData(ed, (void*) buf, len, cb, e, Operations::readAll);
+		ed->misc.bufferIO.len_done = 0;
+		endAddEvent(e, true);
+	}
+	void File::write(const void* buf, int32_t len, const Callback& cb, bool repeat) {
+		if (!_supportsEPoll) {
+			asdfg: int32_t r = write(buf, len);
+			cb(r);
+			if (repeat && r > 0) goto asdfg;
+			return;
+		}
+		static const Events e = Events::out;
+		EventHandlerData* ed = beginAddEvent(e);
+		fillIOEventHandlerData(ed, (void*) buf, len, cb, e, Operations::write);
+		endAddEvent(e, repeat);
+	}
+	void File::writeAll(const void* buf, int32_t len, const Callback& cb) {
+		if (!_supportsEPoll) {
+			int32_t bw = 0, bw1 = 0;
+			while (bw < len && (bw1 = write(((char*) buf) + bw, len - bw)) > 0)
+				bw += bw1;
+			cb((bw1 < 0 && bw <= 0) ? -1 : bw);
+			return;
+		}
+		static const Events e = Events::out;
+		EventHandlerData* ed = beginAddEvent(e);
+		fillIOEventHandlerData(ed, (void*) buf, len, cb, e, Operations::writeAll);
+		ed->misc.bufferIO.len_done = 0;
+		endAddEvent(e, true);
+	}
+	void File::recv(void* buf, int32_t len, int32_t flags, const Callback& cb, bool repeat) {
+		static const Events e = Events::in;
+		EventHandlerData* ed = beginAddEvent(e);
+		fillIOEventHandlerData(ed, buf, len, cb, e, Operations::recv);
+		ed->misc.bufferIO.flags = flags;
+		endAddEvent(e, repeat);
+	}
+	void File::recvAll(void* buf, int32_t len, int32_t flags, const Callback& cb) {
+		if (!_supportsEPoll) {
+			int32_t r = recvAll(buf, len);
+			cb(r);
+			return;
+		}
+		static const Events e = Events::in;
+		EventHandlerData* ed = beginAddEvent(e);
+		fillIOEventHandlerData(ed, (void*) buf, len, cb, e, Operations::recvAll);
+		ed->misc.bufferIO.len_done = 0;
+		endAddEvent(e, true);
+	}
+	void File::send(const void* buf, int32_t len, int32_t flags, const Callback& cb, bool repeat) {
+		static const Events e = Events::out;
+		EventHandlerData* ed = beginAddEvent(e);
+		fillIOEventHandlerData(ed, (void*) buf, len, cb, e, Operations::send);
+		ed->misc.bufferIO.flags = flags;
+		endAddEvent(e, repeat);
+	}
+	void File::sendAll(const void* buf, int32_t len, int32_t flags, const Callback& cb) {
+		static const Events e = Events::out;
+		EventHandlerData* ed = beginAddEvent(e);
+		fillIOEventHandlerData(ed, (void*) buf, len, cb, e, Operations::sendAll);
+		ed->misc.bufferIO.len_done = 0;
+		ed->misc.bufferIO.flags = flags;
+		endAddEvent(e, true);
+	}
+	File::~File() {
+		if (deletionFlag != NULL) *deletionFlag = true;
+		if (handle < 0) return;
+		close();
+	}
+	void File::close() {
+		//if(handle<0)throw runtime_error("asdf");
+		if (onClose != nullptr) onClose(*this);
+		::close(handle);
+		deinit();
+	}
+	void File::flush() {
+
+	}
+	void File::close(const Callback& cb) {
+		if (!_supportsEPoll) {
+			close();
+			cb(0);
+			return;
+		}
+		static const Events e = Events::out;
+		EventHandlerData* ed = beginAddEvent(e);
+		ed->cb = cb;
+		ed->op = Operations::close;
+		endAddEvent(e, true);
+	}
+	void File::flush(const Callback& cb) {
+		cb(0);
+	}
+	void File::cancelRead() {
+		cancel(Events::in);
+	}
+	void File::cancelWrite() {
+		cancel(Events::out);
+	}
+	void File::waitForEvent(Events event, const Callback& cb, bool repeat) {
+		EventHandlerData* ed = beginAddEvent(event);
+		ed->cb = cb;
+		ed->op = Operations::none;
+		endAddEvent(event, repeat);
+	}
+	int32_t File::readv(iovec* iov, int iovcnt) {
+		return ::readv(handle, iov, iovcnt);
+	}
+	int32_t File::writev(iovec* iov, int iovcnt) {
+		return ::writev(handle, iov, iovcnt);
+	}
+	void File::readv(iovec* iov, int iovcnt, const Callback& cb, bool repeat) {
+		if (!_supportsEPoll) {
+			asdfg: int32_t r = readv(iov, iovcnt);
+			cb(r);
+			if (repeat && r > 0) goto asdfg;
+			return;
+		}
+		static const Events e = Events::in;
+		EventHandlerData* ed = beginAddEvent(e);
+		fillIOEventHandlerData(ed, iov, iovcnt, cb, e, Operations::readv);
+		endAddEvent(e, repeat);
+	}
+	void File::writev(iovec* iov, int iovcnt, const Callback& cb, bool repeat) {
+		if (!_supportsEPoll) {
+			asdfg: int32_t r = writev(iov, iovcnt);
+			cb(r);
+			if (repeat && r > 0) goto asdfg;
+			return;
+		}
+		static const Events e = Events::out;
+		EventHandlerData* ed = beginAddEvent(e);
+		fillIOEventHandlerData(ed, iov, iovcnt, cb, e, Operations::writev);
+		ed->opcb= {&File_doWritev,this};
+		endAddEvent(e, repeat);
+	}
+
+//Socket
+	Socket::Socket() :
+			addressFamily(AF_UNSPEC), type(0), protocol(0) {
+
+	}
+	Socket::Socket(HANDLE handle, int32_t d, int32_t t, int32_t p) {
+		init(handle, d, t, p);
+	}
+	Socket::Socket(int32_t d, int32_t t, int32_t p) {
+		init(d, t, p);
+	}
+	void Socket::init(HANDLE handle, int32_t d, int32_t t, int32_t p) {
+		File::init(handle);
+		addressFamily = d;
+		type = t;
+		protocol = p;
+	}
+	void Socket::init(int32_t d, int32_t t, int32_t p) {
+		File::init(socket(d, t | SOCK_CLOEXEC | SOCK_NONBLOCK, p));
+		addressFamily = d;
+		type = t;
+		protocol = p;
+	}
+//the caller must release() or free() the returned object
+	EndPoint* Socket::getLocalEndPoint() {
+		EndPoint* ep = EndPoint::create(addressFamily);
+		socklen_t l = (socklen_t) (ep->getSockAddrSize());
+		char addr[l];
+		getsockname(handle, (struct sockaddr*) addr, &l);
+		ep->setSockAddr((struct sockaddr*) addr);
+		return ep;
+	}
+//the caller must release() or free() the returned object
+	EndPoint* Socket::getRemoteEndPoint() {
+		EndPoint* ep = EndPoint::create(addressFamily);
+		socklen_t l = (socklen_t) (ep->getSockAddrSize());
+		char addr[l];
+		getpeername(handle, (struct sockaddr*) addr, &l);
+		ep->setSockAddr((struct sockaddr*) addr);
+		return ep;
+	}
+	bool Socket::doOperation(Events event, EventHandlerData& ed, const EventData& evtd,
+			EventHandlerData::States oldstate, bool confident) {
+		Operations op = ed.op;
+		int r;
+		redo: r = 0;
+		switch (op) {
+			case Operations::accept:
+			{
+				HANDLE h = acceptHandle();
+				if (h < 0) {
+					if (isWouldBlock()) return false;
+					ed.state = EventHandlerData::States::invalid;
+				}
+				ed.cb(h);
+				goto success;
+			}
+			case Operations::shutdown:
+				if (!confident && (checkEvents(event) & event) != event) return false;
+				ed.cb(shutdown(ed.misc.shutdown.how));
+				return true;
+			case Operations::connect:
+				if (evtd.error || evtd.hungUp) {
+					ed.state = EventHandlerData::States::invalid;
+					ed.cb(-1);
+					return true;
+				}
+				if (!confident && (checkEvents(event) & event) != event) return false;
+				ed.cb(0);
+				goto success;
+			case Operations::sendTo:
+				r = sendTo(ed.misc.bufferIO.buf, ed.misc.bufferIO.len, ed.misc.bufferIO.flags,
+						*ed.misc.bufferIO.const_ep);
+				break;
+			case Operations::recvFrom:
+				r = recvFrom(ed.misc.bufferIO.buf, ed.misc.bufferIO.len, ed.misc.bufferIO.flags,
+						*ed.misc.bufferIO.ep);
+				break;
+			default:
+				return File::doOperation(event, ed, evtd, oldstate, confident);
+		}
+		if (r < 0 && isWouldBlock()) return false;
+		if (r <= 0) {
+			ed.state = EventHandlerData::States::invalid;
+		}
+		if (ed.cb != nullptr) ed.cb(r);
+		success: if (oldstate == EventHandlerData::States::repeat) {
+			confident = false;
+			goto redo;
+		}
+		return true;
+	}
+	void Socket::bind(const sockaddr *addr, int32_t addr_size) {
+		if (handle == -1) init(addr->sa_family, SOCK_STREAM, 0);
+		int32_t tmp12345 = 1;
+		setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &tmp12345, sizeof(tmp12345));
+		if (::bind(handle, addr, addr_size) != 0) throw CPollException(errno);
+	}
+	void Socket::bind(const EndPoint &ep) {
+		int32_t size = ep.getSockAddrSize();
+		uint8_t tmp[size];
+		ep.getSockAddr((sockaddr*) tmp);
+		bind((sockaddr*) tmp, size);
+	}
+	void Socket::bind(const char* hostname, const char* port, int32_t family, int32_t socktype,
+			int32_t proto, int32_t flags, Callback initsock) {
+		//XXX
+		if (handle != -1) throw CPollException(
+				"Socket::bind(string, ...) creates a socket, but the socket is already initialized");
+		auto hosts = EndPoint::lookupHost(hostname, port, 0, socktype, proto);
+		unsigned int i;
+		for (i = 0; i < hosts.size(); i++) {
+			int _f = socket(hosts[i]->addressFamily, socktype | SOCK_CLOEXEC | SOCK_NONBLOCK, proto);
+			if (_f < 0) continue;
+			int32_t tmp12345 = 1;
+			setsockopt(_f, SOL_SOCKET, SO_REUSEADDR, &tmp12345, sizeof(tmp12345));
+			if (initsock != nullptr) initsock(_f);
+			int size = hosts[i]->getSockAddrSize();
+			uint8_t tmp[size];
+			hosts[i]->getSockAddr((sockaddr*) tmp);
+			if (::bind(_f, (sockaddr*) tmp, size) == 0) {
+				init(_f, hosts[i]->addressFamily, socktype, proto);
+				return;
+			} else {
+				::close(_f);
+				continue;
+			}
+		}
+		throw CPollException("no bindable hosts were found; last error: " + string(strerror(errno)));
+	}
+	void Socket::listen(int32_t backlog) {
+		checkError(::listen(handle, backlog));
+	}
+	int32_t Socket::shutdown(int32_t how) {
+		return ::shutdown(handle, how);
+	}
+	void Socket::shutdown(int32_t how, const Callback& cb) {
+		static const Events e = Events::out;
+		EventHandlerData* ed = beginAddEvent(e);
+		ed->cb = cb;
+		ed->op = Operations::shutdown;
+		endAddEvent(e, false);
+	}
+	void __socket_init_if_not_already(Socket* s, int32_t af) {
+		if (s->handle < 0) s->init(af, SOCK_STREAM, 0);
+	}
+	void Socket::connect(const sockaddr *addr, int32_t addr_size) {
+		__socket_init_if_not_already(this, addr->sa_family);
+		retry: int32_t tmp = ::connect(handle, addr, addr_size);
+		if (tmp != 0 && errno != EINPROGRESS) {
+			if (errno == EINTR) goto retry;
+			throw CPollException(errno);
+		}
+	}
+	void Socket::connect(const EndPoint &ep) {
+		int32_t l = ep.getSockAddrSize();
+		char tmp[l];
+		ep.getSockAddr((sockaddr*) tmp);
+		connect((sockaddr*) tmp, l);
+	}
+	void Socket::connect(const char* hostname, const char* port, int32_t family, int32_t socktype,
+			int32_t proto, int32_t flags) {
+		//XXX
+		if (handle != -1) throw CPollException(
+				"Socket::connect(string, ...) creates a socket, but the socket is already initialized");
+		auto hosts = EndPoint::lookupHost(hostname, port, 0, socktype, proto);
+		unsigned int i;
+		for (i = 0; i < hosts.size(); i++) {
+			int _f = socket(hosts[i]->addressFamily, socktype | SOCK_CLOEXEC | SOCK_NONBLOCK, proto);
+			if (_f < 0) continue;
+			int size = hosts[i]->getSockAddrSize();
+			uint8_t tmp[size];
+			hosts[i]->getSockAddr((sockaddr*) tmp);
+			if (::connect(_f, (sockaddr*) tmp, size) == 0) {
+				init(_f, hosts[i]->addressFamily, socktype, proto);
+				break;
+			} else {
+				::close(_f);
+				continue;
+			}
+		}
+		throw CPollException("no reachable hosts were found; last error: " + string(strerror(errno)));
+	}
+//the caller must release() or free() the returned object;
+//also this will NOT automatically add the new socket to this Poll instance
+//because the user might want to handle the socket on a different thread
+//which requires a different Poll instance
+	Socket* Socket::accept() {
+		Socket* sock = new Socket(acceptHandle(), addressFamily, type, protocol);
+		return sock;
+	}
+	HANDLE Socket::acceptHandle() {
+		HANDLE h = ::accept4(handle, NULL, NULL, SOCK_CLOEXEC | SOCK_NONBLOCK);
+		return h;
+	}
+	void Socket::connect(const sockaddr* addr, int32_t addr_size, const Callback& cb) {
+		__socket_init_if_not_already(this, addr->sa_family);
+		checkError(fcntl(handle, F_SETFL, checkError(fcntl(handle, F_GETFL, 0)) | O_NONBLOCK));
+		connect(addr, addr_size);
+		static const Events e = Events::out;
+		EventHandlerData* ed = beginAddEvent(e);
+		ed->cb = cb;
+		ed->op = Operations::connect;
+		endAddEvent(e, false);
+	}
+	void Socket::connect(const EndPoint& ep, const Callback& cb) {
+		__socket_init_if_not_already(this, ep.addressFamily);
+		checkError(fcntl(handle, F_SETFL, checkError(fcntl(handle, F_GETFL, 0)) | O_NONBLOCK));
+		connect(ep);
+		static const Events e = Events::out;
+		EventHandlerData* ed = beginAddEvent(e);
+		ed->cb = cb;
+		ed->op = Operations::connect;
+		endAddEvent(e, false);
+	}
+	void Socket_acceptStub(Socket* th, int32_t i) {
+		Socket* s = new Socket((HANDLE) i, th->addressFamily, th->type, th->protocol);
+		th->_acceptCB(s);
+	}
+	void Socket_acceptHandleStub(Socket* th, int32_t i) {
+		HANDLE h = i;
+		th->_acceptHandleCB(h);
+	}
+//user must eventually release() or free() the received object
+	void Socket::accept(const Delegate<void(Socket*)>& cb, bool repeat) {
+		_acceptCB = cb;
+		static const Events e = Events::in;
+		EventHandlerData* ed = beginAddEvent(e);
+		ed->cb = Callback(&Socket_acceptStub, this);
+		ed->op = Operations::accept;
+		endAddEvent(e, repeat);
+	}
+	void Socket::acceptHandle(const Delegate<void(HANDLE)>& cb, bool repeat) {
+		_acceptHandleCB = cb;
+		static const Events e = Events::in;
+		EventHandlerData* ed = beginAddEvent(e);
+		ed->cb = Callback(&Socket_acceptHandleStub, this);
+		ed->op = Operations::accept;
+		endAddEvent(e, repeat);
+	}
+	int32_t Socket::recvFrom(void* buf, int32_t len, int32_t flags, EndPoint& ep) {
+		socklen_t size = ep.getSockAddrSize();
+		uint8_t addr[size];
+		//ep->GetSockAddr((sockaddr*)tmp);
+		int tmp = recvfrom(handle, buf, len, flags, (sockaddr*) addr, &size);
+		checkError(tmp);
+		ep.setSockAddr((sockaddr*) addr);
+		return tmp;
+	}
+	int32_t Socket::sendTo(const void* buf, int32_t len, int32_t flags, const EndPoint& ep) {
+		socklen_t size = ep.getSockAddrSize();
+		uint8_t addr[size];
+		ep.getSockAddr((sockaddr*) addr);
+		int tmp = sendto(handle, buf, len, flags, (sockaddr*) addr, size);
+		return checkError(tmp);
+	}
+	void Socket::recvFrom(void* buf, int32_t len, int32_t flags, EndPoint& ep, const Callback& cb,
+			bool repeat) {
+		static const Events e = Events::in;
+		EventHandlerData* ed = beginAddEvent(e);
+		fillIOEventHandlerData(ed, buf, len, cb, e, Operations::recvFrom);
+		ed->misc.bufferIO.flags = flags;
+		ed->misc.bufferIO.ep = &ep;
+		endAddEvent(e, repeat);
+	}
+	void Socket::sendTo(const void* buf, int32_t len, int32_t flags, const EndPoint& ep,
+			const Callback& cb, bool repeat) {
+		static const Events e = Events::out;
+		EventHandlerData* ed = beginAddEvent(e);
+		fillIOEventHandlerData(ed, (void*) buf, len, cb, e, Operations::sendTo);
+		ed->misc.bufferIO.flags = flags;
+		ed->misc.bufferIO.const_ep = &ep;
+		endAddEvent(e, repeat);
+	}
+
+//SignalFD
+	int32_t SignalFD::MAX_EVENTS(4);
+	SignalFD::SignalFD(HANDLE handle, const sigset_t& mask) :
+			Handle(handle), mask(mask) {
+	}
+	SignalFD::SignalFD(const sigset_t& mask, int32_t flags) :
+			Handle(signalfd(-1, &mask, flags | SFD_CLOEXEC | SFD_NONBLOCK)), mask(mask) {
+	}
+	bool SignalFD::dispatch(Events event, const EventData& evtd, bool confident) {
+		Signal sig[MAX_EVENTS];
+		int32_t br = ::read(handle, sig, sizeof(sig));
+		if (br < 0 && isWouldBlock()) return false;
+		if (callback != nullptr) {
+			br /= sizeof(Signal);
+			for (int32_t i = 0; i < br; i++) {
+				callback(sig[i]);
+			}
+		}
+		return true;
+	}
+	Events SignalFD::getEvents() {
+		return Events::in;
+	}
+
+//Timer
+	static void Timer_doinit(Timer* This) {
+		This->dispatching = false;
+		This->deletionFlag = NULL;
+	}
+	static void Timer_doSetInterval(Timer* This, struct timespec interval) {
+		This->interval = interval;
+		struct itimerspec tmp1;
+		tmp1.it_interval = interval;
+		tmp1.it_value = interval;
+		timerfd_settime(This->handle, 0, &tmp1, NULL);
+	}
+	static void Timer_doSetInterval(Timer* This, uint64_t interval_ms) {
+		This->interval.tv_sec = interval_ms / 1000;
+		This->interval.tv_nsec = (interval_ms % 1000) * 1000000;
+		struct itimerspec tmp1;
+		tmp1.it_interval = This->interval;
+		tmp1.it_value = This->interval;
+		timerfd_settime(This->handle, 0, &tmp1, NULL);
+	}
+	void Timer::setInterval(struct timespec interval) {
+		bool r;
+		if (!dispatching) r = running();
+		Timer_doSetInterval(this, interval);
+		if (!dispatching && running() != r) {
+			if (onEventsChange != nullptr) onEventsChange(*this, r ? Events::in : Events::none);
+		}
+	}
+	void Timer::setInterval(uint64_t interval_ms) {
+		bool r;
+		if (!dispatching) r = running();
+		Timer_doSetInterval(this, interval_ms);
+		if (!dispatching && running() != r) {
+			if (onEventsChange != nullptr) onEventsChange(*this, r ? Events::in : Events::none);
+		}
+	}
+	void Timer::init(HANDLE handle, struct timespec interval) {
+		Handle::init(handle);
+		Timer_doinit(this);
+		setInterval(interval);
+	}
+	void Timer::init(HANDLE handle, uint64_t interval_ms) {
+		Handle::init(handle);
+		Timer_doinit(this);
+		setInterval(interval_ms);
+	}
+	void Timer::init(struct timespec interval) {
+		Handle::init(timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK));
+		Timer_doinit(this);
+		setInterval(interval);
+	}
+	void Timer::init(uint64_t interval_ms) {
+		Handle::init(timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK));
+		Timer_doinit(this);
+		setInterval(interval_ms);
+	}
+	Timer::Timer(HANDLE handle, uint64_t interval_ms) {
+		this->interval= {0,0};
+		init(handle, interval_ms);
+	}
+	Timer::Timer(HANDLE handle, struct timespec interval) {
+		this->interval= {0,0};
+		init(handle, interval);
+	}
+	Timer::Timer(uint64_t interval_ms) {
+		this->interval= {0,0};
+		init(interval_ms);
+	}
+	Timer::Timer(struct timespec interval) {
+		this->interval= {0,0};
+		init(interval);
+	}
+	struct timespec Timer::getInterval() {
+		return interval;
+	}
+	bool Timer::running() {
+		return !(interval.tv_nsec == 0 && interval.tv_sec == 0);
+	}
+	void Timer::setCallback(const Callback& cb) {
+		this->cb = cb;
+	}
+	bool Timer::dispatch(Events event, const EventData& evtd, bool confident) {
+		if (event == Events::in) {
+			dispatching = true;
+			//bool r = running();
+			uint64_t tmp;
+			bool d(false);
+			this->deletionFlag = &d;
+			int i;
+			if ((i = read(handle, &tmp, sizeof(tmp))) >= (int) sizeof(tmp) && cb != nullptr) cb(
+					(int) tmp);
+			else if (i < 0 && isWouldBlock()) {
+				this->deletionFlag = NULL;
+				dispatching = false;
+				return false;
+			}
+			if (d) return true;
+			dispatching = false;
+			deletionFlag = NULL;
+			return true;
+		}
+		return true;
+	}
+	void Timer::init(HANDLE handle) {
+		Handle::init(handle);
+		struct itimerspec tmp;
+		timerfd_gettime(handle, &tmp);
+		interval = tmp.it_interval;
+		if (running() && onEventsChange != nullptr) onEventsChange(*this, Events::none);
+	}
+	Timer::Timer(HANDLE handle) {
+		init(handle);
+	}
+	void Timer::close() {
+		if (onClose != nullptr) onClose(*this);
+		::close(handle);
+		handle = -1;
+		deinit();
+	}
+	Timer::~Timer() {
+		if (deletionFlag != NULL) *deletionFlag = true;
+		if (handle < 0) return;
+		close();
+	}
+	Events Timer::getEvents() {
+		return running() ? Events::in : Events::none;
+	}
+
+//EventFD
+	EventFD::EventFD(HANDLE handle) :
+			File(handle) {
+	}
+	EventFD::EventFD(uint32_t initval, int32_t flags) :
+			File(eventfd(initval, flags | EFD_CLOEXEC | EFD_NONBLOCK)) {
+	}
+	bool EventFD::doOperation(Events event, EventHandlerData& ed, const EventData& evtd,
+			EventHandlerData::States oldstate, bool confident) {
+		int32_t r = 0;
+		switch (ed.op) {
+			case Operations::read:
+				r = eventfd_read(handle, &ed.misc.eventfd.evt);
+				break;
+			case Operations::write:
+				r = eventfd_write(handle, ed.misc.eventfd.evt);
+				break;
+			default:
+				break;
+		}
+		if (r < 0 && isWouldBlock()) return false;
+		ed.cb(r);
+		return true;
+	}
+	eventfd_t EventFD::getEvent() {
+		eventfd_t tmp;
+		if (eventfd_read(handle, &tmp) == 0) return tmp;
+		return -1;
+	}
+	void EventFD_getEventStub(EventFD* th, int i) {
+		th->cb((i < 0) ? -1 : (th->eventData[eventToIndex(Events::in)].misc.eventfd.evt));
+	}
+	void EventFD::getEvent(const Delegate<void(eventfd_t)>& cb, bool repeat) {
+		Events e = Events::in;
+		EventHandlerData* ed = beginAddEvent(e);
+		this->cb = cb;
+		ed->cb = Callback(&EventFD_getEventStub, this);
+		ed->op = Operations::read;
+		endAddEvent(e, repeat);
+	}
+	int32_t EventFD::sendEvent(eventfd_t evt) {
+		return eventfd_write(handle, evt);
+	}
+	void EventFD::sendEvent(eventfd_t evt, const Delegate<void(int32_t)>& cb) {
+		Events e = Events::out;
+		EventHandlerData* ed = beginAddEvent(e);
+		ed->cb = cb;
+		ed->misc.eventfd.evt = evt;
+		ed->op = Operations::write;
+		endAddEvent(e, false);
+	}
+
+//EPoll
+	static inline void fillEPollEvents(Handle& h, epoll_event& evt, Events e) {
+		evt.events = eventsToEPoll(e);
+		evt.data.u64 = 0; //work around valgrind warning
+		evt.data.ptr = &h;
+	}
+	int32_t EPoll::MAX_EVENTS(32);
+	EPoll::EPoll(HANDLE handle) :
+			Handle(handle), curEvents(NULL), active(0), cur_handle(-1) {
+		disableSignals();
+	}
+	EPoll::EPoll() :
+			Handle(checkError(epoll_create1(EPOLL_CLOEXEC))), curEvents(NULL), active(0),
+					cur_handle(-1) {
+		disableSignals();
+	}
+	void EPoll_disableHandle(EPoll* This, Handle& h) {
+		Events new_e = h.getEvents();
+		h._supportsEPoll = false;
+		EventData evtd;
+		evtd.hungUp = evtd.error = false;
+		while (new_e != Events::none) {
+			h.dispatchMultiple(new_e, new_e, evtd);
+			new_e = h.getEvents();
+		}
+	}
+	static inline void EPoll_applyHandle(EPoll* This, Handle& h, Events old_e) {
+		if (!h._supportsEPoll) {
+			//if (debug) printf("_applyHandle: h=%i, h._supportsEPoll=false\n", h.handle);
+			return;
+		}
+//if (unlikely(has_deleted) && tmp_deleted.find(&h) != tmp_deleted.end()) return;
+		Events new_e = h.getEvents();
+//if (debug) printf("_applyHandle: h=%i, old_e=%i, new_e=%i\n", h.handle, old_e, new_e);
+		if (new_e == old_e) return;
+
+		epoll_event evt;
+		if (old_e == Events::none) {
+			fillEPollEvents(h, evt, new_e);
+			//cout << "added " << h.handle << endl;
+			int r = epoll_ctl(This->handle, EPOLL_CTL_ADD, h.handle, &evt);
+			if (r < 0 && errno == EPERM) {
+				EPoll_disableHandle(This, h);
+				return;
+			}
+			checkError(r);
+			This->active++;
+		} else if (new_e == Events::none) {
+			//cout << "deleted " << h.handle << endl;
+			//checkError(epoll_ctl(this->handle, EPOLL_CTL_DEL, h.handle, NULL));
+			//XXX: removed error checking to work around cURL bug
+			epoll_ctl(This->handle, EPOLL_CTL_DEL, h.handle, NULL);
+			if (likely(This->curEvents!=NULL)) for (int i = This->curIndex; i < This->curLength; i++) {
+				if (This->curEvents[i].data.ptr == (void*) &h) This->curEvents[i].data.ptr = NULL;
+			}
+			This->active--;
+		} else {
+			fillEPollEvents(h, evt, new_e);
+			//cout << "modified " << h.handle << endl;
+			//printf("epoll_ctl: old_e=%i new_e=%i\n", old_e, new_e);
+			checkError(epoll_ctl(This->handle, EPOLL_CTL_MOD, h.handle, &evt));
+			uint32_t ep_e = eventsToEPoll(new_e);
+			if (likely(This->curEvents!=NULL)) for (int i = This->curIndex; i < This->curLength; i++) {
+				if (This->curEvents[i].data.ptr == (void*) &h) {
+					This->curEvents[i].events &= ep_e;
+					if (This->curEvents[i].events == 0) This->curEvents[i].data.ptr = NULL;
+				}
+			}
+		}
+	}
+	static inline int32_t EPoll_doDispatch(EPoll* This, const epoll_event& event) {
+		Handle* h = (Handle*) event.data.ptr;
+		if (unlikely(h==NULL)) return 0;
+		EventData evtd;
+		event_t evt = (event_t) ePollToEvents(event.events);
+		evtd.hungUp = (event.events & EPOLLHUP);
+		evtd.error = (event.events & EPOLLERR);
+		This->cur_handle = h->handle;
+		Events old_e = h->getEvents();
+		This->cur_deleted = false;
+		This->cur_handle = h->handle;
+		h->dispatchMultiple((Events) evt, (Events) evt, evtd);
+		if (This->cur_deleted) goto aaa;
+		if (h->getEvents() != old_e) This->applyHandle(*h, old_e);
+		aaa: This->cur_handle = -1;
+		return 1;
+	}
+	int32_t EPoll::_doEPoll(int32_t timeout) {
+		if (active <= 0) {
+			//printf("active=%i\n", active);
+			return -1;
+		}
+		epoll_event evts[MAX_EVENTS];
+		retry: int32_t n = checkError(epoll_wait(handle, evts, MAX_EVENTS, timeout));
+		if (unlikely(n < 0)) {
+			goto retry;
+		}
+		curEvents = evts;
+		curLength = n;
+		for (curIndex = 0; curIndex < n; curIndex++)
+			EPoll_doDispatch(this, evts[curIndex]);
+
+		return n;
+	}
+	bool EPoll::dispatch(Events event, const EventData& evtd, bool confident) {
+		return _doEPoll(0) > 0;
+	}
+	Events EPoll::dispatchMultiple(Events event, Events confident, const EventData& evtd) {
+//throw CPollException("EPoll::dispatch() not implemented");
+		return _doEPoll(0) <= 0 ? Events::none : Events::all;
+	}
+	Events EPoll::getEvents() {
+//throw CPollException("EPoll::getEvents() not implemented");
+		return active ? (Events::all) : (Events::none);
+	}
+	Events EPoll::waitAndDispatch() {
+		return _doEPoll(-1) <= 0 ? Events::none : Events::all;
+	}
+
+	void EPoll::applyHandle(Handle& h, Events old_e) {
+//cout << "applyHandle" << endl;
+//if (h.handle == cur_handle) return;
+		EPoll_applyHandle(this, h, old_e);
+	}
+	void EPoll::add(Handle& h) {
+//h.retain();
+		h.onEventsChange = Delegate<void(Handle&, Events)>(&EPoll::applyHandle, this);
+		//h.onEventsChange = [this,&h](Events old_events) {this->applyHandle(h,old_events);};
+		EPoll_applyHandle(this, h, Events::none);
+		h.onClose = Delegate<void(Handle& h)>(&EPoll::del, this);
+	}
+	void EPoll::del(Handle& h) {
+//h.release();
+//tmp_deleted.push_back(&h);
+//throw 0;
+//printf("EPoll::del()\n");
+		if (h.handle == cur_handle) cur_deleted = true;
+		if (h.getEvents() != Events::none) {
+			/*if (h.handle < 0) {
+			 //throw runtime_error("test");
+			 Events new_e = h.getEvents();
+			 EventData evtd;
+			 evtd.hungUp = evtd.error = true;
+			 while (new_e != Events::none) {
+			 h.dispatchMultiple(new_e, evtd);
+			 new_e = h.getEvents();
+			 }
+			 }*/
+			//printf("EPoll::del()\n");
+			//if we're in the middle of a _doEPoll() loop, disable all pending events in queue
+			//relating to this handle since it might not even exist anymore after this function
+			//returns
+			if (likely(curEvents!=NULL)) for (int i = curIndex; i < curLength; i++) {
+				if (curEvents[i].data.ptr == (void*) &h) curEvents[i].data.ptr = NULL;
+			}
+			if (h.handle >= 0) {
+				//checkError(epoll_ctl(this->handle, EPOLL_CTL_DEL, h.handle, (epoll_event*) 1));
+				//XXX: see previous comment about EPOLL_CTL_DEL
+				epoll_ctl(this->handle, EPOLL_CTL_DEL, h.handle, (epoll_event*) 1);
+				active--;
+			}
+		}
+		h.onEventsChange = nullptr;
+		h.onClose = nullptr;
+	}
+
+//NewEPoll
+	int32_t NewEPoll::MAX_EVENTS(32);
+	static bool compareDrainInfo(const NewEPoll::drainInfo& a, const NewEPoll::drainInfo& b) {
+		return a.h < b.h;
+	}
+	NewEPoll::NewEPoll(HANDLE h) :
+			Handle(h), _draining(NULL), _dispatchingHandle(NULL), _curEvents(NULL) {
+		disableSignals();
+	}
+	NewEPoll::NewEPoll() :
+			Handle(checkError(epoll_create1(EPOLL_CLOEXEC))), _draining(NULL),
+					_dispatchingHandle(NULL), _curEvents(NULL) {
+		disableSignals();
+	}
+	bool NewEPoll::dispatch(Events event, const EventData& evtd, bool confident) {
+		return _doIteration(0);
+	}
+	Events NewEPoll::dispatchMultiple(Events event, Events confident, const EventData& evtd) {
+		return _doIteration(0) ? event : Events::none;
+	}
+	Events NewEPoll::getEvents() {
+		return Events::all;
+	}
+	Events NewEPoll::waitAndDispatch() {
+		return _doIteration(-1) ? Events::all : Events::none;
+	}
+	void NewEPoll::add(Handle& h) {
+		epoll_event evt;
+		fillEPollEvents(h, evt, Events::all);
+		evt.events |= EPOLLET;
+		int r = epoll_ctl(this->handle, EPOLL_CTL_ADD, h.handle, &evt);
+		if (r < 0 && errno == EPERM) {
+			h._supportsEPoll = false;
+			return;
+		}
+		h.onEventsChange = Delegate<void(Handle&, Events)>(&NewEPoll::_applyHandle, this);
+		_queueHandle(h, h.getEvents());
+		h.onClose = Delegate<void(Handle& h)>(&NewEPoll::del, this);
+	}
+	void NewEPoll::del(Handle& h) {
+		if (&h == _dispatchingHandle) _dispatchingDeleted = true;
+		if (likely(_curEvents!=NULL)) for (int i = _curIndex; i < _curLength; i++) {
+			if (_curEvents[i].data.ptr == (void*) &h) _curEvents[i].data.ptr = NULL;
+		}
+		for (uint32_t i = 0; i < _pending.size(); i++)
+			if (_pending[i].h == &h) _pending[i].h = NULL;
+		if (likely(_draining!=NULL)) for (uint32_t i = 0; i < _draining->size(); i++)
+			if ((*_draining)[i].h == &h) (*_draining)[i].h = NULL;
+		epoll_ctl(this->handle, EPOLL_CTL_DEL, h.handle, (epoll_event*) 1);
+		h.onEventsChange = nullptr;
+		h.onClose = nullptr;
+	}
+	bool NewEPoll::_doIteration(int timeout) {
+		bool ret = false;
+		while (_pending.size() > 0) {
+			vector<drainInfo> tmpevents1 = _pending;
+			_draining = &tmpevents1;
+			_pending.clear();
+			std::sort(tmpevents1.begin(), tmpevents1.end(), compareDrainInfo);
+			Handle* last_h = NULL;
+			Events last_e = Events::none;
+			for (int i = 0; i < (int) tmpevents1.size(); i++) {
+				if (tmpevents1[i].h == NULL) continue;
+				ret = true;
+				if (last_h == tmpevents1[i].h) {
+					last_e = last_e | tmpevents1[i].new_e;
+					continue;
+				}
+				if (last_h != NULL) _drainHandle(*last_h, last_e);
+				last_h = tmpevents1[i].h;
+				last_e = tmpevents1[i].new_e;
+			}
+			if (last_h != NULL) _drainHandle(*last_h, last_e);
+			_draining = NULL;
+		}
+		epoll_event evts[MAX_EVENTS];
+		retry: int32_t n = checkError(epoll_wait(handle, evts, MAX_EVENTS, timeout));
+		if (unlikely(n < 0)) {
+			goto retry;
+		}
+		if (n > 0) ret = true;
+		_curEvents = evts;
+		_curLength = n;
+		for (_curIndex = 0; _curIndex < n; _curIndex++)
+			_doDispatch(evts[_curIndex]);
+		return ret;
+	}
+	void NewEPoll::_doDispatch(const epoll_event& event) {
+		Handle* h = (Handle*) event.data.ptr;
+		if (unlikely(h==NULL)) return;
+		_dispatchingHandle = h;
+		_dispatchingDeleted = false;
+		EventData evtd;
+		event_t evt = (event_t) ePollToEvents(event.events);
+		evt = evt & (event_t) h->getEvents();
+		evtd.hungUp = (event.events & EPOLLHUP);
+		evtd.error = (event.events & EPOLLERR);
+		Events events = h->dispatchMultiple((Events) evt, (Events) evt, evtd);
+		if (_dispatchingDeleted) goto aaa;
+		event_t failed;
+		failed = 0;
+		while (true) {
+			events = Events((event_t) h->getEvents() & ~failed);
+			if (events == Events::none) break;
+			event_t res = (event_t) h->dispatchMultiple(events, Events::none, evtd);
+			failed |= event_t(events) & ~res;
+			if (_dispatchingDeleted) goto aaa;
+		}
+		//_applyHandle(*h, old_e);
+		aaa: _dispatchingHandle = NULL;
+	}
+	void NewEPoll::_drainHandle(Handle& h, Events new_e) {
+		if (new_e != Events::none) {
+			EventData evtd;
+			evtd.hungUp = evtd.error = false;
+			_dispatchingDeleted = false;
+			_dispatchingHandle = &h;
+			event_t failed;
+			failed = 0;
+			while (true) {
+				Events events = Events((event_t) h.getEvents() & ~failed);
+				if (events == Events::none) break;
+				event_t res = (event_t) h.dispatchMultiple(events, Events::none, evtd);
+				failed |= event_t(events) & ~res;
+				if (_dispatchingDeleted) goto out;
+			}
+		}
+		out: _dispatchingHandle = NULL;
+	}
+	void NewEPoll::_queueHandle(Handle& h, Events new_e) {
+		_pending.push_back( { &h, new_e });
+	}
+	void NewEPoll::_applyHandle(Handle& h, Events old_e) {
+		Events new_e = h.getEvents();
+		Events new_added = (old_e ^ new_e) & new_e;
+		if (new_added != Events::none) _queueHandle(h, new_added);
+	}
+
+	StandardStream::StandardStream() :
+			in(0), out(1) {
+	}
+	int32_t StandardStream::read(void* buf, int32_t len) {
+		return in.read(buf, len);
+	}
+	int32_t StandardStream::readAll(void* buf, int32_t len) {
+		return in.readAll(buf, len);
+	}
+	int32_t StandardStream::write(const void* buf, int32_t len) {
+		return out.write(buf, len);
+	}
+	int32_t StandardStream::writeAll(const void* buf, int32_t len) {
+		return out.writeAll(buf, len);
+	}
+	void StandardStream::read(void* buf, int32_t len, const Callback& cb, bool repeat) {
+		in.read(buf, len, cb, repeat);
+	}
+	void StandardStream::readAll(void* buf, int32_t len, const Callback& cb) {
+		in.readAll(buf, len, cb);
+	}
+	void StandardStream::write(const void* buf, int32_t len, const Callback& cb, bool repeat) {
+		out.write(buf, len, cb, repeat);
+	}
+	void StandardStream::writeAll(const void* buf, int32_t len, const Callback& cb) {
+		out.writeAll(buf, len, cb);
+	}
+	void StandardStream::cancelRead() {
+		in.cancelRead();
+	}
+	void StandardStream::cancelWrite() {
+		out.cancelWrite();
+	}
+	void StandardStream::close() {
+
+	}
+	void StandardStream::flush() {
+		out.flush();
+	}
+	void StandardStream::close(const Callback& cb) {
+		cb(0);
+	}
+	void StandardStream::flush(const Callback& cb) {
+		out.flush(cb);
+	}
+
+	FixedMemoryStream::FixedMemoryStream() :
+			BufferedOutput(NULL, 0, 0), len(0) {
+	}
+	FixedMemoryStream::FixedMemoryStream(void* data, int len) :
+			BufferedOutput((uint8_t*) data, 0, len), len(0) {
+	}
+	int32_t FixedMemoryStream::read(void* buf, int32_t len) {
+		int l = len < (this->len - this->bufferPos) ? len : (this->len - this->bufferPos);
+		if (l <= 0) return 0;
+		memcpy(buf, this->buffer + this->bufferPos, l);
+		this->bufferPos += l;
+		return l;
+	}
+	int32_t FixedMemoryStream::readAll(void* buf, int32_t len) {
+		return read(buf, len);
+	}
+	int32_t FixedMemoryStream::write(const void* buf, int32_t len) {
+		int l = len < (this->len - this->bufferPos) ? len : (this->len - this->bufferPos);
+		if (l <= 0) return 0;
+		memcpy(this->buffer + this->bufferPos, buf, l);
+		this->bufferPos += l;
+		return l;
+	}
+	int32_t FixedMemoryStream::writeAll(const void* buf, int32_t len) {
+		if (this->bufferPos + len > this->len) return -1;
+		return write(buf, len);
+	}
+	void FixedMemoryStream::read(void* buf, int32_t len, const Callback& cb, bool repeat) {
+		rep: int tmp = read(buf, len);
+		cb(tmp);
+		if (repeat && tmp > 0) goto rep;
+	}
+	void FixedMemoryStream::readAll(void* buf, int32_t len, const Callback& cb) {
+		int tmp = readAll(buf, len);
+		cb(tmp);
+	}
+	void FixedMemoryStream::write(const void* buf, int32_t len, const Callback& cb, bool repeat) {
+		rep: int tmp = write(buf, len);
+		cb(tmp);
+		if (repeat && tmp > 0) goto rep;
+	}
+	void FixedMemoryStream::writeAll(const void* buf, int32_t len, const Callback& cb) {
+		int tmp = writeAll(buf, len);
+		cb(tmp);
+	}
+	void FixedMemoryStream::cancelRead() {
+	}
+	void FixedMemoryStream::cancelWrite() {
+	}
+	void FixedMemoryStream::close() {
+	}
+	void FixedMemoryStream::flush() {
+	}
+	void FixedMemoryStream::close(const Callback& cb) {
+		cb(0);
+	}
+	void FixedMemoryStream::flush(const Callback& cb) {
+		cb(0);
+	}
+	int32_t FixedMemoryStream::readBuffer(void*& buf, int32_t maxlen) {
+		int l;
+		l = this->len - this->bufferPos;
+		if (maxlen >= 0 && maxlen < l) l = maxlen;
+		if (l <= 0) return 0;
+		buf = this->buffer + this->bufferPos;
+		this->bufferPos += l;
+		return l;
+	}
+	void FixedMemoryStream::flushBuffer(int minBufferAllocation) {
+		if (minBufferAllocation > this->len - this->bufferPos) throw runtime_error(
+				"overflowed FixedMemoryStream");
+	}
+	BufferedOutput* FixedMemoryStream::getBufferedOutput() {
+		return this;
+	}
+
+	MemoryStream::MemoryStream(int capacity) :
+			FixedMemoryStream(malloc(capacity), 0) {
+		if (buffer == NULL) throw bad_alloc();
+		bufferSize = capacity;
+	}
+	MemoryStream::~MemoryStream() {
+		if (buffer != NULL) free(buffer);
+	}
+	void MemoryStream::ensureCapacity(int c) {
+		if (buffer == NULL) throw runtime_error("attempted to write to closed MemoryStream");
+		if (likely(c<=bufferSize)) return;
+		int tmp = bufferSize;
+		if (tmp <= 0) tmp = 4096;
+		while (tmp < c)
+			tmp *= 2;
+		void* v = realloc(buffer, tmp);
+		if (v == NULL) throw bad_alloc();
+		buffer = (uint8_t*) v;
+		bufferSize = tmp;
+	}
+	int32_t MemoryStream::write(const void* buf, int32_t len) {
+		ensureCapacity(this->bufferPos + len);
+		if (this->bufferPos + len > this->len) this->len = this->bufferPos + len;
+		return FixedMemoryStream::write(buf, len);
+	}
+	int32_t MemoryStream::writeAll(const void* buf, int32_t len) {
+		/*ensureCapacity(this->bufferSize + len);
+		 this->bufferPos += len;
+		 if (this->bufferPos > this->len) this->len = this->bufferPos;
+		 return FixedMemoryStream::writeAll(buf, len);*/
+		return write(buf, len);
+	}
+	void MemoryStream::close() {
+		if (buffer == NULL) return;
+		free(buffer);
+		buffer = NULL;
+		bufferSize = len = 0;
+	}
+	void MemoryStream::clear() {
+		len = 0;
+		bufferPos = 0;
+	}
+	void MemoryStream::flushBuffer(int minBufferAllocation) {
+		if (this->bufferPos > this->len) this->len = this->bufferPos;
+		ensureCapacity(this->len + minBufferAllocation);
+	}
+	void MemoryStream::keepBuffer() {
+		buffer = NULL;
+	}
+
+	StringPool::StringPool(int pageSize) :
+			_firstPage(NULL), _curPage(NULL), _firstRawItem(NULL), _curRawItem(NULL),
+					_pageSize(pageSize) {
+
+	}
+	StringPool::~StringPool() {
+		clear();
+		if (_firstPage != NULL) {
+			::free(_firstPage);
+		}
+	}
+	void StringPool::clear() {
+		_pageHeader* h;
+		if (_firstPage != NULL) {
+			h = _firstPage->next;
+			_firstPage->next = NULL;
+			while (h != NULL) {
+				_pageHeader* n = h->next;
+				::free(h);
+				h = n;
+			}
+		}
+		h = _firstRawItem;
+		while (h != NULL) {
+			_pageHeader* n = h->next;
+			::free(h);
+			h = n;
+		}
+		_curPage = _firstPage;
+		_curIndex = 0;
+		_firstRawItem = _curRawItem = NULL;
+	}
+	void StringPool::_addPage() {
+		void* tmp = malloc(_pageSize);
+		if (tmp == NULL) throw bad_alloc();
+
+		if (_curPage != NULL) _curPage->next = (_pageHeader*) tmp;
+		_curPage = (_pageHeader*) tmp;
+		_curPage->next = NULL;
+		if (_firstPage == NULL) _firstPage = (_pageHeader*) tmp;
+		_curIndex = 0;
+	}
+	void StringPool::_addRaw(int len) {
+		void* tmp = malloc(len + sizeof(_pageHeader));
+		if (tmp == NULL) throw bad_alloc();
+		if (_curRawItem != NULL) _curRawItem->next = (_pageHeader*) tmp;
+		_curRawItem = (_pageHeader*) tmp;
+		_curRawItem->next = NULL;
+		if (_firstRawItem == NULL) _firstRawItem = (_pageHeader*) tmp;
+	}
+
+	StringStream::StringStream() :
+			BufferedOutput(NULL, 0, 0), len(0) {
+
+	}
+	int32_t StringStream::read(void* buf, int32_t len) {
+		int l = len < (this->len - this->bufferPos) ? len : (this->len - this->bufferPos);
+		if (l <= 0) return 0;
+		memcpy(buf, buffer + this->bufferPos, l);
+		this->bufferPos += l;
+		return l;
+	}
+	int32_t StringStream::readAll(void* buf, int32_t len) {
+		return read(buf, len);
+	}
+	int32_t StringStream::write(const void* buf, int32_t len) {
+		if (bufferPos + len > this->len) {
+			_str.reserve(bufferPos + len);
+			_str.resize(_str.capacity());
+			this->len = bufferPos + len;
+			this->buffer = (uint8_t*) _str.data();
+		}
+		memcpy(buffer + this->bufferPos, buf, len);
+		this->bufferPos += len;
+		return len;
+	}
+	int32_t StringStream::writeAll(const void* buf, int32_t len) {
+		return write(buf, len);
+	}
+	void StringStream::read(void* buf, int32_t len, const Callback& cb, bool repeat) {
+		rep: int tmp = read(buf, len);
+		cb(tmp);
+		if (repeat && tmp > 0) goto rep;
+	}
+	void StringStream::readAll(void* buf, int32_t len, const Callback& cb) {
+		int tmp = readAll(buf, len);
+		cb(tmp);
+	}
+	void StringStream::write(const void* buf, int32_t len, const Callback& cb, bool repeat) {
+		rep: int tmp = write(buf, len);
+		cb(tmp);
+		if (repeat && tmp > 0) goto rep;
+	}
+	void StringStream::writeAll(const void* buf, int32_t len, const Callback& cb) {
+		int tmp = writeAll(buf, len);
+		cb(tmp);
+	}
+	void StringStream::cancelRead() {
+	}
+	void StringStream::cancelWrite() {
+	}
+	void StringStream::close() {
+	}
+	void StringStream::flush() {
+	}
+	void StringStream::close(const Callback& cb) {
+		cb(0);
+	}
+	void StringStream::flush(const Callback& cb) {
+		cb(0);
+	}
+	int32_t StringStream::readBuffer(void*& buf, int32_t maxlen) {
+		int l;
+		l = this->len - this->bufferPos;
+		if (maxlen >= 0 && maxlen < l) l = maxlen;
+		if (l <= 0) return 0;
+		buf = this->buffer + this->bufferPos;
+		this->bufferPos += l;
+		return l;
+	}
+	void StringStream::flushBuffer(int minBufferAllocation) {
+		if (this->bufferPos > this->len) this->len = this->bufferPos;
+		_str.reserve(_str.length() + minBufferAllocation);
+		_str.resize(_str.capacity());
+		this->bufferSize = _str.length();
+		buffer = (uint8_t*) _str.data();
+	}
+	BufferedOutput* StringStream::getBufferedOutput() {
+		return this;
+	}
+	void StringStream::clear() {
+		_str.clear();
+	}
+
+	void listDirectory(const char* path, Delegate<void(const char*)> cb) {
+		DIR* d = opendir(path);
+		if (d == NULL) {
+			throw runtime_error(strerror(errno));
+			return;
+		}
+		int len = offsetof(dirent, d_name)+ pathconf(path, _PC_NAME_MAX) + 1;
+		char ent[len];
+		dirent* ent1 = (dirent*) ent;
+		while (readdir_r(d, (dirent*) ent, &ent1) == 0 && ent1 != NULL) {
+			if (strcmp(ent1->d_name, ".") == 0 || strcmp(ent1->d_name, "..") == 0) continue;
+			cb(ent1->d_name);
+		}
+		closedir(d);
+	}
+
+	MemoryPool::MemoryPool(int size, int maxItems) :
+			_freeList(NULL), _lastFree(NULL), size(size), items(0), maxItems(maxItems) {
+
+	}
+	MemoryPool::~MemoryPool() {
+		_item* tmp = _freeList;
+		while (tmp != NULL) {
+			_item* n = tmp->nextFree;
+			::free(tmp);
+			tmp = n;
+		}
+	}
+	void* MemoryPool::alloc() {
+		if (_freeList == NULL) {
+			_item* tmp = (_item*) malloc(size + sizeof(_item));
+			tmp->nextFree = (_item*) this;
+			return tmp + 1;
+		} else {
+			_item* tmp = _freeList;
+			_freeList = _freeList->nextFree;
+			items--;
+			if (tmp == _lastFree) _lastFree = NULL;
+			tmp->nextFree = (_item*) this; //for double-free detection
+			return (tmp + 1);
+		}
+	}
+	void* MemoryPool::alloc(int s) {
+		if (s != size) throw CPollException(
+				"attempting to allocate an object of the wrong size from a MemoryPool");
+		return alloc();
+	}
+	void MemoryPool::dealloc(void* obj) {
+		_item* o = ((_item*) obj) - 1;
+		if (o->nextFree != (_item*) this) throw runtime_error(
+				"MemoryPool::free(): double free or corruption");
+		if (items > maxItems) {
+			::free(o);
+		} else {
+			items++;
+			o->nextFree = NULL;
+			if (_lastFree != NULL) {
+				_lastFree->nextFree = o;
+			}
+			_lastFree = o;
+			if (_freeList == NULL) _freeList = o;
+		}
+	}
+
+	PThreadMutex::PThreadMutex() {
+		pthread_mutexattr_t attr;
+		pthread_mutexattr_init(&attr);
+		pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+		pthread_mutex_init(&m, &attr);
+		pthread_mutexattr_destroy(&attr);
+	}
+	PThreadMutex::~PThreadMutex() {
+		pthread_mutex_destroy(&m);
+	}
+	void PThreadMutex::lock() {
+		pthread_mutex_lock(&m);
+	}
+	void PThreadMutex::unlock() {
+		pthread_mutex_unlock(&m);
+	}
+
+}

+ 41 - 0
cpoll_cppsp/cppsp_rel0.2.3/cpoll/cpoll.cbp

@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+<CodeBlocks_project_file>
+	<FileVersion major="1" minor="6" />
+	<Project>
+		<Option title="cpoll" />
+		<Option pch_mode="2" />
+		<Option compiler="gcc" />
+		<Build>
+			<Target title="Debug">
+				<Option output="bin/Debug/cpoll" prefix_auto="1" extension_auto="1" />
+				<Option object_output="obj/Debug/" />
+				<Option type="1" />
+				<Option compiler="gcc" />
+				<Compiler>
+					<Add option="-g" />
+				</Compiler>
+			</Target>
+			<Target title="Release">
+				<Option output="bin/Release/cpoll" prefix_auto="1" extension_auto="1" />
+				<Option object_output="obj/Release/" />
+				<Option type="1" />
+				<Option compiler="gcc" />
+				<Compiler>
+					<Add option="-O2" />
+				</Compiler>
+				<Linker>
+					<Add option="-s" />
+				</Linker>
+			</Target>
+		</Build>
+		<Compiler>
+			<Add option="-Wall" />
+		</Compiler>
+		<Extensions>
+			<envvars />
+			<code_completion />
+			<debugger />
+			<lib_finder disable_auto="1" />
+		</Extensions>
+	</Project>
+</CodeBlocks_project_file>

+ 248 - 0
cpoll_cppsp/cppsp_rel0.2.3/cpoll/http.C

@@ -0,0 +1,248 @@
+/***************************************************************************
+ *
+ * copyright notice: some code is copied from cURL, some code is my own
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <[email protected]>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * //modified by: xaxaxa
+ *
+ ***************************************************************************/
+
+#include "include/http.H"
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <iostream>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/poll.h>
+using namespace std;
+using namespace CP;
+namespace curl
+{
+	struct taskInfo;
+	void processEvent(taskInfo* t, int i);
+	struct taskInfo: public CP::File
+	{
+		instance* inst;
+		CURL* c;
+		int act; //from libcurl
+		bool isAdded;
+		taskInfo(HANDLE h) :
+				File(h), act(0), isAdded(false) {
+		}
+		void inCB(int i) {
+			processEvent(this, CURL_CSELECT_IN);
+		}
+		void outCB(int i) {
+			processEvent(this, CURL_CSELECT_OUT);
+		}
+		void updateEvents(int act) {
+			if (act & CURL_POLL_IN) waitForEvent(CP::Events::in, { &taskInfo::inCB, this }, true);
+			else if (this->act & CURL_POLL_IN) cancelRead();
+			if (act & CURL_POLL_OUT) waitForEvent(CP::Events::out, { &taskInfo::outCB, this }, true);
+			else if (this->act & CURL_POLL_OUT) cancelWrite();
+			this->act = act;
+		}
+		void setTaskInfo(instance* inst, CURL* c, int act) {
+			this->inst = inst;
+			this->c = c;
+
+			updateEvents(act);
+			inst->p->add(*this);
+			this->isAdded = true;
+		}
+	};
+	struct curlTaskInfo
+	{
+		CURL *c;
+		function<void(CURL*, CURLcode)> cb;
+		//void* userdata;
+	};
+	void checkQueue(instance* inst) {
+		CURLMsg *msg;
+		int msgs_left;
+		while ((msg = curl_multi_info_read(inst->m, &msgs_left))) {
+			if (msg->msg == CURLMSG_DONE) {
+				CURL *c = msg->easy_handle;
+				curlTaskInfo* t = NULL;
+				curl_easy_getinfo(c, CURLINFO_PRIVATE, &t);
+				//cout << "t = " << t << endl;
+				curl_multi_remove_handle(inst->m, c);
+				curl_easy_cleanup(c);
+				t->cb(c, msg->data.result);
+				delete t;
+			}
+		}
+	}
+	void processEvent(taskInfo* t, int i) {
+		//printf("processEvent: i=%i\n", i);
+		int num_transfers;
+		curl_multi_socket_action(t->inst->m, t->handle, i, &num_transfers);
+		checkQueue(t->inst);
+	}
+
+	/* CURLMOPT_SOCKETFUNCTION */
+	int cb_sock(CURL *c, curl_socket_t s, int what, void *cbp, void *sockp) {
+		//cout << "cb_sock()" << endl;
+
+		instance* inst = (instance*) cbp;
+		taskInfo* t = (taskInfo*) sockp;
+		if (what == CURL_POLL_REMOVE && t != NULL) {
+			//printf("cb_sock: remove\n");
+			//if (t->isAdded) event_del(&t->ev);
+			inst->p->del(*t);
+			t->handle = -1;
+			delete t;
+		} else {
+			if (t == NULL) { //add
+				//printf("cb_sock: add\n");
+				t = new taskInfo((HANDLE) s);
+				t->setTaskInfo(inst, c, what);
+				curl_multi_assign(inst->m, s, t);
+			} else { //modify events monitored
+				//printf("cb_sock: update\n");
+				t->updateEvents(what);
+			}
+		}
+		return 0;
+	}
+	void addCurlTask(instance* inst, CURL* c, const function<void(CURL*, CURLcode)>& cb) {
+		//printf("addCurlTask\n");
+		curlTaskInfo* t = new curlTaskInfo();
+		t->c = c;
+		t->cb = cb;
+		//t->userdata=userdata;
+		curl_easy_setopt(c, CURLOPT_PRIVATE, t);
+		curl_multi_add_handle(inst->m, c);
+		//int still_running;
+		//curl_multi_perform(inst->m, &still_running);
+	}
+	struct transferInfo
+	{
+		function<bool(const void* data, int len, int state)> cb;
+		CURL* c;
+	};
+	size_t cb_data(void *data, size_t size, size_t nmemb, void *userdata) {
+		transferInfo* t = (transferInfo*) userdata;
+		if (!t->cb(data, size * nmemb, 3)) return 0;
+		return size * nmemb;
+	}
+	transferInfo* addTransfer(instance* inst, const char* url,
+			const function<bool(const void* data, int len, int state)>& cb)
+			/*-1:failed 1:connected 2:sent 3:recving 4:closed*/
+			{
+		CURL* c = curl_easy_init();
+		curl_easy_setopt(c, CURLOPT_URL, url);
+		transferInfo* t = new transferInfo();
+		t->cb = cb;
+		t->c = c;
+		curl_easy_setopt(c, CURLOPT_WRITEDATA, t);
+		curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, cb_data);
+		return t;
+	}
+	void beginTransfer(instance* inst, transferInfo* t) {
+		addCurlTask(inst, t->c, [t](CURL* c,CURLcode res)
+		{
+			if(res==CURLE_OK) t->cb(NULL,0,4);
+			else if(res!=CURLE_WRITE_ERROR) t->cb(NULL,0,-res);
+			delete t;
+		});
+	}
+	int cb_curl_timer(CURLM *m, long timeout_ms, void* userdata) { /* Update the event timer after curl_multi library calls */
+		//printf("cb_curl_timer: timeout=%li\n", timeout_ms);
+		instance* inst = (instance*) userdata;
+		inst->timer.setInterval(timeout_ms < 0 ? 0 : timeout_ms);
+		return 0;
+	}
+	void cb_timer(void *userdata, int count) {
+		//printf("cb_timer: count=%i\n", count);
+		instance* inst = (instance*) userdata;
+		inst->timer.setInterval(0);
+		int num_transfers;
+		curl_multi_socket_action(inst->m, CURL_SOCKET_TIMEOUT, 0, &num_transfers);
+		checkQueue(inst);
+	}
+	void newInstance(instance* inst, CP::Poll* p) {
+		inst->m = curl_multi_init();
+		inst->p = p;
+		inst->timer.setCallback( { &cb_timer, (void*) inst });
+		p->add(inst->timer);
+		//event_assign(&inst->timer_event, inst->eb, -1, 0, cb_timer, inst);
+		curl_multi_setopt(inst->m, CURLMOPT_SOCKETFUNCTION, cb_sock);
+		curl_multi_setopt(inst->m, CURLMOPT_SOCKETDATA, inst);
+		curl_multi_setopt(inst->m, CURLMOPT_TIMERFUNCTION, cb_curl_timer);
+		curl_multi_setopt(inst->m, CURLMOPT_TIMERDATA, inst);
+	}
+	void dispose(instance* inst) {
+		curl_multi_cleanup(inst->m);
+	}
+
+	void transferManager::addTransfer(const char* url, bool post,
+			const function<bool(const void* data, int len, int state)>& cb) {
+		if (itemsProcessing < concurrency) {
+			doTransfer(url, post, cb);
+		} else {
+			q.push( { url, post, cb });
+		}
+	}
+	void transferManager::checkQueue() {
+		if (itemsProcessing < concurrency && q.size() > 0) {
+			item& it = q.front();
+			doTransfer(it.url.c_str(), it.post, it.cb);
+			q.pop();
+		}
+	}
+	void transferManager::doTransfer(const char* url, bool post,
+			const function<bool(const void* data, int len, int state)>& cb) {
+		itemsProcessing++;
+		transferInfo* t = curl::addTransfer(&inst, url,
+				[cb,this](const void* data, int len, int state)
+				{
+					if(state==4) {
+						itemsProcessing--;
+						checkQueue();
+					}
+					return cb(data, len, state);
+				});
+		if (post) curl_easy_setopt(t->c, CURLOPT_POST, 1);
+		curl::beginTransfer(&inst, t);
+	}
+}
+/*
+ int main(int argc, char **argv)
+ {
+ curl::instance inst;
+ curl::newInstance(&inst);
+ curl::addTransfer(&inst,"http://192.168.5.11/",[](const void* data, int len, int state)
+ {
+ cout << len << endl;
+ //if(data!=NULL && len>0)
+ //	write(1,data,len);
+ return true;
+ });
+ curl::eventLoop(&inst);
+
+ return 0;
+ } //*/
+

+ 175 - 0
cpoll_cppsp/cppsp_rel0.2.3/cpoll/include/basictypes.H

@@ -0,0 +1,175 @@
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * */
+/*
+ * basictypes.H
+ *
+ *  Created on: Apr 26, 2013
+ *      Author: xaxaxa
+ */
+
+#ifndef BASICTYPES_H_
+#define BASICTYPES_H_
+#include <string>
+#include <stdexcept>
+#include <rgc.H>
+using namespace std;
+namespace CP
+{
+	typedef int32_t HANDLE; //file descriptor or handle
+	typedef Delegate<void(int32_t)> Callback;
+	typedef uint8_t event_t;
+	struct String;
+	class MemoryBuffer: virtual public RGC::Object
+	{
+	public:
+		virtual uint8_t* data() const=0;
+		virtual int length() const=0;
+		inline CP::String String();
+	};
+	struct String
+	{
+		char* d;
+		int len;
+		String() :
+				d(nullptr), len(0) {
+		}
+		String(std::nullptr_t) :
+				d(nullptr), len(0) {
+		}
+		String(char* data, int length) :
+				d(data), len(length) {
+		}
+		String(char* data) :
+				d(data), len(data == nullptr ? 0 : strlen(data)) {
+		}
+		String(const char* data, int length) :
+				d(const_cast<char*>(data)), len(length) {
+		}
+		String(const void* data, int length) :
+				d((char*) (data)), len(length) {
+		}
+		String(const char* data) :
+				d(const_cast<char*>(data)), len(strlen(data)) {
+		}
+		String(std::string s) :
+				d((char*) s.data()), len(s.length()) {
+		}
+		String(MemoryBuffer& mb) :
+				d((char*) mb.data()), len(mb.length()) {
+		}
+		int compare(const String& other) const {
+			if (len < other.len) return -1;
+			else if (len > other.len) return 1;
+			else if (len == 0) return 0;
+			else return memcmp(d, other.d, len);
+		}
+		inline bool operator<(const String& other) const {
+			return compare(other) < 0;
+		}
+		inline bool operator>(const String& other) const {
+			return compare(other) > 0;
+		}
+		inline bool operator<=(const String& other) const {
+			return compare(other) <= 0;
+		}
+		inline bool operator>=(const String& other) const {
+			return compare(other) >= 0;
+		}
+		inline bool operator==(const String& other) const {
+			return compare(other) == 0;
+		}
+		inline bool operator==(std::nullptr_t other) const {
+			return len == 0;
+		}
+		inline char* data() const {
+			return d;
+		}
+		inline int length() const {
+			return len;
+		}
+		inline std::string toSTDString() const {
+			return std::string(d, len);
+		}
+		inline String subString(int i, int l) {
+			if (i < 0 || i + l > this->len || l < 0) throw range_error(
+					"String::subString() out of range");
+			return String(d + i, l);
+		}
+		inline String subString(int i) {
+			return subString(i, len - i);
+		}
+		inline void clip(int index, int length) {
+			if (index < 0 || index + length > this->len || length < 0) throw range_error(
+					"String::clip() out of range");
+			d += index;
+			len = length;
+		}
+		inline void clip(int index) {
+			if (index < 0 || index > this->len) throw range_error("String::clip() out of range");
+			d += index;
+			len -= index;
+		}
+		inline int indexOf(String s, int i = 0) {
+			void* tmp = memmem(d + i, len - i, s.d, s.len);
+			return tmp == NULL ? -1 : (((char*) tmp) - d);
+		}
+		inline int indexOf(char c, int i = 0) {
+			void* tmp = memchr(d + i, c, len - i);
+			return tmp == NULL ? -1 : (((char*) tmp) - d);
+		}
+		inline char& operator[](int i) {
+			return d[i];
+		}
+	};
+	template<class ... T>
+	String concat(RGC::Allocator& alloc, T ... s...) {
+		int l=sizeof...(s);
+		String tmp[sizeof...(s)] {s...};
+		int size=0;
+		for(int i=0;i<l;i++) size+=tmp[i].len;
+		String r {(char*)alloc.alloc(size),0};
+		for(int i=0;i<l;i++) {
+			memcpy(r.d+r.len,tmp[i].d,tmp[i].len);
+			r.len+=tmp[i].len;
+		}
+		return r;
+	}
+#define __CPOLL_DO_ATOI(func,str) char tmp[str.len + 1];\
+														memcpy(tmp, str.d, str.len);\
+														tmp[str.len] = 0;\
+														return func(tmp);
+	static int atoi(String s) {
+		__CPOLL_DO_ATOI(::atoi, s);
+	}
+	static long atol(String s) {
+		__CPOLL_DO_ATOI(::atol, s);
+	}
+	static long long atoll(String s) {
+		__CPOLL_DO_ATOI(::atoll, s);
+	}
+	static double atof(String s) {
+		__CPOLL_DO_ATOI(::atof, s);
+	}
+
+	/*
+	 static long long atoq(String s) {
+	 __CPOLL_DO_ATOI(::atoq, s);
+	 }*/
+	CP::String MemoryBuffer::String() {
+		return {(char*)data(),length()};
+	}
+}
+
+#endif /* BASICTYPES_H_ */

+ 1784 - 0
cpoll_cppsp/cppsp_rel0.2.3/cpoll/include/cpoll.H

@@ -0,0 +1,1784 @@
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * */
+
+/*
+ * uses code from http://www.cse.yorku.ca/~oz/hash.html
+ * for sdbm hash algorithm
+ * */
+
+/*
+ * TODO:
+ * 
+ * * move readAll and writeAll implementation to Stream
+ * * automatic AIO for file async IO
+ * * socket connect()
+ * * verify that all system call return values are checked
+ * * verify that all code paths that may encounter exceptions
+ *   	release their resources (memory etc) properly when 
+ * 		exceptions are encountered
+ * * HTTP support
+ * 
+ * 
+ * */
+#ifndef __INCLUDED_CPOLL_H
+#define __INCLUDED_CPOLL_H
+#include <string>
+#include <exception>
+#include <poll.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+#include <vector>
+#include <sys/signalfd.h>
+#include <sys/eventfd.h>
+#include <delegate.H>
+#include <sys/epoll.h>
+#include <limits>
+#include "basictypes.H"
+#include "statemachines.H"
+#include <fcntl.h>
+#include <math.h>
+
+#ifndef WARNLEVEL
+#define WARNLEVEL 5
+#endif
+#ifndef WARN
+#define WARN(LEVEL,MSG) if(LEVEL<=WARNLEVEL){if(LEVEL<=1)cerr << "\x1B[41;1;33m"; else if(LEVEL<=2)cerr << "\x1B[1;1;1m"; cerr << MSG << "\x1B[0;0;0m" << endl;}
+#endif
+/*
+ * CPoll: low level c++ wrapper for poll() and epoll(); can be implemented on
+ * other OS's using mechanisms such as overlapped I/O(windows), but currently
+ * there is only a linux implementation; for other OS's patches are welcome ;)
+ *
+ * simple usage example:
+ *
+ * char buf[4096];
+ * char buf2[4096];
+ * File f(1); //stdout
+ * File f2(2); //stderr
+ * f.read(buf, 4096, [](){cout << "read1 done" << endl;});
+ * f2.read(buf2, 4096, [](){cout << "read2 done" << endl;});
+ *
+ * Poll p;
+ * p.add(f);
+ * p.add(f2);
+ * p.loop(); //epoll is used
+ *
+ *
+ *
+ *
+ * nested example:
+ *
+ * File f(0); //stdin
+ * char buf[4096];
+ * f.read([](){}, buf,4096);
+ * Poll poll;
+ * poll.add(f);
+ * Poll poll2;
+ * poll2.add(poll);
+ * poll2.loop();
+ */
+
+#ifndef likely
+#define likely(x)       __builtin_expect((x),1)
+#define unlikely(x)     __builtin_expect((x),0)
+#endif
+
+namespace CP
+{
+	using namespace std;
+	class CPollException: public std::exception
+	{
+	public:
+		string message;
+		int32_t number;
+		CPollException();
+		CPollException(int32_t number);
+		CPollException(string message, int32_t number = 0);
+		~CPollException() throw ();
+		const char* what() const throw ();
+	};
+	class AbortException: public std::exception
+	{ //used for aborting the event loop
+	public:
+		AbortException();
+		~AbortException() throw ();
+		const char* what() const throw ();
+	};
+	class CancelException: public std::exception
+	{ //used for cancelling a repeat[Read|Write] operation
+	  //do NOT throw this exception on one-shot operations such as read()
+	public:
+		CancelException();
+		~CancelException() throw ();
+		const char* what() const throw ();
+	};
+	static inline uint64_t ntohll(uint64_t value) {
+		// The answer is 42
+		static const int32_t num = 42;
+
+		// Check the endianness
+		if (*reinterpret_cast<const char*>(&num) == num) {
+			const uint32_t high_part = htonl(static_cast<uint32_t>(value >> 32));
+			const uint32_t low_part = htonl(static_cast<uint32_t>(value & 0xFFFFFFFFLL));
+
+			return (static_cast<uint64_t>(low_part) << 32) | high_part;
+		} else {
+			return value;
+		}
+	}
+
+	//==============================================================
+	//==============================================================
+	//=================NETWORK UTILITY CLASSES======================
+	//=====================taken from cplib=========================
+	//==============================================================
+	//==============================================================
+	
+	struct IPAddress
+	{
+		in_addr a;
+		inline IPAddress() {
+		}
+		inline IPAddress(const char* addr/*NOT hostname*/) {
+			inet_pton(AF_INET, addr, &a.s_addr);
+		}
+		inline IPAddress(const in_addr& a) {
+			this->a = a;
+		}
+		inline bool operator<(const IPAddress& other) const {
+			return ntohl(a.s_addr) < ntohl(other.a.s_addr);
+		}
+		inline bool operator>(const IPAddress& other) const {
+			return ntohl(a.s_addr) > ntohl(other.a.s_addr);
+		}
+		inline bool operator<=(const IPAddress& other) const {
+			return ntohl(a.s_addr) <= ntohl(other.a.s_addr);
+		}
+		inline bool operator>=(const IPAddress& other) const {
+			return ntohl(a.s_addr) >= ntohl(other.a.s_addr);
+		}
+		inline bool operator==(const IPAddress& other) const {
+			return a.s_addr == other.a.s_addr;
+		}
+		inline IPAddress operator+(const IPAddress& other) const {
+			return IPAddress( { htonl(ntohl(a.s_addr) + ntohl(other.a.s_addr)) });
+		}
+		inline IPAddress operator-(const IPAddress& other) const {
+			return IPAddress( { htonl(ntohl(a.s_addr) - ntohl(other.a.s_addr)) });
+		}
+		inline IPAddress operator+(int i) const {
+			//WARN(1,a.s_addr << " " <<ntohl(a.s_addr));
+			//cout << "a" << endl;
+			return IPAddress( { htonl(ntohl(a.s_addr) + i) });
+		}
+		inline IPAddress operator-(int i) const {
+			return IPAddress( { htonl(ntohl(a.s_addr) - i) });
+		}
+		string toStr() const {
+			char tmp[INET_ADDRSTRLEN];
+			if (inet_ntop(AF_INET, &a, tmp, INET_ADDRSTRLEN) == NULL) throw CPollException();
+			return string(tmp);
+		}
+	};
+	struct IPv6Address
+	{
+		in6_addr a;
+		inline IPv6Address() {
+		}
+		inline IPv6Address(const char* addr) {
+			inet_pton(AF_INET6, addr, &a.__in6_u);
+		}
+		inline IPv6Address(const in6_addr& a) {
+			this->a = a;
+		}
+		string toStr() const {
+			char tmp[INET_ADDRSTRLEN];
+			if (inet_ntop(AF_INET6, &a, tmp, INET6_ADDRSTRLEN) == NULL) throw CPollException();
+			return string(tmp);
+		}
+	};
+	class EndPoint: virtual public RGC::Object
+	{
+	public:
+		int32_t addressFamily;
+		virtual void getSockAddr(sockaddr* addr) const=0;
+		virtual void setSockAddr(const sockaddr* addr)=0;
+		virtual int32_t getSockAddrSize() const=0;
+		static EndPoint* fromSockAddr(const sockaddr* addr);
+		static EndPoint* create(int32_t addressFamily);
+		static int getSize(int32_t addressFamily);
+		static EndPoint* construct(void* mem, int32_t addressFamily);
+		virtual void clone(EndPoint& to) const=0;
+		virtual ~EndPoint() {
+		}
+		static vector<RGC::Ref<EndPoint> > lookupHost(const char* hostname, const char* port,
+				int32_t family = AF_UNSPEC, int32_t socktype = 0, int32_t proto = 0, int32_t flags = 0);
+		//static EndPoint Resolve(
+		virtual string toStr() const=0;
+	};
+	class IPEndPoint: public EndPoint
+	{
+	public:
+		IPAddress address;
+		in_port_t port;
+		IPEndPoint();
+		IPEndPoint(IPAddress address, in_port_t port);
+		void set_addr(const sockaddr_in& addr);
+		virtual void setSockAddr(const sockaddr* addr);
+		IPEndPoint(const sockaddr_in& addr);
+		virtual void getSockAddr(sockaddr* addr) const;
+		virtual int32_t getSockAddrSize() const;
+		virtual void clone(EndPoint& to) const;
+		virtual string toStr() const;
+	};
+	class IPv6EndPoint: public EndPoint
+	{
+	public:
+		IPv6Address address;
+		in_port_t port;
+		uint32_t flowInfo;
+		uint32_t scopeID;
+		IPv6EndPoint();
+		IPv6EndPoint(IPv6Address address, in_port_t port);
+		void set_addr(const sockaddr_in6& addr);
+		IPv6EndPoint(const sockaddr_in6& addr);
+		virtual void setSockAddr(const sockaddr* addr);
+		virtual void getSockAddr(sockaddr* addr) const;
+		virtual int32_t getSockAddrSize() const;
+		virtual void clone(EndPoint& to) const;
+		virtual string toStr() const;
+	};
+	class UNIXEndPoint: public EndPoint
+	{
+	public:
+		string name;
+		UNIXEndPoint();
+		UNIXEndPoint(string name);
+		void set_addr(const sockaddr_un& addr);
+		UNIXEndPoint(const sockaddr_un& addr);
+		virtual void setSockAddr(const sockaddr* addr);
+		virtual void getSockAddr(sockaddr* addr) const;
+		virtual int32_t getSockAddrSize() const;
+		virtual void clone(EndPoint& to) const;
+		virtual string toStr() const;
+	};
+	//===========================================================
+	//======================ABSTRACT CLASSES=====================
+	//===========================================================
+	class BufferedOutput: virtual public RGC::Object
+	{
+	public:
+		uint8_t* buffer;
+		int bufferPos;
+		int bufferSize;
+		BufferedOutput() {
+		}
+		BufferedOutput(uint8_t* buffer, int bufferPos, int bufferSize) :
+				buffer(buffer), bufferPos(bufferPos), bufferSize(bufferSize) {
+		}
+		//flushBuffer() should flush current buffer to stream, reallocate the buffer,
+		//and reset buffer, bufferPos and/or bufferSize accordingly (see below); the function
+		//must reserve at least minBufferAllocation bytes of space in the write buffer
+		virtual void flushBuffer(int minBufferAllocation)=0;
+		void flush() {
+			flushBuffer(0);
+		}
+	};
+
+	class Stream: virtual public RGC::Object
+	{
+	public:
+		Stream() = default;
+		Stream(const Stream& other) = delete;
+		Stream& operator=(const Stream& other) = delete;
+		union
+		{
+			struct
+			{
+				DelegateBase<void(int)> cb;
+				BufferedOutput* out;
+				int bufSize;
+				int br;
+			} _readToEnd;
+			struct
+			{
+				DelegateBase<void(int)> cb;
+				BufferedOutput* out;
+				int len;
+				int bufSize;
+				int br;
+			} _readChunked;
+			struct
+			{
+				DelegateBase<void(int)> cb;
+				iovec* iov;
+				int iovcnt;
+				int i, br;
+			} _readvAll;
+			struct
+			{
+				DelegateBase<void(int)> cb;
+				uint8_t* buf;
+				int len;
+				int i;
+			} _readAll;
+		};
+		union
+		{
+			struct
+			{
+				DelegateBase<void(int)> cb;
+				iovec* iov;
+				int iovcnt;
+				int i, br;
+			} _writevAll;
+			struct
+			{
+				DelegateBase<void(int)> cb;
+				const uint8_t* buf;
+				int len;
+				int i;
+			} _writeAll;
+		};
+		void _readvCB(int r);
+		void _readAllCB(int r);
+		void _writevCB(int r);
+		void _writeAllCB(int r);
+
+		//sync
+		virtual int32_t read(void* buf, int32_t len)=0; //required
+		int32_t read(String buf) {
+			return read(buf.data(), buf.length());
+		}
+		virtual int32_t readv(iovec* iov, int iovcnt) { //optional
+			if (iovcnt <= 0) return 0;
+			return read(iov[0].iov_base, iov[0].iov_len);
+		}
+		virtual int32_t readAll(void* buf, int32_t len) { //optional
+			int off = 0;
+			while (off < len) {
+				int tmp = read((uint8_t*) buf + off, len - off);
+				if (tmp <= 0) return off;
+				off += tmp;
+			}
+			return off;
+		}
+		int32_t readAll(String buf) {
+			return readAll(buf.data(), buf.length());
+		}
+		//note: may destroy the iov array
+		virtual int32_t readvAll(iovec* iov, int iovcnt) { //optional
+			int i = 0;
+			int br = 0;
+			while (i < iovcnt) {
+				int r = readv(iov + i, iovcnt - i);
+				if (r <= 0) break;
+				br += r;
+				while (r > 0 && i < iovcnt) {
+					if ((int) iov[i].iov_len > r) {
+						iov[i].iov_base = ((uint8_t*) iov[i].iov_base) + r;
+						iov[i].iov_len -= r;
+						break;
+					} else {
+						r -= iov[i].iov_len;
+						i++;
+					}
+				}
+			}
+			return br;
+		}
+		virtual int readToEnd(BufferedOutput& out, int32_t bufSize = 4096);
+		virtual int readChunked(BufferedOutput& out, int32_t len, int32_t bufSize = 4096);
+		virtual int32_t write(const void* buf, int32_t len)=0; //required
+		int32_t write(String buf) {
+			return write(buf.data(), buf.length());
+		}
+		virtual int32_t writev(iovec* iov, int iovcnt) { //optional
+			if (iovcnt <= 0) return 0;
+			return write(iov[0].iov_base, iov[0].iov_len);
+		}
+		virtual int32_t writeAll(const void* buf, int32_t len) { //optional
+			int off = 0;
+			while (off < len) {
+				int tmp = write((uint8_t*) buf + off, len - off);
+				if (tmp <= 0) return off;
+				off += tmp;
+			}
+			return off;
+		}
+		int32_t writeAll(String buf) {
+			return writeAll(buf.data(), buf.length());
+		}
+		virtual int32_t writevAll(iovec* iov, int iovcnt) { //optional
+			int i = 0;
+			int br = 0;
+			while (i < iovcnt) {
+				int r = writev(iov + i, iovcnt - i);
+				if (r <= 0) break;
+				br += r;
+				while (r > 0 && i < iovcnt) {
+					if ((int) iov[i].iov_len > r) {
+						iov[i].iov_base = ((uint8_t*) iov[i].iov_base) + r;
+						iov[i].iov_len -= r;
+						break;
+					} else {
+						r -= iov[i].iov_len;
+						i++;
+					}
+				}
+			}
+			return br;
+		}
+
+		//async
+		//all new subclasses of Stream now should only need to implement the hybrid[Read|Write] functions
+		//to provide async behavior; apps using [read|write](..., cb) will still work through the
+		//compatibility wrappers
+
+		//returns -2 to indicate that the operation is scheduled to be completed asynchronously; otherwise
+		//the request has been completed synchronously
+
+		//UPDATE: hybrid[Read|Write] has been canceled because it is extremely hard for users to design applications
+		// to deal with 2 programming models at once and it is very error-prone
+		/*virtual int32_t hybridRead(void* buf, int32_t len, const Callback& cb, bool repeat = false) { //optional (required for async)
+		 }
+		 virtual int32_t hybridWrite(const void* buf, int32_t len, const Callback& cb, bool repeat =
+		 false) { //optional (required for async)
+		 }*/
+		virtual void read(void* buf, int32_t len, const Callback& cb, bool repeat = false)=0;
+		void read(String buf, const Callback& cb, bool repeat = false) {
+			return read(buf.data(), buf.length(), cb, repeat);
+		}
+		virtual void readv(iovec* iov, int iovcnt, const Callback& cb, bool repeat = false) {
+			if (iovcnt <= 0) {
+				cb(0);
+				return;
+			}
+			return read(iov[0].iov_base, iov[0].iov_len, cb, repeat);
+		}
+		inline void repeatRead(void* buf, int32_t len, const Callback& cb) {
+			read(buf, len, cb, true);
+		}
+		inline void repeatRead(String buf, const Callback& cb) {
+			read(buf, cb, true);
+		}
+		inline void repeatReadv(iovec* iov, int iovcnt, const Callback& cb) {
+			readv(iov, iovcnt, cb, true);
+		}
+		virtual void readAll(void* buf, int32_t len, const Callback& cb);
+		void readAll(String buf, const Callback& cb) {
+			return readAll(buf.data(), buf.length(), cb);
+		}
+		virtual void readvAll(iovec* iov, int iovcnt, const Callback& cb);
+		virtual void readToEnd(BufferedOutput& out, const Callback& cb, int bufSize = 4096);
+		virtual void readChunked(BufferedOutput& out, int32_t len, const Callback& cb, int bufSize =
+				4096);
+
+		virtual void write(const void* buf, int32_t len, const Callback& cb, bool repeat = false)=0;
+		void write(String buf, const Callback& cb, bool repeat = false) {
+			return write(buf.data(), buf.length(), cb, repeat);
+		}
+		virtual void writev(iovec* iov, int iovcnt, const Callback& cb, bool repeat = false) {
+			if (iovcnt <= 0) {
+				cb(0);
+				return;
+			}
+			return write(iov[0].iov_base, iov[0].iov_len, cb, repeat);
+		}
+		inline void repeatWrite(const void* buf, int32_t len, const Callback& cb) {
+			write(buf, len, cb, true);
+		}
+		inline void repeatWrite(String buf, const Callback& cb) {
+			write(buf, cb, true);
+		}
+		inline void repeatWritev(iovec* iov, int iovcnt, const Callback& cb) {
+			writev(iov, iovcnt, cb, true);
+		}
+		virtual void writeAll(const void* buf, int32_t len, const Callback& cb);
+		void writeAll(String buf, const Callback& cb) {
+			return writeAll(buf.data(), buf.length(), cb);
+		}
+		virtual void writevAll(iovec* iov, int iovcnt, const Callback& cb);
+		//only for async read/write operations
+		virtual void cancelRead()=0;
+		virtual void cancelWrite()=0;
+
+		//=========misc===========
+		//sync
+		virtual void close()=0; //may block
+		virtual void flush()=0;
+
+		//async
+		virtual void close(const Callback& cb)=0;
+		virtual void flush(const Callback& cb)=0;
+
+		//only for streams with a read buffer; other streams should just return 0
+		//calling this function should "consume" that buffer, but should not perform
+		//further reading operations; this function should NOT block.
+		//returns length of buffer; address of buffer is put in buf
+		//if maxlen==-1, consume entire contiguous buffer
+		virtual int32_t readBuffer(void*& buf, int32_t maxlen) {
+			return 0;
+		}
+		inline String readBuffer(int32_t maxlen) {
+			void* tmp = NULL;
+			int32_t l = readBuffer(tmp, maxlen);
+			return {(char*)tmp,l};
+		}
+		//freeBuffer() must be called following every readBuffer() call;
+		//after calling readBuffer() and before calling freeBuffer(),
+		//all other operations are undefined
+		virtual void freeBuffer(void* buf, int32_t len) {
+		}
+
+		//returns NULL if it doesn't provide a buffer; in that case you need to create
+		//a StreamBuffer yourself
+		virtual BufferedOutput* getBufferedOutput();
+	};
+
+	class StreamBuffer: public BufferedOutput
+	{
+	public:
+		StreamBuffer(const StreamBuffer& other) = delete;
+		StreamBuffer& operator=(const StreamBuffer& other) = delete;
+		RGC::Ref<Stream> output;
+		StreamBuffer();
+		StreamBuffer(Stream& s, int bufsize = 4096);
+		virtual void flushBuffer(int minBufferAllocation);
+		~StreamBuffer() {
+			if (this->buffer != NULL) free(this->buffer);
+		}
+	}
+	;
+	class FixedMemoryStream;
+	class MemoryStream;
+	class StringStream;
+
+	//StreamWriter will directly access the BufferedOutput's buffer
+	//(for performance reasons) and increment bufferPos accordingly.
+	//if bufferPos reaches bufferSize, it will call the BufferedOutput's flushBuffer() method
+	class StreamWriter: public RGC::Object
+	{
+	public:
+		StreamWriter(const StreamWriter& other) = delete;
+		StreamWriter& operator=(const StreamWriter& other) = delete;
+		RGC::Ref<Object> outp;
+		BufferedOutput* buffer;
+		char _sb[sizeof(StreamBuffer)];
+		StreamBuffer& sb;
+		void write(const void* s, int len) {
+			if (buffer->bufferSize - buffer->bufferPos < len) buffer->flushBuffer(len);
+			memcpy(buffer->buffer + buffer->bufferPos, s, len);
+			buffer->bufferPos += len;
+		}
+		void write(const MemoryBuffer& buf) {
+			write(buf.data(), buf.length());
+		}
+		void write(string s) {
+			write(s.data(), s.length());
+		}
+		void write(String s) {
+			write(s.data(), s.length());
+		}
+		void write(const char* s) {
+			write((const uint8_t*) s, strlen(s));
+		}
+		void write(char c) {
+			if (unlikely(buffer->bufferSize - buffer->bufferPos < 1)) buffer->flushBuffer(1);
+			buffer->buffer[buffer->bufferPos] = c;
+			buffer->bufferPos++;
+		}
+		void write(int8_t i) {
+			//snprintf() writes a null byte and possibly a negative sign, so gotta reserve 5 bytes of buffer space
+			if (unlikely(buffer->bufferSize - buffer->bufferPos < 5)) buffer->flushBuffer(5);
+			buffer->bufferPos += snprintf((char*) buffer->buffer + buffer->bufferPos, 5, "%hhi", i);
+		}
+		void write(int16_t i) {
+			if (unlikely(buffer->bufferSize - buffer->bufferPos < 7)) buffer->flushBuffer(7);
+			buffer->bufferPos += snprintf((char*) buffer->buffer + buffer->bufferPos, 7, "%hi", i);
+		}
+		void write(int32_t i) {
+			if (unlikely(buffer->bufferSize - buffer->bufferPos < 12)) buffer->flushBuffer(12);
+			buffer->bufferPos += snprintf((char*) buffer->buffer + buffer->bufferPos, 12, "%i", i);
+		}
+		void write(int64_t i) {
+			if (unlikely(buffer->bufferSize - buffer->bufferPos < 22)) buffer->flushBuffer(22);
+			buffer->bufferPos += snprintf((char*) buffer->buffer + buffer->bufferPos, 22, "%lli", i);
+		}
+		void write(uint8_t i) {
+			if (unlikely(buffer->bufferSize - buffer->bufferPos < 4)) buffer->flushBuffer(4);
+			buffer->bufferPos += snprintf((char*) buffer->buffer + buffer->bufferPos, 4, "%hhu", i);
+		}
+		void write(uint16_t i) {
+			if (unlikely(buffer->bufferSize - buffer->bufferPos < 6)) buffer->flushBuffer(6);
+			buffer->bufferPos += snprintf((char*) buffer->buffer + buffer->bufferPos, 6, "%hu", i);
+		}
+		void write(uint32_t i) {
+			if (unlikely(buffer->bufferSize - buffer->bufferPos < 11)) buffer->flushBuffer(11);
+			buffer->bufferPos += snprintf((char*) buffer->buffer + buffer->bufferPos, 11, "%u", i);
+		}
+		void write(uint64_t i) {
+			if (unlikely(buffer->bufferSize - buffer->bufferPos < 21)) buffer->flushBuffer(21);
+			buffer->bufferPos += snprintf((char*) buffer->buffer + buffer->bufferPos, 21, "%llu", i);
+		}
+		char* beginWrite(int len) {
+			if (unlikely(buffer->bufferSize - buffer->bufferPos < len)) buffer->flushBuffer(len);
+			return (char*) buffer->buffer + buffer->bufferPos;
+		}
+		void endWrite(int len) {
+			buffer->bufferPos += len;
+		}
+		template<class ... P> void writeF(const char* fmt, P&&... p) {
+			int minSpace = 0;
+			if (minSpace + 1 > buffer->bufferSize - buffer->bufferPos) {
+				redo: buffer->flushBuffer(minSpace + 1);
+			}
+			minSpace = snprintf((char*) buffer->buffer + buffer->bufferPos,
+					buffer->bufferSize - buffer->bufferPos, fmt, std::forward<P>(p)...);
+			if (minSpace + 1 > buffer->bufferSize - buffer->bufferPos) goto redo;
+			buffer->bufferPos += minSpace;
+		}
+		void flush() {
+			buffer->flushBuffer(0);
+		}
+		StreamWriter(BufferedOutput& s);
+		StreamWriter(Stream& s);
+		StreamWriter(MemoryStream& s);
+		StreamWriter(StringStream& s);
+		~StreamWriter();
+	};
+
+	class StreamReader: public Stream
+	{ //writes are simply passed through
+	public:
+		typedef Delegate<void(const string&)> Callback;
+		typedef Delegate<void(int)> StreamCallback;
+		RGC::Ref<Stream> input;
+		//void* sr;
+		newStreamReader _sr;
+		bool* deletionFlag;
+		Stream* out_s;
+		union
+		{
+			DelegateBase<void(const string&)> cb;
+			DelegateBase<void(int)> cb_s;
+		};
+		//BufferedOutput* tmp_out;
+		string tmp;
+		string tmp_delim;
+
+		int tmp_i;
+		int bufSize;
+
+		bool eof;
+		/*void* curBuffer;
+		 int curBufferLen;
+		 int bufferSize;
+		 bool bufferIsBorrowed;*/
+
+		StreamReader(Stream& input, int bufsize = 4096);
+		~StreamReader();
+
+		string readTo(char delim);
+		string readTo(const char* delim, int delimLen);
+		string readTo(string delim);
+		string readLine();
+		int readTo(char delim, Stream& s);
+		int readTo(const char* delim, int delimLen, Stream& s);
+		int readTo(string delim, Stream& s);
+		int readLine(Stream& s);
+
+		void readTo(char delim, const Callback& cb);
+		//*delim MUST NOT BE DELETED FOR THE ENTIRE DURATION OF THE READTO REQUEST!!!!!
+		//it does not make a copy of delim!!!!!
+		void readTo(const char* delim, int delimLen, const Callback& cb);
+		void readTo(string delim, const Callback& cb);
+		void readLine(const Callback& cb);
+
+		void readTo(char delim, Stream& s, const StreamCallback& cb);
+		void readTo(const char* delim, int delimLen, Stream& s, const StreamCallback& cb);
+		void readTo(string delim, Stream& s, const StreamCallback& cb);
+		void readLine(Stream& s, const StreamCallback& cb);
+
+		//sync
+		virtual int32_t read(void* buf, int32_t len);
+		virtual int32_t write(const void* buf, int32_t len) {
+			return input->write(buf, len);
+		}
+		virtual int32_t writeAll(const void* buf, int32_t len) {
+			return input->writeAll(buf, len);
+		}
+
+		//async
+		virtual void read(void* buf, int32_t len, const CP::Callback& cb, bool repeat = false);
+		virtual void readAll(void* buf, int32_t len, const CP::Callback& cb);
+		virtual void write(const void* buf, int32_t len, const CP::Callback& cb,
+				bool repeat = false) {
+			return input->write(buf, len, cb, repeat);
+		}
+		virtual void writeAll(const void* buf, int32_t len, const CP::Callback& cb) {
+			return input->writeAll(buf, len, cb);
+		}
+		//does NOT cancel readTo() or readLine() operations
+		virtual void cancelRead();
+		virtual void cancelWrite();
+
+		//=========misc===========
+		//sync
+		virtual void close();
+		virtual void flush();
+
+		//async
+		virtual void close(const CP::Callback& cb);
+		virtual void flush(const CP::Callback& cb);
+
+		virtual int32_t readBuffer(void*& buf, int32_t maxlen);
+		virtual void freeBuffer(void* buf, int32_t len);
+
+		//internal
+		bool _loop(bool);
+		void _beginRead();
+		void _doSyncRead();
+		void _readCB(int i);
+	}
+	;
+
+	//===========================================================
+	//======================UTILITY CLASSES======================
+	//===========================================================
+
+	//===========================================================
+	//======================DATA STRUCTURES======================
+	//===========================================================
+	
+	enum class Events
+		: event_t
+		{
+			none = 0, in = 1, out = 2, other = 4, all = 7
+	}
+	;
+	static inline Events operator&(Events e1, Events e2) {
+		return (Events) (((event_t) e1) & ((event_t) e2));
+	}
+	static inline Events operator|(Events e1, Events e2) {
+		return (Events) (((event_t) e1) | ((event_t) e2));
+	}
+	static inline Events operator^(Events e1, Events e2) {
+		return (Events) (((event_t) e1) ^ ((event_t) e2));
+	}
+	static inline const Events& operator&=(Events& e1, Events e2) {
+		return (Events&) (((event_t&) e1) &= ((event_t) e2));
+	}
+	static inline const Events& operator|=(Events& e1, Events e2) {
+		return (Events&) (((event_t&) e1) |= ((event_t) e2));
+	}
+	static inline const Events& operator^=(Events& e1, Events e2) {
+		return (Events&) (((event_t&) e1) ^= ((event_t) e2));
+	}
+
+	enum class Operations
+		: uint8_t
+		{
+			none = 0, read = 1, write, send, recv, sendTo, recvFrom, accept, readAll, writeAll,
+		sendAll, recvAll, shutdown, connect, close, readv, writev, lastItem
+	};
+
+	struct EventData
+	{
+	public:
+		bool hungUp, error;
+	};
+	struct EventHandlerData
+	{
+	public:
+		Callback cb;
+		union miscUnion
+		{
+			struct
+			{
+				void* buf;
+				union
+				{
+					EndPoint* ep; //recvFrom
+					const EndPoint* const_ep; //sendTo
+				};
+				int32_t len;
+				int32_t flags;
+				int32_t len_done;
+			} bufferIO;
+			struct
+			{
+				iovec* iov;
+				int iovcnt;
+			} bufferIOv;
+			struct
+			{
+				int32_t how;
+			} shutdown;
+			struct
+			{
+				eventfd_t evt;
+			} eventfd;
+		} misc;
+		Delegate<bool(Events event, EventHandlerData& ed, const EventData& evtd, bool confident)> opcb;
+		Operations op;
+		enum class States
+			: uint8_t {
+				invalid = 0, once = 1, repeat
+		} state;
+		EventHandlerData() :
+				state(States::invalid) {
+		}
+	};
+	
+	static const int32_t numEvents = 2;
+	//============================================================
+	//============================================================
+	//=======================MAIN CLASSES=========================
+	//============================================================
+	//============================================================
+	
+	class Handle: virtual public RGC::Object
+	{
+	public:
+		Handle(const Handle& other) = delete;
+		Handle& operator=(const Handle& other) = delete;
+		//void* __private;
+		HANDLE handle;
+		bool _supportsEPoll;
+		Handle();
+		Handle(HANDLE handle);
+		Delegate<void(Handle& h, Events old_events)> onEventsChange;
+		Delegate<void(Handle& h)> onClose;
+
+		virtual void init(HANDLE handle);
+		virtual void deinit();
+		///calls the callback associated with the event
+		///only accepts one event
+		virtual bool dispatch(Events event, const EventData& evtd, bool confident)=0;
+		virtual Events getEvents()=0;
+		virtual Events dispatchMultiple(Events events, Events confident, const EventData& evtd);
+		///get some events from the queue.
+		virtual Events wait(EventData& evtd);
+		virtual Events waitAndDispatch();
+		virtual void loop();
+		void setBlocking(bool b = true) {
+			int f = fcntl(handle, F_GETFL);
+			if (b && (f & O_NONBLOCK)) {
+				fcntl(handle, F_SETFL, f & ~O_NONBLOCK);
+			} else if (!b && (f & O_NONBLOCK) == 0) {
+				fcntl(handle, F_SETFL, f | O_NONBLOCK);
+			}
+		}
+		//void close();
+		~Handle();
+	};
+	class File: public Handle, public Stream
+	{
+	public:
+		EventHandlerData eventData[numEvents];
+		bool* deletionFlag;
+		Events preDispatchEvents;
+		bool dispatching;
+
+		File();
+		File(HANDLE handle);
+		virtual void init(HANDLE handle);
+		Events _getEvents();
+		///only accepts one event
+		EventHandlerData* beginAddEvent(Events event);
+		void endAddEvent(Events event, bool repeat = false);
+		void cancel(Events event);
+		int32_t read(void* buf, int32_t len) override;
+		int32_t readv(iovec* iov, int iovcnt) override;
+		int32_t readAll(void* buf, int32_t len) {
+			return Stream::readAll(buf, len);
+		}
+		int32_t write(const void* buf, int32_t len) override;
+		int32_t writev(iovec* iov, int iovcnt) override;
+		int32_t writeAll(const void* buf, int32_t len) {
+			return Stream::writeAll(buf, len);
+		}
+		int32_t send(const void* buf, int32_t len, int32_t flags = 0);
+		int32_t sendAll(const void* buf, int32_t len, int32_t flags = 0);
+		int32_t recv(void* buf, int32_t len, int32_t flags = 0);
+		int32_t recvAll(void* buf, int32_t len, int32_t flags = 0);
+		Events checkEvents(Events events);
+		virtual bool doOperation(Events event, EventHandlerData& ed, const EventData& evtd,
+				EventHandlerData::States oldstate, bool confident);
+		bool dispatch(Events event, const EventData& evtd, bool confident, bool& deletionFlag);
+		bool dispatch(Events event, const EventData& evtd, bool confident) override {
+			bool d = false;
+			deletionFlag = &d;
+			bool r = dispatch(event, evtd, d);
+			if (!d) deletionFlag = NULL;
+			return r;
+		}
+		Events dispatchMultiple(Events events, Events confident, const EventData& evtd) override;
+		inline void fillIOEventHandlerData(EventHandlerData* ed, void* buf, int32_t len,
+				const Callback& cb, Events e, Operations op);
+		inline void fillIOEventHandlerData(EventHandlerData* ed, iovec* iov, int iovcnt,
+				const Callback& cb, Events e, Operations op);
+		void read(void* buf, int32_t len, const Callback& cb, bool repeat = false) override;
+		void readv(iovec* iov, int iovcnt, const Callback& cb, bool repeat = false) override;
+		void readAll(void* buf, int32_t len, const Callback& cb) override;
+
+		void write(const void* buf, int32_t len, const Callback& cb, bool repeat = false) override;
+		void writev(iovec* iov, int iovcnt, const Callback& cb, bool repeat = false) override;
+		void writeAll(const void* buf, int32_t len, const Callback& cb) override;
+
+		void recv(void* buf, int32_t len, int32_t flags, const Callback& cb, bool repeat = false);
+		inline void repeatRecv(void* buf, int32_t len, int32_t flags, const Callback& cb) {
+			recv(buf, len, flags, cb, true);
+		}
+		void recvAll(void* buf, int32_t len, int32_t flags, const Callback& cb);
+
+		void send(const void* buf, int32_t len, int32_t flags, const Callback& cb,
+				bool repeat = false);
+		inline void repeatSend(const void* buf, int32_t len, int32_t flags, const Callback& cb) {
+			send(buf, len, flags, cb, true);
+		}
+		void sendAll(const void* buf, int32_t len, int32_t flags, const Callback& cb);
+		virtual Events getEvents() override final {
+			return _getEvents();
+		}
+		~File();
+
+		//=========misc===========
+		//sync
+		virtual void close(); //may block
+		virtual void flush();
+
+		//async
+		virtual void close(const Callback& cb);
+		virtual void flush(const Callback& cb);
+
+		//misc
+		void cancelRead();
+		void cancelWrite();
+		void cancelSend() {
+			cancelWrite();
+		}
+		void cancelRecv() {
+			cancelRead();
+		}
+		void waitForEvent(Events event, const Callback& cb, bool repeat = false);
+	};
+	class Socket: public File
+	{
+	public:
+		union
+		{
+			DelegateBase<void(Socket*)> _acceptCB;
+			DelegateBase<void(HANDLE)> _acceptHandleCB;
+		};
+		//Delegate<void(Socket*)> _acceptCB;
+		int32_t addressFamily, type, protocol;
+		//RGC::Ref<EndPoint> peer;
+		Socket();
+		Socket(HANDLE handle, int32_t d, int32_t t, int32_t p);
+		Socket(int32_t d, int32_t t = SOCK_STREAM, int32_t p = 0);
+		virtual void init(HANDLE handle, int32_t d, int32_t t, int32_t p);
+		virtual void init(int32_t d, int32_t t, int32_t p);
+
+		//the caller must release() or free() the returned object
+		EndPoint* getLocalEndPoint();
+		//the caller must release() or free() the returned object
+		EndPoint* getRemoteEndPoint();
+		virtual bool doOperation(Events event, EventHandlerData& ed, const EventData& evtd,
+				EventHandlerData::States oldstate, bool confident) override;
+
+		void connect(const sockaddr *addr, int32_t addr_size);
+		void connect(const EndPoint &ep);
+		void connect(const char* hostname, const char* port, int32_t family = AF_UNSPEC,
+				int32_t socktype = 0, int32_t proto = 0, int32_t flags = 0);
+		void bind(const sockaddr *addr, int32_t addr_size);
+		void bind(const EndPoint &ep);
+		//initsock is called right after creating the socket; you can use it to set socket options
+		//such as SO_REUSEPORT that need to be set before binding
+		void bind(const char* hostname, const char* port, int32_t family = AF_UNSPEC,
+				int32_t socktype = 0, int32_t proto = 0, int32_t flags = 0,
+				Callback initsock = nullptr);
+
+		int32_t shutdown(int32_t how);
+		void shutdown(int32_t how, const Callback& cb);
+		void listen(int32_t backlog = 8);
+		//the caller must release() or free() the returned object
+		Socket* accept();
+		HANDLE acceptHandle();
+
+		void connect(const sockaddr *addr, int32_t addr_size, const Callback& cb);
+		void connect(const EndPoint &ep, const Callback& cb);
+		void connect(const char* hostname, const char* port, const Callback& cb, int32_t family =
+				AF_UNSPEC, int32_t socktype = 0, int32_t proto = 0, int32_t flags = 0);
+
+		//callback function must release() or free() the received object
+		void accept(const Delegate<void(Socket*)>& cb, bool repeat = false);
+		void acceptHandle(const Delegate<void(HANDLE)>& cb, bool repeat = false);
+		inline void repeatAccept(const Delegate<void(Socket*)>& cb) {
+			accept(cb, true);
+		}
+		inline void repeatAcceptHandle(const Delegate<void(HANDLE)>& cb) {
+			acceptHandle(cb, true);
+		}
+
+		int32_t recvFrom(void* buf, int32_t len, int32_t flags, EndPoint& ep);
+		int32_t sendTo(const void* buf, int32_t len, int32_t flags, const EndPoint& ep);
+		//ep has to remain valid for the entire duration of the request
+		void recvFrom(void* buf, int32_t len, int32_t flags, EndPoint& ep, const Callback& cb,
+				bool repeat = false);
+		inline void repeatRecvFrom(void* buf, int32_t len, int32_t flags, EndPoint& ep,
+				const Callback& cb) {
+			recvFrom(buf, len, flags, ep, cb, true);
+		}
+		void sendTo(const void* buf, int32_t len, int32_t flags, const EndPoint& ep,
+				const Callback& cb, bool repeat = false);
+		inline void repeatSendTo(const void* buf, int32_t len, int32_t flags, const EndPoint& ep,
+				const Callback& cb) {
+			sendTo(buf, len, flags, ep, cb, true);
+		}
+	};
+	class SignalFD: public Handle
+	{
+	public:
+		static int32_t MAX_EVENTS;
+		typedef struct signalfd_siginfo Signal;
+		Delegate<void(Signal& sig)> callback;
+		sigset_t mask;
+		SignalFD(HANDLE handle, const sigset_t& mask);
+		SignalFD(const sigset_t& mask, int32_t flags);
+		virtual bool dispatch(Events event, const EventData& evtd, bool confident) override;
+		virtual Events getEvents();
+	};
+	class Timer: public Handle
+	{
+	public:
+		static int32_t MAX_EVENTS;
+		Callback cb;
+		struct timespec interval;
+		bool* deletionFlag;
+		bool dispatching;
+		//if interval is 0, timer is disabled; timer is always recurring (unless disabled)
+		void setInterval(struct timespec interval);
+		void setInterval(uint64_t interval_ms);
+		void init(HANDLE handle);
+		void init(HANDLE handle, struct timespec interval);
+		void init(HANDLE handle, uint64_t interval_ms);
+		void init(struct timespec interval);
+		void init(uint64_t interval_ms = 0);
+		void close();
+		Timer(HANDLE handle);
+		Timer(HANDLE handle, uint64_t interval_ms);
+		Timer(HANDLE handle, struct timespec interval);
+		Timer(uint64_t interval_ms = 0);
+		Timer(struct timespec interval);
+		~Timer();
+		struct timespec getInterval();
+		bool running();
+		void setCallback(const Callback& cb);
+		virtual bool dispatch(Events event, const EventData& evtd, bool confident) override;
+		virtual Events getEvents();
+	};
+	class EventFD: public File
+	{
+	public:
+		Delegate<void(eventfd_t)> cb;
+		EventFD(HANDLE handle);
+		EventFD(uint32_t initval = 0, int32_t flags = 0);
+		virtual bool doOperation(Events event, EventHandlerData& ed, const EventData& evtd,
+				EventHandlerData::States oldstate, bool confident) override;
+		eventfd_t getEvent();
+		void getEvent(const Delegate<void(eventfd_t)>& cb, bool repeat = false);
+		void repeatGetEvent(const Delegate<void(eventfd_t)>& cb) {
+			getEvent(cb, true);
+		}
+		int32_t sendEvent(eventfd_t evt = 1);
+		void sendEvent(eventfd_t evt, const Delegate<void(int32_t)>& cb);
+	};
+	//XXX: AIO support in the linux kernel is incomplete, and
+	//	has many serious limitations such as:
+	//	- files have to be opened as O_DIRECT
+	//	- O_DIRECT implies that all I/O requests have to
+	//		be block-aligned
+	//Because of the said reasons, AIO will not be implemented
+	//for now
+	/*class AIO: public SignalFD
+	 {
+
+	 };*/
+
+	//epoll wrapper
+	class EPoll: public Handle
+	{
+	public:
+		static int32_t MAX_EVENTS;
+		epoll_event* curEvents;
+		int32_t curIndex, curLength;
+		int32_t active;
+		HANDLE cur_handle;
+		bool cur_deleted;
+		//bool debug;
+		//Events cur_last_events;
+		//map<HANDLE, Ref<Handle> > handles;
+		//set<Handle*> tmp_deleted;
+		//bool has_deleted;
+		EPoll(HANDLE handle);
+		EPoll();
+		int32_t _doEPoll(int32_t timeout);
+		virtual bool dispatch(Events event, const EventData& evtd, bool confident) override;
+		virtual Events dispatchMultiple(Events event, Events confident, const EventData& evtd)
+				override;
+		virtual Events getEvents() override;
+		virtual Events waitAndDispatch() override;
+
+		inline void applyHandle(Handle& h, Events old_e);
+		void add(Handle& h);
+		void del(Handle& h);
+	};
+	class NewEPoll: public Handle
+	{
+	public:
+		static int32_t MAX_EVENTS;
+		struct drainInfo
+		{
+			Handle* h;
+			Events new_e;
+		};
+		vector<drainInfo> _pending;
+		vector<drainInfo>* _draining;
+		Handle* _dispatchingHandle;
+		epoll_event* _curEvents;
+		int32_t _curIndex, _curLength;
+		bool _dispatchingDeleted;
+		NewEPoll(HANDLE h);
+		NewEPoll();
+		virtual bool dispatch(Events event, const EventData& evtd, bool confident) override;
+		virtual Events dispatchMultiple(Events event, Events confident, const EventData& evtd)
+				override;
+		virtual Events getEvents() override;
+		virtual Events waitAndDispatch() override;
+		void add(Handle& h);
+		void del(Handle& h);
+		bool _doIteration(int timeout);
+		void _doDispatch(const epoll_event& event);
+		void _drainHandle(Handle& h, Events new_e);
+		void _queueHandle(Handle& h, Events new_e);
+		void _applyHandle(Handle& h, Events old_e);
+	};
+	typedef NewEPoll Poll;
+	class StandardStream: public Stream
+	{
+	public:
+		StandardStream(const StandardStream& other) = delete;
+		StandardStream& operator=(const StandardStream& other) = delete;
+		CP::File in, out;
+		StandardStream();
+		template<class P> void addToPoll(P& p) {
+			p.add(in);
+			p.add(out);
+		}
+		template<class P> void delFromPoll(P& p) {
+			p.del(in);
+			p.del(out);
+		}
+		void setBlocking(bool b = true) {
+			in.setBlocking(b);
+			out.setBlocking(b);
+		}
+		//sync
+		virtual int32_t read(void* buf, int32_t len);
+		virtual int32_t readAll(void* buf, int32_t len);
+		virtual int32_t write(const void* buf, int32_t len);
+		virtual int32_t writeAll(const void* buf, int32_t len);
+
+		//async
+		virtual void read(void* buf, int32_t len, const Callback& cb, bool repeat = false);
+		virtual void readAll(void* buf, int32_t len, const Callback& cb);
+		virtual void write(const void* buf, int32_t len, const Callback& cb, bool repeat = false);
+		virtual void writeAll(const void* buf, int32_t len, const Callback& cb);
+		virtual void cancelRead();
+		virtual void cancelWrite();
+
+		//=========misc===========
+		//sync
+		virtual void close(); //may block
+		virtual void flush();
+
+		//async
+		virtual void close(const Callback& cb);
+		virtual void flush(const Callback& cb);
+	};
+
+	class FixedMemoryStream: public Stream, public BufferedOutput, public MemoryBuffer
+	{
+	public:
+		FixedMemoryStream(const FixedMemoryStream& other) = delete;
+		FixedMemoryStream& operator=(const FixedMemoryStream& other) = delete;
+		//uint8_t* data;
+		//int len, pos;
+		int len;
+		FixedMemoryStream();
+		FixedMemoryStream(void* data, int len);
+		//sync
+		virtual int32_t read(void* buf, int32_t len);
+		virtual int32_t readAll(void* buf, int32_t len);
+		virtual int32_t write(const void* buf, int32_t len);
+		virtual int32_t writeAll(const void* buf, int32_t len);
+
+		//async
+		virtual void read(void* buf, int32_t len, const Callback& cb, bool repeat = false);
+		virtual void readAll(void* buf, int32_t len, const Callback& cb);
+		virtual void write(const void* buf, int32_t len, const Callback& cb, bool repeat = false);
+		virtual void writeAll(const void* buf, int32_t len, const Callback& cb);
+		virtual void cancelRead();
+		virtual void cancelWrite();
+
+		//=========misc===========
+		//sync
+		virtual void close();
+		virtual void flush();
+
+		//async
+		virtual void close(const Callback& cb);
+		virtual void flush(const Callback& cb);
+
+		virtual int32_t readBuffer(void*& buf, int32_t maxlen);
+		virtual void flushBuffer(int minBufferAllocation);
+
+		virtual BufferedOutput* getBufferedOutput() override;
+
+		inline virtual uint8_t* data() const final {
+			return buffer;
+		}
+		inline virtual int length() const final {
+			return len;
+		}
+	};
+	class MemoryStream: public FixedMemoryStream
+	{
+	public:
+		MemoryStream(int capacity = 4096);
+		~MemoryStream();
+		void ensureCapacity(int c);
+		virtual int32_t write(const void* buf, int32_t len);
+		virtual int32_t writeAll(const void* buf, int32_t len);
+		virtual void close();
+		virtual void flush() {
+			this->flushBuffer(0);
+		}
+		void setLength(int l) {
+			len = l;
+		}
+		void setPosition(int i) {
+			bufferPos = i;
+		}
+		void clear();
+		virtual void flushBuffer(int minBufferAllocation);
+		//user must delete the MemoryStream instance after this call
+		void keepBuffer();
+
+		//allocates space in the buffer after the current position
+		CP::String beginAppend(int minLen) {
+			ensureCapacity(bufferPos + minLen);
+			return {(char*)buffer+bufferPos,bufferSize-bufferPos};
+		}
+		void endAppend(int len) {
+			if (bufferPos + len > bufferSize) throw overflow_error(
+					"invalid length parameter to MemoryStream::endAppend()");
+			bufferPos += len;
+			if (bufferPos > this->len) this->len = bufferPos;
+		}
+	};
+	class StringPool: public virtual RGC::Object, public RGC::Allocator
+	{
+	public:
+		StringPool(const StringPool& other) = delete;
+		StringPool& operator=(const StringPool& other) = delete;
+		struct _pageHeader
+		{
+			_pageHeader* next;
+		};
+		struct state
+		{
+			_pageHeader* _curPage;
+			_pageHeader* _curRawItem;
+			int _curIndex;
+		};
+		_pageHeader* _firstPage;
+		_pageHeader* _curPage;
+		_pageHeader* _firstRawItem;
+		_pageHeader* _curRawItem;
+		int _pageSize;
+		int _curIndex;
+		StringPool(int pageSize = 4096);
+		~StringPool();
+		char* beginAdd(int sz) {
+#ifdef STRINGPOOL_MEMORY_DIAG
+			int length = sz + sizeof(int) + 1;
+#else
+			int length = sz + 1;
+#endif
+			if (likely(_curPage!=NULL && length<=(_pageSize - (int) sizeof(_pageHeader) - _curIndex))) {
+				sssss:
+				//insert null byte at the end
+				*(((char*) (_curPage + 1)) + _curIndex + sz) = 0;
+#ifdef STRINGPOOL_MEMORY_DIAG
+				int* ptr = (int*) (((char*) (_curPage + 1)) + _curIndex);
+				*ptr = sz;
+				memset(ptr + 1, 0xff, sz);
+				return (char*) (ptr + 1);
+#else
+				return ((char*) (_curPage + 1)) + _curIndex;
+#endif
+			}
+			if (length > (_pageSize - (int) sizeof(_pageHeader)) / 2) {
+				_addRaw(length);
+				return ((char*) (_curRawItem + 1));
+			}
+			_addPage();
+			goto sssss;
+		}
+		void endAdd(int length) {
+#ifdef STRINGPOOL_MEMORY_DIAG
+			_curIndex += length + sizeof(int) + 1;
+#else
+			_curIndex += length + 1;
+#endif
+		}
+		char* add(int length) {
+			char* tmp = beginAdd(length);
+			endAdd(length);
+			return tmp;
+		}
+		char* add(const char* s, int length) {
+			char* tmp = beginAdd(length);
+			memcpy(tmp, s, length);
+			endAdd(length);
+			return tmp;
+		}
+		char* add(String s) {
+			return add(s.data(), s.length());
+		}
+		char* add(const char* s) {
+			return add(s, strlen(s));
+		}
+		String addString(int length) {
+			return {add(length),length};
+		}
+		String addString(const char* s, int length) {
+			return {add(s,length),length};
+		}
+		String addString(String s) {
+			return {add(s.data(), s.length()),s.length()};
+		}
+		String addString(const char* s) {
+			int l = strlen(s);
+			return {add(s, l),l};
+		}
+		void* alloc(int s) override final {
+			return add(s);
+		}
+		void dealloc(void* obj) override final {
+#ifdef STRINGPOOL_MEMORY_DIAG
+			int* tmp = (int*) obj;
+			tmp--;
+			memset(obj, 0xFE, *tmp);
+#endif
+		}
+		void clear();
+		state saveState() {
+			return {_curPage,_curRawItem,_curIndex};
+		}
+		//deallocate all blocks allocated after s was saved
+		void restoreState(state s) {
+			_pageHeader* h;
+			if (s._curPage != NULL) {
+				h = s._curPage->next;
+				s._curPage->next = NULL;
+				while (h != NULL) {
+					_pageHeader* n = h->next;
+					::free(h);
+					h = n;
+				}
+			}
+			if (s._curRawItem != NULL) {
+				h = s._curRawItem->next;
+				s._curRawItem->next = NULL;
+				while (h != NULL) {
+					_pageHeader* n = h->next;
+					::free(h);
+					h = n;
+				}
+			}
+			_curPage = s._curPage;
+			_curRawItem = s._curRawItem;
+			_curIndex = s._curIndex;
+		}
+		void _addPage();
+		void _addRaw(int len);
+	};
+	template<class T>
+	class PoolAllocator
+	{
+	public:
+		typedef size_t size_type;
+		typedef ptrdiff_t difference_type;
+		typedef T* pointer;
+		typedef const T* const_pointer;
+		typedef T& reference;
+		typedef const T& const_reference;
+		typedef T value_type;
+
+		StringPool* sp;
+		template<class U>
+		struct rebind
+		{
+			typedef PoolAllocator<U> other;
+		};
+		PoolAllocator(StringPool* sp) throw () :
+				sp(sp) {
+
+		}
+		template<class U>
+		PoolAllocator(const PoolAllocator<U>& other) :
+				sp(other.sp) {
+
+		}
+		~PoolAllocator() {
+		}
+		template<class U>
+		PoolAllocator& operator=(const PoolAllocator<U>& other) throw () {
+			sp = other.sp;
+			return *this;
+		}
+		//    address
+		inline pointer address(reference r) {
+			return &r;
+		}
+		inline const_pointer address(const_reference r) {
+			return &r;
+		}
+		//    memory allocation
+		inline pointer allocate(size_type cnt, typename std::allocator<void>::const_pointer = 0) {
+			int size = cnt * sizeof(T);
+			pointer p = (pointer) sp->add(size);
+			//printf("allocate(size=%i): %p\n", size, p);
+			return p;
+		}
+		inline void deallocate(pointer p, size_type) {
+
+		}
+		//    size
+		inline size_type max_size() const {
+			return std::numeric_limits<size_type>::max() / sizeof(T);
+		}
+		//    construction/destruction
+		inline void construct(pointer p, const T& t) {
+			new (p) T(t);
+		}
+		inline void destroy(pointer p) {
+			p->~T();
+		}
+		inline bool operator==(PoolAllocator const&) {
+			return true;
+		}
+		inline bool operator!=(PoolAllocator const& a) {
+			return !operator==(a);
+		}
+	};
+	class StringStream: public Stream, public BufferedOutput, public MemoryBuffer
+	{
+	public:
+		StringStream(const StringStream& other) = delete;
+		StringStream& operator=(const StringStream& other) = delete;
+		//uint8_t* data;
+		//int len, pos;
+		string _str;
+		int len;
+		StringStream();
+		//sync
+		virtual int32_t read(void* buf, int32_t len);
+		virtual int32_t readAll(void* buf, int32_t len);
+		virtual int32_t write(const void* buf, int32_t len);
+		virtual int32_t writeAll(const void* buf, int32_t len);
+
+		//async
+		virtual void read(void* buf, int32_t len, const Callback& cb, bool repeat = false);
+		virtual void readAll(void* buf, int32_t len, const Callback& cb);
+		virtual void write(const void* buf, int32_t len, const Callback& cb, bool repeat = false);
+		virtual void writeAll(const void* buf, int32_t len, const Callback& cb);
+		virtual void cancelRead();
+		virtual void cancelWrite();
+
+		//=========misc===========
+		//sync
+		virtual void close();
+		virtual void flush();
+
+		//async
+		virtual void close(const Callback& cb);
+		virtual void flush(const Callback& cb);
+
+		virtual int32_t readBuffer(void*& buf, int32_t maxlen);
+		virtual void flushBuffer(int minBufferAllocation);
+
+		virtual BufferedOutput* getBufferedOutput() override;
+		void clear();
+		inline string str() const {
+			return _str.substr(0, len);
+		}
+		inline virtual uint8_t* data() const final {
+			return buffer;
+		}
+		inline virtual int length() const final {
+			return len;
+		}
+		CP::String beginAppend(int minLen) {
+			_str.reserve(bufferPos + minLen);
+			_str.resize(_str.capacity());
+			this->buffer = (uint8_t*) _str.data();
+			return {(char*)buffer+bufferPos,bufferSize-bufferPos};
+		}
+		void endAppend(int len) {
+			if (bufferPos + len > bufferSize) throw overflow_error(
+					"invalid length parameter to MemoryStream::endAppend()");
+			bufferPos += len;
+			if (bufferPos > this->len) this->len = bufferPos;
+		}
+	};
+	void listDirectory(const char* path, Delegate<void(const char*)> cb);
+
+	class MemoryPool: public RGC::Allocator
+	{
+	public:
+		struct _item
+		{
+			_item* nextFree;
+		};
+		_item* _freeList;
+		_item* _lastFree;
+		int size;
+		int items;
+		int maxItems;
+		MemoryPool(int size, int maxItems = 1024);
+		MemoryPool(const MemoryPool& other) = delete;
+		~MemoryPool();
+		void* alloc();
+		void* alloc(int s) override;
+		void dealloc(void* obj) override;
+		MemoryPool& operator=(const MemoryPool& other) = delete;
+	};
+	//all mutexes are assumed to be recursive
+	class Mutex
+	{
+	public:
+		virtual void lock()=0;
+		virtual void unlock()=0;
+	};
+	class ScopeLock
+	{
+	public:
+		Mutex* mutex;
+		ScopeLock(Mutex& m) :
+				mutex(&m) {
+			m.lock();
+		}
+		ScopeLock(const ScopeLock& l) = delete;
+		void earlyUnlock() {
+			if (mutex != nullptr) mutex->unlock();
+			mutex = nullptr;
+		}
+		~ScopeLock() {
+			if (mutex != nullptr) mutex->unlock();
+		}
+		ScopeLock& operator=(const ScopeLock& other) = delete;
+	};
+	class PThreadMutex: public Mutex
+	{
+	public:
+		pthread_mutex_t m;
+		PThreadMutex();
+		~PThreadMutex();
+		void lock() override;
+		void unlock() override;
+	};
+
+	//reference counted buffer
+	class Buffer: public String
+	{
+	public:
+		typedef int refc_t;
+		refc_t* pbuf;
+		inline void __inc() {
+			++*pbuf;
+		}
+		inline void __dec_autofree() {
+			if (--*pbuf <= 0) free(pbuf);
+		}
+		inline Buffer() :
+				pbuf(NULL) {
+		}
+		Buffer(refc_t* orig, void* buf, int length) :
+				String((char*) buf, length), pbuf(orig) {
+			__inc();
+		}
+		inline void release() {
+			if (pbuf != NULL) __dec_autofree();
+			pbuf = NULL;
+			d = NULL;
+			len = 0;
+		}
+		Buffer(int length) :
+				String((char*) NULL, length) {
+			if (length <= 0) {
+				this->pbuf = NULL;
+				return;
+			}
+			this->pbuf = (refc_t*) malloc(length + sizeof(refc_t));
+			if (this->pbuf == NULL) throw bad_alloc();
+			*this->pbuf = 1;
+			this->d = (char*) (this->pbuf + 1);
+		}
+		Buffer(const Buffer& b) :
+				String(b), pbuf(b.pbuf) {
+			if (b.pbuf != NULL) __inc();
+		}
+		Buffer& operator=(const Buffer& b) {
+			String::operator=(b);
+			if (pbuf != NULL) __dec_autofree();
+			if ((pbuf = b.pbuf) != NULL) __inc();
+			return *this;
+		}
+		inline ~Buffer() {
+			if (pbuf != NULL) __dec_autofree();
+		}
+		inline Buffer subBuffer(int index, int length) const {
+			if (index < 0 || index + length > this->len || length < 0) throw range_error(
+					"Buffer::subBuffer() out of range");
+			return Buffer(pbuf, d + index, length);
+		}
+		inline Buffer subBuffer(int index) const {
+			return subBuffer(index, len - index);
+		}
+	};
+	class BitArray
+	{
+	public:
+		uint32_t* data;
+		int length;
+		BitArray(int l) :
+				length(l) {
+			data = new uint32_t[(int) ceil(length / 32)];
+		}
+		~BitArray() {
+			delete[] data;
+		}
+		inline bool get(int i) { //WARNING: no runtime check
+			__uint32_t tmp = data[i / 32];
+			return (tmp & ((int) 1 << (i % 32))) != 0;
+		}
+		inline void set(int i, bool b) {
+			int tmp1 = i / 32;
+			__uint32_t tmp = data[tmp1];
+			if (b) data[tmp1] = tmp | ((int) 1 << (i % 32));
+			else data[tmp1] = tmp & (~((int) 1 << (i % 32)));
+		}
+	};
+	template<class T> class CircularQueue: public RGC::Object
+	{
+	public:
+		T* array;
+		BitArray b;
+		int size;
+		int objsize;
+		int __wrap;
+		int s1, s2, e1, e2;
+		CircularQueue(int size, int objsize = 1) :
+				b(size), size(size), objsize(objsize), __wrap(size * 2), s1(0), s2(0), e1(0), e2(0) {
+			array = new T[size * objsize];
+		}
+		~CircularQueue() {
+			delete[] array;
+		}
+		inline int __getlength(int i1, int i2, int wrap) {
+			return (i2 < i1 ? i2 + wrap : i2) - i1;
+		}
+		inline T& getPointer(int i) {
+			i %= size;
+			if (i >= size || i < 0) throw out_of_range("CircularQueue::getPointer() out of range");
+			return array[i * objsize]; //__intwrap(i,size);
+		}
+		inline bool canAppend() {
+			return __getlength(s1, e2, __wrap) < size;
+		}
+		int beginAppend() {
+			if (__getlength(s1, e2, __wrap) >= size) return -1;
+			int tmp = e2++;
+			e2 %= __wrap;
+			b.set(tmp % size, true);
+			return tmp;
+		}
+		void endAppend(int i) {
+			if (i == e1) {
+				do {
+					e1++;
+					e1 %= __wrap;
+				} while (__getlength(e1, e2, __wrap) > 0 && !(b.get(e1 % size)));
+			} else b.set(i % size, false);
+		}
+		inline int length() {
+			return __getlength(s2, e1, __wrap);
+		}
+		inline bool canDequeue() {
+			return __getlength(s2, e1, __wrap) > 0;
+		}
+		int beginDequeue() {
+			if (__getlength(s2, e1, __wrap) <= 0) return -1;
+			int tmp = s2++;
+			s2 %= __wrap;
+			b.set(tmp % size, true);
+			return tmp;
+		}
+		void endDequeue(int i) {
+			if (i == s1) {
+				do {
+					s1++;
+					s1 %= __wrap;
+				} while (__getlength(s1, s2, __wrap) > 0 && !(b.get(s1 % size)));
+			} else b.set(i % size, false);
+		}
+	};
+}
+static unsigned long sdbm(uint8_t* str, int len) {
+	unsigned long hash = 0;
+	int c;
+	for (int i = 0; i < len; i++) {
+		c = str[i];
+		hash = c + (hash << 6) + (hash << 16) - hash;
+	}
+	return hash;
+}
+namespace std
+{
+	template<>
+	struct hash<CP::String>
+	{
+		size_t operator()(const ::CP::String& val) const {
+			return sdbm((uint8_t*) val.data(), val.length());
+		}
+	};
+}
+#endif

+ 110 - 0
cpoll_cppsp/cppsp_rel0.2.3/cpoll/include/cpoll_internal.H

@@ -0,0 +1,110 @@
+/*
+ * cpoll_internal.H
+ *
+ *  Created on: 2012-09-14
+ *      Author: xaxaxa
+ */
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * */
+#ifndef CPOLL_INTERNAL_H_
+#define CPOLL_INTERNAL_H_
+#include <signal.h>
+
+namespace CP
+{
+	static inline int eventToIndex(Events event) {
+		if (event == Events::in) return 0;
+		if (event == Events::out) return 1;
+		if (event == Events::other) return 2;
+		return -1;
+	}
+	static inline short eventToPoll(Events event) {
+		switch (event) {
+			case Events::in:
+				return POLLIN | POLLPRI | POLLRDHUP;
+			case Events::out:
+				return POLLOUT | POLLHUP | POLLERR | POLLNVAL;
+			default:
+				break;
+		}
+		return 0;
+	}
+	static inline short eventsToPoll(Events events) {
+		short ret = 0;
+		if ((event_t) events & (event_t) Events::in) ret |= POLLIN | POLLPRI | POLLRDHUP;
+		if ((event_t) events & (event_t) Events::out) ret |= POLLOUT | POLLHUP | POLLERR | POLLNVAL;
+		return ret;
+	}
+	static inline Events pollToEvents(short events) {
+		event_t ret = 0;
+		if (events & (POLLIN | POLLPRI | POLLRDHUP)) ret |= (event_t) Events::in;
+		if (events & (POLLOUT | POLLHUP | POLLERR | POLLNVAL)) ret |= (event_t) Events::out;
+		return (Events) ret;
+	}
+	static inline uint32_t eventToEPoll(Events event) {
+		switch (event) {
+			case Events::in:
+				return EPOLLIN | EPOLLPRI | EPOLLRDHUP;
+			case Events::out:
+				return EPOLLOUT | EPOLLHUP | EPOLLERR;
+			default:
+				break;
+		}
+		return 0;
+	}
+	static inline uint32_t eventsToEPoll(Events events) {
+		uint32_t ret = 0;
+		if ((event_t) events & (event_t) Events::in) ret |= EPOLLIN | EPOLLPRI | EPOLLRDHUP;
+		if ((event_t) events & (event_t) Events::out) ret |= EPOLLOUT | EPOLLHUP | EPOLLERR;
+		return ret;
+	}
+	static inline Events ePollToEvents(uint32_t events) {
+		event_t ret = 0;
+		//if EPOLLHUP is in events, return both Events::in and Event::out
+		if (events & (EPOLLHUP | EPOLLIN | EPOLLPRI | EPOLLRDHUP)) ret |= (event_t) Events::in;
+		if (events & (EPOLLHUP | EPOLLOUT | EPOLLERR)) ret |= (event_t) Events::out;
+		return (Events) ret;
+	}
+
+	static inline Events indexToEvent(int index) {
+		return (Events) (1 << index);
+	}
+	static inline void onError(int err_no) {
+		throw CPollException(err_no);
+	}
+	static inline int checkError(int err) {
+		if (unlikely(unlikely(err < 0) && errno != EINTR && errno != EINPROGRESS)) throw CPollException();
+		return err;
+	}
+	//disable the retarded SIGHUP and SIGPIPE
+	static void disableSignals() {
+		struct sigaction sa;
+		sa.sa_handler = SIG_IGN;
+		sigemptyset(&sa.sa_mask);
+		sa.sa_flags = SA_RESTART; /* Restart system calls if
+		 interrupted by handler */
+		sigaction(SIGHUP, &sa, NULL);
+		sigaction(SIGPIPE, &sa, NULL);
+		sa.sa_handler = SIG_DFL;
+		//cout<<sigaction(SIGSTOP, &sa, NULL)<<endl;
+		//cout<<errno<<endl;
+		sigaction(SIGCONT, &sa, NULL);
+		sigaction(SIGTSTP, &sa, NULL);
+		sigaction(SIGTTIN, &sa, NULL);
+		sigaction(SIGTTOU, &sa, NULL);
+	}
+}
+
+#endif /* CPOLL_INTERNAL_H_ */

+ 67 - 0
cpoll_cppsp/cppsp_rel0.2.3/cpoll/include/http.H

@@ -0,0 +1,67 @@
+/*
+ * http.H
+ *
+ *  Created on: Apr 17, 2013
+ *      Author: xaxaxa
+ */
+
+#ifndef HTTP_H_
+#define HTTP_H_
+
+#include <curl/curl.h>
+#include <cpoll/cpoll.H>
+#include <functional>
+#include <queue>
+#include <string>
+
+using std::function;
+using std::queue;
+using std::string;
+
+namespace curl
+{
+	struct transferInfo;
+	struct instance
+	{
+		CP::Poll* p;
+		CURLM *m;
+		CP::Timer timer;
+	};
+	void newInstance(instance* inst, CP::Poll* p);
+	void dispose(instance* inst);
+	void checkQueue(instance* inst);
+	void cb_event(int fd, short events, void *userdata);
+	void addCurlTask(instance* inst, CURL* c, const function<void(CURL*, CURLcode)>& cb);
+	transferInfo* addTransfer(instance* inst, const char* url,
+			const function<bool(const void* data, int len, int state)>& cb);
+	/*-1:failed 1:connected 2:sent 3:recving 4:closed*/
+	void beginTransfer(instance* inst, transferInfo* t);
+	class transferManager
+	{
+	public:
+		instance inst;
+		int itemsProcessing, concurrency;
+		struct item
+		{
+			string url;
+			bool post;
+			function<bool(const void* data, int len, int state)> cb;
+		};
+		queue<item> q;
+		transferManager(CP::Poll& p, int concurrency = 3) :
+				itemsProcessing(0), concurrency(concurrency) {
+			curl::newInstance(&inst, &p);
+		}
+		~transferManager() {
+			curl::dispose(&inst);
+		}
+		void checkQueue();
+		void doTransfer(const char* url, bool post,
+				const function<bool(const void* data, int len, int state)>& cb);
+		void addTransfer(const char* url, bool post,
+				const function<bool(const void* data, int len, int state)>& cb);
+	};
+
+}
+
+#endif /* HTTP_H_ */

+ 14 - 0
cpoll_cppsp/cppsp_rel0.2.3/cpoll/include/sendfd.H

@@ -0,0 +1,14 @@
+/*
+ * sendfd.H
+ *
+ *  Created on: Feb 4, 2013
+ *      Author: xaxaxa
+ */
+
+#ifndef SENDFD_H_
+#define SENDFD_H_
+
+int sendfd(int s, int fd, int flags=0);
+int recvfd(int s, int flags=0);
+
+#endif /* SENDFD_H_ */

+ 408 - 0
cpoll_cppsp/cppsp_rel0.2.3/cpoll/include/statemachines.H

@@ -0,0 +1,408 @@
+/*
+ * statemachines.H
+ *
+ *  Created on: Feb 1, 2013
+ *      Author: xaxaxa
+ */
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * */
+#ifndef STATEMACHINES_H_
+#define STATEMACHINES_H_
+#include <functional>
+#include <stdint.h>
+#include <string>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdexcept>
+#include <delegate.H>
+#include "basictypes.H"
+#ifndef likely
+#define likely(x)       __builtin_expect((x),1)
+#define unlikely(x)     __builtin_expect((x),0)
+#endif
+
+using namespace std;
+namespace CP
+{
+	//streamReader C-style API/ABI; this is to avoid breaking the ABI when the
+	//internal state machine structure changes
+	//usage example:
+	//streamReader* sr=(streamReader*)malloc(streamReader_getSize()+4096);
+	//streamReader_init(sr, 4096);
+	// ...
+	//streamReader_deinit(sr);
+
+	//it is safe to delete a streamReader from within your callback
+	struct streamReader;
+	int streamReader_getSize();
+	void streamReader_init(streamReader* sr, void* buffer, int capacity);
+	void streamReader_init(streamReader* sr, int capacity);
+	void streamReader_deinit(streamReader* sr);
+	tuple<uint8_t*, int> streamReader_beginPutData(streamReader* sr);
+	void streamReader_endPutData(streamReader* sr, int len);
+	void streamReader_readUntilString(streamReader* sr, const char* delim, int delimLen);
+	void streamReader_readUntilChar(streamReader* sr, char delim);
+	void streamReader_setCallback(streamReader* sr, const Delegate<void(uint8_t*, int, bool)>& cb);
+	tuple<uint8_t*, int> streamReader_getBufferData(streamReader* sr);
+	void streamReader_reset(streamReader* sr);
+	void streamReader_skip(streamReader* sr, int i);
+
+	//another streamReader implementation that remembers all data that has ever been fed into it;
+	//mainly for socketd
+	struct persistentStreamReader
+	{
+		uint8_t* buffer;
+		int capacity;
+		int len;
+		int pos;
+		int searchPos;
+		int state; //0: none; 1: readUntilString; 2: readUntilChar
+		//function<void(uint8_t*, int)> output;
+		Delegate<void(uint8_t*, int)> output;
+		const char* delim1;
+		int delim1_len;
+		char delim2;
+		inline void clearBuffer() {
+			searchPos = pos = len;
+			//delayProcessing = false;
+		}
+		void resize(int nc) {
+			uint8_t* tmp = (uint8_t*) realloc(buffer, nc);
+			if (tmp == NULL) throw runtime_error(strerror(errno));
+			buffer = tmp;
+			capacity = nc;
+		}
+		void ensureCapacity(int c) {
+			if (likely(c < capacity)) return;
+			int nc = capacity;
+			while (nc < c)
+				nc *= 2;
+			if (nc != capacity) resize(nc);
+		}
+		persistentStreamReader(int c = 4096) :
+				capacity(c), len(0), pos(0), searchPos(0), state(0) {
+			buffer = (uint8_t*) malloc(c);
+			if (buffer == NULL) throw runtime_error(strerror(errno));
+		}
+		~persistentStreamReader() {
+			free(buffer);
+		}
+		void process() {
+			if (len <= searchPos) return;
+			switch (state) {
+				case 0:
+					break;
+				case 1:
+				{
+					uint8_t* tmp = (uint8_t*) memmem(buffer + searchPos, len - searchPos, delim1,
+							delim1_len);
+					if (tmp == NULL) {
+						//overlap the search so that delimitors that are cut in half at
+						//the end of the buffer can be caught
+						searchPos = len - delim1_len;
+					} else {
+						int oldPos = pos;
+						pos = searchPos = (tmp - buffer) + delim1_len;
+						state = 0;
+						output(buffer + oldPos, tmp - buffer - oldPos);
+					}
+					break;
+				}
+				case 2:
+				{
+					uint8_t* tmp = (uint8_t*) memchr(buffer + searchPos, delim2, len - searchPos);
+					if (tmp == NULL) {
+						searchPos = len;
+					} else {
+						int oldPos = pos;
+						pos = searchPos = (tmp - buffer) + 1;
+						state = 0;
+						output(buffer + oldPos, tmp - buffer - oldPos);
+					}
+					break;
+				}
+			}
+		}
+		void readUntilString(const char* delim, int len) {
+			state = 1;
+			delim1 = delim;
+			delim1_len = len;
+			//printf("%i\n",delim.length());
+			process();
+		}
+		void readUntilChar(char delim) {
+			state = 2;
+			delim2 = delim;
+			process();
+		}
+		uint8_t* beginPutData(int len) {
+			ensureCapacity(this->len + len);
+			return buffer + this->len;
+		}
+		void endPutData(int len) {
+			this->len += len;
+			if (len > 0) process();
+		}
+		inline tuple<uint8_t*, int> getBufferData() {
+			return make_tuple(buffer + pos, len - pos);
+		}
+		inline tuple<uint8_t*, int> getHistory(bool includeUnprocessed = true) {
+			return make_tuple(buffer, includeUnprocessed ? len : pos);
+		}
+	};
+
+	//revised version of streamReader which does not use callbacks
+	struct newStreamReader
+	{
+		struct item
+		{
+			String data;
+			bool delimReached;
+		};
+		uint8_t* buffer;
+		const char* delim1;
+		int bufferCapacity;
+		int bufferLen;
+		int bufferPos;
+		int state; //0: none; 1: readUntilString; 2: readUntilChar
+		int delim1len;
+		char delim2;
+		bool repeat;
+		inline void reset() {
+			bufferPos = 0;
+			bufferLen = 0;
+			state = 0;
+			repeat = false;
+			//delayProcessing = false;
+		}
+		newStreamReader(void* buffer, int capacity) {
+			this->buffer = (uint8_t*) buffer;
+			bufferCapacity = capacity;
+			reset();
+		}
+		newStreamReader(int capacity) {
+			this->buffer = (uint8_t*) (this + 1);
+			bufferCapacity = capacity;
+			reset();
+		}
+		inline void readUntilString(const char* delim, int delimLen, bool repeat = false) {
+			state = 1;
+			delim1 = delim;
+			delim1len = delimLen;
+			this->repeat = repeat;
+		}
+		inline void readUntilChar(char delim, bool repeat = false) {
+			state = 2;
+			delim2 = delim;
+			this->repeat = repeat;
+		}
+		inline String beginPutData() {
+			//printf("%i %i\n",bufferLen, bufferCapacity - bufferLen);
+			return {(char*) buffer + bufferLen, bufferCapacity - bufferLen};
+		}
+		//len <= length returned from beginPutData()
+		inline void endPutData(int len) {
+			bufferLen += len;
+		}
+		inline String getBufferData() {
+			return {(char*)buffer + bufferPos, bufferLen - bufferPos};
+		}
+		inline void skip(int i) {
+			bufferPos += i;
+		}
+		bool process(item& it) {
+			if (bufferPos >= bufferLen) {
+				bufferPos = bufferLen = 0;
+				return false;
+			}
+			bool ret = false;
+			switch (state) {
+				case 0:
+					return false;
+				case 1:
+				{
+					uint8_t* buf = buffer;
+					if (bufferLen - bufferPos < (int) delim1len) {
+						if (unlikely(bufferPos==0)) return false;
+						asdfg: memmove(buf, buf + bufferPos, bufferLen - bufferPos);
+						bufferLen -= bufferPos;
+						bufferPos = 0;
+						return ret;
+					}
+					uint8_t* tmp = (uint8_t*) memmem(buf + bufferPos, bufferLen - bufferPos, delim1,
+							delim1len);
+					if (tmp == NULL) {
+						it= { {(char*)buf + bufferPos, bufferLen - bufferPos - delim1len + 1}, false};
+						bufferPos = bufferLen - delim1len + 1;
+						ret=true;
+						goto asdfg;
+					} else {
+						int oldPos = bufferPos;
+						int newPos = tmp - buf;
+						bufferPos = newPos + delim1len;
+						if (bufferPos >= bufferLen) {
+							bufferLen = bufferPos = 0;
+						}
+						if(!repeat)state = 0;
+						it= { {(char*)buf + oldPos, newPos - oldPos}, true};
+						return true;
+					}
+				}
+				case 2:
+				{
+					uint8_t* buf = buffer;
+					uint8_t* tmp = (uint8_t*) memchr(buf + bufferPos, delim2, bufferLen - bufferPos);
+					int oldPos = bufferPos;
+					if (tmp == NULL) {
+						int oldLen = bufferLen;
+						bufferLen = bufferPos = 0;
+						it= { {(char*)buf + oldPos, oldLen - oldPos}, false};
+						return true;
+					} else {
+						int newPos = tmp - buf;
+						bufferPos = newPos + 1;
+						if (bufferPos >= bufferLen) {
+							bufferLen = bufferPos = 0;
+						}
+						if (!repeat) state = 0;
+						it= { {(char*)buf + oldPos, newPos - oldPos}, true};
+						return true;
+					}
+				}
+				default: return false;
+			}
+			//if (delayedProcessing) goto reprocess;
+		}
+	};
+	struct newPersistentStreamReader
+	{
+		struct item
+		{
+			String data;
+		};
+		uint8_t* buffer;
+		const char* delim1;
+		int capacity;
+		int len;
+		int pos;
+		int searchPos;
+		int state; //0: none; 1: readUntilString; 2: readUntilChar
+		int delim1_len;
+		char delim2;
+		bool repeat;
+		inline void clearBuffer() {
+			searchPos = pos = len;
+		}
+		void resize(int nc) {
+			uint8_t* tmp = (uint8_t*) realloc(buffer, nc);
+			if (tmp == NULL) throw runtime_error(strerror(errno));
+			buffer = tmp;
+			capacity = nc;
+		}
+		void ensureCapacity(int c) {
+			if (likely(c < capacity)) return;
+			int nc = capacity;
+			while (nc < c)
+				nc *= 2;
+			if (nc != capacity) resize(nc);
+		}
+		void reset() {
+			len = pos = searchPos = state = 0;
+		}
+		newPersistentStreamReader(int c = 4096) :
+				capacity(c), len(0), pos(0), searchPos(0), state(0) {
+			buffer = (uint8_t*) malloc(c);
+			if (buffer == NULL) throw runtime_error(strerror(errno));
+		}
+		~newPersistentStreamReader() {
+			free(buffer);
+		}
+		bool process(item& it) {
+			if (len <= searchPos) return false;
+			switch (state) {
+				case 0:
+					return false;
+				case 1:
+				{
+					uint8_t* tmp = (uint8_t*) memmem(buffer + searchPos, len - searchPos, delim1,
+							delim1_len);
+					if (tmp == NULL) {
+						//overlap the search so that delimitors that are cut in half at
+						//the end of the buffer can be caught
+						searchPos = len - delim1_len;
+						return false;
+					} else {
+						int oldPos = pos;
+						pos = searchPos = (tmp - buffer) + delim1_len;
+						if (!repeat) state = 0;
+						it= { {(char*)buffer + oldPos, int(tmp - buffer - oldPos)}};
+						return true;
+					}
+				}
+				case 2:
+				{
+					uint8_t* tmp = (uint8_t*) memchr(buffer + searchPos, delim2, len - searchPos);
+					if (tmp == NULL) {
+						searchPos = len;
+						return false;
+					} else {
+						int oldPos = pos;
+						pos = searchPos = (tmp - buffer) + 1;
+						if (!repeat) state = 0;
+						it= { {(char*)buffer + oldPos, int(tmp - buffer - oldPos)}};
+						return true;
+					}
+				}
+				default:
+					return false;
+			}
+		}
+		void readUntilString(const char* delim, int len, bool repeat = false) {
+			state = 1;
+			delim1 = delim;
+			delim1_len = len;
+			this->repeat = repeat;
+		}
+		void readUntilChar(char delim, bool repeat = false) {
+			state = 2;
+			delim2 = delim;
+			this->repeat = repeat;
+		}
+		String beginPutData(int len) {
+			ensureCapacity(this->len + len);
+			return {(char*)buffer + this->len,this->capacity-this->len};
+		}
+		void endPutData(int len) {
+			this->len += len;
+		}
+		inline String getBufferData() {
+			return {(char*)buffer + pos, len - pos};
+		}
+		inline String getHistory(bool includeUnprocessed = true) {
+			return {(char*)buffer, includeUnprocessed ? len : pos};
+		}
+		void clearHistory() {
+			if (pos > 0) {
+				memmove(buffer, buffer + pos, len - pos);
+				len -= pos;
+				searchPos -= pos;
+				pos = 0;
+			}
+		}
+	}
+	;
+}
+#endif /* STATEMACHINES_H_ */

+ 130 - 0
cpoll_cppsp/cppsp_rel0.2.3/cpoll/include/threadpool.H

@@ -0,0 +1,130 @@
+/*
+ * threadpool.H
+ *
+ *  Created on: May 17, 2013
+ *      Author: xaxaxa
+ */
+
+#ifndef THREADPOOL_H_
+#define THREADPOOL_H_
+#include <delegate.H>
+#include <sys/types.h>
+#include <pthread.h>
+#include <vector>
+#include <unistd.h>
+#include <errno.h>
+#include "cpoll.H"
+using namespace std;
+namespace CP
+{
+	class ThreadPool;
+	struct IDLETHREAD
+	{
+		ThreadPool* tp;
+		Delegate<void()> func;
+		pthread_t thread;
+		int32_t efd;
+		enum
+		{
+			none = 0, invoke, kill
+		} op;
+		IDLETHREAD() :
+				efd(eventfd(0, EFD_SEMAPHORE)), op(none) {
+		}
+		~IDLETHREAD() {
+			close(efd);
+		}
+		void signal() {
+			eventfd_t i = 1;
+			eventfd_write(efd, i);
+		}
+	};
+	void* idleThread(void* v);
+
+	class ThreadPool: public RGC::Object
+	{
+	public:
+		Delegate<void()> afterStart, beforeExit;
+		vector<IDLETHREAD*> threads;
+		PThreadMutex mutex;
+		int32_t max;
+		pthread_attr_t _attr;
+		ThreadPool(int32_t max = 8) :
+				max(max) {
+			pthread_attr_init(&_attr);
+			pthread_attr_setdetachstate(&_attr, PTHREAD_CREATE_DETACHED);
+		}
+		~ThreadPool() {
+			for (size_t i = 0; i < threads.size(); i++) {
+				threads[i]->op = IDLETHREAD::kill;
+				threads[i]->signal();
+			}
+			pthread_attr_destroy(&_attr);
+		}
+		IDLETHREAD* create() {
+			IDLETHREAD* tmp = new IDLETHREAD();
+			tmp->tp = this;
+			if (pthread_create(&tmp->thread, &_attr, idleThread, (void*) tmp) == 0) return tmp;
+			else {
+				throw runtime_error(strerror(errno));
+			}
+		}
+		IDLETHREAD* get() {
+			size_t threadcount;
+			{
+				ScopeLock l(mutex);
+				threadcount = threads.size();
+				if (threadcount > 0) {
+					IDLETHREAD* t = threads[threads.size() - 1];
+					threads.resize(threads.size() - 1);
+					return t;
+				}
+			}
+			return create();
+		}
+		void put(IDLETHREAD* t) {
+			bool b;
+			{
+				ScopeLock l(mutex);
+				if ((b = ((int32_t) threads.size() < max))) threads.push_back(t);
+			}
+			if (!b) {
+				t->op = IDLETHREAD::kill;
+				t->signal();
+			}
+		}
+		void invoke(const Delegate<void()>& func) {
+			IDLETHREAD* t = get();
+			t->func = func;
+			t->op = IDLETHREAD::invoke;
+			t->signal();
+		}
+	};
+	void* idleThread(void* v) {
+		IDLETHREAD* thr = (IDLETHREAD*) v;
+		if (thr->tp->afterStart != nullptr) thr->tp->afterStart();
+		while (true) {
+			{
+				eventfd_t i;
+				eventfd_read(thr->efd, &i);
+			}
+			switch (thr->op) {
+				case IDLETHREAD::invoke:
+					try {
+						thr->func();
+					} catch (...) {
+					}
+					thr->tp->put(thr);
+					break;
+				case IDLETHREAD::kill:
+					if (thr->tp->beforeExit != nullptr) thr->tp->beforeExit();
+					delete thr;
+					return NULL;
+				default:
+					break;
+			}
+		}
+	}
+}
+
+#endif /* THREADPOOL_H_ */

+ 8 - 0
cpoll_cppsp/cppsp_rel0.2.3/cpoll/makefile

@@ -0,0 +1,8 @@
+all: t1
+t1:
+	g++ t1.C -g3 -o t1 --std=c++0x -I.
+t1_o:
+	g++ t1.C -Ofast -o t1_o --std=c++0x -I.
+clean:
+	rm -f t1
+

+ 61 - 0
cpoll_cppsp/cppsp_rel0.2.3/cpoll/rgctest.C

@@ -0,0 +1,61 @@
+//#define __debug_obj123
+
+
+#include <iostream>
+#include <functional>
+
+
+using namespace std;
+#include "rgc.H"
+using namespace RGC;
+struct c1: public Object
+{
+	Ref<Object> a;
+	//Object* a;
+};
+
+void func1()
+{
+	cout << "func1 called" << endl;
+}
+void call10times(function<void()> func)
+{
+	for(int i=0;i<10000000;i++)
+		func();
+}
+void aaaaa()
+{
+	Ref<Object> tmp=newObj<Object>();
+	cout << tmp->refCount << endl;
+	
+	
+	
+	c1 obj;
+	obj.a=tmp;
+	cout << tmp->refCount << endl;
+	obj.a=newObj<Object>();
+	cout << tmp->refCount << endl;
+	Ref<Object> r(obj.a);
+	Ref<Object> r1(obj);
+	obj.a=NULL;
+	
+	//tmp=new Object();
+}
+
+
+
+
+
+
+
+int rgctest_main(int argc, char **argv)
+{
+	//aaaaa();
+	/*Ref<FileStream> fs("/dev/urandom",O_RDONLY);
+	Ref<StreamReader> sr(*fs);
+	Ref<StringBuilder> sb;
+	cout << fs() << endl;
+	sr->ReadLine(*sb);
+	cout << sb->ToCString() << endl;*/
+	aaaaa();
+}

+ 90 - 0
cpoll_cppsp/cppsp_rel0.2.3/cpoll/sendfd.C

@@ -0,0 +1,90 @@
+/*
+ * copied from http://code.swtch.com/plan9port/src/0e6ae8ed3276/src/lib9/sendfd.c
+ * modified
+ * */
+
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifndef CMSG_ALIGN
+#       ifdef __sun__
+#               define CMSG_ALIGN _CMSG_DATA_ALIGN
+#       else
+#               define CMSG_ALIGN(len) (((len)+sizeof(long)-1) & ~(sizeof(long)-1))
+#       endif
+#endif
+
+#ifndef CMSG_SPACE
+#       define CMSG_SPACE(len) (CMSG_ALIGN(sizeof(struct cmsghdr))+CMSG_ALIGN(len))
+#endif
+
+#ifndef CMSG_LEN
+#       define CMSG_LEN(len) (CMSG_ALIGN(sizeof(struct cmsghdr))+(len))
+#endif
+
+int sendfd(int s, int fd, int flags) {
+	char buf[1];
+	struct iovec iov;
+	struct msghdr msg;
+	struct cmsghdr *cmsg;
+	int n;
+	char cms[CMSG_SPACE(sizeof(int))];
+
+	buf[0] = 69;
+	iov.iov_base = buf;
+	iov.iov_len = 1;
+
+	memset(&msg, 0, sizeof msg);
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+	msg.msg_control = (caddr_t) cms;
+	msg.msg_controllen = CMSG_LEN(sizeof(int));
+
+	cmsg = CMSG_FIRSTHDR(&msg);
+	cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+	cmsg->cmsg_level = SOL_SOCKET;
+	cmsg->cmsg_type = SCM_RIGHTS;
+	memmove(CMSG_DATA(cmsg), &fd, sizeof(int));
+
+	if ((n = sendmsg(s, &msg, flags)) != (int) iov.iov_len) return -1;
+	return 0;
+}
+
+int recvfd(int s, int flags) {
+	int n;
+	int fd;
+	char buf[1];
+	struct iovec iov;
+	struct msghdr msg;
+	struct cmsghdr *cmsg;
+	char cms[CMSG_SPACE(sizeof(int))];
+
+	iov.iov_base = buf;
+	iov.iov_len = 1;
+
+	memset(&msg, 0, sizeof msg);
+	msg.msg_name = 0;
+	msg.msg_namelen = 0;
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+
+	msg.msg_control = (caddr_t) cms;
+	msg.msg_controllen = sizeof cms;
+
+	if ((n = recvmsg(s, &msg, flags)) <= 0) {
+		//fprintf(stderr,"recvfd(fd=%i): recvmsg() returned %i; errno: %s\n",s,n,strerror(errno));
+		return -1;
+	}
+	cmsg = CMSG_FIRSTHDR(&msg);
+	if (cmsg == NULL) {
+		errno = 0;
+		fprintf(stderr,"recvfd(fd=%i): CMSG_FIRSTHDR(&msg) is NULL; n=%i, val=%i\n",s,n,(int)buf[0]);
+		return -1;
+	}
+	memmove(&fd, CMSG_DATA(cmsg), sizeof(int));
+	return fd;
+}

+ 220 - 0
cpoll_cppsp/cppsp_rel0.2.3/cpoll/statemachines.C

@@ -0,0 +1,220 @@
+/*
+ * statemachines.C
+ *
+ *  Created on: Jan 31, 2013
+ *      Author: xaxaxa
+ */
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * */
+//state machines for asynchronously processing input streams
+#include <tuple>
+#include <functional>
+#include <stdint.h>
+#include <tuple>
+#include <string>
+#include <string.h>
+#include "include/statemachines.H"
+#include <stdio.h>
+using namespace std;
+namespace CP
+{
+	void* memcpymove(uint8_t* dst, const uint8_t* src, size_t n) {
+		if ((dst >= src + n) || (src >= dst + n)) {
+			//not overlapping
+			return memcpy(dst, src, n);
+		} else return memmove(dst, src, n);
+	}
+	struct streamReader
+	{
+		//you must allocate memory for this struct such that there is (bufferSize) bytes of allocated space
+		//right after this struct.
+		//ex.
+		//streamReader* sr=(streamReader*)malloc(sizeof(streamReader)+4096);
+		//new (sr) streamReader(4096);
+
+		//user specified
+		//				data	len	delimReached
+		Delegate<void(uint8_t*, int, bool)> output;
+		void* buffer;
+		int bufferCapacity;
+
+		//internal
+		int bufferLen;
+		int bufferPos;
+		int state; //0: none; 1: readUntilString; 2: readUntilChar
+		const char* delim1;
+		int delim1len;
+		char delim2;
+		//bool delayProcessing;
+		//bool delayedProcessing;
+		inline void reset() {
+			bufferPos = 0;
+			bufferLen = 0;
+			state = 0;
+			//delayProcessing = false;
+		}
+		streamReader(void* buffer, int capacity) {
+			this->buffer = buffer;
+			bufferCapacity = capacity;
+			reset();
+		}
+		streamReader(int capacity) {
+			this->buffer = (void*) (this + 1);
+			bufferCapacity = capacity;
+			reset();
+		}
+		inline uint8_t* getBuffer() {
+			return (uint8_t*) buffer;
+		}
+		inline void setCallback(const Delegate<void(uint8_t*, int, bool)>& cb) {
+			output = cb;
+		}
+
+		void process() {
+			/*if (delayProcessing) {
+			 delayedProcessing = true;
+			 return;
+			 }*/
+			if (bufferPos >= bufferLen) {
+				bufferPos = bufferLen = 0;
+				return;
+			}
+			switch (state) {
+				case 0:
+					break;
+				case 1:
+				{
+					uint8_t* buf = getBuffer();
+					if (bufferLen - bufferPos < (int) delim1len && bufferPos > 0) {
+						asdfg: memmove(buf, buf + bufferPos, bufferLen - bufferPos);
+						bufferLen -= bufferPos;
+						bufferPos = 0;
+						return;
+					}
+
+					//printf("%i\n",bufferLen - bufferPos);
+					uint8_t* tmp = (uint8_t*) memmem(buf + bufferPos, bufferLen - bufferPos, delim1,
+							delim1len);
+					if (tmp == NULL) {
+						//delayProcessing = true;
+						//if (bufferLen - bufferPos - delim1len + 1 <= 0) break;
+						output(buf + bufferPos, bufferLen - bufferPos - delim1len + 1, false);
+						//delayProcessing = false;
+						//memmove(buf, buf + bufferLen - delim1.length(), delim1.length());
+						bufferPos = bufferLen - delim1len + 1;
+						goto asdfg;
+					} else {
+						int oldPos = bufferPos;
+						int newPos = tmp - buf;
+						bufferPos = newPos + delim1len;
+						if (bufferPos >= bufferLen) {
+							bufferLen = bufferPos = 0;
+						}
+						state = 0;
+						output(buf + oldPos, newPos - oldPos, true);
+					}
+					break;
+				}
+				case 2:
+				{
+					uint8_t* buf = getBuffer();
+					uint8_t* tmp = (uint8_t*) memchr(buf + bufferPos, delim2, bufferLen - bufferPos);
+					int oldPos = bufferPos;
+					if (tmp == NULL) {
+						int oldLen = bufferLen;
+						bufferLen = bufferPos = 0;
+						output(buf + oldPos, oldLen - oldPos, false);
+					} else {
+						int newPos = tmp - buf;
+						bufferPos = newPos + 1;
+						if (bufferPos >= bufferLen) {
+							bufferLen = bufferPos = 0;
+						}
+						state = 0;
+						output(buf + oldPos, newPos - oldPos, true);
+					}
+					break;
+				}
+			}
+			//if (delayedProcessing) goto reprocess;
+		}
+		inline void readUntilString(const char* delim, int delimLen) {
+			state = 1;
+			delim1 = delim;
+			delim1len = delimLen;
+			//printf("%i\n",delim.length());
+			process();
+		}
+		inline void readUntilChar(char delim) {
+			state = 2;
+			delim2 = delim;
+			process();
+		}
+		//		buf		length
+		inline tuple<uint8_t*, int> beginPutData() {
+			//printf("%i %i\n",bufferLen, bufferCapacity - bufferLen);
+			return make_tuple(getBuffer() + bufferLen, bufferCapacity - bufferLen);
+		}
+		//len <= length returned from beginPutData()
+		inline void endPutData(int len) {
+			//printf("%i\n",len);
+			bufferLen += len;
+			if (len > 0) process();
+		}
+		inline tuple<uint8_t*, int> getBufferData() {
+			return make_tuple(getBuffer() + bufferPos, bufferLen - bufferPos);
+		}
+		inline void skip(int i) {
+			bufferPos += i;
+		}
+	};
+	int streamReader_getSize() {
+		return sizeof(streamReader);
+	}
+	void streamReader_init(streamReader* sr, int capacity) {
+		new (sr) streamReader(capacity);
+	}
+	void streamReader_init(streamReader* sr, void* buffer, int capacity) {
+		new (sr) streamReader(buffer, capacity);
+	}
+	void streamReader_deinit(streamReader* sr) {
+		sr->~streamReader();
+	}
+	tuple<uint8_t*, int> streamReader_beginPutData(streamReader* sr) {
+		return sr->beginPutData();
+	}
+	void streamReader_endPutData(streamReader* sr, int len) {
+		sr->endPutData(len);
+	}
+	void streamReader_readUntilString(streamReader* sr, const char* delim, int delimLen) {
+		sr->readUntilString(delim, delimLen);
+	}
+	void streamReader_readUntilChar(streamReader* sr, char delim) {
+		sr->readUntilChar(delim);
+	}
+	void streamReader_setCallback(streamReader* sr, const Delegate<void(uint8_t*, int, bool)>& cb) {
+		sr->setCallback(cb);
+	}
+	tuple<uint8_t*, int> streamReader_getBufferData(streamReader* sr) {
+		return sr->getBufferData();
+	}
+	void streamReader_reset(streamReader* sr) {
+		sr->reset();
+	}
+	void streamReader_skip(streamReader* sr, int i) {
+		sr->skip(i);
+	}
+}
+

+ 91 - 0
cpoll_cppsp/cppsp_rel0.2.3/cpoll/t1.C

@@ -0,0 +1,91 @@
+#include "cpoll.H"
+#include <sys/types.h>
+       #include <sys/stat.h>
+       #include <fcntl.h>
+
+using namespace std;
+using namespace CP;
+int main()
+{
+	Poll p;
+	File f(0); //stdin
+	File f2(1); //stdout
+	File f3(open("/etc/passwd", O_RDONLY));
+	
+	/*char buf[4096];
+	f.read(buf, 4096, [&](int br)
+	{
+		cerr << br << " bytes read;" << endl;
+		f3.read(buf, 4096, [](int br){cout << br << " bytes read from file" << endl;});
+		
+	});*/
+	
+	
+	//generate troll
+	stringstream ss1;
+	ss1 << "troll";
+	for(int i=0;i<30;i++)
+		ss1 << " lol";
+	string str1=ss1.str();
+	stringstream ss2;
+	for(int i=0;i<5000;i++)
+		ss2 << str1 << endl;
+	string str2=ss2.str();
+	const char* cstr2=str2.data();
+	int cstr2len=str2.length();
+	
+
+
+	const char* httphdr="HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n";
+	int httphdr_len=strlen(httphdr);
+	
+	Socket* s1=new Socket();
+	s1->bind(IPEndPoint(IPAddress("0.0.0.0"), 12345));
+	s1->listen();
+	//cout << (void*)s1->accept();
+	s1->repeatAccept([&](Socket* s) {
+		if(s==NULL)return;
+		cout << "accepted socket " << s->handle << endl;
+		//s.retain();
+		/*char* buf=new char[4096];
+		s->repeatRead(buf, 4096, [buf, &f2, s](int l) {
+			if(l<=0) {
+				cerr << "closed socket " << s->handle << endl;
+				free(buf);
+				s->release();
+				return;
+			}
+			f2.write(buf, l);
+		});*/
+		s->writeAll(httphdr, httphdr_len, [s,&cstr2,cstr2len](int l) {
+			s->writeAll(cstr2, cstr2len, [s](int l) {
+				char* buf=new char[4096];
+				s->repeatRead(buf, 4096, [buf](int br) {
+					if(br<=0)
+						delete[] buf;
+				});
+			});
+		});
+		p.add(*s);
+		s->release();
+	});
+	p.add(*s1);
+	
+	
+	f2.write("aaaaa\n", 6, [](int bw){cerr << bw << " bytes written" << endl;});
+	//f.loop();
+	
+	p.add(f);
+	p.add(f2);
+	p.add(f3);
+	p.loop();
+	
+	/*File f(0); //stdin
+	char buf[4096];
+	f.read(buf,4096,[](int br){cout << "read " << br << endl;});
+	Poll poll;
+	poll.add(f);
+	Poll poll2;
+	poll2.add(poll);
+	poll2.loop();*/
+}

BIN
cpoll_cppsp/cppsp_rel0.2.3/cppsp.o


+ 179 - 0
cpoll_cppsp/cppsp_rel0.2.3/cppsp/.cproject

@@ -0,0 +1,179 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?fileVersion 4.0.0?>
+
+<cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
+	<storageModule moduleId="org.eclipse.cdt.core.settings">
+		<cconfiguration id="cdt.managedbuild.config.gnu.so.debug.7250834">
+			<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.so.debug.7250834" moduleId="org.eclipse.cdt.core.settings" name="Debug">
+				<externalSettings>
+					<externalSetting>
+						<entry flags="VALUE_WORKSPACE_PATH" kind="includePath" name="/cppsp"/>
+						<entry flags="VALUE_WORKSPACE_PATH" kind="libraryPath" name="/cppsp/Debug"/>
+						<entry flags="RESOLVED" kind="libraryFile" name="cppsp" srcPrefixMapping="" srcRootPath=""/>
+					</externalSetting>
+				</externalSettings>
+				<extensions>
+					<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
+					<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+				</extensions>
+			</storageModule>
+			<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+				<configuration artifactExtension="so" artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.sharedLib" buildProperties="org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.sharedLib" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.so.debug.7250834" name="Debug" parent="cdt.managedbuild.config.gnu.so.debug">
+					<folderInfo id="cdt.managedbuild.config.gnu.so.debug.7250834." name="/" resourcePath="">
+						<toolChain id="cdt.managedbuild.toolchain.gnu.so.debug.1421775255" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.so.debug">
+							<targetPlatform id="cdt.managedbuild.target.gnu.platform.so.debug.1263197157" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.so.debug"/>
+							<builder buildPath="${workspace_loc:/cppsp/Debug}" id="cdt.managedbuild.target.gnu.builder.so.debug.1028490589" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.so.debug"/>
+							<tool id="cdt.managedbuild.tool.gnu.archiver.base.611824652" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
+							<tool command="g++" commandLinePattern="${COMMAND} ${FLAGS} ${OUTPUT_FLAG} ${OUTPUT_PREFIX}${OUTPUT} ${INPUTS}" id="cdt.managedbuild.tool.gnu.cpp.compiler.so.debug.58597657" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.so.debug">
+								<option id="gnu.cpp.compiler.so.debug.option.optimization.level.1224156692" name="Optimization Level" superClass="gnu.cpp.compiler.so.debug.option.optimization.level" value="gnu.cpp.compiler.optimization.level.none" valueType="enumerated"/>
+								<option id="gnu.cpp.compiler.so.debug.option.debugging.level.977519479" name="Debug Level" superClass="gnu.cpp.compiler.so.debug.option.debugging.level" value="gnu.cpp.compiler.debugging.level.max" valueType="enumerated"/>
+								<option id="gnu.cpp.compiler.option.include.paths.932399156" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" valueType="includePath">
+									<listOptionValue builtIn="false" value="../../include/"/>
+								</option>
+								<option id="gnu.cpp.compiler.option.other.other.1817836175" name="Other flags" superClass="gnu.cpp.compiler.option.other.other" value="-c -fmessage-length=0 --std=c++0x -Wno-pmf-conversions -fno-omit-frame-pointer" valueType="string"/>
+								<option id="gnu.cpp.compiler.option.other.pic.1353903621" name="Position Independent Code (-fPIC)" superClass="gnu.cpp.compiler.option.other.pic" value="true" valueType="boolean"/>
+								<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.628017354" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.c.compiler.so.debug.1027837749" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.so.debug">
+								<option defaultValue="gnu.c.optimization.level.none" id="gnu.c.compiler.so.debug.option.optimization.level.778447619" name="Optimization Level" superClass="gnu.c.compiler.so.debug.option.optimization.level" valueType="enumerated"/>
+								<option id="gnu.c.compiler.so.debug.option.debugging.level.1242355031" name="Debug Level" superClass="gnu.c.compiler.so.debug.option.debugging.level" value="gnu.c.debugging.level.max" valueType="enumerated"/>
+								<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1489925180" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.c.linker.so.debug.1070158924" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.so.debug">
+								<option defaultValue="true" id="gnu.c.link.so.debug.option.shared.2020359587" name="Shared (-shared)" superClass="gnu.c.link.so.debug.option.shared" valueType="boolean"/>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.cpp.linker.so.debug.1805037429" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.so.debug">
+								<option defaultValue="true" id="gnu.cpp.link.so.debug.option.shared.1898041057" name="Shared (-shared)" superClass="gnu.cpp.link.so.debug.option.shared" valueType="boolean"/>
+								<option id="gnu.cpp.link.option.paths.292899400" name="Library search path (-L)" superClass="gnu.cpp.link.option.paths" valueType="libPaths">
+									<listOptionValue builtIn="false" value="../../lib/"/>
+								</option>
+								<option id="gnu.cpp.link.option.libs.1527528033" superClass="gnu.cpp.link.option.libs" valueType="libs">
+									<listOptionValue builtIn="false" value="cpoll"/>
+									<listOptionValue builtIn="false" value="cryptopp"/>
+								</option>
+								<inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.944044736" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
+									<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+									<additionalInput kind="additionalinput" paths="$(LIBS)"/>
+								</inputType>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.assembler.so.debug.429164109" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.so.debug">
+								<inputType id="cdt.managedbuild.tool.gnu.assembler.input.1373545929" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
+							</tool>
+						</toolChain>
+					</folderInfo>
+					<sourceEntries>
+						<entry excluding="all.C" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
+					</sourceEntries>
+				</configuration>
+			</storageModule>
+			<storageModule moduleId="org.eclipse.cdt.core.externalSettings">
+				<externalSettings containerId="org.eclipse.cdt.managedbuilder.pkgconfig.extSettings" factoryId="org.eclipse.cdt.core.extension.container.factory">
+					<externalSetting contentTypes="org.eclipse.cdt.core.cSource:org.eclipse.cdt.core.cxxSource"/>
+					<externalSetting contentTypes="org.eclipse.cdt.managedbuilder.core.compiledObjectFile"/>
+				</externalSettings>
+			</storageModule>
+			<storageModule moduleId="packages"/>
+		</cconfiguration>
+		<cconfiguration id="cdt.managedbuild.config.gnu.so.release.1921876389">
+			<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.so.release.1921876389" moduleId="org.eclipse.cdt.core.settings" name="Release">
+				<externalSettings>
+					<externalSetting>
+						<entry flags="VALUE_WORKSPACE_PATH" kind="includePath" name="/cppsp"/>
+						<entry flags="VALUE_WORKSPACE_PATH" kind="libraryPath" name="/cppsp/Release"/>
+						<entry flags="RESOLVED" kind="libraryFile" name="cppsp" srcPrefixMapping="" srcRootPath=""/>
+					</externalSetting>
+				</externalSettings>
+				<extensions>
+					<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
+					<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+				</extensions>
+			</storageModule>
+			<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+				<configuration artifactExtension="so" artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.sharedLib" buildProperties="org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.sharedLib" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.so.release.1921876389" name="Release" parent="cdt.managedbuild.config.gnu.so.release">
+					<folderInfo id="cdt.managedbuild.config.gnu.so.release.1921876389." name="/" resourcePath="">
+						<toolChain id="cdt.managedbuild.toolchain.gnu.so.release.551859874" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.so.release">
+							<targetPlatform id="cdt.managedbuild.target.gnu.platform.so.release.1088646397" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.so.release"/>
+							<builder buildPath="${workspace_loc:/cppsp/Release}" id="cdt.managedbuild.target.gnu.builder.so.release.1538475250" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.so.release"/>
+							<tool id="cdt.managedbuild.tool.gnu.archiver.base.1746531226" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
+							<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.so.release.1956103788" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.so.release">
+								<option id="gnu.cpp.compiler.so.release.option.optimization.level.1032315314" name="Optimization Level" superClass="gnu.cpp.compiler.so.release.option.optimization.level" value="gnu.cpp.compiler.optimization.level.most" valueType="enumerated"/>
+								<option id="gnu.cpp.compiler.so.release.option.debugging.level.335614317" name="Debug Level" superClass="gnu.cpp.compiler.so.release.option.debugging.level" value="gnu.cpp.compiler.debugging.level.none" valueType="enumerated"/>
+								<option id="gnu.cpp.compiler.option.other.other.147619357" name="Other flags" superClass="gnu.cpp.compiler.option.other.other" value="-c -fmessage-length=0 --std=c++0x -Wno-pmf-conversions -fno-omit-frame-pointer -march=native" valueType="string"/>
+								<option id="gnu.cpp.compiler.option.other.pic.1017504045" name="Position Independent Code (-fPIC)" superClass="gnu.cpp.compiler.option.other.pic" value="true" valueType="boolean"/>
+								<option id="gnu.cpp.compiler.option.include.paths.1889336013" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" valueType="includePath">
+									<listOptionValue builtIn="false" value="../../include/"/>
+								</option>
+								<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1799531335" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.c.compiler.so.release.1559171520" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.so.release">
+								<option defaultValue="gnu.c.optimization.level.most" id="gnu.c.compiler.so.release.option.optimization.level.190589092" name="Optimization Level" superClass="gnu.c.compiler.so.release.option.optimization.level" valueType="enumerated"/>
+								<option id="gnu.c.compiler.so.release.option.debugging.level.1594027574" name="Debug Level" superClass="gnu.c.compiler.so.release.option.debugging.level" value="gnu.c.debugging.level.none" valueType="enumerated"/>
+								<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1743877314" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.c.linker.so.release.932230685" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.so.release">
+								<option defaultValue="true" id="gnu.c.link.so.release.option.shared.1083816068" name="Shared (-shared)" superClass="gnu.c.link.so.release.option.shared" valueType="boolean"/>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.cpp.linker.so.release.31575139" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.so.release">
+								<option defaultValue="true" id="gnu.cpp.link.so.release.option.shared.1093357776" name="Shared (-shared)" superClass="gnu.cpp.link.so.release.option.shared" valueType="boolean"/>
+								<option id="gnu.cpp.link.option.paths.1942186616" name="Library search path (-L)" superClass="gnu.cpp.link.option.paths" valueType="libPaths">
+									<listOptionValue builtIn="false" value="../../lib/"/>
+								</option>
+								<option id="gnu.cpp.link.option.flags.2114616824" name="Linker flags" superClass="gnu.cpp.link.option.flags" value="" valueType="string"/>
+								<option id="gnu.cpp.link.option.libs.1358223929" superClass="gnu.cpp.link.option.libs" valueType="libs">
+									<listOptionValue builtIn="false" value="cpoll"/>
+									<listOptionValue builtIn="false" value="cryptopp"/>
+								</option>
+								<inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.1034473443" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
+									<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+									<additionalInput kind="additionalinput" paths="$(LIBS)"/>
+								</inputType>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.assembler.so.release.1631996455" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.so.release">
+								<inputType id="cdt.managedbuild.tool.gnu.assembler.input.510972094" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
+							</tool>
+						</toolChain>
+					</folderInfo>
+					<sourceEntries>
+						<entry excluding="all.C" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
+					</sourceEntries>
+				</configuration>
+			</storageModule>
+			<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+		</cconfiguration>
+	</storageModule>
+	<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+		<project id="cppsp.cdt.managedbuild.target.gnu.so.1663938254" name="Shared Library" projectType="cdt.managedbuild.target.gnu.so"/>
+	</storageModule>
+	<storageModule moduleId="scannerConfiguration">
+		<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.so.debug.7250834;cdt.managedbuild.config.gnu.so.debug.7250834.;cdt.managedbuild.tool.gnu.c.compiler.so.debug.1027837749;cdt.managedbuild.tool.gnu.c.compiler.input.1489925180">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.so.release.1921876389;cdt.managedbuild.config.gnu.so.release.1921876389.;cdt.managedbuild.tool.gnu.cpp.compiler.so.release.1956103788;cdt.managedbuild.tool.gnu.cpp.compiler.input.1799531335">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.so.debug.7250834;cdt.managedbuild.config.gnu.so.debug.7250834.;cdt.managedbuild.tool.gnu.cpp.compiler.so.debug.58597657;cdt.managedbuild.tool.gnu.cpp.compiler.input.628017354">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.so.release.1921876389;cdt.managedbuild.config.gnu.so.release.1921876389.;cdt.managedbuild.tool.gnu.c.compiler.so.release.1559171520;cdt.managedbuild.tool.gnu.c.compiler.input.1743877314">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+		</scannerConfigBuildInfo>
+	</storageModule>
+	<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
+	<storageModule moduleId="refreshScope" versionNumber="2">
+		<configuration configurationName="Release">
+			<resource resourceType="PROJECT" workspacePath="/cppsp"/>
+		</configuration>
+		<configuration configurationName="Debug">
+			<resource resourceType="PROJECT" workspacePath="/cppsp"/>
+		</configuration>
+	</storageModule>
+</cproject>

+ 27 - 0
cpoll_cppsp/cppsp_rel0.2.3/cppsp/.project

@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>cppsp</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
+			<triggers>clean,full,incremental,</triggers>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
+			<triggers>full,incremental,</triggers>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.cdt.core.cnature</nature>
+		<nature>org.eclipse.cdt.core.ccnature</nature>
+		<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
+		<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
+	</natures>
+</projectDescription>

+ 6 - 0
cpoll_cppsp/cppsp_rel0.2.3/cppsp/all.C

@@ -0,0 +1,6 @@
+#include "common.C"
+#include "cppsp_cpoll.C"
+#include "page.C"
+#include "stringutils.C"
+
+

+ 865 - 0
cpoll_cppsp/cppsp_rel0.2.3/cppsp/common.C

@@ -0,0 +1,865 @@
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * */
+/*
+ * common.C
+ *
+ *  Created on: Apr 6, 2013
+ *      Author: xaxaxa
+ */
+#include <cpoll/cpoll.H>
+#include <string>
+#include <string.h>
+#include <exception>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdexcept>
+#include <fcntl.h>
+#include <dlfcn.h>
+#include <libgen.h>
+#include <sys/wait.h>
+#include "include/common.H"
+#include "include/page.H"
+#include <errno.h>
+#include "include/split.H"
+
+using namespace CP;
+using namespace std;
+namespace cppsp
+{
+	PThreadMutex dlMutex;
+	const char* gxx = "g++";
+	ParserException::ParserException() :
+			message(strerror(errno)), number(errno) {
+	}
+	ParserException::ParserException(int32_t number) :
+			message(strerror(number)), number(number) {
+	}
+	ParserException::ParserException(string message, int32_t number) :
+			message(message), number(number) {
+	}
+	ParserException::~ParserException() throw () {
+	}
+	const char* ParserException::what() const throw () {
+		return message.c_str();
+	}
+	CompileException::CompileException() :
+			message("Compilation error") {
+	}
+	CompileException::CompileException(string message) :
+			message(message) {
+	}
+	CompileException::~CompileException() throw () {
+	}
+	const char* CompileException::what() const throw () {
+		return message.c_str();
+	}
+
+	//inline-able memcpy() for copying SHORT STRINGS ONLY
+	static inline void memcpy2(void* dst, const void* src, int len) {
+		for (int i = 0; i < len; i++)
+			((char*) dst)[i] = ((const char*) src)[i];
+	}
+	// "/"		+ "aaaaa"	=> "/aaaaa"
+	// "/asdf/"	+ "zzz"		=> "/asdf/zzz"
+	// "/asdf/"	+ "zzz/"		=> "/asdf/zzz/"
+	// "/asdf"	+ "zzz"		=> "/zzz"
+	// "/asdf/"	+ "../zzz"	=> "/zzz"
+	// "/asdf/"	+ "a/../x"	=> "/asdf/x"
+	// "/asdf/"	+ "/zzz"		=> "/zzz"
+	//the size of buf should be at least strlen(p1)+strlen(p2)
+	//returns the length of the string written to buf; does NOT write null byte
+	int combinePath(const char* p1, int l1, const char* p2, int l2, char* buf) {
+		if (l2 > 0 && p2[0] == '/') {
+			memcpy2(buf, p2, l2);
+			return l2;
+		}
+		int i = l1;
+		memcpy2(buf, p1, i);
+		if (l2 > 0) {
+			i--;
+			while (i >= 0 && buf[i] != '/')
+				i--;
+			if (i < 0) i = 0;
+			split spl(p2, l2, '/');
+			while (spl.read()) {
+				const char* s = spl.value.data();
+				int l = spl.value.length();
+				if (l == 2 && *(const uint16_t*) s == *(const uint16_t*) "..") {
+					i--;
+					while (i >= 0 && buf[i] != '/')
+						i--;
+					if (i < 0) i = 0;
+				} else if (l == 1 && *s == '.') {
+					buf[i] = '/';
+					i++;
+				} else {
+					//while(i>=0 && buf[i]!='/')i--;
+					buf[i] = '/';
+					i++;
+					memcpy2(buf + i, s, l);
+					i += l;
+				}
+			}
+			//if (l2 > 0 && i > 0 && p2[l2 - 1] != '/' && buf[i - 1] == '/')
+		}
+		if (i < 0) i = 0;
+		return i;
+	}
+	int combinePath(const char* p1, const char* p2, char* buf) {
+		return combinePath(p1, strlen(p1), p2, strlen(p2), buf);
+	}
+	//p1 is the "root" directory
+	//guarantees that the resulting path won't be outside of p1
+	int combinePathChroot(const char* p1, int l1, const char* p2, int l2, char* buf) {
+		int i = l1;
+		memcpy2(buf, p1, i);
+		static const uint16_t parentDir = *(const uint16_t*) "..";
+		if (l2 > 0) {
+			bool first(true);
+			split spl(p2, l2, '/');
+			while (spl.read()) {
+				const char* s = spl.value.data();
+				int l = spl.value.length();
+				if (first) {
+					first = false;
+					if (l == 0) continue;
+				}
+				if (l == 2 && *(const uint16_t*) s == parentDir) {
+					i--;
+					while (i >= 0 && buf[i] != '/')
+						i--;
+					if (i < l1) i = l1;
+				} else if (l == 1 && *s == '.') {
+					if (!(i > 0 && buf[i - 1] == '/')) {
+						buf[i] = '/';
+						i++;
+					}
+				} else {
+					//while(i>=0 && buf[i]!='/')i--;
+					if (!(i > 0 && buf[i - 1] == '/')) {
+						buf[i] = '/';
+						i++;
+					}
+					memcpy2(buf + i, s, l);
+					i += l;
+				}
+			}
+			//if (l2 > 0 && i > 0 && p2[l2 - 1] != '/' && buf[i - 1] == '/')
+		}
+		if (i < l1) i = l1;
+		return i;
+	}
+	int combinePathChroot(const char* p1, const char* p2, char* buf) {
+		return combinePathChroot(p1, strlen(p1), p2, strlen(p2), buf);
+	}
+
+	String combinePath(String p1, String p2, StringPool& sp) {
+		char* tmp = sp.beginAdd(p1.length() + p2.length());
+		int l = combinePath(p1.data(), p2.data(), tmp);
+		sp.endAdd(l);
+		return {tmp,l};
+	}
+	String combinePathChroot(String p1, String p2, StringPool& sp) {
+		char* tmp = sp.beginAdd(p1.length() + p2.length());
+		int l = combinePathChroot(p1.data(), p2.data(), tmp);
+		sp.endAdd(l);
+		return {tmp,l};
+	}
+	//parses a cppsp page and generates code (to out) and string table (to st_out)
+	void doParse(const char* name, const char* in, int inLen, Stream& out, Stream& st_out,
+			vector<string>& c_opts) {
+		const char* s = in;
+		const char* end = s + inLen;
+		string inherits = "Page";
+		string classname = (name == NULL ? "__cppsp_unnamed_page" : name);
+		int st_pos = 0;
+		int st_len = 0;
+		//int out_initlen=out.length();
+		Stream& ms1(out); //declarations outside of the class
+		MemoryStream ms2; //declarations outside of the render() function
+		MemoryStream ms3; //code inside render()
+		StreamWriter sw1(ms1);
+		StreamWriter sw2(ms2);
+		StreamWriter sw3(ms3);
+		sw1.write("#include <cppsp/page.H>\n#include <cpoll/cpoll.H>\n");
+		sw1.write("#include <cppsp/common.H>\n#include <cppsp/stringutils.H>\n");
+		sw1.write("#include <rgc.H>\n");
+		sw1.write("using namespace cppsp;\nusing namespace CP;\n");
+		int line = 1;
+		while (true) {
+			if (s >= end) break;
+			const char* old_s = s;
+			s = (const char*) memmem(s, end - s, "<%", 2);
+
+			if (s > old_s) {
+				st_out.write(old_s, s - old_s);
+				st_len += (s - old_s);
+			} else if (s == NULL) {
+				st_out.write(old_s, end - old_s);
+				st_len += (end - old_s);
+
+				sw3.writeF("__writeStringTable(%i,%i);\n", st_pos, st_len - st_pos);
+				break;
+			}
+			for (const char* ch = old_s; ch < s; ch++)
+				if (*ch == '\n') line++;
+			s += 2;
+			if (s >= end) throw ParserException("reached EOF when looking past \"<%\"");
+			const char* s1 = (const char*) memmem(s, end - s, "%>", 2);
+			if (s1 == NULL) throw ParserException("reached EOF when looking for matching \"%>\"");
+
+			switch (*s) {
+				case '!':
+				{ //compiler option
+					c_opts.push_back(string(s + 1, s1 - s - 1));
+					break;
+				}
+				case '@':
+				{ //cppsp options
+					int nextopt = 0;
+					split spl(s + 1, s1 - s - 1, ' ');
+					while (spl.read()) {
+						const char* s1 = spl.value.data();
+						int l1 = spl.value.length();
+						switch (nextopt) {
+							case 0:
+							{
+								if (l1 == 8 && memcmp(s1, "inherits", 8) == 0) nextopt = 1;
+								else if (l1 == 5 && memcmp(s1, "class", 5) == 0) nextopt = 2;
+								continue;
+							}
+							case 1:
+							{
+								inherits = string(s1, l1);
+								break;
+							}
+							case 2:
+							{
+								if (name == NULL) classname = string(s1, l1);
+								break;
+							}
+						}
+						nextopt = 0;
+					}
+					break;
+				}
+				case '#':
+				{ //declarations outside of the class
+					sw1.writeF("#line %i\n", line);
+					sw1.write(s + 1, s1 - s - 1);
+					break;
+				}
+				case '$':
+				{ //declarations outside of the render() function
+					sw2.writeF("#line %i\n", line);
+					sw2.write(s + 1, s1 - s - 1);
+					break;
+				}
+				case '=':
+				{
+					sw3.writeF("__writeStringTable(%i,%i);\n", st_pos, st_len - st_pos);
+					st_pos = st_len;
+
+					sw3.writeF("#line %i\n", line);
+					sw3.write("output.write(");
+					sw3.write(s + 1, s1 - s - 1);
+					sw3.write(");\n");
+					break;
+				}
+				default:
+				{
+					sw3.writeF("__writeStringTable(%i,%i);\n", st_pos, st_len - st_pos);
+					st_pos = st_len;
+
+					sw3.writeF("#line %i\n", line);
+					sw3.write(s, s1 - s);
+					break;
+				}
+			}
+			for (const char* ch = s; ch < s1; ch++)
+				if (*ch == '\n') line++;
+			s = s1 + 2;
+		}
+		sw2.flush();
+		sw3.flush();
+		sw1.writeF("class %s: public %s {\npublic:\n", classname.c_str(), inherits.c_str());
+		sw1.write(ms2.data(), ms2.length());
+		//the name of the StreamWriter parameter should always be "output" -- this is part of
+		//the cppsp API and should not ever be changed; users can rely on its name being "output".
+		sw1.write("virtual void render(StreamWriter& output) override {\n");
+		sw1.write(ms3.data(), ms3.length());
+		sw1.write("}\n};\n");
+		sw1.writeF("extern \"C\" int getObjectSize() {return sizeof(%s);}\n", classname.c_str());
+		sw1.writeF("extern \"C\" Page* createObject(void* mem) {"
+				"if(mem==NULL) return new %s(); else return new (mem) %s();}\n", classname.c_str(),
+				classname.c_str());
+		sw1.writeF("extern \"C\" Page* createObject1(RGC::Allocator* alloc) {"
+				"%s* tmp = new (alloc->alloc(sizeof(%s))) %s(); tmp->allocator=alloc; return tmp;}\n",
+				classname.c_str(), classname.c_str(), classname.c_str());
+		sw1.flush();
+		//out.write(ms1.data(), ms1.length());
+	}
+	static inline int checkError(int i) {
+		if (i < 0) throw runtime_error(strerror(errno));
+		return i;
+	}
+	static inline void* checkError(void* p) {
+		if (p == NULL) throw runtime_error(strerror(errno));
+		return p;
+	}
+	static inline void* checkDLError(void* p) {
+		if (p == NULL) throw runtime_error(dlerror());
+		return p;
+	}
+	CP::File* compilePage(string wd, string path, string cPath, string txtPath, string output,
+			const vector<string>& cxxopts, pid_t& pid, string& compilecmd) {
+		vector<string> c_opts { gxx, gxx, "--std=c++0x", "--shared", "-o", output, cPath };
+		c_opts.insert(c_opts.end(), cxxopts.begin(), cxxopts.end());
+		{
+			File inp(open(path.c_str(), O_RDONLY));
+			MemoryStream ms;
+			inp.readToEnd(ms);
+			ms.flush();
+			//unlink((path + ".C").c_str());
+			File out_c(open(cPath.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0666));
+			File out_s(open(txtPath.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0666));
+			cppsp::doParse(NULL, (const char*) ms.data(), ms.length(), out_c, out_s, c_opts);
+		}
+
+		const char* cmds[c_opts.size() + 1];
+		for (int i = 0; i < (int) c_opts.size(); i++) {
+			cmds[i] = c_opts[i].c_str();
+		}
+		cmds[c_opts.size()] = NULL;
+
+		int p[2];
+		checkError(pipe(p));
+		//unlink((path + ".so").c_str());
+		pid_t tmp = fork();
+		if (tmp > 0) {
+			close(p[1]);
+			pid = tmp;
+			for (int i = 1; i < (int) c_opts.size(); i++) {
+				compilecmd.append(c_opts[i]);
+				compilecmd.append(" ");
+			}
+			return new CP::File(p[0]);
+		} else if (tmp == 0) {
+			close(p[0]);
+			dup2(p[1], 1);
+			dup2(p[1], 2);
+			close(p[1]);
+			chdir(wd.c_str());
+			execvp(cmds[0], (char**) (cmds + 1));
+			_exit(1);
+		} else {
+			checkError(tmp);
+		}
+		return NULL;
+	}
+	int tsCompare(struct timespec time1, struct timespec time2) {
+		if (time1.tv_sec < time2.tv_sec) return (-1); /* Less than. */
+		else if (time1.tv_sec > time2.tv_sec) return (1); /* Greater than. */
+		else if (time1.tv_nsec < time2.tv_nsec) return (-1); /* Less than. */
+		else if (time1.tv_nsec > time2.tv_nsec) return (1); /* Greater than. */
+		else return (0); /* Equal. */
+	}
+
+#define CONCAT_TO(in,inLen,out,conc) char out[strlen(conc)+inLen+1];\
+	memcpy(out,in,inLen);\
+	memcpy(out+inLen,conc,strlen(conc));\
+	out[strlen(conc)+inLen]=0;
+#define TO_C_STR(in,inLen,out) char out[inLen+1];\
+	memcpy(out,in,inLen);\
+	out[inLen]=0;
+	static inline void pageErr_isDir() {
+		throw ParserException("requested path is a directory or socket");
+	}
+	void loadedPage::readCB(int r) {
+		if (r <= 0) {
+			compiling = false;
+			int status = -1;
+			waitpid(compilerPID, &status, 0);
+
+			//keep a copy of the compiled page
+			if (status == 0) {
+				unlink(cPath.c_str());
+				string dll1 = dllPath + ".1";
+				link(dllPath.c_str(), dll1.c_str());
+				rename(dll1.c_str(), (path + ".so").c_str());
+				string txt1 = txtPath + ".1";
+				link(txtPath.c_str(), txt1.c_str());
+				rename(txt1.c_str(), (path + ".txt").c_str());
+			}
+			afterCompile(status == 0);
+			compile_fd = nullptr;
+			//if (compileCB != nullptr) compileCB(*this);
+			return;
+		}
+		ms.bufferPos += r;
+		ms.flush();
+		beginRead();
+	}
+	void loadedPage::deleteTmpfiles() {
+		unlink(txtPath.c_str());
+		unlink(dllPath.c_str());
+	}
+	void loadedPage::afterCompile(bool success) {
+		if (!success) {
+			rename(cPath.c_str(), (path + ".C").c_str());
+			deleteTmpfiles();
+			CompileException exc;
+			exc.compilerOutput = string((const char*) ms.data(), ms.length());
+			auto tmpcb = loadCB;
+			loadCB.clear();
+			for (int i = 0; i < (int) tmpcb.size(); i++)
+				tmpcb[i](nullptr, &exc);
+			return;
+		}
+		try {
+			if (loaded) doUnload();
+			doLoad();
+		} catch (exception& ex) {
+			deleteTmpfiles();
+			auto tmpcb = loadCB;
+			loadCB.clear();
+			for (int i = 0; i < (int) tmpcb.size(); i++)
+				tmpcb[i](nullptr, &ex);
+			return;
+		}
+		deleteTmpfiles();
+		auto tmpcb = loadCB;
+		loadCB.clear();
+		for (int i = 0; i < (int) tmpcb.size(); i++)
+			tmpcb[i](this, nullptr);
+	}
+	void loadedPage::beginRead() {
+		if (ms.bufferSize - ms.bufferPos < 4096) ms.flushBuffer(4096);
+		compile_fd->read(ms.buffer + ms.bufferPos, ms.bufferSize - ms.bufferPos,
+				CP::Callback(&loadedPage::readCB, this));
+	}
+	void loadedPage::doCompile(Poll& p, string wd, const vector<string>& cxxopts) {
+		string tmp;
+		char sss[32];
+		snprintf(sss, 32, "%i", rand());
+		txtPath = path + "." + string(sss) + ".txt";
+		dllPath = path + "." + string(sss) + ".dll";
+		cPath = path + "." + string(sss) + ".C";
+
+		//check if a precompiled page exists; if it exists and is newer than
+		//the .cppsp, then simply hardlink to it
+		timespec modif_txt, modif_so, modif_cppsp;
+		struct stat st;
+		{
+			TO_C_STR(path.data(), path.length(), s1);
+			if (stat(s1, &st) < 0) goto do_comp;
+			modif_cppsp = st.st_mtim;
+		}
+		{
+			CONCAT_TO(path.data(), path.length(), s1, ".txt");
+			if (stat(s1, &st) < 0) goto do_comp;
+			modif_txt = st.st_mtim;
+		}
+		{
+			CONCAT_TO(path.data(), path.length(), s1, ".so");
+			if (stat(s1, &st) < 0) goto do_comp;
+			modif_so = st.st_mtim;
+		}
+		if (tsCompare(modif_cppsp, modif_txt) <= 0 && tsCompare(modif_cppsp, modif_so) <= 0) {
+			string txt1 = path + ".txt";
+			string dll1 = path + ".so";
+			if (link(txt1.c_str(), txtPath.c_str()) < 0) goto do_comp;
+			if (link(dll1.c_str(), dllPath.c_str()) < 0) goto do_comp;
+			afterCompile(true);
+			return;
+		}
+
+		do_comp: deleteTmpfiles();
+		CP::File* f;
+		ms.clear();
+		try {
+			f = (CP::File*) checkError(
+					compilePage(wd, path, cPath, txtPath, dllPath, cxxopts, compilerPID, tmp));
+		} catch (...) {
+			deleteTmpfiles();
+			throw;
+		}
+		tmp += "\n";
+		ms.write(tmp.data(), tmp.length());
+		p.add(*f);
+		compile_fd = f;
+		f->release();
+		beginRead();
+		compiling = true;
+	}
+	void loadedPage::doLoad() {
+		ScopeLock sl(dlMutex);
+		//printf("doLoad(\"%s\");\n",path.c_str());
+		struct stat st;
+		checkError(stat(txtPath.c_str(), &st));
+		stringTableLen = st.st_size;
+		stringTableFD = checkError(open(txtPath.c_str(), O_RDONLY));
+		stringTable = (const uint8_t*) checkError(
+				mmap(NULL, stringTableLen, PROT_READ, MAP_SHARED, stringTableFD, 0));
+		dlHandle = dlopen(dllPath.c_str(), RTLD_LOCAL | RTLD_LAZY);
+		if (dlHandle == NULL) throw runtime_error(dlerror());
+		getObjectSize = (getObjectSize_t) checkDLError(dlsym(dlHandle, "getObjectSize"));
+		createObject = (createObject_t) checkDLError(dlsym(dlHandle, "createObject"));
+		createObject1 = (createObject1_t) checkDLError(dlsym(dlHandle, "createObject1"));
+		initModule_t initModule = (initModule_t) dlsym(dlHandle, "initModule");
+		if (initModule != NULL) {
+			initModule(srv);
+			fprintf(stderr, "module %s loaded\n", path.c_str());
+		}
+		loaded = true;
+		clock_gettime(CLOCK_REALTIME, &lastLoad);
+		//printf("loaded: dlHandle=%p; createObject=%p\n",dlHandle,(void*)createObject);
+	}
+	void loadedPage::doUnload() {
+		//printf("doUnload(\"%s\");\n",path.c_str());
+		loaded = false;
+		if (stringTable != NULL) munmap((void*) stringTable, stringTableLen);
+		if (stringTableFD != -1) close(stringTableFD);
+		if (dlHandle != NULL) {
+			deinitModule_t deinitModule = (deinitModule_t) dlsym(dlHandle, "deinitModule");
+			if (deinitModule != NULL) {
+				deinitModule();
+				fprintf(stderr, "module %s unloaded\n", path.c_str());
+			}
+			ScopeLock sl(dlMutex);
+			checkError(dlclose(dlHandle));
+			//void* tmp=dlopen((path + ".so").c_str(), RTLD_LOCAL | RTLD_LAZY|RTLD_NOLOAD);
+			//if(tmp!=NULL) throw runtime_error("unable to unload library");
+		}
+		dlHandle = NULL;
+		stringTable = NULL;
+		stringTableFD = -1;
+		//printf("unloaded\n");
+	}
+	Page* loadedPage::doCreate(RGC::Allocator* a) {
+		Page* tmp = createObject1(a);
+		checkError(tmp);
+		tmp->__stringTable = stringTable;
+		tmp->filePath = {path.data(),(int)path.length()};
+		return tmp;
+	}
+	loadedPage::loadedPage() :
+			dlHandle(NULL), stringTable(NULL), stringTableFD(-1) {
+		//printf("loadedPage()\n");
+		compiling = false;
+		doUnload();
+	}
+	loadedPage::~loadedPage() {
+		//printf("~loadedPage()\n");
+		doUnload();
+	}
+	//returns: 0: no-op; 1: should reload; 2: should recompile
+	int loadedPage::shouldCompile() {
+		struct stat st;
+		{
+			TO_C_STR(path.data(), path.length(), s1);
+			checkError(stat(s1, &st));
+			if (S_ISDIR(st.st_mode) || S_ISSOCK(st.st_mode)) pageErr_isDir();
+		}
+		if (!loaded) return 2;
+		timespec modif_cppsp = st.st_mtim;
+		/*{
+		 CONCAT_TO(path.data(), path.length(), s1, ".txt");
+		 if (stat(s1, &st) < 0) {
+		 if (errno == ENOENT) return 2;
+		 else checkError(-1);
+		 }
+		 }
+		 timespec modif_txt = st.st_mtim;
+		 {
+		 CONCAT_TO(path.data(), path.length(), s1, ".so");
+		 if (stat(s1, &st) < 0) {
+		 if (errno == ENOENT) return 2;
+		 else checkError(-1);
+		 }
+		 }
+		 timespec modif_so = st.st_mtim;*/
+		int i = 0;
+		if (tsCompare(lastLoad, modif_cppsp) < 0) i = 2;
+		//if(tsCompare(lastLoad, modif_txt)< 0 || tsCompare(lastLoad, modif_so) <0) i=1;
+		//if(tsCompare(modif_cppsp, modif_txt)> 0 || tsCompare(modif_cppsp, modif_so) >0) i=2;
+		//printf("shouldCompile(\"%s\") = %i\n",path.c_str(),i);
+		return i;
+	}
+	void staticPage::doLoad() {
+		struct stat st;
+		checkError(stat(path.c_str(), &st));
+		data.len = st.st_size;
+		int fd = checkError(open(path.c_str(), O_RDONLY));
+		data.d = (char*) checkError(mmap(NULL, data.len, PROT_READ, MAP_SHARED, fd, 0));
+		close(fd);
+		loaded = true;
+		clock_gettime(CLOCK_REALTIME, &lastLoad);
+	}
+	void staticPage::doUnload() {
+		loaded = false;
+		if (data.d != NULL) munmap((void*) data.d, data.len);
+		data = nullptr;
+	}
+	bool staticPage::shouldReload() {
+		struct stat st;
+		{
+			TO_C_STR(path.data(), path.length(), s1);
+			checkError(stat(s1, &st));
+			if (S_ISDIR(st.st_mode) || S_ISSOCK(st.st_mode)) throw ParserException(
+					"requested path is a directory or socket");
+		}
+		if (!loaded) return true;
+		timespec modif_cppsp = st.st_mtim;
+		return (tsCompare(lastLoad, modif_cppsp) < 0);
+	}
+	staticPage::staticPage() {
+		loaded = false;
+	}
+	staticPage::~staticPage() {
+		doUnload();
+	}
+
+	inline void loadedPage::_loadCB::operator()(loadedPage* This, exception* ex) {
+		if (ex == NULL) {
+			void* p;
+			try {
+				p = doCreate ? This->doCreate(alloc) : This->dlHandle;
+			} catch (exception& x) {
+				cb(nullptr, &x);
+				return;
+			}
+			cb(p, nullptr);
+		} else cb(nullptr, ex);
+	}
+
+	static inline void precheckPage(String path) {
+		struct stat st;
+		TO_C_STR(path.data(), path.length(), s1);
+		checkError(stat(s1, &st));
+		if (S_ISDIR(st.st_mode) || S_ISSOCK(st.st_mode)) pageErr_isDir();
+	}
+	cppspManager::cppspManager() :
+			threadID(0) {
+		curRFCTime.d = (char*) malloc(32);
+		curRFCTime.len = 0;
+	}
+	cppspManager::~cppspManager() {
+		free(curRFCTime.d);
+	}
+	String cppspManager::loadStaticPage(String path) {
+		staticPage* lp1;
+		auto it = staticCache.find(path);
+		if (it == staticCache.end()) {
+			precheckPage(path);
+			lp1 = new staticPage();
+			lp1->path = path.toSTDString();
+			staticCache.insert( { sp.addString(path), lp1 });
+		} else lp1 = (*it).second;
+		staticPage& lp(*lp1);
+		if (likely(lp.loaded & !shouldCheck(lp))) {
+			return lp.data;
+		}
+		if (lp.shouldReload()) {
+			lp.doUnload();
+		}
+		if (!lp.loaded) lp.doLoad();
+		return lp.data;
+	}
+	bool cppspManager::shouldCheck(loadedPage& p) {
+		timespec tmp1 = curTime;
+		tmp1.tv_sec -= 2;
+		if (tsCompare(p.lastCheck, tmp1) < 0) {
+			p.lastCheck = curTime;
+			return true;
+		} else return false;
+	}
+	bool cppspManager::shouldCheck(staticPage& p) {
+		timespec tmp1 = curTime;
+		tmp1.tv_sec -= 2;
+		if (tsCompare(p.lastCheck, tmp1) < 0) {
+			p.lastCheck = curTime;
+			return true;
+		} else return false;
+	}
+
+	void cppspManager::loadPage(Poll& p, String wd, String path, RGC::Allocator* a,
+			Delegate<void(Page*, exception* ex)> cb) {
+		loadedPage* lp1;
+		auto it = cache.find(path);
+		if (unlikely(int(it == cache.end()))) {
+			//check if file exists; if not, don't construct loadedPage object to avoid DoS
+			try {
+				precheckPage(path);
+			} catch (exception& ex) {
+				cb(nullptr, &ex);
+				return;
+			}
+			lp1 = new loadedPage();
+			lp1->path = path.toSTDString();
+			cache.insert( { sp.addString(path), lp1 });
+		} else lp1 = (*it).second;
+		loadedPage& lp(*lp1);
+
+		int c = 0;
+		if (unlikely(lp1->compiling)) {
+			lp.loadCB.push_back( { a, Delegate<void(void*, exception* ex)>(cb), true });
+			return;
+		}
+		if (likely(lp1->loaded & !shouldCheck(*lp1))) {
+			xxx: Page* p;
+			try {
+				p = lp.doCreate(a);
+			} catch (exception& ex) {
+				cb(nullptr, &ex);
+			}
+			cb(p, nullptr);
+			return;
+		}
+		try {
+			c = lp.shouldCompile();
+			if (likely(lp1->loaded && c==0)) goto xxx;
+		} catch (exception& ex) {
+			cb(nullptr, &ex);
+			return;
+		}
+		if (c >= 2) {
+			lp.loadCB.push_back( { a, Delegate<void(void*, exception* ex)>(cb), true });
+			try {
+				lp.doCompile(p, wd.toSTDString(), cxxopts);
+			} catch (exception& ex) {
+				lp.loadCB.resize(lp.loadCB.size() - 1);
+				cb(nullptr, &ex);
+			}
+			return;
+		}
+		try {
+			if (c >= 1) {
+				lp.doUnload();
+			}
+			lp.doLoad();
+			goto xxx;
+		} catch (exception& ex) {
+			cb(nullptr, &ex);
+		}
+	}
+	void cppspManager::loadModule(Poll& p, Server* srv, String wd, String path,
+			Delegate<void(void*, exception* ex)> cb) {
+		loadedPage* lp1;
+		auto it = cache.find(path);
+		if (unlikely(int(it == cache.end()))) {
+			try {
+				precheckPage(path);
+			} catch (exception& ex) {
+				cb(nullptr, &ex);
+				return;
+			}
+			lp1 = new loadedPage();
+			lp1->srv = srv;
+			lp1->path = path.toSTDString();
+			cache.insert( { sp.addString(path), lp1 });
+		} else lp1 = (*it).second;
+		loadedPage& lp(*lp1);
+
+		int c = 0;
+		if (unlikely(lp1->compiling)) {
+			lp.loadCB.push_back( { nullptr, cb, false });
+			return;
+		}
+		if (likely(lp1->loaded & !shouldCheck(*lp1))) {
+			xxx: cb(lp1->dlHandle, nullptr);
+			return;
+		}
+		try {
+			c = lp.shouldCompile();
+			if (likely(lp1->loaded && c==0)) goto xxx;
+		} catch (exception& ex) {
+			cb(nullptr, &ex);
+			return;
+		}
+		if (c >= 2) {
+			lp.loadCB.push_back( { nullptr, cb, false });
+			try {
+				lp.doCompile(p, wd.toSTDString(), cxxopts);
+			} catch (exception& ex) {
+				lp.loadCB.resize(lp.loadCB.size() - 1);
+				cb(nullptr, &ex);
+			}
+			return;
+		}
+		try {
+			if (c >= 1) {
+				lp.doUnload();
+			}
+			lp.doLoad();
+			goto xxx;
+		} catch (exception& ex) {
+			cb(nullptr, &ex);
+		}
+	}
+	String loadStaticPage(cppspManager* mgr, String path) {
+		return mgr->loadStaticPage(path);
+	}
+	vector<string>& CXXOpts(cppspManager* mgr) {
+		return mgr->cxxopts;
+	}
+	cppspManager* cppspManager_new() {
+		return new cppspManager();
+	}
+	void setThreadID(cppspManager* mgr, int tid) {
+		mgr->threadID = tid;
+	}
+	void loadPage(cppspManager* mgr, CP::Poll& p, String wd, String path, RGC::Allocator* a,
+			Delegate<void(Page*, exception* ex)> cb) {
+		return mgr->loadPage(p, wd, path, a, cb);
+	}
+	void cppspManager_delete(cppspManager* mgr) {
+		delete mgr;
+	}
+	void updateTime(cppspManager* mgr) {
+		clock_gettime(CLOCK_MONOTONIC, &mgr->curTime);
+		clock_gettime(CLOCK_REALTIME, &mgr->curClockTime);
+		tm time;
+		gmtime_r(&mgr->curClockTime.tv_sec, &time);
+		mgr->curRFCTime.len = rfctime(time, mgr->curRFCTime.d);
+	}
+	
+	void loadModule(cppspManager* mgr, CP::Poll& p, Server* srv, String wd, String path,
+			Delegate<void(void*, exception* ex)> cb) {
+		mgr->loadModule(p, srv, wd, path, cb);
+	}
+	
+	void handleError(exception* ex, cppsp::Response& resp, String path) {
+		resp.clear();
+		resp.statusCode = 500;
+		resp.statusName = "Internal server error";
+		resp.headers["Content-Type"] = "text/html; charset=UTF-8";
+		//resp.writeHeaders();
+		string title = "Server error in " + path.toSTDString();
+		resp.output.writeF("<html><head><title>%s</title>"
+				"<style></style></head>", title.c_str());
+		resp.output.writeF("<body><h1 style=\"color: #aa1111\">%s</h1><hr />"
+				"<h2 style=\"color: #444\">%s</h2>", title.c_str(), ex->what());
+		cppsp::CompileException* ce = dynamic_cast<cppsp::CompileException*>(ex);
+		if (ce != NULL) {
+			resp.output.write("<pre style=\"color: #000; background: #ffc; padding: 8px;\">");
+			htmlEscape(String(ce->compilerOutput), resp.output);
+			resp.output.write("</pre>");
+		}
+		resp.output.writeF("</body></html>");
+	}
+}

+ 103 - 0
cpoll_cppsp/cppsp_rel0.2.3/cppsp/cppsp_cpoll.C

@@ -0,0 +1,103 @@
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * */
+/*
+ * cppsp_socketd.C
+ *
+ *  Created on: Mar 8, 2013
+ *      Author: xaxaxa
+ */
+#include "include/cppsp_cpoll.H"
+#include <stdio.h>
+#include <unistd.h>
+#include "include/stringutils.H"
+using namespace CP;
+namespace cppsp
+{
+	//static int CPollRequest::bufSize=4096;
+	CPollRequest::CPollRequest(CP::Socket& s, CP::StringPool* sp) :
+			Request(s, sp), _parser(&headers), s(s) {
+		_stream.parser = &_parser;
+		_stream.stream = &s;
+		_stream.stream->retain();
+		this->inputStream = &_stream;
+	}
+	bool CPollRequest_parseReqLine(CPollRequest* This) {
+		uint8_t* lineBuf = (uint8_t*) This->_parser.reqLine.data();
+		int lineBufLen = This->_parser.reqLine.length();
+		uint8_t* tmp = (uint8_t*) memchr(lineBuf, ' ', lineBufLen);
+		if (tmp == NULL) return false;
+		This->method = {(char*) lineBuf, int(tmp - lineBuf)};
+		tmp++;
+		if (lineBuf + lineBufLen - tmp <= 0) return false;
+		uint8_t* tmp1 = (uint8_t*) memchr(tmp, ' ', lineBuf + lineBufLen - tmp);
+		if (tmp1 == NULL) return false;
+		const char* path = (const char*) tmp;
+		int pathLen = tmp1 - tmp;
+		if (pathLen <= 0) return false;
+
+		const char* q = (const char*) memchr(path, '?', pathLen);
+		if (q == NULL) This->path = {path, pathLen};
+		else {
+			struct
+			{
+				CPollRequest* This;
+				void operator()(const char* name, int nameLen, const char* value, int valueLen) {
+					String n, v;
+					n=cppsp::urlDecode(name, nameLen, *This->sp);
+					if (value != NULL) {
+						v=cppsp::urlDecode(value, valueLen, *This->sp);
+					} else v= {(char*)nullptr,0};
+					This->queryString[n] = v;
+				}
+			}cb {This};
+			cppsp::parseQueryString(q + 1, path + pathLen - q - 1, &cb, false);
+			This->path = {path, q - path};
+		}
+		return true;
+	}
+	bool CPollRequest::readRequest(const Delegate<void(bool)>& cb) {
+		if (_parser.process()) {
+			if (CPollRequest_parseReqLine(this)) return true;
+			else {
+				cb(false);
+				return false;
+			}
+		} else {
+			this->tmp_cb = cb;
+			_parser.reset();
+			_beginRead();
+			return false;
+		}
+	}
+	void CPollRequest::_beginRead() {
+		String b = _parser.beginPutData(4096);
+		_stream.stream->read(b.data(), b.length(), { &CPollRequest::_readCB, this });
+	}
+	void CPollRequest::_readCB(int i) {
+		if (i <= 0) {
+			tmp_cb(false);
+			return;
+		}
+		_parser.endPutData(i);
+		if (_parser.process()) {
+			tmp_cb(CPollRequest_parseReqLine(this));
+		} else {
+			_beginRead();
+		}
+	}
+	CPollRequest::~CPollRequest() {
+		_stream.stream->release();
+	}
+}

+ 31 - 0
cpoll_cppsp/cppsp_rel0.2.3/cppsp/include/bitap.H

@@ -0,0 +1,31 @@
+#ifndef BITAP_H_
+#define BITAP_H_
+#include <string.h>
+#include <limits.h>
+
+inline void *bitap_bitwise_search(const void *text, int textLen, const void *pattern, int patternLen) {
+	int m = patternLen;
+	unsigned long R;
+	unsigned long pattern_mask[CHAR_MAX + 1];
+	int i;
+
+	if (m > 31) return NULL;
+	/* Initialize the bit array R */
+	R = ~1;
+
+	/* Initialize the pattern bitmasks */
+	for (i = 0; i <= CHAR_MAX; ++i)
+		pattern_mask[i] = ~0;
+	for (i = 0; i < m; ++i)
+		pattern_mask[int(((char*) pattern)[i])] &= ~(1UL << i);
+
+	for (i = 0; i < textLen; ++i) {
+		/* Update the bit array */
+		R |= pattern_mask[int(((char*) text)[i])];
+		R <<= 1;
+		if (0 == (R & (1UL << m))) return ((char*) text + i - m) + 1;
+	}
+	return NULL;
+}
+
+#endif /* BITAP_H_ */

+ 241 - 0
cpoll_cppsp/cppsp_rel0.2.3/cppsp/include/common.H

@@ -0,0 +1,241 @@
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * */
+/*
+ * common.H
+ *
+ *  Created on: Apr 6, 2013
+ *      Author: xaxaxa
+ */
+
+#ifndef CPPSP_COMMON_H_
+#define CPPSP_COMMON_H_
+#include <cpoll/cpoll.H>
+#include <vector>
+#include <unordered_map>
+#include "page.H"
+using namespace std;
+typedef CP::String String;
+namespace cppsp
+{
+	extern const char* gxx;
+	class ParserException: public std::exception
+	{
+	public:
+		string message;
+		int32_t number;
+		ParserException();
+		ParserException(int32_t number);
+		ParserException(string message, int32_t number = 0);
+		~ParserException() throw ();
+		const char* what() const throw ();
+	};
+	class CompileException: public std::exception
+	{
+	public:
+		string message;
+		string compilerOutput;
+		CompileException();
+		CompileException(string message);
+		~CompileException() throw ();
+		const char* what() const throw ();
+	};
+	/**
+	 Internal API.
+	 */
+	class loadedPage
+	{
+	public:
+		Server* srv;
+		loadedPage& operator=(const loadedPage& other) = delete;
+		timespec lastLoad { 0, 0 }; //CLOCK_REALTIME
+		timespec lastCheck { 0, 0 }; //CLOCK_MONOTONIC
+		void* dlHandle;
+		const uint8_t* stringTable;
+		int stringTableLen;
+		typedef int (*getObjectSize_t)();
+		typedef Page* (*createObject_t)(void* mem);
+		typedef Page* (*createObject1_t)(RGC::Allocator* alloc);
+		typedef void (*initModule_t)(Server* s);
+		typedef void (*deinitModule_t)();
+		int (*getObjectSize)();
+		createObject_t createObject;
+		createObject1_t createObject1;
+		RGC::Ref<CP::File> compile_fd;
+		CP::MemoryStream ms;
+		//Delegate<void(loadedPage&)> compileCB;
+		struct _loadCB
+		{
+			RGC::Allocator* alloc;
+			//void* parameter is either the constructed page (if doCreate is true), or
+			//the dlopen()ed handle
+			Delegate<void(void*, exception* ex)> cb;
+			bool doCreate;
+			void operator()(loadedPage* This, exception* ex);
+		};
+		vector<_loadCB> loadCB;
+		string path;
+		string cPath;
+		string txtPath;
+		string dllPath;
+		int stringTableFD;
+		pid_t compilerPID;
+		bool loaded;
+		bool compiling;
+		void readCB(int r);
+		void deleteTmpfiles();
+		void afterCompile(bool success);
+		void beginRead();
+		void doCompile(CP::Poll& p, string wd, const vector<string>& cxxopts);
+		void doLoad();
+		void doUnload();
+		Page* doCreate(RGC::Allocator* a);
+		loadedPage();
+		~loadedPage();
+		//returns: 0: no-op; 1: should reload; 2: should recompile
+		int shouldCompile();
+	};
+	/**
+	 Internal API.
+	 */
+	struct staticPage
+	{
+		String data;
+		timespec lastLoad { 0, 0 }; //CLOCK_REALTIME
+		timespec lastCheck { 0, 0 }; //CLOCK_MONOTONIC
+		timespec lastUse; //CLOCK_MONOTONIC
+		string path;
+		bool loaded;
+		void doLoad();
+		void doUnload();
+		bool shouldReload();
+		staticPage();
+		~staticPage();
+	};
+	/**
+	 Internal API.
+	 */
+	class cppspManager
+	{
+	public:
+		CP::StringPool sp;
+		unordered_map<String, loadedPage*> cache;
+
+		unordered_map<String, staticPage*> staticCache;
+		vector<string> cxxopts;
+		timespec curTime { 0, 0 };
+		timespec curClockTime { 0, 0 }; //CLOCK_REALTIME
+		String curRFCTime;
+		int threadID;
+		cppspManager();
+		~cppspManager();
+		void loadPage(CP::Poll& p, String wd, String path, RGC::Allocator* a,
+				Delegate<void(Page*, exception* ex)> cb);
+		void loadModule(CP::Poll& p, Server* srv, String wd, String path,
+				Delegate<void(void*, exception* ex)> cb);
+		String loadStaticPage(String path);
+		bool shouldCheck(loadedPage& p);
+		bool shouldCheck(staticPage& p);
+	};
+
+	/**
+	 Internal function. Parses a .cppsp page.
+	 @unmaintained_api
+	 */
+	void doParse(const char* name, const char* in, int inLen, CP::Stream& out, CP::Stream& st_out,
+			vector<string>& c_opts);
+	/**
+	 Internal function. Compiles a .cppsp page.
+	 @return file descriptor connected to the standard output of the compiler.
+	 @unmaintained_api
+	 */
+	CP::File* compilePage(string wd, string path, const vector<string>& cxxopts, pid_t& pid);
+	/**
+	 Combine two paths. Result is stored in buf. Does not write a null byte.
+	 The memory block pointed to by buf must be at least l1 + l2 bytes.
+	 @return the length of the string written to buf
+	 */
+	int combinePath(const char* p1, int l1, const char* p2, int l2, char* buf);
+	/**
+	 Combine two paths. Result is stored in buf. Does not write a null byte.
+	 The memory block pointed to by buf must be at least strlen(p1) + strlen(p2) bytes.
+	 @return the length of the string written to buf
+	 */
+	int combinePath(const char* p1, const char* p2, char* buf);
+	/**
+	 Combine two paths securely. The resulting path is guaranteed to be under p1. (The user can not use ".." to leave the root directory)
+	 The memory block pointed to by buf must be at least l1 + l2 bytes.
+	 @return the length of the string written to buf
+	 */
+	int combinePathChroot(const char* p1, int l1, const char* p2, int l2, char* buf);
+	/**
+	 Combine two paths securely. The resulting path is guaranteed to be under p1. (The user can not use ".." to leave the root directory)
+	 The memory block pointed to by buf must be at least strlen(p1) + strlen(p2) bytes.
+	 @return the length of the string written to buf
+	 */
+	int combinePathChroot(const char* p1, const char* p2, char* buf);
+	/**
+	 Combine two paths. Result is allocated from sp.
+	 @return the resulting path
+	 */
+	String combinePath(String p1, String p2, CP::StringPool& sp);
+	/**
+	 Combine two paths securely. The resulting path is guaranteed to be under p1. (The user can not use ".." to leave the root directory)
+	 @return the resulting path
+	 */
+	String combinePathChroot(String p1, String p2, CP::StringPool& sp);
+	/**
+	 Internal function.
+	 @unmaintained_api
+	 */
+	cppspManager* cppspManager_new();
+	/**
+	 Internal function.
+	 @unmaintained_api
+	 */
+	void cppspManager_delete(cppspManager* mgr);
+	/**
+	 Internal function.
+	 @unmaintained_api
+	 */
+	void loadPage(cppspManager* mgr, CP::Poll& p, String wd, String path, RGC::Allocator* a,
+			Delegate<void(Page*, exception* ex)> cb);
+	/**
+	 Internal function.
+	 @unmaintained_api
+	 */
+	void loadModule(cppspManager* mgr, CP::Poll& p, Server* srv, String wd, String path,
+			Delegate<void(void*, exception* ex)> cb);
+	/**
+	 Internal function.
+	 @unmaintained_api
+	 */
+	String loadStaticPage(cppspManager* mgr, String path);
+	/**
+	 Internal function.
+	 @unmaintained_api
+	 */
+	vector<string>& CXXOpts(cppspManager* mgr);
+	/**
+	 Internal function.
+	 @unmaintained_api
+	 */
+	void updateTime(cppspManager* mgr);
+	/**
+	 Internal function.
+	 @unmaintained_api
+	 */
+	void handleError(exception* ex, cppsp::Response& resp, String path);
+}
+#endif /* COMMON_H_ */

+ 55 - 0
cpoll_cppsp/cppsp_rel0.2.3/cppsp/include/cppsp_cpoll.H

@@ -0,0 +1,55 @@
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * */
+/*
+ * cppsp_socketd.H
+ *
+ *  Created on: Mar 8, 2013
+ *      Author: xaxaxa
+ */
+
+#ifndef CPPSP_SOCKETD_H_
+#define CPPSP_SOCKETD_H_
+#include "page.H"
+#include <cpoll/cpoll.H>
+#include <string>
+#include "httpparser.H"
+using namespace std;
+typedef CP::String String;
+namespace cppsp
+{
+	class CPollRequest: public Request
+	{
+	public:
+		HTTPParser _parser;
+		HTTPStream _stream;
+		RGC::Ref<CP::Socket> s;
+		Delegate<void(bool)> tmp_cb;
+		int _headers_begin;
+		bool firstLine;
+
+		CPollRequest(CP::Socket& s, CP::StringPool* sp);
+		//returns: true: request already in buffer; false: read is in progress
+		bool readRequest(const Delegate<void(bool success)>& cb);
+		void readPost(Delegate<void(Request&)> cb) override {
+			parsePost(_parser.content);
+			cb(*this);
+		}
+		void _beginRead();
+		void _readCB(int i);
+		virtual ~CPollRequest();
+	};
+} /* namespace cppsp */
+
+#endif /* CPPSP_SOCKETD_H_ */

+ 233 - 0
cpoll_cppsp/cppsp_rel0.2.3/cppsp/include/headercontainer.H

@@ -0,0 +1,233 @@
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * */
+/*
+ * headerContainer.H
+ *
+ *  Created on: Apr 28, 2013
+ *      Author: xaxaxa
+ */
+
+#ifndef HEADERCONTAINER_H_
+#define HEADERCONTAINER_H_
+#include <ctype.h>
+#include <sys/types.h>
+#include <algorithm>
+#include "stringutils.H"
+namespace cppsp
+{
+	typedef CP::String String;
+#ifndef __CPPSP_TOLOWER
+#define __CPPSP_TOLOWER
+	static inline char tolower(char c) {
+		if (c <= 'Z' && c >= 'A') c = c - 'A' + 'a';
+		return c;
+	}
+#endif
+	struct Header
+	{
+		String name;
+		String value;
+	};
+	//sorted
+	struct headerContainer
+	{
+		RGC::Allocator* a;
+		struct item
+		{
+			const char* name;
+			const char* value;
+			int nameLength;
+			int valueLength;
+			String n() {
+				return {name,nameLength};
+			}
+			String v() {
+				return {value,valueLength};
+			}
+		};
+		static bool compareItem(const item& i1, const item& i2) {
+			return ci_compare( { i1.name, i1.nameLength }, { i2.name, i2.nameLength }) < 0;
+		}
+		struct iterator
+		{
+			headerContainer* c;
+			item* i;
+			void operator+=(int i) {
+				this->i += i;
+				if (this->i >= (c->items + c->length)) this->i = NULL;
+			}
+			void operator++(int) {
+				operator+=(1);
+			}
+			bool operator==(const iterator& other) {
+				return i == other.i;
+			}
+			bool operator!=(const iterator& other) {
+				return !operator==(other);
+			}
+			Header operator*() {
+				item& it = *i;
+				return { {it.name,it.nameLength}, {it.value,it.valueLength}};
+			}
+			item& get() {
+				return *i;
+			}
+		};
+		item* items;
+		int length;
+		headerContainer(RGC::Allocator* a) :
+				a(a), items(NULL), length(0) {
+		}
+		item* beginReplace(int length) {
+			items = (item*) a->alloc(length * sizeof(item));
+			this->length = length;
+			return items;
+		}
+		void endReplace() {
+			std::sort(items, items + length, compareItem);
+		}
+		String operator[](String name) const {
+			item it { name.data(), NULL, name.length(), 0 };
+			item* tmp = std::lower_bound(items, items + length, it, compareItem);
+			if (tmp != NULL && (tmp - items) < length && ci_compare(tmp->n(), name) == 0) return tmp->v();
+			return {(char*)nullptr,0};
+		}
+		iterator find(String name) {
+			item it { name.data(), NULL, name.length(), 0 };
+			item* tmp = std::lower_bound(items, items + length, it, compareItem);
+			if (tmp != NULL && (tmp - items) < length && ci_compare(tmp->n(), name) == 0) return {this,tmp};
+			return end();
+		}
+		iterator begin() {
+			return {this,items};
+		}
+		iterator end() {
+			return {this,NULL};
+		}
+		void clear() {
+			items = NULL;
+			length = 0;
+		}
+
+	};
+	//not sorted; for response headers
+	struct headerContainer2
+	{
+		CP::StringPool* sp;
+		struct item
+		{
+			const char* name;
+			const char* value;
+			int nameLength;
+			int valueLength;
+		};
+		static const int bucketSize = 8;
+		struct bucket
+		{
+			bucket* next;
+			item items[bucketSize];
+			int length;
+		};
+		struct iterator
+		{
+			bucket* b;
+			int i;
+			void operator+=(int i) {
+				this->i += i;
+				while (this->i > bucketSize && b != NULL) {
+					b = b->next;
+					this->i -= bucketSize;
+				}
+				if (b != NULL && this->i >= b->length) b = NULL;
+			}
+			void operator++(int) {
+				operator+=(1);
+			}
+			bool operator==(const iterator& other) {
+				if (b == NULL && other.b == NULL) return true;
+				return b == other.b && i == other.i;
+			}
+			bool operator!=(const iterator& other) {
+				return !operator==(other);
+			}
+			Header operator*() {
+				item& it = b->items[i];
+				return { {it.name,it.nameLength}, {it.value,it.valueLength}};
+			}
+			item& get() {
+				return b->items[i];
+			}
+		};
+		bucket* _first = NULL;
+		bucket* _last = NULL;
+		headerContainer2(CP::StringPool* sp) :
+				sp(sp) {
+		}
+		void add(item it) {
+			if (_last == NULL || _last->length >= bucketSize) addBucket();
+			_last->items[_last->length] = it;
+			_last->length++;
+		}
+		void add(String name, String value) {
+			add( { name.data(), value.data(), name.length(), value.length() });
+		}
+		void addCopy(String name, String value) {
+			name = sp->addString(name);
+			value = sp->addString(value);
+			add( { name.data(), value.data(), name.length(), value.length() });
+		}
+		void addBucket() {
+			bucket* b = (bucket*) sp->add(sizeof(bucket));
+			b->next = NULL;
+			b->length = 0;
+			if (_last != NULL) _last->next = b;
+			_last = b;
+			if (_first == NULL) _first = b;
+		}
+		String operator[](String name) {
+			for (bucket* b = _first; b != NULL; b = b->next) {
+				for (int i = 0; i < b->length; i++)
+					if (ci_compare(name, { b->items[i].name, b->items[i].nameLength }) == 0) return {b->items[i].value,b->items[i].valueLength};
+			}
+			return {(char*)nullptr,0};
+		}
+		iterator find(String name) {
+			for (bucket* b = _first; b != NULL; b = b->next) {
+				for (int i = 0; i < b->length; i++)
+					if (ci_compare(name, { b->items[i].name, b->items[i].nameLength }) == 0) return {b,i};
+			}
+			return end();
+		}
+		void set(String name, String value) {
+			iterator it = find(name);
+			if (it == end()) add(name, value);
+			else {
+				it.get().value = value.data();
+				it.get().valueLength = value.length();
+			}
+		}
+		iterator begin() {
+			return {_first,0};
+		}
+		iterator end() {
+			return {NULL,0};
+		}
+		void clear() {
+			_first = _last = NULL;
+		}
+	};
+}
+
+#endif /* HEADERCONTAINER_H_ */

+ 252 - 0
cpoll_cppsp/cppsp_rel0.2.3/cppsp/include/httpparser.H

@@ -0,0 +1,252 @@
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * */
+/*
+ * httpparser.H
+ *
+ *  Created on: Apr 28, 2013
+ *      Author: xaxaxa
+ */
+
+#ifndef HTTPPARSER_H_
+#define HTTPPARSER_H_
+
+#include <cpoll/cpoll.H>
+#include "headercontainer.H"
+
+#define CPPSP_MAXHEADERS 32
+namespace cppsp
+{
+	using namespace CP;
+	struct HTTPParser: public virtual RGC::Object
+	{
+		static inline char tolower(char c) {
+			if (c <= 'Z' && c >= 'A') c = c - 'A' + 'a';
+			return c;
+		}
+		//s2 must be all lowercase!!!!!
+		static bool ci_equals(String s1, String s2) {
+			if (s1.length() != s2.length()) return false;
+			if (s1.length() == 0) return true;
+			for (int i = 0; i < s1.length(); i++) {
+				if (tolower(s1.data()[i]) != s2.data()[i]) return false;
+			}
+			return true;
+		}
+
+		headerContainer* hc;
+		MemoryStream ms;
+		String content;
+		String reqLine;
+		Delegate<bool()> state;
+		int pos;
+		int rpos;
+		int _ctLen;
+		int reqLine_i;
+		int headerpos[CPPSP_MAXHEADERS];
+		int headercount = 0;
+		bool firstLine = true;
+		HTTPParser(headerContainer* hc) :
+				hc(hc), ms(8192), pos(0), rpos(0), _ctLen(0) {
+			state= {&HTTPParser::_process_readingHeaders,this};
+		}
+		String beginPutData(int len) {
+			if (ms.bufferSize - ms.bufferPos < len) ms.flushBuffer(len);
+			return {(char*)ms.buffer + ms.bufferPos,ms.bufferSize-ms.bufferPos};
+		}
+		void endPutData(int len) {
+			ms.bufferPos += len;
+			ms.flush();
+		}
+
+		static inline char* findCRLF(const void* s, int len) {
+			char* tmp = (char*) memchr(s, '\r', len);
+			if (unlikely(tmp == NULL || tmp >= ((char*) s + len))) return NULL;
+			if (tmp[1] == '\n') return tmp;
+			else return (char*) memmem(tmp + 1, (char*) s + len - tmp - 1, "\r\n", 2);
+		}
+		bool _process_readingHeaders() {
+			uint8_t* buf = ms.data();
+			aaaaa: void* tmp = findCRLF(buf + rpos, ms.length() - rpos);
+			if (tmp == NULL) {
+				//minus one to catch any delimiters that might be cut off
+				//in the middle
+				if (rpos < ms.length() - 1) rpos = ms.length() - 1;
+				return false;
+			}
+			int newpos = ((uint8_t*) tmp) - buf;
+			//line: (buf+pos, newpos-pos)
+			uint8_t* lineBuf = buf + pos;
+			int lineBufLen = newpos - pos;
+
+			if (firstLine) {
+				reqLine.len = newpos - pos;
+				reqLine_i = pos;
+				firstLine = false;
+			} else {
+				if (lineBufLen == 0) {
+					auto* items=hc->beginReplace(headercount);
+					for(int i=0;i<headercount;i++) {
+						int pos1=headerpos[i];
+						int end=(i+1<headercount?headerpos[i+1]:this->pos)-2;
+						lineBuf=buf+pos1;
+						lineBufLen=end-pos1;
+						tmp = memchr(lineBuf, ':', lineBufLen);
+						if (tmp == NULL) {
+							*(items++)= {(char*)lineBuf,(char*)NULL,lineBufLen,0};
+						} else {
+							headerContainer::item it;
+							uint8_t* tmp1 = (uint8_t*) tmp - 1;
+							while (tmp1 >= lineBuf && *tmp1 == ' ') tmp1--;
+							it.name = (char*)lineBuf;
+							it.nameLength = (int) (tmp1 - lineBuf + 1);
+							tmp1 = (uint8_t*) tmp + 1;
+							while (tmp1 < (buf + newpos) && *tmp1 == ' ') tmp1++;
+							it.value = (char*)tmp1;
+							it.valueLength = (int) (lineBuf + lineBufLen - tmp1);
+
+							if (_ctLen == 0
+									&& ci_equals( {(char*) lineBuf, it.nameLength}, "content-length")) {
+								_ctLen = atoi( {(char*) tmp1, it.valueLength});
+							}
+							*(items++)=it;
+						}
+					}
+					hc->endReplace();
+					rpos = pos = newpos + 2;
+					state = {&HTTPParser::_process_readingContent,this};
+					return _process_readingContent();
+				}
+				if(headercount>=CPPSP_MAXHEADERS) goto skipheader;
+				headerpos[headercount++]=pos;
+				skipheader:;
+			}
+			rpos = pos = newpos + 2;
+			goto aaaaa;
+		}
+		bool _process_readingContent() {
+			uint8_t* buf = ms.data();
+			if (ms.length() - pos < _ctLen) return false;
+			content= {(char*)buf+pos,_ctLen};
+			pos += _ctLen;
+			rpos = pos;
+			_ctLen = 0;
+			state = {&HTTPParser::_process_readingHeaders,this};
+			firstLine = true;
+			headercount=0;
+			reqLine.d = (char*) buf + reqLine_i;
+			return true;
+		}
+		//returns whether or not a complete http request was found
+		//headers will be added to *hc, and content will be set to point
+		//to any content received
+		//note: *hc may be modified even when it returns false
+		inline bool process() {
+			if (pos >= ms.length()) return false;
+			return state();
+		}
+		inline String getBufferData() {
+			return {(char*)ms.buffer + pos, ms.length() - pos};
+		}
+		inline String getHistory(bool includeUnprocessed = true) {
+			return {(char*)ms.buffer, includeUnprocessed ? ms.length() : pos};
+		}
+		void skip(int length) {
+			pos+=length;
+			if(rpos<pos)rpos=pos;
+		}
+
+		//free up buffer space
+		void reset() {
+			if (pos > 0) {
+				int shift=firstLine?pos:reqLine_i;
+				if (ms.length() - shift > 0) memmove(ms.buffer, ms.buffer + shift, ms.length() - shift);
+				ms.len -= shift;
+				rpos -= shift;
+				pos -= shift;
+				ms.bufferPos = ms.len;
+			}
+		}
+	};
+	class HTTPStream: public CP::Stream
+	{
+	public:
+		HTTPParser* parser;
+		Stream* stream;
+		int32_t tryFixRead(void* buf, int32_t len) {
+			int& bufPos = parser->pos;
+			int bufLen = parser->ms.length();
+			if (bufPos >= bufLen) return -1;
+			int32_t l = len > (bufLen - bufPos) ? (bufLen - bufPos) : len;
+			if (l <= 0) return 0;
+			memcpy(buf, parser->ms.buffer + bufPos, l);
+			bufPos += l;
+			if (parser->rpos < bufPos) parser->rpos = bufPos;
+			return l;
+		}
+		int32_t read(void* buf, int32_t len) {
+			int32_t r;
+			if ((r = tryFixRead(buf, len)) == -1) return stream->read(buf, len);
+			else return r;
+		}
+		int32_t write(const void* buf, int32_t len) {
+			return stream->write(buf, len);
+		}
+		void read(void* buf, int32_t len, const Callback& cb, bool repeat = false) {
+			int32_t r;
+			if ((r = tryFixRead(buf, len)) == -1) stream->read(buf, len, cb, repeat);
+			else {
+				cb(r);
+				if (repeat && r > 0) stream->read(buf, len, cb, true);
+			}
+		}
+		void write(const void* buf, int32_t len, const Callback& cb, bool repeat = false) override {
+			stream->write(buf, len, cb, repeat);
+		}
+		//sync
+		void close() override {
+		}
+		void flush() override {
+			stream->flush();
+		}
+
+		//async
+		void close(const Callback& cb) override {
+		}
+		void flush(const Callback& cb) override {
+			stream->flush(cb);
+		}
+		void cancelRead() override {
+			stream->cancelRead();
+		}
+		void cancelWrite() override {
+			stream->cancelWrite();
+		}
+		int32_t readBuffer(void*& buf, int32_t maxlen) override {
+			int& bufPos = parser->pos;
+			int bufLen = parser->ms.length();
+			if (bufPos >= bufLen) return 0;
+			if (bufLen - bufPos < maxlen) maxlen = bufLen - bufPos;
+			buf = parser->ms.buffer + bufPos;
+			return maxlen;
+		}
+		void freeBuffer(void* buf, int32_t len) override {
+			int& bufPos = parser->pos;
+			bufPos += len;
+			if (parser->rpos < bufPos) parser->rpos = bufPos;
+		}
+	};
+}
+
+#endif /* HTTPPARSER_H_ */

+ 262 - 0
cpoll_cppsp/cppsp_rel0.2.3/cppsp/include/mountpointmgr.H

@@ -0,0 +1,262 @@
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * */
+/*
+ * mountpointmgr.H
+ *
+ *  Created on: May 1, 2013
+ *      Author: xaxaxa
+ */
+
+#ifndef MOUNTPOINTMGR_H_
+#define MOUNTPOINTMGR_H_
+#include <map>
+#include <cpoll/cpoll.H>
+#include <rgc.H>
+#include "split.H"
+using namespace CP;
+using namespace RGC;
+using namespace std;
+namespace cppsp
+{
+	template<class T> struct less;
+	template<>
+	struct less<String> : binary_function<String, String, bool>
+	{
+		bool operator()(const String& x, const String& y) const {
+			if (x.len == 0 || y.len == 0) return x.len < y.len;
+			int complen = x.len < y.len ? x.len : y.len;
+			int tmp = memcmp(x.d, y.d, complen);
+			if (tmp == 0) return x.len < y.len;
+			else return tmp < 0;
+		}
+	};
+#if false
+	class MountPointMgr
+	{
+	public:
+		map<String, Object*, cppsp::less<String> > items;
+
+		Object* _find(String path) {
+			auto it = items.upper_bound(path);
+			if (it == items.end() && items.begin() == items.end()) return nullptr;
+			it--;
+			if (it == items.end()) return nullptr;
+			if ((*it).first.len > path.len) return nullptr;
+			int complen = (*it).first.len < path.len ? (*it).first.len : path.len;
+			if (memcmp((*it).first.d, path.d, complen) == 0) return (*it).second;
+			return nullptr;
+		}
+		Object* find(String path) {
+			if (path.len > 0 && path.d[path.len - 1] == '/') {
+				return _find(path);
+			} else {
+				char tmp[path.len + 1];
+				memcpy(tmp, path.d, path.len);
+				tmp[path.len] = '/';
+				return _find( {tmp, path.len + 1});
+			}
+		}
+		bool mount(String path, Object* handler) {
+			String tmp;
+			if (path.len > 0 && path.d[path.len - 1] == '/') {
+				tmp.len = path.len;
+				tmp.d = (char*) malloc(tmp.len + 1); //insert null byte just in case
+				memcpy(tmp.d, path.d, tmp.len);
+				tmp.d[tmp.len] = '\0';
+			} else {
+				tmp.len = path.len + 1;
+				tmp.d = (char*) malloc(tmp.len + 1);
+				memcpy(tmp.d, path.d, path.len);
+				tmp.d[path.len] = '/';
+				tmp.d[tmp.len] = '\0';
+			}
+			auto it = items.find(tmp);
+			if (it == items.end()) {
+				items.insert( {tmp, handler});
+				return true;
+			} else {
+				free(tmp.d);
+				return false;
+			}
+		}
+		Object* umount(String path) {
+			String tmp;
+			if (path.len > 0 && path.d[path.len - 1] == '/') {
+				tmp.d = nullptr;
+			} else {
+				tmp.len = path.len + 1;
+				tmp.d = (char*) malloc(tmp.len + 1);
+				memcpy(tmp.d, path.d, path.len);
+				tmp.d[path.len] = '/';
+				tmp.d[tmp.len] = '\0';
+			}
+			auto it = items.find(tmp.d == nullptr ? path : tmp);
+			Object* o;
+			if (it != items.end()) {
+				o = (*it).second;
+				free((*it).first.d);
+				items.erase(it);
+			} else {
+				o = nullptr;
+			}
+			if (tmp.d != nullptr) free(tmp.d);
+			return o;
+		}
+		MountPointMgr() {
+
+		}
+		virtual ~MountPointMgr() {
+
+		}
+	};
+#endif
+	class MountPointMgr
+	{
+	public:
+		struct dirent
+		{
+			Object* obj;
+			void* children;
+			dirent() :
+					obj(nullptr), children(nullptr) {
+			}
+		};
+		typedef map<String, dirent, cppsp::less<String> > Map;
+		dirent root;
+
+		Object* find(String path) {
+			split spl(path.d, path.len, '/');
+			dirent* curr = &root;
+			Object* o = root.obj;
+			while (spl.read()) {
+				if (spl.value.len <= 0) goto aaaaa;
+				{
+					//printf("spl.value=(len=%i) %s\n", spl.value.len, spl.value.toSTDString().c_str());
+					if (curr->children == nullptr) {
+						//printf("curr->children==NULL\n");
+						break;
+					}
+					Map* m = (Map*) curr->children;
+					auto it = m->find(spl.value);
+					if (it == m->end()) {
+						//printf("it == m->end(); spl.value=%s\n", spl.value.toSTDString().c_str());
+						break;
+					}
+					curr = &(*it).second;
+					if (curr->obj != NULL) o = curr->obj;
+				}
+				aaaaa: ;
+			}
+			return o;
+		}
+		bool mount(String path, Object* handler) {
+			split spl(path.d, path.len, '/');
+			dirent* curr = &root;
+			while (spl.read()) {
+				if (spl.value.len <= 0) goto aaaaa;
+				{
+					//printf("spl.value=(len=%i) %s\n", spl.value.len, spl.value.toSTDString().c_str());
+					Map* m;
+					if (curr->children == nullptr) {
+						curr->children = m = new Map();
+					} else {
+						m = (Map*) curr->children;
+					}
+					auto it = m->find(spl.value);
+					if (it == m->end()) {
+						String s;
+						s.d = (char*) malloc((s.len = spl.value.len));
+						memcpy(s.d, spl.value.d, s.len);
+						curr = &(*m)[s];
+					} else curr = &(*it).second;
+				}
+				aaaaa: ;
+			}
+			if (curr->obj == nullptr) {
+				curr->obj = handler;
+				return true;
+			}
+			return false;
+		}
+		Object* umount(String path) {
+			split spl(path.d, path.len, '/');
+			dirent* curr = &root;
+			while (spl.read()) {
+				if (spl.value.len <= 0) goto aaaaa;
+				{
+					Map* m;
+					if (curr->children == nullptr) {
+						return nullptr;
+					} else {
+						m = (Map*) curr->children;
+					}
+					auto it = m->find(spl.value);
+					if (it == m->end()) {
+						return nullptr;
+					} else curr = &(*it).second;
+				}
+				aaaaa: ;
+			}
+			Object* o = curr->obj;
+			curr->obj = NULL;
+			return o;
+		}
+		template<class SW>
+		void print(SW& sw, dirent* d, string s = "/", int l = 0) {
+			char tmp[l + 1];
+			memset(tmp, ' ', l);
+			tmp[l] = 0;
+			if (d->obj != NULL) sw.writeF("%s%s\n", (char*) tmp, s.c_str());
+			if (d->children == nullptr) {
+				return;
+			} else {
+				Map* m = (Map*) d->children;
+				for (auto it = m->begin(); it != m->end(); it++) {
+					print(sw, &(*it).second, s + (*it).first.toSTDString() + "/", l + 1);
+				}
+			}
+		}
+		template<class SW>
+		void print(SW& sw) {
+			print(sw, &root);
+		}
+		void clear(dirent* d) {
+			if (d->obj != nullptr) {
+				d->obj->destruct();
+				d->obj = nullptr;
+			}
+			if (d->children != nullptr) {
+				Map* m = (Map*) d->children;
+				for (auto it = m->begin(); it != m->end(); it++) {
+					clear(&(*it).second);
+					String s = (*it).first;
+					free(s.d);
+				}
+				delete m;
+				d->children = nullptr;
+			}
+		}
+		void clear() {
+			clear(&root);
+		}
+		MountPointMgr() {
+
+		}
+		virtual ~MountPointMgr() {
+			clear();
+		}
+	};
+} /* namespace cppsp */
+#endif /* MOUNTPOINTMGR_H_ */

+ 403 - 0
cpoll_cppsp/cppsp_rel0.2.3/cppsp/include/page.H

@@ -0,0 +1,403 @@
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * */
+/*
+ * page.H
+ *
+ *  Created on: Jan 26, 2013
+ *      Author: xaxaxa
+ */
+
+#ifndef PAGE_H_
+#define PAGE_H_
+#include <rgc.H>
+#include <map>
+#include <cpoll/cpoll.H>
+#include "stringutils.H"
+#include "headercontainer.H"
+using namespace std;
+namespace cppsp
+{
+	class cppspManager;
+	typedef CP::String String;
+	/**
+	 Represents an HTTP request and contains data from the request such as HTTP headers, querystrings, and HTTP POST data.
+	 */
+	class Request: public RGC::Object
+	{
+	public:
+		Request(CP::Stream& inp, CP::StringPool* sp);
+		virtual ~Request() {
+		}
+		/**
+		 internal field do not use.
+		 */
+		RGC::Ref<CP::Stream> inputStream;
+		/**
+		 The per-request StringPool instance. You can allocate memory from this if it only need to persist for the duration of this http request. The StringPool is cleared after the page has finished executing.
+		 */
+		CP::StringPool* sp; //may be used to store headers, querystrings, and POST data
+		typedef map<String, String, less<String>, CP::PoolAllocator<std::pair<const String, String> > > StringMap;
+		CP::PoolAllocator<std::pair<const String, String> > alloc;
+		/**
+		 HTTP request headers.
+		 */
+		headerContainer headers;
+		/**
+		 Query strings.
+		 */
+		StringMap queryString;
+		/**
+		 POST data.
+		 */
+		StringMap form;
+		/**
+		 HTTP method (GET, POST, etc).
+		 */
+		String method;
+		/**
+		 HTTP request path (directly from the HTTP header; not file path; does not include querystrings).
+		 */
+		String path;
+		//string httpVersion;
+
+		/**
+		 You don't need to call this manually; POST data is automatically read for all HTTP POST requests.
+		 */
+		virtual void readPost(Delegate<void(Request&)> cb)=0;
+		/**
+		 internal method do not use.
+		 */
+		void parsePost(String buf);
+		/**
+		 internal method do not use.
+		 */
+		virtual void reset();
+	};
+	/**
+	 Represents an HTTP response.
+	 */
+	class Response: public RGC::Object
+	{
+	public:
+		typedef Delegate<void(Response&)> Callback;
+		Response(CP::Stream& out, CP::StringPool* sp);
+		/**
+		 internal field do not use.
+		 */
+		RGC::Ref<CP::Stream> outputStream;
+		/**
+		 internal field do not use.
+		 */
+		CP::MemoryStream buffer;
+		/**
+		 You can write data to the HTTP response body by writing to "output". Content-Length will be automatically calculated.
+		 */
+		CP::StreamWriter output;
+		/**
+		 internal field do not use.
+		 */
+		Callback _cb;
+		/**
+		 The per-request StringPool instance. You can allocate memory from this if it only need to persist for the duration of this http request. The StringPool is cleared after the page has finished executing.
+		 */
+		CP::StringPool* sp;
+		//headerContainer2 headers;
+		CP::PoolAllocator<std::pair<const String, String> > alloc;
+		typedef map<String, String, less<String>, CP::PoolAllocator<std::pair<const String, String> > > StringMap;
+		/**
+		 HTTP response headers.
+		 */
+		StringMap headers;
+		/**
+		 HTTP response status (OK, Internal Server Error, etc).
+		 */
+		String statusName;
+		/**
+		 internal field do not use.
+		 */
+		iovec iov[2];
+		/**
+		 HTTP response status code (200, 500, etc).
+		 */
+		int statusCode;
+
+		/**
+		 internal field do not use.
+		 */
+		bool headersWritten;
+		/**
+		 internal field do not use.
+		 */
+		bool closed;
+		/**
+		 TODO: chunked output not yet implemented.
+		 */
+		bool sendChunked;
+		/*virtual void doWriteHeaders();
+		 void writeHeaders() {
+		 if (!headersWritten) {
+		 doWriteHeaders();
+		 headersWritten = true;
+		 }
+		 }*/
+		/**
+		 internal method do not use.
+		 */
+		virtual void flush(Callback cb);
+		/**
+		 clear buffered output
+		 */
+		virtual void clear();
+		/**
+		 internal method do not use.
+		 */
+		void addDefaultHeaders();
+		/**
+		 Serialize the HTTP response headers.
+		 */
+		void serializeHeaders(CP::StreamWriter& sw);
+		/**
+		 Write data to the HTTP response body.
+		 */
+		template<class ... T>
+		void write(T&&... a) {
+			output.write(std::forward<T>(a)...);
+		}
+		/**
+		 internal method do not use.
+		 */
+		void _writeCB(int r);
+		/**
+		 internal method do not use.
+		 */
+		virtual void reset();
+	};
+	class Page;
+	/**
+	 Represents a cppsp web server instance.
+	 */
+	class Server: public RGC::Object
+	{
+	public:
+		Server();
+		/**
+		 The handle request callback. It is called for every request right after reading in all the request data and instantiating the Request and Response objects.
+		 You can override the behavior of the web server by attaching (from within a cppsp module). See the example .cppsm modules in /www (included with the cppsp source).
+		 */
+		DelegateChain<void(Request&, Response&, Delegate<void()>)> handleRequest;
+		/**
+		 Load static file from "path" and serve it to the specified response. path is relative to server root.
+		 */
+		virtual void handleStaticRequest(String path, Request& req, Response& resp,
+				Delegate<void()> cb)=0;
+		/**
+		 Load dynamic page from "path" and serve it to the specified response. path is relative to server root.
+		 */
+		virtual void handleDynamicRequest(String path, Request& req, Response& resp,
+				Delegate<void()> cb)=0;
+		/**
+		 default request router.
+		 */
+		void defaultHandleRequest(Request& req, Response& resp, Delegate<void()> cb);
+		/**
+		 Returns absolute path of server root directory.
+		 */
+		virtual String rootDir()=0;
+		/**
+		 Load and instantiate dynamic page from "path". path is relative to server root.
+		 */
+		virtual void loadPage(CP::Poll& p, String path, RGC::Allocator& a,
+				Delegate<void(Page*, exception* ex)> cb)=0;
+		/**
+		 Load and instantiate dynamic page from "path". path is absolute.
+		 */
+		virtual void loadPageFromFile(CP::Poll& p, String path, RGC::Allocator& a,
+				Delegate<void(Page*, exception* ex)> cb)=0;
+
+		/**
+		 Load cppsp module from "path". path is relative to server root.
+		 */
+		virtual void loadModule(CP::Poll& p, String path, Delegate<void(void*, exception* ex)> cb)=0;
+		/**
+		 Load cppsp module from "path". path is absolute.
+		 */
+		virtual void loadModuleFromFile(CP::Poll& p, String path,
+				Delegate<void(void*, exception* ex)> cb)=0;
+		/**
+		 Load static page from "path". path is relative to server root.
+		 */
+		virtual String loadStaticPage(String path)=0;
+		/**
+		 Load static page from "path". path is absolute.
+		 */
+		virtual String loadStaticPageFromFile(String path)=0;
+		/**
+		 Given a path relative to the server root, returns the absolute path.
+		 */
+		virtual string mapPath(string path);
+		/**
+		 Given a path relative to the server root, returns the absolute path. The returned string is allocated from "a".
+		 */
+		virtual String mapPath(String path, RGC::Allocator& a);
+		/**
+		 Returns the cppspManager instance for this Server instance; may be NULL if the underlying server does not use cppspManager.
+		 */
+		virtual cppspManager* manager() {
+			return NULL;
+		}
+	};
+	/**
+	 Base class for all cppsp pages.
+	 */
+	class Page: public RGC::Object
+	{
+	public:
+		typedef Delegate<void()> Callback;
+		Page(Request& req, Response& resp, CP::StringPool* sp);
+		/**
+		 Object representing the HTTP request.
+		 */
+		RGC::Ref<Request> request;
+		/**
+		 Object representing the HTTP response.
+		 */
+		RGC::Ref<Response> response;
+		/**
+		 internal field do not use.
+		 */
+		Delegate<void(Page*, exception* ex)> pageCB;
+		/**
+		 Poll instance for the current thread. Can be used for asynchronous I/O, timers, etc.
+		 */
+		CP::Poll* poll;
+		/**
+		 The current Server instance. Usually there is one Server instance for every thread.
+		 */
+		Server* server;
+		/**
+		 internal field do not use.
+		 */
+		Callback cb;
+		/**
+		 Absolute path of the current cppsp page.
+		 */
+		String filePath;
+		/**
+		 The per-request StringPool instance. You can allocate memory from this if it only need to persist for the duration of this http request. The StringPool is cleared after the page has finished executing.
+		 */
+		CP::StringPool* sp;
+		bool doRender;
+		bool doReadPost;
+		Page() :
+				doRender(true) {
+		}
+		inline void cancelRender() {
+			doRender = false;
+		}
+		/**
+		 internal field do not use. Pointer to mmap()ed address of the string table file.
+		 */
+		const uint8_t* __stringTable;
+		/**
+		 internal method do not use.
+		 */
+		void __writeStringTable(int i, int len);
+		/**
+		 Given a path relative to the current page, returns the absolute path. The returned string is allocated from the request-wide StringPool and is invalid after the page finishes executing.
+		 */
+		String mapPath(String path);
+		/**
+		 Given a path relative to the current page, returns the absolute path. The returned string is allocated from "a".
+		 */
+		String mapPath(String path, RGC::Allocator& a);
+		/**
+		 Given a path relative to the current page, returns the path relative to the server root. The returned string is allocated from the request-wide StringPool and is invalid after the page finishes executing.
+		 */
+		String mapRelativePath(String path);
+		/**
+		 Given a path relative to the current page, returns the path relative to the server root. The returned string is allocated from "a".
+		 */
+		String mapRelativePath(String path, RGC::Allocator& a);
+		/**
+		 Load and instantiate dynamic page from "path". path is relative to the current page.
+		 */
+		void loadNestedPage(String path, Delegate<void(Page*, exception* ex)> cb);
+		/**
+		 Load and instantiate dynamic page from "path". path is relative to the current page. Returned Page object is allocated from "a".
+		 */
+		void loadNestedPage(String path, Delegate<void(Page*, exception* ex)> cb, RGC::Allocator& a);
+		/**
+		 Load and instantiate dynamic page from "path". path is absolute.
+		 */
+		void loadNestedPageFromFile(String path, Delegate<void(Page*, exception* ex)> cb);
+		/**
+		 Load and instantiate dynamic page from "path". path is absolute. Returned Page object is allocated from "a".
+		 */
+		void loadNestedPageFromFile(String path, Delegate<void(Page*, exception* ex)> cb,
+				RGC::Allocator& a);
+		/**
+		 Called by the web server immediately after instantiating the current page. The page calls "cb" when it is done processing, to signal the web server that it can clean up the StringPool and all request-related data. The object pointed to by fields "request" and "response" may be recycled.
+		 */
+		virtual void handleRequest(Callback cb = nullptr);
+		virtual void processRequest() {
+			doInit();
+		}
+		/**
+		 Each page goes through these stages (in order): init, [readPost], load, render, flush, finalize, [web server callback], ~Page
+
+		 To be overridden by base class; called before load() is called, and must call initCB() or cancelLoad() after it's done
+		 */
+		virtual void init() {
+
+		}
+		virtual void doInit();
+		virtual void initCB();
+		virtual void cancelLoad(exception* ex = NULL);
+		/**
+		 To be overridden by derived class; called before headers are written. See init() for a description of the request life-cycle.
+		 */
+		virtual void load() {
+		}
+		virtual void render(CP::StreamWriter& out);
+		/**
+		 Called after rendering. See init() for a description of the request life-cycle.
+		 */
+		virtual void flush();
+		/**
+		 Called by flush() after it is done writing. See init() for a description of the request life-cycle.
+		 */
+		virtual void flushCB() {
+			finalize();
+		}
+		/**
+		 Called after flush() is done. See init() for a description of the request life-cycle.
+		 */
+		virtual void finalize() {
+			finalizeCB();
+		}
+		/**
+		 Called by finalize() after it is done doing its work. This will call the web server's callback and cause it to clean-up and re-cycle the Request and Response objects, and destroy the Page object. See init() for a description of the request life-cycle.
+		 */
+		virtual void finalizeCB();
+		virtual ~Page() {
+		}
+
+		void _readPOSTCB(Request& r);
+		void _flushCB(Response& r);
+		void _pageCB(Page* p, exception* ex);
+	};
+
+} /* namespace cppsp */
+#endif /* PAGE_H_ */

+ 56 - 0
cpoll_cppsp/cppsp_rel0.2.3/cppsp/include/split.H

@@ -0,0 +1,56 @@
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * */
+/*
+ * split.H
+ *
+ *  Created on: May 1, 2013
+ *      Author: xaxaxa
+ */
+
+#ifndef SPLIT_H_
+#define SPLIT_H_
+#include <cpoll/basictypes.H>
+namespace cppsp
+{
+	struct split
+	{
+		const char* s;
+		const char* end;
+		const char* s1;
+		CP::String value;
+		char delim;
+		split(const char* s, int len, char delim) {
+			if (len == -1) len = strlen(s);
+			this->s = s;
+			this->s1 = s;
+			this->end = s + len;
+			this->delim = delim;
+		}
+		bool read() {
+			if (s == nullptr) return false;
+			s = (const char*) memchr(s, delim, end - s);
+			if (s == nullptr) {
+				value= {s1, int(end - s1)};
+				return true;
+			}
+			value= {s1, int(s - s1)};
+			s1 = ++s;
+			return true;
+		}
+	};
+}
+
+
+#endif /* SPLIT_H_ */

+ 106 - 0
cpoll_cppsp/cppsp_rel0.2.3/cppsp/include/stringutils.H

@@ -0,0 +1,106 @@
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * */
+/*
+ * stringutils.H
+ *
+ *  Created on: Apr 9, 2013
+ *      Author: xaxaxa
+ */
+
+#ifndef URLPARSER_H_
+#define URLPARSER_H_
+#include <cpoll/cpoll.H>
+#include <string>
+namespace cppsp
+{
+#ifndef __CPPSP_TOLOWER
+#define __CPPSP_TOLOWER
+	static inline char tolower(char c) {
+		if (c <= 'Z' && c >= 'A') c = c - 'A' + 'a';
+		return c;
+	}
+#endif
+	struct ci_less: std::binary_function<std::string, std::string, bool>
+	{
+		// case-independent (ci) compare_less binary function
+		struct nocase_compare: public std::binary_function<unsigned char, unsigned char, bool>
+		{
+			bool operator()(const unsigned char& c1, const unsigned char& c2) const {
+				return tolower(c1) < tolower(c2);
+			}
+		};
+		bool operator()(const std::string & s1, const std::string & s2) const {
+			return std::lexicographical_compare(s1.begin(), s1.end(), // source range
+					s2.begin(), s2.end(), // dest range
+					nocase_compare()); // comparison
+		}
+	};
+
+	void urlDecode(const char* in, int inLen, CP::StreamWriter& sw);
+	static inline void urlDecode(CP::String in, CP::StreamWriter& sw) {
+		urlDecode(in.data(), in.length(), sw);
+	}
+	CP::String urlDecode(const char* in, int inLen, CP::StringPool& sp);
+	void urlEncode(const char* in, int inLen, CP::StreamWriter& sw);
+	static inline void urlEncode(CP::String in, CP::StreamWriter& sw) {
+		urlEncode(in.data(), in.length(), sw);
+	}
+	std::string urlDecode(const char* in, int inLen);
+	std::string urlEncode(const char* in, int inLen);
+	static inline std::string urlDecode(const char* in) {
+		return urlDecode(in, strlen(in));
+	}
+	static inline std::string urlEncode(const char* in) {
+		return urlEncode(in, strlen(in));
+	}
+	static inline std::string urlDecode(std::string in) {
+		return urlDecode(in.data(), in.length());
+	}
+	static inline std::string urlEncode(std::string in) {
+		return urlEncode(in.data(), in.length());
+	}
+
+	typedef Delegate<void(const char* name, int nameLen, const char* value, int valueLen)> queryStringCallback;
+	void parseQueryString(const char* in, int inLen, queryStringCallback cb, bool decode = true);
+
+	void htmlEscape(const char* in, int inLen, CP::StreamWriter& sw);
+	static inline void htmlEscape(CP::String in, CP::StreamWriter& sw) {
+		htmlEscape(in.data(), in.length(), sw);
+	}
+	std::string htmlEscape(const char* in, int inLen);
+	static inline std::string htmlEscape(const char* in) {
+		return htmlEscape(in, strlen(in));
+	}
+	static inline std::string htmlEscape(std::string in) {
+		return htmlEscape(in.data(), in.length());
+	}
+
+	void htmlAttributeEscape(const char* in, int inLen, CP::StreamWriter& sw);
+	static inline void htmlAttributeEscape(CP::String in, CP::StreamWriter& sw) {
+		htmlAttributeEscape(in.data(), in.length(), sw);
+	}
+	std::string htmlAttributeEscape(const char* in, int inLen);
+	static inline std::string htmlAttributeEscape(const char* in) {
+		return htmlAttributeEscape(in, strlen(in));
+	}
+	static inline std::string htmlAttributeEscape(std::string in) {
+		return htmlAttributeEscape(in.data(), in.length());
+	}
+
+	int ci_compare(CP::String s1, CP::String s2);
+	int rfctime(const tm& time, char* c);
+}
+
+#endif /* URLPARSER_H_ */

+ 230 - 0
cpoll_cppsp/cppsp_rel0.2.3/cppsp/include/websocket.H

@@ -0,0 +1,230 @@
+#include <cpoll/cpoll.H>
+#include <rgc.H>
+using namespace CP;
+using namespace RGC;
+namespace cppsp
+{
+	struct WebSocketParser
+	{
+		struct ws_header1
+		{
+			//char flags:8;
+			unsigned int opcode :4;
+			bool rsv1 :1;
+			bool rsv2 :1;
+			bool rsv3 :1;
+			bool fin :1;
+
+			unsigned int payload_len :7;
+			bool mask :1;
+		}__attribute__((packed));
+		struct ws_footer1
+		{
+			uint32_t masking_key;
+		}__attribute__((packed));
+
+		struct ws_header_extended16
+		{
+			uint16_t payload_len;
+		}__attribute__((packed));
+
+		struct ws_header_extended64
+		{
+			uint64_t payload_len;
+		}__attribute__((packed));
+
+		struct WSFrame
+		{
+			String data;
+			char opcode;
+			bool fin;
+		};
+
+		MemoryStream ms;
+		int pos = 0;
+		String beginPutData(int len) {
+			if (ms.bufferSize - ms.bufferPos < len) ms.flushBuffer(len);
+			return {(char*)ms.buffer + ms.bufferPos,ms.bufferSize-ms.bufferPos};
+		}
+		void endPutData(int len) {
+			ms.bufferPos += len;
+			ms.flush();
+		}
+		void skip(int length) {
+			pos += length;
+		}
+
+		inline void unmask(String data, uint32_t key) {
+			/*uint32_t* d = (uint32_t*) data.data();
+			 int len = data.length() / sizeof(*d);
+			 for (int i = 0; i < len; i++) {
+			 d[i] ^= key;
+			 }
+			 uint8_t* tmp = (uint8_t*) (d + len);
+			 uint8_t* tmp1 = (uint8_t*) &key;
+			 int leftover = data.length() % sizeof(*d);
+			 if (leftover > 0) tmp[0] ^= tmp1[0];
+			 if (leftover > 1) tmp[1] ^= tmp1[1];
+			 if (leftover > 2) tmp[2] ^= tmp1[2];
+			 if (leftover > 3) tmp[3] ^= tmp1[3];*/
+			uint8_t* k = (uint8_t*) &key;
+			for (int i = 0; i < data.length(); i++) {
+				data.d[i] = data.d[i] ^ k[i % sizeof(key)];
+			}
+		}
+		bool process(WSFrame& out) {
+			char* data = (char*) ms.data() + pos;
+			int len = ms.length() - pos;
+			int minLen = sizeof(ws_header1);
+			if (len < minLen) return false;
+			ws_header1* h1 = (ws_header1*) data;
+			uint8_t pLen1 = h1->payload_len; // & ~(uint8_t) 128;
+			//printf("pLen1 = %i\n", pLen1);
+			int pLen2 = 0;
+			if (pLen1 == 126) pLen2 = 2;
+			if (pLen1 == 127) pLen2 = 8;
+			minLen += pLen2;
+			if (h1->mask) minLen += 4;
+			if (len < minLen) return false;
+			//printf("len = %i\n", len);
+			//printf("minLen = %i\n", minLen);
+			uint64_t payloadLen;
+
+			switch (pLen1) {
+				case 126:
+				{
+					ws_header_extended16* h2 = (ws_header_extended16*) (h1 + 1);
+					payloadLen = ntohs(h2->payload_len);
+					break;
+				}
+				case 127:
+				{
+					ws_header_extended64* h2 = (ws_header_extended64*) (h1 + 1);
+					payloadLen = ntohll(h2->payload_len);
+					break;
+				}
+				default:
+					payloadLen = pLen1;
+					break;
+			}
+			//printf("payloadLen = %lli\n", payloadLen);
+			if (len < int(minLen + payloadLen)) return false;
+			char* payload = data + minLen;
+			out.data= {payload,(int)payloadLen};
+			out.fin = h1->fin;
+			out.opcode = h1->opcode;
+			pos += minLen + (int) payloadLen;
+			if (h1->mask) unmask( { payload, (int) payloadLen },
+					((ws_footer1*) ((char*) (h1 + 1) + pLen2))->masking_key);
+			return true;
+		}
+
+		//free up buffer space
+		void reset() {
+			if (pos > 0) {
+				int shift = pos;
+				if (ms.length() - shift > 0) memmove(ms.buffer, ms.buffer + shift, ms.length() - shift);
+				ms.len -= shift;
+				pos -= shift;
+				ms.bufferPos = ms.len;
+			}
+		}
+
+	};
+	class FrameWriter
+	{
+	public:
+		MemoryStream ms1, ms2;
+		Ref<Stream> output;
+		vector<String> queue;
+		struct queueItem
+		{
+			int next; //is actually a pointer, but relative to the base of the array (MemoryStream)
+			int len;
+			char data[0];
+		};
+		int _first = -1, _last = -1, _count = 0;
+		bool use_ms2 = false;
+		bool _append;
+		bool closed = false;
+		bool writeQueued = false;
+		inline MemoryStream& ms() {
+			return use_ms2 ? ms2 : ms1;
+		}
+		inline queueItem& _item(int i) {
+			return *(queueItem*) (ms().data() + i);
+		}
+		/**
+		 Prepare for the insertion of a chunk into the queue;
+		 @param append whether to append to the queue or insert at the beginning
+		 @return the allocated buffer space; may be larger than the requested length
+		 You must not call beginInsert again before calling endInsert.
+		 */
+		String beginInsert(int len, bool append = true) {
+			_append = append;
+			String tmp = ms().beginAppend(len + sizeof(queueItem));
+			return tmp.subString(sizeof(queueItem));
+		}
+		/**
+		 Complete the insertion of a chunk.
+		 */
+		void endInsert(int len) {
+			//printf("endInsert: len=%i\n",len);
+			int tmp = ms().length();
+			ms().endAppend(len + sizeof(queueItem));
+			if (_append) {
+				_item(tmp).next = -1;
+				if (_last >= 0) _item(_last).next = tmp;
+				_last = tmp;
+				if (_first < 0) _first = tmp;
+			} else {
+				_item(tmp).next = _first;
+				_first = tmp;
+				if (_last < 0) _last = tmp;
+			}
+			_item(tmp).len = len;
+			++_count;
+		}
+		bool writing = false;
+		void flush() {
+			beginFlush();
+		}
+		void beginFlush() {
+			if (writing) {
+				writeQueued = true;
+				return;
+			}
+			if (ms().length() <= 0 || _count <= 0) return;
+			writing = true;
+			int iovcnt = 0;
+			iovec* iov = (iovec*) ms().beginAppend(sizeof(iovec) * _count).data();
+			ms().endAppend(sizeof(iovec) * _count);
+
+			for (int i = _first; i >= 0; i = _item(i).next) {
+				iov[iovcnt++]= {_item(i).data,(size_t)_item(i).len};
+				//printf("id=%i iovcnt=%i len=%i\n",i,iovcnt,_item(i).len);
+			}
+			use_ms2 = !use_ms2;
+			_first = _last = -1;
+			_count = 0;
+			output->writevAll(iov, iovcnt, { &FrameWriter::_writevCB, this });
+		}
+		void _writevCB(int i) {
+			writing = false;
+			if (i <= 0) {
+				closed = true;
+				return;
+			}
+			if (writeQueued) {
+				writeQueued = false;
+				beginFlush();
+			}
+		}
+	};
+	String ws_beginWriteFrame(FrameWriter& fw, int len);
+	void ws_endWriteFrame(FrameWriter& fw, String buf, int opcode);
+	struct Page;
+	struct Request;
+	void ws_init(Page& p, CP::Callback cb);
+	bool ws_iswebsocket(const cppsp::Request& req);
+}

+ 297 - 0
cpoll_cppsp/cppsp_rel0.2.3/cppsp/page.C

@@ -0,0 +1,297 @@
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * */
+/*
+ * page.C
+ *
+ *  Created on: Jan 26, 2013
+ *      Author: xaxaxa
+ */
+
+#include "include/page.H"
+#include "include/common.H"
+#include <stdexcept>
+#include <stdlib.h>
+#include <math.h>
+
+using namespace CP;
+namespace cppsp
+{
+	static inline int itoa(int i, char* b) {
+		static char const digit[] = "0123456789";
+		char* p = b;
+		//negative detection is not needed for this specific use-case
+		//(writing the content-length header)
+		/*if (i < 0) {
+		 *p++ = '-';
+		 i = -i;
+		 }*/
+		p += (i==0?0:int(log10f(i))) + 1;
+		*p = '\0';
+		int l = p - b;
+		do { //Move back, inserting digits as u go
+			*--p = digit[i % 10];
+			i = i / 10;
+		} while (i);
+		return l;
+	}
+	//inline-able memcpy() for copying SHORT STRINGS ONLY
+	static inline void memcpy2_1(void* dst, const void* src, int len) {
+		for (int i = 0; i < len; i++)
+			((char*) dst)[i] = ((const char*) src)[i];
+	}
+	Page::Page(Request& req, Response& resp, CP::StringPool* sp) :
+			request(&req), response(&resp), sp(sp), doRender(true) {
+	}
+	void Page::__writeStringTable(int i, int len) {
+		response->output.write(__stringTable + i, len);
+	}
+	void Page::handleRequest(Callback cb) {
+		this->cb = cb;
+		try {
+			processRequest();
+		} catch (exception& ex) {
+			handleError(&ex, *response, this->filePath);
+			flush();
+		}
+	}
+	void Page::render(CP::StreamWriter& out) {
+		out.write("This is the default page of the cppsp C++ "
+				"web application framework. If you see this, it means "
+				"you haven't overridden the render() method derived from cppsp::Page.");
+	}
+	void Page::doInit() {
+		doReadPost = false;
+		init();
+		if (doReadPost && request->method.compare("POST") == 0) request->readPost( {
+				&Page::_readPOSTCB, this });
+		else initCB();
+	}
+	void Page::initCB() {
+		try {
+			load();
+			//response->writeHeaders();
+			if (doRender) render(response->output);
+			flush();
+		} catch (exception& ex) {
+			handleError(&ex, *response, this->filePath);
+			flush();
+		}
+	}
+	void Page::cancelLoad(exception* ex) {
+		if (ex == NULL) {
+			runtime_error re("Web page execution cancelled");
+			handleError(&re, *response, this->filePath);
+		} else handleError(ex, *response, this->filePath);
+		response->flush( { &Page::_flushCB, this });
+	}
+	void Page::_readPOSTCB(Request& r) {
+		initCB();
+	}
+	void Page::flush() {
+		if (response->closed) finalizeCB();
+		else response->flush( { &Page::_flushCB, this });
+	}
+	String Page::mapPath(String path) {
+		return server->mapPath(mapRelativePath(path), *sp);
+	}
+	String Page::mapPath(String path, RGC::Allocator& a) {
+		return server->mapPath(mapRelativePath(path, a), a);
+	}
+	String Page::mapRelativePath(String path) {
+		return mapRelativePath(path, *sp);
+	}
+	String Page::mapRelativePath(String path, RGC::Allocator& a) {
+		char *tmp = (char*) a.alloc(request->path.length() + path.length());
+		int l = combinePath(request->path.data(), request->path.length(), path.data(), path.length(),
+				tmp);
+		return {tmp,l};
+	}
+	void Page::loadNestedPage(String path, Delegate<void(Page*, exception* ex)> cb) {
+		loadNestedPage(path, cb, *sp);
+	}
+	void Page::loadNestedPage(String path, Delegate<void(Page*, exception* ex)> cb,
+			RGC::Allocator& a) {
+		this->pageCB = cb;
+		String tmp = mapRelativePath(path, a);
+		server->loadPage(*poll, { tmp.data(), (int) tmp.length() }, a, { &Page::_pageCB, this });
+	}
+	void Page::loadNestedPageFromFile(String path, Delegate<void(Page*, exception* ex)> cb) {
+		loadNestedPageFromFile(path, cb, *sp);
+	}
+	void Page::loadNestedPageFromFile(String path, Delegate<void(Page*, exception* ex)> cb,
+			RGC::Allocator& a) {
+		this->pageCB = cb;
+		server->loadPageFromFile(*poll, { path.data(), (int) path.length() }, a, { &Page::_pageCB,
+				this });
+	}
+	
+	void Page::_pageCB(Page* p, exception* ex) {
+		if (p != NULL) {
+			p->request = request;
+			p->response = response;
+			p->poll = poll;
+			p->server = server;
+		}
+		pageCB(p, ex);
+	}
+	void Page::_flushCB(Response& r) {
+		flushCB();
+	}
+	void Page::finalizeCB() {
+		if (this->cb != nullptr) cb();
+	}
+
+	Request::Request(CP::Stream& inp, CP::StringPool* sp) :
+			inputStream(&inp), sp(sp), alloc(sp), headers(sp), queryString(less<String>(), alloc),
+					form(less<String>(), alloc) {
+	}
+	void Request::parsePost(String buf) {
+		struct
+		{
+			Request* This;
+			void operator()(const char* name, int nameLen, const char* value, int valueLen) {
+				String n, v;
+				n = cppsp::urlDecode(name, nameLen, *This->sp);
+				if (value != NULL) {
+					v = cppsp::urlDecode(value, valueLen, *This->sp);
+				} else v= {(char*)nullptr,0};
+				This->form[n] = v;
+			}
+		} cb { this };
+		cppsp::parseQueryString(buf.data(), buf.length(), &cb, false);
+	}
+
+	Response::Response(CP::Stream& out, CP::StringPool* sp) :
+			outputStream(&out), output((CP::BufferedOutput&) buffer), sp(sp), alloc(sp),
+					headers(less<String>(), alloc), headersWritten(false), closed(false),
+					sendChunked(false) {
+		addDefaultHeaders();
+	}
+	void Response::addDefaultHeaders() {
+		statusCode = 200;
+		statusName = "OK";
+		headers.insert( { "Content-Type", "text/html; charset=UTF-8" });
+	}
+	void Response_doWriteHeaders(Response* This, CP::StreamWriter& sw) {
+		//sw.writeF("HTTP/1.1 %i %s\r\n", This->statusCode, This->statusName);
+		{
+			char* s1 = sw.beginWrite(32);
+			memcpy2_1(s1, "HTTP/1.1 ", 9);
+			int x = 9 + itoa(This->statusCode, s1 + 9);
+			s1[x] = ' ';
+			x++;
+			memcpy2_1(s1 + x, This->statusName.data(), This->statusName.length());
+			x += This->statusName.length();
+			s1[x] = '\r';
+			s1[x + 1] = '\n';
+			x += 2;
+			sw.endWrite(x);
+		}
+		for (auto it = This->headers.begin(); it != This->headers.end(); it++) {
+			int l1 = (*it).first.length();
+			int l2 = (*it).second.length();
+			char* tmp = sw.beginWrite(l1 + 4 + l2);
+			memcpy2_1(tmp, (*it).first.data(), l1);
+			tmp[l1] = ':';
+			tmp[l1 + 1] = ' ';
+			memcpy2_1(tmp + l1 + 2, (*it).second.data(), l2);
+			tmp[l1 + 2 + l2] = '\r';
+			tmp[l1 + 2 + l2 + 1] = '\n';
+			sw.endWrite(l1 + 4 + l2);
+			//sw.writeF("%s: %s\r\n", (*it).first.c_str(), (*it).second.c_str());
+		}
+		sw.write("\r\n", 2);
+	}
+	void Response::serializeHeaders(CP::StreamWriter& sw) {
+		Response_doWriteHeaders(this, sw);
+	}
+	void Response::flush(Callback cb) {
+		//printf("flush\n");
+		if (closed) throw runtime_error("connection has already been closed by the client");
+		output.flush();
+		this->_cb = cb;
+		if (likely(!headersWritten)) {
+			headersWritten = true;
+			int bufferL = buffer.length();
+			{
+				char* tmps = sp->beginAdd(16);
+				int l = itoa(buffer.length(), tmps);
+				sp->endAdd(l);
+				this->headers.insert( { "Content-Length", { tmps, l } });
+				CP::StreamWriter sw(buffer);
+				Response_doWriteHeaders(this, sw);
+			}
+			iov[0]= {buffer.data()+bufferL, (size_t)(buffer.length()-bufferL)};
+			iov[1]= {buffer.data(), (size_t)bufferL};
+			outputStream->writevAll(iov, 2, { &Response::_writeCB, this });
+			return;
+		} else {
+			if (buffer.length() <= 0) {
+				cb(*this);
+				return;
+			}
+			outputStream->write(buffer.data(), buffer.length(), { &Response::_writeCB, this });
+		}
+	}
+	void Response::clear() {
+		output.flush();
+		buffer.clear();
+		headersWritten = false;
+	}
+	void Response::_writeCB(int r) {
+		if (r <= 0) closed = true;
+		buffer.clear();
+		_cb(*this);
+	}
+	
+	void Request::reset() {
+		headers.clear();
+		queryString.clear();
+		form.clear();
+	}
+	void Response::reset() {
+		headers.clear();
+		addDefaultHeaders();
+		output.flush();
+		buffer.clear();
+		headersWritten = false;
+		closed = false;
+		sendChunked = false;
+	}
+
+	Server::Server() {
+		handleRequest.attach( { &Server::defaultHandleRequest, this });
+	}
+	void Server::defaultHandleRequest(Request& req, Response& resp, Delegate<void()> cb) {
+		if (req.path.length() > 6
+				&& memcmp(req.path.data() + (req.path.length() - 6), ".cppsp", 6) == 0) handleDynamicRequest(
+				req.path, req, resp, cb);
+		else handleStaticRequest(req.path, req, resp, cb);
+	}
+	String Server::mapPath(String path, RGC::Allocator& a) {
+		String r = rootDir();
+		char* tmp = (char*) a.alloc(path.length() + r.length());
+		int l = cppsp::combinePathChroot(r.data(), r.length(), path.data(), path.length(), tmp);
+		return String(tmp, l);
+	}
+
+} /* namespace cppsp */
+
+string cppsp::Server::mapPath(string path) {
+	String r = rootDir();
+	char tmp[path.length() + r.length()];
+	int l = cppsp::combinePathChroot(r.data(), r.length(), path.data(), path.length(), tmp);
+	return string(tmp, l);
+}

+ 323 - 0
cpoll_cppsp/cppsp_rel0.2.3/cppsp/stringutils.C

@@ -0,0 +1,323 @@
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * */
+/*
+ * stringutils.C
+ *
+ *  Created on: Apr 9, 2013
+ *      Author: xaxaxa
+ */
+#include <cpoll/cpoll.H>
+#include "include/stringutils.H"
+#include "include/split.H"
+using namespace CP;
+namespace cppsp
+{
+	inline char hexCharToInt(char ch) {
+		if (ch <= '9') return ch - '0';
+		else if (ch <= 'Z') return ch - 'A' + 10;
+		else return ch - 'a' + 10;
+	}
+	inline char intToHexChar(char i) {
+		if (i < 10) return i + '0';
+		else return i - 10 + 'A';
+	}
+	void urlDecode(const char* in, int inLen, StreamWriter& sw) {
+		const char* end = in + inLen;
+		const char* ptr = in;
+		while (true) {
+			if (ptr >= end) goto E;
+			const char* next = (const char*) memchr(ptr, '%', end - ptr);
+			if (next == NULL) break;
+			sw.write(ptr, next - ptr);
+			if (next + 2 >= end) {
+				sw.write(next, end - next);
+				goto E;
+			}
+			char tmp = hexCharToInt(next[1]) << 4 | hexCharToInt(next[2]);
+			sw.write(tmp);
+			ptr = next + 3;
+		}
+		if (ptr < end) sw.write(ptr, end - ptr);
+		E: ;
+	}
+	String urlDecode(const char* in, int inLen, StringPool& sp) {
+		char* ch = sp.beginAdd(inLen); //output size will never exceed input size
+		char* c = ch;
+		const char* end = in + inLen;
+		const char* ptr = in;
+		while (true) {
+			if (ptr >= end) goto E;
+			const char* next = (const char*) memchr(ptr, '%', end - ptr);
+			if (next == NULL) break;
+			memcpy(c, ptr, next - ptr);
+			c += (next - ptr);
+			if (next + 2 >= end) {
+				memcpy(c, next, end - next);
+				c += (end - next);
+				goto E;
+			}
+			*c = hexCharToInt(next[1]) << 4 | hexCharToInt(next[2]);
+			c++;
+			ptr = next + 3;
+		}
+		if (ptr < end) {
+			memcpy(c, ptr, end - ptr);
+			c += (end - ptr);
+		}
+		sp.endAdd(c - ch);
+		return {ch,c-ch};
+		E: ;
+		return {(char*)nullptr,0};
+	}
+	void urlEncode(const char* in, int inLen, CP::StreamWriter& sw) {
+		int last_i = 0;
+		const char* c = in;
+		char ch[3];
+		ch[0] = '%';
+		for (int i = 0; i < inLen; i++) {
+			if ((48 <= c[i] && c[i] <= 57) || //0-9
+					(65 <= c[i] && c[i] <= 90) || //abc...xyz
+					(97 <= c[i] && c[i] <= 122) || //ABC...XYZ
+					(c[i] == '~' || c[i] == '!' || c[i] == '*' || c[i] == '(' || c[i] == ')'
+							|| c[i] == '\'')) continue;
+			if (i > last_i) sw.write(in + last_i, i - last_i);
+			last_i = i + 1;
+			ch[1] = intToHexChar(c[i] >> 4);
+			ch[2] = intToHexChar(c[i] & (char) 0xF);
+			sw.write(ch, 3);
+		}
+		if (inLen > last_i) sw.write(in + last_i, inLen - last_i);
+	}
+	std::string urlDecode(const char* in, int inLen) {
+		StringStream ss;
+		{
+			StreamWriter sw(ss);
+			urlDecode(in, inLen, sw);
+		}
+		return ss.str();
+	}
+	std::string urlEncode(const char* in, int inLen) {
+		StringStream ss;
+		{
+			StreamWriter sw(ss);
+			urlEncode(in, inLen, sw);
+		}
+		return ss.str();
+	}
+	std::string htmlEscape(const char* in, int inLen) {
+		StringStream ss;
+		{
+			StreamWriter sw(ss);
+			htmlEscape(in, inLen, sw);
+		}
+		return ss.str();
+	}
+	std::string htmlAttributeEscape(const char* in, int inLen) {
+		StringStream ss;
+		{
+			StreamWriter sw(ss);
+			htmlAttributeEscape(in, inLen, sw);
+		}
+		return ss.str();
+	}
+	void parseQueryString(const char* in, int inLen, queryStringCallback cb, bool decode) {
+		if (decode) {
+			MemoryStream ms;
+			StreamWriter sw(ms);
+			split spl(in, inLen, '&');
+			while (spl.read()) {
+				const char* s = spl.value.d;
+				int l = spl.value.len;
+				const char* _end = s + l;
+				const char* tmp = (const char*) memchr(s, '=', l);
+				if (tmp == NULL) {
+					urlDecode(s, l, sw);
+					sw.flush();
+					cb((const char*) ms.data(), ms.length(), nullptr, 0);
+					ms.clear();
+				} else {
+					urlDecode(s, tmp - s, sw);
+					sw.flush();
+					int i = ms.length();
+					urlDecode(tmp + 1, _end - tmp - 1, sw);
+					sw.flush();
+					cb((const char*) ms.data(), i, (const char*) (ms.data() + i), ms.length() - i);
+					ms.clear();
+				}
+			}
+		} else {
+			split spl(in, inLen, '&');
+			while (spl.read()) {
+				const char* s = spl.value.d;
+				int l = spl.value.len;
+				const char* _end = s + l;
+				const char* tmp = (const char*) memchr(s, '=', l);
+				if (tmp == NULL) cb(s, l, nullptr, 0);
+				else cb(s, tmp - s, tmp + 1, _end - tmp - 1);
+			}
+		}
+	}
+	void htmlEscape(const char* in, int inLen, CP::StreamWriter& sw) {
+		int sz = 0;
+		for (int i = 0; i < inLen; i++) {
+			switch (in[i]) {
+				case '&':
+					sz += 5;
+					break;
+				case '<':
+					sz += 4;
+					break;
+				case '>':
+					sz += 4;
+					break;
+				default:
+					sz++;
+					break;
+			}
+		}
+
+		char* data = sw.beginWrite(sz);
+		char* c = data;
+		for (int i = 0; i < inLen; i++) {
+			switch (in[i]) {
+				case '&':
+					c[0] = '&';
+					c[1] = 'a';
+					c[2] = 'm';
+					c[3] = 'p';
+					c[4] = ';';
+					c += 5;
+					break;
+				case '<':
+					c[0] = '&';
+					c[1] = 'l';
+					c[2] = 't';
+					c[3] = ';';
+					c += 4;
+					break;
+				case '>':
+					c[0] = '&';
+					c[1] = 'g';
+					c[2] = 't';
+					c[3] = ';';
+					c += 4;
+					break;
+				default:
+					*(c++) = in[i];
+			}
+		}
+		sw.endWrite(sz);
+	}
+	void htmlAttributeEscape(const char* in, int inLen, CP::StreamWriter& sw) {
+		int last_i = 0;
+		const char* tmp;
+		for (int i = 0; i < inLen; i++) {
+			switch (in[i]) {
+				case '&':
+					tmp = "&amp;";
+					break;
+				case '<':
+					tmp = "&lt;";
+					break;
+				case '>':
+					tmp = "&gt;";
+					break;
+				case '"':
+					tmp = "&quot;";
+					break;
+				case '\'':
+					tmp = "&apos;";
+					break;
+				default:
+					continue;
+			}
+			if (i > last_i) sw.write(in + last_i, i - last_i);
+			last_i = i + 1;
+			sw.write(tmp);
+		}
+		if (inLen > last_i) sw.write(in + last_i, inLen - last_i);
+	}
+	int ci_compare(String s1, String s2) {
+		if (s1.length() > s2.length()) return 1;
+		if (s1.length() < s2.length()) return -1;
+		if (s1.length() == 0) return 0;
+		char a, b;
+		for (int i = 0; i < s1.length(); i++) {
+			a = tolower(s1.data()[i]);
+			b = tolower(s2.data()[i]);
+			if (a < b) return -1;
+			if (a > b) return 1;
+		}
+		return 0;
+	}
+	static inline int itoa1(int i, char* b) {
+		static char const digit[] = "0123456789";
+		char* p = b;
+		//negative detection is not needed for this specific use-case
+		//(writing the content-length header)
+		p += (i == 0 ? 0 : int(log10f(i))) + 1;
+		*p = '\0';
+		int l = p - b;
+		do { //Move back, inserting digits as u go
+			*--p = digit[i % 10];
+			i = i / 10;
+		} while (i);
+		return l;
+	}
+	//pads beginning with 0s
+	//i: input number
+	//d: # of digits
+	static inline int itoa2(int i, int d, char* b) {
+		static char const digit[] = "0123456789";
+		for (int x = d - 1; x >= 0; x--) {
+			b[x] = digit[i % 10];
+			i /= 10;
+		}
+		return d;
+	}
+	int rfctime(const tm& time, char* c) {
+		static const char* days[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
+		static const char* months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
+				"Oct", "Nov", "Dec" };
+		char* s = c;
+		//AAA, AA AAA ???? AA:AA:AA GMT\0
+		const char* day = days[time.tm_wday];
+		//copy 4 bytes (includes extra null byte)
+		*(int*) c = (*(int*) day) | int(',') << 24;
+		c += 4;
+		*(c++) = ' ';
+		c += itoa1(time.tm_mday, c);
+		*(c++) = ' ';
+		const char* month = months[time.tm_mon];
+		*(c++) = *(month++);
+		*(c++) = *(month++);
+		*(c++) = *(month++);
+		*(c++) = ' ';
+		c += itoa1(time.tm_year + 1900, c);
+		*(c++) = ' ';
+		c += itoa2(time.tm_hour, 2, c);
+		*(c++) = ':';
+		c += itoa2(time.tm_min, 2, c);
+		*(c++) = ':';
+		c += itoa2(time.tm_sec, 2, c);
+		*(c++) = ' ';
+		*(c++) = 'G';
+		*(c++) = 'M';
+		*(c++) = 'T';
+		*(c++) = '\0';
+		return int(c - s) - 1;
+	}
+}
+

+ 94 - 0
cpoll_cppsp/cppsp_rel0.2.3/cppsp/websocket.C

@@ -0,0 +1,94 @@
+/*
+ * websocket.C
+ *
+ *  Created on: Jun 1, 2013
+ *      Author: xaxaxa
+ */
+
+#include "include/websocket.H"
+#include "include/page.H"
+#include <cryptopp/cryptlib.h>
+#include <cryptopp/sha.h>
+#include <cryptopp/filters.h>
+#include <cryptopp/base64.h>
+using namespace CryptoPP;
+using namespace CP;
+using namespace std;
+
+namespace cppsp
+{
+	static uint64_t htonll(uint64_t value) {
+		// The answer is 42
+		static const int32_t num = 42;
+
+		// Check the endianness
+		if (*reinterpret_cast<const char*>(&num) == num) {
+			const uint32_t high_part = htonl(static_cast<uint32_t>(value >> 32));
+			const uint32_t low_part = htonl(static_cast<uint32_t>(value & 0xFFFFFFFFLL));
+
+			return (static_cast<uint64_t>(low_part) << 32) | high_part;
+		} else {
+			return value;
+		}
+	}
+	//len must be known in advance; you can not pass a subString of the returned buffer to ws_endWriteFrame()
+	String ws_beginWriteFrame(FrameWriter& fw, int len) {
+		int hdrlen = sizeof(WebSocketParser::ws_header1);
+		if (len > 125 && len <= 0xFFFF) hdrlen += sizeof(WebSocketParser::ws_header_extended16);
+		if (len > 0xFFFF) hdrlen += sizeof(WebSocketParser::ws_header_extended64);
+		String buf = fw.beginInsert(hdrlen + len);
+		return buf.subString(hdrlen, len);
+	}
+	void ws_endWriteFrame(FrameWriter& fw, String buf, int opcode) {
+		int hdrlen = sizeof(WebSocketParser::ws_header1);
+		if (buf.length() > 125 && buf.length() <= 0xFFFF) hdrlen +=
+				sizeof(WebSocketParser::ws_header_extended16);
+		if (buf.length() > 0xFFFF) hdrlen += sizeof(WebSocketParser::ws_header_extended64);
+
+		WebSocketParser::ws_header1* h1 = ((WebSocketParser::ws_header1*) (buf.data() - hdrlen));
+		memset(h1, 0, sizeof(*h1));
+		h1->fin = true;
+		h1->mask = false;
+		h1->opcode = opcode;
+		if (buf.length() > 125 && buf.length() <= 0xFFFF) {
+			h1->payload_len = 126;
+			WebSocketParser::ws_header_extended16* h2 = (WebSocketParser::ws_header_extended16*) (h1
+					+ 1);
+			h2->payload_len = htons((uint16_t) buf.length());
+		} else if (buf.length() > 0xFFFF) {
+			h1->payload_len = 127;
+			WebSocketParser::ws_header_extended64* h2 = (WebSocketParser::ws_header_extended64*) (h1
+					+ 1);
+			h2->payload_len = htonll((uint64_t) buf.length());
+		} else {
+			h1->payload_len = (char) buf.length();
+		}
+		fw.endInsert(hdrlen + buf.length());
+	}
+	void ws_init(Page& p, CP::Callback cb) {
+		p.response->statusCode = 101;
+		p.response->statusName = "Switching Protocols";
+		p.response->headers["Connection"] = "Upgrade";
+		p.response->headers["Upgrade"] = "WebSocket";
+		//response->headers["Sec-WebSocket-Protocol"]="chat";
+		String s = concat(*p.sp, p.request->headers["Sec-WebSocket-Key"],
+				"258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
+
+		SHA1 sha1;
+		byte tmp[sha1.DigestSize()];
+		sha1.CalculateDigest(tmp, (const byte*) s.data(), s.length());
+
+		string encoded;
+		StringSource src(tmp, sizeof(tmp), true, new Base64Encoder(new StringSink(encoded), false));
+		//printf("Sec-WebSocket-Accept: %s\n",encoded.c_str());
+		p.response->headers["Sec-WebSocket-Accept"] = p.sp->addString(encoded);
+		p.response->serializeHeaders(p.response->output);
+		p.response->output.flush();
+		p.response->outputStream->write(p.response->buffer, cb);
+	}
+	bool ws_iswebsocket(const Request& req) {
+		return (ci_compare(req.headers["Connection"], "Upgrade") == 0
+				&& ci_compare(req.headers["Upgrade"], "websocket") == 0);
+	}
+}
+

+ 4 - 0
cpoll_cppsp/cppsp_rel0.2.3/cppsp_server/.gitignore

@@ -0,0 +1,4 @@
+cppsp_standalone
+*.so
+*.html.txt
+*.html.C

+ 347 - 0
cpoll_cppsp/cppsp_rel0.2.3/cppsp_server/cppsp_standalone.C

@@ -0,0 +1,347 @@
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * */
+#include <cpoll/cpoll.H>
+#include <unistd.h>
+#include <iostream>
+#include <signal.h>
+#include <cppsp/page.H>
+#include <cppsp/cppsp_cpoll.H>
+#include <cppsp/common.H>
+#include <assert.h>
+#include <sys/syscall.h>	//SYS_gettid
+#include "server.C"
+#define PRINTSIZE(x) printf("sizeof("#x") = %i\n",sizeof(x))
+#define printerr(x, ...) fprintf(stderr, "\x1B[41;1;33m" x "\x1B[0;0;0m\n", ##__VA_ARGS__)
+#define printinfo(x, ...) fprintf(stderr, "\x1B[1;1;1m" x "\x1B[0;0;0m\n", ##__VA_ARGS__)
+#ifndef SO_REUSEPORT
+#define SO_REUSEPORT	15
+#endif
+#define CPPSP_LISTEN_BACKLOG 256
+
+using namespace std;
+using namespace CP;
+using namespace cppsp;
+using namespace RGC;
+string rootDir;
+
+void parseArgs(int argc, char** argv, const function<void(char*, const function<char*()>&)>& cb);
+
+struct workerThread
+{
+	cppspServer::Server srv;
+	vector<const char*> modules;
+	Ref<CP::Socket> listenSock;
+	union {
+		pid_t pid;
+		pthread_t thread;
+	};
+	int threadid;
+	int cpu;	//id of cpu to pin to, or -1
+	workerThread(Socket& sock): srv(rootDir.c_str()),
+		listenSock(sock),cpu(-1){}
+};
+class handler1: public RGC::Allocator
+{
+public:
+	Socket sock;
+	cppspServer::handler h;
+	handler1(cppspServer::Server& thr,CP::Poll& poll,HANDLE s,int d,int t,int p):
+		sock(s,d,t,p),h(thr,poll,sock) {
+			h.allocator=this;
+	}
+	void* alloc(int s) { return NULL; }
+	void dealloc(void* ptr) {
+		sock.~Socket();
+		if(allocator==NULL)free(this);
+		else allocator->dealloc(this);
+	}
+};
+void pinToCPU(int cpu) {
+	cpu_set_t s;
+	CPU_ZERO(&s);
+	CPU_SET(cpu,&s);
+	if(sched_setaffinity((pid_t)syscall(SYS_gettid),sizeof(s),&s)!=0)
+		perror("sched_setaffinity");
+}
+void* thread1(void* v) {
+	workerThread& thr=*(workerThread*)v;
+	cppspServer::Server& srv=thr.srv;
+	Poll p;
+	if(thr.cpu>=0) pinToCPU(thr.cpu);
+	/*
+	p.add(thr->efd);
+	struct {
+		Poll& p;
+		serverThread* thr;
+		void operator()(eventfd_t eventcount) {
+			cppsp_request* req;
+			while((req=thr->req_queue.beginDequeue())!=NULL) {
+				Socket* sock=new Socket(req->fd,listensock.addressFamily,
+					listensock.type,listensock.protocol);
+				//printf("new socket: %p\n",sock);
+				p.add(*sock);
+				processRequest(*thr,p,*sock);
+				sock->release();
+				thr->req_queue.endDequeue();
+			}
+		}
+	} cb {p, thr};
+	thr->efd.repeatGetEvent(&cb);*/
+	MemoryPool handlerPool(sizeof(handler1),256);
+	struct {
+		Poll& p;
+		workerThread& thr;
+		MemoryPool& handlerPool;
+		int reqn;
+		void operator()(HANDLE sock) {
+			//printf("thread %i: accepted socket: %p (%i)\n",thr->threadid,sock,sock->handle);
+			handler1* hdlr=new (handlerPool.alloc())
+				handler1(thr.srv,p,sock,thr.listenSock->addressFamily,
+					thr.listenSock->type,thr.listenSock->protocol);
+			hdlr->allocator=&handlerPool;
+			if(++reqn>10) {
+				reqn=0;
+				sched_yield();
+			}
+		}
+	} cb {p, thr, handlerPool, 0};
+	
+	p.add(*thr.listenSock);
+	Timer t((uint64_t)2000);
+	struct {
+		cppspServer::Server& srv;
+		void operator()(int count) {
+			srv.updateTime();
+		}
+	} cb1 {srv};
+	t.setCallback(&cb1);
+	p.add(t);
+	
+	int modsLeft;
+	struct {
+		int& modsLeft;
+		workerThread& thr;
+		Delegate<void(HANDLE)> cb;
+		void operator()() {
+			if(--modsLeft == 0) {
+				thr.listenSock->repeatAcceptHandle(cb);
+			}
+		}
+	} afterModuleLoad {modsLeft,thr,&cb};
+	struct {
+		const char* s;
+		Delegate<void()> afterModuleLoad;
+		void operator()(void*,exception* ex) {
+			if(ex!=NULL) {
+				fprintf(stderr,"error loading module %s: %s\n",s,ex->what());
+				cppsp::CompileException* ce = dynamic_cast<cppsp::CompileException*>(ex);
+				if (ce != NULL) {
+					printf("%s\n",ce->compilerOutput.c_str());
+				}
+			}
+			afterModuleLoad();
+		}
+	} moduleCB[thr.modules.size()];
+	modsLeft=thr.modules.size();
+	for(int ii=0;ii<(int)thr.modules.size();ii++) {
+		moduleCB[ii].s=thr.modules[ii];
+		moduleCB[ii].afterModuleLoad=&afterModuleLoad;
+		thr.srv.loadModule(p,thr.modules[ii],&moduleCB[ii]);
+	}
+	if(thr.modules.size()==0) thr.listenSock->repeatAcceptHandle(&cb);
+	p.loop();
+	return NULL;
+}
+
+CP::Socket listensock;
+int main(int argc, char** argv) {
+	{
+		char cwd[255];
+		if(getcwd(cwd,255)==NULL) throw runtime_error(strerror(errno));
+		rootDir=cwd;
+	}
+	string listen="0.0.0.0:80";
+	int threads=-1;
+	bool f0rk=false;
+	vector<string> cxxopts;
+	vector<const char*> modules;
+	bool reusePort=true;
+	bool setAffinity=false;
+	try {
+		parseArgs(argc, argv,
+				[&](char* name, const std::function<char*()>& getvalue)
+				{
+					if(name==NULL) goto help;
+					if(strcmp(name,"r")==0) {
+						rootDir=getvalue();
+					} else if(strcmp(name,"c")==0) {
+						cxxopts.push_back(getvalue());
+					} else if(strcmp(name,"g")==0) {
+						cppsp::gxx=getvalue();
+					} else if(strcmp(name,"l")==0) {
+						listen=getvalue();
+					} else if(strcmp(name,"t")==0) {
+						threads=atoi(getvalue());
+					} else if(strcmp(name,"m")==0) {
+						modules.push_back(getvalue());
+					} else if(strcmp(name,"f")==0) {
+						f0rk=true;
+					} else if(strcmp(name,"s")==0) {
+						reusePort=false;
+					} else if(strcmp(name,"a")==0) {
+						setAffinity=true;
+					} else {
+					help:
+						fprintf(stderr,"usage: %s [options]...\noptions:\n"
+						"\t-l <host:port>: listen on specified host:port (default: 0.0.0.0:80)\n"
+						"\t-g <option>: specify the C++ compiler (default: g++)\n"
+						"\t-c <option>: specify a compiler option to be passed to g++\n"
+						"\t-m <path>: load a cppsp module (path is relative to root)\n"
+						"\t-r <root>: set root directory (must be absolute) (default: $(pwd))\n"
+						"\t-t <threads>: # of worker processes/threads to start up (default: sysconf(_SC_NPROCESSORS_CONF))\n"
+						"\t-f: use multi-processing (forking) instead of multi-threading (pthreads)\n"
+						"\t-a: automatically set cpu affinity for the created worker threads/processes\n",argv[0]);
+						exit(1);
+					}
+				});
+	} catch(exception& ex) {
+		printerr("error: %s\nspecify -? for help",ex.what());
+		return 1;
+	}
+	printinfo("specify -? for help");
+	auto i=listen.find(':');
+	if(i==string::npos) throw runtime_error("expected \":\" in listen");
+	
+	int cpus=(int)sysconf(_SC_NPROCESSORS_CONF);
+	if(threads<0)threads=cpus;
+	if(setAffinity) {
+		if(threads > cpus && (threads%(int)sysconf(_SC_NPROCESSORS_CONF) != 0)) {
+			printerr("warning: cpu affinity is to be set; thread count larger than and not divisible by cpu count");
+		}
+	}
+	
+	EndPoint* ep=NULL;
+	struct {
+		bool& reusePort;
+		void operator()(int s) {
+			int optval = 1;
+			reusePort=(setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval))==0);
+		}
+	} initsock {reusePort};
+	if(reusePort)
+		listensock.bind(listen.substr(0,i).c_str(),
+			listen.substr(i + 1, listen.length() - i - 1).c_str(), AF_UNSPEC, SOCK_STREAM,0,0,&initsock);
+	else
+		listensock.bind(listen.substr(0,i).c_str(),
+			listen.substr(i + 1, listen.length() - i - 1).c_str(), AF_UNSPEC, SOCK_STREAM);
+	if(reusePort) {
+		printinfo("using SO_REUSEPORT");
+		ep=listensock.getLocalEndPoint();
+	} else {
+		printerr("NOT using SO_REUSEPORT");
+		listensock.listen(CPPSP_LISTEN_BACKLOG);
+	}
+	
+	//p.add(listensock);
+	PRINTSIZE(CP::Socket);
+	PRINTSIZE(cppspServer::handler);
+	PRINTSIZE(handler1);
+	if(f0rk) printinfo("starting %i processes",threads);
+	else printinfo("starting %i threads",threads);
+	workerThread* th=(workerThread*)new char[sizeof(workerThread)*threads];
+	for(int i=0;i<threads;i++) {
+		int cpu=i%cpus;
+		Socket* newsock;
+		if(reusePort) {
+			newsock=new Socket(listensock.addressFamily, listensock.type, listensock.protocol);
+			int optval = 1;
+			assert(setsockopt(newsock->handle, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval))==0);
+			newsock->bind(*ep);
+			newsock->listen(CPPSP_LISTEN_BACKLOG);
+		} else {
+			newsock=new Socket(f0rk ? listensock.handle : dup(listensock.handle),
+				listensock.addressFamily, listensock.type, listensock.protocol);
+		}
+		workerThread& tmp=*(new (th+i) workerThread(*newsock));
+		tmp.cpu=(setAffinity?cpu:-1);
+		newsock->release();
+		CXXOpts(tmp.srv.mgr)=cxxopts;
+		tmp.modules=modules;
+		tmp.threadid=i+1;
+		if(threads==1) {
+			thread1(&tmp);
+			return 0;
+		}
+		if(f0rk) {
+			pid_t pid=fork();
+			if(pid==0) {
+				tmp.pid=getpid();
+				srand(int(tmp.pid)^(int)time(NULL));
+				thread1(&tmp);
+				return 0;
+			} else if(pid>0) {
+				tmp.pid=pid;
+				//delete newsock;
+			} else {
+				perror("fork");
+				return 1;
+			}
+		} else {
+			if (pthread_create(&tmp.thread, NULL, thread1, &tmp) != 0) {
+				throw runtime_error(strerror(errno));
+			}
+		}
+	}
+	if(f0rk) {
+		static workerThread* _threads;
+		static int _threadcount;
+		struct sig_handler
+		{
+			static void a(int sig) {
+				for(int i=0;i<_threadcount;i++) {
+					kill(_threads[i].pid, 9);
+				}
+				exit(0);
+			}
+		};
+		_threads=th;
+		_threadcount=threads;
+		struct sigaction sa;
+		sa.sa_handler = &sig_handler::a;
+		sigemptyset(&sa.sa_mask);
+		sigaction(SIGINT, &sa, NULL);
+		sigaction(SIGTERM, &sa, NULL);
+		sigaction(SIGSEGV, &sa, NULL);
+	}
+	while(1)sleep(3600);
+}
+void parseArgs(int argc, char** argv, const function<void(char*, const function<char*()>&)>& cb) {
+	int i = 1;
+	function<char*()> func = [&]()->char*
+	{
+		if(i+1>=argc)throw logic_error(string(argv[i])+" requires an argument");
+		return argv[(++i)];
+	};
+	for (; i < argc; i++) {
+		if (argv[i][0] == '\x00') continue;
+		if (argv[i][0] == '-') {
+			cb(argv[i] + 1, func);
+		} else {
+			cb(NULL, [argv,i]()
+			{	return argv[i];});
+		}
+	}
+}
+

+ 5 - 0
cpoll_cppsp/cppsp_rel0.2.3/cppsp_server/makefile

@@ -0,0 +1,5 @@
+cppsp_standalone: cppsp_standalone.C
+	g++ cppsp_standalone.C -Wall -o cppsp_standalone --std=c++0x -g3 -I../include -L../lib -lcpoll -lcppsp -ldl -lrt -Wno-pmf-conversions
+socketd_cppsp: socketd_cppsp.C
+	g++ socketd_cppsp.C -o socketd_cppsp --std=c++0x -g3 -I../include -L../lib -lcpoll -lcppsp -ldl -Wno-pmf-conversions
+

+ 295 - 0
cpoll_cppsp/cppsp_rel0.2.3/cppsp_server/server.C

@@ -0,0 +1,295 @@
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * */
+#include <cpoll/cpoll.H>
+#include <unistd.h>
+#include <iostream>
+#include <signal.h>
+#include <cppsp/page.H>
+#include <cppsp/cppsp_cpoll.H>
+#include <cppsp/common.H>
+using namespace std;
+using namespace CP;
+using namespace cppsp;
+using namespace RGC;
+#define rmb() /**/
+#define wmb() /**/
+
+namespace cppspServer
+{
+	#define CACHELINE_SIZE 64
+	//currently not used
+	template<class T> class RingBuffer
+	{
+	public:
+		union {
+			struct {
+				T* items;
+				int length;
+			};
+			char padding1[CACHELINE_SIZE];
+		};
+		union {
+			int rpos;
+			char padding2[CACHELINE_SIZE];
+		};
+		union {
+			int wpos;
+			char padding3[CACHELINE_SIZE];
+		};
+		
+		RingBuffer(int length): length(length),rpos(0), wpos(0) {
+			items=new T[length];
+		}
+		inline int __getlength(int i1, int i2, int wrap)
+		{
+			return (i2 < i1 ? i2 + wrap : i2) - i1;
+		}
+		inline bool canEnqueue()
+		{
+			return __getlength(rpos, wpos, (length*2)) < length;
+		}
+		inline bool canDequeue()
+		{
+			return __getlength(rpos, wpos, (length*2)) > 0;
+		}
+		T* beginEnqueue() {
+			if(canEnqueue()) return items+(wpos%length);
+			else return NULL;
+		}
+		void endEnqueue() {
+			wmb();
+			wpos=(wpos+1)%(length*2);
+		}
+		T* beginDequeue() {
+			if(!canDequeue()) return NULL;
+			rmb();
+			return items+(rpos%length);
+		}
+		void endDequeue() {
+			rpos=(rpos+1)%(length*2);
+		}
+	};
+	class Server: public cppsp::Server {
+	public:
+		cppspManager* mgr;
+		String root;
+		Server(String root):mgr(cppspManager_new()),root(root) {
+		}
+		~Server() {
+			cppspManager_delete(mgr);
+		}
+		
+		void handleStaticRequest(String path, cppsp::Request& req, Response& resp, Delegate<void()> cb) override;
+		void handleDynamicRequest(String path, cppsp::Request& req, Response& resp, Delegate<void()> cb) override;
+		
+		void loadPage(CP::Poll& p, String path, RGC::Allocator& a,
+			Delegate<void(Page*, exception* ex)> cb) override {
+			string tmp = mapPath(path.toSTDString());
+			cppsp::loadPage(mgr, p, rootDir(), {tmp.data(), (int) tmp.length()}, &a, cb);
+		}
+		void loadPageFromFile(CP::Poll& p, String path, RGC::Allocator& a,
+				Delegate<void(Page*, exception* ex)> cb) override {
+			cppsp::loadPage(mgr, p, rootDir(), path, &a, cb);
+		}
+		void loadModule(CP::Poll& p, String path, 
+			Delegate<void(void*, exception* ex)> cb) override {
+			string tmp = mapPath(path.toSTDString());
+			cppsp::loadModule(mgr, p, this, rootDir(), {tmp.data(), (int) tmp.length()}, cb);
+		}
+		void loadModuleFromFile(CP::Poll& p, String path, 
+				Delegate<void(void*, exception* ex)> cb) override {
+			cppsp::loadModule(mgr, p, this, rootDir(), path, cb);
+		}
+		String loadStaticPage(String path) override {
+			string tmp = mapPath(path.toSTDString());
+			return cppsp::loadStaticPage(mgr,{tmp.data(), (int) tmp.length()});
+		}
+		String loadStaticPageFromFile(String path) override {
+			return cppsp::loadStaticPage(mgr,path);
+		}
+		String rootDir() override {
+			return root;
+		}
+		cppspManager* manager() override {
+			return mgr;
+		}
+		//this function needs to be called periodically to check for file modifications
+		//otherwise auto re-compile will not work
+		//generally call it every 2 seconds
+		void updateTime() {
+			cppsp::updateTime(mgr);
+		}
+	};
+	class Request:public cppsp::CPollRequest
+	{
+	public:
+		Request(CP::Socket& s, CP::StringPool* sp) :
+			CPollRequest(s, sp) {
+		}
+		void* _handler;
+	};
+	//handles a single connection
+	//just instantiate-and-forget; it will self-destruct when connection is closed
+	struct handler:public RGC::Object {
+		Allocator* alloc;
+		Server& thr;
+		CP::Poll& p;
+		Socket& s;
+		Page* page;
+		StringPool sp;
+		Request req;
+		cppsp::Response resp;
+		//Page* p;
+		//MemoryStream ms;
+		uint8_t* buf;
+		String path;
+		iovec iov[2];
+		bool keepAlive;
+		handler(Server& thr,CP::Poll& poll,Socket& s):thr(thr),
+			p(poll),s(s), req(this->s,&sp),resp(this->s,&sp) {
+			//printf("handler()\n");
+			req._handler=this;
+			poll.add(this->s);
+			s.retain();
+			if(req.readRequest({&handler::readCB, this})) readCB(true);
+		}
+		void readCB(bool success) {
+			if(!success) {
+				destruct();
+				return;
+			}
+			auto it=req.headers.find("connection");
+			if(it!=req.headers.end() && (*it).value=="close")keepAlive=false;
+			else keepAlive=true;
+			resp.headers.insert({"Connection", keepAlive?"keep-alive":"close"});
+			resp.headers.insert({"Date", sp.addString(thr.mgr->curRFCTime)});
+			
+			thr.handleRequest(req,resp,{&handler::finalize,this});
+		}
+		void setPath(String p) {
+			path.d=sp.beginAdd(p.length()+thr.root.length());
+			path.len=cppsp::combinePathChroot(thr.root.data(),thr.root.length(),
+				p.data(),p.length(),path.data());
+			sp.endAdd(path.len);
+		}
+		static inline int itoa(int i, char* b) {
+			static char const digit[] = "0123456789";
+			char* p = b;
+			p += (i==0?0:int(log10f(i))) + 1;
+			*p = '\0';
+			int l = p - b;
+			do { //Move back, inserting digits as u go
+				*--p = digit[i % 10];
+				i = i / 10;
+			} while (i);
+			return l;
+		}
+		void handleStatic(String _path) {
+			try {
+				setPath(_path);
+				String data=cppsp::loadStaticPage(thr.mgr,path);
+				int bufferL = resp.buffer.length();
+				{
+					char* tmps = sp.beginAdd(16);
+					int l = itoa(data.length(), tmps);
+					sp.endAdd(l);
+					resp.headers.insert({"Content-Length", { tmps, l }});
+					StreamWriter sw(resp.buffer);
+					resp.serializeHeaders(sw);
+				}
+				iov[0]= {resp.buffer.data()+bufferL, (size_t)(resp.buffer.length()-bufferL)};
+				iov[1]= {data.data(), (size_t)data.length()};
+				resp.outputStream->writevAll(iov, 2, { &handler::writevCB, this });
+			} catch(exception& ex) {
+				cppsp::handleError(&ex,resp,path);
+				resp.flush( { &handler::flushCB, this });
+			}
+		}
+		void handleDynamic(String _path) {
+			setPath(_path);
+			cppsp::loadPage(thr.mgr,p,thr.root,path,&sp,{&handler::loadCB,this});
+		}
+		void loadCB(Page* p, exception* ex) {
+			//printf("loadCB()\n");
+			if(ex!=NULL) {
+				cppsp::handleError(ex,resp,path);
+				resp.flush( { &handler::flushCB, this });
+				goto doFinish;
+			}
+			{
+				this->page=p;
+				p->sp=&sp;
+				//this->p=p;
+				//p->filePath=path;
+				p->request=&req;
+				p->response=&resp;
+				p->poll=&this->p;
+				p->server=&thr;
+				p->handleRequest({&handler::handleRequestCB,this});
+				return;
+			}
+		doFinish:;
+		}
+		void sockReadCB(int r) {
+			if(r<=0) {
+				free(buf);
+				destruct();
+			}
+		}
+		void flushCB(Response& resp) {
+			//s->shutdown(SHUT_WR);
+			//release();
+			finalize();
+		}
+		void writevCB(int i) {
+			finalize();
+		}
+		void handleRequestCB() {
+			page->destruct();
+			page=nullptr;
+			//s->shutdown(SHUT_WR);
+			//release();
+			//s->repeatRead(buf,sizeof(buf),{&handler::sockReadCB,this});
+			finalize();
+		}
+		void finalize() {
+			if(resp.closed) {
+				destruct(); return;
+			}
+			sp.clear();
+			if(keepAlive) {
+				req.reset();
+				resp.reset();
+				if(req.readRequest({&handler::readCB,this})) readCB(true);
+			} else {
+				s.shutdown(SHUT_WR);
+				buf=(uint8_t*)malloc(4096);
+				s.repeatRead(buf,4096,{&handler::sockReadCB,this});
+			}
+		}
+		~handler() {
+			//printf("~handler()\n");
+			s.release();
+		}
+	};
+	void Server::handleStaticRequest(String path, cppsp::Request& req, Response& resp, Delegate<void()> cb) {
+		cppspServer::Request& r=static_cast<cppspServer::Request&>(req);
+		(*(handler*)r._handler).handleStatic(path);
+	}
+	void Server::handleDynamicRequest(String path, cppsp::Request& req, Response& resp, Delegate<void()> cb) {
+		cppspServer::Request& r=static_cast<cppspServer::Request&>(req);
+		(*(handler*)r._handler).handleDynamic(path);
+	}
+}

+ 124 - 0
cpoll_cppsp/cppsp_rel0.2.3/cppsp_server/socketd_cppsp.C

@@ -0,0 +1,124 @@
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * */
+#include <cpoll/cpoll.H>
+#include <unistd.h>
+#include <iostream>
+#include <socketd.H>
+#include <signal.h>
+#include <socketd_client.H>
+#include <cppsp/page.H>
+#include <cppsp/cppsp_cpoll.H>
+#include <cppsp/common.H>
+#include "server.C"
+
+using namespace std;
+using namespace socketd;
+using namespace CP;
+using namespace cppsp;
+string rootDir;
+void parseArgs(int argc, char** argv, const function<void(char*, const function<char*()>&)>& cb) {
+	int i = 1;
+	function<char*()> func = [&]()->char*
+	{
+		if(i+1>=argc)return NULL;
+		return argv[(++i)];
+	};
+	for (; i < argc; i++) {
+		if (argv[i][0] == '\x00') continue;
+		if (argv[i][0] == '-') {
+			cb(argv[i] + 1, func);
+		} else {
+			cb(NULL, [argv,i]()
+			{	return argv[i];});
+		}
+	}
+}
+int main(int argc, char** argv) {
+	cout << "started child #" << getpid() << endl;
+	srand(int(getpid())^(int)time(NULL));
+	{
+		char cwd[255];
+		if(getcwd(cwd,255)==NULL) throw runtime_error(strerror(errno));
+		rootDir=cwd;
+	}
+	CP::Poll p;
+	vector<string> cxxopts;
+	vector<const char*> modules;
+	parseArgs(argc, argv,
+			[&](char* name, const std::function<char*()>& getvalue)
+			{
+				if(strcmp(name,"r")==0) {
+					rootDir=getvalue();
+				} else if(strcmp(name,"c")==0) {
+					cxxopts.push_back(getvalue());
+				} else if(strcmp(name,"m")==0) {
+					modules.push_back(getvalue());
+				}
+			});
+	
+	cppspServer::Server srv(rootDir.c_str());
+	auto& v=CXXOpts(srv.mgr);
+	v.insert(v.end(),cxxopts.begin(),cxxopts.end());
+	cxxopts.clear();
+	
+	MemoryPool mp(sizeof(cppspServer::handler));
+	struct {
+		CP::Poll& p;
+		MemoryPool& mp;
+		cppspServer::Server& srv;
+		void operator()(socketd_client& cl, Socket* s, int64_t id) {
+			if(s==NULL)kill(getpid(),9);
+			cl.ack(id);
+			cppspServer::handler* hdlr=new (mp.alloc())
+				cppspServer::handler(srv,p,*s);
+			hdlr->allocator=&mp;
+		}
+	} cb {p, mp, srv};
+	
+	int modsLeft;
+	struct {
+		int& modsLeft;
+		CP::Poll& p;
+		Delegate<void(socketd_client& cl, Socket* s, int64_t id)> cb;
+		void operator()() {
+			if(--modsLeft == 0) {
+				new socketd_client(p,cb);
+			}
+		}
+	} afterModuleLoad {modsLeft,p,&cb};
+	struct {
+		const char* s;
+		Delegate<void()> afterModuleLoad;
+		void operator()(void*,exception* ex) {
+			if(ex!=NULL) {
+				fprintf(stderr,"error loading module %s: %s\n",s,ex->what());
+				cppsp::CompileException* ce = dynamic_cast<cppsp::CompileException*>(ex);
+				if (ce != NULL) {
+					printf("%s\n",ce->compilerOutput.c_str());
+				}
+			}
+			afterModuleLoad();
+		}
+	} moduleCB[modules.size()];
+	modsLeft=modules.size();
+	for(int ii=0;ii<(int)modules.size();ii++) {
+		moduleCB[ii].s=modules[ii];
+		moduleCB[ii].afterModuleLoad=&afterModuleLoad;
+		srv.loadModule(p,modules[ii],&moduleCB[ii]);
+	}
+	if(modules.size()==0) new socketd_client(p,&cb);
+	
+	p.loop();
+}

BIN
cpoll_cppsp/cppsp_rel0.2.3/cppsp_standalone


+ 1 - 0
cpoll_cppsp/cppsp_rel0.2.3/include/concat.H

@@ -0,0 +1 @@
+../common_headers/concat.H

+ 1 - 0
cpoll_cppsp/cppsp_rel0.2.3/include/cpoll

@@ -0,0 +1 @@
+../cpoll/include

+ 1 - 0
cpoll_cppsp/cppsp_rel0.2.3/include/cpoll.H

@@ -0,0 +1 @@
+../cpoll/include/cpoll.H

+ 1 - 0
cpoll_cppsp/cppsp_rel0.2.3/include/cpoll_internal.H

@@ -0,0 +1 @@
+../cpoll/include/cpoll_internal.H

+ 1 - 0
cpoll_cppsp/cppsp_rel0.2.3/include/cppsp

@@ -0,0 +1 @@
+../cppsp/include

+ 1 - 0
cpoll_cppsp/cppsp_rel0.2.3/include/delegate.H

@@ -0,0 +1 @@
+../common_headers/delegate.H

+ 1 - 0
cpoll_cppsp/cppsp_rel0.2.3/include/iallocator.H

@@ -0,0 +1 @@
+../common_headers/iallocator.H

+ 1 - 0
cpoll_cppsp/cppsp_rel0.2.3/include/rgc.H

@@ -0,0 +1 @@
+../common_headers/rgc.H

+ 1 - 0
cpoll_cppsp/cppsp_rel0.2.3/include/socketd.H

@@ -0,0 +1 @@
+../socketd/include/socketd.H

+ 1 - 0
cpoll_cppsp/cppsp_rel0.2.3/include/socketd_client.H

@@ -0,0 +1 @@
+../socketd/include/socketd_client.H

+ 22 - 0
cpoll_cppsp/cppsp_rel0.2.3/makefile

@@ -0,0 +1,22 @@
+OPTFLAGS := -Ofast -march=native -flto
+CXXFLAGS := $(OPTFLAGS) -Wall --std=c++0x -Wno-pmf-conversions -I./include
+CXX := g++
+all: cppsp_standalone cpoll.o cppsp.o socketd_bin socketd_cppsp socketd_proxy.so
+cppsp_standalone: 
+	$(CXX) cppsp_server/cppsp_standalone.C cpoll/all.C cppsp/all.C -o cppsp_standalone -lpthread -ldl -lrt $(CXXFLAGS)
+socketd_bin:
+	$(CXX) socketd/all.C cpoll/all.C -o socketd_bin -lpthread -ldl -lrt $(CXXFLAGS) 
+socketd_cppsp:
+	$(CXX) cppsp_server/socketd_cppsp.C cpoll/all.C cppsp/all.C -o socketd_cppsp -lpthread -ldl -lrt $(CXXFLAGS)
+cpoll.o:
+	$(CXX) cpoll/all.C -c -o cpoll.o $(CXXFLAGS) -fPIC
+cppsp.o:
+	$(CXX) cppsp/all.C -c -o cppsp.o $(CXXFLAGS) -fPIC
+socketd_proxy.so:
+	$(CXX) socketd_proxy.C cpoll/all.C -o socketd_proxy.so -ldl -lpthread --std=c++0x --shared -fPIC $(CXXFLAGS) 
+clean:
+	rm -f cpoll.o cppsp.o cppsp_standalone socketd_bin socketd_cppsp socketd_proxy.so
+	rm -f www/*.cppsp.so www/*.cppsp.C www/*.cppsp.txt
+	rm -f www/*.cppsm.so www/*.cppsm.C www/*.cppsm.txt
+	rm -f www/*.html.so www/*.html.C www/*.html.txt
+

+ 7 - 0
cpoll_cppsp/cppsp_rel0.2.3/run_application

@@ -0,0 +1,7 @@
+#!/bin/bash
+# usage: run_application /ABSOLUTE/PATH/TO/APPLICATION
+
+num_cpus=`grep vendor_id /proc/cpuinfo | wc -l`
+./cppsp_standalone -f -l 0.0.0.0:16969 -c -fPIC -c -I"$(pwd)"/include -c -pthread -c -Ofast -c -march=native -c "$(pwd)"/cpoll.o -c "$(pwd)"/cppsp.o -t "$num_cpus" -r "$@"
+
+

+ 4 - 0
cpoll_cppsp/cppsp_rel0.2.3/run_example

@@ -0,0 +1,4 @@
+#!/bin/bash
+num_cpus=`grep vendor_id /proc/cpuinfo | wc -l`
+./cppsp_standalone -r "$(pwd)"/www -l 0.0.0.0:16969 -c -fPIC -c -I"$(pwd)"/include -c -pthread -c -Ofast -c -march=native -c "$(pwd)"/cpoll.o -c "$(pwd)"/cppsp.o -t "$num_cpus" -f $@
+

+ 5 - 0
cpoll_cppsp/cppsp_rel0.2.3/run_socketd_example

@@ -0,0 +1,5 @@
+#!/bin/bash
+export LD_LIBRARY_PATH="$LD_LIBRARY_PATH":"$(pwd)"
+./socketd_exampleconf > socketd_example.conf
+./socketd_bin socketd_example.conf
+

+ 624 - 0
cpoll_cppsp/cppsp_rel0.2.3/socketd/.cproject

@@ -0,0 +1,624 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?fileVersion 4.0.0?>
+
+<cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
+	<storageModule moduleId="org.eclipse.cdt.core.settings">
+		<cconfiguration id="cdt.managedbuild.config.gnu.exe.debug.1222889747">
+			<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.exe.debug.1222889747" moduleId="org.eclipse.cdt.core.settings" name="Debug">
+				<externalSettings/>
+				<extensions>
+					<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
+					<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+				</extensions>
+			</storageModule>
+			<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+				<configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.exe.debug.1222889747" name="Debug" parent="cdt.managedbuild.config.gnu.exe.debug">
+					<folderInfo id="cdt.managedbuild.config.gnu.exe.debug.1222889747." name="/" resourcePath="">
+						<toolChain id="cdt.managedbuild.toolchain.gnu.exe.debug.285320062" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.exe.debug">
+							<targetPlatform id="cdt.managedbuild.target.gnu.platform.exe.debug.620164706" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.exe.debug"/>
+							<builder buildPath="${workspace_loc:/socketd/Debug}" id="cdt.managedbuild.target.gnu.builder.exe.debug.417489085" keepEnvironmentInBuildfile="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.exe.debug"/>
+							<tool id="cdt.managedbuild.tool.gnu.archiver.base.669119044" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
+							<tool command="g++" commandLinePattern="${COMMAND} ${FLAGS} ${OUTPUT_FLAG} ${OUTPUT_PREFIX}${OUTPUT} ${INPUTS}" id="cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug.1665843675" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug">
+								<option id="gnu.cpp.compiler.exe.debug.option.optimization.level.1721323245" name="Optimization Level" superClass="gnu.cpp.compiler.exe.debug.option.optimization.level" value="gnu.cpp.compiler.optimization.level.none" valueType="enumerated"/>
+								<option id="gnu.cpp.compiler.exe.debug.option.debugging.level.2117320934" name="Debug Level" superClass="gnu.cpp.compiler.exe.debug.option.debugging.level" value="gnu.cpp.compiler.debugging.level.max" valueType="enumerated"/>
+								<option id="gnu.cpp.compiler.option.include.paths.1594311139" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" valueType="includePath">
+									<listOptionValue builtIn="false" value="../../include/"/>
+								</option>
+								<option id="gnu.cpp.compiler.option.other.pic.1729804421" name="Position Independent Code (-fPIC)" superClass="gnu.cpp.compiler.option.other.pic" value="true" valueType="boolean"/>
+								<option id="gnu.cpp.compiler.option.other.other.1274566737" name="Other flags" superClass="gnu.cpp.compiler.option.other.other" value="-c -fmessage-length=0 --std=c++0x -fpie -pie -Wno-pmf-conversions" valueType="string"/>
+								<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.132710918" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.c.compiler.exe.debug.1083532738" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.exe.debug">
+								<option defaultValue="gnu.c.optimization.level.none" id="gnu.c.compiler.exe.debug.option.optimization.level.1275638464" name="Optimization Level" superClass="gnu.c.compiler.exe.debug.option.optimization.level" valueType="enumerated"/>
+								<option id="gnu.c.compiler.exe.debug.option.debugging.level.608484651" name="Debug Level" superClass="gnu.c.compiler.exe.debug.option.debugging.level" value="gnu.c.debugging.level.max" valueType="enumerated"/>
+								<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1141195764" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.c.linker.exe.debug.1261115181" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.exe.debug"/>
+							<tool id="cdt.managedbuild.tool.gnu.cpp.linker.exe.debug.156934543" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.exe.debug">
+								<option id="gnu.cpp.link.option.libs.1847566022" name="Libraries (-l)" superClass="gnu.cpp.link.option.libs" valueType="libs">
+									<listOptionValue builtIn="false" value="cpoll"/>
+								</option>
+								<option id="gnu.cpp.link.option.paths.1080967587" name="Library search path (-L)" superClass="gnu.cpp.link.option.paths" valueType="libPaths">
+									<listOptionValue builtIn="false" value="../../lib/"/>
+								</option>
+								<option id="gnu.cpp.link.option.flags.49595677" name="Linker flags" superClass="gnu.cpp.link.option.flags" value="-pthread" valueType="string"/>
+								<inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.1366725832" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
+									<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+									<additionalInput kind="additionalinput" paths="$(LIBS)"/>
+								</inputType>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.assembler.exe.debug.1121446911" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.exe.debug">
+								<inputType id="cdt.managedbuild.tool.gnu.assembler.input.1973806699" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
+							</tool>
+						</toolChain>
+					</folderInfo>
+					<fileInfo id="cdt.managedbuild.config.gnu.exe.debug.1222889747.418032655" name="all.C" rcbsApplicability="disable" resourcePath="all.C" toolsToInvoke="cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug.1665843675.1514642977">
+						<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug.1665843675.1514642977" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug.1665843675"/>
+					</fileInfo>
+					<sourceEntries>
+						<entry excluding="all.C" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
+					</sourceEntries>
+				</configuration>
+			</storageModule>
+			<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+			<storageModule moduleId="packages"/>
+		</cconfiguration>
+		<cconfiguration id="cdt.managedbuild.config.gnu.exe.release.246109486">
+			<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.exe.release.246109486" moduleId="org.eclipse.cdt.core.settings" name="Release">
+				<externalSettings/>
+				<extensions>
+					<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
+					<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+				</extensions>
+			</storageModule>
+			<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+				<configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.exe.release.246109486" name="Release" parent="cdt.managedbuild.config.gnu.exe.release">
+					<folderInfo id="cdt.managedbuild.config.gnu.exe.release.246109486." name="/" resourcePath="">
+						<toolChain id="cdt.managedbuild.toolchain.gnu.exe.release.372495708" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.exe.release">
+							<targetPlatform id="cdt.managedbuild.target.gnu.platform.exe.release.59170688" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.exe.release"/>
+							<builder buildPath="${workspace_loc:/socketd/Release}" id="cdt.managedbuild.target.gnu.builder.exe.release.1448965848" keepEnvironmentInBuildfile="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.exe.release"/>
+							<tool id="cdt.managedbuild.tool.gnu.archiver.base.802454452" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
+							<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.exe.release.991325613" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.exe.release">
+								<option id="gnu.cpp.compiler.exe.release.option.optimization.level.100844386" name="Optimization Level" superClass="gnu.cpp.compiler.exe.release.option.optimization.level" value="gnu.cpp.compiler.optimization.level.most" valueType="enumerated"/>
+								<option id="gnu.cpp.compiler.exe.release.option.debugging.level.1973361512" name="Debug Level" superClass="gnu.cpp.compiler.exe.release.option.debugging.level" value="gnu.cpp.compiler.debugging.level.none" valueType="enumerated"/>
+								<option id="gnu.cpp.compiler.option.include.paths.1605373284" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" valueType="includePath">
+									<listOptionValue builtIn="false" value="../../include/"/>
+								</option>
+								<option id="gnu.cpp.compiler.option.other.pic.1985900202" name="Position Independent Code (-fPIC)" superClass="gnu.cpp.compiler.option.other.pic" value="true" valueType="boolean"/>
+								<option id="gnu.cpp.compiler.option.other.other.1620743624" name="Other flags" superClass="gnu.cpp.compiler.option.other.other" value="-c -fmessage-length=0 --std=c++0x -fpie -pie -Wno-pmf-conversions" valueType="string"/>
+								<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1748004843" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.c.compiler.exe.release.991005626" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.exe.release">
+								<option defaultValue="gnu.c.optimization.level.most" id="gnu.c.compiler.exe.release.option.optimization.level.616801913" name="Optimization Level" superClass="gnu.c.compiler.exe.release.option.optimization.level" valueType="enumerated"/>
+								<option id="gnu.c.compiler.exe.release.option.debugging.level.574641193" name="Debug Level" superClass="gnu.c.compiler.exe.release.option.debugging.level" value="gnu.c.debugging.level.none" valueType="enumerated"/>
+								<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.2055800873" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.c.linker.exe.release.2012259703" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.exe.release"/>
+							<tool id="cdt.managedbuild.tool.gnu.cpp.linker.exe.release.1979375585" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.exe.release">
+								<option id="gnu.cpp.link.option.libs.1666028879" name="Libraries (-l)" superClass="gnu.cpp.link.option.libs" valueType="libs">
+									<listOptionValue builtIn="false" value="cpoll"/>
+								</option>
+								<option id="gnu.cpp.link.option.paths.1967387454" name="Library search path (-L)" superClass="gnu.cpp.link.option.paths" valueType="libPaths">
+									<listOptionValue builtIn="false" value="../../lib/"/>
+								</option>
+								<option id="gnu.cpp.link.option.flags.92404462" name="Linker flags" superClass="gnu.cpp.link.option.flags" value="-pthread" valueType="string"/>
+								<inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.557906462" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
+									<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+									<additionalInput kind="additionalinput" paths="$(LIBS)"/>
+								</inputType>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.assembler.exe.release.1255602266" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.exe.release">
+								<inputType id="cdt.managedbuild.tool.gnu.assembler.input.146125372" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
+							</tool>
+						</toolChain>
+					</folderInfo>
+					<fileInfo id="cdt.managedbuild.config.gnu.exe.release.246109486.1537777732" name="all.C" rcbsApplicability="disable" resourcePath="all.C" toolsToInvoke="cdt.managedbuild.tool.gnu.cpp.compiler.exe.release.991325613.1956221514">
+						<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.exe.release.991325613.1956221514" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.exe.release.991325613"/>
+					</fileInfo>
+					<sourceEntries>
+						<entry excluding="all.C" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
+					</sourceEntries>
+				</configuration>
+			</storageModule>
+			<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+		</cconfiguration>
+	</storageModule>
+	<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+		<project id="socketd.cdt.managedbuild.target.gnu.exe.681259369" name="Executable" projectType="cdt.managedbuild.target.gnu.exe"/>
+	</storageModule>
+	<storageModule moduleId="refreshScope" versionNumber="2">
+		<configuration configurationName="Release">
+			<resource resourceType="PROJECT" workspacePath="/socketd"/>
+		</configuration>
+		<configuration configurationName="Debug">
+			<resource resourceType="PROJECT" workspacePath="/socketd"/>
+		</configuration>
+	</storageModule>
+	<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
+	<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
+	<storageModule moduleId="scannerConfiguration">
+		<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"/>
+		<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+			<buildOutputProvider>
+				<openAction enabled="true" filePath=""/>
+				<parser enabled="true"/>
+			</buildOutputProvider>
+			<scannerInfoProvider id="specsFile">
+				<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+				<parser enabled="true"/>
+			</scannerInfoProvider>
+		</profile>
+		<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+			<buildOutputProvider>
+				<openAction enabled="true" filePath=""/>
+				<parser enabled="true"/>
+			</buildOutputProvider>
+			<scannerInfoProvider id="makefileGenerator">
+				<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+				<parser enabled="true"/>
+			</scannerInfoProvider>
+		</profile>
+		<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+			<buildOutputProvider>
+				<openAction enabled="true" filePath=""/>
+				<parser enabled="true"/>
+			</buildOutputProvider>
+			<scannerInfoProvider id="specsFile">
+				<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+				<parser enabled="true"/>
+			</scannerInfoProvider>
+		</profile>
+		<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+			<buildOutputProvider>
+				<openAction enabled="true" filePath=""/>
+				<parser enabled="true"/>
+			</buildOutputProvider>
+			<scannerInfoProvider id="specsFile">
+				<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+				<parser enabled="true"/>
+			</scannerInfoProvider>
+		</profile>
+		<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+			<buildOutputProvider>
+				<openAction enabled="true" filePath=""/>
+				<parser enabled="true"/>
+			</buildOutputProvider>
+			<scannerInfoProvider id="specsFile">
+				<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+				<parser enabled="true"/>
+			</scannerInfoProvider>
+		</profile>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.release.246109486;cdt.managedbuild.config.gnu.exe.release.246109486.;cdt.managedbuild.tool.gnu.c.compiler.exe.release.991005626;cdt.managedbuild.tool.gnu.c.compiler.input.2055800873">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
+			<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="specsFile">
+					<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+			<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="makefileGenerator">
+					<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+			<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="specsFile">
+					<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+			<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="specsFile">
+					<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+			<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="specsFile">
+					<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.debug.1222889747;cdt.managedbuild.config.gnu.exe.debug.1222889747.;cdt.managedbuild.tool.gnu.c.compiler.exe.debug.1083532738;cdt.managedbuild.tool.gnu.c.compiler.input.1141195764">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
+			<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="specsFile">
+					<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+			<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="makefileGenerator">
+					<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+			<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="specsFile">
+					<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+			<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="specsFile">
+					<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+			<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="specsFile">
+					<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.release.246109486;cdt.managedbuild.config.gnu.exe.release.246109486.;cdt.managedbuild.tool.gnu.cpp.compiler.exe.release.991325613;cdt.managedbuild.tool.gnu.cpp.compiler.input.1748004843">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
+			<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="specsFile">
+					<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+			<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="makefileGenerator">
+					<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+			<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="specsFile">
+					<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+			<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="specsFile">
+					<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+			<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="specsFile">
+					<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.debug.799890233;cdt.managedbuild.config.gnu.exe.debug.799890233.;cdt.managedbuild.tool.gnu.c.compiler.exe.debug.1347941320;cdt.managedbuild.tool.gnu.c.compiler.input.249444364">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
+			<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="specsFile">
+					<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+			<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="makefileGenerator">
+					<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+			<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="specsFile">
+					<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+			<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="specsFile">
+					<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+			<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="specsFile">
+					<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.debug.1222889747;cdt.managedbuild.config.gnu.exe.debug.1222889747.;cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug.1665843675;cdt.managedbuild.tool.gnu.cpp.compiler.input.132710918">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
+			<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="specsFile">
+					<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+			<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="makefileGenerator">
+					<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+			<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="specsFile">
+					<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+			<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="specsFile">
+					<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+			<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="specsFile">
+					<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.release.867503670;cdt.managedbuild.config.gnu.exe.release.867503670.;cdt.managedbuild.tool.gnu.c.compiler.exe.release.2143194614;cdt.managedbuild.tool.gnu.c.compiler.input.1451144698">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
+			<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="specsFile">
+					<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+			<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="makefileGenerator">
+					<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+			<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="specsFile">
+					<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+			<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="specsFile">
+					<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+			<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="specsFile">
+					<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.release.867503670;cdt.managedbuild.config.gnu.exe.release.867503670.;cdt.managedbuild.tool.gnu.cpp.compiler.exe.release.1174218548;cdt.managedbuild.tool.gnu.cpp.compiler.input.1380752036">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
+			<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="specsFile">
+					<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+			<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="makefileGenerator">
+					<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+			<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="specsFile">
+					<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+			<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="specsFile">
+					<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+			<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="specsFile">
+					<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.debug.799890233;cdt.managedbuild.config.gnu.exe.debug.799890233.;cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug.221636982;cdt.managedbuild.tool.gnu.cpp.compiler.input.78613592">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
+			<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="specsFile">
+					<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+			<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="makefileGenerator">
+					<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+			<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="specsFile">
+					<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+			<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="specsFile">
+					<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+			<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+				<buildOutputProvider>
+					<openAction enabled="true" filePath=""/>
+					<parser enabled="true"/>
+				</buildOutputProvider>
+				<scannerInfoProvider id="specsFile">
+					<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+					<parser enabled="true"/>
+				</scannerInfoProvider>
+			</profile>
+		</scannerConfigBuildInfo>
+	</storageModule>
+</cproject>

+ 83 - 0
cpoll_cppsp/cppsp_rel0.2.3/socketd/.project

@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>socketd</name>
+	<comment></comment>
+	<projects>
+		<project>cpoll</project>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
+			<triggers>clean,full,incremental,</triggers>
+			<arguments>
+				<dictionary>
+					<key>?name?</key>
+					<value></value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.append_environment</key>
+					<value>true</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.autoBuildTarget</key>
+					<value>all</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.buildArguments</key>
+					<value>-j5</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.buildCommand</key>
+					<value>make</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.buildLocation</key>
+					<value>${workspace_loc:/socketd/Debug}</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.cleanBuildTarget</key>
+					<value>clean</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.contents</key>
+					<value>org.eclipse.cdt.make.core.activeConfigSettings</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.enableAutoBuild</key>
+					<value>false</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.enableCleanBuild</key>
+					<value>true</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.enableFullBuild</key>
+					<value>true</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.fullBuildTarget</key>
+					<value>all</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.stopOnError</key>
+					<value>true</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.useDefaultBuildCmd</key>
+					<value>true</value>
+				</dictionary>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.cdt.core.cnature</nature>
+		<nature>org.eclipse.cdt.core.ccnature</nature>
+		<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
+		<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
+	</natures>
+</projectDescription>

+ 4 - 0
cpoll_cppsp/cppsp_rel0.2.3/socketd/all.C

@@ -0,0 +1,4 @@
+#include "socketd.C"
+#include "main.C"
+#include "configparser.C"
+

+ 365 - 0
cpoll_cppsp/cppsp_rel0.2.3/socketd/configparser.C

@@ -0,0 +1,365 @@
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * */
+/*
+ * configparser.C
+ *
+ *  Created on: Mar 2, 2013
+ *      Author: xaxaxa
+ */
+#include "include/configparser.H"
+#include <functional>
+#include <sstream>
+#define CONCAT(s) (((stringstream&)(stringstream() << s)).str().c_str())
+using namespace std;
+namespace socketd
+{
+	struct configToken
+	{
+		enum types
+		{
+			none = 0, t_line, t_beginBlock, t_endBlock
+		} type;
+		const char* data;
+		int datalen;
+		struct parserInfo
+		{
+			int pos;
+			int line;
+		} inf;
+	};
+	ParserException::ParserException() :
+			message(strerror(errno)), number(errno) {
+	}
+	ParserException::ParserException(int32_t number) :
+			message(strerror(number)), number(number) {
+	}
+	ParserException::ParserException(string message, int32_t number) :
+			message(message), number(number) {
+	}
+	ParserException::~ParserException() throw () {
+	}
+	const char* ParserException::what() const throw () {
+		return message.c_str();
+	}
+
+	class ParserException_internal: public ParserException
+	{
+	public:
+		string message;
+		int32_t number;
+		ParserException_internal() {
+		}
+		ParserException_internal(int32_t number) :
+				ParserException(number) {
+		}
+		ParserException_internal(string message, int32_t number = 0) :
+				ParserException(message, number) {
+		}
+		ParserException_internal(const configToken::parserInfo& inf, string message, int32_t number =
+				0) :
+				ParserException(CONCAT("line " << inf.line << ": " <<message), number) {
+
+		}
+		ParserException_internal(const configToken& ct, string message, int32_t number = 0) :
+				ParserException(CONCAT("line " << ct.inf.line << ": " <<message), number) {
+
+		}
+		~ParserException_internal() throw () {
+		}
+	};
+
+	inline bool isWhitespace(char ch) {
+		return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
+	}
+	static inline void parseConfig_out(configToken& t, const char* conf, int len, int i, int& last_i,
+			const function<void(const configToken&)>& cb) {
+		while (last_i < i && isWhitespace(conf[last_i]))
+			last_i++;
+		t.data = conf + last_i;
+		t.datalen = i - last_i;
+		cb(t);
+		last_i = i + 1;
+	}
+	void parseConfig(const char* conf, int len, const function<void(const configToken&)>& cb) {
+		configToken t;
+		int i = 0;
+		int last_i = 0;
+		int line = 1;
+		//int tmpline = 0;
+		main_loop: while (i < len) {
+			if (conf[i] == '{') {
+				t.type = configToken::t_beginBlock;
+				goto out;
+			} else if (conf[i] == '}') {
+				for (int x = last_i; x < i; x++) {
+					if (!isWhitespace(conf[x])) throw ParserException_internal( { last_i, line },
+							"garbage before \"}\". maybe you forgot a \";\"?");
+				}
+				t.type = configToken::t_endBlock;
+				goto out;
+			} else if (conf[i] == ';') {
+				t.type = configToken::t_line;
+				goto out;
+			} else if (conf[i] == '/') {
+				goto loop2;
+			} else if (conf[i] == '\n') {
+				line++;
+			}
+			cont: i++;
+		}
+		return;
+		loop2: i++;
+		if (i >= len || conf[i] != '/') goto main_loop;
+		i++;
+		while (i < len) {
+			if (conf[i] == '\r' || conf[i] == '\n') break;
+			i++;
+		}
+		last_i = i;
+		goto main_loop;
+
+		out: t.inf.pos = last_i;
+		t.inf.line = line;
+		parseConfig_out(t, conf, len, i, last_i, cb);
+		//line += tmpline;
+		//tmpline = 0;
+		goto cont;
+	}
+
+	//returns length of prefix, because index is always 0
+	static inline int configGetPrefix(const char* data, int len) {
+		const char* tmp = (const char*) memchr(data, ' ', len);
+		if (tmp == NULL) return len;
+		else return tmp - data;
+	}
+	static inline int mystrcmp(const char* s1, int l1, const char* s2, int l2) {
+		if (l1 != l2) return l1 - l2;
+		return memcmp(s1, s2, l1);
+	}
+	static inline void split(const char* s1, int l1, char c,
+			const function<void(const char*, int)>& cb) {
+		int i = 0;
+		while (i < l1) {
+			const void* tmp = memchr(s1 + i, c, l1 - i);
+			if (tmp == NULL) break;
+			int next = ((const char*) tmp) - s1;
+			cb(s1 + i, next - i);
+			i = next + 1;
+		}
+		cb(s1 + i, l1 - i);
+	}
+	static void parseBindingDirective(binding& b, socketd& sd, const configToken& ct) {
+		int prefLen = configGetPrefix(ct.data, ct.datalen);
+		if (ct.datalen - prefLen - 1 <= 0) throw ParserException_internal(ct,
+				"missing parameter in \"" + string(ct.data, prefLen) + "\" binding target");
+		if (mystrcmp(ct.data, prefLen, "listen", 6) == 0) {
+			const char* s = ct.data + prefLen + 1;
+			int len1 = ct.datalen - prefLen - 1;
+			const char* tmp = (const char*) memchr(s, ':', len1);
+			if (tmp == NULL) throw ParserException_internal(ct, "expected \":\"");
+			int x = tmp - s;
+			for (int i = 0; i < (int) sd.listens.size(); i++) {
+				//cout << "compared " << sd.listens[i].host << " " << sd.listens[i].port << endl;
+				if (mystrcmp(sd.listens[i].host.data(), sd.listens[i].host.length(), s, x) == 0
+						&& mystrcmp(sd.listens[i].port.data(), sd.listens[i].port.length(), s + x + 1,
+								len1 - x - 1) == 0) {
+					b.listenID = sd.listens[i].id;
+					goto sssss;
+				}
+			}
+			throw ParserException_internal(ct,
+					"the specified listen directive \"" + string(s, len1) + "\" was not found");
+			sssss: b.matchLevel |= binding::match_listenID;
+		} else if (mystrcmp(ct.data, prefLen, "httppath", 8) == 0) {
+			b.httpPath = string(ct.data + prefLen + 1, ct.datalen - prefLen - 1);
+			b.matchLevel |= binding::match_httpPath;
+		} else if (mystrcmp(ct.data, prefLen, "httphost", 8) == 0) {
+			b.httpHost = string(ct.data + prefLen + 1, ct.datalen - prefLen - 1);
+			b.matchLevel |= binding::match_httpHost;
+		} else throw ParserException_internal(ct,
+				"expected \"listen\", \"httppath\", or \"httphost\" directive, but got \""
+						+ string(ct.data, prefLen) + "\"");
+	}
+	void loadConfig(const char* conf, int len, socketd& sd) {
+		char state = 0;
+
+		vhost* vh;
+		binding* b;
+		int maxListenID = 0;
+
+		parseConfig(conf, len, [&](const configToken& ct) {
+			//printf("configToken %i: %s\n",ct.type,string(ct.data,ct.datalen).c_str());
+				switch(ct.type) {
+					case configToken::t_beginBlock:
+					{
+						switch(state) {
+							case 0:
+							{
+								int prefLen=configGetPrefix(ct.data,ct.datalen);
+								if(mystrcmp(ct.data,prefLen,"vhost",5)==0) {
+									state='v';
+									sd.vhosts.resize(sd.vhosts.size()+1);
+									vh=&*(sd.vhosts.end()-1);
+									if (ct.datalen - prefLen - 1 > 0) {
+										vh->name=string(ct.data + prefLen + 1,ct.datalen - prefLen - 1);
+									}
+								} else if(mystrcmp(ct.data,prefLen,"binding",7)==0) {
+									if (ct.datalen - prefLen - 1 <= 0) throw ParserException_internal(ct, "missing name in \"binding\" block");
+									sd.extraBindings.resize(sd.extraBindings.size()+1);
+									b=&*(sd.extraBindings.end()-1);
+									b->matchLevel=0;
+									b->vhostName=string(ct.data + prefLen + 1,ct.datalen - prefLen - 1);
+									state='d';
+								} else throw ParserException_internal(ct,"expected \"vhost\" or \"binding\" block, but got \""+string(ct.data,prefLen)+"\"");
+								break;
+							}
+							case 'v':
+							{
+								int prefLen=configGetPrefix(ct.data,ct.datalen);
+								if(mystrcmp(ct.data,prefLen,"bindings",8)==0) {
+									state='b';
+								} else throw ParserException_internal(ct,"expected \"bindings\" block, but got \""+string(ct.data,prefLen)+"\"");
+								break;
+							}
+							case 'b':
+							{
+								vh->bindings.resize(vh->bindings.size()+1);
+								b=&*(vh->bindings.end()-1);
+								b->matchLevel=0;
+								state='c';
+								break;
+							}
+							case 'c':
+							{
+								throw ParserException_internal(ct,"unexpected \"{\" when in \"binding\" section");
+							}
+						}
+						break;
+					}
+					case configToken::t_endBlock:
+					{
+						switch(state) {
+							case 0:
+							throw ParserException_internal(ct,"unexpected \"}\"");
+							case 'v':
+							state=0; break;
+							case 'b':
+							state='v'; break;
+							case 'c':
+							state='b'; break;
+							case 'd':
+							state=0; break;
+						}
+						break;
+					}
+					case configToken::t_line:
+					{
+						switch(state) {
+							case 0:
+							{
+								int prefLen=configGetPrefix(ct.data,ct.datalen);
+								if(mystrcmp(ct.data,prefLen,"listen",6)==0) {
+									sd.listens.resize(sd.listens.size()+1);
+									listen* l;
+									l=&*(sd.listens.end()-1);
+									l->id=(++maxListenID);
+									int ind=0;
+									split(ct.data+prefLen,ct.datalen-prefLen,' ',[&](const char* s, int len) {
+												if(len<=0)return;
+												//cout << "listen directive token: " << string(s,len) << endl;
+												switch(ind) {
+													case 0: //address
+													{
+														const char* tmp=(const char*)memchr(s,':',len);
+														if(tmp==NULL)throw ParserException_internal(ct,"expected \":\"");
+														int i=tmp - s;
+														l->host=string(s,i);
+														l->port=string(s+i+1,len-i-1);
+														//cout << "host: " << l->host << " port: " << l->port << endl;
+														break;
+													}
+													case 1: //backlog
+													{
+														//make a copy because atoi() expects a null byte
+														string tmp(s,len);
+														l->backlog=atoi(tmp.c_str());
+														break;
+													}
+													default:
+													throw ParserException_internal(ct,"trailing garbage in \"listen\" directive");
+													break;
+												}
+												ind++;
+											});
+								} else if(mystrcmp(ct.data,prefLen,"ipcbuffersize",13)==0) {
+									if(ct.datalen-prefLen-1<=0) throw ParserException_internal(ct,"missing parameter in \"ipcbuffersize\" directive");
+									sd.ipcBufSize=atoi(string(ct.data+prefLen+1,ct.datalen-prefLen-1).c_str());
+								} else if(mystrcmp(ct.data,prefLen,"threads",7)==0) {
+									if(ct.datalen-prefLen-1<=0) throw ParserException_internal(ct,"missing parameter in \"threads\" directive");
+									sd.threads=atoi(string(ct.data+prefLen+1,ct.datalen-prefLen-1).c_str());
+								} else throw ParserException_internal(ct,"expected \"listen\" or \"ipcbuffersize\" directive, but got \""+string(ct.data,prefLen)+"\"");
+								break;
+							}
+							case 'v':
+							{
+								int prefLen=configGetPrefix(ct.data,ct.datalen);
+								if(mystrcmp(ct.data,prefLen,"exec",4)==0) {
+									if(ct.datalen-prefLen-1<=0) throw ParserException_internal(ct,"missing parameter in \"exec\" directive");
+									vh->exepath=string(ct.data+prefLen+1,ct.datalen-prefLen-1);
+								} else if(mystrcmp(ct.data,prefLen,"shell",5)==0) {
+									if(ct.datalen-prefLen-1<=0) throw ParserException_internal(ct,"missing parameter in \"shell\" directive");
+									vh->useShell=ct.data[prefLen+1]=='1';
+								} else if(mystrcmp(ct.data,prefLen,"preload",7)==0) {
+									if(ct.datalen-prefLen-1<=0) throw ParserException_internal(ct,"missing parameter in \"preload\" directive");
+									vh->preload=ct.data[prefLen+1]=='1';
+								} else if(mystrcmp(ct.data,prefLen,"authcookie",10)==0) {
+									if(ct.datalen-prefLen-1<=0) throw ParserException_internal(ct,"missing parameter in \"authcookie\" directive");
+									vh->authCookie=string(ct.data+prefLen+1,ct.datalen-prefLen-1);
+								} else if(mystrcmp(ct.data,prefLen,"processes",9)==0) {
+									if(ct.datalen-prefLen-1<=0) throw ParserException_internal(ct,"missing parameter in \"processes\" directive");
+									vh->processes=atoi(string(ct.data+prefLen+1,ct.datalen-prefLen-1).c_str());
+								} else if(mystrcmp(ct.data,prefLen,"ipcbuffersize",13)==0) {
+									if(ct.datalen-prefLen-1<=0) throw ParserException_internal(ct,"missing parameter in \"ipcbuffersize\" directive");
+									vh->ipcBufSize=atoi(string(ct.data+prefLen+1,ct.datalen-prefLen-1).c_str());
+								} else throw ParserException_internal(ct,"expected \"exec\", \"shell\", \"preload\", \"authcookie\", \"processes\", or \"ipcbuffersize\" directive, but got \""+string(ct.data,prefLen)+"\"");
+								break;
+							}
+							case 'b':
+							{
+								throw ParserException_internal(ct,"unexpected directive when in \"bindings\" section");
+								break;
+							}
+							case 'c':
+							{
+								parseBindingDirective(*b,sd,ct);
+								break;
+							}
+							case 'd':
+							{
+								parseBindingDirective(*b,sd,ct);
+								break;
+							}
+						}
+						break;
+					}
+				}
+			});
+		if (state != 0) throw ParserException_internal("got EOF while searching for matching \"}\"");
+	}
+	void reloadConfig(const char* conf, int len, socketd& sd) {
+
+	}
+}
+

+ 43 - 0
cpoll_cppsp/cppsp_rel0.2.3/socketd/include/configparser.H

@@ -0,0 +1,43 @@
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * */
+/*
+ * configparser.H
+ *
+ *  Created on: Mar 2, 2013
+ *      Author: xaxaxa
+ */
+
+#ifndef CONFIGPARSER_H_
+#define CONFIGPARSER_H_
+#include "socketd_internal.H"
+
+namespace socketd
+{
+	class ParserException: public std::exception
+	{
+	public:
+		string message;
+		int32_t number;
+		ParserException();
+		ParserException(int32_t number);
+		ParserException(string message, int32_t number = 0);
+		~ParserException() throw ();
+		const char* what() const throw ();
+	};
+	void loadConfig(const char* conf, int len, socketd& sd);
+	void reloadConfig(const char* conf, int len, socketd& sd);
+}
+
+#endif /* CONFIGPARSER_H_ */

+ 66 - 0
cpoll_cppsp/cppsp_rel0.2.3/socketd/include/socketd.H

@@ -0,0 +1,66 @@
+/*
+ * socketd.H
+ *
+ *  Created on: Feb 4, 2013
+ *      Author: xaxaxa
+ */
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * */
+#ifndef SOCKETD_H_
+#define SOCKETD_H_
+#define SOCKETD_PROT_VERSION 1
+#define SOCKETD_MAX_HEADERLEN 1024
+namespace socketd
+{
+	struct protocolHeader
+	{
+		int version;
+		enum
+		{
+			none = 0, handleConnection, ackConnection, shutdown, attach, attachResponse
+		} type;
+		protocolHeader() :
+				version(SOCKETD_PROT_VERSION), type(none) {
+		}
+	};
+	struct prot_handleConnection
+	{
+		int64_t id;
+		int32_t d;
+		int32_t t;
+		int32_t p;
+		int32_t bufferLen;
+	};
+	struct prot_ackConnection
+	{
+		int64_t id;
+		bool success;
+	};
+	struct prot_attach
+	{
+		int64_t id;
+		int namelen;
+		int authTokenLen;
+		///char name[namelen];
+		///char authToken[authTokenLen];
+	};
+	struct prot_attachResponse
+	{
+		int64_t id;
+		bool success;
+	};
+}
+
+#endif /* SOCKETD_H_ */

+ 267 - 0
cpoll_cppsp/cppsp_rel0.2.3/socketd/include/socketd_client.H

@@ -0,0 +1,267 @@
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * */
+/*
+ * socketd_client.H
+ *
+ *  Created on: Mar 8, 2013
+ *      Author: xaxaxa
+ */
+
+#ifndef SOCKETD_CLIENT_H_
+#define SOCKETD_CLIENT_H_
+#include <socketd.H>
+#include <cpoll/cpoll.H>
+#include <unistd.h>
+#include <cpoll/sendfd.H>
+#include <functional>
+#include <sstream>
+#define CONCAT(X) (((stringstream&)(stringstream()<<X)).str())
+namespace socketd
+{
+	using namespace std;
+	using namespace CP;
+	class SocketProxy: public CP::Socket
+	{
+	public:
+		uint8_t* buf;
+		int bufPos, bufLen;
+		SocketProxy(int fd, int d, int t, int p, int buflen) :
+				CP::Socket(fd, d, t, p), bufPos(0), bufLen(buflen) {
+			buf = new uint8_t[buflen];
+		}
+		int32_t tryFixRead(void* buf, int32_t len) {
+			if (this->buf == NULL || bufPos >= bufLen) return -1;
+			int32_t l = len > (bufLen - bufPos) ? (bufLen - bufPos) : len;
+			if (l <= 0) return 0;
+			memcpy(buf, this->buf + bufPos, l);
+			bufPos += l;
+			if (bufPos >= bufLen) {
+				delete[] this->buf;
+				this->buf = NULL;
+			}
+			return l;
+		}
+		int32_t read(void* buf, int32_t len) {
+			int32_t r;
+			if ((r = tryFixRead(buf, len)) == -1) return CP::Socket::read(buf, len);
+			else return r;
+		}
+		int32_t recv(void* buf, int32_t len, int32_t flags = 0) {
+			int32_t r;
+			if ((r = tryFixRead(buf, len)) == -1) CP::Socket::recv(buf, len, flags);
+			else {
+				if (flags & MSG_WAITALL) {
+					if (r < len) {
+						int32_t tmp = CP::Socket::recv(((uint8_t*) buf) + r, len - r, flags);
+						if (tmp > 0) r += tmp;
+					}
+				}
+				return r;
+			}
+		}
+		void read(void* buf, int32_t len, const Callback& cb, bool repeat = false) {
+			int32_t r;
+			if ((r = tryFixRead(buf, len)) == -1) CP::Socket::read(buf, len, cb, repeat);
+			else {
+				cb(r);
+				if (repeat && r > 0) CP::Socket::read(buf, len, cb, true);
+			}
+		}
+		void recv(void* buf, int32_t len, int32_t flags, const Callback& cb, bool repeat = false) {
+			int32_t r;
+			if ((r = tryFixRead(buf, len)) == -1) CP::Socket::recv(buf, len, flags, cb, repeat);
+			else {
+				//MSG_WAITALL is not supposed to be specified on an asynchoronous CP::Socket::recv() call
+
+				/*
+				 if (flags & MSG_WAITALL) {
+				 if (r < len) {
+				 CP::Socket::recv(((uint8_t*) buf) + r, len - r, flags,
+				 [cb,r,repeat,buf,len,flags,this](int i)
+				 {
+				 int r1=r;
+				 if(i>0)r1+=i;
+				 cb(r1);
+				 if(repeat)CP::Socket::recv(buf, len, flags, cb, true);
+				 }, false);
+				 return;
+				 }
+				 }*/
+				cb(r);
+				if (repeat) CP::Socket::recv(buf, len, flags, cb, true);
+			}
+		}
+		~SocketProxy() {
+			if (buf != NULL) delete[] buf;
+		}
+	};
+	class socketd_client
+	{
+	public:
+		CP::Poll& p;
+		RGC::Ref<CP::Socket> sock;
+		Delegate<void(socketd_client&, Socket*, int64_t id)> cb;
+		protocolHeader ph;
+		prot_handleConnection ph1;
+		bool raw;
+		/*vector<int> acks;
+		 uint8_t* tmp;
+		 int tmplen;
+		 bool writing;
+		 void startWrite() {
+		 if(writing || acks.size()<=0)return;
+		 int sz=sizeof(protocolHeader)+sizeof(prot_ackConnection);
+		 int sz1=sz*acks.size();
+		 if(tmplen<sz1) {
+		 if(tmp!=NULL)free(tmp);
+		 tmplen=sz1;
+		 tmp=(uint8_t*)malloc(sz1);
+		 }
+		 for(int i=0;i<acks.size();i++) {
+		 protocolHeader* ph=(protocolHeader*)(tmp+(sz*i));
+		 prot_ackConnection* ack=(prot_ackConnection*)(ph+1);
+		 ph->type=protocolHeader::ackConnection;
+		 ack->id=acks[i];
+		 ack->success=true;
+		 }
+		 acks.resize(0);
+		 writing=true;
+		 sock->write(tmp,sz1,[this](int r) {
+		 writing=false;
+		 if(r<=0)return;
+		 startWrite();
+		 });
+		 }*/
+		void startRead();
+		void ack(int64_t id) {
+			if (raw) return;
+			protocolHeader ph;
+			memset(&ph, 0, sizeof(ph));
+			ph.type = protocolHeader::ackConnection;
+			prot_ackConnection ack;
+			memset(&ack, 0, sizeof(ack));
+			ack.id = id;
+			ack.success = true;
+			if (this->sock->send(&ph, sizeof(ph), MSG_DONTWAIT) != sizeof(ph)) throw runtime_error(
+					"unix socket buffer overflow");
+			if (this->sock->send(&ack, sizeof(ack), MSG_DONTWAIT) != sizeof(ack)) throw runtime_error(
+					"unix socket buffer overflow");
+			//acks.push_back(id);
+			//startWrite();
+		}
+		void handleConnectionCB(int r) {
+			if (r <= 0) {
+				cb(*this, (Socket*) NULL, 0);
+				return;
+			}
+			int fd = recvfd(sock->handle);
+			if (fd < 0) {
+				cb(*this, (Socket*) NULL, 0);
+				return;
+			}
+			CP::Socket* newsock;
+			//printf("asdfg %i\n",ph1.bufferLen);
+			if (ph1.bufferLen <= 0) {
+				newsock = new CP::Socket(fd, ph1.d, ph1.t, ph1.p);
+			} else {
+				SocketProxy* tmps;
+				tmps = new SocketProxy(fd, ph1.d, ph1.t, ph1.p, ph1.bufferLen);
+				int r = sock->recv(tmps->buf, ph1.bufferLen, MSG_WAITALL);
+				if (r <= 0) {
+					cb(*this, (Socket*) NULL, 0);
+					return;
+				}
+				newsock = tmps;
+				/*char junk[ph1.bufferLen];
+				 sock->recv(junk, ph1.bufferLen, MSG_WAITALL);
+				 newsock = new CP::Socket(fd, ph1.d, ph1.t, ph1.p);*/
+			}
+			p.add(*newsock);
+			int64_t id = ph1.id;
+			//printf("aaaaa %lli %i %i %i\n",ph1.id, ph1.d, ph1.t, ph1.p);
+			cb(*this, newsock, id);
+			newsock->release();
+			startRead();
+		}
+		void readCB(int r) {
+			//printf("readCB: this=%p\n",(void*)this);
+			if (r <= 0) {
+				cb(*this, (Socket*) NULL, 0);
+				return;
+			}
+			if (r != sizeof(ph)) throw runtime_error(
+					CONCAT("attempting to read protocolHeader resulted in short read: r=" << r) );
+			switch (ph.type) {
+				case protocolHeader::handleConnection:
+				{
+					sock->read(&ph1, sizeof(ph1),
+							CP::Callback(&socketd_client::handleConnectionCB, this));
+					return;
+				}
+				default:
+				{
+					throw runtime_error(CONCAT("unrecognized protocolHeader.type " << ph.type) );
+				}
+			}
+			startRead();
+		}
+		socketd_client(CP::Poll& p, const Delegate<void(socketd_client&, Socket*, int64_t)>& cb,
+				CP::Socket* sock = NULL) :
+				p(p), cb(cb), raw(false)/*, tmp(NULL),tmplen(0),writing(false)*/{
+			if (sock == NULL) {
+				char* listen = getenv("SOCKETD_LISTEN");
+				if (listen != NULL) {
+					const char* aaa = (const char*) memchr(listen, ':', strlen(listen));
+					if (aaa == NULL) throw runtime_error("expected \":\" in SOCKETD_LISTEN");
+					int i = aaa - listen;
+					sock = RGC::newObj<CP::Socket>();
+					sock->bind(string(listen, i).c_str(),
+							string(listen + i + 1, strlen(listen) - i - 1).c_str(), AF_UNSPEC,
+							SOCK_STREAM);
+					p.add(*sock);
+					struct CB1
+					{
+						socketd_client* This;
+						Delegate<void(socketd_client&, Socket*, int64_t)> cb;
+						int64_t id;
+						void operator()(Socket* s) {
+							This->p.add(*s);
+							cb(*This, s, (++id));
+							s->release();
+						}
+					}*cb1 = new CB1 { this, cb, 0 };
+					sock->listen();
+					raw = true;
+					sock->repeatAccept(cb1);
+					return;
+				}
+				char* tmp;
+				tmp = getenv("SOCKETD_FD");
+				if (tmp == NULL) throw logic_error("environment \"SOCKETD_FD\" not set");
+				sock = RGC::newObj<CP::Socket>(atoi(tmp), AF_UNIX, SOCK_STREAM, 0);
+				p.add(*sock);
+			}
+			this->sock = sock;
+			startRead();
+		}
+	};
+	void socketd_client::startRead() {
+		//memset(&ph, 0, sizeof(ph));
+		//printf("startRead: this=%p\n",(void*)this);
+		sock->recv(&ph, sizeof(ph), 0, CP::Callback(&socketd_client::readCB, this));
+	}
+
+}
+#endif /* SOCKETD_CLIENT_H_ */

+ 177 - 0
cpoll_cppsp/cppsp_rel0.2.3/socketd/include/socketd_internal.H

@@ -0,0 +1,177 @@
+/*
+ * config.hpp
+ *
+ *  Created on: 2011-05-20
+ *      Author: xaxaxa
+ */
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * */
+#ifndef CONFIG_HPP_
+#define CONFIG_HPP_
+
+#include <cpoll/cpoll.H>
+#include <rgc.H>
+#include <string>
+#include <map>
+#include <vector>
+#include "socketd.H"
+#include <delegate.H>
+#include <unistd.h>
+
+using namespace std;
+
+namespace socketd
+{
+	class SocketDException: public std::exception
+	{
+	public:
+		string message;
+		int32_t number;
+		SocketDException();
+		SocketDException(int32_t number);
+		SocketDException(string message, int32_t number = 0);
+		~SocketDException() throw ();
+		const char* what() const throw ();
+	};
+
+	struct binding;
+	struct vhost;
+	struct listen
+	{
+	public:
+		//user supplied fields
+		//RGC::Ref<CP::EndPoint> ep;
+		string host;
+		string port;
+		int id;
+		int backlog;
+		//internal fields
+		vector<CP::HANDLE> socks;
+		int d,t,p;
+		listen(string host, string port, int id, int backlog = 32) :
+				host(host), port(port), id(id), backlog(backlog) {
+		}
+		listen() :
+				backlog(32) {
+		}
+	};
+	struct binding
+	{
+	public:
+		//user supplied fields
+		string httpPath; //path must not have / at the end!!!!!
+		string httpHost;
+		string vhostName; //only needs to be filled if put in the "extraBindings" array
+		int listenID;
+
+		//bitmap:
+		//0: match listenID
+		//1: match httpPath
+		//2: match httpHost
+		int matchLevel;
+		enum
+		{
+			match_listenID = 1, match_httpPath = 2, match_httpHost = 4
+		};
+		binding() {
+		}
+		binding(int listenID, string httpPath, string httpHost, int matchLevel) :
+				httpPath(httpPath), httpHost(httpHost), listenID(listenID), matchLevel(matchLevel) {
+		}
+		//internal fields
+		vhost* vh;
+	};
+	struct appConnection: public RGC::Object
+	{
+		//						sock		success
+		typedef Delegate<void(bool)> passConnCB;
+		appConnection();
+		virtual void shutDown()=0;
+
+		//return values: 0: success; 1: failed; 2: in progress (passConnCB() will be called later)
+		virtual int passConnection(CP::Socket* s, void* buffer, int buflen, const passConnCB& cb)=0;
+		virtual ~appConnection();
+	};
+	struct vhost: public RGC::Object
+	{
+	public:
+		//user supplied fields
+		vector<binding> bindings;
+		string name;
+		string exepath; //leave blank (length==0) to disable execing and just wait for attachment
+
+		/*int requestsPerProcess;
+		 int maxRequestsPerProcess;
+		 int maxProcesses;*/
+		int processes; //how many processes to spawn (for load balancing)
+		//at runtime, the # of processes will be rounded up to the nearest multiple
+		//of the # of socketd threads
+
+		int ipcBufSize; //set to 0 to use system default, -1 to use global settings
+		//for attaching to a running vhost; arbitrary string; leave blank (length==0) to
+		//disable attachments
+		string authCookie;
+
+		//whether to LD_PRELOAD socketd_proxy.so
+		bool preload;
+		bool useShell;
+		vhost() :
+				processes(1), ipcBufSize(-1), preload(false), useShell(true) {
+		}
+		vhost(const vector<binding>& bindings, string name, string exepath, string authCookie,
+				bool preload = false, bool shell = true, int processes = 1) :
+				bindings(bindings), name(name), exepath(exepath), processes(processes),
+						authCookie(authCookie), preload(preload), useShell(shell) {
+		}
+
+		//internal fields
+		//vector<int> conns_i; //indexed by thread*processes + curProcess
+		RGC::Ref<appConnection> attachmentConn; //readonly by threads
+		//vector<int> curProcess_i;
+		int _ipcBufSize;
+		int _processes; //processes per thread
+		vector<uint8_t*> perCPUData;
+		bool hasAttachments;
+	};
+	static const char* socketd_proxy = "socketd_proxy.so";
+	class socketd
+	{
+	public:
+		//user supplied fields
+		vector<listen> listens;
+		vector<vhost> vhosts;
+		vector<binding> extraBindings; //vhostName must be filled for these
+		string unixAddress;
+		uint8_t** perCPUData;
+		//format of per-cpu data structures:
+		//struct {
+		//		appConnection* conns[processes];
+		//		int curProcess;
+		//		int padding;
+		//} vhostInfo[vhosts];
+		int ipcBufSize; //<=0 to use system default
+		int threads;
+		void run();
+
+		//internal fields
+		vector<binding*> bindings;
+		socketd() :
+				ipcBufSize(0), threads((int) sysconf(_SC_NPROCESSORS_CONF)) {
+		}
+	};
+
+}
+
+#endif /* CONFIG_HPP_ */

+ 100 - 0
cpoll_cppsp/cppsp_rel0.2.3/socketd/main.C

@@ -0,0 +1,100 @@
+/*
+ * main.cpp
+ *
+ *  Created on: 2011-05-20
+ *      Author: xaxaxa
+ */
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * */
+#include <assert.h>
+#include "include/socketd_internal.H"
+#include "include/configparser.H"
+#include <cpoll/cpoll.H>
+#include <tuple>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <stdexcept>
+
+using namespace RGC;
+using namespace socketd;
+using namespace std;
+void listenthread();
+
+tuple<const char*, int> mapFile(const char* path) {
+	struct stat st;
+	if (stat(path, &st) != 0) {
+		if (errno == ENOENT) return make_tuple((const char*) NULL, 0);
+		else throw runtime_error(strerror(errno));
+	}
+	if (st.st_size == 0) return make_tuple((const char*) 1, 0);
+	int fd = open(path, O_RDONLY);
+	if (fd < 0) throw runtime_error(strerror(errno));
+
+	void* tmp = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+	if (tmp == NULL) throw runtime_error(strerror(errno));
+	return make_tuple((const char*) tmp, st.st_size);
+}
+socketd::socketd sd;
+#define PRINTSIZE(x) printf("sizeof("#x") = %i\n",sizeof(x))
+
+int main(int argc, char** argv) {
+	if (argc < 2) {
+		printf("usage: %s socketd.conf\n", argv[0]);
+		return 1;
+	}
+	{
+		const char* confPath = argv[1];
+		tuple<const char*, int> conf = mapFile(confPath);
+		if (get < 0 > (conf) == NULL) {
+			printf("config file not found: %s\n", strerror(errno));
+			return 1;
+		}
+		loadConfig(get < 0 > (conf), get < 1 > (conf), sd);
+		munmap((void*)get < 0 > (conf), get < 1 > (conf));
+	}
+	/*
+	 sd.listens.push_back( { "0.0.0.0", "16969", 1, 32 });
+	 sd.vhosts.push_back( { { { 0, "/asdf", "", binding::match_httpPath } }, "vhost1",
+	 "/home/xaxaxa/workspace/test/socketd_test", "", true });
+	 sd.vhosts.push_back( { { { 0, "/zxcv", "", binding::match_httpPath } }, "vhost2",
+	 "/home/xaxaxa/workspace/test/socketd_test", "", false });
+	 sd.vhosts.push_back( { { { 0, "/zzz", "", binding::match_httpPath } }, "vhost3",
+	 "exec nc -l 0.0.0.0 12345 < /dev/urandom", "", true });
+	 sd.vhosts.push_back( { { { 0, "/sss", "", binding::match_httpPath } }, "vhost4",
+	 "lighttpd -D -f /home/xaxaxa/workspace/test/lighttpd.conf", "", true });*/
+//sd.vhosts.push_back({{{1,"","",binding::match_listenID}},"vhost1","/home/xaxaxa/workspace/test/socketd_test",""});
+	PRINTSIZE(socketd::socketd);
+	PRINTSIZE(socketd::vhost);
+	PRINTSIZE(socketd::listen);
+	sd.run();
+}
+void listenthread() {
+//CP::Poll p;
+
+	/*config::rtconfigmanager *c=config::rtconfigmanager::getmainconfig();
+	 SocketManager m;
+	 int i;
+	 for(i=0;i<c->listens_c;i++)
+	 {
+	 Socket s(AF_INET,SOCK_STREAM|SOCK_CLOEXEC,0);
+	 s.Bind(c->listens[i].ep);
+	 s.Listen(c->listens[i].backlog);
+	 m.BeginAccept(s,SocketManager::Callback(cb1,NULL));
+	 }
+	 m.EventLoop();*/
+
+}

+ 799 - 0
cpoll_cppsp/cppsp_rel0.2.3/socketd/socketd.C

@@ -0,0 +1,799 @@
+/*
+ * config.cpp
+ *
+ *  Created on: 2011-05-20
+ *      Author: xaxaxa
+ *
+ *
+ */
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * */
+#define _ISOC11_SOURCE
+#include "include/socketd_internal.H"
+#include <cpoll/sendfd.H>
+#include <cpoll/statemachines.H>
+#include <stdexcept>
+#include <unistd.h>
+#include <stdint.h>
+#include <rgc.H>
+#include <signal.h>
+#include <tuple>
+#include <ctype.h>
+#include <delegate.H>
+#include <set>
+#include <stdlib.h>
+#include <math.h>
+
+#define PRINTSIZE(x) printf("sizeof("#x") = %i\n",sizeof(x))
+#define SOCKETD_READBUFFER 256
+
+//maximum length of user-controlled data on the stack (for example, http header names)
+//in order to prevent stack overflow attacks
+#define SOCKETD_STACKBUFFER 256
+using namespace std;
+using namespace CP;
+//8: debug; 5: info; 3: warn; 2: err; 1: fatal
+#define SOCKETD_DEBUG(LEVEL, ...) if(LEVEL<=5)printf(__VA_ARGS__)
+//#define SOCKETD_DEBUG(...) /* __VA_ARGS__ */
+namespace socketd
+{
+	static int asdf = 0;
+	//static const int rBufSize = 4096;
+	//static const int rLineBufSize = 512;
+	void spawnApp(vhost* vh, CP::Poll& p, string exepath, int threadID, int i);
+	bool comparePath(const char* conf, int confLen, const char* path, int pathLen) {
+		SOCKETD_DEBUG(10, "comparePath: conf=%s; path=%s\n", string(conf, confLen).c_str(),
+				string(path, pathLen).c_str());
+		//cout << string(path, pathLen) << endl;
+		if (confLen == pathLen && memcmp(conf, path, confLen) == 0) {
+			/*cout << "matched (exact): " << string(path, pathLen) << " against " << string(conf, confLen)
+			 << endl;*/
+			return true;
+		}
+		if (pathLen > confLen && memmem(path, pathLen, conf, confLen) == path
+				&& (confLen == 1 || path[confLen] == '/')) {
+			/*cout << "matched (substring): " << string(path, pathLen) << " against " << string(conf, confLen)
+			 << endl;*/
+			return true;
+		}
+		//
+		return false;
+	}
+	bool compareHost(const char* conf, int confLen, const char* host, int hostLen) {
+		if (confLen == hostLen && memcmp(conf, host, confLen) == 0) {
+			return true;
+		}
+		if (confLen >= 1 && conf[0] == '*') {
+			if (((const char*) memmem(host, hostLen, conf + 1, confLen - 1)) - host
+					== (hostLen - (confLen - 1))) {
+				return true;
+			}
+		}
+		return false;
+	}
+	SocketDException::SocketDException() :
+			message(strerror(errno)), number(errno) {
+	}
+	SocketDException::SocketDException(int32_t number) :
+			message(strerror(number)), number(number) {
+	}
+	SocketDException::SocketDException(string message, int32_t number) :
+			message(message), number(number) {
+	}
+	SocketDException::~SocketDException() throw () {
+	}
+	const char* SocketDException::what() const throw () {
+		return message.c_str();
+	}
+	char* strupper(char* s, int len) {
+		for (char* p = s; *p; ++p)
+			*p = toupper(*p);
+		return s;
+	}
+	char* strlower(char* s, int len) {
+		for (char* p = s; *p; ++p)
+			*p = tolower(*p);
+		return s;
+	}
+	bool compareStringCI(const char* s1, const char* s2, int l) {
+		for (int i = 0; i < l; i++) {
+			if (tolower(s1[i]) != tolower(s2[i])) return false;
+		}
+		return true;
+	}
+	bool compareStringCI(const char* s1, int l1, const char* s2) {
+		int l2 = strlen(s2);
+		if (l1 != l2) return false;
+		return compareStringCI(s1, s2, l1);
+	}
+
+	int& getCurProcess(vhost* vh, socketd* This, int threadID) {
+		uint8_t* data = vh->perCPUData[threadID];
+		uint8_t* tmp = data + sizeof(appConnection*) * vh->_processes;
+		return *(int*) tmp;
+	}
+	appConnection* getConn(vhost* vh, int threadID, int i) {
+		uint8_t* data = vh->perCPUData[threadID];
+		uint8_t* tmp = data + sizeof(appConnection*) * i;
+		return *(appConnection**) tmp;
+	}
+	void setConn(vhost* vh, int threadID, int i, appConnection* c) {
+		uint8_t* data = vh->perCPUData[threadID];
+		uint8_t* tmp = data + sizeof(appConnection*) * i;
+		appConnection*& conn = *(appConnection**) tmp;
+		if (conn != NULL) conn->release();
+		conn = c;
+		if (conn != NULL) conn->retain();
+	}
+	struct connectionInfo
+	{
+		socketd* This;
+		listen* l;
+		CP::Socket s;
+		CP::Poll* p;
+		vhost* tmp_vh;
+		appConnection* tmpptr;
+		bool* deletionFlag;
+		//CP::streamReader* sr;
+		char _sr[sizeof(CP::newPersistentStreamReader)];
+
+		//int lineBufLen;
+		const char* httpPath;
+		const char* httpHost;
+		int httpPathLength;
+		int httpHostLength;
+
+		int tries;
+		//0: none; 1: reqLine; 2: headers
+		int readTo;
+		int pos;
+		int threadID;
+		int processIndex;
+
+		bool firstLine;
+		bool reading;
+		bool cancelread;
+		bool shouldDelete;
+		bool streamReaderInit;
+
+		int& getCurProcess(vhost* vh) {
+			return ::socketd::getCurProcess(vh, This, threadID);
+		}
+		appConnection* getConn(vhost* vh, int i) {
+			uint8_t* data = vh->perCPUData[threadID];
+			uint8_t* tmp = data + sizeof(appConnection*) * i;
+			return *(appConnection**) tmp;
+		}
+		void setConn(vhost* vh, int i, appConnection* c) {
+			uint8_t* data = vh->perCPUData[threadID];
+			uint8_t* tmp = data + sizeof(appConnection*) * i;
+			appConnection*& conn = *(appConnection**) tmp;
+			if (conn != NULL) conn->release();
+			conn = c;
+			if (conn != NULL) conn->retain();
+		}
+		connectionInfo(int fd, int d, int t, int p) :
+				s(fd, d, t, p), deletionFlag(NULL), tries(0), readTo(0), pos(0), processIndex(-1),
+						shouldDelete(false), streamReaderInit(false) {
+		}
+		void startRead();
+		void checkMatch();
+		void startSocketRead();
+		void socketReadCB(int r) {
+			SOCKETD_DEBUG(9, "got %i bytes of data from client socket\n", r);
+			CP::newPersistentStreamReader* sr = (CP::newPersistentStreamReader*) _sr;
+			if (r > 0) {
+				bool d(false);
+				deletionFlag = &d;
+				sr->endPutData(r);
+				newPersistentStreamReader::item it;
+				if (sr->process(it)) readCB((uint8_t*) it.data.data(), it.data.length());
+				if (d) return;
+				deletionFlag = NULL;
+			}
+
+			reading = false;
+			if (shouldDelete) {
+				delete this;
+				return;
+			}
+			if (cancelread) return;
+			if (r <= 0) {
+				String s = sr->getBufferData();
+				sr->clearBuffer();
+				readCB((uint8_t*) s.data(), s.length());
+				return;
+			}
+			startSocketRead();
+		}
+		void processLine(uint8_t* buf, int len) {
+			//uint8_t* lineBuf = ((uint8_t*) sr) + CP::streamReader_getSize() + rBufSize;
+			uint8_t* lineBuf = buf;
+			int lineBufLen = len;
+			SOCKETD_DEBUG(10, "got line: %s\n", string((const char* )lineBuf, lineBufLen).c_str());
+			//printf("got line: ");
+			//fflush(stdout);
+			//write(1, lineBuf, lineBufLen);
+			//printf("\n");
+			if (len <= 0) goto fail;
+
+			if (firstLine) {
+				firstLine = false;
+				uint8_t* tmp = (uint8_t*) memchr(lineBuf, ' ', lineBufLen);
+				if (tmp == NULL) goto fail;
+				tmp++;
+				if (lineBuf + lineBufLen - tmp <= 0) goto fail;
+				uint8_t* tmp1 = (uint8_t*) memchr(tmp, ' ', lineBuf + lineBufLen - tmp);
+				if (tmp1 == NULL) goto fail;
+				const char* path = (const char*) tmp;
+				int pathLen = tmp1 - tmp;
+				if (pathLen <= 0) goto fail;
+				pos = 1;
+				httpPath = path;
+				httpPathLength = pathLen;
+				SOCKETD_DEBUG(10, "got httpPath: %s\n", string(httpPath, httpPathLength).c_str());
+				checkMatch();
+				return;
+			}
+
+			const uint8_t* tmp;
+			const uint8_t* end;
+			end = buf + len;
+			tmp = (const uint8_t*) memchr(buf, ':', len);
+			if (tmp == NULL) goto cont;
+			int i;
+			i = tmp - buf;
+			if (i > SOCKETD_STACKBUFFER) goto fail;
+			if (compareStringCI((const char*) buf, i, "host")) {
+				tmp++;
+				while (tmp < end && *tmp == ' ')
+					tmp++;
+				if (tmp >= end) goto fail;
+				httpHost = (const char*) tmp;
+				httpHostLength = end - tmp;
+				SOCKETD_DEBUG(10, "got httpHost: %s\n", string(httpHost, httpHostLength).c_str());
+				pos = 2;
+				checkMatch();
+				return;
+			}
+			cont: startRead();
+			return;
+			fail: delete this;
+		}
+		void readCB(uint8_t* buf, int len) {
+			/*uint8_t* lineBuf;
+			 if (len <= 0) goto aaa;
+			 //overflowed the line buffer
+			 if (lineBufLen + len > rLineBufSize) goto fail;
+			 lineBuf = ((uint8_t*) sr) + CP::streamReader_getSize() + rBufSize;
+			 memcpy(lineBuf + lineBufLen, buf, len);
+			 lineBufLen += len;
+			 aaa: if (last) {
+			 cancelread = true;
+			 processLine();
+			 }
+			 return;
+			 fail: delete this;*/
+			cancelread = true;
+			processLine(buf, len);
+		}
+		inline int connIndex(vhost* vh) {
+			return threadID * vh->_processes + processIndex;
+		}
+
+		void attachmentCB(bool b) {
+			if (b) {
+				SOCKETD_DEBUG(8, "received acknownedgement for connection %p (with attachment)\n",
+						this);
+				delete this;
+			} else {
+				do_transfer(tmp_vh);
+			}
+		}
+		void appCB(bool b) {
+			if (b) {
+				SOCKETD_DEBUG(8, "received acknownedgement for connection %p\n", this);
+				delete this;
+			} else {
+				if (tmpptr == getConn(tmp_vh, processIndex)) {
+					getConn(tmp_vh, processIndex)->shutDown();
+					setConn(tmp_vh, processIndex, NULL);
+				}
+				do_transfer(tmp_vh);
+			}
+		}
+		//transfer socket to application
+		void do_transfer(vhost* vh) {
+			//cout << "do_transfer" << endl;
+			SOCKETD_DEBUG(8, "do_transfer (%p)\n", this);
+			retry: if ((++tries) > 3) {
+				SOCKETD_DEBUG(3, "exceeded 3 tries for connection %p\n", this);
+				if (reading) shouldDelete = true;
+				else delete this;
+				return;
+			}
+			if (processIndex < 0) {
+				processIndex = (getCurProcess(vh)++) % vh->_processes;
+			}
+			if (getConn(vh, processIndex) == NULL && vh->exepath.length() > 0) {
+				spawnApp(vh, *p, vh->exepath, threadID, processIndex);
+			}
+			uint8_t* buf;
+			int bufLen;
+			if (streamReaderInit) {
+				CP::newPersistentStreamReader* sr = (CP::newPersistentStreamReader*) _sr;
+				String s = sr->getHistory();
+				buf = (uint8_t*) s.data();
+				bufLen = s.length();
+			} else {
+				buf = NULL;
+				bufLen = 0;
+			}
+			if (vh->attachmentConn() != NULL) {
+				tmp_vh = vh;
+				int r = vh->attachmentConn->passConnection(&s, NULL, 0,
+						appConnection::passConnCB(&connectionInfo::attachmentCB, this));
+				if (r == 1) { //fail
+					goto aaaaa;
+				} else if (r == 0) { //success
+					SOCKETD_DEBUG(8, "connection %p pre-succeeded (with attachment)\n", this);
+					delete this;
+					return;
+				} else return;
+			}
+			aaaaa: if (getConn(vh, processIndex) != NULL) {
+				//cout << "vh->conn() != NULL" << endl;
+				appConnection* tmpptr = getConn(vh, processIndex);
+				this->tmp_vh = vh;
+				this->tmpptr = tmpptr;
+				SOCKETD_DEBUG(8, "bufLen=%i\n", bufLen);
+				int r = tmpptr->passConnection(&s, buf, bufLen,
+						appConnection::passConnCB(&connectionInfo::appCB, this));
+				if (r == 1) {
+					//application possibly dead; respawn
+					tmpptr->shutDown();
+					if (tmpptr == getConn(vh, processIndex)) setConn(vh, processIndex, NULL);
+					goto retry;
+				} else if (r == 0) {
+					SOCKETD_DEBUG(8, "connection %p pre-succeeded\n", this);
+					delete this;
+					return;
+				} else return;
+			} else {
+				//no handler found; reset connection
+				SOCKETD_DEBUG(5, "no handler for connection %p\n", this);
+				delete this;
+			}
+
+		}
+		void process() {
+			SOCKETD_DEBUG(9, "connectionInfo::process()\n");
+			checkMatch();
+		}
+
+		~connectionInfo() {
+			SOCKETD_DEBUG(9, "~connectionInfo (%p)\n", this);
+			//s.release();
+			if (streamReaderInit) {
+				CP::newPersistentStreamReader* sr = (CP::newPersistentStreamReader*) _sr;
+				sr->~newPersistentStreamReader();
+			}
+			if (deletionFlag != NULL) *deletionFlag = true;
+		}
+	};
+	void connectionInfo::startSocketRead() {
+		if (reading) return;
+		CP::newPersistentStreamReader* sr = (CP::newPersistentStreamReader*) _sr;
+		auto tmp = sr->beginPutData(SOCKETD_READBUFFER);
+		SOCKETD_DEBUG(9, "attempting to read %i bytes of data from client socket\n",
+				SOCKETD_READBUFFER);
+		reading = true;
+		s.read(tmp.data(), SOCKETD_READBUFFER, CP::Callback(&connectionInfo::socketReadCB, this));
+	}
+	void connectionInfo::checkMatch() {
+		//figure out what needs to be read to decide which binding to use
+
+		//0: none; 1: reqLine; 2: headers
+		//int readTo = 0;
+		if (pos < readTo) {
+			startRead();
+			return;
+		}
+		SOCKETD_DEBUG(9, "bindings.size() = %i\n", This->bindings.size());
+
+		for (uint32_t i = 0; i < This->bindings.size(); i++) {
+			SOCKETD_DEBUG(9, "This->bindings[i]->listenID = %i\n", This->bindings[i]->listenID);
+			if (!(This->bindings[i]->matchLevel & This->bindings[i]->match_listenID)
+					|| This->bindings[i]->listenID == l->id) {
+				if (This->bindings[i]->matchLevel & binding::match_httpPath) {
+					if (pos < 1) {
+						readTo = 1;
+						break;
+					} else {
+						if (comparePath(This->bindings[i]->httpPath.data(),
+								This->bindings[i]->httpPath.length(), httpPath, httpPathLength)) {
+							goto matched_httpPath;
+						} else continue;
+					}
+				} else {
+					matched_httpPath: if (This->bindings[i]->matchLevel & binding::match_httpHost) {
+						if (pos < 2) {
+							readTo = 2;
+							break;
+						} else {
+							if (comparePath(This->bindings[i]->httpHost.data(),
+									This->bindings[i]->httpHost.length(), httpHost, httpHostLength)) {
+								goto matched_httpHost;
+							} else continue;
+						}
+					} else {
+						matched_httpHost: do_transfer(This->bindings[i]->vh);
+						return;
+					}
+				}
+			}
+		}
+		SOCKETD_DEBUG(9, "readTo=%i pos=%i\n", readTo, pos);
+		if (readTo > pos) {
+			if (pos == 0) {
+				//initialize streamReader
+				CP::newPersistentStreamReader* sr;
+				sr = new (_sr) CP::newPersistentStreamReader(SOCKETD_READBUFFER);
+				streamReaderInit = true;
+				//if (sr == NULL) goto fail;
+				//CP::streamReader_init(sr, rBufSize);
+				firstLine = true;
+				reading = false;
+				p->add(s);
+			}
+			startRead();
+		} else goto fail;
+		return;
+		fail: if (reading) shouldDelete = true;
+		else delete this;
+	}
+	void connectionInfo::startRead() {
+		CP::newPersistentStreamReader* sr = (CP::newPersistentStreamReader*) _sr;
+		sr->readUntilString("\r\n", 2);
+		newPersistentStreamReader::item it;
+		if (sr->process(it)) readCB((uint8_t*) it.data.data(), it.data.length());
+		else {
+			cancelread = false;
+			startSocketRead();
+		}
+	}
+	appConnection::appConnection() {
+	}
+
+	appConnection::~appConnection() {
+//if(vh!=NULL && vh->conn==this) vh->conn=NULL;
+	}
+	struct appConnection_unix: public appConnection
+	{
+		RGC::Ref<CP::Socket> unixsock;
+
+//not yet acknowledged
+		map<int64_t, passConnCB> pendingConnections;
+		int64_t maxID;
+		protocolHeader buf;
+		prot_ackConnection buf1;
+		CP::Poll& p;
+		socketd* sd;
+		set<vhost*> bound_vhosts;
+		pid_t pid;
+//char sbuf[sizeof(protocolHeader)+sizeof(prot_handleConnection)];
+		bool dead;
+		bool down;
+
+		virtual void shutDown() {
+			if (!down) {
+				down = true;
+				unixsock->close();
+				kill(pid, 15);
+			}
+		}
+		void die(int64_t ignoreID) {
+			if (dead) return;
+			//throw 5;
+			dead = true;
+			for (auto it = pendingConnections.begin(); it != pendingConnections.end(); it++) {
+				if ((*it).first != ignoreID) (*it).second(false);
+			}
+			pendingConnections.clear();
+			shutDown();
+		}
+		void startRead();
+		void ackConnectionCB(int r) {
+			if (r <= 0) {
+				die(0);
+			}
+			if (dead) {
+				release();
+				return;
+			}
+			//printf("%i\n",buf1.id);
+			auto it = pendingConnections.find(buf1.id);
+			if (it != pendingConnections.end()) {
+				(*it).second(buf1.success);
+				pendingConnections.erase(it);
+			}
+			startRead();
+		}
+		void readCB(int r) {
+			if (r <= 0) {
+				SOCKETD_DEBUG(5, "application died; r=%i; errno: %s\n", r, strerror(errno));
+				die(0);
+			}
+			if (dead) {
+				release();
+				return;
+			}
+			switch (buf.type) {
+				case protocolHeader::ackConnection:
+				{
+					unixsock->read(&buf1, sizeof(buf1),
+							CP::Callback(&appConnection_unix::ackConnectionCB, this));
+					break;
+				}
+				default:
+					startRead();
+					break;
+			}
+		}
+		appConnection_unix(vhost* vh, CP::Poll& p, string exepath) :
+				maxID(0), p(p), pid(0), dead(false), down(false) {
+			int socks[2];
+			if (socketpair(AF_UNIX, SOCK_STREAM, 0, socks) < 0) {
+				throw runtime_error(strerror(errno));
+			}
+			if (vh->_ipcBufSize > 0) {
+				int n;
+				unsigned int n_size = sizeof(n);
+				n = vh->_ipcBufSize;
+				setsockopt(socks[0], SOL_SOCKET, SO_RCVBUF, (void *) &n, n_size);
+				setsockopt(socks[0], SOL_SOCKET, SO_SNDBUF, (void *) &n, n_size);
+				setsockopt(socks[1], SOL_SOCKET, SO_RCVBUF, (void *) &n, n_size);
+				setsockopt(socks[1], SOL_SOCKET, SO_SNDBUF, (void *) &n, n_size);
+			}
+			pid_t pid = fork();
+			if (pid < 0) throw runtime_error(strerror(errno));
+			else if (pid == 0) {
+				//child
+				close(socks[0]);
+				if (socks[1] != 3) {
+					dup2(socks[1], 3); //fd 3
+					close(socks[1]);
+				}
+				setenv("SOCKETD_FD", "3", 1);
+				if (vh->preload) {
+					setenv("LD_PRELOAD", socketd_proxy, 1);
+				}
+				if (vh->useShell) execlp("/bin/sh", "/bin/sh", "-c", exepath.c_str(),
+						(const char*) NULL);
+				else execlp(exepath.c_str(), exepath.c_str(), (const char*) NULL);
+				_exit(1);
+			} else {
+				//parent
+				close(socks[1]);
+				this->pid = pid;
+				//getsockopt(socks[0], SOL_SOCKET, SO_RCVBUF, (void *) &n, &n_size);
+				//SOCKETD_DEBUG(8, "unix socket receive buffer size: %i\n", n);
+
+				unixsock = RGC::newObj<CP::Socket>(socks[0], AF_UNIX, SOCK_STREAM, 0);
+				p.add(*unixsock);
+				//printf("asdfg %i\n", ++asdf);
+				retain();
+				startRead();
+			}
+		}
+		appConnection_unix(CP::Socket* sock, CP::Poll& p, socketd* sd) :
+				maxID(0), p(p), sd(sd), dead(false), down(false) {
+
+		}
+		virtual int passConnection(CP::Socket* s, void* buffer, int buflen, const passConnCB& cb) {
+			if (dead) return 1;
+			//printf("passConnection\n");
+			//s->retain();
+			int64_t id = (++maxID);
+			int r;
+			{
+				int len = sizeof(protocolHeader) + sizeof(prot_handleConnection);
+				uint8_t* hdr[len];
+				memset(hdr, 0, len);
+				protocolHeader* ph = new (hdr) protocolHeader();
+				prot_handleConnection* ph1 = new (ph + 1) prot_handleConnection();
+
+				ph->type = protocolHeader::handleConnection;
+				//printf("zxcv %lli\n",id);
+				ph1->id = id;
+				ph1->d = s->addressFamily;
+				ph1->t = s->type;
+				ph1->p = s->protocol;
+				ph1->bufferLen = buflen;
+				//socket has SOCK_NONBLOCK set, so regular send() won't block;
+				//if the socket buffer is full, then the application is already
+				//considered dead
+				r = unixsock->sendAll(hdr, len, MSG_DONTWAIT);
+				ph->~protocolHeader();
+				ph1->~prot_handleConnection();
+			}
+			if (r <= 0) goto fail;
+			if (sendfd(unixsock->handle, s->handle) < 0) goto fail;
+			if (buflen > 0) if (unixsock->sendAll(buffer, buflen, MSG_DONTWAIT) <= 0) goto fail;
+			//s->release();
+			pendingConnections.insert( { id, cb });
+			return 2;
+			fail: //s->release();
+			SOCKETD_DEBUG(1, "unix socket buffer overflow; %s\n", strerror(errno));
+			die(id);
+			return 1;
+		}
+		virtual ~appConnection_unix() {
+		}
+
+	};
+	void appConnection_unix::startRead() {
+		unixsock->read(&buf, sizeof(buf), CP::Callback(&appConnection_unix::readCB, this));
+	}
+	void spawnApp(vhost* vh, CP::Poll& p, string exepath, int threadID, int i) {
+		setConn(vh, threadID, i, RGC::newObj<appConnection_unix>(vh, p, exepath));
+	}
+
+	struct socketd_execinfo;
+	struct socketd_thread
+	{
+		socketd* This;
+		socketd_execinfo* execinfo;
+		pthread_t thr;
+		int id;
+	};
+	struct socketd_execinfo
+	{
+		vector<socketd_thread> threads;
+	};
+	void* socketd_processorThread(void* v) {
+		socketd_thread* th = (socketd_thread*) v;
+		CP::Poll p;
+		for (uint32_t i = 0; i < th->This->listens.size(); i++) {
+			auto& l = th->This->listens[i];
+			struct cb1
+			{
+				CP::Poll& poll;
+				socketd_thread* th;
+				listen& l;
+				Socket s;
+				cb1(Poll& poll, socketd_thread* th, listen& l) :
+						poll(poll), th(th), l(l), s(l.socks[th->id], l.d, l.t, l.p) {
+					s.repeatAcceptHandle(this);
+					poll.add(s);
+				}
+				void operator()(HANDLE h) {
+					connectionInfo* ci = new connectionInfo(h, l.d, l.t, l.p);
+					ci->threadID = th->id;
+					ci->This = th->This;
+					ci->l = &l;
+					SOCKETD_DEBUG(9, "req.l.id = %i\n", l.id);
+					ci->p = &poll;
+					ci->process();
+				}
+			}* cb = new cb1(p, th, l);
+		}
+		p.loop();
+		printf("%i exited\n", th->id);
+		return NULL;
+	}
+	void socketd::run() {
+		PRINTSIZE(CP::Socket);
+		PRINTSIZE(CP::newPersistentStreamReader);
+		PRINTSIZE(connectionInfo);
+//ignore SIGCHLD
+		struct sigaction sa;
+		sa.sa_handler = SIG_IGN;
+		sigemptyset(&sa.sa_mask);
+		sa.sa_flags = SA_RESTART; /* Restart system calls if
+		 interrupted by handler */
+		sigaction(SIGCHLD, &sa, NULL);
+
+		CP::Poll p;
+		//p.debug=true;
+		this->bindings.clear();
+		for (int i = 0; i < (int) vhosts.size(); i++) {
+			vhosts[i]._processes = ceil(double(vhosts[i].processes) / threads);
+			if (vhosts[i]._processes < 1) vhosts[i]._processes = 1;
+		}
+
+		perCPUData = new uint8_t*[threads];
+		for (int i = 0; i < threads; i++) {
+			int s = 0;
+			for (int ii = 0; ii < (int) vhosts.size(); ii++) {
+				s += sizeof(appConnection*) * vhosts[ii]._processes;
+				s += sizeof(int) * 2;
+			}
+			int align = 64;
+			if (s % align != 0) s = ((s / align) + 1) * align;
+			uint8_t* tmp; // = aligned_alloc(64, s);
+			if (posix_memalign((void**) &tmp, align, s) != 0) throw bad_alloc();
+			memset(tmp, 0, s);
+			s = 0;
+			for (int ii = 0; ii < (int) vhosts.size(); ii++) {
+				vhosts[ii].perCPUData.push_back(tmp + s);
+				s += sizeof(appConnection*) * vhosts[ii]._processes;
+				s += sizeof(int) * 2;
+			}
+		}
+		for (uint32_t i = 0; i < vhosts.size(); i++) {
+			for (uint32_t ii = 0; ii < vhosts[i].bindings.size(); ii++) {
+				binding* tmp = &(vhosts[i].bindings[ii]);
+				this->bindings.push_back(tmp);
+				vhosts[i].bindings[ii].vh = &vhosts[i];
+			}
+			vhosts[i]._ipcBufSize = vhosts[i].ipcBufSize < 0 ? this->ipcBufSize : vhosts[i].ipcBufSize;
+			vhosts[i].hasAttachments = false;
+			//vhosts[i].conns.resize(nthreads * vhosts[i].processes);
+			//vhosts[i].curProcess.resize(nthreads);
+			vhosts[i].perCPUData.resize(threads);
+		}
+		for (uint32_t i = 0; i < extraBindings.size(); i++) {
+			for (uint32_t ii = 0; ii < vhosts.size(); ii++) {
+				if (vhosts[ii].name == extraBindings[i].vhostName) {
+					extraBindings[i].vh = &vhosts[ii];
+					break;
+				}
+			}
+			binding* tmp = &(extraBindings[i]);
+			this->bindings.push_back(tmp);
+		}
+		//start up unix listening socket
+		/*if (unixAddress.length() > 0) {
+		 CP::Socket* unixsock = new CP::Socket(AF_UNIX, SOCK_STREAM);
+		 unixsock->bind(CP::UNIXEndPoint(unixAddress));
+		 unixsock->listen(8);
+		 unixsock->repeatAccept([](CP::Socket* s) {
+
+		 });
+		 }*/
+
+		SOCKETD_DEBUG(9, "bindings.size() = %i\n", bindings.size());
+		for (uint32_t i = 0; i < listens.size(); i++) {
+			auto& l = listens[i];
+			Socket tmp;
+			tmp.bind(l.host.c_str(), l.port.c_str(), AF_UNSPEC, SOCK_STREAM);
+			tmp.listen(l.backlog);
+			l.d = tmp.addressFamily;
+			l.t = tmp.type;
+			l.p = tmp.protocol;
+			l.socks.resize(threads);
+			for (int ii = 0; ii < threads; ii++) {
+				l.socks[ii] = dup(tmp.handle);
+			}
+		}
+		socketd_execinfo execinfo;
+		printf("this=%p\n", this);
+		execinfo.threads.resize(threads);
+		SOCKETD_DEBUG(3, "starting %i threads\n", threads);
+		for (int i = 0; i < threads; i++) {
+			socketd_thread& th = execinfo.threads[i];
+			th.This = this;
+			th.execinfo = &execinfo;
+			th.id = i;
+			//printf("%p %p\n",&th, &th1);
+			if (pthread_create(&th.thr, NULL, socketd_processorThread, &th) != 0) {
+				throw runtime_error(strerror(errno));
+			}
+		}
+		while (true)
+			sleep(3600);
+	}
+}

+ 47 - 0
cpoll_cppsp/cppsp_rel0.2.3/socketd/socketd.conf

@@ -0,0 +1,47 @@
+listen 0.0.0.0:16969 512; //backlog=512
+listen 0.0.0.0:23456;
+threads 4;
+
+//bindings sections embedded in vhost sections are processed
+//before bindings in the global scope
+ipcbuffersize 16777216;
+vhost vh1 {
+	bindings {
+		{
+			listen 0.0.0.0:16969;
+			httppath /asdf;
+		}
+	}
+	exec /home/xaxaxa/workspace/test/socketd_test $(uname -a);
+	shell 1;
+	preload 0;
+	//at runtime, the # of processes will be rounded up to the nearest multiple
+	//of the # of socketd threads, so the actual processes started will be 4
+	processes 1;
+
+	authcookie ghsdfjkgh;
+	ipcbuffersize 16777216;
+}
+vhost vh2 {
+	exec exec lighttpd -D -f /home/xaxaxa/workspace/test/lighttpd.conf;
+	shell 1;
+	preload 1;
+}
+vhost vh3 {
+	bindings {
+		{httppath /cppsp;}
+	}
+//	exec exec valgrind --leak-check=full socketd_cppsp -r /home/xaxaxa/workspace/test/ -c -I../include/ -c -L../lib/ -c -fPIC -c -g3;
+	exec exec socketd_cppsp -r /home/xaxaxa/workspace/test/ -c -I../include/ -c -L../lib/ -c -fPIC -c -g3;
+//	exec exec sleep 6000
+	shell 1;
+	preload 0;
+	processes 2;
+}
+binding vh1 {
+	httppath /test;
+}
+binding vh2 {
+	httppath /sss;
+}
+

BIN
cpoll_cppsp/cppsp_rel0.2.3/socketd_bin


BIN
cpoll_cppsp/cppsp_rel0.2.3/socketd_cppsp


+ 32 - 0
cpoll_cppsp/cppsp_rel0.2.3/socketd_example.conf

@@ -0,0 +1,32 @@
+listen 0.0.0.0:16969 512; //backlog=512
+//default thread count is NCPU
+//threads 2;
+
+//bindings sections embedded in vhost sections are processed
+//before bindings in the global scope
+ipcbuffersize 16777216;
+vhost vh1 {
+	bindings {
+		{
+			listen 0.0.0.0:16969;
+			httphost localhost:16969; //only match requests going to hostname "localhost"
+		}
+	}
+	//the second exec is a shell command telling the shell to not fork, but execve() directly
+	exec exec '/home/xaxaxa/cppsp_rel0.2.1'/socketd_cppsp -m /dir_list.cppsm -r '/home/xaxaxa/cppsp_rel0.2.1'/www -c -fPIC -c -I'/home/xaxaxa/cppsp_rel0.2.1'/include -c -Ofast -c -march=native -c '/home/xaxaxa/cppsp_rel0.2.1'/cpoll.o -c '/home/xaxaxa/cppsp_rel0.2.1'/cppsp.o -f;
+	shell 1;
+	preload 0; //socketd_cppsp is a native socketd application; no need to preload socketd_proxy
+	//at runtime, the # of processes will be rounded up to the nearest multiple
+	//of the # of socketd threads, so the actual processes started will be NCPU
+	processes 1;
+}
+vhost vh2 {
+	bindings {
+		//adjust your /etc/hosts to test this
+		{httphost host1:16969;}	
+	}
+	exec exec lighttpd -D -f /path/to/lighttpd.conf;
+	shell 1;
+	preload 1; //preload socketd_proxy.so to run an unmodified http server under socketd
+}
+

+ 36 - 0
cpoll_cppsp/cppsp_rel0.2.3/socketd_exampleconf

@@ -0,0 +1,36 @@
+#!/bin/bash
+cat <<EOF
+listen 0.0.0.0:16969 512; //backlog=512
+//default thread count is NCPU
+//threads 2;
+
+//bindings sections embedded in vhost sections are processed
+//before bindings in the global scope
+ipcbuffersize 16777216;
+vhost vh1 {
+	bindings {
+		{
+			listen 0.0.0.0:16969;
+			httphost localhost:16969; //only match requests going to hostname "localhost"
+		}
+	}
+	//the second exec is a shell command telling the shell to not fork, but execve() directly
+	exec exec '$(pwd)'/socketd_cppsp -m /dir_list.cppsm -r '$(pwd)'/www -c -fPIC -c -I'$(pwd)'/include -c -Ofast -c -march=native -c '$(pwd)'/cpoll.o -c '$(pwd)'/cppsp.o -f;
+	shell 1;
+	preload 0; //socketd_cppsp is a native socketd application; no need to preload socketd_proxy
+	//at runtime, the # of processes will be rounded up to the nearest multiple
+	//of the # of socketd threads, so the actual processes started will be NCPU
+	processes 1;
+}
+vhost vh2 {
+	bindings {
+		//adjust your /etc/hosts to test this
+		{httphost host1:16969;}	
+	}
+	exec exec lighttpd -D -f /path/to/lighttpd.conf;
+	shell 1;
+	preload 1; //preload socketd_proxy.so to run an unmodified http server under socketd
+}
+
+EOF
+

+ 354 - 0
cpoll_cppsp/cppsp_rel0.2.3/socketd_proxy.C

@@ -0,0 +1,354 @@
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <map>
+#include <set>
+#include <iostream>
+#include <string>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <socketd.H>
+#include <cpoll/statemachines.H>
+#include <cpoll/sendfd.H>
+#include <fcntl.h>
+#include <poll.h>
+
+
+using namespace std;
+using namespace socketd;
+struct scopeLock
+{
+	pthread_mutex_t& mutex;
+	scopeLock(pthread_mutex_t& m):mutex(m)
+	{pthread_mutex_lock(&mutex);}
+	~scopeLock()
+	{pthread_mutex_unlock(&mutex);}
+};
+static void initMutex(pthread_mutex_t& mutex) {
+	pthread_mutexattr_t attr;
+	pthread_mutexattr_init(&attr);
+	pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+	int e;
+	if((e=pthread_mutex_init(&mutex,&attr))!=0) {
+		const char* err=strerror(e);
+		throw runtime_error("mutex initialization failed: "+string(err));
+	}
+	pthread_mutexattr_destroy(&attr);
+}
+
+static pthread_mutex_t mutex;
+struct vhostInfo
+{
+	string name;
+	string authToken;
+	int fd;
+	bool attach;
+};
+struct config
+{
+	map<int, vhostInfo> mappings;
+	vhostInfo defaultVhost;
+	bool hasDefault;
+};
+static bool configLoaded=false;
+static config cfg;
+static set<int> fds;
+struct bufferInfo
+{
+	uint8_t* buf;
+	int offset;
+	int len;
+};
+static map<int,bufferInfo> fdbuffers;
+static void loadConfig() {
+	if(configLoaded)return;
+	configLoaded=true;
+	char* tmp=getenv("SOCKETD_FD");
+	if((cfg.hasDefault=(tmp!=NULL))) {
+		cfg.defaultVhost.attach=false;
+		cfg.defaultVhost.fd=atoi(tmp);
+	}
+	initMutex(mutex);
+	//cfg.mappings.insert({12580,{"vhost1",""}});
+}
+typedef int (*bind_def)(int sockfd, const struct sockaddr *addr,
+                socklen_t addrlen);
+typedef int (*accept_def)(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
+typedef int (*accept4_def)(int sockfd, struct sockaddr *addr,
+                   socklen_t *addrlen, int flags);
+typedef int (*listen_def)(int sockfd, int backlog);
+typedef ssize_t (*recv_def)(int sockfd, void *buf, size_t len, int flags);
+typedef ssize_t (*read_def)(int fd, void *buf, size_t count);
+typedef int (*shutdown_def)(int sockfd, int how);
+typedef int (*close_def)(int fd);
+typedef int (*dup2_def)(int oldfd, int newfd);
+typedef int (*dup3_def)(int oldfd, int newfd, int flags);
+
+static bind_def prev_bind=NULL;
+static accept_def prev_accept=NULL;
+static accept4_def prev_accept4=NULL;
+static listen_def prev_listen=NULL;
+static recv_def prev_recv=NULL;
+static read_def prev_read=NULL;
+static shutdown_def prev_shutdown=NULL;
+static close_def prev_close=NULL;
+static dup2_def prev_dup2=NULL;
+static dup3_def prev_dup3=NULL;
+static int getPort(const struct sockaddr *addr, socklen_t addrlen) {
+	switch(addr->sa_family) {
+		case AF_INET:
+			return ntohs(((const sockaddr_in*)addr)->sin_port);
+		default:
+			return -1;
+	}
+}
+static int fixBind(int sockfd, const vhostInfo& vh) {
+	if(vh.attach) {
+		
+	} else {
+		if(prev_dup2==NULL) {
+			prev_dup2=(dup2_def)dlsym(RTLD_NEXT, "dup2");
+		}
+		prev_dup2(vh.fd,sockfd);
+		fds.insert(sockfd);
+	}
+	return 0;
+}
+extern "C" int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
+	if(prev_bind==NULL) {
+		prev_bind=(bind_def)dlsym(RTLD_NEXT, "bind");
+	}
+	printf("bind()\n");
+	int p=getPort(addr,addrlen);
+	if(p<0) goto aaa;
+	{
+		scopeLock l(mutex);
+		loadConfig();
+		auto it=cfg.mappings.find(p);
+		if(it==cfg.mappings.end()) {
+			if(cfg.hasDefault) return fixBind(sockfd,cfg.defaultVhost);
+		} else fixBind(sockfd,(*it).second);
+	}
+aaa:
+	return prev_bind(sockfd,addr,addrlen);
+}
+extern "C" int listen(int sockfd, int backlog) {
+	if(prev_listen==NULL) {
+		prev_listen=(listen_def)dlsym(RTLD_NEXT, "listen");
+	}
+	{
+		scopeLock l(mutex);
+		if(fds.count(sockfd)>0) return 0;
+	}
+	return prev_listen(sockfd, backlog);
+}
+
+static int fixAccept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
+	protocolHeader ph;
+	prot_handleConnection ph1;
+	int r;
+	r=recv(sockfd,&ph,sizeof(ph),0);
+	if(r<0) return -1;
+	if(r==0) exit(0);
+	if(r!=sizeof(ph)) {
+		fprintf(stderr,"failed to read struct protocolHeader (%i bytes) from fd %i: got %i bytes\n"
+				,sizeof(protocolHeader),r,sockfd);
+		exit(0);
+	}
+	if(ph.type!=protocolHeader::handleConnection) {
+		fprintf(stderr,"protocolHeader.type is not handleConnection; it is %i\n",(int)ph.type);
+		exit(0);
+	}
+	if((r=recv(sockfd,&ph1,sizeof(ph1),MSG_WAITALL))!=sizeof(ph1)) {
+		fprintf(stderr,"failed to read struct prot_handleConnection (%i bytes) from fd %i: got %i bytes\n"
+				,sizeof(prot_handleConnection),r,sockfd);
+		exit(0);
+	}
+aaaaa:
+	int fd=recvfd(sockfd,MSG_WAITALL);
+	if(fd<0) {
+		if(errno==EAGAIN || errno==EWOULDBLOCK) {
+			pollfd pfd;
+			pfd.fd = sockfd;
+			pfd.events = POLLIN;
+			if(poll(&pfd, 1, -1)<=0) return -1;
+			if(!(pfd.revents&POLLIN)) return -1;
+			goto aaaaa;
+		}
+		fprintf(stderr,"failed to recvfd() from fd %i; errno: %s\n",sockfd,strerror(errno));
+		exit(0);
+	}
+	if(ph1.bufferLen<=0) return fd;
+	getpeername(fd, addr, addrlen);
+	bufferInfo bi;
+	bi.buf=(uint8_t*)malloc(ph1.bufferLen);
+	if(bi.buf==NULL) {
+		close(fd);
+		errno=ENOMEM;
+		return -1;
+	}
+	bi.offset=0;
+	bi.len=ph1.bufferLen;
+bbbbb:
+	if((r=recv(sockfd,bi.buf,bi.len,MSG_WAITALL))!=bi.len) {
+		if(r<0 && (errno==EAGAIN||errno==EWOULDBLOCK)) {
+			pollfd pfd;
+			pfd.fd = sockfd;
+			pfd.events = POLLIN;
+			if(poll(&pfd, 1, -1)<=0) return -1;
+			if(!(pfd.revents&POLLIN)) return -1;
+			goto bbbbb;
+		}
+		fprintf(stderr,"failed to read %i bytes from fd %i: got %i bytes; errno: %s\n",bi.len,sockfd,r,strerror(errno));
+		exit(0);
+	}
+	fdbuffers.insert({fd,bi});
+	
+	ph.type=protocolHeader::ackConnection;
+	prot_ackConnection ack;
+	ack.id=ph1.id;
+	ack.success=true;
+	if(send(sockfd,&ph,sizeof(ph),MSG_DONTWAIT)==sizeof(ph)) {
+		send(sockfd,&ack,sizeof(ack),MSG_DONTWAIT);
+	}
+	
+	return fd;
+}
+static int tryFixAccept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
+	{
+		scopeLock l(mutex);
+		if(fds.count(sockfd)<=0) return -2;
+	}
+	return fixAccept(sockfd, addr, addrlen);
+}
+extern "C" int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
+	if(prev_accept==NULL) {
+		prev_accept=(accept_def)dlsym(RTLD_NEXT, "accept");
+	}
+	int fd=tryFixAccept(sockfd,addr,addrlen);
+	if(fd==-2) return prev_accept(sockfd, addr, addrlen);
+	else {
+		if(fd>=0) {
+			int f = fcntl(fd, F_GETFL, 0);
+			f=f&~O_NONBLOCK;
+			f=f&~O_CLOEXEC;
+			fcntl(fd, F_SETFL, f);
+		}
+		return fd;
+	}
+}
+
+extern "C" int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags) {
+	if(prev_accept4==NULL) {
+		prev_accept4=(accept4_def)dlsym(RTLD_NEXT, "accept4");
+	}
+	int fd=tryFixAccept(sockfd,addr,addrlen);
+	if(fd==-2) return prev_accept4(sockfd, addr, addrlen, flags);
+	else {
+		if(fd>=0) {
+			int f = fcntl(fd, F_GETFL, 0);
+			if(flags&SOCK_NONBLOCK)
+				f=f|O_NONBLOCK;
+			else f=f&~O_NONBLOCK;
+			if(flags&SOCK_CLOEXEC)
+				f=f|O_CLOEXEC;
+			else f=f&~O_CLOEXEC;
+			fcntl(fd, F_SETFL, f);
+		}
+		return fd;
+	}
+}
+#define __min(x,y) ((x<y)?x:y)
+static inline bufferInfo* getBufferInfo(int sockfd) {
+	scopeLock l(mutex);
+	auto it=fdbuffers.find(sockfd);
+	if(it!=fdbuffers.end()) {
+		return &(*it).second;
+	} else return NULL;
+}
+static int fixRead(bufferInfo* bi, int sockfd, void *buf, size_t len) {
+	//assumes that the application does not call recv() or read() on the same socket
+	//from 2 threads at once
+	int minLen=__min(len,bi->len - bi->offset);
+	memcpy(buf,bi->buf + bi->offset,minLen);
+	if((bi->offset+=minLen) >= bi->len) {
+		delete bi->buf;
+		scopeLock l(mutex);
+		fdbuffers.erase(sockfd);
+	}
+	return minLen;
+}
+extern "C" ssize_t recv(int sockfd, void *buf, size_t len, int flags) {
+	if(len<=0) return 0;
+	if(prev_recv==NULL) {
+		prev_recv=(recv_def)dlsym(RTLD_NEXT, "recv");
+	}
+	bufferInfo* bi=getBufferInfo(sockfd);
+	if(bi==NULL) return prev_recv(sockfd,buf,len,flags);
+	return fixRead(bi,sockfd,buf,len);
+}
+extern "C" ssize_t read(int fd, void *buf, size_t len) {
+	if(len<=0) return 0;
+	if(prev_read==NULL) {
+		prev_read=(read_def)dlsym(RTLD_NEXT, "read");
+	}
+	bufferInfo* bi=getBufferInfo(fd);
+	if(bi==NULL) return prev_read(fd,buf,len);
+	return fixRead(bi,fd,buf,len);
+}
+int shutdown(int sockfd, int how) {
+	if(prev_shutdown==NULL) {
+		prev_shutdown=(shutdown_def)dlsym(RTLD_NEXT, "shutdown");
+	}
+	bool isListen;
+	{
+		scopeLock l(mutex);
+		if(fds.count(sockfd)>0) {
+			fprintf(stderr,"attempting to shut down listening fd %i\n",sockfd);
+			return 0;
+		}
+	}
+	return prev_shutdown(sockfd,how);
+}
+int close(int fd) {
+	if(prev_close==NULL) {
+		prev_close=(close_def)dlsym(RTLD_NEXT, "close");
+	}
+	{
+		scopeLock l(mutex);
+		if(fds.count(fd)>0)
+			fds.erase(fd);
+	}
+	return prev_close(fd);
+}
+int dup2(int oldfd, int newfd) {
+	if(prev_dup2==NULL) {
+		prev_dup2=(dup2_def)dlsym(RTLD_NEXT, "dup2");
+	}
+	{
+		scopeLock l(mutex);
+		if(fds.count(oldfd)>0)
+			fds.insert(newfd);
+		else if(fds.count(newfd)>0)
+			fds.erase(newfd);
+	}
+	return prev_dup2(oldfd,newfd);
+}
+int dup3(int oldfd, int newfd, int flags) {
+	if(prev_dup3==NULL) {
+		prev_dup3=(dup3_def)dlsym(RTLD_NEXT, "dup3");
+	}
+	{
+		scopeLock l(mutex);
+		if(fds.count(oldfd)>0)
+			fds.insert(newfd);
+		else if(fds.count(newfd)>0)
+			fds.erase(newfd);
+	}
+	return prev_dup3(oldfd,newfd,flags);
+}
+
+

BIN
cpoll_cppsp/cppsp_rel0.2.3/socketd_proxy.so


+ 43 - 0
cpoll_cppsp/cppsp_rel0.2.3/www/1.cppsp

@@ -0,0 +1,43 @@
+<%#
+#include <iostream>
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdexcept>
+#include <cppsp/common.H>
+#include <delegate.H>
+#include <iostream>
+%>
+<%$
+void init() {
+	doReadPost=true;
+}
+%>
+form:
+<table border="1">
+<%
+for(auto it=request->form.begin();it!=request->form.end();it++) {
+	%>
+	<tr>
+		<td><%=htmlEscape((*it).first.toSTDString())%></td>
+		<td><%=htmlEscape((*it).second.toSTDString())%></td>
+	</tr>
+	<%
+}
+%>
+</table>
+querystring:
+<table border="1">
+<%
+for(auto it=request->queryString.begin();it!=request->queryString.end();it++) {
+	%>
+	<tr>
+		<td><%=htmlEscape((*it).first.toSTDString())%></td>
+		<td><%=htmlEscape((*it).second.toSTDString())%></td>
+	</tr>
+	<%
+}
+%>
+</table>
+
+
+

+ 1 - 0
cpoll_cppsp/cppsp_rel0.2.3/www/100.cppsp

@@ -0,0 +1 @@
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

+ 1 - 0
cpoll_cppsp/cppsp_rel0.2.3/www/100.html

@@ -0,0 +1 @@
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

+ 82 - 0
cpoll_cppsp/cppsp_rel0.2.3/www/dir_list.cppsm

@@ -0,0 +1,82 @@
+<%#
+//cppsp module to enable directory listing
+
+#include <sys/stat.h>
+#define TO_C_STR(in,inLen,out) char out[inLen+1];\
+		memcpy(out,in,inLen);\
+		out[inLen]=0;
+DelegateChain<void(Request&, Response&, Delegate<void()>)>::item* it;
+Server* server;
+void handleRequest(void*, Request& req, Response& resp, Delegate<void()> cb) {
+	struct stat st;
+	String s=server->mapPath(req.path,*req.sp);
+	TO_C_STR(s.data(),s.length(),tmp);
+	if(::stat(tmp,&st)>=0 && S_ISDIR(st.st_mode)) {
+		server->handleDynamicRequest("/dir_list.cppsm",req,resp,cb);
+		return;
+	}
+	(*it->prev)(req,resp,cb);
+}
+extern "C" void initModule(Server* s) {
+	server=s;
+	it=s->handleRequest.attach(&handleRequest);
+}
+extern "C" void deinitModule() {
+	server->handleRequest.detach(it);
+}
+%>
+<!DOCTYPE HTML>
+<html>
+<head>
+	<title>Index of <% htmlEscape(request->path,output); %></title>
+</head>
+<body>
+<h1 style="margin-top: 2px;">Index of <% htmlEscape(request->path,output); %></h1>
+<table>
+	<tr>
+		<th>Name</th>
+		<th>Last modified</th>
+		<th>Size</th>
+	</tr>
+	<tr>
+		<th colspan="5"><hr /></th>
+	</tr>
+	
+<%
+string path=server->mapPath(request->path.toSTDString());
+vector<string> list;
+auto tmp=[&](const char* name) {
+	list.push_back(name);
+};
+listDirectory(path.c_str(), &tmp);
+std::sort(list.begin(),list.end());
+for(int i=0;i<list.size();i++) {
+	string name=list[i];
+	struct stat st;
+	char p[path.length()+name.length()+1];
+	p[combinePath(path.c_str(),name.c_str(),p)]=0;
+	if(stat(p,&st)<0) return;
+	time_t rawtime=st.st_mtime;
+	struct tm * timeinfo;
+	char buffer[256];
+	timeinfo = localtime (&rawtime);
+	strftime(buffer,sizeof(buffer),"%F %r",timeinfo);
+	%>
+	<tr>
+		<td>
+			<a href="<% htmlAttributeEscape(name.c_str(),output); %><%if(S_ISDIR(st.st_mode)){%>/<%}%>">
+				<% htmlEscape(name.c_str(),output); %><%if(S_ISDIR(st.st_mode)){%>/<%}%>
+			</a>
+		</td>
+		<td align="right"><%=buffer%></td>
+		<td align="right"><%=(int64_t)st.st_size%></td>
+	</tr>
+	<tr>
+		<td></td>
+	</tr>
+	<%
+}
+%>
+</table>
+</body>
+</html>

+ 6 - 0
cpoll_cppsp/cppsp_rel0.2.3/www/errortest.cppsp

@@ -0,0 +1,6 @@
+gfsdhkjgfdjsk
+
+<%
+throw runtime_error("aaaaa");
+
+%>

+ 16 - 0
cpoll_cppsp/cppsp_rel0.2.3/www/forcestatic.cppsm

@@ -0,0 +1,16 @@
+<%#
+//example cppsp module that causes all pages to be served as static pages
+
+DelegateChain<void(Request&, Response&, Delegate<void()>)>::item* it;
+Server* server;
+void handleRequest(void*, Request& req, Response& resp, Delegate<void()> cb) {
+	server->handleStaticRequest(req.path,req,resp,cb);
+}
+extern "C" void initModule(Server* s) {
+	server=s;
+	it=s->handleRequest.attach(&handleRequest);
+}
+extern "C" void deinitModule() {
+	server->handleRequest.detach(it);
+}
+%>

+ 79 - 0
cpoll_cppsp/cppsp_rel0.2.3/www/test1.cppsp

@@ -0,0 +1,79 @@
+<%#
+#include <iostream>
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdexcept>
+#include <cppsp/common.H>
+#include <delegate.H>
+#include <dirent.h>
+
+int aaaaa=0;
+%>
+<%@ class p %>
+<%#
+void listDir(string dir,const function<void(dirent&)>& cb)
+{
+	DIR* d=opendir(dir.c_str());
+	if(d==NULL) {
+		throw runtime_error(strerror(errno));
+		return;
+	}
+	int len = offsetof(dirent, d_name) + pathconf(dir.c_str(), _PC_NAME_MAX) + 1;
+	char ent[len];
+	dirent* ent1=(dirent*)ent;
+	while(readdir_r(d, (dirent*)ent, &ent1)==0 && ent1!=NULL) {
+		if(strcmp(ent1->d_name, ".")==0 || strcmp(ent1->d_name, "..")==0)
+			continue;
+		cb(*ent1);
+	}
+	closedir(d);
+}
+%>
+<html>
+	<head>
+		<title>fgdhjf</title>
+	</head>
+	<body>
+		<table border="1">
+			<tr>
+				<td>UID: </td>
+				<td><%=getuid()%></td>
+			</tr>
+			<tr>
+				<td>GID: </td>
+				<td><%=getgid()%></td>
+			</tr>
+		</table>
+		<form method="post" action="1.cppsp?a=1111111&b=222222">
+			<input type="text" name="input1" /><br />
+			<input type="text" name="input2" />
+			<input type="submit" value="click here" />
+		</form>
+		
+		<%="ddd"%>
+		s
+		gsjdhkh
+		test1
+		<%
+		for(int i=0;i<10;i++) {
+			%>
+			gfdsgsfdgdsf<br />
+			<%
+		}
+		//throw runtime_error("aaaaa");
+		%>
+		<%=(++aaaaa)%><br />
+		<br />=============================<br />
+		<table border="1">
+		<%
+		listDir(server->mapPath("/"), [&](dirent& d) {
+			%>
+			<tr>
+				<td><%=htmlEscape(d.d_name)%></td>
+			</tr>
+			<%
+		});
+		%>
+		</table>
+	</body>
+</html>

+ 17 - 0
cpoll_cppsp/cppsp_rel0.2.3/www/url_rewrite.cppsm

@@ -0,0 +1,17 @@
+<%#
+//example cppsp module that rewrites all urls to /100.html, and treats it as
+//a dynamic page
+
+DelegateChain<void(Request&, Response&, Delegate<void()>)>::item* it;
+Server* server;
+void handleRequest(void*, Request& req, Response& resp, Delegate<void()> cb) {
+	server->handleDynamicRequest("/100.html",req,resp,cb);
+}
+extern "C" void initModule(Server* s) {
+	server=s;
+	it=s->handleRequest.attach(&handleRequest);
+}
+extern "C" void deinitModule() {
+	server->handleRequest.detach(it);
+}
+%>

+ 1 - 0
cpoll_cppsp/cppsp_rel0.2.3/www/x.cppsp

@@ -0,0 +1 @@
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

BIN
cpoll_cppsp/www/db.so


+ 1 - 0
cpoll_cppsp/www/db.txt

@@ -0,0 +1 @@
+[{"id":,"randomNumber":}]

BIN
cpoll_cppsp/www/db_pg_async.so


+ 1 - 0
cpoll_cppsp/www/db_pg_async.txt

@@ -0,0 +1 @@
+[{"id":,"randomNumber":}]

BIN
cpoll_cppsp/www/db_pg_threadpool.so


+ 1 - 0
cpoll_cppsp/www/db_pg_threadpool.txt

@@ -0,0 +1 @@
+[{"id":,"randomNumber":}]

Some files were not shown because too many files changed in this diff