Skip to content

Commit

Permalink
asyncconnection: raise handle_error on connect exception
Browse files Browse the repository at this point in the history
This happens for DNS errors.
Requires agents locks to be re-entrant as event_close will be called in start.
  • Loading branch information
cladmi committed Mar 3, 2017
1 parent 5830144 commit e7a0dc6
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 7 deletions.
9 changes: 7 additions & 2 deletions iotlabmqtt/asyncconnection.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
Implement a class for AsyncoreService and a NodeConnection with handlers.
"""

from __future__ import (absolute_import, division, print_function,
unicode_literals)
from builtins import * # pylint:disable=W0401,W0614,W0622

import socket
import threading
import asyncore
Expand Down Expand Up @@ -48,11 +52,12 @@ def handle_data(self, data):

def start(self):
"""Connects to node serial port:"""

self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
try:
self.connect(self.address)
except (IOError, OverflowError):
self.handle_close()
except: # pylint:disable=broad-except,bare-except
self.handle_error()

def handle_connect(self):
"""Node connected."""
Expand Down
11 changes: 6 additions & 5 deletions iotlabmqtt/serial.py
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,8 @@ def __init__(self, archi, num, # pylint:disable=too-many-arguments
self.connection = SerialConnection(archi, num, self.conn_event_handler,
service=asyncoreservice)

self._lock = threading.Lock()
# Required Rlock, connection socket errors calls event_handler('close')
self._rlock = threading.RLock()

@staticmethod
def hostname(archi, num):
Expand Down Expand Up @@ -386,7 +387,7 @@ def _reply_request(self, reply, newstate=None):
self.reply_publisher(reply.encode('utf-8'))
self.reply_publisher = None

@common.synchronized('_lock')
@common.synchronized('_rlock')
def close(self):
"""Close connection and state."""
self._close()
Expand All @@ -401,7 +402,7 @@ def _close(self):
self.closed_cb(self)
return previous_state

@common.synchronized('_lock')
@common.synchronized('_rlock')
def conn_event_handler(self, event):
"""Handler for connection events."""
event_handler = {
Expand Down Expand Up @@ -433,7 +434,7 @@ def _event_close(self):
# Jumps to event error
raise Exception('Connection closed in state %s' % self.state)

@common.synchronized('_lock')
@common.synchronized('_rlock')
def req_linestart(self, reply_publisher, line_handler):
"""Request to start line."""

Expand All @@ -453,7 +454,7 @@ def req_linestart(self, reply_publisher, line_handler):
self.connection.start()
return None

@common.synchronized('_lock')
@common.synchronized('_rlock')
def lineinput(self, payload):
"""Send ``payload`` with a newline to the node connection."""
if self.state != 'line':
Expand Down
21 changes: 21 additions & 0 deletions iotlabmqtt/tests/integration_tests/serial_integration_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,27 @@ def _test_serial_agent_no_port(self, client, stdout):
stdout.seek(0)
stdout.truncate(0)

def test_serial_agent_dns_fail(self):
"""Test connecting on non existing dns node."""
with self.start_client_and_server(self.BROKERPORT) as (client, stdout):
self._test_serial_agent_dns_fail(client, stdout)

def _test_serial_agent_dns_fail(self, client, stdout):
"""This dns error is raised directly by connect.
So it triggers a different path than an async failure.
"""

# Start line non existing dns entry (even on IoT-LAB, raises DNS fail)
client.onecmd('linestart m3 1234')

# Error message
err = ('Connection failed: '
'[Errno -5] No address associated with hostname\n')
self.assertEqual(stdout.getvalue(), err)
stdout.seek(0)
stdout.truncate(0)

def test_serial_agent_conn_stop(self):
"""Connection stops on one node, and stopall."""
with self.start_client_and_server(self.BROKERPORT) as (client, stdout):
Expand Down

0 comments on commit e7a0dc6

Please sign in to comment.