send_messages uses NonBlocking P2PConnection

This commit is contained in:
Dimitur Kirov 2006-09-19 19:56:04 +00:00
parent 81b46bb37f
commit 9c60d30351
2 changed files with 85 additions and 48 deletions

View File

@ -30,7 +30,7 @@ DATA_SENT='DATA SENT'
TYPE_SERVER, TYPE_CLIENT = range(2) TYPE_SERVER, TYPE_CLIENT = range(2)
class ZeroconfListener(IdleObject): class ZeroconfListener(IdleObject):
def __init__(self, port, caller = None): def __init__(self, port, conn_holder):
''' handle all incomming connections on ('0.0.0.0', port)''' ''' handle all incomming connections on ('0.0.0.0', port)'''
self.port = port self.port = port
self.queue_idx = -1 self.queue_idx = -1
@ -38,7 +38,8 @@ class ZeroconfListener(IdleObject):
self.started = False self.started = False
self._sock = None self._sock = None
self.fd = -1 self.fd = -1
self.caller = caller self.caller = conn_holder.caller
self.conn_holder = conn_holder
def bind(self): def bind(self):
self._serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self._serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@ -64,7 +65,7 @@ class ZeroconfListener(IdleObject):
def pollin(self): def pollin(self):
''' accept a new incomming connection and notify queue''' ''' accept a new incomming connection and notify queue'''
sock = self.accept_conn() sock = self.accept_conn()
P2PClient(sock[0], sock[1][0], sock[1][1], self.caller) P2PClient(sock[0], sock[1][0], sock[1][1], self.conn_holder)
def disconnect(self): def disconnect(self):
''' free all resources, we are not listening anymore ''' ''' free all resources, we are not listening anymore '''
@ -76,7 +77,7 @@ class ZeroconfListener(IdleObject):
self._serv.close() self._serv.close()
except: except:
pass pass
#XXX kill all active connection self.conn_holder.kill_all_connections()
def accept_conn(self): def accept_conn(self):
''' accepts a new incomming connection ''' ''' accepts a new incomming connection '''
@ -87,32 +88,41 @@ class ZeroconfListener(IdleObject):
class P2PClient(IdleObject): class P2PClient(IdleObject):
def __init__(self, _sock, host, port, caller, messagequeue = []): def __init__(self, _sock, host, port, conn_holder, messagequeue = []):
self._owner = self self._owner = self
self.Namespace = 'jabber:client' self.Namespace = 'jabber:client'
self.defaultNamespace = self.Namespace self.defaultNamespace = self.Namespace
self._component = 0 self._component = 0
self._registered_name = None self._registered_name = None
self._caller = caller self._caller = conn_holder.caller
self.conn_holder = conn_holder
self.messagequeue = messagequeue self.messagequeue = messagequeue
self.Server = host self.Server = host
self.DBG = 'client' self.DBG = 'client'
self.Connection = None
debug = ['always', 'nodebuilder'] debug = ['always', 'nodebuilder']
self._DEBUG = Debug.Debug(debug) self._DEBUG = Debug.Debug(debug)
self.DEBUG = self._DEBUG.Show self.DEBUG = self._DEBUG.Show
self.debug_flags = self._DEBUG.debug_flags self.debug_flags = self._DEBUG.debug_flags
self.debug_flags.append(self.DBG) self.debug_flags.append(self.DBG)
self.sock_hash = None
if _sock: if _sock:
self.sock_type = TYPE_SERVER self.sock_type = TYPE_SERVER
else: else:
self.sock_type = TYPE_CLIENT self.sock_type = TYPE_CLIENT
P2PConnection('', _sock, host, port, caller, self.on_connect) P2PConnection('', _sock, host, port, self._caller, self.on_connect)
def on_connect(self, conn): def on_connect(self, conn):
self.Connection = conn self.Connection = conn
self.Connection.PlugIn(self) self.Connection.PlugIn(self)
dispatcher_nb.Dispatcher().PlugIn(self) dispatcher_nb.Dispatcher().PlugIn(self)
self.RegisterHandler('message', self._messageCB) self.RegisterHandler('message', self._messageCB)
self.sock_hash = conn._sock.__hash__
self.conn_holder.add_connection(self)
if self.sock_type == TYPE_CLIENT:
while self.messagequeue:
message = self.messagequeue.pop(0)
self.send(message)
def StreamInit(self): def StreamInit(self):
''' Send an initial stream header. ''' ''' Send an initial stream header. '''
@ -136,17 +146,32 @@ class P2PClient(IdleObject):
def _check_stream_start(self, ns, tag, attrs): def _check_stream_start(self, ns, tag, attrs):
if ns<>NS_STREAMS or tag<>'stream': if ns<>NS_STREAMS or tag<>'stream':
raise ValueError('Incorrect stream start: (%s,%s). Terminating.' % (tag, ns)) self.Connection.DEBUG('Incorrect stream start: (%s,%s).Terminating! ' % (tag, ns), 'error')
self.Connection.disconnect()
return
if self.sock_type == TYPE_SERVER: if self.sock_type == TYPE_SERVER:
self.send_stream_header() self.send_stream_header()
for message in self.messagequeue: while self.messagequeue:
message = self.messagequeue.pop(0)
self.send(message) self.send(message)
def disconnected(self):
def on_disconnect(self):
if self.conn_holder:
self.conn_holder.remove_connection(self.sock_hash)
if self.__dict__.has_key('Dispatcher'): if self.__dict__.has_key('Dispatcher'):
self.Dispatcher.PlugOut() self.Dispatcher.PlugOut()
if self.__dict__.has_key('P2PConnection'): if self.__dict__.has_key('P2PConnection'):
self.P2PConnection.PlugOut() self.P2PConnection.PlugOut()
self.Connection = None
self._caller = None
self.conn_holder = None
def force_disconnect(self):
if self.Connection:
self.disconnect()
else:
self.on_disconnect()
def _on_receive_document_attrs(self, data): def _on_receive_document_attrs(self, data):
if data: if data:
@ -184,20 +209,19 @@ class P2PConnection(IdleObject, PlugIn):
self._exported_methods=[self.send, self.disconnect, self.onreceive] self._exported_methods=[self.send, self.disconnect, self.onreceive]
self.on_receive = None self.on_receive = None
if _sock: if _sock:
self.connected = True self._sock = _sock
self.state = 1 self.state = 1
_sock.setblocking(False) self._sock.setblocking(False)
self.fd = _sock.fileno() self.fd = self._sock.fileno()
self.on_connect(self) self.on_connect(self)
else: else:
self.connected = False
self.state = 0 self.state = 0
self.idlequeue.plug_idle(self, True, False) self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._sock.setblocking(False)
self.fd = self._sock.fileno()
gajim.idlequeue.plug_idle(self, True, False)
self.do_connect() self.do_connect()
def plugin(self, owner): def plugin(self, owner):
self.onreceive(owner._on_receive_document_attrs) self.onreceive(owner._on_receive_document_attrs)
self._plug_idle() self._plug_idle()
@ -207,7 +231,6 @@ class P2PConnection(IdleObject, PlugIn):
''' Disconnect from the remote server and unregister self.disconnected method from ''' Disconnect from the remote server and unregister self.disconnected method from
the owner's dispatcher. ''' the owner's dispatcher. '''
self.disconnect() self.disconnect()
self._owner.Connection = None
self._owner = None self._owner = None
def onreceive(self, recv_handler): def onreceive(self, recv_handler):
@ -245,6 +268,7 @@ class P2PConnection(IdleObject, PlugIn):
def do_connect(self): def do_connect(self):
errnum = 0
try: try:
self._sock.connect((self.host, self.port)) self._sock.connect((self.host, self.port))
self._sock.setblocking(False) self._sock.setblocking(False)
@ -253,21 +277,17 @@ class P2PConnection(IdleObject, PlugIn):
if errnum in (errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK): if errnum in (errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK):
return return
# win32 needs this # win32 needs this
elif errnum not in (10056, errno.EISCONN) or self.state != 0: elif errnum not in (0, 10056, errno.EISCONN) or self.state != 0:
self.disconnect() self.disconnect()
return None return None
else: # socket is already connected else: # socket is already connected
self._sock.setblocking(False) self._sock.setblocking(False)
self.connected = True
self.state = 1 # connected self.state = 1 # connected
self.on_connect(self) self.on_connect(self)
return 1 # we are connected return 1 # we are connected
def pollout(self): def pollout(self):
if not self.connected:
self.disconnect()
return
if self.state == 0: if self.state == 0:
self.do_connect() self.do_connect()
return return
@ -314,10 +334,8 @@ class P2PConnection(IdleObject, PlugIn):
self.on_receive(received) self.on_receive(received)
else: else:
# This should never happed, so we need the debug # This should never happed, so we need the debug
self.DEBUG('Unhandled data received: %s' % received,'got') self.DEBUG('Unhandled data received: %s' % received,'error')
self.disconnect() self.disconnect()
if self.on_connect_failure:
self.on_connect_failure()
return True return True
def onreceive(self, recv_handler): def onreceive(self, recv_handler):
@ -342,10 +360,9 @@ class P2PConnection(IdleObject, PlugIn):
except: except:
# socket is already closed # socket is already closed
pass pass
self.connected = False
self.fd = -1 self.fd = -1
self.state = -1 self.state = -1
self._owner.disconnected() self._owner.on_disconnect()
def _do_send(self): def _do_send(self):
if not self.sendbuff: if not self.sendbuff:
@ -405,10 +422,23 @@ class ClientZeroconf:
self.roster = roster_zeroconf.Roster(zeroconf) self.roster = roster_zeroconf.Roster(zeroconf)
self.caller = caller self.caller = caller
self.start_listener(zeroconf.port) self.start_listener(zeroconf.port)
self.connections = {}
def kill_all_connections(self):
for connection in self.connections.values():
connection.force_disconnect()
def add_connection(self, connection):
sock_hash = connection.sock_hash
if sock_hash not in self.connections:
self.connections[sock_hash] = connection
def remove_connection(self, sock_hash):
if sock_hash in self.connections:
self.connections[sock_hash]
def start_listener(self, port): def start_listener(self, port):
self.listener = ZeroconfListener(port, self.caller) self.listener = ZeroconfListener(port, self)
self.listener.bind() self.listener.bind()
if self.listener.started is False: if self.listener.started is False:
self.listener = None self.listener = None
@ -416,9 +446,17 @@ class ClientZeroconf:
# dialog from dialogs.py and fail # dialog from dialogs.py and fail
BindPortError(port) BindPortError(port)
return None return None
#~ self.connected += 1
def getRoster(self): def getRoster(self):
return self.roster.getRoster() return self.roster.getRoster()
def send(self, str): def send(self, msg_iq):
pass msg_iq.setFrom(self.roster.zeroconf.name)
to = msg_iq.getTo()
try:
item = self.roster[to]
except KeyError:
#XXX invalid recipient, show some error maybe ?
return
P2PClient(None, item['address'], item['port'], self, [msg_iq])

