def send_raw(self, command, _recurse=0, stime=None): if _recurse > _MAX_RECURSE: raise Exception('Cannot reconnect: %s' % (str(self.userv.address), )) #print('%s.send_raw(%s)' % (id(self), command)) if stime == None: stime = MonoTime() while True: try: self.s.send(command) break except socket.error as why: if why[0] == EINTR: continue elif why[0] in (EPIPE, ENOTCONN, ECONNRESET): self.connect() return self.send_raw(command, _recurse + 1, stime) raise why while True: try: rval = self.s.recv(1024) if len(rval) == 0: self.connect() return self.send_raw(command, _MAX_RECURSE, stime) rval = rval.strip() break except socket.error as why: if why[0] == EINTR: continue elif why[0] in (EPIPE, ENOTCONN, ECONNRESET): self.connect() return self.send_raw(command, _recurse + 1, stime) raise why rtpc_delay = stime.offsetFromNow() return (rval, rtpc_delay)
def send_raw(self, command, _recurse = 0, stime = None): if _recurse > _MAX_RECURSE: raise Exception('Cannot reconnect: %s' % (str(self.userv.address),)) #print('%s.send_raw(%s)' % (id(self), command)) if stime == None: stime = MonoTime() while True: try: self.s.send(command) break except socket.error as why: if why[0] == EINTR: continue elif why[0] in (EPIPE, ENOTCONN, ECONNRESET): self.connect() return self.send_raw(command, _recurse + 1, stime) raise why while True: try: rval = self.s.recv(1024) if len(rval) == 0: self.connect() return self.send_raw(command, _MAX_RECURSE, stime) rval = rval.strip() break except socket.error as why: if why[0] == EINTR: continue elif why[0] in (EPIPE, ENOTCONN, ECONNRESET): self.connect() return self.send_raw(command, _recurse + 1, stime) raise why rtpc_delay = stime.offsetFromNow() return (rval, rtpc_delay)
def send_command(self, command, result_callback=None, *callback_parameters): cookie = md5(str(random()) + str(time())).hexdigest() next_retr = self.delay_flt.lastval * 4.0 rtime = 3.0 if isinstance(command, Rtp_proxy_cmd): if command.type == 'I': rtime = 10.0 if command.type == 'G': rtime = 1.0 nretr = command.nretr command = str(command) else: if command.startswith('I'): rtime = 10.0 elif command.startswith('G'): rtime = 1.0 nretr = None if nretr == None: nretr = getnretrans(next_retr, rtime) command = '%s %s' % (cookie, command) timer = Timeout(self.retransmit, next_retr, 1, cookie) stime = MonoTime() self.worker.send_to(command, self.address) nretr -= 1 self.pending_requests[cookie] = (next_retr, nretr, timer, command, result_callback, stime, callback_parameters)
def process_reply(self, data, address, worker, rtime): try: cookie, result = data.split(None, 1) except: print('Rtp_proxy_client_udp.process_reply(): invalid response from %s: "%s"' % \ (str(address), data)) return preq = self.pending_requests.pop(cookie, None) if preq == None: return preq.timer.cancel() if rtime <= preq.stime: # MonoTime as the name suggests is supposed to be monotonic, # so if we get response earlier than request went out something # is very wrong. Fail immediately. rtime_fix = MonoTime() raise AssertionError('cookie=%s: MonoTime stale/went' \ ' backwards (%f <= %f, now=%f)' % (cookie, rtime.monot, \ preq.stime.monot, rtime_fix.monot)) if preq.result_callback != None: preq.result_callback(result.strip(), *preq.callback_parameters) # When we had to do retransmit it is not possible to figure out whether # or not this reply is related to the original request or one of the # retransmits. Therefore, using it to estimate delay could easily produce # bogus value that is too low or even negative if we cook up retransmit # while the original response is already in the queue waiting to be # processed. This should not be a big issue since UDP command channel does # not work very well if the packet loss goes to more than 30-40%. if preq.retransmits == 0: self.delay_flt.apply(rtime - preq.stime)
def run(self): maxemptydata = 100 while True: try: data, address = self.userv.skt.recvfrom(8192) if not data: # Ugly hack to detect socket being closed under us on Linux. # The problem is that even call on non-closed socket can # sometimes return empty data buffer, making AsyncReceiver # to exit prematurely. maxemptydata -= 1 if maxemptydata == 0: break continue else: maxemptydata = 100 rtime = MonoTime() except Exception as why: if isinstance(why, socket.error) and why[0] in (ECONNRESET, ENOTCONN, ESHUTDOWN): break if isinstance(why, socket.error) and why[0] in (EINTR,): continue else: print(datetime.now(), 'Udp_server: unhandled exception when receiving incoming data') print('-' * 70) traceback.print_exc(file=sys.stdout) print('-' * 70) sys.stdout.flush() sleep(1) continue if self.userv.uopts.family == socket.AF_INET6: address = ('[%s]' % address[0], address[1]) reactor.callFromThread(self.userv.handle_read, data, address, rtime) self.userv = None
def retransmit(self, cookie): next_retr, triesleft, timer, command, result_callback, stime, callback_parameters = self.pending_requests[ cookie] #print 'command to %s timeout %s cookie %s triesleft %d' % (str(self.address), command, cookie, triesleft) if triesleft <= 0 or self.worker == None: del self.pending_requests[cookie] self.go_offline() if result_callback != None: result_callback(None, *callback_parameters) return #next_retr *= 2 timer = Timeout(self.retransmit, next_retr, 1, cookie) stime = MonoTime() self.worker.send_to(command, self.address) triesleft -= 1 self.pending_requests[cookie] = (next_retr, triesleft, timer, command, result_callback, stime, callback_parameters)
def send_raw(self, command, _recurse=0, stime=None): if _recurse > _MAX_RECURSE: raise Exception('Cannot reconnect: %s', self.userv.address) if not command.endswith('\n'): command += '\n' #print '%s.send_raw(%s)' % (id(self), command) if stime == None: stime = MonoTime() while True: try: self.s.send(command) break except socket.error, why: if why[0] == EINTR: continue elif why[0] in (EPIPE, ENOTCONN, ECONNRESET): self.connect() return self.send_raw(command, _recurse + 1, stime) raise why
def __init__(self, next_retr, nretr, timer, command, result_callback, \ callback_parameters): self.stime = MonoTime() self.next_retr, self.triesleft, self.timer, self.command, self.result_callback, \ self.callback_parameters = next_retr, nretr, timer, command, \ result_callback, callback_parameters