#include <cynara-admin-error.h>
#include <common.h>
-#include <exceptions/ServerConnectionErrorException.h>
+#include <exceptions/Exception.h>
+#include <exceptions/UnexpectedErrorException.h>
#include <log/log.h>
#include <protocol/Protocol.h>
#include <protocol/ProtocolAdmin.h>
return ++sequenceNumber;
}
+bool Logic::ensureConnection(void) {
+ return m_socketClient->isConnected() || m_socketClient->connect();
+}
+
template<typename T, typename... Args>
int Logic::askCynaraAndInterpreteCodeResponse(Args... args) {
- ProtocolFrameSequenceNumber sequenceNumber = generateSequenceNumber();
-
- //Ask cynara service
- CodeResponsePtr codeResponse;
try {
- RequestPtr request = std::make_shared<T>(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<T>(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<CodeResponse>(response);
if (!codeResponse) {
LOGC("Critical error. Casting Response to CodeResponse failed.");
static_cast<int>(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;
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<AdminCheckRequest>(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<CheckResponse>(response);
if (!checkResponse) {
LOGC("Casting Response to CheckResponse failed.");
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;
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
private:
SocketClientPtr m_socketClient;
+ bool ensureConnection(void);
template<typename T, typename... Args>
int askCynaraAndInterpreteCodeResponse(Args... args);
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})
--- /dev/null
+/*
+ * 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 <m.niesluchow@samsung.com>
+ * @version 1.0
+ * @brief This file contains definition of cynara's socket asynchronous
+ * client
+ */
+
+#include <request/Request.h>
+#include <request/RequestContext.h>
+
+#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<RequestContext>(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
--- /dev/null
+/*
+ * 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 <m.niesluchow@samsung.com>
+ * @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 <memory>
+#include <string>
+
+#include <containers/BinaryQueue.h>
+#include <protocol/Protocol.h>
+#include <request/pointers.h>
+#include <response/pointers.h>
+#include <sockets/Socket.h>
+
+namespace Cynara {
+
+class SocketClientAsync;
+typedef std::shared_ptr<SocketClientAsync> 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_ */
#include <functional>
#include <new>
+#include <exceptions/NoMemoryException.h>
#include <log/log.h>
#include <cynara-client-error.h>
} 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;
#include <cache/CapacityCache.h>
#include <common.h>
#include <cynara-client-error.h>
-#include <exceptions/ServerConnectionErrorException.h>
+#include <exceptions/Exception.h>
+#include <exceptions/UnexpectedErrorException.h>
#include <log/log.h>
#include <plugins/NaiveInterpreter.h>
#include <protocol/Protocol.h>
}
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;
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<CheckRequest>(key, sequenceNumber);
- ResponsePtr response = m_socket->askCynaraServer(request);
- if (!response) {
- LOGW("Disconnected by cynara server.");
+ RequestPtr request = std::make_shared<CheckRequest>(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<CheckResponse>(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<CheckResponse>(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;
}
PluginCachePtr m_cache;
void onDisconnected(void);
+ bool ensureConnection(void);
int requestResult(const PolicyKey &key, PolicyResult &result);
public:
Logic();
* limitations under the License.
*/
/**
- * @file src/common/exceptions/ServerConnectionErrorException.h
- * @author Lukasz Wojciechowski <l.wojciechow@partner.samsung.com>
+ * @file src/common/exceptions/NoMemoryException.h
+ * @author Marcin Niesluchowski <m.niesluchow@samsung.com>
* @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 <sstream>
+#include <string>
-#include <exception>
+#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_ */
#include <sys/un.h>
#include <unistd.h>
-#include <containers/BinaryQueue.h>
-#include <containers/RawBuffer.h>
#include <exceptions/InitException.h>
-#include <exceptions/ServerConnectionErrorException.h>
+#include <exceptions/NoMemoryException.h>
#include <exceptions/UnexpectedErrorException.h>
#include <log/log.h>
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() {
if (m_sock > -1)
::close(m_sock);
m_sock = -1;
+ m_sendBufferPos = 0;
+ m_sendBufferEnd = 0;
+ m_sendQueue.clear();
}
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");
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));
}
}
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;
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));
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<size_t>(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_t>(size));
+ }
}
} // namespace Cynara
* @file src/common/sockets/Socket.h
* @author Bartlomiej Grzelewski <b.grzelewski@samsung.com>
* @author Lukasz Wojciechowski <l.wojciechow@partner.samsung.com>
+ * @author Marcin Niesluchowski <m.niesluchow@samsung.com>
* @version 1.0
* @brief This file contains definition of UNIX client socket class
*/
#include <string>
#include <containers/BinaryQueue.h>
+#include <containers/RawBuffer.h>
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
//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();
//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);
};
: 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<RequestContext>(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);
}
}
-bool SocketClient::isConnected(void) {
- return m_socket.isConnected() && m_socket.receiveFromServer(m_readQueue);
-}
-
} // namespace Cynara
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