Index: src/client/c/hu/varadiistvan/xplra/xplra.cc
===================================================================
--- src/client/c/hu/varadiistvan/xplra/xplra.cc	(revision 14)
+++ src/client/c/hu/varadiistvan/xplra/xplra.cc	(revision 23)
@@ -34,5 +34,9 @@
 #include "Exception.h"
 
+#include <vector>
+#include <memory>
+
 #include <cstdio>
+#include <cassert>
 
 //------------------------------------------------------------------------------
@@ -40,4 +44,312 @@
 using hu::varadiistvan::xplra::XPlane;
 using hu::varadiistvan::xplra::Exception;
+using hu::varadiistvan::xplra::IOException;
+using hu::varadiistvan::xplra::ProtocolException;
+using hu::varadiistvan::xplra::NotConnectedException;
+using hu::varadiistvan::xplra::TypeMismatchException;
+using hu::varadiistvan::xplra::InvalidIDException;
+
+using std::exception;
+using std::string;
+using std::vector;
+using std::auto_ptr;
+
+//------------------------------------------------------------------------------
+
+namespace {
+
+//------------------------------------------------------------------------------
+
+/**
+ * Information about a connection.
+ */
+class Connection : public XPlane
+{
+private:
+    /**
+     * The last error code.
+     */
+    int lastErrorCode;
+
+    /**
+     * The last error subcode.
+     */
+    unsigned long lastErrorSubCode;
+
+    /**
+     * The string of the last error
+     */
+    std::string lastErrorString;
+
+public:
+    /**
+     * Construct the connection
+     */
+    Connection() throw();
+
+    /**
+     * Handle the currently pending exception.
+     */
+    void handleException() throw();
+
+    /**
+     * Get the last error code.
+     */
+    int getLastError(unsigned long* lastErrorSubCode) const throw();
+
+    /**
+     * Get the string representation of the last error code.
+     */
+    const char* getLastErrorString() const throw();
+
+    /**
+     * Clear the last error code.
+     */
+    void clearLastError() throw();
+};
+
+//------------------------------------------------------------------------------
+
+inline Connection::Connection() throw() :
+    lastErrorCode(0),
+    lastErrorSubCode(0)
+{
+}
+
+//------------------------------------------------------------------------------
+
+void Connection::handleException() throw()
+{
+    try {
+        throw;
+    } catch(const IOException& e) {
+        lastErrorCode = ERROR_IO;
+        lastErrorSubCode = e.getErrorCode();
+        lastErrorString = e.what();
+    } catch(const ProtocolException& e) {
+        lastErrorCode = ERROR_PROTOCOL;
+        lastErrorSubCode = static_cast<unsigned long>(e.getErrorCode());
+        lastErrorString = e.what();
+    } catch(const NotConnectedException& e) {
+        lastErrorCode = ERROR_NOT_CONNECTED;
+        lastErrorSubCode = 0;
+        lastErrorString = e.what();
+    } catch(const TypeMismatchException& e) {
+        lastErrorCode = ERROR_TYPE_MISMATCH;
+        lastErrorSubCode = 0;
+        lastErrorString = e.what();
+    } catch(const InvalidIDException& e) {
+        lastErrorCode = ERROR_INVALID_ID;
+        lastErrorSubCode = 0;
+        lastErrorString = e.what();
+    } catch(const exception& e) {
+        lastErrorCode = ERROR_OTHER;
+        lastErrorSubCode = 0;
+        lastErrorString = e.what();
+    } catch(...) {
+        lastErrorCode = ERROR_OTHER;
+        lastErrorSubCode = 0;
+        lastErrorString = "<Exception of an unknown type>";
+    }
+}
+
+//------------------------------------------------------------------------------
+
+inline int Connection::getLastError(unsigned long* lastErrorSubCode)
+    const throw()
+{
+    if (lastErrorSubCode!=0) *lastErrorSubCode = this->lastErrorSubCode;
+    return lastErrorCode;
+}
+
+//------------------------------------------------------------------------------
+
+inline const char* Connection::getLastErrorString() const throw()
+{
+    return (lastErrorCode==ERROR_NONE) ? 0 : lastErrorString.c_str();
+}
+
+//------------------------------------------------------------------------------
+
+inline void Connection::clearLastError() throw()
+{
+    lastErrorCode = ERROR_NONE;
+    lastErrorSubCode = 0;
+    lastErrorString.clear();
+}
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+
+/**
+ * Information about a connection slot in the vector of connections.
+ */
+struct Slot
+{
+private:
+    /**
+     * The slots.
+     */
+    static std::vector<Slot> slots;
+
+    /**
+     * The index of the first free slot.
+     */
+    static int firstFree;
+
+public:
+    /**
+     * Add a new connection.
+     */
+    static int addConnection(Connection* connection) throw();
+
+    /**
+     * Get the connection with the given ID.
+     */
+    static Connection* getConnection(int connectionID) throw();
+
+    /**
+     * Clear the connection with the given ID.
+     */
+    static void clearConnection(int connectionID) throw();
+
+    // Indicate if the slot contains a valid connection or not
+    bool valid;
+
+    union {
+        // The connection, if it is a valid connection
+        Connection* connection;
+
+        // The index of the next free slot
+        int nextFreeIndex;
+    };
+
+    /**
+     * Construct a slot with the given connection
+     */
+    Slot(Connection* connection) throw();
+
+    /**
+     * Set the connection and return the former next free index. It
+     * should be called for a slot with no connection.
+     */
+    int setConnection(Connection* connection) throw();
+
+    /**
+     * Get the connection if this slot contains a connection.
+     */
+    Connection* getConnection() const throw();
+
+    /**
+     * Clear the connection and set the given next free index.
+     */
+    void clear(int nextFreeIndex) throw();
+};
+
+//------------------------------------------------------------------------------
+
+vector<Slot> Slot::slots;
+
+//------------------------------------------------------------------------------
+
+int Slot::firstFree = -1;
+
+//------------------------------------------------------------------------------
+
+inline Slot::Slot(Connection* connection) throw() :
+    valid(true)
+{
+    this->connection = connection;
+}
+
+//------------------------------------------------------------------------------
+
+inline int Slot::setConnection(Connection* connection) throw()
+{
+    assert(!valid);
+    int nextFreeIndex = this->nextFreeIndex;
+    this->connection = connection;
+    valid = true;
+    return nextFreeIndex;
+}
+
+//------------------------------------------------------------------------------
+
+inline Connection* Slot::getConnection() const throw()
+{
+    return valid ? connection : 0;
+}
+
+//------------------------------------------------------------------------------
+
+inline void Slot::clear(int nextFreeIndex) throw()
+{
+    assert(valid);
+    valid = false;
+    this->nextFreeIndex = nextFreeIndex;
+}
+
+//------------------------------------------------------------------------------
+
+int Slot::addConnection(Connection* connection) throw()
+{
+    int id = firstFree;
+    if (id<0) {
+        id = slots.size();
+        slots.push_back(Slot(connection));
+    } else {
+        Slot& slot = slots[id];
+        firstFree = slot.setConnection(connection);
+    }
+
+    return id;
+}
+
+//------------------------------------------------------------------------------
+
+Connection* Slot::getConnection(int connectionID) throw()
+{
+    size_t index = static_cast<size_t>(connectionID);
+    return (index<slots.size()) ? slots[index].getConnection() : 0;
+}
+
+//------------------------------------------------------------------------------
+
+void Slot::clearConnection(int connectionID) throw()
+{
+    size_t index = static_cast<size_t>(connectionID);
+    if (index<slots.size()) {
+        slots[index].clear(firstFree);
+        firstFree = index;
+    }
+}
+
+//------------------------------------------------------------------------------
+
+} /* anonymous namespace */
+
+//------------------------------------------------------------------------------
+
+extern "C" int xplra_get_last_error(int connectionID, unsigned long* subCode)
+{
+    Connection* connection = Slot::getConnection(connectionID);
+    return (connection==0) ? -1 : connection->getLastError(subCode);
+}
+
+//------------------------------------------------------------------------------
+
+extern "C" const char* xplra_get_last_error_string(int connectionID)
+{
+    Connection* connection = Slot::getConnection(connectionID);
+    return (connection==0) ? 0 : connection->getLastErrorString();
+}
+
+//------------------------------------------------------------------------------
+
+extern "C" void xplra_clear_last_error(int connectionID)
+{
+    Connection* connection = Slot::getConnection(connectionID);
+    if (connection!=0) connection->clearLastError();
+}
 
 //------------------------------------------------------------------------------
