I am making a XMPP middleware in python which listens on a an address(host,port) and when it receives some connection on that port, it sends a XMPP message to a jid(XMPP user) on a server.
A quick review of my setup
For networking part I am using twisted
For XMPP - SleekXMPP
XMPP server - Openfire
Now when I tried using sleekXMPP without importing anything from twistedm it was working fine.
However I i try to mix sleekXMPP and twisted in one program (by importing them) I get the follwing error.
Traceback (most recent call last):
File "sleekXMPP/prog_3.py", line 124, in <module>
main()
File "sleekXMPP/prog_3.py", line 111, in main
xmppThread = ClientThread(dir_q)
File "sleekXMPP/prog_3.py", line 41, in __init__
self.xmpp = xmppClient(self.jid, self.password)
File "sleekXMPP/prog_3.py", line 17, in __init__
sleekxmpp.ClientXMPP.__init__(self, jid, password)
File "build\bdist.win32\egg\sleekxmpp\clientxmpp.py", line 65, in __init__
File "build\bdist.win32\egg\sleekxmpp\basexmpp.py", line 72, in __init__
File "build\bdist.win32\egg\sleekxmpp\jid.py", line 461, in __init__
File "build\bdist.win32\egg\sleekxmpp\jid.py", line 150, in _parse_jid
File "build\bdist.win32\egg\sleekxmpp\jid.py", line 202, in _validate_domain
File "C:\Python27\lib\site-packages\twisted-12.2.0-py2.7-win32.egg\twisted\python \compat.py", line 22, in inet_pton
raise ValueError("Illegal characters: %r" % (''.join(x),))
ValueError: Illegal characters: u't'
The code is as follows:
import sleekxmpp
import ssl
import Queue
import threading
import time
import logging
import traceback
import sys
from twisted.internet import reactor, protocol , endpoints
class xmppClient(sleekxmpp.ClientXMPP):
"""
This class defines the xmppClient object used to interact with the XMPP server
"""
def __init__(self, jid, password):
# the constructor
sleekxmpp.ClientXMPP.__init__(self, jid, password)
self.add_event_handler('session_start', self.start)
def start(self, event):
self.send_presence()
self.get_roster()
def send_note(self):
self.mssg = r"Hello from XMPP Service"
self.recipient = r"testuser2#ghost"
self.send_message(mto=self.recipient,
mbody=self.mssg,
mtype='chat')
print "Message sent"
class ClientThread(threading.Thread):
def __init__(self, dir_q):
super(ClientThread, self).__init__()
self.dir_q = dir_q
self.stoprequest = threading.Event()
self.jid = 'testuser1#ghost'
self.password = 'password'
self.xmpp = xmppClient(self.jid, self.password)
self.xmpp.register_plugin('xep_0030') # Service Discovery
self.xmpp.register_plugin('xep_0004') # Data Forms
self.xmpp.register_plugin('xep_0060') # PubSub
self.xmpp.register_plugin('xep_0199') # XMPP Ping
self.xmpp.ssl_version = ssl.PROTOCOL_SSLv3
if self.xmpp.connect():
print("Connected")
self.xmpp.process(block=False)
else:
print("Unable to connect.")
def run(self):
while not self.stoprequest.isSet():
try:
req = self.dir_q.get(True, 0.05)
if req == 1:
self.xmpp.send_note()
except Queue.Empty:
continue
def join(self, timeout=None):
self.stoprequest.set()
super(ClientThread, self).join(timeout)
class reqSimulator(threading.Thread):
def __init__(self, dir_q):
super(reqSimulator, self).__init__()
self.dir_q = dir_q
def run(self):
while(1):
self.dir_q.put(1)
time.sleep(0.5)
"""class sendProtocol(protocol.Protocol):
def connectionMade(self):
r = reqSimulator(self.factory.dir_q)
r.run()
def connectionLost(self, reason):
pass
def dataReceived(self, data):
self.transport.loseConnection()"""
def main():
logging.basicConfig()
dir_q = Queue.Queue()
xmppThread = ClientThread(dir_q)
xmppThread.start()
sim = reqSimulator(dir_q)
"""factory = protocol.ServerFactory()
factory.dir_q = dir_q
factory.protocol = sendProtocol
endpoints.serverFromString(reactor, "tcp:8001").listen(factory)
reactor.run()
"""
sim.start()
if __name__ == "__main__":
main()
Note that in this code, the actual networking code is commented and I am using a reqSimulator class to simulate the oncoming requests.
I tried to google for any issued but got no result. Does anybody have an idea what is wrong here?
This is due to the fact that Twisted implements inet_pton for Windows, but uses different exceptions for failures than the stdlib version.
I've fixed Sleek on github for this (master and develop branches), and there will be a new point release for it shortly.
Related
Hy, I'm created a AmazonMQ using broker as RabbitMQ. Now I want to publish a message and read that message from the queue using python. So I followed the steps given in the AWS docs.
Link: Using Python Pika with Amazon MQ for RabbitMQ
I follow the same steps in docs but when I tried to send a message to the queue it gives me this error!
Traceback (most recent call last):
File "E:/Axcer/Using-Python-Pika-with-Amazon-MQ-for-RabbitMQ/publisher.py", line 26, in
basic_message_sender = BasicMessageSender(
File "E:\Axcer\Using-Python-Pika-with-Amazon-MQ-for-RabbitMQ\basicClient.py", line 15, in init
parameters = pika.URLParameters(url)
File "E:\Axcer\Using-Python-Pika-with-Amazon-MQ-for-RabbitMQ\Intern\lib\site-packages\pika\connection.py", line 757, in init
if parts.port is not None:
File "C:\Users\Yomal\Python38-32\lib\urllib\parse.py", line 174, in port
raise ValueError(message) from None
ValueError: Port could not be cast to integer value as 'xxxxxyyyy'
I have really no Idea about this issue! I hope that someone can help me with this. Thank you!
basicClient.py
import ssl
import pika
class BasicPikaClient:
def __init__(self, rabbitmq_broker_id, rabbitmq_user, rabbitmq_password, region):
# SSL Context for TLS configuration of Amazon MQ for RabbitMQ
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
ssl_context.set_ciphers('ECDHE+AESGCM:!ECDSA')
url = f"amqps://{rabbitmq_user}:{rabbitmq_password}#{rabbitmq_broker_id}.mq.{region}.amazonaws.com:5671"
parameters = pika.URLParameters(url)
parameters.ssl_options = pika.SSLOptions(context=ssl_context)
self.connection = pika.BlockingConnection(parameters)
self.channel = self.connection.channel()
publisher.py
from basicClient import BasicPikaClient
class BasicMessageSender(BasicPikaClient):
def declare_queue(self, queue_name):
print(f"Trying to declare queue({queue_name})...")
self.channel.queue_declare(queue=queue_name)
def send_message(self, exchange, routing_key, body):
channel = self.connection.channel()
channel.basic_publish(exchange=exchange,
routing_key=routing_key,
body=body)
print(f"Sent message. Exchange: {exchange}, Routing Key: {routing_key}, Body: {body}")
def close(self):
self.channel.close()
self.connection.close()
if __name__ == "__main__":
# Initialize Basic Message Sender which creates a connection
# and channel for sending messages.
basic_message_sender = BasicMessageSender(
"*******************",
"xxxxx",
"xxxxxyyyy#zzzzzzz",
"********"
)
# Declare a queue
basic_message_sender.declare_queue("hello world queue")
# Send a message to the queue.
basic_message_sender.send_message(exchange="", routing_key="hello world queue", body=b'Hello World!')
# Close connections.
basic_message_sender.close()
I am writing a custom SSL proxy with Twisted. I keep running in to an issue that happens every so often and I cant figure out what the problem is.
When I try to connect the client transport to the server's transport through the registerProducer function exactly as twisted.protocols.portforward functions I keep getting this error.
File "/opt/Memory/Mobile/Proxy/forwarder.py", line 40, in connectionMade
self.peer.transport.registerProducer(self.transport, True)
File "/usr/lib/python3.9/site-packages/twisted/protocols/tls.py", line 602, in registerProducer
self.transport.registerProducer(producer, True)
File "/usr/lib/python3.9/site-packages/twisted/internet/_newtls.py", line 233, in registerProducer
FileDescriptor.registerProducer(self, producer, streaming)
File "/usr/lib/python3.9/site-packages/twisted/internet/abstract.py", line 104, in registerProducer
raise RuntimeError(
builtins.RuntimeError: Cannot register producer <twisted.protocols.tls._ProducerMembrane object at 0x7fb5799f0910>, because producer <twisted.protocols.tls._ProducerMembrane object at 0x7fb579b474c0> was never unregistered.
Here are my Inherited Classes from twisted?
from twisted.internet import reactor
from twisted.internet import ssl
from twisted.protocols import portforward
from twisted.internet import protocol
from twisted.python import log
import sys
##SSLProxy base class that will be inherited
class SSLProxy(protocol.Protocol):
noisy = True
peer = None
def setPeer(self, peer):
#log.msg("SSLProxy.setPeer")
self.peer = peer
def connectionLost(self, reason):
#log.msg("SSLProxy.connectionLost")
if self.peer is not None:
self.peer.transport.loseConnection()
self.peer = None
elif self.noisy:
log.msg("Unable to connect to peer: {}".format(reason))
def dataReceived(self, data):
#log.msg("SSLProxy.dataReceived")
if self.peer is not None:
self.peer.transport.write(data)
##Foward data from Proxy to => Remote Server
class SSLProxyClient(SSLProxy):
def connectionMade(self):
#log.msg("SSLProxyClient.connectionMade")
self.peer.setPeer(self)
self.transport.registerProducer(self.peer.transport, True)
self.peer.transport.registerProducer(self.transport, True)
# We're connected, everybody can read to their hearts content.
self.peer.transport.resumeProducing()
class SSLProxyClientFactory(protocol.ClientFactory):
protocol = SSLProxyClient
def setServer(self, server):
#log.msg("SSLProxyClientFactory.setServer")
self.server = server
def buildProtocol(self, *args, **kw):
#log.msg("SSLProxyClientFactory.buildProtocol")
prot = protocol.ClientFactory.buildProtocol(self, *args, **kw)
prot.setPeer(self.server)
return prot
def clientConnectionFailed(self, connector, reason):
#log.msg("SSLProxyClientFactory.clientConnectionFailed")
self.server.transport.loseConnection()
class SSLProxyServer(SSLProxy):
clientProtocolFactory = SSLProxyClientFactory
reactor = None
def connectionMade(self):
log.msg("SSLProxyServer.connectionMade")
#Get Current SSL Context
ssl_context = self.transport._tlsConnection.get_context()
#Hack to get SNI to do two functions in diffrent classes
ssl_context._finishSNI = self.SNICallback
def SNICallback(self, connection):
#log.msg("SSLProxyServer.SNICallback: {}".format(connection))
#print(connection.get_context().new_host)
self.transport.pauseProducing()
#self.transport.transport.pauseProducing()
#print(dir())
self.dst_host, self.dst_port = connection.get_context().new_host
#Setup Clients
self.client = self.clientProtocolFactory()
self.client.setServer(self)
#Start stuff
log.msg('Redirecting to {}:{}'.format(self.dst_host, self.dst_port))
if self.reactor is None:
self.reactor = reactor
log.msg("Making Connection to Dest Server: {}:{}".format(self.dst_host, self.dst_port))
self.reactor.connectSSL(self.dst_host, self.dst_port, self.client, ssl.ClientContextFactory())
#self.transport.resumeProducing()
#Client -> Proxy
def dataReceived(self, data):
log.msg("SSLProxyServer.dataReceived: {}".format(data))
#Call Inherited Function
super().dataReceived(data)
class SSLProxyFactory(protocol.Factory):
"""Factory for port forwarder."""
protocol = SSLProxyServer
def __init__(self):
super().__init__()
#log.msg("SSLProxyFactory.__init__")
def sslToSSL(localport, remotehost, remoteport, serverContextFactory):
log.msg("SSL on localhost:{} forwarding to SSL {}:{}".format(localport, remotehost, remoteport))
return reactor.listenSSL(localport, SSLProxyFactory(), serverContextFactory)
Any guidance would be appreciated.
I found that if you just unregister the current Producer you can register the new one.
##Foward data from Proxy to => Remote Server
class SSLProxyClient(SSLProxy):
def connectionMade(self):
#log.msg("SSLProxyClient.connectionMade")
self.peer.setPeer(self)
self.transport.registerProducer(self.peer.transport, True)
self.peer.transport.unregisterProducer()
self.peer.transport.registerProducer(self.transport, True)
# We're connected, everybody can read to their hearts content.
self.peer.transport.resumeProducing()
I've been learning Twisted as best I can, but together with limited TLS knowledge it's proving challenging. I'm trying to write (ultimately) an SMTP server that can send and receive messages both as plain text, or via TLS depending on requirements of a specific message to be sent / received.
My sample server code (thus far, just handling the TLS connection, no SMTP bits yet!) is borrowed from http://twistedmatrix.com/documents/11.0.0/core/howto/ssl.html#auto5 and looks like:
from OpenSSL import SSL
from twisted.internet import reactor, ssl
from twisted.internet.protocol import ServerFactory
from twisted.protocols.basic import LineReceiver
class TLSServer(LineReceiver):
def lineReceived(self, line):
print "received: " + line
if line == "STARTTLS":
print "-- Switching to TLS"
self.sendLine('READY')
ctx = ServerTLSContext(
privateKeyFileName='SSCerts/serverkey.pem',
certificateFileName='SSCerts/servercert.pem',
)
self.transport.startTLS(ctx, self.factory)
class ServerTLSContext(ssl.DefaultOpenSSLContextFactory):
def __init__(self, *args, **kw):
kw['sslmethod'] = SSL.TLSv1_METHOD
ssl.DefaultOpenSSLContextFactory.__init__(self, *args, **kw)
if __name__ == '__main__':
factory = ServerFactory()
factory.protocol = TLSServer
reactor.listenTCP(8000, factory)
reactor.run()
while the client is borrowed from http://twistedmatrix.com/documents/14.0.0/core/howto/ssl.html#starttls-client and looks like:
from twisted.internet import ssl, endpoints, task, protocol, defer
from twisted.protocols.basic import LineReceiver
from twisted.python.modules import getModule
class StartTLSClient(LineReceiver):
def connectionMade(self):
self.sendLine("plain text")
self.sendLine("STARTTLS")
def lineReceived(self, line):
print("received: " + line)
if line == "READY":
self.transport.startTLS(self.factory.options)
self.sendLine("secure text")
self.transport.loseConnection()
#defer.inlineCallbacks
def main(reactor):
factory = protocol.Factory.forProtocol(StartTLSClient)
certData = getModule(__name__).filePath.sibling('servercert.pem').getContent()
factory.options = ssl.optionsForClientTLS(
u"example.com", ssl.PrivateCertificate.loadPEM(certData)
)
endpoint = endpoints.HostnameEndpoint(reactor, 'localhost', 8000)
startTLSClient = yield endpoint.connect(factory)
done = defer.Deferred()
startTLSClient.connectionLost = lambda reason: done.callback(None)
yield done
if __name__ == "__main__":
import starttls_client
task.react(starttls_client.main)
But when I have the server listening, and I run the client I get:
/usr/lib64/python2.6/site-packages/twisted/internet/endpoints.py:30: DeprecationWarning: twisted.internet.interfaces.IStreamClientEndpointStringParser was deprecated in Twisted 14.0.0: This interface has been superseded by IStreamClientEndpointStringParserWithReactor.
from twisted.internet.interfaces import (
main function encountered error
Traceback (most recent call last):
File "starttls_client.py", line 33, in <module>
task.react(starttls_client.main)
File "/usr/lib64/python2.6/site-packages/twisted/internet/task.py", line 875, in react
finished = main(_reactor, *argv)
File "/usr/lib64/pytho
n2.6/site-packages/twisted/internet/defer.py", line 1237, in unwindGenerator
return _inlineCallbacks(None, gen, Deferred())
--- <exception caught here> ---
File "/usr/lib64/python2.6/site-packages/twisted/internet/defer.py", line 1099, in _inlineCallbacks
result = g.send(result)
File "/root/Robot/Twisted/starttls_client.py", line 22, in main
u"example.com", ssl.PrivateCertificate.loadPEM(certData)
File "/usr/lib64/python2.6/site-packages/twisted/internet/_sslverify.py", line 619, in loadPEM
return Class.load(data, KeyPair.load(data, crypto.FILETYPE_PEM),
File "/usr/lib64/python2.6/site-packages/twisted/internet/_sslverify.py", line 725, in load
return Class(crypto.load_privatekey(format, data))
File "build/bdist.linux-x86_64/egg/OpenSSL/crypto.py", line 2010, in load_privatekey
File "build/bdist.linux-x86_64/egg/OpenSSL/_util.py", line 22, in exception_from_error_queue
OpenSSL.crypto.Error: []
The strange thing is - I know the certificate and key are fine - I have other "dummy" code (not pasted here, I figured this post is long enough!!) that uses them for validation just fine. Can anyone explain where the code above falls over? I'm at a loss...
Thanks :)
So it looks like there is a bug in the sample code found at: http://twistedmatrix.com/documents/14.0.0/core/howto/ssl.html
Looking at the example "echoclient_ssl.py" there is the line:
authority = ssl.Certificate.loadPEM(certData)
However, the equivalent bit of code in the "starttls_client.py" example code is:
ssl.PrivateCertificate.loadPEM(certData)
PrivateCertificate on the client side? Even with my limited understanding of TLS, this seems wrong. Indeed, I modified my code to remove the "Private"... and the error above disappears!
As I say, my knowledge and understanding is growing here - but this certainly seems to be the issue / solution to my question!
I'm trying to build a client/server system that clients send messages to server. Server does nothing more than printing out what clients send.
from twisted.internet import protocol, reactor
class Echo(protocol.Protocol):
def dataReceived(self, data):
print data
self.transport.write(data)
class EchoFactory(protocol.Factory):
def buildProtocol(self, addr):
return Echo()
reactor.listenTCP(8000, EchoFactory())
reactor.run()
The issue is that when I tried to send multiple message from client with this code, the client raises an error after the first connection and send.
from twisted.internet import reactor, protocol
import time
class EchoClient(protocol.Protocol):
def __init__(self, message):
self.message = message
def connectionMade(self):
self.transport.write(self.message)
def dataReceived(self, data):
print "Server said:", data
self.transport.loseConnection()
class EchoFactory(protocol.ClientFactory):
def __init__(self, message):
self.message = message
def buildProtocol(self, addr):
return EchoClient(self.message)
def clientConnectionFailed(self, connector, reason):
print "Connection failed."
reactor.stop()
def clientConnectionLost(self, connector, reason):
print "Connection lost."
reactor.stop()
def sendMessage(message):
reactor.connectTCP("localhost", 8000, EchoFactory(message))
reactor.run()
if __name__ == "__main__":
while True:
r = raw_input(">")
if r == 'q' or len(r) == 0: break
sendMessage(r)
What might be wrong? this is the error message.
>a
Server said: a
Connection lost.
>b
Traceback (most recent call last):
File "echoclient.py", line 38, in <module>
sendMessage(r)
File "echoclient.py", line 32, in sendMessage
reactor.run()
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/twisted/internet/base.py", line 1168, in run
self.startRunning(installSignalHandlers=installSignalHandlers)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/twisted/internet/base.py", line 1148, in startRunning
ReactorBase.startRunning(self)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/twisted/internet/base.py", line 680, in startRunning
raise error.ReactorNotRestartable()
twisted.internet.error.ReactorNotRestartable
Although this question is old and has two irrelevant answers, I would like to answer it for the people who are eager to know. The problem is that in your server code in the dataReceived method you have self.transport.write(data) (which sends every message that it receives to the client), and at the same time in your client code, again in the dataReceived method you have the command self.transport.loseConnection() (which looses the connection to the server as soon as a message comes in). So, if you remove any of these lines you should be fine. In the current setting the first message sent from client will be sent back to the client and that will cause a connection disconnect.
Also, you are calling reactor.run () at each attempt for sending a message. Reactor.run should be called only once preferably in the main function.
The reactor is not restartable.
For my own purposes, using socket to send messages to server works fine.
import socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(('localhost', 8000))
while True:
a = raw_input("> ")
if a == 'q' or len(a) == 0:
client_socket.close()
break
else:
client_socket.send(a)
I am trying to send a message on facebook chat with sleekXMPP, using the answer from here as a boilerplate: Send a Facebook Message with XMPP using Access Tokens in Python
My code is
import sleekxmpp
class SendMsgBot(sleekxmpp.ClientXMPP):
def init(self, jid, recipient, message):
print "..."
sleekxmpp.ClientXMPP.__init__(self, jid, 'ignore')
self.recipient = recipient
self.msg = message
self.add_event_handler("session_start", self.start, threaded=True)
def start(self, event):
self.send_presence()
self.get_roster()
self.send_message(mto=self.recipient, mbody=self.msg, mtype='chat')
self.disconnect(wait=True)
if __name__ == "__main__":
xmpp = SendMsgBot(from_id, to_id, unicode(message))
xmpp.credentials['apikey'] = api_key
xmpp.credentials['accesstoken'] = o_auth_token
if xmpp.connect(('chat.facebook.com', 5222)):
xmpp.process(block=True)
print("Done")
else:
print("Unable to connect")
However, when I run the script I get this error message:
Traceback (most recent call last):
File "sendMessagesScript.py", line 33, in <module>
xmpp = SendMsgBot(from_id, to_id, unicode(message))
File "/Library/Python/2.7/site-packages/sleekxmpp/clientxmpp.py", line 112, in __init__
self.register_plugin('feature_starttls')
File "/Library/Python/2.7/site-packages/sleekxmpp/basexmpp.py", line 264, in register_plugin
pconfig = self.plugin_config.get(plugin, {})
AttributeError: 'unicode' object has no attribute 'get'
Any ideas would be appreciated!
In the class SendMsgBot(sleekxmpp.ClientXMPP):, you need to change
def init(self, jid, recipient, message) to def __init__(self, jid, recipient, message)
I hope it will work.
Additionally, it seems that some important dashes have been ommitted from the original code.
I also had to change
xmpp.credentials['apikey'] = api_key
xmpp.credentials['accesstoken'] = o_auth_token
to
xmpp.credentials['api_key'] = api_key
xmpp.credentials['access_token'] = o_auth_token
These are apparently the parameter names that Facebook expects, as you can see in Facebook's PHP example