Better error handling (including for EAGAIN)

parent 36c82552
...@@ -4,6 +4,10 @@ import re ...@@ -4,6 +4,10 @@ import re
import random import random
from asyncbase import AsyncBase from asyncbase import AsyncBase
# Socket error "Resource temporarily unavailable": try again ;)
EAGAIN = 11
class ClientConnection(object, AsyncBase, asyncore.dispatcher): class ClientConnection(object, AsyncBase, asyncore.dispatcher):
def __init__(self): def __init__(self):
...@@ -53,9 +57,26 @@ class ClientConnection(object, AsyncBase, asyncore.dispatcher): ...@@ -53,9 +57,26 @@ class ClientConnection(object, AsyncBase, asyncore.dispatcher):
def handle_error(self): def handle_error(self):
if hasattr(self, 'main'): if hasattr(self, 'main'):
self.main.execute('disconnect') import sys
self.main.display_info('Error raised due to a broken or refused'\ t, v, tb = sys.exc_info()
+ ' connection') tbinfo = []
while tb:
tbinfo.append((
tb.tb_frame.f_code.co_filename,
tb.tb_frame.f_code.co_name,
str(tb.tb_lineno)
))
tb = tb.tb_next
file, function, line = tbinfo[-1]
info = ' '.join(['[%s|%s|%s]' % x for x in tbinfo])
self.debug_log('Exception raised in "%s" (%s line %s). Traceback:' \
% (function, file, line))
self.debug_log(info)
self.main.display_info(str(v))
#self.main.execute('disconnect')
#self.main.display_info('Error raised due to a broken or refused'\
# + ' connection')
def handle_close(self): def handle_close(self):
self.close() self.close()
...@@ -67,7 +88,18 @@ class ClientConnection(object, AsyncBase, asyncore.dispatcher): ...@@ -67,7 +88,18 @@ class ClientConnection(object, AsyncBase, asyncore.dispatcher):
# Receive a (multiline) message. # Receive a (multiline) message.
while True: while True:
chunk = self.recv(1) try:
chunk = self.recv(1)
except socket.error, e:
# Suppress "Resource temporarily unavailable" exceptions.
if e.errno == EAGAIN:
# Wait 5 ms
import time
time.sleep(0.005)
continue
else:
raise
if not chunk: if not chunk:
raise RuntimeError('socket connection broken') raise RuntimeError('socket connection broken')
if chunk in ['-','+']: if chunk in ['-','+']:
...@@ -77,7 +109,6 @@ class ClientConnection(object, AsyncBase, asyncore.dispatcher): ...@@ -77,7 +109,6 @@ class ClientConnection(object, AsyncBase, asyncore.dispatcher):
elif chunk == '\n' and buf[-1] == '\r': elif chunk == '\n' and buf[-1] == '\r':
if not multi_line: if not multi_line:
break break
self.debug_log('receiving multi line response...')
if buf[-3:] == '\r\n\r': if buf[-3:] == '\r\n\r':
# Remove trailing '\n\r' from multi line response # Remove trailing '\n\r' from multi line response
buf = buf[:-2] buf = buf[:-2]
...@@ -131,9 +162,8 @@ class ClientConnection(object, AsyncBase, asyncore.dispatcher): ...@@ -131,9 +162,8 @@ class ClientConnection(object, AsyncBase, asyncore.dispatcher):
# After authentification, fetch the list of users currently logged in. # After authentification, fetch the list of users currently logged in.
if not self.retrieved_user_list: if not self.retrieved_user_list:
if not self.request_user_list_sent: if not self.request_user_list_sent:
#self.request_user_list_sent = True self.request_user_list_sent = True
#self.retrieve_users() self.retrieve_users()
pass
else: else:
# TODO: process user list # TODO: process user list
self.retrieved_user_list = True self.retrieved_user_list = True
...@@ -153,5 +183,5 @@ class ClientConnection(object, AsyncBase, asyncore.dispatcher): ...@@ -153,5 +183,5 @@ class ClientConnection(object, AsyncBase, asyncore.dispatcher):
if __name__ == '__main__': if __name__ == '__main__':
client = ClientConnection() client = ClientConnection()
client.connect(('ow150.science.uva.nl', 16897)) client.connect(('localhost', 16897))
client.init_loop() client.init_loop()
...@@ -162,7 +162,6 @@ class CLI: ...@@ -162,7 +162,6 @@ class CLI:
self.display_info('Offline. Type "/connect HOST" to connect' \ self.display_info('Offline. Type "/connect HOST" to connect' \
+ ' to another chat server.') + ' to another chat server.')
self.info_bar.prefix('') self.info_bar.prefix('')
self.debug_window.clear()
self.refresh() self.refresh()
def help(main): def help(main):
......
...@@ -190,8 +190,9 @@ class RequestHandler(AsyncBase, asyncore.dispatcher): ...@@ -190,8 +190,9 @@ class RequestHandler(AsyncBase, asyncore.dispatcher):
return self.send_all('SAY %s/%s' % (self.username, buf[4:])) return self.send_all('SAY %s/%s' % (self.username, buf[4:]))
if cmd == 'NAMES': if cmd == 'NAMES':
self.send_raw('+Ok:') self.send_raw('+Ok:')
for c in self.server.clients: clients = self.server.clients
self.send_raw(self.server.clients[c].username) for c in clients:
self.send_raw(clients[c].username)
self.send_raw('') self.send_raw('')
return True return True
return self.send_negative('Unsupported command.') return self.send_negative('Unsupported command.')
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment