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