User visible changes in Foolscap (aka newpb/pb2).           -*- outline -*-

* Release 0.2.3 (24 Dec 2007)

** Compatibilty

All releases between 0.1.3 and 0.2.3 (inclusive) are fully wire-compatible.

** Bug Fixes

RemoteReference.getSturdyRef() didn't work (due to bitrot). It has been
fixed.

** foolscap.logging Changes

This release is mostly about flogging improvements: some bugs and misfeatures
were fixed:

*** tolerate '%' in log message format strings

Dictionary-style kwarg formatting is now done with a twisted-style style
format= argument instead of happening implicitly. That means the acceptable
ways to call foolscap.logging.log.msg are:

 log.msg("plain string")
 log.msg("no args means use 0% interpolation")
 log.msg("pre-interpolated: %d apples" % apples)
 log.msg("posargs: %d apples and %d oranges", apples, oranges)
 log.msg(format="kwargs: %(numapples)d apples", numapples=numapples)

The benefit of the latter two forms are that the arguments are recorded
separately in the event dictionary, so viewing tools can filter on the
structured data, think of something like:

  [e for e in allEvents if e.get("numapples",0) > 4]

*** log facility names are now dot-separated, to match stdlib logging
*** log levels are derived from numerical stdlib logging levels
*** $FLOGFILE to capture flog events during 'trial' runs

One challenge of the flogging system is that, once an application was changed
to write events to flogging instead of twisted's log, those events do not
show up in the normal places where twisted writes its logfiles. For full
applications this will be less of an issue, because application startup will
tell flogging where events should go (flogging is intended to supplant
twisted logging for these applications). But for events emitted during unit
tests, such as those driven by Trial, these events would get lost.

To address this problem, the 0.2.3 flogging code looks for the "FLOGFILE"
environment variable at import time. This specifies a filename where flog
events (a series of pickled event dictionaries) should be written. The file
is opened at import time, events are written during the lifetime of the
process, then the file is closed at shutdown using a Twisted "system event
trigger" (which happens to be enough to work properly under Trial: other
environments may not work so well). If the FLOGFILE filename ends in .bz2,
the event pickles will be compressed, which is highly recommended because it
can result in a 30x space savings (and e.g. the Tahoe unit test run results
in 90MB of uncompressed events). All 'flogtool' modes know how to handle a
.bz2 compressed flogfile as well as an uncompressed one.

The "FLOGTWISTED" environment variable, if set, will cause this same code to
bridge twisted log messages into the flogfile. This makes it easier to see
the relative ordering of Twisted actions and foolscap/application events.
(without this it becomes very hard to correlate the two sources of events).

The "FLOGLEVEL" variable specifies a minimum severity level that will be put
into the flogfile. This defaults to "1", which puts pretty much everything
into the file. The idea is that, for tests, you might as well record
everything, and use the filtering tools to control the display and isolate
the important events. Real applications will use more sophisticated tradeoffs
between disk space and interpretation effort.

The recommended way to run Trial on a unit test suite for an application that
uses Foolscap is:

 FLOGFILE=flog.out FLOGTWISTED=1 trial PACKAGENAME

Note that the logfile cannot be placed in _trial_temp/, because trial deletes
that directory after flogging creates the logfile, so the logfile would get
deleted too. Also note that the file created by $FLOGFILE is truncated on
each run of the program.


* Release 0.2.2 (12 Dec 2007)

** Compatibilty

All releases between 0.1.3 and 0.2.2 (inclusive) are fully wire-compatible.
New (optional) negotiation parameters were added in 0.2.1 (really in 0.2.0).

** Bug Fixes

The new duplicate-connection handling code in 0.2.1 was broken. This release
probably fixes it.

There were other bugs in 0.2.1 which were triggered when a duplicate
connection was shut down, causing remote calls to never be retired, which
would also prevent the Reconnector from doing its job. These should be fixed
now.

** Other Changes

Foolscap's connection-negotiation mechanism has been modified to use foolscap
logging ("flog") instead of twisted.log .

Setting the FLOGFILE= environment variable will cause a Foolscap-using
program to write pickled log events to a file of that name. This is
particularly useful when you want to record log events during 'trial' unit
test run. The normal API for setting this file will be added later. The
FLOGTWISTED= environment variable will cause the creation of a twisted.log
bridge, to copy all events from the twisted log into the foolscap log.

The 'flogtool web-view' mode has been enhanced to color-code events according
to their severity, and to format Failure tracebacks in a more-readable way.


* Release 0.2.1 (10 Dec 2007)

** Compatibilty

All releases between 0.1.3 and 0.2.1 (inclusive) are fully wire-compatible.
0.2.1 introduces some new negotiation parameters (to handle duplicate
connections better), but these are ignored by older versions, and their lack
is tolerated by 0.2.1 .

** New Features

*** new logging support

Foolscap is slowly acquiring advanced diagnostic event-logging features. See
doc/logging.xhtml for the philosophy and design of this logging system. 0.2.1
contains the first few pieces, including a tool named bin/flogtool that can
be used to watch events on a running system, or gather events from multiple
applications into a single place for later analysis. This support is still
preliminary, and many of the controls and interfaces described in that
document are not yet implemented.

*** better handling of duplicate connections / NAT problems

The connection-management code in 0.1.7 and earlier interacted badly with
programs that run behind NAT boxes (especially those with aggressive
connection timeouts) or on laptops which get unplugged from the network
abruptly. Foolscap seeks to avoid duplicate connections, and various
situtations could cause the two ends to disagree about the viability of any
given connection. The net result (no pun intended) was that a client might
have to wait up to 35 minutes (depending upon various timeout values) before
being able to reestablish a connection, and the Reconnector's exponential
backoff strategy could easily push this into 90 minutes of downtime.

0.2.1 uses a different approach to accomplish duplicate-suppression, and
should provide much faster reconnection after netquakes. To benefit from
this, both ends must be running foolscap-0.2.1 or newer, however there is an
additional setting (not enabled by default) to improve the behavior of
pre-0.2.1 clients: tub.setOption("handle-old-duplicate-connections", True).

*** new Reconnector methods

The Reconnector object (as returned by Tub.connectTo) now has three utility
methods that may be useful during debugging. reset() drops the backoff timer
down to one second, causing the Reconnector to reconnect quickly: you could
use this to avoid an hour-long delay if you've just restarted the server or
re-enabled a network connection that was the cause of the earlier connection
failures. getDelayUntilNextAttempt() returns the number of seconds remaining
until the next connection attempt. And getLastFailure() returns a Failure
object explaining why the last connection attempt failed, which may be a
useful diagnostic in trying to resolve the connection problems.

** Bug Fixes

There were other minor changes: an OS-X unit test failure was resolved,
CopiedFailures are serialized in a way that doesn't cause constraint
violations, and the figleaf code-coverage tools (used by foolscap developers
to measure how well the unit tests exercise the code base) have been improved
(including an emacs code-used/unused annotation tool).


* Release 0.2.0 (10 Dec 2007)

This release had a fatal bug that wasn't caught by the unit tests, and was
superseded almost immediately by 0.2.1 .


* Release 0.1.7 (24 Sep 2007)

** Compatibility

All releases between 0.1.3 and 0.1.7 (inclusive) are fully wire-compatible.

** Bug Fixes

*** slow remote_ methods shouldn't delay subsequent messages (#25)

In earlier releases, a remote_ method which runs slowly (i.e. one which
returns a Deferred and does not fire it right away) would have the
unfortunate side-effect of delaying all subsequent calls from the same
Broker. Those later calls would not be delivered until the first message had
completed processing. If, for some reason, that Deferred were never fired,
this Foolscap bug would prevent any other remote_ methods from ever being
called.

This is not how Foolscap's message-ordering logic is designed to work.
Foolscap guarantees in-order *delivery* of messages, but does not require
that they be completed/retired in that same order.

This has now been fixed. The invocation of remote_* is done in-order: any
further sequencing is up to the receiving application.

For example, in the following code:

 sender:
   rref.callRemote("quick", 1)
   rref.callRemote("slow", 2)
   rref.callRemote("quick", 3)

 receiver:
   def remote_quick(self, num):
     print num
   def remote_slow(self, num):
     print num
     d = Deferred()
     def _done():
       print "DONE"
       d.callback(None)
     reactor.callLater(5.0, _done)
     return d

The intended order of printed messages is 1,2,3,DONE . This bug caused the
ordering to be 1,2,DONE,3 instead.

*** default size limits removed from all Constraints (#26)

Constraints in Foolscap serve two purposes: DoS attack mitigation, and strong
typing on remote interfaces to help developers find problems sooner. To
support the former, most container-based Constraints had default size limits.
For example, the default StringConstraint enforced a maximum length of 1000
characters, and the ListConstraint had a maxLength of 30 elements.

In practice, these limits turned out to be more surprising than helpful.
Applications which worked fine in testing would mysteriously break when
subjected to data that was larger than expected. Developers who used
Constraints for their type-checking properties were surprised to discover
that they were getting size limitations as well. In addition, the
DoS-mitigation code in foolscap is not yet complete, so the cost/benefit
ratio of this feature was dubious.

For these reasons, all default size limits have been removed from this
release. The 0.1.7 StringConstraint() schema is equivalent to the 0.1.6
StringConstraint(maxLength=None) version. To get the 0.1.6 behavior, use
StringConstraint(maxLength=1000). The same is true for ListConstraint,
DictConstraint, SetConstraint, and UnicodeConstraint.

** New features

*** Tub.registerReference(furlFile=)

In the spirit of Tub(certFile=), a new argument was added to
registerReference that instructs Foolscap to find and store a
randomly-generated name in the given file. This makes it convenient to allow
subsequent invocations of the same program to use the same stable (yet
unguessable) identifier for long-lived objects. For example, a Foolscap-based
server can make its Server object available under the same FURL from one run
of the program to the next with the following startup code:

  s = MyServer()
  furl = tub.registerReference(s, furlFile=os.path.join(basedir, "server"))

If the furlFile= exists before registerReference is called, a FURL will be
read from it, and a name extracted to use for the object. If not, the file
will be created and filled with a FURL that uses a randomly-generated name.

*** Tub.serialize()

Work is ongoing to implement E-style cryptographic Sealers/Unsealers in
Foolscap (see ticket #20). Part of that work has made it into this release.
The new Tub.serialize() and Tub.unserialize() methods provide access to the
underlying object-graph-serialization code. Normally this code is used to
construct a bytestream that is immediately sent over an SSL connection to a
remote host; these methods return a string instead. Eventually, a Sealer will
return an encrypted version of this string, and the corresponding Unsealer
will take the encrypted string and build a new object graph.

The foolscap.serialize() and .unserialize() functions have existed for a
while. The new Tub.serialize()/.unserialize() methods are special in that you
can serialize Referenceables and RemoteReferences. These are encoded with
their FURLs, so that the unserializing Tub can establish a new live reference
to their targets. foolscap.serialize() cannot handle referenceables.

Note that both Tub.serialize() and foolscap.serialize() are currently
"unsafe", in that they will serialize (and unserialize!) instances of
arbitrary classes, much like the stdlib pickle module. This is a significant
security problem, as this results in arbitrary object constructors being
executed during deserialization. In a future release of Foolscap, this mode
of operation will *not* be the default, and a special argument will have to
be passed to enable such behavior.


** Other Improvements

When methods fail, the error messages that get logged have been improved. The
new messages contain information about which source+dest TubIDs were
involved, and which RemoteInterface and method name was being used.

A new internal method named Tub.debug_listBrokers() will provide information
on which messages are waiting for delivery, either inbound or outbound. It is
intended to help diagnose problems like #25. Any message which remains
unresolved for a significant amount of time is likely to indicate a problem.


* Release 0.1.6 (02 Sep 2007)

** Compatibility

All releases between 0.1.3 and 0.1.6 (inclusive) are fully wire-compatible.

** Bug Fixes

Using a schema of ChoiceOf(StringConstraint(2000), None) would fail to accept
strings between 1000 and 2000 bytes: it would accept a short string, or None,
but not a long string. This has been fixed. ChoiceOf() remains a troublesome
constraint: having it is awfully nice, and things like ChoiceOf(str,None)
seem to work, but it is unreliable. Using ChoiceOf with non-terminal children
is not recommended (the garden-path problem is unlikely to be easy to solve):
schemas are not regular expressions.

The debian packaging rules have been fixed. The ones in 0.1.5 failed to run
because of some renamed documentation files.

** Minor Fixes

Several minor documentation errors have been corrected. A new 'make api-docs'
target has been added to run epydoc and build HTML versions of the API
documentation.

When a remote method fails and needs to send a traceback over the wire, and
when the traceback is too large, trim out the middle rather than the end,
since usually it's the beginning and the end that are the most useful.


* Release 0.1.5 (07 Aug 2007)

** Compatibility

This release is fully compatible with 0.1.4 and 0.1.3 .

** CopiedFailure improvements

When a remote method call fails, the calling side gets back a CopiedFailure
instance. These instances now behave slightly more like the (local) Failure
objects that they are intended to mirror, in that .type now behaves much like
the original class. This should allow trial tests which result in a
CopiedFailure to be logged without exploding. In addition, chained failures
(where A calls B, and B calls C, and C fails, so C's Failure is eventually
returned back to A) should work correctly now.

** Gift improvements

Gifts inside return values should properly stall the delivery of the response
until the gift is resolved. Gifts in all sorts of containers should work
properly now. Gifts which cannot be resolved successfully (either because the
hosting Tub cannot be reached, or because the name cannot be found) will now
cause a proper error rather than hanging forever. Unresolvable gifts in
method arguments will cause the message to not be delivered and an error to
be returned to the caller. Unresolvable gifts in method return values will
cause the caller to receive an error.

** IRemoteReference() adapter

The IRemoteReference() interface now has an adapter from Referenceable which
creates a wrapper that enables the use of callRemote() and other
IRemoteReference methods on a local object.

The situation where this might be useful is when you have a central
introducer and a bunch of clients, and the clients are introducing themselves
to each other (to create a fully-connected mesh), and the introductions are
using live references (i.e. Gifts), then when a specific client learns about
itself from the introducer, that client will receive a local object instead
of a RemoteReference. Each client will wind up with n-1 RemoteReferences and
a single local object.

This adapter allows the client to treat all these introductions as equal. A
client that wishes to send a message to everyone it's been introduced to
(including itself) can use:

  for i in introductions:
    IRemoteReference(i).callRemote("hello", args)

In the future, if we implement coercing Guards (instead of
compliance-asserting Constraints), then IRemoteReference will be useful as a
guard on methods that want to insure that they can do callRemote (and
notifyOnDisconnect, etc) on their argument.

** Tub.registerNameLookupHandler

This method allows a one-argument name-lookup callable to be attached to the
Tub. This augments the table maintained by Tub.registerReference, allowing
Referenceables to be created on the fly, or persisted/retrieved on disk
instead of requiring all of them to be generated and registered at startup.


* Release 0.1.4 (14 May 2007)

** Compatibility

This release is fully compatible with 0.1.3 .

** getReference/connectTo can be called before Tub.startService()

The Tub.startService changes that were suggested in the 0.1.3 release notes
have been implemented. Calling getReference() or connectTo() before the Tub
has been started is now allowed, however no action will take place until the
Tub is running. Don't forget to start the Tub, or you'll be left wondering
why your Deferred or callback is never fired. (A log message is emitted when
these calls are made before the Tub is started, in the hopes of helping
developers find this mistake faster).

** constraint improvements

The RIFoo -style constraint now accepts gifts (third-party references). This
also means that using RIFoo on the outbound side will accept either a
Referenceable that implements the given RemoteInterface or a RemoteReference
that points to a Referenceable that implements the given RemoteInterface.
There is a situation (sending a RemoteReference back to its owner) that will
pass the outbound constraint but be rejected by the inbound constraint on the
other end. It remains to be seen how this will be fixed.

** foolscap now deserializes into python2.4-native 'set' and 'frozenset' types

Since Foolscap is dependent upon python2.4 or newer anyways, it now
unconditionally creates built-in 'set' and 'frozenset' instances when
deserializing 'set'/'immutable-set' banana sequences. The pre-python2.4
'sets' module has non-built-in set classes named sets.Set and
sets.ImmutableSet, and these are serialized just like the built-in forms.

Unfortunately this means that Set and ImmutableSet will not survive a
round-trip: they'll be turned into set and frozenset, respectively. Worse
yet, 'set' and 'sets.Set' are not entirely compatible. This may cause a
problem for older applications that were written to be compatible with both
python-2.3 and python-2.4 (by using sets.Set/sets.ImmutableSet), for which
the compatibility code is still in place (i.e. they are not using
set/frozenset). These applications may experience problems when set objects
that traverse the wire via Foolscap are brought into close proximity with set
objects that remained local. This is unfortunate, but it's the cleanest way
to support modern applications that use the native types exclusively.

** bug fixes

Gifts inside containers (lists, tuples, dicts, sets) were broken: the target
method was frequently invoked before the gift had properly resolved into a
RemoteReference. Constraints involving gifts inside containers were broken
too. The constraints may be too loose right now, but I don't think they
should cause false negatives.

The unused SturdyRef.asLiveRef method was removed, since it didn't work
anyways.

** terminology shift: FURL

The preferred name for the sort of URL that you get back from
registerReference (and hand to getReference or connectTo) has changed from
"PB URL" to "FURL" (short for Foolscap URL). They still start with 'pb:',
however. Documentation is slowly being changed to use this term.


* Release 0.1.3 (02 May 2007)

** Incompatibility Warning

The 'keepalive' feature described below adds a new pair of banana tokens,
PING and PONG, which introduces a compatibility break between 0.1.2 and 0.1.3
. Older versions would throw an error upon receipt of a PING token, so the
version-negotiation mechanism is used to prevent banana-v2 (0.1.2) peers from
connecting to banana-v3 (0.1.3+) peers. Our negotiation mechanism would make
it possible to detect the older (v2) peer and refrain from using PINGs, but
that has not been done for this release.

** Tubs must be running before use

Tubs are twisted.application.service.Service instances, and as such have a
clear distinction between "running" and "not running" states. Tubs are
started by calling startService(), or by attaching them to a running service,
or by starting the service that they are already attached to. The design rule
in operation here is that Tubs are not allowed to perform network IO until
they are running.

This rule was not enforced completely in 0.1.2, and calls to
getReference()/connectTo() that occurred before the Tub was started would
proceed normally (initiating a TCP connection, etc). Starting with 0.1.3,
this rule *is* enforced. For now, that means that you must start the Tub
before calling either of these methods, or you'll get an exception. In a
future release, that may be changed to allow these early calls, and queue or
otherwise defer the network IO until the Tub is eventually started. (the
biggest issue is how to warn users who forget to start the Tub, since in the
face of such a bug the getReference will simply never complete).

** Keepalives

Tubs now keep track of how long a connection has been idle, and will send a
few bytes (a PING of the other end) if no other traffic has been seen for
roughly 4 to 8 minutes. This serves two purposes. The first is to convince an
intervening NAT box that the connection is still in use, to prevent it from
discarding the connection's table entry, since that would block any further
traffic. The second is to accelerate the detection of such blocked
connections, specifically to reduce the size of a window of buggy behavior in
Foolscap's duplicate-connection detection/suppression code.

This problem arises when client A (behind a low-end NAT box) connects to
server B, perhaps using connectTo(). The first connection works fine, and is
used for a while. Then, for whatever reason, A and B are silent for a long
time (perhaps as short as 20 minutes, depending upon the NAT box). During
this silence, A's NAT box thinks the connection is no longer in use and drops
the address-translation table entry. Now suppose that A suddenly decides to
talk to B. If the NAT box creates a new entry (with a new outbound port
number), the packets that arrive on B will be rejected, since they do not
match any existing TCP connections. A sees these rejected packets, breaks the
TCP connection, and the Reconnector initiates a new connection. Meanwhile, B
has no idea that anything has gone wrong. When the second connection reaches
B, it thinks this is a duplicate connection from A, and that it already has a
perfectly functional (albeit quiet) connection for that TubID, so it rejects
the connection during the negotiation phase. A sees this rejection and
schedules a new attempt, which ends in the same result. This has the
potential to prevent hosts behind NAT boxes from ever reconnecting to the
other end, at least until the the program at the far end is restarted, or it
happens to try to send some traffic of its own.

The same problem can occur if a laptop is abruptly shut down, or unplugged
from the network, then moved to a different network. Similar problems have
been seen with virtual machine instances that were suspended and moved to a
different network.

The longer-term fix for this is a deep change to the way duplicate
connections (and cross-connect race conditions) are handled. The keepalives,
however, mean that both sides are continually checking to see that the
connection is still usable, enabling TCP to break the connection once the
keepalives go unacknowledged for a certain amount of time. The default
keepalive timer is 4 minutes, and due to the way it is implemented this means
that no more than 8 minutes will pass without some traffic being sent. TCP
tends to time out connections after perhaps 15 minutes of unacknowledged
traffic, which means that the window of unconnectability is probably reduced
from infinity down to about 25 minutes.

The keepalive-sending timer defaults to 4 minutes, and can be changed by
calling tub.setOption("keepaliveTimeout", seconds).

In addition, an explicit disconnect timer can be enabled, which tells
Foolscap to drop the connection unless traffic has been seen within some
minimum span of time. This timer can be set by calling
tub.setOption("disconnectTimeout", seconds). Obviously it should be set to a
higher value than the keepaliveTimeout. This will close connections faster
than TCP will. Both TCP disconnects and the ones triggered by this
disconnectTimeout run the risk of false negatives, of course, in the face of
unreliable networks.

** New constraints

When a tuple appears in a method constraint specification, it now maps to an
actual TupleOf constraint. Previously they mapped to a ChoiceOf constraint.
In practice, TupleOf appears to be much more useful, and thus better
deserving of the shortcut.

For example, a method defined as follows:

  def get_employee(idnumber=int):
      return (str, int, int)  # (name, room_number, age)

can only return a three-element tuple, in which the first element is a string
(specifically it conforms to a default StringConstraint), and the second two
elements are ints (which conform to a default IntegerConstraint, which means
it fits in a 32-bit signed twos-complement value).

To specify a constraint that can accept alternatives, use ChoiceOf:

  def get_record(key=str):
      """Return the record (a string) if it is present, or None if
          it is not present."""
      return ChoiceOf(str, None)

UnicodeConstraint has been added, with minLength=, maxLength=, and regexp=
arguments.

The previous StringConstraint has been renamed to ByteStringConstraint (for
accuracy), and it is defined to *only* accept string objects (not unicode
objects). 'StringConstraint' itself remains equivalent to
ByteStringConstraint for now, but in the future it may be redefined to be a
constraint that accepts both bytestrings and unicode objects. To accomplish
the bytestring-or-unicode constraint now, you might try
schema.AnyStringConstraint, but it has not been fully tested, and might not
work at all.

** Bugfixes

Errors during negotiation were sometimes delivered in the wrong format,
resulting in a "token prefix is limited to 64 bytes" error message. Several
error messages (including that one) have been improved to give developers a
better chance of determining where the actual problem lies.

RemoteReference.notifyOnDisconnect was buggy when called on a reference that
was already broken: it failed to fire the callback. Now it fires the callback
soon (using an eventual-send). This should remove a race condition from
connectTo+notifyOnDisconnect sequences and allow them to operate reliably.
notifyOnDisconnect() is now tolerant of attempts to remove something twice,
which should make it easier to use safely.

Remote methods which raise string exceptions should no longer cause Foolscap
to explode. These sorts of exceptions are deprecated, of course, and you
shouldn't use them, but at least they won't break Foolscap.

The Reconnector class (accessed by tub.connectTo) was not correctly
reconnecting in certain cases (which appeared to be particularly common on
windows). This should be fixed now.

CopyableSlicer did not work inside containers when streaming was enabled.
Thanks to iacovou-AT-gmail.com for spotting this one.

** Bugs not fixed

Some bugs were identified and characterized but *not* fixed in this release

*** RemoteInterfaces aren't defaulting to fully-qualified classnames

When defining a RemoteInterface, you can specify its name with
__remote_name__, or you can allow it to use the default name. Unfortunately,
the default name is only the *local* name of the class, not the
fully-qualified name, which means that if you have an RIFoo in two different
.py files, they will wind up with the same name (which will cause an error on
import, since all RemoteInterfaces known to a Foolscap-using program must
have unique names).

It turns out that it is rather difficult to determine the fully-qualified
name of the RemoteInterface class early enough to be helpful. The workaround
is to always add a __remote_name__ to your RemoteInterface classes. The
recommendation is to use a globally-unique string, like a URI that includes
your organization's DNS name.

*** Constraints aren't constraining inbound tokens well enough

Constraints (and the RemoteInterfaces they live inside) serve three purposes.
The primary one is as documentation, describing how remotely-accessible
objects behave. The second purpose is to enforce that documentation, by
inspecting arguments (and return values) before invoking the method, as a
form of precondition checking. The third is to mitigate denial-of-service
attacks, in which an attacker sends so much data (or carefully crafted data)
that the receiving program runs out of memory or stack space.

It looks like several constraints are not correctly paying attention to the
tokens as they arrive over the wire, such that the third purpose is not being
achieved. Hopefully this will be fixed in a later release. Application code
can be unaware of this change, since the constraints are still being applied
to inbound arguments before they are passed to the method. Continue to use
RemoteInterfaces as usual, just be aware that you are not yet protected
against certain DoS attacks.

** Use os.urandom instead of falling back to pycrypto

Once upon a time, when Foolscap was compatible with python2.3 (which lacks
os.urandom), we would try to use PyCrypto's random-number-generation routines
when creating unguessable object identifiers (aka "SwissNumbers"). Now that
we require python2.4 or later, this fallback has been removed, eliminating
the last reference to pycrypto within the Foolscap source tree.


* Release 0.1.2 (04 Apr 2007)

** Bugfixes

Yesterday's release had a bug in the new SetConstraint which rendered it
completely unusable. This has been fixed, along with some new tests.

** More debian packaging

Some control scripts were added to make it easier to create debian packages
for the Ubuntu 'edgy' and 'feisty' distributions.


* Release 0.1.1 (03 Apr 2007)

** Incompatibility Warning

Because of the technique used to implement callRemoteOnly() (specifically the
commandeering of reqID=0), this release is not compatible with the previous
release. The protocol negotiation version numbers have been bumped to avoid
confusion, meaning that 0.1.0 Tubs will refuse to connect to 0.1.1 Tubs, and
vice versa. Be aware that the errors reported when this occurs may not be
ideal, in particular I think the "reconnector" (tub.connectTo) might not log
this sort of connection failure in a very useful way.

** changes to Constraints

Method specifications inside RemoteInterfaces can now accept or return
'Referenceable' to indicate that they will accept a Referenceable of any
sort. Likewise, they can use something like 'RIFoo' to indicate that they
want a Referenceable or RemoteReference that implements RIFoo. Note that this
restriction does not quite nail down the directionality: in particular there
is not yet a way to specify that the method will only accept a Referenceable
and not a RemoteReference. I'm waiting to see if such a thing is actually
useful before implementing it. As an example:

class RIUser(RemoteInterface):
    def get_age():
        return int

class RIUserListing(RemoteInterface):
    def get_user(name=str):
        """Get the User object for a given name."""
        return RIUser

In addition, several constraints have been enhanced. StringConstraint and
ListConstraint now accept a minLength= argument, and StringConstraint also
takes a regular expression to apply to the string it inspects (the regexp can
either be passed as a string or as the output of re.compile()). There is a
new SetConstraint object, with 'SetOf' as a short alias. Some examples:

HexIdConstraint = StringConstraint(minLength=20, maxLength=20,
                                   regexp=r'[\dA-Fa-f]+')
class RITable(RemoteInterface):
    def get_users_by_id(id=HexIdConstraint):
        """Get a set of User objects; all will have the same ID number."""
        return SetOf(RIUser, maxLength=200)

These constraints should be imported from foolscap.schema . Once the
constraint interface is stabilized and documented, these classes will
probably be moved into foolscap/__init__.py so that you can just do 'from
foolscap import SetOf', etc.

*** UnconstrainedMethod

To disable schema checking for a specific method, use UnconstrainedMethod in
the RemoteInterface definition:

from foolscap.remoteinterface import UnconstrainedMethod

class RIUse(RemoteInterface):
    def set_phone_number(area_code=int, number=int):
        return bool
    set_arbitrary_data = UnconstrainedMethod

The schema-checking code will allow any sorts of arguments through to this
remote method, and allow any return value. This is like schema.Any(), but for
entire methods instead of just specific values. Obviously, using this defeats
te whole purpose of schema checking, but in some circumstances it might be
preferable to allow one or two unconstrained methods rather than resorting to
leaving the entire class left unconstrained (by not declaring a
RemoteInterface at all).

*** internal schema implementation changes

Constraints underwent a massive internal refactoring in this release, to
avoid a number of messy circular imports. The new way to convert a
"shorthand" description (like 'str') into an actual constraint object (like
StringConstraint) is to adapt it to IConstraint.

In addition, all constraints were moved closer to their associated
slicer/unslicer definitions. For example, SetConstraint is defined in
foolscap.slicers.set, right next to SetSlicer and SetUnslicer. The
constraints for basic tokens (like lists and ints) live in
foolscap.constraint .

** callRemoteOnly

A new "fire and forget" API was added to tell Foolscap that you want to send
a message to the remote end, but do not care when or even whether it arrives.
These messages are guaranteed to not fire an errback if the connection is
already lost (DeadReferenceError) or if the connection is lost before the
message is delivered or the response comes back (ConnectionLost). At present,
this no-error philosophy is so strong that even schema Violation exceptions
are suppressed, and the callRemoteOnly() method always returns None instead
of a Deferred. This last part might change in the future.

This is most useful for messages that are tightly coupled to the connection
itself, such that if the connection is lost, then it won't matter whether the
message was received or not. If the only state that the message modifies is
both scoped to the connection (i.e. not used anywhere else in the receiving
application) and only affects *inbound* data, then callRemoteOnly might be
useful. It may involve less error-checking code on the senders side, and it
may involve fewer round trips (since no response will be generated when the
message is delivered).

As a contrived example, a message which informs the far end that all
subsequent messages on this connection will sent entirely in uppercase (such
that the recipient should apply some sort of filter to them) would be
suitable for callRemoteOnly. The sender does not need to know exactly when
the message has been received, since Foolscap guarantees that all
subsequently sent messages will be delivered *after* the 'SetUpperCase'
message. And, the sender does not need to know whether the connection was
lost before or after the receipt of the message, since the establishment of a
new connection will reset this 'uppercase' flag back to some known
initial-contact state.

  rref.callRemoteOnly("set_uppercase", True)  # returns None!

This method is intended to parallel the 'deliverOnly' method used in E's
CapTP protocol. It is also used (or will be used) in some internal Foolscap
messages to reduce unnecessary network traffic.

** new Slicers: builtin set/frozenset

Code has been added to allow Foolscap to handle the built-in 'set' and
'frozenset' types that were introduced in python-2.4 . The wire protocol does
not distinguish between 'set' and 'sets.Set', nor between 'frozenset' and
'sets.ImmutableSet'.

For the sake of compatibility, everything that comes out of the deserializer
uses the pre-2.4 'sets' module. Unfortunately that means that a 'set' sent
into a Foolscap connection will come back out as a 'sets.Set'. 'set' and
'sets.Set' are not entirely interoperable, and concise things like 'added =
new_things - old_things' will not work if the objects are of different types
(but note that things like 'added = new_things.difference(old_things)' *do*
work).

The current workaround is for remote methods to coerce everything to a
locally-preferred form before use. Better solutions to this are still being
sought. The most promising approach is for Foolscap to unconditionally
deserialize to the builtin types on python >= 2.4, but then an application
which works fine on 2.3 (by using sets.Set) will fail when moved to 2.4 .

** Tub.stopService now indicates full connection shutdown, helping Trial tests

Like all twisted.application.service.MultiService instances, the
Tub.stopService() method returns a Deferred that indicates when shutdown has
finished. Previously, this Deferred could fire a bit early, when network
connections were still trying to deliver the last bits of data. This caused
problems with the Trial unit test framework, which insist upon having a clean
reactor between tests.

Trial test writers who use Foolscap should include the following sequence in
their twisted.trial.unittest.TestCase.tearDown() methods:

def tearDown(self):
    from foolscap.eventual import flushEventualQueue
    d = tub.stopService()
    d.addCallback(flushEventualQueue)
    return d

This will insure that all network activity is complete, and that all message
deliveries thus triggered have been retired. This activity includes any
outbound connections that were initiated (but not completed, or finished
negotiating), as well as any listening sockets.

The only remaining problem I've seen so far is with reactor.resolve(), which
is used to translate DNS names into addresses, and has a window during which
you can shut down the Tub and it will leave a cleanup timer lying around. The
only solution I've found is to avoid using DNS names in URLs. Of course for
real applications this does not matter: it only makes a difference in Trial
unit tests which are making heavy use of short-lived Tubs and connections.


* Release 0.1.0 (15 Mar 2007)

** usability improvements

*** Tubs now have a certFile= argument

A certFile= argument has been added to the Tub constructor to allow the Tub
to manage its own certificates. This argument provides a filename where the
Tub should read or write its certificate. If the file exists, the Tub will
read the certificate data from there. If not, the Tub will generate a new
certificate and write it to the file.

The idea is that you can point certFile= at a persistent location on disk,
perhaps in the application's configuration or preferences subdirectory, and
then not need to distinguish between the first time the Tub has been created
and later invocations. This allows the Tub's identity (derived from the
certificate) to remain stable from one invocation to the next. The related
problem of how to make (unguessable) object names persistent from one program
run to the next is still outstanding, but I expect to implement something
similar in the future (some sort of file to which object names are written
and read later).

certFile= is meant to be used somewhat like this:

 where = os.path.expanduser("~/.myapp.cert")
 t = Tub(certFile=where)
 t.registerReference(obj) # ...

*** All eventual-sends are retired on each reactor tick, not just one.

Applications which make extensive use of the eventual-send operations (in
foolscap.eventual) will probably run more smoothly now. In previous releases,
the _SimpleCallQueue class would only execute a single eventual-send call per
tick, then take care of all pending IO (and any pending timers) before
servicing the next eventual-send. This could probably lead to starvation, as
those eventual-sends might generate more work (and cause more network IO),
which could cause the event queue to grow without bound. The new approach
finishes as much eventual-send work as possible before accepting any IO. Any
new eventual-sends which are queued during the current tick will be put off
until the next tick, but everything which was queued before the current tick
will be retired in the current tick.

** bug fixes

*** Tub certificates can now be used the moment they are created

In previous releases, Tubs were only willing to accept SSL certificates that
created before the moment of checking. If two systems A and B had
unsynchronized clocks, and a Foolscap-using application on A was run for the
first time to connect to B (thus creating a new SSL certificate), system B
might reject the certificate because it looks like it comes from the future.

This problem is endemic in systems which attempt to use the passage of time
as a form of revocation. For now at least, to resolve the practical problem
of certificates generated on demand and used by systems with unsynchronized
clocks, Foolscap does not use certificate lifetimes, and will ignore
timestamps on the certificates it examines.


* Release 0.0.7 (16 Jan 2007)

** bug fixes

*** Tubs can now connect to themselves

In previous releases, Tubs were unable to connect to themselves: the
following code would fail (the negotiation would never complete, so the
connection attempt would eventually time out after about 30 seconds):

 url = mytub.registerReference(target)
 d = mytub.getReference(url)

In release 0.0.7, this has been fixed by catching this case and making it use
a special loopback transport (which serializes all messages but does not send
them over a wire). There may be still be problems with this code, in
particular connection shutdown is not completely tested and producer/consumer
code is completely untested.

*** Tubs can now getReference() the same URL multiple times

A bug was present in the RemoteReference-unslicing code which caused the
following code to fail:

 d = mytub.getReference(url)
 d.addCallback(lambda ref: mytub.getReference(url))

In particular, the second call to getReference() would return None rather
than the RemoteReference it was supposed to.

This bug has been fixed. If the previous RemoteReference is still alive, it
will be returned by the subsequent getReference() call. If it has been
garbage-collected, a new one will be created.

*** minor fixes

Negotiation errors (such as having incompatible versions of Foolscap on
either end of the wire) may be reported more usefully.

In certain circumstances, disconnecting the Tub service from a parent service
might have caused an exception before. It might behave better now.


* Release 0.0.6 (18 Dec 2006)

** INCOMPATIBLE PROTOCOL CHANGES

Version 0.0.6 will not interoperate with versions 0.0.5 or earlier, because
of changes to the negotiation process and the method-calling portion of the
main wire protocol. (you were warned :-). There are still more incompatible
changes to come in future versions as the feature set and protocol
stabilizes. Make sure you can upgrade both ends of the wire until a protocol
freeze has been declared.

*** Negotiation versions now specify a range, instead of a single number

The two ends of a connection will agree to use the highest mutually-supported
version. This approach should make it much easier to maintain backwards
compatibility in the future.

*** Negotiation now includes an initial VOCAB table

One of the outputs of connection negotiation is the initial table of VOCAB
tokens to use for abbreviating commonly-used strings into short tokens
(usually just 2 bytes). Both ends have the ability to modify this table at any
time, but by setting the initial table during negotiation we same some
protocol traffic. VOCAB-izing common strings (like 'list' and 'dict') have
the potential to compress wire traffic by maybe 50%.

*** remote methods now accept both positional and keyword arguments

Previously you had to use a RemoteInterface specification to be able to pass
positional arguments into callRemote(). (the RemoteInterface schema was used
to convert the positional arguments into keyword arguments before sending
them over the wire). In 0.0.6 you can pass both posargs and kwargs over the
wire, and the remote end will pass them directly to the target method. When
schemas are in effect, the arguments you send will be mapped to the method's
named parameters in the same left-to-right way that python does it. This
should make it easier to port oldpb code to use Foolscap, since you don't
have to rewrite everything to use kwargs exclusively.

** Schemas now allow =None and =RIFoo

You can use 'None' in a method schema to indicate that the argument or return
value must be None. This is useful for methods that always return None. You
can also require that the argument be a RemoteReference that provides a
particular RemoteInterface. For example:

class RIUser(RemoteInterface):
    def get_age():
        return int
    def delete():
        return None

class RIUserDatabase(RemoteInterface):
    def get_user(username=str):
        return RIUser

Note that these remote interface specifications are parsed at import time, so
any names they refer to must be defined before they get used (hence placing
RIUserDatabase before RIUser would fail). Hopefully we'll figure out a way to
fix this in the future.

** Violations are now annotated better, might keep more stack-trace information

** Copyable improvements

The Copyable documentation has been split out to docs/copyable.xhtml and
somewhat expanded.

The new preferred Copyable usage is to have a class-level attribute named
"typeToCopy" which holds the unique string. This must match the class-level
"copytype" attribute of the corresponding RemoteCopy class. Copyable
subclasses (or ICopyable adapters) may still implement getTypeToCopy(), but
the default just returns self.typeToCopy . Most significantly, we no longer
automatically use the fully-qualified classname: instead we *require* that
the class definition include "typeToCopy". Feel free to use any stable and
globally-unique string here, like a URI in a namespace that you control, or
the fully-qualified package/module/classname of the Copyable subclass.

The RemoteCopy subclass must set the 'copytype' attribute, as it is used for
auto-registration. These can set copytype=None to inhibit auto-registration.


* Release 0.0.5 (04 Nov 2006)

** add Tub.setOption, add logRemoteFailures and logLocalFailures

These options control whether we log exceptions (to the standard twisted log)
that occur on other systems in response to messages that we've sent, and that
occur on our system in response to messages that we've received
(respectively). These may be useful while developing a distributed
application. All such log messages have each line of the stack trace prefixed
by REMOTE: or LOCAL: to make it clear where the exception is happening.

** add sarge packaging, improve dependencies for sid and dapper .debs

** fix typo that prevented Reconnector from actually reconnecting


* Release 0.0.4 (26 Oct 2006)

** API Changes

*** notifyOnDisconnect() takes args/kwargs

RemoteReference.notifyOnDisconnect(), which registers a callback to be fired
when the connection to this RemoteReference is lost, now accepts args and
kwargs to be passed to the callback function. Without this, application code
needed to use inner functions or bound methods to close over any additional
state you wanted to get into the disconnect handler.

notifyOnDisconnect() returns a "marker", an opaque values that should be
passed into the corresponding dontNotifyOnDisconnect() function to deregister
the callback. (previously dontNotifyOnDisconnect just took the same argument
as notifyOnDisconnect).

For example:

class Foo:
    def _disconnect(self, who, reason):
        print "%s left us, because of %s" % (who, reason)
    def connect(self, url, why):
        d = self.tub.getReference(url)
        def _connected(rref):
            self.rref = rref
            m = rref.notifyOnDisconnect(self._disconnect, who, reason=why)
            self.marker = m
        d.addCallback(_connected)
    def stop_caring(self):
        self.rref.dontNotifyOnDisconnect(self.marker)

*** Reconnector / Tub.connectTo()

There is a new connection API for applications that want to connect to a
target and to reconnect to it if/when that connection is lost. This is like
ReconnectingClientFactory, but at a higher layer. You give it a URL to
connect to, and a callback (plus args/kwargs) that should be called each time
a connection is established. Your callback should use notifyOnDisconnect() to
find out when it is disconnected. Reconnection attempts use exponential
backoff to limit the retry rate, and you can shut off reconnection attempts
when you no longer want to maintain a connection.

Use it something like this:

class Foo:
    def __init__(self, tub, url):
        self.tub = tub
        self.reconnector = tub.connectTo(url, self._connected, "arg")
    def _connected(self, rref, arg):
        print "connected"
        assert arg == "arg"
        self.rref = rref
        self.rref.callRemote("hello")
        self.rref.notifyOnDisconnect(self._disconnected, "blag")
    def _disconnected(self, blag):
        print "disconnected"
        assert blag == "blag"
        self.rref = None
    def shutdown(self):
        self.reconnector.stopConnecting()

Code which uses this pattern will see "connected" events strictly interleaved
with "disconnected" events (i.e. it will never see two "connected" events in
a row, nor two "disconnected" events).

The basic idea is that each time your _connected() method is called, it
should re-initialize all your state by making method calls to the remote
side. When the connection is lost, all that state goes away (since you have
no way to know what is happening until you reconnect).

** Behavioral Changes

*** All Referenceable object are now implicitly "giftable"

In 0.0.3, for a Referenceable to be "giftable" (i.e. useable as the payload
of an introduction), two conditions had to be satisfied. #1: the object must
be published through a Tub with Tub.registerReference(obj). #2: that Tub must
have a location set (with Tub.setLocation). Once those conditions were met,
if the object was sent over a wire from this Tub to another one, the
recipient of the corresponding RemoteReference could pass it on to a third
party. Another side effect of calling registerReference() is that the Tub
retains a strongref to the object, keeping it alive (with respect to gc)
until either the Tub is shut down or the object is explicitly de-registered
with unregisterReference().

Starting in 0.0.4, the first condition has been removed. All objects which
pass through a setLocation'ed Tub will be usable as gifts. This makes it much
more convenient to use third-party references.

Note that the Tub will *not* retain a strongref to these objects (merely a
weakref), so such objects might disappear before the recipient has had a
chance to claim it. The lifecycle of gifts is a subject of much research. The
hope is that, for reasonably punctual recipients, the gift will be kept alive
until they claim it. The whole gift/introduction mechanism is likely to
change in the near future, so this lifetime issue will be revisited in a
later release.

** Build Changes

The source tree now has some support for making debian-style packages (for
both sid and dapper). 'make debian-sid' and 'make debian-dapper' ought to
create a .deb package.


* Release 0.0.3 (05 Oct 2006)

** API Changes

The primary entry point for Foolscap is now the "Tub":

    import foolscap
    t = foolscap.Tub()
    d = t.getReference(pburl)
    d.addCallback(self.gotReference)
    ...

The old "PBService" name is gone, use "Tub" instead. There are now separate
classes for "Tub" and "UnauthenticatedTub", rather than using an "encrypted="
argument. Tubs always use encryption if available: the difference between the
two classes is whether this Tub should use a public key for its identity or
not. Note that you always need encryption to connect to an authenticated Tub.
So install pyopenssl, really.

** eventual send operators

Foolscap now provides 'eventually' and 'fireEventually', to implement the
"eventual send" operator advocated by Mark Miller's "Concurrency Among
Strangers" paper (http://www.erights.org/talks/promises/index.html).
eventually(cb, *args, **kwargs) runs the given call in a later reactor turn.
fireEventually(value=None) returns a Deferred that will be fired (with
'value') in a later turn. These behave a lot like reactor.callLater(0,..),
except that Twisted doesn't actually promise that a pair of callLater(0)s
will be fired in the right order (they usually do under unix, but they
frequently don't under windows). Foolscap's eventually() *does* make this
guarantee. In addition, there is a flushEventualQueue() that is useful for
unit tests, it returns a Deferred that will only fire when the entire queue
is empty. As long as your code only uses eventually() (and not callLater(0)),
putting the following in your trial test cases should keep everything nice
and clean:

 def tearDown(self):
     return foolscap.flushEventualQueue()

** Promises

An initial implementation of Promises is in foolscap.promise for
experimentation. Only "Near" Promises are implemented to far (promises which
resolve to a local object). Eventually Foolscap will offer "Far" Promises as
well, and you will be able to invoke remote method calls through Promises as
well as RemoteReferences. See foolscap/test/test_promise.py for some hints.

** Bug Fixes

Messages containing "Gifts" (third-party references) are now delivered in the
correct order. In previous versions, the presence of these references could
delay delivery of the containing message, causing methods to be executed out
of order.

The VOCAB-manipulating code used to have nasty race conditions, which should
be all fixed now. This would be more important if we actually used the
VOCAB-manipulating code yet, but we don't.

Lots of internal reorganization (put all slicers in a subpackage), not really
user-visible.

Updated to work with recent Twisted HEAD, specifically changes to sslverify.
This release of Foolscap ought to work with the upcoming Twisted-2.5 .

** Incompatible protocol changes

There are now separate add-vocab and set-vocab sequences, which add a single
new VOCAB token and replace the entire table, respectively. These replace the
previous 'vocab' sequence which behaved like set-vocab does now. This would
be an incompatible protocol change, except that previous versions never sent
the vocab sequence anyways. This version doesn't send either vocab-changing
sequence either, but when we finally do start using it, it'll be ready.

* Release 0.0.2 (14 Sep 2006)

Renamed to "Foolscap", extracted from underneat the Twisted packaged,
consolidated API to allow a simple 'import foolscap'. No new features or bug
fixes relative to pb2-0.0.1 .


* Release 0.0.1 (29 Apr 2006)

First release! All basic features are in place. The wire protocol will almost
certainly change at some point, so compatibility with future versions is not
guaranteed.
