6
Created by Thomas Mangin on 2009-09-06.
7
Copyright (c) 2009-2011 Exa Networks. All rights reserved.
16
from exabgp.utils import hexa,trace
17
from exabgp.structure.address import AFI
18
from exabgp.message import Failure
20
from exabgp.log import Logger,LazyFormat
23
class Connection (object):
24
def __init__ (self,peer,local,md5,ttl):
29
logger.wire("Opening connection to %s" % self.peer)
31
if peer.afi != local.afi:
32
raise Failure('The local IP and peer IP must be of the same family (both IPv4 or both IPv6)')
35
if peer.afi == AFI.ipv4:
36
self.io = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP)
37
if peer.afi == AFI.ipv6:
38
self.io = socket.socket(socket.AF_INET6, socket.SOCK_STREAM, socket.IPPROTO_TCP)
40
self.io.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
41
except AttributeError:
44
self.io.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
45
except AttributeError:
48
if peer.afi == AFI.ipv4:
49
self.io.bind((local.ip,0))
50
if peer.afi == AFI.ipv6:
51
self.io.bind((local.ip,0,0,0))
52
except socket.error,e:
54
raise Failure('Could not bind to local ip %s - %s' % (local.ip,str(e)))
59
TCP_MD5SIG_MAXKEYLEN = 80
62
n_addr = socket.inet_aton(peer.ip)
63
n_port = socket.htons(179)
64
tcp_md5sig = 'HH4s%dx2xH4x%ds' % (SS_PADSIZE, TCP_MD5SIG_MAXKEYLEN)
65
md5sig = struct.pack(tcp_md5sig, socket.AF_INET, n_port, n_addr, len(md5), md5)
66
self.io.setsockopt(socket.IPPROTO_TCP, TCP_MD5SIG, md5sig)
67
except socket.error,e:
69
raise Failure('This OS does not support TCP_MD5SIG, you can not use MD5 : %s' % str(e))
71
# None (ttl-security unset) or zero (maximum TTL) is the same thing
74
self.io.setsockopt(socket.IPPROTO_IP,socket.IP_TTL, 20)
75
except socket.error,e:
77
raise Failure('This OS does not support IP_TTL (ttl-security), you can not use MD5 : %s' % str(e))
80
if peer.afi == AFI.ipv4:
81
self.io.connect((peer.ip,179))
82
if peer.afi == AFI.ipv6:
83
self.io.connect((peer.ip,179,0,0))
84
self.io.setblocking(0)
85
except socket.error, e:
87
raise Failure('Could not connect to peer (if you use MD5, check your passwords): %s' % str(e))
90
r,_,_ = select.select([self.io,],[],[],0)
96
def read (self,number):
97
if number == 0: return ''
99
r = self.io.recv(number)
100
self.last_read = time.time()
101
logger.wire(LazyFormat("%15s RECV " % self.peer,hexa,r))
103
except socket.timeout,e:
105
raise Failure('Timeout while reading data from the network: %s ' % str(e))
106
except socket.error,e:
108
raise Failure('Problem while reading data from the network: %s ' % str(e))
110
def write (self,data):
112
logger.wire(LazyFormat("%15s SENT " % self.peer,hexa,data))
113
r = self.io.send(data)
114
self.last_write = time.time()
116
except socket.error, e:
117
# Broken pipe, we ignore as we want to make sure if there is data to read before failing
118
if getattr(e,'errno',None) != 32:
120
logger.wire("%15s %s" % (self.peer,trace()))
121
raise Failure('Problem while writing data to the network: %s' % str(e))
125
logger.wire("Closing connection to %s" % self.peer)