heroku-tokyotyrant 0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (340) hide show
  1. data/COPYING +504 -0
  2. data/README.rdoc +231 -0
  3. data/Rakefile +72 -0
  4. data/benchmarks/balancer.rb +101 -0
  5. data/benchmarks/bulk_db.rb +74 -0
  6. data/benchmarks/bulk_table.rb +87 -0
  7. data/benchmarks/db.rb +114 -0
  8. data/benchmarks/table.rb +161 -0
  9. data/ext/extconf.rb +43 -0
  10. data/ext/tokyo/bin/tcamgr +0 -0
  11. data/ext/tokyo/bin/tcamttest +0 -0
  12. data/ext/tokyo/bin/tcatest +0 -0
  13. data/ext/tokyo/bin/tcbmgr +0 -0
  14. data/ext/tokyo/bin/tcbmttest +0 -0
  15. data/ext/tokyo/bin/tcbtest +0 -0
  16. data/ext/tokyo/bin/tcfmgr +0 -0
  17. data/ext/tokyo/bin/tcfmttest +0 -0
  18. data/ext/tokyo/bin/tcftest +0 -0
  19. data/ext/tokyo/bin/tchmgr +0 -0
  20. data/ext/tokyo/bin/tchmttest +0 -0
  21. data/ext/tokyo/bin/tchtest +0 -0
  22. data/ext/tokyo/bin/tcrmgr +0 -0
  23. data/ext/tokyo/bin/tcrmttest +0 -0
  24. data/ext/tokyo/bin/tcrtest +0 -0
  25. data/ext/tokyo/bin/tctmgr +0 -0
  26. data/ext/tokyo/bin/tctmttest +0 -0
  27. data/ext/tokyo/bin/tcttest +0 -0
  28. data/ext/tokyo/bin/tcucodec +0 -0
  29. data/ext/tokyo/bin/tcumttest +0 -0
  30. data/ext/tokyo/bin/tcutest +0 -0
  31. data/ext/tokyo/bin/ttserver +0 -0
  32. data/ext/tokyo/bin/ttulmgr +0 -0
  33. data/ext/tokyo/bin/ttultest +0 -0
  34. data/ext/tokyo/include/tcadb.h +548 -0
  35. data/ext/tokyo/include/tcbdb.h +1101 -0
  36. data/ext/tokyo/include/tcfdb.h +858 -0
  37. data/ext/tokyo/include/tchdb.h +871 -0
  38. data/ext/tokyo/include/tcrdb.h +801 -0
  39. data/ext/tokyo/include/tctdb.h +1086 -0
  40. data/ext/tokyo/include/tculog.h +392 -0
  41. data/ext/tokyo/include/tcutil.h +4184 -0
  42. data/ext/tokyo/include/ttutil.h +494 -0
  43. data/ext/tokyo/lib/libtokyocabinet.9.4.0.dylib +0 -0
  44. data/ext/tokyo/lib/libtokyocabinet.9.dylib +0 -0
  45. data/ext/tokyo/lib/libtokyocabinet.a +0 -0
  46. data/ext/tokyo/lib/libtokyocabinet.dylib +0 -0
  47. data/ext/tokyo/lib/libtokyotyrant.3.22.0.dylib +0 -0
  48. data/ext/tokyo/lib/libtokyotyrant.3.dylib +0 -0
  49. data/ext/tokyo/lib/libtokyotyrant.a +0 -0
  50. data/ext/tokyo/lib/libtokyotyrant.dylib +0 -0
  51. data/ext/tokyo/lib/pkgconfig/tokyocabinet.pc +14 -0
  52. data/ext/tokyo/lib/pkgconfig/tokyotyrant.pc +14 -0
  53. data/ext/tokyo/lib/ttskeldir.bundle +0 -0
  54. data/ext/tokyo/lib/ttskelmock.bundle +0 -0
  55. data/ext/tokyo/lib/ttskelnull.bundle +0 -0
  56. data/ext/tokyo/lib/ttskelproxy.bundle +0 -0
  57. data/ext/tokyo/libexec/tcawmgr.cgi +0 -0
  58. data/ext/tokyo/sbin/ttservctl +163 -0
  59. data/ext/tokyo/share/man/man1/tcamgr.1 +97 -0
  60. data/ext/tokyo/share/man/man1/tcamttest.1 +35 -0
  61. data/ext/tokyo/share/man/man1/tcatest.1 +55 -0
  62. data/ext/tokyo/share/man/man1/tcbmgr.1 +125 -0
  63. data/ext/tokyo/share/man/man1/tcbmttest.1 +81 -0
  64. data/ext/tokyo/share/man/man1/tcbtest.1 +107 -0
  65. data/ext/tokyo/share/man/man1/tcfmgr.1 +98 -0
  66. data/ext/tokyo/share/man/man1/tcfmttest.1 +62 -0
  67. data/ext/tokyo/share/man/man1/tcftest.1 +73 -0
  68. data/ext/tokyo/share/man/man1/tchmgr.1 +110 -0
  69. data/ext/tokyo/share/man/man1/tchmttest.1 +85 -0
  70. data/ext/tokyo/share/man/man1/tchtest.1 +95 -0
  71. data/ext/tokyo/share/man/man1/tcrmgr.1 +164 -0
  72. data/ext/tokyo/share/man/man1/tcrmttest.1 +55 -0
  73. data/ext/tokyo/share/man/man1/tcrtest.1 +89 -0
  74. data/ext/tokyo/share/man/man1/tctmgr.1 +140 -0
  75. data/ext/tokyo/share/man/man1/tctmttest.1 +92 -0
  76. data/ext/tokyo/share/man/man1/tcttest.1 +105 -0
  77. data/ext/tokyo/share/man/man1/tcucodec.1 +162 -0
  78. data/ext/tokyo/share/man/man1/tcumttest.1 +41 -0
  79. data/ext/tokyo/share/man/man1/tcutest.1 +81 -0
  80. data/ext/tokyo/share/man/man1/ttserver.1 +84 -0
  81. data/ext/tokyo/share/man/man1/ttulmgr.1 +40 -0
  82. data/ext/tokyo/share/man/man1/ttultest.1 +16 -0
  83. data/ext/tokyo/share/man/man3/tcadb.3 +676 -0
  84. data/ext/tokyo/share/man/man3/tcbdb.3 +1355 -0
  85. data/ext/tokyo/share/man/man3/tcfdb.3 +975 -0
  86. data/ext/tokyo/share/man/man3/tchdb.3 +898 -0
  87. data/ext/tokyo/share/man/man3/tclist.3 +1 -0
  88. data/ext/tokyo/share/man/man3/tcmap.3 +1 -0
  89. data/ext/tokyo/share/man/man3/tcmdb.3 +1 -0
  90. data/ext/tokyo/share/man/man3/tcmpool.3 +1 -0
  91. data/ext/tokyo/share/man/man3/tcrdb.3 +1309 -0
  92. data/ext/tokyo/share/man/man3/tctdb.3 +1110 -0
  93. data/ext/tokyo/share/man/man3/tctree.3 +1 -0
  94. data/ext/tokyo/share/man/man3/tculog.3 +15 -0
  95. data/ext/tokyo/share/man/man3/tcutil.3 +4518 -0
  96. data/ext/tokyo/share/man/man3/tcxstr.3 +1 -0
  97. data/ext/tokyo/share/man/man3/tokyocabinet.3 +132 -0
  98. data/ext/tokyo/share/man/man3/ttutil.3 +14 -0
  99. data/ext/tokyo/share/man/man8/ttservctl.8 +37 -0
  100. data/ext/tokyo/share/tokyocabinet/COPYING +504 -0
  101. data/ext/tokyo/share/tokyocabinet/ChangeLog +1252 -0
  102. data/ext/tokyo/share/tokyocabinet/THANKS +12 -0
  103. data/ext/tokyo/share/tokyocabinet/doc/benchmark.pdf +0 -0
  104. data/ext/tokyo/share/tokyocabinet/doc/common.css +211 -0
  105. data/ext/tokyo/share/tokyocabinet/doc/icon16.png +0 -0
  106. data/ext/tokyo/share/tokyocabinet/doc/index.html +156 -0
  107. data/ext/tokyo/share/tokyocabinet/doc/index.ja.html +197 -0
  108. data/ext/tokyo/share/tokyocabinet/doc/logo-ja.png +0 -0
  109. data/ext/tokyo/share/tokyocabinet/doc/logo.png +0 -0
  110. data/ext/tokyo/share/tokyocabinet/doc/spex-en.html +7145 -0
  111. data/ext/tokyo/share/tokyocabinet/doc/spex-ja.html +7476 -0
  112. data/ext/tokyo/share/tokyocabinet/doc/tokyoproducts.pdf +0 -0
  113. data/ext/tokyo/share/tokyocabinet/doc/tokyoproducts.ppt +0 -0
  114. data/ext/tokyo/share/tokyotyrant/COPYING +504 -0
  115. data/ext/tokyo/share/tokyotyrant/ChangeLog +578 -0
  116. data/ext/tokyo/share/tokyotyrant/THANKS +15 -0
  117. data/ext/tokyo/share/tokyotyrant/doc/common.css +211 -0
  118. data/ext/tokyo/share/tokyotyrant/doc/index.html +79 -0
  119. data/ext/tokyo/share/tokyotyrant/doc/spex.html +2264 -0
  120. data/ext/tokyo/share/tokyotyrant/ext/mapreduce.lua +57 -0
  121. data/ext/tokyo/share/tokyotyrant/ext/queue.lua +55 -0
  122. data/ext/tokyo/share/tokyotyrant/ext/senatus.lua +532 -0
  123. data/ext/tokyo/share/tokyotyrant/ext/usherette.lua +438 -0
  124. data/ext/tokyo_tyrant.c +147 -0
  125. data/ext/tokyo_tyrant.h +48 -0
  126. data/ext/tokyo_tyrant_db.c +227 -0
  127. data/ext/tokyo_tyrant_db.h +8 -0
  128. data/ext/tokyo_tyrant_module.c +453 -0
  129. data/ext/tokyo_tyrant_module.h +10 -0
  130. data/ext/tokyo_tyrant_query.c +226 -0
  131. data/ext/tokyo_tyrant_query.h +9 -0
  132. data/ext/tokyo_tyrant_table.c +319 -0
  133. data/ext/tokyo_tyrant_table.h +8 -0
  134. data/ext/tokyocabinet-1.4.41/COPYING +504 -0
  135. data/ext/tokyocabinet-1.4.41/ChangeLog +1252 -0
  136. data/ext/tokyocabinet-1.4.41/Makefile.in +825 -0
  137. data/ext/tokyocabinet-1.4.41/README +38 -0
  138. data/ext/tokyocabinet-1.4.41/THANKS +12 -0
  139. data/ext/tokyocabinet-1.4.41/bros/Makefile +133 -0
  140. data/ext/tokyocabinet-1.4.41/bros/bdbtest.c +438 -0
  141. data/ext/tokyocabinet-1.4.41/bros/cdbtest.c +219 -0
  142. data/ext/tokyocabinet-1.4.41/bros/cmpsqltctest.c +186 -0
  143. data/ext/tokyocabinet-1.4.41/bros/gdbmtest.c +216 -0
  144. data/ext/tokyocabinet-1.4.41/bros/mapreporter +72 -0
  145. data/ext/tokyocabinet-1.4.41/bros/maptest.cc +677 -0
  146. data/ext/tokyocabinet-1.4.41/bros/ndbmtest.c +204 -0
  147. data/ext/tokyocabinet-1.4.41/bros/qdbmtest.c +375 -0
  148. data/ext/tokyocabinet-1.4.41/bros/reporter +141 -0
  149. data/ext/tokyocabinet-1.4.41/bros/result.xls +0 -0
  150. data/ext/tokyocabinet-1.4.41/bros/sdbmtest.c +204 -0
  151. data/ext/tokyocabinet-1.4.41/bros/sqltest.c +404 -0
  152. data/ext/tokyocabinet-1.4.41/bros/tctest.c +748 -0
  153. data/ext/tokyocabinet-1.4.41/bros/tdbtest.c +205 -0
  154. data/ext/tokyocabinet-1.4.41/configure +7402 -0
  155. data/ext/tokyocabinet-1.4.41/configure.in +362 -0
  156. data/ext/tokyocabinet-1.4.41/doc/benchmark.pdf +0 -0
  157. data/ext/tokyocabinet-1.4.41/doc/common.css +211 -0
  158. data/ext/tokyocabinet-1.4.41/doc/icon16.png +0 -0
  159. data/ext/tokyocabinet-1.4.41/doc/index.html +156 -0
  160. data/ext/tokyocabinet-1.4.41/doc/index.ja.html +197 -0
  161. data/ext/tokyocabinet-1.4.41/doc/logo-ja.png +0 -0
  162. data/ext/tokyocabinet-1.4.41/doc/logo.png +0 -0
  163. data/ext/tokyocabinet-1.4.41/doc/spex-en.html +7145 -0
  164. data/ext/tokyocabinet-1.4.41/doc/spex-ja.html +7476 -0
  165. data/ext/tokyocabinet-1.4.41/doc/tokyoproducts.pdf +0 -0
  166. data/ext/tokyocabinet-1.4.41/doc/tokyoproducts.ppt +0 -0
  167. data/ext/tokyocabinet-1.4.41/example/Makefile +113 -0
  168. data/ext/tokyocabinet-1.4.41/example/tcadbex.c +55 -0
  169. data/ext/tokyocabinet-1.4.41/example/tcbdbex.c +64 -0
  170. data/ext/tokyocabinet-1.4.41/example/tcfdbex.c +60 -0
  171. data/ext/tokyocabinet-1.4.41/example/tchdbex.c +60 -0
  172. data/ext/tokyocabinet-1.4.41/example/tctchat.c +97 -0
  173. data/ext/tokyocabinet-1.4.41/example/tctchat.tmpl +141 -0
  174. data/ext/tokyocabinet-1.4.41/example/tctdbex.c +85 -0
  175. data/ext/tokyocabinet-1.4.41/example/tctsearch.c +95 -0
  176. data/ext/tokyocabinet-1.4.41/example/tctsearch.tmpl +122 -0
  177. data/ext/tokyocabinet-1.4.41/example/tcutilex.c +77 -0
  178. data/ext/tokyocabinet-1.4.41/f.tsv +2 -0
  179. data/ext/tokyocabinet-1.4.41/lab/calccomp +118 -0
  180. data/ext/tokyocabinet-1.4.41/lab/datechange +56 -0
  181. data/ext/tokyocabinet-1.4.41/lab/diffcheck +45 -0
  182. data/ext/tokyocabinet-1.4.41/lab/htmltotsv +102 -0
  183. data/ext/tokyocabinet-1.4.41/lab/magic +19 -0
  184. data/ext/tokyocabinet-1.4.41/lab/printenv.cgi +27 -0
  185. data/ext/tokyocabinet-1.4.41/lab/stepcount +26 -0
  186. data/ext/tokyocabinet-1.4.41/lab/stopwatch +61 -0
  187. data/ext/tokyocabinet-1.4.41/lab/tabcheck +43 -0
  188. data/ext/tokyocabinet-1.4.41/lab/wgettsv +239 -0
  189. data/ext/tokyocabinet-1.4.41/lab/widthcheck +57 -0
  190. data/ext/tokyocabinet-1.4.41/man/htmltoman +104 -0
  191. data/ext/tokyocabinet-1.4.41/man/tcadb.3 +676 -0
  192. data/ext/tokyocabinet-1.4.41/man/tcamgr.1 +97 -0
  193. data/ext/tokyocabinet-1.4.41/man/tcamttest.1 +35 -0
  194. data/ext/tokyocabinet-1.4.41/man/tcatest.1 +55 -0
  195. data/ext/tokyocabinet-1.4.41/man/tcbdb.3 +1355 -0
  196. data/ext/tokyocabinet-1.4.41/man/tcbmgr.1 +125 -0
  197. data/ext/tokyocabinet-1.4.41/man/tcbmttest.1 +81 -0
  198. data/ext/tokyocabinet-1.4.41/man/tcbtest.1 +107 -0
  199. data/ext/tokyocabinet-1.4.41/man/tcfdb.3 +975 -0
  200. data/ext/tokyocabinet-1.4.41/man/tcfmgr.1 +98 -0
  201. data/ext/tokyocabinet-1.4.41/man/tcfmttest.1 +62 -0
  202. data/ext/tokyocabinet-1.4.41/man/tcftest.1 +73 -0
  203. data/ext/tokyocabinet-1.4.41/man/tchdb.3 +898 -0
  204. data/ext/tokyocabinet-1.4.41/man/tchmgr.1 +110 -0
  205. data/ext/tokyocabinet-1.4.41/man/tchmttest.1 +85 -0
  206. data/ext/tokyocabinet-1.4.41/man/tchtest.1 +95 -0
  207. data/ext/tokyocabinet-1.4.41/man/tclist.3 +1 -0
  208. data/ext/tokyocabinet-1.4.41/man/tcmap.3 +1 -0
  209. data/ext/tokyocabinet-1.4.41/man/tcmdb.3 +1 -0
  210. data/ext/tokyocabinet-1.4.41/man/tcmpool.3 +1 -0
  211. data/ext/tokyocabinet-1.4.41/man/tctdb.3 +1110 -0
  212. data/ext/tokyocabinet-1.4.41/man/tctmgr.1 +140 -0
  213. data/ext/tokyocabinet-1.4.41/man/tctmttest.1 +92 -0
  214. data/ext/tokyocabinet-1.4.41/man/tctree.3 +1 -0
  215. data/ext/tokyocabinet-1.4.41/man/tcttest.1 +105 -0
  216. data/ext/tokyocabinet-1.4.41/man/tcucodec.1 +162 -0
  217. data/ext/tokyocabinet-1.4.41/man/tcumttest.1 +41 -0
  218. data/ext/tokyocabinet-1.4.41/man/tcutest.1 +81 -0
  219. data/ext/tokyocabinet-1.4.41/man/tcutil.3 +4518 -0
  220. data/ext/tokyocabinet-1.4.41/man/tcxstr.3 +1 -0
  221. data/ext/tokyocabinet-1.4.41/man/tokyocabinet.3 +132 -0
  222. data/ext/tokyocabinet-1.4.41/md5.c +381 -0
  223. data/ext/tokyocabinet-1.4.41/md5.h +101 -0
  224. data/ext/tokyocabinet-1.4.41/myconf.c +493 -0
  225. data/ext/tokyocabinet-1.4.41/myconf.h +549 -0
  226. data/ext/tokyocabinet-1.4.41/tcadb.c +4339 -0
  227. data/ext/tokyocabinet-1.4.41/tcadb.h +548 -0
  228. data/ext/tokyocabinet-1.4.41/tcamgr.c +1019 -0
  229. data/ext/tokyocabinet-1.4.41/tcamttest.c +542 -0
  230. data/ext/tokyocabinet-1.4.41/tcatest.c +1845 -0
  231. data/ext/tokyocabinet-1.4.41/tcawmgr.c +482 -0
  232. data/ext/tokyocabinet-1.4.41/tcbdb.c +4180 -0
  233. data/ext/tokyocabinet-1.4.41/tcbdb.h +1101 -0
  234. data/ext/tokyocabinet-1.4.41/tcbmgr.c +1012 -0
  235. data/ext/tokyocabinet-1.4.41/tcbmttest.c +1810 -0
  236. data/ext/tokyocabinet-1.4.41/tcbtest.c +2586 -0
  237. data/ext/tokyocabinet-1.4.41/tcfdb.c +2746 -0
  238. data/ext/tokyocabinet-1.4.41/tcfdb.h +858 -0
  239. data/ext/tokyocabinet-1.4.41/tcfmgr.c +786 -0
  240. data/ext/tokyocabinet-1.4.41/tcfmttest.c +1220 -0
  241. data/ext/tokyocabinet-1.4.41/tcftest.c +1695 -0
  242. data/ext/tokyocabinet-1.4.41/tchdb.c +5153 -0
  243. data/ext/tokyocabinet-1.4.41/tchdb.h +871 -0
  244. data/ext/tokyocabinet-1.4.41/tchmgr.c +842 -0
  245. data/ext/tokyocabinet-1.4.41/tchmttest.c +1757 -0
  246. data/ext/tokyocabinet-1.4.41/tchtest.c +2129 -0
  247. data/ext/tokyocabinet-1.4.41/tctdb.c +6199 -0
  248. data/ext/tokyocabinet-1.4.41/tctdb.h +1086 -0
  249. data/ext/tokyocabinet-1.4.41/tctmgr.c +1241 -0
  250. data/ext/tokyocabinet-1.4.41/tctmttest.c +1563 -0
  251. data/ext/tokyocabinet-1.4.41/tcttest.c +2062 -0
  252. data/ext/tokyocabinet-1.4.41/tcucodec.c +1357 -0
  253. data/ext/tokyocabinet-1.4.41/tcumttest.c +578 -0
  254. data/ext/tokyocabinet-1.4.41/tcutest.c +1875 -0
  255. data/ext/tokyocabinet-1.4.41/tcutil.c +10528 -0
  256. data/ext/tokyocabinet-1.4.41/tcutil.h +4184 -0
  257. data/ext/tokyocabinet-1.4.41/tokyocabinet.idl +336 -0
  258. data/ext/tokyocabinet-1.4.41/tokyocabinet.pc.in +14 -0
  259. data/ext/tokyotyrant-1.1.39/COPYING +504 -0
  260. data/ext/tokyotyrant-1.1.39/ChangeLog +578 -0
  261. data/ext/tokyotyrant-1.1.39/Makefile.in +365 -0
  262. data/ext/tokyotyrant-1.1.39/README +38 -0
  263. data/ext/tokyotyrant-1.1.39/THANKS +15 -0
  264. data/ext/tokyotyrant-1.1.39/configure +6979 -0
  265. data/ext/tokyotyrant-1.1.39/configure.in +300 -0
  266. data/ext/tokyotyrant-1.1.39/doc/common.css +211 -0
  267. data/ext/tokyotyrant-1.1.39/doc/index.html +79 -0
  268. data/ext/tokyotyrant-1.1.39/doc/spex.html +2264 -0
  269. data/ext/tokyotyrant-1.1.39/example/Makefile +68 -0
  270. data/ext/tokyotyrant-1.1.39/example/httptest.pl +88 -0
  271. data/ext/tokyotyrant-1.1.39/example/mcftest.pl +39 -0
  272. data/ext/tokyotyrant-1.1.39/example/mctest.pl +43 -0
  273. data/ext/tokyotyrant-1.1.39/example/tcrdbex +0 -0
  274. data/ext/tokyotyrant-1.1.39/example/tcrdbex.c +49 -0
  275. data/ext/tokyotyrant-1.1.39/example/tcrdbex.o +0 -0
  276. data/ext/tokyotyrant-1.1.39/example/tcrdbtblex +0 -0
  277. data/ext/tokyotyrant-1.1.39/example/tcrdbtblex.c +79 -0
  278. data/ext/tokyotyrant-1.1.39/example/tcrdbtblex.o +0 -0
  279. data/ext/tokyotyrant-1.1.39/ext/mapreduce.lua +57 -0
  280. data/ext/tokyotyrant-1.1.39/ext/queue.lua +55 -0
  281. data/ext/tokyotyrant-1.1.39/ext/senatus.lua +532 -0
  282. data/ext/tokyotyrant-1.1.39/ext/usherette.lua +438 -0
  283. data/ext/tokyotyrant-1.1.39/lab/datechange +56 -0
  284. data/ext/tokyotyrant-1.1.39/lab/diffcheck +45 -0
  285. data/ext/tokyotyrant-1.1.39/lab/fibonacci.lua +20 -0
  286. data/ext/tokyotyrant-1.1.39/lab/footprint.lua +67 -0
  287. data/ext/tokyotyrant-1.1.39/lab/highlow.lua +88 -0
  288. data/ext/tokyotyrant-1.1.39/lab/killdualmaster +12 -0
  289. data/ext/tokyotyrant-1.1.39/lab/rundualmaster +38 -0
  290. data/ext/tokyotyrant-1.1.39/lab/stepcount +26 -0
  291. data/ext/tokyotyrant-1.1.39/lab/tabcheck +43 -0
  292. data/ext/tokyotyrant-1.1.39/lab/ushrtregister.pl +55 -0
  293. data/ext/tokyotyrant-1.1.39/lab/widthcheck +57 -0
  294. data/ext/tokyotyrant-1.1.39/man/htmltoman +100 -0
  295. data/ext/tokyotyrant-1.1.39/man/tcrdb.3 +1309 -0
  296. data/ext/tokyotyrant-1.1.39/man/tcrmgr.1 +164 -0
  297. data/ext/tokyotyrant-1.1.39/man/tcrmttest.1 +55 -0
  298. data/ext/tokyotyrant-1.1.39/man/tcrtest.1 +89 -0
  299. data/ext/tokyotyrant-1.1.39/man/tculog.3 +15 -0
  300. data/ext/tokyotyrant-1.1.39/man/ttservctl.8 +37 -0
  301. data/ext/tokyotyrant-1.1.39/man/ttserver.1 +84 -0
  302. data/ext/tokyotyrant-1.1.39/man/ttulmgr.1 +40 -0
  303. data/ext/tokyotyrant-1.1.39/man/ttultest.1 +16 -0
  304. data/ext/tokyotyrant-1.1.39/man/ttutil.3 +14 -0
  305. data/ext/tokyotyrant-1.1.39/myconf.c +169 -0
  306. data/ext/tokyotyrant-1.1.39/myconf.h +408 -0
  307. data/ext/tokyotyrant-1.1.39/scrext.c +2394 -0
  308. data/ext/tokyotyrant-1.1.39/scrext.h +96 -0
  309. data/ext/tokyotyrant-1.1.39/tcrdb.c +2637 -0
  310. data/ext/tokyotyrant-1.1.39/tcrdb.h +801 -0
  311. data/ext/tokyotyrant-1.1.39/tcrmgr.c +1559 -0
  312. data/ext/tokyotyrant-1.1.39/tcrmttest.c +915 -0
  313. data/ext/tokyotyrant-1.1.39/tcrtest.c +1542 -0
  314. data/ext/tokyotyrant-1.1.39/tculog.c +1211 -0
  315. data/ext/tokyotyrant-1.1.39/tculog.h +392 -0
  316. data/ext/tokyotyrant-1.1.39/tokyotyrant.idl +143 -0
  317. data/ext/tokyotyrant-1.1.39/tokyotyrant.pc.in +14 -0
  318. data/ext/tokyotyrant-1.1.39/ttservctl +163 -0
  319. data/ext/tokyotyrant-1.1.39/ttserver.c +3583 -0
  320. data/ext/tokyotyrant-1.1.39/ttskeldir.c +141 -0
  321. data/ext/tokyotyrant-1.1.39/ttskelmock.c +64 -0
  322. data/ext/tokyotyrant-1.1.39/ttskelnull.c +79 -0
  323. data/ext/tokyotyrant-1.1.39/ttskelproxy.c +74 -0
  324. data/ext/tokyotyrant-1.1.39/ttulmgr.c +266 -0
  325. data/ext/tokyotyrant-1.1.39/ttultest.c +371 -0
  326. data/ext/tokyotyrant-1.1.39/ttutil.c +1510 -0
  327. data/ext/tokyotyrant-1.1.39/ttutil.h +494 -0
  328. data/lib/tokyo_tyrant/balancer.rb +189 -0
  329. data/spec/ext.lua +4 -0
  330. data/spec/plu_db.rb +538 -0
  331. data/spec/spec.rb +1 -0
  332. data/spec/spec_base.rb +17 -0
  333. data/spec/start_tyrants.sh +36 -0
  334. data/spec/stop_tyrants.sh +9 -0
  335. data/spec/tokyo_tyrant_balancer_db_spec.rb +160 -0
  336. data/spec/tokyo_tyrant_balancer_table_spec.rb +177 -0
  337. data/spec/tokyo_tyrant_query_spec.rb +159 -0
  338. data/spec/tokyo_tyrant_spec.rb +254 -0
  339. data/spec/tokyo_tyrant_table_spec.rb +301 -0
  340. metadata +402 -0
