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