def __init__(self, name, service_class, handler, buff_size=DEFAULT_BUFF_SIZE): """ ctor. @param name: service name @type name: str @param service_class: ServiceDefinition class @type service_class: ServiceDefinition class @param handler: callback function for processing service request. Function takes in a ServiceRequest and returns a ServiceResponse of the appropriate type. Function may also return a list, tuple, or dictionary with arguments to initialize a ServiceResponse instance of the correct type. If handler cannot process request, it may either return None, to indicate failure, or it may raise a rospy.ServiceException to send a specific error message to the client. Returning None is always considered a failure. @type handler: fn(req)->resp @param buff_size: size of buffer for reading incoming requests. Should be at least size of request message @type buff_size: int """ super(Service, self).__init__(name, service_class, handler, buff_size) #TODO: make service manager configurable get_service_manager().register(self.resolved_name, self)
def __init__(self, name, service_class, handler, buff_size=DEFAULT_BUFF_SIZE): """ ctor. @param name: service name, ``str`` @param service_class: Service definition class @param handler: callback function for processing service request. Function takes in a ServiceRequest and returns a ServiceResponse of the appropriate type. Function may also return a list, tuple, or dictionary with arguments to initialize a ServiceResponse instance of the correct type. If handler cannot process request, it may either return None, to indicate failure, or it may raise a rospy.ServiceException to send a specific error message to the client. Returning None is always considered a failure. @type handler: fn(req)->resp @param buff_size: size of buffer for reading incoming requests. Should be at least size of request message @type buff_size: int """ super(Service, self).__init__(name, service_class, handler, buff_size) #TODO: make service manager configurable get_service_manager().register(self.resolved_name, self)
def shutdown(self, reason=''): """ Stop this service @param reason: human-readable shutdown reason @type reason: str """ self.done = True logdebug('[%s].shutdown: reason [%s]'%(self.resolved_name, reason)) try: #TODO: make service manager configurable get_service_manager().unregister(self.resolved_name, self) except Exception as e: logerr("Unable to unregister with master: "+traceback.format_exc()) raise ServiceException("Unable to connect to master: %s"%e)
def test_get_set_service_manager(self): from rospy.impl.registration import get_service_manager, set_service_manager # rospy initialization sets this, but it is out of scope of # rospy.impl.registrations to test its value try: orig = get_service_manager() self.assert_(orig is not None) class ServiceManager(object): pass x = ServiceManager() # currently untyped set_service_manager(x) self.assertEquals(x, get_service_manager()) set_service_manager(None) self.assert_(get_service_manager() is None) finally: set_service_manager(orig)
def service_connection_handler(sock, client_addr, header): """ Process incoming service connection. For use with TCPROSServer. Reads in service name from handshake and creates the appropriate service handler for the connection. @param sock: socket connection @type sock: socket @param client_addr: client address @type client_addr: (str, int) @param header: key/value pairs from handshake header @type header: dict @return: error string or None @rtype: str """ for required in ['service', 'md5sum', 'callerid']: if not required in header: return "Missing required '%s' field" % required else: logger.debug("connection from %s:%s", client_addr[0], client_addr[1]) service_name = header['service'] """ check again if the client request is authorized """ auth_logger.info( "received service connection for %s from %s (%s:%s)" % (service_name, header["callerid"], client_addr[0], client_addr[1])) client_ip_address = client_addr[0] if not is_requester_authorized(service_name, client_ip_address): auth_logger.warn( "service connection for %s from %s (%s) not authorized" % (service_name, header["callerid"], client_ip_address)) return "Client [%s] wants service connection for %s, but %s is not authorized" % ( header['callerid'], service_name, client_ip_address) auth_logger.info("service connection for %s from %s (%s) OK" % (service_name, header["callerid"], client_ip_address)) #TODO: make service manager configurable. I think the right #thing to do is to make these singletons private members of a #Node instance and enable rospy to have multiple node #instances. sm = get_service_manager() md5sum = header['md5sum'] service = sm.get_service(service_name) if not service: return "[%s] is not a provider of [%s]" % ( rospy.names.get_caller_id(), service_name) elif md5sum != rospy.names.SERVICE_ANYTYPE and md5sum != service.service_class._md5sum: return "request from [%s]: md5sums do not match: [%s] vs. [%s]" % ( header['callerid'], md5sum, service.service_class._md5sum) else: transport = TCPROSTransport(service.protocol, service_name, header=header) transport.set_socket(sock, header['callerid']) transport.write_header() # using threadpool reduced performance by an order of # magnitude, need to investigate better t = threading.Thread(target=service.handle, args=(transport, header)) t.setDaemon(True) t.start()
def __init__(self, Name, service_class, handler, buff_size=DEFAULT_BUFF_SIZE, error_handler=None): name = Name status = name.split('/')[-1] if status != '~set_logger_level': if status != '~get_loggers': if name.split('___')[0] != 'OPERATOR': name = name + "_prime" else: name = name.split('___')[1] """ ctor. @param name: service name, ``str`` @param service_class: Service definition class @param handler: callback function for processing service request. Function takes in a ServiceRequest and returns a ServiceResponse of the appropriate type. Function may also return a list, tuple, or dictionary with arguments to initialize a ServiceResponse instance of the correct type. If handler cannot process request, it may either return None, to indicate failure, or it may raise a rospy.ServiceException to send a specific error message to the client. Returning None is always considered a failure. @type handler: fn(req)->resp @param buff_size: size of buffer for reading incoming requests. Should be at least size of request message @type buff_size: int @param error_handler: callback function for handling errors raised in the service code. @type error_handler: fn(exception, exception_type, exception_value, traceback)->None """ super(Service, self).__init__(name, service_class, handler, buff_size, error_handler) #TODO: make service manager configurable get_service_manager().register(self.resolved_name, self)
def service_connection_handler(sock, client_addr, header): """ Process incoming service connection. For use with TCPROSServer. Reads in service name from handshake and creates the appropriate service handler for the connection. @param sock: socket connection @type sock: socket @param client_addr: client address @type client_addr: (str, int) @param header: key/value pairs from handshake header @type header: dict @return: error string or None @rtype: str """ for required in ['service', 'md5sum', 'callerid']: if not required in header: return "Missing required '%s' field"%required else: logger.debug("connection from %s:%s", client_addr[0], client_addr[1]) service_name = header['service'] #TODO: make service manager configurable. I think the right #thing to do is to make these singletons private members of a #Node instance and enable rospy to have multiple node #instances. sm = get_service_manager() md5sum = header['md5sum'] service = sm.get_service(service_name) if not service: return "[%s] is not a provider of [%s]"%(rospy.names.get_caller_id(), service_name) elif md5sum != rospy.names.SERVICE_ANYTYPE and md5sum != service.service_class._md5sum: return "request from [%s]: md5sums do not match: [%s] vs. [%s]"%(header['callerid'], md5sum, service.service_class._md5sum) else: transport = TCPROSTransport(service.protocol, service_name, header=header) transport.set_socket(sock, header['callerid']) transport.write_header() # using threadpool reduced performance by an order of # magnitude, need to investigate better t = threading.Thread(target=service.handle, args=(transport, header)) t.setDaemon(True) t.start()
def test_service_connection_handler(self): import test_rospy.srv from rospy.impl.registration import get_service_manager import rospy.service sock = FakeSocket() from rospy.impl.tcpros_service import service_connection_handler client_addr = '10.0.0.1' # check error conditions on missing headers self.assert_( "Missing" in service_connection_handler(sock, client_addr, {})) header = {'service': '/service', 'md5sum': '*', 'callerid': '/bob'} for k in header: c = header.copy() del c[k] msg = service_connection_handler(sock, client_addr, c) self.assert_("Missing" in msg, str(c) + msg) self.assert_(k in msg, msg) # check error condition on invalid service header['service'] = '/doesnotexist' msg = service_connection_handler(sock, client_addr, header) self.assert_('is not a provider' in msg, msg) # check invalid md5sums name = '/service' sm = get_service_manager() fake_service = \ rospy.service._Service(name, test_rospy.srv.EmptySrv) sm.register(name, fake_service) header['service'] = name header['md5sum'] = 'X' msg = service_connection_handler(sock, client_addr, header) self.assert_('md5sums do not match' in msg, msg)
def test_service_connection_handler(self): import test_rospy.srv from rospy.impl.registration import get_service_manager import rospy.service sock = FakeSocket() from rospy.impl.tcpros_service import service_connection_handler client_addr = '10.0.0.1' # check error conditions on missing headers self.assert_("Missing" in service_connection_handler(sock, client_addr, {})) header = { 'service' : '/service', 'md5sum': '*', 'callerid': '/bob' } for k in header: c = header.copy() del c[k] msg = service_connection_handler(sock, client_addr, c) self.assert_("Missing" in msg, str(c) + msg) self.assert_(k in msg, msg) # check error condition on invalid service header['service'] = '/doesnotexist' msg = service_connection_handler(sock, client_addr, header) self.assert_('is not a provider' in msg, msg) # check invalid md5sums name = '/service' sm = get_service_manager() fake_service = \ rospy.service._Service(name, test_rospy.srv.EmptySrv) sm.register(name, fake_service) header['service'] = name header['md5sum'] = 'X' msg = service_connection_handler(sock, client_addr, header) self.assert_('md5sums do not match' in msg, msg)
def test_service_connection_handler(self): import test_rospy.srv from rospy.impl.registration import get_service_manager import rospy.service sock = FakeSocket() from rospy.impl.tcpros_service import service_connection_handler client_addr = "10.0.0.1" # check error conditions on missing headers self.assert_("Missing" in service_connection_handler(sock, client_addr, {})) header = {"service": "/service", "md5sum": "*", "callerid": "/bob"} for k in header: c = header.copy() del c[k] msg = service_connection_handler(sock, client_addr, c) self.assert_("Missing" in msg, str(c) + msg) self.assert_(k in msg, msg) # check error condition on invalid service header["service"] = "/doesnotexist" msg = service_connection_handler(sock, client_addr, header) self.assert_("is not a provider" in msg, msg) # check invalid md5sums name = "/service" sm = get_service_manager() fake_service = rospy.service._Service(name, test_rospy.srv.EmptySrv) sm.register(name, fake_service) header["service"] = name header["md5sum"] = "X" msg = service_connection_handler(sock, client_addr, header) self.assert_("md5sums do not match" in msg, msg)