@@ -0,0 +1,371 @@
1
+ /*************************************************************************************************
2
+ * The test cases of the update log API
3
+ * Copyright (C) 2006-2009 Mikio Hirabayashi
4
+ * This file is part of Tokyo Tyrant.
5
+ * Tokyo Tyrant is free software; you can redistribute it and/or modify it under the terms of
6
+ * the GNU Lesser General Public License as published by the Free Software Foundation; either
7
+ * version 2.1 of the License or any later version. Tokyo Tyrant is distributed in the hope
8
+ * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
10
+ * License for more details.
11
+ * You should have received a copy of the GNU Lesser General Public License along with Tokyo
12
+ * Tyrant; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
13
+ * Boston, MA 02111-1307 USA.
14
+ *************************************************************************************************/
15
+
16
+
17
+ #include <tculog.h>
18
+ #include "myconf.h"
19
+
20
+ #define RECBUFSIZ 32 // buffer for records
21
+
22
+ typedef struct { // type of structure for read thread
23
+ TCULRD *ulrd;
24
+ int id;
25
+ int rnum;
26
+ } TARGREAD;
27
+
28
+
29
+ /* global variables */
30
+ const char *g_progname; // program name
31
+
32
+
33
+ /* function prototypes */
34
+ int main(int argc, char **argv);
35
+ static void usage(void);
36
+ static void iprintf(const char *format, ...);
37
+ static void eprint(TCULOG *ulog, const char *func);
38
+ static int runwrite(int argc, char **argv);
39
+ static int runread(int argc, char **argv);
40
+ static int runthread(int argc, char **argv);
41
+ static int procwrite(const char *base, int rnum, int64_t limsiz, bool as);
42
+ static int procread(const char *base, uint64_t ts, bool pm);
43
+ static int procthread(const char *base, int tnum, int rnum, int64_t limsiz, bool as);
44
+
45
+
46
+ /* main routine */
47
+ int main(int argc, char **argv){
48
+ g_progname = argv[0];
49
+ srand((unsigned int)(tctime() * 1000) % UINT_MAX);
50
+ if(argc < 2) usage();
51
+ int rv = 0;
52
+ if(!strcmp(argv[1], "write")){
53
+ rv = runwrite(argc, argv);
54
+ } else if(!strcmp(argv[1], "read")){
55
+ rv = runread(argc, argv);
56
+ } else if(!strcmp(argv[1], "thread")){
57
+ rv = runthread(argc, argv);
58
+ } else {
59
+ usage();
60
+ }
61
+ return rv;
62
+ }
63
+
64
+
65
+ /* print the usage and exit */
66
+ static void usage(void){
67
+ fprintf(stderr, "%s: test cases of the remote database API of Tokyo Tyrant\n", g_progname);
68
+ fprintf(stderr, "\n");
69
+ fprintf(stderr, "usage:\n");
70
+ fprintf(stderr, " %s write [-lim num] [-as] base rnum\n", g_progname);
71
+ fprintf(stderr, " %s read [-ts num] [-pm] base\n", g_progname);
72
+ fprintf(stderr, " %s thread [-lim num] [-as] base tnum rnum\n", g_progname);
73
+ fprintf(stderr, "\n");
74
+ exit(1);
75
+ }
76
+
77
+
78
+ /* print formatted information string and flush the buffer */
79
+ static void iprintf(const char *format, ...){
80
+ va_list ap;
81
+ va_start(ap, format);
82
+ vprintf(format, ap);
83
+ fflush(stdout);
84
+ va_end(ap);
85
+ }
86
+
87
+
88
+ /* print error message of abstract database */
89
+ static void eprint(TCULOG *ulog, const char *func){
90
+ fprintf(stderr, "%s: %s: error:\n", g_progname, func);
91
+ }
92
+
93
+
94
+ /* parse arguments of write command */
95
+ static int runwrite(int argc, char **argv){
96
+ char *base = NULL;
97
+ char *rstr = NULL;
98
+ int64_t limsiz = 0;
99
+ bool as = false;
100
+ for(int i = 2; i < argc; i++){
101
+ if(!base && argv[i][0] == '-'){
102
+ if(!strcmp(argv[i], "-lim")){
103
+ if(++i >= argc) usage();
104
+ limsiz = tcatoi(argv[i]);
105
+ } else if(!strcmp(argv[i], "-as")){
106
+ as = true;
107
+ } else {
108
+ usage();
109
+ }
110
+ } else if(!base){
111
+ base = argv[i];
112
+ } else if(!rstr){
113
+ rstr = argv[i];
114
+ } else {
115
+ usage();
116
+ }
117
+ }
118
+ if(!base || !rstr) usage();
119
+ int rnum = tcatoi(rstr);
120
+ if(rnum < 1) usage();
121
+ int rv = procwrite(base, rnum, limsiz, as);
122
+ return rv;
123
+ }
124
+
125
+
126
+ /* parse arguments of read command */
127
+ static int runread(int argc, char **argv){
128
+ char *base = NULL;
129
+ uint64_t ts = 0;
130
+ bool pm = false;
131
+ for(int i = 2; i < argc; i++){
132
+ if(!base && argv[i][0] == '-'){
133
+ if(!strcmp(argv[i], "-ts")){
134
+ if(++i >= argc) usage();
135
+ ts = ttstrtots(argv[i]);
136
+ } else if(!strcmp(argv[i], "-pm")){
137
+ pm = true;
138
+ } else {
139
+ usage();
140
+ }
141
+ } else if(!base){
142
+ base = argv[i];
143
+ } else {
144
+ usage();
145
+ }
146
+ }
147
+ if(!base) usage();
148
+ int rv = procread(base, ts, pm);
149
+ return rv;
150
+ }
151
+
152
+
153
+ /* parse arguments of thread command */
154
+ static int runthread(int argc, char **argv){
155
+ char *base = NULL;
156
+ char *tstr = NULL;
157
+ char *rstr = NULL;
158
+ int64_t limsiz = 0;
159
+ bool as = false;
160
+ for(int i = 2; i < argc; i++){
161
+ if(!base && argv[i][0] == '-'){
162
+ if(!strcmp(argv[i], "-lim")){
163
+ if(++i >= argc) usage();
164
+ limsiz = tcatoi(argv[i]);
165
+ } else if(!strcmp(argv[i], "-as")){
166
+ as = true;
167
+ } else {
168
+ usage();
169
+ }
170
+ } else if(!base){
171
+ base = argv[i];
172
+ } else if(!tstr){
173
+ tstr = argv[i];
174
+ } else if(!rstr){
175
+ rstr = argv[i];
176
+ } else {
177
+ usage();
178
+ }
179
+ }
180
+ if(!base || !tstr || !rstr) usage();
181
+ int tnum = tcatoi(tstr);
182
+ int rnum = tcatoi(rstr);
183
+ if(tnum < 1 || rnum < 1) usage();
184
+ int rv = procthread(base, tnum, rnum, limsiz, as);
185
+ return rv;
186
+ }
187
+
188
+
189
+ /* perform write command */
190
+ static int procwrite(const char *base, int rnum, int64_t limsiz, bool as){
191
+ iprintf("<Writing Test>\n base=%s rnum=%d limsiz=%lld as=%d\n\n",
192
+ base, rnum, (long long)limsiz, as);
193
+ bool err = false;
194
+ double stime = tctime();
195
+ TCULOG *ulog = tculognew();
196
+ if(as && !tculogsetaio(ulog)){
197
+ eprint(ulog, "tculogsetaio");
198
+ err = true;
199
+ }
200
+ if(!tculogopen(ulog, base, limsiz)){
201
+ eprint(ulog, "tculogopen");
202
+ err = true;
203
+ }
204
+ int sid = getpid() & UINT16_MAX;
205
+ for(int i = 1; i <= rnum; i++){
206
+ char buf[RECBUFSIZ];
207
+ int len = sprintf(buf, "%08d", i);
208
+ if(!tculogwrite(ulog, 0, sid, sid, buf, len)){
209
+ eprint(ulog, "tculogwrite");
210
+ err = true;
211
+ break;
212
+ }
213
+ if(rnum > 250 && i % (rnum / 250) == 0){
214
+ putchar('.');
215
+ fflush(stdout);
216
+ if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
217
+ }
218
+ }
219
+ if(!tculogclose(ulog)){
220
+ eprint(ulog, "tculogclose");
221
+ err = true;
222
+ }
223
+ tculogdel(ulog);
224
+ iprintf("time: %.3f\n", tctime() - stime);
225
+ iprintf("%s\n\n", err ? "error" : "ok");
226
+ return err ? 1 : 0;
227
+ }
228
+
229
+
230
+ /* perform read command */
231
+ static int procread(const char *base, uint64_t ts, bool pm){
232
+ if(!pm)
233
+ iprintf("<Reading Test>\n base=%s ts=%llu pm=%d\n\n", base, (unsigned long long)ts, pm);
234
+ bool err = false;
235
+ double stime = tctime();
236
+ TCULOG *ulog = tculognew();
237
+ if(!tculogopen(ulog, base, 0)){
238
+ eprint(ulog, "tculogopen");
239
+ err = true;
240
+ }
241
+ TCULRD *ulrd = tculrdnew(ulog, ts);
242
+ if(ulrd){
243
+ const char *rbuf;
244
+ int rsiz;
245
+ uint64_t rts;
246
+ uint32_t rsid, rmid;
247
+ int i = 1;
248
+ while((rbuf = tculrdread(ulrd, &rsiz, &rts, &rsid, &rmid)) != NULL){
249
+ if(pm){
250
+ printf("%llu\t%u:%u\t", (unsigned long long)rts, (unsigned int)rsid, (unsigned int)rmid);
251
+ for(int i = 0; i < rsiz; i++){
252
+ if(i > 0) putchar(' ');
253
+ printf("%02X", ((unsigned char *)rbuf)[i]);
254
+ }
255
+ putchar('\n');
256
+ } else {
257
+ if(i % 1000 == 0){
258
+ putchar('.');
259
+ fflush(stdout);
260
+ if(i % 25000 == 0) iprintf(" (%08d)\n", i);
261
+ }
262
+ }
263
+ i++;
264
+ }
265
+ if(!pm) iprintf(" (%08d)\n", i - 1);
266
+ tculrddel(ulrd);
267
+ }
268
+ if(!tculogclose(ulog)){
269
+ eprint(ulog, "tculogclose");
270
+ err = true;
271
+ }
272
+ tculogdel(ulog);
273
+ if(!pm){
274
+ iprintf("time: %.3f\n", tctime() - stime);
275
+ iprintf("%s\n\n", err ? "error" : "ok");
276
+ }
277
+ return err ? 1 : 0;
278
+ }
279
+
280
+
281
+ /* thread the read function */
282
+ static void *threadread(void *targ){
283
+ TCULRD *ulrd = ((TARGREAD *)targ)->ulrd;
284
+ int id = ((TARGREAD *)targ)->id;
285
+ int rnum = ((TARGREAD *)targ)->rnum;
286
+ const char *rbuf;
287
+ int rsiz;
288
+ uint64_t rts;
289
+ uint32_t rsid, rmid;
290
+ int i = 1;
291
+ while(i <= rnum){
292
+ while((rbuf = tculrdread(ulrd, &rsiz, &rts, &rsid, &rmid)) != NULL){
293
+ if(id == 0 && rnum > 250 && i % (rnum / 250) == 0){
294
+ putchar('.');
295
+ fflush(stdout);
296
+ if(i == rnum || i % (rnum / 10) == 0) iprintf(" (%08d)\n", i);
297
+ }
298
+ i++;
299
+ }
300
+ tcsleep(0.01);
301
+ }
302
+ return NULL;
303
+ }
304
+
305
+
306
+ /* perform thread command */
307
+ static int procthread(const char *base, int tnum, int rnum, int64_t limsiz, bool as){
308
+ iprintf("<Threading Test>\n base=%s tnum=%d rnum=%d limsiz=%lld as=%d\n\n",
309
+ base, tnum, rnum, (long long)limsiz, as);
310
+ bool err = false;
311
+ double stime = tctime();
312
+ TCULOG *ulog = tculognew();
313
+ if(as && !tculogsetaio(ulog)){
314
+ eprint(ulog, "tculogsetaio");
315
+ err = true;
316
+ }
317
+ if(!tculogopen(ulog, base, limsiz)){
318
+ eprint(ulog, "tculogopen");
319
+ err = true;
320
+ }
321
+ TARGREAD targs[tnum];
322
+ pthread_t threads[tnum];
323
+ for(int i = 0; i < tnum; i++){
324
+ targs[i].ulrd = tculrdnew(ulog, 0);
325
+ targs[i].id = i;
326
+ targs[i].rnum = rnum;
327
+ if(!targs[i].ulrd){
328
+ eprint(ulog, "tculrdnew");
329
+ targs[i].id = -1;
330
+ err = true;
331
+ } else if(pthread_create(threads + i, NULL, threadread, targs + i) != 0){
332
+ eprint(ulog, "pthread_create");
333
+ targs[i].id = -1;
334
+ err = true;
335
+ }
336
+ }
337
+ int sid = getpid() & UINT16_MAX;
338
+ for(int i = 1; i <= rnum; i++){
339
+ char buf[RECBUFSIZ];
340
+ int len = sprintf(buf, "%08d", i);
341
+ if(!tculogwrite(ulog, 0, sid, sid, buf, len)){
342
+ eprint(ulog, "tculogwrite");
343
+ err = true;
344
+ break;
345
+ }
346
+ if(rnum > 250 && i % (rnum / 10) == 0) tcsleep(0.1);
347
+ }
348
+ for(int i = 0; i < tnum; i++){
349
+ if(targs[i].id == -1) continue;
350
+ void *rv;
351
+ if(pthread_join(threads[i], &rv) != 0){
352
+ eprint(ulog, "pthread_join");
353
+ err = true;
354
+ } else if(rv){
355
+ err = true;
356
+ }
357
+ tculrddel(targs[i].ulrd);
358
+ }
359
+ if(!tculogclose(ulog)){
360
+ eprint(ulog, "tculogclose");
361
+ err = true;
362
+ }
363
+ tculogdel(ulog);
364
+ iprintf("time: %.3f\n", tctime() - stime);
365
+ iprintf("%s\n\n", err ? "error" : "ok");
366
+ return err ? 1 : 0;
367
+ }
368
+
369
+
370
+
371
+ // END OF FILE
@@ -0,0 +1,1510 @@
1
+ /*************************************************************************************************
2
+ * The utility API of Tokyo Tyrant
3
+ * Copyright (C) 2006-2009 Mikio Hirabayashi
4
+ * This file is part of Tokyo Tyrant.
5
+ * Tokyo Tyrant is free software; you can redistribute it and/or modify it under the terms of
6
+ * the GNU Lesser General Public License as published by the Free Software Foundation; either
7
+ * version 2.1 of the License or any later version. Tokyo Tyrant is distributed in the hope
8
+ * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
10
+ * License for more details.
11
+ * You should have received a copy of the GNU Lesser General Public License along with Tokyo
12
+ * Tyrant; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
13
+ * Boston, MA 02111-1307 USA.
14
+ *************************************************************************************************/
15
+
16
+
17
+ #include "ttutil.h"
18
+ #include "myconf.h"
19
+
20
+
21
+
22
+ /*************************************************************************************************
23
+ * basic utilities
24
+ *************************************************************************************************/
25
+
26
+
27
+ #define SOCKPATHBUFSIZ 108 // size of a socket path buffer
28
+ #define SOCKRCVTIMEO 0.25 // timeout of the recv call of socket
29
+ #define SOCKSNDTIMEO 0.25 // timeout of the send call of socket
30
+ #define SOCKCNCTTIMEO 5.0 // timeout of the connect call of socket
31
+ #define SOCKLINEBUFSIZ 4096 // size of a line buffer of socket
32
+ #define SOCKLINEMAXSIZ (16*1024*1024) // maximum size of a line of socket
33
+ #define HTTPBODYMAXSIZ (256*1024*1024) // maximum size of the entity body of HTTP
34
+ #define TRILLIONNUM 1000000000000 // trillion number
35
+
36
+
37
+ /* String containing the version information. */
38
+ const char *ttversion = _TT_VERSION;
39
+
40
+
41
+ /* Get the primary name of the local host. */
42
+ bool ttgetlocalhostname(char *name){
43
+ assert(name);
44
+ if(gethostname(name, TTADDRBUFSIZ - 1) != 0){
45
+ sprintf(name, "localhost");
46
+ return false;
47
+ }
48
+ return true;
49
+ }
50
+
51
+
52
+ /* Get the address of a host. */
53
+ bool ttgethostaddr(const char *name, char *addr){
54
+ assert(name && addr);
55
+ struct addrinfo hints, *result;
56
+ memset(&hints, 0, sizeof(hints));
57
+ hints.ai_family = AF_INET;
58
+ hints.ai_socktype = SOCK_STREAM;
59
+ hints.ai_flags = 0;
60
+ hints.ai_protocol = IPPROTO_TCP;
61
+ hints.ai_canonname = NULL;
62
+ hints.ai_addr = NULL;
63
+ hints.ai_next = NULL;
64
+ if(getaddrinfo(name, NULL, &hints, &result) != 0){
65
+ *addr = '\0';
66
+ return false;
67
+ }
68
+ if(!result){
69
+ freeaddrinfo(result);
70
+ return false;
71
+ }
72
+ if(result->ai_addr->sa_family != AF_INET){
73
+ freeaddrinfo(result);
74
+ return false;
75
+ }
76
+ if(getnameinfo(result->ai_addr, result->ai_addrlen,
77
+ addr, TTADDRBUFSIZ, NULL, 0, NI_NUMERICHOST) != 0){
78
+ freeaddrinfo(result);
79
+ return false;
80
+ }
81
+ freeaddrinfo(result);
82
+ return true;
83
+ }
84
+
85
+
86
+ /* Open a client socket of TCP/IP stream to a server. */
87
+ int ttopensock(const char *addr, int port){
88
+ assert(addr && port >= 0);
89
+ struct sockaddr_in sain;
90
+ memset(&sain, 0, sizeof(sain));
91
+ sain.sin_family = AF_INET;
92
+ if(inet_aton(addr, &sain.sin_addr) == 0) return -1;
93
+ uint16_t snum = port;
94
+ sain.sin_port = htons(snum);
95
+ int fd = socket(PF_INET, SOCK_STREAM, 0);
96
+ if(fd == -1) return -1;
97
+ int optint = 1;
98
+ setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&optint, sizeof(optint));
99
+ struct timeval opttv;
100
+ opttv.tv_sec = (int)SOCKRCVTIMEO;
101
+ opttv.tv_usec = (SOCKRCVTIMEO - (int)SOCKRCVTIMEO) * 1000000;
102
+ setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&opttv, sizeof(opttv));
103
+ opttv.tv_sec = (int)SOCKSNDTIMEO;
104
+ opttv.tv_usec = (SOCKSNDTIMEO - (int)SOCKSNDTIMEO) * 1000000;
105
+ setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&opttv, sizeof(opttv));
106
+ optint = 1;
107
+ setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&optint, sizeof(optint));
108
+ double dl = tctime() + SOCKCNCTTIMEO;
109
+ do {
110
+ int ocs = PTHREAD_CANCEL_DISABLE;
111
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &ocs);
112
+ int rv = connect(fd, (struct sockaddr *)&sain, sizeof(sain));
113
+ int en = errno;
114
+ pthread_setcancelstate(ocs, NULL);
115
+ if(rv == 0) return fd;
116
+ if(en != EINTR && en != EAGAIN && en != EINPROGRESS && en != EALREADY && en != ETIMEDOUT)
117
+ break;
118
+ } while(tctime() <= dl);
119
+ close(fd);
120
+ return -1;
121
+ }
122
+
123
+
124
+ /* Open a client socket of UNIX domain stream to a server. */
125
+ int ttopensockunix(const char *path){
126
+ assert(path);
127
+ struct sockaddr_un saun;
128
+ memset(&saun, 0, sizeof(saun));
129
+ saun.sun_family = AF_UNIX;
130
+ snprintf(saun.sun_path, SOCKPATHBUFSIZ, "%s", path);
131
+ int fd = socket(PF_UNIX, SOCK_STREAM, 0);
132
+ if(fd == -1) return -1;
133
+ int optint = 1;
134
+ setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&optint, sizeof(optint));
135
+ struct timeval opttv;
136
+ opttv.tv_sec = (int)SOCKRCVTIMEO;
137
+ opttv.tv_usec = (SOCKRCVTIMEO - (int)SOCKRCVTIMEO) * 1000000;
138
+ setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&opttv, sizeof(opttv));
139
+ opttv.tv_sec = (int)SOCKSNDTIMEO;
140
+ opttv.tv_usec = (SOCKSNDTIMEO - (int)SOCKSNDTIMEO) * 1000000;
141
+ setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&opttv, sizeof(opttv));
142
+ double dl = tctime() + SOCKCNCTTIMEO;
143
+ do {
144
+ int ocs = PTHREAD_CANCEL_DISABLE;
145
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &ocs);
146
+ int rv = connect(fd, (struct sockaddr *)&saun, sizeof(saun));
147
+ int en = errno;
148
+ pthread_setcancelstate(ocs, NULL);
149
+ if(rv == 0) return fd;
150
+ if(en != EINTR && en != EAGAIN && en != EINPROGRESS && en != EALREADY && en != ETIMEDOUT)
151
+ break;
152
+ } while(tctime() <= dl);
153
+ close(fd);
154
+ return -1;
155
+ }
156
+
157
+
158
+ /* Open a server socket of TCP/IP stream to clients. */
159
+ int ttopenservsock(const char *addr, int port){
160
+ assert(port >= 0);
161
+ struct sockaddr_in sain;
162
+ memset(&sain, 0, sizeof(sain));
163
+ sain.sin_family = AF_INET;
164
+ if(inet_aton(addr ? addr : "0.0.0.0", &sain.sin_addr) == 0) return -1;
165
+ uint16_t snum = port;
166
+ sain.sin_port = htons(snum);
167
+ int fd = socket(PF_INET, SOCK_STREAM, 0);
168
+ if(fd == -1) return -1;
169
+ int optint = 1;
170
+ if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&optint, sizeof(optint)) != 0){
171
+ close(fd);
172
+ return -1;
173
+ }
174
+ if(bind(fd, (struct sockaddr *)&sain, sizeof(sain)) != 0 ||
175
+ listen(fd, SOMAXCONN) != 0){
176
+ close(fd);
177
+ return -1;
178
+ }
179
+ return fd;
180
+ }
181
+
182
+
183
+ /* Open a server socket of UNIX domain stream to clients. */
184
+ int ttopenservsockunix(const char *path){
185
+ assert(path);
186
+ if(*path == '\0') return -1;
187
+ struct sockaddr_un saun;
188
+ memset(&saun, 0, sizeof(saun));
189
+ saun.sun_family = AF_UNIX;
190
+ snprintf(saun.sun_path, SOCKPATHBUFSIZ, "%s", path);
191
+ int fd = socket(PF_UNIX, SOCK_STREAM, 0);
192
+ if(fd == -1) return -1;
193
+ if(bind(fd, (struct sockaddr *)&saun, sizeof(saun)) != 0 ||
194
+ listen(fd, SOMAXCONN) != 0){
195
+ close(fd);
196
+ return -1;
197
+ }
198
+ return fd;
199
+ }
200
+
201
+
202
+ /* Accept a TCP/IP connection from a client. */
203
+ int ttacceptsock(int fd, char *addr, int *pp){
204
+ assert(fd >= 0);
205
+ do {
206
+ struct sockaddr_in sain;
207
+ memset(&sain, 0, sizeof(sain));
208
+ sain.sin_family = AF_INET;
209
+ socklen_t slen = sizeof(sain);
210
+ int cfd = accept(fd, (struct sockaddr *)&sain, &slen);
211
+ if(cfd >= 0){
212
+ int optint = 1;
213
+ setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&optint, sizeof(optint));
214
+ struct timeval opttv;
215
+ opttv.tv_sec = (int)SOCKRCVTIMEO;
216
+ opttv.tv_usec = (SOCKRCVTIMEO - (int)SOCKRCVTIMEO) * 1000000;
217
+ setsockopt(cfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&opttv, sizeof(opttv));
218
+ opttv.tv_sec = (int)SOCKSNDTIMEO;
219
+ opttv.tv_usec = (SOCKSNDTIMEO - (int)SOCKSNDTIMEO) * 1000000;
220
+ setsockopt(cfd, SOL_SOCKET, SO_SNDTIMEO, (char *)&opttv, sizeof(opttv));
221
+ optint = 1;
222
+ setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY, (char *)&optint, sizeof(optint));
223
+ if(addr){
224
+ if(getnameinfo((struct sockaddr *)&sain, sizeof(sain), addr, TTADDRBUFSIZ,
225
+ NULL, 0, NI_NUMERICHOST) != 0) sprintf(addr, "0.0.0.0");
226
+ }
227
+ if(pp) *pp = (int)ntohs(sain.sin_port);
228
+ return cfd;
229
+ }
230
+ } while(errno == EINTR || errno == EAGAIN);
231
+ return -1;
232
+ }
233
+
234
+
235
+ /* Accept a UNIX domain connection from a client. */
236
+ int ttacceptsockunix(int fd){
237
+ assert(fd >= 0);
238
+ do {
239
+ int cfd = accept(fd, NULL, NULL);
240
+ if(cfd >= 0){
241
+ int optint = 1;
242
+ setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&optint, sizeof(optint));
243
+ struct timeval opttv;
244
+ opttv.tv_sec = (int)SOCKRCVTIMEO;
245
+ opttv.tv_usec = (SOCKRCVTIMEO - (int)SOCKRCVTIMEO) * 1000000;
246
+ setsockopt(cfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&opttv, sizeof(opttv));
247
+ opttv.tv_sec = (int)SOCKSNDTIMEO;
248
+ opttv.tv_usec = (SOCKSNDTIMEO - (int)SOCKSNDTIMEO) * 1000000;
249
+ setsockopt(cfd, SOL_SOCKET, SO_SNDTIMEO, (char *)&opttv, sizeof(opttv));
250
+ return cfd;
251
+ }
252
+ } while(errno == EINTR || errno == EAGAIN);
253
+ return -1;
254
+ }
255
+
256
+
257
+ /* Shutdown and close a socket. */
258
+ bool ttclosesock(int fd){
259
+ assert(fd >= 0);
260
+ bool err = false;
261
+ if(shutdown(fd, 2) != 0 && errno != ENOTCONN && errno != ECONNRESET) err = true;
262
+ if(close(fd) != 0 && errno != ENOTCONN && errno != ECONNRESET) err = true;
263
+ return !err;
264
+ }
265
+
266
+
267
+ /* Wait an I/O event of a socket. */
268
+ bool ttwaitsock(int fd, int mode, double timeout){
269
+ assert(fd >= 0 && mode >= 0 && timeout >= 0);
270
+ while(true){
271
+ fd_set set;
272
+ FD_ZERO(&set);
273
+ FD_SET(fd, &set);
274
+ double integ, fract;
275
+ fract = modf(timeout, &integ);
276
+ struct timespec ts;
277
+ ts.tv_sec = integ;
278
+ ts.tv_nsec = fract * 1000000000.0;
279
+ int rv = -1;
280
+ switch(mode){
281
+ case 0:
282
+ rv = pselect(fd + 1, &set, NULL, NULL, &ts, NULL);
283
+ break;
284
+ case 1:
285
+ rv = pselect(fd + 1, NULL, &set, NULL, &ts, NULL);
286
+ break;
287
+ case 2:
288
+ rv = pselect(fd + 1, NULL, NULL, &set, &ts, NULL);
289
+ break;
290
+ }
291
+ if(rv > 0) return true;
292
+ if(rv == 0 || errno != EINVAL) break;
293
+ }
294
+ return false;
295
+ }
296
+
297
+
298
+ /* Create a socket object. */
299
+ TTSOCK *ttsocknew(int fd){
300
+ assert(fd >= 0);
301
+ TTSOCK *sock = tcmalloc(sizeof(*sock));
302
+ sock->fd = fd;
303
+ sock->rp = sock->buf;
304
+ sock->ep = sock->buf;
305
+ sock->end = false;
306
+ sock->to = 0.0;
307
+ sock->dl = HUGE_VAL;
308
+ return sock;
309
+ }
310
+
311
+
312
+ /* Delete a socket object. */
313
+ void ttsockdel(TTSOCK *sock){
314
+ assert(sock);
315
+ tcfree(sock);
316
+ }
317
+
318
+
319
+ /* Set the lifetime of a socket object. */
320
+ void ttsocksetlife(TTSOCK *sock, double lifetime){
321
+ assert(sock && lifetime >= 0);
322
+ sock->to = lifetime >= INT_MAX ? 0.0 : lifetime;
323
+ sock->dl = tctime() + lifetime;
324
+ }
325
+
326
+
327
+ /* Send data by a socket. */
328
+ bool ttsocksend(TTSOCK *sock, const void *buf, int size){
329
+ assert(sock && buf && size >= 0);
330
+ const char *rp = buf;
331
+ do {
332
+ int ocs = PTHREAD_CANCEL_DISABLE;
333
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &ocs);
334
+ if(sock->to > 0.0 && !ttwaitsock(sock->fd, 1, sock->to)){
335
+ pthread_setcancelstate(ocs, NULL);
336
+ return false;
337
+ }
338
+ int wb = send(sock->fd, rp, size, 0);
339
+ int en = errno;
340
+ pthread_setcancelstate(ocs, NULL);
341
+ switch(wb){
342
+ case -1:
343
+ if(en != EINTR && en != EAGAIN && en != EWOULDBLOCK){
344
+ sock->end = true;
345
+ return false;
346
+ }
347
+ if(tctime() > sock->dl){
348
+ sock->end = true;
349
+ return false;
350
+ }
351
+ break;
352
+ case 0:
353
+ break;
354
+ default:
355
+ rp += wb;
356
+ size -= wb;
357
+ break;
358
+ }
359
+ } while(size > 0);
360
+ return true;
361
+ }
362
+
363
+
364
+ /* Send formatted data by a socket. */
365
+ bool ttsockprintf(TTSOCK *sock, const char *format, ...){
366
+ assert(sock && format);
367
+ bool err = false;
368
+ TCXSTR *xstr = tcxstrnew();
369
+ pthread_cleanup_push((void (*)(void *))tcxstrdel, xstr);
370
+ va_list ap;
371
+ va_start(ap, format);
372
+ while(*format != '\0'){
373
+ if(*format == '%'){
374
+ char cbuf[TTNUMBUFSIZ];
375
+ cbuf[0] = '%';
376
+ int cblen = 1;
377
+ int lnum = 0;
378
+ format++;
379
+ while(strchr("0123456789 .+-hlLz", *format) && *format != '\0' &&
380
+ cblen < TTNUMBUFSIZ - 1){
381
+ if(*format == 'l' || *format == 'L') lnum++;
382
+ cbuf[cblen++] = *(format++);
383
+ }
384
+ cbuf[cblen++] = *format;
385
+ cbuf[cblen] = '\0';
386
+ int tlen;
387
+ char *tmp, tbuf[TTNUMBUFSIZ*2];
388
+ switch(*format){
389
+ case 's':
390
+ tmp = va_arg(ap, char *);
391
+ if(!tmp) tmp = "(null)";
392
+ tcxstrcat2(xstr, tmp);
393
+ break;
394
+ case 'd':
395
+ if(lnum >= 2){
396
+ tlen = sprintf(tbuf, cbuf, va_arg(ap, long long));
397
+ } else if(lnum >= 1){
398
+ tlen = sprintf(tbuf, cbuf, va_arg(ap, long));
399
+ } else {
400
+ tlen = sprintf(tbuf, cbuf, va_arg(ap, int));
401
+ }
402
+ tcxstrcat(xstr, tbuf, tlen);
403
+ break;
404
+ case 'o': case 'u': case 'x': case 'X': case 'c':
405
+ if(lnum >= 2){
406
+ tlen = sprintf(tbuf, cbuf, va_arg(ap, unsigned long long));
407
+ } else if(lnum >= 1){
408
+ tlen = sprintf(tbuf, cbuf, va_arg(ap, unsigned long));
409
+ } else {
410
+ tlen = sprintf(tbuf, cbuf, va_arg(ap, unsigned int));
411
+ }
412
+ tcxstrcat(xstr, tbuf, tlen);
413
+ break;
414
+ case 'e': case 'E': case 'f': case 'g': case 'G':
415
+ if(lnum >= 1){
416
+ tlen = sprintf(tbuf, cbuf, va_arg(ap, long double));
417
+ } else {
418
+ tlen = sprintf(tbuf, cbuf, va_arg(ap, double));
419
+ }
420
+ tcxstrcat(xstr, tbuf, tlen);
421
+ break;
422
+ case '@':
423
+ tmp = va_arg(ap, char *);
424
+ if(!tmp) tmp = "(null)";
425
+ while(*tmp){
426
+ switch(*tmp){
427
+ case '&': tcxstrcat(xstr, "&amp;", 5); break;
428
+ case '<': tcxstrcat(xstr, "&lt;", 4); break;
429
+ case '>': tcxstrcat(xstr, "&gt;", 4); break;
430
+ case '"': tcxstrcat(xstr, "&quot;", 6); break;
431
+ default:
432
+ if(!((*tmp >= 0 && *tmp <= 0x8) || (*tmp >= 0x0e && *tmp <= 0x1f)))
433
+ tcxstrcat(xstr, tmp, 1);
434
+ break;
435
+ }
436
+ tmp++;
437
+ }
438
+ break;
439
+ case '?':
440
+ tmp = va_arg(ap, char *);
441
+ if(!tmp) tmp = "(null)";
442
+ while(*tmp){
443
+ unsigned char c = *(unsigned char *)tmp;
444
+ if((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
445
+ (c >= '0' && c <= '9') || (c != '\0' && strchr("_-.", c))){
446
+ tcxstrcat(xstr, tmp, 1);
447
+ } else {
448
+ tlen = sprintf(tbuf, "%%%02X", c);
449
+ tcxstrcat(xstr, tbuf, tlen);
450
+ }
451
+ tmp++;
452
+ }
453
+ break;
454
+ case '%':
455
+ tcxstrcat(xstr, "%", 1);
456
+ break;
457
+ }
458
+ } else {
459
+ tcxstrcat(xstr, format, 1);
460
+ }
461
+ format++;
462
+ }
463
+ va_end(ap);
464
+ if(!ttsocksend(sock, tcxstrptr(xstr), tcxstrsize(xstr))) err = true;
465
+ pthread_cleanup_pop(1);
466
+ return !err;
467
+ }
468
+
469
+
470
+ /* Receive data by a socket. */
471
+ bool ttsockrecv(TTSOCK *sock, char *buf, int size){
472
+ assert(sock && buf && size >= 0);
473
+ if(sock->rp + size <= sock->ep){
474
+ memcpy(buf, sock->rp, size);
475
+ sock->rp += size;
476
+ return true;
477
+ }
478
+ bool err = false;
479
+ char *wp = buf;
480
+ while(size > 0){
481
+ int c = ttsockgetc(sock);
482
+ if(c == -1){
483
+ err = true;
484
+ break;
485
+ }
486
+ *(wp++) = c;
487
+ size--;
488
+ }
489
+ return !err;
490
+ }
491
+
492
+
493
+ /* Receive one byte by a socket. */
494
+ int ttsockgetc(TTSOCK *sock){
495
+ assert(sock);
496
+ if(sock->rp < sock->ep) return *(unsigned char *)(sock->rp++);
497
+ int en;
498
+ do {
499
+ int ocs = PTHREAD_CANCEL_DISABLE;
500
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &ocs);
501
+ if(sock->to > 0.0 && !ttwaitsock(sock->fd, 0, sock->to)){
502
+ pthread_setcancelstate(ocs, NULL);
503
+ return -1;
504
+ }
505
+ int rv = recv(sock->fd, sock->buf, TTIOBUFSIZ, 0);
506
+ en = errno;
507
+ pthread_setcancelstate(ocs, NULL);
508
+ if(rv > 0){
509
+ sock->rp = sock->buf + 1;
510
+ sock->ep = sock->buf + rv;
511
+ return *(unsigned char *)sock->buf;
512
+ } else if(rv == 0){
513
+ sock->end = true;
514
+ return -1;
515
+ }
516
+ } while((en == EINTR || en == EAGAIN || en == EWOULDBLOCK) && tctime() <= sock->dl);
517
+ sock->end = true;
518
+ return -1;
519
+ }
520
+
521
+
522
+ /* Push a character back to a socket. */
523
+ void ttsockungetc(TTSOCK *sock, int c){
524
+ assert(sock);
525
+ if(sock->rp <= sock->buf) return;
526
+ sock->rp--;
527
+ *(unsigned char *)sock->rp = c;
528
+ }
529
+
530
+
531
+ /* Receive one line by a socket. */
532
+ bool ttsockgets(TTSOCK *sock, char *buf, int size){
533
+ assert(sock && buf && size > 0);
534
+ bool err = false;
535
+ size--;
536
+ char *wp = buf;
537
+ while(size > 0){
538
+ int c = ttsockgetc(sock);
539
+ if(c == '\n') break;
540
+ if(c == -1){
541
+ err = true;
542
+ break;
543
+ }
544
+ if(c != '\r'){
545
+ *(wp++) = c;
546
+ size--;
547
+ }
548
+ }
549
+ *wp = '\0';
550
+ return !err;
551
+ }
552
+
553
+
554
+ /* Receive one line by a socket into allocated buffer. */
555
+ char *ttsockgets2(TTSOCK *sock){
556
+ assert(sock);
557
+ bool err = false;
558
+ TCXSTR *xstr = tcxstrnew3(SOCKLINEBUFSIZ);
559
+ pthread_cleanup_push((void (*)(void *))tcxstrdel, xstr);
560
+ int size = 0;
561
+ while(true){
562
+ int c = ttsockgetc(sock);
563
+ if(c == '\n') break;
564
+ if(c == -1){
565
+ err = true;
566
+ break;
567
+ }
568
+ if(c != '\r'){
569
+ unsigned char b = c;
570
+ tcxstrcat(xstr, &b, sizeof(b));
571
+ size++;
572
+ if(size >= SOCKLINEMAXSIZ){
573
+ err = true;
574
+ break;
575
+ }
576
+ }
577
+ }
578
+ pthread_cleanup_pop(0);
579
+ return tcxstrtomalloc(xstr);
580
+ }
581
+
582
+
583
+ /* Receive an 32-bit integer by a socket. */
584
+ uint32_t ttsockgetint32(TTSOCK *sock){
585
+ assert(sock);
586
+ uint32_t num;
587
+ ttsockrecv(sock, (char *)&num, sizeof(num));
588
+ return TTNTOHL(num);
589
+ }
590
+
591
+
592
+ /* Receive an 64-bit integer by a socket. */
593
+ uint64_t ttsockgetint64(TTSOCK *sock){
594
+ assert(sock);
595
+ uint64_t num;
596
+ ttsockrecv(sock, (char *)&num, sizeof(num));
597
+ return TTNTOHLL(num);
598
+ }
599
+
600
+
601
+ /* Check whehter a socket is end. */
602
+ bool ttsockcheckend(TTSOCK *sock){
603
+ assert(sock);
604
+ return sock->end;
605
+ }
606
+
607
+
608
+ /* Check the size of prefetched data in a socket. */
609
+ int ttsockcheckpfsiz(TTSOCK *sock){
610
+ assert(sock);
611
+ if(sock->end) return 0;
612
+ return sock->ep - sock->rp;
613
+ }
614
+
615
+
616
+ /* Fetch the resource of a URL by HTTP. */
617
+ int tthttpfetch(const char *url, TCMAP *reqheads, TCMAP *resheads, TCXSTR *resbody){
618
+ assert(url);
619
+ int code = -1;
620
+ TCMAP *elems = tcurlbreak(url);
621
+ pthread_cleanup_push((void (*)(void *))tcmapdel, elems);
622
+ const char *scheme = tcmapget2(elems, "scheme");
623
+ const char *host = tcmapget2(elems, "host");
624
+ const char *port = tcmapget2(elems, "port");
625
+ const char *authority = tcmapget2(elems, "authority");
626
+ const char *path = tcmapget2(elems, "path");
627
+ const char *query = tcmapget2(elems, "query");
628
+ if(scheme && !tcstricmp(scheme, "http") && host){
629
+ if(*host == '\0') host = "127.0.0.1";
630
+ int pnum = port ? tcatoi(port) : 80;
631
+ if(pnum < 1) pnum = 80;
632
+ if(!path) path = "/";
633
+ char addr[TTADDRBUFSIZ];
634
+ int fd;
635
+ if(ttgethostaddr(host, addr) && (fd = ttopensock(addr, pnum)) != -1){
636
+ pthread_cleanup_push((void (*)(void *))ttclosesock, (void *)(intptr_t)fd);
637
+ TTSOCK *sock = ttsocknew(fd);
638
+ pthread_cleanup_push((void (*)(void *))ttsockdel, sock);
639
+ TCXSTR *obuf = tcxstrnew();
640
+ pthread_cleanup_push((void (*)(void *))tcxstrdel, obuf);
641
+ if(query){
642
+ tcxstrprintf(obuf, "GET %s?%s HTTP/1.1\r\n", path, query);
643
+ } else {
644
+ tcxstrprintf(obuf, "GET %s HTTP/1.1\r\n", path);
645
+ }
646
+ if(pnum == 80){
647
+ tcxstrprintf(obuf, "Host: %s\r\n", host);
648
+ } else {
649
+ tcxstrprintf(obuf, "Host: %s:%d\r\n", host, pnum);
650
+ }
651
+ tcxstrprintf(obuf, "Connection: close\r\n", host, port);
652
+ if(authority){
653
+ char *enc = tcbaseencode(authority, strlen(authority));
654
+ tcxstrprintf(obuf, "Authorization: Basic %s\r\n", enc);
655
+ tcfree(enc);
656
+ }
657
+ double tout = -1;
658
+ if(reqheads){
659
+ tcmapiterinit(reqheads);
660
+ const char *name;
661
+ while((name = tcmapiternext2(reqheads)) != NULL){
662
+ if(strchr(name, ':') || !tcstricmp(name, "connection")) continue;
663
+ if(!tcstricmp(name, "x-tt-timeout")){
664
+ tout = tcatof(tcmapget2(reqheads, name));
665
+ } else {
666
+ char *cap = tcstrdup(name);
667
+ tcstrtolower(cap);
668
+ char *wp = cap;
669
+ bool head = true;
670
+ while(*wp != '\0'){
671
+ if(head && *wp >= 'a' && *wp <= 'z') *wp -= 'a' - 'A';
672
+ head = *wp == '-' || *wp == ' ';
673
+ wp++;
674
+ }
675
+ tcxstrprintf(obuf, "%s: %s\r\n", cap, tcmapget2(reqheads, name));
676
+ tcfree(cap);
677
+ }
678
+ }
679
+ }
680
+ tcxstrprintf(obuf, "\r\n", host);
681
+ if(tout > 0) ttsocksetlife(sock, tout);
682
+ if(ttsocksend(sock, tcxstrptr(obuf), tcxstrsize(obuf))){
683
+ char line[SOCKLINEBUFSIZ];
684
+ if(ttsockgets(sock, line, SOCKLINEBUFSIZ) && tcstrfwm(line, "HTTP/")){
685
+ tcstrsqzspc(line);
686
+ const char *rp = strchr(line, ' ');
687
+ code = tcatoi(rp + 1);
688
+ if(resheads) tcmapput2(resheads, "STATUS", line);
689
+ }
690
+ if(code > 0){
691
+ int clen = 0;
692
+ bool chunked = false;
693
+ while(ttsockgets(sock, line, SOCKLINEBUFSIZ) && *line != '\0'){
694
+ tcstrsqzspc(line);
695
+ char *pv = strchr(line, ':');
696
+ if(!pv) continue;
697
+ *(pv++) = '\0';
698
+ while(*pv == ' '){
699
+ pv++;
700
+ }
701
+ tcstrtolower(line);
702
+ if(!strcmp(line, "content-length")){
703
+ clen = tcatoi(pv);
704
+ } else if(!strcmp(line, "transfer-encoding")){
705
+ if(!tcstricmp(pv, "chunked")) chunked = true;
706
+ }
707
+ if(resheads) tcmapput2(resheads, line, pv);
708
+ }
709
+ if(!ttsockcheckend(sock) && resbody){
710
+ bool err = false;
711
+ char *body;
712
+ int bsiz;
713
+ if(code == 304){
714
+ body = tcmemdup("", 0);
715
+ bsiz = 0;
716
+ } else if(chunked){
717
+ int asiz = SOCKLINEBUFSIZ;
718
+ body = tcmalloc(asiz);
719
+ bsiz = 0;
720
+ while(true){
721
+ pthread_cleanup_push(free, body);
722
+ if(!ttsockgets(sock, line, SOCKLINEBUFSIZ)) err = true;
723
+ pthread_cleanup_pop(0);
724
+ if(err || *line == '\0') break;
725
+ int size = tcatoih(line);
726
+ if(bsiz + size > HTTPBODYMAXSIZ){
727
+ err = true;
728
+ break;
729
+ }
730
+ if(bsiz + size > asiz){
731
+ asiz = bsiz * 2 + size;
732
+ body = tcrealloc(body, asiz);
733
+ }
734
+ pthread_cleanup_push(free, body);
735
+ if(size > 0) ttsockrecv(sock, body + bsiz, size);
736
+ if(ttsockgetc(sock) != '\r' || ttsockgetc(sock) != '\n') err = true;
737
+ pthread_cleanup_pop(0);
738
+ if(err || size < 1) break;
739
+ bsiz += size;
740
+ }
741
+ } else if(clen > 0){
742
+ if(clen > HTTPBODYMAXSIZ){
743
+ body = tcmemdup("", 0);
744
+ bsiz = 0;
745
+ err = true;
746
+ } else {
747
+ body = tcmalloc(clen);
748
+ bsiz = 0;
749
+ pthread_cleanup_push(free, body);
750
+ if(ttsockrecv(sock, body, clen)){
751
+ bsiz = clen;
752
+ } else {
753
+ err = true;
754
+ }
755
+ pthread_cleanup_pop(0);
756
+ }
757
+ } else {
758
+ int asiz = SOCKLINEBUFSIZ;
759
+ body = tcmalloc(asiz);
760
+ bsiz = 0;
761
+ while(true){
762
+ int c;
763
+ pthread_cleanup_push(free, body);
764
+ c = ttsockgetc(sock);
765
+ pthread_cleanup_pop(0);
766
+ if(c == -1) break;
767
+ if(bsiz >= HTTPBODYMAXSIZ){
768
+ err = true;
769
+ break;
770
+ }
771
+ if(bsiz >= asiz){
772
+ asiz = bsiz * 2;
773
+ body = tcrealloc(body, asiz);
774
+ }
775
+ body[bsiz++] = c;
776
+ }
777
+ }
778
+ if(err){
779
+ code = -1;
780
+ } else if(resbody){
781
+ tcxstrcat(resbody, body, bsiz);
782
+ }
783
+ tcfree(body);
784
+ }
785
+ }
786
+ }
787
+ pthread_cleanup_pop(1);
788
+ pthread_cleanup_pop(1);
789
+ pthread_cleanup_pop(1);
790
+ }
791
+ }
792
+ pthread_cleanup_pop(1);
793
+ return code;
794
+ }
795
+
796
+
797
+ /* Serialize a real number. */
798
+ void ttpackdouble(double num, char *buf){
799
+ assert(buf);
800
+ double dinteg, dfract;
801
+ dfract = modf(num, &dinteg);
802
+ int64_t linteg, lfract;
803
+ if(isnormal(dinteg) || dinteg == 0){
804
+ linteg = dinteg;
805
+ lfract = dfract * TRILLIONNUM;
806
+ } else if(isinf(dinteg)){
807
+ linteg = dinteg > 0 ? INT64_MAX : INT64_MIN;
808
+ lfract = 0;
809
+ } else {
810
+ linteg = INT64_MIN;
811
+ lfract = INT64_MIN;
812
+ }
813
+ linteg = TTHTONLL(linteg);
814
+ memcpy(buf, &linteg, sizeof(linteg));
815
+ lfract = TTHTONLL(lfract);
816
+ memcpy(buf + sizeof(linteg), &lfract, sizeof(lfract));
817
+ }
818
+
819
+
820
+ /* Redintegrate a serialized real number. */
821
+ double ttunpackdouble(const char *buf){
822
+ assert(buf);
823
+ int64_t linteg, lfract;
824
+ memcpy(&linteg, buf, sizeof(linteg));
825
+ linteg = TTNTOHLL(linteg);
826
+ memcpy(&lfract, buf + sizeof(linteg), sizeof(lfract));
827
+ lfract = TTNTOHLL(lfract);
828
+ if(lfract == INT64_MIN && linteg == INT64_MIN){
829
+ return NAN;
830
+ } else if(linteg == INT64_MAX){
831
+ return INFINITY;
832
+ } else if(linteg == INT64_MIN){
833
+ return -INFINITY;
834
+ }
835
+ return linteg + (double)lfract / TRILLIONNUM;
836
+ }
837
+
838
+
839
+
840
+ /*************************************************************************************************
841
+ * server utilities
842
+ *************************************************************************************************/
843
+
844
+
845
+ #define TTADDRBUFSIZ 1024 // size of an address buffer
846
+ #define TTDEFTHNUM 5 // default number of threads
847
+ #define TTEVENTMAX 256 // maximum number of events
848
+ #define TTWAITREQUEST 0.2 // waiting seconds for requests
849
+ #define TTWAITWORKER 0.1 // waiting seconds for finish of workers
850
+
851
+
852
+ /* private function prototypes */
853
+ static void *ttservtimer(void *argp);
854
+ static void ttservtask(TTSOCK *sock, TTREQ *req);
855
+ static void *ttservdeqtasks(void *argp);
856
+
857
+
858
+ /* Create a server object. */
859
+ TTSERV *ttservnew(void){
860
+ TTSERV *serv = tcmalloc(sizeof(*serv));
861
+ serv->host[0] = '\0';
862
+ serv->addr[0] = '\0';
863
+ serv->port = 0;
864
+ serv->queue = tclistnew();
865
+ if(pthread_mutex_init(&serv->qmtx, NULL) != 0) tcmyfatal("pthread_mutex_init failed");
866
+ if(pthread_cond_init(&serv->qcnd, NULL) != 0) tcmyfatal("pthread_cond_init failed");
867
+ if(pthread_mutex_init(&serv->tmtx, NULL) != 0) tcmyfatal("pthread_mutex_init failed");
868
+ if(pthread_cond_init(&serv->tcnd, NULL) != 0) tcmyfatal("pthread_cond_init failed");
869
+ serv->thnum = TTDEFTHNUM;
870
+ serv->timeout = 0;
871
+ serv->term = false;
872
+ serv->do_log = NULL;
873
+ serv->opq_log = NULL;
874
+ serv->timernum = 0;
875
+ serv->do_task = NULL;
876
+ serv->opq_task = NULL;
877
+ serv->do_term = NULL;
878
+ serv->opq_term = NULL;
879
+ return serv;
880
+ }
881
+
882
+
883
+ /* Delete a server object. */
884
+ void ttservdel(TTSERV *serv){
885
+ assert(serv);
886
+ pthread_cond_destroy(&serv->tcnd);
887
+ pthread_mutex_destroy(&serv->tmtx);
888
+ pthread_cond_destroy(&serv->qcnd);
889
+ pthread_mutex_destroy(&serv->qmtx);
890
+ tclistdel(serv->queue);
891
+ tcfree(serv);
892
+ }
893
+
894
+
895
+ /* Configure a server object. */
896
+ bool ttservconf(TTSERV *serv, const char *host, int port){
897
+ assert(serv);
898
+ bool err = false;
899
+ if(port < 1){
900
+ if(!host || host[0] == '\0'){
901
+ err = true;
902
+ serv->addr[0] = '\0';
903
+ ttservlog(serv, TTLOGERROR, "invalid socket path");
904
+ }
905
+ } else {
906
+ if(host && !ttgethostaddr(host, serv->addr)){
907
+ err = true;
908
+ serv->addr[0] = '\0';
909
+ ttservlog(serv, TTLOGERROR, "ttgethostaddr failed");
910
+ }
911
+ }
912
+ snprintf(serv->host, sizeof(serv->host), "%s", host ? host : "");
913
+ serv->port = port;
914
+ return !err;
915
+ }
916
+
917
+
918
+ /* Set tuning parameters of a server object. */
919
+ void ttservtune(TTSERV *serv, int thnum, double timeout){
920
+ assert(serv && thnum > 0);
921
+ serv->thnum = thnum;
922
+ serv->timeout = timeout;
923
+ }
924
+
925
+
926
+ /* Set the logging handler of a server object. */
927
+ void ttservsetloghandler(TTSERV *serv, void (*do_log)(int, const char *, void *), void *opq){
928
+ assert(serv && do_log);
929
+ serv->do_log = do_log;
930
+ serv->opq_log = opq;
931
+ }
932
+
933
+
934
+ /* Add a timed handler to a server object. */
935
+ void ttservaddtimedhandler(TTSERV *serv, double freq, void (*do_timed)(void *), void *opq){
936
+ assert(serv && freq >= 0.0 && do_timed);
937
+ if(serv->timernum >= TTTIMERMAX - 1) return;
938
+ TTTIMER *timer = serv->timers + serv->timernum;
939
+ timer->freq_timed = freq;
940
+ timer->do_timed = do_timed;
941
+ timer->opq_timed = opq;
942
+ serv->timernum++;
943
+ }
944
+
945
+
946
+ /* Set the response handler of a server object. */
947
+ void ttservsettaskhandler(TTSERV *serv, void (*do_task)(TTSOCK *, void *, TTREQ *), void *opq){
948
+ assert(serv && do_task);
949
+ serv->do_task = do_task;
950
+ serv->opq_task = opq;
951
+ }
952
+
953
+
954
+ /* Set the termination handler of a server object. */
955
+ void ttservsettermhandler(TTSERV *serv, void (*do_term)(void *), void *opq){
956
+ assert(serv && do_term);
957
+ serv->do_term = do_term;
958
+ serv->opq_term = opq;
959
+ }
960
+
961
+
962
+ /* Start the service of a server object. */
963
+ bool ttservstart(TTSERV *serv){
964
+ assert(serv);
965
+ int lfd;
966
+ if(serv->port < 1){
967
+ lfd = ttopenservsockunix(serv->host);
968
+ if(lfd == -1){
969
+ ttservlog(serv, TTLOGERROR, "ttopenservsockunix failed");
970
+ return false;
971
+ }
972
+ } else {
973
+ lfd = ttopenservsock(serv->addr[0] != '\0' ? serv->addr : NULL, serv->port);
974
+ if(lfd == -1){
975
+ ttservlog(serv, TTLOGERROR, "ttopenservsock failed");
976
+ return false;
977
+ }
978
+ }
979
+ int epfd = epoll_create(TTEVENTMAX);
980
+ if(epfd == -1){
981
+ close(lfd);
982
+ ttservlog(serv, TTLOGERROR, "epoll_create failed");
983
+ return false;
984
+ }
985
+ ttservlog(serv, TTLOGSYSTEM, "service started: %d", getpid());
986
+ bool err = false;
987
+ for(int i = 0; i < serv->timernum; i++){
988
+ TTTIMER *timer = serv->timers + i;
989
+ timer->alive = false;
990
+ timer->serv = serv;
991
+ if(pthread_create(&(timer->thid), NULL, ttservtimer, timer) == 0){
992
+ ttservlog(serv, TTLOGINFO, "timer thread %d started", i + 1);
993
+ timer->alive = true;
994
+ } else {
995
+ ttservlog(serv, TTLOGERROR, "pthread_create (ttservtimer) failed");
996
+ err = true;
997
+ }
998
+ }
999
+ int thnum = serv->thnum;
1000
+ TTREQ reqs[thnum];
1001
+ for(int i = 0; i < thnum; i++){
1002
+ reqs[i].alive = true;
1003
+ reqs[i].serv = serv;
1004
+ reqs[i].epfd = epfd;
1005
+ reqs[i].mtime = tctime();
1006
+ reqs[i].keep = false;
1007
+ reqs[i].idx = i;
1008
+ if(pthread_create(&reqs[i].thid, NULL, ttservdeqtasks, reqs + i) == 0){
1009
+ ttservlog(serv, TTLOGINFO, "worker thread %d started", i + 1);
1010
+ } else {
1011
+ reqs[i].alive = false;
1012
+ err = true;
1013
+ ttservlog(serv, TTLOGERROR, "pthread_create (ttservdeqtasks) failed");
1014
+ }
1015
+ }
1016
+ struct epoll_event ev;
1017
+ memset(&ev, 0, sizeof(ev));
1018
+ ev.events = EPOLLIN;
1019
+ ev.data.fd = lfd;
1020
+ if(epoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &ev) != 0){
1021
+ err = true;
1022
+ ttservlog(serv, TTLOGERROR, "epoll_ctl failed");
1023
+ }
1024
+ ttservlog(serv, TTLOGSYSTEM, "listening started");
1025
+ while(!serv->term){
1026
+ struct epoll_event events[TTEVENTMAX];
1027
+ int fdnum = epoll_wait(epfd, events, TTEVENTMAX, TTWAITREQUEST * 1000);
1028
+ if(fdnum != -1){
1029
+ for(int i = 0; i < fdnum; i++){
1030
+ if(events[i].data.fd == lfd){
1031
+ char addr[TTADDRBUFSIZ];
1032
+ int port;
1033
+ int cfd;
1034
+ if(serv->port < 1){
1035
+ cfd = ttacceptsockunix(lfd);
1036
+ sprintf(addr, "(unix)");
1037
+ port = 0;
1038
+ } else {
1039
+ cfd = ttacceptsock(lfd, addr, &port);
1040
+ }
1041
+ if(epoll_reassoc(epfd, lfd) != 0){
1042
+ if(cfd != -1) close(cfd);
1043
+ cfd = -1;
1044
+ }
1045
+ if(cfd != -1){
1046
+ ttservlog(serv, TTLOGINFO, "connected: %s:%d", addr, port);
1047
+ struct epoll_event ev;
1048
+ memset(&ev, 0, sizeof(ev));
1049
+ ev.events = EPOLLIN | EPOLLONESHOT;
1050
+ ev.data.fd = cfd;
1051
+ if(epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &ev) != 0){
1052
+ close(cfd);
1053
+ err = true;
1054
+ ttservlog(serv, TTLOGERROR, "epoll_ctl failed");
1055
+ }
1056
+ } else {
1057
+ err = true;
1058
+ ttservlog(serv, TTLOGERROR, "ttacceptsock failed");
1059
+ if(epoll_ctl(epfd, EPOLL_CTL_DEL, lfd, NULL) != 0)
1060
+ ttservlog(serv, TTLOGERROR, "epoll_ctl failed");
1061
+ if(close(lfd) != 0) ttservlog(serv, TTLOGERROR, "close failed");
1062
+ tcsleep(TTWAITWORKER);
1063
+ if(serv->port < 1){
1064
+ lfd = ttopenservsockunix(serv->host);
1065
+ if(lfd == -1) ttservlog(serv, TTLOGERROR, "ttopenservsockunix failed");
1066
+ } else {
1067
+ lfd = ttopenservsock(serv->addr[0] != '\0' ? serv->addr : NULL, serv->port);
1068
+ if(lfd == -1) ttservlog(serv, TTLOGERROR, "ttopenservsock failed");
1069
+ }
1070
+ if(lfd >= 0){
1071
+ memset(&ev, 0, sizeof(ev));
1072
+ ev.events = EPOLLIN;
1073
+ ev.data.fd = lfd;
1074
+ if(epoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &ev) == 0){
1075
+ ttservlog(serv, TTLOGSYSTEM, "listening restarted");
1076
+ } else {
1077
+ ttservlog(serv, TTLOGERROR, "epoll_ctl failed");
1078
+ }
1079
+ }
1080
+ }
1081
+ } else {
1082
+ int cfd = events[i].data.fd;
1083
+ if(pthread_mutex_lock(&serv->qmtx) == 0){
1084
+ tclistpush(serv->queue, &cfd, sizeof(cfd));
1085
+ if(pthread_mutex_unlock(&serv->qmtx) != 0){
1086
+ err = true;
1087
+ ttservlog(serv, TTLOGERROR, "pthread_mutex_unlock failed");
1088
+ }
1089
+ if(pthread_cond_signal(&serv->qcnd) != 0){
1090
+ err = true;
1091
+ ttservlog(serv, TTLOGERROR, "pthread_cond_signal failed");
1092
+ }
1093
+ } else {
1094
+ err = true;
1095
+ ttservlog(serv, TTLOGERROR, "pthread_mutex_lock failed");
1096
+ }
1097
+ }
1098
+ }
1099
+ } else {
1100
+ if(errno == EINTR){
1101
+ ttservlog(serv, TTLOGINFO, "signal interruption");
1102
+ } else {
1103
+ err = true;
1104
+ ttservlog(serv, TTLOGERROR, "epoll_wait failed");
1105
+ }
1106
+ }
1107
+ if(serv->timeout > 0){
1108
+ double ctime = tctime();
1109
+ for(int i = 0; i < thnum; i++){
1110
+ double itime = ctime - reqs[i].mtime;
1111
+ if(itime > serv->timeout + TTWAITREQUEST + SOCKRCVTIMEO + SOCKSNDTIMEO &&
1112
+ pthread_cancel(reqs[i].thid) == 0){
1113
+ ttservlog(serv, TTLOGINFO, "worker thread %d canceled by timeout", i + 1);
1114
+ void *rv;
1115
+ if(pthread_join(reqs[i].thid, &rv) == 0){
1116
+ if(rv && rv != PTHREAD_CANCELED) err = true;
1117
+ reqs[i].mtime = tctime();
1118
+ if(pthread_create(&reqs[i].thid, NULL, ttservdeqtasks, reqs + i) != 0){
1119
+ reqs[i].alive = false;
1120
+ err = true;
1121
+ ttservlog(serv, TTLOGERROR, "pthread_create (ttservdeqtasks) failed");
1122
+ } else {
1123
+ ttservlog(serv, TTLOGINFO, "worker thread %d started", i + 1);
1124
+ }
1125
+ } else {
1126
+ reqs[i].alive = false;
1127
+ err = true;
1128
+ ttservlog(serv, TTLOGERROR, "pthread_join failed");
1129
+ }
1130
+ }
1131
+ }
1132
+ }
1133
+ }
1134
+ ttservlog(serv, TTLOGSYSTEM, "listening finished");
1135
+ if(pthread_cond_broadcast(&serv->qcnd) != 0){
1136
+ err = true;
1137
+ ttservlog(serv, TTLOGERROR, "pthread_cond_broadcast failed");
1138
+ }
1139
+ if(pthread_cond_broadcast(&serv->tcnd) != 0){
1140
+ err = true;
1141
+ ttservlog(serv, TTLOGERROR, "pthread_cond_broadcast failed");
1142
+ }
1143
+ tcsleep(TTWAITWORKER);
1144
+ if(serv->do_term) serv->do_term(serv->opq_term);
1145
+ for(int i = 0; i < thnum; i++){
1146
+ if(!reqs[i].alive) continue;
1147
+ if(pthread_cancel(reqs[i].thid) == 0)
1148
+ ttservlog(serv, TTLOGINFO, "worker thread %d was canceled", i + 1);
1149
+ void *rv;
1150
+ if(pthread_join(reqs[i].thid, &rv) == 0){
1151
+ ttservlog(serv, TTLOGINFO, "worker thread %d finished", i + 1);
1152
+ if(rv && rv != PTHREAD_CANCELED) err = true;
1153
+ } else {
1154
+ err = true;
1155
+ ttservlog(serv, TTLOGERROR, "pthread_join failed");
1156
+ }
1157
+ }
1158
+ if(tclistnum(serv->queue) > 0)
1159
+ ttservlog(serv, TTLOGINFO, "%d requests discarded", tclistnum(serv->queue));
1160
+ tclistclear(serv->queue);
1161
+ for(int i = 0; i < serv->timernum; i++){
1162
+ TTTIMER *timer = serv->timers + i;
1163
+ if(!timer->alive) continue;
1164
+ void *rv;
1165
+ if(pthread_cancel(timer->thid) == 0)
1166
+ ttservlog(serv, TTLOGINFO, "timer thread %d was canceled", i + 1);
1167
+ if(pthread_join(timer->thid, &rv) == 0){
1168
+ ttservlog(serv, TTLOGINFO, "timer thread %d finished", i + 1);
1169
+ if(rv && rv != PTHREAD_CANCELED) err = true;
1170
+ } else {
1171
+ err = true;
1172
+ ttservlog(serv, TTLOGERROR, "pthread_join failed");
1173
+ }
1174
+ }
1175
+ if(epoll_close(epfd) != 0){
1176
+ err = true;
1177
+ ttservlog(serv, TTLOGERROR, "epoll_close failed");
1178
+ }
1179
+ if(serv->port < 1 && unlink(serv->host) == -1){
1180
+ err = true;
1181
+ ttservlog(serv, TTLOGERROR, "unlink failed");
1182
+ }
1183
+ if(lfd >= 0 && close(lfd) != 0){
1184
+ err = true;
1185
+ ttservlog(serv, TTLOGERROR, "close failed");
1186
+ }
1187
+ ttservlog(serv, TTLOGSYSTEM, "service finished");
1188
+ serv->term = false;
1189
+ return !err;
1190
+ }
1191
+
1192
+
1193
+ /* Send the terminate signal to a server object. */
1194
+ bool ttservkill(TTSERV *serv){
1195
+ assert(serv);
1196
+ serv->term = true;
1197
+ return true;
1198
+ }
1199
+
1200
+
1201
+ /* Call the logging function of a server object. */
1202
+ void ttservlog(TTSERV *serv, int level, const char *format, ...){
1203
+ assert(serv && format);
1204
+ if(!serv->do_log) return;
1205
+ char buf[TTIOBUFSIZ];
1206
+ va_list ap;
1207
+ va_start(ap, format);
1208
+ vsnprintf(buf, TTIOBUFSIZ, format, ap);
1209
+ va_end(ap);
1210
+ serv->do_log(level, buf, serv->opq_log);
1211
+ }
1212
+
1213
+
1214
+ /* Check whether a server object is killed. */
1215
+ bool ttserviskilled(TTSERV *serv){
1216
+ assert(serv);
1217
+ return serv->term;
1218
+ }
1219
+
1220
+
1221
+ /* Break a simple server expression. */
1222
+ char *ttbreakservexpr(const char *expr, int *pp){
1223
+ assert(expr);
1224
+ char *host = tcstrdup(expr);
1225
+ char *pv = strchr(host, '#');
1226
+ if(pv) *pv = '\0';
1227
+ int port = -1;
1228
+ pv = strchr(host, ':');
1229
+ if(pv){
1230
+ *(pv++) = '\0';
1231
+ if(*pv >= '0' && *pv <= '9') port = tcatoi(pv);
1232
+ }
1233
+ if(port < 0) port = TTDEFPORT;
1234
+ if(pp) *pp = port;
1235
+ tcstrtrim(host);
1236
+ if(*host == '\0'){
1237
+ tcfree(host);
1238
+ host = tcstrdup("127.0.0.1");
1239
+ }
1240
+ return host;
1241
+ }
1242
+
1243
+
1244
+ /* Call the timed function of a server object.
1245
+ `argp' specifies the argument structure of the server object.
1246
+ The return value is `NULL' on success and other on failure. */
1247
+ static void *ttservtimer(void *argp){
1248
+ TTTIMER *timer = argp;
1249
+ TTSERV *serv = timer->serv;
1250
+ bool err = false;
1251
+ if(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL) != 0){
1252
+ err = true;
1253
+ ttservlog(serv, TTLOGERROR, "pthread_setcancelstate failed");
1254
+ }
1255
+ tcsleep(TTWAITWORKER);
1256
+ double freqi;
1257
+ double freqd = modf(timer->freq_timed, &freqi);
1258
+ while(!serv->term){
1259
+ if(pthread_mutex_lock(&serv->tmtx) == 0){
1260
+ struct timeval tv;
1261
+ struct timespec ts;
1262
+ if(gettimeofday(&tv, NULL) == 0){
1263
+ ts.tv_sec = tv.tv_sec + (int)freqi;
1264
+ ts.tv_nsec = tv.tv_usec * 1000.0 + freqd * 1000000000.0;
1265
+ if(ts.tv_nsec >= 1000000000){
1266
+ ts.tv_nsec -= 1000000000;
1267
+ ts.tv_sec++;
1268
+ }
1269
+ } else {
1270
+ ts.tv_sec = (1ULL << (sizeof(time_t) * 8 - 1)) - 1;
1271
+ ts.tv_nsec = 0;
1272
+ }
1273
+ int code = pthread_cond_timedwait(&serv->tcnd, &serv->tmtx, &ts);
1274
+ if(code == 0 || code == ETIMEDOUT || code == EINTR){
1275
+ if(pthread_mutex_unlock(&serv->tmtx) != 0){
1276
+ err = true;
1277
+ ttservlog(serv, TTLOGERROR, "pthread_mutex_unlock failed");
1278
+ break;
1279
+ }
1280
+ if(code != 0 && !serv->term) timer->do_timed(timer->opq_timed);
1281
+ } else {
1282
+ pthread_mutex_unlock(&serv->tmtx);
1283
+ err = true;
1284
+ ttservlog(serv, TTLOGERROR, "pthread_cond_timedwait failed");
1285
+ }
1286
+ } else {
1287
+ err = true;
1288
+ ttservlog(serv, TTLOGERROR, "pthread_mutex_lock failed");
1289
+ }
1290
+ }
1291
+ return err ? "error" : NULL;
1292
+ }
1293
+
1294
+
1295
+ /* Call the task function of a server object.
1296
+ `req' specifies the request object.
1297
+ `sock' specifies the socket object. */
1298
+ static void ttservtask(TTSOCK *sock, TTREQ *req){
1299
+ TTSERV *serv = req->serv;
1300
+ if(!serv->do_task) return;
1301
+ serv->do_task(sock, serv->opq_task, req);
1302
+ }
1303
+
1304
+
1305
+ /* Dequeue tasks of a server object and dispatch them.
1306
+ `argp' specifies the argument structure of the server object.
1307
+ The return value is `NULL' on success and other on failure. */
1308
+ static void *ttservdeqtasks(void *argp){
1309
+ TTREQ *req = argp;
1310
+ TTSERV *serv = req->serv;
1311
+ bool err = false;
1312
+ if(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL) != 0){
1313
+ err = true;
1314
+ ttservlog(serv, TTLOGERROR, "pthread_setcancelstate failed");
1315
+ }
1316
+ sigset_t sigset;
1317
+ sigemptyset(&sigset);
1318
+ sigaddset(&sigset, SIGPIPE);
1319
+ sigset_t oldsigset;
1320
+ sigemptyset(&sigset);
1321
+ if(pthread_sigmask(SIG_BLOCK, &sigset, &oldsigset) != 0){
1322
+ err = true;
1323
+ ttservlog(serv, TTLOGERROR, "pthread_sigmask failed");
1324
+ }
1325
+ bool empty = false;
1326
+ while(!serv->term){
1327
+ if(pthread_mutex_lock(&serv->qmtx) == 0){
1328
+ struct timeval tv;
1329
+ struct timespec ts;
1330
+ if(gettimeofday(&tv, NULL) == 0){
1331
+ ts.tv_sec = tv.tv_sec;
1332
+ ts.tv_nsec = tv.tv_usec * 1000.0 + TTWAITREQUEST * 1000000000.0;
1333
+ if(ts.tv_nsec >= 1000000000){
1334
+ ts.tv_nsec -= 1000000000;
1335
+ ts.tv_sec++;
1336
+ }
1337
+ } else {
1338
+ ts.tv_sec = (1ULL << (sizeof(time_t) * 8 - 1)) - 1;
1339
+ ts.tv_nsec = 0;
1340
+ }
1341
+ int code = empty ? pthread_cond_timedwait(&serv->qcnd, &serv->qmtx, &ts) : 0;
1342
+ if(code == 0 || code == ETIMEDOUT || code == EINTR){
1343
+ void *val = tclistshift2(serv->queue);
1344
+ if(pthread_mutex_unlock(&serv->qmtx) != 0){
1345
+ err = true;
1346
+ ttservlog(serv, TTLOGERROR, "pthread_mutex_unlock failed");
1347
+ }
1348
+ if(val){
1349
+ empty = false;
1350
+ int cfd = *(int *)val;
1351
+ tcfree(val);
1352
+ pthread_cleanup_push((void (*)(void *))close, (void *)(intptr_t)cfd);
1353
+ TTSOCK *sock = ttsocknew(cfd);
1354
+ pthread_cleanup_push((void (*)(void *))ttsockdel, sock);
1355
+ bool reuse;
1356
+ do {
1357
+ if(serv->timeout > 0) ttsocksetlife(sock, serv->timeout);
1358
+ req->mtime = tctime();
1359
+ req->keep = false;
1360
+ ttservtask(sock, req);
1361
+ reuse = false;
1362
+ if(sock->end){
1363
+ req->keep = false;
1364
+ } else if(sock->ep > sock->rp){
1365
+ reuse = true;
1366
+ }
1367
+ } while(reuse);
1368
+ pthread_cleanup_pop(1);
1369
+ pthread_cleanup_pop(0);
1370
+ if(req->keep){
1371
+ struct epoll_event ev;
1372
+ memset(&ev, 0, sizeof(ev));
1373
+ ev.events = EPOLLIN | EPOLLONESHOT;
1374
+ ev.data.fd = cfd;
1375
+ if(epoll_ctl(req->epfd, EPOLL_CTL_MOD, cfd, &ev) != 0){
1376
+ close(cfd);
1377
+ err = true;
1378
+ ttservlog(serv, TTLOGERROR, "epoll_ctl failed");
1379
+ }
1380
+ } else {
1381
+ if(epoll_ctl(req->epfd, EPOLL_CTL_DEL, cfd, NULL) != 0){
1382
+ err = true;
1383
+ ttservlog(serv, TTLOGERROR, "epoll_ctl failed");
1384
+ }
1385
+ if(!ttclosesock(cfd)){
1386
+ err = true;
1387
+ ttservlog(serv, TTLOGERROR, "close failed");
1388
+ }
1389
+ ttservlog(serv, TTLOGINFO, "connection finished");
1390
+ }
1391
+ } else {
1392
+ empty = true;
1393
+ }
1394
+ } else {
1395
+ pthread_mutex_unlock(&serv->qmtx);
1396
+ err = true;
1397
+ ttservlog(serv, TTLOGERROR, "pthread_cond_timedwait failed");
1398
+ }
1399
+ } else {
1400
+ err = true;
1401
+ ttservlog(serv, TTLOGERROR, "pthread_mutex_lock failed");
1402
+ }
1403
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
1404
+ pthread_testcancel();
1405
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
1406
+ req->mtime = tctime();
1407
+ }
1408
+ if(pthread_sigmask(SIG_SETMASK, &oldsigset, NULL) != 0){
1409
+ err = true;
1410
+ ttservlog(serv, TTLOGERROR, "pthread_sigmask failed");
1411
+ }
1412
+ return err ? "error" : NULL;
1413
+ }
1414
+
1415
+
1416
+
1417
+ /*************************************************************************************************
1418
+ * features for experts
1419
+ *************************************************************************************************/
1420
+
1421
+
1422
+ #define NULLDEV "/dev/null" // path of the null device
1423
+
1424
+
1425
+ /* Switch the process into the background. */
1426
+ bool ttdaemonize(void){
1427
+ fflush(stdout);
1428
+ fflush(stderr);
1429
+ switch(fork()){
1430
+ case -1: return false;
1431
+ case 0: break;
1432
+ default: _exit(0);
1433
+ }
1434
+ if(setsid() == -1) return false;
1435
+ switch(fork()){
1436
+ case -1: return false;
1437
+ case 0: break;
1438
+ default: _exit(0);
1439
+ }
1440
+ umask(0);
1441
+ if(chdir(MYPATHSTR) == -1) return false;
1442
+ close(0);
1443
+ close(1);
1444
+ close(2);
1445
+ int fd = open(NULLDEV, O_RDWR, 0);
1446
+ if(fd != -1){
1447
+ dup2(fd, 0);
1448
+ dup2(fd, 1);
1449
+ dup2(fd, 2);
1450
+ if(fd > 2) close(fd);
1451
+ }
1452
+ return true;
1453
+ }
1454
+
1455
+
1456
+ /* Get the load average of the system. */
1457
+ double ttgetloadavg(void){
1458
+ double avgs[3];
1459
+ int anum = getloadavg(avgs, sizeof(avgs) / sizeof(*avgs));
1460
+ if(anum < 1) return 0.0;
1461
+ return anum == 1 ? avgs[0] : avgs[1];
1462
+ }
1463
+
1464
+
1465
+ /* Convert a string to a time stamp. */
1466
+ uint64_t ttstrtots(const char *str){
1467
+ assert(str);
1468
+ if(!tcstricmp(str, "now")) str = "-1";
1469
+ int64_t ts = tcatoi(str);
1470
+ if(ts < 0) ts = tctime() * 1000000;
1471
+ return ts;
1472
+ }
1473
+
1474
+
1475
+ /* Get the command name of a command ID number. */
1476
+ const char *ttcmdidtostr(int id){
1477
+ switch(id){
1478
+ case TTCMDPUT: return "put";
1479
+ case TTCMDPUTKEEP: return "putkeep";
1480
+ case TTCMDPUTCAT: return "putcat";
1481
+ case TTCMDPUTSHL: return "putshl";
1482
+ case TTCMDPUTNR: return "putnr";
1483
+ case TTCMDOUT: return "out";
1484
+ case TTCMDGET: return "get";
1485
+ case TTCMDMGET: return "mget";
1486
+ case TTCMDVSIZ: return "vsiz";
1487
+ case TTCMDITERINIT: return "iterinit";
1488
+ case TTCMDITERNEXT: return "iternext";
1489
+ case TTCMDFWMKEYS: return "fwmkeys";
1490
+ case TTCMDADDINT: return "addint";
1491
+ case TTCMDADDDOUBLE: return "adddouble";
1492
+ case TTCMDEXT: return "ext";
1493
+ case TTCMDSYNC: return "sync";
1494
+ case TTCMDOPTIMIZE: return "optimize";
1495
+ case TTCMDVANISH: return "vanish";
1496
+ case TTCMDCOPY: return "copy";
1497
+ case TTCMDRESTORE: return "restore";
1498
+ case TTCMDSETMST: return "setmst";
1499
+ case TTCMDRNUM: return "rnum";
1500
+ case TTCMDSIZE: return "size";
1501
+ case TTCMDSTAT: return "stat";
1502
+ case TTCMDMISC: return "misc";
1503
+ case TTCMDREPL: return "repl";
1504
+ }
1505
+ return "(unknown)";
1506
+ }
1507
+
1508
+
1509
+
1510
+ // END OF FILE