Most active commenters
  • efecan0(9)
  • inetknght(4)
  • reactordev(3)

←back to thread

76 points efecan0 | 23 comments | | HN request time: 0.859s | source | bottom

Hi HN,

I’m a recent CS graduate. During the past few months I wrote BinaryRPC, an open-source RPC framework in modern C++20 focused on low-latency, binary WebSocket messaging.

Why I built it * Wanted first-class session support, pluggable QoS levels and a simple middleware chain (global, specific, multi handler) without extra JSON/XML parsing. * Easy developer experience

A quick feature list * Binary WebSocket frames – minimal overhead * Built-in session layer (login / reconnect / heartbeat) * QoS1 / QoS2 with automatic ACK & retry * Plugin system – rooms, msgpack, etc. can be added in one line * Thread-safe core: RAII + folly

Still early (solo project), so any feedback on design, concurrency model or missing must-have features would help a lot.

Thanks for reading!

also see "Chat Server in 5 Minutes with BinaryRPC": https://medium.com/@efecanerdem0907/building-a-chat-server-i...

1. jayd16 ◴[] No.44543338[source]
My immediate reaction is why websocket based design and TCP (?) over gRPC with http/3 and UDP and multiplexing and such?
replies(6): >>44543363 #>>44543401 #>>44543447 #>>44543548 #>>44544437 #>>44546559 #
2. efecan0 ◴[] No.44543363[source]
I started with WebSocket over TCP for practical reasons:

* Works everywhere today (browsers, LB, PaaS) with zero extra setup. * One upgrade -> binary frames; no gRPC/proto toolchain or HTTP/3 infra needed. * Simple reliability: TCP handles ordering; I add optional QoS2 on top. * Lets me focus on session/room/middleware features first; transport is swappable later.

QUIC / gRPC-HTTP/3 is on the roadmap once the higher-level API stabilises.

replies(1): >>44546626 #
3. inetknght ◴[] No.44543401[source]
I'm not the author but off the top of my head:

- gRPC is not a library I would trust with safety or privacy. It's used a lot but isn't a great product. I have personally found several fuckups in gRPC and protobuf code resulting in application crashes or risks of remote code execution. Their release tagging is dogshit, their implementation makes you think the standard library and boost libraries are easy to read and understand, and neither takes SDLC lifecycles seriously since there aren't sanitizer builds nor fuzzing regime nor static analysis running against new commits last time I checked.

- http/3 using UDP sends performance into the crater, generally requiring _every_ packet to reach the CPU in userspace instead of being handled in the kernel or even directly by the network interface hardware

- multiplexing isn't needed by most websocket applications

replies(2): >>44543464 #>>44544159 #
4. cherryteastain ◴[] No.44543447[source]
gRPC's C++ interfaces have horrible design if you want async behaviour. Tons of unsafe and bad practices like the need to call delete this [1]

[1] https://grpc.io/docs/languages/cpp/callback/

5. efecan0 ◴[] No.44543464[source]
Thank you for the extra information!

I am a recent CS graduate and I work on this project alone. I chose WebSocket over TCP because it is small, easy to read, and works everywhere without extra tools. gRPC + HTTP/3 is powerful but adds many libraries and more code to learn.

When real users need QUIC or multiplexing, I can change the transport later. Your feedback helps me a lot.

replies(1): >>44543664 #
6. jeffbee ◴[] No.44543548[source]
Ironically this library is much closer to what Google uses internally than grpc is.
replies(1): >>44543583 #
7. efecan0 ◴[] No.44543583[source]
Interesting point, thanks!
8. reactordev ◴[] No.44543664{3}[source]
The point people are beating around the bush at here is that a binary RPC framework has no such need for HTTP handling, even for handshaking, when a more terse protocol of your own design would/could/might? be better.

I totally understand your reasoning behind leaning on websockets. You can test with a data channel in a browser app. But if we are talking low-latency, Superman fast, modern C++, RPC and forgeddaboutit. Look into handling an initial payload with credential negotiation outside of HTTP 1.1.

replies(2): >>44543949 #>>44546252 #
9. efecan0 ◴[] No.44543949{4}[source]
You’re right: HTTP adds an extra RTT and headers we don’t strictly need.

My current roadmap is:

1. Keep WebSocket as the “zero-config / browser-friendly” default. 2. Add a raw-TCP transport with a single-frame handshake: [auth-token | caps] → ACK → binary stream starts. 3. Later, test a QUIC version for mobile / lossy networks.

So users can choose: * plug-and-play (WebSocket) * ultra-low-latency (raw TCP)

Thanks for the nudge this will go on the transport roadmap.

replies(1): >>44546294 #
10. tgma ◴[] No.44544159[source]
> I have personally found several fuckups in gRPC and protobuf code resulting in application crashes or risks of remote code execution.

Would be great if you report such remote code executions to the authors/Google. I am sure they handle CVEs etc. There has been a security audit like https://github.com/grpc/grpc/tree/master/doc/grpc_security_a...

> there aren't sanitizer builds nor fuzzing regime nor static analysis running against new commits last time I checked.

Are you making shit up as you go? I randomly picked a recently merged commit and this is the list of test suites ran on the pull request. As far as I recall, this has been the practice for at least 8 years+ (note the MSAN, ASAN, TSAN etc.)

I can see various fuzzers in the code base so that claim is also unsubstantiated https://github.com/grpc/grpc/tree/f5c26aec2904fddffb70471cbc...

  Android (Internal CI) Kokoro build finished
  Basic Tests C Windows Kokoro build finished
  Basic Tests C# Linux Kokoro build finished
  Basic Tests C# MacOS Kokoro build finished
  Basic Tests C# Windows Kokoro build finished
  Basic Tests C++ iOS Kokoro build finished
  Basic Tests C/C++ Linux [Build Only] Kokoro build finished
  Basic Tests ObjC Examples Kokoro build finished
  Basic Tests ObjC iOS Kokoro build finished
  Basic Tests PHP Linux Kokoro build finished
  Basic Tests PHP MacOS Kokoro build finished
  Basic Tests Python Linux Kokoro build finished
  Basic Tests Python MacOS Kokoro build finished
  Bazel Basic Tests for Python (Local) Kokoro build finished
  Bazel Basic build for C/C++ Kokoro build finished
  Bazel C/C++ Opt MacOS Kokoro build finished
  Bazel RBE ASAN C/C++ Kokoro build finished
  Bazel RBE Build Tests Kokoro build finished
  Bazel RBE Debug C/C++ Kokoro build finished
  Bazel RBE MSAN C/C++ Kokoro build finished
  Bazel RBE Opt C/C++ Kokoro build finished
  Bazel RBE TSAN C/C++ Kokoro build finished
  Bazel RBE Thready-TSAN C/C++ Kokoro build finished
  Bazel RBE UBSAN C/C++ Kokoro build finished
  Bazel RBE Windows Opt C/C++ Kokoro build finished
  Bloat Diff Kokoro build finished
  Bloat Difference Bloat Difference
  Clang Tidy (internal CI) Kokoro build finished
  Distribution Tests C# Linux Kokoro build finished
  Distribution Tests C# MacOS Kokoro build finished
  Distribution Tests C# Windows Kokoro build finished
  Distribution Tests Linux (standalone subset) Kokoro build finished
  Distribution Tests PHP Linux Kokoro build finished
  Distribution Tests PHP MacOS Kokoro build finished
  Distribution Tests Python Linux Arm64 Kokoro build finished
  Distribution Tests Ruby MacOS Kokoro build finished
  Distribution Tests Windows (standalone subset) Kokoro build finished
  EasyCLA EasyCLA check passed. You are authorized to contribute.
  Grpc Examples Tests CPP Kokoro build finished
  Memory Difference Memory Difference
  Memory Usage Diff Kokoro build finished
  Mergeable Mergeable Run has been Completed!
  Migration Test MacOS Sonoma Kokoro build finished
  ObjC Bazel Test Kokoro build finished
  Portability Tests Linux [Build Only] (internal CI) Kokoro build finished
  Portability Tests Windows [Build Only] (internal CI) Kokoro build finished
  Sanity Checks (internal CI) Kokoro build finished
  Tooling Tests Python Linux Kokoro build finished
  Windows clang-cl with strict warnings [Build Only] Kokoro build finished
