KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > servlets > FastCGIServlet


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Scott Ferguson
28  */

29
30 package com.caucho.servlets;
31
32 import com.caucho.config.types.Period;
33 import com.caucho.log.Log;
34 import com.caucho.server.webapp.Application;
35 import com.caucho.util.Alarm;
36 import com.caucho.util.CharBuffer;
37 import com.caucho.util.FreeList;
38 import com.caucho.util.L10N;
39 import com.caucho.util.QDate;
40 import com.caucho.vfs.Path;
41 import com.caucho.vfs.ReadStream;
42 import com.caucho.vfs.SocketStream;
43 import com.caucho.vfs.TempBuffer;
44 import com.caucho.vfs.WriteStream;
45
46 import javax.servlet.GenericServlet JavaDoc;
47 import javax.servlet.ServletException JavaDoc;
48 import javax.servlet.ServletRequest JavaDoc;
49 import javax.servlet.ServletResponse JavaDoc;
50 import javax.servlet.http.HttpServletRequest JavaDoc;
51 import javax.servlet.http.HttpServletResponse JavaDoc;
52 import java.io.IOException JavaDoc;
53 import java.io.InputStream JavaDoc;
54 import java.io.OutputStream JavaDoc;
55 import java.net.InetAddress JavaDoc;
56 import java.net.Socket JavaDoc;
57 import java.util.ArrayList JavaDoc;
58 import java.util.Enumeration JavaDoc;
59 import java.util.logging.Level JavaDoc;
60 import java.util.logging.Logger JavaDoc;
61
62 /**
63  * Load balancing.
64  *
65  * <pre>
66  * &lt;servlet-mapping url-pattern='/remote/*'>
67  * &lt;servlet-name>com.caucho.server.http.FastCGIServlet&lt;/servlet-name>
68  * &lt;init-param server-address='localhost:8086'/>
69  * &lt;/servlet-mapping>
70  * </pre>
71  */

