001/*
002 * Copyright 2010-2024 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2010-2024 Ping Identity Corporation
007 *
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * You may obtain a copy of the License at
011 *
012 *    http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing, software
015 * distributed under the License is distributed on an "AS IS" BASIS,
016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 * See the License for the specific language governing permissions and
018 * limitations under the License.
019 */
020/*
021 * Copyright (C) 2010-2024 Ping Identity Corporation
022 *
023 * This program is free software; you can redistribute it and/or modify
024 * it under the terms of the GNU General Public License (GPLv2 only)
025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
026 * as published by the Free Software Foundation.
027 *
028 * This program is distributed in the hope that it will be useful,
029 * but WITHOUT ANY WARRANTY; without even the implied warranty of
030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
031 * GNU General Public License for more details.
032 *
033 * You should have received a copy of the GNU General Public License
034 * along with this program; if not, see <http://www.gnu.org/licenses>.
035 */
036package com.unboundid.ldap.listener;
037
038
039
040import java.net.InetAddress;
041import javax.net.ServerSocketFactory;
042
043import com.unboundid.ldap.sdk.LDAPConnectionOptions;
044import com.unboundid.util.Mutable;
045import com.unboundid.util.NotNull;
046import com.unboundid.util.Nullable;
047import com.unboundid.util.ThreadSafety;
048import com.unboundid.util.ThreadSafetyLevel;
049import com.unboundid.util.Validator;
050
051
052
053/**
054 * This class provides a mechanism for defining the configuration to use for an
055 * {@link LDAPListener} instance.  Note that while instances of this class are
056 * not inherently threadsafe, a private copy of the configuration will be
057 * created whenever a new {@code LDAPListener} is created so that this
058 * configuration may continue to be altered for new instances without impacting
059 * any existing listeners.
060 */
061@Mutable()
062@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
063public final class LDAPListenerConfig
064{
065  /**
066   * The default maximum message size that will be used if no other value is
067   * specified.
068   */
069  static final int DEFAULT_MAX_MESSAGE_SIZE_BYTES =
070       new LDAPConnectionOptions().getMaxMessageSize();
071
072
073
074  // Indicates whether the listener should request that the client provide a
075  // certificate.
076  private boolean requestClientCertificate;
077
078  // Indicates whether the listener should require that the client provide a
079  // certificate.
080  private boolean requireClientCertificate;
081
082  // Indicates whether to use the SO_KEEPALIVE socket option for sockets
083  // accepted by the listener.
084  private boolean useKeepAlive;
085
086  // Indicates whether to use the SO_LINGER socket option for sockets accepted
087  // by the listener.
088  private boolean useLinger;
089
090  // Indicates whether to use the SO_REUSEADDR socket option for sockets
091  // accepted by the listener.
092  private boolean useReuseAddress;
093
094  // Indicates whether to use the TCP_NODELAY for sockets accepted by the
095  // listener.
096  private boolean useTCPNoDelay;
097
098  // The address on which to listen for client connections.
099  @Nullable private InetAddress listenAddress;
100
101  // The linger timeout in seconds to use for sockets accepted by the listener.
102  private int lingerTimeout;
103
104  // The port on which to listen for client connections.
105  private int listenPort;
106
107  // The maximum number of concurrent connections that will be allowed.
108  private int maxConnections;
109
110  // The maximum size in bytes for encoded messages that the listener will
111  // accept.
112  private int maxMessageSizeBytes;
113
114  // The receive buffer size to use for sockets accepted by the listener.
115  private int receiveBufferSize;
116
117  // The send buffer size to use for sockets accepted by the listener.
118  private int sendBufferSize;
119
120  // The exception handler to use for the listener and associated connections.
121  @Nullable private LDAPListenerExceptionHandler exceptionHandler;
122
123  // The request handler that will be used to process requests read from
124  // clients.
125  @NotNull private LDAPListenerRequestHandler requestHandler;
126
127  // The factory that will be used to create server sockets.
128  @NotNull private ServerSocketFactory serverSocketFactory;
129
130
131
132  /**
133   * Creates a new listener configuration.
134   *
135   * @param  listenPort      The port on which to listen for client connections.
136   *                         It must be an integer between 1 and 65535, or 0 to
137   *                         indicate that a free port should be chosen by the
138   *                         JVM.
139   * @param  requestHandler  The request handler that will be used to process
140   *                         requests read from clients.  It must not be
141   *                         {@code null}.
142   */
143  public LDAPListenerConfig(final int listenPort,
144              @NotNull final LDAPListenerRequestHandler requestHandler)
145  {
146    Validator.ensureTrue((listenPort >= 0) && (listenPort <= 65_535));
147    Validator.ensureNotNull(requestHandler);
148
149    this.listenPort     = listenPort;
150    this.requestHandler = requestHandler;
151
152    requestClientCertificate = false;
153    requireClientCertificate = false;
154    useKeepAlive             = true;
155    useLinger                = true;
156    useReuseAddress          = true;
157    useTCPNoDelay            = true;
158    lingerTimeout            = 5;
159    listenAddress            = null;
160    maxConnections           = 0;
161    maxMessageSizeBytes      = DEFAULT_MAX_MESSAGE_SIZE_BYTES;
162    receiveBufferSize        = 0;
163    sendBufferSize           = 0;
164    exceptionHandler         = null;
165    serverSocketFactory      = ServerSocketFactory.getDefault();
166  }
167
168
169
170  /**
171   * Retrieves the port number on which to listen for client connections.  A
172   * value of zero indicates that the listener should allow the JVM to choose a
173   * free port.
174   *
175   * @return  The port number on which to listen for client connections.
176   */
177  public int getListenPort()
178  {
179    return listenPort;
180  }
181
182
183
184  /**
185   * Specifies the port number on which to listen for client connections.  The
186   * provided value must be between 1 and 65535, or it may be 0 to indicate that
187   * the JVM should select a free port on the system.
188   *
189   * @param  listenPort  The port number on which to listen for client
190   *                     connections.
191   */
192  public void setListenPort(final int listenPort)
193  {
194    Validator.ensureTrue((listenPort >= 0) && (listenPort <= 65_535));
195
196    this.listenPort = listenPort;
197  }
198
199
200
201  /**
202   * Retrieves the LDAP listener request handler that should be used to process
203   * requests read from clients.
204   *
205   * @return  The LDAP listener request handler that should be used to process
206   *          requests read from clients.
207   */
208  @NotNull()
209  public LDAPListenerRequestHandler getRequestHandler()
210  {
211    return requestHandler;
212  }
213
214
215
216  /**
217   * Specifies the LDAP listener request handler that should be used to process
218   * requests read from clients.
219   *
220   * @param  requestHandler  The LDAP listener request handler that should be
221   *                         used to process requests read from clients.  It
222   *                         must not be {@code null}.
223   */
224  public void setRequestHandler(
225                   @NotNull final LDAPListenerRequestHandler requestHandler)
226  {
227    Validator.ensureNotNull(requestHandler);
228
229    this.requestHandler = requestHandler;
230  }
231
232
233
234  /**
235   * Indicates whether to use the SO_KEEPALIVE socket option for sockets
236   * accepted by the listener.
237   *
238   * @return  {@code true} if the SO_KEEPALIVE socket option should be used for
239   *          sockets accepted by the listener, or {@code false} if not.
240   */
241  public boolean useKeepAlive()
242  {
243    return useKeepAlive;
244  }
245
246
247
248  /**
249   * Specifies whether to use the SO_KEEPALIVE socket option for sockets
250   * accepted by the listener.
251   *
252   * @param  useKeepAlive  Indicates whether to use the SO_KEEPALIVE socket
253   *                       option for sockets accepted by the listener.
254   */
255  public void setUseKeepAlive(final boolean useKeepAlive)
256  {
257    this.useKeepAlive = useKeepAlive;
258  }
259
260
261
262  /**
263   * Indicates whether to use the SO_LINGER socket option for sockets accepted
264   * by the listener.
265   *
266   * @return  {@code true} if the SO_LINGER socket option should be used for
267   *          sockets accepted by the listener, or {@code false} if not.
268   */
269  public boolean useLinger()
270  {
271    return useLinger;
272  }
273
274
275
276  /**
277   * Specifies whether to use the SO_LINGER socket option for sockets accepted
278   * by the listener.
279   *
280   * @param  useLinger  Indicates whether to use the SO_LINGER socket option for
281   *                    sockets accepted by the listener.
282   */
283  public void setUseLinger(final boolean useLinger)
284  {
285    this.useLinger = useLinger;
286  }
287
288
289
290  /**
291   * Indicates whether to use the SO_REUSEADDR socket option for sockets
292   * accepted by the listener.
293   *
294   * @return  {@code true} if the SO_REUSEADDR socket option should be used for
295   *          sockets accepted by the listener, or {@code false} if not.
296   */
297  public boolean useReuseAddress()
298  {
299    return useReuseAddress;
300  }
301
302
303
304  /**
305   * Specifies whether to use the SO_REUSEADDR socket option for sockets
306   * accepted by the listener.
307   *
308   * @param  useReuseAddress  Indicates whether to use the SO_REUSEADDR socket
309   *                          option for sockets accepted by the listener.
310   */
311  public void setUseReuseAddress(final boolean useReuseAddress)
312  {
313    this.useReuseAddress = useReuseAddress;
314  }
315
316
317
318  /**
319   * Indicates whether to use the TCP_NODELAY socket option for sockets accepted
320   * by the listener.
321   *
322   * @return  {@code true} if the TCP_NODELAY socket option should be used for
323   *          sockets accepted by the listener, or {@code false} if not.
324   */
325  public boolean useTCPNoDelay()
326  {
327    return useTCPNoDelay;
328  }
329
330
331
332  /**
333   * Specifies whether to use the TCP_NODELAY socket option for sockets accepted
334   * by the listener.
335   *
336   * @param  useTCPNoDelay  Indicates whether to use the TCP_NODELAY socket
337   *                        option for sockets accepted by the listener.
338   */
339  public void setUseTCPNoDelay(final boolean useTCPNoDelay)
340  {
341    this.useTCPNoDelay = useTCPNoDelay;
342  }
343
344
345
346  /**
347   * Retrieves the address on which to listen for client connections, if
348   * defined.
349   *
350   * @return  The address on which to listen for client connections, or
351   *          {@code null} if it should listen on all available addresses on all
352   *          interfaces.
353   */
354  @Nullable()
355  public InetAddress getListenAddress()
356  {
357    return listenAddress;
358  }
359
360
361
362  /**
363   * Specifies the address on which to listen for client connections.
364   *
365   * @param  listenAddress  The address on which to listen for client
366   *                        connections.  It may be {@code null} to indicate
367   *                        that it should listen on all available addresses on
368   *                        all interfaces.
369   */
370  public void setListenAddress(@Nullable final InetAddress listenAddress)
371  {
372    this.listenAddress = listenAddress;
373  }
374
375
376
377  /**
378   * Retrieves the timeout in seconds that should be used if the SO_LINGER
379   * socket option is enabled.
380   *
381   * @return  The timeout in seconds that should be used if the SO_LINGER socket
382   *           option is enabled.
383   */
384  public int getLingerTimeoutSeconds()
385  {
386    return lingerTimeout;
387  }
388
389
390
391  /**
392   * Specifies the timeout in seconds that should be used if the SO_LINGER
393   * socket option is enabled.
394   *
395   * @param  lingerTimeout  The timeout in seconds that should be used if the
396   *                        SO_LINGER socket option is enabled.  The value must
397   *                        be between 0 and 65535, inclusive.
398   */
399  public void setLingerTimeoutSeconds(final int lingerTimeout)
400  {
401    Validator.ensureTrue((lingerTimeout >= 0) && (lingerTimeout <= 65_535));
402
403    this.lingerTimeout = lingerTimeout;
404  }
405
406
407
408  /**
409   * Retrieves the maximum number of concurrent connections that the listener
410   * will allow.  If a client tries to establish a new connection while the
411   * listener already has the maximum number of concurrent connections, then the
412   * new connection will be rejected.
413   *
414   * @return  The maximum number of concurrent connections that the listener
415   *          will allow, or zero if no limit should be enforced.
416   */
417  public int getMaxConnections()
418  {
419    return maxConnections;
420  }
421
422
423
424  /**
425   * Specifies the maximum number of concurrent connections that the listener
426   * will allow.  If a client tries to establish a new connection while the
427   * listener already has the maximum number of concurrent connections, then the
428   * new connection will be rejected.
429   *
430   * @param  maxConnections  The maximum number of concurrent connections that
431   *                         the listener will allow.  A value that is less than
432   *                         or equal to zero indicates no limit.
433   */
434  public void setMaxConnections(final int maxConnections)
435  {
436    if (maxConnections > 0)
437    {
438      this.maxConnections = maxConnections;
439    }
440    else
441    {
442      this.maxConnections = 0;
443    }
444  }
445
446
447
448  /**
449   * Retrieves the maximum size in bytes for LDAP messages that will be accepted
450   * by this listener.
451   *
452   * @return  The maximum size in bytes for LDAP messages that will be accepted
453   *          by this listener.
454   */
455  public int getMaxMessageSizeBytes()
456  {
457    return maxMessageSizeBytes;
458  }
459
460
461
462  /**
463   * Specifies the maximum size in bytes for LDAP messages that will be accepted
464   * by this listener.
465   *
466   * @param  maxMessageSizeBytes  The maximum size in bytes for LDAP messages
467   *                              that will be accepted by this listener.  A
468   *                              value that is less than or equal to zero will
469   *                              use the maximum allowed message size.
470   */
471  public void setMaxMessageSizeBytes(final int maxMessageSizeBytes)
472  {
473    if (maxMessageSizeBytes > 0)
474    {
475      this.maxMessageSizeBytes = maxMessageSizeBytes;
476    }
477    else
478    {
479      this.maxMessageSizeBytes = Integer.MAX_VALUE;
480    }
481  }
482
483
484
485  /**
486   * Retrieves the receive buffer size that should be used for sockets accepted
487   * by the listener.
488   *
489   * @return  The receive buffer size that should be used for sockets accepted
490   *          by the listener, or 0 if the default receive buffer size should be
491   *          used.
492   */
493  public int getReceiveBufferSize()
494  {
495    return receiveBufferSize;
496  }
497
498
499
500  /**
501   * Specifies the receive buffer size that should be used for sockets accepted
502   * by the listener.  A value less than or equal to zero indicates that the
503   * default receive buffer size should be used.
504   *
505   * @param  receiveBufferSize  The receive buffer size that should be used for
506   *                            sockets accepted by the listener.
507   */
508  public void setReceiveBufferSize(final int receiveBufferSize)
509  {
510    if (receiveBufferSize > 0)
511    {
512      this.receiveBufferSize = receiveBufferSize;
513    }
514    else
515    {
516      this.receiveBufferSize = 0;
517    }
518  }
519
520
521
522  /**
523   * Retrieves the send  buffer size that should be used for sockets accepted
524   * by the listener.
525   *
526   * @return  The send buffer size that should be used for sockets accepted by
527   *          the listener, or 0 if the default send buffer size should be used.
528   */
529  public int getSendBufferSize()
530  {
531    return sendBufferSize;
532  }
533
534
535
536  /**
537   * Specifies the send buffer size that should be used for sockets accepted by
538   * the listener.  A value less than or equal to zero indicates that the
539   * default send buffer size should be used.
540   *
541   * @param  sendBufferSize  The send buffer size that should be used for
542   *                         sockets accepted by the listener.
543   */
544  public void setSendBufferSize(final int sendBufferSize)
545  {
546    if (sendBufferSize > 0)
547    {
548      this.sendBufferSize = sendBufferSize;
549    }
550    else
551    {
552      this.sendBufferSize = 0;
553    }
554  }
555
556
557
558  /**
559   * Retrieves the exception handler that should be notified of any exceptions
560   * caught while attempting to accept or interact with a client connection.
561   *
562   * @return  The exception handler that should be notified of any exceptions
563   *          caught while attempting to accept or interact with a client
564   *          connection, or {@code null} if none is defined.
565   */
566  @Nullable()
567  public LDAPListenerExceptionHandler getExceptionHandler()
568  {
569    return exceptionHandler;
570  }
571
572
573
574  /**
575   * Specifies the exception handler that should be notified of any exceptions
576   * caught while attempting to accept or interact with a client connection.
577   *
578   * @param  exceptionHandler  The exception handler that should be notified of
579   *                           any exceptions encountered during processing.  It
580   *                           may be {@code null} if no exception handler
581   *                           should be used.
582   */
583  public void setExceptionHandler(
584              @Nullable final LDAPListenerExceptionHandler exceptionHandler)
585  {
586    this.exceptionHandler = exceptionHandler;
587  }
588
589
590
591  /**
592   * Retrieves the factory that will be used to create the server socket that
593   * will listen for client connections.
594   *
595   * @return  The factory that will be used to create the server socket that
596   *          will listen for client connections.
597   */
598  @NotNull()
599  public ServerSocketFactory getServerSocketFactory()
600  {
601    return serverSocketFactory;
602  }
603
604
605
606  /**
607   * Specifies the factory that will be used to create the server socket that
608   * will listen for client connections.
609   *
610   * @param  serverSocketFactory  The factory that will be used to create the
611   *                              server socket that will listen for client
612   *                              connections.  It may be {@code null} to use
613   *                              the JVM-default server socket factory.
614   */
615  public void setServerSocketFactory(
616                   @Nullable final ServerSocketFactory serverSocketFactory)
617  {
618    if (serverSocketFactory == null)
619    {
620      this.serverSocketFactory = ServerSocketFactory.getDefault();
621    }
622    else
623    {
624      this.serverSocketFactory = serverSocketFactory;
625    }
626  }
627
628
629
630  /**
631   * Indicates whether the listener should request that the client present its
632   * own certificate chain during TLS negotiation.  This will be ignored for
633   * non-TLS-based connections.
634   *
635   * @return  {@code true} if the listener should request that the client
636   *          present its own certificate chain during TLS negotiation, or
637   *          {@code false} if not.
638   */
639  public boolean requestClientCertificate()
640  {
641    return requestClientCertificate;
642  }
643
644
645
646  /**
647   * Specifies whether the listener should request that the client present its
648   * own certificate chain during TLS negotiation.  This will be ignored for
649   * non-TLS-based connections.
650   *
651   * @param  requestClientCertificate  Indicates whether the listener should
652   *                                   request that the client present its own
653   *                                   certificate chain during TLS negotiation.
654   */
655  public void setRequestClientCertificate(
656                   final boolean requestClientCertificate)
657  {
658    this.requestClientCertificate = requestClientCertificate;
659  }
660
661
662
663  /**
664   * Indicates whether the listener should require that the client present its
665   * own certificate chain during TLS negotiation and should fail negotiation
666   * if no certificate chain was provided.  This will be ignored for
667   * non-TLS-based connections, and it will also be ignored if
668   * {@link #requestClientCertificate} returns false.
669   *
670   * @return  {@code true} if the listener should require that the client
671   *          present its own certificate chain during TLS negotiation, or
672   *          {@code false} if TLS negotiation should continue even if the
673   *          client did not present a certificate chain when requested.
674   */
675  public boolean requireClientCertificate()
676  {
677    return requireClientCertificate;
678  }
679
680
681
682  /**
683   * Specifies whether the listener should require that the client present its
684   * own certificate chain during TLS negotiation and should fail negotiation
685   * if no certificate chain was provided.  This will be ignored for
686   * non-TLS-based connections, and it will also be ignored if
687   * {@link #requestClientCertificate} returns false.
688   *
689   * @param  requireClientCertificate  Indicates whether the listener should
690   *                                   require that the client present its own
691   *                                   certificate chain during TLS negotiation.
692   */
693  public void setRequireClientCertificate(
694                   final boolean requireClientCertificate)
695  {
696    this.requireClientCertificate = requireClientCertificate;
697  }
698
699
700
701/**
702   * Creates a copy of this configuration that may be altered without impacting
703   * this configuration, and which will not be altered by changes to this
704   * configuration.
705   *
706   * @return  A copy of this configuration that may be altered without impacting
707   *          this configuration, and which will not be altered by changes to
708   *          this configuration.
709   */
710  @NotNull()
711  public LDAPListenerConfig duplicate()
712  {
713    final LDAPListenerConfig copy =
714         new LDAPListenerConfig(listenPort, requestHandler);
715
716    copy.requestClientCertificate = requestClientCertificate;
717    copy.requireClientCertificate = requireClientCertificate;
718    copy.useKeepAlive             = useKeepAlive;
719    copy.useLinger                = useLinger;
720    copy.useReuseAddress          = useReuseAddress;
721    copy.useTCPNoDelay            = useTCPNoDelay;
722    copy.listenAddress            = listenAddress;
723    copy.lingerTimeout            = lingerTimeout;
724    copy.maxConnections           = maxConnections;
725    copy.maxMessageSizeBytes      = maxMessageSizeBytes;
726    copy.receiveBufferSize        = receiveBufferSize;
727    copy.sendBufferSize           = sendBufferSize;
728    copy.exceptionHandler         = exceptionHandler;
729    copy.serverSocketFactory      = serverSocketFactory;
730
731    return copy;
732  }
733
734
735
736  /**
737   * Retrieves a string representation of this LDAP listener config.
738   *
739   * @return  A string representation of this LDAP listener config.
740   */
741  @Override()
742  @NotNull()
743  public String toString()
744  {
745    final StringBuilder buffer = new StringBuilder();
746    toString(buffer);
747    return buffer.toString();
748  }
749
750
751
752  /**
753   * Appends a string representation of this LDAP listener config to the
754   * provided buffer.
755   *
756   * @param  buffer  The buffer to which the information should be appended.
757   */
758  public void toString(@NotNull final StringBuilder buffer)
759  {
760    buffer.append("LDAPListenerConfig(listenAddress=");
761
762    if (listenAddress == null)
763    {
764      buffer.append("null");
765    }
766    else
767    {
768      buffer.append('\'');
769      buffer.append(listenAddress.getHostAddress());
770      buffer.append('\'');
771    }
772
773    buffer.append(", listenPort=");
774    buffer.append(listenPort);
775    buffer.append(", requestHandlerClass='");
776    buffer.append(requestHandler.getClass().getName());
777    buffer.append("', serverSocketFactoryClass='");
778    buffer.append(serverSocketFactory.getClass().getName());
779    buffer.append('\'');
780
781    if (exceptionHandler != null)
782    {
783      buffer.append(", exceptionHandlerClass='");
784      buffer.append(exceptionHandler.getClass().getName());
785      buffer.append('\'');
786    }
787
788    buffer.append(", useKeepAlive=");
789    buffer.append(useKeepAlive);
790    buffer.append(", useTCPNoDelay=");
791    buffer.append(useTCPNoDelay);
792
793    if (useLinger)
794    {
795      buffer.append(", useLinger=true, lingerTimeout=");
796      buffer.append(lingerTimeout);
797    }
798    else
799    {
800      buffer.append(", useLinger=false");
801    }
802
803    buffer.append(", maxConnections=");
804    buffer.append(maxConnections);
805    buffer.append(", maxMessageSizeBytes=");
806    buffer.append(maxMessageSizeBytes);
807    buffer.append(", useReuseAddress=");
808    buffer.append(useReuseAddress);
809    buffer.append(", receiveBufferSize=");
810    buffer.append(receiveBufferSize);
811    buffer.append(", sendBufferSize=");
812    buffer.append(sendBufferSize);
813    buffer.append(", requestClientCertificate=");
814    buffer.append(requestClientCertificate);
815    buffer.append(", requireClientCertificate=");
816    buffer.append(requireClientCertificate);
817    buffer.append(')');
818  }
819}