1 /*
2 * Copyright (C) 2021-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 "client.h"
17 #include <pthread.h>
18 #include <securec.h>
19 #include <signal.h>
20 #include <string.h>
21 #include <sys/un.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include "common.h"
25 #include "log.h"
26 #include "net.h"
27
28 #undef LOG_TAG
29 #define LOG_TAG "WifiRpcClient"
30
31 const int FD_CHECK_TIMEOUT = 1000; /* poll wait time, units: ms */
32 const int CLIENT_STATE_IDLE = 0;
33 const int CLIENT_STATE_DEAL_REPLY = 1;
34 const int CLIENT_STATE_EXIT = 2;
35
36 #define TMP_BUFF_SIZE 16
37
38 static void *RpcClientThreadDeal(void *arg);
39
RpcClientReadMsg(RpcClient * client)40 static char *RpcClientReadMsg(RpcClient *client)
41 {
42 if (client == NULL) {
43 return NULL;
44 }
45
46 char *buff = ContextGetReadRecord(client->context);
47 while (buff == NULL && client->threadRunFlag) {
48 int ret = WaitFdEvent(client->context->fd, READ_EVENT, FD_CHECK_TIMEOUT);
49 if (ret < 0) {
50 LOGE("wait server reply message failed!");
51 client->threadRunFlag = 0;
52 return NULL;
53 } else if (ret == 0) {
54 continue;
55 }
56 ret = ContextReadNet(client->context);
57 if (ret < 0) {
58 LOGE("read server reply message failed!");
59 client->threadRunFlag = 0;
60 return NULL;
61 }
62 buff = ContextGetReadRecord(client->context);
63 }
64 if (!client->threadRunFlag) {
65 if (buff != NULL) {
66 free(buff);
67 buff = NULL;
68 }
69 return NULL;
70 }
71 return buff;
72 }
73
RpcClientDealReadMsg(RpcClient * client,char * buff)74 static void RpcClientDealReadMsg(RpcClient *client, char *buff)
75 {
76 if (client == NULL) {
77 return;
78 }
79
80 char szTmp[TMP_BUFF_SIZE] = {0};
81 if (snprintf_s(szTmp, sizeof(szTmp), sizeof(szTmp) - 1, "N%c", client->context->cSplit) < 0) {
82 return;
83 }
84 if (strncmp(buff, szTmp, strlen(szTmp)) == 0) { /* deal reply message */
85 pthread_mutex_lock(&client->mutex);
86 client->waitReply = CLIENT_STATE_DEAL_REPLY;
87 client->context->oneProcess = buff;
88 client->context->nPos = strlen(szTmp);
89 client->context->nSize = strlen(buff);
90 pthread_cond_signal(&client->condW);
91 pthread_mutex_unlock(&client->mutex);
92 } else { /* deal callback message */
93 pthread_mutex_lock(&client->mutex);
94 while (client->waitReply == CLIENT_STATE_DEAL_REPLY) {
95 pthread_cond_wait(&client->condW, &client->mutex);
96 }
97 pthread_mutex_unlock(&client->mutex);
98 client->context->oneProcess = buff;
99 client->context->nPos = strlen(szTmp);
100 client->context->nSize = strlen(buff);
101 OnTransact(client->context);
102 free(buff);
103 buff = NULL;
104 }
105 return;
106 }
107
RpcClientThreadDeal(void * arg)108 static void *RpcClientThreadDeal(void *arg)
109 {
110 RpcClient *client = (RpcClient *)arg;
111 if (client == NULL) {
112 return NULL;
113 }
114
115 while (client->threadRunFlag) {
116 char *buff = RpcClientReadMsg(client);
117 if (buff == NULL) {
118 continue;
119 }
120 RpcClientDealReadMsg(client, buff);
121 }
122 pthread_mutex_lock(&client->mutex);
123 client->waitReply = CLIENT_STATE_EXIT;
124 pthread_cond_signal(&client->condW);
125 pthread_mutex_unlock(&client->mutex);
126 LOGI("Client read message thread exiting!");
127 return NULL;
128 }
129
CreateRpcClient(const char * path)130 RpcClient *CreateRpcClient(const char *path)
131 {
132 int fd = ConnectUnixServer(path);
133 if (fd < 0) {
134 return NULL;
135 }
136 SetNonBlock(fd, 1);
137 RpcClient *client = (RpcClient *)calloc(1, sizeof(RpcClient));
138 if (client == NULL) {
139 close(fd);
140 return NULL;
141 }
142 client->context = CreateContext(CONTEXT_BUFFER_MIN_SIZE);
143 if (client->context == NULL) {
144 close(fd);
145 free(client);
146 client = NULL;
147 return NULL;
148 }
149 client->context->fd = fd;
150 client->threadRunFlag = 1;
151 client->threadId = 0;
152 client->waitReply = CLIENT_STATE_IDLE;
153 client->callLockFlag = 0;
154 pthread_mutex_init(&client->mutex, NULL);
155 pthread_cond_init(&client->condW, NULL);
156 pthread_mutex_init(&client->lockMutex, NULL);
157 pthread_cond_init(&client->lockCond, NULL);
158 int ret = pthread_create(&client->threadId, NULL, RpcClientThreadDeal, client);
159 if (ret) {
160 pthread_cond_destroy(&client->condW);
161 pthread_mutex_destroy(&client->mutex);
162 pthread_cond_destroy(&client->lockCond);
163 pthread_mutex_destroy(&client->lockMutex);
164 ReleaseContext(client->context);
165 close(fd);
166 free(client);
167 client = NULL;
168 return NULL;
169 }
170 signal(SIGPIPE, SIG_IGN);
171 return client;
172 }
173
ReleaseRpcClient(RpcClient * client)174 void ReleaseRpcClient(RpcClient *client)
175 {
176 if (client != NULL) {
177 if (client->threadId != 0) {
178 client->threadRunFlag = 0;
179 pthread_join(client->threadId, NULL);
180 }
181 pthread_cond_destroy(&client->condW);
182 pthread_mutex_destroy(&client->mutex);
183 pthread_cond_destroy(&client->lockCond);
184 pthread_mutex_destroy(&client->lockMutex);
185 close(client->context->fd);
186 ReleaseContext(client->context);
187 free(client);
188 client = NULL;
189 }
190 return;
191 }
192
RemoteCall(RpcClient * client)193 int RemoteCall(RpcClient *client)
194 {
195 if (client == NULL) {
196 return -1;
197 }
198 if (client->waitReply == CLIENT_STATE_EXIT) {
199 return -1;
200 }
201 int ret = 0;
202 Context *context = client->context;
203 while (context->wBegin != context->wEnd && ret >= 0) {
204 ret = ContextWriteNet(context);
205 }
206 if (ret < 0) {
207 return ret;
208 }
209 ret = 0; /* reset ret value */
210 pthread_mutex_lock(&client->mutex);
211 while (client->waitReply != CLIENT_STATE_DEAL_REPLY && client->waitReply != CLIENT_STATE_EXIT) {
212 pthread_cond_wait(&client->condW, &client->mutex);
213 }
214 if (client->waitReply == CLIENT_STATE_EXIT) {
215 ret = -1;
216 }
217 pthread_mutex_unlock(&client->mutex);
218 return ret;
219 }
220
ReadClientEnd(RpcClient * client)221 void ReadClientEnd(RpcClient *client)
222 {
223 if (client == NULL) {
224 return;
225 }
226
227 pthread_mutex_lock(&client->mutex);
228 free(client->context->oneProcess);
229 client->context->oneProcess = NULL;
230 if (client->waitReply == CLIENT_STATE_DEAL_REPLY) {
231 client->waitReply = CLIENT_STATE_IDLE;
232 }
233 pthread_cond_signal(&client->condW);
234 pthread_mutex_unlock(&client->mutex);
235 return;
236 }
237
LockRpcClient(RpcClient * client)238 void LockRpcClient(RpcClient *client)
239 {
240 if (client == NULL) {
241 return;
242 }
243
244 pthread_mutex_lock(&client->lockMutex);
245 while (client->callLockFlag != 0) {
246 pthread_cond_wait(&client->lockCond, &client->lockMutex);
247 }
248 client->callLockFlag = 1;
249 pthread_mutex_unlock(&client->lockMutex);
250 return;
251 }
252
UnlockRpcClient(RpcClient * client)253 void UnlockRpcClient(RpcClient *client)
254 {
255 if (client == NULL) {
256 return;
257 }
258
259 pthread_mutex_lock(&client->lockMutex);
260 client->callLockFlag = 0;
261 pthread_cond_signal(&client->lockCond);
262 pthread_mutex_unlock(&client->lockMutex);
263 return;
264 }
265