From 151ad8927deea15aa364208b0a7db2f41f05e446 Mon Sep 17 00:00:00 2001 From: Zofia Abramowska Date: Wed, 8 Oct 2014 17:14:01 +0200 Subject: [PATCH 01/16] Change client API error codes Add CYNARA_API_ACCESS_ALLOWED to be returned instead of CYNARA_API_SUCCESS from cynara check call. Renumber client API error codes - now CYNARA_API_ACCESS_DENIED is treated as answer, not as error. Change-Id: I3d64afdc3cc241de8515be507858304efd729da6 --- src/client-common/plugins/NaiveInterpreter.h | 2 +- src/include/cynara-client-error.h | 23 +++++++++++++---------- src/include/cynara-client.h | 2 +- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/client-common/plugins/NaiveInterpreter.h b/src/client-common/plugins/NaiveInterpreter.h index e16f463..a541e19 100644 --- a/src/client-common/plugins/NaiveInterpreter.h +++ b/src/client-common/plugins/NaiveInterpreter.h @@ -37,7 +37,7 @@ class NaiveInterpreter : public InterpreterInterface { } int toResult(const PolicyResult &result) noexcept { if (result.policyType() == PredefinedPolicyType::ALLOW) - return CYNARA_API_SUCCESS; + return CYNARA_API_ACCESS_ALLOWED; else return CYNARA_API_ACCESS_DENIED; } diff --git a/src/include/cynara-client-error.h b/src/include/cynara-client-error.h index 36d20f4..9828942 100644 --- a/src/include/cynara-client-error.h +++ b/src/include/cynara-client-error.h @@ -27,33 +27,36 @@ /** * \name Return Codes * exported by the foundation API. - * result codes begin with the start error code and extend into negative direction. + * result codes beginning with negative codes indicate an error. * @{ */ -/*! \brief indicating the result of the one specific API is successful or access is allowed */ -#define CYNARA_API_SUCCESS 0 +/*! \brief indicating access that was checked is allowed */ +#define CYNARA_API_ACCESS_ALLOWED 2 /*! \brief indicating that access that was checked is denied */ -#define CYNARA_API_ACCESS_DENIED -1 +#define CYNARA_API_ACCESS_DENIED 1 + +/*! \brief indicating the result of the one specific API is successful */ +#define CYNARA_API_SUCCESS 0 /*! \brief indicating system is running out of memory state */ -#define CYNARA_API_OUT_OF_MEMORY -2 +#define CYNARA_API_OUT_OF_MEMORY -1 /*! \brief indicating the API's parameter is malformed */ -#define CYNARA_API_INVALID_PARAM -3 +#define CYNARA_API_INVALID_PARAM -2 /*! \brief service not available */ -#define CYNARA_API_SERVICE_NOT_AVAILABLE -4 +#define CYNARA_API_SERVICE_NOT_AVAILABLE -3 /*! \brief indicating that value is not present in cache */ -#define CYNARA_API_CACHE_MISS -5 +#define CYNARA_API_CACHE_MISS -4 /*! \brief indicating that provided method is not supported by library */ -#define CYNARA_API_METHOD_NOT_SUPPORTED -6 +#define CYNARA_API_METHOD_NOT_SUPPORTED -5 /*! \brief indicating an unknown error */ -#define CYNARA_API_UNKNOWN_ERROR -7 +#define CYNARA_API_UNKNOWN_ERROR -6 /** @}*/ #endif // CYNARA_CLIENT_ERROR_H diff --git a/src/include/cynara-client.h b/src/include/cynara-client.h index dcdab40..3f4c938 100644 --- a/src/include/cynara-client.h +++ b/src/include/cynara-client.h @@ -133,7 +133,7 @@ int cynara_finish(cynara *p_cynara); * \param[in] user User running client. * \param[in] privilege Privilege that is a subject of a check.. * - * \return CYNARA_API_SUCCESS on success (access granted), CYNARA_API_ACCESS_DENIED on access denial + * \return CYNARA_API_ACCESS_ALLOWED on access allowed, CYNARA_API_ACCESS_DENIED on access denial * or other error code on error. */ int cynara_check(cynara *p_cynara, const char *client, const char *client_session, const char *user, -- 2.7.4 From 0475c1d1ed6e0ddf6bc465b9df3e5bc007b10b26 Mon Sep 17 00:00:00 2001 From: Zofia Abramowska Date: Wed, 8 Oct 2014 17:16:18 +0200 Subject: [PATCH 02/16] Add asynchronous API header Add simple API which provide means to: - ask cynara if has permission to using cynara_async_check() for cache check - create request for having permission to to be sent using cynara_async_create_request() - send requests and receive responses using cynara_async_process() - cancel created request using cynara_async_cancel_request() - inform user about available response and status changes of cynara socket through callbacks This is an asynchronus API, so all I/O operations inside are non-blocking. Change-Id: Id6d53eae7587c11288d44bb2dd7980ec039e7ca0 --- src/include/cynara-client-async.h | 508 ++++++++++++++++++++++++++++++++++++++ src/include/cynara-client-error.h | 24 +- 2 files changed, 522 insertions(+), 10 deletions(-) create mode 100644 src/include/cynara-client-async.h diff --git a/src/include/cynara-client-async.h b/src/include/cynara-client-async.h new file mode 100644 index 0000000..c824124 --- /dev/null +++ b/src/include/cynara-client-async.h @@ -0,0 +1,508 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/** + * @file src/include/cynara-client-async.h + * @author Zofia Abramowska + * @author Marcin Niesluchowski + * @version 1.0 + * @brief This file contains asynchronous client APIs of Cynara available + * with libcynara-client-asynchronous. + */ + +#ifndef CYNARA_CLIENT_ASYNC_H +#define CYNARA_CLIENT_ASYNC_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef uint16_t cynara_check_id; +typedef struct cynara_async cynara_async; +typedef struct cynara_async_configuration cynara_async_configuration; + +/** + * \enum cynara_async_status + * Values indicating the status of connected cynara socket. + * + * \var cynara_async_status::CYNARA_STATUS_FOR_READ + * Wait for read events on socket. + * + * \var cynara_async_status::CYNARA_STATUS_FOR_RW + * Wait for both read and write events on socket. + */ +typedef enum { + CYNARA_STATUS_FOR_READ, + CYNARA_STATUS_FOR_RW +} cynara_async_status; + +/** + * \enum cynara_async_call_cause + * Values indicating the reason of cynara_response_callback call. + * + * \var cynara_async_call_cause::CYNARA_CALL_CAUSE_ANSWER + * Callback was called due to response to previous cynara_async_create_request() call. + * + * \var cynara_async_call_cause::CYNARA_CALL_CAUSE_CANCEL + * Callback was called due to request cancelation with cynara_async_cancel_request() call. + * + * \var cynara_async_call_cause::CYNARA_CALL_CAUSE_FINISH + * Callback was called due to cynara_async_finish() call. + * + * \var cynara_async_call_cause::CYNARA_CALL_CAUSE_SERVICE_NOT_AVAILABLE + * Callback was called due to service not available. + */ +typedef enum { + CYNARA_CALL_CAUSE_ANSWER, + CYNARA_CALL_CAUSE_CANCEL, + CYNARA_CALL_CAUSE_FINISH, + CYNARA_CALL_CAUSE_SERVICE_NOT_AVAILABLE +} cynara_async_call_cause; + +/** + * \brief Response_callback is registered once in cynara_async_create_request() + * and will be triggered exactly once in 4 kind of situations: + * 1) after response is received from cynara service (CYNARA_CALL_CAUSE_ANSWER) + * 2) when request is canceled with cynara_async_cancel_request() (CYNARA_CALL_CAUSE_CANCEL) + * 3) when request was pending for response, but cynara_async_finish() was called + * (CYNARA_CALL_CAUSE_FINISH) + * 4) when connection to cynara service was broken and cannot be established again + * - probably cynara is unoperational (CYNARA_CALL_CAUSE_SERVICE_NOT_AVAILABLE) + * + * \param[in] check_id Number identifying check request. Number is generated in + * cynara_async_cancel_request() and returned to user. It can be used to match + * response with sent request. + * Number is valid since cynara_async_create_request() call till callback call. + * After that the number can be reused by cynara to run new request. + * \param[in] cause Cause of triggering this callback. + * \param[in] response Response for created request. Should be ignored if cause is not + * an answer to request (cause != CYNARA_CALL_CAUSE_ANSWER). + * \param[in] user_response_data User specific data - passed to cynara library in + * cynara_async_cancel_request() is being only remembered by library. + * Cynara library does not take any actions on this pointer, + * except for giving it back to user in cynara_response_callback. + * After that cynara forgets this data. + */ +typedef void (*cynara_response_callback) (cynara_check_id check_id, cynara_async_call_cause cause, + int response, void *user_response_data); + +/** + * \brief Callback used by cynara async API when status of cynara socket is changed in + * cynara_async_initialize(), cynara_async_create_request(), cynara_async_process(), + * cynara_async_cancel_request() or cynara_async_finish(). + * File descriptor changes every time cynara library connects or disconnects cynara service. + * Status change is triggered when check_request or cancel needs to be send to + * cynara service or sending data has finished and there is nothing more to send to cynara + * service. + * Note, that provided file descriptor is used internally by libcynara + * so user should not use it in other way than waiting on it in event loop. + * In particular user should not write to, read from or close this fd. + * + * \param[in] old_fd Old descriptor which should be unregistered from event loop, + * Special value -1 is used when callback is called after first + * successful connect. + * \param[in] new_fd New descriptor which should be registered in event loop, + * Special value -1 is used when cynara_async_finish() is called and + * cynara is disconnected. In this case status should be ignored. + * \param[in] status Status indicating which events should be awaited on socket + * \param[in] user_status_data User specific data - passed to cynara library in + * cynara_async_initialize() is being only remembered by library. + * Cynara library does not take any actions on this pointer, + * except for giving it back to user in cynara_status_callback. + * Data should be valid at least until cynara_async_finish() is called. + */ +typedef void (*cynara_status_callback) (int old_fd, int new_fd, cynara_async_status status, + void *user_status_data); + +/** + * \par Description: + * Initialize cynara-async-client library with given configuration. Create structure used in + * following API calls and register callback and user_status_data for + * further cynara async API calls. + * + * \par Purpose: + * This API must be used prior to calling any other cynara async API function. + * It will create cynara_async structure required for any other cynara async API calls. + * + * \par Typical use case: + * Once before entering event loop and before any other cynara async API is called. + * + * \par Method of function operation: + * This API initializes inner library structures and in case of success + * returns cynara_async structure. + * + * \par Sync (or) Async: + * This is an synchronous API. + * + * \par Thread-safety: + * This function is NOT thread-safe. If functions from described API are called by multithreaded + * application from different threads, they must be put into protected critical section. + * + * \par Important notes: + * Structure cynara_async created by cynara_async_initialize() call should be released + * with cynara_async_finish(). + * + * \param[out] pp_cynara Placeholder for created cynara_async structure. + * \param[in] p_conf Configuration for cynara-async-client library. + * NULL should be used for default configuration. + * Configuration management functions will be added later. + * Configuration will be able to specify e.g. size of cache used by library + * for holding checks results. + * \param[in] callback Function called when connection is started. + * If NULL, no callback will be called, when status changes. + * \param[in] user_status_data User specific data, passed to callback is being only remembered + * by library. Cynara library does not take any actions on this pointer, + * except for giving it back to user in cynara_status_callback. + * Data should be valid at least until cynara_async_finish() is called. + * Can be NULL. + * + * \return CYNARA_API_SUCCESS on success + * or negative error code on error. + */ +int cynara_async_initialize(cynara_async **pp_cynara, const cynara_async_configuration *p_conf, + cynara_status_callback callback, void *user_status_data); + +/** + * \par Description: + * Release cynara-async-client library and destroy structure created with cynara_async_initialize(). + * + * \par Purpose: + * This API should be used to clean up after usage of cynara-async-client library. + * + * \par Typical use case: + * Once after connection to cynara is not needed. + * + * \par Method of function operation: + * This API releases inner library structure and destroys cynara_async structure. Connection to + * cynara server is closed. Upon disconnecting this will trigger cynara_status_callback callback + * with -1 as new_fd param so client can unregister file descriptor connected with cynara. It will + * also trigger cynara_response_callback callback for each created request with + * cynara_async_call_cause::CYNARA_CALL_CAUSE_FINISH as cause param. + * + * \par Sync (or) Async: + * This is an asynchronous API. + * + * \par Thread-safety: + * This function is NOT thread-safe. If functions from described API are called by multithreaded + * application from different threads, they must be put into protected critical section. + * + * \par Important notes: + * No other call to cynara-async-client library should be made after call to cynara_async_finish(). + * + * \param[in] p_cynara cynara_async structure. If NULL, then the call has no effect. + */ +void cynara_async_finish(cynara_async *p_cynara); + +/** + * \par Description: + * Check access to given privilege for specified user, client and client_session in cache. + * + * \par Purpose: + * This API should be used to check if cache holds information about access of user, + * running application identified as clients to a privilege. + * This API should be used for fast check in cache. + * + * \par Typical use case: + * A service wants to check in cache, if a client requesting access to some privilege + * has proper rights. + * + * \par Method of function operation: + * Client (a process / application) requesting access to a privilege is running as some user. + * For such triple (client, user, privilege) a cache is checked. + * If cache is invalid it is cleared and call returns same as access not found. + * Additional parameter client_session + * may be used to distinguish between client session (e.g. for allowing access only for this + * particular application launch). EMpty string "" can be used, when session differentation + * is not needed. + * + * \par Sync (or) Async: + * This is an synchronous API. + * + * \par Thread-safety: + * This function is NOT thread-safe. If functions from described API are called by multithreaded + * application from different threads, they must be put into protected critical section. + * + * \par Important notes: + * Call to cynara_async_check_cache() needs cynara_async structure to be created first. + * Use cynara_async_initialize() before calling this function. + * + * \param[in] p_cynara cynara_async structure. + * \param[in] client Application or process identifier. + * \param[in] client_session Client defined session. + * \param[in] user User of running client. + * \param[in] privilege Privilege that is a subject of a check. + * + * \return CYNARA_API_ACCESS_ALLOWED on checked access allowed, + * CYNARA_API_ACCESS_DENIED on checked access denied, + * CYNARA_API_CACHE_MISS on access not in cache, + * or other negative error code on error. + */ +int cynara_async_check_cache(cynara_async *p_cynara, const char *client, const char *client_session, + const char *user, const char *privilege); + +/** + * \par Description: + * Creates access check request to cynara service for client, user accessing given privilege. + * Set callback and user_response_data to be called and passed when request processing is finished. + * + * \par Purpose: + * This API should be used to create check request for client identified by a triple + * (client, user, privilege) in custom defined session. + * Response can be received with cynara_async_process(). + * Check id is returned to pair request with response for canceling purposes. + * + * \par Typical use case: + * When cynara_async_check_cache() returned CYNARA_API_CACHE_MISS, so cynara service + * has to be asked, if a client requesting access to some privilege has proper rights. + * To receive matching response client sets callback and specifies arbitrary data to be passed + * to this callback. + * + * \par Method of function operation: + * Client (a process / application) requesting access to a privilege is running as some user. + * For such triple (client, user, privilege) a request event is created and added to pending + * requests for cynara_async_process() to process. + * Socket status will be changed to CYNARA_STATUS_FOR_RW, to ensure that cynara_async_process() + * will be triggered in event loop after socket is ready to send request to cynara service. + * After request is sent and there is nothing more to send to cynara service, status will change + * back to CYNARA_STATUS_FOR_READ. Status changes are delivered with cynara_status_callback. + * When function is succesfully called unique check_id is returned. It is used for matching + * generated request with response, that will be received by registered callback. + * Because check_id is coded as 16-bit unsigned integer, there can be only 2^16 = 65536 pending + * requests. When response callback is called either because of getting answer or because + * of cancel check_id used for taht request is released and can be reused by cynara library. + * When maximum of pending requests is reached cynara_async_create_request() fails with + * CYNARA_API_MAX_PENDING_REQUESTS error code. + * + * \par Sync (or) Async: + * This is an asynchronous API. + * + * \par Thread-safety: + * This function is NOT thread-safe. If functions from described API are called by multithreaded + * application from different threads, they must be put into protected critical section. + * + * \par Important notes: + * Call to cynara_async_create_request() needs cynara_async structure to be created first with + * cynara_async_initialize(). + * Call cynara_async_cancel_request() to cancel pending request. + * Call cynara_async_process() to receive response. + * It is guaranteed that if cynara_async_create_request() function suceeds (CYNARA_API_SUCCESS) + * a callback will be called exactly once and that it will receive user_response_data. + * If function fails (returns negative error code) request won't be generated and won't be pending, + * callback function won't be ever called and user_response_data won't be remembered by library. + * Also no check_id will be generated and *p_check_id value should be ignored. + * + * \param[in] p_cynara cynara_async structure. + * \param[in] client Application or process identifier. + * \param[in] client_session Client defined session. + * \param[in] user User of running client. + * \param[in] privilege Privilege that is a subject of a check. + * \param[out] p_check_id Placeholder for check id. If NULL, then no check_id is returned. + * \param[in] callback Function called when matching response is received. + * If NULL then no callback will be called when response, cancel, finish + * or service not availble error happens. + * \param[in] user_response_data User specific data, passed to callback is being only remembered + * by library. Cynara library does not take any actions on this pointer, + * except for giving it back to user in cynara_response_callback. + * Can be NULL. + * + * \return CYNARA_API_SUCCESS on success, + * CYNARA_API_MAX_PENDING_REQUESTS on too much pending requests, + * or other negative error code on error. + */ +int cynara_async_create_request(cynara_async *p_cynara, const char *client, + const char *client_session, const char *user, const char *privilege, + cynara_check_id *p_check_id, cynara_response_callback callback, + void *user_response_data); + +/** + * \par Description: + * Process events that appeared on cynara socket. + * + * \par Purpose: + * Process events after they appear on cynara socket. + * + * \par Typical use case: + * After request was queued with cynara_async_create_request() this API will return response. + * When event loop will return readiness on cynara socket, client should use this API. + * + * \par Method of function operation: + * This API sends pending requests, receives all responses and reacts when cynara + * has disconnected. If cynara has disconnected all values in cache become invalid. During these + * operations status of cynara socket may change, so cynara_status_callback callback will be + * triggered to indicate these changes. cynara_response_callback callback will be triggered with + * cynara_async_call_cause::CYNARA_CALL_CAUSE_ANSWER as cause param when response is available. + * If cynara has disconnected it will be triggered with + * cynara_async_call_cause::CYNARA_CALL_CAUSE_SERVICE_NOT_AVAILABLE as cause param. + * + * \par Sync (or) Async: + * This is an asynchronous API. + * + * \par Thread-safety: + * This function is NOT thread-safe. If functions from described API are called by multithreaded + * application from different threads, they must be put into protected critical section. + * + * \par Important notes: + * Call to cynara_async_process() requires initialized cynara_async structure. For this use + * cynara_async_initialize(). + * + * \param[in] p_cynara cynara_async structure. + * + * \return CYNARA_API_SUCCESS on success + * or negative error code on error. + */ +int cynara_async_process(cynara_async *p_cynara); + +/** + * \par Description: + * Cancel request created by cynara_async_create_request(). + * + * \par Purpose: + * This API should be used to cancel pending check request, + * created by cynara_async_create_request(). + * + * \par Typical use case: + * When cynara client is no longer interested in receiving an answer. + * Same check_id value should be used to identify proper request as was generated during + * request creation with cynara_async_create_request(). + * + * \par Method of function operation: + * Cancels request created by cynara_async_create_request() call. + * cynara_status_callback callback may be triggered to be able to send cancel to cynara. + * cynara_response_callback callback will be triggered with with + * cynara_async_call_cause::CYNARA_CALL_CAUSE_CANCEL as cause param. + * + * \par Sync (or) Async: + * This is a synchronous API. + * + * \par Thread-safety: + * This function is NOT thread-safe. If functions from described API are called by multithreaded + * application from different threads, they must be put into protected critical section. + * + * \par Important notes: + * Call to cynara_async_cancel_request() needs cynara_async structure to be created first. For this + * use cynara_async_initialize(). + * + * \param[in] p_cynara cynara_async structure. + * \param[in] check_id Check id to be cancelled + * + * \return CYNARA_API_SUCCESS on success + * or negative error code on error. + */ +int cynara_async_cancel_request(cynara_async *p_cynara, cynara_check_id check_id); + +/* + * Example of usage: + * + * void change_status(int old_fd, int new_fd, cynara_async_status status, void *user_status_data) + * { + * // unregister using old_fd + * ... + * //register using new_fd and new status + * } + * + * int process_response(int check_id, cynara_async_call_cause cause, int response, + * void *user_response_data) + * { + * switch (cause) { + * case cynara_async_call_cause::CYNARA_CALL_CAUSE_ANSWER: + * // handle answer from cynara service - use response value + * break; + * case cynara_async_call_cause::CYNARA_CALL_CAUSE_CANCEL: + * // handle canceled request + * break; + * case cynara_async_call_cause::CYNARA_CALL_CAUSE_FINISH: + * // handle finish of client async + * break; + * case cynara_async_call_cause::CYNARA_CALL_CAUSE_SERVICE_NOT_AVAILABLE: + * // handle disconnection + * } + * ... + * free_user_response_data(user_response_data); + * } + * + * void main_process + * { + * //initialize all required objects + * cynara_async *p_cynara; + * int ret; + * //change_status will be called passing file descriptor connected to cynara server + * if ((ret = cynara_async_initalize(&p_cynara, NULL, change_status, &fd_sets)) != + * CYNARA_API_SUCCESS) { + * // handle error + * } + * + * //start event loop + * event_process(fd_sets, ...) + * + * //event loop stopped, clean-up, before closing program + * cynara_async_finish(p_cynara); + * } + * + * void event_process(fd_sets, ...) + * { + * //event loop of user choice + * select(..., fd_sets.read, fd_sets.write) { + * ... + * if(active_socket == cynara_socket) { + * if(cynara_async_process(p_cynara) != CYNARA_API_SUCCESS) { + * // handle error + * } + * } else if (active_socket == some_client_socket) { + * //processing clients, which may require cynara checks + * ... + * int ret = cynara_async_check_cache(p_cynara, client, client_session, user, + * privilege); + * switch(ret) { + * case CYNARA_API_ACCESS_ALLOWED: + * // allow client + * break; + * case CYNARA_API_ACCESS_DENIED: + * // deny client + * break; + * case CYNARA_API_CACHE_MISS: + * // not in cache - prepare data that will be passed to callback + * allocate_user_response_data(&user_response_data); + * + * // create request + * ret = cynara_async_create_request(p_cynara, + * client, client_session, user, privilege, + * &check_id, + * process_response, user_response_data); + * if(ret != CYNARA_API_SUCCESS) { + * free_user_response_data(user_response_data); + * // handle error + * } + * default: + * // handle error + * } + * ... + * // waiting for some request too long + * if (ret = cynara_async_cancel_request(p_cynara, check_id)) != CYNARA_API_SUCCESS) { + * // handle error + * } + * } + * ... + * } + * ... + * } + */ + +#ifdef __cplusplus +} +#endif + +#endif /* CYNARA_CLIENT_ASYNC_H */ diff --git a/src/include/cynara-client-error.h b/src/include/cynara-client-error.h index 9828942..8dd344f 100644 --- a/src/include/cynara-client-error.h +++ b/src/include/cynara-client-error.h @@ -40,23 +40,27 @@ /*! \brief indicating the result of the one specific API is successful */ #define CYNARA_API_SUCCESS 0 +/*! \brief indicating that value is not present in cache */ +#define CYNARA_API_CACHE_MISS -1 + +/*! \brief indicating that pending requests reached maximum */ +#define CYNARA_API_MAX_PENDING_REQUESTS -2 + /*! \brief indicating system is running out of memory state */ -#define CYNARA_API_OUT_OF_MEMORY -1 +#define CYNARA_API_OUT_OF_MEMORY -3 /*! \brief indicating the API's parameter is malformed */ -#define CYNARA_API_INVALID_PARAM -2 +#define CYNARA_API_INVALID_PARAM -4 -/*! \brief service not available */ -#define CYNARA_API_SERVICE_NOT_AVAILABLE -3 - -/*! \brief indicating that value is not present in cache */ -#define CYNARA_API_CACHE_MISS -4 +/*! \brief indicating that service is not available */ +#define CYNARA_API_SERVICE_NOT_AVAILABLE -5 /*! \brief indicating that provided method is not supported by library */ -#define CYNARA_API_METHOD_NOT_SUPPORTED -5 +#define CYNARA_API_METHOD_NOT_SUPPORTED -6 /*! \brief indicating an unknown error */ -#define CYNARA_API_UNKNOWN_ERROR -6 +#define CYNARA_API_UNKNOWN_ERROR -7 + /** @}*/ -#endif // CYNARA_CLIENT_ERROR_H +#endif /* CYNARA_CLIENT_ERROR_H */ -- 2.7.4 From 711213d22be5b0e68f20051db57417ee534d24cb Mon Sep 17 00:00:00 2001 From: Marcin Niesluchowski Date: Thu, 9 Oct 2014 16:37:56 +0200 Subject: [PATCH 03/16] Add function for catching all client exceptions Change-Id: Ia70b4ee257aa279a26862f3d412f81dfdcae3309 --- src/client-common/exceptions/TryCatch.h | 54 ++++++++++++++++++++++++++++ src/client-common/plugins/NaiveInterpreter.h | 6 ++-- src/client-common/plugins/PluginInterface.h | 6 ++-- src/client/api/client-api.cpp | 31 +++++++++++----- src/client/logic/Logic.cpp | 4 +-- src/client/logic/Logic.h | 4 +-- src/common/sockets/Socket.cpp | 2 +- src/common/sockets/Socket.h | 2 +- 8 files changed, 89 insertions(+), 20 deletions(-) create mode 100644 src/client-common/exceptions/TryCatch.h diff --git a/src/client-common/exceptions/TryCatch.h b/src/client-common/exceptions/TryCatch.h new file mode 100644 index 0000000..8d1fb20 --- /dev/null +++ b/src/client-common/exceptions/TryCatch.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/** + * @file src/client-common/exceptions/TryCatch.h + * @author Marcin Niesluchowski + * @version 1.0 + * @brief This file contains functions for catching exceptions + */ + +#ifndef SRC_CLIENT_COMMON_EXCEPTIONS_TRYCATCH_H_ +#define SRC_CLIENT_COMMON_EXCEPTIONS_TRYCATCH_H_ + +#include +#include +#include + +#include + +#include + +namespace Cynara { + +int tryCatch(const std::function &func) { + try { + return func(); + } catch (const std::bad_alloc &e) { + LOGE(e.what()); + return CYNARA_API_OUT_OF_MEMORY; + } catch (const std::exception &e) { + LOGE(e.what()); + return CYNARA_API_UNKNOWN_ERROR; + } catch (...) { + LOGE("Unexpected exception"); + return CYNARA_API_UNKNOWN_ERROR; + } +} + +} // namespace Cynara + +#endif // SRC_CLIENT_COMMON_EXCEPTIONS_TRYCATCH_H_ + diff --git a/src/client-common/plugins/NaiveInterpreter.h b/src/client-common/plugins/NaiveInterpreter.h index a541e19..04d05de 100644 --- a/src/client-common/plugins/NaiveInterpreter.h +++ b/src/client-common/plugins/NaiveInterpreter.h @@ -29,13 +29,13 @@ namespace Cynara { class NaiveInterpreter : public InterpreterInterface { - bool isUsable(const PolicyResult &result UNUSED) noexcept { + bool isUsable(const PolicyResult &result UNUSED) { return true; } - bool isCacheable(const PolicyResult &result UNUSED) noexcept { + bool isCacheable(const PolicyResult &result UNUSED) { return true; } - int toResult(const PolicyResult &result) noexcept { + int toResult(const PolicyResult &result) { if (result.policyType() == PredefinedPolicyType::ALLOW) return CYNARA_API_ACCESS_ALLOWED; else diff --git a/src/client-common/plugins/PluginInterface.h b/src/client-common/plugins/PluginInterface.h index f1e7ef9..5f3a947 100644 --- a/src/client-common/plugins/PluginInterface.h +++ b/src/client-common/plugins/PluginInterface.h @@ -34,9 +34,9 @@ typedef std::shared_ptr InterpreterInterfacePtr; class InterpreterInterface { public: - virtual bool isCacheable(const PolicyResult &result) noexcept = 0; - virtual bool isUsable(const PolicyResult &result) noexcept = 0; - virtual int toResult(const PolicyResult &result) noexcept = 0; + virtual bool isCacheable(const PolicyResult &result) = 0; + virtual bool isUsable(const PolicyResult &result) = 0; + virtual int toResult(const PolicyResult &result) = 0; virtual ~InterpreterInterface() {}; }; diff --git a/src/client/api/client-api.cpp b/src/client/api/client-api.cpp index 6d086a5..6ca7def 100644 --- a/src/client/api/client-api.cpp +++ b/src/client/api/client-api.cpp @@ -24,6 +24,7 @@ #include +#include #include #include @@ -47,17 +48,15 @@ int cynara_initialize(cynara **pp_cynara, const cynara_configuration *p_conf UNU if (!pp_cynara) return CYNARA_API_INVALID_PARAM; - try { + return Cynara::tryCatch([&]() { *pp_cynara = new cynara(new Cynara::Logic); - } catch (const std::bad_alloc &ex) { - return CYNARA_API_OUT_OF_MEMORY; - } - init_log(); + init_log(); - LOGD("Cynara client initialized"); + LOGD("Cynara client initialized"); - return CYNARA_API_SUCCESS; + return CYNARA_API_SUCCESS; + }); } CYNARA_API @@ -77,5 +76,21 @@ int cynara_check(cynara *p_cynara, const char *client, const char *client_sessio if(!client || !client_session || !user || !privilege) return CYNARA_API_INVALID_PARAM; - return p_cynara->impl->check(client, client_session, user, privilege); + return Cynara::tryCatch([&]() { + std::string clientStr; + std::string clientSessionStr; + std::string userStr; + std::string privilegeStr; + + try { + clientStr = client; + clientSessionStr = client_session; + userStr = user; + privilegeStr = privilege; + } catch (const std::length_error &e) { + LOGE(e.what()); + return CYNARA_API_INVALID_PARAM; + } + return p_cynara->impl->check(clientStr, clientSessionStr, userStr, privilegeStr); + }); } diff --git a/src/client/logic/Logic.cpp b/src/client/logic/Logic.cpp index e090fcc..2708318 100644 --- a/src/client/logic/Logic.cpp +++ b/src/client/logic/Logic.cpp @@ -57,7 +57,7 @@ Logic::Logic() { } int Logic::check(const std::string &client, const ClientSession &session, const std::string &user, - const std::string &privilege) noexcept + const std::string &privilege) { if (!m_socket->isConnected()){ onDisconnected(); @@ -81,7 +81,7 @@ int Logic::check(const std::string &client, const ClientSession &session, const return m_cache->update(session, key, result); } -int Logic::requestResult(const PolicyKey &key, PolicyResult &result) noexcept { +int Logic::requestResult(const PolicyKey &key, PolicyResult &result) { ProtocolFrameSequenceNumber sequenceNumber = generateSequenceNumber(); //Ask cynara service diff --git a/src/client/logic/Logic.h b/src/client/logic/Logic.h index 8f8b1bb..36076fc 100644 --- a/src/client/logic/Logic.h +++ b/src/client/logic/Logic.h @@ -40,13 +40,13 @@ private: PluginCachePtr m_cache; void onDisconnected(void); - int requestResult(const PolicyKey &key, PolicyResult &result) noexcept; + int requestResult(const PolicyKey &key, PolicyResult &result); public: Logic(); virtual ~Logic() {}; virtual int check(const std::string &client, const ClientSession &session, - const std::string &user, const std::string &privilege) noexcept; + const std::string &user, const std::string &privilege); }; } // namespace Cynara diff --git a/src/common/sockets/Socket.cpp b/src/common/sockets/Socket.cpp index 51cd495..e3b91dc 100644 --- a/src/common/sockets/Socket.cpp +++ b/src/common/sockets/Socket.cpp @@ -50,7 +50,7 @@ Socket::~Socket() { close(); } -void Socket::close(void) noexcept { +void Socket::close(void) { if (m_sock > -1) ::close(m_sock); m_sock = -1; diff --git a/src/common/sockets/Socket.h b/src/common/sockets/Socket.h index 95991db..3c5c37b 100644 --- a/src/common/sockets/Socket.h +++ b/src/common/sockets/Socket.h @@ -37,7 +37,7 @@ private: std::string m_socketPath; int m_pollTimeout; - void close(void) noexcept; + void close(void); //returns true if socket is ready //returns false in case of timeout -- 2.7.4 From 24e4b22d3e1d2bd970f92617e1469a40d34e0c0c Mon Sep 17 00:00:00 2001 From: Marcin Niesluchowski Date: Thu, 4 Sep 2014 15:50:32 +0200 Subject: [PATCH 04/16] Add async api stub implementation Below are listed asynchronous API functions with its value returned for valid params and enough memory (stub version). - cynara_async_initialize CYNARA_API_SUCCESS - cynara_finish - cynara_async_cache_check CYNARA_API_CACHE_MISS - cynara_async_create_request CYNARA_API_MAX_PENDING_REQUESTS - cynara_async_process CYNARA_API_SUCCESS - cynara_async_cancel_request CYNARA_API_SUCCESS Change-Id: Ic10d04adc5e7d45fa643a1e817db2670c05790cf --- CMakeLists.txt | 1 + packaging/cynara.spec | 56 ++++++-- packaging/libcynara-client-async.manifest | 5 + pkgconfig/CMakeLists.txt | 1 + pkgconfig/cynara-client-async/CMakeLists.txt | 25 ++++ .../cynara-client-async/cynara-client-async.pc.in | 11 ++ src/CMakeLists.txt | 1 + src/client-async/CMakeLists.txt | 49 +++++++ src/client-async/api/ApiInterface.h | 49 +++++++ src/client-async/api/client-async-api.cpp | 146 +++++++++++++++++++++ src/client-async/logic/Logic.cpp | 59 +++++++++ src/client-async/logic/Logic.h | 49 +++++++ src/include/CMakeLists.txt | 1 + src/include/cynara-client-async.h | 2 + 14 files changed, 445 insertions(+), 10 deletions(-) create mode 100644 packaging/libcynara-client-async.manifest create mode 100644 pkgconfig/cynara-client-async/CMakeLists.txt create mode 100644 pkgconfig/cynara-client-async/cynara-client-async.pc.in create mode 100644 src/client-async/CMakeLists.txt create mode 100644 src/client-async/api/ApiInterface.h create mode 100644 src/client-async/api/client-async-api.cpp create mode 100644 src/client-async/logic/Logic.cpp create mode 100644 src/client-async/logic/Logic.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 0623e9a..ba5fe97 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,6 +78,7 @@ ENDIF (CMAKE_BUILD_TYPE MATCHES "DEBUG") SET(TARGET_CYNARA "cynara") SET(TARGET_LIB_CYNARA "cynara-client") +SET(TARGET_LIB_CYNARA_ASYNC "cynara-client-async") SET(TARGET_LIB_CYNARA_COMMON "cynara-client-commons") SET(TARGET_LIB_CYNARA_ADMIN "cynara-admin") SET(TARGET_CYNARA_COMMON "cynara-commons") diff --git a/packaging/cynara.spec b/packaging/cynara.spec index 4d1c960..7508fbf 100644 --- a/packaging/cynara.spec +++ b/packaging/cynara.spec @@ -7,15 +7,16 @@ License: Apache-2.0 Source0: %{name}-%{version}.tar.gz Source1001: cynara.manifest Source1002: libcynara-client.manifest -Source1003: libcynara-admin.manifest -Source1004: cynara-tests.manifest -Source1005: libcynara-client-commons.manifest -Source1006: libcynara-commons.manifest -Source1007: libcynara-creds-commons.manifest -Source1008: libcynara-creds-dbus.manifest -Source1009: libcynara-creds-socket.manifest -Source1010: libcynara-session.manifest -Source1011: libcynara-storage.manifest +Source1003: libcynara-client-async.manifest +Source1004: libcynara-admin.manifest +Source1005: cynara-tests.manifest +Source1006: libcynara-client-commons.manifest +Source1007: libcynara-commons.manifest +Source1008: libcynara-creds-commons.manifest +Source1009: libcynara-creds-dbus.manifest +Source1010: libcynara-creds-socket.manifest +Source1011: libcynara-session.manifest +Source1012: libcynara-storage.manifest Requires: default-ac-domains Requires(pre): pwdutils Requires(post): smack @@ -42,7 +43,7 @@ BuildRequires: pkgconfig(libunwind) %endif %description -service, client libraries (libcynara-client, libcynara-admin), +service, client libraries (libcynara-client, libcynara-client-async, libcynara-admin), helper libraries (libcynara-session, libcynara-creds-common, libcynara-creds-dbus, libcynara-creds-socket) and tests (cynara-tests) @@ -64,6 +65,22 @@ Requires: libcynara-client-commons-devel = %{version}-%{release} client library (devel) for checking policies ####################################################### +%package -n libcynara-client-async +Summary: Cynara - asynchronous client library +Requires: cynara = %{version}-%{release} + +%description -n libcynara-client-async +asynchronous client library for checking policies + +%package -n libcynara-client-async-devel +Summary: Cynara - asynchronous client library (devel) +Requires: libcynara-client-async = %{version}-%{release} +Requires: libcynara-client-commons-devel = %{version}-%{release} + +%description -n libcynara-client-async-devel +asynchronous client library (devel) for checking policies + +####################################################### %package -n libcynara-client-commons Summary: Cynara - client commons library Requires: cynara = %{version}-%{release} @@ -214,6 +231,7 @@ cp -a %{SOURCE1008} . cp -a %{SOURCE1009} . cp -a %{SOURCE1010} . cp -a %{SOURCE1011} . +cp -a %{SOURCE1012} . cp -a test/db/db* . %build @@ -290,6 +308,10 @@ fi %postun -n libcynara-client -p /sbin/ldconfig +%post -n libcynara-client-async -p /sbin/ldconfig + +%postun -n libcynara-client-async -p /sbin/ldconfig + %post -n libcynara-client-commons -p /sbin/ldconfig %postun -n libcynara-client-commons -p /sbin/ldconfig @@ -314,6 +336,10 @@ fi %postun -n libcynara-client-devel -p /sbin/ldconfig +%post -n libcynara-client-async-devel -p /sbin/ldconfig + +%postun -n libcynara-client-async-devel -p /sbin/ldconfig + %post -n libcynara-client-commons-devel -p /sbin/ldconfig %postun -n libcynara-client-commons-devel -p /sbin/ldconfig @@ -380,6 +406,16 @@ fi %{_libdir}/pkgconfig/cynara-client.pc %{_libdir}/libcynara-client.so +%files -n libcynara-client-async +%manifest libcynara-client-async.manifest +%license LICENSE +%{_libdir}/libcynara-client-async.so.* + +%files -n libcynara-client-async-devel +%{_includedir}/cynara/cynara-client-async.h +%{_libdir}/pkgconfig/cynara-client-async.pc +%{_libdir}/libcynara-client-async.so + %files -n libcynara-client-commons %manifest libcynara-client-commons.manifest %license LICENSE diff --git a/packaging/libcynara-client-async.manifest b/packaging/libcynara-client-async.manifest new file mode 100644 index 0000000..a76fdba --- /dev/null +++ b/packaging/libcynara-client-async.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/pkgconfig/CMakeLists.txt b/pkgconfig/CMakeLists.txt index 0c11631..9d4600f 100644 --- a/pkgconfig/CMakeLists.txt +++ b/pkgconfig/CMakeLists.txt @@ -18,6 +18,7 @@ # ADD_SUBDIRECTORY(cynara-client) +ADD_SUBDIRECTORY(cynara-client-async) ADD_SUBDIRECTORY(cynara-admin) ADD_SUBDIRECTORY(cynara-creds-commons) ADD_SUBDIRECTORY(cynara-creds-dbus) diff --git a/pkgconfig/cynara-client-async/CMakeLists.txt b/pkgconfig/cynara-client-async/CMakeLists.txt new file mode 100644 index 0000000..f827ac4 --- /dev/null +++ b/pkgconfig/cynara-client-async/CMakeLists.txt @@ -0,0 +1,25 @@ +# Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Marcin Niesluchowski +# + +CONFIGURE_FILE(cynara-client-async.pc.in cynara-client-async.pc @ONLY) + +INSTALL(FILES + ${CMAKE_BINARY_DIR}/pkgconfig/cynara-client-async/cynara-client-async.pc + DESTINATION + ${LIB_INSTALL_DIR}/pkgconfig + ) diff --git a/pkgconfig/cynara-client-async/cynara-client-async.pc.in b/pkgconfig/cynara-client-async/cynara-client-async.pc.in new file mode 100644 index 0000000..cf38a83 --- /dev/null +++ b/pkgconfig/cynara-client-async/cynara-client-async.pc.in @@ -0,0 +1,11 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +libdir=@LIB_INSTALL_DIR@ +includedir=${prefix}/include + +Name: cynara-client-async +Description: cynara-client-async package +Version: @CYNARA_VERSION@ +Requires: +Libs: -L${libdir} -lcynara-client-async +Cflags: -I${includedir}/cynara diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 66a1186..fe4d096 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -46,6 +46,7 @@ INCLUDE_DIRECTORIES( ADD_SUBDIRECTORY(include) ADD_SUBDIRECTORY(common) ADD_SUBDIRECTORY(client) +ADD_SUBDIRECTORY(client-async) ADD_SUBDIRECTORY(client-common) ADD_SUBDIRECTORY(admin) ADD_SUBDIRECTORY(storage) diff --git a/src/client-async/CMakeLists.txt b/src/client-async/CMakeLists.txt new file mode 100644 index 0000000..3a4ce35 --- /dev/null +++ b/src/client-async/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Marcin Niesluchowski +# + +SET(LIB_CYNARA_ASYNC_VERSION_MAJOR 0) +SET(LIB_CYNARA_ASYNC_VERSION ${LIB_CYNARA_ASYNC_VERSION_MAJOR}.0.2) + +SET(CYNARA_LIB_CYNARA_ASYNC_PATH ${CYNARA_PATH}/client-async) + +INCLUDE_DIRECTORIES( + ${CYNARA_LIB_CYNARA_ASYNC_PATH} + ${CYNARA_PATH}/client-common + ${CYNARA_PATH}/common + ${CYNARA_PATH}/include + ) + +SET(LIB_CYNARA_ASYNC_SOURCES + ${CYNARA_LIB_CYNARA_ASYNC_PATH}/api/client-async-api.cpp + ${CYNARA_LIB_CYNARA_ASYNC_PATH}/logic/Logic.cpp + ) + +ADD_LIBRARY(${TARGET_LIB_CYNARA_ASYNC} SHARED ${LIB_CYNARA_ASYNC_SOURCES}) + +SET_TARGET_PROPERTIES( + ${TARGET_LIB_CYNARA_ASYNC} + PROPERTIES + SOVERSION ${LIB_CYNARA_ASYNC_VERSION_MAJOR} + VERSION ${LIB_CYNARA_ASYNC_VERSION} + ) + +TARGET_LINK_LIBRARIES(${TARGET_LIB_CYNARA_ASYNC} + ${TARGET_CYNARA_COMMON} + ) + +INSTALL(TARGETS ${TARGET_LIB_CYNARA_ASYNC} DESTINATION ${LIB_INSTALL_DIR}) diff --git a/src/client-async/api/ApiInterface.h b/src/client-async/api/ApiInterface.h new file mode 100644 index 0000000..31478da --- /dev/null +++ b/src/client-async/api/ApiInterface.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/** + * @file src/client-async/api/ApiInterface.h + * @author Marcin Niesluchowski + * @version 1.0 + * @brief This file contains libcynara-client-async API interface definition. + */ + +#ifndef SRC_CLIENT_ASYNC_API_APIINTERFACE_H_ +#define SRC_CLIENT_ASYNC_API_APIINTERFACE_H_ + +#include + +#include + +namespace Cynara { + +class ApiInterface { +public: + ApiInterface() = default; + virtual ~ApiInterface() {}; + + virtual int checkCache(const std::string &client, const std::string &session, + const std::string &user, const std::string &privilege) = 0; + virtual int createRequest(const std::string &client, const std::string &session, + const std::string &user, const std::string &privilege, + cynara_check_id &checkId, cynara_response_callback callback, + void *userResponseData) = 0; + virtual int process(void) = 0; + virtual int cancelRequest(cynara_check_id checkId) = 0; +}; + +} // namespace Cynara + +#endif /* SRC_CLIENT_ASYNC_API_APIINTERFACE_H_ */ diff --git a/src/client-async/api/client-async-api.cpp b/src/client-async/api/client-async-api.cpp new file mode 100644 index 0000000..d350e10 --- /dev/null +++ b/src/client-async/api/client-async-api.cpp @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/** + * @file src/client-async/api/client-async-api.cpp + * @author Marcin Niesluchowski + * @version 1.0 + * @brief Implementation of external libcynara-client-async API + */ + +#include + +#include +#include +#include + +#include +#include +#include + +struct cynara_async { + Cynara::ApiInterface *impl; + + cynara_async(Cynara::ApiInterface *_impl) : impl(_impl) { + } + + ~cynara_async() { + delete impl; + } +}; + +CYNARA_API +int cynara_async_initialize(cynara_async **pp_cynara, + const cynara_async_configuration *p_conf UNUSED, + cynara_status_callback callback, void *user_status_data) { + if (!pp_cynara) + return CYNARA_API_INVALID_PARAM; + + return Cynara::tryCatch([&]() { + *pp_cynara = new cynara_async(new Cynara::Logic(callback, user_status_data)); + + init_log(); + + LOGD("Cynara client async initialized"); + + return CYNARA_API_SUCCESS; + }); +} + +CYNARA_API +void cynara_async_finish(cynara_async *p_cynara) { + delete p_cynara; +} + +CYNARA_API +int cynara_async_check_cache(cynara_async *p_cynara, const char *client, const char *client_session, + const char *user, const char *privilege) { + if (!p_cynara || !p_cynara->impl) + return CYNARA_API_INVALID_PARAM; + if (!client || !client_session || !user || !privilege) + return CYNARA_API_INVALID_PARAM; + + return Cynara::tryCatch([&]() { + std::string clientStr; + std::string clientSessionStr; + std::string userStr; + std::string privilegeStr; + + try { + clientStr = client; + clientSessionStr = client_session; + userStr = user; + privilegeStr = privilege; + } catch (const std::length_error &e) { + LOGE(e.what()); + return CYNARA_API_INVALID_PARAM; + } + return p_cynara->impl->checkCache(clientStr, clientSessionStr, userStr, privilegeStr); + }); +} + +CYNARA_API +int cynara_async_create_request(cynara_async *p_cynara, const char *client, + const char *client_session, const char *user, const char *privilege, + cynara_check_id *p_check_id, cynara_response_callback callback, + void *user_response_data) { + if (!p_cynara || !p_cynara->impl) + return CYNARA_API_INVALID_PARAM; + if (!client || !client_session || !user || !privilege) + return CYNARA_API_INVALID_PARAM; + + return Cynara::tryCatch([&]() { + std::string clientStr; + std::string clientSessionStr; + std::string userStr; + std::string privilegeStr; + + try { + clientStr = client; + clientSessionStr = client_session; + userStr = user; + privilegeStr = privilege; + } catch (const std::length_error &e) { + LOGE(e.what()); + return CYNARA_API_INVALID_PARAM; + } + cynara_check_id checkId; + int ret = p_cynara->impl->createRequest(clientStr, clientSessionStr, userStr, privilegeStr, + checkId, callback, user_response_data); + if (p_check_id && ret == CYNARA_API_SUCCESS) + *p_check_id = checkId; + return ret; + }); +} + +CYNARA_API +int cynara_async_process(cynara_async *p_cynara) { + if (!p_cynara || !p_cynara->impl) + return CYNARA_API_INVALID_PARAM; + + return Cynara::tryCatch([&]() { + return p_cynara->impl->process(); + }); +} + +CYNARA_API +int cynara_async_cancel_request(cynara_async *p_cynara, cynara_check_id check_id) { + if (!p_cynara || !p_cynara->impl) + return CYNARA_API_INVALID_PARAM; + + return Cynara::tryCatch([&]() { + return p_cynara->impl->cancelRequest(check_id); + }); +} diff --git a/src/client-async/logic/Logic.cpp b/src/client-async/logic/Logic.cpp new file mode 100644 index 0000000..f20a216 --- /dev/null +++ b/src/client-async/logic/Logic.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/** + * @file src/client-async/logic/Logic.cpp + * @author Marcin Niesluchowski + * @version 1.0 + * @brief This file contains implementation of Logic class - main + * libcynara-client-async class + */ + +#include + +#include "Logic.h" + +namespace Cynara { + +Logic::Logic(cynara_status_callback callback UNUSED, void *userStatusData UNUSED) { + // MOCKUP +} + +int Logic::checkCache(const std::string &client UNUSED, const std::string &session UNUSED, + const std::string &user UNUSED, const std::string &privilege UNUSED) { + // MOCKUP + return CYNARA_API_CACHE_MISS; +} + +int Logic::createRequest(const std::string &client UNUSED, const std::string &session UNUSED, + const std::string &user UNUSED, const std::string &privilege UNUSED, + cynara_check_id &checkId UNUSED, cynara_response_callback callback UNUSED, + void *userResponseData UNUSED) { + // MOCKUP + return CYNARA_API_MAX_PENDING_REQUESTS; +} + + +int Logic::process(void) { + // MOCKUP + return CYNARA_API_SUCCESS; +} + +int Logic::cancelRequest(cynara_check_id checkId UNUSED) { + // MOCKUP + return CYNARA_API_SUCCESS; +} + +} // namespace Cynara diff --git a/src/client-async/logic/Logic.h b/src/client-async/logic/Logic.h new file mode 100644 index 0000000..d245501 --- /dev/null +++ b/src/client-async/logic/Logic.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/** + * @file src/client-async/logic/Logic.h + * @author Marcin Niesluchowski + * @version 1.0 + * @brief This file contains declaration of Logic class - main + * libcynara-client-async class + */ + +#ifndef SRC_CLIENT_ASYNC_LOGIC_LOGIC_H_ +#define SRC_CLIENT_ASYNC_LOGIC_LOGIC_H_ + +#include +#include + +namespace Cynara { + +class Logic : public ApiInterface { +public: + Logic(cynara_status_callback callback, void *userStatusData); + virtual ~Logic() {}; + + virtual int checkCache(const std::string &client, const std::string &session, + const std::string &user, const std::string &privilege); + virtual int createRequest(const std::string &client, const std::string &session, + const std::string &user, const std::string &privilege, + cynara_check_id &checkId, cynara_response_callback callback, + void *userResponseData); + virtual int process(void); + virtual int cancelRequest(cynara_check_id checkId); +}; + +} // namespace Cynara + +#endif /* SRC_CLIENT_ASYNC_LOGIC_LOGIC_H_ */ diff --git a/src/include/CMakeLists.txt b/src/include/CMakeLists.txt index e4c74a4..1be6e10 100644 --- a/src/include/CMakeLists.txt +++ b/src/include/CMakeLists.txt @@ -21,6 +21,7 @@ INSTALL(FILES ${CYNARA_PATH}/include/cynara-admin-error.h ${CYNARA_PATH}/include/cynara-admin-types.h ${CYNARA_PATH}/include/cynara-client.h + ${CYNARA_PATH}/include/cynara-client-async.h ${CYNARA_PATH}/include/cynara-client-error.h ${CYNARA_PATH}/include/cynara-creds-commons.h ${CYNARA_PATH}/include/cynara-creds-dbus.h diff --git a/src/include/cynara-client-async.h b/src/include/cynara-client-async.h index c824124..1e39d9b 100644 --- a/src/include/cynara-client-async.h +++ b/src/include/cynara-client-async.h @@ -27,6 +27,8 @@ #include +#include + #ifdef __cplusplus extern "C" { #endif -- 2.7.4 From 1dcea79f6b7f2880b32091a3f0a035e878fa0e94 Mon Sep 17 00:00:00 2001 From: Marcin Niesluchowski Date: Mon, 15 Sep 2014 11:17:34 +0200 Subject: [PATCH 05/16] Move socket paths to common library Change-Id: I4b5bf9c2bc47aca6f87bb89942a09b2a8ae6e251 --- src/admin/logic/Logic.cpp | 5 ++--- src/client/logic/Logic.cpp | 5 ++--- src/common/CMakeLists.txt | 1 + src/common/sockets/SocketPath.cpp | 32 ++++++++++++++++++++++++++++++ src/common/sockets/SocketPath.h | 37 +++++++++++++++++++++++++++++++++++ src/service/sockets/SocketManager.cpp | 8 ++++---- 6 files changed, 78 insertions(+), 10 deletions(-) create mode 100644 src/common/sockets/SocketPath.cpp create mode 100644 src/common/sockets/SocketPath.h diff --git a/src/admin/logic/Logic.cpp b/src/admin/logic/Logic.cpp index 95ececc..89c2d2c 100644 --- a/src/admin/logic/Logic.cpp +++ b/src/admin/logic/Logic.cpp @@ -38,16 +38,15 @@ #include #include #include +#include #include #include "Logic.h" namespace Cynara { -const std::string adminSocketPath("/run/cynara/cynara-admin.socket"); - Logic::Logic() { - m_socketClient = std::make_shared(adminSocketPath, + m_socketClient = std::make_shared(SocketPath::admin, std::make_shared()); } diff --git a/src/client/logic/Logic.cpp b/src/client/logic/Logic.cpp index 2708318..d856042 100644 --- a/src/client/logic/Logic.cpp +++ b/src/client/logic/Logic.cpp @@ -35,20 +35,19 @@ #include #include #include +#include #include namespace Cynara { -const std::string clientSocketPath("/run/cynara/cynara.socket"); - static ProtocolFrameSequenceNumber generateSequenceNumber(void) { static ProtocolFrameSequenceNumber sequenceNumber = 0; return ++sequenceNumber; } Logic::Logic() { - m_socket = std::make_shared(clientSocketPath, std::make_shared()); + m_socket = std::make_shared(SocketPath::client, std::make_shared()); m_cache = std::make_shared(); auto naiveInterpreter = std::make_shared(); m_cache->registerPlugin(PredefinedPolicyType::ALLOW, naiveInterpreter); diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 0901962..490a4f3 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -43,6 +43,7 @@ SET(COMMON_SOURCES ${COMMON_PATH}/response/ResponseTaker.cpp ${COMMON_PATH}/sockets/Socket.cpp ${COMMON_PATH}/sockets/SocketClient.cpp + ${COMMON_PATH}/sockets/SocketPath.cpp ${COMMON_PATH}/types/PolicyBucket.cpp ${COMMON_PATH}/types/PolicyKey.cpp ${COMMON_PATH}/types/PolicyKeyHelpers.cpp diff --git a/src/common/sockets/SocketPath.cpp b/src/common/sockets/SocketPath.cpp new file mode 100644 index 0000000..c64e2ff --- /dev/null +++ b/src/common/sockets/SocketPath.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/** + * @file src/common/sockets/SocketPath.cpp + * @author Marcin Niesluchowski + * @version 1.0 + * @brief Source file for common socket paths + */ + +#include "SocketPath.h" + +namespace Cynara { +namespace SocketPath { + +const std::string client("/run/cynara/cynara.socket"); +const std::string admin("/run/cynara/cynara-admin.socket"); + +} // namespace SocketPath +} // namespace Cynara diff --git a/src/common/sockets/SocketPath.h b/src/common/sockets/SocketPath.h new file mode 100644 index 0000000..cca867d --- /dev/null +++ b/src/common/sockets/SocketPath.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/** + * @file src/common/sockets/SocketPath.h + * @author Marcin Niesluchowski + * @version 1.0 + * @brief Header for common socket paths + */ + +#ifndef SRC_COMMON_SOCKETS_SOCKETPATH_H_ +#define SRC_COMMON_SOCKETS_SOCKETPATH_H_ + +#include + +namespace Cynara { +namespace SocketPath { + +extern const std::string client; +extern const std::string admin; + +} // namespace SocketPath +} // namespace Cynara + +#endif // SRC_COMMON_SOCKETS_SOCKETPATH_H_ diff --git a/src/service/sockets/SocketManager.cpp b/src/service/sockets/SocketManager.cpp index 29bc999..cb3c9b4 100644 --- a/src/service/sockets/SocketManager.cpp +++ b/src/service/sockets/SocketManager.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include
@@ -69,14 +70,13 @@ void SocketManager::run(void) { void SocketManager::init(void) { LOGI("SocketManger init start"); - const std::string clientSocketPath("/run/cynara/cynara.socket"); - const std::string adminSocketPath("/run/cynara/cynara-admin.socket"); const mode_t clientSocketUMask(0); const mode_t adminSocketUMask(0077); - createDomainSocket(std::make_shared(), clientSocketPath, clientSocketUMask, + createDomainSocket(std::make_shared(), SocketPath::client, clientSocketUMask, true); - createDomainSocket(std::make_shared(), adminSocketPath, adminSocketUMask, false); + createDomainSocket(std::make_shared(), SocketPath::admin, adminSocketUMask, + false); createSignalSocket(std::make_shared()); LOGI("SocketManger init done"); } -- 2.7.4 From edf3b9e805df58c39137ac1e50dfe17a47f6c844 Mon Sep 17 00:00:00 2001 From: Marcin Niesluchowski Date: Mon, 15 Sep 2014 11:42:42 +0200 Subject: [PATCH 06/16] Add asynchronous socket Change-Id: I1ca062fee144b8244fba88ae3155096df043c61e --- src/admin/logic/Logic.cpp | 67 +++--- src/admin/logic/Logic.h | 1 + src/client-async/CMakeLists.txt | 1 + src/client-async/sockets/SocketClientAsync.cpp | 72 +++++++ src/client-async/sockets/SocketClientAsync.h | 65 ++++++ src/client-common/exceptions/TryCatch.h | 4 + src/client/logic/Logic.cpp | 56 ++--- src/client/logic/Logic.h | 1 + ...nectionErrorException.h => NoMemoryException.h} | 35 ++-- src/common/sockets/Socket.cpp | 231 ++++++++++++--------- src/common/sockets/Socket.h | 81 ++++++-- src/common/sockets/SocketClient.cpp | 31 ++- src/common/sockets/SocketClient.h | 5 +- 13 files changed, 457 insertions(+), 193 deletions(-) create mode 100644 src/client-async/sockets/SocketClientAsync.cpp create mode 100644 src/client-async/sockets/SocketClientAsync.h rename src/common/exceptions/{ServerConnectionErrorException.h => NoMemoryException.h} (52%) diff --git a/src/admin/logic/Logic.cpp b/src/admin/logic/Logic.cpp index 89c2d2c..6906056 100644 --- a/src/admin/logic/Logic.cpp +++ b/src/admin/logic/Logic.cpp @@ -25,7 +25,8 @@ #include #include -#include +#include +#include #include #include #include @@ -55,19 +56,30 @@ ProtocolFrameSequenceNumber generateSequenceNumber(void) { return ++sequenceNumber; } +bool Logic::ensureConnection(void) { + return m_socketClient->isConnected() || m_socketClient->connect(); +} + template int Logic::askCynaraAndInterpreteCodeResponse(Args... args) { - ProtocolFrameSequenceNumber sequenceNumber = generateSequenceNumber(); - - //Ask cynara service - CodeResponsePtr codeResponse; try { - RequestPtr request = std::make_shared(args..., sequenceNumber); - ResponsePtr response = m_socketClient->askCynaraServer(request); - if (!response) { - LOGW("Disconnected by cynara server."); + if (!ensureConnection()) { + LOGE("Cannot connect to cynara. Service not available."); return CYNARA_ADMIN_API_SERVICE_NOT_AVAILABLE; } + + ProtocolFrameSequenceNumber sequenceNumber = generateSequenceNumber(); + + //Ask cynara service + CodeResponsePtr codeResponse; + + RequestPtr request = std::make_shared(args..., sequenceNumber); + ResponsePtr response; + while (!(response = m_socketClient->askCynaraServer(request))) { + if (!m_socketClient->connect()) + return CYNARA_ADMIN_API_SERVICE_NOT_AVAILABLE; + } + codeResponse = std::dynamic_pointer_cast(response); if (!codeResponse) { LOGC("Critical error. Casting Response to CodeResponse failed."); @@ -90,9 +102,6 @@ int Logic::askCynaraAndInterpreteCodeResponse(Args... args) { static_cast(codeResponse->m_code)); return CYNARA_ADMIN_API_UNEXPECTED_CLIENT_ERROR; } - } catch (const ServerConnectionErrorException &ex) { - LOGE("Cynara service not available."); - return CYNARA_ADMIN_API_SERVICE_NOT_AVAILABLE; } catch (const std::bad_alloc &ex) { LOGE("Cynara admin client out of memory."); return CYNARA_ADMIN_API_OUT_OF_MEMORY; @@ -118,19 +127,25 @@ int Logic::removeBucket(const PolicyBucketId &bucket) noexcept { int Logic::adminCheck(const PolicyBucketId &startBucket, bool recursive, const PolicyKey &key, PolicyResult &result) noexcept { + try { + if (!ensureConnection()) { + LOGE("Cannot connect to cynara. Service not available."); + return CYNARA_ADMIN_API_SERVICE_NOT_AVAILABLE; + } - ProtocolFrameSequenceNumber sequenceNumber = generateSequenceNumber(); + ProtocolFrameSequenceNumber sequenceNumber = generateSequenceNumber(); + + //Ask cynara service + CheckResponsePtr checkResponse; - //Ask cynara service - CheckResponsePtr checkResponse; - try { RequestPtr request = std::make_shared(key, startBucket, recursive, sequenceNumber); - ResponsePtr response = m_socketClient->askCynaraServer(request); - if (!response) { - LOGW("Disconnected by cynara server."); - return CYNARA_ADMIN_API_SERVICE_NOT_AVAILABLE; + ResponsePtr response; + while (!(response = m_socketClient->askCynaraServer(request))) { + if (!m_socketClient->connect()) + return CYNARA_ADMIN_API_SERVICE_NOT_AVAILABLE; } + checkResponse = std::dynamic_pointer_cast(response); if (!checkResponse) { LOGC("Casting Response to CheckResponse failed."); @@ -140,9 +155,12 @@ int Logic::adminCheck(const PolicyBucketId &startBucket, bool recursive, const P LOGD("checkResponse: policyType [%" PRIu16 "], metadata <%s>", checkResponse->m_resultRef.policyType(), checkResponse->m_resultRef.metadata().c_str()); - } catch (const ServerConnectionErrorException &ex) { - LOGE("Cynara service not available."); - return CYNARA_ADMIN_API_SERVICE_NOT_AVAILABLE; + + result = checkResponse->m_resultRef; + return CYNARA_ADMIN_API_SUCCESS; + } catch (const UnexpectedErrorException &ex) { + LOGE(ex.what()); + return CYNARA_ADMIN_API_UNEXPECTED_CLIENT_ERROR; } catch (const std::bad_alloc &ex) { LOGE("Cynara admin client out of memory."); return CYNARA_ADMIN_API_OUT_OF_MEMORY; @@ -150,9 +168,6 @@ int Logic::adminCheck(const PolicyBucketId &startBucket, bool recursive, const P LOGE("Unexpected client error: <%s>", ex.what()); return CYNARA_ADMIN_API_UNEXPECTED_CLIENT_ERROR; } - - result = checkResponse->m_resultRef; - return CYNARA_ADMIN_API_SUCCESS; } } // namespace Cynara diff --git a/src/admin/logic/Logic.h b/src/admin/logic/Logic.h index 8a274ff..527e992 100644 --- a/src/admin/logic/Logic.h +++ b/src/admin/logic/Logic.h @@ -35,6 +35,7 @@ class Logic : public ApiInterface { private: SocketClientPtr m_socketClient; + bool ensureConnection(void); template int askCynaraAndInterpreteCodeResponse(Args... args); diff --git a/src/client-async/CMakeLists.txt b/src/client-async/CMakeLists.txt index 3a4ce35..1326f8d 100644 --- a/src/client-async/CMakeLists.txt +++ b/src/client-async/CMakeLists.txt @@ -31,6 +31,7 @@ INCLUDE_DIRECTORIES( SET(LIB_CYNARA_ASYNC_SOURCES ${CYNARA_LIB_CYNARA_ASYNC_PATH}/api/client-async-api.cpp ${CYNARA_LIB_CYNARA_ASYNC_PATH}/logic/Logic.cpp + ${CYNARA_LIB_CYNARA_ASYNC_PATH}/sockets/SocketClientAsync.cpp ) ADD_LIBRARY(${TARGET_LIB_CYNARA_ASYNC} SHARED ${LIB_CYNARA_ASYNC_SOURCES}) diff --git a/src/client-async/sockets/SocketClientAsync.cpp b/src/client-async/sockets/SocketClientAsync.cpp new file mode 100644 index 0000000..e3ffbd4 --- /dev/null +++ b/src/client-async/sockets/SocketClientAsync.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/** + * @file src/client-async/sockets/SocketClientAsync.cpp + * @author Marcin Niesluchowski + * @version 1.0 + * @brief This file contains definition of cynara's socket asynchronous + * client + */ + +#include +#include + +#include "SocketClientAsync.h" + +namespace Cynara { + +SocketClientAsync::SocketClientAsync(const std::string &socketPath, ProtocolPtr protocol) + : m_socket(socketPath, 0), m_protocol(protocol) { +} + +Socket::ConnectionStatus SocketClientAsync::connect(void) { + return m_socket.connect(); +} + +Socket::ConnectionStatus SocketClientAsync::completeConnection(void) { + return m_socket.completeConnection(); +} + +int SocketClientAsync::getSockFd(void) { + return m_socket.getSockFd(); +} + +bool SocketClientAsync::isConnected(void) { + return m_socket.isConnected(); +} + +void SocketClientAsync::appendRequest(RequestPtr request) { + RequestContextPtr context = std::make_shared(ResponseTakerPtr(), m_writeQueue); + request->execute(request, m_protocol, context); +} + +bool SocketClientAsync::isDataToSend(void) { + return m_socket.isDataToSend() || !m_writeQueue.empty(); +} + +Socket::SendStatus SocketClientAsync::sendToCynara(void) { + return m_socket.sendToServer(m_writeQueue); +} + +bool SocketClientAsync::receiveFromCynara(void) { + return m_socket.receiveFromServer(m_readQueue); +} + +ResponsePtr SocketClientAsync::getResponse(void) { + return m_protocol->extractResponseFromBuffer(m_readQueue); +} + +} // namespace Cynara diff --git a/src/client-async/sockets/SocketClientAsync.h b/src/client-async/sockets/SocketClientAsync.h new file mode 100644 index 0000000..5fb0543 --- /dev/null +++ b/src/client-async/sockets/SocketClientAsync.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/** + * @file src/client-async/sockets/SocketClientAsync.h + * @author Marcin Niesluchowski + * @version 1.0 + * @brief This file contains declaration of cynara's socket asynchronous + client + */ + +#ifndef SRC_CLIENT_ASYNC_SOCKETS_SOCKETCLIENTASYNC_H_ +#define SRC_CLIENT_ASYNC_SOCKETS_SOCKETCLIENTASYNC_H_ + +#include +#include + +#include +#include +#include +#include +#include + +namespace Cynara { + +class SocketClientAsync; +typedef std::shared_ptr SocketClientAsyncPtr; + +class SocketClientAsync { +public: + SocketClientAsync(const std::string &socketPath, ProtocolPtr protocol); + ~SocketClientAsync() {}; + + Socket::ConnectionStatus connect(void); + Socket::ConnectionStatus completeConnection(void); + int getSockFd(void); + bool isConnected(void); + void appendRequest(RequestPtr request); + bool isDataToSend(void); + Socket::SendStatus sendToCynara(void); + bool receiveFromCynara(void); + ResponsePtr getResponse(void); + +private: + Socket m_socket; + ProtocolPtr m_protocol; + BinaryQueue m_readQueue; + BinaryQueue m_writeQueue; +}; + +} // namespace Cynara + +#endif /* SRC_CLIENT_ASYNC_SOCKETS_SOCKETCLIENTASYNC_H_ */ diff --git a/src/client-common/exceptions/TryCatch.h b/src/client-common/exceptions/TryCatch.h index 8d1fb20..6dc4d0b 100644 --- a/src/client-common/exceptions/TryCatch.h +++ b/src/client-common/exceptions/TryCatch.h @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -39,6 +40,9 @@ int tryCatch(const std::function &func) { } catch (const std::bad_alloc &e) { LOGE(e.what()); return CYNARA_API_OUT_OF_MEMORY; + } catch (const NoMemoryException &e) { + LOGE(e.what()); + return CYNARA_API_OUT_OF_MEMORY; } catch (const std::exception &e) { LOGE(e.what()); return CYNARA_API_UNKNOWN_ERROR; diff --git a/src/client/logic/Logic.cpp b/src/client/logic/Logic.cpp index d856042..f375e9e 100644 --- a/src/client/logic/Logic.cpp +++ b/src/client/logic/Logic.cpp @@ -25,7 +25,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -56,14 +57,12 @@ Logic::Logic() { } int Logic::check(const std::string &client, const ClientSession &session, const std::string &user, - const std::string &privilege) -{ - if (!m_socket->isConnected()){ - onDisconnected(); - } + const std::string &privilege) { + if (!ensureConnection()) + return CYNARA_API_SERVICE_NOT_AVAILABLE; PolicyKey key(client, user, privilege); - auto ret = m_cache->get(session, key); + int ret = m_cache->get(session, key); //Any other situation than cache miss if (ret != CYNARA_API_CACHE_MISS) { return ret; @@ -80,32 +79,39 @@ int Logic::check(const std::string &client, const ClientSession &session, const return m_cache->update(session, key, result); } +bool Logic::ensureConnection(void) { + if (m_socket->isConnected()) + return true; + onDisconnected(); + if (m_socket->connect()) + return true; + LOGW("Cannot connect to cynara. Service not available."); + return false; +} + int Logic::requestResult(const PolicyKey &key, PolicyResult &result) { ProtocolFrameSequenceNumber sequenceNumber = generateSequenceNumber(); //Ask cynara service CheckResponsePtr checkResponse; - try { - RequestPtr request = std::make_shared(key, sequenceNumber); - ResponsePtr response = m_socket->askCynaraServer(request); - if (!response) { - LOGW("Disconnected by cynara server."); + RequestPtr request = std::make_shared(key, sequenceNumber); + ResponsePtr response; + while (!(response = m_socket->askCynaraServer(request))) { + onDisconnected(); + if (!m_socket->connect()) return CYNARA_API_SERVICE_NOT_AVAILABLE; - } - checkResponse = std::dynamic_pointer_cast(response); - if (!checkResponse) { - LOGC("Critical error. Casting Response to CheckResponse failed."); - return CYNARA_API_ACCESS_DENIED; - } - - LOGD("checkResponse: policyType = %" PRIu16 ", metadata = %s", - checkResponse->m_resultRef.policyType(), - checkResponse->m_resultRef.metadata().c_str()); - } catch (const ServerConnectionErrorException &ex) { - LOGE("Cynara service not available."); - return CYNARA_API_SERVICE_NOT_AVAILABLE; } + checkResponse = std::dynamic_pointer_cast(response); + if (!checkResponse) { + LOGC("Critical error. Casting Response to CheckResponse failed."); + return CYNARA_API_ACCESS_DENIED; + } + + LOGD("checkResponse: policyType = %" PRIu16 ", metadata = %s", + checkResponse->m_resultRef.policyType(), + checkResponse->m_resultRef.metadata().c_str()); + result = checkResponse->m_resultRef; return CYNARA_API_SUCCESS; } diff --git a/src/client/logic/Logic.h b/src/client/logic/Logic.h index 36076fc..c72309c 100644 --- a/src/client/logic/Logic.h +++ b/src/client/logic/Logic.h @@ -40,6 +40,7 @@ private: PluginCachePtr m_cache; void onDisconnected(void); + bool ensureConnection(void); int requestResult(const PolicyKey &key, PolicyResult &result); public: Logic(); diff --git a/src/common/exceptions/ServerConnectionErrorException.h b/src/common/exceptions/NoMemoryException.h similarity index 52% rename from src/common/exceptions/ServerConnectionErrorException.h rename to src/common/exceptions/NoMemoryException.h index fc550ce..d8a6086 100644 --- a/src/common/exceptions/ServerConnectionErrorException.h +++ b/src/common/exceptions/NoMemoryException.h @@ -14,30 +14,39 @@ * limitations under the License. */ /** - * @file src/common/exceptions/ServerConnectionErrorException.h - * @author Lukasz Wojciechowski + * @file src/common/exceptions/NoMemoryException.h + * @author Marcin Niesluchowski * @version 1.0 - * @brief Implementation of ServerConnectionErrorException + * @brief Implementation of NoMemoryException */ -#ifndef SRC_COMMON_EXCEPTIONS_SERVERCONNECTIONERROREXCEPTION_H_ -#define SRC_COMMON_EXCEPTIONS_SERVERCONNECTIONERROREXCEPTION_H_ +#ifndef SRC_COMMON_EXCEPTIONS_NOMEMORYEXCEPTION_H_ +#define SRC_COMMON_EXCEPTIONS_NOMEMORYEXCEPTION_H_ -#include "Exception.h" +#include +#include -#include +#include "Exception.h" namespace Cynara { -class ServerConnectionErrorException : public Exception { +class NoMemoryException : public Exception { public: - ServerConnectionErrorException() = default; - virtual ~ServerConnectionErrorException() noexcept {}; + NoMemoryException() = delete; + NoMemoryException(const std::string &errorMsg) { + m_whatMessage = "NoMemoryException with message <" + errorMsg + ">"; + } + + virtual ~NoMemoryException() noexcept {}; + virtual const std::string message(void) const { - return "ServerConnectionError"; + return m_whatMessage; } + +private: + std::string m_whatMessage; }; -} /* namespace Cynara */ +} // namespace Cynara -#endif /* SRC_COMMON_EXCEPTIONS_SERVERCONNECTIONERROREXCEPTION_H_ */ +#endif /* SRC_COMMON_EXCEPTIONS_NOMEMORYEXCEPTION_H_ */ diff --git a/src/common/sockets/Socket.cpp b/src/common/sockets/Socket.cpp index e3b91dc..0c33a7e 100644 --- a/src/common/sockets/Socket.cpp +++ b/src/common/sockets/Socket.cpp @@ -31,10 +31,8 @@ #include #include -#include -#include #include -#include +#include #include #include @@ -42,8 +40,9 @@ namespace Cynara { -Socket::Socket(const std::string &socketPath, int timeoutMiliseconds) : m_sock(-1), - m_socketPath(socketPath), m_pollTimeout(timeoutMiliseconds) { +Socket::Socket(const std::string &socketPath, int timeoutMiliseconds) + : m_sock(-1), m_connectionInProgress(false), m_socketPath(socketPath), + m_pollTimeout(timeoutMiliseconds), m_sendBufferPos(0), m_sendBufferEnd(0) { } Socket::~Socket() { @@ -54,6 +53,9 @@ void Socket::close(void) { if (m_sock > -1) ::close(m_sock); m_sock = -1; + m_sendBufferPos = 0; + m_sendBufferEnd = 0; + m_sendQueue.clear(); } bool Socket::waitForSocket(int event) { @@ -62,12 +64,14 @@ bool Socket::waitForSocket(int event) { desc[0].fd = m_sock; desc[0].events = event; - ret = TEMP_FAILURE_RETRY(poll(desc, 1, m_pollTimeout)); + if (event != POLLHUP) + ret = TEMP_FAILURE_RETRY(poll(desc, 1, m_pollTimeout)); + else + ret = TEMP_FAILURE_RETRY(poll(desc, 1, 0)); if (ret == -1) { int err = errno; LOGE("'poll' function error [%d] : <%s>", err, strerror(err)); - close(); throw UnexpectedErrorException(err, strerror(err)); } else if (ret == 0) { LOGD("Poll timeout"); @@ -82,7 +86,6 @@ int Socket::getSocketError(void) { int ret = getsockopt(m_sock, SOL_SOCKET, SO_ERROR, &err, &len); if (ret < 0) { int err = errno; - close(); LOGE("'getsockopt' function error [%d] : <%s>", err, strerror(err)); throw UnexpectedErrorException(err, strerror(err)); } @@ -90,26 +93,21 @@ int Socket::getSocketError(void) { } bool Socket::isConnected(void) { + if (m_connectionInProgress) + return true; + if (m_sock < 0) return false; - if (getSocketError() != 0) { - close(); + if (getSocketError() != 0) return false; - } - return true; + return !waitForSocket(POLLHUP); } -bool Socket::connect(void) { - sockaddr_un clientAddr; +void Socket::createSocket(void) { int flags; - if (isConnected()) - return true; - - close(); - m_sock = socket(AF_UNIX, SOCK_STREAM, 0); if (m_sock < 0) { int err = errno; @@ -125,6 +123,10 @@ bool Socket::connect(void) { LOGE("'fcntl' function error [%d] : <%s>", err, strerror(err)); throw UnexpectedErrorException(err, strerror(err)); } +} + +Socket::ConnectionStatus Socket::connectSocket(void) { + sockaddr_un clientAddr; memset(&clientAddr, 0, sizeof(clientAddr)); @@ -145,111 +147,136 @@ bool Socket::connect(void) { SUN_LEN(&clientAddr))); if (retval == -1) { int err = errno; - if (err == EINPROGRESS) { - if (!waitForSocket(POLLOUT)) { - return false; - } - err = getSocketError(); + switch (err) { + case EINPROGRESS: + m_connectionInProgress = true; + return ConnectionStatus::CONNECTION_IN_PROGRESS; + case ECONNREFUSED: + //no one is listening + return ConnectionStatus::CONNECTION_FAILED; + default: + close(); + LOGE("'connect' function error [%d] : <%s>", err, strerror(err)); + throw UnexpectedErrorException(err, strerror(err)); } - if (err == ECONNREFUSED) { - //no one is listening - return false; + } + return ConnectionStatus::CONNECTION_SUCCEEDED; +} + +Socket::SendStatus Socket::sendBuffer(void) { + while (m_sendBufferEnd != m_sendBufferPos) { + if (!waitForSocket(POLLOUT)) { + LOGD("No POLLOUT event"); + return SendStatus::PARTIAL_DATA_SENT; } - close(); - LOGE("'connect' function error [%d] : <%s>", err, strerror(err)); - throw UnexpectedErrorException(err, strerror(err)); + + ssize_t t = TEMP_FAILURE_RETRY(send(m_sock, m_sendBuffer.data() + m_sendBufferPos, + m_sendBufferEnd - m_sendBufferPos, MSG_NOSIGNAL)); + if (t == -1) { + int err = errno; + switch (err) { + case EAGAIN: +#if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + continue; + case ENOMEM: + throw NoMemoryException("'send' function failed due to ENOMEM"); + case EPIPE: + LOGN("Connection closed by server"); + return SendStatus::CONNECTION_LOST; + default: + LOGE("'send' function error [%d] : <%s>", err, strerror(err)); + throw UnexpectedErrorException(err, strerror(err)); + } + } + m_sendBufferPos += static_cast(t); } + return SendStatus::ALL_DATA_SENT; +} + +Socket::ConnectionStatus Socket::connect(void) { + close(); + + createSocket(); - return isConnected(); + ConnectionStatus status = connectSocket(); + if (status != ConnectionStatus::CONNECTION_SUCCEEDED) + return status; + + return isConnected() ? ConnectionStatus::CONNECTION_SUCCEEDED + : ConnectionStatus::CONNECTION_FAILED; } -bool Socket::sendToServer(BinaryQueue &queue) { - bool retry = false; +Socket::ConnectionStatus Socket::completeConnection(void) { + if (!m_connectionInProgress) + return ConnectionStatus::ALREADY_CONNECTED; - RawBuffer buffer(queue.size()); - queue.flattenConsume(buffer.data(), queue.size()); + if (!waitForSocket(POLLOUT)) + return ConnectionStatus::CONNECTION_IN_PROGRESS; - do { - if (!connect()) { - LOGE("Error connecting to socket"); - throw ServerConnectionErrorException(); - } + m_connectionInProgress = false; + return isConnected() ? ConnectionStatus::CONNECTION_SUCCEEDED + : ConnectionStatus::CONNECTION_FAILED; +} - retry = false; - ssize_t done = 0; - while ((buffer.size() - done) > 0) { - if (! waitForSocket(POLLOUT)) { - LOGE("Error in poll(POLLOUT)"); - throw ServerConnectionErrorException(); - } - ssize_t t = TEMP_FAILURE_RETRY(send(m_sock, buffer.data() + done, - buffer.size() - done, MSG_NOSIGNAL)); - if (t == -1) { - int err = errno; - if (err == EPIPE) { - close(); - LOGN("Connection closed by server. Retrying to connect."); - retry = true; - break; - } - close(); - LOGE("'write' function error [%d] : <%s>", err, strerror(err)); - throw UnexpectedErrorException(err, strerror(err)); - } - done += t; - } - } while (retry); +int Socket::getSockFd(void) { + return m_sock; +} - return true; +bool Socket::isDataToSend(void) { + return !m_sendQueue.empty() || m_sendBufferEnd != 0; } -bool Socket::waitAndReceiveFromServer(BinaryQueue &queue) -{ - if (!waitForSocket(POLLIN)) { - LOGE("Error in poll(POLLIN)"); - throw ServerConnectionErrorException(); - } +Socket::SendStatus Socket::sendToServer(BinaryQueue &queue) { + m_sendQueue.appendMoveFrom(queue); - RawBuffer readBuffer(BUFSIZ); - ssize_t size = TEMP_FAILURE_RETRY(read(m_sock, readBuffer.data(), BUFSIZ)); + SendStatus status = sendBuffer(); + if (status != SendStatus::ALL_DATA_SENT) + return status; - if (size == -1) { - int err = errno; - LOGE("'read' function error [%d] : <%s>", err, strerror(err)); - throw UnexpectedErrorException(err, strerror(err)); - } + if (m_sendQueue.size() > m_sendBuffer.size()) + m_sendBuffer.resize(m_sendQueue.size()); - if (size == 0) { - LOGW("read return 0 / Connection closed by server."); - return false; - } - queue.appendCopy(readBuffer.data(), size); + m_sendBufferEnd = m_sendQueue.size(); + m_sendBufferPos = 0; + + m_sendQueue.flattenConsume(m_sendBuffer.data(), m_sendQueue.size()); - return true; + return sendBuffer(); } -bool Socket::receiveFromServer(BinaryQueue &queue) -{ - RawBuffer readBuffer(BUFSIZ); - ssize_t size = TEMP_FAILURE_RETRY(read(m_sock, readBuffer.data(), BUFSIZ)); +bool Socket::receiveFromServer(BinaryQueue &queue) { + if (!waitForSocket(POLLIN)) { + LOGD("No POLLIN event"); + return true; + } - if (size == -1) { - int err = errno; - if (err == EAGAIN) { - LOGD("is connected, but no data available"); - return true; + RawBuffer buffer(BUFSIZ); + ssize_t size = 0; + while (true) { + size = TEMP_FAILURE_RETRY(read(m_sock, buffer.data(), BUFSIZ)); + if (size == 0) { + LOGW("read return 0 / Connection closed by server."); + return false; } - LOGE("'read' function error [%d] : <%s>", err, strerror(err)); - throw UnexpectedErrorException(err, strerror(err)); - } - if (size == 0) { - LOGW("read return 0 / Connection closed by server."); - return false; - } - queue.appendCopy(readBuffer.data(), size); + if (size == -1) { + int err = errno; + switch (err) { + case EAGAIN: +#if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + return true; + default: + LOGE("'read' function error [%d] : <%s>", err, strerror(err)); + throw UnexpectedErrorException(err, strerror(err)); + } + } - return true; + queue.appendCopy(buffer.data(), static_cast(size)); + } } } // namespace Cynara diff --git a/src/common/sockets/Socket.h b/src/common/sockets/Socket.h index 3c5c37b..0309f41 100644 --- a/src/common/sockets/Socket.h +++ b/src/common/sockets/Socket.h @@ -17,6 +17,7 @@ * @file src/common/sockets/Socket.h * @author Bartlomiej Grzelewski * @author Lukasz Wojciechowski + * @author Marcin Niesluchowski * @version 1.0 * @brief This file contains definition of UNIX client socket class */ @@ -27,16 +28,37 @@ #include #include +#include namespace Cynara { class Socket { +public: + enum class ConnectionStatus { + ALREADY_CONNECTED, + CONNECTION_SUCCEEDED, + CONNECTION_IN_PROGRESS, + CONNECTION_FAILED + }; + + enum class SendStatus { + PARTIAL_DATA_SENT, + ALL_DATA_SENT, + CONNECTION_LOST + }; + private: int m_sock; + bool m_connectionInProgress; std::string m_socketPath; int m_pollTimeout; + RawBuffer m_sendBuffer; + size_t m_sendBufferPos; + size_t m_sendBufferEnd; + BinaryQueue m_sendQueue; + void close(void); //returns true if socket is ready @@ -48,6 +70,21 @@ private: //throws in critical situations int getSocketError(void); + //throws in critical situations + void createSocket(void); + + //returns ConnectionStatus::CONNECTION_SUCCEEDED if connection succeeded + //returns ConnectionStatus::CONNECTION_IN_PROGRESS if connection in progress + //returns ConnectionStatus::CONNECTION_FAILED if connection failed + //throws in critical situations + ConnectionStatus connectSocket(void); + + //returns SendStatus::PARTIAL_DATA_SENT if no data to send is available + //returns SendStatus::ALL_DATA_SENT if no additional data to send + //returns SendStatus::CONNECTION_LOST if connection was lost + //throws in critical situations + SendStatus sendBuffer(void); + public: Socket(const std::string &socketPath, int timeoutMiliseconds = -1); ~Socket(); @@ -56,26 +93,36 @@ public: //throws in critical situations bool isConnected(void); - //returns true if connection succeeded - //returns false if connection was timeout or no one is listening - //throws in critical situations - bool connect(void); - - //returns true if data was successfully send to server - //returns false if connection was lost - //throws ServerConnectionErrorException if cannot connect server (or timeout) - //throws other exceptions in critical situations - bool sendToServer(BinaryQueue &queue); - - //returns true if data was successfully read from server - //returns false if connection was lost - //throws ServerConnectionErrorException if cannot connect server (or timeout) - //throws other exceptions in critical situations - bool waitAndReceiveFromServer(BinaryQueue &queue); + //returns ConnectionStatus::CONNECTION_SUCCEEDED if connection succeeded + //returns ConnectionStatus::CONNECTION_IN_PROGRESS if connection in progress + //returns ConnectionStatus::CONNECTION_FAILED if connection failed + //throws in critical situations + ConnectionStatus connect(void); + + //returns ConnectionStatus::ALREADY_CONNECTED if was already connected + //returns ConnectionStatus::CONNECTION_SUCCEEDED if connection succeeded + //returns ConnectionStatus::CONNECTION_IN_PROGRESS if connection in progress + //returns ConnectionStatus::CONNECTION_FAILED if connection failed + //throws in critical situations + ConnectionStatus completeConnection(void); + + //returns socket descriptor + //returns -1 if socket descriptor no present + int getSockFd(void); + + //returns true There is still data to send + //returns false No data to send + bool isDataToSend(void); + + //returns SendStatus::PARTIAL_DATA_SENT if no all data sent + //returns SendStatus::ALL_DATA_SENT if all data was sent + //returns SendStatus::CONNECTION_LOST if connection was lost + //throws in critical situations + SendStatus sendToServer(BinaryQueue &queue); //returns true if data was successfully read from server //returns false if connection was lost - //throws other exceptions in critical situations + //throws in critical situations bool receiveFromServer(BinaryQueue &queue); }; diff --git a/src/common/sockets/SocketClient.cpp b/src/common/sockets/SocketClient.cpp index a23c438..6db91d6 100644 --- a/src/common/sockets/SocketClient.cpp +++ b/src/common/sockets/SocketClient.cpp @@ -39,21 +39,40 @@ SocketClient::SocketClient(const std::string &socketPath, ProtocolPtr protocol) : m_socket(socketPath), m_protocol(protocol) { } +bool SocketClient::connect(void) { + switch (m_socket.connect()) { + case Socket::ConnectionStatus::CONNECTION_FAILED: + LOGW("Error connecting to Cynara. Service not available."); + return false; + case Socket::ConnectionStatus::CONNECTION_IN_PROGRESS: + if (m_socket.completeConnection() == Socket::ConnectionStatus::CONNECTION_FAILED) { + LOGW("Error connecting to Cynara. Service not available."); + return false; + } + default: + return true; + } +} + +bool SocketClient::isConnected(void) { + return m_socket.isConnected(); +} + ResponsePtr SocketClient::askCynaraServer(RequestPtr request) { //pass request to protocol RequestContextPtr context = std::make_shared(ResponseTakerPtr(), m_writeQueue); request->execute(request, m_protocol, context); //send request to cynara - if (!m_socket.sendToServer(m_writeQueue)) { - LOGW("Error sending request to Cynara. Service not available."); + if (m_socket.sendToServer(m_writeQueue) == Socket::SendStatus::CONNECTION_LOST) { + LOGW("Disconnected while sending request to Cynara."); return nullptr; } // receive response from cynara while (true) { - if (!m_socket.waitAndReceiveFromServer(m_readQueue)) { - LOGW("Error receiving response from Cynara. Service not available."); + if (!m_socket.receiveFromServer(m_readQueue)) { + LOGW("Disconnected while receiving response from Cynara."); return nullptr; } ResponsePtr response = m_protocol->extractResponseFromBuffer(m_readQueue); @@ -63,8 +82,4 @@ ResponsePtr SocketClient::askCynaraServer(RequestPtr request) { } } -bool SocketClient::isConnected(void) { - return m_socket.isConnected() && m_socket.receiveFromServer(m_readQueue); -} - } // namespace Cynara diff --git a/src/common/sockets/SocketClient.h b/src/common/sockets/SocketClient.h index a96107e..9f9737f 100644 --- a/src/common/sockets/SocketClient.h +++ b/src/common/sockets/SocketClient.h @@ -48,11 +48,12 @@ public: SocketClient(const std::string &socketPath, ProtocolPtr protocol); virtual ~SocketClient() {}; + bool connect(void); + bool isConnected(void); + //returns pointer to response // or nullptr when connection to cynara service is lost ResponsePtr askCynaraServer(RequestPtr request); - - bool isConnected(void); }; } // namespace Cynara -- 2.7.4 From d4c58c6b56ef4e93f4f052025716b7f80f0306dd Mon Sep 17 00:00:00 2001 From: Marcin Niesluchowski Date: Mon, 15 Sep 2014 11:54:48 +0200 Subject: [PATCH 07/16] Add connection check cynara_async_check_cache should return CYNARA_API_CACHE_MISS if disconnected. cynara_async_create_request and cynara_async_cancel_request should try reconnecting if disconnected and return CYNARA_API_SERVICE_NOT_AVAILABLE on failure. As cynara_async is connecting asynchronously, it could take connection in progress state which is resolved in cynara_async_process and treated as connected in other functions. As this state exists after reconnecting, there should be no cache entries. cynara_async_process should complete connecting if needed by waiting for write event. If connection fails in cynara_async_process, then CYNARA_API_SERVICE_NOT_AVAILABLE should be returned. Change-Id: I2920f4dbd0bde3e7be74096db33f4ff465bc5028 --- src/client-async/CMakeLists.txt | 3 +- src/client-async/callback/StatusCallback.cpp | 46 ++++++++++++++ src/client-async/callback/StatusCallback.h | 47 +++++++++++++++ src/client-async/logic/Logic.cpp | 90 ++++++++++++++++++++++++++-- src/client-async/logic/Logic.h | 15 ++++- 5 files changed, 195 insertions(+), 6 deletions(-) create mode 100644 src/client-async/callback/StatusCallback.cpp create mode 100644 src/client-async/callback/StatusCallback.h diff --git a/src/client-async/CMakeLists.txt b/src/client-async/CMakeLists.txt index 1326f8d..5b3d404 100644 --- a/src/client-async/CMakeLists.txt +++ b/src/client-async/CMakeLists.txt @@ -30,6 +30,7 @@ INCLUDE_DIRECTORIES( SET(LIB_CYNARA_ASYNC_SOURCES ${CYNARA_LIB_CYNARA_ASYNC_PATH}/api/client-async-api.cpp + ${CYNARA_LIB_CYNARA_ASYNC_PATH}/callback/StatusCallback.cpp ${CYNARA_LIB_CYNARA_ASYNC_PATH}/logic/Logic.cpp ${CYNARA_LIB_CYNARA_ASYNC_PATH}/sockets/SocketClientAsync.cpp ) @@ -44,7 +45,7 @@ SET_TARGET_PROPERTIES( ) TARGET_LINK_LIBRARIES(${TARGET_LIB_CYNARA_ASYNC} - ${TARGET_CYNARA_COMMON} + ${TARGET_LIB_CYNARA_COMMON} ) INSTALL(TARGETS ${TARGET_LIB_CYNARA_ASYNC} DESTINATION ${LIB_INSTALL_DIR}) diff --git a/src/client-async/callback/StatusCallback.cpp b/src/client-async/callback/StatusCallback.cpp new file mode 100644 index 0000000..45da823 --- /dev/null +++ b/src/client-async/callback/StatusCallback.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/** + * @file src/client-async/callback/StatusCallback.cpp + * @author Marcin Niesluchowski + * @version 1.0 + * @brief This file contains definition of StatusCallback class + */ + +#include "StatusCallback.h" + +namespace Cynara { + +StatusCallback::StatusCallback(cynara_status_callback callback, void *userData) + : m_callback(callback), m_userData(userData), m_sockFd(-1), + m_status(cynara_async_status::CYNARA_STATUS_FOR_READ) { +} + +void StatusCallback::onStatusChange(int newFd, cynara_async_status status) { + if (!m_callback) + return; + if (m_status == status && m_sockFd == newFd) + return; + m_callback(m_sockFd, newFd, status, m_userData); + m_sockFd = newFd; + m_status = status; +} + +void StatusCallback::onDisconnected(void) { + onStatusChange(-1, cynara_async_status::CYNARA_STATUS_FOR_READ); +} + +} // namespace Cynara diff --git a/src/client-async/callback/StatusCallback.h b/src/client-async/callback/StatusCallback.h new file mode 100644 index 0000000..468f0a0 --- /dev/null +++ b/src/client-async/callback/StatusCallback.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/** + * @file src/client-async/callback/StatusCallback.h + * @author Marcin Niesluchowski + * @version 1.0 + * @brief This file contains declaration of StatusCallback class + */ + +#ifndef SRC_CLIENT_ASYNC_CALLBACK_STATUSCALLBACK_H_ +#define SRC_CLIENT_ASYNC_CALLBACK_STATUSCALLBACK_H_ + +#include + +namespace Cynara { + +class StatusCallback { +public: + StatusCallback(cynara_status_callback callback, void *userData); + ~StatusCallback() {}; + + void onStatusChange(int newFd, cynara_async_status status); + void onDisconnected(void); + +private: + cynara_status_callback m_callback; + void *m_userData; + int m_sockFd; + cynara_async_status m_status; +}; + +} // namespace Cynara + +#endif /* SRC_CLIENT_ASYNC_CALLBACK_STATUSCALLBACK_H_ */ diff --git a/src/client-async/logic/Logic.cpp b/src/client-async/logic/Logic.cpp index f20a216..04ae0de 100644 --- a/src/client-async/logic/Logic.cpp +++ b/src/client-async/logic/Logic.cpp @@ -21,39 +21,121 @@ * libcynara-client-async class */ +#include + #include +#include +#include +#include +#include +#include +#include #include "Logic.h" namespace Cynara { -Logic::Logic(cynara_status_callback callback UNUSED, void *userStatusData UNUSED) { - // MOCKUP +Logic::Logic(cynara_status_callback callback, void *userStatusData) + : m_statusCallback(callback, userStatusData) { + m_socketClient = std::make_shared( + SocketPath::client, std::make_shared()); +} + +Logic::~Logic() { + onDisconnected(); } int Logic::checkCache(const std::string &client UNUSED, const std::string &session UNUSED, const std::string &user UNUSED, const std::string &privilege UNUSED) { + if (!checkCacheValid()) + return CYNARA_API_CACHE_MISS; + // MOCKUP - return CYNARA_API_CACHE_MISS; + return CYNARA_API_SUCCESS; } int Logic::createRequest(const std::string &client UNUSED, const std::string &session UNUSED, const std::string &user UNUSED, const std::string &privilege UNUSED, cynara_check_id &checkId UNUSED, cynara_response_callback callback UNUSED, void *userResponseData UNUSED) { + if (!ensureConnection()) + return CYNARA_API_SERVICE_NOT_AVAILABLE; + // MOCKUP return CYNARA_API_MAX_PENDING_REQUESTS; } - int Logic::process(void) { + bool completed; + int ret = completeConnection(completed); + if (!completed) + return ret; + // MOCKUP return CYNARA_API_SUCCESS; } int Logic::cancelRequest(cynara_check_id checkId UNUSED) { + if (!ensureConnection()) + return CYNARA_API_SERVICE_NOT_AVAILABLE; + // MOCKUP return CYNARA_API_SUCCESS; } +bool Logic::checkCacheValid(void) { + return m_socketClient->isConnected(); +} + +void Logic::prepareRequestsToSend(void) { + // MOCKUP +} + +cynara_async_status Logic::socketDataStatus(void) { + return m_socketClient->isDataToSend() ? cynara_async_status::CYNARA_STATUS_FOR_RW + : cynara_async_status::CYNARA_STATUS_FOR_READ; +} + +bool Logic::ensureConnection(void) { + if (m_socketClient->isConnected()) + return true; + onDisconnected(); + switch (m_socketClient->connect()) { + case Socket::ConnectionStatus::CONNECTION_SUCCEEDED: + prepareRequestsToSend(); + m_statusCallback.onStatusChange(m_socketClient->getSockFd(), socketDataStatus()); + return true; + case Socket::ConnectionStatus::CONNECTION_IN_PROGRESS: + prepareRequestsToSend(); + m_statusCallback.onStatusChange(m_socketClient->getSockFd(), + cynara_async_status::CYNARA_STATUS_FOR_RW); + return true; + default: + return false; + } +} + +int Logic::completeConnection(bool &completed) { + switch (m_socketClient->completeConnection()) { + case Socket::ConnectionStatus::ALREADY_CONNECTED: + completed = true; + return CYNARA_API_SUCCESS; + case Socket::ConnectionStatus::CONNECTION_SUCCEEDED: + m_statusCallback.onStatusChange(m_socketClient->getSockFd(), socketDataStatus()); + completed = true; + return CYNARA_API_SUCCESS; + case Socket::ConnectionStatus::CONNECTION_IN_PROGRESS: + completed = false; + return CYNARA_API_SUCCESS; + default: + completed = false; + onDisconnected(); + return CYNARA_API_SERVICE_NOT_AVAILABLE; + } +} + +void Logic::onDisconnected(void) { + m_statusCallback.onDisconnected(); +} + } // namespace Cynara diff --git a/src/client-async/logic/Logic.h b/src/client-async/logic/Logic.h index d245501..bc43ad9 100644 --- a/src/client-async/logic/Logic.h +++ b/src/client-async/logic/Logic.h @@ -25,14 +25,16 @@ #define SRC_CLIENT_ASYNC_LOGIC_LOGIC_H_ #include +#include #include +#include namespace Cynara { class Logic : public ApiInterface { public: Logic(cynara_status_callback callback, void *userStatusData); - virtual ~Logic() {}; + virtual ~Logic(); virtual int checkCache(const std::string &client, const std::string &session, const std::string &user, const std::string &privilege); @@ -42,6 +44,17 @@ public: void *userResponseData); virtual int process(void); virtual int cancelRequest(cynara_check_id checkId); + +private: + StatusCallback m_statusCallback; + SocketClientAsyncPtr m_socketClient; + + bool checkCacheValid(void); + void prepareRequestsToSend(void); + cynara_async_status socketDataStatus(void); + bool ensureConnection(void); + int completeConnection(bool &completed); + void onDisconnected(void); }; } // namespace Cynara -- 2.7.4 From 380d6f3411a3032afc425d25e7e3f002d29240a2 Mon Sep 17 00:00:00 2001 From: Marcin Niesluchowski Date: Thu, 18 Sep 2014 14:41:01 +0200 Subject: [PATCH 08/16] Implement cynara_async_check_cache() Change-Id: I1930cdf448dcfdf800d0d5c322ff100baf5a4987 --- src/client-async/logic/Logic.cpp | 15 +++++++++++---- src/client-async/logic/Logic.h | 3 +++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/client-async/logic/Logic.cpp b/src/client-async/logic/Logic.cpp index 04ae0de..e1574ce 100644 --- a/src/client-async/logic/Logic.cpp +++ b/src/client-async/logic/Logic.cpp @@ -23,10 +23,12 @@ #include +#include #include #include #include #include +#include #include #include #include @@ -39,19 +41,23 @@ Logic::Logic(cynara_status_callback callback, void *userStatusData) : m_statusCallback(callback, userStatusData) { m_socketClient = std::make_shared( SocketPath::client, std::make_shared()); + + m_cache = std::make_shared(); + auto naiveInterpreter = std::make_shared(); + m_cache->registerPlugin(PredefinedPolicyType::ALLOW, naiveInterpreter); + m_cache->registerPlugin(PredefinedPolicyType::DENY, naiveInterpreter); } Logic::~Logic() { onDisconnected(); } -int Logic::checkCache(const std::string &client UNUSED, const std::string &session UNUSED, - const std::string &user UNUSED, const std::string &privilege UNUSED) { +int Logic::checkCache(const std::string &client, const std::string &session, + const std::string &user, const std::string &privilege) { if (!checkCacheValid()) return CYNARA_API_CACHE_MISS; - // MOCKUP - return CYNARA_API_SUCCESS; + return m_cache->get(session, PolicyKey(client, user, privilege)); } int Logic::createRequest(const std::string &client UNUSED, const std::string &session UNUSED, @@ -135,6 +141,7 @@ int Logic::completeConnection(bool &completed) { } void Logic::onDisconnected(void) { + m_cache->clear(); m_statusCallback.onDisconnected(); } diff --git a/src/client-async/logic/Logic.h b/src/client-async/logic/Logic.h index bc43ad9..0475b08 100644 --- a/src/client-async/logic/Logic.h +++ b/src/client-async/logic/Logic.h @@ -24,6 +24,8 @@ #ifndef SRC_CLIENT_ASYNC_LOGIC_LOGIC_H_ #define SRC_CLIENT_ASYNC_LOGIC_LOGIC_H_ +#include + #include #include #include @@ -47,6 +49,7 @@ public: private: StatusCallback m_statusCallback; + PluginCachePtr m_cache; SocketClientAsyncPtr m_socketClient; bool checkCacheValid(void); -- 2.7.4 From 29946e7cef5b2fd04531acdb8ab911eb85e2decf Mon Sep 17 00:00:00 2001 From: Marcin Niesluchowski Date: Thu, 18 Sep 2014 11:32:15 +0200 Subject: [PATCH 09/16] Add creating, sending and receiving check requests cynara_async_create_request() and cynara_async_process() functions work according to the API header excluding possibility to cancel request. Change-Id: I9818be674d58da5bd431a08b7faf47dfe0157289 --- src/client-async/CMakeLists.txt | 2 + src/client-async/callback/ResponseCallback.cpp | 50 ++++++++++ src/client-async/callback/ResponseCallback.h | 48 ++++++++++ src/client-async/check/CheckData.h | 65 +++++++++++++ src/client-async/logic/Logic.cpp | 122 +++++++++++++++++++++--- src/client-async/logic/Logic.h | 14 +++ src/client-async/sequence/SequenceContainer.cpp | 63 ++++++++++++ src/client-async/sequence/SequenceContainer.h | 48 ++++++++++ 8 files changed, 399 insertions(+), 13 deletions(-) create mode 100644 src/client-async/callback/ResponseCallback.cpp create mode 100644 src/client-async/callback/ResponseCallback.h create mode 100644 src/client-async/check/CheckData.h create mode 100644 src/client-async/sequence/SequenceContainer.cpp create mode 100644 src/client-async/sequence/SequenceContainer.h diff --git a/src/client-async/CMakeLists.txt b/src/client-async/CMakeLists.txt index 5b3d404..a9b9971 100644 --- a/src/client-async/CMakeLists.txt +++ b/src/client-async/CMakeLists.txt @@ -30,8 +30,10 @@ INCLUDE_DIRECTORIES( SET(LIB_CYNARA_ASYNC_SOURCES ${CYNARA_LIB_CYNARA_ASYNC_PATH}/api/client-async-api.cpp + ${CYNARA_LIB_CYNARA_ASYNC_PATH}/callback/ResponseCallback.cpp ${CYNARA_LIB_CYNARA_ASYNC_PATH}/callback/StatusCallback.cpp ${CYNARA_LIB_CYNARA_ASYNC_PATH}/logic/Logic.cpp + ${CYNARA_LIB_CYNARA_ASYNC_PATH}/sequence/SequenceContainer.cpp ${CYNARA_LIB_CYNARA_ASYNC_PATH}/sockets/SocketClientAsync.cpp ) diff --git a/src/client-async/callback/ResponseCallback.cpp b/src/client-async/callback/ResponseCallback.cpp new file mode 100644 index 0000000..e4577b3 --- /dev/null +++ b/src/client-async/callback/ResponseCallback.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/** + * @file src/client-async/callback/ResponseCallback.cpp + * @author Marcin Niesluchowski + * @version 1.0 + * @brief This file contains definition of ResponseCallback class + */ + +#include "ResponseCallback.h" + +namespace Cynara { + +ResponseCallback::ResponseCallback(cynara_response_callback callback, void *userData) + : m_callback(callback), m_userData(userData) { +} + +void ResponseCallback::onAnswer(cynara_check_id checkId, int response) const { + if (!m_callback) + return; + m_callback(checkId, cynara_async_call_cause::CYNARA_CALL_CAUSE_ANSWER, response, m_userData); +} + +void ResponseCallback::onFinish(cynara_check_id checkId) const { + if (!m_callback) + return; + m_callback(checkId, cynara_async_call_cause::CYNARA_CALL_CAUSE_FINISH, 0, m_userData); +} + +void ResponseCallback::onDisconnected(cynara_check_id checkId) const { + if (!m_callback) + return; + m_callback(checkId, cynara_async_call_cause::CYNARA_CALL_CAUSE_SERVICE_NOT_AVAILABLE, 0, + m_userData); +} + +} // namespace Cynara diff --git a/src/client-async/callback/ResponseCallback.h b/src/client-async/callback/ResponseCallback.h new file mode 100644 index 0000000..47d526a --- /dev/null +++ b/src/client-async/callback/ResponseCallback.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/** + * @file src/client-async/callback/ResponseCallback.h + * @author Marcin Niesluchowski + * @version 1.0 + * @brief This file contains declaration of ResponseCallback class + */ + +#ifndef SRC_CLIENT_ASYNC_CALLBACK_RESPONSECALLBACK_H_ +#define SRC_CLIENT_ASYNC_CALLBACK_RESPONSECALLBACK_H_ + +#include + +namespace Cynara { + +class ResponseCallback { +public: + ResponseCallback(cynara_response_callback callback, void *userData); + ResponseCallback(const ResponseCallback&) = default; + ~ResponseCallback() {}; + + void onAnswer(cynara_check_id checkId, int response) const; + // MOCKUP + void onFinish(cynara_check_id checkId) const; + void onDisconnected(cynara_check_id checkId) const; + +private: + cynara_response_callback m_callback; + void *m_userData; +}; + +} // namespace Cynara + +#endif /* SRC_CLIENT_ASYNC_CALLBACK_RESPONSECALLBACK_H_ */ diff --git a/src/client-async/check/CheckData.h b/src/client-async/check/CheckData.h new file mode 100644 index 0000000..1f8fe90 --- /dev/null +++ b/src/client-async/check/CheckData.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/** + * @file src/client-async/check/CheckData.h + * @author Marcin Niesluchowski + * @version 1.0 + * @brief This file contains CheckData class for storing + * information about asynchronous check request. + */ + +#ifndef SRC_CLIENT_ASYNC_CHECK_CHECKDATA_H_ +#define SRC_CLIENT_ASYNC_CHECK_CHECKDATA_H_ + +#include +#include + +#include + +#include + +namespace Cynara { + +class CheckData +{ +public: + CheckData(const PolicyKey &key, const std::string &session, const ResponseCallback &callback) + : m_key(key), m_session(session), m_callback(callback) {} + ~CheckData() {} + + const PolicyKey &key(void) const { + return m_key; + } + + const std::string &session(void) const { + return m_session; + } + + const ResponseCallback &callback(void) const { + return m_callback; + } + +private: + PolicyKey m_key; + std::string m_session; + ResponseCallback m_callback; + // MOCKUP +}; + +} // namespace Cynara + +#endif // SRC_CLIENT_ASYNC_CHECK_CHECKDATA_H_ + diff --git a/src/client-async/logic/Logic.cpp b/src/client-async/logic/Logic.cpp index e1574ce..23cd7cc 100644 --- a/src/client-async/logic/Logic.cpp +++ b/src/client-async/logic/Logic.cpp @@ -26,10 +26,13 @@ #include #include #include +#include #include #include #include #include +#include +#include #include #include @@ -49,7 +52,9 @@ Logic::Logic(cynara_status_callback callback, void *userStatusData) } Logic::~Logic() { - onDisconnected(); + for (auto &kv : m_checks) + kv.second.callback().onFinish(kv.first); + m_statusCallback.onDisconnected(); } int Logic::checkCache(const std::string &client, const std::string &session, @@ -60,25 +65,41 @@ int Logic::checkCache(const std::string &client, const std::string &session, return m_cache->get(session, PolicyKey(client, user, privilege)); } -int Logic::createRequest(const std::string &client UNUSED, const std::string &session UNUSED, - const std::string &user UNUSED, const std::string &privilege UNUSED, - cynara_check_id &checkId UNUSED, cynara_response_callback callback UNUSED, - void *userResponseData UNUSED) { +int Logic::createRequest(const std::string &client, const std::string &session, + const std::string &user, const std::string &privilege, + cynara_check_id &checkId, cynara_response_callback callback, + void *userResponseData) { if (!ensureConnection()) return CYNARA_API_SERVICE_NOT_AVAILABLE; - // MOCKUP - return CYNARA_API_MAX_PENDING_REQUESTS; + ProtocolFrameSequenceNumber sequenceNumber; + if (!m_sequenceContainer.get(sequenceNumber)) + return CYNARA_API_MAX_PENDING_REQUESTS; + + PolicyKey key(client, user, privilege); + ResponseCallback responseCallback(callback, userResponseData); + m_checks.insert(CheckPair(sequenceNumber, CheckData(key, session, responseCallback))); + m_socketClient->appendRequest(std::make_shared(key, sequenceNumber)); + + m_statusCallback.onStatusChange(m_socketClient->getSockFd(), + cynara_async_status::CYNARA_STATUS_FOR_RW); + checkId = static_cast(sequenceNumber); + + return CYNARA_API_SUCCESS; } int Logic::process(void) { bool completed; - int ret = completeConnection(completed); - if (!completed) - return ret; - - // MOCKUP - return CYNARA_API_SUCCESS; + while (true) { + int ret = completeConnection(completed); + if (!completed) + return ret; + if (processOut() && processIn()) + return CYNARA_API_SUCCESS; + onDisconnected(); + if (!connect()) + return CYNARA_API_SERVICE_NOT_AVAILABLE; + } } int Logic::cancelRequest(cynara_check_id checkId UNUSED) { @@ -94,7 +115,67 @@ bool Logic::checkCacheValid(void) { } void Logic::prepareRequestsToSend(void) { + for (auto &kv : m_checks) { + // MOCKUP + m_socketClient->appendRequest(std::make_shared(kv.second.key(), kv.first)); + } +} + +bool Logic::processOut(void) { + switch (m_socketClient->sendToCynara()) { + case Socket::SendStatus::ALL_DATA_SENT: + m_statusCallback.onStatusChange(m_socketClient->getSockFd(), + cynara_async_status::CYNARA_STATUS_FOR_READ); + case Socket::SendStatus::PARTIAL_DATA_SENT: + return true; + default: + return false; + } +} + +void Logic::processCheckResponse(CheckResponsePtr checkResponse) { + LOGD("checkResponse: policyType = [%" PRIu16 "], metadata = <%s>", + checkResponse->m_resultRef.policyType(), + checkResponse->m_resultRef.metadata().c_str()); + + auto it = m_checks.find(checkResponse->sequenceNumber()); + if (it == m_checks.end()) { + LOGC("Critical error. Unknown response received: sequenceNumber = [%" PRIu16 "]", + checkResponse->sequenceNumber()); + throw UnexpectedErrorException("Unexpected response from cynara service"); + } + int result = m_cache->update(it->second.session(), it->second.key(), + checkResponse->m_resultRef); // MOCKUP + it->second.callback().onAnswer(static_cast(it->first), result); + m_sequenceContainer.release(it->first); + m_checks.erase(it); +} + +void Logic::processResponses(void) { + ResponsePtr response; + CheckResponsePtr checkResponse; + while (true) { + response = m_socketClient->getResponse(); + if (!response) + break; + + checkResponse = std::dynamic_pointer_cast(response); + if (checkResponse) { + processCheckResponse(checkResponse); + continue; + } + // MOCKUP + LOGC("Critical error. Casting Response to CheckResponse failed."); + throw UnexpectedErrorException("Unexpected response from cynara service"); + } +} + +bool Logic::processIn(void) { + if (!m_socketClient->receiveFromCynara()) + return false; + processResponses(); + return true; } cynara_async_status Logic::socketDataStatus(void) { @@ -106,6 +187,11 @@ bool Logic::ensureConnection(void) { if (m_socketClient->isConnected()) return true; onDisconnected(); + + return connect(); +} + +bool Logic::connect(void) { switch (m_socketClient->connect()) { case Socket::ConnectionStatus::CONNECTION_SUCCEEDED: prepareRequestsToSend(); @@ -117,6 +203,7 @@ bool Logic::ensureConnection(void) { cynara_async_status::CYNARA_STATUS_FOR_RW); return true; default: + onServiceNotAvailable(); return false; } } @@ -136,10 +223,19 @@ int Logic::completeConnection(bool &completed) { default: completed = false; onDisconnected(); + onServiceNotAvailable(); return CYNARA_API_SERVICE_NOT_AVAILABLE; } } +void Logic::onServiceNotAvailable(void) +{ + for (auto &kv : m_checks) + kv.second.callback().onDisconnected(kv.first); + m_checks.clear(); + m_sequenceContainer.clear(); +} + void Logic::onDisconnected(void) { m_cache->clear(); m_statusCallback.onDisconnected(); diff --git a/src/client-async/logic/Logic.h b/src/client-async/logic/Logic.h index 0475b08..53cfba9 100644 --- a/src/client-async/logic/Logic.h +++ b/src/client-async/logic/Logic.h @@ -25,10 +25,13 @@ #define SRC_CLIENT_ASYNC_LOGIC_LOGIC_H_ #include +#include #include #include +#include #include +#include #include namespace Cynara { @@ -48,15 +51,26 @@ public: virtual int cancelRequest(cynara_check_id checkId); private: + typedef std::map CheckMap; + typedef std::pair CheckPair; + StatusCallback m_statusCallback; PluginCachePtr m_cache; SocketClientAsyncPtr m_socketClient; + CheckMap m_checks; + SequenceContainer m_sequenceContainer; bool checkCacheValid(void); void prepareRequestsToSend(void); cynara_async_status socketDataStatus(void); + bool processOut(void); + void processCheckResponse(CheckResponsePtr checkResponse); + void processResponses(void); + bool processIn(void); bool ensureConnection(void); + bool connect(void); int completeConnection(bool &completed); + void onServiceNotAvailable(void); void onDisconnected(void); }; diff --git a/src/client-async/sequence/SequenceContainer.cpp b/src/client-async/sequence/SequenceContainer.cpp new file mode 100644 index 0000000..95b9318 --- /dev/null +++ b/src/client-async/sequence/SequenceContainer.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/** + * @file src/client-async/sequence/SequenceContainer.cpp + * @author Marcin Niesluchowski + * @version 1.0 + * @brief This file contains definition of SequenceContainer class for + * storing check requests identifiers in libcynara-client-async + */ + +#include +#include +#include +#include + +#include "SequenceContainer.h" + +namespace Cynara { + +SequenceContainer::SequenceContainer() + : m_sequenceVector(((static_cast(UINT16_MAX) + 1) / CHAR_BIT) / sizeof(int), -1) { +} + +bool SequenceContainer::get(ProtocolFrameSequenceNumber &sequenceNumber) { + for (size_t index = 0; index < m_sequenceVector.size(); ++index) { + int pos = ffs(m_sequenceVector[index]); + if (pos != 0) { + sequenceNumber = static_cast(index * sizeof(int) * CHAR_BIT - 1 + pos); + m_sequenceVector[index] ^= 1 << (pos - 1); + return true; + } + } + return false; +} + +bool SequenceContainer::release(ProtocolFrameSequenceNumber sequenceNumber) { + size_t index = static_cast(sequenceNumber) / (CHAR_BIT * sizeof(int)); + int pos = static_cast(sequenceNumber) % (CHAR_BIT * sizeof(int)); + int i = m_sequenceVector[index] | 1 << pos; + if (i == m_sequenceVector[index]) + return false; + m_sequenceVector[index] = i; + return true; +} + +void SequenceContainer::clear(void) { + memset(m_sequenceVector.data(), -1, m_sequenceVector.size() * sizeof(int)); +} + +} // namespace Cynara diff --git a/src/client-async/sequence/SequenceContainer.h b/src/client-async/sequence/SequenceContainer.h new file mode 100644 index 0000000..c8748e6 --- /dev/null +++ b/src/client-async/sequence/SequenceContainer.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/** + * @file src/client-async/sequence/SequenceContainer.h + * @author Marcin Niesluchowski + * @version 1.0 + * @brief This file contains declaration of SequenceContainer class for + * storing check requests identifiers in libcynara-client-async + */ + +#ifndef SRC_CLIENT_ASYNC_SEQUENCE_SEQUENCECONTAINER_H_ +#define SRC_CLIENT_ASYNC_SEQUENCE_SEQUENCECONTAINER_H_ + +#include + +#include + +namespace Cynara { + +class SequenceContainer { +public: + SequenceContainer(); + ~SequenceContainer() {} + + bool get(ProtocolFrameSequenceNumber &sequenceNumber); + bool release(ProtocolFrameSequenceNumber sequenceNumber); + void clear(void); + +private: + std::vector m_sequenceVector; +}; + +} // namespace Cynara + +#endif // SRC_CLIENT_ASYNC_SEQUENCE_SEQUENCECONTAINER_H_ -- 2.7.4 From 27541d0fdb1e97ba59e4a08b8c710af33fe64af9 Mon Sep 17 00:00:00 2001 From: Marcin Niesluchowski Date: Wed, 24 Sep 2014 14:14:07 +0200 Subject: [PATCH 10/16] Implement cynara_async_cancel_request() Change-Id: I028d6a2941dc68359590263cda9e5bff2b839317 --- src/client-async/callback/ResponseCallback.cpp | 6 ++ src/client-async/callback/ResponseCallback.h | 2 +- src/client-async/check/CheckData.h | 12 +++- src/client-async/logic/Logic.cpp | 80 ++++++++++++++++++++------ src/client-async/logic/Logic.h | 1 + src/common/CMakeLists.txt | 2 + src/common/protocol/ProtocolClient.cpp | 37 ++++++++++++ src/common/protocol/ProtocolClient.h | 6 ++ src/common/protocol/ProtocolOpCode.h | 4 +- src/common/request/CancelRequest.cpp | 34 +++++++++++ src/common/request/CancelRequest.h | 44 ++++++++++++++ src/common/request/RequestTaker.cpp | 4 ++ src/common/request/RequestTaker.h | 1 + src/common/request/pointers.h | 3 + src/common/response/CancelResponse.cpp | 34 +++++++++++ src/common/response/CancelResponse.h | 44 ++++++++++++++ src/common/response/ResponseTaker.cpp | 4 ++ src/common/response/ResponseTaker.h | 1 + src/common/response/pointers.h | 3 + src/service/logic/Logic.cpp | 7 +++ src/service/logic/Logic.h | 1 + 21 files changed, 307 insertions(+), 23 deletions(-) create mode 100644 src/common/request/CancelRequest.cpp create mode 100644 src/common/request/CancelRequest.h create mode 100644 src/common/response/CancelResponse.cpp create mode 100644 src/common/response/CancelResponse.h diff --git a/src/client-async/callback/ResponseCallback.cpp b/src/client-async/callback/ResponseCallback.cpp index e4577b3..9307195 100644 --- a/src/client-async/callback/ResponseCallback.cpp +++ b/src/client-async/callback/ResponseCallback.cpp @@ -34,6 +34,12 @@ void ResponseCallback::onAnswer(cynara_check_id checkId, int response) const { m_callback(checkId, cynara_async_call_cause::CYNARA_CALL_CAUSE_ANSWER, response, m_userData); } +void ResponseCallback::onCancel(cynara_check_id checkId) const { + if (!m_callback) + return; + m_callback(checkId, cynara_async_call_cause::CYNARA_CALL_CAUSE_CANCEL, 0, m_userData); +} + void ResponseCallback::onFinish(cynara_check_id checkId) const { if (!m_callback) return; diff --git a/src/client-async/callback/ResponseCallback.h b/src/client-async/callback/ResponseCallback.h index 47d526a..925d7f4 100644 --- a/src/client-async/callback/ResponseCallback.h +++ b/src/client-async/callback/ResponseCallback.h @@ -34,7 +34,7 @@ public: ~ResponseCallback() {}; void onAnswer(cynara_check_id checkId, int response) const; - // MOCKUP + void onCancel(cynara_check_id checkId) const; void onFinish(cynara_check_id checkId) const; void onDisconnected(cynara_check_id checkId) const; diff --git a/src/client-async/check/CheckData.h b/src/client-async/check/CheckData.h index 1f8fe90..a25abb3 100644 --- a/src/client-async/check/CheckData.h +++ b/src/client-async/check/CheckData.h @@ -37,7 +37,7 @@ class CheckData { public: CheckData(const PolicyKey &key, const std::string &session, const ResponseCallback &callback) - : m_key(key), m_session(session), m_callback(callback) {} + : m_key(key), m_session(session), m_callback(callback), m_cancelled(false) {} ~CheckData() {} const PolicyKey &key(void) const { @@ -52,11 +52,19 @@ public: return m_callback; } + bool cancelled(void) const { + return m_cancelled; + } + + void cancel(void) { + m_cancelled = true; + } + private: PolicyKey m_key; std::string m_session; ResponseCallback m_callback; - // MOCKUP + bool m_cancelled; }; } // namespace Cynara diff --git a/src/client-async/logic/Logic.cpp b/src/client-async/logic/Logic.cpp index 23cd7cc..3a92b2c 100644 --- a/src/client-async/logic/Logic.cpp +++ b/src/client-async/logic/Logic.cpp @@ -31,7 +31,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -52,8 +54,10 @@ Logic::Logic(cynara_status_callback callback, void *userStatusData) } Logic::~Logic() { - for (auto &kv : m_checks) - kv.second.callback().onFinish(kv.first); + for (auto &kv : m_checks) { + if (!kv.second.cancelled()) + kv.second.callback().onFinish(kv.first); + } m_statusCallback.onDisconnected(); } @@ -102,11 +106,21 @@ int Logic::process(void) { } } -int Logic::cancelRequest(cynara_check_id checkId UNUSED) { +int Logic::cancelRequest(cynara_check_id checkId) { if (!ensureConnection()) return CYNARA_API_SERVICE_NOT_AVAILABLE; - // MOCKUP + auto it = m_checks.find(checkId); + if (it == m_checks.end() || it->second.cancelled()) + return CYNARA_API_SUCCESS; + + m_socketClient->appendRequest(std::make_shared(it->first)); + + it->second.cancel(); + it->second.callback().onCancel(it->first); + m_statusCallback.onStatusChange(m_socketClient->getSockFd(), + cynara_async_status::CYNARA_STATUS_FOR_RW); + return CYNARA_API_SUCCESS; } @@ -115,9 +129,14 @@ bool Logic::checkCacheValid(void) { } void Logic::prepareRequestsToSend(void) { - for (auto &kv : m_checks) { - // MOCKUP - m_socketClient->appendRequest(std::make_shared(kv.second.key(), kv.first)); + for (auto it = m_checks.begin(); it != m_checks.end();) { + if (it->second.cancelled()) { + m_sequenceContainer.release(it->first); + it = m_checks.erase(it); + } else { + m_socketClient->appendRequest(std::make_shared(it->second.key(), it->first)); + ++it; + } } } @@ -140,14 +159,32 @@ void Logic::processCheckResponse(CheckResponsePtr checkResponse) { auto it = m_checks.find(checkResponse->sequenceNumber()); if (it == m_checks.end()) { - LOGC("Critical error. Unknown response received: sequenceNumber = [%" PRIu16 "]", + LOGC("Critical error. Unknown checkResponse received: sequenceNumber = [%" PRIu16 "]", checkResponse->sequenceNumber()); throw UnexpectedErrorException("Unexpected response from cynara service"); } int result = m_cache->update(it->second.session(), it->second.key(), checkResponse->m_resultRef); - // MOCKUP - it->second.callback().onAnswer(static_cast(it->first), result); + if (!it->second.cancelled()) + it->second.callback().onAnswer(static_cast(it->first), result); + m_sequenceContainer.release(it->first); + m_checks.erase(it); +} + +void Logic::processCancelResponse(CancelResponsePtr cancelResponse) { + LOGD("cancelResponse"); + + auto it = m_checks.find(cancelResponse->sequenceNumber()); + if (it == m_checks.end()) { + LOGC("Critical error. Unknown cancelResponse received: sequenceNumber = [%" PRIu16 "]", + cancelResponse->sequenceNumber()); + throw UnexpectedErrorException("Unexpected response from cynara service"); + } + if (!it->second.cancelled()) { + LOGC("Critical error. CancelRequest not sent: sequenceNumber = [%" PRIu16 "]", + cancelResponse->sequenceNumber()); + throw UnexpectedErrorException("Unexpected response from cynara service"); + } m_sequenceContainer.release(it->first); m_checks.erase(it); } @@ -155,18 +192,21 @@ void Logic::processCheckResponse(CheckResponsePtr checkResponse) { void Logic::processResponses(void) { ResponsePtr response; CheckResponsePtr checkResponse; - while (true) { - response = m_socketClient->getResponse(); - if (!response) - break; - + CancelResponsePtr cancelResponse; + while (response = m_socketClient->getResponse()) { checkResponse = std::dynamic_pointer_cast(response); if (checkResponse) { processCheckResponse(checkResponse); continue; } - // MOCKUP - LOGC("Critical error. Casting Response to CheckResponse failed."); + + cancelResponse = std::dynamic_pointer_cast(response); + if (cancelResponse) { + processCancelResponse(cancelResponse); + continue; + } + + LOGC("Critical error. Casting Response to known response failed."); throw UnexpectedErrorException("Unexpected response from cynara service"); } } @@ -230,8 +270,10 @@ int Logic::completeConnection(bool &completed) { void Logic::onServiceNotAvailable(void) { - for (auto &kv : m_checks) - kv.second.callback().onDisconnected(kv.first); + for (auto &kv : m_checks) { + if (!kv.second.cancelled()) + kv.second.callback().onDisconnected(kv.first); + } m_checks.clear(); m_sequenceContainer.clear(); } diff --git a/src/client-async/logic/Logic.h b/src/client-async/logic/Logic.h index 53cfba9..0bca98e 100644 --- a/src/client-async/logic/Logic.h +++ b/src/client-async/logic/Logic.h @@ -65,6 +65,7 @@ private: cynara_async_status socketDataStatus(void); bool processOut(void); void processCheckResponse(CheckResponsePtr checkResponse); + void processCancelResponse(CancelResponsePtr cancelResponse); void processResponses(void); bool processIn(void); bool ensureConnection(void); diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 490a4f3..d52ddd5 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -32,12 +32,14 @@ SET(COMMON_SOURCES ${COMMON_PATH}/protocol/ProtocolSerialization.cpp ${COMMON_PATH}/protocol/ProtocolSignal.cpp ${COMMON_PATH}/request/AdminCheckRequest.cpp + ${COMMON_PATH}/request/CancelRequest.cpp ${COMMON_PATH}/request/CheckRequest.cpp ${COMMON_PATH}/request/InsertOrUpdateBucketRequest.cpp ${COMMON_PATH}/request/RemoveBucketRequest.cpp ${COMMON_PATH}/request/RequestTaker.cpp ${COMMON_PATH}/request/SetPoliciesRequest.cpp ${COMMON_PATH}/request/SignalRequest.cpp + ${COMMON_PATH}/response/CancelResponse.cpp ${COMMON_PATH}/response/CheckResponse.cpp ${COMMON_PATH}/response/CodeResponse.cpp ${COMMON_PATH}/response/ResponseTaker.cpp diff --git a/src/common/protocol/ProtocolClient.cpp b/src/common/protocol/ProtocolClient.cpp index 5101900..94811dd 100644 --- a/src/common/protocol/ProtocolClient.cpp +++ b/src/common/protocol/ProtocolClient.cpp @@ -31,8 +31,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -52,6 +54,11 @@ ProtocolPtr ProtocolClient::clone(void) { return std::make_shared(); } +RequestPtr ProtocolClient::deserializeCancelRequest(ProtocolFrameHeader &frame) { + LOGD("Deserialized CancelRequest"); + return std::make_shared(frame.sequenceNumber()); +} + RequestPtr ProtocolClient::deserializeCheckRequest(ProtocolFrameHeader &frame) { std::string clientId, userId, privilegeId; @@ -79,6 +86,8 @@ RequestPtr ProtocolClient::extractRequestFromBuffer(BinaryQueue &bufferQueue) { switch (opCode) { case OpCheckPolicyRequest: return deserializeCheckRequest(m_frameHeader); + case OpCancelRequest: + return deserializeCancelRequest(m_frameHeader); default: throw InvalidProtocolException(InvalidProtocolException::WrongOpCode); break; @@ -88,6 +97,11 @@ RequestPtr ProtocolClient::extractRequestFromBuffer(BinaryQueue &bufferQueue) { return nullptr; } +ResponsePtr ProtocolClient::deserializeCancelResponse(ProtocolFrameHeader &frame) { + LOGD("Deserialized CancelResponse"); + return std::make_shared(frame.sequenceNumber()); +} + ResponsePtr ProtocolClient::deserializeCheckResponse(ProtocolFrameHeader &frame) { PolicyType result; PolicyResult::PolicyMetadata additionalInfo; @@ -115,6 +129,8 @@ ResponsePtr ProtocolClient::extractResponseFromBuffer(BinaryQueue &bufferQueue) switch (opCode) { case OpCheckPolicyResponse: return deserializeCheckResponse(m_frameHeader); + case OpCancelResponse: + return deserializeCancelResponse(m_frameHeader); default: throw InvalidProtocolException(InvalidProtocolException::WrongOpCode); break; @@ -124,6 +140,16 @@ ResponsePtr ProtocolClient::extractResponseFromBuffer(BinaryQueue &bufferQueue) return nullptr; } +void ProtocolClient::execute(RequestContextPtr context, CancelRequestPtr request) { + ProtocolFramePtr frame = ProtocolFrameSerializer::startSerialization(request->sequenceNumber()); + + LOGD("Serializing CancelRequest op [%" PRIu8 "]", OpCancelRequest); + + ProtocolSerialization::serialize(*frame, OpCancelRequest); + + ProtocolFrameSerializer::finishSerialization(frame, context->responseQueue()); +} + void ProtocolClient::execute(RequestContextPtr context, CheckRequestPtr request) { ProtocolFramePtr frame = ProtocolFrameSerializer::startSerialization(request->sequenceNumber()); @@ -139,6 +165,17 @@ void ProtocolClient::execute(RequestContextPtr context, CheckRequestPtr request) ProtocolFrameSerializer::finishSerialization(frame, context->responseQueue()); } +void ProtocolClient::execute(RequestContextPtr context, CancelResponsePtr response) { + ProtocolFramePtr frame = ProtocolFrameSerializer::startSerialization( + response->sequenceNumber()); + + LOGD("Serializing CancelResponse: op [%" PRIu8 "]", OpCancelResponse); + + ProtocolSerialization::serialize(*frame, OpCancelResponse); + + ProtocolFrameSerializer::finishSerialization(frame, context->responseQueue()); +} + void ProtocolClient::execute(RequestContextPtr context, CheckResponsePtr response) { ProtocolFramePtr frame = ProtocolFrameSerializer::startSerialization( response->sequenceNumber()); diff --git a/src/common/protocol/ProtocolClient.h b/src/common/protocol/ProtocolClient.h index 9493a88..1bb1b6a 100644 --- a/src/common/protocol/ProtocolClient.h +++ b/src/common/protocol/ProtocolClient.h @@ -41,11 +41,17 @@ public: virtual RequestPtr extractRequestFromBuffer(BinaryQueue &bufferQueue); virtual ResponsePtr extractResponseFromBuffer(BinaryQueue &bufferQueue); + virtual void execute(RequestContextPtr context, CancelRequestPtr request); virtual void execute(RequestContextPtr context, CheckRequestPtr request); + + virtual void execute(RequestContextPtr context, CancelResponsePtr response); virtual void execute(RequestContextPtr context, CheckResponsePtr response); private: + RequestPtr deserializeCancelRequest(ProtocolFrameHeader &frame); RequestPtr deserializeCheckRequest(ProtocolFrameHeader &frame); + + ResponsePtr deserializeCancelResponse(ProtocolFrameHeader &frame); ResponsePtr deserializeCheckResponse(ProtocolFrameHeader &frame); }; diff --git a/src/common/protocol/ProtocolOpCode.h b/src/common/protocol/ProtocolOpCode.h index 7319ad3..2b4171c 100644 --- a/src/common/protocol/ProtocolOpCode.h +++ b/src/common/protocol/ProtocolOpCode.h @@ -33,8 +33,10 @@ enum ProtocolOpCode : uint8_t { /** Client operations */ OpCheckPolicyRequest = 0, OpCheckPolicyResponse, + OpCancelRequest, + OpCancelResponse, - /** Opcodes 2 - 19 are reserved for future use */ + /** Opcodes 4 - 19 are reserved for future use */ /** Admin operations */ OpInsertOrUpdateBucket = 20, diff --git a/src/common/request/CancelRequest.cpp b/src/common/request/CancelRequest.cpp new file mode 100644 index 0000000..d7a5ffa --- /dev/null +++ b/src/common/request/CancelRequest.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file src/common/request/CancelRequest.cpp + * @author Marcin Niesluchowski + * @version 1.0 + * @brief This file implements cancel request class + */ + +#include + +#include "CancelRequest.h" + +namespace Cynara { + +void CancelRequest::execute(RequestPtr self, RequestTakerPtr taker, + RequestContextPtr context) const { + taker->execute(context, std::dynamic_pointer_cast(self)); +} + +} // namespace Cynara diff --git a/src/common/request/CancelRequest.h b/src/common/request/CancelRequest.h new file mode 100644 index 0000000..a6192b8 --- /dev/null +++ b/src/common/request/CancelRequest.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file src/common/request/CancelRequest.h + * @author Marcin Niesluchowski + * @version 1.0 + * @brief This file defines cancel request class + */ + +#ifndef SRC_COMMON_REQUEST_CANCELREQUEST_H_ +#define SRC_COMMON_REQUEST_CANCELREQUEST_H_ + +#include +#include +#include + +namespace Cynara { + +class CancelRequest : public Request { +public: + CancelRequest(ProtocolFrameSequenceNumber sequenceNumber) : Request(sequenceNumber) { + } + + virtual ~CancelRequest() {}; + + virtual void execute(RequestPtr self, RequestTakerPtr taker, RequestContextPtr context) const; +}; + +} // namespace Cynara + +#endif /* SRC_COMMON_REQUEST_CANCELREQUEST_H_ */ diff --git a/src/common/request/RequestTaker.cpp b/src/common/request/RequestTaker.cpp index d645aee..c87a9a4 100644 --- a/src/common/request/RequestTaker.cpp +++ b/src/common/request/RequestTaker.cpp @@ -33,6 +33,10 @@ void RequestTaker::execute(RequestContextPtr context UNUSED, AdminCheckRequestPt throw NotImplementedException(); } +void RequestTaker::execute(RequestContextPtr context UNUSED, CancelRequestPtr request UNUSED) { + throw NotImplementedException(); +} + void RequestTaker::execute(RequestContextPtr context UNUSED, CheckRequestPtr request UNUSED) { throw NotImplementedException(); } diff --git a/src/common/request/RequestTaker.h b/src/common/request/RequestTaker.h index 6f1f112..b1d3466 100644 --- a/src/common/request/RequestTaker.h +++ b/src/common/request/RequestTaker.h @@ -33,6 +33,7 @@ public: virtual ~RequestTaker() {}; virtual void execute(RequestContextPtr context, AdminCheckRequestPtr request); + virtual void execute(RequestContextPtr context, CancelRequestPtr request); virtual void execute(RequestContextPtr context, CheckRequestPtr request); virtual void execute(RequestContextPtr context, InsertOrUpdateBucketRequestPtr request); virtual void execute(RequestContextPtr context, RemoveBucketRequestPtr request); diff --git a/src/common/request/pointers.h b/src/common/request/pointers.h index 5800321..5c90004 100644 --- a/src/common/request/pointers.h +++ b/src/common/request/pointers.h @@ -30,6 +30,9 @@ namespace Cynara { class AdminCheckRequest; typedef std::shared_ptr AdminCheckRequestPtr; +class CancelRequest; +typedef std::shared_ptr CancelRequestPtr; + class CheckRequest; typedef std::shared_ptr CheckRequestPtr; diff --git a/src/common/response/CancelResponse.cpp b/src/common/response/CancelResponse.cpp new file mode 100644 index 0000000..69211e7 --- /dev/null +++ b/src/common/response/CancelResponse.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file src/common/response/CancelResponse.cpp + * @author Marcin Niesluchowski + * @version 1.0 + * @brief This file implements cancel response class + */ + +#include + +#include "CancelResponse.h" + +namespace Cynara { + +void CancelResponse::execute(ResponsePtr self, ResponseTakerPtr taker, + RequestContextPtr context) const { + taker->execute(context, std::dynamic_pointer_cast(self)); +} + +} // namespace Cynara diff --git a/src/common/response/CancelResponse.h b/src/common/response/CancelResponse.h new file mode 100644 index 0000000..657ab2c --- /dev/null +++ b/src/common/response/CancelResponse.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file src/common/response/CancelResponse.h + * @author Marcin Niesluchowski + * @version 1.0 + * @brief This file defines response class for cancel response + */ + +#ifndef SRC_COMMON_RESPONSE_CANCELRESPONSE_H_ +#define SRC_COMMON_RESPONSE_CANCELRESPONSE_H_ + +#include +#include +#include + +namespace Cynara { + +class CancelResponse : public Response { +public: + CancelResponse(ProtocolFrameSequenceNumber sequenceNumber) : Response(sequenceNumber) { + } + + virtual ~CancelResponse() {}; + + virtual void execute(ResponsePtr self, ResponseTakerPtr taker, RequestContextPtr context) const; +}; + +} // namespace Cynara + +#endif /* SRC_COMMON_RESPONSE_CANCELRESPONSE_H_ */ diff --git a/src/common/response/ResponseTaker.cpp b/src/common/response/ResponseTaker.cpp index 7da0dfb..3f558c4 100644 --- a/src/common/response/ResponseTaker.cpp +++ b/src/common/response/ResponseTaker.cpp @@ -28,6 +28,10 @@ namespace Cynara { +void ResponseTaker::execute(RequestContextPtr context UNUSED, CancelResponsePtr response UNUSED) { + throw NotImplementedException(); +} + void ResponseTaker::execute(RequestContextPtr context UNUSED, CheckResponsePtr response UNUSED) { throw NotImplementedException(); } diff --git a/src/common/response/ResponseTaker.h b/src/common/response/ResponseTaker.h index 41425d8..0afdb65 100644 --- a/src/common/response/ResponseTaker.h +++ b/src/common/response/ResponseTaker.h @@ -33,6 +33,7 @@ public: ResponseTaker() = default; virtual ~ResponseTaker() {}; + virtual void execute(RequestContextPtr context, CancelResponsePtr response); virtual void execute(RequestContextPtr context, CheckResponsePtr response); virtual void execute(RequestContextPtr context, CodeResponsePtr response); }; diff --git a/src/common/response/pointers.h b/src/common/response/pointers.h index 088c533..4e9b8fc 100644 --- a/src/common/response/pointers.h +++ b/src/common/response/pointers.h @@ -27,6 +27,9 @@ namespace Cynara { +class CancelResponse; +typedef std::shared_ptr CancelResponsePtr; + class CheckResponse; typedef std::shared_ptr CheckResponsePtr; diff --git a/src/service/logic/Logic.cpp b/src/service/logic/Logic.cpp index c25487e..d05f512 100644 --- a/src/service/logic/Logic.cpp +++ b/src/service/logic/Logic.cpp @@ -30,12 +30,14 @@ #include
#include +#include #include #include #include #include #include #include +#include #include #include #include @@ -70,6 +72,11 @@ void Logic::execute(RequestContextPtr context, AdminCheckRequestPtr request) { request->sequenceNumber())); } +void Logic::execute(RequestContextPtr context, CancelRequestPtr request) { + // MOCKUP + context->returnResponse(context, std::make_shared(request->sequenceNumber())); +} + void Logic::execute(RequestContextPtr context, CheckRequestPtr request) { PolicyResult result(PredefinedPolicyType::DENY); if (check(context, request->key(), result)) { diff --git a/src/service/logic/Logic.h b/src/service/logic/Logic.h index 84af6ff..28fdeea 100644 --- a/src/service/logic/Logic.h +++ b/src/service/logic/Logic.h @@ -51,6 +51,7 @@ public: } virtual void execute(RequestContextPtr context, AdminCheckRequestPtr request); + virtual void execute(RequestContextPtr context, CancelRequestPtr request); virtual void execute(RequestContextPtr context, CheckRequestPtr request); virtual void execute(RequestContextPtr context, InsertOrUpdateBucketRequestPtr request); virtual void execute(RequestContextPtr context, RemoveBucketRequestPtr request); -- 2.7.4 From b13293789e389806a41f15b74ff62a82675d902e Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jos=C3=A9=20Bollo?= Date: Mon, 6 Oct 2014 17:31:59 +0200 Subject: [PATCH 11/16] Improving creation of user 'cynara' MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit To improve the creation of the user cynara, the home directory is now set to /var/lib/empty, the shell is set to /sbin/nologin, the main group is set to cynara. Change-Id: I4582caa9f9a61cd8c52d0a6718f504903cdee479 Signed-off-by: José Bollo --- packaging/cynara.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/cynara.spec b/packaging/cynara.spec index 7508fbf..c25347f 100644 --- a/packaging/cynara.spec +++ b/packaging/cynara.spec @@ -273,7 +273,7 @@ fi id -u %{user_name} > /dev/null 2>&1 if [ $? -eq 1 ]; then - useradd %{user_name} -r > /dev/null 2>&1 + useradd -d /var/lib/empty -s /sbin/nologin -r -g %{group_name} %{user_name} > /dev/null 2>&1 fi %post -- 2.7.4 From 4fc95e366db1631e175bf8955fd3e72e610a4d07 Mon Sep 17 00:00:00 2001 From: Zofia Abramowska Date: Fri, 12 Sep 2014 15:45:36 +0200 Subject: [PATCH 12/16] Redo client plugins Let plugin make decision based on last and current client session. Plugin can change PluginResult. Change-Id: Ia985feaf1d60a8c1ebf858ba0d4e0d6f2cc6fa40 --- src/client-common/cache/CapacityCache.cpp | 49 ++++++++++++++-------------- src/client-common/cache/CapacityCache.h | 5 ++- src/client-common/plugins/NaiveInterpreter.h | 8 +++-- src/client-common/plugins/PluginInterface.h | 10 +++--- 4 files changed, 37 insertions(+), 35 deletions(-) diff --git a/src/client-common/cache/CapacityCache.cpp b/src/client-common/cache/CapacityCache.cpp index c4cf680..04f1cb5 100644 --- a/src/client-common/cache/CapacityCache.cpp +++ b/src/client-common/cache/CapacityCache.cpp @@ -30,13 +30,6 @@ namespace Cynara { int CapacityCache::get(const ClientSession &session, const PolicyKey &key) { - //This can be very time heavy. This part is welcomed to be optimized. - if (session != m_session) { - LOGD("Session changed from %s to %s.", m_session.c_str(), session.c_str()); - clear(); - m_session = session; - return CYNARA_API_CACHE_MISS; - } auto resultIt = m_keyValue.find(keyToString(key)); //Do we have entry in cache? if (resultIt == m_keyValue.end()) { @@ -51,23 +44,33 @@ int CapacityCache::get(const ClientSession &session, const PolicyKey &key) { key.user().toString().c_str(), key.privilege().toString().c_str()); - auto pluginIt = m_plugins.find(resultIt->second.first.policyType()); + auto &cachedValue = resultIt->second; + auto &policyResult = std::get<0>(cachedValue); + + auto pluginIt = m_plugins.find(policyResult.policyType()); if (pluginIt == m_plugins.end()) { LOGE("No plugin registered for given PolicyType : %" PRIu16, - resultIt->second.first.policyType()); + policyResult.policyType()); return CYNARA_API_ACCESS_DENIED; } //Is it still usable? InterpreterInterfacePtr plugin = pluginIt->second; - if (plugin->isUsable(resultIt->second.first)) { + auto &prevSession = std::get<1>(cachedValue); + auto usageIt = std::get<2>(cachedValue); + bool updateSession = false; + if (plugin->isUsable(session, prevSession, updateSession, policyResult)) { LOGD("Entry usable."); - m_keyUsage.splice(m_keyUsage.begin(), m_keyUsage, resultIt->second.second); - return plugin->toResult(resultIt->second.first); + m_keyUsage.splice(m_keyUsage.begin(), m_keyUsage, usageIt); + + if (updateSession) { + prevSession = session; + } + + return plugin->toResult(session, policyResult); } //Remove unusable entry LOGD("Entry not usable"); - auto usageIt = resultIt->second.second; m_keyUsage.erase(usageIt); m_keyValue.erase(resultIt); return CYNARA_API_CACHE_MISS; @@ -77,7 +80,6 @@ int CapacityCache::get(const ClientSession &session, const PolicyKey &key) { void CapacityCache::clear(void) { m_keyUsage.clear(); m_keyValue.clear(); - m_session.clear(); } std::string CapacityCache::keyToString(const PolicyKey &key) { @@ -103,12 +105,6 @@ void CapacityCache::evict(void) { int CapacityCache::update(const ClientSession &session, const PolicyKey &key, const PolicyResult &result) { - //This can be very time heavy. This part is welcomed to be optimized. - if (session != m_session) { - LOGD("Session changed from %s to %s.", m_session.c_str(), session.c_str()); - clear(); - m_session = session; - } auto pluginIt = m_plugins.find(result.policyType()); @@ -120,18 +116,21 @@ int CapacityCache::update(const ClientSession &session, } auto plugin = pluginIt->second; - if (m_capacity != 0) { - if (plugin->isCacheable(result)) { + PolicyResult storedResult = result; + + if (m_capacity > 0) { + if (plugin->isCacheable(session, storedResult)) { LOGD("Entry cacheable"); if (m_keyValue.size() == m_capacity) { LOGD("Capacity reached."); evict(); } - m_keyUsage.push_front(keyToString(key)); - m_keyValue[keyToString(key)] = std::make_pair(result, m_keyUsage.begin()); + std::string cacheKey = keyToString(key); + m_keyUsage.push_front(cacheKey); + m_keyValue[cacheKey] = std::make_tuple(storedResult, session, m_keyUsage.begin()); } } - return plugin->toResult(result); + return plugin->toResult(session, storedResult); } } // namespace Cynara diff --git a/src/client-common/cache/CapacityCache.h b/src/client-common/cache/CapacityCache.h index 5bb083e..4218078 100644 --- a/src/client-common/cache/CapacityCache.h +++ b/src/client-common/cache/CapacityCache.h @@ -24,6 +24,7 @@ #define SRC_CLIENT_COMMON_CACHE_CAPACITYCACHE_H_ #include +#include #include #include @@ -46,15 +47,13 @@ public: private: typedef std::list KeyUsageList; typedef std::unordered_map> KeyValueMap; + std::tuple> KeyValueMap; static std::string keyToString(const PolicyKey &key); void evict(void); std::size_t m_capacity; - ClientSession m_session; KeyUsageList m_keyUsage; KeyValueMap m_keyValue; diff --git a/src/client-common/plugins/NaiveInterpreter.h b/src/client-common/plugins/NaiveInterpreter.h index 04d05de..e306ab7 100644 --- a/src/client-common/plugins/NaiveInterpreter.h +++ b/src/client-common/plugins/NaiveInterpreter.h @@ -29,13 +29,15 @@ namespace Cynara { class NaiveInterpreter : public InterpreterInterface { - bool isUsable(const PolicyResult &result UNUSED) { + bool isUsable(const ClientSession &session UNUSED, const ClientSession &prevSession UNUSED, + bool &updateSession UNUSED, PolicyResult &result UNUSED) { return true; } - bool isCacheable(const PolicyResult &result UNUSED) { + bool isCacheable(const ClientSession &session UNUSED, + const PolicyResult &result UNUSED) { return true; } - int toResult(const PolicyResult &result) { + int toResult(const ClientSession &session UNUSED, PolicyResult &result) { if (result.policyType() == PredefinedPolicyType::ALLOW) return CYNARA_API_ACCESS_ALLOWED; else diff --git a/src/client-common/plugins/PluginInterface.h b/src/client-common/plugins/PluginInterface.h index 5f3a947..54bd341 100644 --- a/src/client-common/plugins/PluginInterface.h +++ b/src/client-common/plugins/PluginInterface.h @@ -25,6 +25,7 @@ #include +#include #include namespace Cynara { @@ -34,13 +35,14 @@ typedef std::shared_ptr InterpreterInterfacePtr; class InterpreterInterface { public: - virtual bool isCacheable(const PolicyResult &result) = 0; - virtual bool isUsable(const PolicyResult &result) = 0; - virtual int toResult(const PolicyResult &result) = 0; + virtual bool isCacheable(const ClientSession &session, const PolicyResult &result) = 0; + virtual bool isUsable(const ClientSession &session, const ClientSession &prevSession, + bool &updateSession, PolicyResult &result) = 0; + virtual int toResult(const ClientSession &session, PolicyResult &result) = 0; virtual ~InterpreterInterface() {}; }; -} +} // namespace Cynara #endif // SRC_CLIENT_COMMON_PLUGINS_PLUGININTERFACE_H_ -- 2.7.4 From 9018caa487c2037baf70868a72b0b2cc39ce7217 Mon Sep 17 00:00:00 2001 From: Zofia Abramowska Date: Tue, 16 Sep 2014 12:53:09 +0200 Subject: [PATCH 13/16] Fix cache update method Support update with existing entry. Change-Id: I0a242c9580ae0a521fddb8bf4fc4c2b8be3507c0 --- src/client-common/cache/CapacityCache.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/client-common/cache/CapacityCache.cpp b/src/client-common/cache/CapacityCache.cpp index 04f1cb5..c6449bc 100644 --- a/src/client-common/cache/CapacityCache.cpp +++ b/src/client-common/cache/CapacityCache.cpp @@ -119,15 +119,31 @@ int CapacityCache::update(const ClientSession &session, PolicyResult storedResult = result; if (m_capacity > 0) { + std::string cacheKey = keyToString(key); + auto resultIt = m_keyValue.find(cacheKey); if (plugin->isCacheable(session, storedResult)) { LOGD("Entry cacheable"); if (m_keyValue.size() == m_capacity) { LOGD("Capacity reached."); evict(); } - std::string cacheKey = keyToString(key); - m_keyUsage.push_front(cacheKey); + + //Move value usage to front + if (resultIt != m_keyValue.end()) { + auto usageIt = std::get<2>(resultIt->second); + m_keyUsage.splice(m_keyUsage.begin(), m_keyUsage, usageIt); + } else { + m_keyUsage.push_front(cacheKey); + } + m_keyValue[cacheKey] = std::make_tuple(storedResult, session, m_keyUsage.begin()); + } else { + //Remove element + if (resultIt != m_keyValue.end()) { + auto usageIt = std::get<2>(resultIt->second); + m_keyUsage.erase(usageIt); + m_keyValue.erase(resultIt); + } } } return plugin->toResult(session, storedResult); -- 2.7.4 From 4c2b3b8d0ce17221e77bcda10be4ef992d82ba72 Mon Sep 17 00:00:00 2001 From: Zofia Abramowska Date: Thu, 18 Sep 2014 17:33:53 +0200 Subject: [PATCH 14/16] Split PolicyResult declaration and definition PolicyResult header will be included in package for external plugin implementations. Change-Id: Ic5224af395b9fd86f57138566295961e80ee8f12 --- src/common/CMakeLists.txt | 1 + src/common/types/PolicyResult.cpp | 64 +++++++++++++++++++++++++++++++++++++++ src/common/types/PolicyResult.h | 53 +++++++++----------------------- test/CMakeLists.txt | 1 + 4 files changed, 81 insertions(+), 38 deletions(-) create mode 100644 src/common/types/PolicyResult.cpp diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index d52ddd5..461450a 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -49,6 +49,7 @@ SET(COMMON_SOURCES ${COMMON_PATH}/types/PolicyBucket.cpp ${COMMON_PATH}/types/PolicyKey.cpp ${COMMON_PATH}/types/PolicyKeyHelpers.cpp + ${COMMON_PATH}/types/PolicyResult.cpp ) IF (CMAKE_BUILD_TYPE MATCHES "DEBUG") diff --git a/src/common/types/PolicyResult.cpp b/src/common/types/PolicyResult.cpp new file mode 100644 index 0000000..010139d --- /dev/null +++ b/src/common/types/PolicyResult.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file src/common/types/PolicyResult.cpp + * @author Aleksander Zdyb + * @author Zofia Abramowska + * @version 1.0 + * @brief PolicyResult implementation + */ + +#include "PolicyResult.h" + +namespace Cynara { + +PolicyResult::PolicyResult() : m_type(PredefinedPolicyType::DENY) {} + +PolicyResult::PolicyResult(const PolicyType &policyType) : m_type(policyType) {} + +PolicyResult::PolicyResult(const PolicyType &policyType, const PolicyMetadata &metadata) + : m_type(policyType) , m_metadata(metadata) {} + +const PolicyType &PolicyResult::policyType(void) const { + return m_type; +} + +const PolicyResult::PolicyMetadata &PolicyResult::metadata(void) const { + return m_metadata; +} + +bool PolicyResult::operator <(const PolicyResult &other) const { + return this->m_type < other.m_type; +} + +bool PolicyResult::operator ==(const PolicyResult &other) const { + return std::tie(m_type, m_metadata) == std::tie(other.m_type, other.m_metadata); +} + +bool PolicyResult::operator !=(const PolicyResult &other) const { + return !(*this == other); +} + +bool PolicyResult::operator ==(const PolicyType &policyType) const { + return (m_type == policyType) && m_metadata.empty(); +} + +bool PolicyResult::operator !=(const PolicyType &policyType) const { + return !(*this == policyType); +} + +} // namespace Cynara + diff --git a/src/common/types/PolicyResult.h b/src/common/types/PolicyResult.h index 28974d7..ae81d15 100644 --- a/src/common/types/PolicyResult.h +++ b/src/common/types/PolicyResult.h @@ -16,12 +16,13 @@ /** * @file src/common/types/PolicyResult.h * @author Aleksander Zdyb + * @author Zofia Abramowska * @version 1.0 * @brief Definitions of PolicyResult and friends */ -#ifndef POLICYRESULT_H_ -#define POLICYRESULT_H_ +#ifndef SRC_COMMON_TYPES_POLICYRESULT_H_ +#define SRC_COMMON_TYPES_POLICYRESULT_H_ #include "types/PolicyType.h" @@ -33,47 +34,23 @@ class PolicyResult { public: typedef std::string PolicyMetadata; -public: - PolicyResult() : m_type(PredefinedPolicyType::DENY) {} - PolicyResult(const PolicyType &policyType) : m_type(policyType) {} - PolicyResult(const PolicyType &policyType, const PolicyMetadata &metadata) - : m_type(policyType), m_metadata(metadata) {} + PolicyResult(); + PolicyResult(const PolicyType &policyType); + PolicyResult(const PolicyType &policyType, const PolicyMetadata &metadata); + + const PolicyType &policyType(void) const; + const PolicyMetadata &metadata(void) const; + bool operator <(const PolicyResult &other) const; + bool operator ==(const PolicyResult &other) const; + bool operator !=(const PolicyResult &other) const; + bool operator ==(const PolicyType &policyType) const; + bool operator !=(const PolicyType &policyType) const; private: PolicyType m_type; PolicyMetadata m_metadata; - -public: - const PolicyType &policyType() const { - return m_type; - } - - const PolicyMetadata& metadata() const { - return m_metadata; - } - - bool operator <(const PolicyResult &other) const { - return this->m_type < other.m_type; - } - - bool operator ==(const PolicyResult &other) const { - return std::tie(m_type, m_metadata) == std::tie(other.m_type, other.m_metadata); - } - - bool operator !=(const PolicyResult &other) const { - return !(*this == other); - } - - bool operator ==(const PolicyType &policyType) const { - return (m_type == policyType) && m_metadata.empty(); - } - - bool operator !=(const PolicyType &policyType) const { - return !(*this == policyType); - } }; } // namespace Cynara - -#endif /* POLICYRESULT_H_ */ +#endif /* SRC_COMMON_TYPES_POLICYRESULT_H_ */ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 47bcfab..62bdbaa 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -25,6 +25,7 @@ SET(CYNARA_SOURCES_FOR_TESTS ${CYNARA_SRC}/common/types/PolicyBucket.cpp ${CYNARA_SRC}/common/types/PolicyKey.cpp ${CYNARA_SRC}/common/types/PolicyKeyHelpers.cpp + ${CYNARA_SRC}/common/types/PolicyResult.cpp ${CYNARA_SRC}/common/types/PolicyType.cpp ${CYNARA_SRC}/storage/BucketDeserializer.cpp ${CYNARA_SRC}/storage/InMemoryStorageBackend.cpp -- 2.7.4 From abb2d89db389d6636c327343b7e6292a12155bd1 Mon Sep 17 00:00:00 2001 From: Zofia Abramowska Date: Thu, 18 Sep 2014 18:37:40 +0200 Subject: [PATCH 15/16] Add cynara external plugins Add interface for creating external cynara plugin to enable custom policy types support. Change-Id: I43bd31a3e48f9667964107dd243f2286e7ffae8a --- packaging/cynara.spec | 14 ++++ pkgconfig/CMakeLists.txt | 1 + pkgconfig/cynara-plugin/CMakeLists.txt | 25 +++++++ pkgconfig/cynara-plugin/cynara-plugin.pc.in | 11 +++ src/common/CMakeLists.txt | 5 ++ src/include/CMakeLists.txt | 1 + src/include/cynara-plugin.h | 107 ++++++++++++++++++++++++++++ 7 files changed, 164 insertions(+) create mode 100644 pkgconfig/cynara-plugin/CMakeLists.txt create mode 100644 pkgconfig/cynara-plugin/cynara-plugin.pc.in create mode 100644 src/include/cynara-plugin.h diff --git a/packaging/cynara.spec b/packaging/cynara.spec index c25347f..6abd205 100644 --- a/packaging/cynara.spec +++ b/packaging/cynara.spec @@ -141,6 +141,14 @@ Requires: libcynara-commons = %{version}-%{release} cynara common library (devel) with common functionalities ####################################################### +%package -n libcynara-plugin-devel +Summary: Cynara - cynara plugin library (devel) +Requires: libcynara-commons-devel = %{version}-%{release} + +%description -n libcynara-plugin-devel +cynara plugin library (devel) with plugin definitions + +####################################################### %package -n libcynara-creds-commons Summary: Base library for cynara credentials helpers @@ -451,8 +459,14 @@ fi %{_libdir}/libcynara-commons.so.* %files -n libcynara-commons-devel +%{_includedir}/cynara/types/PolicyResult.h +%{_includedir}/cynara/types/PolicyType.h %{_libdir}/libcynara-commons.so +%files -n libcynara-plugin-devel +%{_includedir}/cynara/cynara-plugin.h +%{_libdir}/pkgconfig/cynara-plugin.pc + %files -n cynara-tests %manifest cynara-tests.manifest %attr(755,root,root) /usr/bin/cynara-tests diff --git a/pkgconfig/CMakeLists.txt b/pkgconfig/CMakeLists.txt index 9d4600f..a93ae55 100644 --- a/pkgconfig/CMakeLists.txt +++ b/pkgconfig/CMakeLists.txt @@ -23,4 +23,5 @@ ADD_SUBDIRECTORY(cynara-admin) ADD_SUBDIRECTORY(cynara-creds-commons) ADD_SUBDIRECTORY(cynara-creds-dbus) ADD_SUBDIRECTORY(cynara-creds-socket) +ADD_SUBDIRECTORY(cynara-plugin) ADD_SUBDIRECTORY(cynara-session) diff --git a/pkgconfig/cynara-plugin/CMakeLists.txt b/pkgconfig/cynara-plugin/CMakeLists.txt new file mode 100644 index 0000000..1ea74a5 --- /dev/null +++ b/pkgconfig/cynara-plugin/CMakeLists.txt @@ -0,0 +1,25 @@ +# Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Zofia Abramowska +# + +CONFIGURE_FILE(cynara-plugin.pc.in cynara-plugin.pc @ONLY) + +INSTALL(FILES + ${CMAKE_BINARY_DIR}/pkgconfig/cynara-plugin/cynara-plugin.pc + DESTINATION + ${LIB_INSTALL_DIR}/pkgconfig + ) diff --git a/pkgconfig/cynara-plugin/cynara-plugin.pc.in b/pkgconfig/cynara-plugin/cynara-plugin.pc.in new file mode 100644 index 0000000..c14de16 --- /dev/null +++ b/pkgconfig/cynara-plugin/cynara-plugin.pc.in @@ -0,0 +1,11 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +libdir=@LIB_INSTALL_DIR@ +includedir=${prefix}/include + +Name: cynara-plugin +Description: Cynara plugin definition package +Version: @CYNARA_VERSION@ +Requires: +Libs: -L${libdir} -lcynara-commons +Cflags: -I${includedir}/cynara diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 461450a..77c7d56 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -82,3 +82,8 @@ TARGET_LINK_LIBRARIES(${TARGET_CYNARA_COMMON} ) INSTALL(TARGETS ${TARGET_CYNARA_COMMON} DESTINATION ${LIB_INSTALL_DIR}) +INSTALL(FILES + ${COMMON_PATH}/types/PolicyResult.h + ${COMMON_PATH}/types/PolicyType.h + DESTINATION ${INCLUDE_INSTALL_DIR}/cynara/types + ) diff --git a/src/include/CMakeLists.txt b/src/include/CMakeLists.txt index 1be6e10..cb9d00c 100644 --- a/src/include/CMakeLists.txt +++ b/src/include/CMakeLists.txt @@ -26,6 +26,7 @@ INSTALL(FILES ${CYNARA_PATH}/include/cynara-creds-commons.h ${CYNARA_PATH}/include/cynara-creds-dbus.h ${CYNARA_PATH}/include/cynara-creds-socket.h + ${CYNARA_PATH}/include/cynara-plugin.h ${CYNARA_PATH}/include/cynara-session.h DESTINATION ${INCLUDE_INSTALL_DIR}/cynara ) diff --git a/src/include/cynara-plugin.h b/src/include/cynara-plugin.h new file mode 100644 index 0000000..83956fe --- /dev/null +++ b/src/include/cynara-plugin.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file src/include/cynara-plugin.h + * @author Zofia Abramowska + * @version 1.0 + * @brief This file defines cynara side external plugin interface + */ + +#ifndef CYNARA_PLUGIN_H_ +#define CYNARA_PLUGIN_H_ + +#include +#include +#include + +#include +#include + +namespace Cynara { + +class ExternalPluginInterface; + +extern "C" { +typedef ExternalPluginInterface *(*createPlugin)(void); +} + +//These typedefs will be defined in external headers +typedef std::string PluginData; +typedef std::string AgentType; +typedef std::vector PolicyTypes; + +/** + * A class defining external plugins interface. + * These plugins work inside of cynara and either can produce + * response through check instantly or require communication + * with given type of agent. Agent must be registered through + * cynara-agent API. + */ + +class ExternalPluginInterface { +public: + /** + * Enum indicating status of calling plugin method. + */ + enum class PluginStatus { + SUCCESS, /** < update() finished successfully*/ + ANSWER_READY, /** < check() returns answer immediately through argument*/ + ANSWER_NOTREADY, /** < check() cannot return answer immediately, + < communication with agent is required */ + ERROR /** < either check() or update() fails */ + }; + + /** + * Policy type supported by plugin. + */ + virtual PolicyTypes getSupportedPolicyTypes(void) = 0; + + /** + * Asks plugin, what kind of permission does client, user and privilege has. + * + * @param[in] client + * @param[in] user + * @param[in] privilege + * @param[out] result Immediate response (if available) + * @param[out] requiredAgent When ANSWER_NOTREADY, required AgentType to communicate with + * @param[out] pluginData Additional data, that will be passed to agent + * @return PluginStatus In case of success - either ANSWER_READY or ANSWER_NOTREADY, + * in case of error - ERROR + */ + virtual PluginStatus check(const std::string &client, const std::string &user, + const std::string &privilege, PolicyResult &result, + AgentType &requiredAgent, PluginData &pluginData) noexcept = 0; + + /** + * Updates response returned by agent + * @param[in] client + * @param[in] user + * @param[in] privilege + * @param[in] agentData Additional data, passed from agent + * @param[out] result Response interpreted from agent + * @return PluginStatus In case of success - SUCCESS, in case of error - ERROR + */ + virtual PluginStatus update(const std::string &client, const std::string &user, + const std::string &privilege, const PluginData &agentData, + PolicyResult &result) noexcept = 0; + + virtual ~ExternalPluginInterface() {}; + +}; + +} // namespace Cynara + +#endif /* CYNARA_PLUGIN_H_ */ -- 2.7.4 From fa70d3d34bf759389e67f52401adb334cf21ec2e Mon Sep 17 00:00:00 2001 From: Zofia Abramowska Date: Fri, 19 Sep 2014 16:42:02 +0200 Subject: [PATCH 16/16] Add PluginManager Add cynara service manager for loading and managing dynamic loaded plugins supporting custom policy types. Change-Id: I94c3bfa4842a6a8d0a078ac910aba5e54db7b468 --- src/service/CMakeLists.txt | 3 + src/service/logic/Logic.cpp | 28 ++++++-- src/service/logic/Logic.h | 7 ++ src/service/main/Cynara.cpp | 17 +++++ src/service/main/Cynara.h | 2 + src/service/main/pointers.h | 3 + src/service/plugin/PluginManager.cpp | 123 +++++++++++++++++++++++++++++++++++ src/service/plugin/PluginManager.h | 55 ++++++++++++++++ 8 files changed, 232 insertions(+), 6 deletions(-) create mode 100644 src/service/plugin/PluginManager.cpp create mode 100644 src/service/plugin/PluginManager.h diff --git a/src/service/CMakeLists.txt b/src/service/CMakeLists.txt index f1c4c8a..f8d2eb8 100644 --- a/src/service/CMakeLists.txt +++ b/src/service/CMakeLists.txt @@ -22,6 +22,7 @@ SET(CYNARA_SOURCES ${CYNARA_SERVICE_PATH}/logic/Logic.cpp ${CYNARA_SERVICE_PATH}/main/Cynara.cpp ${CYNARA_SERVICE_PATH}/main/main.cpp + ${CYNARA_SERVICE_PATH}/plugin/PluginManager.cpp ${CYNARA_SERVICE_PATH}/sockets/Descriptor.cpp ${CYNARA_SERVICE_PATH}/sockets/SocketManager.cpp ) @@ -29,6 +30,7 @@ SET(CYNARA_SOURCES INCLUDE_DIRECTORIES( ${CYNARA_SERVICE_PATH} ${CYNARA_PATH} + ${CYNARA_PATH}/include ) ADD_EXECUTABLE(${TARGET_CYNARA} ${CYNARA_SOURCES}) @@ -37,6 +39,7 @@ TARGET_LINK_LIBRARIES(${TARGET_CYNARA} ${CYNARA_DEP_LIBRARIES} ${TARGET_CYNARA_COMMON} ${TARGET_LIB_CYNARA_STORAGE} + dl ) INSTALL(TARGETS ${TARGET_CYNARA} DESTINATION ${BIN_INSTALL_DIR}) diff --git a/src/service/logic/Logic.cpp b/src/service/logic/Logic.cpp index d05f512..60a0cce 100644 --- a/src/service/logic/Logic.cpp +++ b/src/service/logic/Logic.cpp @@ -97,13 +97,29 @@ bool Logic::check(RequestContextPtr context UNUSED, const PolicyKey &key, LOGD("check of policy key <%s> returned DENY", key.toString().c_str()); return true; } - //todo pass question to proper plugin that: - // 1) returns false when answer has to be waited for (UI) - // 2) returns true if Response is to be generated - // In case 1) context should be saved in plugin in order to return answer when ready. - //in case no proper plugin is found - throw PluginNotFoundException(result); + ExternalPluginPtr plugin = m_pluginManager->getPlugin(result.policyType()); + if (!plugin) { + throw PluginNotFoundException(result); + } + + AgentType requiredAgent; + PluginData pluginData; + + auto ret = plugin->check(key.client().toString(), key.user().toString(), + key.privilege().toString(), result, requiredAgent, pluginData); + + switch (ret) { + case ExternalPluginInterface::PluginStatus::ANSWER_READY: + return true; + case ExternalPluginInterface::PluginStatus::ANSWER_NOTREADY: + //todo send request to agent + //context should be saved in plugin in order to return answer when ready + return false; + default: + //todo make additional class + throw std::runtime_error("Plugin error"); + } } void Logic::execute(RequestContextPtr context, InsertOrUpdateBucketRequestPtr request) { diff --git a/src/service/logic/Logic.h b/src/service/logic/Logic.h index 28fdeea..3c434a5 100644 --- a/src/service/logic/Logic.h +++ b/src/service/logic/Logic.h @@ -27,6 +27,7 @@ #include #include
+#include #include #include @@ -37,6 +38,10 @@ public: Logic(); virtual ~Logic(); + void bindPluginManager(PluginManagerPtr pluginManager) { + m_pluginManager = pluginManager; + } + void bindStorage(StoragePtr storage) { m_storage = storage; } @@ -46,6 +51,7 @@ public: } void unbindAll(void) { + m_pluginManager.reset(); m_storage.reset(); m_socketManager.reset(); } @@ -59,6 +65,7 @@ public: virtual void execute(RequestContextPtr context, SignalRequestPtr request); private: + PluginManagerPtr m_pluginManager; StoragePtr m_storage; SocketManagerPtr m_socketManager; diff --git a/src/service/main/Cynara.cpp b/src/service/main/Cynara.cpp index 4a4deb4..1a0d45e 100644 --- a/src/service/main/Cynara.cpp +++ b/src/service/main/Cynara.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -58,12 +59,27 @@ const std::string Cynara::storageDir(void) { return dir; } +const std::string Cynara::pluginDir(void) { + std::string dir("/usr/lib/cynara/"); + +#ifdef CYNARA_LIB_PATH + dir = CYNARA_LIB_PATH; +#else + LOGW("Cynara compiled without CYNARA_LIB_PATH flag. Using default plugin directory."); +#endif + dir += "plugin/"; + LOGI("Cynara plugin path <%s>", dir.c_str()); + return dir; +} + void Cynara::init(void) { m_logic = std::make_shared(); + m_pluginManager = std::make_shared(pluginDir()); m_socketManager = std::make_shared(); m_storageBackend = std::make_shared(storageDir()); m_storage = std::make_shared(*m_storageBackend); + m_logic->bindPluginManager(m_pluginManager); m_logic->bindStorage(m_storage); m_logic->bindSocketManager(m_socketManager); @@ -90,6 +106,7 @@ void Cynara::finalize(void) { } m_logic.reset(); + m_pluginManager.reset(); m_socketManager.reset(); m_storageBackend.reset(); m_storage.reset(); diff --git a/src/service/main/Cynara.h b/src/service/main/Cynara.h index ecdde62..e89eda3 100644 --- a/src/service/main/Cynara.h +++ b/src/service/main/Cynara.h @@ -30,10 +30,12 @@ namespace Cynara { class Cynara { private: LogicPtr m_logic; + PluginManagerPtr m_pluginManager; SocketManagerPtr m_socketManager; StoragePtr m_storage; StorageBackendPtr m_storageBackend; + static const std::string pluginDir(void); static const std::string storageDir(void); public: diff --git a/src/service/main/pointers.h b/src/service/main/pointers.h index 652dba3..e31eeb8 100644 --- a/src/service/main/pointers.h +++ b/src/service/main/pointers.h @@ -30,6 +30,9 @@ namespace Cynara { class Logic; typedef std::shared_ptr LogicPtr; +class PluginManager; +typedef std::shared_ptr PluginManagerPtr; + class SocketManager; typedef std::shared_ptr SocketManagerPtr; diff --git a/src/service/plugin/PluginManager.cpp b/src/service/plugin/PluginManager.cpp new file mode 100644 index 0000000..3d21b49 --- /dev/null +++ b/src/service/plugin/PluginManager.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file src/service/plugin/PluginManager.cpp + * @author Zofia Abramowska + * @version 1.0 + * @brief Definition of PluginManager class + */ + +#define _BSD_SOURCE_ + +#include +#include +#include +#include +#include + +#include + +#include "PluginManager.h" + + +namespace { + int pluginFilter(const struct dirent *ent) { +#ifdef _DIRENT_HAVE_D_TYPE + if (ent->d_type != DT_REG) { + return 0; + } +#endif + if (ent->d_name[0] == '.') { + return 0; + } + return 1; + } +} + +namespace Cynara { + +PluginManager::PluginManager(const std::string &pluginDir) : m_dir(pluginDir) { + loadPlugins(); +} + +ExternalPluginPtr PluginManager::getPlugin(PolicyType pType) { + return m_plugins[pType]; +} + +void PluginManager::loadPlugins(void) { + struct dirent **nameList = NULL; + int fileAmount = scandir(m_dir.c_str(), &nameList, pluginFilter, alphasort); + + if (fileAmount < 0) { + auto error = strerror(errno); + LOGE("Couldn't scan for plugins in <%s> : <%s>", m_dir.c_str(), error); + return; + } + + std::unique_ptr> direntPtr(nameList, + [fileAmount](dirent** dirs) { + for (int i = 0; i < fileAmount; i++) { + free(dirs[i]); + } + free(dirs); + }); + for (int i = 0; i < fileAmount; i++) { + openPlugin(m_dir + nameList[i]->d_name); + } +} + +void PluginManager::openPlugin(const std::string &path) { + void *handle = dlopen(path.c_str(), RTLD_LAZY); + + if (!handle) { + LOGW("File could not be dlopened <%s> : <%s>", path.c_str(), dlerror()); + return; + } + PluginLibPtr handlePtr(handle, std::ptr_fun(dlclose)); + + //Flush any previous errors + dlerror(); + createPlugin func = reinterpret_cast(dlsym(handle, "create")); + + char *error; + if ((error = dlerror()) != NULL) { + LOGE("Couldn't resolve symbol from lib <%s> : <%s>", path.c_str(), error); + return; + } + + ExternalPluginPtr pluginPtr(func()); + + if (!pluginPtr) { + LOGE("Couldn't create plugin for <%s>", path.c_str()); + return; + } + + PolicyTypes policies = pluginPtr->getSupportedPolicyTypes(); + if (policies.empty()) { + LOGE("Plugin <%s> does not support any type!", path.c_str()); + return; + } + for (auto type : policies) { + if (!m_plugins.insert(std::make_pair(type, pluginPtr)).second) { + LOGW("policyType [%" PRIu16 "] was already supported.", type); + } + } + + m_pluginLibs.push_back(std::move(handlePtr)); +} + +} // namespace Cynara + diff --git a/src/service/plugin/PluginManager.h b/src/service/plugin/PluginManager.h new file mode 100644 index 0000000..6338cad --- /dev/null +++ b/src/service/plugin/PluginManager.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file src/service/plugin/PluginManager.h + * @author Zofia Abramowska + * @version 1.0 + * @brief Declaration of PluginManager class + */ + +#ifndef SRC_SERVICE_PLUGIN_PLUGINMANAGER_H_ +#define SRC_SERVICE_PLUGIN_PLUGINMANAGER_H_ + +#include +#include +#include +#include + +#include + +namespace Cynara { +typedef std::shared_ptr ExternalPluginPtr; + +class PluginManager { +public: + PluginManager(const std::string &pluginDir); + ExternalPluginPtr getPlugin(PolicyType pType); + ~PluginManager() {} + +private: + typedef std::unique_ptr> PluginLibPtr; + typedef std::list PluginLibs; + + std::string m_dir; + std::map m_plugins; + PluginLibs m_pluginLibs; + + void loadPlugins(void); + void openPlugin(const std::string &path); +}; + +} // namespace Cynara +#endif /* SRC_SERVICE_PLUGIN_PLUGINMANAGER_H_ */ -- 2.7.4