Better error handling (including for EAGAIN)

parent 36c82552
......@@ -4,6 +4,10 @@ import re
import random
from asyncbase import AsyncBase
# Socket error "Resource temporarily unavailable": try again ;)
EAGAIN = 11
class ClientConnection(object, AsyncBase, asyncore.dispatcher):
def __init__(self):
......@@ -53,9 +57,26 @@ class ClientConnection(object, AsyncBase, asyncore.dispatcher):
def handle_error(self):
if hasattr(self, 'main'):
self.main.execute('disconnect')
self.main.display_info('Error raised due to a broken or refused'\
+ ' connection')
import sys
t, v, tb = sys.exc_info()
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):
self.close()
......@@ -67,7 +88,18 @@ class ClientConnection(object, AsyncBase, asyncore.dispatcher):
# Receive a (multiline) message.
while True:
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:
raise RuntimeError('socket connection broken')
if chunk in ['-','+']:
......@@ -77,7 +109,6 @@ class ClientConnection(object, AsyncBase, asyncore.dispatcher):
elif chunk == '\n' and buf[-1] == '\r':
if not multi_line:
break
self.debug_log('receiving multi line response...')
if buf[-3:] == '\r\n\r':
# Remove trailing '\n\r' from multi line response
buf = buf[:-2]
......@@ -131,9 +162,8 @@ class ClientConnection(object, AsyncBase, asyncore.dispatcher):
# After authentification, fetch the list of users currently logged in.
if not self.retrieved_user_list:
if not self.request_user_list_sent:
#self.request_user_list_sent = True
#self.retrieve_users()
pass
self.request_user_list_sent = True
self.retrieve_users()
else:
# TODO: process user list
self.retrieved_user_list = True
......@@ -153,5 +183,5 @@ class ClientConnection(object, AsyncBase, asyncore.dispatcher):
if __name__ == '__main__':
client = ClientConnection()
client.connect(('ow150.science.uva.nl', 16897))
client.connect(('localhost', 16897))
client.init_loop()
......@@ -162,7 +162,6 @@ class CLI:
self.display_info('Offline. Type "/connect HOST" to connect' \
+ ' to another chat server.')
self.info_bar.prefix('')
self.debug_window.clear()
self.refresh()
def help(main):
......
......@@ -190,8 +190,9 @@ class RequestHandler(AsyncBase, asyncore.dispatcher):
return self.send_all('SAY %s/%s' % (self.username, buf[4:]))
if cmd == 'NAMES':
self.send_raw('+Ok:')
for c in self.server.clients:
self.send_raw(self.server.clients[c].username)
clients = self.server.clients
for c in clients:
self.send_raw(clients[c].username)
self.send_raw('')
return True
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