replies(2): >>44544198 #>>44547188 #
11. efecan0 ◴[] No.44544198{3}[source]
Interesting discussion. My current goal isn’t to replace gRPC but to offer a lighter option for simple real-time apps. I’ll keep following the thread; the security links are useful, thanks.
12. gr4vityWall ◴[] No.44546252{4}[source]
Shouldn't WebSockets be comparable to raw TCP + a simple message protocol on top of it once you're done with the initial handshaking and protocol upgrade?

I wouldn't expect latency to be an issue for long lived connections, compared to TCP.

replies(1): >>44546351 #
13. reactordev ◴[] No.44546294{5}[source]
The actual handshake part of WebSockets is good. Send a NONCE/KEY and get back a known hash encoded however you like. This can be as little as 24 bytes or as much as 1024. Just sending the HTTP preamble eats through 151 bytes at least. Imagine that for every connection, per every machine... That's a lot of wasted bandwidth if one can skip it.

Compression helps but I think if you want to win over the embedded crowd, having a pure TCP alternative is going to be a huge win. That said, do NOT abandon the HTTP support, WebSockets are still extremely useful. WebRTC is too. ;)

replies(2): >>44547220 #>>44548314 #
14. reactordev ◴[] No.44546351{5}[source]
no but reliability is. And if you need to re-establish the connection, you'll have to preamble your way through another handshake.

gRPC uses HTTP/2, which has a Client/Server Stream API, to forgo the preamble. In the end though, ANY HTTP based protocol could be throttled by infrastructure in-between. TCP on the other hand, can be encrypted and sent without any preamble - just a protocol, and only L2/L3 can throttle.

15. ◴[] No.44546559[source]
16. seangrogg ◴[] No.44546626[source]
Assuming you're locked in on the browser WebSockets are about as good as it gets at present. HTTP/3 requires WebTransport which has been a bit of a shitshow in terms of getting things up and running so far, in my experience.
replies(1): >>44548302 #
17. inetknght ◴[] No.44547188{3}[source]
> Would be great if you report such remote code executions to the authors/Google. I am sure they handle CVEs etc.

I wasn't getting paid to fix their code, I have no interest in helping Google for free, and don't want to help Google.

> There has been a security audit like

A checkbox report from six years ago. That's ancient times at the pace that things are added to gRPC.

> Are you making shit up as you go?

No. This [0] repo I used to reproduce a stack smash issue before `main()`. I reported the issue here [1]. I don't get paid to fix Google's things and found a workaround for the purposes I needed.

[0]: https://github.com/keith-bennett-airmap/grpc-stacksmash

[1]: https://github.com/protocolbuffers/protobuf/issues/12732

> I can see various fuzzers in the code base so that claim is also unsubstantiated

Fuzzers are cool, but they don't cover the whole codebase.

replies(1): >>44547723 #
18. inetknght ◴[] No.44547220{6}[source]
> Compression helps

It's generally unwise to use compression for encrypted transport such as TLS or HTTP/S.

https://en.wikipedia.org/wiki/Oracle_attack

replies(1): >>44548321 #
19. tgma ◴[] No.44547723{4}[source]
> I wasn't getting paid to fix their code, I have no interest in helping Google for free, and don't want to help Google.

Extraordinary claims need extraordinary evidence. Software can be buggy, for sure, but as you yourself acknowledge, gRPC is widely deployed at many companies that do offer bug bounties. I won't be surprised if folks can occasionally find exploits in it, but if as you suggest it is so easily exploitable to get remote code execution, you in fact should be able to collect many $$$ from not just Google, but Apple, Microsoft, and many more companies who deploy gRPC services at scale. Hard to find a nicer attack target than a network facing library that you have a zero-day RCE for. (Protobuf is an even more popular target and used by virtually all Google services.)