View File

@ -267,7 +267,6 @@ class ConnectionZeroconf(ConnectionHandlersZeroconf):
chatstate = None, msg_id = None, composing_jep = None, resource = None, chatstate = None, msg_id = None, composing_jep = None, resource = None,
user_nick = None): user_nick = None):
print 'connection_zeroconf.py: send_message' print 'connection_zeroconf.py: send_message'
fjid = jid fjid = jid
if not self.connection: if not self.connection:
@ -320,6 +319,7 @@ class ConnectionZeroconf(ConnectionHandlersZeroconf):
if chatstate is 'composing' or msgtxt: if chatstate is 'composing' or msgtxt:
chatstate_node.addChild(name = 'composing') chatstate_node.addChild(name = 'composing')
self.connection.send(msg_iq)
no_log_for = gajim.config.get_per('accounts', self.name, 'no_log_for') no_log_for = gajim.config.get_per('accounts', self.name, 'no_log_for')
ji = gajim.get_jid_without_resource(jid) ji = gajim.get_jid_without_resource(jid)
if self.name not in no_log_for and ji not in no_log_for: if self.name not in no_log_for and ji not in no_log_for:
@ -332,8 +332,7 @@ class ConnectionZeroconf(ConnectionHandlersZeroconf):
else: else:
kind = 'single_msg_sent' kind = 'single_msg_sent'
gajim.logger.write(kind, jid, log_msg) gajim.logger.write(kind, jid, log_msg)
#~ self.zeroconf.send_message(jid, msgtxt, type)
self.zeroconf.send_message(jid, msgtxt, type)
self.dispatch('MSGSENT', (jid, msg, keyID)) self.dispatch('MSGSENT', (jid, msg, keyID))