-
Notifications
You must be signed in to change notification settings - Fork 681
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
Pcap device list refactoring to use smart pointers. #1386
Conversation
…eviceList with smart pointers. Added a secondary vector of non-owning pointers to the devices to keep the signature of some getter methods as they return references.
…ress, instead of copying the address to a new bytes array.
@seladb On the task list above, regarding Edit: Decided to go with |
…capRemoteDevice to be a shared_ptr.
…ore freedom on the caller, to skip a reference counter increase/decrease by moving.
…optimizations if the caller does not require his own ptr anymore
…aders in MemoryUtils header.
…nagement. Added a second helper 'view' vector to keep raw pointers of the devices for backward compat. Replaced iterator types with auto keyword. Removed destructor as the smart pointers handle cleanup.
… a non-owning raw pointer to allow the device to outlive the list if nessesary.
bb2cc09
to
541b198
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@seladb @tigercosmos could you please look at these comments and give an opinion?
@@ -49,50 +57,105 @@ namespace pcpp | |||
|
|||
/** | |||
* @return A vector containing pointers to all live devices currently installed on the machine | |||
* @deprecated This method is deprecated in favor of the SmartPtrAPI overload. | |||
*/ | |||
PCPP_DEPRECATED_RAW_PTR_API const std::vector<PcapLiveDevice*>& getPcapLiveDevicesList() const; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PcapLiveDeviceList
provides a getter API to get all registered devices, while PcapRemoteDeviceList
provides a container-like API to get all registered devices.
In my opinion, it would be best if both lists provided a standardized API. Which one would be better?
Here are my opinions on the pros and cons for both:
Getter method:
✔️ A getter approach would be consistent with the rest of the getter methods.
✔️ A getter can be made more easily to have overloads via tag dispatching.
❌ Reference getter locks down the internal implementation to always keeping a member of this type.
❌ Value getter will have a cost every time the getter is invoked, constructing the vector and coping the shared pointers.
Iterator API:
✔️ An iterator API would allow direct integration with other iterator algorithms and for-each
statements.
✔️ Low overhead iteration over the devices.
❌ Complications with deprecation of existing iterators.[1]
[1] As the current PcapRemoteDeviceList
already has an iterator API, that would be difficult to change with respect to the deprecation polity of 1 version notice of deprecation. Ideally, the iterators would refer to const std::shared_ptr<T>&
with T
being the device class. The current implementation returns iterators to *T
. Theoretically it is possible to write a converting iterator, but it is going to be complicated. The current stopgap I ended up on is keeping a duplicate list of raw pointers to the devices, which is not ideal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it makes sense to have both a getter and an iterator for a container-like object.
Regarding the iterator type, since std::shared_ptr<T>
and T*
are pointer types, the users' existing code (such as ->
) should not have much impact.
However, if we really don't want to break the API, as you said, it's still possible to have some conversion, but it's just troublesome.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it makes sense to have both a getter and an iterator for a container-like object.
Both is an option.
Regarding the iterator type, since
std::shared_ptr<T>
andT*
are pointer types, the users' existing code (such as->
) should not have much impact.
Yeah, they shouldn't really. unless they decided to save the value from the iterator somewhere. That is a breaking change, but it would only need a get()
call from the smart pointer to fix, as old code should still keep the list alive to keep the devices alive.
However, if we really don't want to break the API, as you said, it's still possible to have some conversion, but it's just troublesome.
I tried my hand at converting iterator a bit earlier. It is technically possible but it quickly becomes templated black magic if you try to make a general case converting iterator.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer to remove the old API, and have both getter and new iterator. Then we can also remove the hack of SmartPtrApiTag
and m_LiveDeviceListView
@seladb what do you say?
|
||
/** | ||
* @return An iterator object pointing to the first PcapRemoteDevice in list | ||
*/ | ||
RemoteDeviceListIterator begin() { return m_RemoteDeviceList.begin(); } | ||
RemoteDeviceListIterator begin() { return m_RemoteDeviceListView.begin(); } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See comment in PcapLiveDeviceList
on getPcapLiveDevicesList
|
||
|
||
/// @file | ||
|
||
#define PCPP_DEPRECATED_RAW_PTR_API PCPP_DEPRECATED("This method is deprecated in favor of the SmartPtrAPI overload.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doxygen generation really dislikes this macro for some reason, when used on a member function. No idea why... tried several things to fix them including mirroring the way the define
is written in TcpLayer.h
, but none of them worked. Would like a second opinion on why the generation fails on the macro.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doxygen test fails with the following:
Preprocessing /tmp/cirrus-ci-build/Pcap++/head/tmp/cirrus-ci-build/Pcap++/header/PcapLiveDeviceList.h:62: error: Found ';' while parsing initializer list! (doxygen could be confused by a macro call without semicolon) (warning treated as error, aborting now)
er/MBufRawPacket.h...
…DeviceListSearch, TestPcapLiveDevice, TestPcapLiveDeviceClone and TestRemoteCapture.
…smart-pointers # Conflicts: # Pcap++/header/PcapLiveDevice.h # Pcap++/src/PcapLiveDevice.cpp # Tests/Pcap++Test/Tests/LiveDeviceTests.cpp
@@ -0,0 +1,34 @@ | |||
#pragma once |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggest to put all util functions in one file, as there is not much code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which one to merge into the other tho? I initially separated them as they have different use cases.
MemoryUtils
is for general utilities w.r.t. smart pointer utilities and deleters.
DeviceUtils
is for utility functions for Pcap devices, like fetching devices, etc.
MemoryUtils
will be used a lot more as any time a smart pointer to a Pcap handle is used, it would need to be included for the deleter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. originally I thought we could merge MemoryUtils
and DeviceUtils
, but it did make sense to be separated.
Pcap++/header/PcapLiveDevice.h
Outdated
*/ | ||
struct SmartPtrApiTag{}; | ||
/** | ||
* Helper tag constant for disambuguating smart pointer API. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: disambiguating, btw I rarely see this word, I wonder if it is precise here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed a95c946. I think it should be better now?
Pcap++/header/PcapLiveDevice.h
Outdated
@@ -130,6 +137,8 @@ namespace pcpp | |||
static void onPacketArrivesNoCallback(uint8_t* user, const struct pcap_pkthdr* pkthdr, const uint8_t* packet); | |||
static void onPacketArrivesBlockingMode(uint8_t* user, const struct pcap_pkthdr* pkthdr, const uint8_t* packet); | |||
public: | |||
PcapLiveDevice(const PcapLiveDevice& other) = delete; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please also implement moving construction/assignment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
btw, if the underlying are shared pointers, why do we disallow coping?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
btw, if the underlying are shared pointers, why do we disallow coping?
IDK. I think the reason a LiveDevice
itself is not copiable is something with the underlying Pcap descriptors. Although there is still the clone
method so not really sure. The current change is mostly a stylistic from the pre-Cpp11 style of private ctors to post-Cpp11 deleted ctors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can keep the old clone
, but I think we can now embrace the copy constructor/assignment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I figured out at least partly why its private / deleted. LiveDevice
is a virtual class and usually handled by pointers to base class (i.e. WinPcapLiveDevice
device is used through PcapLiveDevice
pointer). A copy ctor used from a base pointer will only use the base copy ctor, not the actual copy ctor of the class the base ptr points to.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please also implement moving construction/assignment.
Added 4bcb50e
This PR will be split into multiple smaller PRs as part of #1431. |
This PR mainly aims to update
PcapLiveDeviceList
andPcapRemoteDeviceList
to utilize cpp11'sunique_ptr
for dynamic memory management.Overview of changes:
PcapLiveDeviceList
to use smart pointers internally for memory management.PcapRemoteDeviceList
to use smart pointers internally for memory management.PcapRemoteDevice
to keepits owna shared reference ofRemoteAuthentication
copy orRemoteAuthentication
withPcapRemoteDeviceList
viastd::shared_ptr
as it currently uses a raw pointer to share authentication with the device list.shared_ptr
overloads toPcapLiveDeviceList
methods. Deprecate raw pointer methods.shared_ptr
overloads toPcapRemoteDeviceList
methods. Deprecate raw pointer methods.PcapLiveDeviceList
.PcapRemoteDeviceList
.unique_ptr
overloads forclone
toPcapLiveDevice
and.PcapRemoteDevice
PcapLiveDevice
.Additional minor changes:
PcapLiveDeviceList
andPCapRemoteDeviceList
's copy ctors as explicitlydeleted
instead of keeping themprivate
.MemoryUtils.h
.DeviceUtils.h/cpp
. (It was duplicated a couple of times)