1
2 from twisted.python import failure, reflect
3 from twisted.internet import defer
4
5 from foolscap import copyable, slicer, tokens
6 from foolscap.copyable import AttributeDictConstraint
7 from foolscap.constraint import ByteStringConstraint
8 from foolscap.slicers.list import ListConstraint
9 from tokens import BananaError, Violation
10 from foolscap.util import AsyncAND
11 from foolscap.logging import log
12
13
15 opentypes = [("copyable", "twisted.python.failure.Failure")]
16 name = "FailureConstraint"
17 klass = failure.Failure
18
26
28 if not isinstance(obj, self.klass):
29 raise Violation("is not an instance of %s" % self.klass)
30
31
33
34
35 active = True
36
38 self.reqID = reqID
39 self.rref = rref
40 self.broker = None
41 self.deferred = defer.Deferred()
42 self.constraint = None
43 self.failure = None
44
47
56
57 - def fail(self, why):
58 if self.active:
59 if self.broker:
60 self.broker.removeRequest(self)
61 self.active = False
62 self.failure = why
63 if (self.broker and
64 self.broker.tub and
65 self.broker.tub.logRemoteFailures):
66
67 my_short_tubid = "??"
68 if self.broker.tub:
69 my_short_tubid = self.broker.tub.getShortTubID()
70 their_short_tubid = self.broker.remote_tubref.getShortTubID()
71
72 lp = log.msg("an outbound callRemote (that we [%s] sent to "
73 "someone else [%s]) failed on the far end"
74 % (my_short_tubid, their_short_tubid),
75 level=log.UNUSUAL)
76 methname = ".".join([self.interfaceName or "?",
77 self.methodName or "?"])
78 log.msg(" reqID=%d, rref=%s, methname=%s"
79 % (self.reqID, self.rref, methname),
80 level=log.NOISY, parent=lp)
81
82
83
84
85 log.msg(" the REMOTE failure was:", failure=why,
86 level=log.NOISY, parent=lp)
87
88 self.deferred.errback(why)
89 else:
90 log.msg("WEIRD: fail() on an inactive request", traceback=True)
91 if self.failure:
92 log.msg("multiple failures")
93 log.msg("first one was:", self.failure)
94 log.msg("this one was:", why)
95 log.err("multiple failures indicate a problem")
96
98 opentype = ('arguments',)
99
105
106 - def sliceBody(self, streamable, banana):
107 yield len(self.args)
108 for i,arg in enumerate(self.args):
109 self.which = "arg[%d]" % i
110 yield arg
111 keys = self.kwargs.keys()
112 keys.sort()
113 for argname in keys:
114 self.which = "arg[%s]" % argname
115 yield argname
116 yield self.kwargs[argname]
117
119 return "<%s>" % self.which
120
121
123 opentype = ('call',)
124
125 - def __init__(self, reqID, clid, methodname, args, kwargs):
132
133 - def sliceBody(self, streamable, banana):
134 yield self.reqID
135 yield self.clid
136 yield self.methodname
137 yield ArgumentSlicer(self.args, self.kwargs)
138
140 return "<call-%s-%s-%s>" % (self.reqID, self.clid, self.methodname)
141
143 """An inbound message that has not yet been delivered.
144
145 This is created when a 'call' sequence has finished being received. The
146 Broker will add it to a queue. The delivery at the head of the queue is
147 serviced when all of its arguments have been resolved.
148
149 The only way that the arguments might not all be available is if one of
150 the Unslicers which created them has provided a 'ready_deferred' along
151 with the prospective object. The only standard Unslicer which does this
152 is the TheirReferenceUnslicer, which handles introductions. (custom
153 Unslicers might also provide a ready_deferred, for example a URL
154 slicer/unslicer pair for which the receiving end fetches the target of
155 the URL as its value, or a UnixFD slicer/unslicer that had to wait for a
156 side-channel unix-domain socket to finish transferring control over the
157 FD to the recipient before being ready).
158
159 Most Unslicers refuse to accept unready objects as their children (most
160 implementations of receiveChild() do 'assert ready_deferred is None').
161 The CallUnslicer is fairly unique in not rejecting such objects.
162
163 We do require, however, that all of the arguments be at least
164 referenceable. This is not generally a problem: the only time an
165 unslicer's receiveChild() can get a non-referenceable object (represented
166 by a Deferred) is if that unslicer is participating in a reference cycle
167 that has not yet completed, and CallUnslicers only live at the top level,
168 above any cycles.
169 """
170
171 - def __init__(self, broker, reqID, obj,
172 interface, methodname, methodSchema,
173 allargs):
181
183
184 my_short_tubid = "??"
185 if self.broker.tub:
186 my_short_tubid = self.broker.tub.getShortTubID()
187 their_short_tubid = "<unauth>"
188 if self.broker.remote_tubref:
189 their_short_tubid = self.broker.remote_tubref.getShortTubID()
190 lp = log.msg("an inbound callRemote that we [%s] executed (on behalf "
191 "of someone else, TubID %s) failed"
192 % (my_short_tubid, their_short_tubid),
193 level=log.UNUSUAL)
194 if self.interface:
195 methname = self.interface.getName() + "." + self.methodname
196 else:
197 methname = self.methodname
198 log.msg(" reqID=%d, rref=%s, methname=%s" %
199 (self.reqID, self.obj, methname),
200 level=log.NOISY, parent=lp)
201 log.msg(" args=%s" % (self.allargs.args,), level=log.NOISY, parent=lp)
202 log.msg(" kwargs=%s" % (self.allargs.kwargs,),
203 level=log.NOISY, parent=lp)
204
205
206
207
208
209
210 log.msg(" the LOCAL failure was:", failure=f,
211 level=log.NOISY, parent=lp)
212
213