Having my client factory here:
import logging, traceback
from twisted.internet.protocol import ClientFactory
from twisted.internet import defer, reactor, ssl
from twisted.application import service
from protocols.smpp.protocol import SMPPClientProtocol
class SMPPClientFactory(ClientFactory):
protocol = SMPPClientProtocol
def __init__(self, config):
self.config = config
def getConfig(self):
return self.config
def clientConnectionFailed(self, connector, reason):
print "clientConnectionFailed"
self.connectDeferred.errback(reason)
def clientConnectionLost(self, connector, reason):
print "clientConnectionLost"
def connect(self):
self.connectDeferred = defer.Deferred()
factory = SMPPClientFactory(self.config, self.msgHandler)
self.log.warning('Establishing TCP connection to %s:%d' % (self.config.host, self.config.port))
reactor.connectTCP(self.config.host, self.config.port, factory)
return self.connectDeferred
And it's launching code here:
import logging, traceback
from twisted.internet import reactor, defer
from protocols.smpp.configs import SMPPClientConfig
from protocols.smpp.smpp_operations import SMPPOperationFactory
from testbed.client import SMPPClientFactory
class SMPP(object):
def __init__(self, config=None):
if config is None:
config = SMPPClientConfig()
self.config = config
self.opFactory = SMPPOperationFactory(config)
def run(self):
try:
#Bind
SMPPClientFactory(self.config, self.handleMsg).connect().addErrback(self.connectFailed)
except Exception, e:
print "ERROR: %s" % str(e)
def connectFailed(self, reason):
print "Connection failed %s" % str(reason)
def handleMsg(self, smpp, pdu):
pass
if __name__ == '__main__':
config = SMPPClientConfig(host='127.0.0.1', port=2775, username='smppclient1', password='password',
log_level=logging.DEBUG)
logging.basicConfig(level=config.log_level, filename=config.log_file, format=config.log_format,datefmt=config.log_dateformat)
SMPP(config).run()
reactor.run()
When the connection is failing (the remote server is down), i get factory's clientConnectionFailed called but it is strangely getting a "exceptions.AttributeError: SMPPClientFactory instance has no attribute 'connectDeferred'".
I need to call the errback when the connection fails, it seems there's something missing when dealing with deferreds ..
On your launch code, you instantiated an SMPPClientFactory and called connect() on it. This particular instance will have the connectDeferred attribute. However, connect also instantiated another SMPPClientFactory: factory = SMPPClientFactory(self.config, self.msgHandler) and this is the instance you used to create the actual connection. This doesn't have the connectDeferred attribute because with this instance connect has never been called.
Related
I am trying to create a resolving DNS server using python twisted. I am wanting to do a domain lookup and then manipulate (or at least parse) the returned look-up value. Here is what I have done so far:
from twisted.names import client, dns, server, error
from twisted.internet import task
from twisted.internet import reactor, defer
class DNS_Reslover(object):
def __init__(self, rsvr):
self.__resolver = rsvr
def dump(self, obj):
for attr in dir(obj):
if hasattr(obj, attr):
print("obj.%s = %s" % (attr, getattr(obj, attr)))
def _qryCallBack(self, qry):
# print(qry)
print(len(qry))
for i in qry[1]:
print(i)
def _qryError(self, domainname):
print("error {}".format(domainname))
def query(self, query, timeout=None):
"""
Check if the query should be answered dynamically, otherwise dispatch to
the fallback resolver.
"""
_d = self.__resolver.lookupService(query.name.name)
_d.addCallback(self._qryCallBack)
_d.addErrback(self._qryError)
return defer.fail(error.DomainError())
def main():
"""
Running server
"""
client_resolver = client.Resolver(resolv='/etc/resolv.conf')
factory = server.DNSServerFactory(clients=[DNS_Reslover(client_resolver)])
protocol = dns.DNSDatagramProtocol(controller=factory)
reactor.listenUDP(5553, protocol)
reactor.listenTCP(5553, factory)
reactor.run()
if __name__ == "__main__":
raise SystemExit(main())
What is returned is
<RR name=google.com type=SOA class=IN ttl=59s auth=False>
I am interested in parsing and validating the IP address but it is not being retuned. Can someone point me to what I am doing wrong?
Thank you
I know a similar question has been asked here, but I am still battling with the following issue:
I am using putty as a telnet client and am using Win10. The code is given below. When I start the reactor and then connect a client, I get a response after each character is typed which is printed using the dataReceived function. However I can never seem to get the function lineReceived() to fire. I also tried a simple chat server example which worked fine using the lineReceived() function (and that example had no dataReceived() function. I tried commenting out dataReceived(), thinking perhaps it was masking out lineReceived().
In the code below, I cannot get lineReceived() to fire , only dataReceived() fires after each character is typed.
#! C:/Python37/python.exe
from twisted.internet import reactor
from twisted.internet.protocol import Factory, Protocol
from datetime import datetime, tzinfo, timedelta
from twisted.protocols.basic import LineReceiver
class Echo(Protocol):
def dataReceived(self, data):
self.transport.write(data)
class LineReceiver(Protocol):
print("Starting.......")
delimiter = "\n"
TIMEOUT = 300 # Client timeout period in seconds
def timeOut(self):
print("Client: %s. %s" % (self.addr, "Connection Timed out"))
self.transport.loseConnection()
def lineLengthExceeded(self, line):
return self.transport.loseConnection()
def connectionMade(self):
print("Connected......")
self.transport.write(b"hell...")
self.timeout = reactor.callLater(
self.TIMEOUT, self.timeOut
) # start client timeout timer
self.addr = self.transport.getPeer().host
addr = self.addr
self.addr_test = self.transport.getPeer().host
self.factory.NUM_CLIENTS += 1
def connectionLost(self, reason):
print("Lost.......")
# self.sendMsg("- %s left." % self.name)
self.transport.write(b"a client left")
self.factory.NUM_CLIENTS -= 1
print("Client disconnected: - " + str(self.addr))
print("Number of connections = %s" % self.factory.NUM_CLIENTS)
# def dataReceived(self, data): # this runs a few times after an initial connection
# self.transport.write(b"you typed: " + data +b"\n" + b"\r")
# print(data) # prints to log file with byte order marks
def lineReceived(self, line):
self.sendLine(b"Welcome, %s!" % (name,))
self.transport.write(b"line rx function...")
class DataFactory(Factory):
protocol = LineReceiver
NUM_CLIENTS = 0
def main():
print("Started...Listening for incoming connections.")
if __name__ == "__main__":
main()
reactor.listenTCP(10003, DataFactory())
reactor.run()
You overwrote LineReceiver with your own Protocol subclass, which does not have a lineReceived() method. You just gave me a good reason for using the module path as a namespace instead of importing a specific object :D
from twisted.protocols import basic
from twisted.internet import endpoints, protocol, reactor
class LnRcv(basic.LineReceiver):
def lineReceived(self, line):
print(line)
class DataFactory(protocol.Factory):
protocol = LnRcv
server = endpoints.TCP4ServerEndpoint(reactor, 10003)
server.listen(DataFactory())
reactor.run()
Update
I had some spare time to fix your code. You have string/bytes mismatching all over and unreferenced objects that were not in your original code. Here's an example that should work and give you a base to off of.
from uuid import uuid4
from twisted.internet import reactor
from twisted.internet.endpoints import TCP4ServerEndpoint
from twisted.internet.protocol import Factory, Protocol
from twisted.protocols.basic import LineReceiver
class LnRcv(LineReceiver):
# Client timeout period in seconds
TIMEOUT = 10
def timeOut(self):
print ("Client: %s. %s" % (self.addr, 'Connection Timed out' ))
self.transport.loseConnection()
def connectionMade(self):
self.factory.NUM_CLIENTS += 1
print(f"Connected......number of connections = {self.factory.NUM_CLIENTS}")
peer = self.transport.getPeer()
self.addr = f"{peer.host}:{peer.port}"
self.name = uuid4().hex[:9].upper()
self.transport.write(f"Hello! I temporarily set your ID to {self.name}. What is your name? ".encode("utf8"))
# Start client timeout timer
self.timeout = reactor.callLater(self.TIMEOUT, self.timeOut)
def connectionLost(self, reason):
self.factory.NUM_CLIENTS -= 1
print(f"- {self.name} left because:\n{reason.getErrorMessage()}")
print(f"- Client disconnected: - {self.addr}")
print(f"- Number of connections = {self.factory.NUM_CLIENTS}")
def lineReceived(self, line):
self.sendLine(f"Welcome, {line.decode('utf8')}!".encode("utf8"))
class DataFactory(Factory):
protocol = LnRcv
NUM_CLIENTS = 0
def main():
print("Started...Listening for incoming connections.")
server = TCP4ServerEndpoint(reactor, 10003)
server.listen(DataFactory())
reactor.run()
if __name__ == "__main__":
main()
How do I send without calling Reactor.ListenUDP?
If I try, then I get an exception in the protocol class that the transport is NULL. It seems it doesn't get set up in the base class until you call the reactor.ListenUDP. Surely, you have the ability to send without listening for incoming messages. After all, a server might not even want to receive at all.
----main.py------
import wx
from twisted.internet import wxreactor
from main_window import MainWindow
def main():
app = wx.App(False)
frame = MainWindow(None, 'UDP Demo')
from twisted.internet import reactor
reactor.registerWxApp(app)
reactor.run()
if __name__ == "__main__":
wxreactor.install()
main()
---main_window.py---
# SNIP - Nothing really relevant. Just creates the classes below and hooks up buttons to call their methods
---plugin.py----
from enum import Enum
from twisted.internet.error import CannotListenError
from udp_protocol import UDPProtocol
class PluginBase(object):
"""
This is just a dummy class to match what is in Falco
"""
def __init__(self, app_dist, *args, **kwargs):
pass
class Plugin(PluginBase):
class State(Enum):
"""
Represents the states that the plugin can be in
"""
CLOSED = 0 # Initial state
LISTENING = 1 # After open() is called
RECV_CALLBACK_REGISTERED = 2 # After listen() is called
def __init__(self, app_dist, *args, **kwargs):
super(Plugin, self).__init__(app_dist, *args, **kwargs)
self.state = self.State.CLOSED
self.port = None
self.listener = None
self.listen_callback = None
self.protocol = UDPProtocol(self.on_data_received)
def listen(self, port, isBroadcast, callback, errback=None):
if self.state != self.State.CLOSED:
raise RuntimeError("UDP Plugin already in an opened state")
self.port = port
# Start listening
try:
from twisted.internet import reactor
self.listener = reactor.listenUDP(self.port, self.protocol)
self.state = self.State.LISTENING
callback()
except CannotListenError as err:
error_json = {"error": err[2].strerror}
if errback is not None:
errback(error_json)
def stop_listening(self):
if self.listener is not None:
self.listener.stopListening()
self.listener = None
self.listen_callback = None
self.port = None
self.state = self.State.CLOSED
def send(self, addr, port, data):
# While it seems like one could send without listening for incoming messages,
# twisted's implementation doesn't seem to work that way?
# The transport in the protocol object only gets created when we call reactor.listenUDP,
# as far as I can tell
if self.state == self.State.CLOSED:
raise RuntimeError(
"UDP Plugin must be in an open state before attempting to send")
self.protocol.send(addr, port, data)
# SNIP recv
----udp_protocol.py---
from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor
class MyProtocol(DatagramProtocol):
def datagramReceived(self, data, (host, port)):
print "received %r from %s:%d" % (data, host, port)
self.transport.write(data, (host, port))
def send(self, addr, port, data):
self.transport.write(data, (addr, port))
Surely, you have the ability to send without listening for incoming messages.
As it turns out, no. However, nothing compels you to do anything with any incoming messages that arrive.
I need to create an independent class that provides an RPC server running in its own Python process using wamp and autobahn.
Following some guides found here, I managed to create this server in these classes saved into the file rpcwampserver.py:
from twisted.internet.defer import inlineCallbacks
from autobahn.twisted.wamp import ApplicationSession, ApplicationRunner
import multiprocessing
from twisted.internet import reactor
class Manager(ApplicationSession):
#inlineCallbacks
def onJoin(self, details):
print("session ready")
def test():
return u'hello!'
try:
yield self.register(test, u'rpc.test')
print("procedure registered")
except Exception as e:
print("could not register procedure: {0}".format(e))
class RPCWampServer:
def __init__(self):
self._url = u'ws://localhost:8080/ws'
self.real = u'realm'
self.runner = ApplicationRunner(url=self._url, realm=self.realm,
#debug=True, debug_wamp=True, debug_app=True
)
def start(self):
self.runner.run(Manager, start_reactor=False)
class RPC_Wamp_Server:
def __init__(self):
server = RPCWampServer()
server.start()
multi = multiprocessing.Process(target=reactor.run,args=())
multi.start()
If RPC_Wamp_Server is imported directly into a file close to rpcwampserver.py the the code works fine:
from rpcwampserver import RPC_Wamp_Server
c=RPC_Wamp_Server()
BUT
If I use this class inside a package located in a different path, the reactor doesn't work:
from mymodules.wamp.rpcwampserver import RPC_Wamp_Server
c=RPC_Wamp_Server()
The class RPC_Wamp_Server is found but the initialization of the Manager seems to be skipped.
Enabling the debug (commented in the code) it appears:
Starting factory [...]
and after a while
Stopped factory [...]
EDIT:
Using 127.0.0.1 instead of localhost solved the problem
I am trying to build a simple "quote of the day" server and client modified from the twisted tutorial documentation. I want the "quote of the day" to be printed from the client to prove the communication. However, from what I can tell the client is not connecting. Here is my code.
Server
from twisted.python import log
from twisted.internet.protocol import Protocol
from twisted.internet.protocol import Factory
from twisted.internet.endpoints import TCP4ServerEndpoint
from twisted.internet import reactor
class QOTD(Protocol):
def connectionMade(self):
self.transport.write("An apple a day keeps the doctor away\r\n")
self.transport.loseConnection()
class QOTDFactory(Factory):
def buildProtocol(self, addr):
return QOTD()
# 8007 is the port you want to run under. Choose something >1024
endpoint = TCP4ServerEndpoint(reactor, 8007)
endpoint.listen(QOTDFactory())
reactor.run()
Client
import sys
from twisted.python import log
from twisted.internet import reactor
from twisted.internet.protocol import Factory, Protocol
from twisted.internet.endpoints import TCP4ClientEndpoint
class SimpleClient(Protocol):
def connectionMade(self):
log.msg("connection made")
#self.transport.loseConnection()
def lineReceived(self, line):
print "receive:", line
class SimpleClientFactory(Factory):
def buildProtocol(self, addr):
return SimpleClient()
def startlog():
log.startLogging(sys.stdout)
point = TCP4ClientEndpoint(reactor, "localhost", 8007)
d = point.connect(SimpleClientFactory)
reactor.callLater(0.1, startlog)
reactor.run()
pass instance of SimpleClientFactory, not the class itself to point.connect()
subclass SimpleClient from twisted.protocol.basic.LineReceiver instead of Protocol if you use lineReceived
call addErrback on the results of endpoint.listen and point.connect to handle errors