﻿ticket	summary	component	version	milestone	type	owner	status	created	_changetime	_description	_reporter
207	deprecate notifyOnDisconnect()	usability	0.6.4	0.14.0	enhancement		new	2013-08-23T13:27:30-07:00	2017-11-20T01:15:38-08:00	"In my opinion, people should not try to write code that uses disconnection-notification. Tahoe-LAFS has one bit of code left that tries to use {{{notifyOnDisconnect}}}, and there is an open ticket to remove that last usage from Tahoe-LAFS: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1975

Please see also my complaint in https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1768#comment:3, which says that foolscap's current {{{notifyOnDisconnect}}} sometimes fires 0 times (#140) and sometimes fires more than once when it was supposed to fire once.

Deprecating {{{notifyOnDisconnect}}} would solve #140 and #42, would make for less work for the foolscap maintainers in the long run, and would spur Tahoe-LAFS (which is probably the only user of {{{notifyOnDisconnect}}} currently) to hurry up and move off of it, and would deter other users from starting to rely on it."	Zooko
147	NoneType is not callable error in RemoteReferenceTracker	unknown	0.4.1	eventually	defect		new	2010-01-31T20:07:33-08:00	2011-10-08T16:20:30-07:00	"Brian,

A few months ago, I emailed you about this. I said I would file a ticket, but lost track of it.  Here is the report.

I hope things are going well. I am seeing a very odd error in foolscap occasionally.  Here is what I see:

{{{
Exception exceptions.TypeError: ""'NoneType' object is not callable"" in <bound
method RemoteReferenceTracker._refLost of
<RemoteReferenceTracker(clid=1,url=pb://ahrpv6rtya6exuk75h2quxaubdkdubst@10.0.1.163:55071,127.0.0.1:55071/quegnf6enammggq33rgwiq3sgdt4dhh5)>>
ignored
}}}

This happens sometimes when my foolscap using process *ends*.  I looked at RemoteRemoteReferenceTracker:


{{{
    def _refLost(self, wref):
        # don't do anything right now, we could be in the middle of all sorts
        # of weird code. both __del__ and weakref callbacks can fire at any
        # time. Almost as bad as threads..

        # instead, do stuff later.
        eventually(self._handleRefLost)

    def _handleRefLost(self):
        if self.ref() is None:
            count, self.received_count = self.received_count, 0
            if count == 0:
                return
            self.broker.freeYourReference(self, count)
        # otherwise our RemoteReference is actually still alive, resurrected
        # between the call to _refLost and the eventual call to
        # _handleRefLost. In this case, don't decref anything.
}}}


I suspect the problem is in _handleRefLost, when it does if self.ref() is None.  For some reason
self.ref is None so calling it gives the TypeError.  Should this be protected by a ""if self.ref is None""?

Your response:

Yeah, please file a bug on that one. Your analysis sounds correct, but
I'd need to walk through the code to find where .ref is being
manipulated, and a bug will help me not forget about it. (it'll be
mid-week before I get a chance to look at it).

Thanks,

Brian Granger
"	bgranger
181	foolscap.test.test_negotiate.Crossfire[Reverse].test1 fail on Windows	unknown	0.6.1	eventually	defect		new	2011-05-08T15:47:48-07:00	2011-10-08T13:29:44-07:00	"{{{
[FAIL]
Traceback (most recent call last):
  File ""C:\cygwin\home\David-Sarah\tahoe\trunk\support\Lib\site-packages\foolscap-0.6.1-py2.7.egg\fo
olscap\test\test_negotiate.py"", line 586, in <lambda>
    d.addCallbacks(lambda res: self.fail(""hey! this is supposed to fail""),
twisted.trial.unittest.FailTest: hey! this is supposed to fail

foolscap.test.test_negotiate.Crossfire.test1
foolscap.test.test_negotiate.CrossfireReverse.test1
}}}

but it doesn't fail on Unix, so I think the exception message is misleading."	davidsarah
212	replace foolscap.test.common.ShouldFailMixin.shouldFail with twisted.trial.unittest.TestCase.failUnlessFailure ?	unknown	0.6.4	eventually	defect		new	2013-09-29T12:34:06-07:00	2017-01-12T22:06:07-08:00	The foolscap shouldFail thing can require substrings, so maybe we need to use `twisted.trial.unittest.TestCase.failUnlessSubstring` too.	Zooko
269	HTTP-to-foolscap doesn't yield useful error	negotiation	0.12.3	eventually	defect		new	2016-09-15T10:28:59-07:00	2016-09-15T10:28:59-07:00	"I made the Foolscap negotiation protocol look like HTTP for two reasons: to allow ordinary HTTP servers to act as redirectors, and to give a useful error message if you accidentally point a web browser at a Foolscap port.

It appears that the latter isn't happening, at least not any more. If I do a `curl` to a URL made up from HOST and PORT, I get zero bytes of output followed by a connection closed.

In `negotiate.py`, we get to `handlePLAINTEXTServer`, and hit the `if not url.startswith(""/id/""):` check, which then raises `BananaError`. However it looks like !BananaError at that point doesn't cause any text to be written back to the client.

So the task for this ticket is to make sure that *some* form of error message gets written, preferably one that says ""hey this is foolscap not http"".
"	Brian Warner
273	SHA1 is broken	negotiation	0.12.5	eventually	defect		new	2017-02-24T17:46:50-08:00	2017-02-24T17:46:50-08:00	"https://shattered.it announced the first (public) SHA1 collision yesterday. We've known this was coming for years, but their work provided a vivid demonstration.

There's unfortunately one place in Foolscap that still uses SHA1: TubIDs are defined to be the base32-encoded SHA1 hash of the certificate. (The TLS certificates themselves use SHA256 for their !DigestAlgorithm).

The presence of a collision attack means that, with enough effort (110 GPU-years), and some clever X.509 format-twiddling, you could create two different TLS certs that present as the same TubID. This is counter to the intention of TubIDs, so it's a valid bug. (Note that the published attack uses a PDF-specific prefix, so I don't believe it could be used to generate a valid X.509 collision, so any would-be attacker would have to duplicate the computation effort of the shattered.it team).

However I'm going to call it a low-priority one, because what really matters in the Foolscap context is a second-preimage attack, and nobody believes that's happening any time soon (it *still* hasn't happened for MD5, 13 years after a collision was published; in fact the only once-considered-secure cryptographic hash function for which a preimage attack exists is SNEFRU-2, from 1990.. even MD2 is still preimage-resistant).

Unlike a certificate authority, Foolscap doesn't sign anything on behalf of outside callers. With a collision, you could produce a TubID with two different certs, but you'd be the one deciding the public RSA keys that went into both certs. For this to be useful to an attacker, they need to make a new cert (with their public key, i.e. one that matches a private key which they control) that hashes to the same TubID as your pre-existing one. That requires a pre-image attack.

So we should fix this, but I don't think it needs to be anytime soon. We might even manage to move to Ed25519 first (see #219).

Details of the fix: we'll replace the TubID with a longer string, and maybe put a version identifier in front. Maybe https://github.com/multiformats/multihash . We'll need to tolerate old SHA1-based tubids. The code around https://github.com/warner/foolscap/blob/master/src/foolscap/negotiate.py#L683 should look at `theirTubID`, determine the hash being used from its format, hash the peer's cert that way, then compare the results.

(I thought maybe the peer should send a negotiation option that says ""please use hash=X to compute my tubid"", but it already effectively does that, in the `my-tub-id` offer field).

At the end of the day, our Tub compares the connection's TubID against the one in the FURL that it's trying to reach. So algorithm=null -style shenanigans (e.g. a multihash that declares to use 0 bits, or something) won't help an attacker pretend to be any legitmate (normal-length) server, as long as no preimage attack is successful.
"	Brian Warner
21	log failures better: add caller stack	logging	0.1.6	eventually	enhancement		new	2007-09-08T19:20:33-07:00	2013-02-16T09:10:11-08:00	"When a method fails, we can log some information about it (if that option is
turned on in the Tub). The information logged looks like this:

{{{
2007/09/08 19:10 -0700 [Negotiation,client] an outbound callRemote (that we sent to someone else) failed on the far end
2007/09/08 19:10 -0700 [Negotiation,client]  reqID=858, rref=<RemoteReference at 0x48b37174 [pb://onxnl2fpfqruabaku26fa4t5543vj3at@207.7.153.181:36611,127.0.0.1:36611/vdrive]>, methname=get
}}}

and includes the remote stack trace.

This information is missing the following useful pieces:

 * the RemoteInterface in use: that methname=get is hard to use without
   knowing exactly __which__ ""get"" method we're talking about
 * the stack trace (or at least the top-most frame) of the callRemote(),
   so we can find out __why__ we were sending this message
"	Brian Warner
88	incident-gatherer needs web interface	logging	0.3.0	eventually	enhancement		new	2008-08-20T12:46:30-07:00	2009-10-04T16:24:46-07:00	"Now that the incident-gatherer is running and classifying properly, the next step is to give it a web interface.

What I want is:

 * a ""recent events"" page that shows incidents sorted by time, color-coded according to how recent they are. Each line should show the incident category, and the triggering event.
 * an events-over-time page that shows the rate of each category. This will need to be recomputed
   when the classification functions are changed.
 * an RSS feed so folks can subscribe to hear about problems
"	Brian Warner
135	flappserver: add upload-tree	usability	0.4.1	eventually	enhancement		new	2009-07-20T20:02:15-07:00	2010-01-11T18:40:53-08:00	"it would be handy to have a flappserver tool to replace ""scp -r"", to upload a whole directory tree at once. We have a replacement for single-file ""scp"", but to upload figleaf coverage data from the buildslave to the web server, I need the multiple-file version.
"	Brian Warner
136	flappserver run-command: add --one-at-a-time, --merge-requests	usability	0.4.1	eventually	enhancement		new	2009-07-20T20:04:55-07:00	2010-01-11T18:41:06-08:00	"The run-command service should get server-side options to wrap command execution in a semaphore (to make sure that only one instance is running at a time), and then a second option to merge multiple requests that are blocked by the semaphore. A related feature would be a client-side ""fire-and-forget"" flag, to indicate that the client should return immediately, and any output/error/exitcode should be discarded or logged. This would let me replace the Makefile-based wrappers around debian/apt repo-updating scripts with a simple flappserver option.
"	Brian Warner
139	logging: send all failure= arguments to twisted.python.log	logging	0.4.1	eventually	enhancement		new	2009-07-20T20:11:25-07:00	2010-01-11T18:01:45-08:00	"I think it would be best to have foolscap.logging.log.msg tell twisted.python.log about any failure= arguments it sees. This would make foolscap's log.err behave better w.r.t. unit tests.
"	Brian Warner
83	new-style classes	banana	0.2.9	eventually	task		new	2008-07-31T10:02:27-07:00	2015-12-23T07:26:58-08:00	"I need to check on our handling of new-style classes. Specifically:

 * is pb.Referenceable new-style? I think the answer is yes.
 * can we use ISliceable adapters to serialize new-style classes? I think yes.
 * there is a test TODO item involving !StorageBanana and new-style classes,
   which is failing. Twisted ticket [http://twistedmatrix.com/trac/ticket/3354 #3354] might be related.
"	Brian Warner
127	give up on resource-consumption defenses	schemas	0.4.1	eventually	task		new	2009-05-31T15:37:25-07:00	2010-12-05T13:34:40-08:00	"One of the original motivations for building Foolscap (relative to its
Perspective Broker ancestry) was to create something that would defend your
code against resource-consumption attacks. A PB server can be trivially
damaged by sending it a long series of OPEN tokens: the receiver will blow
the Python stack limit, and !StackOverflow errors typically cause a lot of
collateral damage (unrelated code can find itself running in low-stack
environments, causing errors in weird places). Likewise, sending a dense tree
of lists can consume target memory at a rate faster than one byte per byte,
and can exhaust the receiver's memory (and !MemoryError is even more damaging
than a stack overflow).

So when Glyph and I first started talking about ""PB2"" (which turned into
Foolscap), one of my desires was to have code which would protect you from
this sort of thing. Since we were talking about having optional explicit
typechecking too (which is rather non-Pythonic for local code, but we felt it
would make remotely-reachable code safer), I figured we could use the same
information to do fine-grained size checking of the inbound token stream,
letting us hang up on a caller who was sending more data than the enclosing
!RemoteInterface said they should be doing.

== The Approach ==

One way to think about the receive-side deserialization code in Foolscap is
to pretend that it is holding a parse tree, something which has one
first-level child node for each Referenceable object which is remotely
accessible (indexed by the CLID: the connection-local ID). Each such object
then has a child node for each method that could be invoked on it: everything
declared in that object's !RemoteInterface. These method nodes then have
child nodes for each argument which they accept, which are either simple
atoms (foo= takes a string, bar= takes an int) with maximum sizes, or
composite types ({{{ListOf(DictOf(int,str))}}}) with upper bounds on number
of elements, etc.

The receive code then knows, at any given moment, where in this parse tree
we're currently sitting. It knows which low-level tokens are allowed to come
next: if we just received the CLID integer, then the next token must be the
method name, so we require a string with a max length of the longest declared
methodname. The arguments stage requires a dictionary (i.e. an OPEN token
followed by the string ""dict""), which itself is limited in the number and
length of its keys. And so on.

The tokens themselves have a 65-byte header+type limit, at which point we
know what the token type is and how long the body can be, so we can test it
against the current constraint. If we're accepting a STRING token but the
length is limited to 13 bytes (because that's the longest method name that's
been declared), we can know to reject a 4 billion byte string.

One additional use of this approach is basic bug-detection. It's always a
good idea to push the explosion closer to the trigger (well, unless you're a
demolitionist). If something gets out of sync on the wire and starts sending
strings where it's supposed to be sending integers, it's nice to detect it
early. Doing this on the inbound token stream is hypothetically better than
doing it after deserialization.

== The Reality ==

This approach has two main problems. The first is that, to make it work,
there must be no holes. To start with, all objects that are ever published or
passed over the wire must have a !RemoteInterface, and their schemas must not
use the ""Any"" wildcard (which turns out to be hard to do in the face of
forward references). Every size limit that you impose in these schemas
affects the overall resource-consumption-attack exposure, but to actually
measure that exposure (which is equivalent to calculating the deepest path in
the parse tree) is a hassle. There is some half-written code to look at your
!RemoteInterface and tell you the maximum depth (or throw an !UnboundedSchema
exception if it's infinite), but it was never really completed.

Moreover, every node in the parse tree must be bounded, even the ones that
aren't explicitly tied to a !RemoteInterface. The 3rd-party reference handoff
""gifting"" mechanism (one of the biggest features that Foolscap adds over PB)
relies upon sending the reference's FURL to the gift-recipient, generally in
an argument that they merely describe as expecting a reference of some sort
(not necessarily a 3rd-party one). So the parse-tree node for this sort of
slot must be able to accept a ""their-reference"" sequence. What constraints
should it impose?

Since I had resource-consumption attacks and constraints in mind as I wrote
the code, I tried to impose limits everywhere (since leaving them
unconstrained would expose the whole thing to attack). But the limits I
imposed (like the 200-byte limit on ""their-reference"" FURLs) were arbitrary,
and based upon my (narrow) expectations of how people would use the system. I
didn't consider that multi-homed Solaris users would have 5 IP addresses in
their FURLs and blow that 200-byte limit, or that people would want to sent
100MB strings and be surprised by the default 2KB limit, or the 30-key limit
on dictionaries. Foolscap-0.1.7 removed the default sizelimits from
user-controllable constraints, but all the internal ones were left in place
(since otherwise it would be impossible to create something that was actually
bounded).

So it's easy to have an unbounded schema, and it's hard to really plug all
the holes. I strongly suspect that, even with perfectly bounded schemas,
there are at least a few unconstrained points in the deserialization code.

The second problem is that these limits all surprise the programmer. Hidden
limits always do. You write your code, you run your tests, everything works
fine (because your datasets are small), you deploy it, things are still fine
(because the datasets are medium), and it takes years before someone uses the
thing enough to run into the hidden limitation. Even when the original
programmer set the constraints to match their use of it, some other
programmer down the line can make a different set of assumptions, change the
use case without knowing to update the constraints, and then run into limits
that they never knew existed. A distributed system makes it worse, because
now some of the servers (but not all) are enforcing some of the constraints
too, depending upon which versions they're running..

== The Advice ==

When I first described Foolscap to Mark Miller, Mark Stiegler, and Tyler
Close, in perhaps 2005 or 2006, they discouraged me from going down the
count-every-byte route, for all of the reasons described above. Their
recommendation was instead to use a per-user proxy. The idea is to funnel all
of Bob's traffic through a single process, upon which you could impose coarse
OS-based resource limits (like setting a ulimit on memory size, or on CPU
time spent). The proxy receives the messages, deserializes them (thus
exposing itself to any attacks), then packages them back up and sends them to
the real server. The outside world never gets access to the real server, only
to a proxy-builder.

If done right, a resource-consumption attack will kill the proxy, but not the
real server, and since Bob is the only one using Bob's proxy, he's only
hurting himself, and can't deny service to Alice or Carol (who have their own
proxies).

But this felt too hard to implement (it still does). Should the proxies be
per-remote-reference? (eek, one process per remote object?). I expected
performance to be a problem, since every incoming message gets an extra
deserialize+reserialize pass (and of course I commit the usual mistake of
letting hypothetical performance impacts drive design decisions without
actually implementing and measuring them first). Keeping the CLIDs in sync
between the proxy and the real server sounded hard, and not doing that
requires the proxy to also behave as a Membrane. Building the proxy-generator
sounded hard. And how would this work on a platform that makes it difficult
or expensive to spawn off new processes, like windows?

Plus, I had already sunk a lot of time into the token-checking scheme, so I
was reluctant to give it up. Also a common mistake. So I stuck with it.

== The Present ==

