summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorghostop14 <ghostop14@gmail.com>2020-03-04 12:58:09 -0500
committerMartin Braun <martin@gnuradio.org>2020-03-29 21:59:37 -0700
commitcc37c3e8cd5eabcb5c9d919e5fffc5d938690140 (patch)
tree42654449ea975b87aa322dfef81ed21f9bcf838e
parent046793f8d22a774107adabdce02eb65f95b53d2e (diff)
gr-network: Add grnet networking blocks to GNU Radio
This PR is to create a new gr-network structure that includes the grnet TCP and UDP source/sink blocks for inclusion into GNU Radio. This includes new modes (TCP source/sink can act as either a TCP server/listener or a client), and UDP supports multiple new header options for dropped packet detection and integration with external sources such as the Allen Telescope Array. The UDP blocks have a number of important performance and tuning comments in the block documentation to help ensure success with the blocks, and examples for each scenario are included. This PR also deprecates the old TCP/UDP blocks but keeps them in place. The new blocks and new functionality resulted in not a 1:1 drop-in replacement for the old blocks so the old blocks were moved to the deprecated UI group to avoid breaking flowgraphs going to GR 3.9. Some of the new features included in these blocks are: 1. The only TCP block is a sink that listens for inbound connections. This inherently limits the ability to transmit data to another 3rd party application listening for data in TCP server mode. A source block is included here as well. 2. The TCP sink block supports both TCP client and server modes. 3. All blocks (TCP and UDP) support IPv6. 4. UDP blocks now include a variety of header options: None, a 64-bit sequence number that can be used to track dropped packets, CHDR, and the Allen Telescope Array header format for GR-native ATA integration. 5. UDP blocks paired with headers can now notify if any data is lost in transit. 6. UDP blocks now have the option to source 0's (no signal) to allow the flowgraph to run if no incoming data is available. 7. UDP blocks now include a buffering mechanism to ensure data is not lost between different timing domains (network packets and GNU Radio scheduler). 8. Block documentation has been added to help guide users through how to properly configure addresses for IPv6 or dual-stack operations, and tuning / testing before using UDP blocks in a production environment. 9. TCP sink has enhanced work logic to remain running and continue to listen for reconnections if a client disconnects.
-rw-r--r--CMakeLists.txt1
-rw-r--r--gr-blocks/grc/blocks.tree.yml7
-rw-r--r--gr-blocks/grc/blocks_tcp_server_sink.block.yml5
-rw-r--r--gr-blocks/grc/blocks_udp_sink.block.yml5
-rw-r--r--gr-blocks/grc/blocks_udp_source.block.yml5
-rw-r--r--gr-network/CMakeLists.txt62
-rw-r--r--gr-network/apps/CMakeLists.txt14
-rw-r--r--gr-network/docs/CMakeLists.txt11
-rw-r--r--gr-network/docs/README.network11
-rw-r--r--gr-network/examples/CMakeLists.txt24
-rw-r--r--gr-network/examples/test_tcp_sink_client.grc205
-rw-r--r--gr-network/examples/test_tcp_sink_client_ipv6.grc205
-rw-r--r--gr-network/examples/test_tcp_sink_server.grc205
-rw-r--r--gr-network/examples/test_tcp_source.grc184
-rw-r--r--gr-network/examples/test_tcp_source_client.grc218
-rw-r--r--gr-network/examples/test_tcp_source_ipv6.grc184
-rw-r--r--gr-network/examples/test_udp_sink.grc195
-rw-r--r--gr-network/examples/test_udp_sink_ipv6.grc206
-rw-r--r--gr-network/examples/test_udp_sink_seq.grc195
-rw-r--r--gr-network/examples/test_udp_source.grc175
-rw-r--r--gr-network/examples/test_udp_source_ipv6.grc187
-rw-r--r--gr-network/examples/test_udp_source_seq.grc175
-rw-r--r--gr-network/gnuradio-network.pc.in11
-rw-r--r--gr-network/grc/CMakeLists.txt15
-rw-r--r--gr-network/grc/network_tcp_sink.block.yml58
-rw-r--r--gr-network/grc/network_tcp_source.block.yml56
-rw-r--r--gr-network/grc/network_udp_sink.block.yml82
-rw-r--r--gr-network/grc/network_udp_source.block.yml86
-rw-r--r--gr-network/include/gnuradio/network/CMakeLists.txt19
-rw-r--r--gr-network/include/gnuradio/network/api.h22
-rw-r--r--gr-network/include/gnuradio/network/packet_headers.h65
-rw-r--r--gr-network/include/gnuradio/network/tcp_sink.h53
-rw-r--r--gr-network/include/gnuradio/network/udp_header_types.h20
-rw-r--r--gr-network/include/gnuradio/network/udp_sink.h69
-rw-r--r--gr-network/include/gnuradio/network/udp_source.h67
-rw-r--r--gr-network/lib/CMakeLists.txt75
-rw-r--r--gr-network/lib/tcp_sink_impl.cc292
-rw-r--r--gr-network/lib/tcp_sink_impl.h75
-rw-r--r--gr-network/lib/udp_sink_impl.cc270
-rw-r--r--gr-network/lib/udp_sink_impl.h80
-rw-r--r--gr-network/lib/udp_source_impl.cc375
-rw-r--r--gr-network/lib/udp_source_impl.h85
-rw-r--r--gr-network/python/network/CMakeLists.txt33
-rw-r--r--gr-network/python/network/__init__.py20
-rw-r--r--gr-network/python/network/tcp_source.py86
-rw-r--r--gr-network/swig/CMakeLists.txt43
-rw-r--r--gr-network/swig/network_swig.i21
47 files changed, 4551 insertions, 6 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 066e973f6a..1bed494ea5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -499,6 +499,7 @@ add_subdirectory(gr-video-sdl)
add_subdirectory(gr-vocoder)
add_subdirectory(gr-wavelet)
add_subdirectory(gr-zeromq)
+add_subdirectory(gr-network)
# Defining GR_CTRLPORT for gnuradio/config.h
if(ENABLE_GR_CTRLPORT)
diff --git a/gr-blocks/grc/blocks.tree.yml b/gr-blocks/grc/blocks.tree.yml
index 2c05555883..f4a8ad8cd9 100644
--- a/gr-blocks/grc/blocks.tree.yml
+++ b/gr-blocks/grc/blocks.tree.yml
@@ -29,6 +29,10 @@
- blocks_message_strobe_random
- blocks_tags_strobe
- blocks_test_tag_variable_rate_ff
+- Deprecated:
+ - blocks_tcp_server_sink
+ - blocks_udp_source
+ - blocks_udp_sink
- File Operators:
- blocks_wavfile_source
- blocks_wavfile_sink
@@ -112,9 +116,6 @@
- Networking Tools:
- blocks_tuntap_pdu
- blocks_socket_pdu
- - blocks_tcp_server_sink
- - blocks_udp_source
- - blocks_udp_sink
- Peak Detectors:
- blocks_burst_tagger
- blocks_peak_detector_xb
diff --git a/gr-blocks/grc/blocks_tcp_server_sink.block.yml b/gr-blocks/grc/blocks_tcp_server_sink.block.yml
index 4069be8588..32c5a8043b 100644
--- a/gr-blocks/grc/blocks_tcp_server_sink.block.yml
+++ b/gr-blocks/grc/blocks_tcp_server_sink.block.yml
@@ -1,5 +1,5 @@
id: blocks_tcp_server_sink
-label: TCP Server Sink
+label: TCP Server Sink (Deprecated)
flags: [ python, cpp ]
parameters:
@@ -48,4 +48,7 @@ cpp_templates:
'True': 'true'
'False': 'false'
+documentation: |-
+ This block has been deprecated and replaced with more capable TCP source/sink blocks in Networking Tools.
+
file_format: 1
diff --git a/gr-blocks/grc/blocks_udp_sink.block.yml b/gr-blocks/grc/blocks_udp_sink.block.yml
index 3afcc44845..e000ba6f57 100644
--- a/gr-blocks/grc/blocks_udp_sink.block.yml
+++ b/gr-blocks/grc/blocks_udp_sink.block.yml
@@ -1,5 +1,5 @@
id: blocks_udp_sink
-label: UDP Sink
+label: UDP Sink (Deprecated)
flags: [ python, cpp ]
parameters:
@@ -51,4 +51,7 @@ cpp_templates:
'True': 'true'
'False': 'false'
+documentation: |-
+ This block has been deprecated and replaced with a more capable UDP sink block in Networking Tools.
+
file_format: 1
diff --git a/gr-blocks/grc/blocks_udp_source.block.yml b/gr-blocks/grc/blocks_udp_source.block.yml
index 45e7bf7db7..c5e1226527 100644
--- a/gr-blocks/grc/blocks_udp_source.block.yml
+++ b/gr-blocks/grc/blocks_udp_source.block.yml
@@ -1,5 +1,5 @@
id: blocks_udp_source
-label: UDP Source
+label: UDP Source (Deprecated)
flags: [ throttle, python, cpp ]
parameters:
@@ -53,4 +53,7 @@ cpp_templates:
'True': 'true'
'False': 'false'
+documentation: |-
+ This block has been deprecated and replaced with a more capable UDP source block in Networking Tools.
+
file_format: 1
diff --git a/gr-network/CMakeLists.txt b/gr-network/CMakeLists.txt
new file mode 100644
index 0000000000..475a2bf9aa
--- /dev/null
+++ b/gr-network/CMakeLists.txt
@@ -0,0 +1,62 @@
+# Copyright 2020 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+
+########################################################################
+# Setup dependencies
+########################################################################
+include(GrBoost)
+
+########################################################################
+# Register component
+########################################################################
+include(GrComponent)
+GR_REGISTER_COMPONENT("gr-network" ENABLE_GR_NETWORK
+ Boost_FOUND
+ ENABLE_VOLK
+ ENABLE_GNURADIO_RUNTIME
+)
+
+SET(GR_PKG_NETWORK_EXAMPLES_DIR ${GR_PKG_DATA_DIR}/examples/network)
+
+
+########################################################################
+# Begin conditional configuration
+########################################################################
+if(ENABLE_GR_NETWORK)
+
+########################################################################
+# Add subdirectories
+########################################################################
+add_subdirectory(include/gnuradio/network)
+add_subdirectory(lib)
+#if(ENABLE_TESTING)
+# add_subdirectory(tests)
+#endif(ENABLE_TESTING)
+if(ENABLE_PYTHON)
+ add_subdirectory(python/network)
+ add_subdirectory(swig)
+ add_subdirectory(docs)
+ add_subdirectory(examples)
+endif(ENABLE_PYTHON)
+if(ENABLE_GRC)
+ add_subdirectory(grc)
+endif(ENABLE_GRC)
+
+########################################################################
+# Create Pkg Config File
+########################################################################
+configure_file(
+ ${CMAKE_CURRENT_SOURCE_DIR}/gnuradio-network.pc.in
+ ${CMAKE_CURRENT_BINARY_DIR}/gnuradio-network.pc
+@ONLY)
+
+install(
+ FILES ${CMAKE_CURRENT_BINARY_DIR}/gnuradio-network.pc
+ DESTINATION ${GR_LIBRARY_DIR}/pkgconfig
+)
+
+endif(ENABLE_GR_NETWORK)
diff --git a/gr-network/apps/CMakeLists.txt b/gr-network/apps/CMakeLists.txt
new file mode 100644
index 0000000000..c580a91d06
--- /dev/null
+++ b/gr-network/apps/CMakeLists.txt
@@ -0,0 +1,14 @@
+# Copyright 2020 Free Software Foundation, Inc.
+#
+# This file was generated by gr_modtool, a tool from the GNU Radio framework
+# This file is a part of gr-network
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+
+include(GrPython)
+
+GR_PYTHON_INSTALL(
+ PROGRAMS
+ DESTINATION bin
+)
diff --git a/gr-network/docs/CMakeLists.txt b/gr-network/docs/CMakeLists.txt
new file mode 100644
index 0000000000..8cd76763ed
--- /dev/null
+++ b/gr-network/docs/CMakeLists.txt
@@ -0,0 +1,11 @@
+# Copyright 2020 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+
+install(
+ FILES README.network
+ DESTINATION ${GR_PKG_DOC_DIR}
+)
diff --git a/gr-network/docs/README.network b/gr-network/docs/README.network
new file mode 100644
index 0000000000..43617f62b5
--- /dev/null
+++ b/gr-network/docs/README.network
@@ -0,0 +1,11 @@
+This is the GNU Radio network package. It contains the blocks that
+implement UDP and TCP source and sink blocks supporting both IPv4
+and IPv6. To use the network blocks, the Python namespace
+is in 'network', which is imported as:
+
+ from gnuradio import network
+
+A quick listing of the details can be found in Python after
+importing by using:
+
+ help(network)
diff --git a/gr-network/examples/CMakeLists.txt b/gr-network/examples/CMakeLists.txt
new file mode 100644
index 0000000000..d4d0af7a74
--- /dev/null
+++ b/gr-network/examples/CMakeLists.txt
@@ -0,0 +1,24 @@
+# Copyright 2020 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+
+include(GrPython)
+
+install(
+ FILES
+ test_tcp_sink_client.grc
+ test_tcp_sink_client_ipv6.grc
+ test_tcp_sink_server.grc
+ test_tcp_source.grc
+ test_tcp_source_ipv6.grc
+ test_udp_sink.grc
+ test_udp_sink_ipv6.grc
+ test_udp_sink_seq.grc
+ test_udp_source.grc
+ test_udp_source_ipv6.grc
+ test_udp_source_seq.grc
+ DESTINATION ${GR_PKG_NETWORK_EXAMPLES_DIR}
+)
diff --git a/gr-network/examples/test_tcp_sink_client.grc b/gr-network/examples/test_tcp_sink_client.grc
new file mode 100644
index 0000000000..6fce7b798d
--- /dev/null
+++ b/gr-network/examples/test_tcp_sink_client.grc
@@ -0,0 +1,205 @@
+options:
+ parameters:
+ author: ''
+ catch_exceptions: 'True'
+ category: '[GRC Hier Blocks]'
+ cmake_opt: ''
+ comment: ''
+ copyright: ''
+ description: ''
+ gen_cmake: 'On'
+ gen_linking: dynamic
+ generate_options: qt_gui
+ hier_block_src_path: '.:'
+ id: test_tcp_sink_client
+ max_nouts: '0'
+ output_language: python
+ placement: (0,0)
+ qt_qss_theme: ''
+ realtime_scheduling: ''
+ run: 'True'
+ run_command: '{python} -u {filename}'
+ run_options: prompt
+ sizing_mode: fixed
+ thread_safe_setters: ''
+ title: ''
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [8, 8]
+ rotation: 0
+ state: enabled
+
+blocks:
+- name: center_freq
+ id: variable
+ parameters:
+ comment: ''
+ value: 1691e6
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [216, 28]
+ rotation: 0
+ state: enabled
+- name: samp_rate
+ id: variable
+ parameters:
+ comment: ''
+ value: 1e6
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [8, 160]
+ rotation: 0
+ state: enabled
+- name: analog_sig_source_x_0
+ id: analog_sig_source_x
+ parameters:
+ affinity: ''
+ alias: ''
+ amp: '1'
+ comment: ''
+ freq: '1000'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ offset: '0'
+ phase: '0'
+ samp_rate: samp_rate
+ type: complex
+ waveform: analog.GR_COS_WAVE
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [136, 268]
+ rotation: 0
+ state: enabled
+- name: blocks_throttle_0
+ id: blocks_throttle
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ ignoretag: 'True'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ samples_per_second: samp_rate
+ type: complex
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [424, 300]
+ rotation: 0
+ state: enabled
+- name: network_tcp_sink_0
+ id: network_tcp_sink
+ parameters:
+ addr: 127.0.0.1
+ affinity: ''
+ alias: ''
+ comment: ''
+ mode: '1'
+ port: '2000'
+ type: complex
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [656, 285]
+ rotation: 0
+ state: true
+- name: qtgui_freq_sink_x_0
+ id: qtgui_freq_sink_x
+ parameters:
+ affinity: ''
+ alias: ''
+ alpha1: '1.0'
+ alpha10: '1.0'
+ alpha2: '1.0'
+ alpha3: '1.0'
+ alpha4: '1.0'
+ alpha5: '1.0'
+ alpha6: '1.0'
+ alpha7: '1.0'
+ alpha8: '1.0'
+ alpha9: '1.0'
+ autoscale: 'False'
+ average: '1.0'
+ axislabels: 'True'
+ bw: samp_rate
+ color1: '"blue"'
+ color10: '"dark blue"'
+ color2: '"red"'
+ color3: '"green"'
+ color4: '"black"'
+ color5: '"cyan"'
+ color6: '"magenta"'
+ color7: '"yellow"'
+ color8: '"dark red"'
+ color9: '"dark green"'
+ comment: ''
+ ctrlpanel: 'False'
+ fc: '0'
+ fftsize: '1024'
+ freqhalf: 'True'
+ grid: 'False'
+ gui_hint: ''
+ label: Relative Gain
+ label1: ''
+ label10: ''
+ label2: ''
+ label3: ''
+ label4: ''
+ label5: ''
+ label6: ''
+ label7: ''
+ label8: ''
+ label9: ''
+ legend: 'True'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ name: '""'
+ nconnections: '1'
+ showports: 'True'
+ tr_chan: '0'
+ tr_level: '0.0'
+ tr_mode: qtgui.TRIG_MODE_FREE
+ tr_tag: '""'
+ type: complex
+ units: dB
+ update_time: '0.10'
+ width1: '1'
+ width10: '1'
+ width2: '1'
+ width3: '1'
+ width4: '1'
+ width5: '1'
+ width6: '1'
+ width7: '1'
+ width8: '1'
+ width9: '1'
+ wintype: firdes.WIN_BLACKMAN_hARRIS
+ ymax: '10'
+ ymin: '-140'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [552, 36]
+ rotation: 0
+ state: enabled
+
+connections:
+- [analog_sig_source_x_0, '0', blocks_throttle_0, '0']
+- [blocks_throttle_0, '0', network_tcp_sink_0, '0']
+- [blocks_throttle_0, '0', qtgui_freq_sink_x_0, '0']
+
+metadata:
+ file_format: 1
diff --git a/gr-network/examples/test_tcp_sink_client_ipv6.grc b/gr-network/examples/test_tcp_sink_client_ipv6.grc
new file mode 100644
index 0000000000..9801dff771
--- /dev/null
+++ b/gr-network/examples/test_tcp_sink_client_ipv6.grc
@@ -0,0 +1,205 @@
+options:
+ parameters:
+ author: ''
+ catch_exceptions: 'True'
+ category: '[GRC Hier Blocks]'
+ cmake_opt: ''
+ comment: ''
+ copyright: ''
+ description: ''
+ gen_cmake: 'On'
+ gen_linking: dynamic
+ generate_options: qt_gui
+ hier_block_src_path: '.:'
+ id: test_tcp_sink_client
+ max_nouts: '0'
+ output_language: python
+ placement: (0,0)
+ qt_qss_theme: ''
+ realtime_scheduling: ''
+ run: 'True'
+ run_command: '{python} -u {filename}'
+ run_options: prompt
+ sizing_mode: fixed
+ thread_safe_setters: ''
+ title: ''
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [8, 8]
+ rotation: 0
+ state: enabled
+
+blocks:
+- name: center_freq
+ id: variable
+ parameters:
+ comment: ''
+ value: 1691e6
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [216, 28]
+ rotation: 0
+ state: enabled
+- name: samp_rate
+ id: variable
+ parameters:
+ comment: ''
+ value: 1e6
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [8, 160]
+ rotation: 0
+ state: enabled
+- name: analog_sig_source_x_0
+ id: analog_sig_source_x
+ parameters:
+ affinity: ''
+ alias: ''
+ amp: '1'
+ comment: ''
+ freq: '1000'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ offset: '0'
+ phase: '0'
+ samp_rate: samp_rate
+ type: complex
+ waveform: analog.GR_COS_WAVE
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [136, 268]
+ rotation: 0
+ state: enabled
+- name: blocks_throttle_0
+ id: blocks_throttle
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ ignoretag: 'True'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ samples_per_second: samp_rate
+ type: complex
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [424, 300]
+ rotation: 0
+ state: enabled
+- name: network_tcp_sink_0
+ id: network_tcp_sink
+ parameters:
+ addr: ::1
+ affinity: ''
+ alias: ''
+ comment: ''
+ mode: '1'
+ port: '2000'
+ type: complex
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [650, 283]
+ rotation: 0
+ state: true
+- name: qtgui_freq_sink_x_0
+ id: qtgui_freq_sink_x
+ parameters:
+ affinity: ''
+ alias: ''
+ alpha1: '1.0'
+ alpha10: '1.0'
+ alpha2: '1.0'
+ alpha3: '1.0'
+ alpha4: '1.0'
+ alpha5: '1.0'
+ alpha6: '1.0'
+ alpha7: '1.0'
+ alpha8: '1.0'
+ alpha9: '1.0'
+ autoscale: 'False'
+ average: '1.0'
+ axislabels: 'True'
+ bw: samp_rate
+ color1: '"blue"'
+ color10: '"dark blue"'
+ color2: '"red"'
+ color3: '"green"'
+ color4: '"black"'
+ color5: '"cyan"'
+ color6: '"magenta"'
+ color7: '"yellow"'
+ color8: '"dark red"'
+ color9: '"dark green"'
+ comment: ''
+ ctrlpanel: 'False'
+ fc: '0'
+ fftsize: '1024'
+ freqhalf: 'True'
+ grid: 'False'
+ gui_hint: ''
+ label: Relative Gain
+ label1: ''
+ label10: ''
+ label2: ''
+ label3: ''
+ label4: ''
+ label5: ''
+ label6: ''
+ label7: ''
+ label8: ''
+ label9: ''
+ legend: 'True'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ name: '""'
+ nconnections: '1'
+ showports: 'True'
+ tr_chan: '0'
+ tr_level: '0.0'
+ tr_mode: qtgui.TRIG_MODE_FREE
+ tr_tag: '""'
+ type: complex
+ units: dB
+ update_time: '0.10'
+ width1: '1'
+ width10: '1'
+ width2: '1'
+ width3: '1'
+ width4: '1'
+ width5: '1'
+ width6: '1'
+ width7: '1'
+ width8: '1'
+ width9: '1'
+ wintype: firdes.WIN_BLACKMAN_hARRIS
+ ymax: '10'
+ ymin: '-140'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [552, 36]
+ rotation: 0
+ state: enabled
+
+connections:
+- [analog_sig_source_x_0, '0', blocks_throttle_0, '0']
+- [blocks_throttle_0, '0', network_tcp_sink_0, '0']
+- [blocks_throttle_0, '0', qtgui_freq_sink_x_0, '0']
+
+metadata:
+ file_format: 1
diff --git a/gr-network/examples/test_tcp_sink_server.grc b/gr-network/examples/test_tcp_sink_server.grc
new file mode 100644
index 0000000000..7dace9f652
--- /dev/null
+++ b/gr-network/examples/test_tcp_sink_server.grc
@@ -0,0 +1,205 @@
+options:
+ parameters:
+ author: ''
+ catch_exceptions: 'True'
+ category: '[GRC Hier Blocks]'
+ cmake_opt: ''
+ comment: ''
+ copyright: ''
+ description: ''
+ gen_cmake: 'On'
+ gen_linking: dynamic
+ generate_options: qt_gui
+ hier_block_src_path: '.:'
+ id: test_tcp_sink_server
+ max_nouts: '0'
+ output_language: python
+ placement: (0,0)
+ qt_qss_theme: ''
+ realtime_scheduling: ''
+ run: 'True'
+ run_command: '{python} -u {filename}'
+ run_options: prompt
+ sizing_mode: fixed
+ thread_safe_setters: ''
+ title: ''
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [8, 8]
+ rotation: 0
+ state: enabled
+
+blocks:
+- name: center_freq
+ id: variable
+ parameters:
+ comment: ''
+ value: 1691e6
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [216, 28]
+ rotation: 0
+ state: enabled
+- name: samp_rate
+ id: variable
+ parameters:
+ comment: ''
+ value: 1e6
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [8, 160]
+ rotation: 0
+ state: enabled
+- name: analog_sig_source_x_0
+ id: analog_sig_source_x
+ parameters:
+ affinity: ''
+ alias: ''
+ amp: '1'
+ comment: ''
+ freq: '1000'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ offset: '0'
+ phase: '0'
+ samp_rate: samp_rate
+ type: complex
+ waveform: analog.GR_COS_WAVE
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [152, 268]
+ rotation: 0
+ state: enabled
+- name: blocks_throttle_0
+ id: blocks_throttle
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ ignoretag: 'True'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ samples_per_second: samp_rate
+ type: complex
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [424, 300]
+ rotation: 0
+ state: enabled
+- name: network_tcp_sink_1
+ id: network_tcp_sink
+ parameters:
+ addr: 127.0.0.1
+ affinity: ''
+ alias: ''
+ comment: ''
+ mode: '2'
+ port: '2000'
+ type: complex
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [630, 293]
+ rotation: 0
+ state: true
+- name: qtgui_freq_sink_x_0
+ id: qtgui_freq_sink_x
+ parameters:
+ affinity: ''
+ alias: ''
+ alpha1: '1.0'
+ alpha10: '1.0'
+ alpha2: '1.0'
+ alpha3: '1.0'
+ alpha4: '1.0'
+ alpha5: '1.0'
+ alpha6: '1.0'
+ alpha7: '1.0'
+ alpha8: '1.0'
+ alpha9: '1.0'
+ autoscale: 'False'
+ average: '1.0'
+ axislabels: 'True'
+ bw: samp_rate
+ color1: '"blue"'
+ color10: '"dark blue"'
+ color2: '"red"'
+ color3: '"green"'
+ color4: '"black"'
+ color5: '"cyan"'
+ color6: '"magenta"'
+ color7: '"yellow"'
+ color8: '"dark red"'
+ color9: '"dark green"'
+ comment: ''
+ ctrlpanel: 'False'
+ fc: '0'
+ fftsize: '1024'
+ freqhalf: 'True'
+ grid: 'False'
+ gui_hint: ''
+ label: Relative Gain
+ label1: ''
+ label10: ''
+ label2: ''
+ label3: ''
+ label4: ''
+ label5: ''
+ label6: ''
+ label7: ''
+ label8: ''
+ label9: ''
+ legend: 'True'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ name: '""'
+ nconnections: '1'
+ showports: 'True'
+ tr_chan: '0'
+ tr_level: '0.0'
+ tr_mode: qtgui.TRIG_MODE_FREE
+ tr_tag: '""'
+ type: complex
+ units: dB
+ update_time: '0.10'
+ width1: '1'
+ width10: '1'
+ width2: '1'
+ width3: '1'
+ width4: '1'
+ width5: '1'
+ width6: '1'
+ width7: '1'
+ width8: '1'
+ width9: '1'
+ wintype: firdes.WIN_BLACKMAN_hARRIS
+ ymax: '10'
+ ymin: '-140'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [552, 36]
+ rotation: 0
+ state: enabled
+
+connections:
+- [analog_sig_source_x_0, '0', blocks_throttle_0, '0']
+- [blocks_throttle_0, '0', network_tcp_sink_1, '0']
+- [blocks_throttle_0, '0', qtgui_freq_sink_x_0, '0']
+
+metadata:
+ file_format: 1
diff --git a/gr-network/examples/test_tcp_source.grc b/gr-network/examples/test_tcp_source.grc
new file mode 100644
index 0000000000..f65de7a26e
--- /dev/null
+++ b/gr-network/examples/test_tcp_source.grc
@@ -0,0 +1,184 @@
+options:
+ parameters:
+ author: ''
+ catch_exceptions: 'True'
+ category: '[GRC Hier Blocks]'
+ cmake_opt: ''
+ comment: ''
+ copyright: ''
+ description: ''
+ gen_cmake: 'On'
+ gen_linking: dynamic
+ generate_options: qt_gui
+ hier_block_src_path: '.:'
+ id: test_tcp_source
+ max_nouts: '0'
+ output_language: python
+ placement: (0,0)
+ qt_qss_theme: ''
+ realtime_scheduling: ''
+ run: 'True'
+ run_command: '{python} -u {filename}'
+ run_options: prompt
+ sizing_mode: fixed
+ thread_safe_setters: ''
+ title: ''
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [8, 8]
+ rotation: 0
+ state: enabled
+
+blocks:
+- name: center_freq
+ id: variable
+ parameters:
+ comment: ''
+ value: 1691e6
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [216, 28]
+ rotation: 0
+ state: enabled
+- name: samp_rate
+ id: variable
+ parameters:
+ comment: ''
+ value: 1e6
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [8, 160]
+ rotation: 0
+ state: enabled
+- name: blocks_throttle_0
+ id: blocks_throttle
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ ignoretag: 'True'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ samples_per_second: samp_rate
+ type: complex
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [424, 300]
+ rotation: 0
+ state: enabled
+- name: network_tcp_source_0
+ id: network_tcp_source
+ parameters:
+ addr: 127.0.0.1
+ affinity: ''
+ alias: ''
+ comment: ''
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ port: '2000'
+ server: 'False'
+ type: complex
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [200, 284]
+ rotation: 0
+ state: true
+- name: qtgui_freq_sink_x_0
+ id: qtgui_freq_sink_x
+ parameters:
+ affinity: ''
+ alias: ''
+ alpha1: '1.0'
+ alpha10: '1.0'
+ alpha2: '1.0'
+ alpha3: '1.0'
+ alpha4: '1.0'
+ alpha5: '1.0'
+ alpha6: '1.0'
+ alpha7: '1.0'
+ alpha8: '1.0'
+ alpha9: '1.0'
+ autoscale: 'False'
+ average: '1.0'
+ axislabels: 'True'
+ bw: samp_rate
+ color1: '"blue"'
+ color10: '"dark blue"'
+ color2: '"red"'
+ color3: '"green"'
+ color4: '"black"'
+ color5: '"cyan"'
+ color6: '"magenta"'
+ color7: '"yellow"'
+ color8: '"dark red"'
+ color9: '"dark green"'
+ comment: ''
+ ctrlpanel: 'False'
+ fc: '0'
+ fftsize: '2048'
+ freqhalf: 'True'
+ grid: 'True'
+ gui_hint: ''
+ label: Relative Gain
+ label1: ''
+ label10: ''
+ label2: ''
+ label3: ''
+ label4: ''
+ label5: ''
+ label6: ''
+ label7: ''
+ label8: ''
+ label9: ''
+ legend: 'True'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ name: '""'
+ nconnections: '1'
+ showports: 'True'
+ tr_chan: '0'
+ tr_level: '0.0'
+ tr_mode: qtgui.TRIG_MODE_FREE
+ tr_tag: '""'
+ type: complex
+ units: dB
+ update_time: '0.10'
+ width1: '1'
+ width10: '1'
+ width2: '1'
+ width3: '1'
+ width4: '1'
+ width5: '1'
+ width6: '1'
+ width7: '1'
+ width8: '1'
+ width9: '1'
+ wintype: firdes.WIN_BLACKMAN_hARRIS
+ ymax: '-30'
+ ymin: '-140'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [632, 284]
+ rotation: 0
+ state: enabled
+
+connections:
+- [blocks_throttle_0, '0', qtgui_freq_sink_x_0, '0']
+- [network_tcp_source_0, '0', blocks_throttle_0, '0']
+
+metadata:
+ file_format: 1
diff --git a/gr-network/examples/test_tcp_source_client.grc b/gr-network/examples/test_tcp_source_client.grc
new file mode 100644
index 0000000000..d2a9049daa
--- /dev/null
+++ b/gr-network/examples/test_tcp_source_client.grc
@@ -0,0 +1,218 @@
+options:
+ parameters:
+ author: ''
+ catch_exceptions: 'True'
+ category: '[GRC Hier Blocks]'
+ cmake_opt: ''
+ comment: ''
+ copyright: ''
+ description: ''
+ gen_cmake: 'On'
+ gen_linking: dynamic
+ generate_options: qt_gui
+ hier_block_src_path: '.:'
+ id: test_tcp_source_client
+ max_nouts: '0'
+ output_language: python
+ placement: (0,0)
+ qt_qss_theme: ''
+ realtime_scheduling: ''
+ run: 'True'
+ run_command: '{python} -u {filename}'
+ run_options: prompt
+ sizing_mode: fixed
+ thread_safe_setters: ''
+ title: ''
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [8, 8]
+ rotation: 0
+ state: enabled
+
+blocks:
+- name: center_freq
+ id: variable
+ parameters:
+ comment: ''
+ value: 1691e6
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [216, 28]
+ rotation: 0
+ state: enabled
+- name: samp_rate
+ id: variable
+ parameters:
+ comment: ''
+ value: 1e6
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [8, 160]
+ rotation: 0
+ state: enabled
+- name: blocks_message_debug_0
+ id: blocks_message_debug
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [888, 152]
+ rotation: 0
+ state: disabled
+- name: blocks_probe_rate_0
+ id: blocks_probe_rate
+ parameters:
+ affinity: ''
+ alias: ''
+ alpha: '0.15'
+ comment: ''
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ mintime: '500.0'
+ type: complex
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [616, 140]
+ rotation: 0
+ state: disabled
+- name: blocks_throttle_0
+ id: blocks_throttle
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ ignoretag: 'True'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ samples_per_second: samp_rate
+ type: complex
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [424, 300]
+ rotation: 0
+ state: enabled
+- name: grnet_tcp_source_0
+ id: grnet_tcp_source
+ parameters:
+ addr: 127.0.0.1
+ affinity: ''
+ alias: ''
+ comment: ''
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ port: '2000'
+ server: 'False'
+ type: complex
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [192, 260]
+ rotation: 0
+ state: enabled
+- name: qtgui_freq_sink_x_0
+ id: qtgui_freq_sink_x
+ parameters:
+ affinity: ''
+ alias: ''
+ alpha1: '1.0'
+ alpha10: '1.0'
+ alpha2: '1.0'
+ alpha3: '1.0'
+ alpha4: '1.0'
+ alpha5: '1.0'
+ alpha6: '1.0'
+ alpha7: '1.0'
+ alpha8: '1.0'
+ alpha9: '1.0'
+ autoscale: 'False'
+ average: '1.0'
+ axislabels: 'True'
+ bw: samp_rate
+ color1: '"blue"'
+ color10: '"dark blue"'
+ color2: '"red"'
+ color3: '"green"'
+ color4: '"black"'
+ color5: '"cyan"'
+ color6: '"magenta"'
+ color7: '"yellow"'
+ color8: '"dark red"'
+ color9: '"dark green"'
+ comment: ''
+ ctrlpanel: 'False'
+ fc: '0'
+ fftsize: '2048'
+ freqhalf: 'True'
+ grid: 'True'
+ gui_hint: ''
+ label: Relative Gain
+ label1: ''
+ label10: ''
+ label2: ''
+ label3: ''
+ label4: ''
+ label5: ''
+ label6: ''
+ label7: ''
+ label8: ''
+ label9: ''
+ legend: 'True'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ name: '""'
+ nconnections: '1'
+ showports: 'True'
+ tr_chan: '0'
+ tr_level: '0.0'
+ tr_mode: qtgui.TRIG_MODE_FREE
+ tr_tag: '""'
+ type: complex
+ units: dB
+ update_time: '0.10'
+ width1: '1'
+ width10: '1'
+ width2: '1'
+ width3: '1'
+ width4: '1'
+ width5: '1'
+ width6: '1'
+ width7: '1'
+ width8: '1'
+ width9: '1'
+ wintype: firdes.WIN_BLACKMAN_hARRIS
+ ymax: '-30'
+ ymin: '-140'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [632, 284]
+ rotation: 0
+ state: enabled
+
+connections:
+- [blocks_probe_rate_0, rate, blocks_message_debug_0, print]
+- [blocks_throttle_0, '0', blocks_probe_rate_0, '0']
+- [blocks_throttle_0, '0', qtgui_freq_sink_x_0, '0']
+- [grnet_tcp_source_0, '0', blocks_throttle_0, '0']
+
+metadata:
+ file_format: 1
diff --git a/gr-network/examples/test_tcp_source_ipv6.grc b/gr-network/examples/test_tcp_source_ipv6.grc
new file mode 100644
index 0000000000..8fa15abdfb
--- /dev/null
+++ b/gr-network/examples/test_tcp_source_ipv6.grc
@@ -0,0 +1,184 @@
+options:
+ parameters:
+ author: ''
+ catch_exceptions: 'True'
+ category: '[GRC Hier Blocks]'
+ cmake_opt: ''
+ comment: ''
+ copyright: ''
+ description: ''
+ gen_cmake: 'On'
+ gen_linking: dynamic
+ generate_options: qt_gui
+ hier_block_src_path: '.:'
+ id: test_tcp_source6
+ max_nouts: '0'
+ output_language: python
+ placement: (0,0)
+ qt_qss_theme: ''
+ realtime_scheduling: ''
+ run: 'True'
+ run_command: '{python} -u {filename}'
+ run_options: prompt
+ sizing_mode: fixed
+ thread_safe_setters: ''
+ title: ''
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [8, 8]
+ rotation: 0
+ state: enabled
+
+blocks:
+- name: center_freq
+ id: variable
+ parameters:
+ comment: ''
+ value: 1691e6
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [216, 28]
+ rotation: 0
+ state: enabled
+- name: samp_rate
+ id: variable
+ parameters:
+ comment: ''
+ value: 1e6
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [8, 160]
+ rotation: 0
+ state: enabled
+- name: blocks_throttle_0
+ id: blocks_throttle
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ ignoretag: 'True'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ samples_per_second: samp_rate
+ type: complex
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [424, 300]
+ rotation: 0
+ state: enabled
+- name: network_tcp_source_0
+ id: network_tcp_source
+ parameters:
+ addr: '::'
+ affinity: ''
+ alias: ''
+ comment: ''
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ port: '2000'
+ server: 'True'
+ type: complex
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [232, 284]
+ rotation: 0
+ state: true
+- name: qtgui_freq_sink_x_0
+ id: qtgui_freq_sink_x
+ parameters:
+ affinity: ''
+ alias: ''
+ alpha1: '1.0'
+ alpha10: '1.0'
+ alpha2: '1.0'
+ alpha3: '1.0'
+ alpha4: '1.0'
+ alpha5: '1.0'
+ alpha6: '1.0'
+ alpha7: '1.0'
+ alpha8: '1.0'
+ alpha9: '1.0'
+ autoscale: 'False'
+ average: '1.0'
+ axislabels: 'True'
+ bw: samp_rate
+ color1: '"blue"'
+ color10: '"dark blue"'
+ color2: '"red"'
+ color3: '"green"'
+ color4: '"black"'
+ color5: '"cyan"'
+ color6: '"magenta"'
+ color7: '"yellow"'
+ color8: '"dark red"'
+ color9: '"dark green"'
+ comment: ''
+ ctrlpanel: 'False'
+ fc: '0'
+ fftsize: '2048'
+ freqhalf: 'True'
+ grid: 'True'
+ gui_hint: ''
+ label: Relative Gain
+ label1: ''
+ label10: ''
+ label2: ''
+ label3: ''
+ label4: ''
+ label5: ''
+ label6: ''
+ label7: ''
+ label8: ''
+ label9: ''
+ legend: 'True'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ name: '""'
+ nconnections: '1'
+ showports: 'True'
+ tr_chan: '0'
+ tr_level: '0.0'
+ tr_mode: qtgui.TRIG_MODE_FREE
+ tr_tag: '""'
+ type: complex
+ units: dB
+ update_time: '0.10'
+ width1: '1'
+ width10: '1'
+ width2: '1'
+ width3: '1'
+ width4: '1'
+ width5: '1'
+ width6: '1'
+ width7: '1'
+ width8: '1'
+ width9: '1'
+ wintype: firdes.WIN_BLACKMAN_hARRIS
+ ymax: '-30'
+ ymin: '-140'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [632, 284]
+ rotation: 0
+ state: enabled
+
+connections:
+- [blocks_throttle_0, '0', qtgui_freq_sink_x_0, '0']
+- [network_tcp_source_0, '0', blocks_throttle_0, '0']
+
+metadata:
+ file_format: 1
diff --git a/gr-network/examples/test_udp_sink.grc b/gr-network/examples/test_udp_sink.grc
new file mode 100644
index 0000000000..4bdc68172e
--- /dev/null
+++ b/gr-network/examples/test_udp_sink.grc
@@ -0,0 +1,195 @@
+options:
+ parameters:
+ author: ''
+ catch_exceptions: 'True'
+ category: '[GRC Hier Blocks]'
+ cmake_opt: ''
+ comment: ''
+ copyright: ''
+ description: ''
+ gen_cmake: 'On'
+ gen_linking: dynamic
+ generate_options: qt_gui
+ hier_block_src_path: '.:'
+ id: test_udp_sink
+ max_nouts: '0'
+ output_language: python
+ placement: (0,0)
+ qt_qss_theme: ''
+ realtime_scheduling: ''
+ run: 'True'
+ run_command: '{python} -u {filename}'
+ run_options: prompt
+ sizing_mode: fixed
+ thread_safe_setters: ''
+ title: ''
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [8, 8]
+ rotation: 0
+ state: enabled
+
+blocks:
+- name: samp_rate
+ id: variable
+ parameters:
+ comment: ''
+ value: 1e6
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [188, 14]
+ rotation: 0
+ state: enabled
+- name: analog_sig_source_x_0
+ id: analog_sig_source_x
+ parameters:
+ affinity: ''
+ alias: ''
+ amp: '1'
+ comment: ''
+ freq: '1000'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ offset: '0'
+ phase: '0'
+ samp_rate: samp_rate
+ type: complex
+ waveform: analog.GR_COS_WAVE
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [144, 268]
+ rotation: 0
+ state: enabled
+- name: blocks_throttle_0
+ id: blocks_throttle
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ ignoretag: 'True'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ samples_per_second: samp_rate
+ type: complex
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [424, 300]
+ rotation: 0
+ state: enabled
+- name: network_udp_sink_0
+ id: network_udp_sink
+ parameters:
+ addr: 127.0.0.1
+ affinity: ''
+ alias: ''
+ comment: ''
+ header: '0'
+ payloadsize: '1472'
+ port: '2000'
+ send_eof: 'False'
+ type: complex
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [632, 270]
+ rotation: 0
+ state: true
+- name: qtgui_freq_sink_x_0
+ id: qtgui_freq_sink_x
+ parameters:
+ affinity: ''
+ alias: ''
+ alpha1: '1.0'
+ alpha10: '1.0'
+ alpha2: '1.0'
+ alpha3: '1.0'
+ alpha4: '1.0'
+ alpha5: '1.0'
+ alpha6: '1.0'
+ alpha7: '1.0'
+ alpha8: '1.0'
+ alpha9: '1.0'
+ autoscale: 'False'
+ average: '1.0'
+ axislabels: 'True'
+ bw: samp_rate
+ color1: '"blue"'
+ color10: '"dark blue"'
+ color2: '"red"'
+ color3: '"green"'
+ color4: '"black"'
+ color5: '"cyan"'
+ color6: '"magenta"'
+ color7: '"yellow"'
+ color8: '"dark red"'
+ color9: '"dark green"'
+ comment: ''
+ ctrlpanel: 'False'
+ fc: '0'
+ fftsize: '1024'
+ freqhalf: 'True'
+ grid: 'True'
+ gui_hint: ''
+ label: Relative Gain
+ label1: ''
+ label10: ''
+ label2: ''
+ label3: ''
+ label4: ''
+ label5: ''
+ label6: ''
+ label7: ''
+ label8: ''
+ label9: ''
+ legend: 'True'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ name: '""'
+ nconnections: '1'
+ showports: 'True'
+ tr_chan: '0'
+ tr_level: '0.0'
+ tr_mode: qtgui.TRIG_MODE_FREE
+ tr_tag: '""'
+ type: complex
+ units: dB
+ update_time: '0.10'
+ width1: '1'
+ width10: '1'
+ width2: '1'
+ width3: '1'
+ width4: '1'
+ width5: '1'
+ width6: '1'
+ width7: '1'
+ width8: '1'
+ width9: '1'
+ wintype: firdes.WIN_BLACKMAN_hARRIS
+ ymax: '0'
+ ymin: '-140'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [552, 36]
+ rotation: 0
+ state: enabled
+
+connections:
+- [analog_sig_source_x_0, '0', blocks_throttle_0, '0']
+- [blocks_throttle_0, '0', network_udp_sink_0, '0']
+- [blocks_throttle_0, '0', qtgui_freq_sink_x_0, '0']
+
+metadata:
+ file_format: 1
diff --git a/gr-network/examples/test_udp_sink_ipv6.grc b/gr-network/examples/test_udp_sink_ipv6.grc
new file mode 100644
index 0000000000..371fe57838
--- /dev/null
+++ b/gr-network/examples/test_udp_sink_ipv6.grc
@@ -0,0 +1,206 @@
+options:
+ parameters:
+ author: ''
+ catch_exceptions: 'True'
+ category: '[GRC Hier Blocks]'
+ cmake_opt: ''
+ comment: ''
+ copyright: ''
+ description: ''
+ gen_cmake: 'On'
+ gen_linking: dynamic
+ generate_options: qt_gui
+ hier_block_src_path: '.:'
+ id: test_udp_sink6
+ max_nouts: '0'
+ output_language: python
+ placement: (0,0)
+ qt_qss_theme: ''
+ realtime_scheduling: ''
+ run: 'True'
+ run_command: '{python} -u {filename}'
+ run_options: prompt
+ sizing_mode: fixed
+ thread_safe_setters: ''
+ title: ''
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [8, 8]
+ rotation: 0
+ state: enabled
+
+blocks:
+- name: center_freq
+ id: variable
+ parameters:
+ comment: ''
+ value: 1691e6
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [216, 28]
+ rotation: 0
+ state: enabled
+- name: samp_rate
+ id: variable
+ parameters:
+ comment: ''
+ value: 1e6
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [8, 160]
+ rotation: 0
+ state: enabled
+- name: analog_sig_source_x_0
+ id: analog_sig_source_x
+ parameters:
+ affinity: ''
+ alias: ''
+ amp: '1'
+ comment: ''
+ freq: '1000'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ offset: '0'
+ phase: '0'
+ samp_rate: samp_rate
+ type: complex
+ waveform: analog.GR_COS_WAVE
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [144, 268]
+ rotation: 0
+ state: enabled
+- name: blocks_throttle_0
+ id: blocks_throttle
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ ignoretag: 'True'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ samples_per_second: samp_rate
+ type: complex
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [424, 300]
+ rotation: 0
+ state: enabled
+- name: network_udp_sink_0
+ id: network_udp_sink
+ parameters:
+ addr: ::1
+ affinity: ''
+ alias: ''
+ comment: ''
+ header: '0'
+ payloadsize: '1472'
+ port: '2001'
+ send_eof: 'False'
+ type: complex
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [662, 268]
+ rotation: 0
+ state: true
+- name: qtgui_freq_sink_x_0
+ id: qtgui_freq_sink_x
+ parameters:
+ affinity: ''
+ alias: ''
+ alpha1: '1.0'
+ alpha10: '1.0'
+ alpha2: '1.0'
+ alpha3: '1.0'
+ alpha4: '1.0'
+ alpha5: '1.0'
+ alpha6: '1.0'
+ alpha7: '1.0'
+ alpha8: '1.0'
+ alpha9: '1.0'
+ autoscale: 'False'
+ average: '1.0'
+ axislabels: 'True'
+ bw: samp_rate
+ color1: '"blue"'
+ color10: '"dark blue"'
+ color2: '"red"'
+ color3: '"green"'
+ color4: '"black"'
+ color5: '"cyan"'
+ color6: '"magenta"'
+ color7: '"yellow"'
+ color8: '"dark red"'
+ color9: '"dark green"'
+ comment: ''
+ ctrlpanel: 'False'
+ fc: '0'
+ fftsize: '1024'
+ freqhalf: 'True'
+ grid: 'False'
+ gui_hint: ''
+ label: Relative Gain
+ label1: ''
+ label10: ''
+ label2: ''
+ label3: ''
+ label4: ''
+ label5: ''
+ label6: ''
+ label7: ''
+ label8: ''
+ label9: ''
+ legend: 'True'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ name: '""'
+ nconnections: '1'
+ showports: 'True'
+ tr_chan: '0'
+ tr_level: '0.0'
+ tr_mode: qtgui.TRIG_MODE_FREE
+ tr_tag: '""'
+ type: complex
+ units: dB
+ update_time: '0.10'
+ width1: '1'
+ width10: '1'
+ width2: '1'
+ width3: '1'
+ width4: '1'
+ width5: '1'
+ width6: '1'
+ width7: '1'
+ width8: '1'
+ width9: '1'
+ wintype: firdes.WIN_BLACKMAN_hARRIS
+ ymax: '10'
+ ymin: '-140'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [552, 36]
+ rotation: 0
+ state: enabled
+
+connections:
+- [analog_sig_source_x_0, '0', blocks_throttle_0, '0']
+- [blocks_throttle_0, '0', network_udp_sink_0, '0']
+- [blocks_throttle_0, '0', qtgui_freq_sink_x_0, '0']
+
+metadata:
+ file_format: 1
diff --git a/gr-network/examples/test_udp_sink_seq.grc b/gr-network/examples/test_udp_sink_seq.grc
new file mode 100644
index 0000000000..b79e235191
--- /dev/null
+++ b/gr-network/examples/test_udp_sink_seq.grc
@@ -0,0 +1,195 @@
+options:
+ parameters:
+ author: ''
+ catch_exceptions: 'True'
+ category: '[GRC Hier Blocks]'
+ cmake_opt: ''
+ comment: ''
+ copyright: ''
+ description: ''
+ gen_cmake: 'On'
+ gen_linking: dynamic
+ generate_options: qt_gui
+ hier_block_src_path: '.:'
+ id: test_udp_sink_seq
+ max_nouts: '0'
+ output_language: python
+ placement: (0,0)
+ qt_qss_theme: ''
+ realtime_scheduling: ''
+ run: 'True'
+ run_command: '{python} -u {filename}'
+ run_options: prompt
+ sizing_mode: fixed
+ thread_safe_setters: ''
+ title: ''
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [8, 8]
+ rotation: 0
+ state: enabled
+
+blocks:
+- name: samp_rate
+ id: variable
+ parameters:
+ comment: ''
+ value: 1e6
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [188, 14]
+ rotation: 0
+ state: enabled
+- name: analog_sig_source_x_0
+ id: analog_sig_source_x
+ parameters:
+ affinity: ''
+ alias: ''
+ amp: '1'
+ comment: ''
+ freq: '1000'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ offset: '0'
+ phase: '0'
+ samp_rate: samp_rate
+ type: complex
+ waveform: analog.GR_COS_WAVE
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [144, 268]
+ rotation: 0
+ state: enabled
+- name: blocks_throttle_0
+ id: blocks_throttle
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ ignoretag: 'True'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ samples_per_second: samp_rate
+ type: complex
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [424, 300]
+ rotation: 0
+ state: enabled
+- name: network_udp_sink_0
+ id: network_udp_sink
+ parameters:
+ addr: 127.0.0.1
+ affinity: ''
+ alias: ''
+ comment: ''
+ header: '1'
+ payloadsize: '1472'
+ port: '2001'
+ send_eof: 'False'
+ type: complex
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [632, 270]
+ rotation: 0
+ state: true
+- name: qtgui_freq_sink_x_0
+ id: qtgui_freq_sink_x
+ parameters:
+ affinity: ''
+ alias: ''
+ alpha1: '1.0'
+ alpha10: '1.0'
+ alpha2: '1.0'
+ alpha3: '1.0'
+ alpha4: '1.0'
+ alpha5: '1.0'
+ alpha6: '1.0'
+ alpha7: '1.0'
+ alpha8: '1.0'
+ alpha9: '1.0'
+ autoscale: 'False'
+ average: '1.0'
+ axislabels: 'True'
+ bw: samp_rate
+ color1: '"blue"'
+ color10: '"dark blue"'
+ color2: '"red"'
+ color3: '"green"'
+ color4: '"black"'
+ color5: '"cyan"'
+ color6: '"magenta"'
+ color7: '"yellow"'
+ color8: '"dark red"'
+ color9: '"dark green"'
+ comment: ''
+ ctrlpanel: 'False'
+ fc: '0'
+ fftsize: '1024'
+ freqhalf: 'True'
+ grid: 'True'
+ gui_hint: ''
+ label: Relative Gain
+ label1: ''
+ label10: ''
+ label2: ''
+ label3: ''
+ label4: ''
+ label5: ''
+ label6: ''
+ label7: ''
+ label8: ''
+ label9: ''
+ legend: 'True'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ name: '""'
+ nconnections: '1'
+ showports: 'True'
+ tr_chan: '0'
+ tr_level: '0.0'
+ tr_mode: qtgui.TRIG_MODE_FREE
+ tr_tag: '""'
+ type: complex
+ units: dB
+ update_time: '0.10'
+ width1: '1'
+ width10: '1'
+ width2: '1'
+ width3: '1'
+ width4: '1'
+ width5: '1'
+ width6: '1'
+ width7: '1'
+ width8: '1'
+ width9: '1'
+ wintype: firdes.WIN_BLACKMAN_hARRIS
+ ymax: '0'
+ ymin: '-140'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [552, 36]
+ rotation: 0
+ state: enabled
+
+connections:
+- [analog_sig_source_x_0, '0', blocks_throttle_0, '0']
+- [blocks_throttle_0, '0', network_udp_sink_0, '0']
+- [blocks_throttle_0, '0', qtgui_freq_sink_x_0, '0']
+
+metadata:
+ file_format: 1
diff --git a/gr-network/examples/test_udp_source.grc b/gr-network/examples/test_udp_source.grc
new file mode 100644
index 0000000000..7cc8af3d9c
--- /dev/null
+++ b/gr-network/examples/test_udp_source.grc
@@ -0,0 +1,175 @@
+options:
+ parameters:
+ author: ''
+ catch_exceptions: 'True'
+ category: '[GRC Hier Blocks]'
+ cmake_opt: ''
+ comment: ''
+ copyright: ''
+ description: ''
+ gen_cmake: 'On'
+ gen_linking: dynamic
+ generate_options: qt_gui
+ hier_block_src_path: '.:'
+ id: test_udp_source
+ max_nouts: '0'
+ output_language: python
+ placement: (0,0)
+ qt_qss_theme: ''
+ realtime_scheduling: ''
+ run: 'True'
+ run_command: '{python} -u {filename}'
+ run_options: prompt
+ sizing_mode: fixed
+ thread_safe_setters: ''
+ title: ''
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [8, 8]
+ rotation: 0
+ state: enabled
+
+blocks:
+- name: samp_rate
+ id: variable
+ parameters:
+ comment: ''
+ value: 1e6
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [206, 8]
+ rotation: 0
+ state: enabled
+- name: blocks_throttle_0
+ id: blocks_throttle
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ ignoretag: 'True'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ samples_per_second: samp_rate
+ type: complex
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [424, 300]
+ rotation: 0
+ state: enabled
+- name: network_udp_source_0
+ id: network_udp_source
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ header: '0'
+ ipv6: 'True'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ notify_missed: 'True'
+ payloadsize: '1472'
+ port: '2000'
+ src_zeros: 'False'
+ type: complex
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [175, 274]
+ rotation: 0
+ state: true
+- name: qtgui_freq_sink_x_0
+ id: qtgui_freq_sink_x
+ parameters:
+ affinity: ''
+ alias: ''
+ alpha1: '1.0'
+ alpha10: '1.0'
+ alpha2: '1.0'
+ alpha3: '1.0'
+ alpha4: '1.0'
+ alpha5: '1.0'
+ alpha6: '1.0'
+ alpha7: '1.0'
+ alpha8: '1.0'
+ alpha9: '1.0'
+ autoscale: 'False'
+ average: '1.0'
+ axislabels: 'True'
+ bw: samp_rate
+ color1: '"blue"'
+ color10: '"dark blue"'
+ color2: '"red"'
+ color3: '"green"'
+ color4: '"black"'
+ color5: '"cyan"'
+ color6: '"magenta"'
+ color7: '"yellow"'
+ color8: '"dark red"'
+ color9: '"dark green"'
+ comment: ''
+ ctrlpanel: 'False'
+ fc: '0'
+ fftsize: '2048'
+ freqhalf: 'True'
+ grid: 'True'
+ gui_hint: ''
+ label: Relative Gain
+ label1: ''
+ label10: ''
+ label2: ''
+ label3: ''
+ label4: ''
+ label5: ''
+ label6: ''
+ label7: ''
+ label8: ''
+ label9: ''
+ legend: 'True'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ name: '""'
+ nconnections: '1'
+ showports: 'True'
+ tr_chan: '0'
+ tr_level: '0.0'
+ tr_mode: qtgui.TRIG_MODE_FREE
+ tr_tag: '""'
+ type: complex
+ units: dB
+ update_time: '0.10'
+ width1: '1'
+ width10: '1'
+ width2: '1'
+ width3: '1'
+ width4: '1'
+ width5: '1'
+ width6: '1'
+ width7: '1'
+ width8: '1'
+ width9: '1'
+ wintype: firdes.WIN_BLACKMAN_hARRIS
+ ymax: '0'
+ ymin: '-140'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [632, 284]
+ rotation: 0
+ state: enabled
+
+connections:
+- [blocks_throttle_0, '0', qtgui_freq_sink_x_0, '0']
+- [network_udp_source_0, '0', blocks_throttle_0, '0']
+
+metadata:
+ file_format: 1
diff --git a/gr-network/examples/test_udp_source_ipv6.grc b/gr-network/examples/test_udp_source_ipv6.grc
new file mode 100644
index 0000000000..11ab936c80
--- /dev/null
+++ b/gr-network/examples/test_udp_source_ipv6.grc
@@ -0,0 +1,187 @@
+options:
+ parameters:
+ author: ''
+ catch_exceptions: 'True'
+ category: '[GRC Hier Blocks]'
+ cmake_opt: ''
+ comment: ''
+ copyright: ''
+ description: ''
+ gen_cmake: 'On'
+ gen_linking: dynamic
+ generate_options: qt_gui
+ hier_block_src_path: '.:'
+ id: test_udp_source6
+ max_nouts: '0'
+ output_language: python
+ placement: (0,0)
+ qt_qss_theme: ''
+ realtime_scheduling: ''
+ run: 'True'
+ run_command: '{python} -u {filename}'
+ run_options: prompt
+ sizing_mode: fixed
+ thread_safe_setters: ''
+ title: ''
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [8, 8]
+ rotation: 0
+ state: enabled
+
+blocks:
+- name: center_freq
+ id: variable
+ parameters:
+ comment: ''
+ value: 1691e6
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [216, 28]
+ rotation: 0
+ state: enabled
+- name: samp_rate
+ id: variable
+ parameters:
+ comment: ''
+ value: 1e6
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [8, 160]
+ rotation: 0
+ state: enabled
+- name: blocks_throttle_0
+ id: blocks_throttle
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ ignoretag: 'True'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ samples_per_second: samp_rate
+ type: complex
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [424, 300]
+ rotation: 0
+ state: enabled
+- name: network_udp_source_0
+ id: network_udp_source
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ header: '0'
+ ipv6: 'True'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ notifyMissed: 'False'
+ payloadsize: '1472'
+ port: '2001'
+ recv_buff_size: 1024*1024
+ srcZeros: 'False'
+ type: complex
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [161, 275]
+ rotation: 0
+ state: true
+- name: qtgui_freq_sink_x_0
+ id: qtgui_freq_sink_x
+ parameters:
+ affinity: ''
+ alias: ''
+ alpha1: '1.0'
+ alpha10: '1.0'
+ alpha2: '1.0'
+ alpha3: '1.0'
+ alpha4: '1.0'
+ alpha5: '1.0'
+ alpha6: '1.0'
+ alpha7: '1.0'
+ alpha8: '1.0'
+ alpha9: '1.0'
+ autoscale: 'True'
+ average: '1.0'
+ axislabels: 'True'
+ bw: samp_rate
+ color1: '"blue"'
+ color10: '"dark blue"'
+ color2: '"red"'
+ color3: '"green"'
+ color4: '"black"'
+ color5: '"cyan"'
+ color6: '"magenta"'
+ color7: '"yellow"'
+ color8: '"dark red"'
+ color9: '"dark green"'
+ comment: ''
+ ctrlpanel: 'False'
+ fc: center_freq
+ fftsize: '2048'
+ freqhalf: 'True'
+ grid: 'True'
+ gui_hint: ''
+ label: Relative Gain
+ label1: ''
+ label10: ''
+ label2: ''
+ label3: ''
+ label4: ''
+ label5: ''
+ label6: ''
+ label7: ''
+ label8: ''
+ label9: ''
+ legend: 'True'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ name: '""'
+ nconnections: '1'
+ showports: 'True'
+ tr_chan: '0'
+ tr_level: '0.0'
+ tr_mode: qtgui.TRIG_MODE_FREE
+ tr_tag: '""'
+ type: complex
+ units: dB
+ update_time: '0.10'
+ width1: '1'
+ width10: '1'
+ width2: '1'
+ width3: '1'
+ width4: '1'
+ width5: '1'
+ width6: '1'
+ width7: '1'
+ width8: '1'
+ width9: '1'
+ wintype: firdes.WIN_BLACKMAN_hARRIS
+ ymax: '-30'
+ ymin: '-60'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [632, 284]
+ rotation: 0
+ state: enabled
+
+connections:
+- [blocks_throttle_0, '0', qtgui_freq_sink_x_0, '0']
+- [network_udp_source_0, '0', blocks_throttle_0, '0']
+
+metadata:
+ file_format: 1
diff --git a/gr-network/examples/test_udp_source_seq.grc b/gr-network/examples/test_udp_source_seq.grc
new file mode 100644
index 0000000000..4b573a6ed1
--- /dev/null
+++ b/gr-network/examples/test_udp_source_seq.grc
@@ -0,0 +1,175 @@
+options:
+ parameters:
+ author: ''
+ catch_exceptions: 'True'
+ category: '[GRC Hier Blocks]'
+ cmake_opt: ''
+ comment: ''
+ copyright: ''
+ description: ''
+ gen_cmake: 'On'
+ gen_linking: dynamic
+ generate_options: qt_gui
+ hier_block_src_path: '.:'
+ id: test_udp_source_seq
+ max_nouts: '0'
+ output_language: python
+ placement: (0,0)
+ qt_qss_theme: ''
+ realtime_scheduling: ''
+ run: 'True'
+ run_command: '{python} -u {filename}'
+ run_options: prompt
+ sizing_mode: fixed
+ thread_safe_setters: ''
+ title: ''
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [8, 8]
+ rotation: 0
+ state: enabled
+
+blocks:
+- name: samp_rate
+ id: variable
+ parameters:
+ comment: ''
+ value: 1e6
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [206, 8]
+ rotation: 0
+ state: enabled
+- name: blocks_throttle_0
+ id: blocks_throttle
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ ignoretag: 'True'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ samples_per_second: samp_rate
+ type: complex
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [424, 300]
+ rotation: 0
+ state: enabled
+- name: network_udp_source_0
+ id: network_udp_source
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ header: '1'
+ ipv6: 'False'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ notify_missed: 'True'
+ payloadsize: '1472'
+ port: '2001'
+ src_zeros: 'False'
+ type: complex
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [175, 274]
+ rotation: 0
+ state: true
+- name: qtgui_freq_sink_x_0
+ id: qtgui_freq_sink_x
+ parameters:
+ affinity: ''
+ alias: ''
+ alpha1: '1.0'
+ alpha10: '1.0'
+ alpha2: '1.0'
+ alpha3: '1.0'
+ alpha4: '1.0'
+ alpha5: '1.0'
+ alpha6: '1.0'
+ alpha7: '1.0'
+ alpha8: '1.0'
+ alpha9: '1.0'
+ autoscale: 'False'
+ average: '1.0'
+ axislabels: 'True'
+ bw: samp_rate
+ color1: '"blue"'
+ color10: '"dark blue"'
+ color2: '"red"'
+ color3: '"green"'
+ color4: '"black"'
+ color5: '"cyan"'
+ color6: '"magenta"'
+ color7: '"yellow"'
+ color8: '"dark red"'
+ color9: '"dark green"'
+ comment: ''
+ ctrlpanel: 'False'
+ fc: '0'
+ fftsize: '2048'
+ freqhalf: 'True'
+ grid: 'True'
+ gui_hint: ''
+ label: Relative Gain
+ label1: ''
+ label10: ''
+ label2: ''
+ label3: ''
+ label4: ''
+ label5: ''
+ label6: ''
+ label7: ''
+ label8: ''
+ label9: ''
+ legend: 'True'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ name: '""'
+ nconnections: '1'
+ showports: 'True'
+ tr_chan: '0'
+ tr_level: '0.0'
+ tr_mode: qtgui.TRIG_MODE_FREE
+ tr_tag: '""'
+ type: complex
+ units: dB
+ update_time: '0.10'
+ width1: '1'
+ width10: '1'
+ width2: '1'
+ width3: '1'
+ width4: '1'
+ width5: '1'
+ width6: '1'
+ width7: '1'
+ width8: '1'
+ width9: '1'
+ wintype: firdes.WIN_BLACKMAN_hARRIS
+ ymax: '0'
+ ymin: '-140'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [632, 284]
+ rotation: 0
+ state: enabled
+
+connections:
+- [blocks_throttle_0, '0', qtgui_freq_sink_x_0, '0']
+- [network_udp_source_0, '0', blocks_throttle_0, '0']
+
+metadata:
+ file_format: 1
diff --git a/gr-network/gnuradio-network.pc.in b/gr-network/gnuradio-network.pc.in
new file mode 100644
index 0000000000..3ecd2ad6de
--- /dev/null
+++ b/gr-network/gnuradio-network.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: gnuradio-network
+Description: GNU Radio network block library
+Requires: gnuradio-runtime
+Version: @LIBVER@
+Libs: -L${libdir} -lgnuradio-network
+Cflags: -I${includedir}
diff --git a/gr-network/grc/CMakeLists.txt b/gr-network/grc/CMakeLists.txt
new file mode 100644
index 0000000000..8ac8bb68c8
--- /dev/null
+++ b/gr-network/grc/CMakeLists.txt
@@ -0,0 +1,15 @@
+# Copyright 2020 Free Software Foundation, Inc.
+#
+# This file was generated by gr_modtool, a tool from the GNU Radio framework
+# This file is a part of gr-network
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+
+install(FILES
+ network_tcp_sink.block.yml
+ network_tcp_source.block.yml
+ network_udp_sink.block.yml
+ network_udp_source.block.yml
+ DESTINATION share/gnuradio/grc/blocks
+)
diff --git a/gr-network/grc/network_tcp_sink.block.yml b/gr-network/grc/network_tcp_sink.block.yml
new file mode 100644
index 0000000000..9e26e76fa3
--- /dev/null
+++ b/gr-network/grc/network_tcp_sink.block.yml
@@ -0,0 +1,58 @@
+id: network_tcp_sink
+label: TCP Sink
+category: '[Core]/Networking Tools'
+
+parameters:
+- id: type
+ label: Input Type
+ dtype: enum
+ options: [complex, float, int, short, byte]
+ option_attributes:
+ size: [gr.sizeof_gr_complex, gr.sizeof_float, gr.sizeof_int, gr.sizeof_short,
+ gr.sizeof_char]
+ hide: part
+- id: mode
+ label: Mode
+ dtype: enum
+ options: ['1', '2']
+ option_labels: [Client, Server]
+ option_attributes:
+ hide_specific: [none, all]
+- id: addr
+ label: Address
+ dtype: string
+ default: '127.0.0.1'
+ hide: ${ mode.hide_specific }
+- id: port
+ label: Port
+ dtype: int
+ default: '2000'
+- id: vlen
+ label: Vec Length
+ dtype: int
+ default: '1'
+ hide: ${ 'part' if vlen == 1 else 'none' }
+
+inputs:
+- domain: stream
+ dtype: ${ type }
+ vlen: ${ vlen }
+asserts:
+- ${ vlen > 0 }
+
+templates:
+ imports: from gnuradio import network
+ make: network.tcp_sink(${type.size}, ${vlen}, ${addr}, ${port},${mode})
+
+documentation: "This block supports TCP connections in both server (listening for inbound\
+ \ connections) and client mode (initiating connections to other systems as a client).\
+ \ In client mode,the block connects to a server at the given address and port. \
+ \ In server mode, the block starts a local listener on the given port and accepts \
+ \ the first client connection.\n\n\
+ \ This block does support IPv6 addresses. If an IPv6 address\
+ \ is detected as the destination IP address, the block will automatically\
+ \ adjust for proper connection. Just make sure your IPv6 stack is enabled.\
+ \ To listen in server mode for both IPv4 and IPv6, use :: as the address. \
+ \ To connect to IPv6 localhost use ::1 as the address."
+
+file_format: 1
diff --git a/gr-network/grc/network_tcp_source.block.yml b/gr-network/grc/network_tcp_source.block.yml
new file mode 100644
index 0000000000..74f4b19932
--- /dev/null
+++ b/gr-network/grc/network_tcp_source.block.yml
@@ -0,0 +1,56 @@
+id: network_tcp_source
+label: TCP Source
+category: '[Core]/Networking Tools'
+
+parameters:
+- id: type
+ label: Output Type
+ dtype: enum
+ options: [complex, float, int, short, byte]
+ option_attributes:
+ size: [gr.sizeof_gr_complex, gr.sizeof_float, gr.sizeof_int, gr.sizeof_short,
+ gr.sizeof_char]
+ hide: part
+- id: addr
+ label: Address
+ dtype: string
+ default: 127.0.0.1
+- id: port
+ label: Port
+ dtype: int
+ default: '2000'
+- id: server
+ label: Mode
+ dtype: enum
+ default: 'True'
+ options: ['True', 'False']
+ option_labels: [Server, Client]
+- id: vlen
+ label: Vec Length
+ dtype: int
+ default: '1'
+ hide: ${ 'part' if vlen == 1 else 'none' }
+
+outputs:
+- domain: stream
+ dtype: ${ type }
+ vlen: ${ vlen }
+asserts:
+- ${ vlen > 0 }
+
+templates:
+ imports: from gnuradio import network
+ make: network.tcp_source.tcp_source(itemsize=${type.size}*${vlen},addr=${addr},port=${port},server=${server})
+
+documentation: "This block supports TCP connections in both server (listening for inbound\
+ \ connections) and client mode (initiating connections to other systems as a client).\
+ \ In client mode,the block connects to a server at the given address and port. \
+ \ In server mode, the block starts a local listener on the given port and accepts \
+ \ the first client connection.\n\n\
+ \ This block does support IPv6 addresses. If an IPv6 address\
+ \ is detected as the destination IP address, the block will automatically\
+ \ adjust for proper connection. Just make sure your IPv6 stack is enabled.\
+ \ To listen in server mode for both IPv4 and IPv6, use :: as the address. \
+ \ To connect to IPv6 localhost use ::1 as the address."
+
+file_format: 1
diff --git a/gr-network/grc/network_udp_sink.block.yml b/gr-network/grc/network_udp_sink.block.yml
new file mode 100644
index 0000000000..957205345d
--- /dev/null
+++ b/gr-network/grc/network_udp_sink.block.yml
@@ -0,0 +1,82 @@
+id: network_udp_sink
+label: UDP Sink
+category: '[Core]/Networking Tools'
+
+parameters:
+- id: type
+ label: Input Type
+ dtype: enum
+ options: [complex, float, int, short, byte]
+ option_attributes:
+ size: [gr.sizeof_gr_complex, gr.sizeof_float, gr.sizeof_int, gr.sizeof_short,
+ gr.sizeof_char]
+ hide: part
+- id: addr
+ label: Address
+ dtype: string
+ default: 127.0.0.1
+- id: port
+ label: Destination Port
+ dtype: int
+ default: '2000'
+- id: header
+ label: Header
+ dtype: enum
+ options: ['0', '1', '2', '4']
+ option_labels: [None, 64-bit Sequence Number, Sequence + 16-bit data size, CHDR
+ (64-bit)]
+- id: payloadsize
+ label: UDP Packet Data Size
+ dtype: int
+ default: '1472'
+- id: send_eof
+ label: Send Null Packet as EOF
+ dtype: enum
+ options: ['False', 'True']
+ option_labels: ['No', 'Yes']
+- id: vlen
+ label: Vec Length
+ dtype: int
+ default: '1'
+ hide: ${ 'part' if vlen == 1 else 'none' }
+
+inputs:
+- domain: stream
+ dtype: ${ type }
+ vlen: ${ vlen }
+
+asserts:
+- ${ port > 0 }
+- ${ payloadsize > 0 }
+- ${ vlen > 0 }
+
+templates:
+ imports: from gnuradio import network
+ make: network.udp_sink(${type.size}, ${vlen}, ${addr}, ${port}, ${header}, ${payloadsize}, ${send_eof})
+
+documentation: "This block provides basic UDP data transmission capabilities with\
+ \ a few additional features for processing in custom receiving applications. \
+ \ \nA header can be added in various formats for tracking. For instance all headers\
+ \ also provide a sequence number that can be used to identify gaps in packets.\
+ \ \nNote that payload size impacts the overall size of a single UDP packet. \
+ \ For a normal network, a payload size of 1472 (1500-28 for UDP headers) represents\
+ \ the max size for a standard UDP packet. For jumbo frames, 8972 can be used\
+ \ (9000-28). Be careful adjusting this parameter as you could inadvertently cause\
+ \ unnecessary packet fragmentation and reconstruction.\n\n\
+ \ NOTES:\n\
+ \ This block does support connecting to IPv6 addresses. If an IPv6 address\
+ \ is detected as the destination IP address, the block will automatically\
+ \ adjust for proper connection. Just make sure your IPv6 stack is enabled.\n\n\
+ \ For best performance and to ensure UDP packets are not dropped, add the following\
+ \ lines to your /etc/sysctl.conf and reboot (the reboot is required).\n\n\
+ \ net.core.rmem_default=26214400\n\
+ \ net.core.rmem_max=104857600\n\
+ \ net.core.wmem_default=65536\n\
+ \ net.core.wmem_max=104857600\n\n\
+ \ IT IS HIGHLY RECOMMENDED that the example test_udp_source/sink flowgraphs be\
+ \ tested with the sequence number header enabled (the default in those flowgraphs)\
+ \ as a validation that no network or IP stack bottlenecks may cause dropped packets\
+ \ at the rates planned in your environment before using in production, especially if\
+ \ headers will not be used in your environment to track dropped packets."
+
+file_format: 1
diff --git a/gr-network/grc/network_udp_source.block.yml b/gr-network/grc/network_udp_source.block.yml
new file mode 100644
index 0000000000..850359ee3b
--- /dev/null
+++ b/gr-network/grc/network_udp_source.block.yml
@@ -0,0 +1,86 @@
+id: network_udp_source
+label: UDP Source
+category: '[Core]/Networking Tools'
+
+parameters:
+- id: type
+ label: Input Type
+ dtype: enum
+ options: [complex, float, int, short, byte]
+ option_attributes:
+ size: [gr.sizeof_gr_complex, gr.sizeof_float, gr.sizeof_int, gr.sizeof_short,
+ gr.sizeof_char]
+ hide: part
+- id: port
+ label: Port
+ dtype: int
+ default: '1234'
+- id: header
+ label: Header
+ dtype: enum
+ options: ['0', '1', '2', '5']
+ option_labels: [None, 64-bit Sequence Number, Sequence + 16-bit data size, ATA Header]
+- id: payloadsize
+ label: UDP Packet Data Size
+ dtype: int
+ default: '1472'
+ hide: part
+- id: notify_missed
+ label: Notify Missed Frames
+ dtype: enum
+ options: ['False', 'True']
+ option_labels: ['No', 'Yes']
+- id: src_zeros
+ label: Src 0s If No Data
+ dtype: enum
+ options: ['False', 'True']
+ option_labels: ['No', 'Yes']
+- id: ipv6
+ label: Enable IPv6 Support
+ dtype: enum
+ options: ['False', 'True']
+ option_labels: ['No', 'Yes']
+- id: vlen
+ label: Vec Length
+ dtype: int
+ default: '1'
+ hide: ${ 'part' if vlen == 1 else 'none' }
+
+outputs:
+- domain: stream
+ dtype: ${ type }
+ vlen: ${ vlen }
+
+asserts:
+- ${ vlen > 0 }
+
+templates:
+ imports: from gnuradio import network
+ make: network.udp_source(${type.size}, ${vlen}, ${port}, ${header}, ${payloadsize}, ${notify_missed}, ${src_zeros}, ${ipv6})
+
+documentation: "This block listens for traffic on the specified UDP port and outputs\
+ \ the specified data type. Note that the header setting and payload size should\
+ \ match on both the sender and receiver. For a normal network, a payload size\
+ \ of 1472 (1500-28 for UDP headers) represents the max size for a standard UDP\
+ \ packet. For jumbo frames, 8972 can be used (9000-28). Be careful adjusting\
+ \ this parameter as you could inadvertently cause unnecessary packet fragmentation\
+ \ and reconstruction.\n\nIf you need the block to generate 0s when there is\
+ \ no UDP data, you can turn on the 'Src 0s If No Data' flag, however this is best\
+ \ paired with the grnet UDP sink block. If using a separate application, problems\
+ \ can arise if the sending application is not calling its send function with blocks\
+ \ matching payload size (the logic here can get a 'partial' packet after starting\
+ \ and not continue to produce zeros).\n\n\
+ \ NOTE:\n\
+ \ For best performance and to ensure UDP packets are not dropped, add the following\
+ \ lines to your /etc/sysctl.conf and reboot (the reboot is required).\n\n\
+ \ net.core.rmem_default=26214400\n\
+ \ net.core.rmem_max=104857600\n\
+ \ net.core.wmem_default=65536\n\
+ \ net.core.wmem_max=104857600\n\n\
+ \ IT IS HIGHLY RECOMMENDED that the example test_udp_source/sink flowgraphs be\
+ \ tested with the sequence number header enabled (the default in those flowgraphs)\
+ \ as a validation that no network or IP stack bottlenecks may cause dropped packets\
+ \ at the rates planned in your environment before using in production, especially if\
+ \ headers will not be used in your environment to track dropped packets."
+
+file_format: 1
diff --git a/gr-network/include/gnuradio/network/CMakeLists.txt b/gr-network/include/gnuradio/network/CMakeLists.txt
new file mode 100644
index 0000000000..8712ed00d2
--- /dev/null
+++ b/gr-network/include/gnuradio/network/CMakeLists.txt
@@ -0,0 +1,19 @@
+#Copyright 2020 Free Software Foundation, Inc.
+#
+#This file is a part of gnuradio
+#
+#SPDX - License - Identifier : GPL - 3.0 - or -later
+#
+
+########################################################################
+#Install public header files
+########################################################################
+install(FILES
+ api.h
+ packet_headers.h
+ tcp_sink.h
+ udp_header_types.h
+ udp_sink.h
+ udp_source.h
+ DESTINATION ${GR_INCLUDE_DIR}/gnuradio/network
+)
diff --git a/gr-network/include/gnuradio/network/api.h b/gr-network/include/gnuradio/network/api.h
new file mode 100644
index 0000000000..e1fa631a09
--- /dev/null
+++ b/gr-network/include/gnuradio/network/api.h
@@ -0,0 +1,22 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+
+#ifndef INCLUDED_NETWORK_API_H
+#define INCLUDED_NETWORK_API_H
+
+#include <gnuradio/attributes.h>
+
+#ifdef gnuradio_network_EXPORTS
+#define NETWORK_API __GR_ATTR_EXPORT
+#else
+#define NETWORK_API __GR_ATTR_IMPORT
+#endif
+
+#endif /* INCLUDED_NETWORK_API_H */
diff --git a/gr-network/include/gnuradio/network/packet_headers.h b/gr-network/include/gnuradio/network/packet_headers.h
new file mode 100644
index 0000000000..5d3d282bc3
--- /dev/null
+++ b/gr-network/include/gnuradio/network/packet_headers.h
@@ -0,0 +1,65 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+
+#ifndef INCLUDED_NETWORK_PACKET_HEADERS_H
+#define INCLUDED_NETWORK_PACKET_HEADERS_H
+
+#include <gnuradio/network/udp_header_types.h>
+
+class header_seq_num
+{
+public:
+ // size: 8 (64-bit)
+ uint64_t seqnum;
+
+ header_seq_num() { seqnum = 0; };
+};
+
+class header_seq_plus_size
+{
+public:
+ // size: 10 (80-bit)
+ uint64_t seqnum;
+ int16_t length;
+
+ header_seq_plus_size()
+ {
+ seqnum = 0;
+ length = 0;
+ };
+};
+
+class ata_header
+{
+public:
+ // Total size: 64 bytes
+ uint8_t group, version, bitsPerSample, binaryPoint;
+ uint32_t order;
+ uint8_t type, streams, polCode, hdrLen;
+ uint32_t src;
+ uint32_t chan;
+ uint32_t seq;
+ double freq;
+ double sampleRate;
+ float usableFraction;
+ float reserved;
+ uint64_t absTime;
+ uint32_t flags;
+ uint32_t len;
+
+ ata_header()
+ {
+ seq = 0;
+ freq = 0.0;
+ sampleRate = 0.0;
+ };
+};
+
+#endif /* INCLUDED_NETWORK_PACKET_HEADERS_H */
diff --git a/gr-network/include/gnuradio/network/tcp_sink.h b/gr-network/include/gnuradio/network/tcp_sink.h
new file mode 100644
index 0000000000..8cbc05fd3b
--- /dev/null
+++ b/gr-network/include/gnuradio/network/tcp_sink.h
@@ -0,0 +1,53 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+
+#ifndef INCLUDED_NETWORK_TCP_SINK_H
+#define INCLUDED_NETWORK_TCP_SINK_H
+
+#include <gnuradio/network/api.h>
+#include <gnuradio/sync_block.h>
+
+#define TCPSINKMODE_CLIENT 1
+#define TCPSINKMODE_SERVER 2
+
+namespace gr {
+namespace network {
+
+/*!
+ * \brief This block provides a TCP Sink block that supports
+ * both client and server modes.
+ * \ingroup networking_tools
+ *
+ * \details
+ * This block provides a TCP sink that supports both listening for
+ * inbound connections (server mode) and connecting to other applications
+ * (client mode) in order to send data from a GNU Radio flowgraph.
+ * The block supports both IPv4 and IPv6 with appropriate code determined
+ * by the address used. In server mode, if a client disconnects, the
+ * flowgraph will continue to execute. If/when a new client connection
+ * is established, data will then pick up with the current stream for
+ * transmission to the new client.
+ */
+class NETWORK_API tcp_sink : virtual public gr::sync_block
+{
+public:
+ typedef boost::shared_ptr<tcp_sink> sptr;
+
+ /*!
+ * Build a tcp_sink block.
+ */
+ static sptr
+ make(size_t itemsize, size_t veclen, const std::string& host, int port, int sinkmode);
+};
+
+} // namespace network
+} // namespace gr
+
+#endif /* INCLUDED_NETWORK_TCP_SINK_H */
diff --git a/gr-network/include/gnuradio/network/udp_header_types.h b/gr-network/include/gnuradio/network/udp_header_types.h
new file mode 100644
index 0000000000..521e51497e
--- /dev/null
+++ b/gr-network/include/gnuradio/network/udp_header_types.h
@@ -0,0 +1,20 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+
+#ifndef NETWORK_UDPHEADERTYPES_H_
+#define NETWORK_UDPHEADERTYPES_H_
+
+constexpr int HEADERTYPE_NONE = 0;
+constexpr int HEADERTYPE_SEQNUM = 1;
+constexpr int HEADERTYPE_SEQPLUSSIZE = 2;
+// 3 and 4 were defined but have been removed. ATA kept as 5 for backward compatibility.
+constexpr int HEADERTYPE_OLDATA = 5;
+
+#endif /* NETWORK_UDPHEADERTYPES_H_ */
diff --git a/gr-network/include/gnuradio/network/udp_sink.h b/gr-network/include/gnuradio/network/udp_sink.h
new file mode 100644
index 0000000000..415cc22736
--- /dev/null
+++ b/gr-network/include/gnuradio/network/udp_sink.h
@@ -0,0 +1,69 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+
+#ifndef INCLUDED_NETWORK_UDP_SINK_H
+#define INCLUDED_NETWORK_UDP_SINK_H
+
+#include <gnuradio/network/api.h>
+#include <gnuradio/sync_block.h>
+
+namespace gr {
+namespace network {
+
+/*!
+ * \brief This block provides a UDP Sink block that can send
+ * data over UDP streams to a specified host.
+ * \ingroup networking_tools
+ *
+ * \details
+ * This block provides a UDP sink that supports sending data over
+ * a UDP stream to external applications. A number of header formats
+ * are supported including None (raw stream), and other header formats
+ * that allow for sequence numbers to be tracked. This feature allows
+ * the recipient to be aware of any frames dropped in transit or by
+ * its receiving stack. The UDP packet size can also be adjusted
+ * to support jumbo frames. For most networks, 1472 is the correct
+ * UDP data packet size that optimizes network transmission. Adjusting
+ * this value without a full understanding of the network implications
+ * can create additional network fragmentation and inefficient packet
+ * usage so should be avoided. For networks and endpoints supporting
+ * jumbo frames of 9000, 8972 would be the appropriate size
+ * (9000 - 28 header bytes). If send NULL packet as EOF is set, when
+ * the flowgraph terminates, an empty UDP packet is sent. This can
+ * be used on the receiving side to be aware that no more data may
+ * be received from the sending application. When pairing with the
+ * GNU Radio UDP source block, this isn't necessary and the source
+ * block can simply be set to source zero's when an incoming network
+ * data stream is not present in order to continue returning data
+ * from the work function. This block also supports IPv4 and IPv6
+ * addresses and is automatically determined from the address
+ * provided.
+ */
+class NETWORK_API udp_sink : virtual public gr::sync_block
+{
+public:
+ typedef boost::shared_ptr<udp_sink> sptr;
+
+ /*!
+ * Build a udp_sink block.
+ */
+ static sptr make(size_t itemsize,
+ size_t veclen,
+ const std::string& host,
+ int port,
+ int header_type,
+ int payloadsize,
+ bool send_eof);
+};
+
+} // namespace network
+} // namespace gr
+
+#endif /* INCLUDED_NETWORK_UDP_SINK_H */
diff --git a/gr-network/include/gnuradio/network/udp_source.h b/gr-network/include/gnuradio/network/udp_source.h
new file mode 100644
index 0000000000..7c90f875b1
--- /dev/null
+++ b/gr-network/include/gnuradio/network/udp_source.h
@@ -0,0 +1,67 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+
+#ifndef INCLUDED_NETWORK_UDP_SOURCE_H
+#define INCLUDED_NETWORK_UDP_SOURCE_H
+
+#include <gnuradio/network/api.h>
+#include <gnuradio/sync_block.h>
+
+namespace gr {
+namespace network {
+
+/*!
+ * \brief This block provides a UDP source block that starts a
+ * listener on the specified port and waits for inbound UDP packets.
+ * \ingroup networking_tools
+ *
+ * \details
+ * This block provides a UDP source that supports receiving data over
+ * a UDP stream from external applications. A number of header formats
+ * are supported including None (raw stream), and other header formats
+ * that allow for sequence numbers to be tracked. This feature allows
+ * the flowgraph to be aware of any frames dropped in transit or by
+ * its receiving stack. However, this needs to be appropriately
+ * paired with the sending application (it needs to send the same
+ * header). The UDP packet size can also be adjusted
+ * to support jumbo frames. For most networks, 1472 is the correct
+ * UDP data packet size that optimizes network transmission. Adjusting
+ * this value without a full understanding of the network implications
+ * can create additional network fragmentation and inefficient packet
+ * usage so should be avoided. For networks and endpoints supporting
+ * jumbo frames of 9000, 8972 would be the appropriate size
+ * (9000 - 28 header bytes). This block does support IPv4 only or
+ * dual stack IPv4/IPv6 listening as an endpoint with an enable
+ * IPv6 option that can be set on the block properties page. It can
+ * also be set to source zeros (no signal) in the event no data
+ * is being received.
+ */
+class NETWORK_API udp_source : virtual public gr::sync_block
+{
+public:
+ typedef boost::shared_ptr<udp_source> sptr;
+
+ /*!
+ * Build a udp_source block.
+ */
+ static sptr make(size_t itemsize,
+ size_t vecLen,
+ int port,
+ int header_type,
+ int payloadsize,
+ bool notify_missed,
+ bool source_zeros,
+ bool ipv6);
+};
+
+} // namespace network
+} // namespace gr
+
+#endif /* INCLUDED_NETWORK_UDP_SOURCE_H */
diff --git a/gr-network/lib/CMakeLists.txt b/gr-network/lib/CMakeLists.txt
new file mode 100644
index 0000000000..999e39d18b
--- /dev/null
+++ b/gr-network/lib/CMakeLists.txt
@@ -0,0 +1,75 @@
+#Copyright 2020 Free Software Foundation, Inc.
+#
+#This file is a part of gnuradio
+#
+#SPDX - License - Identifier : GPL - 3.0 - or -later
+#
+
+########################################################################
+#Setup library
+########################################################################
+include(GrPlatform)
+
+#define LIB_SUFFIX
+
+list(APPEND network_sources
+ tcp_sink_impl.cc
+ udp_sink_impl.cc
+ udp_source_impl.cc
+)
+
+set(network_sources "${network_sources}" PARENT_SCOPE)
+if (NOT network_sources)
+ MESSAGE(STATUS "No C++ sources... skipping lib/")
+ return ()
+endif(NOT network_sources)
+
+add_library(gnuradio-network SHARED ${network_sources})
+target_link_libraries(gnuradio-network PUBLIC gnuradio-runtime)
+target_include_directories(gnuradio-network
+ PUBLIC $<INSTALL_INTERFACE:include>
+ PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>
+)
+
+set_target_properties(gnuradio-network PROPERTIES DEFINE_SYMBOL "gnuradio_network_EXPORTS")
+
+if (APPLE)
+ set_target_properties(gnuradio-network PROPERTIES
+ INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib"
+ )
+endif(APPLE)
+
+########################################################################
+#Install built library files
+########################################################################
+include(GrMiscUtils)
+GR_LIBRARY_FOO(gnuradio-network)
+
+########################################################################
+#Print summary
+########################################################################
+message(STATUS "Using install prefix: ${CMAKE_INSTALL_PREFIX}")
+message(STATUS "Building for version: ${VERSION} / ${LIBVER}")
+
+########################################################################
+#Build and register unit test
+########################################################################
+include(GrTest)
+
+#If your unit tests require special include paths, add them here
+#include_directories()
+#List all files that contain Boost.UTF unit tests here
+list(APPEND test_network_sources)
+#Anything we need to link to for the unit tests go here
+list(APPEND GR_TEST_TARGET_DEPS gnuradio-network)
+
+if (NOT test_network_sources)
+ MESSAGE(STATUS "No C++ unit tests... skipping")
+ return ()
+endif(NOT test_network_sources)
+
+foreach (qa_file ${test_network_sources})
+ GR_ADD_CPP_TEST("network_${qa_file}"
+ ${CMAKE_CURRENT_SOURCE_DIR }/${ qa_file }
+ )
+endforeach(qa_file)
diff --git a/gr-network/lib/tcp_sink_impl.cc b/gr-network/lib/tcp_sink_impl.cc
new file mode 100644
index 0000000000..aae7c429aa
--- /dev/null
+++ b/gr-network/lib/tcp_sink_impl.cc
@@ -0,0 +1,292 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "tcp_sink_impl.h"
+#include <gnuradio/io_signature.h>
+
+#include <sstream>
+
+namespace gr {
+namespace network {
+
+tcp_sink::sptr tcp_sink::make(
+ size_t itemsize, size_t veclen, const std::string& host, int port, int sinkmode)
+{
+ return gnuradio::get_initial_sptr(
+ new tcp_sink_impl(itemsize, veclen, host, port, sinkmode));
+}
+
+/*
+ * The private constructor
+ */
+tcp_sink_impl::tcp_sink_impl(
+ size_t itemsize, size_t veclen, const std::string& host, int port, int sinkmode)
+ : gr::sync_block("tcp_sink",
+ gr::io_signature::make(1, 1, itemsize * veclen),
+ gr::io_signature::make(0, 0, 0)),
+ d_itemsize(itemsize),
+ d_veclen(veclen),
+ d_host(host),
+ d_port(port),
+ d_sinkmode(sinkmode),
+ d_thread_running(false),
+ d_stop_thread(false),
+ d_listener_thread(NULL),
+ d_start_new_listener(false),
+ d_initial_connection(true)
+{
+ d_block_size = d_itemsize * d_veclen;
+
+ if (d_sinkmode == TCPSINKMODE_CLIENT) {
+ // In this mode, we're connecting to a remote TCP service listener
+ // as a client.
+ std::stringstream msg;
+
+ msg << "[TCP Sink] connecting to " << host << " on port " << port;
+ GR_LOG_INFO(d_logger, msg.str());
+
+ boost::system::error_code err;
+ d_tcpsocket = new boost::asio::ip::tcp::socket(d_io_service);
+
+ std::string s_port = (boost::format("%d") % port).str();
+ boost::asio::ip::tcp::resolver resolver(d_io_service);
+ boost::asio::ip::tcp::resolver::query query(
+ d_host, s_port, boost::asio::ip::resolver_query_base::passive);
+
+ d_endpoint = *resolver.resolve(query, err);
+
+ if (err) {
+ throw std::runtime_error(
+ std::string("[TCP Sink] Unable to resolve host/IP: ") + err.message());
+ }
+
+ if (d_host.find(":") != std::string::npos)
+ d_is_ipv6 = true;
+ else {
+ // This block supports a check that a name rather than an IP is provided.
+ // the endpoint is then checked after the resolver is done.
+ if (d_endpoint.address().is_v6())
+ d_is_ipv6 = true;
+ else
+ d_is_ipv6 = false;
+ }
+
+ d_tcpsocket->connect(d_endpoint, err);
+ if (err) {
+ throw std::runtime_error(std::string("[TCP Sink] Connection error: ") +
+ err.message());
+ }
+
+ d_connected = true;
+
+ boost::asio::socket_base::keep_alive option(true);
+ d_tcpsocket->set_option(option);
+ } else {
+ // In this mode, we're starting a local port listener and waiting
+ // for inbound connections.
+ d_start_new_listener = true;
+ d_listener_thread =
+ new boost::thread(boost::bind(&tcp_sink_impl::run_listener, this));
+ }
+}
+
+void tcp_sink_impl::run_listener()
+{
+ d_thread_running = true;
+
+ while (!d_stop_thread) {
+ // this will block
+ if (d_start_new_listener) {
+ d_start_new_listener = false;
+ connect(d_initial_connection);
+ d_initial_connection = false;
+ } else
+ usleep(10);
+ }
+
+ d_thread_running = false;
+}
+
+void tcp_sink_impl::accept_handler(boost::asio::ip::tcp::socket* new_connection,
+ const boost::system::error_code& error)
+{
+ if (!error) {
+ GR_LOG_INFO(d_logger, "Client connection received.");
+
+ // Accept succeeded.
+ d_tcpsocket = new_connection;
+
+ boost::asio::socket_base::keep_alive option(true);
+ d_tcpsocket->set_option(option);
+ d_connected = true;
+
+ } else {
+ std::stringstream msg;
+ msg << "Error code " << error << " accepting TCP session.";
+ GR_LOG_ERROR(d_logger, msg.str());
+
+ // Boost made a copy so we have to clean up
+ delete new_connection;
+
+ // safety settings.
+ d_connected = false;
+ d_tcpsocket = NULL;
+ }
+}
+
+void tcp_sink_impl::connect(bool initial_connection)
+{
+ std::stringstream msg;
+ msg << "Waiting for connection on port " << d_port;
+ GR_LOG_INFO(d_logger, msg.str());
+
+ if (initial_connection) {
+ if (d_is_ipv6)
+ d_acceptor = new boost::asio::ip::tcp::acceptor(
+ d_io_service,
+ boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), d_port));
+ else
+ d_acceptor = new boost::asio::ip::tcp::acceptor(
+ d_io_service,
+ boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), d_port));
+ } else {
+ d_io_service.reset();
+ }
+
+ if (d_tcpsocket) {
+ delete d_tcpsocket;
+ }
+ d_tcpsocket = NULL;
+ d_connected = false;
+
+ boost::asio::ip::tcp::socket* tmpSocket =
+ new boost::asio::ip::tcp::socket(d_io_service);
+ d_acceptor->async_accept(*tmpSocket,
+ boost::bind(&tcp_sink_impl::accept_handler,
+ this,
+ tmpSocket,
+ boost::asio::placeholders::error));
+
+ d_io_service.run();
+}
+
+/*
+ * Our virtual destructor.
+ */
+tcp_sink_impl::~tcp_sink_impl() { stop(); }
+
+bool tcp_sink_impl::stop()
+{
+ if (d_thread_running) {
+ d_stop_thread = true;
+ }
+
+ if (d_tcpsocket) {
+ d_tcpsocket->close();
+ delete d_tcpsocket;
+ d_tcpsocket = NULL;
+ }
+
+ d_io_service.reset();
+ d_io_service.stop();
+
+ if (d_acceptor) {
+ delete d_acceptor;
+ d_acceptor = NULL;
+ }
+
+ if (d_listener_thread) {
+ while (d_thread_running)
+ usleep(5);
+
+ delete d_listener_thread;
+ d_listener_thread = NULL;
+ }
+
+ return true;
+}
+
+void tcp_sink_impl::check_for_disconnect()
+{
+ char buff[1];
+ int bytes_read =
+ d_tcpsocket->receive(boost::asio::buffer(buff), d_tcpsocket->message_peek, ec);
+ if ((boost::asio::error::eof == ec) || (boost::asio::error::connection_reset == ec)) {
+ std::stringstream msg;
+ msg << "Disconnect detected on " << d_host << ":" << d_port << ".";
+ GR_LOG_INFO(d_logger, msg.str());
+
+ d_tcpsocket->close();
+ delete d_tcpsocket;
+ d_tcpsocket = NULL;
+
+ exit(1);
+ } else {
+ if (ec) {
+ std::stringstream msg;
+ msg << "Socket error " << ec << " detected.";
+ GR_LOG_ERROR(d_logger, msg.str());
+ }
+ }
+}
+
+int tcp_sink_impl::work(int noutput_items,
+ gr_vector_const_void_star& input_items,
+ gr_vector_void_star& output_items)
+{
+ gr::thread::scoped_lock guard(d_setlock);
+
+ if (!d_connected)
+ return noutput_items;
+
+ unsigned int noi = noutput_items * d_block_size;
+ int bytes_written;
+ int bytes_remaining = noi;
+
+ ec.clear();
+
+ char* p_buff;
+ p_buff = (char*)input_items[0];
+
+ while ((bytes_remaining > 0) && (!ec)) {
+ bytes_written = boost::asio::write(
+ *d_tcpsocket, boost::asio::buffer((const void*)p_buff, bytes_remaining), ec);
+ bytes_remaining -= bytes_written;
+ p_buff += bytes_written;
+
+ if (ec == boost::asio::error::connection_reset ||
+ ec == boost::asio::error::broken_pipe) {
+
+ // Connection was reset
+ d_connected = false;
+ bytes_remaining = 0;
+
+ if (d_sinkmode == TCPSINKMODE_CLIENT) {
+ GR_LOG_WARN(d_logger,
+ "Server closed the connection. Stopping processing.");
+
+ return WORK_DONE;
+ } else {
+ GR_LOG_INFO(d_logger, "Client disconnected. Waiting for new connection.");
+
+ // start waiting for another connection
+ d_start_new_listener = true;
+ }
+ }
+ }
+
+ return noutput_items;
+}
+} /* namespace network */
+} /* namespace gr */
diff --git a/gr-network/lib/tcp_sink_impl.h b/gr-network/lib/tcp_sink_impl.h
new file mode 100644
index 0000000000..68e0861bb5
--- /dev/null
+++ b/gr-network/lib/tcp_sink_impl.h
@@ -0,0 +1,75 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+
+#ifndef INCLUDED_NETWORK_TCP_SINK_IMPL_H
+#define INCLUDED_NETWORK_TCP_SINK_IMPL_H
+
+#include <gnuradio/network/tcp_sink.h>
+#include <boost/asio.hpp>
+#include <boost/asio/ip/tcp.hpp>
+#include <boost/thread/thread.hpp>
+
+namespace gr {
+namespace network {
+
+class NETWORK_API tcp_sink_impl : public tcp_sink
+{
+protected:
+ size_t d_itemsize;
+ size_t d_veclen;
+ std::string d_host;
+ int d_port;
+ int d_sinkmode;
+
+ bool d_thread_running;
+ bool d_stop_thread;
+ boost::thread* d_listener_thread;
+ bool d_start_new_listener;
+ bool d_initial_connection;
+
+ size_t d_block_size;
+ bool d_is_ipv6;
+
+ boost::system::error_code ec;
+
+ boost::asio::io_service d_io_service;
+ boost::asio::ip::tcp::endpoint d_endpoint;
+ boost::asio::ip::tcp::socket* d_tcpsocket = NULL;
+ boost::asio::ip::tcp::acceptor* d_acceptor = NULL;
+
+ bool d_connected;
+
+ virtual void check_for_disconnect();
+ virtual void connect(bool initial_connection);
+
+ virtual void run_listener();
+
+public:
+ tcp_sink_impl(size_t itemsize,
+ size_t veclen,
+ const std::string& host,
+ int port,
+ int sinkmode = TCPSINKMODE_CLIENT);
+ ~tcp_sink_impl();
+
+ virtual bool stop();
+
+ void accept_handler(boost::asio::ip::tcp::socket* new_connection,
+ const boost::system::error_code& error);
+
+ int work(int noutput_items,
+ gr_vector_const_void_star& input_items,
+ gr_vector_void_star& output_items);
+};
+
+} // namespace network
+} // namespace gr
+
+#endif /* INCLUDED_NETWORK_TCP_SINK_IMPL_H */
diff --git a/gr-network/lib/udp_sink_impl.cc b/gr-network/lib/udp_sink_impl.cc
new file mode 100644
index 0000000000..5c2f3d1a75
--- /dev/null
+++ b/gr-network/lib/udp_sink_impl.cc
@@ -0,0 +1,270 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "udp_sink_impl.h"
+#include <gnuradio/io_signature.h>
+#include <boost/array.hpp>
+
+namespace gr {
+namespace network {
+
+udp_sink::sptr udp_sink::make(size_t itemsize,
+ size_t veclen,
+ const std::string& host,
+ int port,
+ int header_type,
+ int payloadsize,
+ bool send_eof)
+{
+ return gnuradio::get_initial_sptr(new udp_sink_impl(
+ itemsize, veclen, host, port, header_type, payloadsize, send_eof));
+}
+
+/*
+ * The private constructor
+ */
+udp_sink_impl::udp_sink_impl(size_t itemsize,
+ size_t veclen,
+ const std::string& host,
+ int port,
+ int header_type,
+ int payloadsize,
+ bool send_eof)
+ : gr::sync_block("udp_sink",
+ gr::io_signature::make(1, 1, itemsize * veclen),
+ gr::io_signature::make(0, 0, 0)),
+ d_itemsize(itemsize),
+ d_veclen(veclen),
+ d_header_type(header_type),
+ d_header_size(0),
+ d_seq_num(0),
+ d_payloadsize(payloadsize),
+ b_send_eof(send_eof)
+{
+ // Lets set up the max payload size for the UDP packet based on the requested
+ // payload size. Some important notes: For a standard IP/UDP packet, say
+ // crossing the Internet with a standard MTU, 1472 is the max UDP payload
+ // size. Larger values can be sent, however the IP stack will fragment the
+ // packet. This can cause additional network overhead as the packet gets
+ // reassembled. Now for local nets that support jumbo frames, the max payload
+ // size is 8972 (9000-the UDP 28-byte header) Same rules apply with
+ // fragmentation.
+
+ d_port = port;
+
+ d_header_size = 0;
+
+ switch (d_header_type) {
+ case HEADERTYPE_SEQNUM:
+ d_header_size = sizeof(header_seq_num);
+ break;
+
+ case HEADERTYPE_SEQPLUSSIZE:
+ d_header_size = sizeof(header_seq_plus_size);
+ break;
+
+ case HEADERTYPE_NONE:
+ d_header_size = 0;
+ break;
+
+ default:
+ GR_LOG_ERROR(d_logger, "Unknown header type.");
+ throw std::invalid_argument("Unknown UDP header type.");
+ break;
+ }
+
+ if (d_payloadsize < 8) {
+ GR_LOG_ERROR(d_logger,
+ "Payload size is too small. Must be at "
+ "least 8 bytes once header/trailer adjustments are made.");
+ throw std::invalid_argument(
+ "Payload size is too small. Must be at "
+ "least 8 bytes once header/trailer adjustments are made.");
+ }
+
+ d_seq_num = 0;
+
+ d_block_size = d_itemsize * d_veclen;
+
+ d_precomp_datasize = d_payloadsize - d_header_size;
+ d_precomp_data_overitemsize = d_precomp_datasize / d_itemsize;
+
+ d_localbuffer = new char[d_payloadsize];
+
+ long max_circ_buffer;
+
+ // Let's keep it from getting too big
+ if (d_payloadsize < 2000) {
+ max_circ_buffer = d_payloadsize * 4000;
+ } else {
+ if (d_payloadsize < 5000)
+ max_circ_buffer = d_payloadsize * 2000;
+ else
+ max_circ_buffer = d_payloadsize * 1500;
+ }
+
+ d_localqueue = new boost::circular_buffer<char>(max_circ_buffer);
+
+ d_udpsocket = new boost::asio::ip::udp::socket(d_io_service);
+
+ std::string s_port = (boost::format("%d") % port).str();
+ std::string s_host = host.empty() ? std::string("localhost") : host;
+ boost::asio::ip::udp::resolver resolver(d_io_service);
+ boost::asio::ip::udp::resolver::query query(
+ s_host, s_port, boost::asio::ip::resolver_query_base::passive);
+
+ boost::system::error_code err;
+ d_endpoint = *resolver.resolve(query, err);
+
+ if (err) {
+ throw std::runtime_error(std::string("[UDP Sink] Unable to resolve host/IP: ") +
+ err.message());
+ }
+
+ if (host.find(":") != std::string::npos)
+ is_ipv6 = true;
+ else {
+ // This block supports a check that a name rather than an IP is provided.
+ // the endpoint is then checked after the resolver is done.
+ if (d_endpoint.address().is_v6())
+ is_ipv6 = true;
+ else
+ is_ipv6 = false;
+ }
+
+ if (is_ipv6) {
+ d_udpsocket->open(boost::asio::ip::udp::v6());
+ } else {
+ d_udpsocket->open(boost::asio::ip::udp::v4());
+ }
+
+ int out_multiple = (d_payloadsize - d_header_size) / d_block_size;
+
+ if (out_multiple == 1)
+ out_multiple = 2; // Ensure we get pairs, for instance complex -> ichar pairs
+
+ gr::block::set_output_multiple(out_multiple);
+}
+
+/*
+ * Our virtual destructor.
+ */
+udp_sink_impl::~udp_sink_impl() { stop(); }
+
+bool udp_sink_impl::stop()
+{
+ if (d_udpsocket) {
+ gr::thread::scoped_lock guard(d_setlock);
+
+ if (b_send_eof) {
+ // Send a few zero-length packets to signal receiver we are done
+ boost::array<char, 0> send_buf;
+ for (int i = 0; i < 3; i++)
+ d_udpsocket->send_to(boost::asio::buffer(send_buf), d_endpoint);
+ }
+
+ d_udpsocket->close();
+ d_udpsocket = NULL;
+
+ d_io_service.reset();
+ d_io_service.stop();
+ }
+
+ if (d_localbuffer) {
+ delete[] d_localbuffer;
+ d_localbuffer = NULL;
+ }
+
+ if (d_localqueue) {
+ delete d_localqueue;
+ d_localqueue = NULL;
+ }
+
+ return true;
+}
+
+void udp_sink_impl::build_header()
+{
+ switch (d_header_type) {
+ case HEADERTYPE_SEQNUM: {
+ d_seq_num++;
+ header_seq_num seq_header;
+ seq_header.seqnum = d_seq_num;
+ memcpy((void*)d_tmpheaderbuff, (void*)&seq_header, d_header_size);
+ } break;
+
+ case HEADERTYPE_SEQPLUSSIZE: {
+ d_seq_num++;
+ header_seq_plus_size seq_header_plus_size;
+ seq_header_plus_size.seqnum = d_seq_num;
+ seq_header_plus_size.length = d_payloadsize;
+ memcpy((void*)d_tmpheaderbuff, (void*)&seq_header_plus_size, d_header_size);
+ } break;
+ }
+}
+
+int udp_sink_impl::work(int noutput_items,
+ gr_vector_const_void_star& input_items,
+ gr_vector_void_star& output_items)
+{
+ gr::thread::scoped_lock guard(d_setlock);
+
+ long num_bytes_to_transmit = noutput_items * d_block_size;
+ const char* in = (const char*)input_items[0];
+
+ // Build a long local queue to pull from so we can break it up easier
+ for (int i = 0; i < num_bytes_to_transmit; i++) {
+ d_localqueue->push_back(in[i]);
+ }
+
+ // Local boost buffer for transmitting
+ std::vector<boost::asio::const_buffer> transmitbuffer;
+
+ // Let's see how many blocks are in the buffer
+ int bytes_available = d_localqueue->size();
+ long blocks_available = bytes_available / d_precomp_datasize;
+
+ for (int cur_block = 0; cur_block < blocks_available; cur_block++) {
+ // Clear the next transmit buffer
+ transmitbuffer.clear();
+
+ // build our next header if we need it
+ if (d_header_type != HEADERTYPE_NONE) {
+ build_header();
+
+ transmitbuffer.push_back(
+ boost::asio::buffer((const void*)d_tmpheaderbuff, d_header_size));
+ }
+
+ // Fill the data buffer
+ for (int i = 0; i < d_precomp_datasize; i++) {
+ d_localbuffer[i] = d_localqueue->at(0);
+ d_localqueue->pop_front();
+ }
+
+ // Set up for transmit
+ transmitbuffer.push_back(
+ boost::asio::buffer((const void*)d_localbuffer, d_precomp_datasize));
+
+ // Send
+ d_udpsocket->send_to(transmitbuffer, d_endpoint);
+ }
+
+ int itemsreturned = blocks_available * d_precomp_data_overitemsize;
+
+ return itemsreturned;
+}
+
+} /* namespace network */
+} /* namespace gr */
diff --git a/gr-network/lib/udp_sink_impl.h b/gr-network/lib/udp_sink_impl.h
new file mode 100644
index 0000000000..8addbe6c7e
--- /dev/null
+++ b/gr-network/lib/udp_sink_impl.h
@@ -0,0 +1,80 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+
+#ifndef INCLUDED_NETWORK_UDP_SINK_IMPL_H
+#define INCLUDED_NETWORK_UDP_SINK_IMPL_H
+
+#include <gnuradio/network/udp_sink.h>
+#include <boost/asio.hpp>
+#include <boost/asio/ip/udp.hpp>
+#include <boost/circular_buffer.hpp>
+
+#include <gnuradio/network/packet_headers.h>
+
+namespace gr {
+namespace network {
+
+class NETWORK_API udp_sink_impl : public udp_sink
+{
+protected:
+ int d_port;
+ size_t d_itemsize;
+ size_t d_veclen;
+ size_t d_block_size;
+
+ bool is_ipv6;
+ int d_header_type;
+ int d_header_size;
+ uint64_t d_seq_num;
+ uint16_t d_payloadsize;
+ bool b_send_eof;
+
+ int d_precomp_datasize;
+ int d_precomp_data_overitemsize;
+
+ char d_tmpheaderbuff[12]; // Largest header is 10 bytes
+
+ // A queue is required because we have 2 different timing
+ // domains: The network packets and the GR work()/scheduler
+ boost::circular_buffer<char>* d_localqueue;
+ char* d_localbuffer;
+
+ boost::system::error_code ec;
+
+ boost::asio::io_service d_io_service;
+ boost::asio::ip::udp::endpoint d_endpoint;
+ boost::asio::ip::udp::socket* d_udpsocket;
+
+ boost::mutex d_mutex;
+
+ virtual void
+ build_header(); // returns header size. Header is stored in tmpHeaderBuff
+
+public:
+ udp_sink_impl(size_t itemsize,
+ size_t veclen,
+ const std::string& host,
+ int port,
+ int header_type = HEADERTYPE_NONE,
+ int payloadsize = 1472,
+ bool send_eof = true);
+ ~udp_sink_impl();
+
+ bool stop();
+
+ int work(int noutput_items,
+ gr_vector_const_void_star& input_items,
+ gr_vector_void_star& output_items);
+};
+
+} // namespace network
+} // namespace gr
+
+#endif /* INCLUDED_NETWORK_UDP_SINK_IMPL_H */
diff --git a/gr-network/lib/udp_source_impl.cc b/gr-network/lib/udp_source_impl.cc
new file mode 100644
index 0000000000..4758b9e219
--- /dev/null
+++ b/gr-network/lib/udp_source_impl.cc
@@ -0,0 +1,375 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "udp_source_impl.h"
+#include <gnuradio/io_signature.h>
+#include <sstream>
+
+namespace gr {
+namespace network {
+
+udp_source::sptr udp_source::make(size_t itemsize,
+ size_t veclen,
+ int port,
+ int header_type,
+ int payloadsize,
+ bool notify_missed,
+ bool source_zeros,
+ bool ipv6)
+{
+ return gnuradio::get_initial_sptr(new udp_source_impl(itemsize,
+ veclen,
+ port,
+ header_type,
+ payloadsize,
+ notify_missed,
+ source_zeros,
+ ipv6));
+}
+
+/*
+ * The private constructor
+ */
+udp_source_impl::udp_source_impl(size_t itemsize,
+ size_t veclen,
+ int port,
+ int header_type,
+ int payloadsize,
+ bool notify_missed,
+ bool source_zeros,
+ bool ipv6)
+ : gr::sync_block("udp_source",
+ gr::io_signature::make(0, 0, 0),
+ gr::io_signature::make(1, 1, itemsize * veclen)),
+ is_ipv6(ipv6),
+ d_itemsize(itemsize),
+ d_veclen(veclen),
+ d_port(port),
+ d_notify_missed(notify_missed),
+ d_source_zeros(source_zeros),
+ d_header_type(header_type),
+ d_payloadsize(payloadsize),
+ d_seq_num(0),
+ d_header_size(0),
+ d_partial_frame_counter(0)
+{
+ d_block_size = d_itemsize * d_veclen;
+
+ switch (d_header_type) {
+ case HEADERTYPE_SEQNUM:
+ d_header_size = sizeof(header_seq_num);
+ break;
+
+ case HEADERTYPE_SEQPLUSSIZE:
+ d_header_size = sizeof(header_seq_plus_size);
+ break;
+
+ case HEADERTYPE_OLDATA:
+ d_header_size = sizeof(ata_header);
+ break;
+
+ case HEADERTYPE_NONE:
+ d_header_size = 0;
+ break;
+
+ default:
+ GR_LOG_ERROR(d_logger, "Unknown UDP header type.");
+ throw std::invalid_argument("Unknown UDP header type.");
+ break;
+ }
+
+ if (d_payloadsize < 8) {
+ GR_LOG_ERROR(d_logger,
+ "Payload size is too small. Must be at "
+ "least 8 bytes once header/trailer adjustments are made.");
+
+ throw std::invalid_argument(
+ "Payload size is too small. Must be at "
+ "least 8 bytes once header/trailer adjustments are made.");
+ }
+
+ d_precomp_data_size = d_payloadsize - d_header_size;
+ d_precomp_data_over_item_size = d_precomp_data_size / d_itemsize;
+
+ d_local_buffer = new char[d_payloadsize];
+ long max_circ_buffer;
+
+ // Let's keep it from getting too big
+ if (d_payloadsize < 2000) {
+ max_circ_buffer = d_payloadsize * 4000;
+ } else {
+ if (d_payloadsize < 5000)
+ max_circ_buffer = d_payloadsize * 2000;
+ else
+ max_circ_buffer = d_payloadsize * 1500;
+ }
+
+ d_localqueue = new boost::circular_buffer<char>(max_circ_buffer);
+
+ if (is_ipv6)
+ d_endpoint = boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v6(), port);
+ else
+ d_endpoint = boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), port);
+
+ try {
+ d_udpsocket = new boost::asio::ip::udp::socket(d_io_service, d_endpoint);
+ } catch (const std::exception& ex) {
+ throw std::runtime_error(std::string("[UDP Source] Error occurred: ") +
+ ex.what());
+ }
+
+ int out_multiple = (d_payloadsize - d_header_size) / d_block_size;
+
+ if (out_multiple == 1)
+ out_multiple = 2; // Ensure we get pairs, for instance complex -> ichar pairs
+
+ gr::block::set_output_multiple(out_multiple);
+
+ std::stringstream msg_stream;
+ msg_stream << "Listening for data on UDP port " << port << ".";
+ GR_LOG_INFO(d_logger, msg_stream.str());
+}
+
+/*
+ * Our virtual destructor.
+ */
+udp_source_impl::~udp_source_impl() { stop(); }
+
+bool udp_source_impl::stop()
+{
+ if (d_udpsocket) {
+ d_udpsocket->close();
+
+ d_udpsocket = NULL;
+
+ d_io_service.reset();
+ d_io_service.stop();
+ }
+
+ if (d_local_buffer) {
+ delete[] d_local_buffer;
+ d_local_buffer = NULL;
+ }
+
+ if (d_localqueue) {
+ delete d_localqueue;
+ d_localqueue = NULL;
+ }
+ return true;
+}
+
+size_t udp_source_impl::data_available()
+{
+ // Get amount of data available
+ boost::asio::socket_base::bytes_readable command(true);
+ d_udpsocket->io_control(command);
+ size_t bytes_readable = command.get();
+
+ return (bytes_readable + d_localqueue->size());
+}
+
+size_t udp_source_impl::netdata_available()
+{
+ // Get amount of data available
+ boost::asio::socket_base::bytes_readable command(true);
+ d_udpsocket->io_control(command);
+ size_t bytes_readable = command.get();
+
+ return bytes_readable;
+}
+
+uint64_t udp_source_impl::get_header_seqnum()
+{
+ uint64_t retVal = 0;
+
+ switch (d_header_type) {
+ case HEADERTYPE_SEQNUM: {
+ retVal = ((header_seq_num*)d_local_buffer)->seqnum;
+ } break;
+
+ case HEADERTYPE_SEQPLUSSIZE: {
+ retVal = ((header_seq_plus_size*)d_local_buffer)->seqnum;
+ } break;
+
+ case HEADERTYPE_OLDATA: {
+ retVal = ((ata_header*)d_local_buffer)->seq;
+ } break;
+ }
+
+ return retVal;
+}
+
+int udp_source_impl::work(int noutput_items,
+ gr_vector_const_void_star& input_items,
+ gr_vector_void_star& output_items)
+{
+ gr::thread::scoped_lock guard(d_setlock);
+
+ static bool first_time = true;
+ static int underrun_counter = 0;
+
+ int bytes_available = netdata_available();
+ char* out = (char*)output_items[0];
+ unsigned int num_requested = noutput_items * d_block_size;
+
+ // quick exit if nothing to do
+ if ((bytes_available == 0) && (d_localqueue->size() == 0)) {
+ underrun_counter++;
+ d_partial_frame_counter = 0;
+ if (d_source_zeros) {
+ // Just return 0's
+ memset((void*)out, 0x00, num_requested); // num_requested will be in bytes
+ return noutput_items;
+ } else {
+ if (underrun_counter == 0) {
+ if (!first_time) {
+ std::cout << "nU";
+ } else
+ first_time = false;
+ } else {
+ if (underrun_counter > 100)
+ underrun_counter = 0;
+ }
+
+ return 0;
+ }
+ }
+
+ int bytes_read;
+
+ // we could get here even if no data was received but there's still data in
+ // the queue. however read blocks so we want to make sure we have data before
+ // we call it.
+ if (bytes_available > 0) {
+ boost::asio::streambuf::mutable_buffers_type buf =
+ d_read_buffer.prepare(bytes_available);
+ // http://stackoverflow.com/questions/28929699/boostasio-read-n-bytes-from-socket-to-streambuf
+ bytes_read = d_udpsocket->receive_from(buf, d_endpoint);
+
+ if (bytes_read > 0) {
+ d_read_buffer.commit(bytes_read);
+
+ // Get the data and add it to our local queue. We have to maintain a
+ // local queue in case we read more bytes than noutput_items is asking
+ // for. In that case we'll only return noutput_items bytes
+ const char* read_data =
+ boost::asio::buffer_cast<const char*>(d_read_buffer.data());
+ for (int i = 0; i < bytes_read; i++) {
+ d_localqueue->push_back(read_data[i]);
+ }
+ d_read_buffer.consume(bytes_read);
+ }
+ }
+
+ if (d_localqueue->size() < d_payloadsize) {
+ // since we should be getting these in UDP packet blocks matched on the
+ // sender/receiver, this should be a fringe case, or a case where another
+ // app is sourcing the packets.
+ d_partial_frame_counter++;
+
+ if (d_partial_frame_counter >= 100) {
+ std::stringstream msg_stream;
+ msg_stream << "Insufficient block data. Check your sending "
+ "app is using "
+ << d_payloadsize << " send blocks.";
+ GR_LOG_WARN(d_logger, msg_stream.str());
+
+ // This is just a safety to clear in the case there's a hanging partial
+ // packet. If we've lingered through a number of calls and we still don't
+ // have any data, clear the stale data.
+ while (d_localqueue->size() > 0)
+ d_localqueue->pop_front();
+
+ d_partial_frame_counter = 0;
+ }
+ return 0; // Don't memset 0x00 since we're starting to get data. In this
+ // case we'll hold for the rest.
+ }
+
+ // If we're here, it's not a partial hanging frame
+ d_partial_frame_counter = 0;
+
+ // Now if we're here we should have at least 1 block.
+
+ // let's figure out how much we have in relation to noutput_items, accounting
+ // for headers
+
+ // Number of data-only blocks requested (set_output_multiple() should make
+ // sure this is an integer multiple)
+ long blocks_requested = noutput_items / d_precomp_data_over_item_size;
+ // Number of blocks available accounting for the header as well.
+ long blocks_available = d_localqueue->size() / (d_payloadsize);
+ long blocks_retrieved;
+ int itemsreturned;
+
+ if (blocks_requested <= blocks_available)
+ blocks_retrieved = blocks_requested;
+ else
+ blocks_retrieved = blocks_available;
+
+ // items returned is going to match the payload (actual data) of the number of
+ // blocks.
+ itemsreturned = blocks_retrieved * d_precomp_data_over_item_size;
+
+ // We're going to have to read the data out in blocks, account for the header,
+ // then just move the data part into the out[] array.
+
+ char* data_ptr;
+ data_ptr = &d_local_buffer[d_header_size];
+ int out_index = 0;
+ int skipped_packets = 0;
+
+ for (int cur_pkt = 0; cur_pkt < blocks_retrieved; cur_pkt++) {
+ // Move a packet to our local buffer
+ for (int cur_byte = 0; cur_byte < d_payloadsize; cur_byte++) {
+ d_local_buffer[cur_byte] = d_localqueue->at(0);
+ d_localqueue->pop_front();
+ }
+
+ // Interpret the header if present
+ if (d_header_type != HEADERTYPE_NONE) {
+ uint64_t pkt_seq_num = get_header_seqnum();
+
+ if (d_seq_num > 0) { // d_seq_num will be 0 when this block starts
+ if (pkt_seq_num > d_seq_num) {
+ // Ideally pkt_seq_num = d_seq_num + 1. Therefore this should do += 0
+ // when no packets are dropped.
+ skipped_packets += pkt_seq_num - d_seq_num - 1;
+ }
+
+ // Store as current for next pass.
+ d_seq_num = pkt_seq_num;
+ } else {
+ // just starting. Prime it for no loss on the first packet.
+ d_seq_num = pkt_seq_num;
+ }
+ }
+
+ // Move the data to the output buffer and increment the out index
+ memcpy(&out[out_index], data_ptr, d_precomp_data_size);
+ out_index = out_index + d_precomp_data_size;
+ }
+
+ if (skipped_packets > 0 && d_notify_missed) {
+ std::stringstream msg_stream;
+ msg_stream << "[UDP source:" << d_port
+ << "] missed packets: " << skipped_packets;
+ GR_LOG_WARN(d_logger, msg_stream.str());
+ }
+
+ // If we had less data than requested, it'll be reflected in the return value.
+ return itemsreturned;
+}
+} /* namespace network */
+} /* namespace gr */
diff --git a/gr-network/lib/udp_source_impl.h b/gr-network/lib/udp_source_impl.h
new file mode 100644
index 0000000000..73975608a4
--- /dev/null
+++ b/gr-network/lib/udp_source_impl.h
@@ -0,0 +1,85 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2020 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+
+#ifndef INCLUDED_NETWORK_UDP_SOURCE_IMPL_H
+#define INCLUDED_NETWORK_UDP_SOURCE_IMPL_H
+
+#include <gnuradio/network/udp_source.h>
+#include <boost/asio.hpp>
+#include <boost/asio/ip/udp.hpp>
+#include <boost/circular_buffer.hpp>
+
+#include <gnuradio/network/packet_headers.h>
+
+namespace gr {
+namespace network {
+
+class NETWORK_API udp_source_impl : public udp_source
+{
+protected:
+ bool is_ipv6;
+ size_t d_itemsize;
+ size_t d_veclen;
+ int d_port;
+
+ bool d_notify_missed;
+ bool d_source_zeros;
+ int d_header_type;
+ uint16_t d_payloadsize;
+
+ uint64_t d_seq_num;
+ int d_header_size;
+ int d_partial_frame_counter;
+
+ int d_precomp_data_size;
+ int d_precomp_data_over_item_size;
+ size_t d_block_size;
+
+ char* d_local_buffer;
+
+ boost::system::error_code ec;
+
+ boost::asio::io_service d_io_service;
+ boost::asio::ip::udp::endpoint d_endpoint;
+ boost::asio::ip::udp::socket* d_udpsocket;
+
+ boost::asio::streambuf d_read_buffer;
+
+ // A queue is required because we have 2 different timing
+ // domains: The network packets and the GR work()/scheduler
+ boost::circular_buffer<char>* d_localqueue;
+
+ uint64_t get_header_seqnum();
+
+public:
+ udp_source_impl(size_t itemsize,
+ size_t veclen,
+ int port,
+ int header_type,
+ int payloadsize,
+ bool notify_missed,
+ bool source_zeros,
+ bool ipv6);
+ ~udp_source_impl();
+
+ bool stop();
+
+ size_t data_available();
+ inline size_t netdata_available();
+
+ int work(int noutput_items,
+ gr_vector_const_void_star& input_items,
+ gr_vector_void_star& output_items);
+};
+
+} // namespace network
+} // namespace gr
+
+#endif /* INCLUDED_NETWORK_UDP_SOURCE_IMPL_H */
diff --git a/gr-network/python/network/CMakeLists.txt b/gr-network/python/network/CMakeLists.txt
new file mode 100644
index 0000000000..5cd946cc7b
--- /dev/null
+++ b/gr-network/python/network/CMakeLists.txt
@@ -0,0 +1,33 @@
+# Copyright 2020 Free Software Foundation, Inc.
+#
+# This file was generated by gr_modtool, a tool from the GNU Radio framework
+# This file is a part of gr-network
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+
+########################################################################
+# Include python install macros
+########################################################################
+include(GrPython)
+if(NOT PYTHONINTERP_FOUND)
+ return()
+endif()
+
+########################################################################
+# Install python sources
+########################################################################
+GR_PYTHON_INSTALL(
+ FILES
+ __init__.py
+ tcp_source.py
+ DESTINATION ${GR_PYTHON_DIR}/gnuradio/network
+)
+
+########################################################################
+# Handle the unit tests
+########################################################################
+include(GrTest)
+
+set(GR_TEST_TARGET_DEPS gnuradio-network)
+set(GR_TEST_PYTHON_DIRS ${CMAKE_BINARY_DIR}/swig)
diff --git a/gr-network/python/network/__init__.py b/gr-network/python/network/__init__.py
new file mode 100644
index 0000000000..f5844994bb
--- /dev/null
+++ b/gr-network/python/network/__init__.py
@@ -0,0 +1,20 @@
+#
+# Copyright 2020 Free Software Foundation, Inc.
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+
+# The presence of this file turns this directory into a Python package
+
+'''
+This is the GNU Radio NETWORK module. Place your Python package
+description here (python/__init__.py).
+'''
+from __future__ import unicode_literals
+
+# import swig generated symbols into the network namespace
+from .network_swig import *
+
+# import any pure python here
+#
+from . import tcp_source
diff --git a/gr-network/python/network/tcp_source.py b/gr-network/python/network/tcp_source.py
new file mode 100644
index 0000000000..4e07a68497
--- /dev/null
+++ b/gr-network/python/network/tcp_source.py
@@ -0,0 +1,86 @@
+#
+# Copyright 2009,2019,2020 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+import socket
+import os
+from gnuradio import gr, blocks
+
+def _get_sock_fd(addr, port, server):
+ """
+ Get the file descriptor for the socket.
+ As a client, block on connect, dup the socket descriptor.
+ As a server, block on accept, dup the client descriptor.
+
+ Args:
+ addr: the ip address string
+ port: the tcp port number
+ server: true for server mode, false for client mode
+
+ Returns:
+ the file descriptor number
+ """
+ is_ipv6 = False
+
+ if ":" in addr:
+ sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM, 0)
+ is_ipv6 = True
+ else:
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+
+ if server:
+ try:
+ if is_ipv6:
+ bind_addr = addr.replace("::ffff:", "")
+ sock.bind((bind_addr, port))
+ else:
+ sock.bind((addr, port))
+
+ gr.log.info('Waiting for a connection on port ' + str(port))
+
+ sock.listen(1)
+ clientsock, address = sock.accept()
+ return os.dup(clientsock.fileno())
+ except OSError as e:
+ gr.log.error('Unable to bind to port ' + str(port))
+ gr.log.error('Error: ' + e.strerror)
+
+ if is_ipv6:
+ gr.log.error('IPv6 HINT: If trying to start a local listener, '
+ 'try "::" for the address.')
+ return None
+ except:
+ gr.log.error('Unable to bind to port ' + str(port))
+ return None
+
+ else:
+ sock.connect((addr, port))
+ return os.dup(sock.fileno())
+
+class tcp_source(gr.hier_block2):
+ def __init__(self, itemsize, addr, port, server=True):
+ #init hier block
+ gr.hier_block2.__init__(
+ self, 'tcp_source',
+ gr.io_signature(0, 0, 0),
+ gr.io_signature(1, 1, itemsize),
+ )
+ fd = _get_sock_fd(addr, port, server)
+ self.connect(blocks.file_descriptor_source(itemsize, fd), self)
diff --git a/gr-network/swig/CMakeLists.txt b/gr-network/swig/CMakeLists.txt
new file mode 100644
index 0000000000..7a2f2090ca
--- /dev/null
+++ b/gr-network/swig/CMakeLists.txt
@@ -0,0 +1,43 @@
+# Copyright 2020 Free Software Foundation, Inc.
+#
+# This file was generated by gr_modtool, a tool from the GNU Radio framework
+# This file is a part of gr-network
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+
+include(GrSwig)
+include(GrPython)
+
+########################################################################
+# Setup swig generation
+########################################################################
+set(GR_SWIG_INCLUDE_DIRS $<TARGET_PROPERTY:runtime_swig,INCLUDE_DIRECTORIES>)
+set(GR_SWIG_TARGET_DEPS runtime_swig)
+
+set(GR_SWIG_LIBRARIES gnuradio-network)
+
+set(GR_SWIG_DOC_FILE ${CMAKE_CURRENT_BINARY_DIR}/network_swig_doc.i)
+set(GR_SWIG_DOC_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/../include/gnuradio/network)
+set(GR_SWIG_DOCS_TARGET_DEPS runtime_swig_swig_doc)
+
+set(GR_SWIG_LIBRARIES gnuradio-network)
+GR_SWIG_MAKE(network_swig network_swig.i)
+
+########################################################################
+# Install the build swig module
+########################################################################
+GR_SWIG_INSTALL(
+ TARGETS network_swig
+ DESTINATION ${GR_PYTHON_DIR}/gnuradio/network
+)
+
+########################################################################
+# Install swig .i files for development
+########################################################################
+install(
+ FILES
+ network_swig.i
+ ${CMAKE_CURRENT_BINARY_DIR}/network_swig_doc.i
+ DESTINATION ${GR_INCLUDE_DIR}/gnuradio/swig
+)
diff --git a/gr-network/swig/network_swig.i b/gr-network/swig/network_swig.i
new file mode 100644
index 0000000000..630a35b092
--- /dev/null
+++ b/gr-network/swig/network_swig.i
@@ -0,0 +1,21 @@
+/* -*- c++ -*- */
+
+#define NETWORK_API
+
+%include "gnuradio.i" // the common stuff
+
+//load generated python docstrings
+%include "network_swig_doc.i"
+
+%{
+#include "gnuradio/network/tcp_sink.h"
+#include "gnuradio/network/udp_source.h"
+#include "gnuradio/network/udp_sink.h"
+%}
+
+%include "gnuradio/network/tcp_sink.h"
+GR_SWIG_BLOCK_MAGIC2(network, tcp_sink);
+%include "gnuradio/network/udp_source.h"
+GR_SWIG_BLOCK_MAGIC2(network, udp_source);
+%include "gnuradio/network/udp_sink.h"
+GR_SWIG_BLOCK_MAGIC2(network, udp_sink);