Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions core/pva/src/main/java/org/epics/pva/PVASettings.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
******************************************************************************/
package org.epics.pva;

import java.io.File;
import java.util.logging.Level;
import java.util.logging.Logger;

Expand All @@ -20,6 +21,13 @@
*/
public class PVASettings
{
/** PVA protocol version for XDG path construction.
*
* <p>Matches PVXS versionString() so that the Java client
* and PVXS share the same well-known keychain locations.
*/
private static final String PVA_VERSION = "1.5";

/** Common logger
*
* Usage of levels:
Expand Down Expand Up @@ -281,6 +289,15 @@
EPICS_PVA_TCP_SOCKET_TMO = get("EPICS_PVA_TCP_SOCKET_TMO", EPICS_PVA_TCP_SOCKET_TMO);
EPICS_PVA_MAX_ARRAY_FORMATTING = get("EPICS_PVA_MAX_ARRAY_FORMATTING", EPICS_PVA_MAX_ARRAY_FORMATTING);
EPICS_PVAS_TLS_KEYCHAIN = get("EPICS_PVAS_TLS_KEYCHAIN", EPICS_PVAS_TLS_KEYCHAIN);
if (EPICS_PVAS_TLS_KEYCHAIN.isEmpty() && !isDefined("EPICS_PVAS_TLS_KEYCHAIN"))
{
final String xdg_server = getXdgPvaKeychainPath("server.p12");
if (!xdg_server.isEmpty())
{
EPICS_PVAS_TLS_KEYCHAIN = xdg_server;
logger.log(Level.CONFIG, "EPICS_PVAS_TLS_KEYCHAIN auto-discovered at " + xdg_server);

Check warning on line 298 in core/pva/src/main/java/org/epics/pva/PVASettings.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Format specifiers or lambda should be used instead of string concatenation.

See more on https://sonarcloud.io/project/issues?id=ControlSystemStudio_phoebus&issues=AZ2RmV5fBWYYs-d7vw0C&open=AZ2RmV5fBWYYs-d7vw0C&pullRequest=3782

Check warning on line 298 in core/pva/src/main/java/org/epics/pva/PVASettings.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use the built-in formatting to construct this argument.

See more on https://sonarcloud.io/project/issues?id=ControlSystemStudio_phoebus&issues=AZ2RmV5fBWYYs-d7vw0A&open=AZ2RmV5fBWYYs-d7vw0A&pullRequest=3782
}
}
EPICS_PVAS_TLS_OPTIONS = get("EPICS_PVAS_TLS_OPTIONS", EPICS_PVAS_TLS_OPTIONS);
require_client_cert = EPICS_PVAS_TLS_OPTIONS.contains("client_cert=require");
EPICS_PVA_TLS_KEYCHAIN = get("EPICS_PVA_TLS_KEYCHAIN", EPICS_PVA_TLS_KEYCHAIN);
Expand All @@ -289,6 +306,15 @@
EPICS_PVA_TLS_KEYCHAIN = EPICS_PVAS_TLS_KEYCHAIN;
logger.log(Level.CONFIG, "EPICS_PVA_TLS_KEYCHAIN (empty) updated from EPICS_PVAS_TLS_KEYCHAIN");
}
if (EPICS_PVA_TLS_KEYCHAIN.isEmpty() && !isDefined("EPICS_PVA_TLS_KEYCHAIN"))
{
final String xdg_client = getXdgPvaKeychainPath("client.p12");
if (!xdg_client.isEmpty())
{
EPICS_PVA_TLS_KEYCHAIN = xdg_client;
logger.log(Level.CONFIG, "EPICS_PVA_TLS_KEYCHAIN auto-discovered at " + xdg_client);

Check warning on line 315 in core/pva/src/main/java/org/epics/pva/PVASettings.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use the built-in formatting to construct this argument.

See more on https://sonarcloud.io/project/issues?id=ControlSystemStudio_phoebus&issues=AZ2RmV5fBWYYs-d7vw0B&open=AZ2RmV5fBWYYs-d7vw0B&pullRequest=3782

Check warning on line 315 in core/pva/src/main/java/org/epics/pva/PVASettings.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Format specifiers or lambda should be used instead of string concatenation.

See more on https://sonarcloud.io/project/issues?id=ControlSystemStudio_phoebus&issues=AZ2RmV5fBWYYs-d7vw0D&open=AZ2RmV5fBWYYs-d7vw0D&pullRequest=3782
}
}
EPICS_PVA_SEND_BUFFER_SIZE = get("EPICS_PVA_SEND_BUFFER_SIZE", EPICS_PVA_SEND_BUFFER_SIZE);
EPICS_PVA_FAST_BEACON_MIN = get("EPICS_PVA_FAST_BEACON_MIN", EPICS_PVA_FAST_BEACON_MIN);
EPICS_PVA_FAST_BEACON_MAX = get("EPICS_PVA_FAST_BEACON_MAX", EPICS_PVA_FAST_BEACON_MAX);
Expand Down Expand Up @@ -339,4 +365,71 @@
{
return Integer.parseInt(get(name, Integer.toString(default_value)));
}

/** Check whether a setting has been explicitly defined as a Java property or environment variable.
*
* <p>Unlike {@link #get(String, String)}, this returns {@code true} even when the
* variable is defined but set to an empty string. This is used to distinguish
* "user explicitly set the variable to empty (disable TLS)" from
* "variable is absent (fall back to auto-discovery)".
*
* @param name Name of setting
* @return {@code true} if the setting is present as a Java property or environment variable
*/
private static boolean isDefined(final String name)
{
return System.getProperty(name) != null || System.getenv(name) != null;
}

/** Get XDG config home directory.
*
* <p>Uses {@code XDG_CONFIG_HOME} environment variable if set.
* Falls back to {@code $HOME/.config} on Unix or
* {@code %USERPROFILE%} on Windows,
* matching the PVXS {@code getXdgConfigHome()} behavior.
*
* @return XDG config home path, or empty string if home cannot be determined
*/
private static String getXdgConfigHome()
{
final String xdg = System.getenv("XDG_CONFIG_HOME");
if (xdg != null && !xdg.isEmpty())
return xdg;

final String home = System.getProperty("user.home");
if (home == null || home.isEmpty())
return "";

if (System.getProperty("os.name", "").toLowerCase().startsWith("win"))
return home;

return home + File.separator + ".config";
}

/** Try to find a PVA keychain at the XDG well-known location.
*
* <p>Constructs the path
* {@code <xdg_config_home>/pva/<PVA_VERSION>/<filename>}
* and returns it if the file exists, otherwise returns empty string.
* This mirrors the PVXS fallback in {@code config.cpp} when
* {@code EPICS_PVA_TLS_KEYCHAIN} / {@code EPICS_PVAS_TLS_KEYCHAIN}
* are not configured.
*
* @param filename Keychain filename, e.g. "client.p12" or "server.p12"
* @return Absolute path to the keychain file, or empty string if not found
*/
private static String getXdgPvaKeychainPath(final String filename)
{
final String config_home = getXdgConfigHome();
if (config_home.isEmpty())
return "";

final String path = config_home + File.separator + "pva"
+ File.separator + PVA_VERSION
+ File.separator + filename;
final File file = new File(path);
if (file.isFile() && file.canRead())
return path;
return "";
}
}
Loading