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}