#include <fcntl.h>
#include <arpa/inet.h>
#include <netinet/in.h>
+#include <netinet/tcp.h>
#include <net/if.h>
#include <errno.h>
*/
static CATCPConnectionHandleCallback g_connectionCallback = NULL;
+/**
+ * Error code to hold the errno(Timeout, Destination unreachable, etc) when send/recv fails.
+ * Main purpose is to hold the reason for connection drop when keep-alive is in use.
+ */
+static int g_lastErrorCode;
+
static CASocketFd_t CACreateAcceptSocket(int family, CASocket_t *sock);
static void CAAcceptConnection(CATransportFlags_t flag, CASocket_t *sock);
static void CAFindReadyMessage();
{
if (!g_mutexObjectList)
{
- g_mutexObjectList = oc_mutex_new();
+ g_mutexObjectList = oc_mutex_new_recursive();
if (!g_mutexObjectList)
{
OIC_LOG(ERROR, TAG, "Failed to create mutex!");
len = recv(fd, svritem->tlsdata + svritem->tlsLen, nbRead, 0);
if (len < 0)
{
+ g_lastErrorCode = errno;
+ OIC_LOG_V(DEBUG, TAG, "Set g_lastErrorCode to %s", strerror(g_lastErrorCode));
OIC_LOG_V(ERROR, TAG, "recv failed %s", strerror(errno));
res = CA_RECEIVE_FAILED;
}
len = recv(fd, svritem->tlsdata, TLS_DATA_MAX_SIZE, 0);
if (len < 0)
{
+ g_lastErrorCode = errno;
+ OIC_LOG_V(DEBUG, TAG, "Set g_lastErrorCode to %s", strerror(g_lastErrorCode));
OIC_LOG_V(ERROR, TAG, "recv failed %s", strerror(errno));
res = CA_RECEIVE_FAILED;
}
#endif
if (-1 == len)
{
+ g_lastErrorCode = errno;
+ OIC_LOG_V(DEBUG, TAG, "Set g_lastErrorCode to %s", strerror(g_lastErrorCode));
if (EWOULDBLOCK != errno && EAGAIN != errno)
{
OIC_LOG_V(ERROR, TAG, "unicast ipv4tcp sendTo failed: %s", strerror(errno));
{
g_tcpErrorHandler = errorHandleCallback;
}
+
+CAResult_t CASetKeepAlive(const CAEndpoint_t *endpoint, int time, int cnt, int intvl)
+{
+ OIC_LOG(INFO, TAG, "IN - CATCPSetKeepAlive");
+
+ VERIFY_NON_NULL(endpoint, TAG, "endpoint is NULL");
+
+ size_t index = 0;
+ bool revertKeepAliveSetting = false;
+ CAResult_t result = CA_STATUS_OK;
+ oc_mutex_lock(g_mutexObjectList);
+ CATCPSessionInfo_t *svritem = CAGetTCPSessionInfoFromEndpoint(endpoint, &index);
+ if (!svritem)
+ {
+ // There is no connection with the given endpoint, so the parameter is considered to be invalid.
+ result = CA_STATUS_INVALID_PARAM;
+ goto exit;
+ }
+
+ if (svritem->fd < 0 || svritem->state != CONNECTED)
+ {
+ result = CA_DESTINATION_DISCONNECTED;
+ goto exit;
+ }
+
+ int option = 1;
+ if (-1 == setsockopt(svritem->fd, SOL_SOCKET, SO_KEEPALIVE, &option, sizeof(option)))
+ {
+ OIC_LOG_V(ERROR, TAG, "setsockopt SO_KEEPALIVE failed on socket(%d): %s",
+ svritem->fd, strerror(errno));
+ result = CA_SOCKET_OPERATION_FAILED;
+ goto exit;
+ }
+
+ if (-1 == setsockopt(svritem->fd, SOL_TCP, TCP_KEEPIDLE, &time, sizeof(time)))
+ {
+ OIC_LOG_V(ERROR, TAG, "setsockopt TCP_KEEPIDLE failed on socket(%d): %s",
+ svritem->fd, strerror(errno));
+ revertKeepAliveSetting = true;
+ result = CA_SOCKET_OPERATION_FAILED;
+ goto exit;
+ }
+
+ if (-1 == setsockopt(svritem->fd, SOL_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt)))
+ {
+ OIC_LOG_V(ERROR, TAG, "setsockopt TCP_KEEPCNT failed on socket(%d): %s",
+ svritem->fd, strerror(errno));
+ revertKeepAliveSetting = true;
+ result = CA_SOCKET_OPERATION_FAILED;
+ goto exit;
+ }
+
+ if (-1 == setsockopt(svritem->fd, SOL_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl)))
+ {
+ OIC_LOG_V(ERROR, TAG, "setsockopt TCP_KEEPINTVL failed on socket(%d): %s",
+ svritem->fd, strerror(errno));
+ revertKeepAliveSetting = true;
+ result = CA_SOCKET_OPERATION_FAILED;
+ }
+
+exit:
+ if (revertKeepAliveSetting)
+ {
+ // Unset SO_KEEPALIVE
+ option = 0;
+ if (-1 == setsockopt(svritem->fd, SOL_SOCKET, SO_KEEPALIVE, &option, sizeof(option)))
+ {
+ OIC_LOG_V(ERROR, TAG, "unset SO_KEEPALIVE failed on socket(%d): %s",
+ svritem->fd, strerror(errno));
+ }
+ }
+ oc_mutex_unlock(g_mutexObjectList);
+ OIC_LOG(INFO, TAG, "OUT - CATCPSetKeepAlive");
+ return result;
+}
+
+CAResult_t CAUnSetKeepAlive(const CAEndpoint_t *endpoint)
+{
+ OIC_LOG(INFO, TAG, "IN - CATCPUnSetKeepAlive");
+
+ VERIFY_NON_NULL(endpoint, TAG, "endpoint is NULL");
+
+ size_t index = 0;
+ CAResult_t result = CA_STATUS_OK;
+ oc_mutex_lock(g_mutexObjectList);
+ CATCPSessionInfo_t *svritem = CAGetTCPSessionInfoFromEndpoint(endpoint, &index);
+ if (!svritem)
+ {
+ // There is no connection with the given endpoint, so the parameter is considered to be invalid.
+ result = CA_STATUS_INVALID_PARAM;
+ goto exit;
+ }
+
+ if (svritem->fd < 0 || svritem->state != CONNECTED)
+ {
+ result = CA_DESTINATION_DISCONNECTED;
+ goto exit;
+ }
+
+ int option = 0;
+ if (-1 == setsockopt(svritem->fd, SOL_SOCKET, SO_KEEPALIVE, &option, sizeof(option)))
+ {
+ OIC_LOG_V(ERROR, TAG, "setsockopt SO_KEEPALIVE failed on socket(%d): %s",
+ svritem->fd, strerror(errno));
+ result = CA_SOCKET_OPERATION_FAILED;
+ }
+
+exit:
+ oc_mutex_unlock(g_mutexObjectList);
+ OIC_LOG(INFO, TAG, "OUT - CATCPUnSetKeepAlive");
+ return result;
+}
+
+int CAGetLastErrorCode()
+{
+ return g_lastErrorCode;
+}