hillz
hillz

Reputation: 547

Python - How to properly set timeout of a function

I have 2 functions called on_outbounddata() and on_execute I want these functions to have timeout of 3 seconds, if they take longer than 3 seconds then exit the functions and continue running the other ones. Here's my code:

import socket,select,time,base64,os,sys,re,datetime, signal

class TheServer:
    input_list = []
    channel = {}
    channel_ = {}
    request = {}

    def handler(self, signum, frame):
        print "Time is up (3 sec)"
        raise Exception("end of time")

    def main_loop(self):
        self.input_list.append(self.server)
        while 1:
            ss = select.select
            inputready, outputready, exceptready = ss(self.input_list, [], [])
            for self.s in inputready:
                if self.s == self.server:
                    self.on_accept()
                    break
                try:
                    self.netdata = self.s.recv(buffer_size)
                except Exception, e:
                    self.netdata =''
                if len(self.netdata) == 0:
                    self.on_close()
                else:
                    signal.signal(signal.SIGALRM, self.handler)
                    signal.alarm(3)
                    try:
                        if cmp(self.channel[self.s],self.channel_[self.s]):
                            self.on_outbounddata() # I want this function to have a timeout of 3 seconds
                        else:
                            self.on_execute() # I want this function to have a timeout of 3 seconds
                    except Exception, exc: 
                        print exc

        def on_execute(self):
            print "ON_EXECUTE"
            netdata = self.netdata
    #-----------------------------------------------------------
            if netdata.find("CONNECT") ==0:
                req="CONNECT " + host + ":" + port
                payloads=payload           
                payloads=payloads.replace('^request^',req)
                ms = re.search(r"\^s(\d+)\^", payloads)
                if ms:
                  pay=payloads.split('^s'+ms.group(1)+'^')
                  self.request[self.channel[self.s]]=pay[1];
                  netdata=pay[0]
                else:
                     netdata=payloads
                #print netdata
            try:
                self.channel[self.s].send(netdata)
            except Exception, e:
                print e            
    #-----------------------------------------------------------
        def on_outbounddata(self):
            print "ON_OUTBOUNDDATA"
            netdata = self.netdata
            if netdata.find('HTTP/1.') ==0:
                ms = re.search(r"\^s(\d+)\^", payload)
                if ms:
                  print "Sleeping for " + ms.group(1) + "ms"
                  dec = int(ms.group(1)) / float(1000)
                  time.sleep(dec)
                  print self.request[self.s]
                  try:
                    self.channel_[self.s].send(self.request[self.s])
                    self.request[self.s]=''
                  except ValueError:
                    print "self.s is not in the list (on_outbounddata)"
                    pass
                netdata='HTTP/1.1 200 Connection established\r\n\r\n'
            try:
                self.channel[self.s].send(netdata)
            except Exception, e:
                print e
            except:
                pass

Please note that I want to apply timeout only to on_outbounddata() and on_execute. When I run that code, instead of continuing to run the other functions it just breaks the while loop. How can I fix that ?

This is the error output:

ON_EXECUTE
ON_EXECUTE
ON_OUTBOUNDDATA
ON_OUTBOUNDDATA
ON_CLOSE
ON_CLOSE
Time is up (3 sec)
Traceback (most recent call last):
  File "/usr/bin/socks", line 278, in <module>
    server.main_loop()
  File "/usr/bin/socks", line 159, in main_loop
    inputready, outputready, exceptready = ss(self.input_list, [], [])
  File "/usr/bin/socks", line 152, in handler
    raise Exception("end of time")
Exception: end of time

Upvotes: 2

Views: 1467

Answers (1)

TemporalWolf
TemporalWolf

Reputation: 7952

Your issue is because you're not unsetting the alarm afterwards, so it continues and 3 seconds later it triggers, even if you're no longer in the section you wanted to timeout. The documentation explains how to do this:

signal.alarm(time) If time is non-zero, this function requests that a SIGALRM signal be sent to the process in time seconds. Any previously scheduled alarm is canceled (only one alarm can be scheduled at any time). The returned value is then the number of seconds before any previously set alarm was to have been delivered. If time is zero, no alarm is scheduled, and any scheduled alarm is canceled. If the return value is zero, no alarm is currently scheduled. (See the Unix man page alarm(2).) Availability: Unix.

Upvotes: 1

Related Questions