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