Asterisk + Starpy : Failed to originate call - python

I'm using Starpy to automate Asterisk. Everything works except sometimes I get one call out of 150 where Asterisk fails to originate call.
Unhandled Error
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/starpy/manager.py", line 154, in lineReceived
self.dispatchIncoming() # does dispatch and clears cache
File "/usr/local/lib/python2.7/dist-packages/starpy/manager.py", line 242, in dispatchIncoming
callback(message)
File "/usr/lib/python2.7/dist-packages/twisted/internet/defer.py", line 362, in callback
self._startRunCallbacks(result)
File "/usr/lib/python2.7/dist-packages/twisted/internet/defer.py", line 458, in _startRunCallbacks
self._runCallbacks()
--- <exception caught here> ---
File "/usr/lib/python2.7/dist-packages/twisted/internet/defer.py", line 545, in _runCallbacks
current.result = callback(current.result, *args, **kw)
File "/usr/local/lib/python2.7/dist-packages/starpy/manager.py", line 348, in errorUnlessResponse
raise error.AMICommandFailure(message)
starpy.error.AMICommandFailure: {'message': 'Originate failed', 'response': 'Error', 'actionid': '53345672-2'}
Based on my research, this error occurs when the callee does not answer the call. However, I'm not convinced and looking for more details about why "origiate failed". I thought about monitoring the channel before we start dialing, but it doesn't work. Channel monitor needs to be called after the callee answers the call.
Please let me know if you have any suggestions.
Thanks.

Use tcpdump or other similar tool to see what exactly asterisk sends
After that fix that library, very likly it just have bug.

Related

How to debug a stuck asyncio coroutine in Python?

There are lots of coroutines in my production code, which are stuck at unknown position while processing request. I attached gdb with Python support extension to the process, but it doesn't show the exact line in the coroutine where the process is stuck, only primary stack trace. Here is a minimal example:
import asyncio
async def hello():
await asyncio.sleep(30)
print('hello world')
asyncio.run(hello())
(gdb) py-bt
Traceback (most recent call first):
File "/usr/lib/python3.8/selectors.py", line 468, in select
fd_event_list = self._selector.poll(timeout, max_ev)
File "/usr/lib/python3.8/asyncio/base_events.py", line 2335, in _run_once
File "/usr/lib/python3.8/asyncio/base_events.py", line 826, in run_forever
None, getaddr_func, host, port, family, type, proto, flags)
File "/usr/lib/python3.8/asyncio/base_events.py", line 603, in run_until_complete
self.run_forever()
File "/usr/lib/python3.8/asyncio/runners.py", line 299, in run
File "main.py", line 7, in <module>
GDB shows a trace that ends on line 7, but the code is obviously stuck on line 4. How to make it show a more complete trace with nested coroutines?
You can use the aiodebug.log_slow_callbacks.enable(0.05)
Follow for more : https://pypi.org/project/aiodebug/

Try/except not working with twisted starttls given cert/key mismatch

So my twisted mail receiver is working nicely. Right up until we try to handle a case where the config is fubarred, and a mismatched cert/key is passed to the certificate options object for the factory.
I have a module, custom_esmtp.py, which includes an overload of ext_STARTLS(self,rest) which I have modified as follows, to include a try/except:
elif self.ctx and self.canStartTLS:
try:
self.sendCode(220, 'Begin TLS negotiation now')
self.transport.startTLS(self.ctx)
self.startedTLS = True
except:
log.err()
self.sendCode(550, "Internal server error")
return
When I run the code, having passed a cert and key that do not match, I get the following call stack:
Unhandled Error
Traceback (most recent call last):
File "/usr/local/lib/python2.7/site-packages/twisted/internet/tcp.py", line 220, in _dataReceived
rval = self.protocol.dataReceived(data)
File "/usr/local/lib/python2.7/site-packages/twisted/protocols/basic.py", line 454, in dataReceived
self.lineReceived(line)
File "/usr/local/lib/python2.7/site-packages/twisted/mail/smtp.py", line 568, in lineReceived
return getattr(self, 'state_' + self.mode)(line)
File "/usr/local/lib/python2.7/site-packages/twisted/mail/smtp.py", line 582, in state_COMMAND
method('')
--- <exception caught here> ---
File "custom_esmtp.py", line 286, in ext_STARTTLS
self.transport.startTLS(self.ctx)
File "/usr/local/lib/python2.7/site-packages/twisted/internet/_newtls.py", line 179, in startTLS
startTLS(self, ctx, normal, FileDescriptor)
File "/usr/local/lib/python2.7/site-packages/twisted/internet/_newtls.py", line 139, in startTLS
tlsFactory = TLSMemoryBIOFactory(contextFactory, client, None)
File "/usr/local/lib/python2.7/site-packages/twisted/protocols/tls.py", line 769, in __init__
contextFactory = _ContextFactoryToConnectionFactory(contextFactory)
File "/usr/local/lib/python2.7/site-packages/twisted/protocols/tls.py", line 648, in __init__
oldStyleContextFactory.getContext()
File "/usr/local/lib/python2.7/site-packages/twisted/internet/_sslverify.py", line 1429, in getContext
self._context = self._makeContext()
File "/usr/local/lib/python2.7/site-packages/twisted/internet/_sslverify.py", line 1439, in _makeContext
ctx.use_privatekey(self.privateKey)
OpenSSL.SSL.Error: [('x509 certificate routines', 'X509_check_private_key', 'key values mismatch')]
Line 286 of custom_esmtp.py is the self.transport.startTLS(self.ctx). I've looked through all the twisted modules listed in the stack, at the quoted lines, and there are no other try/except blocks.... So my understanding is that the error should be passed back up the stack, unhandled, until it reaches my handler in custom_esmtp.py? So why is it not getting handled - especially since the only except I have is a "catch all"?
Thanks in advance!
If you want this error to be caught, you can do:
from OpenSSL import SSL
# ...
try:
# ...
except SSL.Error:
# ...
Perhaps the syntax changes a bit. I can't check because I don't use this precise package, but the idea is that you have to declare the import path of the exceptions you want to catch.

