BIN-RPC Live Converter

Nutzung von XML RPC, Remote Script, JSON RPC, XMLAPI

Moderator: Co-Administratoren

VolkerB
Beiträge: 58
Registriert: 25.04.2011, 14:37
Wohnort: Stuttgart

Re: BIN-RPC Live Converter

Beitrag von VolkerB » 14.07.2012, 19:30

Hallo an alle Homematic Freaks,
ich bin am Aufgeben: ich bekomme hmxmlbin zusammen mit dem CCU Historien (0.6.0), der ja angeblich den hmxmlbin unterstützen soll, nicht zum Laufen.
In der Konfigurationsdatei wird eine neue Schnittstelle wie folgt definiert:
ccu.interfaces.Bezeichner= new CcuInterfaceConfig('IP-Adresse', Portnummer)
Die binäre Version der XMLRPC-Schnittstelle wird nicht direkt unterstützt. Es existiert aber ein
Protokoll-Wandler mit dem Namen BINRPC Live Converter (zu finden auf http://www.fhz-
forum.de/viewtopic.php?f=31&t=8211), der diese Konvertierung vornehmen kann.
Erst mal mein Setup:
CCU: 192.168.178.11
Ubuntu Server: 192.168.178.10 (hmxmlbin und ccu-historian laufen hier)

Also die Kopfzeilen von hmxmlbin:
// Homematic CUxD order anderes Interface
$hm_host = '192.168.178.11';
$hm_port = '8701';
// XMLRPC Server wird für bidirektionalle Kommunikation gebruacht
$url = "http://192.168.178.11/hms/modules/Homem ... .class.php";
---------------------------
Den CCU-Historian habe ich so konfiguriert:
ccu.interfaces.cuxd=new CcuInterfaceConfig('192.168.178.10',8701)

Die Dokumentation ist auch über einige Seiten verstreut. Das Positive: ich kann die hmxmlbin Konfiguration erfolgreich testen - wie angebeben und finde in /var/log/debug die Ausgaben meiner CCU. Selbstverständlich kann ich auch telnet localhost 8701 auf meinem Ubuntu Server erfolgreich aufrufen. Das Setup von hmxmlbin sieht also gut aus.

Nach dem Starten des CCU-Historian erhalte ich dann in dessen Log folgendes:

Code: Alles auswählen

2012-07-14 18:25:42|INFO   |Starting RPC server on port 2010
2012-07-14 18:25:42|INFO   |Creating RPC client for http://192.168.178.11:2000 with name BidCos-Wired
2012-07-14 18:25:43|INFO   |Creating RPC client for http://192.168.178.11:2001 with name BidCos-RF
2012-07-14 18:25:47|INFO   |Creating RPC client for http://192.168.178.11:2002 with name System
2012-07-14 18:25:48|INFO   |Creating RPC client for http://192.168.178.10:8701 with name cuxd
2012-07-14 18:25:48|SEVERE |Exception: Can't connect to CCU with address http://192.168.178.10:8701
...und dann folgt Neustart über Neustart...

Ich habe ebenfalls den Hinweis in Thread probiert, in Zeile 143 des hmxmlbin die Reihenfolge \n\r und \r\n zu ändern. Beides hatte keinen Erfolg.

Code: Alles auswählen

$data = explode("\r\n", $data, 2);
Hat schon jemand den hmxmlbin erfolgreich mit dem CCU-Historian zum Laufen gebracht und kann helfen?

Danke schön
Grüßle
Volker.

leonsio
Beiträge: 1107
Registriert: 07.01.2012, 14:06
Danksagung erhalten: 6 Mal

Re: BIN-RPC Live Converter

Beitrag von leonsio » 18.07.2012, 23:35

was steht im debug log wenn historian auf den conberter zugreift?
die url angabe ist wahrscheinlich falsch, was da stand ist nur ein Beispiel

Benutzeravatar
anli
Beiträge: 4326
Registriert: 10.06.2009, 14:01
Wohnort: 20 Min. nördlich von Hannover und bei Bremen
Hat sich bedankt: 1 Mal
Danksagung erhalten: 23 Mal
Kontaktdaten:

Re: BIN-RPC Live Converter

Beitrag von anli » 04.09.2012, 17:19

leonsio hat geschrieben:die url angabe ist wahrscheinlich falsch, was da stand ist nur ein Beispiel
Welche URL muss denn da hin?
Herzliche Grüße, anli

