Remove Sock::Get() and Sock::Sock() #26312

pull vasild wants to merge 6 commits into bitcoin:master from vasild:remove_Sock_Get changing 9 files +62 −55
  1. vasild commented at 8:28 am on October 14, 2022: contributor

    This is a piece of #21878, chopped off to ease review.

    Peeking at the underlying socket file descriptor of Sock and checkig if it is INVALID_SOCKET is bad encapsulation and stands in the way of testing/mocking/fuzzing.

    Instead use an empty unique_ptr to denote that there is no valid socket where appropriate or outright remove such checks where they are not necessary.

    The default constructor Sock::Sock() is unnecessary now after recent changes, thus remove it.

  2. DrahtBot commented at 10:46 am on October 14, 2022: contributor

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    ACK ajtowns, jonatack
    Concept ACK theStack

    If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #27375 (net: support unix domain sockets for -proxy and -onion by pinheadmz)
    • #26812 (test: add end-to-end tests for CConnman and PeerManager by vasild)
    • #21878 (Make all networking code mockable by vasild)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

  3. yancyribbens commented at 3:06 am on October 15, 2022: contributor
    Why not add additional testing/mocking/fuzzing in this PR since this seems to be laying the groundwork for that?
  4. vasild commented at 7:23 am on October 17, 2022: contributor
    @yancyribbens, to ease review. Right now, #21878 consists of this PR + the tests (it is almost complete :balloon:). If somebody has spare review cycles they can review/ACK #21878 directly.
  5. yancyribbens commented at 8:43 am on October 17, 2022: contributor
    @vasild If the tests are not yet complete, then that may change this PR, right? Besides adding more safety, seeing the accompanying tests would make this easier (for me anyway) to review.
  6. vasild commented at 10:31 am on October 17, 2022: contributor

    If the tests are not yet complete, then that may change this PR, right?

    The tests are “complete” in a sense that they are “production ready” and can be merged. “Not complete” in a sense that more tests can be added. I do not think that tweaking the tests can change this PR. The point of #21878 is to have high level code not deal with int sockets (file descriptor), but to deal with Sock instead, which can be mocked together with all the relevant operations (connect, accept, read, write, etc).

    Besides adding more safety, seeing the accompanying tests would make this easier (for me anyway) to review.

    The tests are in #21878, feel free to look at them :heart:

  7. yancyribbens commented at 10:54 am on October 17, 2022: contributor

    .. to have high level code not deal with int sockets (file descriptor), but to deal with Sock instead

    Thanks for the additional explanation. I was wondering if you could explain this a bit more. It’s been a while since i’ve done anything with int sockets but if I remember, it was in C (not C++). Is Sock a C++ construct that makes it easier to Mock?

    The tests are in #21878, feel free to look at them heart

    I looked over 21878 and I see there’s some additional fuzz testing however I don’t see the Mocks that this PR enables. Am I missing the place where the Mocks are tested or is it yet to be added? Would this PR be merged before 21878?

  8. vasild commented at 9:22 am on October 25, 2022: contributor

    The int sockets is the API provided by the OS. It is in C. We call it from the C++ code.

    Before #21878 we would use that OS C API directly from all over the place. E.g.:

    0int s = socket(...); // create the socket, see man 2 socket
    1...
    2connect(s, to_addr); // see man 2 connect
    

    The problem with this is that in order to test it we have to create a real socket that really connects to the given address which is very inconvenient. It cannot be mocked.

    #21878 aims to replace all such calls to the operating system with constructs like

    0Sock sock = CreateSock(); // can return Sock, FuzzedSock, StaticContentsSock or another class that implements the interface
    1sock->Connect(to_addr);
    

    This way a mock Sock class can be used and the high level code avoids calling the OS socket API at all in tests or dealing/touching int sockets at all. The last piece of that is the removal of Sock::Get() and changing the high level code which checks whether the int socket stored in Sock is INVALID_SOCKET.

  9. yancyribbens commented at 9:28 am on October 25, 2022: contributor

    @vasild

    The problem with this is that in order to test it we have to create a real socket that really connects to the given address which is very inconvenient. It cannot be mocked.

    I understand. What I am asking is if you wouldn’t mind adding the Mock tests to this PR, or create a new PR with the Mocks before merging this one?

  10. vasild commented at 10:18 am on October 25, 2022: contributor

    What I am asking is if you wouldn’t mind adding the Mock tests to this PR,

    I assume that by “the Mock tests” you mean the tests that are in the last 4 commits of #21878, right? If I add them to this PR then this PR would be the same as #21878.

    I created this PR as a smaller piece of #21878 to ease review. If you want to peek or fully review the tests, then see the last 4 commits in #21878.

    or create a new PR with the Mocks before merging this one?

    Because those tests depend on removing the Sock::Get() call which is done in this PR. If the tests get merged first, this may happen: CConnman::OpenNetworkConnection() -> CConnman::ConnectNode() -> i2p::sam::Session::Connect() and later i2p::sam::Session::~Session() -> i2p::sam::Session::Disconnect() -> Sock::Get(). Calling Get() on FuzzedSock is a bit fishy, the high level code shouldn’t peek at the internal int socket and make decisions based on its value.

  11. yancyribbens commented at 11:28 am on October 25, 2022: contributor

    @vasild

    Are there any Mock tests that are not part of fuzz tests?

  12. vasild commented at 1:49 pm on October 25, 2022: contributor
    There is one in src/test/i2p_tests.cpp.
  13. yancyribbens commented at 3:45 pm on October 25, 2022: contributor
    Which PR is the one Mock in src/test/i2p_tests.cpp, or is it already merged?
  14. vasild commented at 7:19 am on October 26, 2022: contributor
    It is already merged.
  15. yancyribbens commented at 8:34 am on October 26, 2022: contributor
    I’m confused. I thought this PR was required before a Mock could be used.
  16. vasild commented at 10:36 am on October 26, 2022: contributor

    FuzzedSock and StaticContentsSock are mock implementations of Sock that are already used in master.

    Depending on the code being tested various methods of Sock (or a mocked implementation) are going to be called. For example, if you write an unit or fuzz test for CConnman::SocketSendData() that is only going to invoke Sock::Send().

  17. DrahtBot added the label Needs rebase on Nov 25, 2022
  18. vasild force-pushed on Dec 12, 2022
  19. vasild commented at 10:47 am on December 12, 2022: contributor
    7b6fe6761a...666c7584cf: rebase due to conflicts
  20. DrahtBot removed the label Needs rebase on Dec 12, 2022
  21. DrahtBot added the label Needs rebase on Feb 1, 2023
  22. jonatack commented at 7:24 pm on February 1, 2023: member
    ACK 666c7584cfb5abe882909155ed0af76ead74ef3c modulo trivial rebase
  23. vasild force-pushed on Feb 9, 2023
  24. vasild commented at 2:08 pm on February 9, 2023: contributor

    666c7584cf...c40c25763c: rebase due to conflicts

    Invalidates ACK from @jonatack

  25. DrahtBot removed the label Needs rebase on Feb 9, 2023
  26. jonatack commented at 10:30 pm on February 9, 2023: member

    re-ACK c40c25763c6acc12e54824202b7bf503d3b2ae68 per git range-diff dc905f6 666c758 c40c257

    It’s good to have them in place, just noting that the Sock::IsConnected() virtual member function overrides in src/test/util/net.h and src/test/fuzz/util/net.{h.cpp} aren’t used currently or here or in the parent yet.

  27. vasild commented at 8:15 am on February 10, 2023: contributor

    Sock::IsConnected() is used in src/i2p.cpp. It is important to override all methods from the mocked sock implementations because when we exercise some real code from the tests with a mocked socket, then we do not want the real IsConnected() method to be called. For example, the tests from the parent PR mock the socket with FuzzedSock and call:

    0FUZZ_TARGET_INIT(connman, ...) which calls
    1  Connman::OpenNetworkConnection() which calls
    2    Connman::ConnectNode() which calls
    3      i2p::sam::Session::Connect() which calls
    4        i2p::sam::Session::CreateIfNotCreatedAlready() which calls
    5          Sock::IsConnected()  // must end up calling FuzzedSock::IsConnected()
    
  28. DrahtBot added the label Needs rebase on Feb 17, 2023
  29. vasild force-pushed on Feb 24, 2023
  30. vasild commented at 2:01 pm on February 24, 2023: contributor

    c40c25763c...e536b3a67b: rebase due to conflicts

    Invalidates ACK from @jonatack

  31. DrahtBot removed the label Needs rebase on Feb 24, 2023
  32. jonatack commented at 4:19 pm on February 24, 2023: member
    re-ACK e536b3a67b390c3c46dce99cb7466862d3fd4863 per git range-diff be2e748 c40c257 e536b3a
  33. jonatack commented at 2:33 pm on April 18, 2023: member
    This is the last part of parent #21878 opened 2 years ago, anyone else like to have a look?
  34. theStack commented at 2:34 pm on June 9, 2023: contributor
    Concept ACK
  35. in src/util/sock.h:69 in 19508a1d0c outdated
    60@@ -62,12 +61,6 @@ class Sock
    61      */
    62     virtual Sock& operator=(Sock&& other);
    63 
    64-    /**
    65-     * Get the value of the contained socket.
    66-     * @return socket or INVALID_SOCKET if empty
    67-     */
    68-    [[nodiscard]] virtual SOCKET Get() const;
    


    ajtowns commented at 8:06 am on August 21, 2023:
    Should be removing a bunch of “Equivalent to blah(this->Get())” comments as well (or replacing them with blah(m_socket)).

    vasild commented at 1:47 pm on August 24, 2023:
    Done
  36. in src/test/sock_tests.cpp:62 in e536b3a67b outdated
    55@@ -56,14 +56,25 @@ BOOST_AUTO_TEST_CASE(move_constructor)
    56 
    57 BOOST_AUTO_TEST_CASE(move_assignment)
    58 {
    59-    const SOCKET s = CreateSocket();
    60-    Sock* sock1 = new Sock(s);
    61-    Sock* sock2 = new Sock();
    62+    const SOCKET s1 = CreateSocket();
    63+    const SOCKET s2 = CreateSocket();
    


    ajtowns commented at 8:29 am on August 21, 2023:
    Maybe separate the move_assignment change to its own commit? The old code wasn’t checking that the moved-to socket got closed, so this is improving coverage, not just avoiding the default constructor?

    vasild commented at 1:47 pm on August 24, 2023:
    Done
  37. in src/util/sock.h:33 in e536b3a67b outdated
    25@@ -26,11 +26,6 @@ static constexpr auto MAX_WAIT_FOR_IO = 1s;
    26 class Sock
    27 {
    28 public:
    29-    /**
    30-     * Default constructor, creates an empty object that does nothing when destroyed.
    31-     */
    32-    Sock();
    


    ajtowns commented at 8:33 am on August 21, 2023:
    Sock() = delete; just to be explicit and improve the error message slightly?

    vasild commented at 1:47 pm on August 24, 2023:
    Done
  38. in src/test/sock_tests.cpp:41 in 19508a1d0c outdated
    37@@ -38,7 +38,6 @@ BOOST_AUTO_TEST_CASE(constructor_and_destructor)
    38 {
    39     const SOCKET s = CreateSocket();
    40     Sock* sock = new Sock(s);
    41-    BOOST_CHECK_EQUAL(sock->Get(), s);
    


    ajtowns commented at 9:12 am on August 21, 2023:

    Checking that you actually got the socket you wanted seems valuable (particularly for move operations). Maybe:

    0class Sock {
    1public:
    2    /** For unit tests */
    3    bool CheckSocket(SOCKET s) const { return s == m_socket; }
    4...
    5};
    6
    7//  BOOST_CHECK_EQUAL(sock->Get(), s);
    8    BOOST_CHECK(sock->CheckSocket(s));
    

    vasild commented at 1:50 pm on August 24, 2023:
    Done, but named it operator== instead of CheckSocket.

    ajtowns commented at 10:35 am on August 25, 2023:
    Could consider updating the commit message for net: remove now unnecessary Sock::Get()

    vasild commented at 12:42 pm on August 25, 2023:
    Done.
  39. ajtowns commented at 9:13 am on August 21, 2023: contributor
    Approach ACK
  40. i2p: avoid using Sock::Get() for checking for a valid socket
    Peeking at the underlying socket file descriptor of `Sock` and checkig
    if it is `INVALID_SOCKET` is bad encapsulation and stands in the way of
    testing/mocking/fuzzing.
    
    Instead use an empty unique_ptr to denote that there is no valid socket.
    5ac1a51ee5
  41. net: don't check if the socket is valid in GetBindAddress()
    The socket is always valid (the underlying file descriptor is not
    `INVALID_SOCKET`) when `GetBindAddress()` is called.
    aeac68d036
  42. net: don't check if the socket is valid in ConnectSocketDirectly()
    The socket is always valid (the underlying file descriptor is not
    `INVALID_SOCKET`) when `ConnectSocketDirectly()` is called.
    944b21b70a
  43. vasild force-pushed on Aug 24, 2023
  44. vasild commented at 1:46 pm on August 24, 2023: contributor
    e536b3a67b...b44e493890: address suggestions
  45. net: remove now unnecessary Sock::Get()
    `Sock::Get()` was used only in `sock.{cpp,h}`. Remove it and access
    `Sock::m_socket` directly.
    
    Unit tests that used `Get()` to test for equality still verify that the
    behavior is correct by using the added `operator==()`.
    7829272f78
  46. net: remove Sock default constructor, it's not necessary 5086a99b84
  47. vasild force-pushed on Aug 25, 2023
  48. vasild commented at 12:43 pm on August 25, 2023: contributor
    b44e493890...384e9e3552: reword a commit message, see #26312 (review)
  49. in src/test/sock_tests.cpp:77 in 384e9e3552 outdated
    77     delete sock1;
    78-    BOOST_CHECK(!SocketIsClosed(s));
    79-    BOOST_CHECK_EQUAL(sock2->Get(), s);
    80+    BOOST_CHECK(!SocketIsClosed(s1));
    81+    BOOST_CHECK(SocketIsClosed(s2));
    82+    BOOST_CHECK(*sock2 == s1);
    


    jonatack commented at 4:30 pm on August 27, 2023:

    384e9e3552 while testing, added these assertions if you think they are worthwhile (feel free to ignore)

    0@@ -65,10 +66,12 @@ BOOST_AUTO_TEST_CASE(move_assignment)
    1 
    2     BOOST_CHECK(!SocketIsClosed(s1));
    3     BOOST_CHECK(!SocketIsClosed(s2));
    4+    BOOST_CHECK(*sock2 != s1);
    5 
    6     *sock2 = std::move(*sock1);
    7     BOOST_CHECK(!SocketIsClosed(s1));
    8     BOOST_CHECK(SocketIsClosed(s2));
    9+    BOOST_CHECK(*sock2 == s1);
    

    vasild commented at 12:33 pm on August 28, 2023:
    Added the second one.
  50. jonatack commented at 4:31 pm on August 27, 2023: member
    ACK 384e9e3552d7ee80b34bf695f1862884d6e34fd2
  51. test: improve sock_tests/move_assignment
    Use also a socket for the moved-to object and check which one is closed when.
    7df4508369
  52. vasild force-pushed on Aug 28, 2023
  53. vasild commented at 12:33 pm on August 28, 2023: contributor
    384e9e3552...7df4508369: add one more check in the unit test: #26312 (review)
  54. ajtowns commented at 5:57 pm on August 29, 2023: contributor
    ACK 7df450836969b81e98322c9a09c08b35d1095a25
  55. DrahtBot requested review from jonatack on Aug 29, 2023
  56. jonatack commented at 4:44 pm on August 30, 2023: member
    ACK 7df450836969b81e98322c9a09c08b35d1095a25
  57. DrahtBot removed review request from jonatack on Aug 30, 2023
  58. jonatack commented at 1:32 pm on October 2, 2023: member
    rfm or is anything left to be done here?
  59. ryanofsky commented at 1:27 pm on October 3, 2023: contributor

    rfm or is anything left to be done here? @vasild pinged me on irc, and agree looks this looks ready for merge. Will merge shortly

  60. ryanofsky merged this on Oct 3, 2023
  61. ryanofsky closed this on Oct 3, 2023

  62. vasild deleted the branch on Oct 3, 2023
  63. vasild commented at 11:42 am on October 4, 2023: contributor

    Thank you! This concludes #21878 :white_check_mark:

    Some more fuzz tests for review in #28584.

  64. Frank-GER referenced this in commit 4ea7ddec96 on Oct 13, 2023
  65. HiHat referenced this in commit 9c67ca0353 on Sep 29, 2024
  66. bitcoin locked this on Oct 3, 2024

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-11-17 12:12 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me