https://github.com/EttusResearch/uhd/commit/adfe953d965e58b5931c1b1968899492c8087cf6
https://bugs.gentoo.org/946371#c12

From adfe953d965e58b5931c1b1968899492c8087cf6 Mon Sep 17 00:00:00 2001
From: Martin Braun <martin.braun@ettus.com>
Date: Tue, 3 Dec 2024 12:05:50 +0100
Subject: [PATCH] uhd: Update ASIO usage to modern style, compatible with Boost
 1.87
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Starting with Boost 1.66 and the corresponding ASIO version, there were
some changes introduced based on the C++ Networking TS. This includes
changes like replacing io_service with io_context, deprecating some
functions, etc. Starting with Boost 1.87, the old style is no longer
supported.

This commit updates all usage of ASIO in a way that makes UHD compatible
with future versions of ASIO. However, this makes UHD no longer
compatible with Boost 1.65 and below.

Summary of changes:
- Replace asio::io_service with asio::io_context
- Replace asio::io_service::strand with
  asio::strand<asio::io_context::executor_type>
  - This implies using asio::post() instead of asio::strand::post()
- Replace asio::buffer_cast<T>(buf) with static_cast<T>(buf.data())
- Update resolve(query) with new API
- Replace references to endpoint_iterator with resolver::results_type
- Replace ip::address::from_string() with ip::make_address()

Co-authored-by: Jörg Hofrichter <joerg.hofrichter@emerson.com>
---
 host/examples/network_relay.cpp               | 18 ++++-----
 .../uhd/transport/nirio/rpc/rpc_client.hpp    | 14 +++----
 .../rpclib/include/rpc/detail/async_writer.h  | 12 +++---
 .../include/rpc/detail/server_session.h       |  6 +--
 host/lib/deps/rpclib/lib/rpc/client.cc        | 24 +++++------
 .../rpclib/lib/rpc/detail/server_session.cc   | 23 +++++------
 host/lib/deps/rpclib/lib/rpc/server.cc        |  4 +-
 .../uhdlib/transport/udp_boost_asio_link.hpp  |  2 +-
 .../include/uhdlib/transport/udp_common.hpp   |  9 ++---
 .../lib/include/uhdlib/utils/eeprom_utils.hpp | 12 +++---
 host/lib/transport/dpdk_simple.cpp            |  4 +-
 host/lib/transport/if_addrs.cpp               |  4 +-
 host/lib/transport/nirio/rpc/rpc_client.cpp   | 24 +++++------
 host/lib/transport/udp_boost_asio_link.cpp    |  2 +-
 host/lib/transport/udp_simple.cpp             | 19 ++++-----
 host/lib/transport/udp_wsa_zero_copy.cpp      |  8 ++--
 host/lib/transport/udp_zero_copy.cpp          |  4 +-
 host/lib/usrp/cores/xport_adapter_ctrl.cpp    |  9 ++---
 host/lib/usrp/usrp1/mb_eeprom.cpp             |  1 +
 host/lib/usrp/usrp2/io_impl.cpp               | 12 +++---
 host/lib/usrp/usrp2/mb_eeprom.cpp             |  9 ++---
 host/lib/usrp/x300/x300_mb_eeprom.cpp         | 32 ++++++++++-----
 .../usrp_clock/octoclock/octoclock_eeprom.cpp |  6 +--
 host/tests/eeprom_utils_test.cpp              | 40 +++++++++++++++----
 24 files changed, 164 insertions(+), 134 deletions(-)

tomjbe@gentoo.org
Modified default capture elements for session.cc according to 
https://github.com/EttusResearch/uhd/commit/2dc7b3e572830c71d49ee0648eef445e7f3abfd6

diff --git a//examples/network_relay.cpp b//examples/network_relay.cpp
index 9105844523..2387f3b2ab 100644
--- a//examples/network_relay.cpp
+++ b//examples/network_relay.cpp
@@ -78,21 +78,21 @@ class udp_relay_type
         : _port(port)
     {
         {
-            asio::ip::udp::resolver resolver(_io_service);
-            asio::ip::udp::resolver::query query(asio::ip::udp::v4(), server_addr, port);
-            asio::ip::udp::endpoint endpoint = *resolver.resolve(query);
+            asio::ip::udp::resolver resolver(_io_context);
+            asio::ip::udp::endpoint endpoint =
+                *resolver.resolve(asio::ip::udp::v4(), server_addr, port).begin();
 
             _server_socket = std::shared_ptr<asio::ip::udp::socket>(
-                new asio::ip::udp::socket(_io_service, endpoint));
+                new asio::ip::udp::socket(_io_context, endpoint));
             resize_buffs(_server_socket, server_rx_size, server_tx_size);
         }
         {
-            asio::ip::udp::resolver resolver(_io_service);
-            asio::ip::udp::resolver::query query(asio::ip::udp::v4(), client_addr, port);
-            asio::ip::udp::endpoint endpoint = *resolver.resolve(query);
+            asio::ip::udp::resolver resolver(_io_context);
+            asio::ip::udp::endpoint endpoint =
+                *resolver.resolve(asio::ip::udp::v4(), client_addr, port).begin();
 
             _client_socket = std::shared_ptr<asio::ip::udp::socket>(
-                new asio::ip::udp::socket(_io_service));
+                new asio::ip::udp::socket(_io_context));
             _client_socket->open(asio::ip::udp::v4());
             _client_socket->connect(endpoint);
             resize_buffs(_client_socket, client_rx_size, client_tx_size);
@@ -173,7 +173,7 @@ class udp_relay_type
 
     const std::string _port;
     boost::thread_group _thread_group;
-    asio::io_service _io_service;
+    asio::io_context _io_context;
     asio::ip::udp::endpoint _endpoint;
     std::mutex _endpoint_mutex;
     socket_type _server_socket, _client_socket;
diff --git a//include/uhd/transport/nirio/rpc/rpc_client.hpp b//include/uhd/transport/nirio/rpc/rpc_client.hpp
index 844e36c763..98f1e2860d 100644
--- a//include/uhd/transport/nirio/rpc/rpc_client.hpp
+++ b//include/uhd/transport/nirio/rpc/rpc_client.hpp
@@ -56,20 +56,20 @@ class rpc_client : private uhd::noncopyable
         const boost::system::error_code& err, size_t transferred, size_t expected);
     void _wait_for_next_response_header();
 