Alle Angaben ohne Gewähr und Haftung meinerseits. Verwendung der von mir zur Verfügung gestellten Downloads auf eigene Gefahr. Ich bitte um Verständnis, dass ich aus zeitlichen Gründen keine unaufgeforderte Hilfestellung per PN/Mail geben kann. Bitte allgemeine Fragen ins Forum stellen, hier können viele fähige User viel schneller helfen.

Homematic-Manager v2: einfaches Tool zum Erstellen von Direktverknüpfungen und Bearbeiten von Gerätenamen, -parametern etc. für Homematic und HomematicIP (Alternative diesbzgl. zur WebUI)

Einsteiger-Hilfeerweiterter Skript-Parser

Benutzeravatar
anli
Beiträge: 4326
Registriert: 10.06.2009, 14:01
Wohnort: 20 Min. nördlich von Hannover und bei Bremen
Hat sich bedankt: 1 Mal
Danksagung erhalten: 23 Mal
Kontaktdaten:

Re: BIN-RPC Live Converter

Beitrag von anli » 04.09.2012, 22:36

So, habe mal versucht, den Converter ans Laufen zu kriegen, habe allerdings Probleme.

Code: Alles auswählen

[/share/software/hmxmlbin] # telnet localhost 8701
Connection closed by foreign host.
xinetd.log zeigt:

Code: Alles auswählen

12/9/4@22:31:33: START: hmxmlbin pid=27932 from=127.0.0.1
Habe die hmxmlbin wie folgt angepasst:

Code: Alles auswählen

// Homematic CUxD order anderes Interface
$hm_host = '192.168.100.2';
$hm_port = '8701';
// XMLRPC Server wird für bidirektionalle Kommunikation gebruacht
$url = "http://192.168.100.245/Server.class.php";
// Debug auf true setzen, zum aktivieren. Ausgabe wird nach syslog(debug) geschrieben
Die Server.class.php sieht wie folgt aus:

Code: Alles auswählen

<?php
/**
 * An XML-RPC server
 *
 * @author  Donal McMullan  donal@catalyst.net.nz
 * @version 0.0.1
 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
 * @package mnet
 */

/**
 * This class represents the handler for XML-RPC requests, and dispatches
 * to extensions to handle specific calls
 *
 * The server will read the required data directly off the POST stream, all
 * you need to do to dispatch a request to the server is call:
 * mnet_xmlrpc_server::handle_request();
 *
 * Once invoked, the server will output directly back to the output buffer,
 * and will not return.
 *
 */
class mnet_xmlrpc_server {
    // stores the current remotely connected client
    private static $remote_client;

    /**
     * Called statically, this invokes the XMLRPC server and asks it to
     * parse the current request
     *
     */
    public static function handle_request() {
       $instance = new mnet_xmlrpc_server();
       $instance->_handle_request();
    }

    /**
     * This method returns true if the MNet server is currently handling a
     * valid request. Your code may check this before performing an action that
     * should only be dispatched by XML-RPC, as it with return true only iff
     * a valid remote endpoint has called in.
     *
     * Tip: Use this as an alternative to checking the global self::$remote_client
     * in earlier versions of MNet
     *
     * @return bool true if we have a valid remote endpoint making a request currently
     */
    public static function is_in_request() {
        return isset(self::$remote_client);
    }
   
    /**
     * Returns the currently connected client
     *
     * @return mnet_remote_client the currently connected client, or null if none
     */
    public static function get_current_client() {
        return self::$remote_client;
    }

    /**
     * Empty private constructor - invoke using static handle_request() instead
     *
     */
    private function __construct() {
       
    }
   
