Skip to content

Commit c297548

Browse files
authored
Merge pull request #2271 from ControlSystemStudio/pva_byteorder
PVA: Check/clarify handling of byte order
2 parents 761c43b + d7a3f63 commit c297548

File tree

5 files changed

+52
-9
lines changed

5 files changed

+52
-9
lines changed

core/pva/src/main/java/org/epics/pva/client/ClientTCPHandler.java

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2019-2021 Oak Ridge National Laboratory.
2+
* Copyright (c) 2019-2022 Oak Ridge National Laboratory.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v1.0
55
* which accompanies this distribution, and is available at
@@ -296,6 +296,12 @@ protected void onReceiverExited(final boolean running)
296296
@Override
297297
protected void handleControlMessage(final byte command, final ByteBuffer buffer) throws Exception
298298
{
299+
// 0 byte magic
300+
// 1 byte version
301+
// 2 byte flags
302+
// 3 byte command
303+
// 4 int32 payload size
304+
// 8 .. payload
299305
if (command == PVAHeader.CTRL_SET_BYTE_ORDER)
300306
{
301307
// First message received from server, remember its version
@@ -308,12 +314,23 @@ protected void handleControlMessage(final byte command, final ByteBuffer buffer)
308314
// configure it
309315
send_buffer.order(buffer.order());
310316

311-
logger.log(Level.FINE, () -> "Server Version " + server_version + " sets byte order to " + send_buffer.order());
312-
// Payload indicates if the server will send messages in that same order,
317+
if (connection_validated.get())
318+
logger.log(Level.WARNING, () -> "Server Version " + server_version + " sets byte order to " + send_buffer.order() +
319+
" after connection has already been validated");
320+
else
321+
logger.log(Level.FINE, () -> "Server Version " + server_version + " sets byte order to " + send_buffer.order());
322+
// Payload 'size' indicates if the server will send messages in that same order,
313323
// or might change order for each message.
314324
// We always adapt based on the flags of each received message,
315325
// so ignore.
316326
// send_buffer byte order is locked at this time, though.
327+
final int hint = buffer.getInt(4);
328+
if (hint == 0x00000000)
329+
logger.log(Level.FINE, () -> "Server hints that it will send all messages in byte order " + send_buffer.order());
330+
else if (hint == 0xFFFFFFFF)
331+
logger.log(Level.FINE, () -> "Server hints that client needs to check each received messages for changing byte order");
332+
else
333+
logger.log(Level.WARNING, () -> String.format("Server sent SET_BYTE_ORDER hint 0x%08X, expecting 0x00000000 or 0xFFFFFFFF", hint));
317334
}
318335
else
319336
super.handleControlMessage(command, buffer);

core/pva/src/main/java/org/epics/pva/common/PVAHeader.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2019-2021 Oak Ridge National Laboratory.
2+
* Copyright (c) 2019-2022 Oak Ridge National Laboratory.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v1.0
55
* which accompanies this distribution, and is available at
@@ -124,7 +124,7 @@ public class PVAHeader
124124
public static final byte CMD_SUB_GET = 0x40;
125125

126126

127-
/** Control message command to set byte order */
127+
/** Control message command to set byte order, aka 'SetEndian' */
128128
public static final byte CTRL_SET_BYTE_ORDER = 2;
129129

130130
/** Size of common PVA message header */
@@ -145,6 +145,7 @@ public class PVAHeader
145145
*/
146146
public static void encodeMessageHeader(final ByteBuffer buffer, byte flags, final byte command, final int payload_size)
147147
{
148+
// Indicate byte order within message header
148149
if (buffer.order() == ByteOrder.BIG_ENDIAN)
149150
flags |= FLAG_BIG_ENDIAN;
150151
else
@@ -168,6 +169,8 @@ public static int checkMessageAndGetSize(final ByteBuffer buffer, final boolean
168169
if (buffer.position() < PVAHeader.HEADER_SIZE)
169170
return PVAHeader.HEADER_SIZE;
170171

172+
// Byte order of message is irrelevant for
173+
// parsing the initial set of bytes
171174
final byte magic = buffer.get(0);
172175
if (magic != PVAHeader.PVA_MAGIC)
173176
throw new Exception(String.format("Message lacks magic 0x%02X, got 0x%02X", PVAHeader.PVA_MAGIC, magic));
@@ -184,6 +187,9 @@ public static int checkMessageAndGetSize(final ByteBuffer buffer, final boolean
184187
if (is_server != expect_server)
185188
throw new Exception(expect_server ? "Expected server message" : "Expected client message");
186189

190+
// With each received message, check the byte order
191+
// and adjust buffer to read further content which usually
192+
// contains data larger than byte-sized, so the order matters
187193
if ((flags & PVAHeader.FLAG_BIG_ENDIAN) == 0)
188194
buffer.order(ByteOrder.LITTLE_ENDIAN);
189195
else

core/pva/src/main/java/org/epics/pva/common/TCPHandler.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2019-2021 Oak Ridge National Laboratory.
2+
* Copyright (c) 2019-2022 Oak Ridge National Laboratory.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v1.0
55
* which accompanies this distribution, and is available at
@@ -12,6 +12,7 @@
1212
import java.net.InetSocketAddress;
1313
import java.net.SocketAddress;
1414
import java.nio.ByteBuffer;
15+
import java.nio.ByteOrder;
1516
import java.nio.channels.SocketChannel;
1617
import java.util.concurrent.BlockingQueue;
1718
import java.util.concurrent.ExecutorService;
@@ -117,6 +118,12 @@ public TCPHandler(final SocketChannel socket, final boolean client_mode)
117118
this.socket = socket;
118119
this.client_mode = client_mode;
119120

121+
// Receive buffer byte order is set based on header flag of each received message.
122+
// Send buffer of server and client starts out with native byte order.
123+
// For server, it stays that way.
124+
// For client, order is updated during connection validation (PVAHeader.CTRL_SET_BYTE_ORDER)
125+
send_buffer.order(ByteOrder.nativeOrder());
126+
120127
// Start receiving data
121128
receive_thread = thread_pool.submit(this::receiver);
122129
}
@@ -376,7 +383,11 @@ private void handleMessage(final ByteBuffer buffer) throws Exception
376383
final boolean control = (flags & PVAHeader.FLAG_CONTROL) != 0;
377384
final byte command = buffer.get(3);
378385
// Move to start of potential payload
379-
buffer.position(8);
386+
if (buffer.limit() >= 8)
387+
buffer.position(8);
388+
else
389+
logger.log(Level.SEVERE, Thread.currentThread().getName() + " received buffer with only " +
390+
buffer.limit() + " bytes:" + Hexdump.toHex(buffer));
380391
if (control)
381392
handleControlMessage(command, buffer);
382393
else

core/pva/src/main/java/org/epics/pva/common/UDPHandler.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2019 Oak Ridge National Laboratory.
2+
* Copyright (c) 2019-2022 Oak Ridge National Laboratory.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v1.0
55
* which accompanies this distribution, and is available at
@@ -75,6 +75,9 @@ private void handleMessages(final InetSocketAddress from, final ByteBuffer buffe
7575

7676
final byte version = buffer.get();
7777

78+
// After initial byte-sized header entries,
79+
// adjust buffer byte order as indicated in message header
80+
// to allow decoding of following data (size, payload)
7881
final byte flags = buffer.get();
7982
if ((flags & PVAHeader.FLAG_BIG_ENDIAN) != 0)
8083
buffer.order(ByteOrder.BIG_ENDIAN);

core/pva/src/main/java/org/epics/pva/server/ServerTCPHandler.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,15 @@ public ServerTCPHandler(final PVAServer server, final SocketChannel client) thro
6464
submit((version, buffer) ->
6565
{
6666
logger.log(Level.FINE, () -> "Set byte order " + buffer.order());
67+
// Payload size is used as byte order hint
68+
// 0xFFFFFFFF: Client needs to check each message for byte order
69+
// 0x00000000: Server sends each message in the same byte order,
70+
// but there's still a valid byte order flag,
71+
// so client is free to keep checking each message
72+
final int size_used_as_hint = 0x00000000;
6773
PVAHeader.encodeMessageHeader(buffer,
6874
(byte) (PVAHeader.FLAG_CONTROL | PVAHeader.FLAG_SERVER),
69-
PVAHeader.CTRL_SET_BYTE_ORDER, 0);
75+
PVAHeader.CTRL_SET_BYTE_ORDER, size_used_as_hint);
7076
});
7177
// .. and requesting connection validation
7278
submit((version, buffer) ->

0 commit comments

Comments
 (0)