00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 import copy
00012 import cPickle as pickle
00013
00014 import os
00015
00016 from Crypto.PublicKey import RSA
00017 import Crypto.Util.number as CUN
00018
00019 from gateway_msgs.msg import Rule, ConnectionType
00020
00021
00022
00023
00024
00025
00026 connection_types = frozenset([ConnectionType.PUBLISHER, ConnectionType.SUBSCRIBER,
00027 ConnectionType.SERVICE, ConnectionType.ACTION_CLIENT, ConnectionType.ACTION_SERVER])
00028 connection_types_list = [ConnectionType.PUBLISHER, ConnectionType.SUBSCRIBER,
00029 ConnectionType.SERVICE, ConnectionType.ACTION_CLIENT, ConnectionType.ACTION_SERVER]
00030 connection_type_strings_list = ["publisher", "subscriber", "service", "action_client", "action_server"]
00031 action_types = ['/goal', '/cancel', '/status', '/feedback', '/result']
00032
00033
00034
00035
00036
00037
00038 class Connection():
00039
00040 '''
00041 An object that represents a connection containing all the gory details
00042 about a connection, allowing a connection to be passed through to a
00043 foreign gateway
00044
00045 - rule (gateway_msgs.msg.Rule) (containing type,name,node)
00046 - type_info (msg type for pubsub or service api for services)
00047 - xmlrpc_uri (the xmlrpc node uri for the connection)
00048 '''
00049
00050 def __init__(self, rule, type_info, xmlrpc_uri):
00051 '''
00052 @param type_info : either topic_type (pubsub), service api (service) or ??? (action)
00053 @type string
00054 '''
00055 self.rule = rule
00056 self.type_info = type_info
00057 self.xmlrpc_uri = xmlrpc_uri
00058
00059 def __eq__(self, other):
00060 if isinstance(other, self.__class__):
00061 return self.__dict__ == other.__dict__
00062 else:
00063 return False
00064
00065 def __ne__(self, other):
00066 return not self.__eq__(other)
00067
00068 def __str__(self):
00069 if self.rule.type == ConnectionType.SERVICE:
00070 return '{type: %s, name: %s, node: %s, uri: %s, service_api: %s}' % (
00071 self.rule.type, self.rule.name, self.rule.node, self.xmlrpc_uri, self.type_info)
00072 else:
00073 return '{type: %s, name: %s, node: %s, uri: %s, topic_type: %s}' % (
00074 self.rule.type, self.rule.name, self.rule.node, self.xmlrpc_uri, self.type_info)
00075
00076 def __repr__(self):
00077 return self.__str__()
00078
00079 def inConnectionList(self, connection_list):
00080 '''
00081 Checks to see if this connection has the same rule
00082 as an item in the given connection_list
00083
00084 @param connection_list : connection list to trawl.
00085 @type utils.Connection[]
00086 @return true if this connection rule matches a connection rule in the list
00087 @rtype Bool
00088 '''
00089 for connection in connection_list:
00090 if self.hasSameRule(connection):
00091 return True
00092 return False
00093
00094 def hasSameRule(self, connection):
00095 '''
00096 Checks for equivalency regardless of type_info and xmlrpc_uri.
00097
00098 @param connection : connection to compare with
00099 @type utils.Connection
00100 @return true if equivalent, false otherwise
00101 @rtype Bool
00102 '''
00103 return (self.rule.name == connection.rule.name and
00104 self.rule.type == connection.rule.type and
00105 self.rule.node == connection.rule.node)
00106
00107
00108
00109
00110
00111
00112 class Registration():
00113
00114 '''
00115 An object that represents a connection registered with the local
00116 master (or about to be registered). This has all the gory detail
00117 for the connection. It includes the gateway name it originated
00118 from as well as master registration information.
00119
00120 - connection (the remote connection information)
00121 - remote_gateway (the remote gateway from where this connection originated)
00122 - local_node (the local anonymously generated node name)
00123 '''
00124
00125 def __init__(self, connection, remote_gateway, local_node=None):
00126 '''
00127 @param connection : string identifier storing the remote connection details (type, name, node)
00128 @type gateway_msgs.msg.RemoteRule
00129
00130 @param remote_gateway : string identifier for where this registration game from
00131 @type string
00132
00133 @param local_node : the local node that this registration is created under
00134 @type string
00135 '''
00136 self.connection = connection
00137 self.remote_gateway = remote_gateway
00138 self.local_node = local_node
00139
00140 def __eq__(self, other):
00141 if isinstance(other, self.__class__):
00142 return self.__dict__ == other.__dict__
00143 else:
00144 return False
00145
00146 def __ne__(self, other):
00147 return not self.__eq__(other)
00148
00149 def __str__(self):
00150 return '[%s]%s' % (self.remote_gateway, format_rule(self.connection.rule))
00151
00152 def __repr__(self):
00153 return self.__str__()
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175 def serialize(data):
00176
00177 return pickle.dumps(data)
00178
00179
00180 def deserialize(str_msg):
00181
00182 try:
00183 deserialized_data = pickle.loads(str_msg)
00184 except ValueError as e:
00185 rospy.logwarn("Gateway : Error while deserialization[%s]"%e)
00186 import traceback
00187 print(traceback.format_exc())
00188 print("Data : %s"%str_msg)
00189 return deserialized_data
00190
00191
00192 def serialize_connection(connection):
00193 return serialize([connection.rule.type,
00194 connection.rule.name,
00195 connection.rule.node,
00196 connection.type_info,
00197 connection.xmlrpc_uri]
00198 )
00199
00200
00201 def deserialize_connection(connection_str):
00202 deserialized_list = deserialize(connection_str)
00203 rule = Rule(deserialized_list[0],
00204 deserialized_list[1],
00205 deserialized_list[2]
00206 )
00207 return Connection(rule, deserialized_list[3], deserialized_list[4])
00208
00209
00210 def serialize_connection_request(command, source, connection):
00211 return serialize([command, source,
00212 connection.rule.type,
00213 connection.rule.name,
00214 connection.rule.node,
00215 connection.type_info,
00216 connection.xmlrpc_uri]
00217 )
00218
00219
00220 def serialize_rule_request(command, source, rule):
00221 return serialize([command, source, rule.type, rule.name, rule.node])
00222
00223
00224 def deserialize_request(request_str):
00225 deserialized_list = deserialize(request_str)
00226 return deserialized_list[0], deserialized_list[1], deserialized_list[2:]
00227
00228
00229 def get_connection_from_list(connection_argument_list):
00230 rule = Rule(connection_argument_list[0], connection_argument_list[1], connection_argument_list[2])
00231 return Connection(rule, connection_argument_list[3], connection_argument_list[4])
00232
00233
00234 def get_rule_from_list(rule_argument_list):
00235 return Rule(rule_argument_list[0], rule_argument_list[1], rule_argument_list[2])
00236
00237
00238
00239
00240
00241 MAX_PLAINTEXT_LENGTH = 256
00242
00243
00244 def generate_private_public_key():
00245 key = RSA.generate(8 * MAX_PLAINTEXT_LENGTH)
00246 public_key = key.publickey()
00247 return key, public_key
00248
00249
00250 def deserialize_key(serialized_key):
00251 return RSA.importKey(serialized_key)
00252
00253
00254 def serialize_key(key):
00255 return key.exportKey()
00256
00257
00258 def encrypt(plaintext, public_key):
00259 if len(plaintext) > MAX_PLAINTEXT_LENGTH:
00260
00261 raise ValueError('Trying to encrypt text longer than ' + MAX_PLAINTEXT_LENGTH + ' bytes!')
00262 K = CUN.getRandomNumber(128, os.urandom)
00263 ciphertext = public_key.encrypt(plaintext, K)
00264 return ciphertext[0]
00265
00266
00267
00268 def decrypt(ciphertext, key):
00269 return key.decrypt(ciphertext)
00270
00271
00272
00273 def decrypt_connection(connection, key):
00274 decrypted_connection = copy.deepcopy(connection)
00275 decrypted_connection.type_info = decrypt(connection.type_info, key)
00276 decrypted_connection.xmlrpc_uri = decrypt(connection.xmlrpc_uri, key)
00277 return decrypted_connection
00278
00279
00280 def encrypt_connection(connection, key):
00281 encrypted_connection = copy.deepcopy(connection)
00282 encrypted_connection.type_info = encrypt(connection.type_info, key)
00283 encrypted_connection.xmlrpc_uri = encrypt(connection.xmlrpc_uri, key)
00284 return encrypted_connection
00285
00286
00287
00288
00289
00290
00291 def is_all_pattern(pattern):
00292 '''
00293 Convenience function for detecting the 'all' pattern.
00294
00295 @param pattern : the name rule string for the flip all concept
00296 @type str
00297 @return true if matching, false otherwise
00298 @rtype Bool
00299 '''
00300 if pattern == ".*":
00301 return True
00302 else:
00303 return False
00304
00305
00306
00307
00308
00309
00310 def format_rule(rule):
00311 return '[%s][%s][%s]' % (rule.type, rule.name, rule.node)
00312
00313
00314
00315
00316
00317
00318 def create_empty_connection_type_dictionary():
00319 '''
00320 Used to initialise a dictionary with rule type keys
00321 and empty lists.
00322 '''
00323 dic = {}
00324 for connection_type in connection_types:
00325 dic[connection_type] = []
00326 return dic
00327
00328 difflist = lambda l1, l2: [x for x in l1 if x not in l2]