@@ -46,10 +358,70 @@
 {
     try {
-        XPlane xplane;
+        auto_ptr<Connection> connection(new Connection());
+        connection->connect();
+        return Slot::addConnection(connection.release());
+    } catch(...) {
+        return -1;
+    }
+}
+
+//------------------------------------------------------------------------------
+
+extern "C" int xplra_get_int(int* value, int connectionID, const char* name)
+{
+    Connection* connection = Slot::getConnection(connectionID);
+    if (connection==0) return -1;
+    try {
+        *value = connection->getInt(name);
         return 0;
-    } catch(const Exception& e) {
-        printf("xplra_connect failed: %s\n", e.what());
+    } catch (...) {
+        connection->handleException();
         return -1;
     }
+}
+
+//------------------------------------------------------------------------------
+
+extern "C" int xplra_get_float(float* value, int connectionID, const char* name)
+{
+    Connection* connection = Slot::getConnection(connectionID);
+    if (connection==0) return -1;
+    try {
+        *value = connection->getFloat(name);
+        return 0;
+    } catch (...) {
+        connection->handleException();
+        return -1;
+    }
+}
+
+//------------------------------------------------------------------------------
+
+extern "C" int xplra_get_double(double* value,
+                                int connectionID, const char* name)
+{
+    Connection* connection = Slot::getConnection(connectionID);
+    if (connection==0) return -1;
+    try {
+        *value = connection->getDouble(name);
+        return 0;
+    } catch (...) {
+        connection->handleException();
+        return -1;
+    }
+}
+
+//------------------------------------------------------------------------------
+
+extern "C" int xplra_disconnect(int connectionID)
+{
+    Connection* connection = Slot::getConnection(connectionID);
+    if (connection==0) return -1;
+
+    Slot::clearConnection(connectionID);
+    connection->disconnect();
+    delete connection;
+
+    return 0;
 }
 
