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 #include <threads.h>
16 #include <pthread.h>
17 #include "ipc_skeleton.h"
18 #include "rpc_log.h"
19 #include "lite_ipc.h"
20 #include "serializer_inner.h"
21 
22 #define IPC_IO_RETURN_IF_FAIL(value)                                             \
23     do {                                                                         \
24         if (!(value)) {                                                          \
25             RPC_LOG_ERROR("IPC_ASSERT_ERR: [%s:%d]\n", __FUNCTION__, __LINE__);  \
26             if (io != NULL) {                                                    \
27                 io->flag |= IPC_IO_OVERFLOW;                                     \
28             }                                                                    \
29             return NULL;                                                         \
30         }                                                                        \
31     } while (0)
32 
33 thread_local uintptr_t g_objectStub = NULL;
34 
GetObjectStub(uintptr_t cookie)35 uintptr_t GetObjectStub(uintptr_t cookie)
36 {
37     if (cookie != NULL) {
38         g_objectStub = cookie;
39     }
40     return g_objectStub;
41 }
42 
IoPushSpecObj(IpcIo * io)43 static SpecialObj* IoPushSpecObj(IpcIo* io)
44 {
45     IPC_IO_RETURN_IF_FAIL(io != NULL);
46     IPC_IO_RETURN_IF_FAIL(io->offsetsCur != NULL);
47     SpecialObj* ptr = IoPush(io, sizeof(SpecialObj));
48     if ((ptr != NULL) && io->offsetsLeft) {
49         io->offsetsLeft--;
50         *(io->offsetsCur) = (char*)ptr - io->bufferBase;
51         io->offsetsCur++;
52         return ptr;
53     } else {
54         io->flag |= IPC_IO_OVERFLOW;
55         return NULL;
56     }
57 }
58 
IoPopSpecObj(IpcIo * io)59 static SpecialObj* IoPopSpecObj(IpcIo* io)
60 {
61     IPC_IO_RETURN_IF_FAIL(io != NULL);
62     IPC_IO_RETURN_IF_FAIL(io->offsetsCur != NULL);
63     if ((io->offsetsLeft == 0) || (*(io->offsetsCur) != io->bufferCur - io->bufferBase)) {
64         goto ERROR;
65     }
66 
67     SpecialObj* obj = IoPop(io, sizeof(SpecialObj));
68     if (obj != NULL) {
69         io->offsetsCur++;
70         io->offsetsLeft--;
71         return obj;
72     }
73 
74 ERROR:
75     io->flag |= IPC_IO_OVERFLOW;
76     return NULL;
77 }
78 
AddList(IpcObjectStub * stub,uint32_t * token,IpcCallback * ipcCallback)79 static int32_t AddList(IpcObjectStub *stub, uint32_t *token, IpcCallback *ipcCallback)
80 {
81     int32_t ret = -1;
82     pthread_mutex_lock(&ipcCallback->mutex);
83     static uint32_t index = 0;
84     AnonymousApi *anonymousApi = (AnonymousApi *)malloc(sizeof(AnonymousApi));
85     if (anonymousApi == NULL) {
86         RPC_LOG_ERROR("anonymousApi malloc failed");
87         pthread_mutex_unlock(&ipcCallback->mutex);
88         return ret;
89     }
90     *token = index++;
91     anonymousApi->token = *token;
92     ret = memcpy_s((char *)&anonymousApi->hdlerPair, sizeof(IpcObjectStub), stub, sizeof(IpcObjectStub));
93     if (ret == 0) {
94         UtilsListAdd(&ipcCallback->apis, &anonymousApi->list);
95         pthread_mutex_unlock(&ipcCallback->mutex);
96         return ret;
97     }
98     RPC_LOG_ERROR("anonymousApi memcpy_s failed");
99     free(anonymousApi);
100     anonymousApi = NULL;
101     pthread_mutex_unlock(&ipcCallback->mutex);
102     return ret;
103 }
104 
WriteRemoteObject(IpcIo * io,const SvcIdentity * svc)105 bool WriteRemoteObject(IpcIo *io, const SvcIdentity *svc)
106 {
107     if (io == NULL) {
108         return false;
109     }
110     if (svc == NULL) {
111         io->flag |= IPC_IO_OVERFLOW;
112         return false;
113     }
114     SpecialObj* ptr = IoPushSpecObj(io);
115     if (ptr == NULL) {
116         return false;
117     }
118     ptr->type = OBJ_SVC;
119     ptr->content.svc.handle = svc->handle;
120     ptr->content.svc.token = svc->token;
121     ptr->content.svc.cookie = svc->cookie;
122     if (ptr->content.svc.handle != IPC_INVALID_HANDLE) {
123         return true;
124     }
125     IpcObjectStub *stub = (IpcObjectStub *)ptr->content.svc.cookie;
126     if (ptr->content.svc.token == SERVICE_TYPE_NORMAL) {
127         g_objectStub = stub;
128     } else if (ptr->content.svc.token == SERVICE_TYPE_ANONYMOUS) {
129         IpcCallback *ipcCallback = GetIpcCb();
130         uint32_t token;
131         int32_t ret = AddList(stub, &token, ipcCallback);
132         if (ret != 0) {
133             RPC_LOG_ERROR("Add list failed.");
134             return false;
135         }
136         ptr->content.svc.token = token;
137         if (!ipcCallback->threadWorking) {
138             pthread_mutex_lock(&ipcCallback->mutex);
139             ret = StartCallbackDispatch();
140             if (ret < 0) {
141                 RPC_LOG_ERROR("WriteRemoteObject StartCallbackDispatch failed.");
142                 pthread_mutex_unlock(&ipcCallback->mutex);
143                 return false;
144             }
145             pthread_mutex_unlock(&ipcCallback->mutex);
146         }
147         ptr->content.svc.handle = GetThreadId();
148     }
149     return true;
150 }
151 
ReadRemoteObject(IpcIo * io,SvcIdentity * svc)152 bool ReadRemoteObject(IpcIo *io, SvcIdentity *svc)
153 {
154     SpecialObj* ptr = IoPopSpecObj(io);
155     if (ptr == NULL || ptr->type != OBJ_SVC) {
156         return false;
157     } else {
158         *svc = ptr->content.svc;
159         WaitForProxyInit(svc);
160         return true;
161     }
162 }
163 
WriteFileDescriptor(IpcIo * io,uint32_t fd)164 bool WriteFileDescriptor(IpcIo *io, uint32_t fd)
165 {
166     SpecialObj* ptr = IoPushSpecObj(io);
167     if (ptr != NULL) {
168         ptr->type = OBJ_FD;
169         ptr->content.fd = fd;
170         return true;
171     }
172     return false;
173 }
174 
ReadFileDescriptor(IpcIo * io)175 int32_t ReadFileDescriptor(IpcIo *io)
176 {
177     SpecialObj* ptr = IoPopSpecObj(io);
178     if (ptr == NULL || ptr->type != OBJ_FD) {
179         return -1;
180     } else {
181         return ptr->content.fd;
182     }
183 }
184