1/*
2 * Copyright (C) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "rpc_session_handle.h"
17
18#include <stdlib.h>
19#include <errno.h>
20#include <sys/time.h>
21
22#include "rpc_log.h"
23#include "rpc_errno.h"
24
25static int32_t GetWaitTime(struct timespec *waitTime)
26{
27#define USECTONSEC 1000
28    struct timeval now;
29    if (gettimeofday(&now, NULL) != 0) {
30        RPC_LOG_ERROR("gettimeofday failed");
31        return ERR_FAILED;
32    }
33    waitTime->tv_sec = now.tv_sec + CONNECT_WAIT_TIME_SECONDS;
34    waitTime->tv_nsec = now.tv_usec * USECTONSEC;
35
36    return ERR_NONE;
37}
38
39static SessionIdList *FindOrNewSessionIdObject(SessionIdList *sessionIdList, int32_t sessionId)
40{
41    RPC_LOG_INFO("FindOrNewSessionIdObject sessionId=%d", sessionId);
42    if (sessionIdList == NULL) {
43        RPC_LOG_ERROR("FindOrNewSessionIdObject sessionIdList is null");
44        return NULL;
45    }
46    pthread_mutex_lock(&sessionIdList->mutex);
47    SessionIdList *node = NULL;
48    UTILS_DL_LIST_FOR_EACH_ENTRY(node, &sessionIdList->idList, SessionIdList, idList)
49    {
50        if (node->sessionId == sessionId) {
51            RPC_LOG_INFO("find sessionId in sessionIdList");
52            pthread_mutex_unlock(&sessionIdList->mutex);
53            return node;
54        }
55    }
56
57    node = (SessionIdList *)malloc(sizeof(SessionIdList));
58    if (node == NULL) {
59        RPC_LOG_ERROR("FindOrNewSessionIdObject malloc failed");
60        pthread_mutex_unlock(&sessionIdList->mutex);
61        return NULL;
62    }
63    memset_s(node, sizeof(SessionIdList), 0, sizeof(SessionIdList));
64    (void)pthread_mutex_init(&node->mutex, NULL);
65    (void)pthread_cond_init(&node->condition, NULL);
66    node->sessionId = sessionId;
67    node->isReady = false;
68
69    UtilsListAdd(&sessionIdList->idList, &node->idList);
70    pthread_mutex_unlock(&sessionIdList->mutex);
71    return node;
72}
73
74int32_t WaitForSessionIdReady(SessionIdList *sessionIdList, int32_t sessionId)
75{
76    if (sessionIdList == NULL) {
77        RPC_LOG_ERROR("WaitForSessionIdReady sessionIdList is null");
78        return ERR_FAILED;
79    }
80    if (sessionId <= 0) {
81        RPC_LOG_ERROR("invalid sessionid %d", sessionId);
82        return ERR_FAILED;
83    }
84    SessionIdList *sessionIdObject = FindOrNewSessionIdObject(sessionIdList, sessionId);
85    if (sessionIdObject == NULL) {
86        RPC_LOG_ERROR("FindOrNewSessionIdObject return null");
87        return ERR_FAILED;
88    }
89    pthread_mutex_lock(&sessionIdObject->mutex);
90    if (sessionIdObject->isReady) {
91        pthread_mutex_unlock(&sessionIdObject->mutex);
92        return ERR_NONE;
93    }
94
95    struct timespec waitTime;
96    if (GetWaitTime(&waitTime) != ERR_NONE) {
97        pthread_mutex_unlock(&sessionIdObject->mutex);
98        return ERR_FAILED;
99    }
100
101    if (pthread_cond_timedwait(&sessionIdObject->condition,
102        &sessionIdObject->mutex, &waitTime) == ETIMEDOUT) {
103        RPC_LOG_ERROR("WaitForSessionIdReady timeout");
104        pthread_mutex_unlock(&sessionIdObject->mutex);
105        return ERR_FAILED;
106    }
107
108    RPC_LOG_INFO("WaitForSessionIdReady wakeup!");
109    int32_t ret = sessionIdObject->isReady ? ERR_NONE : ERR_FAILED;
110    pthread_mutex_unlock(&sessionIdObject->mutex);
111    return ret;
112}
113
114int32_t HandleNewConnection(SessionIdList *sessionIdList, int32_t sessionId)
115{
116    if (sessionIdList == NULL) {
117        RPC_LOG_ERROR("HandleNewConnection sessionIdList is null");
118        return ERR_FAILED;
119    }
120    if (sessionId <= 0) {
121        return ERR_FAILED;
122    }
123
124    SessionIdList *sessionIdObject = FindOrNewSessionIdObject(sessionIdList, sessionId);
125    if (sessionIdObject == NULL) {
126        RPC_LOG_ERROR("HandleNewConnection get sessionIdObject null");
127        return ERR_FAILED;
128    }
129
130    pthread_mutex_lock(&sessionIdObject->mutex);
131    if (!sessionIdObject->isReady) {
132        sessionIdObject->isReady = true;
133        pthread_cond_broadcast(&sessionIdObject->condition);
134        RPC_LOG_INFO("HandleNewConnection broadcast thread, sessionId=%d", sessionId);
135    }
136    pthread_mutex_unlock(&sessionIdObject->mutex);
137    return ERR_NONE;
138}