The daemon post
This commit is contained in:
		
							parent
							
								
									9ca7d28cca
								
							
						
					
					
						commit
						ba4f0cb206
					
				
							
								
								
									
										186
									
								
								daemons.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										186
									
								
								daemons.py
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user