As of May 2009, every programmer on Tahoe to date (well, Brian, Zooko, and
Rob) has run into a mysterious failure that ultimately resulted from a
Foolscap constraint being violated. (I've hit fewer of them, of course, since
I tend to program under the same assumptions that I baked into Foolscap in
the first place). In many cases, these errors were mysterious because the
Violations were not reported very well, or because they resembled remote
errors that Tahoe normally tries to work around by asking alternate servers
(""no shares found"", well because everybody we asked gave us an error, oh and
all the errors were constraint Violations: you had to dig a lot to discover
the triply-wrapped Failure, but of course ""no shares"" makes you assume that
you've got the filecap wrong so you investigate that for a while first).

The maxKeys=30 limit on dictionaries hit us once (I think, in the introducer,
when we grew to more than 30 servers). The 2MB sizelimit that I declared for
Tahoe shares bit us when we raised the max_segment_size for mutable files. We
increased it, but then it bit us again when we used older servers that had
not yet been upgraded, and the mismatch between the two sides caused
confusion for a release or two (was max size 2MB or 2MiB? oops). The internal
200-byte limit on FURL sizes bit two separate end users who happened to have
a lot of IP addresses.

The fact that schemas no longer have default sizelimits on their constraints
means that to get a bounded schema, you must set a sizelimit on absolutely
everything. The fact that nobody ever finished the depth-checking code means
that it's hard to discover where the holes are in your schemas. The fact that
forward references require the use of Any (#18) makes less likely that you
can even try to get a bounded schema. The internal limitations (like FURL
size in Gifts) cause surprises even if the !RemoteInterface writer didn't add
any. And the likely remaining unbounded holes in the deserialization code
mean that all of this work is probably moot anyways.

== The Future ==

So, I'm going to remove deserialization-based resource-consumption-attack
mitigation from Foolscap. !RemoteInterface will still be there, and any
typelimits and sizelimits you impose will still be honored, but they'll be
applied to the deserialized arguments, rather than to the incoming token
stream. Your {{{foo=StringConstraint(1999)}}} argument will still be guaranteed to
never see a 2kB string (or a list or int), but an attacker will be able to
crash your process by sending a 2TB string (or an infinite list, etc).
Removing the token-type checkers from the deserialization code should
simplify things, and maybe help performance a little bit.

I'll also open up a ticket about implementing the proxy-based approach. It
might be feasible, and would be nice to have. It's certainly more likely to
solve the problem than the deserialization-based approach.

(note: [http://allmydata.org/trac/tahoe/ticket/690 Tahoe#690] is an
expression of the 200-byte gift-FURL limit problem)
"	Brian Warner
272	rewrite Reconnector using t.a.i.ClientService	network	0.12.5	eventually	task		new	2016-12-15T11:22:25-08:00	2016-12-15T11:22:25-08:00	"{{{twisted.application.internet.ClientService}}} wasn't around when I first wrote {{{foolscap.reconnector}}}, but it's here now, and using upstream code is always better than using our own (especially from Twisted).
"	Brian Warner
4	improve CopiedFailure processing	error-handling	0.1.4	undecided	defect		new	2007-07-25T18:22:38-07:00	2010-01-11T12:57:53-08:00	"I've been inspecting !CopiedFailure more closely today, while working on fixes to #2.

For reference, when an exception occurs as a result of a message being delivered, the remote_foo() method results in a Failure, which is a Twisted object that wraps an exception. The Failure is then serialized to deliver over the wire, and is reconstituted into a !CopiedFailure on the calling end.

The general problem is that a !CopiedFailure is not quite the same as a real Failure. It doesn't have any stack frames, for one, but we accomodate this by overriding getTraceback().

The main problem is that the .type attribute is a string rather than a reference to a real exception type like {{{exceptions.IndexError}}} . The only places where this gets used is in Failure.check and Failure.trap, which are utility methods to allow error-processing chains make decisions about the kind of failure that occurred. Both compare self.type against some types passed in by the user.

The comparison itself works fine, since Failure.check is thoughtful enough to stringify the candidates before comparing them to self.type . The actual problem is in Failure.trap(), because it is specified to re-raise the original exception if it doesn't match the candidates. This is usually called inside a deferred callback, which means that the enclosing Deferred is going to wrap a brand new Failure around the exception just raised.

The Failure class is clever enough to notice that it is wrapping another Failure, and then copy the {{{__dict__}}} out of the old one into itself. The problem is that it thus copies .type (which is a string instead of, say, {{{IndexError}}}), but the class changes from !CopiedFailure to a normal Failure . This means that any methods we've overridden in !CopiedFailure (specifically to accomodate the fact that !CopiedFailures aren't the same as regular Failures) go away.

The specific problem I witnessed was when, during the course of a unit test, a callRemote() triggered a remote exception, and then tried to use f.trap on the result, and the f.trap failed, and no other errback in the active Deferred chain caught the failure. The ""unhandled error in deferred"" threw the resulting Failure-with-string-.type into the error log, and eventually trial's error-scanner noticed it and tried to print it, using getTraceback(), which failed.

"	Brian Warner
18	can't handle forward references in RemoteInterface classes	schemas	0.1.5	undecided	defect		new	2007-08-27T15:15:33-07:00	2010-10-13T10:34:14-07:00	"At the moment, the !RemoteInterface metaclass mechanism fully parses the !RemoteInterface specification before the class itself is defined. This makes it impossible to have methods which e.g. return instances of the same class (think graph-traversal interfaces: A.get_children() returns more instances of A). Likewise, it is impossible to have two classes mutually reference each other.

To fix this, the parsing of the methods inside the !RemoteInterface should be put off as long as possible. The first time that someone uses a !RemoteInterface (to obtain a schema or enumerate the methods) should trigger the parsing.
"	Brian Warner
22	log NegotiationErrors better	negotiation	0.1.6	undecided	defect		new	2007-09-08T19:30:22-07:00	2007-12-07T18:23:02-08:00	"We need better logging of NegotiationErrors and other connection failures:

 * Each connection failure should log which TubID we were trying to connect
   to and the connection hint it was using

 * each reconnector-tracked disconnect should announce how long it will be
   until the next connection attempt

 * when a Negotiation rejects the initial GET because it was for an unknown
   TubID, consider putting the list of known TubIDs in the error message (if
   it is short).

The use cases for this logging:

 * someone provides the wrong hostname to a Tub.setLocation, causing it to
   emit FURLs with a bad connection hint. When clients use this FURL, they
   connect to the wrong host/port. One of three things happens:

   * the port has nothing on it, causing a ConnectionFailed error

   * the port has a non-Foolscap server on it, most likely causing a protocol
     error in the Negotiation phase

   * the port has a Foolscap server without the desired TubID on it, causing
     a ""not right"" error during Negotiation

 * in all three cases, there should be enough information in the logs to
   locate the bad FURL.

 * when one of these bad FURLs is used in a Gift, the log message is emitted
   on the far end of the wire, but the NegotiationError probably shows up in
   the errback returned to the sender of the gift.

   
"	Brian Warner
78	post-incident logging breaks trial unit tests	usability	0.2.5	undecided	defect		new	2008-07-04T14:29:25-07:00	2008-09-02T20:53:54-07:00	"The timer that is used to record post-Incident log events causes problems with trial unit tests: if any incidents are triggered during the tests (perhaps due to intentionally induced failures), this timer will probably still be running when the test finishes, which means trial will flunk the test with an ""Unclean Reactor"" error.

One workaround would be to have any unit test suite which is likely to trigger Incidents to also modify {{{foolscap.logging.incident.IncidentReporter.TRAILING_DELAY}}} to None, which would disable this timer, or to have the unit test suite register a replacement {{{IncidentReporter}}} subclass with this same change. This might need to be done from any test which had the potential to trigger incidents, though, and there could be a lot of them.
"	Brian Warner
86	add Constraint for Copyables	schemas	0.3.0	undecided	defect		new	2008-08-11T18:54:21-07:00	2008-08-11T18:54:21-07:00	"As Marco Giusti noted on the twisted-dev mailing list, we don't currently have a Constraint that means ""I expect a Copyable of type X"". There's the attrdict constraint, but that's for use by a !RemoteCopy to describe which attributes are expected to be provided: it's one level lower than what we want.

The desired syntax for this is just to use the Copyable class inside the constraint:

{{{
class Label(Copyable):
  typeToCopy = ""label.example.com""
  def __init__(self, text):
    self.text = text

class CopiedLabel(RemoteCopy):
  copytype = ""label.example.com""
  stateSchema = AttributeDictConstraint( (""text"", str) )

class IFoo(RemoteInterface):
  def getLabel():
    return Label
}}}

To do this, we need:

 * create a !CopyableConstraint class, inheriting from constraint.Constraint,
   and created with a Copyable subclass (or maybe a !RemoteCopy subclass)
  * implement !CopyableConstraint.checkObject(), somehow. If inbound=False
    then it should probably assert an isinstance(obj, myCopyableClass).
    If inbound=True, it should probably check against myRemoteCopyClass
    instead. checkObject() is used outbound before serialization, and
    inbound post-deserialization; i.e. it examines fully-formed objects
    rather than individual tokens.
 * add code to schema.adapt_obj_to_iconstraint() (or register an adapter)
   that knows how to create a !CopyableConstraint from a Copyable or
   !RemoteCopy class.
"	Brian Warner
101	traceback from remote host doesn't come with identifying information about which remote host	error-handling	0.3.0	undecided	defect		new	2008-10-13T09:36:40-07:00	2010-01-11T12:58:26-08:00	"{{{
ax5avvay#1693941923 21:24:12.428: error during query: [CopiedFailure instance: Traceback from remote host -- Traceback (most recent call last):
  File ""/usr/lib/python2.5/site-packages/foolscap/eventual.py"", line 26, in _turn
    cb(*args, **kwargs)
  File ""/usr/lib/python2.5/site-packages/foolscap/broker.py"", line 536, in doNextCall
    d.addCallback(lambda res: self._doCall(delivery))
  File ""/usr/lib/python2.5/site-packages/twisted/internet/defer.py"", line 191, in addCallback
    callbackKeywords=kw)
  File ""/usr/lib/python2.5/site-packages/twisted/internet/defer.py"", line 182, in addCallbacks
    self._runCallbacks()
--- <exception caught here> ---
  File ""/usr/lib/python2.5/site-packages/twisted/internet/defer.py"", line 317, in _runCallbacks
    self.result = callback(self.result, *args, **kw)
  File ""/usr/lib/python2.5/site-packages/foolscap/broker.py"", line 536, in <lambda>
    d.addCallback(lambda res: self._doCall(delivery))
  File ""/usr/lib/python2.5/site-packages/foolscap/broker.py"", line 571, in _doCall
    return obj.doRemoteCall(delivery.methodname, args, kwargs)
  File ""/usr/lib/python2.5/site-packages/foolscap/referenceable.py"", line 59, in doRemoteCall
    res = meth(*args, **kwargs)
  File ""/usr/lib/python2.5/site-packages/allmydata/storage.py"", line 1202, in remote_slot_readv
    msf = MutableShareFile(filename, self)
  File ""/usr/lib/python2.5/site-packages/allmydata/storage.py"", line 383, in __init__
    data = f.read(self.HEADER_SIZE)
exceptions.IOError: [Errno 5] Input/output error
] [Errno 5] Input/output error
}}}

I would really like to know which storage server is having I/O errors.  Too bad this stack trace doesn't tell me.  Any identifying information would work -- tubid or IP address would be fine."	Zooko
110	TypeError in CopiedFailure .parents serialization	error-handling	0.3.0	undecided	defect		new	2009-01-16T08:36:46-08:00	2010-01-11T12:58:43-08:00	"I'm sure that I'm doing something wrong in my use of foolscap, but maybe it shouldn't do this:

{{{
local#1990 20:44:28.717: response from peer iwlrbdlr: alreadygot=(), allocated=(9,)
local#1991 20:44:28.717: peer selection successful for <Tahoe2PeerSelector for upload smt5x>: placed all 10 shares, sent 10 queries to 5 peers, 10 queries placed some shares, 0 pla
ced none, got 0 errors
local#1992 20:44:28.717: _send_shares, used_peers is set([<PeerTracker for peer a2niqogj and SI smt5x>, <PeerTracker for peer z3g3meyl and SI smt5x>, <PeerTracker for peer ncieuno4
 and SI smt5x>, <PeerTracker for peer bduf2tsg and SI smt5x>, <PeerTracker for peer iwlrbdlr and SI smt5x>])
local#1993 20:44:28.717: <Encoder for smt5x> starting
local#1994 20:44:28.733: starting shareholders
local#1995 20:44:28.937: an inbound callRemote that we [ncie] executed (on behalf of someone else, TubID ncie) failed
local#1996 20:44:28.937:  reqID=5, rref=<BucketWriter C:\playground\allmydata\tahoe\trunk\_trial_temp\allmydata.test.test_repairer\Verifier\test_verify_no_problem\zzyjl8\temp\clien
t0\storage\shares\sm\smt5xifqfpy6xecdu7d3q7vuqu\2>, methname=RIBucketWriter.write
local#1997 20:44:28.937:  args=[0, '\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x13\x00\x00\x00$\x00\x00\x007\x00\x00\x02\x17\x00\x00\x03\xf7\x00\x00\x05\xd7\x00\x00\x06\x81']
local#1998 20:44:28.937:  kwargs={}
local#2000 20:44:29.015: 
 FAILURE:
 [CopiedFailure instance: Traceback from remote host -- Traceback (most recent call last):
   File ""build\bdist.win32\egg\foolscap\eventual.py"", line 26, in _turn
     cb(*args, **kwargs)
   File ""build\bdist.win32\egg\foolscap\broker.py"", line 538, in doNextCall
     d.addErrback(self.callFailed, delivery.reqID, delivery)
   File ""c:\python25\lib\site-packages\twisted-8.1.0-py2.5-win32.egg\twisted\internet\defer.py"", line 204, in addErrback
     errbackKeywords=kw)
   File ""c:\python25\lib\site-packages\twisted-8.1.0-py2.5-win32.egg\twisted\internet\defer.py"", line 186, in addCallbacks
     self._runCallbacks()
 --- <exception caught here> ---
   File ""c:\python25\lib\site-packages\twisted-8.1.0-py2.5-win32.egg\twisted\internet\defer.py"", line 328, in _runCallbacks
     self.result = callback(self.result, *args, **kw)
   File ""build\bdist.win32\egg\foolscap\broker.py"", line 610, in callFailed
     delivery.logFailure(f)
   File ""build\bdist.win32\egg\foolscap\call.py"", line 211, in logFailure
     level=log.NOISY, parent=lp)
   File ""build\bdist.win32\egg\foolscap\logging\log.py"", line 196, in msg
     
   File ""build\bdist.win32\egg\foolscap\call.py"", line 818, in getStateToCopy
     parents[i] = truncate(value, 200)
   File ""build\bdist.win32\egg\foolscap\call.py"", line 747, in truncate
     if s and len(s) > limit:
 exceptions.TypeError: object of type 'type' has no len()
 ]
}}}"	Zooko
123	consider making RemoteException mode the default	error-handling	0.3.0	undecided	defect		new	2009-05-12T19:38:26-07:00	2010-12-30T09:28:37-08:00	"Ticket #105 introduced a mode to wrap all remote exceptions in a special {{{RemoteException}}} type, to make them easier to distinguish from local exceptions. It added a Tub option to enable this mode, because application code needs to change to accomodate it.

Let's consider making this mode the default, after some suitable warning (i.e. release 0.4.0 with the mode available, then a release with the !RemoteException mode being the default but the old mode still being available, then finally a release without the old mode at all).

On the other hand, I'm still on the fence as to whether I think Foolscap-using programs should distinguish remote exceptions so.. forcefully. E doesn't make a distinction, so I'm occasionally hesitant to obligate Foolscap programs to do differently.
"	Brian Warner
130	problems in CopiedFailure	error-handling	0.4.1	undecided	defect		new	2009-06-16T13:50:08-07:00	2010-01-11T12:59:16-08:00	"While trying to debug a remote exception (which turned out to be in remote_decref, being called on a CLID which had already gone away), I was frustrated to see that the trial output was an extremely terse {{{[ERROR] ""KeyError: 1""}}}. Asking trial for more detail (by passing it {{{--tbformat=verbose}}} provoked an internal trial error, no attribute "".count"" while trying to do printTraceback.