Index: src/client/c/hu/varadiistvan/xplra/xplra.h
===================================================================
--- src/client/c/hu/varadiistvan/xplra/xplra.h	(revision 14)
+++ src/client/c/hu/varadiistvan/xplra/xplra.h	(revision 23)
@@ -38,5 +38,121 @@
 /*----------------------------------------------------------------------------*/
 
+/** No error occured */
+#define ERROR_NONE 0
+
+/**
+ * An I/O error has occured. The subcode is the errno value on Linux, or the
+ * Windows error code.
+ */
+#define ERROR_IO 1
+
+/**
+ * A protocol error has occured. The subcode is one of the
+ * ERROR_PROTOCOL_XXX values.
+ */
+#define ERROR_PROTOCOL 2
+
+/** Invalid command was passed to the plugin */
+#define ERROR_PROTOCOL_INVALID_COMMAND = 1
+
+/** An unknown dataref was specified */
+#define ERROR_PROTOCOL_UNKNOWN_DATAREF = 2
+
+/** An invalid type was specified */
+#define ERROR_PROTOCOL_INVALID_TYPE = 3
+
+/** An invalid length was specified */
+#define ERROR_PROTOCOL_INVALID_LENGTH = 4
+
+/** An invalid offset was specified */
+#define ERROR_PROTOCOL_INVALID_OFFSET = 5
+
+/** An invalid count was specified */
+#define ERROR_PROTOCOL_INVALID_COUNT = 6
+
+/** An invalid ID was specified */
+#define ERROR_PROTOCOL_INVALID_ID = 7
+
+/** Other protocol error  */
+#define ERROR_PROTOCOL_OTHER = 8
+
+/** A function requiring a connection is called without a connection */
+#define ERROR_NOT_CONNECTED 3
+
+/** A type-specific function was called for a dataref of a different type */
+#define ERROR_TYPE_MISMATCH 4
+
+/** An invalid ID was passed to a function */
+#define ERROR_INVALID_ID 5
+
+/** Some other error */
+#define ERROR_OTHER 255
+
+/*----------------------------------------------------------------------------*/
+
+/**
+ * Get the last error code with the subcode.
+ *
+ * @return the last error code, or -1 if the given connection ID is invalid.
+ */
+int xplra_get_last_error(int connectionID, unsigned long* subCode);
+
+/**
+ * Get a string representation of the last error.
+ *
+ * @return the string representation of the last error, or 0 if there
+ * was no last error, or the connection ID is invalid.
+ */
+const char* xplra_get_last_error_string(int connectionID);
+
+/**
+ * Clear the last error.
+ */
+void xplra_clear_last_error(int connectionID);
+
+/*----------------------------------------------------------------------------*/
+
+/**
+ * Connect to the simulator.
+ *
+ * @return an ID for the created connection, or -1 on error.
+ */
 int xplra_connect();
+
+/*----------------------------------------------------------------------------*/
+
+/**
+ * Get an integer value from the simulator.
+ *
+ * @return 0 on success, -1 on error
+ */
+int xplra_get_int(int* value, int connectionID, const char* name);
+
+/*----------------------------------------------------------------------------*/
+
+/**
+ * Get a float value from the simulator.
+ *
+ * @return 0 on success, -1 on error
+ */
+int xplra_get_float(float* value, int connectionID, const char* name);
+
+/*----------------------------------------------------------------------------*/
+
+/**
+ * Get a double value from the simulator.
+ *
+ * @return 0 on success, -1 on error
+ */
+int xplra_get_double(double* value, int connectionID, const char* name);
+
+/*----------------------------------------------------------------------------*/
+
+/**
+ * Destroy the connection with the given ID.
+ *
+ * @return 0 on success, -1 on error.
+ */
+int xplra_disconnect(int connectionID);
 
 /*----------------------------------------------------------------------------*/
