Passed
Push — master ( cf72e6...2ad18d )
by Humberto
06:56 queued 03:57
created

kytos.core.connection.Connection.__repr__()   A

Complexity

Conditions 1

Size

Total Lines 3
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
"""Module with main classes related to Connections."""
2 1
import logging
3 1
from enum import Enum
4 1
from errno import EBADF, ENOTCONN
5 1
from socket import SHUT_RDWR
6 1
from socket import error as SocketError
7
8 1
__all__ = ('Connection', 'ConnectionProtocol', 'ConnectionState')
9
10 1
LOG = logging.getLogger(__name__)
11
12
13 1
class ConnectionState(Enum):
14
    """Enum of possible general connections states."""
15
16 1
    NEW = 0
17 1
    SETUP = 1
18 1
    ESTABLISHED = 2
19 1
    FAILED = 3
20 1
    FINISHED = 4
21
22
23 1
class ConnectionProtocol:
24
    """Class to hold simple protocol information for the connection."""
25
26 1
    def __init__(self, name=None, version=None, state=None):
27
        """Assign parameters to instance variables."""
28 1
        self.name = name
29 1
        self.version = version
30 1
        self.state = state
31
32
33 1
class Connection:
34
    """Connection class to abstract a network connections."""
35
36 1
    def __init__(self, address, port, socket, switch=None):
37
        """Assign parameters to instance variables.
38
39
        Args:
40
            address (|hw_address|): Source address.
41
            port (int): Port number.
42
            socket (socket): socket.
43
            switch (:class:`~.Switch`): switch with this connection.
44
        """
45 1
        self.address = address
46 1
        self.port = port
47 1
        self.socket = socket
48 1
        self.switch = switch
49 1
        self.state = ConnectionState.NEW
50 1
        self.protocol = ConnectionProtocol()
51 1
        self.remaining_data = b''
52
53 1
    def __str__(self):
54 1
        return f"Connection({self.address!r}, {self.port!r})"
55
56 1
    def __repr__(self):
57 1
        return f"Connection({self.address!r}, {self.port!r}," + \
58
               f" {self.socket!r}, {self.switch!r}, {self.state!r})"
59
60 1
    @property
61
    def state(self):
62
        """Return the state of the connection."""
63 1
        return self._state
64
65 1
    @state.setter
66
    def state(self, new_state):
67 1
        if new_state not in ConnectionState:
68 1
            raise Exception('Unknown State', new_state)
69
        # pylint: disable=attribute-defined-outside-init
70 1
        self._state = new_state
71
        # pylint: enable=attribute-defined-outside-init
72 1
        LOG.debug('Connection %s changed state: %s',
73
                  self.id, self.state)
74
75 1
    @property
76
    def id(self):  # pylint: disable=invalid-name
77
        """Return id from Connection instance.
78
79
        Returns:
80
            string: Connection id.
81
82
        """
83 1
        return (self.address, self.port)
84
85 1
    def send(self, buffer):
86
        """Send a buffer message using the socket from the connection instance.
87
88
        Args:
89
            buffer (bytes): Message buffer that will be sent.
90
        """
91 1
        try:
92 1
            if self.is_alive():
93 1
                self.socket.sendall(buffer)
94 1
        except (OSError, SocketError) as exception:
95 1
            LOG.debug('Could not send packet. Exception: %s', exception)
96 1
            self.close()
97
98 1
    def close(self):
99
        """Close the socket from connection instance."""
100 1
        self.state = ConnectionState.FINISHED
101 1
        if self.switch and self.switch.connection is self:
102 1
            self.switch.connection = None
103
104 1
        LOG.debug('Shutting down Connection %s', self.id)
105
106 1
        try:
107 1
            self.socket.shutdown(SHUT_RDWR)
108 1
            self.socket.close()
109 1
            self.socket = None
110 1
            LOG.debug('Connection Closed: %s', self.id)
111 1
        except OSError as exception:
112 1
            if exception.errno not in (ENOTCONN, EBADF):
113 1
                raise exception
114 1
        except AttributeError as exception:
115 1
            LOG.debug('Socket Already Closed: %s', self.id)
116
117 1
    def is_alive(self):
118
        """Return True if the connection socket is alive. False otherwise."""
119 1
        return self.socket is not None and self.state not in (
120
            ConnectionState.FINISHED, ConnectionState.FAILED)
121
122 1
    def is_new(self):
123
        """Return True if the connection is new. False otherwise."""
124 1
        return self.state == ConnectionState.NEW
125
126 1
    def is_established(self):
127
        """Return True if the connection is established. False otherwise."""
128 1
        return self.state == ConnectionState.ESTABLISHED
129
130 1
    def is_during_setup(self):
131
        """Return True if the connection is in setup state. False otherwise."""
132 1
        return self.state == ConnectionState.SETUP
133
134 1
    def set_established_state(self):
135
        """Set the connection state to Established."""
136 1
        self.state = ConnectionState.ESTABLISHED
137
138 1
    def set_setup_state(self):
139
        """Set the connection state to Setup."""
140 1
        self.state = ConnectionState.SETUP
141
142 1
    def update_switch(self, switch):
143
        """Update switch with this instance of Connection.
144
145
        Args:
146
          switch (:class:`~.Switch`): switch instance.
147
        """
148 1
        self.switch = switch
149
        self.switch.connection = self
150