const int TIMEOUT_INFINITE = -1;
} //namespace
-void HostIPCConnection::createSystem()
+void HostIPCConnection::connect(const std::string& address, ipc::epoll::EventPoll& eventPoll)
{
- mClient.reset(new ipc::Client(mDispatcher.getPoll(), HOST_IPC_SOCKET));
+ mClient.reset(new ipc::Client(eventPoll, address));
mClient->start();
}
-ipc::epoll::ThreadDispatcher& HostIPCConnection::getDispatcher()
+
+void HostIPCConnection::disconnect()
{
- return mDispatcher;
+ mClient.reset();
}
-void HostIPCConnection::create(const std::string& address)
+bool HostIPCConnection::isConnected()
{
- mClient.reset(new ipc::Client(mDispatcher.getPoll(), address));
- mClient->start();
+ return mClient && mClient->isStarted();
}
+
void HostIPCConnection::callGetZoneIds(api::ZoneIds& argOut)
{
argOut = *mClient->callSync<api::Void, api::ZoneIds>(
#define VASUM_CLIENT_HOST_IPC_CONNECTION_HPP
#include <api/messages.hpp>
-#include <ipc/epoll/thread-dispatcher.hpp>
#include <ipc/client.hpp>
+#include <ipc/epoll/event-poll.hpp>
#include <functional>
public:
typedef unsigned int SubscriptionId;
typedef std::function<void(const vasum::api::Notification&)> NotificationCallback;
- void createSystem();
- void create(const std::string& address);
- ipc::epoll::ThreadDispatcher& getDispatcher();
+ void connect(const std::string& address, ipc::epoll::EventPoll& eventPoll);
+ void disconnect();
+ bool isConnected();
void callGetZoneIds(vasum::api::ZoneIds& argOut);
void callGetActiveZoneId(vasum::api::ZoneId& argOut);
void unsubscribe(const SubscriptionId& id);
private:
- ipc::epoll::ThreadDispatcher mDispatcher;
std::unique_ptr<ipc::Client> mClient;
};
* @brief This file contains vasum-server's client implementation
*/
+//TODO: Make dispatcher related function thread-safe.
+//For now vsm_connect, vsm_get_dispatcher_type, vsm_set_dispatcher_type,
+//vsm_get_poll_fd, vsm_enter_eventloop can't be used at the same time.
+//TODO: Make vsm_get_status_message thread-safe version (vsm_get_status_message_r)
+
#include <config.hpp>
#include "vasum-client-impl.hpp"
#include "utils.hpp"
#include <algorithm>
#include <vector>
#include <cstring>
-#include <cassert>
#include <fstream>
#include <arpa/inet.h>
#include <linux/if.h>
} //namespace
+#define IS_SET(param) \
+ if (!param) { \
+ throw InvalidArgumentException(#param " is not set"); \
+ }
+
Client::Status::Status()
: mVsmStatus(VSMCLIENT_SUCCESS), mMsg()
{
{
}
+bool Client::isInternalDispatcherEnabled() const
+{
+ return static_cast<bool>(mInternalDispatcher);
+}
+
+ipc::epoll::EventPoll& Client::getEventPoll() const
+{
+ if ((mInternalDispatcher && mEventPoll) || (!mInternalDispatcher && !mEventPoll)) {
+ throw OperationFailedException("Can't determine dispatcher method");
+ }
+
+ if (isInternalDispatcherEnabled()) {
+ return mInternalDispatcher->getPoll();
+ } else {
+ return *mEventPoll;
+ }
+}
+
VsmStatus Client::coverException(const function<void(void)>& worker) noexcept
{
try {
worker();
+ mStatusMutex.lock();
mStatus = Status(VSMCLIENT_SUCCESS);
- } catch (const vasum::IOException& ex) {
+ } catch (const IOException& ex) {
mStatus = Status(VSMCLIENT_IO_ERROR, ex.what());
- } catch (const vasum::OperationFailedException& ex) {
+ } catch (const OperationFailedException& ex) {
mStatus = Status(VSMCLIENT_OPERATION_FAILED, ex.what());
- } catch (const vasum::InvalidArgumentException& ex) {
+ } catch (const InvalidArgumentException& ex) {
mStatus = Status(VSMCLIENT_INVALID_ARGUMENT, ex.what());
- } catch (const vasum::InvalidResponseException& ex) {
+ } catch (const InvalidResponseException& ex) {
mStatus = Status(VSMCLIENT_OTHER_ERROR, ex.what());
- } catch (const vasum::ClientException& ex) {
+ } catch (const ClientException& ex) {
mStatus = Status(VSMCLIENT_CUSTOM_ERROR, ex.what());
} catch (const ipc::IPCUserException& ex) {
mStatus = Status(VSMCLIENT_CUSTOM_ERROR, ex.what());
} catch (const exception& ex) {
mStatus = Status(VSMCLIENT_CUSTOM_ERROR, ex.what());
}
- return mStatus.mVsmStatus;
+ VsmStatus ret = mStatus.mVsmStatus;
+ mStatusMutex.unlock();
+ return ret;
+}
+
+VsmStatus Client::connectSystem() noexcept
+{
+ return connect(HOST_IPC_SOCKET);
+}
+
+VsmStatus Client::connect(const std::string& address) noexcept
+{
+ return coverException([&] {
+ if (!mInternalDispatcher && !mEventPoll) {
+ vsm_set_dispatcher_type(VSMDISPATCHER_INTERNAL);
+ }
+ mHostClient.connect(address, getEventPoll());
+ });
+}
+
+VsmStatus Client::disconnect() noexcept
+{
+ return coverException([&] {
+ mHostClient.disconnect();
+ });
}
-VsmStatus Client::createSystem() noexcept
+VsmStatus Client::vsm_get_poll_fd(int* fd) noexcept
{
return coverException([&] {
- mHostClient.createSystem();
+ IS_SET(fd);
+ if (isInternalDispatcherEnabled()) {
+ throw OperationFailedException("Can't get event fd from internal dispatcher");
+ }
+ *fd = mEventPoll->getPollFD();
});
}
-VsmStatus Client::create(const string& address) noexcept
+VsmStatus Client::vsm_enter_eventloop(int /* flags */, int timeout) noexcept
{
return coverException([&] {
- mHostClient.create(address);
+ if (isInternalDispatcherEnabled()) {
+ throw OperationFailedException("Can't enter to event loop of internal dispatcher");
+ }
+ mEventPoll->dispatchIteration(timeout);
});
}
-ipc::epoll::EventPoll& Client::getEventPoll() noexcept
+VsmStatus Client::vsm_set_dispatcher_type(VsmDispacherType dispacher) noexcept
{
- return mHostClient.getDispatcher().getPoll();
+ return coverException([&] {
+ if (mHostClient.isConnected()) {
+ throw OperationFailedException("Can't change dispacher");
+ }
+ switch (dispacher) {
+ case VSMDISPATCHER_INTERNAL:
+ mInternalDispatcher.reset(new ipc::epoll::ThreadDispatcher());
+ mEventPoll.reset();
+ break;
+ case VSMDISPATCHER_EXTERNAL:
+ mEventPoll.reset(new ipc::epoll::EventPoll());
+ mInternalDispatcher.reset();
+ break;
+ default:
+ throw OperationFailedException("Unsupported EventDispacher type");
+ }
+ });
+}
+
+VsmStatus Client::vsm_get_dispatcher_type(VsmDispacherType* dispacher) noexcept
+{
+ return coverException([&] {
+ IS_SET(dispacher);
+
+ if (isInternalDispatcherEnabled()) {
+ *dispacher = VSMDISPATCHER_INTERNAL;
+ } else {
+ *dispacher = VSMDISPATCHER_EXTERNAL;
+ }
+ });
}
const char* Client::vsm_get_status_message() const noexcept
VsmStatus Client::vsm_get_status() const noexcept
{
+ lock_guard<mutex> lock(mStatusMutex);
return mStatus.mVsmStatus;
}
VsmStatus Client::vsm_get_zone_ids(VsmArrayString* array) noexcept
{
- assert(array);
-
return coverException([&] {
+ IS_SET(array);
+
api::ZoneIds zoneIds;
mHostClient.callGetZoneIds(zoneIds);
convert(zoneIds, *array);
VsmStatus Client::vsm_get_active_zone_id(VsmString* id) noexcept
{
- assert(id);
-
return coverException([&] {
+ IS_SET(id);
+
api::ZoneId zoneId;
mHostClient.callGetActiveZoneId(zoneId);
*id = ::strdup(zoneId.value.c_str());
VsmStatus Client::vsm_get_zone_rootpath(const char* id, VsmString* rootpath) noexcept
{
- assert(id);
- assert(rootpath);
-
return coverException([&] {
+ IS_SET(id);
+ IS_SET(rootpath);
+
api::ZoneInfoOut info;
mHostClient.callGetZoneInfo({ id }, info);
*rootpath = ::strdup(info.rootPath.c_str());
VsmStatus Client::vsm_lookup_zone_by_pid(int pid, VsmString* id) noexcept
{
- assert(id);
-
return coverException([&] {
+ IS_SET(id);
+
const string path = "/proc/" + to_string(pid) + "/cpuset";
string cpuset;
VsmStatus Client::vsm_lookup_zone_by_id(const char* id, VsmZone* zone) noexcept
{
- assert(id);
- assert(zone);
-
return coverException([&] {
+ IS_SET(id);
+ IS_SET(zone);
+
api::ZoneInfoOut info;
mHostClient.callGetZoneInfo({ id }, info);
convert(info, *zone);
VsmStatus Client::vsm_set_active_zone(const char* id) noexcept
{
- assert(id);
-
return coverException([&] {
+ IS_SET(id);
+
mHostClient.callSetActiveZone({ id });
});
}
VsmStatus Client::vsm_create_zone(const char* id, const char* tname) noexcept
{
- assert(id);
-
return coverException([&] {
+ IS_SET(id);
+
string template_name = tname ? tname : "default";
mHostClient.callCreateZone({ id, template_name });
});
VsmStatus Client::vsm_destroy_zone(const char* id) noexcept
{
- assert(id);
-
return coverException([&] {
+ IS_SET(id);
mHostClient.callDestroyZone({ id });
});
}
VsmStatus Client::vsm_shutdown_zone(const char* id) noexcept
{
- assert(id);
-
return coverException([&] {
+ IS_SET(id);
mHostClient.callShutdownZone({ id });
});
}
VsmStatus Client::vsm_start_zone(const char* id) noexcept
{
- assert(id);
-
return coverException([&] {
+ IS_SET(id);
mHostClient.callStartZone({ id });
});
}
VsmStatus Client::vsm_lock_zone(const char* id) noexcept
{
- assert(id);
-
return coverException([&] {
+ IS_SET(id);
mHostClient.callLockZone({ id });
});
}
VsmStatus Client::vsm_unlock_zone(const char* id) noexcept
{
- assert(id);
-
return coverException([&] {
+ IS_SET(id);
mHostClient.callUnlockZone({ id });
});
}
VsmStatus Client::vsm_grant_device(const char* id, const char* device, uint32_t flags) noexcept
{
- assert(id);
- assert(device);
-
return coverException([&] {
+ IS_SET(id);
+ IS_SET(device);
+
mHostClient.callGrantDevice({ id, device, flags });
});
}
VsmStatus Client::vsm_revoke_device(const char* id, const char* device) noexcept
{
- assert(id);
- assert(device);
-
return coverException([&] {
+ IS_SET(id);
+ IS_SET(device);
+
mHostClient.callRevokeDevice({ id, device });
});
}
VsmStatus Client::vsm_zone_get_netdevs(const char* id, VsmArrayString* netdevIds) noexcept
{
- assert(id);
- assert(netdevIds);
-
return coverException([&] {
+ IS_SET(id);
+ IS_SET(netdevIds);
+
api::NetDevList netdevs;
mHostClient.callGetNetdevList({ id }, netdevs);
convert(netdevs, *netdevIds);
{
using namespace boost::algorithm;
- assert(id);
- assert(netdevId);
- assert(addr);
-
return coverException([&] {
+ IS_SET(id);
+ IS_SET(netdevId);
+ IS_SET(addr);
+
api::GetNetDevAttrs attrs;
mHostClient.callGetNetdevAttrs({ id, netdevId }, attrs);
struct in_addr* addr,
int prefix) noexcept
{
- assert(id);
- assert(netdevId);
- assert(addr);
-
return coverException([&] {
+ IS_SET(id);
+ IS_SET(netdevId);
+ IS_SET(addr);
+
string value = "ip:" + toString(addr) + ",""prefixlen:" + to_string(prefix);
mHostClient.callSetNetdevAttrs({ id, netdevId, { { "ipv4", value } } } );
});
struct in6_addr* addr,
int prefix) noexcept
{
- assert(id);
- assert(netdevId);
- assert(addr);
-
return coverException([&] {
+ IS_SET(id);
+ IS_SET(netdevId);
+ IS_SET(addr);
+
string value = "ip:" + toString(addr) + ",""prefixlen:" + to_string(prefix);
mHostClient.callSetNetdevAttrs({ id, netdevId, { { "ipv6", value } } } );
});
struct in_addr* addr,
int prefix) noexcept
{
- assert(id);
- assert(netdevId);
- assert(addr);
-
return coverException([&] {
+ IS_SET(id);
+ IS_SET(netdevId);
+ IS_SET(addr);
+
//CIDR notation
string ip = toString(addr) + "/" + to_string(prefix);
mHostClient.callDeleteNetdevIpAddress({ id, netdevId, ip });
struct in6_addr* addr,
int prefix) noexcept
{
- assert(id);
- assert(netdevId);
- assert(addr);
-
return coverException([&] {
+ IS_SET(id);
+ IS_SET(netdevId);
+ IS_SET(addr);
+
//CIDR notation
string ip = toString(addr) + "/" + to_string(prefix);
mHostClient.callDeleteNetdevIpAddress({ id, netdevId, ip });
VsmStatus Client::vsm_netdev_up(const char* id, const char* netdevId) noexcept
{
- assert(id);
- assert(netdevId);
-
return coverException([&] {
+ IS_SET(id);
+ IS_SET(netdevId);
+
mHostClient.callSetNetdevAttrs({ id, netdevId, { { "flags", to_string(IFF_UP) },
{ "change", to_string(IFF_UP) } } } );
});
VsmStatus Client::vsm_netdev_down(const char* id, const char* netdevId) noexcept
{
- assert(id);
- assert(netdevId);
-
return coverException([&] {
+ IS_SET(id);
+ IS_SET(netdevId);
+
mHostClient.callSetNetdevAttrs({ id, netdevId, { { "flags", to_string(~IFF_UP) },
{ "change", to_string(IFF_UP) } } } );
});
const char* zoneDev,
const char* hostDev) noexcept
{
- assert(id);
- assert(zoneDev);
- assert(hostDev);
-
return coverException([&] {
+ IS_SET(id);
+ IS_SET(zoneDev);
+ IS_SET(hostDev);
+
mHostClient.callCreateNetdevVeth({ id, zoneDev, hostDev });
});
}
const char* hostDev,
enum macvlan_mode mode) noexcept
{
- assert(id);
- assert(zoneDev);
- assert(hostDev);
-
return coverException([&] {
+ IS_SET(id);
+ IS_SET(zoneDev);
+ IS_SET(hostDev);
+
mHostClient.callCreateNetdevMacvlan({ id, zoneDev, hostDev, mode });
});
}
VsmStatus Client::vsm_create_netdev_phys(const char* id, const char* devId) noexcept
{
- assert(id);
- assert(devId);
-
return coverException([&] {
+ IS_SET(id);
+ IS_SET(devId);
+
mHostClient.callCreateNetdevPhys({ id, devId });
});
}
{
using namespace boost::algorithm;
- assert(id);
- assert(netdevId);
- assert(netdev);
-
return coverException([&] {
+ IS_SET(id);
+ IS_SET(netdevId);
+ IS_SET(netdev);
+
api::GetNetDevAttrs attrs;
mHostClient.callGetNetdevAttrs({ id, netdevId }, attrs);
auto it = find_if(attrs.values.begin(),
VsmStatus Client::vsm_destroy_netdev(const char* id, const char* devId) noexcept
{
- assert(id);
- assert(devId);
-
return coverException([&] {
+ IS_SET(id);
+ IS_SET(devId);
+
mHostClient.callDestroyNetdev({ id, devId });
});
}
mode_t mode,
VsmString* declarationId) noexcept
{
- assert(id);
- assert(path);
-
return coverException([&] {
+ IS_SET(id);
+ IS_SET(path);
+
api::Declaration declaration;
mHostClient.callDeclareFile({ id, type, path, flags, (int)mode }, declaration);
if (declarationId != NULL) {
const char *data,
VsmString* declarationId) noexcept
{
- assert(source);
- assert(id);
- assert(target);
- assert(type);
- if (!data) {
- data = "";
- }
-
return coverException([&] {
+ IS_SET(source);
+ IS_SET(id);
+ IS_SET(target);
+ IS_SET(type);
+ if (!data) {
+ data = "";
+ }
+
api::Declaration declaration;
mHostClient.callDeclareMount({ source, id, target, type, flags, data }, declaration);
if (declarationId != NULL) {
const char* target,
VsmString* declarationId) noexcept
{
- assert(source);
- assert(id);
- assert(target);
-
return coverException([&] {
+ IS_SET(source);
+ IS_SET(id);
+ IS_SET(target);
+
api::Declaration declaration;
mHostClient.callDeclareLink({ source, id, target }, declaration);
if (declarationId != NULL) {
VsmStatus Client::vsm_list_declarations(const char* id, VsmArrayString* declarations) noexcept
{
- assert(id);
- assert(declarations);
-
return coverException([&] {
+ IS_SET(id);
+ IS_SET(declarations);
+
api::Declarations declarationsOut;
mHostClient.callGetDeclarations({ id }, declarationsOut);
convert(declarationsOut, *declarations);
VsmStatus Client::vsm_remove_declaration(const char* id, VsmString declaration) noexcept
{
- assert(id);
- assert(declaration);
-
return coverException([&] {
+ IS_SET(id);
+ IS_SET(declaration);
+
mHostClient.callRemoveDeclaration({ id, declaration });
});
}
#include "vasum-client.h"
#include "host-ipc-connection.hpp"
+#include <ipc/epoll/thread-dispatcher.hpp>
+#include <ipc/epoll/event-poll.hpp>
+
+#include <mutex>
+#include <memory>
#include <functional>
#include <linux/if_link.h>
~Client() noexcept;
/**
- * Create client with system dbus address.
+ * Connect client with system ipc address.
*
* @return status of this function call
*/
- VsmStatus createSystem() noexcept;
-
- ipc::epoll::EventPoll& getEventPoll() noexcept;
+ VsmStatus connectSystem() noexcept;
/**
- * Create client.
+ * Connect client.
*
- * @param address Dbus socket address
+ * @param address ipc socket address
* @return status of this function call
*/
- VsmStatus create(const std::string& address) noexcept;
+ VsmStatus connect(const std::string& address) noexcept;
+
+ /**
+ * Disconnect client
+ */
+ VsmStatus disconnect() noexcept;
+
+ /**
+ * @see ::vsm_get_poll_fd
+ */
+ VsmStatus vsm_get_poll_fd(int* fd) noexcept;
+
+ /**
+ * @see ::vsm_enter_eventloop
+ */
+ VsmStatus vsm_enter_eventloop(int flags, int timeout) noexcept;
+
+ /**
+ * @see ::vsm_set_dispatcher_type
+ */
+ VsmStatus vsm_set_dispatcher_type(VsmDispacherType dispacher) noexcept;
+
+ /**
+ * @see ::vsm_get_dispatcher_type
+ */
+ VsmStatus vsm_get_dispatcher_type(VsmDispacherType* dispacher) noexcept;
/**
* @see ::vsm_get_status_message
VsmStatus mVsmStatus;
std::string mMsg;
};
-
Status mStatus;
+ mutable std::mutex mStatusMutex;
+ std::unique_ptr<ipc::epoll::ThreadDispatcher> mInternalDispatcher;
+ std::unique_ptr<ipc::epoll::EventPoll> mEventPoll;
HostConnection mHostClient;
+ bool isInternalDispatcherEnabled() const;
+ ipc::epoll::EventPoll& getEventPoll() const;
VsmStatus coverException(const std::function<void(void)>& worker) noexcept;
VsmStatus vsm_netdev_get_ip_addr(const char* zone,
const char* netdevId,
} // namespace
+API VsmStatus vsm_get_poll_fd(VsmClient client, int* fd)
+{
+ return getClient(client).vsm_get_poll_fd(fd);
+}
+
+API VsmStatus vsm_enter_eventloop(VsmClient client, int flags, int timeout)
+{
+ return getClient(client).vsm_enter_eventloop(flags, timeout);
+}
+
+API VsmStatus vsm_set_dispatcher_type(VsmClient client, VsmDispacherType dispacher)
+{
+ return getClient(client).vsm_set_dispatcher_type(dispacher);
+}
+
+API VsmStatus vsm_get_dispatcher_type(VsmClient client, VsmDispacherType* dispacher)
+{
+ return getClient(client).vsm_get_dispatcher_type(dispacher);
+}
+
API VsmClient vsm_client_create()
{
Client* clientPtr = new(nothrow) Client();
API VsmStatus vsm_connect(VsmClient client)
{
- return getClient(client).createSystem();
+ return getClient(client).connectSystem();
}
API VsmStatus vsm_connect_custom(VsmClient client, const char* address)
{
- return getClient(client).create(address);
+ return getClient(client).connect(address);
+}
+
+API VsmStatus vsm_disconnect(VsmClient client)
+{
+ return getClient(client).disconnect();
}
API void vsm_array_string_free(VsmArrayString astring)
VSMFILE_REGULAR
} VsmFileType;
+/**
+ * Event dispacher types.
+ *
+ * @par Example usage:
+ * @code
+#include <pthread.h>
+#include <assert.h>
+#include <stdio.h>
+#include <signal.h>
+#include <sys/epoll.h>
+#include <vasum-client.h>
+
+volatile static sig_atomic_t running;
+static int LOOP_INTERVAL = 1000; // ms
+
+void* main_loop(void* client)
+{
+ int fd = -1;
+ VsmStatus status = vsm_get_poll_fd(client, &fd);
+ assert(VSMCLIENT_SUCCESS == status);
+
+ while (running) {
+ struct epoll_event event;
+ int num = epoll_wait(fd, &event, 1, LOOP_INTERVAL);
+ if (num > 0) {
+ status = vsm_enter_eventloop(client, 0 , 0);
+ assert(VSMCLIENT_SUCCESS == status);
+ }
+ }
+ return NULL;
+}
+
+int main(int argc, char** argv)
+{
+ pthread_t loop;
+ VsmStatus status;
+ VsmClient client;
+ int ret = 0;
+
+ client = vsm_client_create();
+ assert(client);
+
+ status = vsm_set_dispatcher_type(client, VSMDISPATCHER_EXTERNAL);
+ assert(VSMCLIENT_SUCCESS == status);
+
+ status = vsm_connect(client);
+ assert(VSMCLIENT_SUCCESS == status);
+
+ // start event loop
+ running = 1;
+ ret = pthread_create(&loop, NULL, main_loop, client);
+ assert(ret == 0);
+
+ // make vsm_* calls on client
+ // ...
+
+ status = vsm_disconnect(client);
+ assert(VSMCLIENT_SUCCESS == status);
+
+ //stop event loop
+ running = 0;
+ ret = pthread_join(loop, NULL);
+ assert(ret == 0);
+
+ vsm_client_free(client); // destroy client handle
+ return ret;
+}
+ @endcode
+ */
+typedef enum {
+ VSMDISPATCHER_EXTERNAL, /**< User must handle dispatching messages */
+ VSMDISPATCHER_INTERNAL /**< Library will take care of dispatching messages */
+} VsmDispacherType;
+
#ifndef __VASUM_WRAPPER_SOURCE__
/**
+ * Get file descriptor associated with event dispatcher of zone client
+ *
+ * The function vsm_get_poll_fd() returns the file descriptor associated with the event dispatcher of vsm client.
+ * The file descriptor can be bound to another I/O multiplexing facilities like epoll, select, and poll.
+ *
+ * @param[in] client vsm client
+ * @param[out] fd epoll file descriptor
+ * @return status of this function call
+*/
+VsmStatus vsm_get_poll_fd(VsmClient client, int* fd);
+
+/**
+ * Wait for an I/O event on a vsm client
+ *
+ * vsm_enter_eventloop() waits for event on the vsm client
+ *
+ * The call waits for a maximum time of timout milliseconds. Specifying a timeout of -1 makes vsm_enter_eventloop() wait indefinitely,
+ * while specifying a timeout equal to zero makes vsm_enter_eventloop() to return immediately even if no events are available.
+ *
+ * @param[in] client vasum-server's client
+ * @param[in] flags Reserved
+ * @param[in] timeout Timeout time (milisecond), -1 is infinite
+ * @return status of this function call
+*/
+VsmStatus vsm_enter_eventloop(VsmClient client, int flags, int timeout);
+
+/**
+ * Set dispatching method
+ *
+ * @param[in] client vasum-server's client
+ * @param[in] dispacher dispatching method
+ * @return status of this function call
+ */
+VsmStatus vsm_set_dispatcher_type(VsmClient client, VsmDispacherType dispacher);
+
+/**
+ * Get dispatching method
+ *
+ * @param[in] client vasum-server's client
+ * @param[out] dispacher dispatching method
+ * @return status of this function call
+ */
+VsmStatus vsm_get_dispatcher_type(VsmClient client, VsmDispacherType* dispacher);
+
+/**
* Create a new vasum-server's client.
*
* @return Created client pointer or NULL on failure.
VsmStatus vsm_connect_custom(VsmClient client, const char* address);
/**
+ * Disconnect client from vasum-server.
+ *
+ * @param[in] client vasum-server's client
+ * @return status of this function call
+ */
+VsmStatus vsm_disconnect(VsmClient client);
+
+/**
* Release VsmArrayString.
*
* @param[in] astring VsmArrayString
#include <tuple>
#include <utility>
+#include <sys/epoll.h>
+
using namespace vasum;
using namespace utils;
VSM_TEST_CONFIG_INSTALL_DIR "/test-daemon.conf";
const std::string ZONES_PATH = "/tmp/ut-zones"; // the same as in daemon.conf
const std::string TEMPLATE_NAME = "console-ipc";
+const int EVENT_TIMEOUT = 500; // ms
struct Fixture {
utils::ScopedDir mZonesPathGuard;
}
};
+class SimpleEventLoop {
+public:
+ SimpleEventLoop(VsmClient client)
+ : mClient(client)
+ , mIsProcessing(true)
+ , mThread([this] { loop(); })
+ {
+ }
+ ~SimpleEventLoop()
+ {
+ mIsProcessing = false;
+ mThread.join();
+ }
+
+private:
+ VsmClient mClient;
+ std::atomic_bool mIsProcessing;
+ std::thread mThread;
+ void loop() {
+ while (mIsProcessing) {
+ vsm_enter_eventloop(mClient, 0, EVENT_TIMEOUT);
+ }
+ }
+};
+
+class AggragatedEventLoop {
+public:
+ AggragatedEventLoop()
+ : mIsProcessing(true)
+ , mThread([this] { loop(); })
+ {
+ }
+
+ ~AggragatedEventLoop()
+ {
+ mIsProcessing = false;
+ mThread.join();
+ }
+
+ VsmStatus addEventSource(VsmClient client) {
+ int fd = -1;
+ VsmStatus ret = vsm_get_poll_fd(client, &fd);
+ if (VSMCLIENT_SUCCESS != ret) {
+ return ret;
+ }
+ mEventPoll.addFD(fd, EPOLLIN | EPOLLHUP | EPOLLRDHUP, [client] (int, ipc::epoll::Events) {
+ vsm_enter_eventloop(client, 0, 0);
+ });
+ mFds.push_back(fd);
+ return VSMCLIENT_SUCCESS;
+ }
+private:
+ std::atomic_bool mIsProcessing;
+ std::thread mThread;
+ ipc::epoll::EventPoll mEventPoll;
+ std::vector<int> mFds;
+
+ void loop() {
+ while (mIsProcessing) {
+ mEventPoll.dispatchIteration(EVENT_TIMEOUT);
+ }
+ for (int fd : mFds) {
+ mEventPoll.removeFD(fd);
+ }
+ }
+};
+
const std::set<std::string> EXPECTED_ZONES = { "zone1", "zone2", "zone3" };
void convertArrayToSet(VsmArrayString values, std::set<std::string>& ret)
return i;
}
+VsmStatus makeSimpleRequest(VsmClient client)
+{
+ BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, vsm_connect(client));
+ //make a simple call
+ VsmString zone = NULL;
+ VsmStatus status = vsm_get_active_zone_id(client, &zone);
+ vsm_string_free(zone);
+ // disconnect but not destroy
+ vsm_disconnect(client);
+ return status;
+}
+
} // namespace
// make nice BOOST_*_EQUAL output
vsm_client_free(client);
}
+BOOST_AUTO_TEST_CASE(DefaultDispatcher)
+{
+ VsmClient client = vsm_client_create();
+
+ BOOST_CHECK_EQUAL(VSMCLIENT_SUCCESS, makeSimpleRequest(client));
+
+ vsm_client_free(client);
+}
+
+BOOST_AUTO_TEST_CASE(SetDispatcher)
+{
+ VsmClient client = vsm_client_create();
+
+ BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, vsm_set_dispatcher_type(client, VSMDISPATCHER_INTERNAL));
+ BOOST_CHECK_EQUAL(VSMCLIENT_SUCCESS, makeSimpleRequest(client));
+
+ BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, vsm_set_dispatcher_type(client, VSMDISPATCHER_EXTERNAL));
+ {
+ SimpleEventLoop loop(client);
+ BOOST_CHECK_EQUAL(VSMCLIENT_SUCCESS, makeSimpleRequest(client));
+ }
+
+ BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, vsm_set_dispatcher_type(client, VSMDISPATCHER_INTERNAL));
+ BOOST_CHECK_EQUAL(VSMCLIENT_SUCCESS, makeSimpleRequest(client));
+
+ BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, vsm_set_dispatcher_type(client, VSMDISPATCHER_EXTERNAL));
+ {
+ SimpleEventLoop loop(client);
+ BOOST_CHECK_EQUAL(VSMCLIENT_SUCCESS, makeSimpleRequest(client));
+ }
+
+ BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, vsm_set_dispatcher_type(client, VSMDISPATCHER_INTERNAL));
+ BOOST_CHECK_EQUAL(VSMCLIENT_SUCCESS, makeSimpleRequest(client));
+
+ vsm_client_free(client);
+}
+
+BOOST_AUTO_TEST_CASE(GetPollFd)
+{
+ VsmClient client1 = vsm_client_create();
+ VsmClient client2 = vsm_client_create();
+
+ BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, vsm_set_dispatcher_type(client1, VSMDISPATCHER_EXTERNAL));
+ BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, vsm_set_dispatcher_type(client2, VSMDISPATCHER_EXTERNAL));
+ {
+ AggragatedEventLoop loop;
+ BOOST_CHECK_EQUAL(VSMCLIENT_SUCCESS, loop.addEventSource(client1));
+ BOOST_CHECK_EQUAL(VSMCLIENT_SUCCESS, loop.addEventSource(client2));
+
+ BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, vsm_connect(client1));
+ BOOST_REQUIRE_EQUAL(VSMCLIENT_SUCCESS, vsm_connect(client2));
+
+ VsmString zone;
+ //make a simple call
+ zone = NULL;
+ BOOST_CHECK_EQUAL(VSMCLIENT_SUCCESS, vsm_get_active_zone_id(client1, &zone));
+ vsm_string_free(zone);
+ zone = NULL;
+ BOOST_CHECK_EQUAL(VSMCLIENT_SUCCESS, vsm_get_active_zone_id(client2, &zone));
+ vsm_string_free(zone);
+
+ // disconnect but not destroy
+ vsm_disconnect(client1);
+ vsm_disconnect(client2);
+ }
+ vsm_client_free(client1);
+ vsm_client_free(client2);
+}
+
//TODO: We need createBridge from vasum::netdev
//BOOST_AUTO_TEST_CASE(CreateDestroyNetdev)
//BOOST_AUTO_TEST_CASE(LookupNetdev)
static void init_context_wrap(WrappedContext *w)
{
w->client = new Client();
- VsmStatus st = w->client->createSystem();
+ VsmStatus st = w->client->connectSystem();
wrap_error(st, w->client);
memset(&w->hq_ctx, 0, sizeof(w->hq_ctx));