PageRenderTime 39ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 0ms

/tools/vfcgi2/ev/fcgi/Request.d

http://gool.googlecode.com/
D | 407 lines | 164 code | 17 blank | 226 comment | 16 complexity | 562debb7aa3713df47ec85677587dbe0 MD5 | raw file
  1. module vlib.ev.fcgi.Request ;
  2. import vlib.Types;
  3. private {
  4. extern(C){
  5. int fclose(int);
  6. }
  7. extern(Windows) {
  8. int connect(int, vAddr4*, int) ;
  9. int socket(int af, int type, int protocol);
  10. }
  11. }
  12. struct vFcgReq {
  13. alias typeof(*this) This ;
  14. alias typeof(this) pThis ;
  15. static void* _root ;
  16. static This[] _list ;
  17. static int _len = 4 ;
  18. static Mutex _mux ;
  19. static void Init() {
  20. _mux = new Mutex ;
  21. expand(4) ;
  22. }
  23. static void expand(int i) {
  24. if( i < _len ) {
  25. return ;
  26. }
  27. _len = _len * 2 ;
  28. if( _len < i ) {
  29. _len = i ;
  30. }
  31. int size = This.sizeof * _len ;
  32. _root = GC.realloc (_root, size , GC.BlkAttr.NO_MOVE | GC.BlkAttr.NO_SCAN ) ;
  33. _list = cast(This[]) _root[0..size] ;
  34. assert(_list.length is _len ) ;
  35. }
  36. static void accept(ref Berkeley ssoc){
  37. _mux.lock();
  38. scope(exit) _mux.unlock() ;
  39. pThis _this = null ;
  40. foreach(ref q; _list){
  41. if( !q._running ){
  42. _this = &q ;
  43. break ;
  44. }
  45. }
  46. if( _this is null ) {
  47. int len = _list.length ;
  48. expand(len + 1 ) ;
  49. _this = &_list[len] ;
  50. }
  51. _this.Setup ;
  52. _this._running = true ;
  53. ssoc.accept(_this.si) ;
  54. assert( _this._res !is null);
  55. _this._res.start() ;
  56. }
  57. enum State {
  58. None ,
  59. Connecting ,
  60. Proxying ,
  61. Closing ,
  62. }
  63. enum Errno {
  64. None ,
  65. Connect ,
  66. Res_Read,
  67. Res_Write,
  68. Req_Read,
  69. Req_Write,
  70. }
  71. Thread _req, _res ;
  72. Semaphore _sem = null ;
  73. bool _running ;
  74. Berkeley si ;
  75. Berkeley so ;
  76. vProcess* php ;
  77. State _state ;
  78. Errno _errno ;
  79. void Setup() {
  80. if( _sem !is null ) {
  81. return ;
  82. }
  83. _req = new Thread(&Req_Loop) ;
  84. _res = new Thread(&Res_Loop) ;
  85. _sem = new Semaphore ;
  86. }
  87. void Free(){
  88. so.detach ;
  89. si.detach ;
  90. _mux.lock();
  91. scope(exit) _mux.unlock() ;
  92. _running = false ;
  93. }
  94. void Req_Loop(){
  95. scope(exit){
  96. log!(__FILE__, __LINE__)("exit Req_Loop :{:x}", cast(void*)Thread.getThis) ;
  97. }
  98. log!(__FILE__, __LINE__)("connected , start req proxy:{:x}", cast(void*)Thread.getThis) ;
  99. Thread.sleep(.1);
  100. ubyte[512] tmp ;
  101. while(true){
  102. int i = so.receive(tmp) ;
  103. if( i <= 0 || i > tmp.length ) {
  104. _errno = Errno.Res_Read ;
  105. log!(__FILE__, __LINE__)("Res_Read: {}", i ) ;
  106. return ;
  107. }
  108. ubyte[] _tmp = tmp[0..i];
  109. while( _tmp.length ) {
  110. int j = si.send( _tmp) ;
  111. if( j < 0 || j > _tmp.length ) {
  112. _errno = Errno.Req_Write ;
  113. log!(__FILE__, __LINE__)("Req_Write: {}", j ) ;
  114. return ;
  115. }
  116. if( j is _tmp.length ) {
  117. break ;
  118. }
  119. _tmp = _tmp[ j .. $] ;
  120. }
  121. }
  122. }
  123. void Res_Loop(){
  124. scope(exit){
  125. Free;
  126. log!(__FILE__, __LINE__)("exit Res_Loop :{:x}", cast(void*)Thread.getThis) ;
  127. }
  128. _errno = Errno.None ;
  129. _state = State.Connecting ;
  130. so.open(AddressFamily.INET, SocketType.STREAM, ProtocolType.TCP) ;
  131. vProcess.find(php);
  132. int ret = connect(so.handle, &php._addr, php._addr.sizeof );
  133. if( ret !is 0 ) {
  134. log!(__FILE__, __LINE__)(" connect error :{}", ret) ;
  135. _state = State.Closing ;
  136. _errno = Errno.Connect ;
  137. Free;
  138. return ;
  139. }
  140. log!(__FILE__, __LINE__)("connected , start res proxy, {:x},", cast(void*)Thread.getThis) ;
  141. ubyte[512] tmp ;
  142. while(true) {
  143. int i = si.receive(tmp) ;
  144. if( i <= 0 || i > tmp.length ) {
  145. _errno = Errno.Req_Read ;
  146. log!(__FILE__, __LINE__)("Req_Read: {}", i ) ;
  147. return ;
  148. }
  149. ubyte[] _tmp = tmp[0..i];
  150. while( _tmp.length ) {
  151. int j = so.send( _tmp) ;
  152. if( j < 0 || j > _tmp.length ) {
  153. _errno = Errno.Res_Write ;
  154. log!(__FILE__, __LINE__)("Res_Write: {}", j ) ;
  155. return ;
  156. }
  157. if( j is _tmp.length ) {
  158. break ;
  159. }
  160. _tmp = _tmp[ j .. $] ;
  161. }
  162. }
  163. }
  164. /*
  165. void proxy() {
  166. _connected = true ;
  167. if( ob is null ) {
  168. ob = new vBuffer(1024, 1024);
  169. ib = new vBuffer(1024, 1024);
  170. oo = new vBuffer(1024, 1024);
  171. } else {
  172. ob.clear ;
  173. ib.clear ;
  174. oo.clear ;
  175. }
  176. so.open(AddressFamily.INET, SocketType.STREAM, ProtocolType.TCP) ;
  177. si.blocking( false ) ;
  178. so.blocking( false ) ;
  179. si_fd = osf_open(cast(void*) si.handle) ;
  180. so_fd = osf_open(cast(void*) so.handle) ;
  181. static int php_i = 0 ;
  182. php = &vProcess.list [ php_i ++ % vProcess.list.length ] ;
  183. io_timer.data = this ;
  184. i_read.data = this ;
  185. i_write.data = this ;
  186. o_read.data = this ;
  187. o_write.data = this ;
  188. ev_timer_init(&io_timer, &On_Timer, 6, 6) ;
  189. ev_io_init(&i_read, &On_Req_Read, si_fd, EV_READ) ;
  190. ev_io_init(&i_write, &On_Req_Write, si_fd, EV_WRITE ) ;
  191. ev_io_init(&o_read, &On_Res_Read, so_fd, EV_READ) ;
  192. ev_io_init(&o_write, &On_Res_Write, so_fd, EV_WRITE ) ;
  193. // ev_io_set(&io_res, si_fd, EV_READ) ;
  194. int ret = connect(so.handle, &php._addr, php._addr.sizeof ) ;
  195. ev_timer_start(vLib.loop, &io_timer);
  196. ev_io_start(vLib.loop, &i_read);
  197. ev_io_start(vLib.loop, &o_write);
  198. _state = State.Connecting ;
  199. }
  200. void close() {
  201. ev_timer_stop(vLib.loop, &io_timer);
  202. ev_io_stop(vLib.loop, &i_read);
  203. ev_io_stop(vLib.loop, &i_write);
  204. ev_io_stop(vLib.loop, &o_read);
  205. ev_io_stop(vLib.loop, &o_write);
  206. osf_close(si_fd);
  207. osf_close(so_fd);
  208. so.detach ;
  209. si.detach ;
  210. _state = State.Closing ;
  211. _connected = false ;
  212. }
  213. static extern(C) void On_Timer(ev_loop_t* loop, ev_timer* w, int ev) {
  214. pThis _this = cast(pThis) w.data ;
  215. if( _this._state is State.Connecting ) {
  216. // restart php
  217. }
  218. log!(__FILE__, __LINE__)("On_Timer");
  219. _this.php.reboot() ;
  220. _this.close() ;
  221. return ;
  222. }
  223. static extern(C) void On_Req_Read (ev_loop_t* loop, ev_io* w, int ev) {
  224. pThis _this = cast(pThis) w.data ;
  225. log!(__FILE__, __LINE__)("On_Req_Read start, len:{}", _this.ib.readable);
  226. bool is_first ;
  227. ubyte[512] tmp ;
  228. while( true ) {
  229. int i = _this.si.receive(tmp);
  230. if( i < 0 || i > tmp.length ) {
  231. log!(__FILE__, __LINE__)("read:{}:`{}`", i, _this.ib.readable );
  232. break ;
  233. }
  234. if( is_first ) {
  235. is_first = false ;
  236. if( i is 0 ) {
  237. log!(__FILE__, __LINE__)("close, read:`{}`", i, _this.ib.readable );
  238. _this.close() ;
  239. return ;
  240. }
  241. }
  242. if( i is 0 ) {
  243. break ;
  244. }
  245. _this.ib(tmp[0..i]) ;
  246. }
  247. log!(__FILE__, __LINE__)("On_Req_Read end, len:{}", _this.ib.readable);
  248. if( _this.ib.readable ) {
  249. ev_io_start(vLib.loop, &_this.o_write) ;
  250. }
  251. ev_timer_stop(vLib.loop, &_this.io_timer);
  252. ev_timer_start(vLib.loop, &_this.io_timer);
  253. }
  254. static extern(C) void On_Req_Write(ev_loop_t* loop, ev_io* w, int ev) {
  255. pThis _this = cast(pThis) w.data ;
  256. log!(__FILE__, __LINE__)("On_Req_Write start, len:{}", _this.ob.readable );
  257. if( _this.ob.readable is 0 ) {
  258. ev_io_stop(vLib.loop, &_this.i_write) ;
  259. return ;
  260. }
  261. bool is_write = false ;
  262. ubyte[] _tmp = cast(ubyte[]) _this.ob.slice ;
  263. while(true) {
  264. int i = _this.si.send( _tmp ) ;
  265. if( i > _tmp.length || i < 0 ) {
  266. log!(__FILE__, __LINE__)("close");
  267. _this.php.reboot() ;
  268. _this.close() ;
  269. return ;
  270. }
  271. if( i is 0 ) {
  272. break ;
  273. }
  274. is_write = true ;
  275. if( i is _tmp.length ) {
  276. _tmp = _tmp[0..0] ;
  277. break ;
  278. }
  279. _tmp = _tmp[i..$] ;
  280. }
  281. log!(__FILE__, __LINE__)("On_Req_Write end:`{}:{}`", _this.ob.readable - _tmp.length, _tmp.length );
  282. _this.ob.clear;
  283. if( _tmp.length ) {
  284. _this.oo(_tmp);
  285. _this.ob( _this.oo.slice ) ;
  286. _this.oo.clear ;
  287. } else {
  288. ev_io_stop(vLib.loop, &_this.i_write) ;
  289. }
  290. if( is_write ) {
  291. ev_io_stop(vLib.loop, &_this.o_read) ;
  292. }
  293. ev_timer_stop(vLib.loop, &_this.io_timer);
  294. ev_timer_start(vLib.loop, &_this.io_timer);
  295. }
  296. static extern(C) void On_Res_Read (ev_loop_t* loop, ev_io* w, int ev) {
  297. pThis _this = cast(pThis) w.data ;
  298. log!(__FILE__, __LINE__)("On_Res_Read start, len:{}", _this.ob.readable);
  299. bool is_first ;
  300. ubyte[512] tmp ;
  301. while( true ) {
  302. int i = _this.so.receive(tmp);
  303. if( i < 0 || i > tmp.length ) {
  304. ev_io_stop(vLib.loop, &_this.o_read) ;
  305. //ev_io_start(vLib.loop, &_this.i_read) ;
  306. log!(__FILE__, __LINE__)("read:{}:{}", i, _this.ob.readable );
  307. break ;
  308. }
  309. if( is_first ) {
  310. is_first = false ;
  311. if( i is 0 ) {
  312. log!(__FILE__, __LINE__)("close");
  313. _this.php.reboot() ;
  314. _this.close() ;
  315. return ;
  316. }
  317. }
  318. if( i is 0 ) {
  319. break ;
  320. }
  321. _this.ob(tmp[0..i]) ;
  322. }
  323. log!(__FILE__, __LINE__)("On_Res_Read end, {}", _this.ob.readable );
  324. if( _this.ob.readable ) {
  325. ev_io_stop(vLib.loop, &_this.o_read) ;
  326. ev_io_start(vLib.loop, &_this.i_write) ;
  327. }
  328. ev_timer_stop(vLib.loop, &_this.io_timer);
  329. ev_timer_start(vLib.loop, &_this.io_timer);
  330. }
  331. static extern(C) void On_Res_Write(ev_loop_t* loop, ev_io* w, int ev) {
  332. pThis _this = cast(pThis) w.data ;
  333. log!(__FILE__, __LINE__)("On_Res_Write start, len:{}", _this.ib.readable);
  334. if( _this._state is State.Connecting ) {
  335. _this._state = State.Proxying ;
  336. }
  337. if( _this.ib.readable is 0 ) {
  338. ev_io_stop(vLib.loop, &_this.o_write) ;
  339. return ;
  340. }
  341. ubyte[] _tmp = cast(ubyte[]) _this.ib.slice ;
  342. while(true) {
  343. int i = _this.so.send( _tmp ) ;
  344. if( i > _tmp.length || i < 0 ) {
  345. log!(__FILE__, __LINE__)("close");
  346. _this.php.reboot() ;
  347. _this.close() ;
  348. return ;
  349. }
  350. if( i is _tmp.length ) {
  351. _tmp = _tmp[0..0] ;
  352. break ;
  353. }
  354. if( i is 0 || i is _tmp.length ) {
  355. break ;
  356. }
  357. _tmp = _tmp[i..$] ;
  358. }
  359. log!(__FILE__, __LINE__)("On_Res_Write end:`{}:{}`", _this.ib.readable - _tmp.length, _tmp.length );
  360. _this.ib.clear;
  361. if( _tmp.length ) {
  362. _this.oo(_tmp);
  363. _this.ib( _this.oo.slice ) ;
  364. _this.oo.clear ;
  365. } else {
  366. ev_io_stop(vLib.loop, &_this.o_write) ;
  367. ev_io_start(vLib.loop, &_this.o_read) ;
  368. }
  369. ev_timer_stop(vLib.loop, &_this.io_timer);
  370. ev_timer_start(vLib.loop, &_this.io_timer);
  371. }
  372. */
  373. }