    /**
     * After instanciating a singleton of this class, this
     * method takes care of actually processing the incoming
     * request
     *
     */
    private function _handle_request() {
        global $MNET, $MNET_SYSTEM;

        $MNET_SYSTEM->log(MNET_LOG_DEBUG, 'Handling incoming request (unknown so far)');

        // Set up output headers
        header('Content-type: text/xml; charset=utf-8', true);

        try {
            // Ensure $_SERVER exists
            if (!isset($_SERVER)) {
                throw new xmlrpc_fault(712, 'phperror');
            }

            // PHP 5.2.2: $HTTP_RAW_POST_DATA not populated bug:
            // http://bugs.php.net/bug.php?id=41293
            if (empty($HTTP_RAW_POST_DATA)) {
                $HTTP_RAW_POST_DATA = file_get_contents('php://input');
            }

            // Check that something was POSTed
            if (empty($HTTP_RAW_POST_DATA)) {
                throw new xmlrpc_fault(712, 'norequest');
            }

            // Set the $remote_client to null for now since we don't yet know who we're talking to
            self::$remote_client = null;

            // Construct an mnet_message out of the incoming request
            $request = new mnet_message($HTTP_RAW_POST_DATA);

            if ($request->get_state() == mnet_message::STATE_INVALID) {
                // the incoming request isn't valid XML
                $MNET_SYSTEM->log(MNET_LOG_ERR, "Incoming XMLRPC request isn't valid XML");
                throw new xmlrpc_fault(712, 'invalidxml');
            }
            else if ($request->get_state() == mnet_message::STATE_CLEARTEXT) {
                // Cleartext XML-RPC is only allowed for system/keyswap
                $method = null; // modifed by reference
                $params = xmlrpc_decode_request($xmlrpcrequest, $method);
               
                if ($method != 'system/keyswap') {
                    // Not allowed
                    throw new xmlrpc_fault(7021, 'forbidden transport');
                }
            }
           
            // The request is either encrypted or signed, either way it should have a wwwroot
            $wwwroot = $request->get_wwwroot();

            if (empty($wwwroot)) {
                throw new xmlrpc_fault(7020, 'no wwwroot found');
            }

            self::$remote_client = $MNET_SYSTEM->get_peer_by_wwwroot($wwwroot);

            if (!self::$remote_client) {
                throw new xmlrpc_fault(7020, 'unknown wwwroot');
            }

            // Now continue checking the message
            if ($request->get_state() == mnet_message::STATE_SIGNED) {
                // This message is signed but not encrypted. If we trust the host
                // then this is OK
                if (!self::$remote_client->plaintext_is_ok()) {
                    throw new xmlrpc_fault(7021, 'forbidden transport');
                }
            }
            else if ($request->get_state() == mnet_message::STATE_ENCRYPTED) {
                // the message is encrypted. attempt to unlock it with our private key
                try {
                    $request->decrypt($MNET->get_keypair_pem());
                }
                catch (mnet_message_encryption_error $e) {
                    // our current key didn't work, hunt through our history for one that might
                    $keypair_history = $MNET_SYSTEM->get_keypair_history();
                    foreach ($keypair_history as $keypair) {
                        try {
                            $request->decrypt($keypair['keypair_PEM']);

                            // if we get here -> success
                            // Now we need to inform the client that their public key for us
                            // is out-of-date. We do this by raising a '7025' XMLRPC fault, including
                            // our latest public key in the faultString. This fault will be encrypted
                            // using our older private key that matches the key the client used to
                            // make this request, therefore the client knows they can trust the result
                            // still

                            $MNET_SYSTEM->log(MNET_LOG_NOTICE, 'Replying with 7025 to supply '.self::$remote_client.' with new pubkey');
                            exit($this->fault_xml(7025, $MNET->get_public_key_cert(), $keypair['keypair_PEM']));
                        }
                        catch (mnet_message_encryption_error $e2) {} // ignore
                    }
                   
                    // If we get here, none of our keys worked, error out
                    $MNET_SYSTEM->log(MNET_LOG_ERR, 'Unable to find a working keypair for this request');
                    throw new xmlrpc_fault(7023, 'encryption invalid (unable to find a working keypair)');
                }
            }

            // We expect the message to be in the signed state
            if ($request->get_state() != mnet_message::STATE_SIGNED) {
                // this is rather unexpected... (breaking mnet protocol)
                $MNET_SYSTEM->log(MNET_LOG_ERR, 'Request is not signed when it is expected to be');
                throw new xmlrpc_fault(711, 'message not signed');
            }

            // Decryption was fine, check the signature is valid for this client
            if (!$request->check_signature(self::$remote_client->get_public_key())) {
                $MNET_SYSTEM->log(MNET_LOG_NOTICE, 'Incoming request is not signed with the expected key, checking for an updated pubkey');

                // Call the client back - if their public key has changed, they'll send the 7025 fault (see above)
                self::$remote_client->check_for_key_update();

                if (!$request->check_signature(self::$remote_client->get_public_key())) {
                    $MNET_SYSTEM->log(MNET_LOG_ERR, 'No new key -> signature is invalid');
                    throw new xmlrpc_fault(710, 'signature not recognised');
                }
            }

            // if we get here, the signature is valid
            self::$remote_client->touch();

            $request->strip_signature();

            // dispatch the XML-RPC request - will output the result directly
            $this->dispatch($request->get_xml());

        }
        catch (Exception $e) {
            if (get_class($e) != 'xmlrpc_fault') {
                // convert it into one
                $e = new xmlrpc_fault(712, 'Uncaught exception at server: '.$e);
            }

            // convert the XML-RPC fault exception to a real fault
            exit($this->fault_xml($e->getCode(), $e->getMessage(), $MNET->get_keypair_pem()));
        }
    }

