root/NEWS

Revision 501:bd9e90d0a621, 80.2 kB (checked in by "Brian Warner <warner@lothar.com>", 1 month ago)

NEWS: update for the next release

Line 
1 User visible changes in Foolscap (aka newpb/pb2).           -*- outline -*-
2
3 * Release 0.3.2 (14 Oct 2008)
4
5 ** Compatibility: same as 0.2.6
6
7 Incident classifier functions (introduced in 0.3.0) have been changed: if you
8 have written custom functions for an Incident Gatherer, you will need to
9 modify them upon upgrading to this release.
10
11 ** Logging Changes
12
13 The log.msg counter now uses a regular Python integer/bigint. The counter in
14 0.3.1 used itertools.count(), which, despite its documentation, stores the
15 counter in a C signed int, and thus throws an exception when the message
16 number exceeds 2**31-1 . This exception would pretty much kill any program
17 which ran long enough to emit this many messages, a situation which was
18 observed in a busy production server with an uptime of about three or four
19 weeks. The 0.3.2 counter will be promoted to a bigint when necessary,
20 removing this limitation. (ticket #99)
21
22 The Incident-Gatherer now imports classification functions from files named
23 'classify_*.py' in the gatherer's directory. This effectively adds
24 "classifier plugins". The signature of the functions has changed since the
25 0.3.0 release, making them easier to use. If you have written custom
26 functions (and edited the gatherer.tac file to activate them, using
27 gs.add_classifier()), you will need to modify the functions to take a single
28 'trigger' argument.
29
30 These same 'classify_*.py' plugins are used by a new "flogtool
31 classify-incident" subcommand, which can be pointed at an incident file, and
32 performs the same kind of classification as the Incident Gatherer. (#102).
33
34 The logfiles produced by the "flogtool tail" command and the internal
35 incident-reporter now include the PID of the reporting process. This can be
36 seen by passing the --verbose option to "flogtool dump", and will be made
37 more visible in later releases. (#80).
38
39 The "flogtool web-viewer" tool now marks Incident triggers (#79), and
40 features a "Reload Logfile" button to re-read the logfile on disk (#103).
41 This is most useful when running unit tests, in conjunction with the
42 FLOGFILE= environment variable.
43
44 ** Other Changes
45
46 When running unit tests, if the #62 bug is encountered (pyopenssl >= 0.7 and
47 twisted <= 8.1.0 and selectreactor), the test process will emit a warning and
48 pause for ten seconds to give the operator a chance to halt the test and
49 re-run it with --reactor=poll. This may help to reduce the confusion of a
50 hanging+failing test run.
51
52 The xfer-client.py example tool (in doc/listings/) has been made more
53 useable, by calling os.path.expanduser() on its input files, and by doing
54 sys.exit(1) on failure (instead of hanging), so that external programs can
55 react appropriately.
56
57
58 * Release 0.3.1 (03 Sep 2008)
59
60 ** Compatibility: same as 0.2.6
61
62 ** callRemote API changes: DeadReferenceError
63
64 All partitioning exceptions are now mapped to DeadReferenceError. Previously
65 there were three separate exceptions that might indicate a network partition:
66 DeadReferenceError, ConnectionLost, and ConnectionDone. (a network partition
67 is when one party cannot reach the other party, due to a variety of reasons:
68 temporary network failure, the remote program being shut down, the remote
69 host being taken offline, etc).
70
71 This means that, if you want to send a message and don't care whether that
72 message makes it to the recipient or not (but you *do* still care if the
73 recipient raises an exception during processing of that message), you can set
74 up the Deferred chain like this:
75
76  d = rref.callRemote("message", args)
77  d.addCallback(self.handle_response)
78  d.addErrback(lambda f: f.trap(foolscap.DeadReferenceError))
79  d.addErrback(log.err)
80
81 The first d.addErrback will use f.trap to catch DeadReferenceError, but will
82 pass other exceptions through to the log.err() errback. This will cause
83 DeadReferenceError to be ignored, but other errors to be logged.
84
85 DeadReferenceError will be signalled in any of the following situations:
86
87  1: the TCP connection was lost before callRemote was invoked
88  2: the connection was lost after the request was sent, but before
89     the response was received
90  3: when the active connection is dropped because a duplicate connection was
91     established. This can occur when two programs are simultaneously
92     connecting to each other.
93
94 ** logging improvements
95
96 *** bridge foolscap logs into twistd.log
97
98 By calling foolscap.logging.log.bridgeLogsToTwisted(), or by setting the
99 $FLOGTOTWISTED environment variable (to anything), a subset of Foolscap log
100 events will be copied into the Twisted logging system. The default filter
101 will not copy events below the log.OPERATIONAL level, nor will it copy
102 internal foolscap events (i.e. those with a facility name that starts with
103 "foolscap"). This mechanism is careful to avoid loops, so it is safe to use
104 both bridgeLogsToTwisted() and bridgeTwistedLogs() at the same time. The
105 events that are copied into the Twisted logging system will typically show up
106 in the twistd.log file (for applications that are run under twistd).
107
108 An alternate filter function can be passed to bridgeLogsToTwisted().
109
110 This feature provides a human-readable on-disk record of significant events,
111 using a traditional one-line-per-event all-text sequential logging structure.
112 It does not record parent/child relationships, structured event data, or
113 causality information.
114
115 *** Incident Gatherer improvements
116
117 If an Incident occurs while a previous Incident is still being recorded (i.e.
118 during the "trailing log period"), the two will be folded together.
119 Specifically, the second event will not trigger a new Incident, but will be
120 recorded in the first Incident as a normal log event. This serves to address
121 some performance problems we've seen when incident triggers occur in
122 clusters, which used to cause dozens of simultaneous Incident Recorders to
123 swing into action.
124
125 The Incident Gatherer has been changed to only fetch one Incident at a time
126 (per publishing application), to avoid overloading the app with a large
127 outbound TCP queue.
128
129 The Incident Gatherer has also been changed to scan the classified/* output
130 files and reclassify any stored incidents it has that are not mentioned in
131 one of these files. This means that you can update the classification
132 functions (to add a function for some previously unknown type of incident),
133 delete the classified/unknown file, then restart the incident gatherer, and
134 it will only reclassify the previously-unknown incidents. This makes it much
135 easier to iteratively develop classification functions.
136
137 *** Application Version data
138
139 The table of application versions, previously displayed only by the 'flogtool
140 tail' command, is now recorded in the header of both Incidents and the
141 'flogtool tail --save-to' output file.
142
143 The API to add application versions has changed: now programs should call
144 foolscap.logging.app_versions.add_version(name, verstr).
145
146
147 * Release 0.3.0 (04 Aug 2008)
148
149 ** Compatibility: same as 0.2.6
150
151 The wire-level protocol remains the same as other recent releases.
152
153 The new incident-gatherer will only work with applications that use Foolscap
154 0.3.0 or later.
155
156 ** logging improvements
157
158 The "incident gatherer" has finally been implemented. This is a service, like
159 the log-gatherer, which subscribes to an application's logport and collects
160 incident reports: each is a dump of accumulated log messages, triggered by
161 some special event (such as those above a certain severity threshold). The
162 "flogtool create-incident-gatherer" command is used to create one, and twistd
163 is used to start it. Please see doc/logging.xhtml for more details.
164
165 The incident publishing API was changed to support the incident-gatherer. The
166 incident-gatherer will only work with logports using foolscap 0.3.0 or newer.
167
168 The log-publishing API was changed slightly, to encourage the use of
169 subscription.unsubscribe() rather than publisher.unsubscribe(subscription).
170 The old API remains in place for backwards compatibility with log-gatherers
171 running foolscap 0.2.9 or earlier.
172
173 The Tub.setOption("log-gatherer-furlfile") can accept a file with multiple
174 FURLs, one per line, instead of just a single FURL. This makes the
175 application contact multiple log gatherers, offering its logport to each
176 independently, e.g. to connect to both a log-gatherer and an
177 incident-gatherer.
178
179 ** API Additions
180
181 RemoteReferences now have a getRemoteTubID() method, which returns a string
182 (base32-encoded) representing the secure Tub ID of the remote end of the
183 connection. For any given Tub ID, only the possessor of the matching private
184 key should be able to provide a RemoteReference for which getRemoteTubID()
185 will return that value. I'm not yet sure if getRemoteTubID() is a good idea
186 or not (the traditional object-capability model discourages making
187 access-control decisions on the basis of "who", instead these decisions
188 should be controlled by "what": what objects do they have access to). This
189 method is intended for use by application code that needs to use TubIDs as an
190 index into a table of some sort. It is used by Tahoe to securely compute
191 shared cryptographic secrets for each remote server (by hashing the TubID
192 together with some other string).
193
194 Note that the rref.getSturdyRef() call (which has been present in Foolscap
195 since forever) is *not* secure: the remote application controls all parts of
196 the sturdy ref FURL, including the tubid. A future version of foolscap may
197 remedy this.
198
199 ** Bug fixes
200
201 The log-gatherer FURL can now be set before Tub.setLocation (the connection
202 request will be deferred until setLocation is called), and
203 getLogPort/getLogPortFURL cannot be called until after setLocation. These two
204 changes, in combination, resolve a problem (#55) in which the gatherer
205 connection could be made before the logport was ready, causing the
206 log-gatherer to fail to subscribe to receive log events.
207
208 ** Dependent Libraries
209
210 Foolscap uses PyOpenSSL for all of its cryptographic routines. A bug (#62)
211 has been found in which the current version of Twisted (8.1.0) and the
212 current version of PyOpenSSL (0.7) interact badly, causing Foolscap's unit
213 tests to fail. This problem will affect application code as well
214 (specifically, Tub.stopService will hang forever). The problem only appears
215 to affect the selectreactor, so the current recommended workaround is to run
216 unit tests (and applications that need to shut down Tubs) with --reactor=poll
217 (or whatever other reactor is appropriate for the platform, perhaps iocp). A
218 less-desireable workaround is to downgrade PyOpenSSL to 0.6, or Twisted to
219 something older. The Twisted maintainers are aware of the problem and intend
220 to fix it in an upcoming Twisted release.
221
222
223 * Release 0.2.9 (02 Jul 2008)
224
225 ** Compatibility: exactly the same as 0.2.6
226
227 ** logging bugs fixed
228
229 The foolscap.logging.log.setLogDir() option would throw an exception if the
230 directory already existed, making it unsuitable for use in an application
231 which is expected to be run multiple times. This has been fixed.
232
233 ** logging improvements
234
235 'flogtool tail' now displays the process ID and version information about the
236 remote process. The tool will tolerate older versions of foolscap which do
237 not offer the get_pid interface. (foolscap ticket #71)
238
239 The remote logport now uses a size-limited queue for messages going to a
240 gatherer or 'flogtool tail', to prevent the monitored process from using
241 unbounded amounts of memory during overload situations (when it is generating
242 messages faster than the receiver can handle them). This solves a runaway
243 load problem we've seen in Tahoe production systems, in which a busy node
244 sends log messages to a gatherer too quickly for it to absorb, using lots of
245 memory to hold the pending messages, which causes swapping, which causes more
246 load, making the problem worse. We frequently see an otherwise well-behaved
247 process swell to 1.4GB due to this problem, occasionally failing due to VM
248 exhaustion. Of course, a bounded queue means that new log events will be
249 dropped during this overload situation. (#72)
250
251 ** serialization added for the Decimal type (#50)
252
253 ** debian packaging targets added for gutsy and hardy
254
255 The Makefile now has 'make debian-gutsy' and 'make debian-hardy' targets.
256 These do the same thing as 'make debian-feisty'. (#76)
257
258
259 * Release 0.2.8 (04 Jun 2008)
260
261 ** Compatibility: exactly the same as 0.2.6
262
263 ** setuptools dependencies updated
264
265 Foolscap (when built with setuptools) now uses the "extras_require" feature
266 to declare that it needs pyOpenSSL if you want to use the
267 "secure_connections" feature. This makes easy_install easier to use in
268 projects that depend upon Foolscap (and also insist upon using secure
269 connections): they do not need to declare a dependency on pyOpenSSL
270 themselves, instead they declare a dependency on
271 "Foolscap[secure_connections]". See the following documentation for more
272 details:
273 http://peak.telecommunity.com/DevCenter/setuptools#declaring-extras-optional-features-with-their-own-dependencies
274
275 ** New RemoteReference.getPeer() method
276
277 The new rref.getPeer() method will return address information about the far
278 end of the connection, allowing you to determine their IP address and port
279 number. This may be useful for debugging or diagnostic purposes.
280
281 ** Minor bugs fixed
282
283 Tub.registerReference() with both name= and furlFile= arguments now works
284 even when the furlFile= already exists.
285
286 Tubs which have been shutdown now give more useful error messages when you
287 (incorrectly) try to use them again. Previously a bug caused them to emit a
288 TypeError.
289
290
291 * Release 0.2.7 (13 May 2008)
292
293 ** Compatibility: exactly the same as 0.2.6
294
295 ** flogtool works again
296
297 The "flogtool" utility was completely non-functional in 0.2.6 . This has been
298 fixed.
299
300 ** Known Issues
301
302 *** some debian packages are wrong
303
304 When using the 'make debian-dapper' target (to build a .deb for a dapper
305 system), the resulting .deb sometimes includes a full copy of Twisted, and is
306 probably unsuitable for installation. This appears to be a result of
307 installation behavior changing due to setuptools being imported (even though
308 it is not explicitly used). No other platforms .deb files seem to be affected
309 this way. Package builders are advised to examine the generated .deb closely
310 before using it.
311
312
313 * Release 0.2.6 (06 May 2008)
314
315 ** Compatibility
316
317 All releases between 0.1.3 and 0.2.6 (inclusive) are fully wire-compatible.
318
319 The saved logfiles produced (by e.g. 'flogtool tail --save-to' and the
320 log-gatherer) in 0.2.6 and beyond are not readable by tools (e.g. 'flogtool
321 dump' and 'flogtool filter') from 0.2.5 and earlier.
322
323 FURLs which contain "extensions" (described below) will not be tolerated by
324 foolscap 0.2.5 or earlier. If, at some point in the future, we add such
325 extensions to published FURLs, then such an application will require
326 foolscap-0.2.6 or later to interpret those FURLs.
327
328 ** Logging Changes
329
330 *** "Incident" Logging
331
332 This release finally implements the "strangeness-triggered logging" espoused
333 in doc/logging.xhtml . By giving the foolscap logging code a directory to
334 work with, the logging system will automatically save a compressed pickled
335 logfile containing the messages that lead up to sufficiently-severe log
336 event. The docs explain how to control what "sufficiently-severe" means.
337 These events are retrievable through the logport, although no tools have been
338 written yet to actually extract them. They are also retrievable by using
339 'flogtool dump' directly on the incident files.
340
341 *** 'flogtool as a subcommand
342
343 The implementation of the 'flogtool' executable has been rearranged to make
344 it possible to add a 'flogtool' subcommand to some other executable.
345
346 *** 'flogtool filter' now has --above LEVEL and --from TUBID options
347 *** 'flogtool dump' has --rx-time option, also shows failure tracebacks
348 *** gatherer: don't add erroneous UTC-implying "Z" suffix to filename timestamps
349 *** 'flogtool tail': don't add spurious "0" to timestamps
350
351 ** constraints no longer reject ('reference',) sequences
352
353 The foolscap/banana serialization protocol responds to sending two separate
354 copies of the same object in the same callRemote message by emitting one
355 serialized object sequence and one 'reference' sequence: this is the standard
356 way by which cycles are broken in the serialized data. Unfortunately, the
357 wire-level constraint checkers in 0.2.5 and earlier would reject reference
358 sequences with a Violation exception: if they were expecting a tuple, they
359 would reject anything else, even a reference sequence that pointed at a
360 tuple.
361
362 Worse yet, python's normal constant-object folding code can produce shared
363 references where you might not expect. In the following example, the two
364 tuples are identical objects (and result in a 'reference' sequence on the
365 wire), despite the programmer having typed them separately:
366
367  rref.callRemote("haveTwoTuples", (0,1), (0,1) )
368
369 Foolscap-0.2.6 now allows reference sequence in all wire-level constraint
370 checks, to avoid this false-negative Violation. The post-deserialization
371 check will still enforce the constraint properly. It just does it late enough
372 to be able to tell what the reference points to.
373
374 ** Twisted/pyopenssl compatibility
375
376 *** compatible with Twisted-8.0.x
377
378 Some unit test failures under Twisted-8.0.x (the most recent release) were
379 fixed: tests now pass against Twisted-8.0.x, and a buildbot is used to make
380 sure compatibility is maintained in the future.
381
382 *** incompatible with pyOpenSSL-0.7
383
384 An incompatibility has been discovered with the most recent version of
385 PyOpenSSL. pyopenssl 0.6 works correctly, but pyopenssl 0.7 causes modern
386 versions of Twisted (both 2.5.x and 8.0.x) to follow a code path that breaks
387 the Foolscap unit tests. This may or may not cause a problem in actual
388 application use (the symptom is that the non-winning parallel connections are
389 not disconnected properly, and several negotiation timers are left running).
390 Until a fix is developed for either Twisted or PyOpenSSL, the recommended
391 workaround is to downgrade to PyOpenSSL-0.6 . Twisted bug #3218 and Foolscap
392 bug #62 exist to track this problem.
393
394 ** setup.py is more setuptools-friendly
395
396 The foolscap version string is located with a regular expression rather than
397 an import, allowing setuptools to install Foolscap as a build-dependency of
398 some other project without having Twisted available first. If setuptools is
399 available, we also declare a dependency upon Twisted (at least 2.4.0), to
400 give more information to the setuptools dependency-auto-installer.
401
402 ** Unauthenticated FURLs can now contain multiple connection hints
403
404 Previously they were limited to a single one
405
406 ** FURLs can now contain extensions, providing forwards-compatibility
407
408 The parsing of FURLs has been refined to tolerate (and ignore) certain kinds
409 of extensions. The "tubid" section will be able to have additional
410 identifiers (perhaps stronger hashes for the public key, or an
411 encryption-ready EC-DSA public key). In addition, the "connection hints"
412 section will be able to contain alternate protocol specifiers (for TCP over
413 IPv6, or a less connection-oriented UDP transport).
414
415 By ignoring such extensions, foolscap-0.2.6 will tolerate FURLs produced
416 (with extensions) by some future version of foolscap. This marks the
417 beginning of a "transition period": when such extensions are introduced,
418 0.2.6 will be the oldest version still capable of interoperating with the
419 extension-using new version.
420
421
422 * Release 0.2.5 (25 Mar 2008)
423
424 ** Compatibility
425
426 All releases between 0.1.3 and 0.2.5 (inclusive) are fully wire-compatible.
427
428 The new 'flogtool tail --catch-up' command requires a log publisher running
429 0.2.5 or later. 'flogtool tail' without the --catch-up option will work with
430 earlier publishers.
431
432 ** Licensing clarification
433
434 Foolscap is distributed under the (very liberal) terms of the MIT license,
435 which is the same license that Twisted uses. It's been like this since the
436 beginning, but this is the first release to make this obvious by including a
437 LICENSE file.
438
439 ** foolscap.logging Changes
440
441 'flogtool tail' now has a --catch-up option, which prompts the remote
442 publisher to deliver stored historical events to the subscribe, in proper
443 sequential order. This allows you to connect to a process that has just done
444 something interesting and grab a copy of the log events relevant to that
445 event.
446
447 'flogtool tail' also has a --save-to option, which specifies a filename to
448 which all captured events should be saved. This file can be processed further
449 with 'flogtool dump', 'flogtool filter', or 'flogtool web-viewer'. This
450 behaves much like the unix 'tee' utility, except that the saved data is
451 recorded in a lossless binary format (whereas the text emitted to stdout is
452 not particularly machine-readable).
453
454 'flogtool tail' and 'flogtool dump' both emit human-readable log messages by
455 default. The --verbose option will emit raw event dictionaries, which contain
456 slightly more information but are harder to read.
457
458 'flogtool create-gatherer' will create a log gatherer .tac file in a new
459 working directory. This .tac file can be launched with 'twistd', the standard
460 Twisted daemon-launching program. This is significantly easier to work with
461 than the previous 'flogtool gather' command (which has been removed). The new
462 --rotate option will cause the log-gatherer to switch to a new output file
463 every N seconds. The --bzip option will make it compress the logfiles after
464 rotating them. For example, a log gatherer that rotates and compresses log
465 files once per day could be created and launched with:
466
467  flogtool create-gatherer --rotate 86400 --bzip ./workdir
468  (cd workdir && twistd -y gatherer.tac)
469
470 ** New sample programs
471
472 doc/listings/command-server.py and command-client.py are a pair of programs
473 that let you safely grant access to a specific command. The server is
474 configured with a command line to run, and a directory to run it from. The
475 client gets a FURL: when the client is executed, the server will run its
476 preconfigured command. The client gets to see stdout and stderr (and the exit
477 status), but does not get to influence the command being run in any way.
478 This is much like setting up an ssh server with a restricted command, but
479 somewhat easier to configure.
480
481 doc/listings/xfer-server.py and xfer-client.py are similar, but provide file
482 transfer services instead of command execution.
483
484 ** New Features
485
486 Tub.setLocationAutomatically() will try to determine an externally-visible IP
487 address and feed it to Tub.setLocation(). It does this by preparing to send a
488 packet to a well-known public IP address (one of the root DNS servers) and
489 seeing which network interface would be used. This will tend to find the
490 outbound default route, which of course is only externally-visible if the
491 host is externally-visible. Applications should not depend upon this giving a
492 useful value, and should give the user a way to configure a list of
493 hostname+portnumbers so that manually-configured firewalls, port forwarders,
494 and NAT boxes can be dealt with.
495
496
497 * Release 0.2.4 (28 Jan 2008)
498
499 ** Compatibility
500
501 All releases between 0.1.3 and 0.2.4 (inclusive) are fully wire-compatible.
502
503 ** foolscap.logging Changes
504
505 *** 'flogtool filter' command added
506
507 This mode is used to take one event-log file and produce another with a
508 subset of the events. There are several options to control the filtering:
509 "--strip-facility=foolscap" would remove all the foolscap-related messages,
510 and "--after=start --before=end" will retain events that occur within the
511 given period. The syntax is still in flux, expect these options to change in
512 the next few releases. The main idea is to take a very large logfile and turn
513 it into a smaller, more manageable one.
514
515 *** error logging
516
517 Applications should avoid recording application-specific instances in log
518 events. Doing so will forces the log viewer to access the original source
519 code. The current release of foolscap uses pickle, so such instances will be
520 loadable if the viewer can import the same code, but future versions will
521 probably switch to using Banana, at which point trying to log such instances
522 will cause an error.
523
524 In this release, foolscap stringifies the type of an exception/Failure passed
525 in through the failure= kwarg, to avoid inducing this import dependency in
526 serialized Failures. It also uses the CopiedFailure code to improve
527 portability of Failure instances, and CopiedFailures have been made
528 pickleable.
529
530 The preferred way to log a Failure instance is to pass it like so:
531
532  def _oops(f):
533    log.msg("Oh no, it failed", failure=f, level=log.BAD)
534  d.addErrback(_oops)
535
536 Finally, a 'log.err()' method was added, which behaves just like Twisted's
537 normal log.err(): it can be used in a Deferred errback, or inside an
538 exception handler.
539
540 *** 'flogtool web-viewer'
541
542 Adding a "sort=time" query argument to the all-events viewing page URL will
543 turn off the default nested view, and instead will sort all events strictly
544 by time of generation (note that unsynchronized clocks may confuse the
545 relative ordering of events on different machines). "sort=number" sorts all
546 events by their event number, which is of dubious utility (since these
547 numbers are only scoped to the Tub). "sort=nested" is the default mode.
548
549 The web-viewer now provides "summary views", which show just the events that
550 occurred at a given severity level. Each event is a hyperlink to the line in
551 the all-events page (using anchor/fragment tags), which may make them more
552 convenient to bookmark or reference externally.
553
554
555 * Release 0.2.3 (24 Dec 2007)
556
557 ** Compatibility
558
559 All releases between 0.1.3 and 0.2.3 (inclusive) are fully wire-compatible.
560
561 ** Bug Fixes
562
563 RemoteReference.getSturdyRef() didn't work (due to bitrot). It has been
564 fixed.
565
566 ** foolscap.logging Changes
567
568 This release is mostly about flogging improvements: some bugs and misfeatures
569 were fixed:
570
571 *** tolerate '%' in log message format strings
572
573 Dictionary-style kwarg formatting is now done with a twisted-style style
574 format= argument instead of happening implicitly. That means the acceptable
575 ways to call foolscap.logging.log.msg are:
576
577  log.msg("plain string")
578  log.msg("no args means use 0% interpolation")
579  log.msg("pre-interpolated: %d apples" % apples)
580  log.msg("posargs: %d apples and %d oranges", apples, oranges)
581  log.msg(format="kwargs: %(numapples)d apples", numapples=numapples)
582
583 The benefit of the latter two forms are that the arguments are recorded
584 separately in the event dictionary, so viewing tools can filter on the
585 structured data, think of something like:
586
587   [e for e in allEvents if e.get("numapples",0) > 4]
588
589 *** log facility names are now dot-separated, to match stdlib logging
590 *** log levels are derived from numerical stdlib logging levels
591 *** $FLOGFILE to capture flog events during 'trial' runs
592
593 One challenge of the flogging system is that, once an application was changed
594 to write events to flogging instead of twisted's log, those events do not
595 show up in the normal places where twisted writes its logfiles. For full
596 applications this will be less of an issue, because application startup will
597 tell flogging where events should go (flogging is intended to supplant
598 twisted logging for these applications). But for events emitted during unit
599 tests, such as those driven by Trial, these events would get lost.
600
601 To address this problem, the 0.2.3 flogging code looks for the "FLOGFILE"
602 environment variable at import time. This specifies a filename where flog
603 events (a series of pickled event dictionaries) should be written. The file
604 is opened at import time, events are written during the lifetime of the
605 process, then the file is closed at shutdown using a Twisted "system event
606 trigger" (which happens to be enough to work properly under Trial: other
607 environments may not work so well). If the FLOGFILE filename ends in .bz2,
608 the event pickles will be compressed, which is highly recommended because it
609 can result in a 30x space savings (and e.g. the Tahoe unit test run results
610 in 90MB of uncompressed events). All 'flogtool' modes know how to handle a
611 .bz2 compressed flogfile as well as an uncompressed one.
612
613 The "FLOGTWISTED" environment variable, if set, will cause this same code to
614 bridge twisted log messages into the flogfile. This makes it easier to see
615 the relative ordering of Twisted actions and foolscap/application events.
616 (without this it becomes very hard to correlate the two sources of events).
617
618 The "FLOGLEVEL" variable specifies a minimum severity level that will be put
619 into the flogfile. This defaults to "1", which puts pretty much everything
620 into the file. The idea is that, for tests, you might as well record
621 everything, and use the filtering tools to control the display and isolate
622 the important events. Real applications will use more sophisticated tradeoffs
623 between disk space and interpretation effort.
624
625 The recommended way to run Trial on a unit test suite for an application that
626 uses Foolscap is:
627
628  FLOGFILE=flog.out FLOGTWISTED=1 trial PACKAGENAME
629
630 Note that the logfile cannot be placed in _trial_temp/, because trial deletes
631 that directory after flogging creates the logfile, so the logfile would get
632 deleted too. Also note that the file created by $FLOGFILE is truncated on
633 each run of the program.
634
635
636 * Release 0.2.2 (12 Dec 2007)
637
638 ** Compatibility
639
640 All releases between 0.1.3 and 0.2.2 (inclusive) are fully wire-compatible.
641 New (optional) negotiation parameters were added in 0.2.1 (really in 0.2.0).
642
643 ** Bug Fixes
644
645 The new duplicate-connection handling code in 0.2.1 was broken. This release
646 probably fixes it.
647
648 There were other bugs in 0.2.1 which were triggered when a duplicate
649 connection was shut down, causing remote calls to never be retired, which
650 would also prevent the Reconnector from doing its job. These should be fixed
651 now.
652
653 ** Other Changes
654
655 Foolscap's connection-negotiation mechanism has been modified to use foolscap
656 logging ("flog") instead of twisted.log .
657
658 Setting the FLOGFILE= environment variable will cause a Foolscap-using
659 program to write pickled log events to a file of that name. This is
660 particularly useful when you want to record log events during 'trial' unit
661 test run. The normal API for setting this file will be added later. The
662 FLOGTWISTED= environment variable will cause the creation of a twisted.log
663 bridge, to copy all events from the twisted log into the foolscap log.
664
665 The 'flogtool web-view' mode has been enhanced to color-code events according
666 to their severity, and to format Failure tracebacks in a more-readable way.
667
668
669 * Release 0.2.1 (10 Dec 2007)
670
671 ** Compatibility
672
673 All releases between 0.1.3 and 0.2.1 (inclusive) are fully wire-compatible.
674 0.2.1 introduces some new negotiation parameters (to handle duplicate
675 connections better), but these are ignored by older versions, and their lack
676 is tolerated by 0.2.1 .
677
678 ** New Features
679
680 *** new logging support
681
682 Foolscap is slowly acquiring advanced diagnostic event-logging features. See
683 doc/logging.xhtml for the philosophy and design of this logging system. 0.2.1
684 contains the first few pieces, including a tool named bin/flogtool that can
685 be used to watch events on a running system, or gather events from multiple
686 applications into a single place for later analysis. This support is still
687 preliminary, and many of the controls and interfaces described in that
688 document are not yet implemented.
689
690 *** better handling of duplicate connections / NAT problems
691
692 The connection-management code in 0.1.7 and earlier interacted badly with
693 programs that run behind NAT boxes (especially those with aggressive
694 connection timeouts) or on laptops which get unplugged from the network
695 abruptly. Foolscap seeks to avoid duplicate connections, and various
696 situtations could cause the two ends to disagree about the viability of any
697 given connection. The net result (no pun intended) was that a client might
698 have to wait up to 35 minutes (depending upon various timeout values) before
699 being able to reestablish a connection, and the Reconnector's exponential
700 backoff strategy could easily push this into 90 minutes of downtime.
701
702 0.2.1 uses a different approach to accomplish duplicate-suppression, and
703 should provide much faster reconnection after netquakes. To benefit from
704 this, both ends must be running foolscap-0.2.1 or newer, however there is an
705 additional setting (not enabled by default) to improve the behavior of
706 pre-0.2.1 clients: tub.setOption("handle-old-duplicate-connections", True).
707
708 *** new Reconnector methods
709
710 The Reconnector object (as returned by Tub.connectTo) now has three utility
711 methods that may be useful during debugging. reset() drops the backoff timer
712 down to one second, causing the Reconnector to reconnect quickly: you could
713 use this to avoid an hour-long delay if you've just restarted the server or
714 re-enabled a network connection that was the cause of the earlier connection
715 failures. getDelayUntilNextAttempt() returns the number of seconds remaining
716 until the next connection attempt. And getLastFailure() returns a Failure
717 object explaining why the last connection attempt failed, which may be a
718 useful diagnostic in trying to resolve the connection problems.
719
720 ** Bug Fixes
721
722 There were other minor changes: an OS-X unit test failure was resolved,
723 CopiedFailures are serialized in a way that doesn't cause constraint
724 violations, and the figleaf code-coverage tools (used by foolscap developers
725 to measure how well the unit tests exercise the code base) have been improved
726 (including an emacs code-used/unused annotation tool).
727
728
729 * Release 0.2.0 (10 Dec 2007)
730
731 This release had a fatal bug that wasn't caught by the unit tests, and was
732 superseded almost immediately by 0.2.1 .
733
734
735 * Release 0.1.7 (24 Sep 2007)
736
737 ** Compatibility
738
739 All releases between 0.1.3 and 0.1.7 (inclusive) are fully wire-compatible.
740
741 ** Bug Fixes
742
743 *** slow remote_ methods shouldn't delay subsequent messages (#25)
744
745 In earlier releases, a remote_ method which runs slowly (i.e. one which
746 returns a Deferred and does not fire it right away) would have the
747 unfortunate side-effect of delaying all subsequent calls from the same
748 Broker. Those later calls would not be delivered until the first message had
749 completed processing. If, for some reason, that Deferred were never fired,
750 this Foolscap bug would prevent any other remote_ methods from ever being
751 called.
752
753 This is not how Foolscap's message-ordering logic is designed to work.
754 Foolscap guarantees in-order *delivery* of messages, but does not require
755 that they be completed/retired in that same order.
756
757 This has now been fixed. The invocation of remote_* is done in-order: any
758 further sequencing is up to the receiving application.
759
760 For example, in the following code:
761
762  sender:
763    rref.callRemote("quick", 1)
764    rref.callRemote("slow", 2)
765    rref.callRemote("quick", 3)
766
767  receiver:
768    def remote_quick(self, num):
769      print num
770    def remote_slow(self, num):
771      print num
772      d = Deferred()
773      def _done():
774        print "DONE"
775        d.callback(None)
776      reactor.callLater(5.0, _done)
777      return d
778
779 The intended order of printed messages is 1,2,3,DONE . This bug caused the
780 ordering to be 1,2,DONE,3 instead.
781
782 *** default size limits removed from all Constraints (#26)
783
784 Constraints in Foolscap serve two purposes: DoS attack mitigation, and strong
785 typing on remote interfaces to help developers find problems sooner. To
786 support the former, most container-based Constraints had default size limits.
787 For example, the default StringConstraint enforced a maximum length of 1000
788 characters, and the ListConstraint had a maxLength of 30 elements.
789
790 In practice, these limits turned out to be more surprising than helpful.
791 Applications which worked fine in testing would mysteriously break when
792 subjected to data that was larger than expected. Developers who used
793 Constraints for their type-checking properties were surprised to discover
794 that they were getting size limitations as well. In addition, the
795 DoS-mitigation code in foolscap is not yet complete, so the cost/benefit
796 ratio of this feature was dubious.
797
798 For these reasons, all default size limits have been removed from this
799 release. The 0.1.7 StringConstraint() schema is equivalent to the 0.1.6
800 StringConstraint(maxLength=None) version. To get the 0.1.6 behavior, use
801 StringConstraint(maxLength=1000). The same is true for ListConstraint,
802 DictConstraint, SetConstraint, and UnicodeConstraint.
803
804 ** New features
805
806 *** Tub.registerReference(furlFile=)
807
808 In the spirit of Tub(certFile=), a new argument was added to
809 registerReference that instructs Foolscap to find and store a
810 randomly-generated name in the given file. This makes it convenient to allow
811 subsequent invocations of the same program to use the same stable (yet
812 unguessable) identifier for long-lived objects. For example, a Foolscap-based
813 server can make its Server object available under the same FURL from one run
814 of the program to the next with the following startup code:
815
816   s = MyServer()
817   furl = tub.registerReference(s, furlFile=os.path.join(basedir, "server"))
818
819 If the furlFile= exists before registerReference is called, a FURL will be
820 read from it, and a name extracted to use for the object. If not, the file
821 will be created and filled with a FURL that uses a randomly-generated name.
822
823 *** Tub.serialize()
824
825 Work is ongoing to implement E-style cryptographic Sealers/Unsealers in
826 Foolscap (see ticket #20). Part of that work has made it into this release.
827 The new Tub.serialize() and Tub.unserialize() methods provide access to the
828 underlying object-graph-serialization code. Normally this code is used to
829 construct a bytestream that is immediately sent over an SSL connection to a
830 remote host; these methods return a string instead. Eventually, a Sealer will
831 return an encrypted version of this string, and the corresponding Unsealer
832 will take the encrypted string and build a new object graph.
833
834 The foolscap.serialize() and .unserialize() functions have existed for a
835 while. The new Tub.serialize()/.unserialize() methods are special in that you
836 can serialize Referenceables and RemoteReferences. These are encoded with
837 their FURLs, so that the unserializing Tub can establish a new live reference
838 to their targets. foolscap.serialize() cannot handle referenceables.
839
840 Note that both Tub.serialize() and foolscap.serialize() are currently
841 "unsafe", in that they will serialize (and unserialize!) instances of
842 arbitrary classes, much like the stdlib pickle module. This is a significant
843 security problem, as this results in arbitrary object constructors being
844 executed during deserialization. In a future release of Foolscap, this mode
845 of operation will *not* be the default, and a special argument will have to
846 be passed to enable such behavior.
847
848
849 ** Other Improvements
850
851 When methods fail, the error messages that get logged have been improved. The
852 new messages contain information about which source+dest TubIDs were
853 involved, and which RemoteInterface and method name was being used.
854
855 A new internal method named Tub.debug_listBrokers() will provide information
856 on which messages are waiting for delivery, either inbound or outbound. It is
857 intended to help diagnose problems like #25. Any message which remains
858 unresolved for a significant amount of time is likely to indicate a problem.
859
860
861 * Release 0.1.6 (02 Sep 2007)
862
863 ** Compatibility
864
865 All releases between 0.1.3 and 0.1.6 (inclusive) are fully wire-compatible.
866
867 ** Bug Fixes
868
869 Using a schema of ChoiceOf(StringConstraint(2000), None) would fail to accept
870 strings between 1000 and 2000 bytes: it would accept a short string, or None,
871 but not a long string. This has been fixed. ChoiceOf() remains a troublesome
872 constraint: having it is awfully nice, and things like ChoiceOf(str,None)
873 seem to work, but it is unreliable. Using ChoiceOf with non-terminal children
874 is not recommended (the garden-path problem is unlikely to be easy to solve):
875 schemas are not regular expressions.
876
877 The debian packaging rules have been fixed. The ones in 0.1.5 failed to run
878 because of some renamed documentation files.
879
880 ** Minor Fixes
881
882 Several minor documentation errors have been corrected. A new 'make api-docs'
883 target has been added to run epydoc and build HTML versions of the API
884 documentation.
885
886 When a remote method fails and needs to send a traceback over the wire, and
887 when the traceback is too large, trim out the middle rather than the end,
888 since usually it's the beginning and the end that are the most useful.
889
890
891 * Release 0.1.5 (07 Aug 2007)
892
893 ** Compatibility
894
895 This release is fully compatible with 0.1.4 and 0.1.3 .
896
897 ** CopiedFailure improvements
898
899 When a remote method call fails, the calling side gets back a CopiedFailure
900 instance. These instances now behave slightly more like the (local) Failure
901 objects that they are intended to mirror, in that .type now behaves much like
902 the original class. This should allow trial tests which result in a
903 CopiedFailure to be logged without exploding. In addition, chained failures
904 (where A calls B, and B calls C, and C fails, so C's Failure is eventually
905 returned back to A) should work correctly now.
906
907 ** Gift improvements
908
909 Gifts inside return values should properly stall the delivery of the response
910 until the gift is resolved. Gifts in all sorts of containers should work
911 properly now. Gifts which cannot be resolved successfully (either because the
912 hosting Tub cannot be reached, or because the name cannot be found) will now
913 cause a proper error rather than hanging forever. Unresolvable gifts in
914 method arguments will cause the message to not be delivered and an error to
915 be returned to the caller. Unresolvable gifts in method return values will
916 cause the caller to receive an error.
917
918 ** IRemoteReference() adapter
919
920 The IRemoteReference() interface now has an adapter from Referenceable which
921 creates a wrapper that enables the use of callRemote() and other
922 IRemoteReference methods on a local object.
923
924 The situation where this might be useful is when you have a central
925 introducer and a bunch of clients, and the clients are introducing themselves
926 to each other (to create a fully-connected mesh), and the introductions are
927 using live references (i.e. Gifts), then when a specific client learns about
928 itself from the introducer, that client will receive a local object instead
929 of a RemoteReference. Each client will wind up with n-1 RemoteReferences and
930 a single local object.
931
932 This adapter allows the client to treat all these introductions as equal. A
933 client that wishes to send a message to everyone it's been introduced to
934 (including itself) can use:
935
936   for i in introductions:
937     IRemoteReference(i).callRemote("hello", args)
938
939 In the future, if we implement coercing Guards (instead of
940 compliance-asserting Constraints), then IRemoteReference will be useful as a
941 guard on methods that want to insure that they can do callRemote (and
942 notifyOnDisconnect, etc) on their argument.
943
944 ** Tub.registerNameLookupHandler
945
946 This method allows a one-argument name-lookup callable to be attached to the
947 Tub. This augments the table maintained by Tub.registerReference, allowing
948 Referenceables to be created on the fly, or persisted/retrieved on disk
949 instead of requiring all of them to be generated and registered at startup.
950
951
952 * Release 0.1.4 (14 May 2007)
953
954 ** Compatibility
955
956 This release is fully compatible with 0.1.3 .
957
958 ** getReference/connectTo can be called before Tub.startService()
959
960 The Tub.startService changes that were suggested in the 0.1.3 release notes
961 have been implemented. Calling getReference() or connectTo() before the Tub
962 has been started is now allowed, however no action will take place until the
963 Tub is running. Don't forget to start the Tub, or you'll be left wondering
964 why your Deferred or callback is never fired. (A log message is emitted when
965 these calls are made before the Tub is started, in the hopes of helping
966 developers find this mistake faster).
967
968 ** constraint improvements
969
970 The RIFoo -style constraint now accepts gifts (third-party references). This
971 also means that using RIFoo on the outbound side will accept either a
972 Referenceable that implements the given RemoteInterface or a RemoteReference
973 that points to a Referenceable that implements the given RemoteInterface.
974 There is a situation (sending a RemoteReference back to its owner) that will
975 pass the outbound constraint but be rejected by the inbound constraint on the
976 other end. It remains to be seen how this will be fixed.
977
978 ** foolscap now deserializes into python2.4-native 'set' and 'frozenset' types
979
980 Since Foolscap is dependent upon python2.4 or newer anyways, it now
981 unconditionally creates built-in 'set' and 'frozenset' instances when
982 deserializing 'set'/'immutable-set' banana sequences. The pre-python2.4
983 'sets' module has non-built-in set classes named sets.Set and
984 sets.ImmutableSet, and these are serialized just like the built-in forms.
985
986 Unfortunately this means that Set and ImmutableSet will not survive a
987 round-trip: they'll be turned into set and frozenset, respectively. Worse
988 yet, 'set' and 'sets.Set' are not entirely compatible. This may cause a
989 problem for older applications that were written to be compatible with both
990 python-2.3 and python-2.4 (by using sets.Set/sets.ImmutableSet), for which
991 the compatibility code is still in place (i.e. they are not using
992 set/frozenset). These applications may experience problems when set objects
993 that traverse the wire via Foolscap are brought into close proximity with set
994 objects that remained local. This is unfortunate, but it's the cleanest way
995 to support modern applications that use the native types exclusively.
996
997 ** bug fixes
998
999 Gifts inside containers (lists, tuples, dicts, sets) were broken: the target
1000 method was frequently invoked before the gift had properly resolved into a
1001 RemoteReference. Constraints involving gifts inside containers were broken
1002 too. The constraints may be too loose right now, but I don't think they
1003 should cause false negatives.
1004
1005 The unused SturdyRef.asLiveRef method was removed, since it didn't work
1006 anyways.
1007
1008 ** terminology shift: FURL
1009
1010 The preferred name for the sort of URL that you get back from
1011 registerReference (and hand to getReference or connectTo) has changed from
1012 "PB URL" to "FURL" (short for Foolscap URL). They still start with 'pb:',
1013 however. Documentation is slowly being changed to use this term.
1014
1015
1016 * Release 0.1.3 (02 May 2007)
1017
1018 ** Incompatibility Warning
1019
1020 The 'keepalive' feature described below adds a new pair of banana tokens,
1021 PING and PONG, which introduces a compatibility break between 0.1.2 and 0.1.3
1022 . Older versions would throw an error upon receipt of a PING token, so the
1023 version-negotiation mechanism is used to prevent banana-v2 (0.1.2) peers from
1024 connecting to banana-v3 (0.1.3+) peers. Our negotiation mechanism would make
1025 it possible to detect the older (v2) peer and refrain from using PINGs, but
1026 that has not been done for this release.
1027
1028 ** Tubs must be running before use
1029
1030 Tubs are twisted.application.service.Service instances, and as such have a
1031 clear distinction between "running" and "not running" states. Tubs are
1032 started by calling startService(), or by attaching them to a running service,
1033 or by starting the service that they are already attached to. The design rule
1034 in operation here is that Tubs are not allowed to perform network IO until
1035 they are running.
1036
1037 This rule was not enforced completely in 0.1.2, and calls to
1038 getReference()/connectTo() that occurred before the Tub was started would
1039 proceed normally (initiating a TCP connection, etc). Starting with 0.1.3,
1040 this rule *is* enforced. For now, that means that you must start the Tub
1041 before calling either of these methods, or you'll get an exception. In a
1042 future release, that may be changed to allow these early calls, and queue or
1043 otherwise defer the network IO until the Tub is eventually started. (the
1044 biggest issue is how to warn users who forget to start the Tub, since in the
1045 face of such a bug the getReference will simply never complete).
1046
1047 ** Keepalives
1048
1049 Tubs now keep track of how long a connection has been idle, and will send a
1050 few bytes (a PING of the other end) if no other traffic has been seen for
1051 roughly 4 to 8 minutes. This serves two purposes. The first is to convince an
1052 intervening NAT box that the connection is still in use, to prevent it from
1053 discarding the connection's table entry, since that would block any further
1054 traffic. The second is to accelerate the detection of such blocked
1055 connections, specifically to reduce the size of a window of buggy behavior in
1056 Foolscap's duplicate-connection detection/suppression code.
1057
1058 This problem arises when client A (behind a low-end NAT box) connects to
1059 server B, perhaps using connectTo(). The first connection works fine, and is
1060 used for a while. Then, for whatever reason, A and B are silent for a long
1061 time (perhaps as short as 20 minutes, depending upon the NAT box). During
1062 this silence, A's NAT box thinks the connection is no longer in use and drops
1063 the address-translation table entry. Now suppose that A suddenly decides to
1064 talk to B. If the NAT box creates a new entry (with a new outbound port
1065 number), the packets that arrive on B will be rejected, since they do not
1066 match any existing TCP connections. A sees these rejected packets, breaks the
1067 TCP connection, and the Reconnector initiates a new connection. Meanwhile, B
1068 has no idea that anything has gone wrong. When the second connection reaches
1069 B, it thinks this is a duplicate connection from A, and that it already has a
1070 perfectly functional (albeit quiet) connection for that TubID, so it rejects
1071 the connection during the negotiation phase. A sees this rejection and
1072 schedules a new attempt, which ends in the same result. This has the
1073 potential to prevent hosts behind NAT boxes from ever reconnecting to the
1074 other end, at least until the the program at the far end is restarted, or it
1075 happens to try to send some traffic of its own.
1076
1077 The same problem can occur if a laptop is abruptly shut down, or unplugged
1078 from the network, then moved to a different network. Similar problems have
1079 been seen with virtual machine instances that were suspended and moved to a
1080 different network.
1081
1082 The longer-term fix for this is a deep change to the way duplicate
1083 connections (and cross-connect race conditions) are handled. The keepalives,
1084 however, mean that both sides are continually checking to see that the
1085 connection is still usable, enabling TCP to break the connection once the
1086 keepalives go unacknowledged for a certain amount of time. The default
1087 keepalive timer is 4 minutes, and due to the way it is implemented this means
1088 that no more than 8 minutes will pass without some traffic being sent. TCP
1089 tends to time out connections after perhaps 15 minutes of unacknowledged
1090 traffic, which means that the window of unconnectability is probably reduced
1091 from infinity down to about 25 minutes.
1092
1093 The keepalive-sending timer defaults to 4 minutes, and can be changed by
1094 calling tub.setOption("keepaliveTimeout", seconds).
1095
1096 In addition, an explicit disconnect timer can be enabled, which tells
1097 Foolscap to drop the connection unless traffic has been seen within some
1098 minimum span of time. This timer can be set by calling
1099 tub.setOption("disconnectTimeout", seconds). Obviously it should be set to a
1100 higher value than the keepaliveTimeout. This will close connections faster
1101 than TCP will. Both TCP disconnects and the ones triggered by this
1102 disconnectTimeout run the risk of false negatives, of course, in the face of
1103 unreliable networks.
1104
1105 ** New constraints
1106
1107 When a tuple appears in a method constraint specification, it now maps to an
1108 actual TupleOf constraint. Previously they mapped to a ChoiceOf constraint.
1109 In practice, TupleOf appears to be much more useful, and thus better
1110 deserving of the shortcut.
1111
1112 For example, a method defined as follows:
1113
1114   def get_employee(idnumber=int):
1115       return (str, int, int)  # (name, room_number, age)
1116
1117 can only return a three-element tuple, in which the first element is a string
1118 (specifically it conforms to a default StringConstraint), and the second two
1119 elements are ints (which conform to a default IntegerConstraint, which means
1120 it fits in a 32-bit signed twos-complement value).
1121
1122 To specify a constraint that can accept alternatives, use ChoiceOf:
1123
1124   def get_record(key=str):
1125       """Return the record (a string) if it is present, or None if
1126           it is not present."""
1127       return ChoiceOf(str, None)
1128
1129 UnicodeConstraint has been added, with minLength=, maxLength=, and regexp=
1130 arguments.
1131
1132 The previous StringConstraint has been renamed to ByteStringConstraint (for
1133 accuracy), and it is defined to *only* accept string objects (not unicode
1134 objects). 'StringConstraint' itself remains equivalent to
1135 ByteStringConstraint for now, but in the future it may be redefined to be a
1136 constraint that accepts both bytestrings and unicode objects. To accomplish
1137 the bytestring-or-unicode constraint now, you might try
1138 schema.AnyStringConstraint, but it has not been fully tested, and might not
1139 work at all.
1140
1141 ** Bugfixes
1142
1143 Errors during negotiation were sometimes delivered in the wrong format,
1144 resulting in a "token prefix is limited to 64 bytes" error message. Several
1145 error messages (including that one) have been improved to give developers a
1146 better chance of determining where the actual problem lies.
1147
1148 RemoteReference.notifyOnDisconnect was buggy when called on a reference that
1149 was already broken: it failed to fire the callback. Now it fires the callback
1150 soon (using an eventual-send). This should remove a race condition from
1151 connectTo+notifyOnDisconnect sequences and allow them to operate reliably.
1152 notifyOnDisconnect() is now tolerant of attempts to remove something twice,
1153 which should make it easier to use safely.
1154
1155 Remote methods which raise string exceptions should no longer cause Foolscap
1156 to explode. These sorts of exceptions are deprecated, of course, and you
1157 shouldn't use them, but at least they won't break Foolscap.
1158
1159 The Reconnector class (accessed by tub.connectTo) was not correctly
1160 reconnecting in certain cases (which appeared to be particularly common on
1161 windows). This should be fixed now.
1162
1163 CopyableSlicer did not work inside containers when streaming was enabled.
1164 Thanks to iacovou-AT-gmail.com for spotting this one.
1165
1166 ** Bugs not fixed