def run(self): """ Main TCP receive loop. Should be run in a separate thread -- use start() to do this automatically. """ self.is_shutdown = False if not self.server_sock: raise ROSInternalException("%s did not connect"%self.__class__.__name__) while not self.is_shutdown: try: (client_sock, client_addr) = self.server_sock.accept() except socket.timeout: continue except ConnectionAbortedError: continue except IOError as e: (e_errno, msg, *_) = e.args if e_errno == errno.EINTR: #interrupted system call continue if not self.is_shutdown: raise if self.is_shutdown: break try: #leave threading decisions up to inbound_handler self.inbound_handler(client_sock, client_addr) except socket.error as e: if not self.is_shutdown: traceback.print_exc() logwarn("Failed to handle inbound connection due to socket error: %s"%e) logdebug("TCPServer[%s] shutting down", self.port)
def run(self): """ Main TCP receive loop. Should be run in a separate thread -- use start() to do this automatically. """ self.is_shutdown = False if not self.server_sock: raise ROSInternalException("%s did not connect"%self.__class__.__name__) while not self.is_shutdown: try: (client_sock, client_addr) = self.server_sock.accept() except socket.timeout: continue except IOError as e: (errno, msg) = e.args if errno == 4: #interrupted system call continue raise if self.is_shutdown: break try: #leave threading decisions up to inbound_handler self.inbound_handler(client_sock, client_addr) except socket.error as e: if not self.is_shutdown: traceback.print_exc() logwarn("Failed to handle inbound connection due to socket error: %s"%e) logdebug("TCPServer[%s] shutting down", self.port)
def reg_removed(self, resolved_name, data_type_or_uri, reg_type): """ RegistrationListener callback @param resolved_name: resolved name of topic or service @type resolved_name: str @param data_type_or_uri: either the data type (for topic regs) or the service URI (for service regs). @type data_type_or_uri: str @param reg_type: Valid values are L{Registration.PUB}, L{Registration.SUB}, L{Registration.SRV} @type reg_type: str """ master_uri = self.master_uri if not master_uri: self.logger.error("Registrar: master_uri is not set yet, cannot inform master of deregistration") else: try: master = xmlrpcapi(master_uri) if reg_type == Registration.PUB: self.logger.debug("unregisterPublisher(%s, %s)", resolved_name, self.uri) master.unregisterPublisher(get_caller_id(), resolved_name, self.uri) elif reg_type == Registration.SUB: self.logger.debug("unregisterSubscriber(%s, %s)", resolved_name, data_type_or_uri) master.unregisterSubscriber(get_caller_id(), resolved_name, self.uri) elif reg_type == Registration.SRV: self.logger.debug("unregisterService(%s, %s)", resolved_name, data_type_or_uri) master.unregisterService(get_caller_id(), resolved_name, data_type_or_uri) except: logwarn("unable to communicate with ROS Master, registrations are now out of sync") self.logger.error(traceback.format_exc())
def run(self): """ Main TCP receive loop. Should be run in a separate thread -- use start() to do this automatically. """ self.is_shutdown = False if not self.server_sock: raise ROSInternalException("%s did not connect" % self.__class__.__name__) while not self.is_shutdown: try: (client_sock, client_addr) = self.server_sock.accept() except socket.timeout: continue if self.is_shutdown: break try: #leave threading decisions up to inbound_handler self.inbound_handler(client_sock, client_addr) except socket.error, e: if not self.is_shutdown: traceback.print_exc() logwarn( "Failed to handle inbound connection due to socket error: %s" % e)
def _tcp_server_callback(self, sock, client_addr): """ TCPServer callback: detects incoming topic or service connection and passes connection accordingly @param sock: socket connection @type sock: socket.socket @param client_addr: client address @type client_addr: (str, int) @raise TransportInitError: If transport cannot be succesfully initialized """ #TODOXXX:rewrite this logic so it is possible to create TCPROSTransport object first, set its protocol, #and then use that to do the writing try: buff_size = 4096 # size of read buffer if python3 == 0: #initialize read_ros_handshake_header with BytesIO for Python 3 (instead of bytesarray()) header = read_ros_handshake_header(sock, StringIO(), buff_size) else: header = read_ros_handshake_header(sock, BytesIO(), buff_size) if 'topic' in header: err_msg = self.topic_connection_handler( sock, client_addr, header) elif 'service' in header: err_msg = self.service_connection_handler( sock, client_addr, header) else: err_msg = 'no topic or service name detected' if err_msg: # shutdown race condition: nodes that come up and down # quickly can receive connections during teardown. # We use is_shutdown_requested() because we can get # into bad connection states during client shutdown # hooks. if not rospy.core.is_shutdown_requested(): write_ros_handshake_header(sock, {'error': err_msg}) raise TransportInitError( "Could not process inbound connection: " + err_msg + str(header)) else: write_ros_handshake_header(sock, {'error': 'node shutting down'}) return except rospy.exceptions.TransportInitError as e: logwarn(str(e)) if sock is not None: sock.close() except Exception as e: # collect stack trace separately in local log file if not rospy.core.is_shutdown_requested(): logwarn("Inbound TCP/IP connection failed from '%s': %s", str(client_addr), e) rospyerr("Inbound TCP/IP connection failed from '%s':\n%s", str(client_addr), traceback.format_exc()) if sock is not None: sock.close()
def _tcp_server_callback(self, sock, client_addr): """ TCPServer callback: detects incoming topic or service connection and passes connection accordingly @param sock: socket connection @type sock: socket.socket @param client_addr: client address @type client_addr: (str, int) @raise TransportInitError: If transport cannot be succesfully initialized """ #TODOXXX:rewrite this logic so it is possible to create TCPROSTransport object first, set its protocol, #and then use that to do the writing try: buff_size = 4096 # size of read buffer if python3 == 0: #initialize read_ros_handshake_header with BytesIO for Python 3 (instead of bytesarray()) header = read_ros_handshake_header(sock, StringIO(), buff_size) else: header = read_ros_handshake_header(sock, BytesIO(), buff_size) if 'topic' in header: err_msg = self.topic_connection_handler(sock, client_addr, header) elif 'service' in header: err_msg = self.service_connection_handler(sock, client_addr, header) else: err_msg = 'no topic or service name detected' if err_msg: # shutdown race condition: nodes that come up and down # quickly can receive connections during teardown. # We use is_shutdown_requested() because we can get # into bad connection states during client shutdown # hooks. if not rospy.core.is_shutdown_requested(): write_ros_handshake_header(sock, {'error' : err_msg}) raise TransportInitError("Could not process inbound connection: "+err_msg+str(header)) else: write_ros_handshake_header(sock, {'error' : 'node shutting down'}) return except rospy.exceptions.TransportInitError as e: logwarn(str(e)) if sock is not None: sock.close() except Exception as e: # collect stack trace separately in local log file if not rospy.core.is_shutdown_requested(): logwarn("Inbound TCP/IP connection failed: %s", e) rospyerr("Inbound TCP/IP connection failed:\n%s", traceback.format_exc()) if sock is not None: sock.close()
def _configure_pub_socket(sock, is_tcp_nodelay): """ Configure socket options on a new publisher socket. @param sock: socket.socket @type sock: socket.socket @param is_tcp_nodelay: if True, TCP_NODELAY will be set on outgoing socket if available @param is_tcp_nodelay: bool """ # #956: low latency, TCP_NODELAY support if is_tcp_nodelay: if hasattr(socket, 'TCP_NODELAY'): sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) else: logwarn("WARNING: cannot enable TCP_NODELAY as its not supported on this platform")
def _tcp_server_callback(self, sock, client_addr): """ TCPServer callback: detects incoming topic or service connection and passes connection accordingly @param sock: socket connection @type sock: socket.socket @param client_addr: client address @type client_addr: (str, int) @raise TransportInitError: If transport cannot be succesfully initialized """ #TODOXXX:rewrite this logic so it is possible to create TCPROSTransport object first, set its protocol, #and then use that to do the writing try: buff_size = 4096 # size of read buffer header = read_ros_handshake_header(sock, cStringIO.StringIO(), buff_size) if 'topic' in header: err_msg = self.topic_connection_handler( sock, client_addr, header) elif 'service' in header: err_msg = self.service_connection_handler( sock, client_addr, header) else: err_msg = 'no topic or service name detected' if err_msg: # shutdown race condition: nodes that come up and down quickly can receive connections during teardown if not rospy.core.is_shutdown(): write_ros_handshake_header(sock, {'error': err_msg}) raise TransportInitError( "Could not process inbound connection: " + err_msg + str(header)) else: write_ros_handshake_header(sock, {'error': 'node shutting down'}) return except rospy.exceptions.TransportInitError, e: logwarn(str(e)) if sock is not None: sock.close()
def connect(self, dest_addr, dest_port, endpoint_id, timeout=None): """ Establish TCP connection to the specified address/port. connect() always calls L{write_header()} and L{read_header()} after the connection is made @param dest_addr: destination IP address @type dest_addr: str @param dest_port: destination port @type dest_port: int @param endpoint_id: string identifier for connection (for statistics) @type endpoint_id: str @param timeout: (optional keyword) timeout in seconds @type timeout: float @raise TransportInitError: if unable to create connection """ # first make sure that if ROS_HOSTNAME=localhost, we will not attempt # to connect to anything other than localhost if ("ROS_HOSTNAME" in os.environ) and (os.environ["ROS_HOSTNAME"] == "localhost"): if not rosgraph.network.is_local_address(dest_addr): msg = "attempted to connect to non-local host [%s] from a node launched with ROS_HOSTNAME=localhost" % (dest_addr) logwarn(msg) self.close() raise TransportInitError(msg) # bubble up # now we can proceed with trying to connect. try: self.endpoint_id = endpoint_id self.dest_address = (dest_addr, dest_port) if rosgraph.network.use_ipv6(): s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) else: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) if _is_use_tcp_keepalive(): # OSX (among others) does not define these options if hasattr(socket, 'TCP_KEEPCNT') and \ hasattr(socket, 'TCP_KEEPIDLE') and \ hasattr(socket, 'TCP_KEEPINTVL'): # turn on KEEPALIVE s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) # - # keepalive failures before actual connection failure s.setsockopt(socket.SOL_TCP, socket.TCP_KEEPCNT, 9) # - timeout before starting KEEPALIVE process s.setsockopt(socket.SOL_TCP, socket.TCP_KEEPIDLE, 60) # - interval to send KEEPALIVE after IDLE timeout s.setsockopt(socket.SOL_TCP, socket.TCP_KEEPINTVL, 10) if timeout is not None: s.settimeout(timeout) self.socket = s logdebug('connecting to ' + str(dest_addr)+ ' ' + str(dest_port)) self.socket.connect((dest_addr, dest_port)) self.write_header() self.read_header() self.local_endpoint = self.socket.getsockname() self.remote_endpoint = (dest_addr, dest_port) except TransportInitError as tie: rospyerr("Unable to initiate TCP/IP socket to %s:%s (%s): %s"%(dest_addr, dest_port, endpoint_id, traceback.format_exc())) raise except Exception as e: #logerr("Unknown error initiating TCP/IP socket to %s:%s (%s): %s"%(dest_addr, dest_port, endpoint_id, str(e))) rospywarn("Unknown error initiating TCP/IP socket to %s:%s (%s): %s"%(dest_addr, dest_port, endpoint_id, traceback.format_exc())) # check for error type and reason. On unknown errors the socket will be closed # to avoid reconnection and error reproduction if not isinstance(e, socket.error): # FATAL: no reconnection as error is unknown self.close() elif not isinstance(e, socket.timeout) and e.errno not in [ errno.ENETDOWN, errno.ENETUNREACH, errno.ENETRESET, errno.ECONNABORTED, errno.ETIMEDOUT, errno.EHOSTDOWN, errno.EHOSTUNREACH]: # reconnect in follow cases, otherwise close the socket: # 1. socket.timeout: on timeouts caused by delays on wireless links # 2. ENETDOWN (100), ENETUNREACH (101), ENETRESET (102), ECONNABORTED (103): # while using ROS_HOSTNAME ros binds to a specific interface. Theses errors # are thrown on interface shutdown e.g. on reconnection in LTE networks # 3. ETIMEDOUT (110): same like 1. (for completeness) # 4. EHOSTDOWN (112), EHOSTUNREACH (113): while network and/or DNS-server is not reachable # # no reconnection as error is not 1.-4. self.close() raise TransportInitError(str(e)) #re-raise i/o error
def connect(self, dest_addr, dest_port, endpoint_id, timeout=None): """ Establish TCP connection to the specified address/port. connect() always calls L{write_header()} and L{read_header()} after the connection is made @param dest_addr: destination IP address @type dest_addr: str @param dest_port: destination port @type dest_port: int @param endpoint_id: string identifier for connection (for statistics) @type endpoint_id: str @param timeout: (optional keyword) timeout in seconds @type timeout: float @raise TransportInitError: if unable to create connection """ # first make sure that if ROS_HOSTNAME=localhost, we will not attempt # to connect to anything other than localhost if ("ROS_HOSTNAME" in os.environ) and (os.environ["ROS_HOSTNAME"] == "localhost"): if not rosgraph.network.is_local_address(dest_addr): msg = "attempted to connect to non-local host [%s] from a node launched with ROS_HOSTNAME=localhost" % (dest_addr) logwarn(msg) self.close() raise TransportInitError(msg) # bubble up # now we can proceed with trying to connect. try: self.endpoint_id = endpoint_id self.dest_address = (dest_addr, dest_port) if rosgraph.network.use_ipv6(): s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) else: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) if _is_use_tcp_keepalive(): # OSX (among others) does not define these options if hasattr(socket, 'TCP_KEEPCNT') and \ hasattr(socket, 'TCP_KEEPIDLE') and \ hasattr(socket, 'TCP_KEEPINTVL'): # turn on KEEPALIVE s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) # - # keepalive failures before actual connection failure s.setsockopt(socket.SOL_TCP, socket.TCP_KEEPCNT, 9) # - timeout before starting KEEPALIVE process s.setsockopt(socket.SOL_TCP, socket.TCP_KEEPIDLE, 60) # - interval to send KEEPALIVE after IDLE timeout s.setsockopt(socket.SOL_TCP, socket.TCP_KEEPINTVL, 10) if timeout is not None: s.settimeout(timeout) self.socket = s logdebug('connecting to ' + str(dest_addr)+ ' ' + str(dest_port)) self.socket.connect((dest_addr, dest_port)) self.write_header() self.read_header() self.local_endpoint = self.socket.getsockname() self.remote_endpoint = (dest_addr, dest_port) except TransportInitError as tie: rospyerr("Unable to initiate TCP/IP socket to %s:%s (%s): %s"%(dest_addr, dest_port, endpoint_id, traceback.format_exc())) raise except Exception as e: #logerr("Unknown error initiating TCP/IP socket to %s:%s (%s): %s"%(dest_addr, dest_port, endpoint_id, str(e))) rospywarn("Unknown error initiating TCP/IP socket to %s:%s (%s): %s"%(dest_addr, dest_port, endpoint_id, traceback.format_exc())) # check for error type and reason. On unknown errors the socket will be closed # to avoid reconnection and error reproduction if not isinstance(e, socket.error): # FATAL: no reconnection as error is unknown self.close() elif not isinstance(e, socket.timeout) and e.errno not in [100, 101, 102, 103, 110, 112, 113]: # reconnect in follow cases, otherwise close the socket: # 1. socket.timeout: on timeouts caused by delays on wireless links # 2. ENETDOWN (100), ENETUNREACH (101), ENETRESET (102), ECONNABORTED (103): # while using ROS_HOSTNAME ros binds to a specific interface. Theses errors # are thrown on interface shutdown e.g. on reconnection in LTE networks # 3. ETIMEDOUT (110): same like 1. (for completeness) # 4. EHOSTDOWN (112), EHOSTUNREACH (113): while network and/or DNS-server is not reachable # # no reconnection as error is not 1.-4. self.close() raise TransportInitError(str(e)) #re-raise i/o error
def connect(self, dest_addr, dest_port, endpoint_id, timeout=None): """ Establish TCP connection to the specified address/port. connect() always calls L{write_header()} and L{read_header()} after the connection is made @param dest_addr: destination IP address @type dest_addr: str @param dest_port: destination port @type dest_port: int @param endpoint_id: string identifier for connection (for statistics) @type endpoint_id: str @param timeout: (optional keyword) timeout in seconds @type timeout: float @raise TransportInitError: if unable to create connection """ # first make sure that if ROS_HOSTNAME=localhost, we will not attempt # to connect to anything other than localhost if ("ROS_HOSTNAME" in os.environ) and (os.environ["ROS_HOSTNAME"] == "localhost"): if not rosgraph.network.is_local_address(dest_addr): msg = "attempted to connect to non-local host [%s] from a node launched with ROS_HOSTNAME=localhost" % ( dest_addr) logwarn(msg) self.close() raise TransportInitError(msg) # bubble up # now we can proceed with trying to connect. try: self.endpoint_id = endpoint_id self.dest_address = (dest_addr, dest_port) if rosgraph.network.use_ipv6(): s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) else: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) if _is_use_tcp_keepalive(): # OSX (among others) does not define these options if hasattr(socket, 'TCP_KEEPCNT') and \ hasattr(socket, 'TCP_KEEPIDLE') and \ hasattr(socket, 'TCP_KEEPINTVL'): # turn on KEEPALIVE s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) # - # keepalive failures before actual connection failure s.setsockopt(socket.SOL_TCP, socket.TCP_KEEPCNT, 9) # - timeout before starting KEEPALIVE process s.setsockopt(socket.SOL_TCP, socket.TCP_KEEPIDLE, 60) # - interval to send KEEPALIVE after IDLE timeout s.setsockopt(socket.SOL_TCP, socket.TCP_KEEPINTVL, 10) if timeout is not None: s.settimeout(timeout) self.socket = s logdebug('connecting to ' + str(dest_addr) + ' ' + str(dest_port)) self.socket.connect((dest_addr, dest_port)) self.write_header() self.read_header() self.local_endpoint = self.socket.getsockname() self.remote_endpoint = (dest_addr, dest_port) except TransportInitError as tie: rospyerr( "Unable to initiate TCP/IP socket to %s:%s (%s): %s" % (dest_addr, dest_port, endpoint_id, traceback.format_exc())) raise except Exception as e: #logerr("Unknown error initiating TCP/IP socket to %s:%s (%s): %s"%(dest_addr, dest_port, endpoint_id, str(e))) rospywarn( "Unknown error initiating TCP/IP socket to %s:%s (%s): %s" % (dest_addr, dest_port, endpoint_id, traceback.format_exc())) # FATAL: no reconnection as error is unknown self.close() raise TransportInitError(str(e)) #re-raise i/o error
def connect(self, dest_addr, dest_port, endpoint_id, timeout=None): """ Establish TCP connection to the specified address/port. connect() always calls L{write_header()} and L{read_header()} after the connection is made @param dest_addr: destination IP address @type dest_addr: str @param dest_port: destination port @type dest_port: int @param endpoint_id: string identifier for connection (for statistics) @type endpoint_id: str @param timeout: (optional keyword) timeout in seconds @type timeout: float @raise TransportInitError: if unable to create connection """ # first make sure that if ROS_HOSTNAME=localhost, we will not attempt # to connect to anything other than localhost if ("ROS_HOSTNAME" in os.environ) and (os.environ["ROS_HOSTNAME"] == "localhost"): if not rosgraph.network.is_local_address(dest_addr): msg = "attempted to connect to non-local host [%s] from a node launched with ROS_HOSTNAME=localhost" % (dest_addr) logwarn(msg) self.close() raise TransportInitError(msg) # bubble up # now we can proceed with trying to connect. try: self.endpoint_id = endpoint_id self.dest_address = (dest_addr, dest_port) if rosgraph.network.use_ipv6(): s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) else: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) if _is_use_tcp_keepalive(): # OSX (among others) does not define these options if hasattr(socket, 'TCP_KEEPCNT') and \ hasattr(socket, 'TCP_KEEPIDLE') and \ hasattr(socket, 'TCP_KEEPINTVL'): # turn on KEEPALIVE s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) # - # keepalive failures before actual connection failure s.setsockopt(socket.SOL_TCP, socket.TCP_KEEPCNT, 9) # - timeout before starting KEEPALIVE process s.setsockopt(socket.SOL_TCP, socket.TCP_KEEPIDLE, 60) # - interval to send KEEPALIVE after IDLE timeout s.setsockopt(socket.SOL_TCP, socket.TCP_KEEPINTVL, 10) if timeout is not None: s.settimeout(timeout) self.socket = s logdebug('connecting to ' + str(dest_addr)+ ' ' + str(dest_port)) self.socket.connect((dest_addr, dest_port)) self.write_header() self.read_header() self.local_endpoint = self.socket.getsockname() self.remote_endpoint = (dest_addr, dest_port) except TransportInitError as tie: rospyerr("Unable to initiate TCP/IP socket to %s:%s (%s): %s"%(dest_addr, dest_port, endpoint_id, traceback.format_exc())) raise except Exception as e: #logerr("Unknown error initiating TCP/IP socket to %s:%s (%s): %s"%(dest_addr, dest_port, endpoint_id, str(e))) rospywarn("Unknown error initiating TCP/IP socket to %s:%s (%s): %s"%(dest_addr, dest_port, endpoint_id, traceback.format_exc())) # FATAL: no reconnection as error is unknown self.close() raise TransportInitError(str(e)) #re-raise i/o error
if not rospy.core.is_shutdown(): write_ros_handshake_header(sock, {'error': err_msg}) raise TransportInitError( "Could not process inbound connection: " + err_msg + str(header)) else: write_ros_handshake_header(sock, {'error': 'node shutting down'}) return except rospy.exceptions.TransportInitError, e: logwarn(str(e)) if sock is not None: sock.close() except Exception, e: # collect stack trace separately in local log file logwarn("Inbound TCP/IP connection failed: %s", e) rospyerr("Inbound TCP/IP connection failed:\n%s", traceback.format_exc(e)) if sock is not None: sock.close() class TCPROSTransportProtocol(object): """ Abstraction of TCPROS connections. Implementations Services/Publishers/Subscribers must implement this protocol, which defines how messages are deserialized from an inbound connection (read_messages()) as well as which fields to send when creating a new connection (get_header_fields()). """ def __init__(self, resolved_name, recv_data_class,