There are several overlapping problems:
 * Twisted's {{{Failure}}} object has acquired some new attributes in recent versions. In particular, each Failure instance gets a unique .count attribute, assigned in the constructor, and {{{Failure.printTraceback}}} will include it in the rendered traceback if tbformat==verbose. Foolscap was not sending a copy of .count over the wire.
 * the receiving process is getting an actual Failure instance, rather than a {{{CopiedFailure}}} instance. In particular, {{{Failure.printTraceback}}} is being called instead of {{{CopiedFailure.printTraceback}}}, so the lack of .count is more troublesome. I don't understand why this could be the case. I think what we do is instantiate a !CopiedFailure and then set its {{{__dict__}}} to the deserialized attribute dictionary. Perhaps that {{{__dict__}}} set also manages to set {{{__class__}}} and thus changes the method lookup behavior. But {{{__class__}}} isn't supposed to be part of the attribute dictionary that is sent over the wire.
 * if {{{CopiedFailure}}} could produce a .frames attribute that looked more like what {{{Failure}}} was expecting, this wouldn't be such a problem.

"	Brian Warner
142	analyze consequences of recent TLS plaintext-injection vulnerability	unknown	0.4.1	undecided	defect		new	2009-11-10T16:34:51-08:00	2009-11-16T15:44:02-08:00	"A week ago, a new problem in TLS surfaced, in which an attacker can inject arbitrary plaintext into the supposedly-authenticated connection just after a ""renegotiation"" takes place. There was also some suggestion that the attacker could force a renegotiation to occur whenever they liked. I don't yet know if this means that the attacker can inject data into just the beginning of the conversation, or into other places too.

Foolscap is somewhat less vulnerable to this than systems (like HTTP using client-side certificates) that depend upon authorizing clients. Foolscap generally doesn't care *who* you are, just whether or not you know the swissnum.

However, a plaintext-injecting attacker could still cause mischief, sometimes with consequences that violate the expected security properties. If the injection can occur after a {{{getReferenceByName}}}, then the attacker will be able to send arbitrary messages to objects which the real client has already accessed and retains a {{{RemoteReference}}} to (because the swissnum-to-CLID mapping is cached for each connection). They'd have to guess which object you're using, and what methods/arguments it responds to, and couldn't see the results.

The attacker could also inject a message which updates the ""vocab table"" (a mapping from small integer to string, used to compress frequently-used strings like ""getReferenceByName""). This would probably only be usable to prevent methods from being called (a DoS attack), but the attacker might also be able to e.g. transform calls to remote_foo() into calls to remote_bar().

We need to:
 * learn more about the TLS vulnerability: arbitrary injection, or only at the beginning?
 * identify where renegotiation might take place
 * explain how foolscap-using applications might be vulnerable

(note that if every single message included the swissnum, and we didn't use CLIDs at all, then the injection-vulnerability window would be much smaller: they'd have to jam something exactly after the swissnum and before the normal message name/args).
"	Brian Warner
146	does TubConnectorClientFactory stick around too long?	unknown	0.4.1	undecided	defect		new	2010-01-26T14:40:42-08:00	2010-01-26T14:45:59-08:00	"While investigating the incidents in [http://allmydata.org/trac/tahoe/ticket/899 tahoe#899] (I'll attach one of them here), I noticed that {{{TubConnectorClientFactory}}} appears to be sticking around until the winning connection has been closed, rather than going away after the winner has finished negotiating.

I don't think this has any negative effects, but it's not how I intended it to work, so I need to either fix it to work as intended, or walk through and make sure that this unexpected behavior isn't causing problems.

In the attached incident, grep for ""hndn3"", and pay attention to the ""Stopping factory"" lines, in particular in event number 16234.
"	Brian Warner
160	foolscap cannot serialize DeprecationWarning during logging?	unknown	0.5.1	undecided	defect	Brian Warner	new	2010-08-27T17:05:47-07:00	2011-12-20T10:43:10-08:00	"
I see this bug while using tahoe-lafs:
from: http://tahoe-lafs.org/trac/tahoe-lafs/ticket/1188



I'm using the darcs branch (of tahoe), and I setup an introducer/storage client on a VM with an sftp interface. I removed pycrypto from the VM so that tahoe downloads the latest (pycrypto 2.3) during build.

connecting from the Host machine via sshfs produces the output below in the flog.

this isn't really a critical bug, because it seems the sshfs interface to tahoe continues to work normally regardless of the error, and read/write operations I've tried all work fine (md5 hashes even verify). It's only a problem if you're using the flog, because once this exception occurs, the flog stops producing output until you reconnect flogtool.

also, this only appears to happen when I first start tahoe. If i reconnect the flogtool, then disconnect and reconnect sshfs, I don't see the error.