How to start a task for a Twisted ServerFactory?

I have a Twisted ServerFactory, which I started with listenTCP. How do I start a task that is a function of that factory?
I tried:
if __name__ == "__main__":
factory = MyFactory()
reactor.listenTCP(555558, factory)
reactor.connectTCP("127.0.0.1", 55555, MyConnector(factory))
sanitizing = task.LoopingCall(factory.sanitize())
sanitizing.start(3, False)
reactor.run()
But that throws an error:
Unhandled error in Deferred:
Unhandled Error
Traceback (most recent call last):
File "/usr/lib/python2.7/dist-packages/twisted/internet/base.py", line 1192, in run self.mainLoop()
File "/usr/lib/python2.7/dist-packages/twisted/internet/base.py", line 1201, in mainLoop
self.runUntilCurrent()
File "/usr/lib/python2.7/dist-packages/twisted/internet/base.py", line 824, in runUntilCurrent
call.func(*call.args, **call.kw)
File "/usr/lib/python2.7/dist-packages/twisted/internet/task.py", line 218, in __call__
d = defer.maybeDeferred(self.f, *self.a, **self.kw)
--- <exception caught here> ---
File "/usr/lib/python2.7/dist-packages/twisted/internet/defer.py", line 139, in maybeDeferred
result = f(*args, **kw)
exceptions.TypeError: 'NoneType' object is not callable
The factory is actually listening, so I don't understand why it is NoneType.
In Python, name() is the syntax to call an object (usually a function or method). By extension, name(another_name()) is how you call an object (referenced by the name another_name) and then pass the return value of that call to another object (referenced by the name name).
To apply this to your example, LoopingCall(factory.sanitize()) is how you call factory.sanitize and pass the return value to LoopingCall.
This is most likely not what you meant. Instead, you probably meant to pass factory.sanitize as an argument to LoopingCall. This is what you would need to do if you wanted LoopingCall to call factory.sanitize periodically, anyway. I'm just guessing this is what you want - you didn't actually explicitly say what you want in your question. :)

How to get the exception in nose.plugins.base.Plugin.addFailure?

