Merry Christmas!!
so! I spent the first two weeks of my vacation studying about Web servers and how to do it in C!!
honestly, I have no reason to do it. I only have static Web pages to serve. so https://neocities.org really is the way right now. I intend to explore keeping data in C and troff-like files to generate the HTML, however.
now let's say you want dynamic Web pages in C?
actually, many functionality of dynamic Web pages can be replaced by active Web pages, that is: JavaScript, or more recently: WebAssembly. AND YOU KNOW WHAT? you can compile C to JavaScript or WebAssembly using https://emscripten.org/ hahahahha
but let's say you really need dynamic Web pages
the easiest way is to setup an industry standard Web server like Apache or nginx, or something recent like H2O (notice the trend: there are tons of Web servers, but I only mention those written in C! muahahaha) then you use https://kristaps.bsd.lv/kcgi/ to easily parse and answer HTTP requests through FastCGI (or CGI if you really feel like)
and let me tell you. FastCGI and its predecessor CGI abstracts away A LOT of bullshit going under the hood.
FastCGI is a protocol between two processes: the Web server and a stream process generating HTML (or other files) on the fly. this has two advantages: multiple FastCGI streams as a form of parallelization, and replacing the FastCGI script while the server is running (understand: updating a Web site without restarting the Web server).
but let's say you want to go lower. https://nodepp.org/ is one way. it is written in C++, but it has a C interface. looking good! one executable that does everything: it is a Web server and it actually serves the Web pages. no FastCGI
but what if we want to go LOWER? for the sake of SPEED. the lowest would be so use sockets directly.
or is it?
you can go lower by keeping an userland TCP/IP stack or writing a kernel-module that bypasses the "slow" userland API, dealing directly with the Network Interface Card (NIC) and it's driver and Direct Memory Access (DMA) and kernel internals. but I'm told this unmaintainable, which defeats the whole purpose. so as others say relentlessly, we MUST trust the TCP/IP stack inside the kernels of Windows, Linux, macOS and BSD and AIX and Solaris and whatnot. because apparently the World Wide Web does not adhere strictly to TCP/IP, so a perfect implementation doesn't work in real life.
back to sockets: we have three approaches: 1) synchronous blocking API, 2) non-blocking API and 3) asynchronous API
synchronous blocking API works great if you spawn a few dozen threads. that's good for a client, but a Web server must attend millions of concurrent requests nowadays. actually, some argue that if kernels provided better more lightweight native threads, threading would and should be THE WAY.
truly asynchronous API is quite rare. surprisingly, Windows does it, and Solaris and AIX? yes, apparently Linux and BSD doesn't have true asynchronous APIs available, only emulations using... guess what: threads. an asynchronous API is ridiculously simple: "execute this callback when this operation finishes"
so Linux and BSD and macOS rely on non-blocking APIs which... kinda suck very very hard? I mean, look how simple and obvious asynchronous APIs are. now non-blocking API requires that you keep asking: is it ready? is it ready? is it ready? is it ready? is it ready? in a closed loop. and only recent APIs are okayish, in the past there were terrible attempts where you'd need to ask for readiness for EVERY open socket, or do a linear search on a list of readiness
so Linux last years added io_uring, which is very fast, but some say it is unsafe :(
the worst is: there is no standard, and most stuff is out of touch with the reality of hardware and operating systems. so every system has multiple and differing implementations.
overall, networking APIs and libraries are so braindead and out of touch and messy compared to rock-solid standardized GPU and concurrency libraries like OpenGL, DirectX, OpenMP, CUDA, MPI and pthreads.
to answer that, we have event libraries that abstract all this bullshit: libevent, libev, libuv and libhv. I listed in order of older to newest. these are asynchronous event libraries. because asynchronous is superior. so they use asynchronous APIs where available, and emulate them in systems with only shitty non-blocking APIs *stares at Linux and BSD in disappointment*. IOCP from Windows is apparently the ultimate immortal epic API.
and there is also something about RX and TX queues in NICs that impact performance and limit concurrency...
anyway. libevent is the older library, it is very portable and has many features and is used in many projects. libev is a non-blocking event library that only runs in UNIX-like systems, and is used in a few projects. libuv originated using libev to be used inside Node.js, but evolved to an asynchronous event library when adding support to Windows's IOCP, and now doesn't use libev anymore, it's scope is very constrained, it doesn't even have TLS, which can be seen as good (or bad for H2O). libhv is a chinese thing that sounds super cool, but feels like having feature creep which will probably affect reliability and security.
established Web servers have a complicated API to use raw in C: H2O, nginx and others. not worth the effort even to write a simple "Hello, World!" in text/plain.
so IF I don't use FastCGI nor node++, I'd go with libuv or libevent, and then implement HTTP support manually by stacking libraries one on top of each other. some of these libraries I discovered follows:
- https://github.com/tatsuhiro-t/wslay
- https://github.com/nghttp2/nghttp2
- https://github.com/ngtcp2/nghttp3
- https://github.com/ngtcp2/ngtcp2
- some TLS library (with QUIC preferably, there are dozens)
- ...
- profit?
the POINT is: by going this low-level, I can support easily other protocols like, eeerhm, Gopher? WebSockets? and maybe add a multiplayer server and a binary protocol API for an non-existent app? the possibilities: not a lot hahahahaha. it's not like there is a lot to be invented.
all of this, to go back to my neocities Website and give up trying to host my own Web server LMAO
end of braindump.