72 public class FastCGIServlet extends GenericServlet JavaDoc {
73   static final protected Logger JavaDoc log = Log.open(FastCGIServlet.class);
74   static final L10N L = new L10N(FastCGIServlet.class);
75   
76   private static final int FCGI_BEGIN_REQUEST = 1;
77   private static final int FCGI_ABORT_REQUEST = 2;
78   private static final int FCGI_END_REQUEST = 3;
79   private static final int FCGI_PARAMS = 4;
80   private static final int FCGI_STDIN = 5;
81   private static final int FCGI_STDOUT = 6;
82   private static final int FCGI_STDERR = 7;
83   private static final int FCGI_DATA = 8;
84   private static final int FCGI_GET_VALUES = 9;
85   private static final int FCGI_GET_VALUES_RESULT = 10;
86   private static final int FCGI_UNKNOWNE_TYPE = 11;
87
88   private static final int FCGI_RESPONDER = 1;
89   private static final int FCGI_AUTHORIZER = 2;
90   private static final int FCGI_FILTER = 3;
91
92   private static final int FCGI_VERSION = 1;
93   
94   private static final int FCGI_KEEP_CONN = 1;
95   
96   private static final int FCGI_REQUEST_COMPLETE = 0;
97   private static final int FCGI_CANT_MPX_CONN = 1;
98   private static final int FCGI_OVERLOADED = 2;
99   private static final int FCGI_UNKNOWN_ROLE = 3;
100
101   private static final ArrayList JavaDoc<Integer JavaDoc> _fcgiServlets
102     = new ArrayList JavaDoc<Integer JavaDoc>();
103
104   private int _servletId;
105
106   private FreeList<FastCGISocket> _freeSockets =
107     new FreeList<FastCGISocket>(8);
108
109   private String JavaDoc _hostAddress;
110   private InetAddress JavaDoc _hostAddr;
111   private int _hostPort;
112   protected QDate _calendar = new QDate();
113   private Application _app;
114   private long _readTimeout = 120000;
115
116   private int _maxKeepaliveCount = 250;
117   private long _keepaliveTimeout = 15000;
118
119   private int _idCount = 0;
120
121   /**
122    * Sets the host address.
123    */

124   public void setServerAddress(String JavaDoc hostAddress)
125     throws ServletException JavaDoc
126   {
127     _hostAddress = hostAddress;
128
129     try {
130       int p = hostAddress.indexOf(':');
131       if (p > 0) {
132         _hostPort = new Integer JavaDoc(_hostAddress.substring(p + 1)).intValue();
133         _hostAddr = InetAddress.getByName(_hostAddress.substring(0, p));
134       }
135     } catch (Exception JavaDoc e) {
136       throw new ServletException JavaDoc(e);
137     }
138   }
139
140   /**
141    * Sets the keepalive max.
142    */

143   public void setMaxKeepalive(int max)
144   {
145     _maxKeepaliveCount = max;
146   }
147
148   /**
149    * Sets the keepalive timeout.
150    */

151   public void setKeepaliveTimeout(Period period)
152   {
153     _keepaliveTimeout = period.getPeriod();
154   }
155
156   /**
157    * Sets the socket timeout.
158    */

159   public void setReadTimeout(Period timeout)
160   {
161     _readTimeout = timeout.getPeriod();
162   }
163
164   /**
165    * Initialize the servlet with the server's sruns.
166    */

167   public void init()
168     throws ServletException JavaDoc
169   {
170     int id = -1;
171     
172     for (int i = 0; i < 0x10000; i += 1024) {
173       if (! _fcgiServlets.contains(new Integer JavaDoc(i))) {
174     id = i;
175     break;
176       }
177     }
178
179     if (id < 0)
180       throw new ServletException JavaDoc("Can't open FastCGI servlet");
181
182     _fcgiServlets.add(new Integer JavaDoc(id));
183
184     _servletId = id;
185
186     _app = (Application) getServletContext();
187
188     String JavaDoc serverAddress = getInitParameter("server-address");
189     if (serverAddress != null)
190       setServerAddress(serverAddress);
191     
192     if (_hostAddress == null)
193       throw new ServletException JavaDoc("FastCGIServlet needs valid server-address");
194   }
195
196   /**
197    * Handle the request.
198    */

199   public void service(ServletRequest JavaDoc request, ServletResponse JavaDoc response)
200     throws ServletException JavaDoc, IOException JavaDoc
201   {
202     HttpServletRequest JavaDoc req = (HttpServletRequest JavaDoc) request;
203     HttpServletResponse JavaDoc res = (HttpServletResponse JavaDoc) response;
204
205     OutputStream JavaDoc out = res.getOutputStream();
206
207     FastCGISocket fcgiSocket = null;
208
209     do {
210       if (fcgiSocket != null)
211     fcgiSocket.close();
212       
213       fcgiSocket = _freeSockets.allocate();
214     } while (fcgiSocket != null && ! fcgiSocket.isValid());
215
216     if (fcgiSocket != null && fcgiSocket.isValid()) {
217       log.finer(fcgiSocket + ": reuse()");
218     }
219     else {
220       if (fcgiSocket != null)
221     fcgiSocket.close();
222       
223       try {
224     Socket JavaDoc socket = new Socket JavaDoc(_hostAddr, _hostPort);
225
226     if (_readTimeout > 0)
227       socket.setSoTimeout((int) _readTimeout);
228
229     fcgiSocket = new FastCGISocket(nextId(), socket, _maxKeepaliveCount);
230       } catch (IOException JavaDoc e) {
231     log.log(Level.FINE, e.toString(), e);
232
233     throw new ServletException JavaDoc(L.l("Can't connect to FastCGI {0}:{1}. Check that the FastCGI service has started.", _hostAddr, _hostPort));
234       }
235     }
236
237     boolean isOkay = false;
238
239     try {
240       fcgiSocket.setExpire(Alarm.getCurrentTime() + _keepaliveTimeout);
241     
242       if (handleRequest(req, res, fcgiSocket, out,
243             fcgiSocket.allocateKeepalive())) {
244     if (_freeSockets.free(fcgiSocket)) {
245       log.finer(fcgiSocket + ": keepalive()");
246       
247       fcgiSocket = null;
248     }
249       }
250     } catch (Exception JavaDoc e) {
251       log.log(Level.WARNING, e.toString(), e);
252     } finally {
253       if (fcgiSocket != null)
254         fcgiSocket.close();
255     }
256   }
257
258   private int nextId()
259   {
260     synchronized (this) {
261       int id = _idCount++;
262
263       if (id <= 0 || 1024 < id) {
264     _idCount = 2;
265     id = 1;
266       }
267
268       return id + _servletId;
269     }
270   }
271
272   private boolean handleRequest(HttpServletRequest JavaDoc req,
273                 HttpServletResponse JavaDoc res,
274                 FastCGISocket fcgiSocket,
275                 OutputStream JavaDoc out,
276                 boolean keepalive)
277     throws ServletException JavaDoc, IOException JavaDoc
278   {
279     ReadStream rs = fcgiSocket.getReadStream();
280     WriteStream ws = fcgiSocket.getWriteStream();
281     
282     writeHeader(fcgiSocket, ws, FCGI_BEGIN_REQUEST, 8);
283
284     int role = FCGI_RESPONDER;
285     
286     ws.write(role >> 8);
287     ws.write(role);
288     ws.write(keepalive ? FCGI_KEEP_CONN : 0); // flags
289
for (int i = 0; i < 5; i++)
290       ws.write(0);
291
292     setEnvironment(fcgiSocket, ws, req);
293
294     InputStream JavaDoc in = req.getInputStream();
295     TempBuffer tempBuf = TempBuffer.allocate();
296     byte []buf = tempBuf.getBuffer();
297     int len = buf.length;
298     int sublen;
299
300     writeHeader(fcgiSocket, ws, FCGI_PARAMS, 0);
301     
302     boolean hasStdin = false;
303     while ((sublen = in.read(buf, 0, len)) > 0) {
304       hasStdin = true;
305       writeHeader(fcgiSocket, ws, FCGI_STDIN, sublen);
306       ws.write(buf, 0, sublen);
307     }
308
309     TempBuffer.free(tempBuf);
310
311     if (hasStdin)
312       writeHeader(fcgiSocket, ws, FCGI_STDIN, 0);
313
314     FastCGIInputStream is = new FastCGIInputStream(fcgiSocket);
315
316     int ch = parseHeaders(res, is);
317
318     if (ch >= 0)
319       out.write(ch);
320
321     while ((ch = is.read()) >= 0)
322       out.write(ch);
323
324     return ! is.isDead() && keepalive;
325   }
326
327   private void setEnvironment(FastCGISocket fcgi,
328                   WriteStream ws, HttpServletRequest JavaDoc req)
329     throws IOException JavaDoc
330   {
331     addHeader(fcgi, ws, "REQUEST_URI", req.getRequestURI());
332     addHeader(fcgi, ws, "REQUEST_METHOD", req.getMethod());
333     
334     addHeader(fcgi, ws, "SERVER_SOFTWARE", "Resin/" + com.caucho.Version.VERSION);
335     
336     addHeader(fcgi, ws, "SERVER_NAME", req.getServerName());
337     //addHeader(fcgi, ws, "SERVER_ADDR=" + req.getServerAddr());
338
addHeader(fcgi, ws, "SERVER_PORT", String.valueOf(req.getServerPort()));
339     
340     addHeader(fcgi, ws, "REMOTE_ADDR", req.getRemoteAddr());
341     addHeader(fcgi, ws, "REMOTE_HOST", req.getRemoteAddr());
342     // addHeader(fcgi, ws, "REMOTE_PORT=" + req.getRemotePort());
343

344     if (req.getRemoteUser() != null)
345       addHeader(fcgi, ws, "REMOTE_USER", req.getRemoteUser());
346     else
347       addHeader(fcgi, ws, "REMOTE_USER", "");
348     if (req.getAuthType() != null)
349       addHeader(fcgi, ws, "AUTH_TYPE", req.getAuthType());
350     
351     addHeader(fcgi, ws, "GATEWAY_INTERFACE", "CGI/1.1");
352     addHeader(fcgi, ws, "SERVER_PROTOCOL", req.getProtocol());
353     if (req.getQueryString() != null)
354       addHeader(fcgi, ws, "QUERY_STRING", req.getQueryString());
355     else
356       addHeader(fcgi, ws, "QUERY_STRING", "");
357
358     String JavaDoc scriptPath = req.getServletPath();
359     String JavaDoc pathInfo = req.getPathInfo();
360     
361     Path appDir = _app.getAppDir();
362     String JavaDoc realPath = _app.getRealPath(scriptPath);
363     
364     if (! appDir.lookup(realPath).isFile() && pathInfo != null)
365       scriptPath = scriptPath + pathInfo;
366
367     /*
368      * FastCGI (specifically quercus) uses the PATH_INFO and PATH_TRANSLATED
369      * for the script path.
370      */

371     log.finer("FCGI file: " + _app.getRealPath(scriptPath));
372
373     addHeader(fcgi, ws, "PATH_INFO", req.getContextPath() + scriptPath);
374     addHeader(fcgi, ws, "PATH_TRANSLATED", _app.getRealPath(scriptPath));
375     
376     /* These are the values which would be sent to CGI.
377     addHeader(fcgi, ws, "SCRIPT_NAME", req.getContextPath() + scriptPath);
378     addHeader(fcgi, ws, "SCRIPT_FILENAME", app.getRealPath(scriptPath));
379     
380     if (pathInfo != null) {
381       addHeader(fcgi, ws, "PATH_INFO", pathInfo);
382       addHeader(fcgi, ws, "PATH_TRANSLATED", req.getRealPath(pathInfo));
383     }
384     else {
385       addHeader(fcgi, ws, "PATH_INFO", "");
386       addHeader(fcgi, ws, "PATH_TRANSLATED", "");
387     }
388     */

389
390     int contentLength = req.getContentLength();
391     if (contentLength < 0)
392       addHeader(fcgi, ws, "CONTENT_LENGTH", "0");
393     else
394       addHeader(fcgi, ws, "CONTENT_LENGTH", String.valueOf(contentLength));
395
396     addHeader(fcgi, ws, "DOCUMENT_ROOT", _app.getContext("/").getRealPath("/"));
397
398     CharBuffer cb = new CharBuffer();
399     
400     Enumeration JavaDoc e = req.getHeaderNames();
401     while (e.hasMoreElements()) {
402       String JavaDoc key = (String JavaDoc) e.nextElement();
403       String JavaDoc value = req.getHeader(key);
404
405       if (key.equalsIgnoreCase("content-length"))
406         addHeader(fcgi, ws, "CONTENT_LENGTH", value);
407       else if (key.equalsIgnoreCase("content-type"))
408         addHeader(fcgi, ws, "CONTENT_TYPE", value);
409       else if (key.equalsIgnoreCase("if-modified-since")) {
410       }
411       else if (key.equalsIgnoreCase("if-none-match")) {
412       }
413       else if (key.equalsIgnoreCase("authorization")) {
414       }
415       else if (key.equalsIgnoreCase("proxy-authorization")) {
416       }
417       else
418         addHeader(fcgi, ws, convertHeader(cb, key), value);
419     }
420   }
421
422   private CharBuffer convertHeader(CharBuffer cb, String JavaDoc key)
423   {
424     cb.clear();
425
426     cb.append("HTTP_");
427     
428     for (int i = 0; i < key.length(); i++) {
429       char ch = key.charAt(i);
430       if (ch == '-')
431         cb.append('_');
432       else if (ch >= 'a' && ch <= 'z')
433         cb.append((char) (ch + 'A' - 'a'));
434       else
435         cb.append(ch);
436     }
437
438     return cb;
439   }
440   
441   private int parseHeaders(HttpServletResponse JavaDoc res, InputStream JavaDoc is)
442     throws IOException JavaDoc
443   {
444     CharBuffer key = new CharBuffer();
445     CharBuffer value = new CharBuffer();
446
447     int ch = is.read();
448
449     if (ch < 0) {
450       log.fine("Can't contact FastCGI");
451       res.sendError(404);
452       return -1;
453     }
454     
455     while (ch >= 0) {
456       key.clear();
457       value.clear();
458
459       for (;
460            ch >= 0 && ch != ' ' && ch != '\r' && ch != '\n' && ch != ':';
461            ch = is.read()) {
462         key.append((char) ch);
463       }
464       
465       for (;
466            ch >= 0 && ch == ' ' || ch == ':';
467            ch = is.read()) {
468       }
469
470       for (;
471            ch >= 0 && ch != '\r' && ch != '\n';
472            ch = is.read()) {
473         value.append((char) ch);
474       }
475
476       if (ch == '\r') {
477         ch = is.read();
478         if (ch == '\n')
479           ch = is.read();
480       }
481
482       if (key.length() == 0)
483         return ch;
484
485       if (log.isLoggable(Level.FINE))
486     log.fine("fastcgi:" + key + ": " + value);
487     
488       if (key.equalsIgnoreCase("status")) {
489     int status = 0;
490     int len = value.length();
491
492     for (int i = 0; i < len; i++) {
493       char digit = value.charAt(i);
494
495       if ('0' <= digit && digit <= '9')
496         status = 10 * status + digit - '0';
497       else
498         break;
499     }
500     
501     res.setStatus(status);
502       }
503       else if (key.startsWith("http") || key.startsWith("HTTP")) {
504       }
505       else if (key.equalsIgnoreCase("location")) {
506     res.sendRedirect(value.toString());
507       }
508       else
509     res.addHeader(key.toString(), value.toString());
510     }
511
512     return ch;
513   }
514
515   private void addHeader(FastCGISocket fcgiSocket, WriteStream ws,
516              String JavaDoc key, String JavaDoc value)
517     throws IOException JavaDoc
518   {
519     int keyLen = key.length();
520     int valLen = value.length();
521
522     int len = keyLen + valLen;
523
524     if (keyLen < 0x80)
525       len += 1;
526     else
527       len += 4;
528
529     if (valLen < 0x80)
530       len += 1;
531     else
532       len += 4;
533
534     writeHeader(fcgiSocket, ws, FCGI_PARAMS, len);
535     
536     if (keyLen < 0x80)
537       ws.write(keyLen);
538     else {
539       ws.write(0x80 | (keyLen >> 24));
540       ws.write(keyLen >> 16);
541       ws.write(keyLen >> 8);
542       ws.write(keyLen);
543     }
544     
545     if (valLen < 0x80)
546       ws.write(valLen);
547     else {
548       ws.write(0x80 | (valLen >> 24));
549       ws.write(valLen >> 16);
550       ws.write(valLen >> 8);
551       ws.write(valLen);
552     }
553
554     ws.print(key);
555     ws.print(value);
556   }
557
558   private void addHeader(FastCGISocket fcgiSocket, WriteStream ws,
559              CharBuffer key, String JavaDoc value)
560     throws IOException JavaDoc
561   {
562     int keyLen = key.getLength();
563     int valLen = value.length();
564
565     int len = keyLen + valLen;
566
567     if (keyLen < 0x80)
568       len += 1;
569     else
570       len += 4;
571
572     if (valLen < 0x80)
573       len += 1;
574     else
575       len += 4;
576
577     writeHeader(fcgiSocket, ws, FCGI_PARAMS, len);
578     
579     if (keyLen < 0x80)
580       ws.write(keyLen);
581     else {
582       ws.write(0x80 | (keyLen >> 24));
583       ws.write(keyLen >> 16);
584       ws.write(keyLen >> 8);
585       ws.write(keyLen);
586     }
587     
588     if (valLen < 0x80)
589       ws.write(valLen);
590     else {
591       ws.write(0x80 | (valLen >> 24));
592       ws.write(valLen >> 16);
593       ws.write(valLen >> 8);
594       ws.write(valLen);
595     }
596
597     ws.print(key.getBuffer(), 0, keyLen);
598     ws.print(value);
599   }
600
601   private void writeHeader(FastCGISocket fcgiSocket,
602                WriteStream ws, int type, int length)
603     throws IOException JavaDoc
604   {
605     int id = 1;
606     int pad = 0;
607
608     ws.write(FCGI_VERSION);
609     ws.write(type);
610     ws.write(id >> 8);
611     ws.write(id);
612     ws.write(length >> 8);
613     ws.write(length);
614     ws.write(pad);
615     ws.write(0);
616   }
617
618   public void destroy()
619   {
620     FastCGISocket socket;
621     
622     while ((socket = _freeSockets.allocate()) != null) {
623       try {
624     socket.close();
625       } catch (Throwable JavaDoc e) {
626       }
627     }
628        
629     _fcgiServlets.remove(new Integer JavaDoc(_servletId));
630   }
631
632   static class FastCGIInputStream extends InputStream JavaDoc {
633     private FastCGISocket _fcgiSocket;
634     
635     private InputStream JavaDoc _is;
636     private int _chunkLength;
637     private int _padLength;
638     private boolean _isDead;
639
640     public FastCGIInputStream()
641     {
642     }
643
644     public FastCGIInputStream(FastCGISocket fcgiSocket)
645     {
646       init(fcgiSocket);
647     }
648
649     public void init(FastCGISocket fcgiSocket)
650     {
651       _fcgiSocket = fcgiSocket;
652       
653       _is = fcgiSocket.getReadStream();
654       _chunkLength = 0;
655       _isDead = false;
656     }
657
658     public boolean isDead()
659     {
660       return _isDead;
661     }
662
663     public int read()
664       throws IOException JavaDoc
665     {
666       do {
667     if (_chunkLength > 0) {
668       _chunkLength--;
669       return _is.read();
670     }
671       } while (readNext());
672
673       return -1;
674     }
675
676     private boolean readNext()
677       throws IOException JavaDoc
678     {
679       if (_is == null)
680         return false;
681
682       if (_padLength > 0) {
683         _is.skip(_padLength);
684         _padLength = 0;
685       }
686       
687       int version;
688
689       while ((version = _is.read()) >= 0) {
690         int type = _is.read();
691         int id = (_is.read() << 8) + _is.read();
692         int length = (_is.read() << 8) + _is.read();
693         int padding = _is.read();
694         _is.read();
695     
696         switch (type) {
697         case FCGI_END_REQUEST:
698         {
699           int appStatus = ((_is.read() << 24) +
700                            (_is.read() << 16) +
701                            (_is.read() << 8) +
702                            (_is.read()));
703           int pStatus = _is.read();
704
705       if (log.isLoggable(Level.FINER)) {
706         log.finer(_fcgiSocket + ": FCGI_END_REQUEST(appStatus:" + appStatus + ", pStatus:" + pStatus + ")");
707       }
708       
709           if (appStatus != 0)
710             _isDead = true;
711
712       if (pStatus != FCGI_REQUEST_COMPLETE)
713         _isDead = true;
714           
715           _is.skip(3);
716           _is = null;
717           return false;
718         }
719
720         case FCGI_STDOUT:
721       if (log.isLoggable(Level.FINER)) {
722         log.finer(_fcgiSocket + ": FCGI_STDOUT(length:" + length + ", padding:" + padding + ")");
723       }
724       
725           if (length == 0) {
726         if (padding > 0)
727           _is.skip(padding);
728         
729             break;
730       }
731           else {
732             _chunkLength = length;
733             _padLength = padding;
734             return true;
735           }
736
737         case FCGI_STDERR:
738       if (log.isLoggable(Level.FINER)) {
739         log.finer(_fcgiSocket + ": FCGI_STDERR(length:" + length + ", padding:" + padding + ")");
740       }
741       
742           byte []buf = new byte[length];
743           _is.read(buf, 0, length);
744           log.warning(new String JavaDoc(buf, 0, length));
745
746       if (padding > 0)
747         _is.skip(padding);
748           break;
749
750         default:
751       log.warning(_fcgiSocket + ": Unknown Protocol(" + type + ")");
752
753       _isDead = true;
754           _is.skip(length + padding);
755           break;
756         }
757       }
758
759       _isDead = true;
760         
761       return false;
762     }
763   }
764
765   static class FastCGISocket {
766     private int _id;
767     private int _keepaliveCount;
768     private long _expireTime;
769     private Socket JavaDoc _socket;
770     private SocketStream _socketStream;
771     private ReadStream _rs;
772     private WriteStream _ws;
773
774     FastCGISocket(int id, Socket JavaDoc socket, int maxKeepaliveCount)
775     {
776       _id = id;
777       _socket = socket;
778       _keepaliveCount = maxKeepaliveCount;
779
780       _socketStream = new SocketStream(_socket);
781
782       _ws = new WriteStream(_socketStream);
783       _ws.setDisableClose(true);
784       
785       _rs = new ReadStream(_socketStream, _ws);
786       _rs.setDisableClose(true);
787       
788       log.fine(this + ": open()");
789     }
790
791     int getId()
792     {
793       return _id;
794     }
795
796     void setExpire(long expireTime)
797     {
798       _expireTime = expireTime;
799     }
800
801     ReadStream getReadStream()
802     {
803       return _rs;
804     }
805
806     WriteStream getWriteStream()
807     {
808       return _ws;
809     }
810
811     boolean isValid()
812     {
813       return _socket != null && Alarm.getCurrentTime() < _expireTime;
814     }
815
816     boolean allocateKeepalive()
817     {
818       if (! isValid())
819     return false;
820       else
821     return --_keepaliveCount > 0;
822     }
823
824     boolean isKeepalive()
825     {
826       return _keepaliveCount > 0;
827     }
828
829     void close()
830     {
831       try {
832     log.fine(this + ": close()");
833     
834     Socket JavaDoc socket = _socket;
835     _socket = null;
836
837     _socketStream = null;
838
839     if (socket != null)
840       socket.close();
841       
842     _ws.close();
843     _rs.close();
844       } catch (Throwable JavaDoc e) {
845     log.log(Level.FINER, e.toString(), e);
846       }
847     }
848
849     public String JavaDoc toString()
850     {
851       return "FastCGISocket[" + _id + "," + _socket + "]";
852     }
853   }
854 }
855
Popular Tags