← Articles
SECS/GEM/6 min read/— views

Why HSMS SystemBytes Uniqueness Is Your Host's Job, Not the Equipment's

A real capture where two HSMS requests share one SystemBytes and the replies come back byte-identical, plus the allocation rules that prevent it.

SECS/GEMMESSCADATroubleshootingChecklists

The host log says timeout and the capture shows the reply arriving on time. That much is a familiar picture. What is different here is that the SystemBytes match exactly. Nothing is out of alignment.

Which leaves one question: which request was that a reply to? If the host had two transactions open under the same SystemBytes, the first reply closes the second request and the second reply has nowhere to go. The one left over waits out its timer and dies. Below is that situation built over a real socket.

Two Linktest.req sent under the same SystemBytes 00 00 07 02 come back as two byte-identical Linktest.rsp HostEquipment Linktest.req 00 00 07 02 Linktest.req 00 00 07 02 Linktest.rsp 00 00 07 02 Linktest.rsp 00 00 07 02 same SystemBytes

The equipment does not check SystemBytes

I opened a socket directly against the simulator's passive listener on 127.0.0.1:5501. First, bring the session up.

TX Select.req     00 00 00 0A 00 0B 00 00 00 01 00 00 07 01
RX Select.rsp     00 00 00 0A 00 0B 00 00 00 02 00 00 07 01

The last four bytes of the header are the SystemBytes. I sent 00 00 07 01 and the same value came back. SEMI E37 requires a reply to carry the request's SystemBytes unchanged. Normal so far.

So what happens with an odd value? I tried 0 and 0xFFFFFFFF.

TX Linktest.req   00 00 00 0A 00 0B 00 00 00 05 00 00 00 00
RX Linktest.rsp   00 00 00 0A 00 0B 00 00 00 06 00 00 00 00

TX Linktest.req   00 00 00 0A 00 0B 00 00 00 05 FF FF FF FF
RX Linktest.rsp   00 00 00 0A 00 0B 00 00 00 06 FF FF FF FF

Both echoed straight back. No refusal, no warning. To this listener the SystemBytes field is something to copy, not something to validate.

Whether E37 reserves any particular value I have not verified — I did not check the clause text against the document. Nor can this capture tell you how a different tool behaves. One thing is settled though: when you write the host, there is no basis for assuming the equipment will filter a bad value for you.

Two requests, one value

On the same socket I sent two Linktest.req back to back with the SystemBytes pinned to 00 00 07 02 on both. I did not wait for the first reply, so both transactions are open at once.

TX Linktest.req A  00 00 00 0A 00 0B 00 00 00 05 00 00 07 02
TX Linktest.req B  00 00 00 0A 00 0B 00 00 00 05 00 00 07 02

RX Linktest.rsp    00 00 00 0A 00 0B 00 00 00 06 00 00 07 02
RX Linktest.rsp    00 00 00 0A 00 0B 00 00 00 06 00 00 07 02

The two replies are byte-identical. Length, SessionID 00 0B, PType, SType 06, SystemBytes — all the same. The equipment log holds two RX entries and two TX entries, exactly as it should. The equipment did what it was told.

The damage is inside the host. Keeping pending transactions in a map keyed on SystemBytes is the common structure, and inserting B overwrites A's slot. The first reply closes B; the second reply finds no matching entry and is dropped without a sound. A never gets an answer and expires on its timer.

The line that reaches the log is "one reply missing". It was not the equipment and it was not the network. The host cut two identical keys.

Allocation rules

  • One counter per connection. Do not split it by stream or by message kind. Select.req, Linktest.req and data messages all draw from the same SystemBytes space. The capture above ran Select and Linktest off one counter.
  • The scope that has to be unique is "among open transactions". A value whose reply has come back is free to reuse. It does not have to be unique across the life of the connection.
  • It is 32 bits, so it wraps. After 0xFFFFFFFF comes 0. There is no need to prevent the wrap — only to check that no open transaction is holding the value you are about to hand out. As the capture shows, 0 and 0xFFFFFFFF are ordinary values as far as the equipment is concerned.
  • Increment atomically. Two threads reading and writing the same counter produce precisely the situation captured above. In practice this is the most common way to get there.
  • Decide whether a reconnect continues the counter or resets it. The socket is closed, so a late reply from the old session cannot arrive on the new one. Either choice works — but if nobody decides, two people implement it differently.

What I did not verify

I did not check clause numbers against E37. That SystemBytes is the identifier binding a request to its reply, and that the reply returns the value unchanged, is in E37. "Must be unique among open transactions" is the condition that rule needs in order to work — it is not a sentence I quoted from the document.

Worth naming the timer, too. The scenario above uses Linktest, a control transaction, so T6 governs it. Move the same mistake onto a data message and it is T3. Telling which one fired is T3, T6, T7 and T8 apart.

Every capture here came from a socket opened against the passive listener in the SECS/GEM simulator. No fault was set. This is what a healthy tool answering correctly looks like. Send two requests under one value and you will know in five minutes what your host stack does with the second reply. If nothing lands in the log at all, that is the worst answer.

A reply that arrives with completely different SystemBytes is a separate problem — that one is the equipment answered and the host logged no reply.