Skip to content
Merged
Show file tree
Hide file tree
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
60 changes: 54 additions & 6 deletions core/pva/src/main/java/org/epics/pva/client/PVAClientMain.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
package org.epics.pva.client;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CountDownLatch;
Expand All @@ -17,9 +18,11 @@
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;
import java.util.stream.Collectors;

import org.epics.pva.PVASettings;
import org.epics.pva.data.PVAData;
import org.epics.pva.data.PVAStructure;

/** Command line tool for PVA client
*
Expand All @@ -37,9 +40,17 @@ public class PVAClientMain
private static boolean completion = false;
private static String request = "";

/** Commands */
private static enum Cmd
{
info, get, monitor, put, call, beacons
}

private static void help()
{
System.out.println("USAGE: pvaclient info|get|monitor|put|beacons [options] <PV name>...");
System.out.println("USAGE: pvaclient " +
Arrays.stream(Cmd.values()).map(Object::toString).collect(Collectors.joining("|")) +
" [options] <PV name>...");
System.out.println();
System.out.println("Options:");
System.out.println(" -h Help");
Expand All @@ -54,6 +65,7 @@ private static void help()
System.out.println("get <PV name> Read PV's value");
System.out.println("monitor <PV name> Subscribe to PV's value changes");
System.out.println("put <PV name> <value> Write value to PV");
System.out.println("call <PV name> Call RPC PV (no request params)");
System.out.println("beacons Display received beacons");
}

Expand Down Expand Up @@ -240,6 +252,36 @@ private static void put(final String name, final String value) throws Exception
}
}

private static void call(final String name, final PVAStructure request) throws Exception
{
try (final PVAClient pva = new PVAClient())
{
final CountDownLatch connected = new CountDownLatch(1);
final PVAChannel pv = pva.getChannel(name, (ch, state) ->
{
if (state == ClientChannelState.CONNECTED)
connected.countDown();
});
final long timeout_ms = Math.round(seconds*1000);
if (! connected.await(timeout_ms, TimeUnit.MILLISECONDS))
{
System.err.println("Timeout waiting for " + name);
return;
}

try
{
PVAStructure result = pv.invoke(request).get(timeout_ms, TimeUnit.MILLISECONDS);
System.out.println(result);
}
catch (TimeoutException ex)
{
System.err.println("Call timed out");
}
pv.close();
}
}

/** Watch received beacons
* @throws Exception on error
*/
Expand Down Expand Up @@ -336,21 +378,27 @@ else if (arg.startsWith("-"))

final String command = names.remove(0);

if (command.equals("beacons") && names.size() == 0)
if (command.equals(Cmd.beacons.name()) && names.size() == 0)
beacons();
else if (command.equals("info") && names.size() > 0)
else if (command.equals(Cmd.info.name()) && names.size() > 0)
info(names);
else if (command.equals("get") && names.size() > 0)
else if (command.equals(Cmd.get.name()) && names.size() > 0)
get(names);
else if (command.equals("monitor") && names.size() > 0)
else if (command.equals(Cmd.monitor.name()) && names.size() > 0)
monitor(names);
else if (command.equals("put") && names.size() == 2)
else if (command.equals(Cmd.put.name()) && names.size() == 2)
{
// By default, write to the 'value' element data structure
if (request.isEmpty())
request = "value";
put(names.get(0), names.get(1));
}
else if (command.equals(Cmd.call.name()) && names.size() > 0)
{
// For now not supporting any request detail from cmdline
PVAStructure request = new PVAStructure("", "");
call(names.get(0), request);
}
else
help();
}
Expand Down
6 changes: 3 additions & 3 deletions core/pva/src/main/java/org/epics/pva/data/nt/PVATable.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@
*/
public class PVATable extends PVAStructure {
public static final String STRUCT_NAME = "epics:nt/NTTable:1.0";
private static final String LABELS_NAME = "labels";
private static final String VALUE_NAME = "value";
private static final String DESCRIPTOR_NAME = "descriptor";
public static final String LABELS_NAME = "labels";
public static final String VALUE_NAME = "value";
public static final String DESCRIPTOR_NAME = "descriptor";

private final PVAStringArray labels;
private final PVAStructure value;
Expand Down
21 changes: 21 additions & 0 deletions core/pva/src/main/java/org/epics/pva/server/PVAServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import static org.epics.pva.PVASettings.logger;

import java.net.InetSocketAddress;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentHashMap.KeySetView;
import java.util.concurrent.ForkJoinPool;
Expand Down Expand Up @@ -161,6 +162,26 @@ ServerPV getPV(final int sid)
return pv_by_sid.get(sid);
}


/** Info about a client to the PVA server:
* Network address and authentication info
*/
public static record ClientInfo(InetSocketAddress address,
ServerAuth authentication)
{
}

/** Get information about clients to this PVA server
* @return {@link ClientInfo}s
*/
public Collection<ClientInfo> getClientInfos()
{
return tcp_handlers.stream()
.map(tcp -> new ClientInfo(tcp.getRemoteAddress(),
tcp.getAuth()))
.toList();
}

/** Special address used in TCP search reply to indicate "Use this TCP connection" */
private static final InetSocketAddress USE_THIS_TCP_CONNECTION = new InetSocketAddress(0);

Expand Down
6 changes: 3 additions & 3 deletions core/pva/src/main/java/org/epics/pva/server/ServerAuth.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2019-2023 Oak Ridge National Laboratory.
* Copyright (c) 2019-2025 Oak Ridge National Laboratory.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
Expand All @@ -20,7 +20,7 @@
* @author Kay Kasemir
*/
@SuppressWarnings("nls")
abstract class ServerAuth
public abstract class ServerAuth
{
/** @param channel Channel for which to check write access
* @return Does client have write access?
Expand Down Expand Up @@ -62,7 +62,7 @@ public static ServerAuth decode(final ServerTCPHandler tcp, final ByteBuffer buf

if (PVAAuth.X509.equals(auth))
return new X509ServerAuth(tls_info);

return Anonymous;
}

Expand Down