~ntt-pf-lab/nova/monkey_patch_notification

« back to all changes in this revision

Viewing changes to vendor/Twisted-10.0.0/twisted/internet/protocol.py

  • Committer: Jesse Andrews
  • Date: 2010-05-28 06:05:26 UTC
  • Revision ID: git-v1:bf6e6e718cdc7488e2da87b21e258ccc065fe499
initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- test-case-name: twisted.test.test_factories -*-
 
2
#
 
3
# Copyright (c) 2001-2009 Twisted Matrix Laboratories.
 
4
# See LICENSE for details.
 
5
 
 
6
 
 
7
"""
 
8
Standard implementations of Twisted protocol-related interfaces.
 
9
 
 
10
Start here if you are looking to write a new protocol implementation for
 
11
Twisted.  The Protocol class contains some introductory material.
 
12
 
 
13
Maintainer: Itamar Shtull-Trauring
 
14
"""
 
15
 
 
16
import random
 
17
from zope.interface import implements
 
18
 
 
19
# Twisted Imports
 
20
from twisted.python import log, failure, components
 
21
from twisted.internet import interfaces, error, defer
 
22
 
 
23
 
 
24
class Factory:
 
25
    """This is a factory which produces protocols.
 
26
 
 
27
    By default, buildProtocol will create a protocol of the class given in
 
28
    self.protocol.
 
29
    """
 
30
 
 
31
    implements(interfaces.IProtocolFactory)
 
32
 
 
33
    # put a subclass of Protocol here:
 
34
    protocol = None
 
35
 
 
36
    numPorts = 0
 
37
    noisy = True
 
38
 
 
39
    def doStart(self):
 
40
        """Make sure startFactory is called.
 
41
 
 
42
        Users should not call this function themselves!
 
43
        """
 
44
        if not self.numPorts:
 
45
            if self.noisy:
 
46
                log.msg("Starting factory %r" % self)
 
47
            self.startFactory()
 
48
        self.numPorts = self.numPorts + 1
 
49
 
 
50
    def doStop(self):
 
51
        """Make sure stopFactory is called.
 
52
 
 
53
        Users should not call this function themselves!
 
54
        """
 
55
        if self.numPorts == 0:
 
56
            # this shouldn't happen, but does sometimes and this is better
 
57
            # than blowing up in assert as we did previously.
 
58
            return
 
59
        self.numPorts = self.numPorts - 1
 
60
        if not self.numPorts:
 
61
            if self.noisy:
 
62
                log.msg("Stopping factory %r" % self)
 
63
            self.stopFactory()
 
64
 
 
65
    def startFactory(self):
 
66
        """This will be called before I begin listening on a Port or Connector.
 
67
 
 
68
        It will only be called once, even if the factory is connected
 
69
        to multiple ports.
 
70
 
 
71
        This can be used to perform 'unserialization' tasks that
 
72
        are best put off until things are actually running, such
 
73
        as connecting to a database, opening files, etcetera.
 
74
        """
 
75
 
 
76
    def stopFactory(self):
 
77
        """This will be called before I stop listening on all Ports/Connectors.
 
78
 
 
79
        This can be overridden to perform 'shutdown' tasks such as disconnecting
 
80
        database connections, closing files, etc.
 
81
 
 
82
        It will be called, for example, before an application shuts down,
 
83
        if it was connected to a port. User code should not call this function
 
84
        directly.
 
85
        """
 
86
 
 
87
    def buildProtocol(self, addr):
 
88
        """Create an instance of a subclass of Protocol.
 
89
 
 
90
        The returned instance will handle input on an incoming server
 
91
        connection, and an attribute \"factory\" pointing to the creating
 
92
        factory.
 
93
 
 
94
        Override this method to alter how Protocol instances get created.
 
95
 
 
96
        @param addr: an object implementing L{twisted.internet.interfaces.IAddress}
 
97
        """
 
98
        p = self.protocol()
 
99
        p.factory = self
 
100
        return p
 
101
 
 
102
 
 
103
class ClientFactory(Factory):
 
104
    """A Protocol factory for clients.
 
105
 
 
106
    This can be used together with the various connectXXX methods in
 
107
    reactors.
 
108
    """
 
109
 
 
110
    def startedConnecting(self, connector):
 
111
        """Called when a connection has been started.
 
112
 
 
113
        You can call connector.stopConnecting() to stop the connection attempt.
 
114
 
 
115
        @param connector: a Connector object.
 
116
        """
 
117
 
 
118
    def clientConnectionFailed(self, connector, reason):
 
119
        """Called when a connection has failed to connect.
 
120
 
 
121
        It may be useful to call connector.connect() - this will reconnect.
 
122
 
 
123
        @type reason: L{twisted.python.failure.Failure}
 
124
        """
 
125
 
 
126
    def clientConnectionLost(self, connector, reason):
 
127
        """Called when an established connection is lost.
 
128
 
 
129
        It may be useful to call connector.connect() - this will reconnect.
 
130
 
 
131
        @type reason: L{twisted.python.failure.Failure}
 
132
        """
 
133
 
 
134
 
 
135
class _InstanceFactory(ClientFactory):
 
136
    """Factory used by ClientCreator."""
 
137
 
 
138
    noisy = False
 
139
 
 
140
    def __init__(self, reactor, instance, deferred):
 
141
        self.reactor = reactor
 
142
        self.instance = instance
 
143
        self.deferred = deferred
 
144
 
 
145
    def __repr__(self):
 
146
        return "<ClientCreator factory: %r>" % (self.instance, )
 
147
 
 
148
    def buildProtocol(self, addr):
 
149
        self.reactor.callLater(0, self.deferred.callback, self.instance)
 
150
        del self.deferred
 
151
        return self.instance
 
152
 
 
153
    def clientConnectionFailed(self, connector, reason):
 
154
        self.reactor.callLater(0, self.deferred.errback, reason)
 
155
        del self.deferred
 
156
 
 
157
 
 
158
class ClientCreator:
 
159
    """Client connections that do not require a factory.
 
160
 
 
161
    The various connect* methods create a protocol instance using the given
 
162
    protocol class and arguments, and connect it, returning a Deferred of the
 
163
    resulting protocol instance.
 
164
 
 
165
    Useful for cases when we don't really need a factory.  Mainly this
 
166
    is when there is no shared state between protocol instances, and no need
 
167
    to reconnect.
 
168
    """
 
169
 
 
170
    def __init__(self, reactor, protocolClass, *args, **kwargs):
 
171
        self.reactor = reactor
 
172
        self.protocolClass = protocolClass
 
173
        self.args = args
 
174
        self.kwargs = kwargs
 
175
 
 
176
    def connectTCP(self, host, port, timeout=30, bindAddress=None):
 
177
        """Connect to remote host, return Deferred of resulting protocol instance."""
 
178
        d = defer.Deferred()
 
179
        f = _InstanceFactory(self.reactor, self.protocolClass(*self.args, **self.kwargs), d)
 
180
        self.reactor.connectTCP(host, port, f, timeout=timeout, bindAddress=bindAddress)
 
181
        return d
 
182
 
 
183
    def connectUNIX(self, address, timeout = 30, checkPID=0):
 
184
        """Connect to Unix socket, return Deferred of resulting protocol instance."""
 
185
        d = defer.Deferred()
 
186
        f = _InstanceFactory(self.reactor, self.protocolClass(*self.args, **self.kwargs), d)
 
187
        self.reactor.connectUNIX(address, f, timeout = timeout, checkPID=checkPID)
 
188
        return d
 
189
 
 
190
    def connectSSL(self, host, port, contextFactory, timeout=30, bindAddress=None):
 
191
        """Connect to SSL server, return Deferred of resulting protocol instance."""
 
192
        d = defer.Deferred()
 
193
        f = _InstanceFactory(self.reactor, self.protocolClass(*self.args, **self.kwargs), d)
 
194
        self.reactor.connectSSL(host, port, f, contextFactory, timeout=timeout, bindAddress=bindAddress)
 
195
        return d
 
196
 
 
197
 
 
198
class ReconnectingClientFactory(ClientFactory):
 
199
    """
 
200
    Factory which auto-reconnects clients with an exponential back-off.
 
201
 
 
202
    Note that clients should call my resetDelay method after they have
 
203
    connected successfully.
 
204
 
 
205
    @ivar maxDelay: Maximum number of seconds between connection attempts.
 
206
    @ivar initialDelay: Delay for the first reconnection attempt.
 
207
    @ivar factor: a multiplicitive factor by which the delay grows
 
208
    @ivar jitter: percentage of randomness to introduce into the delay length
 
209
        to prevent stampeding.
 
210
    @ivar clock: the clock used to schedule reconnection. It's mainly useful to
 
211
        be parametrized in tests. If the factory is serialized, this attribute
 
212
        will not be serialized, and the default value (the reactor) will be
 
213
        restored when deserialized.
 
214
    """
 
215
    maxDelay = 3600
 
216
    initialDelay = 1.0
 
217
    # Note: These highly sensitive factors have been precisely measured by
 
218
    # the National Institute of Science and Technology.  Take extreme care
 
219
    # in altering them, or you may damage your Internet!
 
220
    # (Seriously: <http://physics.nist.gov/cuu/Constants/index.html>)
 
221
    factor = 2.7182818284590451 # (math.e)
 
222
    # Phi = 1.6180339887498948 # (Phi is acceptable for use as a
 
223
    # factor if e is too large for your application.)
 
224
    jitter = 0.11962656472 # molar Planck constant times c, joule meter/mole
 
225
 
 
226
    delay = initialDelay
 
227
    retries = 0
 
228
    maxRetries = None
 
229
    _callID = None
 
230
    connector = None
 
231
    clock = None
 
232
 
 
233
    continueTrying = 1
 
234
 
 
235
 
 
236
    def clientConnectionFailed(self, connector, reason):
 
237
        if self.continueTrying:
 
238
            self.connector = connector
 
239
            self.retry()
 
240
 
 
241
 
 
242
    def clientConnectionLost(self, connector, unused_reason):
 
243
        if self.continueTrying:
 
244
            self.connector = connector
 
245
            self.retry()
 
246
 
 
247
 
 
248
    def retry(self, connector=None):
 
249
        """
 
250
        Have this connector connect again, after a suitable delay.
 
251
        """
 
252
        if not self.continueTrying:
 
253
            if self.noisy:
 
254
                log.msg("Abandoning %s on explicit request" % (connector,))
 
255
            return
 
256
 
 
257
        if connector is None:
 
258
            if self.connector is None:
 
259
                raise ValueError("no connector to retry")
 
260
            else:
 
261
                connector = self.connector
 
262
 
 
263
        self.retries += 1
 
264
        if self.maxRetries is not None and (self.retries > self.maxRetries):
 
265
            if self.noisy:
 
266
                log.msg("Abandoning %s after %d retries." %
 
267
                        (connector, self.retries))
 
268
            return
 
269
 
 
270
        self.delay = min(self.delay * self.factor, self.maxDelay)
 
271
        if self.jitter:
 
272
            self.delay = random.normalvariate(self.delay,
 
273
                                              self.delay * self.jitter)
 
274
 
 
275
        if self.noisy:
 
276
            log.msg("%s will retry in %d seconds" % (connector, self.delay,))
 
277
 
 
278
        def reconnector():
 
279
            self._callID = None
 
280
            connector.connect()
 
281
        if self.clock is None:
 
282
            from twisted.internet import reactor
 
283
            self.clock = reactor
 
284
        self._callID = self.clock.callLater(self.delay, reconnector)
 
285
 
 
286
 
 
287
    def stopTrying(self):
 
288
        """
 
289
        Put a stop to any attempt to reconnect in progress.
 
290
        """
 
291
        # ??? Is this function really stopFactory?
 
292
        if self._callID:
 
293
            self._callID.cancel()
 
294
            self._callID = None
 
295
        if self.connector:
 
296
            # Hopefully this doesn't just make clientConnectionFailed
 
297
            # retry again.
 
298
            try:
 
299
                self.connector.stopConnecting()
 
300
            except error.NotConnectingError:
 
301
                pass
 
302
        self.continueTrying = 0
 
303
 
 
304
 
 
305
    def resetDelay(self):
 
306
        """
 
307
        Call this method after a successful connection: it resets the delay and
 
308
        the retry counter.
 
309
        """
 
310
        self.delay = self.initialDelay
 
311
        self.retries = 0
 
312
        self._callID = None
 
313
        self.continueTrying = 1
 
314
 
 
315
 
 
316
    def __getstate__(self):
 
317
        """
 
318
        Remove all of the state which is mutated by connection attempts and
 
319
        failures, returning just the state which describes how reconnections
 
320
        should be attempted.  This will make the unserialized instance
 
321
        behave just as this one did when it was first instantiated.
 
322
        """
 
323
        state = self.__dict__.copy()
 
324
        for key in ['connector', 'retries', 'delay',
 
325
                    'continueTrying', '_callID', 'clock']:
 
326
            if key in state:
 
327
                del state[key]
 
328
        return state
 
329
 
 
330
 
 
331
 
 
332
class ServerFactory(Factory):
 
333
    """Subclass this to indicate that your protocol.Factory is only usable for servers.
 
334
    """
 
335
 
 
336
 
 
337
class BaseProtocol:
 
338
    """This is the abstract superclass of all protocols.
 
339
 
 
340
    If you are going to write a new protocol for Twisted, start here.  The
 
341
    docstrings of this class explain how you can get started.  Any protocol
 
342
    implementation, either client or server, should be a subclass of me.
 
343
 
 
344
    My API is quite simple.  Implement dataReceived(data) to handle both
 
345
    event-based and synchronous input; output can be sent through the
 
346
    'transport' attribute, which is to be an instance that implements
 
347
    L{twisted.internet.interfaces.ITransport}.
 
348
 
 
349
    Some subclasses exist already to help you write common types of protocols:
 
350
    see the L{twisted.protocols.basic} module for a few of them.
 
351
    """
 
352
 
 
353
    connected = 0
 
354
    transport = None
 
355
 
 
356
    def makeConnection(self, transport):
 
357
        """Make a connection to a transport and a server.
 
358
 
 
359
        This sets the 'transport' attribute of this Protocol, and calls the
 
360
        connectionMade() callback.
 
361
        """
 
362
        self.connected = 1
 
363
        self.transport = transport
 
364
        self.connectionMade()
 
365
 
 
366
    def connectionMade(self):
 
367
        """Called when a connection is made.
 
368
 
 
369
        This may be considered the initializer of the protocol, because
 
370
        it is called when the connection is completed.  For clients,
 
371
        this is called once the connection to the server has been
 
372
        established; for servers, this is called after an accept() call
 
373
        stops blocking and a socket has been received.  If you need to
 
374
        send any greeting or initial message, do it here.
 
375
        """
 
376
 
 
377
connectionDone=failure.Failure(error.ConnectionDone())
 
378
connectionDone.cleanFailure()
 
379
 
 
380
 
 
381
class Protocol(BaseProtocol):
 
382
 
 
383
    implements(interfaces.IProtocol)
 
384
 
 
385
    def dataReceived(self, data):
 
386
        """Called whenever data is received.
 
387
 
 
388
        Use this method to translate to a higher-level message.  Usually, some
 
389
        callback will be made upon the receipt of each complete protocol
 
390
        message.
 
391
 
 
392
        @param data: a string of indeterminate length.  Please keep in mind
 
393
            that you will probably need to buffer some data, as partial
 
394
            (or multiple) protocol messages may be received!  I recommend
 
395
            that unit tests for protocols call through to this method with
 
396
            differing chunk sizes, down to one byte at a time.
 
397
        """
 
398
 
 
399
    def connectionLost(self, reason=connectionDone):
 
400
        """Called when the connection is shut down.
 
401
 
 
402
        Clear any circular references here, and any external references
 
403
        to this Protocol.  The connection has been closed.
 
404
 
 
405
        @type reason: L{twisted.python.failure.Failure}
 
406
        """
 
407
 
 
408
 
 
409
class ProtocolToConsumerAdapter(components.Adapter):
 
410
    implements(interfaces.IConsumer)
 
411
 
 
412
    def write(self, data):
 
413
        self.original.dataReceived(data)
 
414
 
 
415
    def registerProducer(self, producer, streaming):
 
416
        pass
 
417
 
 
418
    def unregisterProducer(self):
 
419
        pass
 
420
 
 
421
components.registerAdapter(ProtocolToConsumerAdapter, interfaces.IProtocol,
 
422
                           interfaces.IConsumer)
 
423
 
 
424
class ConsumerToProtocolAdapter(components.Adapter):
 
425
    implements(interfaces.IProtocol)
 
426
 
 
427
    def dataReceived(self, data):
 
428
        self.original.write(data)
 
429
 
 
430
    def connectionLost(self, reason):
 
431
        pass
 
432
 
 
433
    def makeConnection(self, transport):
 
434
        pass
 
435
 
 
436
    def connectionMade(self):
 
437
        pass
 
438
 
 
439
components.registerAdapter(ConsumerToProtocolAdapter, interfaces.IConsumer,
 
440
                           interfaces.IProtocol)
 
441
 
 
442
class ProcessProtocol(BaseProtocol):
 
443
    """
 
444
    Base process protocol implementation which does simple dispatching for
 
445
    stdin, stdout, and stderr file descriptors.
 
446
    """
 
447
    implements(interfaces.IProcessProtocol)
 
448
 
 
449
    def childDataReceived(self, childFD, data):
 
450
        if childFD == 1:
 
451
            self.outReceived(data)
 
452
        elif childFD == 2:
 
453
            self.errReceived(data)
 
454
 
 
455
 
 
456
    def outReceived(self, data):
 
457
        """
 
458
        Some data was received from stdout.
 
459
        """
 
460
 
 
461
 
 
462
    def errReceived(self, data):
 
463
        """
 
464
        Some data was received from stderr.
 
465
        """
 
466
 
 
467
 
 
468
    def childConnectionLost(self, childFD):
 
469
        if childFD == 0:
 
470
            self.inConnectionLost()
 
471
        elif childFD == 1:
 
472
            self.outConnectionLost()
 
473
        elif childFD == 2:
 
474
            self.errConnectionLost()
 
475
 
 
476
 
 
477
    def inConnectionLost(self):
 
478
        """
 
479
        This will be called when stdin is closed.
 
480
        """
 
481
 
 
482
 
 
483
    def outConnectionLost(self):
 
484
        """
 
485
        This will be called when stdout is closed.
 
486
        """
 
487
 
 
488
 
 
489
    def errConnectionLost(self):
 
490
        """
 
491
        This will be called when stderr is closed.
 
492
        """
 
493
 
 
494
 
 
495
    def processExited(self, reason):
 
496
        """
 
497
        This will be called when the subprocess exits.
 
498
 
 
499
        @type reason: L{twisted.python.failure.Failure}
 
500
        """
 
501
 
 
502
 
 
503
    def processEnded(self, reason):
 
504
        """
 
505
        This will be called when the subprocess is finished.
 
506
 
 
507
        @type reason: L{twisted.python.failure.Failure}
 
508
        """
 
509
 
 
510
 
 
511
 
 
512
class AbstractDatagramProtocol:
 
513
    """
 
514
    Abstract protocol for datagram-oriented transports, e.g. IP, ICMP, ARP, UDP.
 
515
    """
 
516
 
 
517
    transport = None
 
518
    numPorts = 0
 
519
    noisy = True
 
520
 
 
521
    def __getstate__(self):
 
522
        d = self.__dict__.copy()
 
523
        d['transport'] = None
 
524
        return d
 
525
 
 
526
    def doStart(self):
 
527
        """Make sure startProtocol is called.
 
528
 
 
529
        This will be called by makeConnection(), users should not call it.
 
530
        """
 
531
        if not self.numPorts:
 
532
            if self.noisy:
 
533
                log.msg("Starting protocol %s" % self)
 
534
            self.startProtocol()
 
535
        self.numPorts = self.numPorts + 1
 
536
 
 
537
    def doStop(self):
 
538
        """Make sure stopProtocol is called.
 
539
 
 
540
        This will be called by the port, users should not call it.
 
541
        """
 
542
        assert self.numPorts > 0
 
543
        self.numPorts = self.numPorts - 1
 
544
        self.transport = None
 
545
        if not self.numPorts:
 
546
            if self.noisy:
 
547
                log.msg("Stopping protocol %s" % self)
 
548
            self.stopProtocol()
 
549
 
 
550
    def startProtocol(self):
 
551
        """Called when a transport is connected to this protocol.
 
552
 
 
553
        Will only be called once, even if multiple ports are connected.
 
554
        """
 
555
 
 
556
    def stopProtocol(self):
 
557
        """Called when the transport is disconnected.
 
558
 
 
559
        Will only be called once, after all ports are disconnected.
 
560
        """
 
561
 
 
562
    def makeConnection(self, transport):
 
563
        """Make a connection to a transport and a server.
 
564
 
 
565
        This sets the 'transport' attribute of this DatagramProtocol, and calls the
 
566
        doStart() callback.
 
567
        """
 
568
        assert self.transport == None
 
569
        self.transport = transport
 
570
        self.doStart()
 
571
 
 
572
    def datagramReceived(self, datagram, addr):
 
573
        """Called when a datagram is received.
 
574
 
 
575
        @param datagram: the string received from the transport.
 
576
        @param addr: tuple of source of datagram.
 
577
        """
 
578
 
 
579
 
 
580
class DatagramProtocol(AbstractDatagramProtocol):
 
581
    """
 
582
    Protocol for datagram-oriented transport, e.g. UDP.
 
583
 
 
584
    @type transport: C{NoneType} or
 
585
        L{IUDPTransport<twisted.internet.interfaces.IUDPTransport>} provider
 
586
    @ivar transport: The transport with which this protocol is associated,
 
587
        if it is associated with one.
 
588
    """
 
589
 
 
590
    def connectionRefused(self):
 
591
        """Called due to error from write in connected mode.
 
592
 
 
593
        Note this is a result of ICMP message generated by *previous*
 
594
        write.
 
595
        """
 
596
 
 
597
 
 
598
class ConnectedDatagramProtocol(DatagramProtocol):
 
599
    """Protocol for connected datagram-oriented transport.
 
600
 
 
601
    No longer necessary for UDP.
 
602
    """
 
603
 
 
604
    def datagramReceived(self, datagram):
 
605
        """Called when a datagram is received.
 
606
 
 
607
        @param datagram: the string received from the transport.
 
608
        """
 
609
 
 
610
    def connectionFailed(self, failure):
 
611
        """Called if connecting failed.
 
612
 
 
613
        Usually this will be due to a DNS lookup failure.
 
614
        """
 
615
 
 
616
 
 
617
 
 
618
class FileWrapper:
 
619
    """A wrapper around a file-like object to make it behave as a Transport.
 
620
 
 
621
    This doesn't actually stream the file to the attached protocol,
 
622
    and is thus useful mainly as a utility for debugging protocols.
 
623
    """
 
624
 
 
625
    implements(interfaces.ITransport)
 
626
 
 
627
    closed = 0
 
628
    disconnecting = 0
 
629
    producer = None
 
630
    streamingProducer = 0
 
631
 
 
632
    def __init__(self, file):
 
633
        self.file = file
 
634
 
 
635
    def write(self, data):
 
636
        try:
 
637
            self.file.write(data)
 
638
        except:
 
639
            self.handleException()
 
640
        # self._checkProducer()
 
641
 
 
642
    def _checkProducer(self):
 
643
        # Cheating; this is called at "idle" times to allow producers to be
 
644
        # found and dealt with
 
645
        if self.producer:
 
646
            self.producer.resumeProducing()
 
647
 
 
648
    def registerProducer(self, producer, streaming):
 
649
        """From abstract.FileDescriptor
 
650
        """
 
651
        self.producer = producer
 
652
        self.streamingProducer = streaming
 
653
        if not streaming:
 
654
            producer.resumeProducing()
 
655
 
 
656
    def unregisterProducer(self):
 
657
        self.producer = None
 
658
 
 
659
    def stopConsuming(self):
 
660
        self.unregisterProducer()
 
661
        self.loseConnection()
 
662
 
 
663
    def writeSequence(self, iovec):
 
664
        self.write("".join(iovec))
 
665
 
 
666
    def loseConnection(self):
 
667
        self.closed = 1
 
668
        try:
 
669
            self.file.close()
 
670
        except (IOError, OSError):
 
671
            self.handleException()
 
672
 
 
673
    def getPeer(self):
 
674
        # XXX: According to ITransport, this should return an IAddress!
 
675
        return 'file', 'file'
 
676
 
 
677
    def getHost(self):
 
678
        # XXX: According to ITransport, this should return an IAddress!
 
679
        return 'file'
 
680
 
 
681
    def handleException(self):
 
682
        pass
 
683
 
 
684
    def resumeProducing(self):
 
685
        # Never sends data anyways
 
686
        pass
 
687
 
 
688
    def pauseProducing(self):
 
689
        # Never sends data anyways
 
690
        pass
 
691
 
 
692
    def stopProducing(self):
 
693
        self.loseConnection()
 
694
 
 
695
 
 
696
__all__ = ["Factory", "ClientFactory", "ReconnectingClientFactory", "connectionDone",
 
697
           "Protocol", "ProcessProtocol", "FileWrapper", "ServerFactory",
 
698
           "AbstractDatagramProtocol", "DatagramProtocol", "ConnectedDatagramProtocol",
 
699
           "ClientCreator"]