Package sick_ldmrs :: Module xport
[frames] | no frames]

Source Code for Module sick_ldmrs.xport

  1  #*********************************************************** 
  2  #* Software License Agreement (BSD License) 
  3  #* 
  4  #*  Copyright (c) 2010, CSIRO Autonomous Systems Laboratory 
  5  #*  All rights reserved. 
  6  #* 
  7  #*  Redistribution and use in source and binary forms, with or without 
  8  #*  modification, are permitted provided that the following conditions 
  9  #*  are met: 
 10  #* 
 11  #*   * Redistributions of source code must retain the above copyright 
 12  #*     notice, this list of conditions and the following disclaimer. 
 13  #*   * Redistributions in binary form must reproduce the above 
 14  #*     copyright notice, this list of conditions and the following 
 15  #*     disclaimer in the documentation and/or other materials provided 
 16  #*     with the distribution. 
 17  #*   * Neither the name of the CSIRO nor the names of its 
 18  #*     contributors may be used to endorse or promote products derived 
 19  #*     from this software without specific prior written permission. 
 20  #* 
 21  #*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 22  #*  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 23  #*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 24  #*  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 25  #*  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 26  #*  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 27  #*  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 28  #*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
 29  #*  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 30  #*  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
 31  #*  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 32  #*  POSSIBILITY OF SUCH DAMAGE. 
 33  #*********************************************************** 
 34   
 35  # Author: Brett Grandbois 
 36  #$Id$ 
 37   
 38  import socket 
 39  import errno 
 40   
 41  from exceptions import * 
 42   
43 -class XPort(object):
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
51 - def __init__ (self, host, port):
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 # don't want small messages lingering in the buffers 71 self.__sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) 72 # needed for just calling connect()? doesn't hurt to set it... 73 self.__sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 74 75 # 5 second timeout should be more than sufficient 76 # in any case of this timeout happening we want the exception to 77 # force a restart 78 self.__sock.settimeout(5.0) 79 80 host_ip = socket.gethostbyname(host) 81 82 self.__sock.connect((host_ip, port)) 83 84 # addressing error is fatal, it means a supplied host does not exist 85 # or can not be found 86 except (socket.herror, socket.gaierror), e: 87 raise FatalException('address exception in XPort init: %s' % e) 88 89 # in init a timeout means restart the system, most likely the LD-MRS 90 # isn't ready yet 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 # EPIPE should be a shutdown signal 173 raise InfoRestartException('socket.sendall: %s' % e) 174 else: 175 raise ErrorRestartExcetpion('error in socket.sendall: %s' % e)
176
177 - def shutdown(self):
178 ''' Call socket.shutdown to pop out of any blocking send/recv ''' 179 # this can be called from external callbacks as well 180 # as the main loop exit 181 if not self.__shutdown: 182 # call shutdown first to immediately terminate comms 183 # close will linger trying to flush any pending data 184 self.__shutdown = True 185 try: 186 self.__sock.shutdown(socket.SHUT_RDWR) 187 except socket.error: 188 # we're shutting down so don't care about socket level errors 189 pass
190
191 - def close(self):
192 '''close the xport socket''' 193 try: 194 self.__sock.close() 195 except socket.error: 196 # we're shutting down so don't care about socket-level errors 197 pass
198