    /**
     * Construct an XML-RPC fault message, encrypting towards the provided
     * private key if supplied
     *
     * @param  int      $code   The ID code of the error message
     * @param  string   $text   The error message
     * @param  resource $privatekey The private key that should be used to sign the response (or null to not sign or encrypt the response)
     * @return string   $text   The XML text of the error message
     */
    private function fault_xml($code, $text, $privatekey) {
        if (!is_numeric($code)) {
            $code = 0;
        }
        $code = intval($code);

        $return = $this->prepare_response('<?xml version="1.0"?>
    <methodResponse>
       <fault>
          <value>
             <struct>
                <member>
                   <name>faultCode</name>
                   <value><int>'.intval($code).'</int></value>
                </member>
                <member>
                   <name>faultString</name>
                   <value><string>'.htmlspecialchars($text).'</string></value>
                </member>
             </struct>
          </value>
       </fault>
    </methodResponse>', $privatekey);

        return $return;
    }

    /**
     * Package a response in any required envelope, and return it to the client
     *
     * @param   string   $response_xml  The XMLRPC response string
     * @param   resource $privatekey    The private key to sign the response with, or null to not sign/encrypt
     * @return  string                  The encoded response string
     */
    private function prepare_response($response_xml, $privatekey) {
        global $MNET, $MNET_SYSTEM;

        $response = new mnet_message($response_xml);

        if ($privatekey && is_object(self::$remote_client)) {
            $response->sign($privatekey);
            $response->encrypt(self::$remote_client->get_public_key());
        }

        return $response->get_xml();
    }

    /**
     * If security checks are passed, dispatch the request to the extension/method
     *
     * @param  string  $payload    The XML-RPC request
     * @return                     No return val - just echo the response
     */
    private function dispatch($payload) {
        global $MNET, $MNET_SYSTEM;

        // xmlrpc_decode_request returns an array of parameters, and the $method
        // variable (which is passed by reference) is instantiated with the value from
        // the methodName tag in the xml payload
        //            xmlrpc_decode_request($xml,                   &$method)
        $params     = xmlrpc_decode_request($payload, $method);

        // $method is in the form extensionname/function or system/function
        // $params is an array of parameters. A parameter might itself be an array.

        // Whitelist characters that are permitted in a method name
        // The method name must not begin with a / - avoid absolute paths
        // A dot character . is only allowed in the filename, i.e. something.php
        if (0 == preg_match("@^[A-Za-z0-9]+/[A-Za-z0-9/_-]+(\.php/)?[A-Za-z0-9_-]+$@", $method)) {
            throw new xmlrpc_fault(713, 'nosuchfunction');
        }

        if (preg_match("/^system\./", $method)) {
            $callstack  = explode('.', $method);
        } else {
            $callstack  = explode('/', $method);
            // the callstack in this instance might be a legacy call to the "custom" extension,
            // passing array('mod', 'forum', 'lib.php', 'forum_add_instance');
            // Or in modern times, array('mnet', 'extname', 'methodname')
            // If it starts with the first element 'mnet' then we know it's going to name an extension
            // rather than a file path
        }

        // will store the required call params
        $extension = null;
        $method = null;

        if ($callstack[0] == 'system' && count($callstack) == 2) {
            // Special case - map this to ths system extension
            $extension = 'system';
            $method = $callstack[1];
        }
        else if ($callstack[0] == 'mnet' && count($callstack) == 3) {
            // Specifies an MNet-2 extension name directly
            $extension = $callstack[1];
            $method = $callstack[2];
           
        }
        else if (in_array($callstack[0], array('auth', 'enrol', 'portfolio'))) {
            // this is a call to a legacy service from an MNet-1 client. Map it to
            // the appropriate new extension
            switch ($callstack[0]) {
                case 'auth'     : $extension = 'authentication'; break;
                case 'enrol'    : $extension = 'enrolment'; break;
                case 'portfolio': $extension = 'portfolio'; break;
                default         : $extension = null;
            }
        }
        else if ($callstack[0] == 'mod') {
            // This is a legacy MNet-1 client call to the "Custom" extension to execute
            // arbitrary methods. Assume they're targeting a moodle system and use the call_moodle()
            // method to invoke some code within Moodle.
            $extension = 'custom';
            $method = 'call_moodle';
        }

        if (!$extension || !$method) {
            // unknown call
            throw new xmlrpc_fault(7012, 'nosuchfunction');
        }

        // Get an instance of the extension
        $extension_instance = mnet_extension::get($extension);
        if (!is_object($extension_instance)) {
            throw new xmlrpc_fault(704, 'nosuchservice');
        }
       
        // Check if they have access to this extension and this method
        if (!$extension_instance->check_call_access(self::$remote_client, $method)) {
            // access denied
            throw new xmlrpc_fault(702, 'nosuchservice');
        }

        // Validate the method and params for this extension
        if (!$extension_instance->validate_call($method, $params)) {
            // invalid method or param count
            throw new xmlrpc_fault(702, 'nosuchfunction');
        }

        // Everything checks out, execute this method on this extension via the dummy
        // and get the XML-RPC encoded result
        $xmlrpc_server = xmlrpc_server_create();
        $xmlrpc_method = implode('/', $callstack);
        xmlrpc_server_register_method($xmlrpc_server, $xmlrpc_method, array($this, 'dispatch_dummy'));

        // we pass the actual callback through to the dummy via the $user_data param
        $response = xmlrpc_server_call_method($xmlrpc_server, $payload, array($extension_instance, 'rpc_'.$method), array('encoding' => 'utf-8'));

        // Encrypt and sign the XML response
        $response = $this->prepare_response($response, $MNET->get_keypair_pem());

        // output the response to the output stream
        echo $response;

        return;
    }

    /**
         * Because PHP's XMLRPC calls with the convention of func($methodname, $params_array, $user_data),
         * we use this dummy adapter to convert it to a normal call of func($param1, $param2, ...) and return
         * the result. For this, the user data parameter is filled with a callback suitable for call_user_func_array()
         *
         * @param string $method the original xmlrpc method, eg. system/keyswap. Ignored
         * @param array $params the parameters to pass through
         * @param callback $callback the callback to actually call, from user data
         * @return mixed whatever the actual method returns
     */
    private function dispatch_dummy($method, $params, $callback) {
        return call_user_func_array($callback, $params);
    }
}
Was mache ich falsch? Das ganze läuft auf meiner Qnap, auf der auch der Historian läuft. PHP ist 5.2.14 mit

Code: Alles auswählen

xmlrpc
core library version 	xmlrpc-epi v. 0.51
php extension version 	0.51
author 	Dan Libby
homepage 	http://xmlrpc-epi.sourceforge.net
open sourced by 	Epinions.com 
Bin dankbar für jeden Hinweis :)
Herzliche Grüße, anli

