1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 import socket
39 import errno
40
41 from exceptions import *
42
44 '''Class representation of a socket transport thread.
45
46 Simplification wrapper around socket.socket and related objects.
47 The send and recv methods will wait for all requested data and/or
48 provide a filtered exception (something good, bad, or ugly happened).
49 '''
50
52 ''' XPort constructor, connect to requested peer.
53
54 Connect to requested network peer or raise reason why not.
55 @param host: hostname to connect to. can be name or IPv4 dot notation.
56 @type host: str
57 @param port: network port to connect to
58 @type port: int
59 @raise FatalExcetpion: Host/port does not exist or is unreachable.
60 @raise TimeoutException: Network is reachable but timeout on connect.
61 Likely host is not yet ready.
62 @raise InfoRestartException: Non-fatal network problem, able to re-try.
63 @raise ErrorRestartException: More serious network problem, possibly can
64 re-try.
65 '''
66 try:
67 self.__shutdown = False
68
69 self.__sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
70
71 self.__sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
72
73 self.__sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
74
75
76
77
78 self.__sock.settimeout(5.0)
79
80 host_ip = socket.gethostbyname(host)
81
82 self.__sock.connect((host_ip, port))
83
84
85
86 except (socket.herror, socket.gaierror), e:
87 raise FatalException('address exception in XPort init: %s' % e)
88
89
90
91 except socket.timeout, e:
92 raise TimeoutException('timeout exceeded in host connect: %s' % e)
93
94 except socket.error, e:
95 fatals = [errno.ENETUNREACH, errno.EACCES, errno.EPERM, errno.EFAULT]
96 not_found = [errno.ECONNREFUSED, errno.EHOSTUNREACH, errno.EHOSTDOWN,
97 errno.EALREADY]
98 if e.errno in fatals:
99 raise FatalException('fatal error in socket init sequence: %s'
100 % e)
101 elif e.errno in not_found:
102 raise InfoRestartException('no host found at %s:%d...continuing to try'
103 % (host, port))
104 else:
105 raise ErrorRestartException('error in socket init sequence: %s'
106 % e)
107
108 - def recv(self, length):
109 ''' Wait for data from the network peer.
110
111 Wait until all requested data from the network peer has arrived.
112 @param length: how much data is requested
113 @type length: int
114 @return: data from network peer
115 @rtype: str
116 @raise TimeoutException: no data has arrived in the timeout period
117 @raise InfoRestartException: remote peer has closed the socket, the
118 data request can not be fulfilled but able to reconnect to peer.
119 @raise NextMsgException: signal interruption, current data request
120 can not be fulfilled but new request can be issued
121 @raise ErrorRestartException: network problem reported and data request
122 can not be fulfilled. should reconnect to peer.
123 '''
124 data_recv = 0
125 return_string = ''
126 next_msg = [errno.EINTR, ]
127 info = [errno.ECONNRESET, errno.EPIPE]
128 while data_recv < length:
129 try:
130 data = self.__sock.recv(length - data_recv, socket.MSG_WAITALL)
131 except socket.timeout:
132 raise TimeoutException('timeout on socket.recv')
133 except socket.error, e:
134 if e.errno in next_msg:
135 raise NextMsgException()
136 elif e.errno in info:
137 raise InfoRestartException('socket.recv restarting xport: %s'
138 % e)
139 else:
140 raise ErrorRestartException('error in socket recv: %s' % e)
141
142 if not data:
143 raise InfoRestartException('socket.recv zero-length, likely a shutdown signal')
144 else:
145 return_string += data
146 data_recv += len(data)
147
148 return return_string
149
150
151 - def send(self, cmd):
152 '''Send a data message to the network peer.
153
154 Send all requested message data.
155 @param cmd: data to send
156 @type cmd: str
157 @raise TimeoutException: data could not be sent during the timeout
158 period, likely the peer has gone down
159 @raise InfoRestartException: peer has closed connection or local shutdown
160 signal caught. either way current send can not be fulfilled.
161 @raise ErrorRestartException: network problem reported and data send
162 can not be fulfilled. should reconnect to peer.
163 '''
164
165 info = [errno.EPIPE, errno.ECONNRESET, errno.EINTR]
166 try:
167 self.__sock.sendall(cmd)
168 except socket.timeout:
169 raise TimeoutException('timeout on socket.sendall')
170 except socket.error, e:
171 if e.errno in info:
172
173 raise InfoRestartException('socket.sendall: %s' % e)
174 else:
175 raise ErrorRestartExcetpion('error in socket.sendall: %s' % e)
176
178 ''' Call socket.shutdown to pop out of any blocking send/recv '''
179
180
181 if not self.__shutdown:
182
183
184 self.__shutdown = True
185 try:
186 self.__sock.shutdown(socket.SHUT_RDWR)
187 except socket.error:
188
189 pass
190
192 '''close the xport socket'''
193 try:
194 self.__sock.close()
195 except socket.error:
196
197 pass
198