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