Re: [hackers] [quark] Make the serving process interruptible || Laslo Hunhold
On Wed, 7 Oct 2020 11:22:24 -0700 Anselm Garbe wrote: Dear Anselm, thanks for your feedback! > Do you really think the world needs another poll or select based web > server? Actually the forking model is the most common, from what I've seen. > The beauty of quark (as implied by its name) is the pure simplicity > and hackability it may provide. What's wrong with fork()? Aren't > processes and threads pretty much the same these days? What real > problem do you intend to fix with running everything from the same > process and introducing threads etc. when Unix fixed this problem 40 > years ago already by introducing processes. Handling processes is quirky and the static nature of quark opens a new approach to handle connections. It's not visible now, as I haven't pushed the changes yet, but let's discuss this once they are mainlined. > Wasn't the idea behind quark to have a clear purpose, to easily maybe > proxy or embed some scripts on top of http, to just serve some static > content from a random directory for a limited time? Kind of the > counterpart of curl, maybe allowing you to build a proxying tee for > some debugging as apache/tomcat/etc. and other such monsters cannot > easily be debugged anymore? > > Or in other words are we still on the right track? > > Isn't suckless all about sticking to the paradigms that have proven > during time? If fork() ain't good enough, then fix the process model > of your kernel instead ;) You bring up really good points and I, of course, heavily weighed them in the process. The interesting thing about quark, I think, is that it's possible to run a server in constant memory without any mallocs at runtime. A fork() can fail when resources are exhausted, but if you have worker-threads, you have full control over the process and are not susceptible to really low-hanging attacks like the HTTP-sloth, which you can, though, handle much better in a shared connection "pool". Sure, it adds a small overhead, because you launch a thread pool in a few lines, but it allows much finer control (if you desire) over quark's resource-usage. The proclimit really wasn't explicit enough and could lead to runtime-limits. When the changes are done, quark will allocate all it needs on startup and then never ask for anything ever again (except for dirlistings, which you can disable and have a reasonable resource-usage that is "guaranteed" by the kernel). With best regards Laslo
Re: [hackers] [quark] Make the serving process interruptible || Laslo Hunhold
Hi Laslo, Do you really think the world needs another poll or select based web server? The beauty of quark (as implied by its name) is the pure simplicity and hackability it may provide. What's wrong with fork()? Aren't processes and threads pretty much the same these days? What real problem do you intend to fix with running everything from the same process and introducing threads etc. when Unix fixed this problem 40 years ago already by introducing processes. Wasn't the idea behind quark to have a clear purpose, to easily maybe proxy or embed some scripts on top of http, to just serve some static content from a random directory for a limited time? Kind of the counterpart of curl, maybe allowing you to build a proxying tee for some debugging as apache/tomcat/etc. and other such monsters cannot easily be debugged anymore? Or in other words are we still on the right track? Isn't suckless all about sticking to the paradigms that have proven during time? If fork() ain't good enough, then fix the process model of your kernel instead ;) Thanks, Anselm
Re: [hackers] [quark] Make the serving process interruptible || Laslo Hunhold
On Sun, 4 Oct 2020 07:06:51 -0700 Jeremy wrote: Dear Jeremy, thanks for your feedback! > Thanks to this patch, I've realized that there were two design > desicions made, which make quark easy to hack on, and easy to > maintain: 1. Each resp_* function wrote 100% of the HTTP response > 2. Each request is handled in a new process > > 1: Not only does this make it easier to read, but it also allows > an end user-developer to to: > - add their own non-standard header > - offload the the response generation to a different program, > a program that may set the "Content-Type" or "Set-Cookie" > headers Yes, even though it has its limits of course. > 2: Forking for each request allows the end user-developer to manage > connections as he/she sees fit, while building on their existing > knowledge of process management. This is just a remnant and will be changed later. I actually have quite a lot of commits "lined up", which I haven't pushed, as I want to handle sloth attacks better. > Here's how I might prevent sloth attacks(this should kill children of > quark that are >10 seconds old): > > ps --ppid $QUARK_PID -oetimes,pid | awk 'NR!=1 && $2 > 10 { print $2 > }' | > > xargs kill > > The command is not the important part, but that by using a well-known > process management interface, I can manage connections the way I like. > > I believe that if one didn't want to use fork(3), while also keeping > the simplicity of quark, that person should rewrite quark in Golang. > > I look forward to your feedback. Stay tuned for the upcoming changes, which implement worker threads using epoll. In the case of a sloth attack, I want to implement it in a way that each thread can look at its list of active connections and select an offender to "drop" (e.g. first determine the IP-address from which most requests originate or look at the total connection age or the time since last activity). I like the idea of using external tools to drop connections, but the forking-model, imho, just doesn't scale well enough and I wanted a challenge. :) Thanks again for your elaborate feedback, I really appreciate it! Stay tuned for the upcoming changes. With best regards Laslo
Re: [hackers] [quark] Make the serving process interruptible || Laslo Hunhold
Hey Laslo, On 09/14/20 02:56PM, g...@suckless.org wrote: > Make the serving process interruptible > > Given the static nature of quark, I wanted to try something out that > is not really possible with a "dynamic" server: Making the serving > process interruptible in constant memory (except dir-listings of > course). This can easily be extended to a polling architecture later > on, but it most importantly warrants a non-blocking I/O scheme and > makes the server more or less immune to sloth attacks (i.e. clients > sending requests very slowly), and provides a more flexible approach to > connections. Any thread can pick up a connection and continue work on > it, without requiring a separate process for each (which might hit the > forking limit at some point). If we hit a point where all connections > are busy (due to many sloth attacks), one can apply arbitrary complex > logic to "cancel" connections that show malicious behaviour (e.g. taking > a long time to send the request header, etc.). > Thanks to this patch, I've realized that there were two design desicions made, which make quark easy to hack on, and easy to maintain: 1. Each resp_* function wrote 100% of the HTTP response 2. Each request is handled in a new process 1: Not only does this make it easier to read, but it also allows an end user-developer to to: - add their own non-standard header - offload the the response generation to a different program, a program that may set the "Content-Type" or "Set-Cookie" headers 2: Forking for each request allows the end user-developer to manage connections as he/she sees fit, while building on their existing knowledge of process management. Here's how I might prevent sloth attacks(this should kill children of quark that are >10 seconds old): ps --ppid $QUARK_PID -oetimes,pid | awk 'NR!=1 && $2 > 10 { print $2 }' | > xargs kill The command is not the important part, but that by using a well-known process management interface, I can manage connections the way I like. I believe that if one didn't want to use fork(3), while also keeping the simplicity of quark, that person should rewrite quark in Golang. I look forward to your feedback. Jeremy