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