Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Safe way to connect to RPC server

This question is related to How do we handle Python xmlrpclib Connection Refused?

When I try to use the following code, with my RPC server down, _get_rpc() returns False and I'm good to go. However if the server is running, it fails with unknown method. Is it trying to execute .connect() on the remote server? How can I get around this, when I needed to use .connect() to detect if the returned proxy worked (see related question)?

import xmlrpclib
import socket

def _get_rpc():
    try:
        a = xmlrpclib.ServerProxy('http://dd:[email protected]:9001')
        a.connect()     # Try to connect to the server
        return a.supervisor
    except socket.error:
        return False


if not _get_rpc():
    print "Failed to connect"

Here is the issue:

ahiscox@lenovo:~/code/dd$ python xmlrpctest2.py
Failed to connect
ahiscox@lenovo:~/code/dd$ supervisord -c ~/.supervisor # start up RPC server
ahiscox@lenovo:~/code/dd$ python xmlrpctest2.py
Traceback (most recent call last):
  File "xmlrpctest2.py", line 13, in <module>
    if not _get_rpc():
  File "xmlrpctest2.py", line 7, in _get_rpc
    a.connect()     # Try to connect to the server
  File "/usr/lib/python2.6/xmlrpclib.py", line 1199, in __call__
    return self.__send(self.__name, args)
  File "/usr/lib/python2.6/xmlrpclib.py", line 1489, in __request
    verbose=self.__verbose
  File "/usr/lib/python2.6/xmlrpclib.py", line 1253, in request
    return self._parse_response(h.getfile(), sock)
  File "/usr/lib/python2.6/xmlrpclib.py", line 1392, in _parse_response
    return u.close()
  File "/usr/lib/python2.6/xmlrpclib.py", line 838, in close
    raise Fault(**self._stack[0])
xmlrpclib.Fault: <Fault 1: 'UNKNOWN_METHOD'>
like image 626
Anthony Hiscox Avatar asked Jan 17 '11 18:01

Anthony Hiscox


1 Answers

Well i was just looking in to it ; my old method suck because xmlrpclib.ServerProxy try to connect to the XmlRPC server when you call a method, not before !!!

Try this instead :

import xmlrpclib
import socket

def _get_rpc():
    a = xmlrpclib.ServerProxy('http://dd:[email protected]:9001')

    try:
        a._()   # Call a fictive method.
    except xmlrpclib.Fault:
        # connected to the server and the method doesn't exist which is expected.
        pass
    except socket.error:
        # Not connected ; socket error mean that the service is unreachable.
        return False, None

    # Just in case the method is registered in the XmlRPC server
    return True, a

connected, server_proxy = _get_rpc():
if not connected
    print "Failed to connect"
    import sys
    sys.exit(1)

To summarize this we have 3 cases :

  1. XmlRPC server is up and in it we defined a method called _():
    (EDIT : i did choose the name _ because it unlikely to have a method with this name, but this case still can happen)
    In this case no exception will be catch and the code will execute the return True

  2. XmlRPC server is up and in it we don't have any method methoded call _():
    This time xmlrpclib.Fault will be raised and we will also pass to the return True

  3. XmlRPC server is down:
    Now the socket.error exception will be raised and that when we call a._() so we should return False

I don't know if there is an easy way to do this and i will love to see it until then , hope this can fix thing this time :)

N.B: when you do if a: python will again search for a method __nonzero__() to test the boolean value of a and this will fail to.

N.B 2: Some xmlrpc service offer a rpc path specialized to do an authentication , in this path the service offer methods like login() ... , this kinds of method can replace the _() method in our case, so just calling login(), will be enough to know if the service is up or down (socket.error), and in the same time this login() method authenticate the user if the service is up .

like image 153
mouad Avatar answered Oct 11 '22 18:10

mouad