ObjectCallGPCS.py (30019B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\script\net\ObjectCallGPCS.py 2 import copy 3 import sys 4 import types 5 import weakref 6 import blue 7 import carbon.common.script.net.machobase as macho 8 import localstorage 9 import log 10 import monolithconfig 11 import stackless 12 import uthread 13 from carbon.common.lib import const 14 from carbon.common.script.net.machoNetExceptions import UnMachoDestination 15 from carbon.common.script.net.moniker import Moniker 16 from carbon.common.script.sys.sessions import GetSessions 17 from carbon.common.script.util.timerstuff import ClockThisWithoutTheStars 18 from carbon.common.script.net import objectCaching 19 from carbon.common.script.sys import basesession, service 20 from carbon.common.script.net.machoNetPacket import CallReq 21 from carbon.common.script.net.machoNetPacket import Notification 22 from carbon.common.script.net.machoNetAddress import MachoAddress 23 from carbon.common.script.net.cachedObject import CachedObject as utilCachedObject 24 from cluster import MACHONETMSG_TYPE_AUTHENTICATION_REQ 25 from eveprefs import prefs, boot 26 from machonet_tracing import EgressTracer, IngressTracer 27 from stringutil import strx 28 29 class ObjectCall(): 30 __guid__ = 'gpcs.ObjectCall' 31 32 def __init__(self): 33 if macho.mode == 'client': 34 self.identifier = 'C=0' 35 else: 36 self.identifier = 'N=%d' % sm.services['machoNet'].nodeID 37 self.releasedObjects = {} 38 self.logClientCall = prefs.GetValue('logClientCall', 0) or prefs.GetValue('clusterMode', '') == 'LOCAL' 39 uthread.new(self.__ReleaseObjectHelper).context = 'machoNet::ObjectCall.ReleaseObjectHelper' 40 41 def __ReleaseObjectHelper(self): 42 while not self.machoNet.stop: 43 blue.pyos.synchro.SleepWallclock(30000) 44 if self.releasedObjects: 45 tmp = self.releasedObjects 46 self.releasedObjects = {} 47 chrto = {} 48 for objectID, v in tmp.iteritems(): 49 for refID, sess, destination in v: 50 if hasattr(destination, 'nodeID'): 51 try: 52 if objectID not in sess.machoObjectConnectionsByObjectID: 53 daKey = (sess.sid, destination.nodeID) 54 if daKey in chrto: 55 chrto[daKey][2].append((objectID, refID)) 56 else: 57 chrto[daKey] = [sess, destination, [(objectID, refID)]] 58 except ReferenceError: 59 sys.exc_clear() 60 61 for v in chrto.itervalues(): 62 oidsminus = {} 63 for each in v[2]: 64 if each[0] in oidsminus: 65 oidsminus[each[0]] = max(each[1], oidsminus[each[0]]) 66 else: 67 oidsminus[each[0]] = each[1] 68 69 oob = {'OID-': oidsminus} 70 self.ObjectCall(oob, 'ClientHasReleasedTheseObjects', -1, v[0], v[1], v[2], 'ClientHasReleasedTheseObjects') 71 72 def CallUp(self, packet): 73 if packet.command == MACHONETMSG_TYPE_AUTHENTICATION_REQ: 74 retval = self.ForwardCallUp(packet) 75 self.__StringifyPayloadForLogging(retval, retval.payload) 76 retval.payload = self.ToPickle(retval.payload) 77 if self.added_objects: 78 retval.oob['OID+'] = self.added_objects 79 retval.compressedPart = self.compressedPart 80 return retval 81 elif packet.payload[0]: 82 tup = self.FromPickle(packet.payload[1], packet.source) 83 objectID, method, args = tup[0], tup[1], tup[2] 84 if objectID[0] == 'C' and macho.mode == 'client': 85 cid, oid = objectID.split(':') 86 objectID = '%s:%s' % (self.identifier, oid) 87 if objectID not in session.machoObjectsByID: 88 session.DumpSession('OBJECTNOTMEMBER', 'The specified object (%s) is not a member of this session' % objectID) 89 raise UnMachoDestination('The specified object (%s) is not a member of this session' % objectID) 90 object = session.machoObjectsByID[objectID][1] 91 if isinstance(object, basesession.ObjectConnection): 92 objclass = object.GetObjectConnectionLogClass() 93 else: 94 objclass = macho.AssignLogName(object) 95 IngressTracer.start_trace(packet, objclass, method) 96 callTimer = basesession.CallTimer('%s::%s (ObjectCall\\Server)' % (objclass, method)) 97 if self.logClientCall and packet.source.addressType == const.ADDRESS_TYPE_CLIENT: 98 kwargs = tup[3] if len(tup) >= 4 else None 99 self.machoNet.LogClientCall(session, objclass, method, args, kwargs) 100 try: 101 func = getattr(object, method) 102 if method in object.__dict__.get('__restrictedcalls__', {}) or method.startswith('_'): 103 raise RuntimeError('This call can only be the result of a hack attack', method) 104 if not isinstance(object, basesession.ObjectConnection): 105 if 0 == session.role & service.ROLE_SERVICE and hasattr(object, '__exportedcalls__') and method not in object.__exportedcalls__: 106 raise RuntimeError('%s call is not exported from this pass-by-reference object.' % method) 107 if not session.role & service.ROLE_SERVICE: 108 paramList = object.__exportedcalls__.get(method, None) 109 paramDict = None 110 if paramList is not None: 111 if type(paramList) is list: 112 if len(paramList): 113 tmp = {} 114 tmp['role'] = paramList[0] 115 tmp['preargs'] = paramList[1:] 116 paramDict = tmp 117 elif type(paramList) is dict: 118 paramDict = paramList 119 if paramDict is not None: 120 role = paramDict.get('role', service.ROLE_SERVICE) 121 if not role & session.role: 122 session.LogSessionError("Called %s::%s, which requires role 0x%x, which the user doesn't have. User has role 0x%x" % (object.__class__.__name__, 123 method, 124 role, 125 session.role)) 126 raise RuntimeError('RoleNotAssigned', "%s::%s requires role 0x%x, which the user doesn't have. User has role 0x%x. Calling session: %s" % (object.__class__.__name__, 127 method, 128 role, 129 session.role, 130 str(session))) 131 preargs = paramDict.get('preargs', []) 132 args2 = len(preargs) * [None] + list(args) 133 for i in range(len(preargs)): 134 args2[i] = getattr(session, preargs[i]) 135 136 args = tuple(args2) 137 if len(tup) == 4 and 'machoVersion' in tup[3]: 138 if len(tup[3]) == 1: 139 tup = (tup[0], tup[1], tup[2]) 140 else: 141 del tup[3]['machoVersion'] 142 with IngressTracer.record_process_call_ms(): 143 if len(tup) == 3: 144 retval = ClockThisWithoutTheStars('Remote Object Call::%s::%s' % (objclass, method), func, args) 145 else: 146 retval = ClockThisWithoutTheStars('Remote Object Call::%s::%s' % (objclass, method), func, args, tup[3]) 147 retpickle = self.ToPickle(retval) 148 retval = packet.Response(payload=retpickle) 149 if self.added_objects: 150 retval.oob['OID+'] = self.added_objects 151 self.__StringifyPayloadForLogging(retval, retpickle) 152 retval.compressedPart = self.compressedPart 153 finally: 154 callTimer.Done() 155 156 return retval 157 else: 158 packet.payload = self.FromPickle(packet.payload[1], packet.source) 159 retval = self.ForwardCallUp(packet) 160 self.__StringifyPayloadForLogging(retval, retval.payload) 161 retval.payload = self.ToPickle(retval.payload) 162 if self.added_objects: 163 retval.oob['OID+'] = self.added_objects 164 retval.compressedPart = self.compressedPart 165 return retval 166 167 def CallDown(self, packet): 168 if packet.command == MACHONETMSG_TYPE_AUTHENTICATION_REQ: 169 retval = self.ForwardCallDown(packet) 170 retval.payload = self.FromPickle(retval.payload, packet.destination) 171 return retval 172 else: 173 trace = False 174 if packet.oob.get('traceMe', False) is True: 175 log.general.Log('ObjectCall::CallDown: ForwardCallDown ist: %s' % str(self.ForwardCallDown), log.LGNOTICE) 176 self.__StringifyPayloadForLogging(packet, packet.payload) 177 packet.payload = (0, self.ToPickle(packet.payload, 0)) 178 if self.added_objects: 179 packet.oob['OID+'] = self.added_objects 180 packet.compressedPart = self.compressedPart 181 retval = self.ForwardCallDown(packet) 182 retval.payload = self.FromPickle(retval.payload, packet.destination) 183 return retval 184 185 def NotifyUp(self, packet): 186 if packet.payload[0] == 1: 187 tup = self.FromPickle(packet.payload[1], packet.source) 188 objectID, method, args = tup[0], tup[1], tup[2] 189 if method == 'ClientHasReleasedTheseObjects': 190 oidsandrefs = objectID 191 for each in oidsandrefs: 192 objectID, refID = each 193 if objectID in session.machoObjectsByID: 194 object = session.machoObjectsByID[objectID][1] 195 objectType, guts = self.__GetObjectTypeAndGuts(object) 196 session.UnregisterMachoObject(objectID, refID) 197 198 return 199 else: 200 if objectID[0] == 'C' and macho.mode == 'client': 201 cid, oid = objectID.split(':') 202 objectID = '%s:%s' % (self.identifier, oid) 203 if objectID not in session.machoObjectsByID: 204 raise UnMachoDestination('The specified object (%s) is not a member of this session' % objectID) 205 object = session.machoObjectsByID[objectID][1] 206 if isinstance(object, basesession.ObjectConnection): 207 objclass = object.GetObjectConnectionLogClass() 208 else: 209 objclass = macho.AssignLogName(object) 210 callTimer = basesession.CallTimer('%s::%s (ObjectNotify\\Server)' % (objclass, method)) 211 try: 212 func = getattr(object, method) 213 if method in object.__dict__.get('__restrictedcalls__', {}) or method.startswith('_'): 214 raise RuntimeError('This call can only be the result of a hack attack', method) 215 if not isinstance(object, basesession.ObjectConnection) and len(tup) == 4 and 'machoVersion' in tup[3]: 216 if len(tup[3]) == 1: 217 tup = (tup[0], tup[1], tup[2]) 218 else: 219 del tup[3]['machoVersion'] 220 if len(tup) == 3: 221 ClockThisWithoutTheStars('Remote Object Notify::%s::%s' % (objclass, method), func, args) 222 else: 223 ClockThisWithoutTheStars('Remote Object Notify::%s::%s' % (objclass, method), func, args, tup[3]) 224 finally: 225 callTimer.Done() 226 227 return 228 else: 229 packet.payload = self.FromPickle(packet.payload[1], packet.source) 230 self.ForwardNotifyUp(packet) 231 232 def NotifyDown(self, packet): 233 self.__StringifyPayloadForLogging(packet, packet.payload) 234 packet.payload = (0, self.ToPickle(packet.payload)) 235 if self.added_objects: 236 packet.oob['OID+'] = self.added_objects 237 packet.compressedPart = self.compressedPart 238 self.ForwardNotifyDown(packet) 239 240 def __GetObjectTypeAndGuts(self, object): 241 ob = object 242 if isinstance(object, basesession.ObjectConnection): 243 ob = object.__dict__['__object__'] 244 objclass = object.GetObjectConnectionLogClass() 245 else: 246 objclass = macho.AssignLogName(object) 247 return (objclass, ob) 248 249 def GetObjectID(self, object): 250 if type(object) == types.InstanceType: 251 if isinstance(object, stackless.tasklet): 252 raise RuntimeError('Thou shall not send stackless.tasklet across the wire') 253 if not getattr(object, '__passbyvalue__', 0): 254 objectID = basesession.GetObjectUUID(object) 255 if objectID in session.machoObjectsByID: 256 session.machoObjectsByID[objectID][0] = blue.os.GetWallclockTime() 257 else: 258 objectType, guts = self.__GetObjectTypeAndGuts(object) 259 session.LogSessionHistory('%s object %s added to session' % (objectType, objectID), strx(guts)) 260 if objectType is None: 261 raise RuntimeError('NoneType object added by reference, undoubtedly ObjectConnection to None') 262 if objectID not in self.added_objects: 263 refID = blue.os.GetWallclockTime() 264 self.added_objects[objectID] = refID 265 session.RegisterMachoObject(objectID, object, refID) 266 else: 267 refID = self.added_objects[objectID] 268 pa = {} 269 for each in getattr(object, '__publicattributes__', []): 270 if hasattr(object, each): 271 pa[each] = getattr(object, each) 272 273 if pa: 274 return blue.marshal.Save((objectID, pa, refID), self.GetObjectID) 275 else: 276 return blue.marshal.Save((objectID, refID), self.GetObjectID) 277 elif isinstance(object, utilCachedObject): 278 sm.services['objectCaching'].CacheObject(object) 279 elif isinstance(object, objectCaching.CachedObject): 280 self.compressedPart += object.CompressedPart() 281 elif isinstance(object, Moniker): 282 object.QuickResolve() 283 284 def ParseObjectID(self, objectID): 285 if session is None: 286 self.machoNet.LogError('Session is none during ParseObjectID!!!') 287 log.LogTraceback() 288 t = blue.marshal.Load(objectID, self.ParseObjectID) 289 if len(t) == 2: 290 objectID, refID = t 291 pa = {} 292 else: 293 objectID, pa, refID = t 294 if objectID not in session.machoObjectsByID: 295 nid, oid = objectID.split(':') 296 if nid != self.identifier: 297 if nid[0] == 'C': 298 if self.otherDudesAddress.addressType == const.ADDRESS_TYPE_CLIENT: 299 objectID = 'C=%d:%s' % (self.otherDudesAddress.clientID, oid) 300 return MachoObjectConnection(session.GetActualSession(), self, objectID, pa, refID) 301 raise RuntimeError('The specified object (%s) does not exist within this session (%s)' % (strx(objectID), strx(session))) 302 return weakref.proxy(session.machoObjectsByID[objectID][1]) 303 304 def OnObjectPublicAttributesUpdated(self, uuid, pa, args, keywords): 305 for sess in GetSessions(): 306 try: 307 if sess.machoObjectConnectionsByObjectID.get(uuid, 0): 308 for conn in sess.machoObjectConnectionsByObjectID[uuid][1].itervalues(): 309 k = keywords.get('partial', []) 310 if k: 311 old = {} 312 for each in k: 313 old[each] = conn.__publicattributes__[each] 314 conn.__publicattributes__[each] = pa[each] 315 316 else: 317 old = conn.__publicattributes__ 318 conn.__publicattributes__ = pa 319 for each in conn.objectChangeHandlers.iterkeys(): 320 try: 321 func = getattr(each, 'OnObjectChanged') 322 except Exception: 323 log.LogException() 324 sys.exc_clear() 325 continue 326 327 theArgs = [conn, old, conn.__publicattributes__] + list(args) 328 uthread.worker('machoNet::OnObjectChanged', func, *theArgs, **keywords) 329 330 except Exception: 331 log.LogException('Exception during OnObjectPublicAttributesUpdated') 332 sys.exc_clear() 333 334 def ToPickle(self, value, nonblocking = 1): 335 try: 336 self.compressedPart = 0 337 self.added_objects = {} 338 ret = blue.marshal.Save(value, self.GetObjectID) 339 if nonblocking and len(ret) > self.machoNet.largeResponseWarningThreshold: 340 ctk = localstorage.GetLocalStorage().get('calltimer.key', None) 341 if len(ret) > self.machoNet.largeResponseErrorThreshold: 342 if ctk is not None: 343 self.machoNet.LogError('Unacceptably large response from ', ctk, ', ', len(ret), ' bytes') 344 else: 345 try: 346 self.machoNet.LogError('Unacceptably large response from unknown source, ', len(ret), ' bytes - ', repr(value)[:1024]) 347 except Exception: 348 self.machoNet.LogError('Unacceptably large response from unknown source 2, ', len(ret), ' bytes - ', ret[:256]) 349 350 log.LogTraceback() 351 elif ctk is not None: 352 self.machoNet.LogWarn('Unacceptably large response from ', ctk, ', ', len(ret), ' bytes') 353 else: 354 try: 355 self.machoNet.LogWarn('Unacceptably large response from unknown source, ', len(ret), ' bytes - ', repr(value)[:1024]) 356 except Exception: 357 self.machoNet.LogWarn('Unacceptably large response from unknown source 2, ', len(ret), ' bytes - ', ret[:256]) 358 359 return ret 360 except Exception: 361 self.machoNet.LogError("That was NOT a nice thing to do! Keep yo' unpicklables to yourself.") 362 log.LogTraceback() 363 raise 364 365 def __StringifyPayloadForLogging(self, packet, payload): 366 if self.machoNet.logChannel.IsOpen(1): 367 packet.strayload = strx(payload) 368 369 def FromPickle(self, thePickle, otherDudesAddress): 370 try: 371 self.otherDudesAddress = otherDudesAddress 372 payload = blue.marshal.Load(thePickle, self.ParseObjectID) 373 except Exception: 374 self.machoNet.LogError('Failed unpickling buffer of length %d' % len(thePickle)) 375 self.machoNet.LogError('First 100 bytes: %s' % strx(thePickle[:100])) 376 log.LogTraceback() 377 raise 378 379 return payload 380 381 def ObjectCall(self, oob, persistantObjectID, blocking, sess, destination, objectID, method, *args, **keywords): 382 return self.ObjectCallWithoutTheStars(oob, persistantObjectID, blocking, sess, destination, objectID, method, args, keywords) 383 384 def ObjectCallWithoutTheStars(self, oob, persistantObjectID, blocking, sess, destination, objectID, method, args, keywords): 385 cachable, versionCheck, throwOK, cachedResultRecord, cacheKey, cacheDetails = sm.GetService('objectCaching').PerformCachedMethodCall(None, persistantObjectID, method, args) 386 if cachable: 387 if not versionCheck: 388 if throwOK: 389 sm.GetService('objectCaching').LogInfo('Local cache hit with throw for remote object ', persistantObjectID, '::', method, '(', args, ')') 390 raise objectCaching.CacheOK() 391 elif cachedResultRecord: 392 sm.GetService('objectCaching').LogInfo('Local cache hit for remote object ', persistantObjectID, '::', method, '(', args, ')') 393 return cachedResultRecord['lret'] 394 if keywords: 395 kw2 = copy.copy(keywords) 396 else: 397 kw2 = {} 398 if kw2.get('machoVersion', None) is None: 399 if cachedResultRecord is not None and cachedResultRecord['version'] is not None: 400 kw2['machoVersion'] = cachedResultRecord['version'] 401 else: 402 kw2['machoVersion'] = 1 403 if currentcall: 404 machoTimeout = kw2.get('machoTimeout', currentcall.packet.oob.get('machoTimeout', None)) 405 else: 406 machoTimeout = kw2.get('machoTimeout', None) 407 if 'machoTimeout' in kw2: 408 del kw2['machoTimeout'] 409 payload = (1, self.ToPickle((objectID, 410 method, 411 args, 412 kw2))) 413 if blocking == 1: 414 packet = CallReq(destination=destination, payload=payload) 415 service_name = self.get_brokering_service_name(persistantObjectID) 416 with EgressTracer(packet, service_name, method) as trace: 417 bind_params = self.get_object_bind_params(persistantObjectID) 418 trace.set_bind_parameters(bind_params) 419 if oob: 420 packet.oob = oob 421 if machoTimeout is not None: 422 packet.oob['machoTimeout'] = machoTimeout 423 if self.added_objects: 424 if 'OID+' in packet.oob: 425 packet.oob['OID+'].update(self.added_objects) 426 else: 427 packet.oob['OID+'] = self.added_objects 428 try: 429 callTimer = basesession.CallTimer('Remote Object Call::%s (ObjectCall\\Client)' % (method,)) 430 try: 431 response = self.ForwardCallDown(packet) 432 finally: 433 callTimer.Done() 434 435 retval = self.FromPickle(response.payload, packet.destination) 436 except objectCaching.CacheOK: 437 if cachedResultRecord is None: 438 raise 439 sys.exc_clear() 440 sm.GetService('objectCaching').LogInfo('Version matches for remote object ', persistantObjectID, '::', method, '(', args, ')') 441 sm.GetService('objectCaching').UpdateVersionCheckPeriod(cacheKey) 442 return cachedResultRecord['lret'] 443 444 if isinstance(retval, objectCaching.CachedMethodCallResult): 445 sm.GetService('objectCaching').CacheMethodCall(persistantObjectID, method, args, retval) 446 retval = retval.GetResult() 447 return retval 448 else: 449 packet = Notification(destination=destination, payload=payload) 450 if oob: 451 packet.oob = oob 452 if machoTimeout is not None: 453 packet.oob['machoTimeout'] = machoTimeout 454 if self.added_objects: 455 if 'OID+' in packet.oob: 456 packet.oob['OID+'].update(self.added_objects) 457 else: 458 packet.oob['OID+'] = self.added_objects 459 self.ForwardNotifyDown(packet) 460 return MachoBoobyTrap() 461 462 def get_brokering_service_name(self, persistantObjectID): 463 if isinstance(persistantObjectID, tuple) and len(persistantObjectID) > 1: 464 return persistantObjectID[0] 465 return 'unknown object call type' 466 467 def get_object_bind_params(self, persistantObjectID): 468 if isinstance(persistantObjectID, tuple) and len(persistantObjectID) > 1: 469 return persistantObjectID[1] 470 471 472 class MachoBoobyTrap(): 473 __guid__ = 'gpcs.MachoBoobyTrap' 474 475 def __str__(self): 476 return 'MachoBoobyTrap' 477 478 def __getattr__(self, attribute): 479 try: 480 log.LogTraceback() 481 except Exception: 482 sys.exc_clear() 483 484 raise RuntimeError("Attempted to access %s from a non-blocking call's result" % attribute) 485 486 487 class MachoObjectConnection(): 488 489 def __init__(self, sess, gpcs, objectID, pa, refID): 490 try: 491 self.__dict__['session'] = weakref.proxy(sess) 492 except TypeError: 493 self.__dict__['session'] = sess 494 sys.exc_clear() 495 496 self.__dict__['objectID'] = objectID 497 self.__dict__['sessionCheck'] = None 498 self.__dict__['persistantObjectID'] = objectID 499 self.__dict__['gpcs'] = weakref.proxy(gpcs) 500 self.__dict__['__publicattributes__'] = pa 501 self.__dict__['objectChangeHandlers'] = weakref.WeakKeyDictionary({}) 502 mask = sess.Masquerade() 503 try: 504 self.__dict__['clisid'] = gpcs.machoNet.GetClientSessionID() 505 finally: 506 mask.UnMask() 507 508 if objectID[0] == 'C': 509 self.__dict__['blocking'] = 0 510 cid, oid = objectID.split(':') 511 cid = cid.split('=')[1] 512 self.__dict__['destination'] = MachoAddress(clientID=long(cid)) 513 else: 514 self.__dict__['blocking'] = 1 515 nid, oid = objectID.split(':') 516 nid = nid.split('=')[1] 517 self.__dict__['destination'] = MachoAddress(nodeID=long(nid)) 518 self.__dict__['deleted'] = 0 519 sess.RegisterMachoObjectConnection(objectID, self, refID) 520 521 def SetSessionCheck(self, sessionCheck): 522 self.sessionCheck = sessionCheck 523 524 def PerformSessionCheck(self): 525 if not self.sessionCheck: 526 return 527 for attribute, expected in self.sessionCheck.iteritems(): 528 current = None 529 if self.session: 530 current = getattr(self.session, attribute, None) 531 if current != expected or not expected: 532 log.LogTraceback() 533 raise RuntimeError('RemoteObjectSessionCheckFailure', {'attribute': attribute, 534 'expected': expected, 535 'current': current, 536 'objectID': self.objectID, 537 'persistantObjectID': self.persistantObjectID}) 538 539 def __del__(self): 540 if not self.deleted: 541 self.deleted = 1 542 releaseRefID = self.session.UnregisterMachoObjectConnection(self.objectID, self) 543 if releaseRefID: 544 try: 545 if self.objectID not in self.gpcs.releasedObjects: 546 self.gpcs.releasedObjects[self.objectID] = [] 547 self.gpcs.releasedObjects[self.objectID].append((releaseRefID, self.session, self.destination)) 548 except ReferenceError: 549 pass 550 551 def __str__(self): 552 return '<RemoteObject:' + strx(self.__dict__['objectID']) + '>' 553 554 def __nonzero__(self): 555 return 1 556 557 def __repr__(self): 558 return '<RemoteObject:' + strx(self.__dict__['objectID']) + '>' 559 560 def RegisterObjectChangeHandler(self, callback): 561 self.objectChangeHandlers[callback] = None 562 563 def UnRegisterObjectChangeHandler(self, callback): 564 try: 565 del self.objectChangeHandlers[callback] 566 except ReferenceError as e: 567 sys.exc_clear() 568 except KeyError as e: 569 sys.exc_clear() 570 571 def __getattr__(self, attribute): 572 if getattr(self, 'deleted', 0): 573 raise AttributeError(attribute, 'This object is being deleted, so the attribute is no longer available') 574 if not attribute[0].isupper(): 575 pa = self.__publicattributes__ 576 if attribute not in pa: 577 raise AttributeError(attribute) 578 return pa[attribute] 579 self.PerformSessionCheck() 580 return MachoObjectCallWrapper(self.__dict__['persistantObjectID'], self.__dict__['clisid'], self.__dict__['blocking'], self.__dict__['session'], self.__dict__['gpcs'], self.__dict__['destination'], self.__dict__['objectID'], attribute) 581 582 583 class MachoObjectCallWrapper(): 584 585 def __init__(self, persistantObjectID, clisid, blocking, sess, gpcs, destination, objectID, method): 586 self.persistantObjectID = persistantObjectID 587 self.clisid = clisid 588 self.blocking = blocking 589 self.session = sess 590 self.gpcs = gpcs 591 self.destination = destination 592 self.objectID = objectID 593 self.method = method 594 595 def __call__(self, *args, **kwargs): 596 mask = self.session.Masquerade() 597 try: 598 if self.gpcs.machoNet.GetClientSessionID() != self.clisid: 599 raise RuntimeError('This object was acquired by a different session') 600 if boot.role == 'client': 601 if kwargs.get('noCallThrottling', None) is None: 602 key = (self.objectID, 603 self.method, 604 str(args), 605 str(kwargs)) 606 return macho.ThrottledCall(key, self.gpcs.ObjectCallWithoutTheStars, {}, self.persistantObjectID, self.blocking, self.session, self.destination, self.objectID, self.method, args, kwargs) 607 del kwargs['noCallThrottling'] 608 return self.gpcs.ObjectCallWithoutTheStars({}, self.persistantObjectID, self.blocking, self.session, self.destination, self.objectID, self.method, args, kwargs) 609 finally: 610 mask.UnMask() 611 self.__dict__.clear()