2

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
hillz
  • 537
  • 6
  • 10
  • 18
  • 1
    First, please never do this [`except: pass`](http://stackoverflow.com/questions/21553327/why-is-except-pass-a-bad-programming-practice). This will suppress everything, silently, which means you have no idea what is going on. Remove it and try it and you may be surprised what is actually killing your program. – TemporalWolf Nov 18 '16 at 22:31
  • Okay but can we please focus on the timeout instead of that ? I have updated my post with the error output please take a look once again @TemporalWolf – hillz Nov 18 '16 at 22:34
  • that's directly related to debugging - if you can't see the error, you can't show me it and who knows what is going on. I needed the error information before I could answer your question, and `except: pass` suppresses error information. – TemporalWolf Nov 18 '16 at 22:44
  • I use `except: pass` because when my script encounters `socket.error: [Errno 32] Broken pipe` it will exit the script and I have to re-run it again. – hillz Nov 18 '16 at 22:49
  • You can [`except socket.error:`](http://stackoverflow.com/a/25448603/3579910) to catch that without masking everything else. – TemporalWolf Nov 18 '16 at 22:52

1 Answers1

1

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.

TemporalWolf
  • 7,727
  • 1
  • 30
  • 50