-    inline void _stop_io_service()
+    inline void _stop_io_context()
     {
-        if (_io_service_thread.get()) {
+        if (_io_context_thread.get()) {
             UHD_LOG_DEBUG("NIRIO", "rpc_client stopping...");
-            _io_service.stop();
-            _io_service_thread->join();
-            _io_service_thread.reset();
+            _io_context.stop();
+            _io_context_thread->join();
+            _io_context_thread.reset();
             UHD_LOG_DEBUG("NIRIO", "rpc_client stopped.");
         }
     }
 
     // Services
-    boost::asio::io_service _io_service;
-    std::unique_ptr<boost::thread> _io_service_thread;
+    boost::asio::io_context _io_context;
+    std::unique_ptr<boost::thread> _io_context_thread;
     boost::asio::ip::tcp::socket _socket;
     // Handshake info
     hshake_args_t _hshake_args_client;
diff --git a//lib/deps/rpclib/include/rpc/detail/async_writer.h b//lib/deps/rpclib/include/rpc/detail/async_writer.h
index 1e17f1292a..2b97361c86 100644
--- a//lib/deps/rpclib/include/rpc/detail/async_writer.h
+++ b//lib/deps/rpclib/include/rpc/detail/async_writer.h
@@ -19,9 +19,9 @@ namespace detail {
 //! \brief Common logic for classes that have a write queue with async writing.
 class async_writer : public std::enable_shared_from_this<async_writer> {
 public:
-    async_writer(boost::asio::io_service *io,
+    async_writer(boost::asio::io_context* io,
                  boost::asio::ip::tcp::socket socket)
-        : socket_(std::move(socket)), write_strand_(*io), exit_(false) {}
+        : socket_(std::move(socket)), write_strand_(io->get_executor()), exit_(false) {}
 
     void do_write() {
         if (exit_) {
@@ -31,9 +31,9 @@ class async_writer : public std::enable_shared_from_this<async_writer> {
         auto &item = write_queue_.front();
         // the data in item remains valid until the handler is called
         // since it will still be in the queue physically until then.
-        boost::asio::async_write(
-            socket_, boost::asio::buffer(item.data(), item.size()),
-            write_strand_.wrap(
+        boost::asio::async_write(socket_,
+            boost::asio::buffer(item.data(), item.size()),
+            boost::asio::bind_executor(write_strand_,
                 [this, self](boost::system::error_code ec, std::size_t transferred) {
                     (void)transferred;
                     if (!ec) {
@@ -69,7 +69,7 @@ class async_writer : public std::enable_shared_from_this<async_writer> {
 
 protected:
     boost::asio::ip::tcp::socket socket_;
-    boost::asio::io_service::strand write_strand_;
+    boost::asio::strand<boost::asio::io_context::executor_type> write_strand_;
     std::atomic_bool exit_{false};
     bool exited_ = false;
     std::mutex m_exit_;
diff --git a//lib/deps/rpclib/include/rpc/detail/server_session.h b//lib/deps/rpclib/include/rpc/detail/server_session.h
index 754c0879cd..474e4b589b 100644
--- a//lib/deps/rpclib/include/rpc/detail/server_session.h
+++ b//lib/deps/rpclib/include/rpc/detail/server_session.h
@@ -22,7 +22,7 @@ namespace detail {
 
 class server_session : public async_writer {
 public:
-    server_session(server *srv, boost::asio::io_service *io,
+    server_session(server* srv, boost::asio::io_context* io,
                    boost::asio::ip::tcp::socket socket,
                    std::shared_ptr<dispatcher> disp, bool suppress_exceptions);
     void start();
@@ -34,8 +34,8 @@ class server_session : public async_writer {
 
 private:
     server* parent_;
-    boost::asio::io_service *io_;
-    boost::asio::io_service::strand read_strand_;
+    boost::asio::io_context* io_;
+    boost::asio::strand<boost::asio::io_context::executor_type> read_strand_;
     std::shared_ptr<dispatcher> disp_;
     RPCLIB_MSGPACK::unpacker pac_;
     RPCLIB_MSGPACK::sbuffer output_buf_;
diff --git a//lib/deps/rpclib/lib/rpc/client.cc b//lib/deps/rpclib/lib/rpc/client.cc
index ed4a8e329f..b3d8579832 100644
--- a//lib/deps/rpclib/lib/rpc/client.cc
+++ b//lib/deps/rpclib/lib/rpc/client.cc
@@ -38,7 +38,7 @@ struct client::impl {
     impl(client *parent, std::string const &addr, uint16_t port)
         : parent_(parent),
           io_(),
-          strand_(io_),
+          strand_(io_.get_executor()),
           call_idx_(0),
           addr_(addr),
           port_(port),
@@ -50,11 +50,11 @@ struct client::impl {
         pac_.reserve_buffer(default_buffer_size);
     }
 
-    void do_connect(tcp::resolver::iterator endpoint_iterator) {
+    void do_connect(const tcp::resolver::results_type& endpoints) {
         LOG_INFO("Initiating connection.");
         boost::asio::async_connect(
-            writer_->socket_, endpoint_iterator,
-            [this](boost::system::error_code ec, tcp::resolver::iterator) {
+            writer_->socket_, endpoints,
+            [this](boost::system::error_code ec, tcp::endpoint) {
                 std::unique_lock<std::mutex> lock(mut_connection_finished_);
                 if (!ec) {
                     LOG_INFO("Client connected to {}:{}", addr_, port_);
@@ -101,7 +101,7 @@ struct client::impl {
                             std::get<1>(current_call)
                                 .set_exception(std::current_exception());
                         }
-                        strand_.post(
+                        boost::asio::post(strand_,
                             [this, id]() { ongoing_calls_.erase(id); });
                     }
 
@@ -144,8 +144,8 @@ struct client::impl {
         std::pair<std::string, std::promise<RPCLIB_MSGPACK::object_handle>>;
 
     client *parent_;
-    boost::asio::io_service io_;
-    boost::asio::io_service::strand strand_;
+    boost::asio::io_context io_;
+    boost::asio::strand<boost::asio::io_context::executor_type> strand_;
     std::atomic<int> call_idx_; /// The index of the last call made
     std::unordered_map<uint32_t, call_t> ongoing_calls_;
     std::string addr_;
@@ -164,9 +164,9 @@ struct client::impl {
 client::client(std::string const &addr, uint16_t port)
     : pimpl(new client::impl(this, addr, port)) {
     tcp::resolver resolver(pimpl->io_);
-    auto endpoint_it =
-        resolver.resolve({pimpl->addr_, std::to_string(pimpl->port_)});
-    pimpl->do_connect(endpoint_it);
+    auto endpoints =
+        resolver.resolve(pimpl->addr_, std::to_string(pimpl->port_));
+    pimpl->do_connect(endpoints);
     std::thread io_thread([this]() {
         RPCLIB_CREATE_LOG_CHANNEL(client)
         name_thread("client");
@@ -190,7 +190,7 @@ int client::get_next_call_idx() {
 void client::post(std::shared_ptr<RPCLIB_MSGPACK::sbuffer> buffer, int idx,
                   std::string const &func_name,
                   std::shared_ptr<rsp_promise> p) {
-    pimpl->strand_.post([=]() {
+    boost::asio::post(pimpl->strand_, [buffer, idx, func_name, p, this]() {
         pimpl->ongoing_calls_.insert(
             std::make_pair(idx, std::make_pair(func_name, std::move(*p))));
         pimpl->write(std::move(*buffer));
@@ -198,7 +198,7 @@ void client::post(std::shared_ptr<RPCLIB_MSGPACK::sbuffer> buffer, int idx,
 }
 
 void client::post(RPCLIB_MSGPACK::sbuffer *buffer) {
-    pimpl->strand_.post([=]() {
+    boost::asio::post(pimpl->strand_, [buffer, this]() {
         pimpl->write(std::move(*buffer));
         delete buffer;
     });
diff --git a//lib/deps/rpclib/lib/rpc/detail/server_session.cc b//lib/deps/rpclib/lib/rpc/detail/server_session.cc
index d3e13c89fa..1468a62e5a 100644
--- a//lib/deps/rpclib/lib/rpc/detail/server_session.cc
+++ b//lib/deps/rpclib/lib/rpc/detail/server_session.cc
@@ -22,14 +22,14 @@ namespace detail {
 
 static constexpr std::size_t default_buffer_size = rpc::constants::DEFAULT_BUFFER_SIZE;
 
-server_session::server_session(server *srv, boost::asio::io_service *io,
+server_session::server_session(server *srv, boost::asio::io_context *io,
                                boost::asio::ip::tcp::socket socket,
                                std::shared_ptr<dispatcher> disp,
                                bool suppress_exceptions)
     : async_writer(io, std::move(socket)),
       parent_(srv),
       io_(io),
-      read_strand_(*io),
+      read_strand_(io->get_executor()),
       disp_(disp),
       pac_(),
       suppress_exceptions_(suppress_exceptions) {
@@ -42,7 +42,7 @@ void server_session::start() { do_read(); }
 void server_session::close() {
     LOG_INFO("Closing session.");
     exit_ = true;
-    write_strand_.post([this]() {
+    boost::asio::post(write_strand_, [this]() {
         try {
             socket_.close();
         } catch (const boost::system::system_error&) {
@@ -54,12 +54,11 @@ void server_session::close() {
 void server_session::do_read() {
     auto self(shared_from_this());
     constexpr std::size_t max_read_bytes = default_buffer_size;
-    socket_.async_read_some(
-        boost::asio::buffer(pac_.buffer(), default_buffer_size),
+    socket_.async_read_some(boost::asio::buffer(pac_.buffer(), default_buffer_size),
         // I don't think max_read_bytes needs to be captured explicitly
         // (since it's constexpr), but MSVC insists.
-        read_strand_.wrap([this, self, max_read_bytes](boost::system::error_code ec,
-                                                       std::size_t length) {
+        boost::asio::bind_executor(read_strand_, [this, self, max_read_bytes](boost::system::error_code ec,
+                                                                              std::size_t length) {
             if (!ec) {
                 pac_.buffer_consumed(length);
                 RPCLIB_MSGPACK::unpacked result;
@@ -69,7 +68,7 @@ void server_session::do_read() {
 
                     // any worker thread can take this call
                     auto z = std::shared_ptr<RPCLIB_MSGPACK::zone>(result.zone().release());
-                    io_->post([
+                    boost::asio::post(io_->get_executor(), [
                         this, msg, z
                     ]() {
                         this_handler().clear();
@@ -102,10 +101,10 @@ void server_session::do_read() {
                         if (!resp.is_empty()) {
 #ifdef _MSC_VER
                             // doesn't compile otherwise.
-                            write_strand_.post(
+                            boost::asio::post(write_strand_,
                                 [=]() { write(resp.get_data()); });
 #else
-                            write_strand_.post(
+                            boost::asio::post(write_strand_,
                                 [this, resp, z]() { write(resp.get_data()); });
 #endif
                         }
@@ -114,14 +113,14 @@ void server_session::do_read() {
                             LOG_WARN("Session exit requested from a handler.");
                             // posting through the strand so this comes after
                             // the previous write
-                            write_strand_.post([this]() { exit_ = true; });
+                            boost::asio::post(write_strand_, [this]() { exit_ = true; });
                         }
 
                         if (this_server().stopping_) {
                             LOG_WARN("Server exit requested from a handler.");
                             // posting through the strand so this comes after
                             // the previous write
-                            write_strand_.post(
+                            boost::asio::post(write_strand_,
                                 [this]() { parent_->close_sessions(); });
                         }
                     });
diff --git a//lib/deps/rpclib/lib/rpc/server.cc b//lib/deps/rpclib/lib/rpc/server.cc
index 4facb93a85..d0638cb8fc 100644
--- a//lib/deps/rpclib/lib/rpc/server.cc
+++ b//lib/deps/rpclib/lib/rpc/server.cc
@@ -25,7 +25,7 @@ struct server::impl {
         : parent_(parent),
           io_(),
           acceptor_(io_,
-                    tcp::endpoint(ip::address::from_string(address), port)),
+                    tcp::endpoint(ip::make_address(address), port)),
           socket_(io_),
           suppress_exceptions_(false) {}
 
@@ -66,7 +66,7 @@ struct server::impl {
     }
 
     server *parent_;
-    io_service io_;
+    io_context io_;
     ip::tcp::acceptor acceptor_;
     ip::tcp::socket socket_;
     rpc::detail::thread_group loop_workers_;
diff --git a//lib/include/uhdlib/transport/udp_boost_asio_link.hpp b//lib/include/uhdlib/transport/udp_boost_asio_link.hpp
index 8944aa9991..80b585af73 100644
--- a//lib/include/uhdlib/transport/udp_boost_asio_link.hpp
+++ b//lib/include/uhdlib/transport/udp_boost_asio_link.hpp
@@ -146,7 +146,7 @@ class udp_boost_asio_link : public recv_link_base<udp_boost_asio_link>,
     std::vector<udp_boost_asio_frame_buff> _recv_buffs;
     std::vector<udp_boost_asio_frame_buff> _send_buffs;
 
-    boost::asio::io_service _io_service;
+    boost::asio::io_context _io_context;
     std::shared_ptr<boost::asio::ip::udp::socket> _socket;
     int _sock_fd;
     adapter_id_t _adapter_id;
diff --git a//lib/include/uhdlib/transport/udp_common.hpp b//lib/include/uhdlib/transport/udp_common.hpp
index 96146a7017..b4b0ec309f 100644
--- a//lib/include/uhdlib/transport/udp_common.hpp
+++ b//lib/include/uhdlib/transport/udp_common.hpp
@@ -81,17 +81,16 @@ UHD_INLINE bool wait_for_recv_ready(int sock_fd, int32_t timeout_ms)
 }
 
 UHD_INLINE socket_sptr open_udp_socket(
-    const std::string& addr, const std::string& port, boost::asio::io_service& io_service)
+    const std::string& addr, const std::string& port, boost::asio::io_context& io_context)
 {
     using udp = boost::asio::ip::udp;
 
     // resolve the address
-    udp::resolver resolver(io_service);
-    udp::resolver::query query(udp::v4(), addr, port);
-    udp::endpoint receiver_endpoint = *resolver.resolve(query);
+    udp::resolver resolver(io_context);
+    udp::endpoint receiver_endpoint = *resolver.resolve(udp::v4(), addr, port).begin();
 
     // create, open, and connect the socket
-    socket_sptr socket = socket_sptr(new udp::socket(io_service));
+    socket_sptr socket = socket_sptr(new udp::socket(io_context));
     socket->open(udp::v4());
     socket->connect(receiver_endpoint);
 
diff --git a//lib/include/uhdlib/utils/eeprom_utils.hpp b//lib/include/uhdlib/utils/eeprom_utils.hpp
index d3be4c03c4..ea05136738 100644
--- a//lib/include/uhdlib/utils/eeprom_utils.hpp
+++ b//lib/include/uhdlib/utils/eeprom_utils.hpp
@@ -10,7 +10,6 @@
 #include <uhd/types/dict.hpp>
 #include <uhd/types/mac_addr.hpp>
 #include <uhd/utils/log.hpp>
-#include <boost/asio/ip/address_v4.hpp>
 #include <string>
 #include <vector>
 
@@ -29,7 +28,7 @@ std::string uint16_bytes_to_string(const uhd::byte_vector_t& bytes);
  * see if the resulting contents will contain duplicates.  Useful error
  * messages are logged describing any duplicates.
  *
- * <field_type> must provide to_string() and from_string() functions
+ * <field_type> must provide from_string() functions
  *
  * \param error_label Label to put on error messages
  * \param new_eeprom New EEPROM contents
@@ -38,12 +37,13 @@ std::string uint16_bytes_to_string(const uhd::byte_vector_t& bytes);
  * \param keys Keys to examine for duplicate values
  * \return true if duplicates are found, false if not
  */
-template <typename field_type>
+template <typename str_normalizer_type>
 bool check_for_duplicates(const std::string& error_label,
     const uhd::dict<std::string, std::string>& new_eeprom,
     const uhd::dict<std::string, std::string>& curr_eeprom,
     const std::string& category,
-    const std::vector<std::string>& keys)
+    const std::vector<std::string>& keys,
+    str_normalizer_type&& str_normalizer)
 {
     bool has_duplicates = false;
     for (size_t i = 0; i < keys.size(); i++) {
@@ -54,7 +54,7 @@ bool check_for_duplicates(const std::string& error_label,
             continue;
         }
 
-        auto value = field_type::from_string(new_eeprom[key]).to_string();
+        auto value = str_normalizer(new_eeprom[key]);
 
         // Check other values in new_eeprom for duplicate
         // Starting at key index i+1 so the same duplicate is not found twice
@@ -63,7 +63,7 @@ bool check_for_duplicates(const std::string& error_label,
             if (not new_eeprom.has_key(other_key)) {
                 continue;
             }
-            auto other_value = field_type::from_string(new_eeprom[other_key]).to_string();
+            auto other_value = str_normalizer(new_eeprom[other_key]);
             if (value == other_value) {
                 // Value is a duplicate of another supplied value
                 UHD_LOG_ERROR(error_label,
diff --git a//lib/transport/dpdk_simple.cpp b//lib/transport/dpdk_simple.cpp
index e258ddb2f8..f2787ba8c8 100644
--- a//lib/transport/dpdk_simple.cpp
+++ b//lib/transport/dpdk_simple.cpp
@@ -96,7 +96,7 @@ class dpdk_simple_impl : public dpdk_simple
         // Extract buff and sanity check
         const size_t nbytes = boost::asio::buffer_size(user_buff);
         UHD_ASSERT_THROW(nbytes <= _link->get_send_frame_size())
-        const uint8_t* user_data = boost::asio::buffer_cast<const uint8_t*>(user_buff);
+        const uint8_t* user_data = static_cast<const uint8_t*>(user_buff.data());
 
         // Get send buff
         auto buff = _send_io->get_send_buff(SEND_TIMEOUT_MS);
@@ -120,7 +120,7 @@ class dpdk_simple_impl : public dpdk_simple
     size_t recv(const boost::asio::mutable_buffer& user_buff, double timeout) override
     {
         size_t user_buff_size = boost::asio::buffer_size(user_buff);
-        uint8_t* user_data    = boost::asio::buffer_cast<uint8_t*>(user_buff);
+        uint8_t* user_data    = static_cast<uint8_t*>(user_buff.data());
 
         auto buff = _recv_io->get_recv_buff(static_cast<int32_t>(timeout * 1e3));
         if (!buff) {
diff --git a//lib/transport/if_addrs.cpp b//lib/transport/if_addrs.cpp
index a1cb6909f0..4c43c95d57 100644
--- a//lib/transport/if_addrs.cpp
+++ b//lib/transport/if_addrs.cpp
@@ -50,8 +50,8 @@ std::vector<uhd::transport::if_addrs_t> uhd::transport::get_if_addrs(void)
                        == boost::asio::ip::address_v4(0)) {
                 // manually calculate broadcast address
                 // https://svn.boost.org/trac/boost/ticket/5198
-                const uint32_t addr  = sockaddr_to_ip_addr(iter->ifa_addr).to_ulong();
-                const uint32_t mask  = sockaddr_to_ip_addr(iter->ifa_netmask).to_ulong();
+                const uint32_t addr  = sockaddr_to_ip_addr(iter->ifa_addr).to_uint();
+                const uint32_t mask  = sockaddr_to_ip_addr(iter->ifa_netmask).to_uint();
                 const uint32_t bcast = (addr & mask) | ~mask;
                 if_addr.bcast        = boost::asio::ip::address_v4(bcast).to_string();
             }
diff --git a//lib/transport/nirio/rpc/rpc_client.cpp b//lib/transport/nirio/rpc/rpc_client.cpp
index 16dd5aa823..aaa9753ee9 100644
--- a//lib/transport/nirio/rpc/rpc_client.cpp
+++ b//lib/transport/nirio/rpc/rpc_client.cpp
@@ -27,7 +27,7 @@ rpc_client::rpc_client(const std::string& server,
     const std::string& port,
     uint32_t process_id,
     uint32_t host_id)
-    : _socket(_io_service), _hshake_args_server()
+    : _socket(_io_context), _hshake_args_server()
 {
     // Fill in handshake info
     _hshake_args_client.version             = CURRENT_VERSION;
@@ -38,16 +38,14 @@ rpc_client::rpc_client(const std::string& server,
 
     try {
         // Synchronous resolve + connect
-        tcp::resolver resolver(_io_service);
-        // Create flags object with all special flags disabled. Especially the following:
+        tcp::resolver resolver(_io_context);
+        // All special flags disabled. Especially the following:
         //- address_configured: Only return addresses if a non-loopback address is
         // configured for the system.
         //- numeric_host: No name resolution should be attempted for host
         //- numeric_service: No name resolution should be attempted for service
-        tcp::resolver::query::flags query_flags(tcp::resolver::query::passive);
-        tcp::resolver::query query(tcp::v4(), server, port, query_flags);
-        tcp::resolver::iterator iterator = resolver.resolve(query);
-        boost::asio::connect(_socket, iterator);
+        auto endpoints = resolver.resolve(server, port, tcp::resolver::passive);
+        boost::asio::connect(_socket, endpoints);
 
         UHD_LOGGER_TRACE("NIRIO") << "rpc_client connected to server.";
 
@@ -73,10 +71,10 @@ rpc_client::rpc_client(const std::string& server,
                 UHD_LOGGER_TRACE("NIRIO") << "rpc_client bound to server.";
                 _wait_for_next_response_header();
 
-                // Spawn a thread for the io_service callback handler. This thread will
+                // Spawn a thread for the io_context callback handler. This thread will
                 // run until rpc_client is destroyed.
-                _io_service_thread.reset(new boost::thread(
-                    boost::bind(&boost::asio::io_service::run, &_io_service)));
+                _io_context_thread.reset(new boost::thread(
+                    boost::bind(&boost::asio::io_context::run, &_io_context)));
             } else {
                 UHD_LOGGER_DEBUG("NIRIO") << "rpc_client handshake failed.";
                 _exec_err.assign(boost::asio::error::connection_refused,
@@ -100,7 +98,7 @@ rpc_client::rpc_client(const std::string& server,
 
 rpc_client::~rpc_client()
 {
-    _stop_io_service();
+    _stop_io_context();
 }
 
 const boost::system::error_code& rpc_client::call(func_id_t func_id,
@@ -110,7 +108,7 @@ const boost::system::error_code& rpc_client::call(func_id_t func_id,
 {
     std::unique_lock<std::mutex> lock(_mutex);
 
-    if (_io_service_thread.get()) {
+    if (_io_context_thread.get()) {
         _request.header.func_id = func_id;
         in_args.store(_request.data);
         _request.header.func_args_size = uhd::narrow_cast<uint32_t>(_request.data.size());
@@ -147,7 +145,7 @@ const boost::system::error_code& rpc_client::call(func_id_t func_id,
             UHD_LOGGER_DEBUG("NIRIO") << "rpc_client connection dropped.";
             _exec_err.assign(boost::asio::error::connection_aborted,
                 boost::asio::error::get_system_category());
-            _stop_io_service();
+            _stop_io_context();
         }
 
         // Verify that we are talking to the correct endpoint
diff --git a//lib/transport/udp_boost_asio_link.cpp b//lib/transport/udp_boost_asio_link.cpp
index f91bad09e1..b6a6b550c1 100644
--- a//lib/transport/udp_boost_asio_link.cpp
+++ b//lib/transport/udp_boost_asio_link.cpp
@@ -37,7 +37,7 @@ udp_boost_asio_link::udp_boost_asio_link(
     }
 
     // create, open, and connect the socket
-    _socket  = open_udp_socket(addr, port, _io_service);
+    _socket  = open_udp_socket(addr, port, _io_context);
     _sock_fd = _socket->native_handle();
 
     auto info   = udp_boost_asio_adapter_info(*_socket);
diff --git a//lib/transport/udp_simple.cpp b//lib/transport/udp_simple.cpp
index c83e72d03b..2d031f2b00 100644
--- a//lib/transport/udp_simple.cpp
+++ b//lib/transport/udp_simple.cpp
@@ -8,7 +8,6 @@
 #include <uhd/transport/udp_simple.hpp>
 #include <uhd/utils/log.hpp>
 #include <uhdlib/transport/udp_common.hpp>
-#include <boost/format.hpp>
 
 using namespace uhd::transport;
 namespace asio = boost::asio;
@@ -23,17 +22,19 @@ class udp_simple_impl : public udp_simple
         const std::string& addr, const std::string& port, bool bcast, bool connect)
         : _connected(connect)
     {
-        UHD_LOGGER_TRACE("UDP")
-            << boost::format("Creating udp transport for %s %s") % addr % port;
+        UHD_LOG_TRACE("UDP", "Creating udp transport for " << addr << " " << port);
 
         // resolve the address
-        asio::ip::udp::resolver resolver(_io_service);
-        asio::ip::udp::resolver::query query(
-            asio::ip::udp::v4(), addr, port, asio::ip::resolver_query_base::all_matching);
-        _send_endpoint = *resolver.resolve(query);
+        asio::ip::udp::resolver resolver(_io_context);
+        _send_endpoint = *resolver
+                              .resolve(asio::ip::udp::v4(),
+                                  addr,
+                                  port,
+                                  asio::ip::resolver_query_base::all_matching)
+                              .begin();
 
         // create and open the socket
-        _socket = socket_sptr(new asio::ip::udp::socket(_io_service));
+        _socket = socket_sptr(new asio::ip::udp::socket(_io_context));
         _socket->open(asio::ip::udp::v4());
 
         // allow broadcasting
@@ -72,7 +73,7 @@ class udp_simple_impl : public udp_simple
 
 private:
     bool _connected;
-    asio::io_service _io_service;
+    asio::io_context _io_context;
     socket_sptr _socket;
     asio::ip::udp::endpoint _send_endpoint;
     asio::ip::udp::endpoint _recv_endpoint;
diff --git a//lib/transport/udp_wsa_zero_copy.cpp b//lib/transport/udp_wsa_zero_copy.cpp
index 55773296fe..f189396361 100644
--- a//lib/transport/udp_wsa_zero_copy.cpp
+++ b//lib/transport/udp_wsa_zero_copy.cpp
@@ -216,10 +216,10 @@ class udp_zero_copy_wsa_impl : public udp_zero_copy
         UHD_ASSERT_THROW(_num_send_frames <= WSA_MAXIMUM_WAIT_EVENTS);
 
         // resolve the address
-        asio::io_service io_service;
-        asio::ip::udp::resolver resolver(io_service);
-        asio::ip::udp::resolver::query query(asio::ip::udp::v4(), addr, port);
-        asio::ip::udp::endpoint receiver_endpoint = *resolver.resolve(query);
+        asio::io_context io_context;
+        asio::ip::udp::resolver resolver(io_context);
+        asio::ip::udp::endpoint receiver_endpoint =
+            *resolver.resolve(asio::ip::udp::v4(), addr, port).begin();
 
         // create the socket
         _sock_fd =
diff --git a//lib/transport/udp_zero_copy.cpp b//lib/transport/udp_zero_copy.cpp
index be527be5cb..1a43f9d6be 100644
--- a//lib/transport/udp_zero_copy.cpp
+++ b//lib/transport/udp_zero_copy.cpp
@@ -161,7 +161,7 @@ class udp_zero_copy_asio_impl : public udp_zero_copy
         check_registry_for_fast_send_threshold(this->get_send_frame_size());
 #endif /*CHECK_REG_SEND_THRESH*/
 
-        _socket  = open_udp_socket(addr, port, _io_service);
+        _socket  = open_udp_socket(addr, port, _io_context);
         _sock_fd = _socket->native_handle();
 
         UHD_LOGGER_TRACE("UDP") << boost::format("Local UDP socket endpoint: %s:%s")
@@ -252,7 +252,7 @@ class udp_zero_copy_asio_impl : public udp_zero_copy
     size_t _next_recv_buff_index, _next_send_buff_index;
 
     // asio guts -> socket and service
-    asio::io_service _io_service;
+    asio::io_context _io_context;
     socket_sptr _socket;
     int _sock_fd;
 };
diff --git a//lib/usrp/cores/xport_adapter_ctrl.cpp b//lib/usrp/cores/xport_adapter_ctrl.cpp
index 224f51ba22..9b3556ad3a 100644
--- a//lib/usrp/cores/xport_adapter_ctrl.cpp
+++ b//lib/usrp/cores/xport_adapter_ctrl.cpp
@@ -28,13 +28,12 @@ std::pair<uint32_t, uint32_t> cast_ipv4_and_port(
     const std::string& ipv4, const std::string& port)
 {
     using namespace boost::asio;
-    io_service io_service;
-    ip::udp::resolver resolver(io_service);
+    io_context io_context;
+    ip::udp::resolver resolver(io_context);
     try {
-        ip::udp::resolver::query query(ip::udp::v4(), ipv4, port);
-        ip::udp::endpoint endpoint = *resolver.resolve(query);
+        ip::udp::endpoint endpoint = *(resolver.resolve(ipv4, port).begin());
         return {
-            uint32_t(endpoint.address().to_v4().to_ulong()), uint32_t(endpoint.port())};
+            uint32_t(endpoint.address().to_v4().to_uint()), uint32_t(endpoint.port())};
     } catch (const std::exception&) {
         throw uhd::value_error("Invalid UDP address: " + ipv4 + ":" + port);
     }
diff --git a//lib/usrp/usrp1/mb_eeprom.cpp b//lib/usrp/usrp1/mb_eeprom.cpp
index 756a103953..e5648dd34d 100644
--- a//lib/usrp/usrp1/mb_eeprom.cpp
+++ b//lib/usrp/usrp1/mb_eeprom.cpp
@@ -8,6 +8,7 @@
 #include <uhd/types/byte_vector.hpp>
 #include <uhd/usrp/mboard_eeprom.hpp>
 #include <uhdlib/utils/eeprom_utils.hpp>
+#include <boost/asio.hpp>
 
 namespace {
 const uint8_t USRP1_EEPROM_ADDR = 0x50;
diff --git a//lib/usrp/usrp2/io_impl.cpp b//lib/usrp/usrp2/io_impl.cpp
index c58787e3e5..48ab7b5f0e 100644
--- a//lib/usrp/usrp2/io_impl.cpp
+++ b//lib/usrp/usrp2/io_impl.cpp
@@ -415,12 +415,12 @@ void usrp2_impl::program_stream_dest(
                              "IPv4 Address: %s, UDP Port: %s")
                    % args.args["addr"] % args.args["port"];
 
-        asio::io_service io_service;
-        asio::ip::udp::resolver resolver(io_service);
-        asio::ip::udp::resolver::query query(
-            asio::ip::udp::v4(), args.args["addr"], args.args["port"]);
-        asio::ip::udp::endpoint endpoint = *resolver.resolve(query);
-        stream_ctrl.ip_addr = uhd::htonx(uint32_t(endpoint.address().to_v4().to_ulong()));
+        asio::io_context io_context;
+        asio::ip::udp::resolver resolver(io_context);
+        asio::ip::udp::endpoint endpoint =
+            *resolver.resolve(asio::ip::udp::v4(), args.args["addr"], args.args["port"])
+                 .begin();
+        stream_ctrl.ip_addr  = uhd::htonx(uint32_t(endpoint.address().to_v4().to_uint()));
         stream_ctrl.udp_port = uhd::htonx(uint32_t(endpoint.port()));
 
         for (size_t i = 0; i < 3; i++) {
diff --git a//lib/usrp/usrp2/mb_eeprom.cpp b//lib/usrp/usrp2/mb_eeprom.cpp
index 7bfe6159d0..2b01c0bf40 100644
--- a//lib/usrp/usrp2/mb_eeprom.cpp
+++ b//lib/usrp/usrp2/mb_eeprom.cpp
@@ -141,8 +141,7 @@ void usrp2_impl::set_mb_eeprom(const std::string& mb, const mboard_eeprom_t& mb_
 
     if (mb_eeprom.has_key("ip-addr")) {
         byte_vector_t ip_addr_bytes(4);
-        byte_copy(
-            boost::asio::ip::address_v4::from_string(mb_eeprom["ip-addr"]).to_bytes(),
+        byte_copy(boost::asio::ip::make_address_v4(mb_eeprom["ip-addr"]).to_bytes(),
             ip_addr_bytes);
         iface->write_eeprom(
             N200_EEPROM_ADDR, offsetof(n200_eeprom_map, ip_addr), ip_addr_bytes);
@@ -150,8 +149,7 @@ void usrp2_impl::set_mb_eeprom(const std::string& mb, const mboard_eeprom_t& mb_
 
     if (mb_eeprom.has_key("subnet")) {
         byte_vector_t ip_addr_bytes(4);
-        byte_copy(
-            boost::asio::ip::address_v4::from_string(mb_eeprom["subnet"]).to_bytes(),
+        byte_copy(boost::asio::ip::make_address_v4(mb_eeprom["subnet"]).to_bytes(),
             ip_addr_bytes);
         iface->write_eeprom(
             N200_EEPROM_ADDR, offsetof(n200_eeprom_map, subnet), ip_addr_bytes);
@@ -159,8 +157,7 @@ void usrp2_impl::set_mb_eeprom(const std::string& mb, const mboard_eeprom_t& mb_
 
     if (mb_eeprom.has_key("gateway")) {
         byte_vector_t ip_addr_bytes(4);
-        byte_copy(
-            boost::asio::ip::address_v4::from_string(mb_eeprom["gateway"]).to_bytes(),
+        byte_copy(boost::asio::ip::make_address_v4(mb_eeprom["gateway"]).to_bytes(),
             ip_addr_bytes);
         iface->write_eeprom(
             N200_EEPROM_ADDR, offsetof(n200_eeprom_map, gateway), ip_addr_bytes);
diff --git a//lib/usrp/x300/x300_mb_eeprom.cpp b//lib/usrp/x300/x300_mb_eeprom.cpp
index e0e6072aa1..273ad2b1ed 100644
--- a//lib/usrp/x300/x300_mb_eeprom.cpp
+++ b//lib/usrp/x300/x300_mb_eeprom.cpp
@@ -9,6 +9,7 @@
 #include <uhd/types/serial.hpp>
 #include <uhd/usrp/mboard_eeprom.hpp>
 #include <uhdlib/utils/eeprom_utils.hpp>
+#include <boost/asio.hpp>
 
 namespace {
 const uint8_t X300_EEPROM_ADDR = 0x50;
@@ -122,10 +123,22 @@ void uhd::usrp::x300::set_mb_eeprom(
         "ip-addr0", "ip-addr1", "ip-addr2", "ip-addr3"};
 
     // make sure there are no duplicate values
-    if (check_for_duplicates<uhd::mac_addr_t>(
-            "X300", mb_eeprom, curr_eeprom, "MAC address", mac_keys)
-        or check_for_duplicates<boost::asio::ip::address_v4>(
-            "X300", mb_eeprom, curr_eeprom, "IP address", ip_keys)) {
+    if (check_for_duplicates("X300",
+            mb_eeprom,
+            curr_eeprom,
+            "MAC address",
+            mac_keys,
+            [](const std::string& str) {
+                return mac_addr_t::from_string(str).to_string();
+            })
+        or check_for_duplicates("X300",
+            mb_eeprom,
+            curr_eeprom,
+            "IP address",
+            ip_keys,
+            [](const std::string& str) {
+                return boost::asio::ip::make_address(str).to_string();
+            })) {
         throw uhd::value_error(
             "Duplicate values not permitted - write to EEPROM aborted");
     }
@@ -161,8 +174,7 @@ void uhd::usrp::x300::set_mb_eeprom(
     // store the ip addresses
     byte_vector_t ip_addr_bytes(4);
     if (mb_eeprom.has_key("gateway")) {
-        byte_copy(
-            boost::asio::ip::address_v4::from_string(mb_eeprom["gateway"]).to_bytes(),
+        byte_copy(boost::asio::ip::make_address_v4(mb_eeprom["gateway"]).to_bytes(),
             ip_addr_bytes);
         iface->write_eeprom(
             X300_EEPROM_ADDR, offsetof(x300_eeprom_map, gateway), ip_addr_bytes);
@@ -170,8 +182,8 @@ void uhd::usrp::x300::set_mb_eeprom(
     for (size_t i = 0; i < 4; i++) {
         const std::string n(1, char(i) + '0');
         if (mb_eeprom.has_key("ip-addr" + n)) {
-            byte_copy(boost::asio::ip::address_v4::from_string(mb_eeprom["ip-addr" + n])
-                          .to_bytes(),
+            byte_copy(
+                boost::asio::ip::make_address_v4(mb_eeprom["ip-addr" + n]).to_bytes(),
                 ip_addr_bytes);
             iface->write_eeprom(X300_EEPROM_ADDR,
                 offsetof(x300_eeprom_map, ip_addr) + (i * 4),
@@ -179,8 +191,8 @@ void uhd::usrp::x300::set_mb_eeprom(
         }
 
         if (mb_eeprom.has_key("subnet" + n)) {
-            byte_copy(boost::asio::ip::address_v4::from_string(mb_eeprom["subnet" + n])
-                          .to_bytes(),
+            byte_copy(
+                boost::asio::ip::make_address_v4(mb_eeprom["subnet" + n]).to_bytes(),
                 ip_addr_bytes);
             iface->write_eeprom(X300_EEPROM_ADDR,
                 offsetof(x300_eeprom_map, subnet) + (i * 4),
diff --git a//lib/usrp_clock/octoclock/octoclock_eeprom.cpp b//lib/usrp_clock/octoclock/octoclock_eeprom.cpp
index 9023c6607a..adddb23f3e 100644
--- a//lib/usrp_clock/octoclock/octoclock_eeprom.cpp
+++ b//lib/usrp_clock/octoclock/octoclock_eeprom.cpp
@@ -99,7 +99,7 @@ void octoclock_eeprom_t::_store() const
     // IP address
     if ((*this).has_key("ip-addr")) {
         ip_v4::bytes_type ip_addr_bytes =
-            ip_v4::from_string((*this)["ip-addr"]).to_bytes();
+            boost::asio::ip::make_address_v4((*this)["ip-addr"]).to_bytes();
         memcpy(&eeprom_out->ip_addr, &ip_addr_bytes, 4);
         eeprom_out->ip_addr = uhd::htonx<uint32_t>(eeprom_out->ip_addr);
     }
@@ -107,7 +107,7 @@ void octoclock_eeprom_t::_store() const
     // Default router
     if ((*this).has_key("gateway")) {
         ip_v4::bytes_type dr_addr_bytes =
-            ip_v4::from_string((*this)["gateway"]).to_bytes();
+            boost::asio::ip::make_address_v4((*this)["gateway"]).to_bytes();
         memcpy(&eeprom_out->dr_addr, &dr_addr_bytes, 4);
         eeprom_out->dr_addr = uhd::htonx<uint32_t>(eeprom_out->dr_addr);
     }
@@ -115,7 +115,7 @@ void octoclock_eeprom_t::_store() const
     // Netmask
     if ((*this).has_key("netmask")) {
         ip_v4::bytes_type netmask_bytes =
-            ip_v4::from_string((*this)["netmask"]).to_bytes();
+            boost::asio::ip::make_address_v4((*this)["netmask"]).to_bytes();
         memcpy(&eeprom_out->netmask, &netmask_bytes, 4);
         eeprom_out->netmask = uhd::htonx<uint32_t>(eeprom_out->netmask);
     }
diff --git a//tests/eeprom_utils_test.cpp b//tests/eeprom_utils_test.cpp
index 728b4b8b67..57d107a177 100644
--- a//tests/eeprom_utils_test.cpp
+++ b//tests/eeprom_utils_test.cpp
@@ -44,13 +44,37 @@ BOOST_AUTO_TEST_CASE(test_eeprom_duplicate_check)
         map_list_of("0", "b")("1", "B");
     const std::vector<std::string> keys = {"0", "1", "2"};
 
-    BOOST_CHECK_EQUAL(check_for_duplicates<upper_case_char>(
-                          "TEST", new_eeprom_no_dups, curr_eeprom, "Test Value", keys),
+    BOOST_CHECK_EQUAL(check_for_duplicates("TEST",
+                          new_eeprom_no_dups,
+                          curr_eeprom,
+                          "Test Value",
+                          keys,
+                          [](const std::string& str) {
+                              return upper_case_char::from_string(str).to_string();
+                          }),
         false);
-    BOOST_CHECK(check_for_duplicates<upper_case_char>(
-        "TEST", new_eeprom_dups_in_curr, curr_eeprom, "Test Value", keys));
-    BOOST_CHECK(check_for_duplicates<upper_case_char>(
-        "TEST", new_eeprom_dups_in_new, curr_eeprom, "Test Value", keys));
-    BOOST_CHECK(check_for_duplicates<upper_case_char>(
-        "TEST", new_eeprom_dups_in_both, curr_eeprom, "Test Value", keys));
+    BOOST_CHECK(check_for_duplicates("TEST",
+        new_eeprom_dups_in_curr,
+        curr_eeprom,
+        "Test Value",
+        keys,
+        [](const std::string& str) {
+            return upper_case_char::from_string(str).to_string();
+        }));
+    BOOST_CHECK(check_for_duplicates("TEST",
+        new_eeprom_dups_in_new,
+        curr_eeprom,
+        "Test Value",
+        keys,
+        [](const std::string& str) {
+            return upper_case_char::from_string(str).to_string();
+        }));
+    BOOST_CHECK(check_for_duplicates("TEST",
+        new_eeprom_dups_in_both,
+        curr_eeprom,
+        "Test Value",
+        keys,
+        [](const std::string& str) {
+            return upper_case_char::from_string(str).to_string();
+        }));
 }
