Search code examples
pythonpython-3.xxml-rpc

Xmlrpc error from a client when using a string


My use case is :

  • a client sends data via xmlrpc
  • the xmlrpc server retrieves these data so the function is called with it as parameters

The code as reproduced here gives the following error :

Traceback (most recent call last):
  File "rpcclient.py", line 37, in <module>
    s.on(pinaddr)
  File "/usr/lib/python3.5/xmlrpc/client.py", line 1092, in __call__
    return self.__send(self.__name, args)
  File "/usr/lib/python3.5/xmlrpc/client.py", line 1432, in __request
    verbose=self.__verbose
  File "/usr/lib/python3.5/xmlrpc/client.py", line 1134, in request
    return self.single_request(host, handler, request_body, verbose)
  File "/usr/lib/python3.5/xmlrpc/client.py", line 1150, in single_request
    return self.parse_response(resp)
  File "/usr/lib/python3.5/xmlrpc/client.py", line 1322, in parse_response
    return u.close()
  File "/usr/lib/python3.5/xmlrpc/client.py", line 655, in close
    raise Fault(**self._stack[0])
xmlrpc.client.Fault: <Fault 1: "<class 'SystemError'>:<built-in function setup> returned NULL without setting an error">

my tests and tries :

  1. from the server code below : print(type(pin_address)) returns class 'str' so this is fine.
  2. if I call the function hard coded server side : GPIO.setup("P8_45", GPIO.OUT) it's fine as well
  3. if I use print(s.on("P8_45")) : it's ok. It's left commented in the code
  4. if I force pinaddr = "p8_45" client side, it fails. It's left commented in the code

The CLI line is :

python3 rpcclient.py -s 192.168.1.2 on -p p8_45

the client code

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import xmlrpc.client
import argparse
import time

RPC_PORT = 1234
RPC_HOSTNAME = "####"

parser = argparse.ArgumentParser()
parser.add_argument("-s", "--server", help="Specify ACME Hostname")
parser.add_argument("-p", "--pinaddress", help="Specify which pin to use")
parser.add_argument("command", help="ACME Command, use 'help' to get all commands")
parser.add_argument("args", nargs='?', help="ACME Command Arguments")
args = parser.parse_args()

if args.server:
    serveraddr = "%s:%d" % (args.server, RPC_PORT)
else:
    serveraddr = "%s:%d" % (RPC_HOSTNAME, RPC_PORT)

s = xmlrpc.client.ServerProxy("http://%s/ci" % serveraddr)

if args.pinaddress:
    pinaddr = "%s" % (args.pinaddress)
#    pinaddr = "p8_45"  
    print ("using pinaddr = ", pinaddr)

if args.command == "version":
    print(s.version())

if args.command == "on":
    print(s.on(pinaddr))
#    print(s.on("P8_45"))   this will be accepted

if args.command == "off":
    print(s.off(pinaddr))

the server code

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
'''
Python RPC Daemon
'''
from xmlrpc.server import SimpleXMLRPCServer
from xmlrpc.server import SimpleXMLRPCRequestHandler
import subprocess
import Adafruit_BBIO.GPIO as GPIO    
VERSION = "123"

def run_cmd(cmd, arg=""):
    try:
        return subprocess.Popen([cmd, arg], \
                                stdout=subprocess.PIPE, \
                                stderr=subprocess.PIPE).communicate()
    except:
        return False, False

class RequestHandler(SimpleXMLRPCRequestHandler):
    rpc_paths = ('/ci',)

# Create server
server = SimpleXMLRPCServer(("0.0.0.0", 1234),
                            requestHandler=RequestHandler)
server.register_introspection_functions()

# Info function, get ACME info string
def version():
    return VERSION
server.register_function(version)

def on(pin_address):
    print(type(pin_address))
    GPIO.setup( (pin_address) , GPIO.OUT)
    return ("on for ", (pin_address))

server.register_function(on)

def off(pin_address):
    GPIO.setup(pin_address,GPIO.IN)
    return ("off for ", pin_address)

server.register_function(off)

# Run the server's main loop
server.serve_forever()

Solution

  • Actually this was coming from a space character which wasn't properly parsed from Server side.