How can I debug a connection issue within VOLTTRON? - python

I am connecting to an external VOLTTRON instance. I am not getting a response from the connection. What's the issue?
I am writing a simple python script to connect to an external platform and retrieve the peers. If I get the serverkey, clientkey, and/or publickey incorrect I don't know how to determine which is the culprit, from the client side. I just get a gevent timeout. Is there a way to know?
import os
import gevent
from volttron.platform.vip.agent import Agent
secret = "secret"
public = "public"
serverkey = "server"
tcp_address = "tcp://external:22916"
agent = Agent(address=tcp_address, serverkey=serverkey, secretkey=secret,
publickey=public)
event = gevent.event.Event()
greenlet = gevent.spawn(agent.core.run, event)
event.wait(timeout=30)
print("My id: {}".format(agent.core.identity))
peers = agent.vip.peerlist().get(timeout=5)
for p in peers:
print(p)
gevent.sleep(3)
greenlet.kill()

The short answer: no, the client cannot determine why its connection to the server failed. The client will attempt to connect until it times out.
Logs and debug messages on the server side can help troubleshoot a connection problem. There are three distinct messages related to key errors:
CURVE I: cannot open client HELLO -- wrong server key?
Either the client omit the server key, the client used the wrong server key, or the server omit the secret key.
CURVE I: cannot open client INITIATE vouch
Either the client omit the public or secret key, or its public and secret keys don't correspond to each other.
authentication failure
The server key was correct and the secret and public keys are valid, but the server rejected the connection because the client was not authorized to connect (based on the client's public key).
The first two messages are printed by libzmq. To see the third message volttron must be started with increased verboseness (at least -v).
Here is a simple ZMQ server-client example you can use to test some of these scenarios:
Server:
import zmq
context = zmq.Context()
socket = context.socket(zmq.REP)
socket.curve_server = 1
socket.curve_secretkey = "mW4i2O{kmcOXs9q>UP0(no4-Sp1r(p>vK?*NFwV$"
# The corresponding public key is "krEC0>hsx+o4Jxg2yvitCOVwr2GF85akNIsUdiH5"
socket.bind("ipc://test123")
while True:
msg = socket.recv()
new_msg = "I got the message: {}".format(msg)
print(new_msg)
socket.send(new_msg)
Client:
import zmq
pub, sec = zmq.curve_keypair()
context = zmq.Context()
socket = context.socket(zmq.REQ)
socket.curve_secretkey = sec
socket.curve_publickey = pub
socket.curve_serverkey = "krEC0>hsx+o4Jxg2yvitCOVwr2GF85akNIsUdiH5"
socket.connect("ipc://test123")
socket.send(b'Hello')
msg = socket.recv()
print("From the server: {}".format(msg))

Related

Unable to send or recieve emails from python aiosmtpd SMTP server, stuck at 250 ok [duplicate]

This question already has an answer here:
aiosmtpd - python smtp server
(1 answer)
Closed 3 months ago.
I had "successfully" made an SMTP server. The code works fine connecting to SMTP clients. But it is neither able to recieve emails nor send it. I tried with various test servers and also the standard gmail/yahoo etc.
Here is the code:
# Copyright 2014-2021 The aiosmtpd Developers
# SPDX-License-Identifier: Apache-2.0
import asyncio
from asyncio.base_events import Server
import logging
import aiosmtpd
from aiosmtpd.controller import DEFAULT_READY_TIMEOUT, Controller
import ssl
from aiosmtpd.smtp import Envelope, Session
from smtplib import SMTP as SMTPCLient
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context.load_cert_chain('cert.pem', 'privkey.pem')
class ExampleHandler():
async def handle_RCPT(self, server, session, envelope, address, rcpt_options):
if address.endswith('#example.com'):
print('not relaying to that domain bro :(')
return '550 not relaying to that domain'
envelope.rcpt_tos.append(address)
print(address+" "+"is added to rcpt_tos")
# Make an envelope for the recipient with the same content.
return '250 OK'
# async def handle_EHLO(self, server, session, envelope):
# print('EHLO from %s' % envelope.mail_from)
# return '250-Hello, how are you?\n250-I am fine\n250 HELP'
async def handle_DATA(self, server, session, envelope):
print('Message from %s' % envelope.mail_from)
print('Message for %s' % envelope.rcpt_tos)
print('Message data:\n')
for ln in envelope.content.decode('utf8', errors='replace').splitlines():
print(f'> {ln}'.strip())
print()
print('End of message')
# Dump the contents of envelope.content to a file.
fi=open('./mailbox/firstletter.txt','w')
fi.write(envelope.content.decode('utf8', errors='replace'))
fi.close()
# print everything in DATA.
# Send the envelope to the recipient.
return '250 Message will be delivered'
#Define Relay server.
async def amain(loop):
cont = Controller(ExampleHandler(),hostname='x.x.x.x', port=25, server_hostname='Galam Limited',ready_timeout=5000)
# Combining ExampleHandler and Controller into a single Controller.
cont.start()
if __name__ == '__main__':
logging.basicConfig(level=logging.DEBUG)
loop = asyncio.get_event_loop()
loop.create_task(amain(loop=loop))
try:
loop.run_forever()
except KeyboardInterrupt:
pass
You can test the server reachability . I am stuck and spent 2 whole days to no avail. The issue is definetely not connectivity, I put the port 25 open. Made sure there are no external issues with godaddy either. Any help will be appreicated.
Edit:1
A quick peak at the wire shark data shows absolutely no packet is being transmitted to the outside when I run the client script.
Here is the clinet script I used for testing.
from smtplib import SMTP as Client
from aiosmtpd.controller import Controller
class controller:
hostname='192.168.1.33'
port=25
client = Client(controller.hostname, controller.port)
r = client.sendmail('a#galam.in', ['tester#192.168.1.200'], """\
From: Anne Person <anne#galam.in>
To: Bart Person <tester#192.168.1.200>
Subject: A test
Message-ID: <ant>
Hi Bart, this is Anne.
""")
SMTP 250 code means that a successful connection has been established however the remote host you are sending mails to might have categorized the domain the mail is being sent from as not legitimate.
This can happen if your domain is not authenticated/verified.
You can relay your messages through a trusted SMTP service like sendgrid
You can also check if your domain is verified by sending a mail from your service to check-auth#verifier.port25.com. Port25 is an automated tool that verified your DNS records, SPF records etc.
Hope this works for you!

ZeroMQ - N-to-N server communication for a consensus negotiation

I am implementing a consensus algorithm (raft) where 5 servers have to communicate together asynchronously to manage a replicated log.
I am using python and multiprocessing package to run 5 processes acting as servers, and ØMQ (pyzmq) to handle communications between servers.
I drafted a first design and I am wondering about a few things:
I have 5 servers, and I hardcode 5 "identities" I configure sockets with. For each server, I am using two ROUTER sockets:
the first one is binding to the server's identity (this socket is responsible for receiving others messages)
the other one is connecting to the other servers' identities (this one is responsible for sending messages)
It looks strange to me to use two ROUTER sockets on the same node/server, but I do not find better : is there a more elegant way to proceed?
I tried to use only one ROUTER socket per server, i.e a socket that sets its identity, binds on its given port, and connects to the others, but this 'connect' step on each side doesn't work : what is the reason for that?
Here is a simple example with 3 servers:
import time
from threading import Thread
from typing import List
import zmq
SEND_RULE = {
'5555': '6666',
'6666': '7777',
'7777': '5555'
}
def worker(socket_port: str, peer_ports: List[str]):
context = zmq.Context()
receiving_socket = context.socket(zmq.ROUTER)
receiving_socket.setsockopt(zmq.IDENTITY, socket_port.encode())
receiving_socket.bind(f'tcp://*:{socket_port}')
sending_socket = context.socket(zmq.ROUTER)
sending_socket.setsockopt(zmq.IDENTITY, socket_port.encode())
for peer_port in peer_ports:
sending_socket.connect(f'tcp://localhost:{peer_port}')
time.sleep(1)
recipient_id = SEND_RULE[socket_port].encode()
message_for_recipient = b'coucou!'
print(socket_port, ' sending a message to ', recipient_id.decode())
sending_socket.send_multipart([recipient_id, message_for_recipient])
# Receive a message from peer
sender_id, sender_message = receiving_socket.recv_multipart()
print( socket_port,
' server received: ',
sender_message.decode(),
' from: ',
sender_id.decode()
)
if __name__ == '__main__':
socket_ports = ['5555', '6666', '7777']
for socket_port in socket_ports:
Thread( target = worker,
args = ( socket_port,
[ port for port in socket_ports
if port != socket_ports ]
)
).start()
time.sleep(3)

Websocket Client not receiving any messages

I have Python client which opens a websocket connection to a server and subscribes to particular topic using STOMP protocol, subscription goes just fine as i see on the server all is fine. However, When the server publishes a few messages the client does not receive any.
Here are the codes used:
Client
# coding: utf-8
import websocket
import stomp
import stomper
token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsInByaW5jaXBhbF9uYW1lIjoiYWRtaW4iLCJpc3MiOiJBdGhlbmEiLCJ1c2VydHlwZSI6IkxPQ0FMIiwiYW9zX3ZlcnNpb24iOiJldXBocmF0ZXMtNS4xMS1zdGFibGUiLCJyZWdpb24iOiJlbi1VUyIsImV4cCI6MTczNDI4MDI3NywidXVpZCI6ImI4MzhjOGRkLWI4NmQtNGNkZS05ZTE4LTUxM2E1OTk4ODhhYyIsImlhdCI6MTU3NjYwMDI3NywiYXV0aG9yaXRpZXMiOiJST0xFX0NMVVNURVJfQURNSU4sUk9MRV9NVUxUSUNMVVNURVJfQURNSU4sUk9MRV9VU0VSX0FETUlOLFJPTEVfQ0xVU1RFUl9WSUVXRVIiLCJqdGkiOiI1NTU1ZjEwZC04NGQ5LTRkZGYtOThhNC1mZmI1OTM1ZTQwZWEifQ.LOMX6ppkcSBBS_UwW9Qo2ieWZAGrKqADQL6ZQuTi2oieYa_LzykNiGMWMYXY-uw40bixDcE-aVWyrIEZQbVsvA"
headers = {"Authorization": "Bearer " + token}
uri = "ws://127.0.0.1:8765/notifications/websocket"
def on_msg(ws, msg):
print(msg)
def on_error(ws, err):
print(err)
def on_closed(ws):
print("#Closed#")
def on_open(ws):
sub = stomper.subscribe("/user/queue/alert", "MyuniqueId", ack="auto")
ws.send(sub)
headers = {"Authorization": "Bearer " + token}
websocket.enableTrace(True)
ws = websocket.WebSocketApp(uri, header=headers, on_message=on_msg, on_error=on_error, on_close=on_closed)
ws.on_open = on_open
ws.run_forever()
Code server uses to publish the message:
for (WatchesSubscription s : subscriptions) {
template.convertAndSendToUser(s.getSession().getUser(), destination, dto);
}
When i checked out the value of the above variables i saw that destination was as expected queue/alerts. I have java client to test out as well and it works just fine. I have even tried this by subscribing to /topic/alerts and sending to it via template.convertAndSend(/topic/alerts), here too i received nothing. I am a drawing a complete blank on this and would appreciate any sort of help!
After many days of hair pulling I finally figured out the reason and the fix!
The java client I used was
WebSocketStompClient stompClient = new WebSocketStompClient(transport);.The stompClient.connect(URL, webSocketHttpHeaders, sessionHandler); method implicitly sends a stomp CONNECT\n\n\x00\n
The Springboot server which has been configured for STOMP understands this as a connection request and responds with a CONNECT_ACK.
When this ACK is sent it also updates it's local UserRegistry with the new user. So the internal message broker knows that there is a user who has subscribed to so-and-so topic.
In my Python code, i had merely opened a Websocket connection and after that directly sent a SUBSCRIBE message. So the broker never got a CONNECT so the user was never stored! This resulted in the messages later on being published to be merely discarded by the broker.
The fix was to send a CONNECT\n\n\x00\n after opening up the connection and before the subscription. Here is the code:
def on_open(ws):
#The magic happens here!
ws.send("CONNECT\naccept-version:1.0,1.1,2.0\n\n\x00\n")
sub = stomper.subscribe("/user/queue/alert", "MyuniqueId", ack="auto")
ws.send(sub)

Event hub Send failed MessageSendResult.Timeout Python

I have been having some issues with timeouts while sending messages to EventHub.
import sys
import logging
import datetime
import time
import os
from azure.eventhub import EventHubClient, Sender, EventData
logger = logging.getLogger("azure")
ADDRESS = "xxx"
USER = "xxx"
KEY = "xxx"
ENDPOINT = "xxx"
try:
if not ADDRESS:
raise ValueError("No EventHubs URL supplied.")
# Create Event Hubs client
client = EventHubClient(ADDRESS, username=USER, password=KEY, debug=True)
sender = client.add_sender(partition="0", send_timeout=300, keep_alive=10)
client.run()
try:
start_time = time.time()
for i in range(10000):
print("Sending message: {}".format(i))
message = "Message {}".format(i)
sender.send(EventData(message))
except:
raise
finally:
end_time = time.time()
client.stop()
run_time = end_time - start_time
logger.info("Runtime: {} seconds".format(run_time))
except KeyboardInterrupt:
pass
My context is as follow; i am able to send messages without problem from my personal development computer, from a virtual machine in Azure, and from on premises server1, but when trying to send messages to on premises server2 i receive the error:
azure.eventhub.common.EventHubError: Send failed: Message send failed with result: MessageSendResult.Timeout
I have tried modifying the send_timeout and the keep_alive (even though i dont belive this configurations are to blame) but with no success, my personal guess is that there is something in my on premises server2 that is blocking or interfering with my communication. Firstly, am i changing the timeout value correctly? i have checked the source code of the class here: link but it seems i am doing it right, but i actually belive such property implies the time after the message is in the queue for sending instead of how long we wait for the response of the event. Secondly, is there a way i can validate that the problem relies on the envoiroment of my on premises server2? for example like exploring the network path with traceroute, or dig? The system is a CentOS. Could it be related to new upgrades in the Python SDK? i just saw this other question where it shows that my method for uploading events has been upgraded just the "01/08/2020" maybe is something related to such upgrades(i doubt it)?
Anyhow, any clues would be greatly aprecciated. For now i will be testing on other servers and checking i can manage to change my implementation to the newer version and see if that solves the issue.
It sounds like a networking issue. Try pinging TCP endpoint of your namespace on port 9354 on server2. If firewall is blocking outbound connection to the endpoint, then either you need to fix it or try enabling websockets which can go through 443.

Simple XMPP bot on python

I have the simple code of XMPP bot by python and http://xmpppy.sourceforge.net/
#!/usr/bin/python
# -*- coding: utf-8 -*-
import xmpp
import urllib2
import ConfigParser
config = ConfigParser.ConfigParser()
config.read('ipbot.conf')
##########################
user= (config.get('account', 'login'))
password=(config.get('account', 'password'))
presence=(config.get('presence','presence'))
##########################
jid=xmpp.protocol.JID(user)
client=xmpp.Client(jid.getDomain())
client.connect()
client.auth(jid.getNode(),password)
################Parse IP##################
strURL='http://api.wipmania.com/'
f = urllib2.urlopen(urllib2.Request(strURL))
response = f.read()
ipget= response.split("<br>")
f.close()
#############################################
def status(xstatus):
status=xmpp.Presence(status=xstatus,show=presence,priority='1')
client.send(msging)
def message(conn,mess):
global client
if ( mess.getBody() == "ip" ):
client.send(xmpp.protocol.Message(mess.getFrom(),ipget[1]+" => "+ipget[0]))#Send IP
client.RegisterHandler('message',message)
client.sendInitPresence()
while True:
client.Process(1)
Please, tell me, how to translate this code to use http://wokkel.ik.nu/ and twistedmatrix.com/
Thanks a lot.
The following code should do it. A few notes:
Wokkel uses so-called subprotocol handlers to cover support for specific
subprotocols, usually split up by conceptual feature, by namespace or per
XEP.
XMPPClient is a so-called stream manager that establishes connections,
and takes care of authentication with the server. It works with the
hooked-up subprotocol handlers to process traffic with the XML stream it
manages. It automatically reconnects if the connection has been lost.
This example defines one new handler to process incoming messages.
Unlike the original code, here the request to retrieve the IP address is
done for each incoming message with ip in the body.
In the original code, status was never called. I now the use
PresenceProtocol subprotocol handler to send out the presence each time
a connection has been established and authentication has taken place.
The example is a so-called Twisted Application, to be started using twistd, as mentioned in the docstring. This will daemonize the process and logs go to twisted.log. If you specify -n (before -y), it will not detach and log to the console instead.
#!/usr/bin/python
"""
XMPP example client that replies with its IP address upon request.
Usage:
twistd -y ipbot.tac
"""
import ConfigParser
from twisted.application import service
from twisted.python import log
from twisted.web.client import getPage
from twisted.words.protocols.jabber.jid import JID
from twisted.words.protocols.jabber.xmlstream import toResponse
from wokkel.client import XMPPClient
from wokkel.xmppim import PresenceProtocol, MessageProtocol
class IPHandler(MessageProtocol):
"""
Message handler that sends presence and returns its IP upon request.
#ivar presenceHandler: Presence subprotocol handler.
#type presenceHandler: L{PresenceProtocol}
#ivar show: Presence show value to send upon connecting.
#type show: C{unicode} or C{NoneType}
"""
def __init__(self, presenceHandler, show=None):
self.presenceHandler = presenceHandler
self.show = show
def connectionInitialized(self):
"""
Connection established and authenticated.
Use the given presence handler to send presence.
"""
MessageProtocol.connectionInitialized(self)
self.presenceHandler.available(show=self.show, priority=1)
def onMessage(self, message):
"""
A message has been received.
If the body of the incoming message equals C{"ip"}, retrieve our
IP address and format the response message in the callback.
"""
def onPage(page):
address, location = page.split(u"<br>")
body = u"%s => %s" % (location, address)
response = toResponse(message, stanzaType=message['type'])
response.addElement("body", content=body)
self.send(response)
if unicode(message.body) != u"ip":
return
d = getPage("http://api.wipmania.com")
d.addCallback(onPage)
d.addErrback(log.err)
# Read the configuration file
config = ConfigParser.ConfigParser()
config.read('ipbot.conf')
user = config.get('account', 'login')
password = config.get('account', 'password')
presence = config.get('presence','presence')
# Set up a Twisted application.
application = service.Application('XMPP client')
# Set up an XMPP Client.
jid = JID(user)
client = XMPPClient(jid, password)
client.logTraffic = True
client.setServiceParent(application)
# Add a presence handler.
presenceHandler = PresenceProtocol()
presenceHandler.setHandlerParent(client)
# Add our custom handler
ipHandler = IPHandler(presenceHandler, presence)
ipHandler.setHandlerParent(client)

Categories

Resources