gsliepen / tinc

a VPN daemon
http://tinc-vpn.org/
Other
1.93k stars 283 forks source link

Investigate rewriting tinc in C++11 #364

Open gsliepen opened 2 years ago

gsliepen commented 2 years ago

NOTE: This ticket is here just to discuss the pros and cons of a potential rewrite into C++11, and what steps should be taken to achieve this. Feel free to add your comments below. I will keep a summary in this top post.

Why consider rewriting tinc in C++11?

The C language has its drawbacks, and a language that allows code to be written in a cleaner and safer way would be preferred. There are many other languages, but we also want to be able to run tinc on embedded systems, routers and so on, which likely have non-x86 processors, not too much memory, and we want it to be performant. This rules out many languages. I think there are only two alternatives:

While Rust is tempting, C++ has the advantages of having a much easier path converting the existing code base, and at the moment it still has much better support for lesser known architectures, and can work with older compilers.

Pros

Cons

Steps that need to be taken

  1. Make the current code base compile with C++ compilers
  2. Test C++11 support on platforms supported by tinc
  3. Gradually migrate code to idiomatic C++11.
  4. ...?
  5. Profit!
hg commented 2 years ago

Summoning @lancethepants

You mentioned recently that some routers still require using GCC 4.2. I looked at the site, but it isn't really obvious what's the standard support like. Could you please explain in a few words how many of such routers are out there? Any really popular models among them?

If we look at C++11 support matrix, moving to it would practically rule out anything older than GCC 4.8 (otherwise so few important features are supported that it probably makes sense to stick to C).

While I agree that Rust is the new hotness, its platform support guarantees don't inspire much confidence:

Tier 2 targets can be thought of as "guaranteed to build". Automated tests are not always run so it's not guaranteed to produce a working build, but tier 2 targets often work to quite a good degree

And that's Tier 2. There's also Tier 3 with this clause:

may or may not work

although it includes many targets where current tinc works just fine (and is likely to continue working even on C++).

hg commented 2 years ago

Did a quick 'n dirty port of the C code to make it build with a C++ compiler.

https://github.com/hg/tinc/tree/cpp

Not proposing to merge this, it's just a demonstration to have something concrete to look at.

Those ugly casts around alloca() can probably be quickly replaced with std::vector, and custom allocation functions can probably be templated so there's less need for casts (until we get rid of manual memory management altogether).

Things to do (these are pretty heavy so I'll continue working on this if/when language change is agreed upon):

  1. replace some non-standard features (like designated initializers) with standards-compliant code; this will remove a ton of warnings and unbreak compilation on MSVC and old GCC (MSVC refuses to provide them unless you set the standard to C++20, and old GCC doesn't support them at all, so a lot of CI jobs fail)
  2. fix types in all global functions so C++ linkage works
  3. remove extern "C" everywhere (those are prefixed with #ifdef __cplusplus to make the diff smaller — so astyle doesn't reindent the whole project)
  4. fix Linux cross-compilation CI jobs
fangfufu commented 2 years ago

To build OpenWRT, you need at least GCC 8.4. https://forum.openwrt.org/t/gcc-version-on-openwrt/84417 https://git.openwrt.org/?p=openwrt/openwrt.git;a=blob_plain;f=toolchain/gcc/Config.version;hb=HEAD

Is using C causing any serious problems for Tinc right now? Will C limit the project's future? I feel moving to C++ sounds like a lot of work.

gsliepen commented 2 years ago

C is quite limiting, especially since tinc relies a lot on data structures that require lots of manual allocations and type casting, and our own balanced tree implementation because the C standard library comes with almost nothing. This would all be very safe and trivial to do in C++ with STL containers. Moving to C++ will indeed be a lot of work, but it can be done gradually. I think the end result would be a much more maintainable code base. But this is for after a 1.1 release.

lancethepants commented 2 years ago

You know, if it keeps the project active and interesting then I would support moving to another language. I really like the flurry of recent activity after some years of stagnation. More than anything I'd like to see that momentum keep going. Maybe I've changed my tune a bit, but I don't want to stand in the way of progress. Tomato firmware and others can adapt I say.

While tomato firmware is stuck with their toolchain for its kernel (arm/3.6.36.4, mipsel/2.6.22.19) and a select few userspace tools, it doesn't mean they can't use a modern toolchain for everything else. My project tomatoware is exactly that, the latest gcc compiler paired with these old kernel headers, and it works great for cross and native compilation. At the very least I can compile static binaries with a newer toolchain that can be included in tomato.

My biggest concern would be the use of newer kernel features without at least a fallback to something an older kernel could run.

I could even get behind a rust port. I'm the maintainer of target armv7-unknown-linux-uclibceabi (tier 3) which actually just became official in 1.60.0. I can even natively compile rust on arm routers. The mipsel kernel is too old to build a native rust compiler, but I can cross-compile for it just fine so long as the project I'm building doesn't require any kernel features newer than version 2.6.22.19. I have noticed that language compiled with a gcc backend are more performant on my arm32 target than languages using an llvm backend. I don't think that's a huge deal though, and there are two separate efforts to bring rust to the gcc backend.

Sorry for the superfluous length of my reply I am glad to see this would only happen after a 1.1 release. I'd like to see fewer delays to a stable release :)

fangfufu commented 2 years ago

I would support moving to C++, if it is after the release of 1.1.