I am trying to write a plugin for nose that produces and displays additional debug information for certain kinds of exceptions in a GUI. The reason I want to do this in a plugin is because I want the GUI to be launched only when the --enable-gui option has been given, and plugins are the only way to add command-line options to the nose runner.
According to the documentation, I need to override addFailure(step, err) and addError(step, err), and they say that err is the sys.exc_info() tuple:
http://nose.readthedocs.org/en/latest/plugins/interface.html
Unfortunately, I'm getting something else entirely: The exception is replaced with the string value representing it. Here's my code:
def addError(self, test, err):
info = ', '.join((type(x).__name__) for x in err)
open('/tmp/xxxxx', 'a').write(info + '\n')
def addFailure(self, test, err):
info = ', '.join((type(x).__name__) for x in err)
open('/tmp/xxxxx', 'a').write(info + '\n')
Here's the output:
type, str, traceback
type, str, traceback
So, instead of exc_type, exc_value, exc_tb, I'm getting exc_type, str(exc_value), exc_tb.
Here's the stack of the call to my overriden methods:
Traceback (most recent call last):
File "runtests.py", line 6, in <module>
nose.main(module=tests, addplugins=tests.plugins.get_all_plugins())
File "/usr/lib/python2.7/dist-packages/nose/core.py", line 118, in __init__
**extra_args)
File "/usr/lib/python2.7/unittest/main.py", line 95, in __init__
self.runTests()
File "/usr/lib/python2.7/dist-packages/nose/core.py", line 197, in runTests
result = self.testRunner.run(self.test)
File "/usr/lib/python2.7/dist-packages/nose/core.py", line 61, in run
test(result)
File "/usr/lib/python2.7/dist-packages/nose/suite.py", line 176, in __call__
return self.run(*arg, **kw)
File "/usr/lib/python2.7/dist-packages/nose/suite.py", line 223, in run
test(orig)
File "/usr/lib/python2.7/dist-packages/nose/suite.py", line 176, in __call__
return self.run(*arg, **kw)
File "/usr/lib/python2.7/dist-packages/nose/suite.py", line 223, in run
test(orig)
File "/usr/lib/python2.7/dist-packages/nose/suite.py", line 176, in __call__
return self.run(*arg, **kw)
File "/usr/lib/python2.7/dist-packages/nose/suite.py", line 223, in run
test(orig)
File "/usr/lib/python2.7/dist-packages/nose/case.py", line 45, in __call__
return self.run(*arg, **kwarg)
File "/usr/lib/python2.7/dist-packages/nose/case.py", line 138, in run
result.addError(self, err)
File "/usr/lib/python2.7/dist-packages/nose/proxy.py", line 134, in addError
plugins.addError(self.test, err)
File "/usr/lib/python2.7/dist-packages/nose/plugins/manager.py", line 94, in __call__
return self.call(*arg, **kw)
File "/usr/lib/python2.7/dist-packages/nose/plugins/manager.py", line 162, in simple
result = meth(*arg, **kw)
File "<snip>/plugins.py", line 31, in addError
open('/tmp/xxxxx', 'a').write(info + '\n')
I can't extract the exception from sys.exc_info(), because it has already been replaced with another one (in particular, the UnicodeEncodeError caught during __str__ of the raised exception).
Is there any way to extract exc_value from somewhere, say, the traceback?
A potential workaround: I know I can make my plugin a global variable, and instead of handling exceptions in it, I can directly send the information to the plugin itself. Unfortunately, that's not a very clean solution, so I'd like to avoid it.
Why I need a GUI: The error that I'm getting is coloured HTML traceback created by twisted, which is unreadable in the console whether I'm printing the HTML or using the html2text representation.
The err tuple is actually: (exception type, actual exception, traceback). You should be able to access the information you need from either the exception or the traceback.
Note that in your code you write everything to a string:
info = ', '.join((type(x).__name__) for x in err)
This means it will indeed be cast to a string, which, if I understand correctly, is what you are complaining about...

Twisted and starpy error (python)

I'm using this:
from twisted.web.client import getPage
df = getPage(url) # there is some url
I'm getting the following error. Please can anyone guide me on this
ERROR:twsited:Unhandled error in Deferred:
ERROR:twsited:Unhandled Error
Traceback (most recent call last):
File "/usr/local/lib/python2.6/dist-packages/starpy/manager.py", line 123, in lineReceived
self.dispatchIncoming() # does dispatch and clears cache
File "/usr/local/lib/python2.6/dist-packages/starpy/manager.py", line 200, in dispatchIncoming
callback( message )
File "/usr/lib/python2.6/dist-packages/twisted/internet/defer.py", line 243, in callback
self._startRunCallbacks(result)
File "/usr/lib/python2.6/dist-packages/twisted/internet/defer.py", line 312, in _startRunCallbacks
self._runCallbacks()
--- <exception caught here> ---
File "/usr/lib/python2.6/dist-packages/twisted/internet/defer.py", line 328, in _runCallbacks
self.result = callback(self.result, *args, **kw)
File "/usr/local/lib/python2.6/dist-packages/starpy/manager.py", line 298, in errorUnlessResponse
raise error.AMICommandFailure( message )
starpy.error.AMICommandFailure: {'message': 'Channel not specified', 'response': 'Error', 'actionid': 'askme-158811948-5'}
I'm not sure this error is due to getPage() method because even when i've commented this it still give me the same error. Can anyone help. I can't figure out the reason for the error and where it is generated
The code posted is not complete. The error is not due to getPage.
From the stack trace clues, this uses AMIProtocol (line receiver) .
I guess some where you have to specify your protocol channel in AMIProtocol
setVar(self, channel, variable, value) in star.py.
This is not a twisted issue.

Categories