Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement poll() for startCaptureBlockingMode #1245

Merged
merged 69 commits into from
Dec 13, 2023

Conversation

tigercosmos
Copy link
Collaborator

@tigercosmos tigercosmos commented Nov 24, 2023

please refer to #1220

new in PR:

  • timeout of startCaptureBlockingMode keeps the unit as second but changes to use double type to allow millisecond precision.
  • add usePoll option
  • main behavior difference: originally, if there are no packets coming, then the timeout will never be triggered due to blocking of pcap_dispatch. Use poll() to frequently check if it is already timeout.

@tigercosmos tigercosmos requested a review from seladb as a code owner November 24, 2023 08:30
@tigercosmos
Copy link
Collaborator Author

@seladb please take a look.

@seladb seladb changed the base branch from master to dev November 25, 2023 01:55
@seladb
Copy link
Owner

seladb commented Nov 25, 2023

@tigercosmos I updated the base branch to dev. We always merge PRs to dev first before merging them to master.

Please also note CI fails on many platforms. Can you please check?

@tigercosmos
Copy link
Collaborator Author

tigercosmos commented Nov 25, 2023

@tigercosmos I updated the base branch to dev. We always merge PRs to dev first before merging them to master.

Please also note CI fails on many platforms. Can you please check?

@seladb Sure, I will fix the CI. I would like to ask your opinion about this PR. Does the current implementation make sense to you?

Copy link
Owner

@seladb seladb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see a few initial comments. I will do a more thorough review once CI passes

Pcap++/src/PcapLiveDevice.cpp Show resolved Hide resolved
Pcap++/src/PcapLiveDevice.cpp Outdated Show resolved Hide resolved
Tests/Pcap++Test/Tests/LiveDeviceTests.cpp Outdated Show resolved Hide resolved
@tigercosmos
Copy link
Collaborator Author

@seladb I think it's ready for review

@tigercosmos
Copy link
Collaborator Author

it's weird, it seems that iptables does not work by default, but it succeeded before: 1a50a03

@tigercosmos
Copy link
Collaborator Author

@seladb I try to use sudo in the std::system and also try to use sudo to start the test. Neither of them work:

iptables v1.6.1: can't initialize iptables table `filter': Permission denied (you must be root)
Perhaps iptables or your kernel needs to be upgraded.
iptables v1.6.1: can't initialize iptables table `filter': Permission denied (you must be root)
Perhaps iptables or your kernel needs to be upgraded.

Moreover, currently CI containers complain there is no iptables, so we also need to install it.
However, before a couple of commits merged into dev, I already used iptables, and CI was totally fine.

I also check the changes on dev, it seems it should not affect this "cannot use iptables".

@seladb
Copy link
Owner

seladb commented Dec 7, 2023

@seladb I try to use sudo in the std::system and also try to use sudo to start the test. Neither of them work:

iptables v1.6.1: can't initialize iptables table `filter': Permission denied (you must be root)
Perhaps iptables or your kernel needs to be upgraded.
iptables v1.6.1: can't initialize iptables table `filter': Permission denied (you must be root)
Perhaps iptables or your kernel needs to be upgraded.

Moreover, currently CI containers complain there is no iptables, so we also need to install it. However, before a couple of commits merged into dev, I already used iptables, and CI was totally fine.

I also check the changes on dev, it seems it should not affect this "cannot use iptables".

Maybe it's not possible to run iptables inside a docker container: https://forums.docker.com/t/iptables-permission-denied/81211/3 😕

@tigercosmos
Copy link
Collaborator Author

@seladb I try to use sudo in the std::system and also try to use sudo to start the test. Neither of them work:

iptables v1.6.1: can't initialize iptables table `filter': Permission denied (you must be root)
Perhaps iptables or your kernel needs to be upgraded.
iptables v1.6.1: can't initialize iptables table `filter': Permission denied (you must be root)
Perhaps iptables or your kernel needs to be upgraded.

Moreover, currently CI containers complain there is no iptables, so we also need to install it. However, before a couple of commits merged into dev, I already used iptables, and CI was totally fine.
I also check the changes on dev, it seems it should not affect this "cannot use iptables".

Maybe it's not possible to run iptables inside a docker container: https://forums.docker.com/t/iptables-permission-denied/81211/3 😕

True... after survey, seems that Github action has some limitations.
seems a possible solution is to run a docker inside Github action with --cap-add=NET_ADMIN

Or, probably we should think of some other ways to test the function.

@tigercosmos
Copy link
Collaborator Author

@seladb Maybe we should not make it very complicated... as long as the poll version can work the same as the original version, maybe we don't need to prove that poll can timeout with no packets coming (we should believe that poll is always correct)

@seladb
Copy link
Owner

seladb commented Dec 8, 2023

@seladb Maybe we should not make it very complicated... as long as the poll version can work the same as the original version, maybe we don't need to prove that poll can timeout with no packets coming (we should believe that poll is always correct)

@tigercosmos I tend to agree... I can't think of a good way to test the poll timeout so let's just keep the existing tests. It's not ideal but we currently don't have a CI infra that is robust enough to test this scenario.

Can you clean up the PR and I'll review it again?

m_StopThread = true;
#if !defined(_WIN32)
// Be careful when you modify the code related to `poll` in this block
// Some tests are not supported to run on CIs: `TestPcapLiveDeviceBlockingModePollTimeout`, `TestPcapLiveDeviceBlockingModeNotTimeoutWithoutPoll`
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@seladb I added some comments here to mention that manual tests are required here


#if !defined(_WIN32)
configs.emplace_back(); // the config used poll
configs[1].usePoll = true;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this ensures the behaviour is as same as before.


PTF_TEST_CASE(TestPcapLiveDeviceBlockingModePollTimeout)
{
#if !defined(_WIN32) and defined(MANUAL_TEST)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

although this test cannot run on CI, we can manually run it locally.
I think it is worth keeping it, so I added a MANUAL_TEST flag for it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found that it's really difficult to use iptables to block all packets. No matter how I set up rules, I still can see packets on Wireshark. Maybe the easiest way is to use a clean interface to test... since we can ensure no packets on it ...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@seladb please let me know your opinion

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I also encountered problems with iptables. I think we should just remove these tests. There is no point in MANUAL_TEST which we don't run anywhere...

PTF_ASSERT_TRUE(liveDev->startCapture(packetArrives, &packetCount));
PTF_TEST_CASE(TestPcapLiveDeviceBlockingModeNotTimeoutWithoutPoll)
{
#if !defined(_WIN32) and defined(MANUAL_TEST)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same for this test. use MANUAL_TEST here.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can remove this test also...

else if(ready < 0)
{
PCPP_LOG_ERROR("poll() got error '" << strerror(errno) << "'");
return -1;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we can return 0 directly because in lines 597-600 we reset a few private members.
Instead we should set m_StopThread = true and maybe add a new local variable pollError and I think we can return 0 in this case (poll error)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed.

}
#else
PCPP_LOG_ERROR("Windows doesn't support poll()");
return 0;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto: we cannot return 0 here. We should probably add a new local variable pollError and set it to true

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed.

{
while (!m_StopThread)
{
if (pcap_dispatch(m_PcapDescriptor, -1, onPacketArrivesBlockingMode, reinterpret_cast<uint8_t*>(this)) == -1)
if(pcap_dispatch(m_PcapDescriptor, -1, onPacketArrivesBlockingMode, (uint8_t*)this) < 0)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An error in pcap_dispatch is -1 and not other values:

https://linux.die.net/man/3/pcap_dispatch

It returns -1 if an error occurs or -2 if the loop terminated due to a call to pcap_breakloop() before any packets were processed. If your application uses pcap_breakloop(), make sure that you explicitly check for -1 and -2, rather than just checking for a return value < 0.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry, fixed.


PTF_TEST_CASE(TestPcapLiveDeviceBlockingModePollTimeout)
{
#if !defined(_WIN32) and defined(MANUAL_TEST)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I also encountered problems with iptables. I think we should just remove these tests. There is no point in MANUAL_TEST which we don't run anywhere...

PTF_ASSERT_TRUE(liveDev->startCapture(packetArrives, &packetCount));
PTF_TEST_CASE(TestPcapLiveDeviceBlockingModeNotTimeoutWithoutPoll)
{
#if !defined(_WIN32) and defined(MANUAL_TEST)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can remove this test also...

@tigercosmos
Copy link
Collaborator Author

@seladb all addressed

@seladb seladb merged commit 660843e into seladb:dev Dec 13, 2023
39 checks passed
@tigercosmos
Copy link
Collaborator Author

finally 🎉
thanks @seladb

@tigercosmos tigercosmos deleted the blockingCall branch December 13, 2023 07:22
@seladb
Copy link
Owner

seladb commented Dec 13, 2023

finally 🎉 thanks @seladb

Thank you @tigercosmos for your hard work and patience in solving all the issues, very much appreciated! 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants