title: Proper use of a client and Deferred with Twisted
body: <p>I implemented a basic SOCKS4 client with <code>socket</code>, but my Twisted translation isn't coming along too well. Here's my current code:</p>
  
  <pre><code>import struct
  import socket
  
  from twisted.python.failure import Failure
  
  from twisted.internet import reactor
  from twisted.internet.defer import Deferred
  from twisted.internet.protocol import Protocol, ClientFactory
  
  class Socks4Client(Protocol):
      VERSION = 4
      HOST = "0.0.0.0"
      PORT = 80
  
      REQUESTS = {
          "CONNECT": 1,
          "BIND": 2
      }
  
      RESPONSES = {
          90: "request granted",
          91: "request rejected or failed",
          92: "request rejected because SOCKS server cannot connect to identd on the client",
          93: "request rejected because the client program and identd report different user-ids"
      }
  
      def __init__(self):
          self.buffer = ""
  
      def connectionMade(self):
          self.connect(self.HOST, self.PORT)
  
      def dataReceived(self, data):
          self.buffer += data
  
          if len(self.buffer) == 8:
              self.validateResponse(self.buffer)
  
      def connect(self, host, port):
          data = struct.pack("!BBH", self.VERSION, self.REQUESTS["CONNECT"], port)
          data += socket.inet_aton(host)
          data += "\x00"
  
          self.transport.write(data)
  
      def validateResponse(self, data):
          version, result_code = struct.unpack("!BB", data[1:3])
  
          if version != 4:
              self.factory.protocolError(Exception("invalid version"))
          elif result_code == 90:
              self.factory.deferred.callback(self.responses[result_code])
          elif result_code in self.RESPONSES:
              self.factory.protocolError(Exception(self.responses[result_code]))
          else:
              self.factory.protocolError(Exception())
  
          self.transport.abortConnection()
  
  class Socks4Factory(ClientFactory):
      protocol = Socks4Client
  
      def __init__(self, deferred):
          self.deferred = deferred
  
      def clientConnectionFailed(self, connector, reason):
          self.deferred.errback(reason)
  
      def clientConnectionLost(self, connector, reason):
          print "Connection lost:", reason
  
      def protocolError(self, reason):
          self.deferred.errback(reason)
  
  def result(result):
      print "Success:", result
  
  def error(reason):
      print "Error:", reason
  
  if __name__ == "__main__":
      d = Deferred()
      d.addCallbacks(result, error)
  
      factory = Socks4Factory(d)
      reactor.connectTCP('127.0.0.1', 1080, factory)
  
      reactor.run()
  </code></pre>
  
  <ol>
  <li>I have a feeling that I'm abusing <code>Deferred</code>. Is this the right way to send results from my client?</li>
  <li>I've read a few tutorials, looked at the documentation, and read through most of the protocols bundled with Twisted, but I still can't figure it out: what exactly is a <code>ClientFactory</code> for? Am I using it the right way?</li>
  <li><code>clientConnectionLost</code>s gets triggered a lot. Sometimes I lose the connection and get a successful response. How is that so? What does this mean, and should I treat it as an error?</li>
  <li>How do I make sure that my deferred calls only one callback/errback?</li>
  </ol>
  
  <p>Any tips are appreciated.</p>