[Tutor] Bug with fork / socket from CGI

Lloyd Kvam pythontutor@venix.com
Fri Aug 1 14:51:03 2003


I did not attempt to figure out your problem,  the cgitb module with
its traceback facility usually helps a great deal with debugging an
errant cgi script.

However, wouldn't it be simpler to use fastCGI or an equivalent connection
between the web server and the persistent process?

Jonathan Hayward http://JonathansCorner.com wrote:

> I'm trying to make a CGI script that, on first invocation, starts a 
> daemon. Every invocation from then on queries the daemon via a socket.
> 
> As is, the first invocation hangs, and subsequent invocations give an 
> error ('Bad file descriptor' refers to a socket.makefile() variable):
> 
> There was an error loading this page.
> (9, 'Bad file descriptor')
> 
> Here's the multitasking object code. Any bugfixes or corrections welcome.
> 
> class multitasking_manager(ancestor):
>     """Class to handle multithreading and multiprocessing material."""
>     def __init__(self):
>         ancestor.__init__(self)
>         self.thread_specific_storage = {}
>         self.thread_specific_storage_lock = thread.allocate_lock()
>         self.is_in_check_and_appropriately_update_stored_information = 0
>     def check_and_appropriately_update_stored_information(self):
>         self.is_in_check_and_appropriately_update_stored_information = 1
>         # Check if databases etc. should be updated, and if so perform
>         # appropriate updates.
>         self.is_in_check_and_appropriately_update_stored_information = 0
>     def check_and_start_oracle(self):
>         if not self.is_oracle_running():
>             self.start_oracle()
>     def get_page_from_oracle(self):
>         self.check_and_start_oracle()
>         sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>         sockIn = sock.makefile("r")
>         sockOut = sock.makefile("wb")
>         sock.close()
>         try:
>             sock.connect((configuration.get_search_server_ip(), \
>               configuration.get_search_server_port()))
>             for current_environment_key in os.environ.keys():
>                 sockOut.write("environmental_variable " + \
>                   current_environment_key + "\r\n")
>                 cPickle.dump(os.environ[current_environment_key], sockOut)
>             for cgi_key in cgi.FieldStorage().keys():
>                 sockOut.write("cgi_value " + cgi_key + "\r\n")
>                 cPickle.dump(cgi.FieldStorage[cgi_key])
>             sockOut.write("\r\n")
>             result = cPickle.load(sockIn)
>             sockOut.close()
>             sockIn.close()
>         except socket.error, e:
>             return "Content-type: text/html\n\n<h1>There was an error 
> loading this page.</h1>" + str(e)
>     def get_thread_specific_storage():
>         thread_id = thread.get_ident()
>         result = thread_specific_storage.get(thread_id)
>         if thread_specific_storage is None:
>             try:
>                 thread_specific_storage_lock.acquire()
>                 thread_specific_storaget[thread_id] = result = {}
>             finally:
>                 thread_specific_storage_lock.release()
>         return result
>     def is_oracle_running(self):
>         sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>         try:
>             sock.connect((configuration.get_search_server_ip(), \
>               configuration.get_search_server_port()))
>             sock.close()
>             return 1
>         except socket.error:
>             return 0
>     def run_oracle(self):
>         thread.start_new_thread(\
>           self.check_and_appropriately_update_stored_information, ())
>         sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>         sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
>         sock.bind(("", configuration.get_search_server_port()))
>         sock.listen(5)
>         while 1:
>             try:
>                 newsocket, address = sock.accept()
>                 thread.start_new_thread(self.run_oracle_thread, 
> (newsocket, \
>                   address))
>             except socket.error:
>                 sock.close()
>                 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>                 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
>                 sock.bind(("", configuration.get_search_server_port()))
>                 sock.listen(5)
>     def run_oracle_thread(sock, address):
>         """Reads a CGI or other header variable alone on a line, format 
> like
>             cgi_value <HTML form element name>
>             environmental_variable REMOTE_ADDR
>         and then a pickled value. There is exactly one space between the 
> two
>         elements, and neither element may contain a space"""
>         sockIn = sock.makefile("wb")
>         sockOut = sock.makefile("r")
>         sock.close()
>         line = sockIn.readline()
>         while line:
>             if get_thread_specific_storage()["cgi"] == None:
>                 get_thread_specific_storage()["cgi"] = {}
>             if get_thread_specific_storage()["environmental_variables"] 
> == \
>               None:
> 
> get_thread_specific_storage()["environmental_variables"] = {}
>             cgi = get_thread_specific_storage["cgi"]
>             environmental_variables = \
>               get_thread_specific_storage["environmental_variables"]
>             line = re.sub("[\r\n]+", "", line)
>             if line != "":
>                 query_line = re.split("\s+", line)
>                 input_type = query_line[0]
>                 input_name = query_line[1]
>                 if input_type == "cgi_value":
>                     cgi[input_name] = cPickle.load(sockIn)
>                 elif input_type == "environmental_variables":
>                     environmental_variables[input_name] = 
> cPickle.load(sockIn)
>                 line = sockIn.readline()
>             else:
>                 generate_output()
>                 print_output(sockOut)
>         sockIn.close()
>         sockOut.close()
>     def start_oracle(self):
>         try:
>             first_pid = os.fork()
>         except OSError, e:
>             log_error("Failed to make first fork for oracle. Error: " + \
>               e.strerror)
>             return
>         if first_pid == 0:
>             os.chdir("/")
>             os.setsid()
>             os.umask(066)
>             try:
>                 second_pid = os.fork()
>             except OSError, e:
>                 log_error("Failed to make second fork for oracle. Error: 
> " + \
>                   e.strerror)
>                 return
>             if second_pid == 0:
>                 self.run_oracle()
>             else:
>                 sys.exit(0)
> 
> 

-- 
Lloyd Kvam
Venix Corp.
1 Court Street, Suite 378
Lebanon, NH 03766-1358

voice:	603-443-6155
fax:	801-459-9582