Alle Angaben ohne Gewähr und Haftung meinerseits. Verwendung der von mir zur Verfügung gestellten Downloads auf eigene Gefahr. Ich bitte um Verständnis, dass ich aus zeitlichen Gründen keine unaufgeforderte Hilfestellung per PN/Mail geben kann. Bitte allgemeine Fragen ins Forum stellen, hier können viele fähige User viel schneller helfen.

Homematic-Manager v2: einfaches Tool zum Erstellen von Direktverknüpfungen und Bearbeiten von Gerätenamen, -parametern etc. für Homematic und HomematicIP (Alternative diesbzgl. zur WebUI)

Einsteiger-Hilfeerweiterter Skript-Parser

zwaenn
Beiträge: 11
Registriert: 01.10.2013, 20:09
Wohnort: Meck-Pom

Re: BIN-RPC Live Converter

Beitrag von zwaenn » 20.11.2013, 20:11

ich versuche den converter auf mein raspberry zum laufen zu bringen.
wenn ich

Code: Alles auswählen

telnet localhost 8701
eingebe bekomme ich als Antwort

Code: Alles auswählen

Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
PHP Fatal error:  Call-time pass-by-reference has been removed in /usr/bin/hmxmlbin on line 170
Connection closed by foreign host.
kann mir da irgendjemand weiter helfen?

wenn das weiter hilft ich habe php5 installiert in der version 5.4.4-14+deb7u5
betriebssystem ist Raspbian

Antworten

Zurück zu „Softwareentwicklung von externen Applikationen“