1 //========================================================================
2 //$Id: AbstractConnector.java,v 1.9 2005/11/14 11:00:31 gregwilkins Exp $
3 //Copyright 2004-2005 Mort Bay Consulting Pty. Ltd.
4 //------------------------------------------------------------------------
5 //Licensed under the Apache License, Version 2.0 (the "License");
6 //you may not use this file except in compliance with the License.
7 //You may obtain a copy of the License at
8 //http://www.apache.org/licenses/LICENSE-2.0
9 //Unless required by applicable law or agreed to in writing, software
10 //distributed under the License is distributed on an "AS IS" BASIS,
11 //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 //See the License for the specific language governing permissions and
13 //limitations under the License.
14 //========================================================================
15
16 package org.mortbay.jetty;
17
18 import java.io.IOException;
19 import java.net.InetAddress;
20 import java.net.Socket;
21 import java.net.UnknownHostException;
22
23 import javax.servlet.ServletRequest;
24
25 import org.mortbay.component.LifeCycle;
26 import org.mortbay.io.EndPoint;
27 import org.mortbay.log.Log;
28 import org.mortbay.thread.ThreadPool;
29 import org.mortbay.util.ajax.Continuation;
30 import org.mortbay.util.ajax.WaitingContinuation;
31
32
33 /** Abstract Connector implementation.
34 * This abstract implementation of the Connector interface provides:<ul>
35 * <li>AbstractLifeCycle implementation</li>
36 * <li>Implementations for connector getters and setters</li>
37 * <li>Buffer management</li>
38 * <li>Socket configuration</li>
39 * <li>Base acceptor thread</li>
40 * <li>Optional reverse proxy headers checking</li>
41 * </ul>
42 *
43 * @author gregw
44 *
45 * TODO - allow multiple Acceptor threads
46 */
47 public abstract class AbstractConnector extends AbstractBuffers implements Connector
48 {
49 private String _name;
50
51 private Server _server;
52 private ThreadPool _threadPool;
53 private String _host;
54 private int _port=0;
55 private String _integralScheme=HttpSchemes.HTTPS;
56 private int _integralPort=0;
57 private String _confidentialScheme=HttpSchemes.HTTPS;
58 private int _confidentialPort=0;
59 private int _acceptQueueSize=0;
60 private int _acceptors=1;
61 private int _acceptorPriorityOffset=0;
62 private boolean _useDNS;
63 private boolean _forwarded;
64 private String _hostHeader;
65 private String _forwardedHostHeader = "X-Forwarded-Host"; // default to mod_proxy_http header
66 private String _forwardedServerHeader = "X-Forwarded-Server"; // default to mod_proxy_http header
67 private String _forwardedForHeader = "X-Forwarded-For"; // default to mod_proxy_http header
68 private boolean _reuseAddress=true;
69
70 protected int _maxIdleTime=200000;
71 protected int _lowResourceMaxIdleTime=-1;
72 protected int _soLingerTime=-1;
73
74 private transient Thread[] _acceptorThread;
75
76 Object _statsLock = new Object();
77 transient long _statsStartedAt=-1;
78 transient int _requests;
79 transient int _connections; // total number of connections made to server
80
81 transient int _connectionsOpen; // number of connections currently open
82 transient int _connectionsOpenMin; // min number of connections open simultaneously
83 transient int _connectionsOpenMax; // max number of connections open simultaneously
84
85 transient long _connectionsDurationMin; // min duration of a connection
86 transient long _connectionsDurationMax; // max duration of a connection
87 transient long _connectionsDurationTotal; // total duration of all coneection
88
89 transient int _connectionsRequestsMin; // min requests per connection
90 transient int _connectionsRequestsMax; // max requests per connection
91
92
93 /* ------------------------------------------------------------------------------- */
94 /**
95 */
96 public AbstractConnector()
97 {
98 }
99
100 /* ------------------------------------------------------------------------------- */
101 /*
102 */
103 public Server getServer()
104 {
105 return _server;
106 }
107
108 /* ------------------------------------------------------------------------------- */
109 public void setServer(Server server)
110 {
111 _server=server;
112 }
113
114 /* ------------------------------------------------------------------------------- */
115 /*
116 * @see org.mortbay.jetty.HttpListener#getHttpServer()
117 */
118 public ThreadPool getThreadPool()
119 {
120 return _threadPool;
121 }
122
123 /* ------------------------------------------------------------------------------- */
124 public void setThreadPool(ThreadPool pool)
125 {
126 _threadPool=pool;
127 }
128
129 /* ------------------------------------------------------------------------------- */
130 /**
131 */
132 public void setHost(String host)
133 {
134 _host=host;
135 }
136
137 /* ------------------------------------------------------------------------------- */
138 /*
139 */
140 public String getHost()
141 {
142 return _host;
143 }
144
145 /* ------------------------------------------------------------------------------- */
146 /*
147 * @see org.mortbay.jetty.HttpListener#setPort(int)
148 */
149 public void setPort(int port)
150 {
151 _port=port;
152 }
153
154 /* ------------------------------------------------------------------------------- */
155 /*
156 * @see org.mortbay.jetty.HttpListener#getPort()
157 */
158 public int getPort()
159 {
160 return _port;
161 }
162
163
164 /* ------------------------------------------------------------ */
165 /**
166 * @return Returns the maxIdleTime.
167 */
168 public int getMaxIdleTime()
169 {
170 return _maxIdleTime;
171 }
172
173 /* ------------------------------------------------------------ */
174 /**
175 * Set the maximum Idle time for a connection, which roughly translates
176 * to the {@link Socket#setSoTimeout(int)} call, although with NIO
177 * implementations other mechanisms may be used to implement the timeout.
178 * The max idle time is applied:<ul>
179 * <li>When waiting for a new request to be received on a connection</li>
180 * <li>When reading the headers and content of a request</li>
181 * <li>When writing the headers and content of a response</li>
182 * </ul>
183 * Jetty interprets this value as the maximum time between some progress being
184 * made on the connection. So if a single byte is read or written, then the
185 * timeout (if implemented by jetty) is reset. However, in many instances,
186 * the reading/writing is delegated to the JVM, and the semantic is more
187 * strictly enforced as the maximum time a single read/write operation can
188 * take. Note, that as Jetty supports writes of memory mapped file buffers,
189 * then a write may take many 10s of seconds for large content written to a
190 * slow device.
191 * <p>
192 * Previously, Jetty supported separate idle timeouts and IO operation timeouts,
193 * however the expense of changing the value of soTimeout was significant, so
194 * these timeouts were merged. With the advent of NIO, it may be possible to
195 * again differentiate these values (if there is demand).
196 *
197 * @param maxIdleTime The maxIdleTime to set.
198 */
199 public void setMaxIdleTime(int maxIdleTime)
200 {
201 _maxIdleTime = maxIdleTime;
202 }
203
204 /* ------------------------------------------------------------ */
205 /**
206 * @return Returns the maxIdleTime.
207 */
208 public int getLowResourceMaxIdleTime()
209 {
210 return _lowResourceMaxIdleTime;
211 }
212
213 /* ------------------------------------------------------------ */
214 /**
215 * @param maxIdleTime The maxIdleTime to set.
216 */
217 public void setLowResourceMaxIdleTime(int maxIdleTime)
218 {
219 _lowResourceMaxIdleTime = maxIdleTime;
220 }
221
222 /* ------------------------------------------------------------ */
223 /**
224 * @return Returns the soLingerTime.
225 */
226 public int getSoLingerTime()
227 {
228 return _soLingerTime;
229 }
230
231 /* ------------------------------------------------------------ */
232 /**
233 * @return Returns the acceptQueueSize.
234 */
235 public int getAcceptQueueSize()
236 {
237 return _acceptQueueSize;
238 }
239
240 /* ------------------------------------------------------------ */
241 /**
242 * @param acceptQueueSize The acceptQueueSize to set.
243 */
244 public void setAcceptQueueSize(int acceptQueueSize)
245 {
246 _acceptQueueSize = acceptQueueSize;
247 }
248
249 /* ------------------------------------------------------------ */
250 /**
251 * @return Returns the number of acceptor threads.
252 */
253 public int getAcceptors()
254 {
255 return _acceptors;
256 }
257
258 /* ------------------------------------------------------------ */
259 /**
260 * @param acceptors The number of acceptor threads to set.
261 */
262 public void setAcceptors(int acceptors)
263 {
264 _acceptors = acceptors;
265 }
266
267 /* ------------------------------------------------------------ */
268 /**
269 * @param soLingerTime The soLingerTime to set or -1 to disable.
270 */
271 public void setSoLingerTime(int soLingerTime)
272 {
273 _soLingerTime = soLingerTime;
274 }
275
276 /* ------------------------------------------------------------ */
277 protected void doStart() throws Exception
278 {
279 if (_server==null)
280 throw new IllegalStateException("No server");
281
282 // open listener port
283 open();
284
285 super.doStart();
286
287 if (_threadPool==null)
288 _threadPool=_server.getThreadPool();
289 if (_threadPool!=_server.getThreadPool() && (_threadPool instanceof LifeCycle))
290 ((LifeCycle)_threadPool).start();
291
292 // Start selector thread
293 synchronized(this)
294 {
295 _acceptorThread=new Thread[getAcceptors()];
296
297 for (int i=0;i<_acceptorThread.length;i++)
298 {
299 if (!_threadPool.dispatch(new Acceptor(i)))
300 {
301 Log.warn("insufficient maxThreads configured for {}",this);
302 break;
303 }
304 }
305 }
306
307 Log.info("Started {}",this);
308 }
309
310 /* ------------------------------------------------------------ */
311 protected void doStop() throws Exception
312 {
313 Log.info("Stopped {}",this);
314 try{close();} catch(IOException e) {Log.warn(e);}
315
316 if (_threadPool==_server.getThreadPool())
317 _threadPool=null;
318 else if (_threadPool instanceof LifeCycle)
319 ((LifeCycle)_threadPool).stop();
320
321 super.doStop();
322
323 Thread[] acceptors=null;
324 synchronized(this)
325 {
326 acceptors=_acceptorThread;
327 _acceptorThread=null;
328 }
329 if (acceptors != null)
330 {
331 for (int i=0;i<acceptors.length;i++)
332 {
333 Thread thread=acceptors[i];
334 if (thread!=null)
335 thread.interrupt();
336 }
337 }
338
339 }
340
341 /* ------------------------------------------------------------ */
342 public void join() throws InterruptedException
343 {
344 Thread[] threads=_acceptorThread;
345 if (threads!=null)
346 for (int i=0;i<threads.length;i++)
347 if (threads[i]!=null)
348 threads[i].join();
349 }
350
351 /* ------------------------------------------------------------ */
352 protected void configure(Socket socket)
353 throws IOException
354 {
355 try
356 {
357 socket.setTcpNoDelay(true);
358 if (_maxIdleTime >= 0)
359 socket.setSoTimeout(_maxIdleTime);
360 if (_soLingerTime >= 0)
361 socket.setSoLinger(true, _soLingerTime/1000);
362 else
363 socket.setSoLinger(false, 0);
364 }
365 catch (Exception e)
366 {
367 Log.ignore(e);
368 }
369 }
370
371
372 /* ------------------------------------------------------------ */
373 public void customize(EndPoint endpoint, Request request)
374 throws IOException
375 {
376 if (isForwarded())
377 checkForwardedHeaders(endpoint, request);
378 }
379
380 /* ------------------------------------------------------------ */
381 protected void checkForwardedHeaders(EndPoint endpoint, Request request)
382 throws IOException
383 {
384 HttpFields httpFields = request.getConnection().getRequestFields();
385
386 // Retrieving headers from the request
387 String forwardedHost = getLeftMostValue(httpFields.getStringField(getForwardedHostHeader()));
388 String forwardedServer = getLeftMostValue(httpFields.getStringField(getForwardedServerHeader()));
389 String forwardedFor = getLeftMostValue(httpFields.getStringField(getForwardedForHeader()));
390
391 if (_hostHeader!=null)
392 {
393 // Update host header
394 httpFields.put(HttpHeaders.HOST_BUFFER, _hostHeader);
395 request.setServerName(null);
396 request.setServerPort(-1);
397 request.getServerName();
398 }
399 else if (forwardedHost != null)
400 {
401 // Update host header
402 httpFields.put(HttpHeaders.HOST_BUFFER, forwardedHost);
403 request.setServerName(null);
404 request.setServerPort(-1);
405 request.getServerName();
406 }
407 else if (forwardedServer != null)
408 {
409 // Use provided server name
410 request.setServerName(forwardedServer);
411 }
412
413 if (forwardedFor != null)
414 {
415 request.setRemoteAddr(forwardedFor);
416 InetAddress inetAddress = null;
417
418 if (_useDNS)
419 {
420 try
421 {
422 inetAddress = InetAddress.getByName(forwardedFor);
423 }
424 catch (UnknownHostException e)
425 {
426 Log.ignore(e);
427 }
428 }
429
430 request.setRemoteHost(inetAddress==null?forwardedFor:inetAddress.getHostName());
431 }
432 }
433
434 /* ------------------------------------------------------------ */
435 protected String getLeftMostValue(String headerValue) {
436 if (headerValue == null)
437 return null;
438
439 int commaIndex = headerValue.indexOf(',');
440
441 if (commaIndex == -1)
442 {
443 // Single value
444 return headerValue;
445 }
446
447 // The left-most value is the farthest downstream client
448 return headerValue.substring(0, commaIndex);
449 }
450
451 /* ------------------------------------------------------------ */
452 public void persist(EndPoint endpoint)
453 throws IOException
454 {
455 }
456
457
458 /* ------------------------------------------------------------ */
459 /* ------------------------------------------------------------ */
460 /*
461 * @see org.mortbay.jetty.Connector#getConfidentialPort()
462 */
463 public int getConfidentialPort()
464 {
465 return _confidentialPort;
466 }
467
468 /* ------------------------------------------------------------ */
469 /* ------------------------------------------------------------ */
470 /*
471 * @see org.mortbay.jetty.Connector#getConfidentialScheme()
472 */
473 public String getConfidentialScheme()
474 {
475 return _confidentialScheme;
476 }
477
478 /* ------------------------------------------------------------ */
479 /*
480 * @see org.mortbay.jetty.Connector#isConfidential(org.mortbay.jetty.Request)
481 */
482 public boolean isIntegral(Request request)
483 {
484 return false;
485 }
486
487 /* ------------------------------------------------------------ */
488 /*
489 * @see org.mortbay.jetty.Connector#getConfidentialPort()
490 */
491 public int getIntegralPort()
492 {
493 return _integralPort;
494 }
495
496 /* ------------------------------------------------------------ */
497 /*
498 * @see org.mortbay.jetty.Connector#getIntegralScheme()
499 */
500 public String getIntegralScheme()
501 {
502 return _integralScheme;
503 }
504
505 /* ------------------------------------------------------------ */
506 /*
507 * @see org.mortbay.jetty.Connector#isConfidential(org.mortbay.jetty.Request)
508 */
509 public boolean isConfidential(Request request)
510 {
511 return false;
512 }
513
514 /* ------------------------------------------------------------ */
515 /**
516 * @param confidentialPort The confidentialPort to set.
517 */
518 public void setConfidentialPort(int confidentialPort)
519 {
520 _confidentialPort = confidentialPort;
521 }
522
523 /* ------------------------------------------------------------ */
524 /**
525 * @param confidentialScheme The confidentialScheme to set.
526 */
527 public void setConfidentialScheme(String confidentialScheme)
528 {
529 _confidentialScheme = confidentialScheme;
530 }
531
532 /* ------------------------------------------------------------ */
533 /**
534 * @param integralPort The integralPort to set.
535 */
536 public void setIntegralPort(int integralPort)
537 {
538 _integralPort = integralPort;
539 }
540
541 /* ------------------------------------------------------------ */
542 /**
543 * @param integralScheme The integralScheme to set.
544 */
545 public void setIntegralScheme(String integralScheme)
546 {
547 _integralScheme = integralScheme;
548 }
549
550 /* ------------------------------------------------------------ */
551 public Continuation newContinuation()
552 {
553 return new WaitingContinuation();
554 }
555
556 /* ------------------------------------------------------------ */
557 protected abstract void accept(int acceptorID) throws IOException, InterruptedException;
558
559 /* ------------------------------------------------------------ */
560 public void stopAccept(int acceptorID) throws Exception
561 {
562 }
563
564 /* ------------------------------------------------------------ */
565 public boolean getResolveNames()
566 {
567 return _useDNS;
568 }
569
570 /* ------------------------------------------------------------ */
571 public void setResolveNames(boolean resolve)
572 {
573 _useDNS=resolve;
574 }
575
576 /* ------------------------------------------------------------ */
577 /**
578 * Is reverse proxy handling on?
579 * @return true if this connector is checking the x-forwarded-for/host/server headers
580 */
581 public boolean isForwarded()
582 {
583 return _forwarded;
584 }
585
586 /* ------------------------------------------------------------ */
587 /**
588 * Set reverse proxy handling
589 * @param check true if this connector is checking the x-forwarded-for/host/server headers
590 */
591 public void setForwarded(boolean check)
592 {
593 if (check)
594 Log.debug(this+" is forwarded");
595 _forwarded=check;
596 }
597
598 /* ------------------------------------------------------------ */
599 public String getHostHeader()
600 {
601 return _hostHeader;
602 }
603
604 /* ------------------------------------------------------------ */
605 /**
606 * Set a forced valued for the host header to control what is returned
607 * by {@link ServletRequest#getServerName()} and {@link ServletRequest#getServerPort()}.
608 * This value is only used if {@link #isForwarded()} is true.
609 * @param hostHeader The value of the host header to force.
610 */
611 public void setHostHeader(String hostHeader)
612 {
613 _hostHeader=hostHeader;
614 }
615
616 /* ------------------------------------------------------------ */
617 public String getForwardedHostHeader()
618 {
619 return _forwardedHostHeader;
620 }
621
622 /* ------------------------------------------------------------ */
623 /**
624 * @param forwardedHostHeader The header name for forwarded hosts (default x-forwarded-host)
625 */
626 public void setForwardedHostHeader(String forwardedHostHeader)
627 {
628 _forwardedHostHeader=forwardedHostHeader;
629 }
630
631 /* ------------------------------------------------------------ */
632 public String getForwardedServerHeader()
633 {
634 return _forwardedServerHeader;
635 }
636
637 /* ------------------------------------------------------------ */
638 /**
639 * @param forwardedServerHeader The header name for forwarded server (default x-forwarded-server)
640 */
641 public void setForwardedServerHeader(String forwardedServerHeader)
642 {
643 _forwardedServerHeader=forwardedServerHeader;
644 }
645
646 /* ------------------------------------------------------------ */
647 public String getForwardedForHeader()
648 {
649 return _forwardedForHeader;
650 }
651
652 /* ------------------------------------------------------------ */
653 /**
654 * @param forwardedRemoteAddressHeader The header name for forwarded for (default x-forwarded-for)
655 */
656 public void setForwardedForHeader(String forwardedRemoteAddressHeader)
657 {
658 _forwardedForHeader=forwardedRemoteAddressHeader;
659 }
660
661 /* ------------------------------------------------------------ */
662 public String toString()
663 {
664 String name = this.getClass().getName();
665 int dot = name.lastIndexOf('.');
666 if (dot>0)
667 name=name.substring(dot+1);
668
669 return name+"@"+(getHost()==null?"0.0.0.0":getHost())+":"+(getLocalPort()<=0?getPort():getLocalPort());
670 }
671
672
673 /* ------------------------------------------------------------ */
674 /* ------------------------------------------------------------ */
675 /* ------------------------------------------------------------ */
676 private class Acceptor implements Runnable
677 {
678 int _acceptor=0;
679
680 Acceptor(int id)
681 {
682 _acceptor=id;
683 }
684
685 /* ------------------------------------------------------------ */
686 public void run()
687 {
688 Thread current = Thread.currentThread();
689 String name;
690 synchronized(AbstractConnector.this)
691 {
692 if (_acceptorThread==null)
693 return;
694
695 _acceptorThread[_acceptor]=current;
696 name =_acceptorThread[_acceptor].getName();
697 current.setName(name+" - Acceptor"+_acceptor+" "+AbstractConnector.this);
698 }
699 int old_priority=current.getPriority();
700
701 try
702 {
703 current.setPriority(old_priority-_acceptorPriorityOffset);
704 while (isRunning() && getConnection()!=null)
705 {
706 try
707 {
708 accept(_acceptor);
709 }
710 catch(EofException e)
711 {
712 Log.ignore(e);
713 }
714 catch(IOException e)
715 {
716 Log.ignore(e);
717 }
718 catch(ThreadDeath e)
719 {
720 throw e;
721 }
722 catch(Throwable e)
723 {
724 Log.warn(e);
725 }
726 }
727 }
728 finally
729 {
730 current.setPriority(old_priority);
731 current.setName(name);
732
733 synchronized(AbstractConnector.this)
734 {
735 if (_acceptorThread!=null)
736 _acceptorThread[_acceptor]=null;
737 }
738 }
739 }
740 }
741
742 /* ------------------------------------------------------------ */
743 public String getName()
744 {
745 if (_name==null)
746 _name= (getHost()==null?"0.0.0.0":getHost())+":"+(getLocalPort()<=0?getPort():getLocalPort());
747 return _name;
748 }
749
750 /* ------------------------------------------------------------ */
751 public void setName(String name)
752 {
753 _name = name;
754 }
755
756
757
758 /* ------------------------------------------------------------ */
759 /**
760 * @return Get the number of requests handled by this context
761 * since last call of statsReset(). If setStatsOn(false) then this
762 * is undefined.
763 */
764 public int getRequests() {return _requests;}
765
766 /* ------------------------------------------------------------ */
767 /**
768 * @return Returns the connectionsDurationMin.
769 */
770 public long getConnectionsDurationMin()
771 {
772 return _connectionsDurationMin;
773 }
774
775 /* ------------------------------------------------------------ */
776 /**
777 * @return Returns the connectionsDurationTotal.
778 */
779 public long getConnectionsDurationTotal()
780 {
781 return _connectionsDurationTotal;
782 }
783
784 /* ------------------------------------------------------------ */
785 /**
786 * @return Returns the connectionsOpenMin.
787 */
788 public int getConnectionsOpenMin()
789 {
790 return _connectionsOpenMin;
791 }
792
793 /* ------------------------------------------------------------ */
794 /**
795 * @return Returns the connectionsRequestsMin.
796 */
797 public int getConnectionsRequestsMin()
798 {
799 return _connectionsRequestsMin;
800 }
801
802
803 /* ------------------------------------------------------------ */
804 /**
805 * @return Number of connections accepted by the server since
806 * statsReset() called. Undefined if setStatsOn(false).
807 */
808 public int getConnections() {return _connections;}
809
810 /* ------------------------------------------------------------ */
811 /**
812 * @return Number of connections currently open that were opened
813 * since statsReset() called. Undefined if setStatsOn(false).
814 */
815 public int getConnectionsOpen() {return _connectionsOpen;}
816
817 /* ------------------------------------------------------------ */
818 /**
819 * @return Maximum number of connections opened simultaneously
820 * since statsReset() called. Undefined if setStatsOn(false).
821 */
822 public int getConnectionsOpenMax() {return _connectionsOpenMax;}
823
824 /* ------------------------------------------------------------ */
825 /**
826 * @return Average duration in milliseconds of open connections
827 * since statsReset() called. Undefined if setStatsOn(false).
828 */
829 public long getConnectionsDurationAve() {return _connections==0?0:(_connectionsDurationTotal/_connections);}
830
831 /* ------------------------------------------------------------ */
832 /**
833 * @return Maximum duration in milliseconds of an open connection
834 * since statsReset() called. Undefined if setStatsOn(false).
835 */
836 public long getConnectionsDurationMax() {return _connectionsDurationMax;}
837
838 /* ------------------------------------------------------------ */
839 /**
840 * @return Average number of requests per connection
841 * since statsReset() called. Undefined if setStatsOn(false).
842 */
843 public int getConnectionsRequestsAve() {return _connections==0?0:(_requests/_connections);}
844
845 /* ------------------------------------------------------------ */
846 /**
847 * @return Maximum number of requests per connection
848 * since statsReset() called. Undefined if setStatsOn(false).
849 */
850 public int getConnectionsRequestsMax() {return _connectionsRequestsMax;}
851
852
853
854 /* ------------------------------------------------------------ */
855 /** Reset statistics.
856 */
857 public void statsReset()
858 {
859 _statsStartedAt=_statsStartedAt==-1?-1:System.currentTimeMillis();
860
861 _connections=0;
862
863 _connectionsOpenMin=_connectionsOpen;
864 _connectionsOpenMax=_connectionsOpen;
865 _connectionsOpen=0;
866
867 _connectionsDurationMin=0;
868 _connectionsDurationMax=0;
869 _connectionsDurationTotal=0;
870
871 _requests=0;
872
873 _connectionsRequestsMin=0;
874 _connectionsRequestsMax=0;
875 }
876
877 /* ------------------------------------------------------------ */
878 public void setStatsOn(boolean on)
879 {
880 if (on && _statsStartedAt!=-1)
881 return;
882 Log.debug("Statistics on = "+on+" for "+this);
883 statsReset();
884 _statsStartedAt=on?System.currentTimeMillis():-1;
885 }
886
887 /* ------------------------------------------------------------ */
888 /**
889 * @return True if statistics collection is turned on.
890 */
891 public boolean getStatsOn()
892 {
893 return _statsStartedAt!=-1;
894 }
895
896 /* ------------------------------------------------------------ */
897 /**
898 * @return Timestamp stats were started at.
899 */
900 public long getStatsOnMs()
901 {
902 return (_statsStartedAt!=-1)?(System.currentTimeMillis()-_statsStartedAt):0;
903 }
904
905 /* ------------------------------------------------------------ */
906 protected void connectionOpened(HttpConnection connection)
907 {
908 if (_statsStartedAt==-1)
909 return;
910 synchronized(_statsLock)
911 {
912 _connectionsOpen++;
913 if (_connectionsOpen > _connectionsOpenMax)
914 _connectionsOpenMax=_connectionsOpen;
915 }
916 }
917
918 /* ------------------------------------------------------------ */
919 protected void connectionClosed(HttpConnection connection)
920 {
921 if (_statsStartedAt>=0)
922 {
923 long duration=System.currentTimeMillis()-connection.getTimeStamp();
924 int requests=connection.getRequests();
925 synchronized(_statsLock)
926 {
927 _requests+=requests;
928 _connections++;
929 _connectionsOpen--;
930 _connectionsDurationTotal+=duration;
931 if (_connectionsOpen<0)
932 _connectionsOpen=0;
933 if (_connectionsOpen<_connectionsOpenMin)
934 _connectionsOpenMin=_connectionsOpen;
935 if (_connectionsDurationMin==0 || duration<_connectionsDurationMin)
936 _connectionsDurationMin=duration;
937 if (duration>_connectionsDurationMax)
938 _connectionsDurationMax=duration;
939 if (_connectionsRequestsMin==0 || requests<_connectionsRequestsMin)
940 _connectionsRequestsMin=requests;
941 if (requests>_connectionsRequestsMax)
942 _connectionsRequestsMax=requests;
943 }
944 }
945
946 connection.destroy();
947 }
948
949 /* ------------------------------------------------------------ */
950 /**
951 * @return the acceptorPriority
952 */
953 public int getAcceptorPriorityOffset()
954 {
955 return _acceptorPriorityOffset;
956 }
957
958 /* ------------------------------------------------------------ */
959 /**
960 * Set the priority offset of the acceptor threads. The priority is adjusted by
961 * this amount (default 0) to either favour the acceptance of new threads and newly active
962 * connections or to favour the handling of already dispatched connections.
963 * @param offset the amount to alter the priority of the acceptor threads.
964 */
965 public void setAcceptorPriorityOffset(int offset)
966 {
967 _acceptorPriorityOffset=offset;
968 }
969
970 /* ------------------------------------------------------------ */
971 /**
972 * @return True if the the server socket will be opened in SO_REUSEADDR mode.
973 */
974 public boolean getReuseAddress()
975 {
976 return _reuseAddress;
977 }
978
979 /* ------------------------------------------------------------ */
980 /**
981 * @param reuseAddress True if the the server socket will be opened in SO_REUSEADDR mode.
982 */
983 public void setReuseAddress(boolean reuseAddress)
984 {
985 _reuseAddress=reuseAddress;
986 }
987
988 }