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