{{{
Application versions (embedded in logfile):
          Nevow: 0.10.0
        Twisted: 10.1.0
allmydata-tahoe: 1.8.0c2-r4702
       argparse: 1.1
       foolscap: 0.5.1
       platform: Linux-Ubuntu_10.04-i686-32bit_ELF
      pyOpenSSL: 0.10
         pyasn1: 0.0.11a
       pycrypto: 2.3
     pycryptopp: 0.5.19
       pysqlite: 2.4.1
         python: 2.6.5
         pyutil: 1.7.10
     setuptools: 0.6c16dev
     simplejson: 2.0.9
         sqlite: 3.6.22
        twisted: 10.1.0
        zbase32: 1.1.2
           zfec: 1.4.7
 zope.interface: 3.5.3
PID: 13223

4wuin3ng#202 15:13:12.236: kex alg, key alg: diffie-hellman-group-exchange-sha1 ssh-rsa
4wuin3ng#203 15:13:12.236: outgoing: aes128-ctr hmac-md5 none
4wuin3ng#204 15:13:12.236: incoming: aes128-ctr hmac-md5 none
4wuin3ng#206 15:13:12.915: an outbound callRemote (that we [4wui] sent to someone else [pmy3]) failed on the far end
4wuin3ng#207 15:13:12.915:  reqID=4, rref=<RemoteReference at 0xafed82c>, methname=RILogObserver.foolscap.lothar.com.msg
4wuin3ng#208 15:13:12.915:  the REMOTE failure was:
 FAILURE:
 [CopiedFailure instance: Traceback from remote host -- Traceback (most recent call last):
   File ""/usr/lib/pymodules/python2.6/foolscap/slicers/root.py"", line 107, in send
     d.callback(None)
   File ""/home/bjp/tahoe/tahoe-lafs/support/lib/python2.6/site-packages/Twisted-10.1.0-py2.6-linux-i686.egg/twisted/internet/defer.py"", line 318, in callback
     self._startRunCallbacks(result)
   File ""/home/bjp/tahoe/tahoe-lafs/support/lib/python2.6/site-packages/Twisted-10.1.0-py2.6-linux-i686.egg/twisted/internet/defer.py"", line 424, in _startRunCallbacks
     self._runCallbacks()
   File ""/home/bjp/tahoe/tahoe-lafs/support/lib/python2.6/site-packages/Twisted-10.1.0-py2.6-linux-i686.egg/twisted/internet/defer.py"", line 441, in _runCallbacks
     self.result = callback(self.result, *args, **kw)
 --- <exception caught here> ---
   File ""/usr/lib/pymodules/python2.6/foolscap/banana.py"", line 215, in produce
     slicer = self.newSlicerFor(obj)
   File ""/usr/lib/pymodules/python2.6/foolscap/banana.py"", line 314, in newSlicerFor
     return topSlicer.slicerForObject(obj)
   File ""/usr/lib/pymodules/python2.6/foolscap/slicer.py"", line 48, in slicerForObject
     return self.parent.slicerForObject(obj)
   File ""/usr/lib/pymodules/python2.6/foolscap/slicer.py"", line 126, in slicerForObject
     return self.parent.slicerForObject(obj)
   File ""/usr/lib/pymodules/python2.6/foolscap/slicer.py"", line 126, in slicerForObject
     return self.parent.slicerForObject(obj)
   File ""/usr/lib/pymodules/python2.6/foolscap/slicers/root.py"", line 66, in slicerForObject
     raise Violation(""cannot serialize %s (%s)"" % (obj, name))
 foolscap.tokens.Violation: Violation (<RootSlicer>.<call-4-1-msg>.<arg[0]>.??): (""cannot serialize Crypto.Util.number.getRandomNumber has confusing semantics and has been deprecated.  Use getRandomInteger or getRandomNBitInteger instead. (<class 'Crypto.pct_warnings.GetRandomNumber_DeprecationWarning'>)"",)
 ]


}}}
"	bj0
186	Remote tracebacks often elide important lines	error-handling	0.6.1	undecided	defect		new	2012-03-07T22:46:06-08:00	2012-03-08T11:59:45-08:00	"Remote exception tracebacks often have {{{-- TRACEBACK ELIDED --}}} replacing the lines that would be most useful for debugging. I think this is a consequence of the default stringification of Twisted {{{Failure}}}s. In [source:foolscap/tokens.py@b9bc4a4#L91], we have
{{{
    def __str__(self):
        return ""<RemoteException around '%s'>"" % str(self.failure)
}}}
which should probably instead be using the {{{traceback}}} module to get a more complete traceback from {{{self.failure.value}}}.
"	davidsarah
205	"""an inbound callRemote ... failed"" log entries include all arguments of the failed call"	logging	0.6.4	undecided	defect		new	2013-05-27T16:56:58-07:00	2013-05-27T16:56:58-07:00	"This can cause performance problems and also leak secrets. [https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1989 An example of the former from Tahoe-LAFS]:

{{{
allmydata.storage.backends.cloud.cloud_common.CloudError: (""try 1 failed: PUT object ('shares/oh/ohcac6xn5ot7hxwfcstdeqcf4e/0.16624',) {}"", '')
]
03:53:03.778 L23 []#87614 an inbound callRemote that we [n4zt] executed (on behalf of someone else, TubID uzie) failed
03:53:03.778 L10 []#87615  reqID=66831, rref=<allmydata.storage.bucket.BucketWriter object at 0x3bf6b50>, methname=RIBucketWriter.write
03:53:03.792 L10 []#87616  args=[8716681284L, '<VERY long string>']
03:53:03.792 L10 []#87617  kwargs={}
03:53:03.792 L10 []#87618  the LOCAL failure was: [...]

Note that in this case the Tahoe-LAFS code has avoided including the data that we attempted to write in the exception message (for !CloudError), but foolscap has logged it, causing a temporary memory leak, and possibly resulting in performance problems when argument strings are large. In other cases, logging the arguments of remote operations may leak secrets into the log.
"	davidsarah
220	mitigate heartbleed vulnerability	negotiation	0.6.4	undecided	defect		new	2014-04-10T08:57:00-07:00	2014-08-12T22:45:00-07:00	"* Make a FAQ describing the impact of heartbleed on foolscap.
* Check the OpenSSL version number and refuse to run if vulnerable.
"	davidsarah
233	investigate serialization efficiency	banana	0.7.0	undecided	defect		new	2015-04-14T14:17:53-07:00	2015-04-14T14:17:53-07:00	"in #163 I noticed that a simple `callRemote(""add"",a=1,b=2)` (from `doc/listings/pb2server.py`) resulted in a 2350-byte TLS packet. I don't know how much plaintext that was, but 2350 seems a bit large, and I don't think TLS is adding that much overhead.
"	Brian Warner
256	implement the transport plugins as zope/twisted IPlugin	unknown	0.9.1	undecided	defect		new	2016-06-01T01:46:11-07:00	2016-06-01T01:48:13-07:00	"
currently in Tahoe-LAFS land we are discussing the new transport plugins system... and it seems there is a need to utilize the twisted plugin system for this."	dawuud
10	better control over unexpected-exception logging	logging	0.1.5	undecided	enhancement		new	2007-08-08T17:33:03-07:00	2010-01-11T18:08:06-08:00	"Foolscap currently has an option to let you log (via twisted.python.log) all exceptions that occur during remote method calls. There is a separate option which logs all exceptions that occur during local method calls (ones that were run on behalf of some distant caller). This is handy when tracking down problems, since the process in which the exception occurred is likely to have more information (either in the logfile or in the head of the human watching it) than any other.

However, using this feature has the annoying property that it discourages developers from using exceptions as part of the normal remote API of their objects. For example, robk has a protocol that uses python's normal !KeyError to signal that a given resource is unavailable, a situation which is actually fairly common. The huge numbers of !KeyError exceptions then spam the logfiles with their tracebacks, masking other problems and consuming resources like crazy.

It would be nice if there were a way to tell Foolscap that, for this particular method, !KeyError is a normal part of the API, and that it doesn't need to be logged.

oldpb did this by creating a special exception class, pb.Error, with the property that any exceptions inheriting from it would not be logged. Any exceptions that occur during message processing that do __not__ inherit from pb.Error __will__ be logged locally.

We're thinking of better ways to express this sort of distinction. The problem with pb.Error is that it discourages you from using standard python exception types as part of your API, since something like !KeyError has no way of inheriting from pb.Error . This is slightly annoying but not majorly so.. you have to do things like:

{{{
  class MyKeyError(pb.Error):
    pass

  def remote_fetch(self, key):
    if key in self.data:
      return self.data[key]
    else:
        raise MyKeyError(""key '%s' not in my data"" % (key,))
}}}

instead of:

{{{
  def remote_fetch(self, key):
    return self.data[key]
}}}

Rob's proposal was to use the RemoteInterface to indicate a list of exceptions that are a ""normal"" part of the API. Foolscap would know that it shouldn't log any instances of these exceptions. (note that foolscap won't log anything about exceptions unless you enable it, but it's so useful that usually you do enable it).

In trying to figure out how to implement this proposal, two ways come to mind. The first is to add a special magic argument to the prototype method definition inside the RemoteInterface:

{{{
class RIFoo(RemoteInterface):
  def fetch(key=str, _raises=(KeyError, IndexError)):
    return int
}}}

(and of course _raises could be either a single exception class or a sequence of them).

The second is to use the established epydoc conventions and have the RemoteInterface code parse the docstring for a '@raises' field:
{{{
class RIFoo(RemoteInterface):
  def fetch(key=str):
    """"""Fetch a key.
    @raises: KeyError if the key does not exist
    """"""
    return int
}}}

the docstring approach is trickier, for several reasons:
 * docstrings are traditionally intended for humans, so they aren't as rigorously defined
   as code
 * scoping: builtins like !KeyError are pretty straightforward to turn into exception classes (or compare against existing exception classes), but what about more local classes? Either the docstring must use the fully-qualified exception classname (what a drag!) or the RemoteInterface parser needs to be aware of the module names that are currently in scope and use them to locate a fully-qualified classname for everything in there.

If we go with the docstring approach, it also hint that we should use @param fields for the type information rather than our current default-values trick.

The way that remote method schemas are defined is a large area to explore.. zope.schema has some stuff to examine, as are some of the method-signature-annotation changes proposed for python itself. The goal has to be to make the RemoteInterface definition easy for humans to read and understand, and feasible for foolscap to parse and enforce.
"	Brian Warner
12	schema checks as precondition tools	schemas	0.1.5	undecided	enhancement		new	2007-08-16T18:58:48-07:00	2012-01-03T13:46:14-08:00	"robk would like the following function:

{{{
def check(constraint, target):
    try:
        constraint.checkObject(target, True)
        return True
    except Violation:
        return False
}}}

I'm thinking that it would be slick to put this sort of stuff into a decorator, so that you could define your method as:

{{{
    @schema(a=str, b=ListOf(int), _return=bool)
    def do_something(a, b):
        print a + "" string only""
        print ""maximum b"", max(b)
        return True
}}}

The {{{@schema}}} decorator should do two things:
 * wrap the method with some precondition/postcondition checks that enforce
   the schema on both ends
 * set a method attribute that foolscap's deserialization mechanism can see,
   so that it can enforce the schema on the inbound tokens as they arrive,
   before they are deserialized.

This approach moves the constraint closer to the method definition, which has
its advantages: programmers can glance upwards to see the conditions they
know they can rely upon, and thus don't have to add code to enforce those
constraints themselves. This also allows constraints to be attached to some
methods but not to all of them, and would allow constraints on standalone
functions (not just on methods of class instances).

On the other hand, the RemoteInterface approach has advantages too. It moves
the interface away from the implementation, but by doing so it means that the
interface is a concentrated bundle of documentation, which is easy to publish
and reference. For one program, I implemented the server half of it and
emailed the RemoteInterface .py file to zooko, and he implemented the client
half of it without seeing any details of the server implementation.
InterfacesAsDocumentation is a useful thing.
"	Brian Warner
17	implements() with multiple RemoteInterfaces	schemas	0.1.5	undecided	enhancement		new	2007-08-21T17:43:22-07:00	2010-01-11T13:04:20-08:00	"it would be awfully useful if Referenceable subclasses could indicate that they implement
multiple [RemoteInterface RemoteInterfaces], not just one. This only-one-RemoteInterface limitation
requires users to play weird games and mix together interfaces that really ought to be separate.

To fix this, we'll need to change the way that Referenceables get sent over the wire the very first time. At the moment, there's a slot in the serialized (my-reference) sequence for a RemoteInterface name: that needs to accept either a single string or a list of strings.
"	Brian Warner
20	implement Sealers/Unsealers	unknown	0.1.5	undecided	enhancement		new	2007-08-30T18:56:09-07:00	2008-07-01T18:40:34-07:00	"Sealers and Unsealers are the object-capabilities equivalent of public key
operations: encryption, decryption, signing, verifying. It would be useful to
have them available in a Foolscap environment.

(note, #19 is about making the Tub's public/private key available for use as
a sealer/unsealer. This ticket is about creating and using new keys, not the
Tub's SSL key).

The API that I'm imagining for this is:

{{{
   s,u = tub.createSealerUnsealerPair(brand)
   d = s.seal(obj)
   d.addCallback(lambda sealed_box: u.unseal(sealed_box))
   d.addCallback(lambda new_obj: yay)
}}}


The big questions in my mind right now are how to handle interesting objects.
I want the contents of the box to be an arbitrary object graph (almost
anything you could pass to {{{callRemote}}}), but things things like live
references may or may not work. Handling live references will certainly
require access to a Tub, which is why {{{create()}}} is a method of a tub
instance rather than a top-level Foolscap function. {{{seal()}}} and
{{{unseal()}}} return Deferreds for the same reason.

My plan is to implement the serialization by using the normal banana code,
but with a different root Slicer that provides alternative Slicers for the
things that get handled differently here (i.e. ones that reject liverefs, or
turn them into sturdyrefs, or something).

There are two different forms of sealers: cryptographic-based and
reference-based. The first can be copy-by-value, the latter must be
copy-by-reference (and requires a connection to its host to use). Both have
their uses.. I'm not yet sure if I should implement both or just the
cryptographic one.

In E, each sealer/unsealer has a distinct ""Brand"" object, which also have
non-distinct string names (i.e. there could be two Brands with the same name
but which are completely unrelated). I'm not sure if I should do that here or
just attach a string name to the sealer/unsealer.

Here is a useful thread on cryptographic sealers/unsealers in the objcap world:
http://www.eros-os.org/pipermail/cap-talk/2007-March/007595.html
"	Brian Warner
24	provide URL-safe FURLs	network	0.1.6	undecided	enhancement		new	2007-09-11T11:52:02-07:00	2015-09-14T15:44:06-07:00	"For several places in [http://allmydata.org Tahoe] we need to pass FURLS around in HTTP URL query arguments. The fact that normal FURLs look a lot like HTTP URLs causes problems with this: I've found that even after you URL-quote the FURL, the slashes in it can cause problems for HTTP reverse-proxies (what I observed was that the proxy un-escaped the URL and got confused by the
slashes in the query arguments, thinking they were part of the query itself).

To this end, it would be convenient if there were a URL-safe form of a FURL, preferably entirely base32 characters (with perhaps a few other URL-safe characters as delimiters, like maybe a decimal point or comma or something).

I'd like these FURLs to be passable to Tub.getReference just like the normal {{{pb://}}} FURL.

Zooko describes this in terms of ""compressed FURLs"", which are packed, non-human readable, and don't necessarily need to be self-describing. I'm hoping he'll chime in with his thoughts on this ticket.

I'm not sure what the best API for this would be.. maybe {{{Tub.compressFURL(oldfurl)}}} ? It doesn't need to be a method of the Tub, really.. {{{foolscap.compressFURL(oldfurl)}}} could work too.

"	Brian Warner
32	logging: eventual() causality tracing	logging	0.1.7	undecided	enhancement	Brian Warner	new	2007-11-28T12:26:22-08:00	2007-12-07T18:23:34-08:00	"Zooko mentioned that some recent debugging work of his would have gone faster
if eventual-sends didn't break the chain of causality in stack traces.
Specifically, when you have code like the following:

{{{
def parent():
    eventual.eventually(child)

def child():
    raise OopsError
}}}

Then the ""unhandled error in Deferred"" -type stuff logs the OopsError, but
the parent of the stack that it records is going to be the eventual-send
code's {{{_turn}}} method, and {{{parent}}} is nowhere visible on that stack.

It would probably suffice to have {{{eventual.eventually()}}} record a single
frame of the stack that calls into it, and store that next to the
callback+args tuple. Call this the ""causality record"", since other logging
improvements are going to be using similar concepts (in which the record
might include the whole stack, or might have a remote message number, or a
turn number, or perhaps an application-generated explicit context structure).

The trickier part will be how to include this causality record in with the
resulting log messages. When foolscap's 'flog' mechanism grows to the point
where it is involved in recording Unhandled Error In Deferreds and the like,
it could crawl the stack, locate the {{{_turn()}}} frame, extract the
causality record, then include it in the message it is generating. (likewise
when a remote call is what triggered the turn, the request-id and remote
tub-id should be used as the causality record).

"	Brian Warner
37	make RIFoo.providedBy(rref) work	schemas	0.2.2	undecided	enhancement		new	2007-12-13T11:28:19-08:00	2007-12-13T11:28:19-08:00	"it would be nice to be able to do:

{{{
 def set_remote(self, rref):
     assert RIFoo.providedBy(rref)
     self._remote = rref
}}}

and have that assert two things: 'rref' is a RemoteReference, and that
RemoteReference is associated with a Referenceable that claims to implement
RIFoo. If {{{set_remote}}} were {{{remote_set_remote}}}, we could do this
with a schema check, but we don't currently have the ability to test this
sort of thing outside (un)serialization time.
"	Brian Warner
41	bandwidth limiting	banana	0.2.2	undecided	enhancement		new	2007-12-31T13:32:06-08:00	2007-12-31T13:32:06-08:00	"It would be awfully handy if an application could tell Foolscap to limit the outgoing bandwidth it is using to some N bits per second. It would also be useful to have it limit the inbound bandwidth, but of course that's a lot harder.

This needs to be done on at least the Tub level. If an app has multiple Tubs, it would be nice if they could coordinate to keep their aggregate limit below the configured value. (it would even be cool if the bandwidth manager were a foolscap.Referenceable object, so it could be shared between multiple applications, perhaps on different hosts, all sharing the same narrow pipe).
"	Brian Warner
44	build support for membranes	unknown	0.2.4	undecided	enhancement		new	2008-01-29T15:27:28-08:00	2008-01-29T15:27:28-08:00	"The sealer/unsealer code should also be usable to make it easy to create
Membranes (which are like a revokable forwarder, but every reference you pass
through it is also wrapped in a revokable forwarder, so that the users of the
interface don't have to refrain from passing their own references).

Something with an API like:

{{{
 wrapfunc = RevocableForwarder()
 d = tub.makeMembrane(orig, wrapfunc)
 # then later..
 wrapfunc.revoke()
}}}

I'm thinking that {{{wrapfunc}}} will be called for each Referenceable or
RemoteReference (ooh, interesting to think about the difference there..) that
passes through, and it is expected to return a new reference for each one.
{{{RovocableForwarder.__call__}}} would provide this.

This would also provide for things like:

{{{
 wrapfunc = LoggingForwarder(logfunc)
 wrapfunc = ArgumentAddingForwarder(owner=""bob"")
}}}

{{{makeMembrane}}} would be implemented with a special serialize/unserialize
pair, in which the unslicer table uses the wrapper function to handle
my-reference sequences.
"	Brian Warner
46	relay server	introduction	0.2.4	undecided	enhancement		new	2008-03-20T15:48:53-07:00	2010-01-11T11:28:02-08:00	"To enable endpoints that are both behind NAT boxes or firewalls to speak
using Foolscap, it would be useful to provide support for an easy-to-use
""relay server"". We've kicked around a couple different approaches to this for
[http://allmydata.org Tahoe], and this one is currently our favorite.

The Foolscap negotiation protocol is specifically designed to provide for
multiple Tubs listening on the same port. We build a Relay process to which
the NAT-bound Tubs can attach, registering themselves with a (tubid,
listener_rref) tuple. This listener_rref object has a single accept() method,
which returns a handler_rref object. When B wants to connect to C, the FURL
it uses will contain C's tubid but will have connection hints that point to
the relay's listening socket. When B connects to the relay and says it wants
to talk to tubidC, the relay (during the negotiation process) tells the
listener_rref that it wants a new connection, gets the handler_rref, then
switches into a simple proxy mode where it copies data from the B-side
connection into remote_write() messages sent to the handler_rref. On C, the
contents of these messages are written into a loopback TCP socket that mimics
the data being exchanged between B and the relay. Responses generated by C
get proxied backwards to the relay over the same connection.

This requires more code, but it's the ""right way to do it"" for relay. The
intermediate relay doesn't get to see or corrupt the traffic that it is
carrying, and the remote objects on B and C don't need to be aware that
anything unusual is going on. C needs to register with the relay, and the
FURL needs to be created with the right connection hints, but that can be
done once at startup (instead of requiring that every single message be
specially encrypted).
"	Brian Warner
56	log gatherer should export a logport	logging	0.2.5	undecided	enhancement		new	2008-03-25T21:19:40-07:00	2008-03-25T21:20:47-07:00	"It would be nice if I could connect 'flogtool tail' to the log-gatherer, to watch the stream of
events that it is writing out to the file.
"	Brian Warner
57	logging: remote filtering expressions	logging	0.2.5	undecided	enhancement		new	2008-03-26T13:09:39-07:00	2008-03-26T13:09:39-07:00	"It would be great if tools like 'flogtool tail' could subscribe to less than the full event stream. The most generalized approach I can think of is to pass a filtering expression to the far end, but Python is not E, and this is not safe. However, we could define a simple stack-based language, and compile the filtering expression into the opcodes of this language, and then evaluate the filtering program for each event.

It might not be feasible to actually compile the python expression into that language, but it might be simple enough for users to write the opcodes directly.

I'm thinking things like:

* compare(GT, e.level, 20)
* AND(top two items on the stack)
* OR
* NOT
* SWAP

things like that. A basic ""A and B and C"" test would be:

* compare(A)
* compare(B)
* compare(C)
* AND
* AND
"	Brian Warner
58	'flogtool filter' as a network pipe	logging	0.2.5	undecided	enhancement		new	2008-03-26T13:09:49-07:00	2008-03-26T13:09:49-07:00	"Good idea from zooko: make the 'flogtool filter' command (which currently takes a file and produces a new smaller file) accept a logport.furl and produce a logport.furl . Then, once the filters described in #53 are in place (and the gatherer tap from #56 too), we could efficiently follow a subset of the log events by doing:

 * configure the gatherer with a #56 tap
 * run 'flogtool filter' on the same host as the gatherer, with a #53 filter expression
 * run 'flogtool tail' on your remote host, pointing at the filter's logport

This would be an easier-to-implement point along the way to the remote-filtering-expressions that I want to build in #57.
"	Brian Warner
73	logging tools to analyze hard failures like segfaults	logging	0.2.5	undecided	enhancement		new	2008-06-23T18:23:27-07:00	2008-07-01T20:05:03-07:00	"We were analyzing a Tahoe failure that resulted from an overloaded logger (#72). One intermediate hypothesis was that python segfaulted in response to some inbound callRemote, and the log.msg that would have reported the inbound method call was lost while it was still inside the sending process's transmit buffer. So we were discussing ways to get log messages from a process to a gatherer that didn't depend upon python or foolscap working.

One approach that I looked at for a different project many years ago was to use shared memory. The sending process allocates a buffer (perhaps 1MB) that is shared with a receiver, and writes some structures into place that define a circular buffer (or a slab to which we write in chunks from one end to the other, and use memmove when we reach the end instead of wrapping around). The messages should have checksums, and the structure should have a bunch of pointers, so that the receiver can look at the pointers at any moment (in between python opcodes) and read any message that was fully written by that point.

Shared memory is not the easiest thing to manipulate from python, but it's possible. The log messages would be serialized (perhaps safely with Tub.serialize) before being added to the buffer.
"	Brian Warner
74	log-gatherer: track last-heard-from time	logging	0.2.5	undecided	enhancement		new	2008-06-23T18:27:19-07:00	2009-05-19T16:06:16-07:00	"It would be useful if the log-gatherer were to keep track of the last time we've heard anything from a given supervised process. This could be last-log-message-received and/or connection-level keepalive timestamp.
"	Brian Warner
77	automatic VOCAB-compression of common strings	banana	0.2.5	undecided	enhancement		new	2008-07-03T09:33:01-07:00	2008-07-03T09:33:01-07:00	"At some point I need to finally implement a long-standing TODO item: automatic VOCABization of strings that are sent over the wire many times. The VOCAB token is a small integer that represents a larger string, effectively compressing the wire protocol. The first 128 such strings are represented by two bytes on the wire, and the next 16k strings are represented by 3 bytes.

Foolscaps pre-populates this table with the strings that are used by Foolscap itself, things like ""my-reference"" and ""call"" and ""unicode"". There is a mechanism (the ADDVOCAB token, or maybe it's the add-vocab sequence, I forget) to add new items to the receiver's table.

So what's missing is code in the sender to watch the strings being sent over the wire for ones that are repeated frequently: remote method names are the most likely. If this code decides that we would save space by assigning a VOCAB number to the string, it will send the add-vocab sequence, then start using that VOCAB token every time it sees the string.

An outstanding question is how to do this efficiently.. nominally this new code would manage a dictionary that maps strings to numbers, counting how many times it has seen that string go by. When the count goes above, say, 3, it should add the vocab entry, then remove it from the dict. (This code should look at the strings after they've passed the VOCAB table, so it won't see strings that were already in the VOCAB table). But this would get expensive for applications which send a lot of strings. Maybe Bloom filters..

Note that this is a backwards-compatible change. The add-vocab sequence has been supported by Foolscap since forever, so even old recipients will be able to handle it.
"	Brian Warner
87	use banana+compression for flogfiles on wire	logging	0.3.0	undecided	enhancement		new	2008-08-12T19:58:58-07:00	2008-09-03T12:13:46-07:00	"0.3.0 stores log events on disk using pickle, with optional compression. The compression is a big win, usually about 10x.

But when we send these events over the wire in an Incident Report, we decompress the file, pickle.load into memory, serialize with Banana over the wire, then the incident-gatherer at the other end must deserialize the Banana, reserialize with pickle, recompress, then write to a file.

The idea was to avoid the unsafe pickle deserialization at the receiving end. But we could use banana instead. We almost have enough Tub.serialize code in place to let us do streaming safe serialization of the log events, which we could then compress as normal. We can add a new incident-subscription protocol (rather a replacement for get_incident) which returns a big string of bzip2'ed banana'ed log events, instead of getting a stream of distinct log events.

I think this would reduce the CPU usage of catching up the incident-gatherer considerably. At the moment it takes a second or two per incident, and probably 10x as much network traffic as we really want.
"	Brian Warner
98	overlapping incidents: record in a trailer	logging	0.3.0	undecided	enhancement		new	2008-09-03T12:15:05-07:00	2008-09-03T12:15:05-07:00	"In 0.3.1 we changed the way the Incident Reporter worked, so that if a bunch of incident-triggering log events occur at about the same time, they'll all go into a single incident instead of spawning dozens. This was done because we observed (in Tahoe) that these triggers tend to occur in clusters, and having a dozen overlapping incidents didn't give us any more information than a single one (and the extra processing time of the additional incidents was a problem).

But it would be nice if the tools that display and analyze incidents could know about the events that would have triggered their own incidents if only they'd occurred a little bit later. Since the incident header is already written by the time we encounter the extra triggers, maybe we should put them in a 'trailer' dictionary. Or perhaps the event-wrapper dict could get an extra ""this is also a trigger"" flag.

The web-viewer (and other tools) should mark these secondary triggers with similar highlighting as they mark the primary trigger.
"	Brian Warner
116	"consider adding ""current caller context"" function"	unknown	0.3.0	undecided	enhancement		new	2009-03-24T11:50:41-07:00	2013-05-27T16:50:56-07:00	"This function would allow a remote_foo() method to learn the tubid of the client which sent the activating message. (another possibility is to add magic argument markers to the schema, which would be filled in with locally-generated values that didn't come from the remote client). The ""current caller context"" function would work by crawling the stack upwards until the foolscap dispatch routine was located, then looking inside that routine's stack frame for the client tubid. It would only be callable from the first reactor turn: if remote_foo() defers execution to a subsequent turn, the information would be lost. This function could also indicate which !RemoteReference the message arrived on (in case the same object is referenced in multiple ways).

It's not clear to me that this would be a good idea, but it's occurred to me more than once, so it needed to be written down.
"	Brian Warner
117	performance improvements: receive-side tokenization, send-side streamingness	banana	0.3.0	undecided	enhancement		new	2009-03-24T14:47:59-07:00	2010-10-28T15:17:43-07:00	"Brian Granger asked me (in email) to identify some of the places where we
might be able to improve Foolscap's performance. Here's my list.

> What is your sense of where the bottlenecks in Foolscap are that
> would affect latency?  Am I correct that send and produce are the
> primary candidates for optimization?

Yes, I think you're right. I'm seeing 15ms operation times in a similar Tahoe
environment.. I don't really know how much the two ends are using themselves,
but I expect that a lot of that 15ms is in Foolscap
serialization/deserialization. (we're considering moving to a simpler
HTTP-based protocol for Tahoe, because the higher-layer data structures
already have encryption and integrity checks, so we don't really need it at
the transport level).

I haven't spent any time trying to optimize/improve performance (or really
even measuring it) yet.

First thing I'd do is to figure out whether to focus on the sending side or
on the receiving side. To measure the receiving side separately, I'd generate
a bunch of pre-serialized test cases, instantiate a Banana object, poke it a
bit to make it think that it's undergone negotation already, attach it to a
Broker that will ignore receiveChild() (so the message-send won't actually do
anything), then time/profile banana.dataReceived(teststring). Measuring the
sending side is easier, since serialization is complete by the time
callRemote() returns. (there is additional time spent by Twisted to move the
serialized data from the Transport's send buffer into the kernel, but that's
probably pretty efficient compared to what Foolscap is doing).

The lowest-hanging fruit I can think of is the receive-side tokenization
loop, in Banana.handleData(), since it uses a lot of string copies (one per
extracted token). You might try:

 * modify Banana.handleData() to use python ""buffers"" instead of doing so
   many string copies: the ""rest = buffer[pos+1:]"" is the biggest culprit,
   doing a copy for each received token

 * write a C function that takes a buffer of input and returns a list of
   tokens plus a leftover string, and use that to drive the loop instead of
   that big ""while"" loop (i.e. move the tokenization into C). Have that
   function return tokens of type (int, float, str, tuple), with tuples being
   used to indicate OPEN, CLOSE, ABORT, LIST, etc:

{{{
    tokens, rest = c_tokenizer(buffer)
    for t in tokens:
      t1 = type(t)
      if t1 is tuple:
       if t[0] == OPEN:
        self.handleOpen(t[1:]) ...
       elif t[0] == CLOSE:
        self.handleClose(t[1:]) ...
      if t1 in (int, long, float, str):
       obj = t
       ...
}}}

 * inline some of the handleFOO() methods, to reduce the number of function
   calls

The behavior of the tokenizer will depend upon how many tokens arrive in a
single TCP hunk: an argument object graph with lots of nodes will do lots of
copies. The size of each copy will depend upon how much data is in the graph:
you might benchmark

  callRemote(""foo"", [""a"" for i in range(1000)])

separately from

  callRemote(""foo"", [""a""*10 for i in range(100)])

to measure the difference. The first will create 1000 STRING(""a"") tokens
(each of which will be 3 bytes long), the second will create 100
STRING(""a""*10) tokens (each of which will be 12 bytes long). Assuming that
both the 3000ish-long message and the 1200ish-long message make it into a
single socket read() call, the first will do 1000 copies of successively
shorter leftover strings, while the second will only do 100.

If the workload includes a lot of simple graphs of primitive types (list of
ints, no cycles), you might be able to have a C-based tokenizer look at the
full list of tokens that came out of the current hunk, locate the matched
OPEN/CLOSE pairs, and create composite python objects directly. This would
probably break under more complicated object graphs, so it might require a
change to the protocol to use safely, like a new OPEN_UNSHARED token (which
promises that nobody will ever reference any of its child objects from
outside, so you don't need to keep track of openID numbers for them).


On the transmit side, I'd guess the main bottleneck to be the overly flexible
serialization scheme. In particular, any Slicer can return a Deferred, so the
banana serialization loop must be prepared to handle that at any time, even
though this is only used for streaming serialization and there isn't any API
to enable that. It must also be prepared to handle a new Slicer. And it's
using a lot of delegate-to-self (which introduces extra method calls, but was
handy for testing). Banana.produce() is the method to look at.

I've got one note in there which suggests an optimization to try (cache
'next'). I'd also look at inlining some of the delegate-to-self methods
(making produce() bigger). Some other options:

 * stop sending then openID numbers with the OPEN and CLOSE tokens: those are
   mainly to detect programming errors that cause loss-of-sync, and aren't
   needed once you've got confidence in the code
 * find a way to avoid tracking references for every object we send out.
   There's a dictionary that maps openID to object (used to avoid getting
   trapped in cycles, and to allow the recipient to correctly reconstruct
   cycles in the object graph). We might be putting more objects into this
   dictionary that we really need to. (but maybe not).
 * consider ripping out produce() and replacing it with a synchronous
   stack-based serializer, possibly keyed by a Schema note that says ""I
   promise that all of my arguments can be serialized synchronously, none of
   them contains a shared reference or a cycle, and the diameter of the graph
   is smaller than python's maximum stack depth"".
  * if that is true, the serialization code can use Slicers as usual, but
    drive it with a different loop that isn't quite so flexible. It could
    special-case all the primitive types (dict, list, tuple, set, int, str)
    instead of using the general-purpose Slicers.. that could be a lot
    faster.


But start with measuring the receive-side tokenizer. I'm sure there's a
pretty simple way to use buffer objects and replace that ""rest =
buffer[pos+1:]"" with a simple incrementing offset: that would eliminate the
string copies and probably give you a big win on the rx side.
"	Brian Warner
153	os._exit() after logging a FATAL message	unknown	0.4.1	undecided	enhancement		new	2010-07-17T20:01:39-07:00	2010-07-17T20:01:39-07:00	I would like it if foolscap called {{{os._exit()}}} after it finishes durably/reliably logging a {{{FATAL}}} message. Note that I don't want {{{os.abort()}}} because that allows more Python code to run before ending the operating system process. (Alternately you might consider {{{os.kill(os.getpid(), 9)}}}, but I don't think that works right on Windows.)	Zooko
183	release the Negotiation instance after connection establishment	negotiation	0.6.1	undecided	enhancement		new	2011-06-05T20:38:08-07:00	2011-06-05T20:38:08-07:00	"As mentioned in #173, the (large) {{{Negotiation}}} instance should be deallocated after negotiation is complete. The fix for #173 broke this (if it actually worked before): the {{{Negotiation}}} object will live as long as the connection stays up.

The fix will probably be to introduce a new, smaller {{{Protocol}}} (named {{{FoolscapProtocol}}}) which lives as long as the connection. It will start by delegating inbound {{{.dataReceived}}}/{{{.connectionLost}}} messages to the {{{Negotiation}}} instance, then later switch to send them to the {{{Banana}}} instance (releasing the {{{Negotiation}}}).
"	Brian Warner
219	Use NaCl/Curve25519 for Tub authentication	negotiation	0.6.4	undecided	enhancement		new	2014-03-24T15:44:01-07:00	2014-09-23T22:14:20-07:00	"The current TubID system uses the `.startTLS()` method of the TCP for authenticating Tubs and securing connections. But with #203 on the horizon, foolscap will support endpoints that do not have (or need) `.startTLS()`, because they have their own encryption (I2P/Tor). Attempting to use the existing SSL TubIDs over these transports will require considerable heroics. Some FURLs may also contain multiple endpoints, and these should authenticate with the same TubID / public key regardless of transport.

At RWC2014 warner suggested moving to !NaCl crypto instead of SSL. This has the advantage of making Tub authentication independent of the transport used.

Legacy SSL TubIDs would still be supported, but only tcp location hints would be considered. The following table shows how location hints would be supported.

|| ||||||= Location Hint =||
||= TubID =|| tcp || i2p || tor ||
|| SSL || yes |||| no (unless heroics) ||
|| !NaCl |||||| uniform auth, aware of which transport is being used ||"	str4d
230	when a failure is not serializable, try to indicate which exception type was responsible	banana	0.7.0	undecided	enhancement		new	2014-10-24T17:27:12-07:00	2014-10-24T17:27:12-07:00	A common reason to get a `foolscap.tokens.Violation` is that some exception type transitively references an unserializable object. However the traceback doesn't provide any information about where to start looking, i.e. which exception type. In some cases, even without trying to fix the unserializability, just knowing the exception type would be a sufficient clue to the cause of the original error.	davidsarah
237	share a Listener with HTTP	negotiation	0.7.0	undecided	enhancement		new	2015-07-23T18:30:36-07:00	2015-07-23T18:30:36-07:00	"For Tahoe's ""storage server over HTTP"" project ([https://tahoe-lafs.org/trac/tahoe-lafs/ticket/510 tahoe#510]), it would be awfully handy if a single TCP port could host both a Foolscap Tub and a regular web server (`twisted.web.server`). I think the easiest way to do this would be to have our `Negotiation` protocol notice that the client didn't provide the ""please switch protocols"" header, create a new HTTPServer protocol instance, connect it to the transport, then write in all the buffered header text. The switch would look a lot like how `Negotiation` hands off to `Banana`, except it has to deal with leftover input bytes too.

The UI would be something like:

{{{
l = tub.listenOn(""tcp:1234"")
l.addHTTPServer(twisted.web.server.Site(root))
}}}

I don't know how to make this work with HTTPS (it might help that HTTP-over-TLS is traditionally run at a different port than unencrypted HTTP, but we'd still need two separate `--listen=` arguments for Tahoe). To do it properly, we'd need the foolscap Negotiation object to handle using TLS right off the bat, instead of using `startTLS()`. That would preclude sharing a listening port between multiple Tubs (since we must commit to a specific certificate before hearing the GET that asks for a TubID), and the initial who-do-you-want message would happen *inside* the TLS session, instead of outside. Probably feasible, but a bit trickier than the Foolscap+HTTP case.
"	Brian Warner
255	test unix-domain sockets	network	0.9.1	undecided	enhancement		new	2016-04-19T11:16:07-07:00	2016-04-21T12:51:14-07:00	"A quick glance at twisted/internet/unix.py suggests that the unix-domain `Server` and `Port` classes inherit from their `tcp.*` cousins, which would mean `.startTLS()` should work on them. That'd be great, because then we could use unix-domain sockets for e.g. SOCKS and `txtorcon` connections, instead of localhost-bound TCP.

We should test this. The test should do `tub.listenOn(""unix:/tmp/filename"")`. We also need a connection handler that knows how to make unix-domain outbound sockets, maybe something to wire a TCP socket to a unix one.
"	Brian Warner
257	use CBOR instead of Banana for serialization?	banana	0.9.1	undecided	enhancement		new	2016-06-22T07:55:36-07:00	2016-06-22T09:13:50-07:00	"I've been reading up on CBOR, which is like JSON except dense (binary) and supports bytestrings properly. There are some accelerated C codecs for it, as well as pure-python ones. It can handle cyclic object graphs. And it has a ""tag"" mechanism to mark objects for special processing, which we could use for our my-reference/your-reference/call sequences.

http://cbor.io/

I'm thinking it might be faster than our banana implementation (which has a lot of unused extensibility, and schema-enforcement hooks that we've already given up on), and might make it a bit easier for someone to write a compatible non-python implementation.

Of course we'd need the Negotiation phase to decide whether a given connection will use banana or CBOR, to deploy it gradually.
"	Brian Warner
266	onion vs tor+exit: which will win? which should win?	network	0.12.0	undecided	enhancement		new	2016-08-29T17:37:28-07:00	2016-08-29T17:37:28-07:00	"If a FURL contains both `tcp:` and `tor:` (perhaps from a server that wants to assist Tor-capable clients, but remain accessible to non-capable clients), and the client is configured to use Tor for `tcp:` hints too (because it wants to hide its own IP address), what will happen?

I think the two connections will race, and I suspect the `tcp:` hint will win (it will go through an exit node, but it doesn't have to look up the onion descriptor, so I think it'll have less work to do).

But I think we'd prefer the `tor:` (onion) hint to win, since that reveals less information to the internet at large.

Is there a clean way to make this more likely to happen? If hints were processed as a group, we could make the `tcp` handler notice the presence of the `tor` handler, and then stall itself for a few seconds, to give the `tor` handler a chance to win. But connection handlers are pretty independent: they're unaware of each other.

Maybe connection-handlers could return a priority value (synchronously, before `hint_to_endpoint` is called). If there are multiple hints with different priorities, the overall connection manager could impose a delay.

Or maybe the handler could get an additional argument that says ""by the way, here are the other handlers that I'm about to ask, feel free to let that influence your behavior"". We know all the handlers that will be used early (once we see the hint types), so this wouldn't be too hard to implement. And then the TCP handler could notice the Tor handler and stall itself. We might add a marker Interface to let the connection manager know that this handler is capable of understanding the extra argument. Or add a static class attribute, or something.
"	Brian Warner
164	measure memory usage per connection	performance	0.5.1	undecided	task		new	2010-10-28T15:22:20-07:00	2010-10-28T15:22:20-07:00	"Reading http://www.imperialviolet.org/2010/06/25/overclocking-ssl.html , I
saw the following note:

  OpenSSL tends to allocate about 50KB of memory for each connection. We have
  patched OpenSSL to reduce this to about 5KB and the Tor project have
  independently written a similar patch that is now upstream. (Check for
  SSL_MODE_RELEASE_BUFFERS in OpenSSL 1.0.0a.). Keeping memory usage down is
  vitally important when dealing with many connections.

and I remembered that we used to see bad memory usage in Foolscap
applications that maintain open connections to hundreds of peers. I don't
remember the details, but I think it was something like 1MB per connection or
something crazy. This was back in 2005/2006.

One of the first things I did at Allmydata was to build a test harness to
measure this memory usage. The task is to ressurect that harness, measure RAM
footprint for 10/100/1k/10k connections, and figure out the slope. I'm ok
with 50kB/connection for now, but if there's something we can do from
Foolscap to hit 5kB instead, that'd be a nice improvement.
"	Brian Warner
143	add PONG-sending timer	unknown	0.4.1	eventually	enhancement		new	2009-11-23T22:03:32-08:00	2011-01-16T14:13:48-08:00	"As David-Sarah Hopwood pointed out in [http://allmydata.org/trac/tahoe/ticket/521 tahoe#521], Foolscap's connection-keepalive timers might be improved by adding an outbound timer to the existing inbound- and disconnect- timers. The idea would be to ensure that we *send* data on a regular basis, not just that we've received data on a regular basis. This ""PONG"" timer would send an unsolicited PONG message (which is generally ignored, except to update the last-heard-from timestamp) if we had not sent any data in the previous window. It would probably be implemented by adding code to the existing PING timer (which fires when we haven't *received* data recently, with the intention of provoking a PONG response from the other end). This code would check the last-sent timestamp and send a PONG if it was too old.

The purpose of this timer would be to keep our peer's disconnect- timer from firing, especially when the peer was busy sending us a large STRING token. If the token is large enough, the peer will not be able to get a PING through to us, so we won't know to send a PONG, and the peer might then believe that we've failed to respond (even though in fact we're still connected and happily receiving data). This false-disconnect would be the result of application-level messages not getting through (blocked by other app-level messages), even though the transport-level messages *were* getting through.
"	Brian Warner
27	Changelog doesn't appear in Ubuntu update manager	packaging	0.1.7	undecided	defect		new	2007-10-10T17:48:10-07:00	2007-10-10T20:06:25-07:00	It looks like what should be in changelog.Debian.gz is ending up in changelog.gz	Zandr
53	flogtool tail/dump need event filters	logging	0.2.5	undecided	defect		new	2008-03-24T15:21:47-07:00	2008-03-25T21:20:33-07:00	"There should be some kind of --filter option to remove events by facility or below a certain level.
"	Brian Warner
189	bad swissnum in logGathererFurl is hard to diagnose	error-handling	0.6.1	undecided	defect	zancas	new	2012-04-01T23:33:02-07:00	2012-04-01T23:33:02-07:00	"  If a request is submitted to a tub with an invalid Swissnum, the tub returns a 500 HTTP server error without further details.

  More informative error messages would be quite handy.  They'll be particularly useful in the case the allowed values of swissnums changes!"	zancas
198	improve handling of code errors during negotiation	negotiation	0.6.3	undecided	defect		new	2012-06-18T16:26:46-07:00	2012-06-18T16:28:28-07:00	"While working on #195, I tried to exercise the error-handling code by inserting {{{raise KeyError(""xyz"")}}} into the start of {{{negotiate.evaluateHello}}}, restarting a tahoe node with the modified code, then watch a flogtool-tail of a second node as it reconnected to the now-broken node. (both the second node and the flogtool process were started before breaking negotiate.py).

What I expected to see was a {{{RemoteNegotiationError}}} triggered by the {{{KeyError}}}. Instead, my local monitoring node got a {{{BananaError}}}, as it received the error block ({{{banana-decision-version: 1, error: internal server error see logs}}}) while it was expecting banana data.

I think this means the receiving code is jumping forward to {{{receive_phase=BANANA}}} too early. It might also mean that my code in {{{negotiationFailed}}} that tries to unpack a {{{RemoteNegotiationError}}} is unexercised. That code runs after all the necessary events have been eventual-sent, so it shouldn't break anything if it fails, but it'd be nice to capture remote errors usefully.
"	Brian Warner
254	"log message: ""pre-0.2.0 peer detected"" (when all peers are recent)"	negotiation	0.9.1	undecided	defect		new	2016-04-07T23:11:01-07:00	2016-04-07T23:11:01-07:00	"I'd enabled FLOGFILE= logging for a tahoe unit test run (specifically `allmydata.test.test_system.SystemTest.test_filesystem_with_cli_in_subprocess` from trunk, which is getting !DirtyReactorErrors against a wide variety of Foolscap versions), and noticed the following CURIOUS log message:

{{{
pre-0.2.0 peer detected (no my-incarnation or last-connection)
}}}

This is coming from `Negotiation.compareOfferAndExisting`, and looks like it's been happening for a while (I was able to see it with tahoe-trunk and foolscap-0.9.0).

I think this is a consequence of the TODO note just before the warning: `TODO: new servers send my-incarnation but not last-connection`.

The task is to figure out whether this warning should be displayed, and whether the related handle-old-connections code should be run, and fix things so that the warning is not displayed for modern peers. It might be appropriate to just delete that whole thing, since foolscap-0.2.0 was released over 8 years ago.
"	Brian Warner
19	consider allowing access to the Tub's private SSL key for sealing/unsealing	unknown	0.1.5	undecided	enhancement		new	2007-08-28T21:10:44-07:00	2007-09-01T23:45:08-07:00	"I'm really not sure this is a good idea, but I figure it's worth discussing:

Since we have a private key inside the SSL certificate for the Tub, it might be useful to provide a way to use it to encrypt/decrypt/sign/verify things. This would let someone with access to the Tub prove that they have access to the Tub, by signing a challenge, for example.

The reason that I suspect this to be a bad idea is because I believe that any conceivable use case for this is already provided for by the references we currently have, and that making it easy for users to test things like ""who sent me this message"" is counter to the goal of encouraging the use of the object-capabilities model. For example, rather than writing an object which performs some action because the message was signed by some particular key, you should instead only give access to this object to the entity that you wish to be able to perform the action. This simplifies the case analysis and allows for delegation, which (in general) the holder of the capability is able to do anyways (via forwarding), so there's no point in trying to prohibit it.

Anyways, I'm trying to come up with some hypothetical use cases for this sort of functionality, and then identify how they could be accomodated using a more objcaps-oriented approach instead.
"	Brian Warner
54	flogtool tail/dump should have color-coded output for different tubids	logging	0.2.4	undecided	enhancement		new	2008-03-24T15:22:56-07:00	2008-07-01T18:32:31-07:00	"if there are multiple sources in the logfile (tubids, or different incarnation records), there should be an option to color-code the output according to which program created the message. This suggests that 'flogtool tail FURL1 FURL2...' might be a good idea, to follow multiple programs at once.
"	Brian Warner
68	compute tubid from the root of a certificate chain	usability	0.2.5	undecided	enhancement		new	2008-06-16T12:06:46-07:00	2009-05-19T15:46:45-07:00	"Somewhere I have a ""key-management"" document, describing a new way to deal with certificates. The idea is to use a certificate chain instead of a single cert, and to compute the tubid from the root of the chain. This would allow key-rotation.
"	Brian Warner
69	build cred for foolscap?	usability	0.2.5	undecided	enhancement		new	2008-06-16T12:10:01-07:00	2009-05-19T15:44:51-07:00	"We've considered building a ""cred"" layer for Foolscap in the past. I don't personally have much of a use for such a thing: the obj-cap nature of Foolscap fits my current style of programming much better than Cred ever did. But some folks might find benefit in such a thing, particularly for porting older code from PB over to Foolscap.

http://twistedmatrix.com/trac/ticket/712 was the old Twisted/pb2 ticket.
"	Brian Warner
91	show overload-caused gaps in the event log	logging	0.3.0	undecided	enhancement		new	2008-08-21T15:46:16-07:00	2008-08-21T15:46:26-07:00	"When a log-gatherer gets overloaded, the sending application will drop log messages (to avoid unbounded memory usage). We can detect these in the recorded event stream by noticing non-sequential event numbers. 'flogtool dump' and 'flogtool web-viewer' should put a blank line between these events, to remind the user that there is a gap there.

This needs to take multiple-sources into account: only insert a gap if the higest seen event number for that particular source is less than one minus the new number.
"	Brian Warner
151	Accept I2P destinations	network	0.5.0	undecided	enhancement	duck	new	2010-03-27T14:31:23-07:00	2017-01-12T22:14:53-08:00	"To be able to use I2P with Foolscap (see #150 and [http://tahoe-lafs.org/trac/tahoe-lafs/ticket/1007 Tahoe-LAFS #1007], I have extended `decode_location_hint` to accept I2P base32 destinations. Since I2P destinations can't have a port as part of the location, the current IPv4 regex doesn't work.

These I2P destinations look like this:
{{{
3u2mqm3mvcyc27yliky3xnr4khpgfd4eeadhwwjneaqhj25a65ua.b32.i2p
}}}

They have the format: `base32_encode(sha256_hash) + "".b32.i2p""`"	duck
168	keep last Incident in RAM to help debug disk-full conditions	logging	0.5.1	undecided	enhancement		new	2010-12-05T13:12:06-08:00	2011-01-15T13:55:52-08:00	"As mentioned in #144, it'd be nice if disk-full situations were easier to debug. The idea would be to record the last Incident as a single string (serialized+compressed) in memory, and to make in-memory Incidents available to the incident-gatherer (just like on-disk Incident files are). It might also be useful to make {{{flogtool tail}}} have a mode or a message to indicate that an Incident is available, and to fetch its contents (since launching an incident-gatherer just to fetch a single Incident is a hassle).

We should think about when this would actually be useful, though. I think that mostly we need to remember that a disk-full situation occurred, so we can rule out other weird problems.
"	Brian Warner
171	missing copyright headers	unknown	0.6.1	undecided	enhancement		new	2011-02-28T02:20:30-08:00	2011-10-08T13:35:38-07:00	"each file should have a header indicating under which license the source is published.

only foolscap/sslverify.py and misc/testutils/figleaf.py have such a header, all others do not.
Attached a licensecheck -r --copyright output."	Julian Taylor
264	use new IHandshakeListener	negotiation	0.12.0	undecided	task		new	2016-08-27T23:59:57-07:00	2016-08-27T23:59:57-07:00	"Twisted-16.4.0 was just released, and includes an interface named `IHandshakeListener`. When a protocol implements this, it's `handshakeCompleted` method will be called just after TLS negotiation finishes.

This might simplify some code in negotiate.py.
"	Brian Warner
