Socket write (socket_write)
socket_write is an asset in the ocpi.assets.util_comps component library. Implementations include socket_write RCC Worker (socket_write.rcc). Tested platforms include Rocky9, xilinx24_1_aarch32.
Design
The Socket Write component forwards all incoming data to a TCP port or acts as a demultiplexer/router by parsing any protocol and routing different opcodes to various output ports.
The serving/listening TCP ports, along with various ways to determine the Worker’s “done” status, are extremely configurable using Properties.
Note
This Component provides minimal error checking and is not recommended for production use, but is only intended for prototyping and testing of other Components.
A block diagram representation of the implementation is given in Figure 168:
Figure 168: socket_write block diagram.
Interface
<ComponentSpec>
<Port Name="in" numberofopcodes='256'/>
<Port Name="out" numberofopcodes='256' optional='true' producer='true'/>
<!-- Socket to write to -->
<Property name="outSocket" type="Struct" writable="true">
<Member name='address' type='string' stringLength='16' default='0.0.0.0'/>
<Member name='expectedClients' type='ushort' default='0'/>
<Member name='port' type='ushort'/>
<Member name='ports' arrayLength="256" type='ushort'/>
<Member name='messagesInStream' type='bool' arrayLength="256" default='false'/>
</Property>
<!-- Statistics for each opcode -->
<Property name="current" type="Struct" volatile="true">
<Member name="Total" type="Struct">
<Member name="bytes" type="ULongLong"/>
<Member name="messages" type="ULongLong"/>
</Member>
<Member name="Opcode" type="Struct" arrayLength="256">
<Member name="bytes" type="ULongLong"/>
<Member name="messages" type="ULongLong"/>
</Member>
</Property>
<Property name="stopOn" type="Struct" writable="true">
<!-- Stop on TOTAL bytes/messages -->
<Member name="Total" type="Struct">
<Member name="bytes" type="ULongLong"/>
<Member name="messages" type="ULongLong"/>
</Member>
<!-- Stop on bytes/messages with a certain opcode -->
<Member name="Opcode" type="Struct" arrayLength="256">
<Member name="bytes" type="ULongLong"/>
<Member name="messages" type="ULongLong"/>
</Member>
<!-- Stop on bytes/messages with any single unspecified opcode -->
<Member name="Any" type="Struct">
<Member name="bytes" type="ULongLong"/>
<Member name="messages" type="ULongLong"/>
</Member>
<!-- Stop on ZLM for given opcode. To disable, not within 0..255 -->
<Member name='ZLM' type='UShort'/>
</Property>
</ComponentSpec>
Properties
outSocketType:
structMembers:
address:
data_type:
stringstringlength:
16
expectedClients:
data_type:
ushort
port:
data_type:
ushort
ports:
data_type:
ushortarraydimensions:
['256']
messagesInStream:
data_type:
boolarraydimensions:
['256']
Access:
Parameter:
FalseWritable:
TrueInitial:
FalseVolatile:
False
Default value:
None
currentType:
structMembers:
Total:
bytes:
data_type:
ulonglong
messages:
data_type:
ulonglong
Opcode:
bytes:
data_type:
ulonglong
messages:
data_type:
ulonglong
Access:
Parameter:
FalseWritable:
FalseInitial:
FalseVolatile:
True
Default value:
None
stopOnType:
structMembers:
Total:
bytes:
data_type:
ulonglong
messages:
data_type:
ulonglong
Opcode:
bytes:
data_type:
ulonglong
messages:
data_type:
ulonglong
Any:
bytes:
data_type:
ulonglong
messages:
data_type:
ulonglong
ZLM:
data_type:
ushort
Access:
Parameter:
FalseWritable:
TrueInitial:
FalseVolatile:
False
Default value:
None
Ports
Inputs:
inProtocol:
NoneOptional:
False
Outputs:
outProtocol:
NoneOptional:
True
Implementations
socket_write(RCC)
Dependencies
The dependencies to other elements in OpenCPI are:
<assets>/components/util_comps/.rcc/socket_write.cc
<assets>/components/util_comps/.rcc/ ext_src/connection.cpp
<assets>/components/util_comps/.rcc/ ext_src/connection.hpp
<assets>/components/util_comps/.rcc/ ext_src/connection_manager.cpp
<assets>/components/util_comps/.rcc/ ext_src/connection_manager.hpp
<assets>/components/util_comps/.rcc/ ext_src/outbound.hpp
<assets>/components/util_comps/.rcc/ ext_src/server.cpp
<assets>/components/util_comps/.rcc/ ext_src/server.hpp
<assets>/components/util_comps/.rcc/ asio/\*1
Limitations
Limitations of socket_write are:
None.
Testing
Usage (local/x86)
After building the component, the user needs to type make tests RCC_CONTAINERS=1 in the socket_write.test directory. Various properties and data flows will be tested to try to cover as many use cases as possible.
If the user would like to execute only one test, TESTS=test_XX can be added to the end of the command.
Experimental: Usage (remote/ARM)
Full test environment configuration (e.g. NFS mounting, OCPI_CDK_DIR, etc.) on the remote GPP is beyond the scope of this document. The test procedures assume that both shells’ current working directory is the socket_write.test directory (NFS-mounted on remote) and ocpirun is in the remote’s current PATH. NFS must be used for the scripts to properly verify the outputs.
In the host shell, the user types make tests IP=xx.xx.xx.xx. A command that can be copied and then pasted into the remote shell will be displayed. This command should be executed in less than a minute to ensure the test system begins listening before the host times out. The timeout can be changed using the LISTEN_TIMEOUT variable. Once the remote shell returns to the bash prompt, pressing “Enter” on the host will begin the verification process.
Single tests can be performed in the same manner as documented above.
Detailed Theory of Operation
Each test_XX subdirectory has the following files:
description - a one-line description of the test
application.xml - the OAS XML for the test setup
portmap - (optional) list of TCP ports paired to output files
localinclude.mk - (optional) custom
Makefilerules needed for testgolden.md5 - (optional) MD5 checksums of golden/expected output
generate.[sh|pl|py] - (optional) script to generate test data
verify.sh - (optional) script to verify output(s)
Data is sourced with a source component (often pattern or file_read) within the OAS. If the former, the source data is encapsulated in the OAS. When the latter, a generate.py script generates the required data. Most OASs dump the “current” property to a file UUT.current.dump, which is also confirmed to match expected output. Some tests connect a file_write_demux to the out port to verify pass-through operation.
If generate.sh does not exist, a default one is created that will run generate.pl and/or generate.py if they exist and are executable. This default script is removed with make clean.
At test launch, if a file portmap exists, it launches a Python-based utility script busy_loop_socket.py, which opens a client on a given port and repeatedly attempts to connect. Each line is a port number followed by a (relative) file path where the data is written upon successful connection.
If verify.sh does not exist, a default one is created that will ensure the application did not time out and then run md5sum to verify all the checksums listed in golden.md5. This default script is also removed upon make clean.
- 1
Externally provided ASIO library for asynchronous IO with C++, with OpenCPI-specific build system