-
Notifications
You must be signed in to change notification settings - Fork 0
ENG-27785: allow port-only for -m, require host for -b #21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,145 @@ | ||
| /* | ||
| * Copyright (C) 2024-2025 Volt Active Data Inc. | ||
| * | ||
| * Use of this source code is governed by an MIT | ||
| * license that can be found in the LICENSE file or at | ||
| * https://opensource.org/licenses/MIT. | ||
| */ | ||
| package org.voltdb.meshmonitor.cli; | ||
|
|
||
| import java.net.InetSocketAddress; | ||
|
|
||
| import picocli.CommandLine; | ||
|
|
||
| public abstract class BaseInetSocketAddressConverter implements CommandLine.ITypeConverter<InetSocketAddress> { | ||
|
|
||
| protected abstract int getDefaultPort(); | ||
| protected abstract boolean requiresHostname(); | ||
| protected abstract boolean treatPlainValueAsPort(); | ||
|
|
||
| @Override | ||
| public InetSocketAddress convert(String value) { | ||
| value = value.trim(); | ||
|
|
||
| // start with null host and default port, to be replaced as we go | ||
| String host; | ||
| int port = getDefaultPort(); | ||
|
|
||
| // IPv6 must start with brackets | ||
| if (value.startsWith("[")) { | ||
|
|
||
| // and must have a close bracket | ||
| int closeBracket = value.indexOf("]"); | ||
| if (closeBracket == -1) { | ||
| throw new IllegalArgumentException("IPv6 address missing closing bracket"); | ||
| } | ||
|
|
||
| // host is within the brackets | ||
| host = value.substring(1, closeBracket); | ||
|
|
||
| String remainder = value.substring(closeBracket + 1); | ||
|
|
||
| if (remainder.isEmpty() || remainder.equals(":")) { | ||
| // no port provided, keep the default port | ||
| } else if (remainder.startsWith(":")) { | ||
| port = Integer.parseInt(remainder.substring(1)); | ||
| } else { | ||
| throw new IllegalArgumentException("Invalid format after IPv6 address"); | ||
| } | ||
|
|
||
| validateHost(host); | ||
| validatePort(port); | ||
| if (host.isEmpty() && treatPlainValueAsPort()) { | ||
| return new InetSocketAddress(port); | ||
| } else { | ||
| return new InetSocketAddress(host, port); | ||
| } | ||
|
|
||
| } else { | ||
|
|
||
| int lastColon = value.lastIndexOf(":"); | ||
|
|
||
| if (lastColon == -1) { | ||
| // there is no colon | ||
| return handlePlainValue(value); | ||
| } | ||
|
|
||
| if (value.indexOf(":") != lastColon) { | ||
| // There is more than one colon | ||
|
|
||
| // Either it's invalid or it's an IPv6 address without brackets, which we require | ||
| // otherwise there is ambiguity between the port vs. the last group of the address | ||
| throw new IllegalArgumentException("Too many colons or IPv6 address missing brackets"); | ||
| } | ||
|
|
||
| if (value.equals(":")) { | ||
| // there is only just a colon, treat this the same as "" | ||
| return handlePlainValue(""); | ||
| } | ||
|
|
||
| if (lastColon == 0) { | ||
| // no hostname given, but the colon indicates value should be the port | ||
| if (requiresHostname()) { | ||
| throw new IllegalArgumentException("Hostname is required. Please provide a valid FQDN or IP address."); | ||
| } else { | ||
| // skip over the colon and handle Plain value as a port | ||
| port = Integer.parseInt(value.substring(1)); | ||
| validatePort(port); | ||
| return new InetSocketAddress(port); | ||
| } | ||
| } | ||
|
|
||
| // there is one and only one colon | ||
| host = value.substring(0, lastColon); | ||
| String portString = value.substring(lastColon + 1); | ||
| if (!portString.isEmpty()) { | ||
| port = Integer.parseInt(portString); | ||
| } | ||
| validateHost(host); | ||
| validatePort(port); | ||
| return new InetSocketAddress(host, port); | ||
| } | ||
| } | ||
|
|
||
| private InetSocketAddress handlePlainValue(String value) { | ||
| if (value.isEmpty()) { | ||
| if (requiresHostname()) { | ||
| throw new IllegalArgumentException("Hostname is required. Please provide a valid FQDN or IP address."); | ||
| } else { | ||
| // use default port + wildcard | ||
| return new InetSocketAddress(getDefaultPort()); | ||
| } | ||
| } else if (treatPlainValueAsPort() && isValidPort(value)) { | ||
| int port = Integer.parseInt(value); | ||
| return new InetSocketAddress(port); // wildcard | ||
| } else { | ||
| validateHost(value); | ||
| return new InetSocketAddress(value, getDefaultPort()); | ||
| } | ||
| } | ||
|
|
||
| private void validateHost(String host) { | ||
| if (requiresHostname() && (host == null || host.isEmpty())) { | ||
| throw new IllegalArgumentException("Hostname is required. Please provide a valid FQDN or IP address."); | ||
| } | ||
| } | ||
|
|
||
| private void validatePort(int port) { | ||
| if (!portInValidRange(port)) { | ||
| throw new IllegalArgumentException("Port must be in range 1 - 65535"); | ||
| } | ||
| } | ||
|
|
||
| private boolean isValidPort(String input) { | ||
| try { | ||
| int port = Integer.parseInt(input); | ||
| return portInValidRange(port); | ||
| } catch (NumberFormatException e) { | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| private boolean portInValidRange(int port) { | ||
| return port >=1 && port <= 65535; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| /* | ||
| * Copyright (C) 2024-2025 Volt Active Data Inc. | ||
| * | ||
| * Use of this source code is governed by an MIT | ||
| * license that can be found in the LICENSE file or at | ||
| * https://opensource.org/licenses/MIT. | ||
| */ | ||
| package org.voltdb.meshmonitor.cli; | ||
|
|
||
| public class BindInetSocketAddressConverter extends BaseInetSocketAddressConverter { | ||
|
|
||
| @Override | ||
| protected int getDefaultPort() { | ||
| return 12222; | ||
| } | ||
|
|
||
| @Override | ||
| protected boolean requiresHostname() { | ||
| return true; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this mean you only listen on a single interface?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. requiresHostname = true means the user must provide some sort of hostname. It could be [:::] or 0.0.0.0, or locahost, but it can't be empty. |
||
| } | ||
|
|
||
| @Override | ||
| protected boolean treatPlainValueAsPort() { | ||
| return false; | ||
| } | ||
| } | ||
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| /* | ||
| * Copyright (C) 2024-2025 Volt Active Data Inc. | ||
| * | ||
| * Use of this source code is governed by an MIT | ||
| * license that can be found in the LICENSE file or at | ||
| * https://opensource.org/licenses/MIT. | ||
| */ | ||
| package org.voltdb.meshmonitor.cli; | ||
|
|
||
| public class MetricsInetSocketAddressConverter extends BaseInetSocketAddressConverter { | ||
|
|
||
| @Override | ||
| protected int getDefaultPort() { | ||
| return 12223; | ||
| } | ||
|
|
||
| @Override | ||
| protected boolean requiresHostname() { | ||
| return false; | ||
| } | ||
|
|
||
| @Override | ||
| protected boolean treatPlainValueAsPort() { | ||
| return true; | ||
| } | ||
| } |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wow!