diff --git a/interfaces/innerkits/c/BUILD.gn b/interfaces/innerkits/c/BUILD.gn index 91f56900bd6d4a43d2b8cc0a9b23b627d4d7c5d4..68719c118539bb6b4564d6e73f117e1de8717b70 100644 --- a/interfaces/innerkits/c/BUILD.gn +++ b/interfaces/innerkits/c/BUILD.gn @@ -14,10 +14,18 @@ import("//build/lite/config/component/lite_component.gni") lite_component("rpc") { - features = [ "ipc:ipc_single" ] + features = [ + "ipc:rpc_manager", + "dbinder:dbinder", + ] + if (ohos_kernel_type != "liteos_m") { + features += [ "ipc:ipc_single" ] + } + if (ohos_build_type == "debug") { features += [ "//foundation/communication/ipc/ipc/test/unittest/ipc:ipc_test_gtest", + "//foundation/communication/ipc/ipc/test/rpc:rpc_test", ] } } diff --git a/interfaces/innerkits/c/dbinder/BUILD.gn b/interfaces/innerkits/c/dbinder/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..bcd94135465b313ec4e610ee835d8ea1138a2d11 --- /dev/null +++ b/interfaces/innerkits/c/dbinder/BUILD.gn @@ -0,0 +1,81 @@ +# Copyright (c) 2020 Huawei Device Co., Ltd. +# 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. + +import("//build/lite/config/component/lite_component.gni") + +SUBSYSTEM_DIR = "//foundation/communication/ipc" +DBINDER_ROOT = "$SUBSYSTEM_DIR/services/dbinder/c" + +config("ipc_rpc_interface") { + include_dirs = [ + "$SUBSYSTEM_DIR/interfaces/innerkits/c/ipc/include", + "$SUBSYSTEM_DIR/interfaces/innerkits/c/dbinder/include", + ] +} +if (ohos_kernel_type == "linux") { + SYSTEM_LEVEL = "small" + shared_library("dbinder") { + sources = [ + "$DBINDER_ROOT/ipc_adapter/${SYSTEM_LEVEL}/dbinder_ipc_adapter.c", + "$DBINDER_ROOT/src/dbinder_service.c", + "$DBINDER_ROOT/src/dbinder_stub.c", + "$DBINDER_ROOT/src/dbinder_trans_callback.c", + ] + public_configs = [ ":ipc_rpc_interface" ] + include_dirs = [ + "$DBINDER_ROOT/include", + "$DBINDER_ROOT/ipc_adapter/include", + "$SUBSYSTEM_DIR/ipc/native/c/ipc/include", + "$SUBSYSTEM_DIR/ipc/native/c/rpc/include", + "$SUBSYSTEM_DIR/ipc/native/c/rpc/ipc_adapter/include", + "$SUBSYSTEM_DIR/ipc/native/c/rpc/trans_adapter/include", + "$SUBSYSTEM_DIR/ipc/native/c/manager/include", + "//third_party/bounds_checking_function/include", + "//utils/native/lite/include", + ] + ldflags = [ + "-lstdc++", + "-lpthread", + ] + public_deps = [ + "$SUBSYSTEM_DIR/interfaces/innerkits/c/ipc:rpc_log", + "//third_party/bounds_checking_function/:libsec_shared", + ] + } +} else if (ohos_kernel_type == "liteos_m") { + SYSTEM_LEVEL = "mini" + static_library("dbinder") { + sources = [ + "$DBINDER_ROOT/ipc_adapter/${SYSTEM_LEVEL}/dbinder_ipc_adapter.c", + "$DBINDER_ROOT/src/dbinder_service.c", + "$DBINDER_ROOT/src/dbinder_stub.c", + "$DBINDER_ROOT/src/dbinder_trans_callback.c", + ] + public_configs = [ ":ipc_rpc_interface" ] + include_dirs = [ + "$DBINDER_ROOT/include", + "$DBINDER_ROOT/ipc_adapter/include", + "$SUBSYSTEM_DIR/ipc/native/c/ipc/include", + "$SUBSYSTEM_DIR/ipc/native/c/rpc/include", + "$SUBSYSTEM_DIR/ipc/native/c/rpc/ipc_adapter/include", + "$SUBSYSTEM_DIR/ipc/native/c/rpc/trans_adapter/include", + "$SUBSYSTEM_DIR/ipc/native/c/manager/include", + "$SUBSYSTEM_DIR/ipc/test/rpc/include", + "//third_party/bounds_checking_function/include", + "//utils/native/lite/include", + "//base/hiviewdfx/hilog_lite/interfaces/native/kits/hilog_lite", + ] + ldflags = [ "-lpthread" ] + deps = [ "//foundation/communication/ipc/ipc/native/c/adapter:rpc_adapter" ] + } +} diff --git a/interfaces/innerkits/c/dbinder/include/dbinder_service.h b/interfaces/innerkits/c/dbinder/include/dbinder_service.h new file mode 100644 index 0000000000000000000000000000000000000000..9b424467775dc6e80a25bb12c892980027590909 --- /dev/null +++ b/interfaces/innerkits/c/dbinder/include/dbinder_service.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef DBINDER_SERVICE_H +#define DBINDER_SERVICE_H + +#include +#include +#include +#include + +#include "dbinder_types.h" +#include "utils_list.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif + +typedef struct { + struct DHandleEntryHead head; + uint32_t transType; + uint32_t dBinderCode; + uint16_t fromPort; + uint16_t toPort; + uint64_t stubIndex; + uint32_t seqNumber; + uintptr_t binderObject; + struct DeviceIdInfo deviceIdInfo; + uintptr_t stub; + uint16_t serviceNameLength; + char serviceName[SERVICENAME_LENGTH + 1]; + uint32_t pid; + uint32_t uid; +} DHandleEntryTxRx; + +int32_t StartDBinderService(void); +int32_t RegisterRemoteProxy(const void *name, uint32_t len, int32_t systemAbility); +int32_t MakeRemoteBinder(const void *serviceName, uint32_t nameLen, const char *deviceID, uint32_t idLen, + uintptr_t binderObject, uint64_t pid, void *remoteObject); +int32_t OnRemoteMessageTask(const DHandleEntryTxRx *message); +SessionInfo *QuerySessionObject(uintptr_t stub); +void DetachProxyObject(ProxyObject *proxy); + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ +#endif /* DBINDER_SERVICE_H */ \ No newline at end of file diff --git a/interfaces/innerkits/c/ipc/BUILD.gn b/interfaces/innerkits/c/ipc/BUILD.gn index 6723a5e126045f5303a9310afcaea98f65a9101e..96617390140b0b42bf0fd53777826d6bade0a493 100644 --- a/interfaces/innerkits/c/ipc/BUILD.gn +++ b/interfaces/innerkits/c/ipc/BUILD.gn @@ -17,7 +17,10 @@ SUBSYSTEM_DIR = "//foundation/communication/ipc" IPC_CORE_ROOT = "$SUBSYSTEM_DIR/ipc/native/c" config("ipc_rpc_interface") { - include_dirs = [ "$SUBSYSTEM_DIR/interfaces/innerkits/c/ipc/include" ] + include_dirs = [ + "$SUBSYSTEM_DIR/interfaces/innerkits/c/ipc/include", + "$SUBSYSTEM_DIR/interfaces/innerkits/c/dbinder/include", + ] } if (ohos_kernel_type == "liteos_m") { @@ -45,14 +48,40 @@ ipc_common_src = [ ] if (ohos_kernel_type == "liteos_m") { - static_library("ipc_single") { + SYSTEM_LEVEL = "mini" + static_library("rpc_manager") { sources = ipc_common_src sources += [ "$IPC_CORE_ROOT/ipc/src/binder_invoker_virtual.c", "$IPC_CORE_ROOT/manager/src/rpc_log.c", + "$IPC_CORE_ROOT/rpc/ipc_adapter/${SYSTEM_LEVEL}/ipc_proxy_inner.c", + "$IPC_CORE_ROOT/rpc/ipc_adapter/${SYSTEM_LEVEL}/ipc_stub_inner.c", + "$IPC_CORE_ROOT/rpc/src/dbinder_invoker.c", + "$IPC_CORE_ROOT/rpc/src/rpc_process_skeleton.c", + "$IPC_CORE_ROOT/rpc/src/rpc_trans_callback.c", + "$IPC_CORE_ROOT/rpc/trans_adapter/src/rpc_trans.c", ] - include_dirs = ipc_common_include public_configs = [ ":ipc_rpc_interface" ] + include_dirs = ipc_common_include + include_dirs += [ + "$IPC_CORE_ROOT/rpc/include", + "$IPC_CORE_ROOT/rpc/ipc_adapter/include", + "$IPC_CORE_ROOT/rpc/trans_adapter/include", + "$SUBSYSTEM_DIR/services/dbinder/c/include", + ] + if (ohos_build_type == "debug") { + sources += [ + "$SUBSYSTEM_DIR/ipc/test/rpc/samgr/rpc_mini_samgr.c", + "$SUBSYSTEM_DIR/ipc/test/rpc/socket_trans/src/rpc_${SYSTEM_LEVEL}_socket_trans.c", + ] + include_dirs += [ + "$SUBSYSTEM_DIR/ipc/test/rpc/include", + "$SUBSYSTEM_DIR/ipc/test/rpc/socket_trans/include", + "//third_party/lwip/src/include", + ] + defines = [ "RPC_SOCKET_TRANS" ] + } + ldflags = [ "-lpthread" ] deps = [ "//foundation/communication/ipc/ipc/native/c/adapter:rpc_adapter" ] } } else if (ohos_kernel_type == "liteos_a") { @@ -85,6 +114,9 @@ if (ohos_kernel_type == "liteos_m") { "//third_party/bounds_checking_function/:libsec_shared", ] } + + shared_library("rpc_manager") { + } } else { shared_library("rpc_log") { sources = [ "$IPC_CORE_ROOT/manager/src/rpc_log.c" ] @@ -100,9 +132,17 @@ if (ohos_kernel_type == "liteos_m") { shared_library("ipc_single") { sources = ipc_common_src - sources += [ "$IPC_CORE_ROOT/ipc/src/binder_invoker.c" ] + sources += [ + "$IPC_CORE_ROOT/ipc/src/binder_invoker.c", + "$IPC_CORE_ROOT/rpc/src/rpc_process_skeleton_virtual.c", + ] public_configs = [ ":ipc_rpc_interface" ] include_dirs = ipc_common_include + include_dirs += [ + "$IPC_CORE_ROOT/rpc/include", + "$IPC_CORE_ROOT/rpc/trans_adapter/include", + "$SUBSYSTEM_DIR/services/dbinder/c/include", + ] ldflags = [ "-lstdc++", "-lpthread", @@ -116,4 +156,45 @@ if (ohos_kernel_type == "liteos_m") { ] configs -= [ "//build/lite/config:clang_opt" ] } + + SYSTEM_LEVEL = "small" + shared_library("rpc_manager") { + sources = ipc_common_src + sources += [ + "$IPC_CORE_ROOT/ipc/src/binder_invoker.c", + "$IPC_CORE_ROOT/rpc/ipc_adapter/${SYSTEM_LEVEL}/ipc_proxy_inner.c", + "$IPC_CORE_ROOT/rpc/ipc_adapter/${SYSTEM_LEVEL}/ipc_stub_inner.c", + "$IPC_CORE_ROOT/rpc/src/dbinder_invoker.c", + "$IPC_CORE_ROOT/rpc/src/rpc_process_skeleton.c", + "$IPC_CORE_ROOT/rpc/src/rpc_trans_callback.c", + "$IPC_CORE_ROOT/rpc/trans_adapter/src/rpc_trans.c", + ] + public_configs = [ ":ipc_rpc_interface" ] + include_dirs = ipc_common_include + include_dirs += [ + "$IPC_CORE_ROOT/rpc/include", + "$IPC_CORE_ROOT/rpc/ipc_adapter/include", + "$IPC_CORE_ROOT/rpc/trans_adapter/include", + "$SUBSYSTEM_DIR/services/dbinder/c/include", + "//third_party/bounds_checking_function/include", + ] + ldflags = [ + "-lstdc++", + "-lpthread", + ] + cflags = [ "-fPIC" ] + cflags_cc = cflags + public_deps = [ + ":rpc_log", + "//foundation/communication/ipc/ipc/native/c/adapter:rpc_adapter", + "//third_party/bounds_checking_function/:libsec_shared", + ] + + if (ohos_build_type == "debug") { + sources += + [ "$SUBSYSTEM_DIR/ipc/test/rpc/socket_trans/src/rpc_socket_trans.c" ] + include_dirs += [ "$SUBSYSTEM_DIR/ipc/test/rpc/socket_trans/include" ] + defines = [ "RPC_SOCKET_TRANS" ] + } + } } diff --git a/ipc/native/c/manager/include/ipc_thread_pool.h b/ipc/native/c/manager/include/ipc_thread_pool.h index 5ae73d865c64e2f8831bc005257285b5d3d31b67..90cffecf56d40b588c5f16d66ce5e73c1a0759da 100644 --- a/ipc/native/c/manager/include/ipc_thread_pool.h +++ b/ipc/native/c/manager/include/ipc_thread_pool.h @@ -22,6 +22,7 @@ #include "ipc_skeleton.h" #include "iremote_invoker.h" +#include "dbinder_types.h" #ifdef __cplusplus #if __cplusplus @@ -43,7 +44,7 @@ typedef struct { IpcObjectStub *objectStub; pid_t callerPid; pid_t callerUid; - char callerDeviceID[64]; + char callerDeviceID[DEVICEID_LENGTH + 1]; bool stopWorkThread; uint64_t seqNumber; uint32_t clientFd; diff --git a/ipc/native/c/manager/src/ipc_process_skeleton.c b/ipc/native/c/manager/src/ipc_process_skeleton.c index c3f976055a1d2accd317a80ea8c16e48dd6dfd2d..c71b8874153085c332fdba6ed7824265f6502aef 100644 --- a/ipc/native/c/manager/src/ipc_process_skeleton.c +++ b/ipc/native/c/manager/src/ipc_process_skeleton.c @@ -20,6 +20,7 @@ #include "rpc_errno.h" #include "rpc_log.h" #include "rpc_os_adapter.h" +#include "rpc_process_skeleton.h" #include "rpc_types.h" #include "securec.h" #include "utils_list.h" @@ -81,6 +82,10 @@ IpcSkeleton *GetCurrentSkeleton(void) return NULL; } g_ipcSkeleton = temp; + int32_t ret = RpcProcessSkeleton(); + if (ret != ERR_NONE) { + RPC_LOG_ERROR("rpc process skeleton init failed"); + } } pthread_mutex_unlock(&g_ipcSkeletonMutex); } @@ -265,7 +270,7 @@ static uint32_t SetDeathHandlerPair(DeathCallback *node, uint32_t index, OnRemot int32_t ProcessAddDeathRecipient(int32_t handle, OnRemoteDead deathFunc, void *args, uint32_t *cbId) { - int32_t ret = ERR_INVALID_PARAM; + int32_t ret = ERR_NONE; if (g_ipcSkeleton == NULL) { return ERR_IPC_SKELETON_NOT_INIT; } @@ -359,6 +364,7 @@ int32_t ProcessRemoveDeathRecipient(int32_t handle, uint32_t cbId) int32_t OnRemoteRequestInner(uint32_t code, IpcIo *data, IpcIo *reply, MessageOption option, IpcObjectStub *objectStub) { int32_t result = ERR_NOT_RPC; + result = RpcOnRemoteRequestInner(code, data, reply, option, objectStub); if (result == ERR_NOT_RPC) { if (objectStub != NULL && objectStub->func != NULL) { result = (OnRemoteRequest)(objectStub->func)(code, data, reply, option); @@ -417,4 +423,5 @@ void WaitForProxyInit(int32_t handle) { RPC_LOG_INFO("ipc skeleton wait for proxy init"); OnFirstStrongRef(handle); + UpdateProtoIfNeed(handle); } \ No newline at end of file diff --git a/ipc/native/c/manager/src/iremote_invoker.c b/ipc/native/c/manager/src/iremote_invoker.c index ff852c488f65b37735648207fbce780fc0c50bd8..7ce63f056a3c16bd557226e34df84bc8c1f0838c 100644 --- a/ipc/native/c/manager/src/iremote_invoker.c +++ b/ipc/native/c/manager/src/iremote_invoker.c @@ -16,6 +16,7 @@ #include "iremote_invoker.h" #include "binder_invoker.h" +#include "dbinder_invoker.h" #include "rpc_types.h" RemoteInvoker *InitRemoteInvoker(int32_t proto) @@ -23,6 +24,8 @@ RemoteInvoker *InitRemoteInvoker(int32_t proto) RemoteInvoker *remoteInvoker = NULL; if (proto == IF_PROT_BINDER) { remoteInvoker = GetIpcInvoker(); + } else { + remoteInvoker = GetRpcInvoker(); } return remoteInvoker; } \ No newline at end of file diff --git a/ipc/native/c/rpc/include/dbinder_invoker.h b/ipc/native/c/rpc/include/dbinder_invoker.h new file mode 100644 index 0000000000000000000000000000000000000000..3063336a8f02844b5d25b4346875d9b1b9a8b24e --- /dev/null +++ b/ipc/native/c/rpc/include/dbinder_invoker.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_RPC_INVOKER_H +#define OHOS_RPC_INVOKER_H + +#include +#include + +#include "rpc_process_skeleton.h" +#include "iremote_invoker.h" + +#ifdef __cplusplus +extern "C" { +#endif + +RemoteInvoker *GetRpcInvoker(void); +void DeleteRpcInvoker(RemoteInvoker *remoteInvoker); +void RpcStopWorkThread(void); +int32_t OnReceiveNewConnection(int sessionId); +void OnDatabusSessionClosed(int sessionId); +void OnMessageAvailable(int sessionId, const void *data, unsigned int len); +void UpdateClientSession(int32_t handle, HandleSessionList *sessionObject, const char *sessionName, + const char *serviceName, const char *deviceId); +int32_t CreateTransServer(const char *sessionName); + +#ifdef __cplusplus +} +#endif +#endif // OHOS_RPC_INVOKER_H \ No newline at end of file diff --git a/ipc/native/c/rpc/include/rpc_process_skeleton.h b/ipc/native/c/rpc/include/rpc_process_skeleton.h new file mode 100644 index 0000000000000000000000000000000000000000..0f48c3d4d2820b371079003a0debc285125df99d --- /dev/null +++ b/ipc/native/c/rpc/include/rpc_process_skeleton.h @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_RPC_PROCESS_SKELETON_H +#define OHOS_RPC_PROCESS_SKELETON_H + +#include +#include + +#include "ipc_skeleton.h" +#include "rpc_trans.h" +#include "utils_list.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + pthread_mutex_t lock; + uint64_t stubIndex; + char *sessionName; + uint64_t seqNumber; + TransInterface *rpcTrans; + int32_t isServerCreated; +} RpcSkeleton; + +typedef struct { + UTILS_DL_LIST list; + uint64_t stubIndex; + OnRemoteRequest func; +} StubObject; + +typedef struct { + UTILS_DL_LIST stubObjects; + pthread_mutex_t mutex; +} StubObjectList; + +typedef struct { + UTILS_DL_LIST list; + pthread_t threadId; + uint32_t listenFd; + uint32_t packageSize; + char *buffer; +} ThreadProcessInfo; + +typedef struct { + UTILS_DL_LIST processInfo; + pthread_mutex_t mutex; +} ThreadProcessInfoList; + +typedef struct { + UTILS_DL_LIST list; + pthread_t threadId; + pthread_mutex_t mutex; + pthread_cond_t condition; +} SocketThreadLockInfo; + +typedef struct { + UTILS_DL_LIST socketLockInfo; + pthread_mutex_t mutex; +} SocketThreadLockInfoList; + +typedef struct { + UTILS_DL_LIST list; + pthread_t threadId; +} IdleDataThread; + +typedef struct { + UTILS_DL_LIST idleDataThread; + pthread_mutex_t mutex; +} IdleDataThreadsList; + +typedef struct { + UTILS_DL_LIST list; + uint32_t handle; + uint32_t sessionId; + char *buffer; + uint32_t len; +} HandleSessionList; + +typedef struct { + UTILS_DL_LIST list; + uint32_t handle; + uint64_t index; +} HandleToIndexList; + +typedef struct { + UTILS_DL_LIST list; + pthread_t threadId; + uint64_t seqNumber; + uint32_t flags; + size_t bufferSize; + size_t offsetsSize; + uintptr_t offsets; + uint32_t socketId; + void *buffer; +} ThreadMessageInfo; + +int32_t RpcProcessSkeleton(void); +RpcSkeleton *GetCurrentRpcSkeleton(void); +int32_t AddStubByIndex(StubObject *stubObject); +StubObject *QueryStubByIndex(uint64_t stubIndex); +void AddDataThreadInWait(pthread_t threadId); +IdleDataThread *GetIdleDataThread(void); +void AddDataInfoToThread(ThreadProcessInfo *processInfo); +ThreadProcessInfo *PopDataInfoFromThread(pthread_t threadId); +uint32_t ConvertChannelID2Int(int64_t databusChannelId); +int32_t AttachStubSession(HandleSessionList *handleSession); +void DetachStubSession(HandleSessionList *handleSession); +HandleSessionList *QueryStubSession(uint32_t handle); +int32_t AttachProxySession(HandleSessionList *handleSession); +void DetachProxySession(HandleSessionList *handleSession); +HandleSessionList *QueryProxySession(uint32_t handle); +HandleSessionList *QueryProxySessionBySessionId(uint32_t sessionId); +uint64_t ProcessGetSeqNumber(void); +int32_t AttachHandleToIndex(HandleToIndexList *handleToIndex); +void DetachHandleToIndex(HandleToIndexList *handleToIndex); +HandleToIndexList *QueryHandleToIndex(uint32_t handle); +int32_t AddSendThreadInWait(uint64_t seqNumber, ThreadMessageInfo *messageInfo, int userWaitTime); +void EraseThreadBySeqNumber(ThreadMessageInfo *messageInfo); +ThreadMessageInfo *QueryThreadBySeqNumber(uint64_t seqNumber); +void WakeUpThreadBySeqNumber(uint64_t seqNumber, uint32_t handle); +int32_t RpcOnRemoteRequestInner(uint32_t code, IpcIo *data, IpcIo *reply, + MessageOption option, IpcObjectStub *objectStub); +void UpdateProtoIfNeed(int32_t handle); +void WakeUpDataThread(pthread_t threadId); +uint64_t GetNewStubIndex(void); + +#ifdef __cplusplus +} +#endif +#endif // OHOS_RPC_PROCESS_SKELETON_H \ No newline at end of file diff --git a/ipc/native/c/rpc/include/rpc_trans_callback.h b/ipc/native/c/rpc/include/rpc_trans_callback.h new file mode 100644 index 0000000000000000000000000000000000000000..d8f2d1c3ed0e27277a6f01c2e525f5ff5763531a --- /dev/null +++ b/ipc/native/c/rpc/include/rpc_trans_callback.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_RPC_TRANS_CALLBACK_H +#define OHOS_RPC_TRANS_CALLBACK_H + +#include "rpc_trans.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +TransCallback *GetRpcTransCallback(void); + +#ifdef __cplusplus +} +#endif +#endif // OHOS_RPC_TRANS_CALLBACK_H \ No newline at end of file diff --git a/ipc/native/c/rpc/ipc_adapter/include/ipc_proxy_inner.h b/ipc/native/c/rpc/ipc_adapter/include/ipc_proxy_inner.h new file mode 100644 index 0000000000000000000000000000000000000000..90f269ef643ce91a7e7075f4e69d313805b5958b --- /dev/null +++ b/ipc/native/c/rpc/ipc_adapter/include/ipc_proxy_inner.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_PROXY_INNER_H +#define OHOS_IPC_PROXY_INNER_H + +#include + +#include "dbinder_types.h" +#include "serializer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int32_t InvokerListenThread(ProxyObject *proxyObject, const char *localDeviceID, + const char *remoteDeviceID, uint32_t pid, uint32_t uid, IpcIo *reply, uintptr_t *ptr); +int32_t GetPidAndUidInfo(ProxyObject *proxy); +char *GetDataBusName(void); +void UpdateProto(int32_t handle); + +#ifdef __cplusplus +} +#endif +#endif // OHOS_IPC_PROXY_INNER_H \ No newline at end of file diff --git a/ipc/native/c/rpc/ipc_adapter/include/ipc_stub_inner.h b/ipc/native/c/rpc/ipc_adapter/include/ipc_stub_inner.h new file mode 100644 index 0000000000000000000000000000000000000000..6715d5493a83593f12b870c86b2a2b6740ec1625 --- /dev/null +++ b/ipc/native/c/rpc/ipc_adapter/include/ipc_stub_inner.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_IPC_STUB_INNER_H +#define OHOS_IPC_STUB_INNER_H + +#include + +#include "serializer.h" +#include "ipc_skeleton.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int32_t InvokerListenThreadStub(uint32_t code, IpcIo *data, IpcIo *reply, int32_t option, OnRemoteRequest *func); +int32_t GetPidAndUidInfoStub(uint32_t code, IpcIo *data, IpcIo *reply, int32_t option); +int32_t GrantDataBusNameStub(uint32_t code, IpcIo *data, IpcIo *reply, int32_t option); + +#ifdef __cplusplus +} +#endif +#endif // OHOS_IPC_STUB_INNER_H \ No newline at end of file diff --git a/ipc/native/c/rpc/ipc_adapter/mini/ipc_proxy_inner.c b/ipc/native/c/rpc/ipc_adapter/mini/ipc_proxy_inner.c new file mode 100644 index 0000000000000000000000000000000000000000..1897a6d8ff503e4c3d533c3ef744562c3ee41056 --- /dev/null +++ b/ipc/native/c/rpc/ipc_adapter/mini/ipc_proxy_inner.c @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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. + */ + +#include "ipc_proxy_inner.h" + +#include +#include +#include + +#include "ipc_thread_pool.h" +#include "rpc_process_skeleton.h" +#include "dbinder_invoker.h" +#include "dbinder_types.h" +#include "rpc_errno.h" +#include "rpc_log.h" + +static int32_t GetDigits(int32_t number) +{ + int32_t n = 0; + while (number > 0) { + n++; + number /= ID_DIGITS; + } + if (n == 0) { + n++; + } + return n; +} + +static int32_t MakeInvokerListenReply(ProxyObject *proxyObject, uint64_t stubIndex, IpcIo *reply, uintptr_t *ptr) +{ + ptr = (uintptr_t *)calloc(1, RPC_IPC_LENGTH); + if (ptr == NULL) { + RPC_LOG_ERROR("InvokerListenThread ptr calloc failed"); + return ERR_FAILED; + } + IpcIoInit(reply, (void *)ptr, RPC_IPC_LENGTH, 0); + + if (!WriteUint64(reply, stubIndex)) { + RPC_LOG_ERROR("InvokerListenThread WriteUint64 failed"); + free((void *)ptr); + return ERR_FAILED; + } + if (!WriteString(reply, proxyObject->sessionName)) { + RPC_LOG_ERROR("InvokerListenThread WriteString failed"); + free((void *)ptr); + return ERR_FAILED; + } + ((IpcIo *)reply)->bufferCur = ((IpcIo *)reply)->bufferBase; + return ERR_NONE; +} + +int32_t InvokerListenThread(ProxyObject *proxyObject, const char *localDeviceID, const char *remoteDeviceID, + uint32_t pid, uint32_t uid, IpcIo *reply, uintptr_t *ptr) +{ + if (proxyObject == NULL) { + RPC_LOG_ERROR("InvokerListenThread proxy is null"); + return ERR_FAILED; + } + int32_t sessionNameLen = strlen(proxyObject->sessionName); + + RpcSkeleton *current = GetCurrentRpcSkeleton(); + if (current == NULL) { + RPC_LOG_ERROR("GetCurrentSkeleton failed"); + return ERR_FAILED; + } + if (CreateTransServer(proxyObject->sessionName) != ERR_NONE) { + return ERR_FAILED; + } + + if (current->sessionName != NULL) { + free(current->sessionName); + } + if (sessionNameLen == 0 || sessionNameLen > SERVICENAME_LENGTH) { + RPC_LOG_ERROR("sessionNameLen invalid"); + return ERR_FAILED; + } + current->sessionName = (char *)malloc(sessionNameLen + 1); + if (current->sessionName == NULL) { + return ERR_FAILED; + } + if (sessionNameLen == 0 || sessionNameLen > SERVICENAME_LENGTH) { + RPC_LOG_ERROR("sessionNameLen invalid"); + return ERR_FAILED; + } + if (strcpy_s(current->sessionName, sessionNameLen + 1, proxyObject->sessionName) != EOK) { + free(current->sessionName); + return ERR_FAILED; + } + + StubObject *stubObject = (StubObject *)malloc(sizeof(StubObject)); + if (stubObject == NULL) { + return ERR_FAILED; + } + uint64_t stubIndex = GetNewStubIndex(); + stubObject->stubIndex = stubIndex; + IpcObjectStub *cookie = (IpcObjectStub *)(proxyObject->proxy->cookie); + stubObject->func = cookie->func; + if (AddStubByIndex(stubObject) != ERR_NONE) { + free(stubObject); + return ERR_FAILED; + } + + return MakeInvokerListenReply(proxyObject, stubIndex, reply, ptr); +} + +int32_t GetPidAndUidInfo(ProxyObject *proxyObject) +{ + if (proxyObject == NULL) { + RPC_LOG_ERROR("GetPidAndUidInfo proxy is null"); + return ERR_FAILED; + } + + int32_t pid = (int32_t)GetCallingPid(); + int32_t pidLen = GetDigits(pid); + int32_t uid = (int32_t)GetCallingUid(); + int32_t uidLen = GetDigits(uid); + + uint32_t sessionNameLen = SESSION_NAME_LEGNTH + pidLen + uidLen; + proxyObject->sessionName = (char *)malloc(sessionNameLen + 1); + if (proxyObject->sessionName == NULL) { + RPC_LOG_ERROR("sessionName mallo failed"); + return ERR_FAILED; + } + if (sprintf_s(proxyObject->sessionName, sessionNameLen + 1, "DBinder%d_%d", uid, pid) == -1) { + RPC_LOG_ERROR("sessionName sprintf failed"); + free(proxyObject->sessionName); + return ERR_FAILED; + } + + return ERR_NONE; +} + +char *GetDataBusName(void) +{ + return NULL; +} + +static char *CreateDatabusName(void) +{ + int32_t pid = (int32_t)GetCallingPid(); + int32_t pidLen = GetDigits(pid); + int32_t uid = (int32_t)GetCallingUid(); + int32_t uidLen = GetDigits(uid); + + uint32_t sessionNameLen = SESSION_NAME_LEGNTH + pidLen + uidLen; + char *sessionName = (char *)malloc(sessionNameLen + 1); + if (sessionName == NULL) { + RPC_LOG_ERROR("sessionName mallo failed"); + return NULL; + } + if (sprintf_s(sessionName, sessionNameLen + 1, "DBinder%d_%d", uid, pid) == -1) { + RPC_LOG_ERROR("sessionName sprintf failed"); + free(sessionName); + return NULL; + } + return sessionName; +} + +static int GetSessionFromDBinderService(uint32_t handle) +{ + RPC_LOG_INFO("GetSessionFromDBinderService start"); + + int32_t proto = IF_PROT_DATABUS; + SessionInfo *session = QuerySessionObject((uintptr_t)handle); + if (session == NULL) { + RPC_LOG_ERROR("client find session is null"); + return proto; + } + const char *localBusName = CreateDatabusName(); + if (localBusName == NULL) { + RPC_LOG_ERROR("ProcessProto CreateDatabusName failed"); + return proto; + } + + HandleSessionList *sessionObject = (HandleSessionList *)malloc(sizeof(HandleSessionList)); + if (sessionObject == NULL) { + RPC_LOG_ERROR("UpdateDatabusClientSession sessionObject malloc failed"); + return proto; + } + + HandleToIndexList *handleToIndex = (HandleToIndexList *)malloc(sizeof(HandleToIndexList)); + if (handleToIndex == NULL) { + RPC_LOG_ERROR("UpdateDatabusClientSession handleToIndex malloc failed"); + free(sessionObject); + return proto; + } + handleToIndex->handle = handle; + handleToIndex->index = session->stubIndex; + + if (AttachHandleToIndex(handleToIndex) != ERR_NONE) { + RPC_LOG_ERROR("AttachHandleToIndex failed"); + free(sessionObject); + free(handleToIndex); + return proto; + } + + if (CreateTransServer(localBusName) != ERR_NONE) { + RPC_LOG_ERROR("create bus server fail name = %s, localID = %s", + localBusName, session->deviceIdInfo.fromDeviceId); + DetachHandleToIndex(handleToIndex); + free(sessionObject); + free(handleToIndex); + return proto; + } + + UpdateClientSession(handle, sessionObject, localBusName, session->serviceName, session->deviceIdInfo.toDeviceId); + + return proto; +} + +void UpdateProto(int32_t handle) +{ + if (handle < 0) { + RPC_LOG_ERROR("UpdateProto handle invalid"); + return; + } + + ThreadContext *threadContext = GetCurrentThreadContext(); + if (threadContext == NULL) { + RPC_LOG_ERROR("UpdateProto threadContext is null"); + return; + } + HandleSessionList *sessionObject = QueryProxySession(handle); + if (sessionObject != NULL) { + threadContext->proto = IF_PROT_DATABUS; + return; + } + threadContext->proto = GetSessionFromDBinderService(handle); + RPC_LOG_INFO("UpdateProto get proto: %d", threadContext->proto); +} \ No newline at end of file diff --git a/ipc/native/c/rpc/ipc_adapter/mini/ipc_stub_inner.c b/ipc/native/c/rpc/ipc_adapter/mini/ipc_stub_inner.c new file mode 100644 index 0000000000000000000000000000000000000000..f8e5edecaee51fff5532e802a2960dc713100fdc --- /dev/null +++ b/ipc/native/c/rpc/ipc_adapter/mini/ipc_stub_inner.c @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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. + */ + +#include "ipc_stub_inner.h" + +#include "rpc_errno.h" + +int32_t InvokerListenThreadStub(uint32_t code, IpcIo *data, IpcIo *reply, int32_t option, OnRemoteRequest *func) +{ + return ERR_NONE; +} + +int32_t GetPidAndUidInfoStub(uint32_t code, IpcIo *data, IpcIo *reply, int32_t option) +{ + return ERR_NONE; +} + +int32_t GrantDataBusNameStub(uint32_t code, IpcIo *data, IpcIo *reply, int32_t option) +{ + return ERR_NONE; +} \ No newline at end of file diff --git a/ipc/native/c/rpc/ipc_adapter/small/ipc_proxy_inner.c b/ipc/native/c/rpc/ipc_adapter/small/ipc_proxy_inner.c new file mode 100644 index 0000000000000000000000000000000000000000..35d57493aa98a98c64b9ca25f9237fc9bde54419 --- /dev/null +++ b/ipc/native/c/rpc/ipc_adapter/small/ipc_proxy_inner.c @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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. + */ + +#include "ipc_proxy_inner.h" + +#include "securec.h" +#include "serializer.h" +#include "rpc_log.h" +#include "rpc_errno.h" +#include "ipc_process_skeleton.h" +#include "ipc_thread_pool.h" +#include "dbinder_invoker.h" +#include "dbinder_types.h" +#include "rpc_process_skeleton.h" + +static void UpdateDatabusClientSession(int32_t handle, IpcIo *reply) +{ + uint64_t stubIndex; + if (!ReadUint64(reply, &stubIndex)) { + return; + } + + size_t len; + char *serviceName = (char *)ReadString(reply, &len); + char *peerID = (char *)ReadString(reply, &len); + char *localID = (char *)ReadString(reply, &len); + char *localBusName = (char *)ReadString(reply, &len); + + HandleSessionList *sessionObject = (HandleSessionList *)malloc(sizeof(HandleSessionList)); + if (sessionObject == NULL) { + RPC_LOG_ERROR("UpdateDatabusClientSession sessionObject malloc failed"); + return; + } + + HandleToIndexList *handleToIndex = (HandleToIndexList *)malloc(sizeof(HandleToIndexList)); + if (handleToIndex == NULL) { + RPC_LOG_ERROR("UpdateDatabusClientSession handleToIndex malloc failed"); + free(sessionObject); + return; + } + handleToIndex->handle = handle; + handleToIndex->index = stubIndex; + + if (AttachHandleToIndex(handleToIndex) != ERR_NONE) { + RPC_LOG_ERROR("AttachHandleToIndex failed"); + free(sessionObject); + free(handleToIndex); + return; + } + + if (CreateTransServer(localBusName) != ERR_NONE) { + RPC_LOG_ERROR("create bus server fail name = %s, localID = %s", localBusName, localID); + DetachHandleToIndex(handleToIndex); + free(sessionObject); + free(handleToIndex); + return; + } + + UpdateClientSession(handle, sessionObject, localBusName, serviceName, peerID); +} + +static int GetSessionFromDBinderService(uint32_t handle) +{ + RPC_LOG_INFO("GetSessionFromDBinderService start"); + IpcIo data; + IpcIo reply; + uint8_t dataAlloc[RPC_IPC_LENGTH_LONG]; + IpcIoInit(&data, dataAlloc, RPC_IPC_LENGTH_LONG, 0); + MessageOption option = TF_OP_SYNC; + SvcIdentity target = { + .handle = handle + }; + uintptr_t ptr; + int32_t ret = ProcessSendRequest(target, GET_PROTO_INFO, &data, &reply, option, &ptr); + if (ret != ERR_NONE) { + RPC_LOG_ERROR("sendrequest GET_PROTO_INFO failed, error %d", ret); + FreeBuffer((void *)ptr); + return IF_PROT_BINDER; + } + uint32_t proto; + if (!ReadUint32(&reply, &proto)) { + FreeBuffer((void *)ptr); + return IF_PROT_BINDER; + } + + switch (proto) { + case IF_PROT_BINDER: + break; + case IF_PROT_DATABUS: { + UpdateDatabusClientSession(handle, &reply); + proto = IF_PROT_DATABUS; + break; + } + default: + break; + } + + FreeBuffer((void *)ptr); + return proto; +} + +int32_t InvokerListenThread(ProxyObject *proxyObject, const char *localDeviceID, const char *remoteDeviceID, + uint32_t pid, uint32_t uid, IpcIo *reply, uintptr_t *ptr) +{ + if (proxyObject == NULL || localDeviceID == NULL || remoteDeviceID == NULL) { + return ERR_FAILED; + } + + IpcIo *ipcReply = (IpcIo *)reply; + + IpcIo data; + uint8_t dataAlloc[RPC_IPC_LENGTH_LONG]; + IpcIoInit(&data, dataAlloc, RPC_IPC_LENGTH_LONG, 0); + WriteUint16(&data, DATABUS_TYPE); + WriteString(&data, localDeviceID); + WriteUint32(&data, pid); + WriteUint32(&data, uid); + WriteString(&data, remoteDeviceID); + WriteString(&data, proxyObject->sessionName); + MessageOption option = TF_OP_SYNC; + + int32_t ret = SendRequest(*proxyObject->proxy, INVOKE_LISTEN_THREAD, &data, ipcReply, option, ptr); + if (ret != ERR_NONE) { + RPC_LOG_ERROR("INVOKE_LISTEN_THREAD failed"); + } + return ret; +} + +int32_t GetPidAndUidInfo(ProxyObject *proxyObject) +{ + if (proxyObject == NULL) { + RPC_LOG_ERROR("GetPidAndUidInfo proxy is null"); + return ERR_FAILED; + } + + IpcIo data; + IpcIo reply; + uint8_t dataAlloc[RPC_IPC_LENGTH]; + IpcIoInit(&data, dataAlloc, RPC_IPC_LENGTH, 0); + MessageOption option = TF_OP_SYNC; + uintptr_t ptr; + + int32_t ret = SendRequest(*proxyObject->proxy, GET_UIDPID_INFO, &data, &reply, option, &ptr); + if (ret != ERR_NONE) { + RPC_LOG_ERROR("sendrequest GET_UIDPID_INFO failed, error %d", ret); + FreeBuffer((void *)ptr); + return ERR_FAILED; + } + + size_t len; + char *sessionName = (char *)ReadString(&reply, &len); + + proxyObject->sessionName = (char *)malloc(len + 1); + if (proxyObject->sessionName == NULL) { + RPC_LOG_ERROR("GetPidAndUidInfo proxy name malloc failed"); + FreeBuffer((void *)ptr); + return ERR_FAILED; + } + if (strcpy_s(proxyObject->sessionName, len + 1, sessionName) != 0) { + RPC_LOG_ERROR("GetPidAndUidInfo proxy name copy failed"); + free(proxyObject->sessionName); + FreeBuffer((void *)ptr); + return ERR_FAILED; + } + + FreeBuffer((void *)ptr); + return ERR_NONE; +} + +char *GetDataBusName(void) +{ + IpcIo data; + IpcIo reply; + uint8_t dataAlloc[RPC_IPC_LENGTH]; + IpcIoInit(&data, dataAlloc, RPC_IPC_LENGTH, 0); + MessageOption option = TF_OP_SYNC; + uintptr_t ptr; + int32_t ret = ProcessSendRequest(*GetContextObject(), GRANT_DATABUS_NAME, &data, &reply, option, &ptr); + if (ret != ERR_NONE) { + RPC_LOG_ERROR("sendrequest GRANT_DATABUS_NAME failed, error %d", ret); + FreeBuffer((void *)ptr); + return NULL; + } + + int32_t proto; + if (!ReadInt32(&reply, &proto)) { + FreeBuffer((void *)ptr); + return NULL; + } + + if (proto != IF_PROT_DATABUS) { + RPC_LOG_INFO("GetDataBusName normal binder"); + FreeBuffer((void *)ptr); + return NULL; + } + size_t len; + const char *name = (const char *)ReadString(&reply, &len); + RPC_LOG_INFO("GetDataBusName name %s, len %d", name, len); + char *sessionName = (char *)malloc(len + 1); + if (sessionName == NULL) { + RPC_LOG_ERROR("GetDataBusName sessionName malloc failed"); + FreeBuffer((void *)ptr); + return NULL; + } + if (strcpy_s(sessionName, len + 1, name) != EOK) { + RPC_LOG_ERROR("GetDataBusName sessionName copy failed"); + free(sessionName); + FreeBuffer((void *)ptr); + return NULL; + } + + FreeBuffer((void *)ptr); + return sessionName; +} + +void UpdateProto(int32_t handle) +{ + if (handle < 0) { + RPC_LOG_ERROR("UpdateProto handle invalid"); + return; + } + + ThreadContext *threadContext = GetCurrentThreadContext(); + if (threadContext == NULL) { + RPC_LOG_ERROR("UpdateProto threadContext is null"); + return; + } + HandleSessionList *sessionObject = QueryProxySession(handle); + if (sessionObject != NULL) { + threadContext->proto = IF_PROT_DATABUS; + return; + } + threadContext->proto = GetSessionFromDBinderService(handle); + RPC_LOG_INFO("UpdateProto get proto: %d", threadContext->proto); +} \ No newline at end of file diff --git a/ipc/native/c/rpc/ipc_adapter/small/ipc_stub_inner.c b/ipc/native/c/rpc/ipc_adapter/small/ipc_stub_inner.c new file mode 100644 index 0000000000000000000000000000000000000000..5dfa2e1b2da7cfb161cb95092983c4dd99d17586 --- /dev/null +++ b/ipc/native/c/rpc/ipc_adapter/small/ipc_stub_inner.c @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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. + */ + +#include "ipc_stub_inner.h" + +#include "securec.h" + +#include "dbinder_types.h" +#include "dbinder_invoker.h" +#include "rpc_process_skeleton.h" +#include "rpc_types.h" +#include "rpc_errno.h" +#include "rpc_log.h" +#include "ipc_proxy_inner.h" +#include "ipc_thread_pool.h" + +static int32_t IsDeviceIdIllegal(const char *deviceID, uint32_t len) +{ + if (deviceID == NULL || len > DEVICEID_LENGTH) { + return ERR_FAILED; + } + return ERR_NONE; +} + +static int32_t MakeStubCached(IpcIo *reply, OnRemoteRequest func, + const char *sessionName, const char *deviceID) +{ + RpcSkeleton *current = GetCurrentRpcSkeleton(); + if (current == NULL) { + RPC_LOG_ERROR("GetCurrentSkeleton failed"); + return ERR_FAILED; + } + + StubObject *stubObject = (StubObject *)malloc(sizeof(StubObject)); + if (stubObject == NULL) { + return ERR_FAILED; + } + uint64_t stubIndex = GetNewStubIndex(); + stubObject->stubIndex = stubIndex; + stubObject->func = func; + if (AddStubByIndex(stubObject) != ERR_NONE) { + free(stubObject); + return ERR_FAILED; + } + + WriteUint64(reply, stubIndex); + WriteString(reply, sessionName); + WriteString(reply, deviceID); + return ERR_NONE; +} + +static int32_t InvokerDataBusThread(IpcIo *data, IpcIo *reply, OnRemoteRequest func) +{ + size_t deviceIDLen; + const char *deviceID = (const char*)ReadString(data, &deviceIDLen); + uint32_t remotePid; + if (!ReadUint32(data, &remotePid)) { + return ERR_FAILED; + } + + uint32_t remoteUid; + if (!ReadUint32(data, &remoteUid)) { + return ERR_FAILED; + } + + size_t remoteDeviceIDLen; + const char *remoteDeviceID = (const char*)ReadString(data, &remoteDeviceIDLen); + size_t sessionNameLen; + const char *sessionName = (const char*)ReadString(data, &sessionNameLen); + if (IsDeviceIdIllegal(deviceID, deviceIDLen) != ERR_NONE || + IsDeviceIdIllegal(remoteDeviceID, remoteDeviceIDLen) != ERR_NONE || sessionName == NULL) { + RPC_LOG_ERROR("deviceID invalid or session name is null"); + return ERR_FAILED; + } + + RpcSkeleton *current = GetCurrentRpcSkeleton(); + if (current == NULL) { + RPC_LOG_ERROR("GetCurrentSkeleton failed"); + return ERR_FAILED; + } + if (CreateTransServer(sessionName) != ERR_NONE) { + return ERR_FAILED; + } + + if (current->sessionName != NULL) { + free(current->sessionName); + } + if (sessionNameLen == 0 || sessionNameLen > SERVICENAME_LENGTH) { + RPC_LOG_ERROR("sessionNameLen invalid"); + return ERR_FAILED; + } + current->sessionName = (char *)malloc(sessionNameLen + 1); + if (current->sessionName == NULL) { + return ERR_FAILED; + } + if (strcpy_s(current->sessionName, sessionNameLen + 1, sessionName) != EOK) { + free(current->sessionName); + return ERR_FAILED; + } + + return MakeStubCached(reply, func, sessionName, deviceID); +} + +int32_t InvokerListenThreadStub(uint32_t code, IpcIo *data, IpcIo *reply, int32_t option, OnRemoteRequest *func) +{ + uint16_t type; + if (!ReadUint16(data, &type)) { + return ERR_FAILED; + } + switch (type) { + case DATABUS_TYPE: { + if (InvokerDataBusThread(data, reply, func) != 0) { + RPC_LOG_ERROR("Invoker databus thread fail"); + return ERR_FAILED; + } + break; + } + default: { + RPC_LOG_ERROR("InvokerThread Invalid Type"); + return ERR_FAILED; + } + } + return ERR_NONE; +} + +int32_t GetPidAndUidInfoStub(uint32_t code, IpcIo *data, IpcIo *reply, int32_t option) +{ + int32_t result = ERR_NONE; + + char *sessionName = GetDataBusName(); + if (sessionName == NULL || strlen(sessionName) == 0) { + RPC_LOG_ERROR("GetDataBusName failed"); + result = ERR_FAILED; + } else { + WriteString(reply, sessionName); + free(sessionName); + result = ERR_NONE; + } + return result; +} + +static int32_t GetDigits(int32_t number) +{ + int32_t n = 0; + while (number > 0) { + n++; + number /= ID_DIGITS; + } + if (n == 0) { + n++; + } + return n; +} + +int32_t GrantDataBusNameStub(uint32_t code, IpcIo *data, IpcIo *reply, int32_t option) +{ + int32_t pid = (int32_t)GetCallingPid(); + int32_t pidLen = GetDigits(pid); + int32_t uid = (int32_t)GetCallingUid(); + int32_t uidLen = GetDigits(uid); + + uint32_t sessionNameLen = SESSION_NAME_LEGNTH + pidLen + uidLen; + char *sessionName = (char *)malloc(sessionNameLen + 1); + if (sessionName == NULL) { + RPC_LOG_ERROR("sessionName mallo failed"); + return ERR_FAILED; + } + if (sprintf_s(sessionName, sessionNameLen + 1, "DBinder%d_%d", uid, pid) == -1) { + RPC_LOG_ERROR("sessionName sprintf failed"); + free(sessionName); + return ERR_FAILED; + } + + WriteInt32(reply, IF_PROT_DATABUS); + WriteString(reply, sessionName); + free(sessionName); + return ERR_NONE; +} \ No newline at end of file diff --git a/ipc/native/c/rpc/src/dbinder_invoker.c b/ipc/native/c/rpc/src/dbinder_invoker.c new file mode 100644 index 0000000000000000000000000000000000000000..e9ca459100f9f535ebd6fda95c492c5a0a5279ac --- /dev/null +++ b/ipc/native/c/rpc/src/dbinder_invoker.c @@ -0,0 +1,790 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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. + */ + +#include "dbinder_invoker.h" + +#include +#include +#include + +#include "securec.h" +#include "utils_list.h" + +#include "rpc_log.h" +#include "rpc_errno.h" +#include "rpc_trans.h" +#include "rpc_trans_callback.h" +#include "ipc_skeleton.h" +#include "ipc_process_skeleton.h" +#include "ipc_thread_pool.h" +#include "dbinder_types.h" + +#define BC_TRANSACTION 1076388608 +#define BC_REPLY 1076388609 + +static const int DBINDER_MAGICWORD = 0X4442494E; +static const int SOCKET_MAX_BUFF_SIZE = 1024 * 1024; +static RemoteInvoker *g_rpcInvoker = NULL; + +void DeleteRpcInvoker(RemoteInvoker *remoteInvoker) +{ + if (remoteInvoker == NULL) { + return; + } + free(remoteInvoker); +} + +static HandleSessionList *GetSessionObject(uint32_t handle, uint32_t socketId) +{ + if (handle != 0) { + /* transact case */ + return QueryProxySession(handle); + } else { + /* reply case */ + return QueryStubSession(socketId); + } +} + +static uint64_t GetUniqueSeqNumber(int cmd) +{ + if (cmd == BC_TRANSACTION) { + return ProcessGetSeqNumber(); + } else if (cmd == BC_REPLY) { + ThreadContext *threadContext = GetCurrentThreadContext(); + if (threadContext == NULL) { + RPC_LOG_ERROR("GetUniqueSeqNumber threadContext is null"); + return 0; + } + return threadContext->seqNumber; + } + return 0; +} + +static void ToTransData(const IpcIo *data, dbinder_transaction_data *buf) +{ + buf->buffer_size = (data == NULL) ? 0 : (data->bufferCur - data->bufferBase); + buf->offsets = buf->buffer_size; + buf->offsets_size = (data == NULL) ? 0 : + ((size_t)(data->offsetsCur - data->offsetsBase) * sizeof(size_t)); +} + +static void ToIpcData(const dbinder_transaction_data *tr, IpcIo *data) +{ + data->bufferBase = data->bufferCur = (char *)(tr->buffer); + data->offsetsBase = data->offsetsCur = (size_t *)(data->bufferBase + (size_t)tr->buffer_size); + data->bufferLeft = (size_t)tr->buffer_size; + data->offsetsLeft = (tr->offsets_size) / sizeof(size_t); + data->flag = IPC_IO_INITIALIZED; +} + +static int32_t MoveIpcToTransData(IpcIo *data, dbinder_transaction_data *transData, int status) +{ + if (data != NULL) { + ToTransData(data, transData); + if (memcpy_s(transData->buffer, transData->buffer_size, data->bufferBase, transData->buffer_size) != EOK) { + RPC_LOG_ERROR("transData buffer memset failed"); + return ERR_FAILED; + } + uint32 offsetsSize = transData->sizeOfSelf - sizeof(dbinder_transaction_data) - transData->buffer_size; + if (offsetsSize > 0) { + if (memcpy_s(transData->buffer + transData->buffer_size, offsetsSize, + data->offsetsBase, offsetsSize) != EOK) { + RPC_LOG_ERROR("transData buffer memset failed"); + return ERR_FAILED; + } + } + } else { + transData->flags |= TF_OP_STATUS_CODE; + transData->buffer_size = sizeof(size_t); + transData->offsets_size = (size_t)status; + transData->offsets = transData->buffer_size; + } + return ERR_NONE; +} + +static int32_t ProcessNormalData(IpcIo *data, int32_t handle, int status, dbinder_transaction_data *transData) +{ + if (transData == NULL) { + RPC_LOG_ERROR("ProcessNormalData transData is null"); + return ERR_FAILED; + } + + uint32_t dataSize = (uint32_t)(data->offsetsCur - data->offsetsBase) + + (uint32_t)(data->bufferCur - data->bufferBase); + transData->buffer = (char *)malloc(dataSize); + if (transData->buffer == NULL) { + RPC_LOG_ERROR("transData buffer malloc failed"); + return ERR_FAILED; + } + transData->sizeOfSelf = sizeof(dbinder_transaction_data) + dataSize; + + if (handle == 0) { + transData->cookie = 0; + } else { + HandleToIndexList *handleToIndex = QueryHandleToIndex(handle); + if (handleToIndex == NULL) { + RPC_LOG_ERROR("stubIndex not found for handle %{public}d", handle); + return ERR_FAILED; + } + transData->cookie = handleToIndex->index; + } + + if (MoveIpcToTransData(data, transData, status) != ERR_NONE) { + RPC_LOG_ERROR("move parcel to transData failed, handle = %d", handle); + return ERR_FAILED; + } + + return ERR_NONE; +} + +static int32_t MoveTransData2Buffer(HandleSessionList *sessionObject, dbinder_transaction_data *transData) +{ + sessionObject->buffer = (char *)malloc((size_t)transData->sizeOfSelf); + if (sessionObject->buffer == NULL) { + RPC_LOG_ERROR("sessionObject buffer malloc failed"); + return ERR_FAILED; + } + sessionObject->len = (uint32_t)transData->sizeOfSelf; + + if (memcpy_s(sessionObject->buffer, sizeof(dbinder_transaction_data), + transData, sizeof(dbinder_transaction_data)) != EOK) { + RPC_LOG_ERROR("sessionObject buffer memset failed"); + free(sessionObject->buffer); + return ERR_FAILED; + } + + if (memcpy_s(sessionObject->buffer + sizeof(dbinder_transaction_data), + transData->buffer_size, transData->buffer, transData->buffer_size) != EOK) { + RPC_LOG_ERROR("sessionObject buffer memset failed"); + free(sessionObject->buffer); + return ERR_FAILED; + } + + return ERR_NONE; +} + +static HandleSessionList *WriteTransaction(int cmd, MessageOption option, int32_t handle, + int32_t socketId, uint32_t code, IpcIo *data, uint64_t *seqNumber, int status) +{ + HandleSessionList *sessionObject = GetSessionObject(handle, socketId); + if (sessionObject == NULL) { + RPC_LOG_ERROR("session is not exist for listenFd = %d, handle = %d", socketId, handle); + return NULL; + } + + uint64_t seqNum = GetUniqueSeqNumber(cmd); + if (seqNum == 0) { + RPC_LOG_ERROR("seqNum invalid"); + if (sessionObject->buffer != NULL) { + free(sessionObject->buffer); + } + return NULL; + } + *seqNumber = seqNum; + + dbinder_transaction_data transData = { + .magic = DBINDER_MAGICWORD, + .version = VERSION_NUM, + .cmd = cmd, + .code = code, + .flags = option, + .seqNumber = *seqNumber, + .buffer = NULL + }; + + if (ProcessNormalData(data, handle, status, &transData) != ERR_NONE) { + RPC_LOG_ERROR("ProcessNormalData failed"); + if (transData.buffer != NULL) { + free(transData.buffer); + return NULL; + } + } + + if (MoveTransData2Buffer(sessionObject, &transData) != ERR_NONE) { + RPC_LOG_ERROR("move transaction data to buffer failed"); + free(transData.buffer); + return NULL; + } + + free(transData.buffer); + return sessionObject; +} + +static int32_t OnSendMessage(HandleSessionList *sessionOfPeer) +{ + if (sessionOfPeer == NULL || sessionOfPeer->buffer == NULL) { + RPC_LOG_ERROR("sessionOfPeer or buffer is null"); + return ERR_FAILED; + } + RpcSkeleton *rpcSkeleton = GetCurrentRpcSkeleton(); + if (rpcSkeleton == NULL) { + RPC_LOG_ERROR("RpcSkeleton is null"); + return ERR_FAILED; + } + + int32_t ret = rpcSkeleton->rpcTrans->Send((int)sessionOfPeer->sessionId, + (void *)sessionOfPeer->buffer, (unsigned int)sessionOfPeer->len); + + free(sessionOfPeer->buffer); + return ret; +} + +static ThreadMessageInfo *MakeThreadMessageInfo(uint64_t seqNumber, uint32_t handle) +{ + ThreadMessageInfo *messageInfo = (ThreadMessageInfo *)malloc(sizeof(ThreadMessageInfo)); + if (messageInfo == NULL) { + RPC_LOG_ERROR("messageInfo malloc failed"); + return NULL; + } + + messageInfo->threadId = pthread_self(); + messageInfo->seqNumber = seqNumber; + messageInfo->buffer = NULL; + messageInfo->offsets = 0; + messageInfo->socketId = handle; + return messageInfo; +} + +static int32_t HandleReply(uint64_t seqNumber, IpcIo *reply, uintptr_t *buffer) +{ + if (reply == NULL) { + RPC_LOG_ERROR("no need reply, free the buffer"); + return ERR_FAILED; + } + + ThreadMessageInfo *messageInfo = QueryThreadBySeqNumber(seqNumber); + if (messageInfo == NULL) { + RPC_LOG_ERROR("receive buffer is nullptr"); + return ERR_NONE; + } + + if (messageInfo->flags & TF_OP_STATUS_CODE) { + int32_t err = messageInfo->offsetsSize; + return err; + } + + dbinder_transaction_data transData = { + .buffer_size = messageInfo->bufferSize, + .offsets_size = messageInfo->offsetsSize, + .offsets = messageInfo->offsets, + .buffer = messageInfo->buffer + }; + ToIpcData(&transData, reply); + buffer = (uintptr_t *)messageInfo->buffer; + + return ERR_NONE; +} + +static int32_t WaitForReply(uint64_t seqNumber, IpcIo *reply, uint32_t handle, int userWaitTime, uintptr_t *buffer) +{ + if (reply == NULL || userWaitTime == 0) { + return ERR_NONE; + } + + ThreadMessageInfo *messageInfo = MakeThreadMessageInfo(seqNumber, handle); + if (messageInfo == NULL) { + RPC_LOG_ERROR("make thread message info failed, no memory"); + return ERR_FAILED; + } + if (AddSendThreadInWait(seqNumber, messageInfo, userWaitTime) != ERR_NONE) { + RPC_LOG_ERROR("sender thread wait reply message time out"); + EraseThreadBySeqNumber(messageInfo); + free(messageInfo); + return ERR_FAILED; + } + int32_t result = HandleReply(seqNumber, reply, buffer); + EraseThreadBySeqNumber(messageInfo); + free(messageInfo); + return result; +} + +static int32_t SendOrWaitForCompletion(int userWaitTime, uint64_t seqNumber, + HandleSessionList *sessionOfPeer, IpcIo *reply, uintptr_t *buffer) +{ + if (seqNumber == 0) { + RPC_LOG_ERROR("seqNumber can not be zero"); + return ERR_FAILED; + } + if (sessionOfPeer == NULL) { + RPC_LOG_ERROR("current session is invalid"); + return ERR_FAILED; + } + int32_t result = OnSendMessage(sessionOfPeer); + if (result != ERR_NONE) { + RPC_LOG_ERROR("fail to send to remote session with error = %d", result); + // no return, for msg send failed maybe not mine + } + return WaitForReply(seqNumber, reply, sessionOfPeer->handle, userWaitTime, buffer); +} + +static int32_t GetClientFd(void) +{ + ThreadContext *threadContext = GetCurrentThreadContext(); + return threadContext->clientFd; +} + +static int32_t SendReply(IpcIo *reply, uint32_t flags, int32_t result) +{ + uint64_t seqNumber = 0; + HandleSessionList *sessionObject = WriteTransaction(BC_REPLY, flags, 0, GetClientFd(), + 0, reply, &seqNumber, result); + + if (seqNumber == 0) { + RPC_LOG_ERROR("seqNumber can not be zero"); + return ERR_FAILED; + } + SendOrWaitForCompletion(0, seqNumber, sessionObject, reply, NULL); + return ERR_NONE; +} + +static void ProcessTransaction(const dbinder_transaction_data *tr, uint32_t listenFd) +{ + if (tr == NULL || tr->cookie == 0) { + return; + } + + IpcIo data; + IpcIo reply; + uint8_t replyAlloc[RPC_IPC_LENGTH]; + IpcIoInit(&reply, replyAlloc, RPC_IPC_LENGTH, 0); + MessageOption option = tr->flags; + uint64_t senderSeqNumber = tr->seqNumber; + + ToIpcData(tr, &data); + + ThreadContext *threadContext = GetCurrentThreadContext(); + const pid_t oldPid = threadContext->callerPid; + const pid_t oldUid = threadContext->callerUid; + char oldDeviceId[DEVICEID_LENGTH]; + if (memcpy_s(oldDeviceId, DEVICEID_LENGTH, threadContext->callerDeviceID, DEVICEID_LENGTH) != EOK) { + RPC_LOG_ERROR("oldDeviceId memcpy failed"); + return; + } + + StubObject *stubObject = QueryStubByIndex(tr->cookie); + if (stubObject == NULL) { + RPC_LOG_ERROR("stubIndex is invalid"); + return; + } + + int32_t result = stubObject->func(tr->code, &data, &reply, option); + if (result != ERR_NONE) { + RPC_LOG_ERROR("stub is invalid, has not OnReceive or Request"); + } + if (!(option & TF_OP_ASYNC)) { + threadContext->clientFd = listenFd; + threadContext->seqNumber = senderSeqNumber; + SendReply(&reply, 0, result); + threadContext->clientFd = 0; + threadContext->seqNumber = 0; + } + + threadContext->callerPid = oldPid; + threadContext->callerUid = oldUid; + if (memcpy_s(threadContext->callerDeviceID, DEVICEID_LENGTH, oldDeviceId, DEVICEID_LENGTH) != EOK) { + RPC_LOG_ERROR("threadContext callerDeviceID memcpy failed"); + } +} + +static void ProcessReply(const dbinder_transaction_data *tr, uint32_t listenFd) +{ + ThreadMessageInfo *messageInfo = QueryThreadBySeqNumber(tr->seqNumber); + if (messageInfo == NULL) { + RPC_LOG_ERROR("no thread waiting reply message of this seqNumber"); + /* messageInfo is null, no thread need to wakeup */ + return; + } + + size_t bufferSize = tr->sizeOfSelf - sizeof(dbinder_transaction_data); + messageInfo->buffer = (void *)malloc(bufferSize); + if (messageInfo->buffer == NULL) { + RPC_LOG_ERROR("some thread is waiting for reply message, but no memory"); + /* wake up sender thread */ + WakeUpThreadBySeqNumber(tr->seqNumber, listenFd); + return; + } + + if (memcpy_s(messageInfo->buffer, bufferSize, tr->buffer, bufferSize) != EOK) { + RPC_LOG_ERROR("messageInfo buffer memset failed"); + free(messageInfo->buffer); + WakeUpThreadBySeqNumber(tr->seqNumber, listenFd); + return; + } + + messageInfo->flags = tr->flags; + messageInfo->bufferSize = tr->buffer_size; + messageInfo->offsetsSize = tr->offsets_size; + messageInfo->offsets = tr->offsets; + messageInfo->socketId = listenFd; + + /* wake up sender thread */ + WakeUpThreadBySeqNumber(tr->seqNumber, listenFd); +} + +static void OnTransaction(ThreadProcessInfo *processInfo) +{ + if (processInfo == NULL) { + return; + } + dbinder_transaction_data *tr = (dbinder_transaction_data *)processInfo->buffer; + tr->buffer = (char *)(processInfo->buffer + sizeof(dbinder_transaction_data)); + + if (tr->cmd == BC_TRANSACTION) { + ProcessTransaction(tr, processInfo->listenFd); + } else if (tr->cmd == BC_REPLY) { + ProcessReply(tr, processInfo->listenFd); + } +} + +static ThreadProcessInfo *MakeThreadProcessInfo(uint32_t handle, const char *inBuffer, uint32_t size) +{ + if (inBuffer == NULL || size < sizeof(dbinder_transaction_data)) { + RPC_LOG_ERROR("buffer is null or size invalid"); + return NULL; + } + + ThreadProcessInfo *processInfo = (ThreadProcessInfo *)malloc(sizeof(ThreadProcessInfo)); + if (processInfo == NULL) { + return NULL; + } + processInfo->buffer = (char *)malloc(size); + if (processInfo->buffer == NULL) { + free(processInfo); + return NULL; + } + if (memcpy_s(processInfo->buffer, size, inBuffer, size) != EOK) { + free(processInfo->buffer); + free(processInfo); + return NULL; + } + processInfo->listenFd = handle; + processInfo->packageSize = size; + + return processInfo; +} + +static int32_t CreateProcessThread(void) +{ + IpcSkeleton *current = GetCurrentSkeleton(); + if (current == NULL) { + RPC_LOG_ERROR("current ipcskeleton is nullptr"); + return ERR_FAILED; + } + if (current->threadPool->idleSocketThreadNum > 0) { + SpawnThread(SPAWN_PASSIVE, IF_PROT_DATABUS); + RPC_LOG_INFO("create Process thread success"); + return ERR_NONE; + } + return ERR_FAILED; +} + +static void StartProcessLoop(uint32_t handle, const void *buffer, uint32_t size) +{ + ThreadProcessInfo *processInfo = MakeThreadProcessInfo(handle, buffer, size); + if (processInfo == NULL) { + RPC_LOG_ERROR("MakeThreadProcessInfo failed"); + return; + } + + IdleDataThread *idleDataThread = GetIdleDataThread(); + if (idleDataThread == NULL) { + if (CreateProcessThread() != ERR_NONE) { + RPC_LOG_ERROR("create IO thread failed"); + } + do { + /* no IO thread in idle state, wait a monent */ + usleep(GET_IDLE_THREAD_WAIT_TIME); + idleDataThread = GetIdleDataThread(); + } while (idleDataThread == NULL); + } + pthread_t threadId = idleDataThread->threadId; + processInfo->threadId = threadId; + AddDataInfoToThread(processInfo); + WakeUpDataThread(threadId); +} + +int32_t OnReceiveNewConnection(int sessionId) +{ + uint32_t handle = sessionId; + IpcSkeleton *current = GetCurrentSkeleton(); + if (current == NULL) { + RPC_LOG_ERROR("current ipcskeleton is nullptr"); + return ERR_FAILED; + } + + HandleSessionList *stubSession = (HandleSessionList *)malloc(sizeof(HandleSessionList)); + if (stubSession == NULL) { + RPC_LOG_ERROR("stubSession malloc failed"); + return ERR_FAILED; + } + stubSession->handle = handle; + stubSession->sessionId = sessionId; + if (AttachStubSession(stubSession) != ERR_NONE) { + RPC_LOG_ERROR("AttachStubSession failed"); + free(stubSession); + return ERR_FAILED; + } + return ERR_NONE; +} + +void OnDatabusSessionClosed(int sessionId) +{ + if (sessionId < 0) { + return; + } + + uint32_t handle = sessionId; + HandleSessionList *handleSession = QueryStubSession(handle); + if (handleSession != NULL) { + DetachStubSession(handleSession); + free(handleSession); + RPC_LOG_INFO("OnDatabusSessionClosed called on rpc stub"); + return; + } + + handleSession = QueryProxySessionBySessionId(sessionId); + if (handleSession == NULL) { + RPC_LOG_INFO("OnDatabusSessionClosed query session is null"); + return; + } + DetachProxySession(handleSession); + + HandleToIndexList *handeleIndex = QueryHandleToIndex(handleSession->handle); + if (handeleIndex == NULL) { + RPC_LOG_INFO("OnDatabusSessionClosed query stub index is null"); + return; + } + DetachHandleToIndex(handeleIndex); + + IpcSkeleton *ipcSkeleton = GetCurrentSkeleton(); + if (ipcSkeleton == NULL) { + RPC_LOG_ERROR("GetCurrentSkeleton return null"); + return; + } + + DeathCallback *node = NULL; + UTILS_DL_LIST_FOR_EACH_ENTRY(node, &ipcSkeleton->objects, DeathCallback, list) + { + if (node->handle == handleSession->handle) { + RPC_LOG_INFO("OnDatabusSessionClosed SendObituary handle %d", node->handle); + SendObituary(node); + DeleteDeathCallback(node); + break; + } + } +} + +static uint32_t HasCompletePackage(const char *data, uint32_t readCursor, unsigned int len) +{ + const dbinder_transaction_data *tr = (const dbinder_transaction_data *)(data + readCursor); + if ((tr->magic == DBINDER_MAGICWORD) && + (tr->sizeOfSelf <= SOCKET_MAX_BUFF_SIZE + sizeof(dbinder_transaction_data)) && + (readCursor + tr->sizeOfSelf <= len)) { + return (uint32_t)tr->sizeOfSelf; + } + return 0; +} + +void OnMessageAvailable(int sessionId, const void *data, unsigned int len) +{ + if (sessionId < 0 || data == NULL || len < sizeof(dbinder_transaction_data)) { + RPC_LOG_ERROR("session has wrong inputs"); + return; + } + + uint32_t handle = sessionId; + uint32_t readSize = 0; + while (readSize + sizeof(dbinder_transaction_data) < len) { + uint32_t packageSize = HasCompletePackage(data, readSize, len); + if (packageSize > 0) { + StartProcessLoop(handle, data, packageSize); + readSize += packageSize; + } else { + // If the current is abnormal, the subsequent is no longer processed. + break; + } + }; +} + +void UpdateClientSession(int32_t handle, HandleSessionList *sessionObject, const char *sessionName, + const char *serviceName, const char *deviceId) +{ + if (handle < 0 || sessionObject == NULL || sessionName == NULL || serviceName == NULL || deviceId == NULL) { + return; + } + + RpcSkeleton *rpcSkeleton = GetCurrentRpcSkeleton(); + if (rpcSkeleton == NULL) { + return; + } + int sessionId = rpcSkeleton->rpcTrans->Connect(serviceName, deviceId, NULL); + if (sessionId < 0) { + RPC_LOG_ERROR("UpdateClientSession OpenSessionSync failed"); + return; + } + + sessionObject->handle = handle; + sessionObject->sessionId = sessionId; + if (AttachProxySession(sessionObject) != ERR_NONE) { + RPC_LOG_ERROR("UpdateClientSession AttachProxySession failed"); + } +} + +int32_t CreateTransServer(const char *sessionName) +{ + if (sessionName == NULL) { + return ERR_FAILED; + } + RpcSkeleton *rpcSkeleton = GetCurrentRpcSkeleton(); + if (rpcSkeleton == NULL) { + return ERR_FAILED; + } + + if (rpcSkeleton->isServerCreated == 0) { + return ERR_NONE; + } + + pthread_mutex_lock(&rpcSkeleton->lock); + if (rpcSkeleton->isServerCreated == -1) { + if (rpcSkeleton->rpcTrans->StartListen(sessionName, GetRpcTransCallback()) != ERR_NONE) { + RPC_LOG_ERROR("CreateTransServer failed"); + pthread_mutex_unlock(&rpcSkeleton->lock); + return ERR_FAILED; + } + rpcSkeleton->isServerCreated = 0; + pthread_mutex_unlock(&rpcSkeleton->lock); + return SpawnThread(SPAWN_ACTIVE, IF_PROT_DATABUS); + } + pthread_mutex_unlock(&rpcSkeleton->lock); + + return ERR_NONE; +} + +static int32_t RpcAcquireHandle(int32_t handle) +{ + return ERR_NONE; +} + +static int32_t RpcReleaseHandle(int32_t handle) +{ + return ERR_NONE; +} + +static int32_t RpcInvokerSendRequest(SvcIdentity target, uint32_t code, IpcIo *data, IpcIo *reply, + MessageOption option, uintptr_t *buffer) +{ + RPC_LOG_INFO("RPCInvokerSendRequest called"); + int32_t result = ERR_NONE; + uint64_t seqNumber = 0; + int userWaitTime = DEFAULT_SEND_WAIT_TIME; + + HandleSessionList *sessinoObject = WriteTransaction(BC_TRANSACTION, option, target.handle, + 0, code, data, &seqNumber, 0); + if (sessinoObject == NULL) { + return ERR_FAILED; + } + + if (option & TF_OP_ASYNC) { + result = SendOrWaitForCompletion(userWaitTime, seqNumber, sessinoObject, NULL, buffer); + } else { + result = SendOrWaitForCompletion(userWaitTime, seqNumber, sessinoObject, reply, buffer); + } + + return result; +} + +static int32_t RpcFreeBuffer(void *ptr) +{ + if (ptr != NULL) { + free(ptr); + } + return ERR_NONE; +} + +static int32_t RpcSetMaxWorkThread(int32_t maxThreadNum) +{ + return ERR_NONE; +} + +static void RpcJoinThread(bool initiative) +{ + pthread_t threadId = pthread_self(); + + ThreadContext *threadContext = GetCurrentThreadContext(); + if (threadContext == NULL) { + return; + } + threadContext->stopWorkThread = false; + + while (threadContext->stopWorkThread == false) { + AddDataThreadInWait(threadId); + ThreadProcessInfo *processInfo = PopDataInfoFromThread(threadId); + if (processInfo != NULL) { + OnTransaction(processInfo); + free(processInfo->buffer); + free(processInfo); + } + }; +} + +void RpcStopWorkThread(void) +{ + IpcSkeleton *current = GetCurrentSkeleton(); + if (current == NULL) { + return; + } + + ThreadContext *threadContext = GetCurrentThreadContext(); + if (threadContext == NULL) { + return; + } + threadContext->stopWorkThread = true; +} + +int32_t RpcSetRegistryObject(void) +{ + return ERR_NONE; +} + +static int32_t RpcAddDeathRecipient(int32_t handle, void *cookie) +{ + return ERR_NONE; +} + +static int32_t RpcRemoveDeathRecipient(int32_t handle, void *cookie) +{ + return ERR_NONE; +} + +RemoteInvoker *GetRpcInvoker(void) +{ + if (g_rpcInvoker == NULL) { + g_rpcInvoker = (RemoteInvoker *)malloc(sizeof(RemoteInvoker)); + if (g_rpcInvoker != NULL) { + g_rpcInvoker->AcquireHandle = RpcAcquireHandle; + g_rpcInvoker->ReleaseHandle = RpcReleaseHandle; + g_rpcInvoker->SendRequest = RpcInvokerSendRequest; + g_rpcInvoker->FreeBuffer = RpcFreeBuffer; + g_rpcInvoker->SetMaxWorkThread = RpcSetMaxWorkThread; + g_rpcInvoker->JoinThread = RpcJoinThread; + g_rpcInvoker->ExitCurrentThread = RpcStopWorkThread; + g_rpcInvoker->SetRegistryObject = RpcSetRegistryObject; + g_rpcInvoker->AddDeathRecipient = RpcAddDeathRecipient; + g_rpcInvoker->RemoveDeathRecipient = RpcRemoveDeathRecipient; + } + } + + return g_rpcInvoker; +} \ No newline at end of file diff --git a/ipc/native/c/rpc/src/rpc_process_skeleton.c b/ipc/native/c/rpc/src/rpc_process_skeleton.c new file mode 100644 index 0000000000000000000000000000000000000000..b5053f698344a641c835f9ed72a286b8909d9575 --- /dev/null +++ b/ipc/native/c/rpc/src/rpc_process_skeleton.c @@ -0,0 +1,497 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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. + */ + +#include "rpc_process_skeleton.h" + +#include +#include +#include + +#include "ipc_proxy_inner.h" +#include "ipc_stub_inner.h" +#include "dbinder_types.h" +#include "rpc_trans_callback.h" +#include "rpc_types.h" +#include "rpc_errno.h" +#include "rpc_log.h" + +#define USECTONSEC 1000 + +static RpcSkeleton g_rpcSkeleton = { + .lock = PTHREAD_MUTEX_INITIALIZER, + .isServerCreated = -1 +}; +static pthread_mutex_t g_rpcSkeletonMutex = PTHREAD_MUTEX_INITIALIZER; + +// rpc data cache +static StubObjectList g_stubObjectList = {.mutex = PTHREAD_MUTEX_INITIALIZER}; +static ThreadProcessInfoList g_processInfoList = {.mutex = PTHREAD_MUTEX_INITIALIZER}; +static SocketThreadLockInfoList g_socketLockInfoList = {.mutex = PTHREAD_MUTEX_INITIALIZER}; +static IdleDataThreadsList g_idleDataThreadsList = {.mutex = PTHREAD_MUTEX_INITIALIZER}; +static HandleSessionList g_stubSessionList; +static pthread_mutex_t g_stubSessionMutex = PTHREAD_MUTEX_INITIALIZER; +static HandleSessionList g_proxySessionList; +static pthread_mutex_t g_proxySessionMutex = PTHREAD_MUTEX_INITIALIZER; +static HandleToIndexList g_handleToIndexList; +static pthread_mutex_t g_handleToIndexMutex = PTHREAD_MUTEX_INITIALIZER; +static ThreadMessageInfo g_seqNumberToThread; +static pthread_mutex_t g_seqNumberToThreadMutex = PTHREAD_MUTEX_INITIALIZER; + +int32_t RpcProcessSkeleton(void) +{ + pthread_mutex_lock(&g_rpcSkeletonMutex); + + UtilsListInit(&g_stubObjectList.stubObjects); + UtilsListInit(&g_processInfoList.processInfo); + UtilsListInit(&g_socketLockInfoList.socketLockInfo); + UtilsListInit(&g_idleDataThreadsList.idleDataThread); + UtilsListInit(&g_stubSessionList.list); + UtilsListInit(&g_proxySessionList.list); + UtilsListInit(&g_handleToIndexList.list); + UtilsListInit(&g_seqNumberToThread.list); + + g_rpcSkeleton.seqNumber = 0; + g_rpcSkeleton.rpcTrans = GetRpcTrans(); + + pthread_mutex_unlock(&g_rpcSkeletonMutex); + + return ERR_NONE; +} + +RpcSkeleton *GetCurrentRpcSkeleton(void) +{ + return &g_rpcSkeleton; +} + +int32_t AddStubByIndex(StubObject *stubObject) +{ + pthread_mutex_lock(&g_stubObjectList.mutex); + UtilsListAdd(&g_stubObjectList.stubObjects, &stubObject->list); + pthread_mutex_unlock(&g_stubObjectList.mutex); + return ERR_NONE; +} + +StubObject *QueryStubByIndex(uint64_t stubIndex) +{ + StubObject *node = NULL; + pthread_mutex_lock(&g_stubObjectList.mutex); + UTILS_DL_LIST_FOR_EACH_ENTRY(node, &g_stubObjectList.stubObjects, StubObject, list) + { + if (node->stubIndex == stubIndex) { + pthread_mutex_unlock(&g_stubObjectList.mutex); + return node; + } + } + pthread_mutex_unlock(&g_stubObjectList.mutex); + return NULL; +} + +static int32_t AttachThreadLockInfo(SocketThreadLockInfo *threadLockInfo) +{ + pthread_mutex_lock(&g_socketLockInfoList.mutex); + UtilsListAdd(&g_socketLockInfoList.socketLockInfo, &threadLockInfo->list); + pthread_mutex_unlock(&g_socketLockInfoList.mutex); + return ERR_NONE; +} + +static SocketThreadLockInfo *QueryThreadLockInfo(pthread_t threadId) +{ + SocketThreadLockInfo *node = NULL; + pthread_mutex_lock(&g_socketLockInfoList.mutex); + UTILS_DL_LIST_FOR_EACH_ENTRY(node, &g_socketLockInfoList.socketLockInfo, SocketThreadLockInfo, list) + { + if (pthread_equal(node->threadId, threadId) != 0) { + pthread_mutex_unlock(&g_socketLockInfoList.mutex); + return node; + } + } + pthread_mutex_unlock(&g_socketLockInfoList.mutex); + return NULL; +} + +static int32_t AddDataThreadToIdle(IdleDataThread *idleDataThread) +{ + pthread_mutex_lock(&g_idleDataThreadsList.mutex); + UtilsListAdd(&g_idleDataThreadsList.idleDataThread, &idleDataThread->list); + pthread_mutex_unlock(&g_idleDataThreadsList.mutex); + return ERR_NONE; +} + +static void DeleteDataThreadFromIdle(IdleDataThread *idleDataThread) +{ + pthread_mutex_lock(&g_idleDataThreadsList.mutex); + UtilsListDelete(&idleDataThread->list); + pthread_mutex_unlock(&g_idleDataThreadsList.mutex); +} + +void AddDataThreadInWait(pthread_t threadId) +{ + SocketThreadLockInfo *threadLockInfo = QueryThreadLockInfo(threadId); + if (threadLockInfo == NULL) { + threadLockInfo = (SocketThreadLockInfo *)malloc(sizeof(SocketThreadLockInfo)); + if (threadLockInfo == NULL) { + RPC_LOG_ERROR("SocketThreadLockInfo malloc failed"); + return; + } + threadLockInfo->threadId = threadId; + if (pthread_mutex_init(&threadLockInfo->mutex, NULL) != 0) { + RPC_LOG_ERROR("SocketThreadLockInfo mutex init failed"); + free(threadLockInfo); + return; + } + if (pthread_cond_init(&threadLockInfo->condition, NULL) != 0) { + RPC_LOG_ERROR("SocketThreadLockInfo cond init failed"); + free(threadLockInfo); + return; + } + if (AttachThreadLockInfo(threadLockInfo) != ERR_NONE) { + free(threadLockInfo); + return; + } + } + + pthread_mutex_lock(&threadLockInfo->mutex); + IdleDataThread idleDataThread = {.threadId = threadId}; + if (AddDataThreadToIdle(&idleDataThread) != ERR_NONE) { + RPC_LOG_ERROR("AddDataThreadToIdle failed"); + pthread_mutex_unlock(&threadLockInfo->mutex); + return; + } + + pthread_cond_wait(&threadLockInfo->condition, &threadLockInfo->mutex); + DeleteDataThreadFromIdle(&idleDataThread); + pthread_mutex_unlock(&threadLockInfo->mutex); +} + +void WakeUpDataThread(pthread_t threadId) +{ + SocketThreadLockInfo *threadLockInfo = QueryThreadLockInfo(threadId); + if (threadLockInfo != NULL) { + pthread_mutex_lock(&threadLockInfo->mutex); + pthread_cond_signal(&threadLockInfo->condition); + pthread_mutex_unlock(&threadLockInfo->mutex); + } +} + +IdleDataThread *GetIdleDataThread(void) +{ + IdleDataThread *node = NULL; + pthread_mutex_lock(&g_idleDataThreadsList.mutex); + UTILS_DL_LIST_FOR_EACH_ENTRY(node, &g_idleDataThreadsList.idleDataThread, IdleDataThread, list) + { + pthread_mutex_unlock(&g_idleDataThreadsList.mutex); + return node; + } + pthread_mutex_unlock(&g_idleDataThreadsList.mutex); + return NULL; +} + +void AddDataInfoToThread(ThreadProcessInfo *processInfo) +{ + pthread_mutex_lock(&g_processInfoList.mutex); + UtilsListAdd(&g_processInfoList.processInfo, &processInfo->list); + pthread_mutex_unlock(&g_processInfoList.mutex); +} + +ThreadProcessInfo *PopDataInfoFromThread(pthread_t threadId) +{ + ThreadProcessInfo *node = NULL; + pthread_mutex_lock(&g_processInfoList.mutex); + UTILS_DL_LIST_FOR_EACH_ENTRY(node, &g_processInfoList.processInfo, ThreadProcessInfo, list) + { + if (pthread_equal(node->threadId, threadId) != 0) { + UtilsListDelete(&node->list); + pthread_mutex_unlock(&g_processInfoList.mutex); + return node; + } + } + pthread_mutex_unlock(&g_processInfoList.mutex); + return NULL; +} + +uint32_t ConvertChannelID2Int(int64_t databusChannelId) +{ + if (databusChannelId < 0) { + return 0; + } + uint32_t channelType = (uint32_t)((databusChannelId >> 8) & 0X00000000FF000000ULL); + uint32_t channelID = (uint32_t)(databusChannelId & 0X0000000000FFFFFFULL); + return (channelType | channelID); +} + +int32_t AttachStubSession(HandleSessionList *handleSession) +{ + pthread_mutex_lock(&g_stubSessionMutex); + UtilsListAdd(&g_stubSessionList.list, &handleSession->list); + pthread_mutex_unlock(&g_stubSessionMutex); + return ERR_NONE; +} + +void DetachStubSession(HandleSessionList *handleSession) +{ + pthread_mutex_lock(&g_stubSessionMutex); + UtilsListDelete(&handleSession->list); + pthread_mutex_unlock(&g_stubSessionMutex); +} + +HandleSessionList *QueryStubSession(uint32_t handle) +{ + HandleSessionList *node = NULL; + pthread_mutex_lock(&g_stubSessionMutex); + UTILS_DL_LIST_FOR_EACH_ENTRY(node, &g_stubSessionList.list, HandleSessionList, list) + { + if (node->handle == handle) { + pthread_mutex_unlock(&g_stubSessionMutex); + return node; + } + } + pthread_mutex_unlock(&g_stubSessionMutex); + return NULL; +} + +int32_t AttachProxySession(HandleSessionList *handleSession) +{ + pthread_mutex_lock(&g_proxySessionMutex); + UtilsListAdd(&g_proxySessionList.list, &handleSession->list); + pthread_mutex_unlock(&g_proxySessionMutex); + return ERR_NONE; +} + +void DetachProxySession(HandleSessionList *handleSession) +{ + pthread_mutex_lock(&g_proxySessionMutex); + UtilsListDelete(&handleSession->list); + pthread_mutex_unlock(&g_proxySessionMutex); +} + +HandleSessionList *QueryProxySession(uint32_t handle) +{ + HandleSessionList *node = NULL; + pthread_mutex_lock(&g_proxySessionMutex); + UTILS_DL_LIST_FOR_EACH_ENTRY(node, &g_proxySessionList.list, HandleSessionList, list) + { + if (node->handle == handle) { + pthread_mutex_unlock(&g_proxySessionMutex); + return node; + } + } + pthread_mutex_unlock(&g_proxySessionMutex); + return NULL; +} + +HandleSessionList *QueryProxySessionBySessionId(uint32_t sessionId) +{ + HandleSessionList *node = NULL; + pthread_mutex_lock(&g_proxySessionMutex); + UTILS_DL_LIST_FOR_EACH_ENTRY(node, &g_proxySessionList.list, HandleSessionList, list) + { + if (node->sessionId == sessionId) { + pthread_mutex_unlock(&g_proxySessionMutex); + return node; + } + } + pthread_mutex_unlock(&g_proxySessionMutex); + return NULL; +} + +uint64_t ProcessGetSeqNumber() +{ + pthread_mutex_lock(&g_rpcSkeleton.lock); + + ++g_rpcSkeleton.seqNumber; // can be overflow, and seqNumber do not use 0 + if (g_rpcSkeleton.seqNumber == 0) { + ++g_rpcSkeleton.seqNumber; + } + + pthread_mutex_unlock(&g_rpcSkeleton.lock); + return g_rpcSkeleton.seqNumber; +} + +int32_t AttachHandleToIndex(HandleToIndexList *handleToIndex) +{ + pthread_mutex_lock(&g_handleToIndexMutex); + UtilsListAdd(&g_handleToIndexList.list, &handleToIndex->list); + pthread_mutex_unlock(&g_handleToIndexMutex); + return ERR_NONE; +} + +void DetachHandleToIndex(HandleToIndexList *handleToIndex) +{ + pthread_mutex_lock(&g_handleToIndexMutex); + UtilsListDelete(&handleToIndex->list); + pthread_mutex_unlock(&g_handleToIndexMutex); +} + +HandleToIndexList *QueryHandleToIndex(uint32_t handle) +{ + HandleToIndexList *node = NULL; + pthread_mutex_lock(&g_handleToIndexMutex); + UTILS_DL_LIST_FOR_EACH_ENTRY(node, &g_handleToIndexList.list, HandleToIndexList, list) + { + if (node->handle == handle) { + pthread_mutex_unlock(&g_handleToIndexMutex); + return node; + } + } + pthread_mutex_unlock(&g_handleToIndexMutex); + return NULL; +} + +static int32_t AddThreadBySeqNumber(ThreadMessageInfo *messageInfo) +{ + pthread_mutex_lock(&g_seqNumberToThreadMutex); + UtilsListAdd(&g_seqNumberToThread.list, &messageInfo->list); + pthread_mutex_unlock(&g_seqNumberToThreadMutex); + return ERR_NONE; +} + +int32_t AddSendThreadInWait(uint64_t seqNumber, ThreadMessageInfo *messageInfo, int userWaitTime) +{ + if (AddThreadBySeqNumber(messageInfo) != ERR_NONE) { + RPC_LOG_ERROR("add seqNumber = %llu failed", seqNumber); + free(messageInfo); + return ERR_FAILED; + } + + SocketThreadLockInfo *threadLockInfo = QueryThreadLockInfo(messageInfo->threadId); + if (threadLockInfo == NULL) { + threadLockInfo = (SocketThreadLockInfo *)malloc(sizeof(SocketThreadLockInfo)); + if (threadLockInfo == NULL) { + RPC_LOG_ERROR("threadLockInfo malloc failed"); + return ERR_FAILED; + } + + pthread_mutex_init(&threadLockInfo->mutex, NULL); + pthread_cond_init(&threadLockInfo->condition, NULL); + threadLockInfo->threadId = messageInfo->threadId; + + int32_t ret = AttachThreadLockInfo(threadLockInfo); + if (ret != ERR_NONE) { + RPC_LOG_ERROR("AttachThreadLockInfo fail"); + free(threadLockInfo); + return ERR_FAILED; + } + } + + pthread_mutex_lock(&threadLockInfo->mutex); + if (userWaitTime < 0) { + pthread_cond_wait(&threadLockInfo->condition, &threadLockInfo->mutex); + } else { + struct timespec waitTime; + struct timeval now; + if (gettimeofday(&now, NULL) != 0) { + RPC_LOG_ERROR("gettimeofday failed"); + pthread_mutex_unlock(&threadLockInfo->mutex); + return ERR_FAILED; + } + + waitTime.tv_sec = now.tv_sec + DEFAULT_SEND_WAIT_TIME; + waitTime.tv_nsec = now.tv_usec * USECTONSEC; + int ret = pthread_cond_timedwait(&threadLockInfo->condition, &threadLockInfo->mutex, &waitTime); + pthread_mutex_unlock(&threadLockInfo->mutex); + if (ret == ETIMEDOUT) { + RPC_LOG_ERROR("send thread wait for reply timeout"); + return ERR_FAILED; + } + } + + return ERR_NONE; +} + +void EraseThreadBySeqNumber(ThreadMessageInfo *messageInfo) +{ + pthread_mutex_lock(&g_seqNumberToThreadMutex); + UtilsListDelete(&messageInfo->list); + pthread_mutex_unlock(&g_seqNumberToThreadMutex); +} + +ThreadMessageInfo *QueryThreadBySeqNumber(uint64_t seqNumber) +{ + ThreadMessageInfo *node = NULL; + pthread_mutex_lock(&g_seqNumberToThreadMutex); + UTILS_DL_LIST_FOR_EACH_ENTRY(node, &g_seqNumberToThread.list, ThreadMessageInfo, list) + { + if (node->seqNumber == seqNumber) { + pthread_mutex_unlock(&g_seqNumberToThreadMutex); + return node; + } + } + pthread_mutex_unlock(&g_seqNumberToThreadMutex); + return NULL; +} + +void WakeUpThreadBySeqNumber(uint64_t seqNumber, uint32_t handle) +{ + ThreadMessageInfo *messageInfo = QueryThreadBySeqNumber(seqNumber); + if (messageInfo == NULL) { + RPC_LOG_ERROR("error! messageInfo is nullptr"); + return; + } + + if (handle != messageInfo->socketId) { + RPC_LOG_ERROR("error! handle is not equal messageInfo, handle = %d, messageFd = %u", handle, + messageInfo->socketId); + return; + } + if (pthread_equal(messageInfo->threadId, pthread_self()) == 0) { + SocketThreadLockInfo *threadLockInfo = QueryThreadLockInfo(messageInfo->threadId); + if (threadLockInfo != NULL) { + /* wake up this IO thread to process socket stream + * Wake up the client processing thread + */ + pthread_mutex_lock(&threadLockInfo->mutex); + pthread_cond_signal(&threadLockInfo->condition); + pthread_mutex_unlock(&threadLockInfo->mutex); + } + } +} + +int32_t RpcOnRemoteRequestInner(uint32_t code, IpcIo *data, IpcIo *reply, MessageOption option, + IpcObjectStub *objectStub) +{ + int32_t result = ERR_FAILED; + switch (code) { + case INVOKE_LISTEN_THREAD: { + result = InvokerListenThreadStub(code, data, reply, option, objectStub->func); + break; + } + case GET_UIDPID_INFO: { + result = GetPidAndUidInfoStub(code, data, reply, option); + break; + } + case GRANT_DATABUS_NAME: { + result = GrantDataBusNameStub(code, data, reply, option); + break; + } + default: + result = ERR_NOT_RPC; + break; + } + return result; +} + +void UpdateProtoIfNeed(int32_t handle) +{ + RPC_LOG_INFO("rpc manager update proto, handle %d", handle); + UpdateProto(handle); +} + +uint64_t GetNewStubIndex(void) +{ + pthread_mutex_lock(&g_rpcSkeleton.lock); + uint64_t stubIndex = ++g_rpcSkeleton.stubIndex; + pthread_mutex_unlock(&g_rpcSkeleton.lock); + return stubIndex; +} \ No newline at end of file diff --git a/ipc/native/c/rpc/src/rpc_process_skeleton_virtual.c b/ipc/native/c/rpc/src/rpc_process_skeleton_virtual.c new file mode 100644 index 0000000000000000000000000000000000000000..bba055c15f13c336a39e923eef8e00b086d8bb86 --- /dev/null +++ b/ipc/native/c/rpc/src/rpc_process_skeleton_virtual.c @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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. + */ + +#include "rpc_process_skeleton.h" + +#include "dbinder_invoker.h" +#include "rpc_errno.h" + +int32_t RpcProcessSkeleton(void) +{ + return ERR_NONE; +} + +RpcSkeleton *GetCurrentRpcSkeleton(void) +{ + return NULL; +} + +int32_t RpcOnRemoteRequestInner(uint32_t code, IpcIo *data, IpcIo *reply, MessageOption option, + IpcObjectStub *objectStub) +{ + return ERR_NOT_RPC; +} + +void UpdateProtoIfNeed(int32_t handle) +{ + return; +} + +RemoteInvoker *GetRpcInvoker(void) +{ + return NULL; +} \ No newline at end of file diff --git a/ipc/native/c/rpc/src/rpc_trans_callback.c b/ipc/native/c/rpc/src/rpc_trans_callback.c new file mode 100644 index 0000000000000000000000000000000000000000..1c09a6baa8110ed7a316eff4993694e7aa67258e --- /dev/null +++ b/ipc/native/c/rpc/src/rpc_trans_callback.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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. + */ + +#include "rpc_trans_callback.h" + +#include "rpc_log.h" +#include "rpc_errno.h" +#include "dbinder_invoker.h" + +static int32_t OnConnected(int32_t sessionId, int32_t result) +{ + if (sessionId < 0 || result != 0) { + RPC_LOG_ERROR("fail to open session because of wrong channel ID"); + return ERR_FAILED; + } + RPC_LOG_INFO("rpc OnConnected callback, receive sessionId: %d", sessionId); + return OnReceiveNewConnection(sessionId); +} + +static int32_t OnDisconnected(int32_t sessionId) +{ + RPC_LOG_INFO("rpc OnDisconnected callback, receive sessionId: %d", sessionId); + OnDatabusSessionClosed(sessionId); + return ERR_NONE; +} + +static int32_t OnRecieved(int32_t sessionId, const void *data, uint32_t len) +{ + RPC_LOG_INFO("rpc OnRecieved callback, receive sessionId: %d", sessionId); + OnMessageAvailable(sessionId, data, len); + return ERR_NONE; +} + +static TransCallback g_sessionListener = { + .OnConnected = OnConnected, + .OnDisconnected = OnDisconnected, + .OnRecieved = OnRecieved +}; + +TransCallback *GetRpcTransCallback(void) +{ + RPC_LOG_INFO("GetTransCallback rpc"); + return &g_sessionListener; +} \ No newline at end of file diff --git a/ipc/native/c/rpc/trans_adapter/include/rpc_trans.h b/ipc/native/c/rpc/trans_adapter/include/rpc_trans.h new file mode 100644 index 0000000000000000000000000000000000000000..1d8983ddabbe7c0d42406e0658ce785221297f2b --- /dev/null +++ b/ipc/native/c/rpc/trans_adapter/include/rpc_trans.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_RPC_TRANS_H +#define OHOS_RPC_TRANS_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + int32_t (*OnConnected)(int32_t sessionId, int32_t result); + int32_t (*OnDisconnected)(int32_t sessionId); + int32_t (*OnRecieved)(int32_t sessionId, const void *data, uint32_t len); +} TransCallback; + +typedef struct { + int32_t (*StartListen)(const char *SaSessionName, void *cb); + int32_t (*StopListen)(const char *SaSessionName); + int32_t (*Connect)(const char *SaSessionName, const char *peerDeviceId, void *args); + int32_t (*Disconnect)(int32_t sessionId); + int32_t (*Send)(int32_t sessionId, const void *data, uint32_t len); +} TransInterface; + +TransInterface *GetRpcTrans(void); +char *GetLocalDeviceID(void); + +#ifdef __cplusplus +} +#endif +#endif // OHOS_RPC_TRANS_H \ No newline at end of file diff --git a/ipc/native/c/rpc/trans_adapter/src/rpc_trans.c b/ipc/native/c/rpc/trans_adapter/src/rpc_trans.c new file mode 100644 index 0000000000000000000000000000000000000000..08371b14637913f469b8d833ac8400512d3601e2 --- /dev/null +++ b/ipc/native/c/rpc/trans_adapter/src/rpc_trans.c @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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. + */ + +#include "rpc_trans.h" + +#include + +#if defined(RPC_SOCKET_TRANS) +#include "rpc_socket_trans.h" +#endif + +TransInterface *GetRpcTrans(void) +{ +#if defined(RPC_SOCKET_TRANS) + return GetSocketTrans(); +#endif + + return NULL; +} + +char *GetLocalDeviceID(void) +{ +#if defined(RPC_SOCKET_TRANS) + return GetSocketLocalDeviceID(); +#endif + + return NULL; +} \ No newline at end of file diff --git a/ipc/test/rpc/BUILD.gn b/ipc/test/rpc/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..edebd1809540f3d0a4e9d1856c7730f62dced486 --- /dev/null +++ b/ipc/test/rpc/BUILD.gn @@ -0,0 +1,25 @@ +# Copyright (c) 2022 Huawei Device Co., Ltd. +# 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. + +import("//build/lite/config/component/lite_component.gni") + +lite_component("rpc_test") { + features = [] + if (ohos_kernel_type == "linux") { + features += [ + "client:rpc_client", + "server:rpc_server", + "samgr:rpc_samgr", + ] + } +} diff --git a/ipc/test/rpc/client/BUILD.gn b/ipc/test/rpc/client/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..b336c4b2e2a0d9bd672debdbffd0ead2dc49d2b2 --- /dev/null +++ b/ipc/test/rpc/client/BUILD.gn @@ -0,0 +1,41 @@ +# Copyright (c) 2020 Huawei Device Co., Ltd. +# 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. + +import("//build/lite/config/component/lite_component.gni") + +SUBSYSTEM_DIR = "//foundation/communication/ipc" +IPC_CORE_ROOT = "${SUBSYSTEM_DIR}/ipc/native/c" + +executable("rpc_client") { + sources = [ "$SUBSYSTEM_DIR/ipc/test/rpc/client/rpc_client.c" ] + include_dirs = [ + "//third_party/bounds_checking_function/include", + "//utils/native/lite/include", + "$IPC_CORE_ROOT/manager/include", + "$IPC_CORE_ROOT/rpc/trans_adapter/include", + "$IPC_CORE_ROOT/rpc/ipc_adapter/include", + "$IPC_CORE_ROOT/rpc/include", + "$IPC_CORE_ROOT/ipc/include", + "$SUBSYSTEM_DIR/interfaces/innerkits/c/dbinder/include", + "$SUBSYSTEM_DIR/interfaces/innerkits/c/ipc/include", + "$SUBSYSTEM_DIR/services/dbinder/c/include", + "//base/hiviewdfx/hilog_lite/interfaces/native/innerkits", + ] + ldflags = [ "-lstdc++" ] + deps = [ + "${SUBSYSTEM_DIR}/interfaces/innerkits/c/dbinder:dbinder", + "${SUBSYSTEM_DIR}/interfaces/innerkits/c/ipc:rpc_manager", + ] + + configs -= [ "//build/lite/config:clang_opt" ] +} diff --git a/ipc/test/rpc/client/rpc_client.c b/ipc/test/rpc/client/rpc_client.c new file mode 100644 index 0000000000000000000000000000000000000000..a29e5ed0780aee7c8e6c45f19d9d0800385bb505 --- /dev/null +++ b/ipc/test/rpc/client/rpc_client.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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. + */ + +#include +#include +#include + +#include "rpc_log.h" +#include "rpc_errno.h" +#include "rpc_trans.h" +#include "dbinder_service.h" +#include "ipc_skeleton.h" +#include "ipc_process_skeleton.h" +#include "rpc_process_skeleton.h" +#include "serializer.h" + +#define IPC_LENGTH 64 +#define NUMBER_A 12 +#define NUMBER_B 17 + +enum { + OP_ADD = 1, + OP_SUB = 2, + OP_MULTI = 3, + OP_ADD_SERVICE = 4, + OP_DBINDER_CONNECT = 5, + OP_DBINDER_RECEIVED = 6, +}; + +enum { + GET_REMOTE_SYSTEM_ABILITY_TRANSACTION = 3, + ADD_REMOTE_SYSTEM_ABILITY_TRANSACTION = 4, +}; + +static const int32_t g_saID = 16; + +static void ServerDead1(void) +{ + RPC_LOG_INFO("#### rpc server dead callback11 called"); +} + +static void RpcClientTestOne(SvcIdentity sid, MessageOption option) +{ + IpcIo data2; + uint8_t tmpData2[IPC_LENGTH]; + IpcIoInit(&data2, tmpData2, IPC_LENGTH, 0); + WriteInt32(&data2, NUMBER_A); + WriteInt32(&data2, NUMBER_B); + + IpcIo reply2; + uintptr_t ptr2 = 0; + int32_t ret = SendRequest(sid, OP_ADD, &data2, &reply2, option, &ptr2); + if (ret != ERR_NONE) { + RPC_LOG_ERROR("SendRequest OP_ADD failed, error = %d", ret); + FreeBuffer((void *)ptr2); + return; + } + + int32_t sum; + ReadInt32(&reply2, &sum); + RPC_LOG_INFO("%d + %d = %d", NUMBER_A, NUMBER_B, sum); + FreeBuffer((void *)ptr2); +} + +static void RpcClientTestTwo(SvcIdentity sid, MessageOption option) +{ + IpcIo data3; + uint8_t tmpData3[IPC_LENGTH]; + IpcIoInit(&data3, tmpData3, IPC_LENGTH, 0); + WriteInt32(&data3, NUMBER_A); + WriteInt32(&data3, NUMBER_B); + + IpcIo reply3; + uintptr_t ptr3 = 0; + int32_t ret = SendRequest(sid, OP_MULTI, &data3, &reply3, option, &ptr3); + if (ret != ERR_NONE) { + RPC_LOG_ERROR("SendRequest OP_MULTI failed, error = %d", ret); + FreeBuffer((void *)ptr3); + return; + } + + int32_t mutil; + ReadInt32(&reply3, &mutil); + RPC_LOG_INFO("%d * %d = %d", NUMBER_A, NUMBER_B, mutil); + FreeBuffer((void *)ptr3); +} + +int main(int argc, char *argv[]) +{ + RPC_LOG_INFO("Enter System Ability Client .... "); + + if (argc == 1) { + RPC_LOG_INFO("input deviceid please"); + return -1; + } + + RPC_LOG_INFO("argv 1 is %s", argv[1]); + if (strcmp(argv[1], "deviceId") == 0) { + RPC_LOG_INFO("local deviceId is %s", GetLocalDeviceID()); + return 0; + } + + const char *deviceId = argv[1]; + + IpcIo data1; + uint8_t tmpData1[IPC_LENGTH]; + IpcIoInit(&data1, tmpData1, IPC_LENGTH, 0); + WriteInt32(&data1, g_saID); + WriteString(&data1, deviceId); + + IpcIo reply1; + MessageOption option = TF_OP_SYNC; + + SvcIdentity target = { + .handle = 0 + }; + + RPC_LOG_INFO("get remote system ability from samgr."); + uintptr_t ptr = 0; + int32_t ret = SendRequest(target, GET_REMOTE_SYSTEM_ABILITY_TRANSACTION, &data1, &reply1, option, &ptr); + SvcIdentity sid; + ReadRemoteObject(&reply1, &sid); + RPC_LOG_INFO("call server add func server handle = %d.", sid.handle); + FreeBuffer((void *)ptr); + + uint32_t cbId1 = 0; + ret = AddDeathRecipient(sid, ServerDead1, NULL, &cbId1); + RPC_LOG_INFO("add death callback cbid1 = %d", ret); + + RpcClientTestOne(sid, option); + RpcClientTestTwo(sid, option); + + JoinWorkThread(); + + return 0; +} \ No newline at end of file diff --git a/ipc/test/rpc/include/rpc_mini_samgr.h b/ipc/test/rpc/include/rpc_mini_samgr.h new file mode 100644 index 0000000000000000000000000000000000000000..c02dc43d24219172874aee93f81335979da4dd3a --- /dev/null +++ b/ipc/test/rpc/include/rpc_mini_samgr.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_RPC_RPC_MINI_SAMGR_H +#define OHOS_RPC_RPC_MINI_SAMGR_H + +#include "serializer.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void RpcStartSamgr(void); +int32_t AddSystemAbility(int32_t saId, SvcIdentity *sid); +SvcIdentity *GetSystemAbilityById(int32_t systemAbility); +int32_t AddRemoteSystemAbility(int32_t saId, SvcIdentity *sid); +int32_t GetRemoteSystemAbility(int32_t saId, const char* deviceId, SvcIdentity *sid); + +#ifdef __cplusplus +} +#endif +#endif // OHOS_RPC_RPC_MINI_SAMGR_H \ No newline at end of file diff --git a/ipc/test/rpc/samgr/BUILD.gn b/ipc/test/rpc/samgr/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..a824137ffdac16be7e58144ba5d287feea7bb54c --- /dev/null +++ b/ipc/test/rpc/samgr/BUILD.gn @@ -0,0 +1,42 @@ +# Copyright (c) 2022 Huawei Device Co., Ltd. +# 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. + +import("//build/lite/config/component/lite_component.gni") + +SUBSYSTEM_DIR = "//foundation/communication/ipc" +IPC_CORE_ROOT = "${SUBSYSTEM_DIR}/ipc/native/c" + +executable("rpc_samgr") { + sources = [ "$SUBSYSTEM_DIR/ipc/test/rpc/samgr/rpc_samgr.c" ] + include_dirs = [ + "//third_party/bounds_checking_function/include", + "//utils/native/lite/include", + "$IPC_CORE_ROOT/manager/include", + "$IPC_CORE_ROOT/ipc/include", + "//foundation/communication/ipc/services/dbinder/c/include", + "//base/hiviewdfx/hilog_lite/interfaces/native/innerkits", + "$SUBSYSTEM_DIR/interfaces/innerkits/c/dbinder/include", + "$SUBSYSTEM_DIR/interfaces/innerkits/c/ipc/include", + "$SUBSYSTEM_DIR/services/dbinder/c/include", + ] + ldflags = [ + "-lstdc++", + "-lpthread", + ] + deps = [ + "${SUBSYSTEM_DIR}/interfaces/innerkits/c/dbinder:dbinder", + "${SUBSYSTEM_DIR}/interfaces/innerkits/c/ipc:rpc_manager", + ] + + configs -= [ "//build/lite/config:clang_opt" ] +} diff --git a/ipc/test/rpc/samgr/rpc_mini_samgr.c b/ipc/test/rpc/samgr/rpc_mini_samgr.c new file mode 100644 index 0000000000000000000000000000000000000000..17641eaabc4ec3382808b2e8f6230acb93b8d016 --- /dev/null +++ b/ipc/test/rpc/samgr/rpc_mini_samgr.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#include "rpc_mini_samgr.h" + +#include +#include +#include + +#include "rpc_log.h" +#include "rpc_errno.h" +#include "ipc_skeleton.h" +#include "serializer.h" +#include "utils_list.h" +#include "securec.h" +#include "dbinder_service.h" + +typedef struct { + UTILS_DL_LIST list; + int32_t saId; + SvcIdentity *sid; +} SvcInfo; + +static UTILS_DL_LIST *g_saList = NULL; +static pthread_mutex_t g_handleMutex = PTHREAD_MUTEX_INITIALIZER; +static int32_t g_handle = 0; + +int32_t AddSystemAbility(int32_t saId, SvcIdentity *sid) +{ + RPC_LOG_INFO("AddSystemAbility called.... handle = %d", sid->handle); + RPC_LOG_INFO("AddSystemAbility called.... cookie = %u, said = %d", sid->cookie, saId); + if (g_saList == NULL) { + return ERR_FAILED; + } + + SvcInfo* node = (SvcInfo *)calloc(1, sizeof(SvcInfo)); + if (node == NULL) { + RPC_LOG_ERROR("AddSystemAbility node calloc failed"); + return ERR_FAILED; + } + node->saId = saId; + node->sid = (SvcIdentity *)calloc(1, sizeof(SvcIdentity)); + if (memcpy_s(node->sid, sizeof(SvcIdentity), sid, sizeof(SvcIdentity)) != EOK) { + RPC_LOG_INFO("AddSystemAbility memcpy failed"); + free(node->sid); + free(node); + return ERR_FAILED; + } + + pthread_mutex_lock(&g_handleMutex); + node->sid->handle = ++g_handle; + pthread_mutex_unlock(&g_handleMutex); + + UtilsListAdd(g_saList, &node->list); + return ERR_NONE; +} + +SvcIdentity *GetSystemAbilityById(int32_t systemAbility) +{ + SvcInfo* node = NULL; + SvcInfo* next = NULL; + UTILS_DL_LIST_FOR_EACH_ENTRY_SAFE(node, next, g_saList, SvcInfo, list) + { + RPC_LOG_INFO("GetSystemAbilityById %d", node->saId); + if (node->saId == systemAbility) { + return node->sid; + } + } + return NULL; +} + +int32_t AddRemoteSystemAbility(int32_t saId, SvcIdentity *sid) +{ + if (AddSystemAbility(saId, sid) == ERR_FAILED) { + RPC_LOG_ERROR("AddSystemAbility failed"); + return ERR_FAILED; + } + + const char *name = "16"; + if (RegisterRemoteProxy(name, strlen(name), saId) != ERR_NONE) { + RPC_LOG_ERROR("RegisterRemoteProxy failed"); + return ERR_FAILED; + } + + return ERR_NONE; +} + +int32_t GetRemoteSystemAbility(int32_t saId, const char* deviceId, SvcIdentity *sid) +{ + RPC_LOG_INFO("GetRemoteSystemAbility start"); + const char *name = "16"; + uint32_t idLen = (uint32_t)strlen(deviceId); + + int32_t ret = MakeRemoteBinder(name, 2, deviceId, idLen, (uintptr_t)saId, 0, (void *)sid); + if (ret != ERR_NONE) { + RPC_LOG_ERROR("MakeRemoteBinder failed"); + } + + return ret; +} + +void RpcStartSamgr(void) +{ + RPC_LOG_INFO("RpcStartSamgr start"); + g_saList = (UTILS_DL_LIST *)calloc(1, sizeof(UTILS_DL_LIST)); + UtilsListInit(g_saList); + + StartDBinderService(); + RPC_LOG_INFO("StartDBinderService finished"); + + return; +} \ No newline at end of file diff --git a/ipc/test/rpc/samgr/rpc_samgr.c b/ipc/test/rpc/samgr/rpc_samgr.c new file mode 100644 index 0000000000000000000000000000000000000000..0f69adb1267e574ac52b816bd9f4e893916e2ffd --- /dev/null +++ b/ipc/test/rpc/samgr/rpc_samgr.c @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#include +#include + +#include "rpc_log.h" +#include "rpc_errno.h" +#include "ipc_skeleton.h" +#include "serializer.h" +#include "utils_list.h" +#include "dbinder_service.h" + +typedef struct { + UTILS_DL_LIST list; + int32_t saId; + SvcIdentity *sid; +} SvcInfo; + +static UTILS_DL_LIST *g_saList = NULL; + +enum { + ADD_SYSTEM_ABILITY_TRANSACTION = 2, + GET_REMOTE_SYSTEM_ABILITY_TRANSACTION = 3, + ADD_REMOTE_SYSTEM_ABILITY_TRANSACTION = 4, +}; + +int32_t AddSystemAbility(int32_t saId, SvcIdentity *sid) +{ + RPC_LOG_INFO("AddSystemAbility called.... handle = %d", sid->handle); + RPC_LOG_INFO("AddSystemAbility called.... cookie = %u", sid->cookie); + if (g_saList == NULL) { + return ERR_FAILED; + } + + SvcInfo* node = (SvcInfo *)calloc(1, sizeof(SvcInfo)); + if (node == NULL) { + RPC_LOG_ERROR("AddSystemAbility node calloc failed"); + return ERR_FAILED; + } + node->saId = saId; + node->sid = sid; + UtilsListAdd(g_saList, &node->list); + return ERR_NONE; +} + +int32_t GetSystemAbility(int32_t saId, const char* deviceId, SvcIdentity *sid) +{ + SvcInfo* node = NULL; + SvcInfo* next = NULL; + UTILS_DL_LIST_FOR_EACH_ENTRY_SAFE(node, next, g_saList, SvcInfo, list) + { + if (node->saId == saId) { + sid->handle = node->sid->handle; + sid->token = node->sid->token; + sid->cookie = node->sid->cookie; + RPC_LOG_INFO("find sa, said = %d, handle = %d, cookie = %u", saId, sid->handle, sid->cookie); + return ERR_NONE; + } + } + return ERR_FAILED; +} + +int32_t AddRemoteSystemAbility(int32_t saId, SvcIdentity *sid) +{ + if (AddSystemAbility(saId, sid) == ERR_FAILED) { + RPC_LOG_ERROR("AddSystemAbility failed"); + return ERR_FAILED; + } + + const char *name = "16"; + if (RegisterRemoteProxy(name, strlen(name), saId) != ERR_NONE) { + RPC_LOG_ERROR("RegisterRemoteProxy failed"); + return ERR_FAILED; + } + + return ERR_NONE; +} + +int32_t GetRemoteSystemAbility(IpcIo *data, SvcIdentity *sid) +{ + int32_t saId; + ReadInt32(data, &saId); + size_t len; + const char *deviceId = (const char *)ReadString(data, &len); + + const char *name = "16"; + uint32_t idLen = (uint32_t)strlen(deviceId); + RPC_LOG_INFO("GetRemoteSystemAbility start"); + + int32_t ret = MakeRemoteBinder(name, 2, deviceId, idLen, (uintptr_t)saId, 0, (void *)sid); + if (ret != ERR_NONE) { + RPC_LOG_ERROR("MakeRemoteBinder failed"); + } + RPC_LOG_INFO("GetRemoteSystemAbility handle=%d, cookie=%u", sid->handle, sid->cookie); + + return ret; +} + +int32_t RemoteRequest(uint32_t code, IpcIo *data, IpcIo *reply, MessageOption option) +{ + int32_t result = ERR_NONE; + RPC_LOG_INFO("OnRemoteRequest called.... code = %d", code); + switch (code) { + case GET_SYSTEM_ABILITY_TRANSACTION: { + int32_t saId; + ReadInt32(data, &saId); + SvcIdentity sid; + result = GetSystemAbility(saId, "", &sid); + WriteRemoteObject(reply, &sid); + break; + } + case ADD_SYSTEM_ABILITY_TRANSACTION: { + int32_t saId; + ReadInt32(data, &saId); + SvcIdentity *sid = (SvcIdentity *)malloc(sizeof(SvcIdentity)); + if (sid == NULL) { + result = ERR_FAILED; + break; + } + ReadRemoteObject(data, sid); + result = AddSystemAbility(saId, sid); + break; + } + case GET_REMOTE_SYSTEM_ABILITY_TRANSACTION: { + SvcIdentity sid; + result = GetRemoteSystemAbility(data, &sid); + WriteRemoteObject(reply, &sid); + break; + } + case ADD_REMOTE_SYSTEM_ABILITY_TRANSACTION: { + int32_t saId; + ReadInt32(data, &saId); + SvcIdentity *sid = (SvcIdentity *)malloc(sizeof(SvcIdentity)); + if (sid == NULL) { + result = ERR_FAILED; + break; + } + ReadRemoteObject(data, sid); + result = AddRemoteSystemAbility(saId, sid); + break; + } + default: + RPC_LOG_ERROR("unknown code %d", code); + break; + } + return result; +} + +int main(int argc, char *argv[]) +{ + RPC_LOG_INFO("Enter System Ability Manager .... "); + + g_saList = (UTILS_DL_LIST *)calloc(1, sizeof(UTILS_DL_LIST)); + UtilsListInit(g_saList); + + IpcObjectStub objectStub = { + .func = RemoteRequest, + .isRemote = false + }; + + SvcIdentity target = { + .handle = 0, + .cookie = (uintptr_t)&objectStub + }; + + if (SetContextObject(target) != ERR_NONE) { + RPC_LOG_ERROR("SAMGR register samgr failed"); + return -1; + } + + StartDBinderService(); + RPC_LOG_INFO("StartDBinderService finished"); + + JoinWorkThread(); + return -1; +} \ No newline at end of file diff --git a/ipc/test/rpc/server/BUILD.gn b/ipc/test/rpc/server/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..40317806009a32fffa44d7d2b7b0f00d6dad51ba --- /dev/null +++ b/ipc/test/rpc/server/BUILD.gn @@ -0,0 +1,41 @@ +# Copyright (c) 2022 Huawei Device Co., Ltd. +# 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. + +import("//build/lite/config/component/lite_component.gni") + +SUBSYSTEM_DIR = "//foundation/communication/ipc" +IPC_CORE_ROOT = "${SUBSYSTEM_DIR}/ipc/native/c" + +executable("rpc_server") { + sources = [ "$SUBSYSTEM_DIR/ipc/test/rpc/server/rpc_server.c" ] + include_dirs = [ + "//third_party/bounds_checking_function/include", + "//utils/native/lite/include", + "$IPC_CORE_ROOT/ipc/include", + "$IPC_CORE_ROOT/manager/include", + "$IPC_CORE_ROOT/rpc/include", + "$IPC_CORE_ROOT/rpc/ipc_adapter/include", + "$IPC_CORE_ROOT/rpc/trans_adapter/include", + "$SUBSYSTEM_DIR/interfaces/innerkits/c/dbinder/include", + "$SUBSYSTEM_DIR/interfaces/innerkits/c/ipc/include", + "$SUBSYSTEM_DIR/services/dbinder/c/include", + "//base/hiviewdfx/hilog_lite/interfaces/native/innerkits", + ] + ldflags = [ "-lstdc++" ] + deps = [ + "${SUBSYSTEM_DIR}/interfaces/innerkits/c/dbinder:dbinder", + "${SUBSYSTEM_DIR}/interfaces/innerkits/c/ipc:rpc_manager", + ] + + configs -= [ "//build/lite/config:clang_opt" ] +} diff --git a/ipc/test/rpc/server/rpc_server.c b/ipc/test/rpc/server/rpc_server.c new file mode 100644 index 0000000000000000000000000000000000000000..292a008e80d032c322e955ba0c5f6e312d70b3a2 --- /dev/null +++ b/ipc/test/rpc/server/rpc_server.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#include +#include +#include "rpc_log.h" +#include "rpc_errno.h" +#include "ipc_skeleton.h" +#include "serializer.h" +#include "dbinder_invoker.h" +#include "dbinder_types.h" + +enum { + OP_ADD = 1, + OP_SUB = 2, + OP_MULTI = 3, + OP_ADD_SERVICE = 4, +}; + +enum { + ADD_SYSTEM_ABILITY_TRANSACTION = 2, + GET_REMOTE_SYSTEM_ABILITY_TRANSACTION = 3, + ADD_REMOTE_SYSTEM_ABILITY_TRANSACTION = 4, +}; + +static const int32_t g_saID = 16; +static const uint32_t IPC_LENGTH = 128; + +int32_t RemoteRequestOne(uint32_t code, IpcIo *data, IpcIo *reply, MessageOption option) +{ + int32_t result = ERR_NONE; + RPC_LOG_INFO("server OnRemoteRequestOne called...."); + switch (code) { + case OP_ADD: { + int32_t a; + ReadInt32(data, &a); + int32_t b; + ReadInt32(data, &b); + RPC_LOG_INFO("RemoteRequestOne add called a = %d, b = %d", a, b); + WriteInt32(reply, a + b); + break; + } + case OP_SUB: { + int32_t a; + ReadInt32(data, &a); + int32_t b; + ReadInt32(data, &b); + RPC_LOG_INFO("RemoteRequestOne sub called a = %d, b = %d", a, b); + WriteInt32(reply, a - b); + break; + } + case OP_MULTI: { + int32_t a; + ReadInt32(data, &a); + int32_t b; + ReadInt32(data, &b); + RPC_LOG_INFO("RemoteRequestOne mulit called a = %d, b = %d", a, b); + WriteInt32(reply, a * b); + break; + } + default: + RPC_LOG_ERROR("unknown code %d", code); + break; + } + return result; +} + +int main(int argc, char *argv[]) +{ + RPC_LOG_INFO("Enter System Ability Server .... "); + + IpcObjectStub objectStubOne = { + .func = RemoteRequestOne, + .isRemote = false + }; + + SvcIdentity svcOne = { + .handle = -1, + .token = (uintptr_t)&objectStubOne, + .cookie = (uintptr_t)&objectStubOne + }; + + IpcIo data; + uint8_t tmpData1[IPC_LENGTH]; + IpcIoInit(&data, tmpData1, IPC_LENGTH, 1); + WriteInt32(&data, g_saID); + WriteRemoteObject(&data, &svcOne); + + IpcIo reply; + MessageOption option = TF_OP_SYNC; + + SvcIdentity target = { + .handle = 0 + }; + + RPC_LOG_INFO("====== add ability one to samgr ======"); + uintptr_t ptr = 0; + SendRequest(target, ADD_REMOTE_SYSTEM_ABILITY_TRANSACTION, &data, &reply, option, &ptr); + int32_t ret; + ReadInt32(&reply, &ret); + RPC_LOG_INFO("send request one ret = %d .... ", ret); + FreeBuffer((void *)ptr); + + JoinWorkThread(); + return -1; +} \ No newline at end of file diff --git a/ipc/test/rpc/socket_trans/include/rpc_socket_trans.h b/ipc/test/rpc/socket_trans/include/rpc_socket_trans.h new file mode 100644 index 0000000000000000000000000000000000000000..0e2f69d89aea089005418c6ea2a4abf7592bef9d --- /dev/null +++ b/ipc/test/rpc/socket_trans/include/rpc_socket_trans.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_RPC_SOCKET_TRANS_H +#define OHOS_RPC_SOCKET_TRANS_H + +#include + +#include "utils_list.h" +#include "rpc_trans.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define DEFAULT_BACKLOG 4 +#define DEFAULT_PACKET_SIZE 1024 +#define DEFAULT_HASH_OFFSET 3 +static char const *SOCKET_SERVER_ADDR = "0.0.0.0"; +static char const *DEFAULT_NET_INTERFACE = "eth0"; +static const uint16_t DEFAULT_HASH_SEED = 5381; +static const uint16_t DEFAULT_PORT_MIN = 10000; + +TransInterface *GetSocketTrans(void); +char *GetSocketLocalDeviceID(void); + +#ifdef __cplusplus +} +#endif +#endif // OHOS_RPC_SOCKET_TRANS_H \ No newline at end of file diff --git a/ipc/test/rpc/socket_trans/src/rpc_mini_socket_trans.c b/ipc/test/rpc/socket_trans/src/rpc_mini_socket_trans.c new file mode 100644 index 0000000000000000000000000000000000000000..926c8a2147ccd5dbf4289625859d3fd296d0e109 --- /dev/null +++ b/ipc/test/rpc/socket_trans/src/rpc_mini_socket_trans.c @@ -0,0 +1,389 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#include "rpc_socket_trans.h" + +#include +#include +#include +#include +#include +#include +#include "lwip/def.h" +#include "lwip/inet.h" +#include "lwip/netif.h" +#include "lwip/netifapi.h" + +#include "utils_list.h" +#include "securec.h" +#include "rpc_errno.h" +#include "rpc_log.h" + +#define DEVICEID_LENGTH 64 +#define SERVICENAME_LENGTH 200 +#define DEFAULT_LOCAL_DEVICEID "192.168.1.74" +#define DEFAULT_THREAD_STACK_SIZE 8192 + +typedef struct { + UTILS_DL_LIST list; + char *saSessionName; + char *deviceId; + TransCallback cb; +} SocketNode; + +typedef struct { + UTILS_DL_LIST list; + pthread_mutex_t mutex; +} SocketNodeList; + +static SocketNodeList g_socketNodeList = {.mutex = PTHREAD_MUTEX_INITIALIZER}; +static int32_t g_init = -1; +static int32_t g_serverCreated = -1; +static TransCallback g_callback; +static char *g_localDeviceId = NULL; + +static uint16_t Hash(const char *name) +{ + if (name == NULL) { + return 0; + } + RPC_LOG_INFO("Hash called %s", name); + sleep(1); + + uint16_t hash = DEFAULT_HASH_SEED; + uint16_t c; + + while (c = *name++) + hash = ((hash << DEFAULT_HASH_OFFSET) + hash) + c; + + return hash % DEFAULT_PORT_MIN + DEFAULT_PORT_MIN; +} + +static int32_t BindLocalIP(int fd, const char *localIP, uint16_t port, struct sockaddr_in *addr) +{ + if (memset_s(addr, sizeof(struct sockaddr_in), 0, sizeof(*addr)) != EOK) { + RPC_LOG_ERROR("sockaddr_in memset failed"); + return ERR_FAILED; + } + + addr->sin_family = AF_INET; + int rc = inet_pton(AF_INET, localIP, &addr->sin_addr); + if (rc <= 0) { + RPC_LOG_ERROR("inet_pton rc=%d", rc); + return ERR_FAILED; + } + addr->sin_port = lwip_htons(port); + + errno = 0; + rc = bind(fd, (struct sockaddr *)addr, sizeof(*addr)); + if (rc < 0) { + RPC_LOG_ERROR("bind fd=%d,rc=%d", fd, rc); + return ERR_FAILED; + } + return ERR_NONE; +} + +static void TcpShutDown(int fd) +{ + if (fd >= 0) { + shutdown(fd, SHUT_RDWR); + close(fd); + } +} + +static void *HandleAccept(void *args) +{ + if (args == NULL) { + return NULL; + } + int32_t clientFd = *(int32_t *)args; + int32_t ret; + if (g_callback.OnConnected != NULL) { + ret = g_callback.OnConnected(clientFd, 0); + if (ret != ERR_NONE) { + RPC_LOG_ERROR("g_callback OnConnected failed"); + return NULL; + } + } + + char buf[DEFAULT_PACKET_SIZE]; + if (g_callback.OnRecieved != NULL) { + for (;;) { + ssize_t readLen = read(clientFd, buf, DEFAULT_PACKET_SIZE); + if (readLen == 0) { + RPC_LOG_INFO("client socket close"); + g_callback.OnDisconnected(clientFd); + TcpShutDown(clientFd); + return NULL; + } + if (readLen < 0) { + RPC_LOG_ERROR("socket read error=%d", readLen); + TcpShutDown(clientFd); + return NULL; + } + ret = g_callback.OnRecieved(clientFd, (void *)buf, (uint32_t)readLen); + if (ret != ERR_NONE) { + RPC_LOG_ERROR("g_callback OnRecieved failed"); + return NULL; + } + } + } + return NULL; +} + +static void *OpenTcpServerSocket(void *args) +{ + printf("OpenTcpServerSocket %d\n", strlen((char *)args)); + sleep(1); + if (args == NULL) { + return NULL; + } + + char *ip = (char *)SOCKET_SERVER_ADDR; + uint16_t port = Hash((char *)args); + + int fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) { + RPC_LOG_ERROR("fd=%d", fd); + return NULL; + } + + struct sockaddr_in addr; + int32_t ret = BindLocalIP(fd, ip, port, &addr); + if (ret != ERR_NONE) { + RPC_LOG_ERROR("BindLocalIP ret=%d", ret); + TcpShutDown(fd); + return NULL; + } + + if (listen(fd, DEFAULT_BACKLOG) != 0) { + RPC_LOG_ERROR("listen failed"); + TcpShutDown(fd); + return NULL; + } + + g_serverCreated = 0; + for (;;) { + socklen_t len = sizeof(addr); + int32_t clientFd = accept(fd, (struct sockaddr *)&addr, &len); + RPC_LOG_INFO("accept get fd %d", clientFd); + + pthread_t threadId; + pthread_attr_t threadAttr; + ret = pthread_attr_init(&threadAttr); + if (ret != 0) { + RPC_LOG_ERROR("pthread_attr_init failed %d", ret); + return ERR_FAILED; + } + + if (pthread_attr_setstacksize(&threadAttr, DEFAULT_THREAD_STACK_SIZE) != 0) { + RPC_LOG_ERROR("pthread_attr_setstacksize failed"); + return ERR_FAILED; + } + + ret = pthread_create(&threadId, &threadAttr, HandleAccept, (void *)&clientFd); + if (ret != 0) { + RPC_LOG_ERROR("pthread_create failed %d", ret); + return ERR_FAILED; + } + pthread_detach(threadId); + } + return NULL; +} + +static int32_t StartListen(const char *SaSessionName, void *cb) +{ + printf("StartListen called %s, %d\n", SaSessionName, strlen(SaSessionName)); + if (SaSessionName == NULL) { + RPC_LOG_ERROR("SaSessionName is null"); + return ERR_FAILED; + } + if (memcpy_s(&g_callback, sizeof(TransCallback), cb, sizeof(TransCallback)) != EOK) { + RPC_LOG_ERROR("g_callback memcpy_s failed"); + return ERR_FAILED; + } + + pthread_t threadId; + pthread_attr_t threadAttr; + int ret = pthread_attr_init(&threadAttr); + if (ret != 0) { + RPC_LOG_ERROR("pthread_attr_init failed %d", ret); + return ERR_FAILED; + } + + if (pthread_attr_setstacksize(&threadAttr, DEFAULT_THREAD_STACK_SIZE) != 0) { + RPC_LOG_ERROR("pthread_attr_setstacksize failed"); + return ERR_FAILED; + } + + ret = pthread_create(&threadId, &threadAttr, OpenTcpServerSocket, (void *)SaSessionName); + if (ret != 0) { + RPC_LOG_ERROR("pthread_create failed %d", ret); + return ERR_FAILED; + } + pthread_detach(threadId); + + return ERR_NONE; +} + +static int32_t StopListen(const char *SaSessionName) +{ + return ERR_NONE; +} + +static void *HandleSendReply(void *args) +{ + if (args == NULL) { + RPC_LOG_ERROR("HandleSendReply args is null"); + return NULL; + } + int32_t fd = *(int32_t *)args; + free(args); + + char buf[DEFAULT_PACKET_SIZE]; + if (g_callback.OnRecieved != NULL) { + for (;;) { + ssize_t readLen = read(fd, buf, DEFAULT_PACKET_SIZE); + if (readLen == 0) { + RPC_LOG_INFO("HandleSendReply received len %d", readLen); + g_callback.OnDisconnected(fd); + TcpShutDown(fd); + return NULL; + } + if (readLen < 0) { + RPC_LOG_ERROR("HandleSendReply received len %d", readLen); + TcpShutDown(fd); + return NULL; + } + g_callback.OnRecieved(fd, buf, readLen); + } + } + return NULL; +} + +static int32_t Connect(const char *SaSessionName, const char *peerDeviceId, void *args) +{ + if (SaSessionName == NULL) { + RPC_LOG_INFO("SaSessionName is null"); + return ERR_FAILED; + } + uint16_t port = Hash(SaSessionName); + + int fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) { + RPC_LOG_ERROR("%s:%d:fd=%d", __func__, __LINE__, fd); + return ERR_FAILED; + } + + struct sockaddr_in addr; + if (memset_s(&addr, sizeof(addr), 0, sizeof(addr)) != EOK) { + RPC_LOG_ERROR("memset failed"); + } + addr.sin_family = AF_INET; + inet_pton(AF_INET, peerDeviceId, &addr.sin_addr); + addr.sin_port = lwip_htons(port); + errno = 0; + + int rc = connect(fd, (struct sockaddr *)&addr, sizeof(addr)); + if ((rc == -1) && (errno != EINPROGRESS)) { + RPC_LOG_ERROR("fd=%d,connect rc=%d, errno=%d", fd, rc, errno); + TcpShutDown(fd); + return ERR_FAILED; + } + + int32_t *sessionId = (int32_t *)malloc(sizeof(int32_t)); + if (sessionId == NULL) { + return ERR_FAILED; + } + + *sessionId = fd; + pthread_t threadId; + pthread_attr_t threadAttr; + int ret = pthread_attr_init(&threadAttr); + if (ret != 0) { + RPC_LOG_ERROR("pthread_attr_init failed %d", ret); + return ERR_FAILED; + } + + if (pthread_attr_setstacksize(&threadAttr, DEFAULT_THREAD_STACK_SIZE) != 0) { + RPC_LOG_ERROR("pthread_attr_setstacksize failed"); + return ERR_FAILED; + } + + ret = pthread_create(&threadId, &threadAttr, HandleSendReply, (void *)sessionId); + if (ret != 0) { + RPC_LOG_ERROR("pthread_create failed %d", ret); + return ERR_FAILED; + } + pthread_detach(threadId); + + return fd; +} + +static int32_t Disconnect(int32_t sessionId) +{ + return ERR_NONE; +} + +static int32_t Send(int32_t sessionId, const void *data, uint32_t len) +{ + if (sessionId < 0 || data == NULL || len <= 0) { + RPC_LOG_ERROR("send invail params"); + return ERR_FAILED; + } + + ssize_t ret = write(sessionId, data, len); + if (ret < 0) { + RPC_LOG_ERROR("send error=%d", ret); + return ERR_FAILED; + } + + return ERR_NONE; +} + +static TransInterface g_socketTrans = { + .StartListen = StartListen, + .StopListen = StopListen, + .Connect = Connect, + .Disconnect = Disconnect, + .Send = Send +}; + +TransInterface *GetSocketTrans(void) +{ + if (g_init == -1) { + pthread_mutex_lock(&g_socketNodeList.mutex); + UtilsListInit(&g_socketNodeList.list); + g_init = 0; + printf("g_socketTrans %x\n", g_socketTrans.StartListen); + pthread_mutex_unlock(&g_socketNodeList.mutex); + } + return &g_socketTrans; +} + +char *GetSocketLocalDeviceID(void) +{ + extern struct netif if_wifi; + + uint32_t ip = ((ip4_addr_t *)&if_wifi.ip_addr)->addr; + char *localDeviceId = inet_ntoa(ip); + if (localDeviceId == NULL) { + RPC_LOG_ERROR("GetSocketLocalDeviceID inet_ntoa return null"); + return NULL; + } + + RPC_LOG_INFO("GetSocketLocalDeviceID %s\n", localDeviceId); + return localDeviceId; +} \ No newline at end of file diff --git a/ipc/test/rpc/socket_trans/src/rpc_socket_trans.c b/ipc/test/rpc/socket_trans/src/rpc_socket_trans.c new file mode 100644 index 0000000000000000000000000000000000000000..956a202b4b8bc5dd3c801bd35fe8b1e1c32e90bf --- /dev/null +++ b/ipc/test/rpc/socket_trans/src/rpc_socket_trans.c @@ -0,0 +1,368 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * 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. + */ + +#include "rpc_socket_trans.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utils_list.h" +#include "securec.h" +#include "rpc_errno.h" +#include "rpc_log.h" + +#define DEVICEID_LENGTH 64 +#define SERVICENAME_LENGTH 200 + +typedef struct { + UTILS_DL_LIST list; + char *saSessionName; + char *deviceId; + TransCallback cb; +} SocketNode; + +typedef struct { + UTILS_DL_LIST list; + pthread_mutex_t mutex; +} SocketNodeList; + +static SocketNodeList g_socketNodeList = {.mutex = PTHREAD_MUTEX_INITIALIZER}; +static int32_t g_init = -1; +static int32_t g_serverCreated = -1; +static TransCallback g_callback; +static char *g_localDeviceId = NULL; + +static uint16_t Hash(const char *name) +{ + if (name == NULL) { + return 0; + } + + uint16_t hash = DEFAULT_HASH_SEED; + uint16_t c; + + while (c = *name++) + hash = ((hash << DEFAULT_HASH_OFFSET) + hash) + c; + + return hash % DEFAULT_PORT_MIN + DEFAULT_PORT_MIN; +} + +static int32_t BindLocalIP(int fd, const char *localIP, uint16_t port, struct sockaddr_in *addr) +{ + if (memset_s(addr, sizeof(struct sockaddr_in), 0, sizeof(*addr)) != EOK) { + RPC_LOG_ERROR("sockaddr_in memset failed"); + return ERR_FAILED; + } + + addr->sin_family = AF_INET; + int rc = inet_pton(AF_INET, localIP, &addr->sin_addr); + if (rc <= 0) { + RPC_LOG_ERROR("inet_pton rc=%d", rc); + return ERR_FAILED; + } + addr->sin_port = htons(port); + + errno = 0; + rc = bind(fd, (struct sockaddr *)addr, sizeof(*addr)); + if (rc < 0) { + RPC_LOG_ERROR("bind fd=%d,rc=%d", fd, rc); + return ERR_FAILED; + } + return ERR_NONE; +} + +static void TcpShutDown(int fd) +{ + if (fd >= 0) { + shutdown(fd, SHUT_RDWR); + close(fd); + } +} + +static void HandleAccept(void *args) +{ + if (args == NULL) { + return; + } + int32_t clientFd = *(int32_t *)args; + int32_t ret; + if (g_callback.OnConnected != NULL) { + ret = g_callback.OnConnected(clientFd, 0); + if (ret != ERR_NONE) { + RPC_LOG_ERROR("g_callback OnConnected failed"); + return; + } + } + + char buf[DEFAULT_PACKET_SIZE]; + if (g_callback.OnRecieved != NULL) { + for (;;) { + ssize_t readLen = read(clientFd, buf, DEFAULT_PACKET_SIZE); + if (readLen == 0) { + RPC_LOG_INFO("client socket close"); + g_callback.OnDisconnected(clientFd); + TcpShutDown(clientFd); + return; + } + if (readLen < 0) { + RPC_LOG_ERROR("socket read error=%d", readLen); + TcpShutDown(clientFd); + return; + } + ret = g_callback.OnRecieved(clientFd, (void *)buf, (uint32_t)readLen); + if (ret != ERR_NONE) { + RPC_LOG_ERROR("g_callback OnRecieved failed"); + return; + } + } + } +} + +static void OpenTcpServerSocket(void *args) +{ + if (args == NULL) { + return; + } + + char *ip = (char *)SOCKET_SERVER_ADDR; + uint16_t port = Hash((char *)args); + + errno = 0; + int fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) { + RPC_LOG_ERROR("fd=%d", fd); + return; + } + + struct sockaddr_in addr; + int32_t ret = BindLocalIP(fd, ip, port, &addr); + if (ret != ERR_NONE) { + RPC_LOG_ERROR("BindLocalIP ret=%d", ret); + TcpShutDown(fd); + return; + } + + if (listen(fd, DEFAULT_BACKLOG) != 0) { + RPC_LOG_ERROR("listen failed"); + TcpShutDown(fd); + return; + } + + g_serverCreated = 0; + for (;;) { + socklen_t len = sizeof(addr); + int32_t clientFd = accept(fd, (struct sockaddr *)&addr, &len); + pthread_t threadId; + pthread_create(&threadId, NULL, HandleAccept, (void *)&clientFd); + pthread_detach(threadId); + } +} + +static int32_t StartListen(const char *SaSessionName, void *cb) +{ + if (g_serverCreated == 0) { + return ERR_NONE; + } + + RPC_LOG_INFO("StartListen called"); + if (SaSessionName == NULL) { + RPC_LOG_ERROR("SaSessionName is null"); + return ERR_FAILED; + } + if (memcpy_s(&g_callback, sizeof(TransCallback), cb, sizeof(TransCallback)) != EOK) { + RPC_LOG_ERROR("g_callback memcpy_s failed"); + return ERR_FAILED; + } + pthread_t threadId; + pthread_create(&threadId, NULL, OpenTcpServerSocket, (void *)SaSessionName); + pthread_detach(threadId); + + return ERR_NONE; +} + +static int32_t StopListen(const char *SaSessionName) +{ + return ERR_NONE; +} + +static void HandleSendReply(void *args) +{ + if (args == NULL) { + RPC_LOG_ERROR("HandleSendReply args is null"); + return; + } + int32_t fd = *(int32_t *)args; + free(args); + + char buf[DEFAULT_PACKET_SIZE]; + if (g_callback.OnRecieved != NULL) { + for (;;) { + ssize_t readLen = read(fd, buf, DEFAULT_PACKET_SIZE); + if (readLen == 0) { + RPC_LOG_INFO("HandleSendReply received len %d", readLen); + g_callback.OnDisconnected(fd); + TcpShutDown(fd); + return; + } + if (readLen < 0) { + RPC_LOG_ERROR("HandleSendReply received len %d", readLen); + TcpShutDown(fd); + return; + } + g_callback.OnRecieved(fd, buf, readLen); + } + } +} + +static int32_t Connect(const char *SaSessionName, const char *peerDeviceId, void *args) +{ + if (SaSessionName == NULL) { + RPC_LOG_INFO("SaSessionName is null"); + return ERR_FAILED; + } + uint16_t port = Hash(SaSessionName); + + int fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) { + RPC_LOG_ERROR("%s:%d:fd=%d", __func__, __LINE__, fd); + return ERR_FAILED; + } + + struct sockaddr_in addr; + if (memset_s(&addr, sizeof(addr), 0, sizeof(addr)) != EOK) { + RPC_LOG_ERROR("memset failed"); + } + addr.sin_family = AF_INET; + inet_pton(AF_INET, peerDeviceId, &addr.sin_addr); + addr.sin_port = htons(port); + errno = 0; + + int rc = connect(fd, (struct sockaddr *)&addr, sizeof(addr)); + if ((rc == -1) && (errno != EINPROGRESS)) { + RPC_LOG_ERROR("fd=%d,connect rc=%d, errno=%d", fd, rc, errno); + TcpShutDown(fd); + return ERR_FAILED; + } + + int32_t *sessionId = (int32_t *)malloc(sizeof(int32_t)); + if (sessionId == NULL) { + return ERR_FAILED; + } + + *sessionId = fd; + pthread_t threadId; + pthread_create(&threadId, NULL, HandleSendReply, (void *)sessionId); + pthread_detach(threadId); + + return fd; +} + +static int32_t Disconnect(int32_t sessionId) +{ + return ERR_NONE; +} + +static int32_t Send(int32_t sessionId, const void *data, uint32_t len) +{ + if (sessionId < 0 || data == NULL || len <= 0) { + RPC_LOG_ERROR("send invail params"); + return ERR_FAILED; + } + + ssize_t ret = write(sessionId, data, len); + if (ret < 0) { + RPC_LOG_ERROR("send error=%d", ret); + return ERR_FAILED; + } + + return ERR_NONE; +} + +static TransInterface g_socketTrans = { + .StartListen = StartListen, + .StopListen = StopListen, + .Connect = Connect, + .Disconnect = Disconnect, + .Send = Send +}; + +TransInterface *GetSocketTrans(void) +{ + if (g_init == -1) { + pthread_mutex_lock(&g_socketNodeList.mutex); + UtilsListInit(&g_socketNodeList.list); + g_init = 0; + pthread_mutex_unlock(&g_socketNodeList.mutex); + } + return &g_socketTrans; +} + +char *GetSocketLocalDeviceID(void) +{ + if (g_localDeviceId != NULL) { + return g_localDeviceId; + } + + struct ifaddrs *ifaddr; + struct ifaddrs *ifa; + int family; + + if (getifaddrs(&ifaddr) == -1) { + RPC_LOG_ERROR("getifaddrs failed"); + freeifaddrs(ifaddr); + return NULL; + } + + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr != NULL) { + family = ifa->ifa_addr->sa_family; + if (family != AF_INET || strcmp(ifa->ifa_name, DEFAULT_NET_INTERFACE) != 0) { + continue; + } + + char *localDeviceId = inet_ntoa(((struct sockaddr_in*)ifa->ifa_addr)->sin_addr); + if (localDeviceId == NULL) { + RPC_LOG_ERROR("GetSocketLocalDeviceID inet_ntoa get null"); + break; + } + + size_t deviceIdLen = strlen(localDeviceId); + if (deviceIdLen == 0 || deviceIdLen > DEVICEID_LENGTH) { + RPC_LOG_ERROR("deviceIdLen invalid"); + break; + } + g_localDeviceId = (char *)malloc(deviceIdLen + 1); + if (g_localDeviceId == NULL) { + RPC_LOG_ERROR("g_localDeviceId malloc failed"); + break; + } + if (strcpy_s(g_localDeviceId, deviceIdLen + 1, localDeviceId) != EOK) { + RPC_LOG_ERROR("g_localDeviceId strcpy failed"); + } else { + RPC_LOG_INFO("GetSocketLocalDeviceID %s", g_localDeviceId); + } + break; + } + } + freeifaddrs(ifaddr); + + return g_localDeviceId; +} \ No newline at end of file diff --git a/services/dbinder/c/include/dbinder_stub.h b/services/dbinder/c/include/dbinder_stub.h new file mode 100644 index 0000000000000000000000000000000000000000..c432f207797c2939da74eaf6922ae8695ddabeb7 --- /dev/null +++ b/services/dbinder/c/include/dbinder_stub.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_RPC_DBINDER_STUB_H +#define OHOS_RPC_DBINDER_STUB_H + +#include +#include + +#include "dbinder_types.h" +#include "serializer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + UTILS_DL_LIST list; + char serviceName[SERVICENAME_LENGTH + 1]; + char deviceID[DEVICEID_LENGTH + 1]; + uintptr_t binderObject; + SvcIdentity svc; +} DBinderServiceStub; + +int32_t GetDBinderStub(const char *serviceName, const char *deviceID, + uintptr_t binderObject, DBinderServiceStub *dBinderServiceStub); + +#ifdef __cplusplus +} +#endif +#endif // OHOS_RPC_DBINDER_STUB_H \ No newline at end of file diff --git a/services/dbinder/c/include/dbinder_trans_callback.h b/services/dbinder/c/include/dbinder_trans_callback.h new file mode 100644 index 0000000000000000000000000000000000000000..a25bb2bfa8b66525d7e77647a29e76a230ba0ad7 --- /dev/null +++ b/services/dbinder/c/include/dbinder_trans_callback.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_RPC_DBINDER_RTANS_CALLBACK_H +#define OHOS_RPC_DBINDER_RTANS_CALLBACK_H + +#include +#include + +#include "rpc_trans.h" +#include "dbinder_service.h" + +#ifdef __cplusplus +extern "C" { +#endif + +TransCallback *GetDBinderTransCallback(void); + +#ifdef __cplusplus +} +#endif +#endif // OHOS_RPC_DBINDER_RTANS_CALLBACK_H \ No newline at end of file diff --git a/services/dbinder/c/include/dbinder_types.h b/services/dbinder/c/include/dbinder_types.h new file mode 100644 index 0000000000000000000000000000000000000000..5ff382d53c746381760b211a37b91332d0b9f919 --- /dev/null +++ b/services/dbinder/c/include/dbinder_types.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_RPC_DBINDER_TYPES_H +#define OHOS_RPC_DBINDER_TYPES_H + +#include + +#include "utils_list.h" + +#include "serializer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define DEVICEID_LENGTH 64 +#define SERVICENAME_LENGTH 200 +#define VERSION_NUM 1 +#define SESSION_NAME_LEGNTH 8 +#define RPC_IPC_LENGTH 128 +#define RPC_IPC_LENGTH_LONG 256 +#define GET_SYSTEM_ABILITY_TRANSACTION 1 +#define ID_DIGITS 10 +#define DEFAULT_SEND_WAIT_TIME 4 + +enum DBinderCode { + MESSAGE_AS_INVOKER = 1, + MESSAGE_AS_REPLY = 2, + MESSAGE_AS_OBITUARY = 3, +}; + +enum AfType { + IPV4_TYPE = 1, + IPV6_TYPE = 2, + DATABBUS_TYPE = 3, +}; + +enum { + DATABUS_TYPE +}; + +struct DeviceIdInfo { + uint16_t afType; + uint16_t reserved; + char fromDeviceId[DEVICEID_LENGTH + 1]; + char toDeviceId[DEVICEID_LENGTH + 1]; +}; + +struct DHandleEntryHead { + uint32_t len; + uint32_t version; +}; + +typedef struct { + UTILS_DL_LIST list; + uint32_t type; + uint16_t toPort; + uint16_t fromPort; + uint64_t stubIndex; + uint32_t socketFd; + char serviceName[SERVICENAME_LENGTH + 1]; + struct DeviceIdInfo deviceIdInfo; + uintptr_t stub; +} SessionInfo; + +typedef struct { + UTILS_DL_LIST list; + uintptr_t binderObject; + SvcIdentity *proxy; + char *sessionName; + uint32_t cbId; +} ProxyObject; + +typedef struct { + uint32_t sizeOfSelf; + uint32_t magic; + uint32_t version; + int cmd; + uint32_t code; + uint32_t flags; + uint64_t cookie; + uint64_t seqNumber; + size_t buffer_size; + size_t offsets_size; + uintptr_t offsets; + char *buffer; +} dbinder_transaction_data; + +#ifdef __cplusplus +} +#endif +#endif // OHOS_RPC_DBINDER_TYPES_H \ No newline at end of file diff --git a/services/dbinder/c/ipc_adapter/include/dbinder_ipc_adapter.h b/services/dbinder/c/ipc_adapter/include/dbinder_ipc_adapter.h new file mode 100644 index 0000000000000000000000000000000000000000..4a57e21578ebc1dc4343c44fd1d80f6c772fdd31 --- /dev/null +++ b/services/dbinder/c/ipc_adapter/include/dbinder_ipc_adapter.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_RPC_DBINDER_IPC_ADAPTER_H +#define OHOS_RPC_DBINDER_IPC_ADAPTER_H + +#include +#include + +#include "dbinder_stub.h" +#include "dbinder_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +bool IsSameStub(DBinderServiceStub *stub, const char *serviceName, + const char *deviceID, uintptr_t binderObject); +int32_t GetDBinderHandle(uintptr_t stubAddr); +int32_t UpdateSessionIfNeed(uintptr_t stubAddr); +ProxyObject *RpcGetSystemAbility(int32_t systemAbility); + +#ifdef __cplusplus +} +#endif +#endif // OHOS_RPC_DBINDER_IPC_ADAPTER_H \ No newline at end of file diff --git a/services/dbinder/c/ipc_adapter/mini/dbinder_ipc_adapter.c b/services/dbinder/c/ipc_adapter/mini/dbinder_ipc_adapter.c new file mode 100644 index 0000000000000000000000000000000000000000..ce7b964426bd4dbbd0c18f2f713ded6762919bc9 --- /dev/null +++ b/services/dbinder/c/ipc_adapter/mini/dbinder_ipc_adapter.c @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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. + */ + +#include "dbinder_ipc_adapter.h" + +#include "securec.h" +#include "ipc_proxy_inner.h" +#include "rpc_errno.h" +#include "rpc_log.h" + +#include "rpc_mini_samgr.h" // samgr refactory needed in mini system + +bool IsSameStub(DBinderServiceStub *stub, const char *serviceName, + const char *deviceID, uintptr_t binderObject) +{ + return false; +} + +int32_t GetDBinderHandle(uintptr_t stubAddr) +{ + return (int32_t)stubAddr; +} + +int32_t UpdateSessionIfNeed(uintptr_t stubAddr) +{ + UpdateProto((int32_t)stubAddr); + return ERR_NONE; +} + +ProxyObject *RpcGetSystemAbility(int32_t systemAbility) +{ + SvcIdentity *target = GetSystemAbilityById(systemAbility); + if (target == NULL) { + RPC_LOG_ERROR("GetSystemAbilityById return null"); + return NULL; + } + + ProxyObject *proxyObject = (ProxyObject *)calloc(1, sizeof(ProxyObject)); + if (proxyObject == NULL) { + return NULL; + } + proxyObject->proxy = (SvcIdentity *)malloc(sizeof(SvcIdentity)); + if (proxyObject->proxy == NULL) { + free(proxyObject); + return NULL; + } + + if (memcpy_s(proxyObject->proxy, sizeof(SvcIdentity), target, sizeof(SvcIdentity)) != EOK) { + free(proxyObject->proxy); + free(proxyObject); + return NULL; + } + + return proxyObject; +} \ No newline at end of file diff --git a/services/dbinder/c/ipc_adapter/small/dbinder_ipc_adapter.c b/services/dbinder/c/ipc_adapter/small/dbinder_ipc_adapter.c new file mode 100644 index 0000000000000000000000000000000000000000..5faf5982c4d6805497d93d564a03d0baccaba615 --- /dev/null +++ b/services/dbinder/c/ipc_adapter/small/dbinder_ipc_adapter.c @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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. + */ + +#include "dbinder_ipc_adapter.h" + +#include +#include + +#include "securec.h" +#include "ipc_skeleton.h" +#include "rpc_log.h" +#include "rpc_errno.h" + +#define IPC_STUB_HANDLE (-1) + +bool IsSameStub(DBinderServiceStub *stub, const char *serviceName, + const char *deviceID, uintptr_t binderObject) +{ + if (stub == NULL) { + return false; + } + return (strcmp(stub->serviceName, serviceName) == 0 && strcmp(stub->deviceID, deviceID) == 0 + && stub->binderObject == binderObject); +} + +int32_t GetDBinderHandle(uintptr_t stubAddr) +{ + return IPC_STUB_HANDLE; +} + +int32_t UpdateSessionIfNeed(uintptr_t stubAddr) +{ + return ERR_NONE; +} + +ProxyObject *RpcGetSystemAbility(int32_t systemAbility) +{ + IpcIo data; + uint8_t tmpData[RPC_IPC_LENGTH]; + IpcIoInit(&data, tmpData, RPC_IPC_LENGTH, 0); + RPC_LOG_INFO("GetSystemAbility systemAbility %d", systemAbility); + WriteInt32(&data, systemAbility); + + IpcIo reply; + MessageOption option = TF_OP_SYNC; + + RPC_LOG_INFO("get system ability from samgr"); + uintptr_t ptr; + int32_t ret = SendRequest(*GetContextObject(), GET_SYSTEM_ABILITY_TRANSACTION, &data, &reply, option, &ptr); + if (ret != ERR_NONE) { + RPC_LOG_ERROR("GetSystemAbility failed"); + FreeBuffer((void *)ptr); + return NULL; + } + + SvcIdentity svc; + ReadRemoteObject(&reply, &svc); + + ProxyObject *proxyObject = (ProxyObject *)malloc(sizeof(ProxyObject)); + if (proxyObject == NULL) { + FreeBuffer((void *)ptr); + return NULL; + } + proxyObject->proxy = (SvcIdentity *)malloc(sizeof(SvcIdentity)); + if (proxyObject->proxy == NULL) { + free(proxyObject); + FreeBuffer((void *)ptr); + return NULL; + } + + if (memcpy_s(proxyObject->proxy, sizeof(SvcIdentity), &svc, sizeof(SvcIdentity)) != EOK) { + free(proxyObject->proxy); + free(proxyObject); + FreeBuffer((void *)ptr); + return NULL; + } + + FreeBuffer((void *)ptr); + return proxyObject; +} \ No newline at end of file diff --git a/services/dbinder/c/src/dbinder_service.c b/services/dbinder/c/src/dbinder_service.c new file mode 100644 index 0000000000000000000000000000000000000000..782d135a2742ef429a0e4155c6ba1b59639df85e --- /dev/null +++ b/services/dbinder/c/src/dbinder_service.c @@ -0,0 +1,811 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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. + */ + +#include "dbinder_service.h" + +#include +#include +#include +#include +#include + +#include "utils_list.h" +#include "securec.h" + +#include "rpc_trans.h" +#include "dbinder_trans_callback.h" +#include "dbinder_ipc_adapter.h" +#include "serializer.h" +#include "dbinder_stub.h" +#include "ipc_skeleton.h" +#include "ipc_proxy_inner.h" +#include "rpc_log.h" +#include "rpc_errno.h" + +typedef struct { + UTILS_DL_LIST list; + char *serviceName; + uintptr_t binder; +} RemoteBinderObjects; + +typedef struct { + UTILS_DL_LIST remoteBinderObjects; + pthread_mutex_t mutex; +} RemoteBinderObjectsList; + +typedef struct { + UTILS_DL_LIST dBinderStubs; + pthread_mutex_t mutex; +} DBinderStubRegistedList; + +typedef struct { + UTILS_DL_LIST list; + pthread_mutex_t mutex; + pthread_cond_t condition; + uint32_t seqNumber; +} ThreadLockInfo; + +typedef struct { + UTILS_DL_LIST threadLocks; + pthread_mutex_t mutex; +} ThreadLockInfoList; + +typedef struct { + UTILS_DL_LIST sessionInfos; + pthread_mutex_t mutex; +} SessionInfoList; + +typedef struct { + UTILS_DL_LIST proxyObject; + pthread_mutex_t mutex; +} ProxyObjectList; + +static RemoteBinderObjectsList g_binderList = {.mutex = PTHREAD_MUTEX_INITIALIZER}; +static DBinderStubRegistedList g_stubRegistedList = {.mutex = PTHREAD_MUTEX_INITIALIZER}; +static ThreadLockInfoList g_threadLockInfoList = {.mutex = PTHREAD_MUTEX_INITIALIZER}; +static SessionInfoList g_sessionInfoList = {.mutex = PTHREAD_MUTEX_INITIALIZER}; +static ProxyObjectList g_proxyObjectList = {.mutex = PTHREAD_MUTEX_INITIALIZER}; + +static TransInterface *g_trans = NULL; +static char const *DBINDER_SESSION_NAME = "DBinderService"; +static const uint32_t RETRY_TIMES = 2; +static const int32_t FIRST_SYS_ABILITY_ID = 0x00000001; +static const int32_t LAST_SYS_ABILITY_ID = 0x00ffffff; + +static int32_t InitDBinder(void) +{ + UtilsListInit(&g_binderList.remoteBinderObjects); + UtilsListInit(&g_stubRegistedList.dBinderStubs); + UtilsListInit(&g_threadLockInfoList.threadLocks); + UtilsListInit(&g_sessionInfoList.sessionInfos); + UtilsListInit(&g_proxyObjectList.proxyObject); + return ERR_NONE; +} + +static char *GetRegisterService(uintptr_t binderObject) +{ + RemoteBinderObjects *node = NULL; + pthread_mutex_lock(&g_binderList.mutex); + UTILS_DL_LIST_FOR_EACH_ENTRY(node, &g_binderList.remoteBinderObjects, RemoteBinderObjects, list) + { + if (node->binder == binderObject) { + pthread_mutex_unlock(&g_binderList.mutex); + return node->serviceName; + } + } + pthread_mutex_unlock(&g_binderList.mutex); + return NULL; +} + +static void AddRegisterService(RemoteBinderObjects *binderObject) +{ + pthread_mutex_lock(&g_binderList.mutex); + UtilsListAdd(&g_binderList.remoteBinderObjects, &binderObject->list); + pthread_mutex_unlock(&g_binderList.mutex); +} + +static int32_t CheckBinderParams(const void *serviceName, uint32_t nameLen, const char *deviceID, + uint32_t idLen, void *remoteObject) +{ + if (serviceName == NULL || deviceID == NULL || remoteObject == NULL) { + RPC_LOG_ERROR("MakeRemoteBinder null poiter"); + return ERR_FAILED; + } + + if (strlen((char *)serviceName) != nameLen || strlen(deviceID) != idLen) { + RPC_LOG_ERROR("MakeRemoteBinder length invalid"); + return ERR_FAILED; + } + return ERR_NONE; +} + +static DBinderServiceStub *QueryDBinderStub(const char *serviceName, const char *deviceID, + uintptr_t binderObject) +{ + pthread_mutex_lock(&g_stubRegistedList.mutex); + DBinderServiceStub *node = NULL; + UTILS_DL_LIST_FOR_EACH_ENTRY(node, &g_stubRegistedList.dBinderStubs, DBinderServiceStub, list) + { + if (IsSameStub(node, serviceName, deviceID, binderObject)) { + RPC_LOG_INFO("find dBinderStub in g_stubRegistedList"); + pthread_mutex_unlock(&g_stubRegistedList.mutex); + return node; + } + } + pthread_mutex_unlock(&g_stubRegistedList.mutex); + return NULL; +} + +static void AddDBinderStub(DBinderServiceStub *stub) +{ + pthread_mutex_lock(&g_stubRegistedList.mutex); + UtilsListAdd(&g_stubRegistedList.dBinderStubs, &stub->list); + pthread_mutex_unlock(&g_stubRegistedList.mutex); +} + +static DBinderServiceStub *FindOrNewDBinderStub(const char *serviceName, uint32_t nameLen, + const char *deviceID, uint32_t idLen, uintptr_t binderObject) +{ + if (serviceName == NULL || deviceID == NULL) { + RPC_LOG_ERROR("FindOrNewDBinderStub get null input params"); + return NULL; + } + + DBinderServiceStub *node = QueryDBinderStub(serviceName, deviceID, binderObject); + if (node != NULL) { + RPC_LOG_INFO("DBinderStub cached already"); + return node; + } + + node = (DBinderServiceStub *)malloc(sizeof(DBinderServiceStub)); + if (node == NULL) { + RPC_LOG_ERROR("dBinderServiceStub malloc failed"); + return NULL; + } + if (GetDBinderStub(serviceName, deviceID, binderObject, node) != ERR_NONE) { + RPC_LOG_ERROR("GetDBinderStub failed"); + free(node); + return NULL; + } + + AddDBinderStub(node); + return node; +} + +static int32_t SendDataToRemote(const char *deviceId, const DHandleEntryTxRx *msg) +{ + if (deviceId == NULL || msg == NULL) { + return ERR_FAILED; + } + + int32_t sessionId = 0; + sessionId = g_trans->Connect(DBINDER_SESSION_NAME, deviceId, NULL); + if (sessionId < 0) { + RPC_LOG_ERROR("SendDataToRemote connect failed"); + return ERR_FAILED; + } + + if (g_trans->Send(sessionId, (void *)msg, msg->head.len) != ERR_NONE) { + RPC_LOG_ERROR("SendDataToRemote send failed"); + return ERR_FAILED; + } + + return ERR_NONE; +} + +static int32_t SendEntryToRemote(DBinderServiceStub *stub, const uint32_t seqNumber) +{ + char *toDeviceID = stub->deviceID; + if (toDeviceID == NULL) { + RPC_LOG_ERROR("toDeviceID invalid"); + return ERR_FAILED; + } + uint32_t toDeviceIDLength = (uint32_t)strlen(toDeviceID); + + char *localDeviceID = GetLocalDeviceID(); + if (localDeviceID == NULL) { + RPC_LOG_ERROR("GetLocalDeviceID failed"); + return ERR_FAILED; + } + uint32_t localDeviceIDLength = (uint32_t)strlen(localDeviceID); + if (toDeviceIDLength > DEVICEID_LENGTH || localDeviceIDLength > DEVICEID_LENGTH) { + RPC_LOG_ERROR("deviceID invalid"); + return ERR_FAILED; + } + + DHandleEntryTxRx message = { + .head.len = sizeof(DHandleEntryTxRx), + .head.version = VERSION_NUM, + .transType = DATABUS_TYPE, + .dBinderCode = MESSAGE_AS_INVOKER, + .fromPort = 0, + .toPort = 0, + .stubIndex = atoi(stub->serviceName), + .seqNumber = seqNumber, + .binderObject = stub->binderObject, + .deviceIdInfo.afType = DATABBUS_TYPE, + .stub = (uintptr_t)(stub->svc.cookie), + .pid = (uint32_t)GetCallingPid(), + .uid = (uint32_t)GetCallingUid() + }; + if (memcpy_s(message.deviceIdInfo.fromDeviceId, DEVICEID_LENGTH, localDeviceID, localDeviceIDLength) != EOK || + memcpy_s(message.deviceIdInfo.toDeviceId, DEVICEID_LENGTH, toDeviceID, toDeviceIDLength) != EOK) { + RPC_LOG_ERROR("deviceIdInfo memory copy failed"); + return ERR_FAILED; + } + message.deviceIdInfo.fromDeviceId[localDeviceIDLength] = '\0'; + message.deviceIdInfo.toDeviceId[toDeviceIDLength] = '\0'; + + if (SendDataToRemote(toDeviceID, &message) != ERR_NONE) { + RPC_LOG_ERROR("SendDataToRemote failed"); + return ERR_FAILED; + } + return ERR_NONE; +} + +static int32_t AttachThreadLockInfo(ThreadLockInfo *threadLockInfo) +{ + pthread_mutex_lock(&g_threadLockInfoList.mutex); + UtilsListAdd(&g_threadLockInfoList.threadLocks, &threadLockInfo->list); + pthread_mutex_unlock(&g_threadLockInfoList.mutex); + return ERR_NONE; +} + +static void DetachThreadLockInfo(ThreadLockInfo *threadLockInfo) +{ + pthread_mutex_lock(&g_threadLockInfoList.mutex); + UtilsListDelete(&threadLockInfo->list); + pthread_mutex_unlock(&g_threadLockInfoList.mutex); +} + +static int32_t InvokerRemoteDBinder(DBinderServiceStub *dBinderServiceStub, uint32_t seqNumber) +{ + if (dBinderServiceStub == NULL) { + RPC_LOG_ERROR("InvokerRemoteDBinder dBinderServiceStub is NULL"); + return ERR_FAILED; + } + + int32_t ret = ERR_FAILED; + ThreadLockInfo *threadLockInfo = (ThreadLockInfo *)malloc(sizeof(ThreadLockInfo)); + if (threadLockInfo == NULL) { + RPC_LOG_ERROR("threadLockInfo malloc failed"); + return ERR_FAILED; + } + if (pthread_mutex_init(&threadLockInfo->mutex, NULL) != 0) { + RPC_LOG_ERROR("threadLockInfo mutex init failed"); + free(threadLockInfo); + return ERR_FAILED; + } + if (pthread_cond_init(&threadLockInfo->condition, NULL) != 0) { + RPC_LOG_ERROR("threadLockInfo condition init failed"); + pthread_mutex_destroy(&threadLockInfo->mutex); + free(threadLockInfo); + return ERR_FAILED; + } + + threadLockInfo->seqNumber = seqNumber; + ret = AttachThreadLockInfo(threadLockInfo); + if (ret != ERR_NONE) { + RPC_LOG_ERROR("AttachThreadLockInfo failed"); + pthread_mutex_destroy(&threadLockInfo->mutex); + pthread_cond_destroy(&threadLockInfo->condition); + free(threadLockInfo); + return ret; + } + + pthread_mutex_lock(&threadLockInfo->mutex); + ret = SendEntryToRemote(dBinderServiceStub, seqNumber); + if (ret != ERR_NONE) { + RPC_LOG_ERROR("send entry to remote dbinderService failed"); + } else { + pthread_cond_wait(&threadLockInfo->condition, &threadLockInfo->mutex); + RPC_LOG_INFO("InvokerRemoteDBinder wakeup!"); + } + + if (QuerySessionObject((uintptr_t)(dBinderServiceStub->svc.cookie)) == NULL) { + RPC_LOG_ERROR("QuerySessionObject is null"); + ret = ERR_FAILED; + } + + if (UpdateSessionIfNeed(dBinderServiceStub->svc.cookie) != ERR_NONE) { + RPC_LOG_ERROR("UpdateSessionIfNeed failed"); + ret = ERR_FAILED; + } + + pthread_mutex_unlock(&threadLockInfo->mutex); + DetachThreadLockInfo(threadLockInfo); + free(threadLockInfo); + + return ret; +} + +static uint32_t GetSeqNumber(void) +{ + static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + static uint32_t seqNumber = 0; + pthread_mutex_lock(&mutex); + seqNumber++; + pthread_mutex_unlock(&mutex); + return seqNumber; +} + +static int32_t AttachSessionObject(SessionInfo *sessionInfo) +{ + pthread_mutex_lock(&g_sessionInfoList.mutex); + UtilsListAdd(&g_sessionInfoList.sessionInfos, &sessionInfo->list); + pthread_mutex_unlock(&g_sessionInfoList.mutex); + return ERR_NONE; +} + +static void DetachSessionObject(SessionInfo *sessionInfo) +{ + pthread_mutex_lock(&g_sessionInfoList.mutex); + UtilsListDelete(&sessionInfo->list); + pthread_mutex_unlock(&g_sessionInfoList.mutex); +} + +SessionInfo *QuerySessionObject(uintptr_t stub) +{ + SessionInfo *node = NULL; + pthread_mutex_lock(&g_sessionInfoList.mutex); + UTILS_DL_LIST_FOR_EACH_ENTRY(node, &g_sessionInfoList.sessionInfos, SessionInfo, list) + { + if (node->stub == stub) { + pthread_mutex_unlock(&g_sessionInfoList.mutex); + return node; + } + } + pthread_mutex_unlock(&g_sessionInfoList.mutex); + return NULL; +} + +static void DeleteDBinderStub(DBinderServiceStub *stub) +{ + if (stub == NULL) { + RPC_LOG_ERROR("DeleteDBinderStub get null stub"); + return; + } + pthread_mutex_lock(&g_stubRegistedList.mutex); + UtilsListDelete(&stub->list); + pthread_mutex_unlock(&g_stubRegistedList.mutex); +} + +static ProxyObject *QueryProxyObject(uintptr_t binderObject) +{ + ProxyObject *node = NULL; + pthread_mutex_lock(&g_proxyObjectList.mutex); + UTILS_DL_LIST_FOR_EACH_ENTRY(node, &g_proxyObjectList.proxyObject, ProxyObject, list) + { + if (node->binderObject == binderObject) { + pthread_mutex_unlock(&g_proxyObjectList.mutex); + return node; + } + } + pthread_mutex_unlock(&g_proxyObjectList.mutex); + return NULL; +} + +static int32_t AttachProxyObject(ProxyObject *proxy) +{ + pthread_mutex_lock(&g_proxyObjectList.mutex); + UtilsListAdd(&g_proxyObjectList.proxyObject, &proxy->list); + pthread_mutex_unlock(&g_proxyObjectList.mutex); + return ERR_NONE; +} + +void DetachProxyObject(ProxyObject *proxy) +{ + pthread_mutex_lock(&g_proxyObjectList.mutex); + UtilsListDelete(&proxy->list); + pthread_mutex_unlock(&g_proxyObjectList.mutex); +} + +static void DbinderSaDeathRecipient(void *args) +{ + if (args == NULL) { + RPC_LOG_ERROR("DbinderSaDeathRecipient args is null"); + return; + } + ProxyObject *proxyObject = (ProxyObject *)args; + RPC_LOG_INFO("DbinderSaDeathRecipient cbiId %d", proxyObject->cbId); + DetachProxyObject(proxyObject); +} + +static ProxyObject *FindOrNewProxy(uintptr_t binderObject, int32_t systemAbilityId) +{ + ProxyObject *proxyObject = QueryProxyObject(binderObject); + if (proxyObject != NULL) { + RPC_LOG_INFO("FindOrNewProxy found cached proxy"); + return proxyObject; + } + + char *serviceName = GetRegisterService(binderObject); + if (serviceName == NULL && (systemAbilityId < FIRST_SYS_ABILITY_ID || systemAbilityId > LAST_SYS_ABILITY_ID)) { + RPC_LOG_ERROR("service is not registered in this device, saId:%d", systemAbilityId); + return NULL; + } + + int32_t digitalName = systemAbilityId; + if (serviceName != NULL) { + digitalName = atoi(serviceName); + } + + proxyObject = RpcGetSystemAbility(digitalName); + if (proxyObject == NULL) { + RPC_LOG_ERROR("RpcGetSystemAbility failed, saId: %d", systemAbilityId); + return NULL; + } + proxyObject->binderObject = binderObject; + + int32_t ret = AddDeathRecipient(*proxyObject->proxy, DbinderSaDeathRecipient, + (void *)proxyObject, &proxyObject->cbId); + if (ret != ERR_NONE) { + RPC_LOG_ERROR("FindOrNewProxy AddDeathRecipient failed, error %d", ret); + free(proxyObject->proxy); + free(proxyObject); + return NULL; + } + + if (AttachProxyObject(proxyObject) != ERR_NONE) { + RPC_LOG_ERROR("FindOrNewProxy AttachProxyObject failed"); + RemoveDeathRecipient(*proxyObject->proxy, proxyObject->cbId); + free(proxyObject->proxy); + free(proxyObject); + return NULL; + } + return proxyObject; +} + +static int32_t GetDatabusNameByProxy(ProxyObject *proxy) +{ + if (proxy == NULL) { + RPC_LOG_ERROR("GetDatabusNameByProxy proxy is null"); + return ERR_FAILED; + } + + if (proxy->sessionName != NULL && strlen(proxy->sessionName) > 0) { + RPC_LOG_ERROR("GetDatabusNameByProxy proxy got sessionName already"); + return ERR_NONE; + } + if (GetPidAndUidInfo(proxy) != ERR_NONE) { + RPC_LOG_ERROR("GetDatabusNameByProxy GetPidAndUidInfo failed"); + return ERR_FAILED; + } + return ERR_NONE; +} + +static int32_t OnRemoteInvokerDataBusMessage(ProxyObject *proxy, DHandleEntryTxRx *replyMessage, + const char *remoteDeviceID, uint32_t pid, uint32_t uid) +{ + if (remoteDeviceID == NULL || strlen(remoteDeviceID) > DEVICEID_LENGTH) { + RPC_LOG_ERROR("remote deviceID invalid"); + return ERR_FAILED; + } + + if (GetDatabusNameByProxy(proxy) != ERR_NONE) { + RPC_LOG_ERROR("GetDatabusNameByProxy failed"); + return ERR_FAILED; + } + + IpcIo reply; + uintptr_t ptr; + int32_t ret = InvokerListenThread(proxy, GetLocalDeviceID(), remoteDeviceID, pid, uid, &reply, &ptr); + if (ret != ERR_NONE) { + RPC_LOG_ERROR("INVOKE_LISTEN_THREAD failed"); + FreeBuffer((void *)ptr); + return ERR_FAILED; + } + + uint64_t stubIndex; + if (!ReadUint64(&reply, &stubIndex)) { + FreeBuffer((void *)ptr); + return ERR_FAILED; + } + + size_t sessionLen; + char *serverSessionName = (char *)ReadString(&reply, &sessionLen); + + if (stubIndex == 0 || serverSessionName == NULL || strlen(serverSessionName) > SERVICENAME_LENGTH) { + RPC_LOG_ERROR("INVOKE_LISTEN_THREAD reply stubIndex or sessionName invalid"); + FreeBuffer((void *)ptr); + return ERR_FAILED; + } + + replyMessage->dBinderCode = MESSAGE_AS_REPLY; + replyMessage->stubIndex = stubIndex; + replyMessage->serviceNameLength = (uint16_t)sessionLen; + if (memcpy_s(replyMessage->serviceName, SERVICENAME_LENGTH, serverSessionName, sessionLen) != 0) { + RPC_LOG_ERROR("replyMessage serviceName memcpy failed"); + FreeBuffer((void *)ptr); + return ERR_FAILED; + } + replyMessage->serviceName[replyMessage->serviceNameLength] = '\0'; + FreeBuffer((void *)ptr); + return ERR_NONE; +} + +static int32_t OnRemoteInvokerMessage(const DHandleEntryTxRx *message) +{ + ProxyObject *saProxy = FindOrNewProxy(message->binderObject, (int32_t)message->stubIndex); + if (saProxy == NULL) { + RPC_LOG_ERROR("OnRemoteInvokerMessage get SA Proxy failed"); + return ERR_FAILED; + } + + DHandleEntryTxRx replyMessage; + if (memcpy_s(&replyMessage, sizeof(DHandleEntryTxRx), message, sizeof(DHandleEntryTxRx)) != EOK) { + RPC_LOG_ERROR("OnRemoteInvokerMessage replyMessage memcpy failed"); + return ERR_FAILED; + } + char *fromDeviceID = replyMessage.deviceIdInfo.fromDeviceId; + + switch (replyMessage.transType) { + case DATABUS_TYPE: { + if (OnRemoteInvokerDataBusMessage(saProxy, &replyMessage, fromDeviceID, + message->pid, message->uid) != ERR_NONE) { + RPC_LOG_ERROR("OnRemoteInvokerMessage Invoker Databus Message fail"); + return ERR_FAILED; + } + break; + } + default: { + RPC_LOG_ERROR("OnRemoteInvokerMessage msg transType invalid"); + return ERR_FAILED; + } + } + + if (SendDataToRemote(fromDeviceID, &replyMessage) != ERR_NONE) { + RPC_LOG_ERROR("fail to send data from server DBS to client DBS"); + return ERR_FAILED; + } + return ERR_NONE; +} + +static ThreadLockInfo *QueryThreadLockInfo(uint32_t seqNumber) +{ + ThreadLockInfo *node = NULL; + pthread_mutex_lock(&g_threadLockInfoList.mutex); + UTILS_DL_LIST_FOR_EACH_ENTRY(node, &g_threadLockInfoList.threadLocks, ThreadLockInfo, list) + { + if (node->seqNumber == seqNumber) { + pthread_mutex_unlock(&g_threadLockInfoList.mutex); + return node; + } + } + pthread_mutex_unlock(&g_threadLockInfoList.mutex); + return NULL; +} + +static void WakeupThreadByStub(uint32_t seqNumber) +{ + ThreadLockInfo *threadLockInfo = QueryThreadLockInfo(seqNumber); + if (threadLockInfo == NULL) { + RPC_LOG_ERROR("threadLockInfo is not exist"); + return; + } + pthread_mutex_lock(&threadLockInfo->mutex); + pthread_cond_signal(&threadLockInfo->condition); + pthread_mutex_unlock(&threadLockInfo->mutex); +} + +static bool HasDBinderStub(uintptr_t binderObject) +{ + DBinderServiceStub *node; + pthread_mutex_lock(&g_stubRegistedList.mutex); + UTILS_DL_LIST_FOR_EACH_ENTRY(node, &g_stubRegistedList.dBinderStubs, DBinderServiceStub, list) + { + if (node->binderObject == binderObject) { + pthread_mutex_unlock(&g_stubRegistedList.mutex); + return true; + } + } + pthread_mutex_unlock(&g_stubRegistedList.mutex); + return false; +} + +static void MakeSessionByReplyMessage(const DHandleEntryTxRx *replyMessage) +{ + if (replyMessage == NULL) { + RPC_LOG_ERROR("replyMessage is null"); + return; + } + if (!HasDBinderStub(replyMessage->binderObject)) { + RPC_LOG_ERROR("invalid stub object"); + return; + } + if (QuerySessionObject(replyMessage->stub) != NULL) { + RPC_LOG_ERROR("invoker remote session already, do nothing"); + return; + } + + SessionInfo *session = (SessionInfo *)malloc(sizeof(SessionInfo)); + if (session == NULL) { + RPC_LOG_ERROR("session malloc failed"); + return; + } + if (memcpy_s(&session->deviceIdInfo, sizeof(struct DeviceIdInfo), + &replyMessage->deviceIdInfo, sizeof(struct DeviceIdInfo)) != 0) { + RPC_LOG_ERROR("deviceIdInfo memory copy failed"); + free(session); + return; + } + if (strcpy_s(session->serviceName, SERVICENAME_LENGTH + 1, replyMessage->serviceName) != EOK) { + RPC_LOG_ERROR("session serviceName copy failed"); + free(session); + return; + } + session->serviceName[replyMessage->serviceNameLength] = '\0'; + + session->socketFd = 0; + session->stubIndex = replyMessage->stubIndex; + session->toPort = replyMessage->toPort; + session->fromPort = replyMessage->fromPort; + session->type = replyMessage->transType; + session->stub = replyMessage->stub; + + if (session->stubIndex == 0) { + RPC_LOG_ERROR("stubIndex invalid"); + free(session); + return; + } + if (AttachSessionObject(session) != 0) { + RPC_LOG_ERROR("AttachSessionObject failed"); + return; + } +} + +static int32_t OnRemoteReplyMessage(const DHandleEntryTxRx *replyMessage) +{ + MakeSessionByReplyMessage(replyMessage); + WakeupThreadByStub(replyMessage->seqNumber); + return ERR_NONE; +} + +int32_t StartDBinderService(void) +{ + static bool isDBinderCreated = false; + int32_t ret = ERR_NONE; + if (isDBinderCreated) { + return ret; + } + + g_trans = GetRpcTrans(); + if (g_trans == NULL) { + RPC_LOG_ERROR("GetRpcTrans failed"); + return ERR_FAILED; + } + ret = g_trans->StartListen(DBINDER_SESSION_NAME, (void *)GetDBinderTransCallback()); + if (ret != ERR_NONE) { + RPC_LOG_ERROR("StartListen failed"); + return ret; + } + + ret = InitDBinder(); + if (ret != ERR_NONE) { + RPC_LOG_ERROR("InitDBinder failed"); + } + isDBinderCreated = true; + return ret; +} + +int32_t RegisterRemoteProxy(const void *name, uint32_t len, int32_t systemAbility) +{ + RPC_LOG_INFO("register remote proxy, service name = %s", (char*)name); + if (name == NULL || systemAbility < 0) { + RPC_LOG_ERROR("RegisterRemoteProxy name is null or systemAbility invalid"); + return ERR_FAILED; + } + const char *serviceName = (char *)name; + + RemoteBinderObjects *binderObject = (RemoteBinderObjects *)malloc(sizeof(RemoteBinderObjects)); + if (binderObject == NULL) { + RPC_LOG_ERROR("binder object malloc failed"); + return ERR_FAILED; + } + + uintptr_t binder = (uintptr_t)systemAbility; + binderObject->binder = binder; + + if (len == 0 || len > SERVICENAME_LENGTH || len != strlen(serviceName)) { + RPC_LOG_ERROR("RegisterRemoteProxy name length invalid"); + free(binderObject); + return ERR_FAILED; + } + binderObject->serviceName = (char *)malloc(len + 1); + if (binderObject->serviceName == NULL) { + RPC_LOG_ERROR("RegisterRemoteProxy binderObject->serviceName malloc failed"); + free(binderObject); + return ERR_FAILED; + } + + if (strcpy_s(binderObject->serviceName, len + 1, serviceName) != EOK) { + RPC_LOG_ERROR("RegisterRemoteProxy binderObject->serviceName copy failed"); + free(binderObject->serviceName); + free(binderObject); + return ERR_FAILED; + } + + AddRegisterService(binderObject); + return ERR_NONE; +} + +int32_t MakeRemoteBinder(const void *serviceName, uint32_t nameLen, const char *deviceID, uint32_t idLen, + uintptr_t binderObject, uint64_t pid, void *remoteObject) +{ + RPC_LOG_INFO("MakeRemoteBinder start"); + if (CheckBinderParams(serviceName, nameLen, deviceID, idLen, remoteObject) != ERR_NONE) { + RPC_LOG_ERROR("MakeRemoteBinder failed"); + return ERR_FAILED; + } + + const char *name = (const char *)serviceName; + DBinderServiceStub *dBinderServiceStub = FindOrNewDBinderStub(name, nameLen, deviceID, idLen, binderObject); + if (dBinderServiceStub == NULL) { + RPC_LOG_ERROR("FindOrNewDBinderStub return null"); + return ERR_FAILED; + } + + uint32_t retryTimes = 0; + int32_t ret = ERR_FAILED; + do { + ret = InvokerRemoteDBinder(dBinderServiceStub, GetSeqNumber()); + retryTimes++; + } while (ret != ERR_NONE && (retryTimes < RETRY_TIMES)); + + if (ret != ERR_NONE) { + RPC_LOG_ERROR("fail to invoke service, service name = %s", serviceName); + SessionInfo *sessionObject = QuerySessionObject((uintptr_t)(dBinderServiceStub->svc.cookie)); + if (sessionObject != NULL) { + DetachSessionObject(sessionObject); + free(sessionObject); + } + DeleteDBinderStub(dBinderServiceStub); + free((void *)dBinderServiceStub->svc.cookie); + free(dBinderServiceStub); + } else { + if (memcpy_s(remoteObject, sizeof(SvcIdentity), &dBinderServiceStub->svc, sizeof(SvcIdentity)) != 0) { + RPC_LOG_ERROR("svc memory copy failed"); + ret = ERR_FAILED; + } + } + + return ret; +} + +int32_t OnRemoteMessageTask(const DHandleEntryTxRx *message) +{ + if (message == NULL) { + RPC_LOG_ERROR("OnRemoteMessageTask message is NULL"); + return ERR_FAILED; + } + + int32_t ret = ERR_NONE; + switch (message->dBinderCode) { + case MESSAGE_AS_INVOKER: { + ret = OnRemoteInvokerMessage(message); + break; + } + case MESSAGE_AS_REPLY: { + ret = OnRemoteReplyMessage(message); + break; + } + default: { + RPC_LOG_ERROR("OnRemoteMessageTask dbindercode=%d valid", message->dBinderCode); + ret = ERR_FAILED; + break; + } + } + return ret; +} \ No newline at end of file diff --git a/services/dbinder/c/src/dbinder_stub.c b/services/dbinder/c/src/dbinder_stub.c new file mode 100644 index 0000000000000000000000000000000000000000..627e8f97b21311994dd7bb66102bc566fe192efe --- /dev/null +++ b/services/dbinder/c/src/dbinder_stub.c @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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. + */ + +#include "dbinder_stub.h" + +#include +#include + +#include "rpc_log.h" +#include "rpc_errno.h" +#include "securec.h" +#include "ipc_thread_pool.h" +#include "ipc_skeleton.h" +#include "ipc_process_skeleton.h" +#include "dbinder_service.h" +#include "dbinder_ipc_adapter.h" + +static int32_t GetDigits(int32_t number) +{ + int32_t n = 0; + while (number > 0) { + n++; + number /= ID_DIGITS; + } + if (n == 0) { + n++; + } + return n; +} + +static char *CreateDatabusName(void) +{ + int32_t pid = (int32_t)GetCallingPid(); + int32_t pidLen = GetDigits(pid); + int32_t uid = (int32_t)GetCallingUid(); + int32_t uidLen = GetDigits(uid); + + uint32_t sessionNameLen = SESSION_NAME_LEGNTH + pidLen + uidLen; + char *sessionName = (char *)malloc(sessionNameLen + 1); + if (sessionName == NULL) { + RPC_LOG_ERROR("sessionName mallo failed"); + return NULL; + } + if (sprintf_s(sessionName, sessionNameLen + 1, "DBinder%d_%d", uid, pid) == -1) { + RPC_LOG_ERROR("sessionName sprintf failed"); + free(sessionName); + return NULL; + } + return sessionName; +} + +static int32_t ProcessProto(uint32_t code, IpcIo *data, IpcIo *reply, MessageOption *option) +{ + int32_t result = ERR_NONE; + ThreadContext *threadContext = GetCurrentThreadContext(); + if (threadContext == NULL) { + RPC_LOG_ERROR("ProcessProto threadContext is null"); + return ERR_FAILED; + } + + SessionInfo *session = QuerySessionObject((uintptr_t)threadContext->objectStub); + if (session == NULL) { + RPC_LOG_ERROR("client find session is null"); + return ERR_FAILED; + } + const char *localBusName = CreateDatabusName(); + if (localBusName == NULL) { + RPC_LOG_ERROR("ProcessProto CreateDatabusName failed"); + return ERR_FAILED; + } + + switch (session->type) { + case DATABUS_TYPE: { + WriteUint32(reply, IF_PROT_DATABUS); + WriteUint64(reply, session->stubIndex); + WriteString(reply, session->serviceName); + WriteString(reply, session->deviceIdInfo.toDeviceId); + WriteString(reply, session->deviceIdInfo.fromDeviceId); + WriteString(reply, localBusName); + free((void *)localBusName); + break; + } + default: { + result = ERR_FAILED; + break; + } + } + return result; +} + +static int32_t DBinderRemoteRequest(uint32_t code, IpcIo *data, IpcIo *reply, MessageOption *option) +{ + int32_t ret = 0; + switch (code) { + case GET_PROTO_INFO: { + ret = ProcessProto(code, data, reply, option); + break; + } + default: { + RPC_LOG_ERROR("unknown dbinder code %{public}d", code); + ret = -1; + break; + } + } + return ret; +} + +int32_t GetDBinderStub(const char *serviceName, const char *deviceID, + uintptr_t binderObject, DBinderServiceStub *dBinderServiceStub) +{ + if (strcpy_s(dBinderServiceStub->serviceName, SERVICENAME_LENGTH, serviceName) != EOK + || strcpy_s(dBinderServiceStub->deviceID, DEVICEID_LENGTH, deviceID) != EOK) { + RPC_LOG_ERROR("dBinderServiceStub string copy failed"); + return ERR_FAILED; + } + + IpcObjectStub *objectStub = (IpcObjectStub *)malloc(sizeof(IpcObjectStub)); + if (objectStub == NULL) { + RPC_LOG_ERROR("objectStub malloc failed"); + return ERR_FAILED; + } + objectStub->func = (OnRemoteRequest)DBinderRemoteRequest; + objectStub->isRemote = true; + + dBinderServiceStub->binderObject = binderObject; + dBinderServiceStub->svc.handle = GetDBinderHandle((uintptr_t)objectStub); + dBinderServiceStub->svc.token = (uintptr_t)objectStub; + dBinderServiceStub->svc.cookie = (uintptr_t)objectStub; + return ERR_NONE; +} \ No newline at end of file diff --git a/services/dbinder/c/src/dbinder_trans_callback.c b/services/dbinder/c/src/dbinder_trans_callback.c new file mode 100644 index 0000000000000000000000000000000000000000..55393d67db8e4b83e255186cb7ec6112d78fc999 --- /dev/null +++ b/services/dbinder/c/src/dbinder_trans_callback.c @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * 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. + */ + +#include "rpc_trans.h" + +#include + +#include "dbinder_service.h" +#include "rpc_log.h" +#include "rpc_errno.h" + +static int32_t OnConnected(int32_t sessionId, int32_t result) +{ + RPC_LOG_ERROR("dbinder OnConnected callback, receive sessionId: %d", sessionId); + return ERR_NONE; +} + +static int32_t OnDisconnected(int32_t sessionId) +{ + RPC_LOG_ERROR("dbinder OnDisconnected callback, receive sessionId: %d", sessionId); + return ERR_NONE; +} + +static int32_t OnRecieved(int32_t sessionId, const void *data, uint32_t len) +{ + RPC_LOG_INFO("dbinder OnRecieved callback, receive sessionId: %d", sessionId); + if (data == NULL) { + RPC_LOG_ERROR("OnRecieved failed, data is null"); + return ERR_FAILED; + } + if (len != sizeof(DHandleEntryTxRx)) { + RPC_LOG_ERROR("OnRecieved received data length %d, excepted length %d", len, sizeof(DHandleEntryTxRx)); + return ERR_FAILED; + } + + DHandleEntryTxRx *handleEntry = (DHandleEntryTxRx *)data; + if (OnRemoteMessageTask(handleEntry) != ERR_NONE) { + RPC_LOG_ERROR("OnRemoteMessageTask failed"); + return ERR_FAILED; + } + + return ERR_NONE; +} + +static TransCallback g_sessionListener = { + .OnConnected = OnConnected, + .OnDisconnected = OnDisconnected, + .OnRecieved = OnRecieved +}; + +TransCallback *GetDBinderTransCallback(void) +{ + RPC_LOG_INFO("GetTransCallback dbinder"); + return &g_sessionListener; +} \ No newline at end of file