https://bughunters.google.com

> No. This [0] repo I used to reproduce a stack smash issue before `main()`. I reported the issue here [1]. I don't get paid to fix Google's things and found a workaround for the purposes I needed.

As you have figured out yourself in the repo referred, the bug (not sure if exploitable or not) is from protobuf, a distinct library from gRPC, and appeared under certain compiler configurations. gRPC library does not even have a dependency on `libprotobuf`. It just happens to be the most popular format used jointly with gRPC. (It could be argued to be a bug in compiler conditions where abseil substitution of absl::string_view to std::string_view happens and is not fully compatible.)

Google also specifically pays for some open source project vulnerability reports (specifically covering Protobuf as an important target), so repeated claims of I am not getting paid otherwise I had dozens of exploits should be taken with a grain of salt and considered FUD: https://bughunters.google.com/about/rules/open-source/652133...

> Fuzzers are cool, but they don't cover the whole codebase.

You just went from the claim "they have no fuzzers or static analysis" to "fuzzers don't cover X". Of course, you cannot prove correctness by testing and fuzzing. Testing is not verification. Tests can only prove the existence of bugs, not their non-existence.

In any case, I would be really interested to see a comparable RPC stack that is close or more well-tested than gRPC...

replies(1): >>44550419 #
20. efecan0 ◴[] No.44548302{3}[source]
Thanks, that matches my experience as well. For browser clients WebSocket is still ‘the path of least pain’, so I’m keeping it as the default. When WebTransport and QUIC become easier to deploy I’ll add an optional transport module. If you’ve tried any recent WebTransport builds and have tips or docs, I’d love to see them—feel free to open an issue or drop a link. Appreciate the confirmation!
21. efecan0 ◴[] No.44548314{6}[source]
Agree: for small devices every byte counts. Plan is to keep WebSocket for zero-config use, but add a raw-TCP handshake (~24-40 bytes) so embedded clients can skip the HTTP preamble. I’ll note that on the transport roadmap. Appreciate the insights!
22. efecan0 ◴[] No.44548321{7}[source]
Good point, thank you.

You’re right—no compression over TLS by default. If I add deflate support later it will be opt-in and disabled when the connection is encrypted.

Appreciate the insights!

23. inetknght ◴[] No.44550419{5}[source]
> gRPC is widely deployed at many companies that do offer bug bounties

Ahh yeah, bug bounties. The things that are notoriously underpaid if paid at all. The things that require many hours/days/weeks of work for a "maybe" payoff.

I'm sorry but I don't like the risk of spending so much time for free or significantly discounted. My time is worth more than that.

If these companies really want to lean on shit software, then that's their business. But I neither support nor condone it.

> gRPC library does not even have a dependency on `libprotobuf`

I see this espoused a lot. Have you tried building gRPC? It requires protobuf to build...

> You just went from the claim "they have no fuzzers or static analysis" to "fuzzers don't cover X"

And it's amazing that both claims are true. You linked some page where some fuzzers were run. Nice! Those fuzzers aren't enabled in default tests. So `make test` doesn't run them. Moreover `make test` didn't find any issues and would take a while so I commented it out.

> I would be really interested to see a comparable RPC stack

This has been a call since forever. But "RPC" is very loosely defined.

Realistically, almost anything that can serialize to/from a file without relying on knowing the file size can be adapted to socket-based RPC. There's thousands of libraries which can do that.

> that is close or more well-tested than gRPC

I'd rather have an "RPC" whose design is both well-documented and clearly readable. That's definitely not gRPC. HTTP is fairly well-documented and many implementations are clearly readable. Message queues are too. Even databases are generally better documented and usable for RPC. Did you know that POSIX has a specification for RPC?

Good documentation and clearly readable means "well tested" comes with much lower costs.