Skip to content

Instantly share code, notes, and snippets.

@thepaul
Created January 9, 2013 00:16
Show Gist options
  • Save thepaul/4489345 to your computer and use it in GitHub Desktop.
Save thepaul/4489345 to your computer and use it in GitHub Desktop.
Simple cross-protocol forwarder (Twisted). Run under twistd -y with FWD_LISTEN and FWD_CONNECT set according to the rules for serverFromString (http://twistedmatrix.com/documents/current/api/twisted.internet.endpoints.html#serverFromString) and clientFromString (http://twistedmatrix.com/documents/current/api/twisted.internet.endpoints.html#clien…
import os
from twisted.internet import protocol, reactor, endpoints, error
from twisted.application import service
from twisted.python import log
class Forwarder(protocol.Protocol):
def __init__(self):
self.peer = None
self.peer_queue = []
def dataReceived(self, data):
log.msg('received from %s: %r' % (self.transport.getPeer(), data))
self.sendToPeer(data)
def peerConnected(self, peer):
self.peer = peer
sendme = self.peer_queue
self.peer_queue = []
for data in sendme:
peer.dataFromPeer(data)
def dataFromPeer(self, data):
log.msg('writing to %s: %r' % (self.transport.getPeer(), data))
self.transport.write(data)
def sendToPeer(self, data):
if self.peer is None:
self.peer_queue.append(data)
else:
self.peer.dataFromPeer(data)
def connectionMade(self):
log.msg('connected to %s' % self.transport.getPeer())
if self.peer:
self.peer.peerConnected(self)
def connectionLost(self, reason):
if not reason.check(error.ConnectionDone):
log.err(reason, 'connection to %s lost' % self.transport.getPeer())
if self.peer:
self.peer.peerConnectionLost(reason)
self.peer = None
self.transport = None
def peerConnectionFailed(self, reason):
if self.transport:
log.msg('closing because peer conn failed')
self.transport.loseConnection()
def peerConnectionLost(self, reason):
if self.transport:
log.msg('closing because peer conn was lost')
self.transport.loseConnection()
class ForwarderClientFactory(protocol.ClientFactory):
protocol = Forwarder
def __init__(self, other_end):
self.other_end = other_end
def buildProtocol(self, addr):
p = protocol.ClientFactory.buildProtocol(self, addr)
p.peer = self.other_end
del self.other_end
return p
class ForwarderServerFactory(protocol.ServerFactory):
protocol = Forwarder
clientFactory = ForwarderClientFactory
def __init__(self, forward_endpoint):
self.forward_endpoint = forward_endpoint
def connectClient(self, serverside):
clientfact = self.clientFactory(serverside)
d = self.forward_endpoint.connect(clientfact)
log.msg('started connecting to %s' % self.forward_endpoint)
d.addErrback(log.err, "connection to %s failed"
% self.forward_endpoint)
def buildProtocol(self, addr):
log.msg('connection from %s' % addr)
p = protocol.Factory.buildProtocol(self, addr)
self.connectClient(p)
return p
class ForwarderService(service.Service):
def __init__(self, server_endpoint, client_endpoint):
self.server_endpoint = server_endpoint
self.client_endpoint = client_endpoint
self.servport_d = None
def startService(self):
servfactory = ForwarderServerFactory(self.client_endpoint)
self.servport_d = self.server_endpoint.listen(servfactory)
def stopService(self):
if self.servport_d is not None:
return self.servport_d.addCallback(lambda p: p.stopListening())
server_ep = endpoints.serverFromString(reactor, os.environ['FWD_LISTEN'])
client_ep = endpoints.clientFromString(reactor, os.environ['FWD_CONNECT'])
application = service.Application('Forwarder')
forwarder = ForwarderService(server_ep, client_ep)
forwarder.setServiceParent(application)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment