From ba4f0cb2069ae41eee4ce6dba67835068b77604e Mon Sep 17 00:00:00 2001 From: Matt Arnold Date: Thu, 4 Sep 2025 17:32:52 -0400 Subject: [PATCH] The daemon post --- daemons.py | 186 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 daemons.py diff --git a/daemons.py b/daemons.py new file mode 100644 index 0000000..cff37bf --- /dev/null +++ b/daemons.py @@ -0,0 +1,186 @@ +#!/usr/bin/env python3 +## This Blog post is executable python code, it requires the gevent modules to run +# pip as gevent, Debian as python3-gevent. + +import os +import sys +import gevent +import gevent.socket as socket +import signal + + +# A long time ago circa 2010ish when i was taking the network programing class in +# college there was a blog post that explained in great detail, +# how to "fork into the background" e.g make a daemon on a Unix +# system. It was called Demystifing Daemons. By some guy on Blogspot, +# I think they went by Tom. I can no longer find this post. +# I get back more and more AI slop every time I look. +# This trick is not something i see often anymore. +# Therefore let's recreate a classic. +# Daemon's Demystified 2.0 starts right now + +# Sometimes programs need to run unattended, without tying up +# a terminal session. This is less of a problem now today +# then 30 years ago with our new fangled terminal multiplexers +# and the like. But i find that there's value in learning archane +# knowledge. Unix has had the concept of daemons since AT&T version 7 +# I think, but I'm finding that a decreasing number of people are +# familiar with this once basic knowledge. + +# To that end this post will show how to create a Disk and Execution Monitor +# a daemon, also called a service by the systemd kids. + +# In order to have a service we must first have something to serve. +# Here's one of my favorite prank services. RickRoll over http + +# you know it, you love it, It's a valid HTTP response + +RICKROLL_LYRICS = """ +HTTP/1.1 200 OK +Content-Type: text/plain; charset=UTF-8 +Last-Modified: Mon, 27 July 1987 00:00 GMT +Content-Length: 982 + + +We're no strangers to love +You know the rules and so do I +A full commitment's what I'm thinkin' of +You wouldn't get this from any other guy + +I just wanna tell you how I'm feeling +Gotta make you understand + +Never gonna give you up, never gonna let you down +Never gonna run around and desert you +Never gonna make you cry, never gonna say goodbye +Never gonna tell a lie and hurt you + +We've known each other for so long +Your heart's been aching, but you're too shy to say it +Inside, we both know what's been going on +We know the game and we're gonna play it + +And if you ask me how I'm feeling +Don't tell me you're too blind to see + +Never gonna give you up, never gonna let you down +Never gonna run around and desert you +Never gonna make you cry, never gonna say goodbye +Never gonna tell a lie and hurt you + +Never gonna give you up, never gonna let you down +Never gonna run around and desert you +Never gonna make you cry, never gonna say goodbye +Never gonna tell a lie and hurt you + +""" + +client_procs = [] + +svr_proc = None + + +# more on this later +class NullDevice: + def write(self, s): + pass + + +# See ln 104 and following +def hup_handle(sig, fr): + sys.exit() + + +# just standard Unix Network Programing Stuff +# Only interesting bit is if using INET6 in python at least +# IPV4 comes for free so no need to use AF_UNSPEC. +# See Refs 1 and 2 for more info + +# By the way i hate python 3's concurrency stuff so we'll be using +# gevent. + + +def server_handler(): + serversock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) + serversock.bind(("", 1337)) + serversock.listen(10) + while True: + client, addr = serversock.accept() + print(addr) + client_procs.append(gevent.spawn(client_handler, client)) + gevent.sleep(0) + + serversock.close() + return + + +# This is a simple infinite rickroll http server +# it only responds to GET requests. and no matter what +# will give you a rickroll back. +# +# This is somewhat useful in elfing with ai scraper bots. +# There are better methods if you wanna try that +def client_handler(sock): + print("Client handler spawn") + while True: + data = sock.recv(4096) + dstring = data.decode("UTF-8") + if dstring.startswith("GET"): + break + gevent.sleep(0) + + sock.send(RICKROLL_LYRICS.encode("utf-8")) + sock.close() + return + + +def daemon_main(): + svr_proc = gevent.spawn(server_handler) + client_procs.append(svr_proc) + gevent.joinall(client_procs) + sys.exit(0) + + +pid = os.fork() # Hmmm this looks an awful lot like... C +# Yes it does per C fork(3) creates a nearly identical copy of the +# calling process as a child of the calling process +# returning it's pid to the caller. Asexual reproduction at it's finest + +if pid: + os._exit(0) + # exit without running exit handlers, that might cause race condition + # in the child + + +# Per the fork manual the child begins execution at the point where fork +# is called, as if the child had called it. The only difference being +# is the child process gets a zero as return value, and so the else branch +# of this if is followed. +else: + # It turns out my CS prof lied about the purpose of these two calls + # the child process needs to be the process group leader, when parent + # exits or it gets reaped by the init system + os.setpgrp() + os.umask(0) + +print(os.getpid()) # to aid in stopping the server +# We want to close our connection to the controlling terminal +# to avoid accedentially spamming the use. And causing interactive processes +# to be SIGSTOP'ed. I do this with a Null Device class. +# You could just as easily do some sort of logging thing. +sys.stdin.close() +sys.stdout = NullDevice() +sys.stderr = NullDevice() + +# The last thing we do before handing things off to the daemon's main +# function is set up the daemon's signal table how we want it +# fork, may have initialized it with the default handlers +# depending on implementation +signal.signal(signal.SIGHUP, hup_handle) +signal.signal(signal.SIGTERM, hup_handle) +daemon_main() + + +# References +# 1. Beej's guide to Network Programing https://beej.us/guide/bgnet/ +# 2. Foundations of Python Network Programming 2ed Rhodes and Goerzen