summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorToshikazuOhiwa <toshikazu_ohiwa@mail.toyota.co.jp>2020-03-30 09:35:51 +0900
committerToshikazuOhiwa <toshikazu_ohiwa@mail.toyota.co.jp>2020-03-30 09:35:51 +0900
commit004c91acd4c8b4510fe1a003b83d858787f41be2 (patch)
treef1471ec4539d9ec70dce5edd8231a001a4476ae6
parent706ad73eb02caf8532deaf5d38995bd258725cb8 (diff)
-rw-r--r--other_service.mk42
-rw-r--r--rpc_library/LICENSE177
-rw-r--r--rpc_library/Makefile.client19
-rw-r--r--rpc_library/library/Makefile46
-rw-r--r--rpc_library/library/include/other_service/rpc.h765
-rw-r--r--rpc_library/library/include/other_service/rpc_id.h96
-rw-r--r--rpc_library/library/include/other_service/rpc_library.h41
-rw-r--r--rpc_library/library/include/rpc_internal.h135
-rw-r--r--rpc_library/library/include/rpc_thread.h240
-rw-r--r--rpc_library/library/include/rpc_udp.h162
-rw-r--r--rpc_library/library/librpc.ver29
-rw-r--r--rpc_library/library/src/rpc_event.c158
-rw-r--r--rpc_library/library/src/rpc_lib.c1264
-rw-r--r--rpc_library/library/src/rpc_marshall.c740
-rw-r--r--rpc_library/library/src/rpc_thread.c1224
-rw-r--r--rpc_library/library/src/rpc_udp.c473
-rw-r--r--rpc_library/tool/Makefile62
-rw-r--r--rpc_library/tool/apidef.cc1104
-rw-r--r--rpc_library/tool/apidef.h333
-rw-r--r--rpc_library/tool/apidef.l136
-rw-r--r--rpc_library/tool/apidef.y615
-rw-r--r--rpc_library/tool_for_arm/Makefile50
22 files changed, 7911 insertions, 0 deletions
diff --git a/other_service.mk b/other_service.mk
new file mode 100644
index 00000000..908176bf
--- /dev/null
+++ b/other_service.mk
@@ -0,0 +1,42 @@
+#############################################################
+#
+# Common Makefile for other_service
+# Copyright (C) 2017-2019 TOYOTA MOTOR CORPORATION
+#
+# 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.
+#
+#############################################################
+
+CURRENT_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
+
+#############################################################
+# COMPONENT_NAME must not be blank and be named snake_case
+
+COMPONENT_NAME := other_service
+
+#############################################################
+
+#############################################################
+# You can add several flags and libraries.
+# When you add -I or -L path, DO NOT USE relative path.
+# Instead, use $(CURRENT_DIR) variable
+# that indicates the path this .mk file is stored.
+
+COMPONENT_CFLAGS :=
+COMPONENT_CXXFLAGS :=
+COMPONENT_LDLIBS :=
+COMPONENT_LDFLAGS :=
+
+##############################################################
+
+include $(SDKTARGETSYSROOT)/usr/agl/share/agl.mk
diff --git a/rpc_library/LICENSE b/rpc_library/LICENSE
new file mode 100644
index 00000000..f433b1a5
--- /dev/null
+++ b/rpc_library/LICENSE
@@ -0,0 +1,177 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
diff --git a/rpc_library/Makefile.client b/rpc_library/Makefile.client
new file mode 100644
index 00000000..c5ca6e04
--- /dev/null
+++ b/rpc_library/Makefile.client
@@ -0,0 +1,19 @@
+#
+# @copyright Copyright (c) 2016-2019 TOYOTA MOTOR CORPORATION.
+#
+# 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.
+#
+
+SUBDIRS := tool_for_arm library
+
+include ../other_service.mk
diff --git a/rpc_library/library/Makefile b/rpc_library/library/Makefile
new file mode 100644
index 00000000..38016a26
--- /dev/null
+++ b/rpc_library/library/Makefile
@@ -0,0 +1,46 @@
+#
+# @copyright Copyright (c) 2016-2019 TOYOTA MOTOR CORPORATION.
+#
+# 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.
+#
+
+INST_SHLIBS := librpc
+librpc_SRCS := rpc_lib.c \
+ rpc_marshall.c \
+ rpc_event.c \
+ rpc_udp.c \
+ rpc_thread.c
+
+CPPFLAGS = -I../tool \
+ -I./include \
+ -D_GNU_SOURCE \
+
+CPPFLAGS += -Wl,--no-undefined
+CPPFLAGS += -Werror=implicit-function-declaration
+CPPFLAGS += -Werror=format-security
+
+CPPFLAGS += -Wconversion
+CPPFLAGS += -Wpointer-to-int-cast
+CPPFLAGS += -Wint-to-pointer-cast
+CPPFLAGS += -Wpointer-arith
+CPPFLAGS += -Wformat
+LDFLAGS += -Wl,--no-as-needed
+LDLIBS := -lrt -lcommon
+
+
+VPATH = ./src ./include/$(COMPONENT_NAME)
+INST_HEADERS := rpc.h \
+ rpc_id.h \
+ rpc_library.h \
+
+include ../../other_service.mk
diff --git a/rpc_library/library/include/other_service/rpc.h b/rpc_library/library/include/other_service/rpc.h
new file mode 100644
index 00000000..6947134c
--- /dev/null
+++ b/rpc_library/library/include/other_service/rpc.h
@@ -0,0 +1,765 @@
+/*
+ * @copyright Copyright (c) 2016-2019 TOYOTA MOTOR CORPORATION.
+ *
+ * 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.
+ */
+
+/**
+ * @file rpc.h
+ * @brief \~english RPC library --API define header file
+ */
+/** @addtogroup BaseSystem
+ * @{
+ */
+/** @addtogroup other_service
+ * @ingroup BaseSystem
+ * @{
+ */
+/** @addtogroup rpc_library
+ * @ingroup other_service
+ * @{
+ */
+#ifndef OTHERSERVICE_RPC_H_ // NOLINT(build/header_guard)
+#define OTHERSERVICE_RPC_H_ // NOLINT(build/header_guard)
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include <other_service/rpc_id.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+* @brief \~english RPC_ID max number
+*/
+#define RPC_MAX_THREADS_IN_PROCESS 64
+
+/** @brief \~english fd max number in one process.
+ * 0 = main/sub thread communication pipe fd.
+ * 1 = inotify() process listen fd.
+ * 2~129 = even num : API request data socket.
+ * odd num : secure stream socket.
+ * */
+#define RPC_MAX_FD_IN_PROCESS 130
+
+
+#define RPC_MAX_API_ARG_NUM 8
+///< \~english API call parameter max num
+
+
+#define RPC_MAX_API_ARG_SIZE 1024
+///< \~english API call one parameter max byte
+
+#define RPC_MAX_API_ARG_TOTAL_SIZE 1500
+///< \~english API call all parameter max byte
+
+#define RPC_MAX_APICALL_QUEUE 16
+///< \~english API call max queue num
+
+#define RPC_NO_PORT 0
+///< \~english invalid port num
+
+/** @brief \~english RPC library function return value
+ */
+enum rpc_result { // NOLINT (readability/nolint)
+ RPC_OK = 0, ///< \~english ok
+ RPC_ERR_No_Response = 0x8fff0000, ///< \~english has no response
+ RPC_ERR_Timeout, ///< \~english timeout
+ RPC_ERR_Busy, ///< \~english busy
+ RPC_ERR_API_Error, ///< \~english API error
+ RPC_ERR_API_Fatal, ///< \~english API fatal
+ RPC_ERR_Fatal, ///< \~english fatal
+ RPC_ERR_Configuration, ///< \~english configuration
+ RPC_ERR_Server_DeadLock, ///< \~english server deadlock
+ RPC_ERR_Server_Finish, ///< \~english server finish
+ RPC_ERR_Reject_connect, ///< \~english reject connect
+};
+/** @brief \~english RPC library function return type
+ * @see rpc_result
+ * */
+typedef INT32 RPC_Result;
+
+/** @brief \~english RPC ID
+ *
+ */
+typedef UINT32 RPC_ID;
+
+#define RPC_NO_ID RPC_NO_PORT
+///< \~english The ID when destination is invalid
+
+#define RPC_SELF_ID RPC_NO_PORT
+///< \~english The ID when destination is self
+
+/** @brief \~english The ID when destination is any
+ * */
+#define RPC_ANY_ID RPC_NO_PORT
+
+
+typedef RPC_Result (*RPC_dispatch_func_t)(UINT16 api_num,
+ const char *args_string,
+ unsigned int args_size,
+ char **ret_string,
+ unsigned int *ret_bytes);
+
+#ifdef RPC_DISPATCH_FUNC
+#error "Please include <rpc.h> before \"*_srvr.h\"."
+#else /* !RPC_DISPATCH_FUNC */
+#define RPC_DISPATCH_FUNC NULL
+#endif /* !RPC_DISPATCH_FUNC */
+
+/* RPC Library Start Function Macro */
+/////////////////////////////////////////////////////////////////////////////////////
+/// \ingroup RPC_START_SERVER
+/// \~english @par Brief
+/// server start(certification of the client by UID)
+/// \~english @param [in] ID
+/// RPC_ID - program's RPC_ID
+/// \~english @retval RPC_OK Normal End
+/// \~english @retval RPC_ERR_Fatal Fatal Error
+/// \~english @par Prerequisite
+/// None
+/// \~english @par Change of internal state
+/// None
+/// \~english @par Conditions of processing failure
+/// - Case of an input parameter error
+/// - Case of fail to information generation
+/// - When RPC_start has already been issued
+/// - Case of space reservation fails
+/// - Case of socket generation fails
+/// - Case of socket allocation fails
+/// - Case of creating a pipe fails
+/// - RPC_ERR_Fatal
+/// \~english @par Classification
+/// Public
+/// \~english @par Type
+/// Sync Only
+/// \~english @par Detail
+/// - Used when the server program of RPC-API performs RPC library use start processing
+/// - ID specifies a symbol in the form of XXX_RPC_ID defined by rpc_id.h
+/// - Only one server program is permitted per thread
+/// - When the server program calls the API as a client of another server,
+/// it only needs to call RPC_START_SERVER, there is no need to call RPC_START_CLIENT
+/// \~english @see RPC_start, RPC_end
+////////////////////////////////////////////////////////////////////////////////////
+#define RPC_START_SERVER(ID) RPC_start((ID), RPC_DISPATCH_FUNC, NULL, NO_SECURE_CHECK)
+
+/////////////////////////////////////////////////////////////////////////////////////
+/// \ingroup RPC_START_SECURE_SERVER
+/// \~english @par Brief
+/// server start(certification of the client by UID)
+/// \~english @param [in] ID
+/// RPC_ID - program's RPC_ID
+/// \~english @retval RPC_OK Normal End
+/// \~english @retval RPC_ERR_Fatal Fatal Error
+/// \~english @par Prerequisite
+/// None
+/// \~english @par Change of internal state
+/// None
+/// \~english @par Conditions of processing failure
+/// - Case of an input parameter error
+/// - Case of fail to information generation
+/// - When RPC_start has already been issued
+/// - Case of space reservation fails
+/// - Case of socket generation fails
+/// - Case of socket allocation fails
+/// - Case of creating a pipe fails
+/// - RPC_ERR_Fatal
+/// \~english @par Classification
+/// Public
+/// \~english @par Type
+/// Sync Only
+/// \~english @par Detail
+/// - Used when the server program of RPC-API performs RPC library use start processing
+/// - ID specifies a symbol in the form of XXX_RPC_ID defined by rpc_id.h
+/// - Only one server program is permitted per thread
+/// - When the server program calls the API as a client of another server,
+/// it only needs to call RPC_START_SERVER, there is no need to call RPC_START_CLIENT
+/// \~english @see RPC_start, RPC_end
+////////////////////////////////////////////////////////////////////////////////////
+#define RPC_START_SECURE_SERVER(ID) RPC_start((ID), RPC_DISPATCH_FUNC, NULL, NEED_SECURE_CHECK)
+
+/////////////////////////////////////////////////////////////////////////////////////
+/// \ingroup RPC_START_CLIENT
+/// \~english @par Brief
+/// client start
+/// \~english @param [out] pID
+/// RPC_ID * - auto allocated program's RPC_ID
+/// \~english @retval RPC_OK Normal End
+/// \~english @retval RPC_ERR_Fatal Fatal Error
+/// \~english @par Prerequisite
+/// None
+/// \~english @par Change of internal state
+/// None
+/// \~english @par Conditions of processing failure
+/// - input parameter error
+/// - Unable to get the rpc lib info for the self-thread.
+/// - Memory allocation fail for id info.
+/// - Socket generation fail.
+/// - Socket allocation fail.
+/// - Unable to get the socket name.
+/// - RPC_ERR_Fatal
+/// \~english @par Classification
+/// Public
+/// \~english @par Type
+/// Sync Only
+/// \~english @par Detail
+/// - This macro supports only client function of RPC library.
+/// - Run the start processing by using this macro only when the APIs provided by the other program are called.
+/// \~english @see RPC_start, RPC_end
+////////////////////////////////////////////////////////////////////////////////////
+#define RPC_START_CLIENT(pID) RPC_start((UINT16)RPC_NO_ID, NULL, (pID), NO_SECURE_CHECK)
+//!< \~english client start
+
+/* Client authentication by registering the server's UID list */
+#define NEED_SECURE_CHECK 1 ///< \~english has secure check
+#define NO_SECURE_CHECK 0 ///< \~english has no secure check
+
+/* Setting whether to register UID list of server */
+#define REGISTERED 1 ///< \~english registered
+#define NO_REGISTERED 0 ///< \~english not registered
+
+/* API Function Prototypes in the RPC Library */
+RPC_Result RPC_start(RPC_ID id, RPC_dispatch_func_t func, RPC_ID *pID, INT32 secure_check); // NOLINT (readability/nolint)
+
+/////////////////////////////////////////////////////////////////////////////////////
+/// \ingroup RPC_get_fd
+/// \~english @par Brief
+/// Get the file descriptor to judge whether there is the request of RPC-API call or not.
+/// \~english @param [in] id
+/// RPC_ID - server program's RPC_ID
+/// \~english @param [out] fd
+/// int * - area for fd
+/// \~english @retval RPC_OK Normal End
+/// \~english @retval RPC_ERR_Fatal Fatal Error
+/// \~english @par Prerequisite
+/// RPC_START_SERVER or RPC_START_SECURE_SERVER is already called.
+/// \~english @par Change of internal state
+/// None
+/// \~english @par Conditions of processing failure
+/// - Argument(id) is RPC_NO_ID.
+/// - Argument(fd) is NULL.
+/// - Unable to get the rpc lib info for the self-thread.
+/// - RPC sub thread doesn't exist.
+/// - RPC_ERR_Fatal
+/// \~english @par Classification
+/// Public
+/// \~english @par Type
+/// Sync Only
+/// \~english @par Detail
+/// - This function returns the fd(file descriptor) to judge whether there is the request to server.
+/// - Return value(fd) is used only for poll function or select function parameter.
+/// - Usage
+/// - To get fd from this function.
+/// - Wait for the data to use poll function or select function.
+/// - After that, call RPC_process_API_request function.
+/// - As a result, the API call request from client is done(that is, run the server API).
+/// \~english @see None
+////////////////////////////////////////////////////////////////////////////////////
+RPC_Result RPC_get_fd(RPC_ID id, int *fd); // NOLINT (readability/nolint)
+
+/////////////////////////////////////////////////////////////////////////////////////
+/// \ingroup RPC_process_API_request
+/// \~english @par Brief
+/// Run the processing of RPC-API call
+/// \~english @param [in] id
+/// RPC_ID - server program's RPC_ID
+/// \~english @retval RPC_OK Normal End
+/// \~english @retval RPC_ERR_Fatal Fatal Error
+/// \~english @par Prerequisite
+/// RPC_START_SERVER or RPC_START_SECURE_SERVER is already called.
+/// \~english @par Change of internal state
+/// None
+/// \~english @par Conditions of processing failure
+/// - Argument(id) is RPC_NO_ID.
+/// - Unable to get the rpc lib info for the self-thread.
+/// - RPC sub thread doesn't exist.
+/// - fail to send UDP packet.
+/// - API processing from the client returns the error.
+/// - RPC_ERR_Fatal
+/// \~english @par Classification
+/// Public
+/// \~english @par Type
+/// Sync Only
+/// \~english @par Detail
+/// - Process all the queued API running requests from the client.
+/// - API function of server program is called in this function.
+/// - If there are no requests to run API, this function doesn't wait and return immediately.
+/// \~english @see None
+////////////////////////////////////////////////////////////////////////////////////
+RPC_Result RPC_process_API_request(RPC_ID id); // NOLINT (readability/nolint)
+
+/////////////////////////////////////////////////////////////////////////////////////
+/// \ingroup RPC_end
+/// \~english @par Brief
+/// End processing of RPC library.
+/// \~english @param [in] id
+/// RPC_ID - program's RPC_ID
+/// \~english @retval None
+/// \~english @par Prerequisite
+/// RPC_START_SERVER or RPC_START_SECURE_SERVER or RPC_START_CLIENT is already called.
+/// \~english @par Change of internal state
+/// None
+/// \~english @par Conditions of processing failure
+/// None
+/// \~english @par Classification
+/// Public
+/// \~english @par Type
+/// Sync Only
+/// \~english @par Detail
+/// - End processing(socket close and memory release etc) is done.
+/// - When there are no more program that uses RPC_ID, RPC sub thread started by RPC_start will be ended.
+/// - Need to call this function before the program is ended.
+/// - Need to call this function from which the thread called RPC_start.
+/// - Nothing is done when incorrect or no more used RPC_ID is designated.
+/// \~english @see None
+////////////////////////////////////////////////////////////////////////////////////
+void RPC_end(RPC_ID id); // NOLINT (readability/nolint)
+
+////////////////////////////////////////////////////////////////////////////////
+/// \ingroup RPC_end_all
+/// \~english @par Brief
+/// End processing of RPC library(forcing to clean up).
+/// \~english @par Prerequisite
+/// - None
+/// \~english @par Change of internal state
+/// - None
+/// \~english @par Conditions of processing failure
+/// - None
+/// \~english @par Classification
+/// Public
+/// \~english @par Type
+/// Sync Only
+/// \~english @par Detail
+/// Delete the socket files created in process for communication. /n
+/// The program which use RPC library must call RPC_end() to free resource, /n
+/// This API is used for insurance processing when socket file's link lost. /n
+/// 1,Before process ends, call this API. /n
+/// When process is ending, auto running socket's close and memory free is not work. /n
+/// 2,After called this API, all the RPC's process(both server and client) become to useless. /n
+/// Even if after called this API, call RPC_START to repair it also can't make sure to active. /n
+/// RPC library which use Unix autobind is nothing to do. /n
+/// \~english @see None
+////////////////////////////////////////////////////////////////////////////////
+void RPC_end_all(void); // NOLINT (readability/nolint)
+
+/////////////////////////////////////////////////////////////////////////////////////
+/// \ingroup RPC_set_API_timeout
+/// \~english @par Brief
+/// Set timeout time for server side API processing time
+/// \~english @param [in] sec
+/// INT32 - timeout time
+/// \~english @retval RPC_OK Normal End
+/// \~english @retval RPC_ERR_Fatal Fatal Error
+/// \~english @retval RPC_ERR_Configuration Argument is out of range
+/// \~english @par Prerequisite
+/// RPC_START_SERVER or RPC_START_SECURE_SERVER is already called.
+/// \~english @par Change of internal state
+/// None
+/// \~english @par Conditions of processing failure
+/// - Unable to get the rpc lib info for the self-thread.
+/// - Server id info doesn't exist.
+/// - Info for API call reception processing doesn't exist.
+/// - RPC_ERR_Fatal
+/// - The value of the argument(sec) is out of range.
+/// - RPC_ERR_Configuration
+/// \~english @par Classification
+/// Public
+/// \~english @par Type
+/// Sync Only
+/// \~english @par Detail
+/// None
+/// \~english @see None
+////////////////////////////////////////////////////////////////////////////////////
+RPC_Result RPC_set_API_timeout(INT32 sec); // NOLINT (readability/nolint)
+
+
+////////////////////////////////////////////////////////////////////////////////
+/// \ingroup RPC_is_server_ready
+/// \~english @par Brief
+/// Return RPC server's status
+/// \~english @param [in] id
+/// RPC_ID - server program's RPC_ID
+///
+/// \~english @retval RPC_OK : Success
+/// \~english @retval RPC_ERR_No_Response : No response
+///
+/// \~english @par Prerequisite
+/// - None
+/// \~english @par Change of internal state
+/// - None
+/// \~english @par Conditions of processing failure
+/// - None
+/// \~english @par Classification
+/// Public
+/// \~english @par Type
+/// Sync Only
+/// \~english @par Detail
+/// return the server's work status.
+/// \~english @see None
+////////////////////////////////////////////////////////////////////////////////
+RPC_Result RPC_is_server_ready(RPC_ID id); // NOLINT (readability/nolint)
+
+/////////////////////////////////////////////////////////////////////////////////////
+/// \ingroup RPC_regist_credential
+/// \~english @par Brief
+/// Register UID and GID list
+/// \~english @param [in] uid_num
+/// int - UID number to regist(number of elements of UID list)
+/// \~english @param [in] uid_list
+/// uid_t* - head pointer of UID list
+/// \~english @param [in] gid_num
+/// int - GID number to regist(number of elements of GID list)
+/// \~english @param [in] uid_list
+/// gid_t* - head pointer of GID list
+/// \~english @retval RPC_OK Normal End
+/// \~english @retval RPC_ERR_Fatal Fatal Error
+/// \~english @retval RPC_ERR_Configuration Argument is out of range
+/// \~english @par Prerequisite
+/// RPC_START_SECURE_SERVER is already called.
+/// \~english @par Change of internal state
+/// None
+/// \~english @par Conditions of processing failure
+/// - Unable to get the rpc lib info for the self-thread.
+/// - Server id info doesn't exist.
+/// - Info for API call reception processing doesn't exist.
+/// - Arguments(client_uid and client_gid) are NULL.
+/// - Client authentication check is not necessary.
+/// - Authentication info is already registered.
+/// - Memory allocation fail for UID and GID lists.
+/// - RPC_ERR_Fatal
+/// - Values of Arguments(uid_num and gid_num) are out of range.
+/// - RPC_ERR_Configuration
+/// \~english @par Classification
+/// Public
+/// \~english @par Type
+/// Sync Only
+/// \~english @par Detail
+/// - Register the UID and GID lists acceptable by the RPC server.
+/// - If RPC_START_SECURE_SERVER is not called, this function returns the error.
+/// \~english @see None
+////////////////////////////////////////////////////////////////////////////////////
+RPC_Result RPC_regist_credential(int uid_num, uid_t *uid_list, int gid_num, gid_t *gid_list); // NOLINT (readability/nolint)
+
+/////////////////////////////////////////////////////////////////////////////////////
+/// \ingroup RPC_get_client_credential
+/// \~english @par Brief
+/// Get UID and GID of client that requested to run APIs processing
+/// \~english @param [out] client_uid
+/// uid_t* - UID of client that requested to run APIs processing
+/// \~english @param [out] client_gid
+/// gid_t* - GID of client that requested to run APIs processing
+/// \~english @retval RPC_OK Normal End
+/// \~english @retval RPC_ERR_Fatal Fatal Error
+/// \~english @par Prerequisite
+/// RPC_START_SECURE_SERVER is already called.
+/// \~english @par Change of internal state
+/// None
+/// \~english @par Conditions of processing failure
+/// - Server id info doesn't exist.
+/// - Info for API call reception processing doesn't exist.
+/// - Arguments(client_uid and client_gid) are NULL.
+/// - Client authentication check is not necessary.
+/// - There are no running clients.
+/// - Info for the running client is not applicable.
+/// - RPC_ERR_Fatal
+/// \~english @par Classification
+/// Public
+/// \~english @par Type
+/// Sync Only
+/// \~english @par Detail
+/// - This function is to get UID and GID of client that requested to run APIs processing.
+/// - If RPC_START_SECURE_SERVER is not called, this function returns the error.
+/// - If the running client doesn't exist, this function returns the error.
+/// \~english @see None
+////////////////////////////////////////////////////////////////////////////////////
+RPC_Result RPC_get_client_credential(uid_t *client_uid, gid_t *client_gid); // NOLINT (readability/nolint)
+
+/*
+ * The following are only used in stub files
+ */
+#define RPC_RETCODE_LEN 9
+
+#define RPC_MARSHALL_FLAG_BITS_CODE 12
+#define RPC_MARSHALL_FLAG_BITS_IS_VARARRAY 1
+#define RPC_MARSHALL_FLAG_BITS_IS_POINTER 1
+#define RPC_MARSHALL_FLAG_BITS_IN_OUT 2
+
+/** @brief \~english APIcall property stored struct
+ *
+ */
+typedef union {
+ UINT32 all; ///< \~english all property
+ struct {
+ unsigned int code: RPC_MARSHALL_FLAG_BITS_CODE; ///< \~english value type
+ /** @brief \~english vararray or not
+ *
+ */
+ unsigned int is_vararray: RPC_MARSHALL_FLAG_BITS_IS_VARARRAY;
+ /** @brief \~english pointer or not
+ *
+ */
+ unsigned int is_pointer: RPC_MARSHALL_FLAG_BITS_IS_POINTER;
+ /** @brief \~english in/out parameter property
+ *
+ */
+ unsigned int in_out: RPC_MARSHALL_FLAG_BITS_IN_OUT;
+ /** @brief \~english string or user define type byte num.other is 0
+ *
+ */
+ UINT16 bytes;
+ } bits; ///< \~english variable properties
+} RPC_marshall_flag;
+
+/////////////////////////////////////////////////////////////////////////////////////
+/// \ingroup RPC_API_call
+/// \~english @par brief
+/// API call execution function (client)
+/// \~english @param [in] id
+/// RPC_ID - RPC_ID of server program
+/// \~english @param [in] api_num
+/// UINT16 - Request API number
+/// \~english @param [in] args_string
+/// const char* - Argument string
+/// \~english @param [in] args_size
+/// unsigned int - Argument string length
+/// \~english @param [out] ret_string
+/// char** - Process result string
+/// \~english @param [out] ret_size
+/// unsigned int* - Process result string length
+/// \~english @retval RPC_OK Normal End
+/// \~english @retval RPC_ERR_Fatal Fatal error
+/// \~english @retval RPC_ERR_No_Response No response
+/// \~english @retval RPC_ERR_Busy API call queue overflow
+/// \~english @retval RPC_ERR_Server_DeadLock RPC server deadlock
+/// \~english @retval RPC_ERR_Reject_connect The RPC server does not allow communication
+/// \~english @par Prerequisite
+/// The RPC server is running.
+/// \~english @par Change of internal state
+/// None
+/// \~english @par Conditions of processing failure
+/// - Acquisition of rpc library information for self thread fails
+/// - Generation of self-thread rpc library information fails
+/// - The RPC ID information does not exist
+/// - Failed to receive data from the server at initial authentication
+/// - Analysis of received data failed during initial authentication
+/// - Commands not expected to be received during initial authentication
+/// - Server response when initial authentication is API call error
+/// - Failed to receive data from the server at API processing request
+/// - Analysis of received data failed during API processing request
+/// - Commands not expected to be received during API processing request
+/// - Server response when API processing request is API call error
+/// - Error in server response other than deadlock when processing results are received
+/// - Server shut down
+/// - RPC_ERR_Fatal
+/// - UDP packet transmission fails at initial authentication
+/// - A timeout occurred in response from the server during initial authentication
+/// - UDP packet transmission failed at API processing request
+/// - A timeout occurred in response from the server during API processing request
+/// - RPC_ERR_No_Response
+/// - Server response when initial authentication is API call queue overflow
+/// - Server response when API processing request is API call queue overflow
+/// - RPC_ERR_Busy
+/// - When the server response is deadlocked on initial authentication
+/// - When the server response is deadlocked on API processing request
+/// - Server response is deadlocked when processing result is received
+/// - RPC_ERR_Server_DeadLock
+/// - Server response is not authenticated at initial authentication
+/// - RPC_ERR_Reject_connect
+/// \~english @par Classification
+/// Public
+/// \~english @par Type
+/// Sync Only
+/// \~english @par Detail
+/// - Request execution of RPC-API from the client side.
+/// - However, since this API is called from the automatically generated code, it is not used directly by the user.
+/// \~english @see None
+////////////////////////////////////////////////////////////////////////////////////
+RPC_Result RPC_API_call(RPC_ID id, UINT16 api_num, // NOLINT (readability/nolint)
+ const char *args_string, unsigned int args_size,
+ char **ret_string, unsigned int *ret_size);
+
+/////////////////////////////////////////////////////////////////////////////////////
+/// \ingroup RPC_demarshall_arguments
+/// \~english @par Brief
+/// Confirm whether the input character string conforms to the prescribed format.
+/// \~english @param [in] from
+/// const char * - Input string
+/// \~english @param [in] size
+/// unsigned int - Byte length of the input string
+/// \~english @param [in] need_alloc
+/// int - Flag whether memory allocation is necessary or not.
+/// \~english @param [in] num_args
+/// int - Number of the variable length arguments
+/// \~english @param [in] ...
+/// void * - Variable length arguments
+/// \~english @retval 0 Normal End
+/// \~english @retval -1 Abnormal End
+/// \~english @par Prerequisite
+/// None
+/// \~english @par Change of internal state
+/// None
+/// \~english @par Conditions of processing failure
+/// - Byte length of the input string is 0 bytes or less or larger than 1024 bytes.
+/// - The input character string doesn't conform to the prescribed format.
+/// - -1
+/// \~english @par Classification
+/// Public
+/// \~english @par Type
+/// Sync Only
+/// \~english @par Detail
+/// This function is used in the stub file only and user must not call this function directly.
+/// \~english @see RPC_marshall_arguments
+////////////////////////////////////////////////////////////////////////////////////
+int RPC_demarshall_arguments(const char *from, unsigned int size, // NOLINT (readability/nolint)
+ int need_alloc, int num_args, ...);
+
+/////////////////////////////////////////////////////////////////////////////////////
+/// \ingroup RPC_marshall_arguments
+/// \~english @par Brief
+/// Collect variable arguments, convert them to a format that matches the receiver's specification,
+/// and stuff them into the message buffer.
+/// \~english @param [in] size
+/// unsigned int * - data size after conversion
+/// \~english @param [in] dont_marshall_out_args
+/// int - input/output kind(when the argument is a pointer)
+/// \~english @param [in] num_args
+/// int - value of variable argument
+/// \~english @param [in] ...
+/// void * - variable argument
+/// \~english @retval char * Message buffer after conversion
+/// \~english @retval NULL Abnormal
+/// \~english @par Prerequisite
+/// None
+/// \~english @par Change of internal state
+/// None
+/// \~english @par Conditions of processing failure
+/// - When marshall work securing work area fails
+/// - When the specified type size is abnormal
+/// - When securing the area of the message buffer after conversion fails
+/// - NULL
+/// \~english @par Classification
+/// Public
+/// \~english @par Type
+/// Sync Only
+/// \~english @par Detail
+/// This function is used in the stub file for client only and user must not call this function directly.
+/// \~english @see RPC_demarshalol_arguments
+////////////////////////////////////////////////////////////////////////////////////
+char *RPC_marshall_arguments(unsigned int *size, int dont_marshall_out_args, // NOLINT (readability/nolint)
+ int num_args, ...);
+
+/////////////////////////////////////////////////////////////////////////////////////
+/// \ingroup RPC_marshall_free
+/// \~english @par Brief
+/// Variadic function for memory release
+/// \~english @param [in] num
+/// int - number of memory to be released
+/// \~english @param [in] ...
+/// void * - allocated memory
+/// \~english @retval None
+/// \~english @par Prerequisite
+/// None
+/// \~english @par Change of internal state
+/// None
+/// \~english @par Conditions of processing failure
+/// None
+/// \~english @par Classification
+/// Public
+/// \~english @par Type
+/// Sync Only
+/// \~english @par Detail
+/// - This function is used in the stub file only and user must not call this function directly.
+/// \~english @see None
+////////////////////////////////////////////////////////////////////////////////////
+void RPC_marshall_free(int num, ...); // NOLINT (readability/nolint)
+
+/////////////////////////////////////////////////////////////////////////////////////
+/// \ingroup RPC_free_return_string
+/// \~english @par Brief
+/// release memory allocated during running API call.
+/// \~english @param [in] ptr
+/// void * - allocated memory
+/// \~english @retval None
+/// \~english @par Prerequisite
+/// RPC_API_call is already called.
+/// \~english @par Change of internal state
+/// None
+/// \~english @par Conditions of processing failure
+/// None
+/// \~english @par Classification
+/// Public
+/// \~english @par Type
+/// Sync Only
+/// \~english @par Detail
+/// - This function is used in the stub file for client only and user must not call this function directly.
+/// \~english @see None
+////////////////////////////////////////////////////////////////////////////////////
+void RPC_free_return_string(void *ptr); // NOLINT (readability/nolint)
+
+#ifdef DBG_ENABLE
+
+////////////////////////////////////////////////////////////////////////////////
+/// \ingroup RPC_record_dbg_log
+/// \~english @par Brief
+/// RPC-API call process's log
+/// \~english @param [in] filename
+/// const char - filename's point
+/// \~english @param [in] funcname
+/// const char - function name's point
+/// \~english @param [in] line
+/// int - file's line
+/// \~english @param [in] apiname
+/// const char - called API name's point
+/// \~english @param [out]
+///
+/// \~english @retval 0 : Success
+///
+/// \~english @par Prerequisite
+/// - DBG_ENABLE is defined.
+/// \~english @par Change of internal state
+/// - None
+/// \~english @par Conditions of processing failure
+/// - None
+/// \~english @par Classification
+/// Public
+/// \~english @par Type
+/// Sync Only
+/// \~english @par Detail
+/// Receipt and record the client's filename, function name,
+/// line and called API's function name which called this API.
+/// \~english @see None
+////////////////////////////////////////////////////////////////////////////////
+int RPC_record_dbg_log(const char *filename, const char *funcname, int line,
+ const char *apiname);
+#endif
+
+#define rpc_malloc malloc
+#define rpc_free free
+
+/*
+ * RPC debug message control
+ * if set to non-null and some critical information is displayed.
+ */
+extern char *RPC_DEBUG; // NOLINT (readability/nolint)
+
+/** @}*/ // end of rpc_library
+/** @}*/ // end of other_service
+/** @}*/ // end of BaseSystem
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // OTHERSERVICE_RPC_H_
diff --git a/rpc_library/library/include/other_service/rpc_id.h b/rpc_library/library/include/other_service/rpc_id.h
new file mode 100644
index 00000000..fdc36caf
--- /dev/null
+++ b/rpc_library/library/include/other_service/rpc_id.h
@@ -0,0 +1,96 @@
+/*
+ * @copyright Copyright (c) 2016-2019 TOYOTA MOTOR CORPORATION.
+ *
+ * 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.
+ */
+
+/**
+ * @file rpc_id.h
+ * @brief \~english RPC library -- RPC_ID(port no) define
+ */
+/** @addtogroup BaseSystem
+ * @{
+ */
+/** @addtogroup other_service
+ * @ingroup BaseSystem
+ * @{
+ */
+/** @addtogroup rpc_library
+ * @ingroup other_service
+ * @{
+ */
+
+/** @brief \~english define the RPC_ID used by program
+ * like #define XXX_RPC_ID ID
+ * but RPC_START_CLIENT() is not necessary
+ *
+ * RPC_ID as the following
+ * - UI Application : 50xxx
+ * - Application Service : 51xxx
+ * + HMI : 511xx
+ * + AV : 512xx
+ * + Radio : 513xx
+ * + Connectivity : 514xx
+ * + Navigation/Location: 515xx
+ * + Vehicle : 516xx
+ * + Communication : 517xx
+ * + BasePF : 518xx
+ * + System : 519xx
+ * + Others : 510xx
+ * - Common Service : 53xxx
+ * - Extension Service : 55xxx
+ * - System/Device Driver : 56xxx
+ *
+ * - 49152~59999 are Reserved.
+ * @note \~english RPC_ID==port num ,
+ * when not call from RPClibrary, and not well-known(~1023)/registered(1024~49151)
+ * use the fixed port num to IP communicate, use 6xxxx port number.
+ * @note \~english when RPC_START_CLIENT,and distribute automatically.
+ * use the linux kernel port distribute function
+ * 1024~4999 as the port num unused.
+ */
+
+#ifndef OTHERSERVICE_RPCID_H_ // NOLINT(build/header_guard)
+#define OTHERSERVICE_RPCID_H_ // NOLINT(build/header_guard)
+
+
+#define test_RPC_ID 49999
+///< \~english sample(ID is used by RPClibrary test program)
+
+/* UI Aapplication : 50xxx */
+
+/* Application Service : 51xxx */
+#define MODEMANAGER_RPC_ID 51100 /* ModeManager */
+#define ACTIVITYMANAGER_RPC_ID 51101 /* ActivityManager */
+
+/* Common Service : 53xxx */
+#define TIMERENTRYDRV_RPC_ID 53000 /* TimerEntryDrv */
+#define TSKM_RPC_ID 53001 /* TaskManager */
+#define MSGBRK_RPC_ID 53002 /* MessageBroker */
+#define IPMANAGER_RPC_ID 53003 /* IPManager */
+#define IPMANAGER_RPC_ID 53003 /* IPManager */
+#define DEVICEMANAGER_RPC_ID 53004 /* DeviceManager */
+#define CAN_RPC_ID 53005 /* Communication(CAN) */
+#define _CWORD83__RPC_ID 53006 /* Communication(_CWORD83_) */
+#define SENSOR_RPC_ID 53007 /* Vehicle(Sensor) */
+#define GPS_RPC_ID 53008 /* Vehicle(GPS) */
+#define RESMGR_RPC_ID 53009 /* ResourceManager */
+#define GRAPHICS_RPC_ID 53010 /* Graphic */
+
+/* Extension Service : 55xxx */
+
+/* System/Device Driver : 56xxx */
+/** @}*/ // end of rpc_library
+/** @}*/ // end of other_service
+/** @}*/ // end of BaseSystem
+#endif // OTHERSERVICE_RPCID_H_
diff --git a/rpc_library/library/include/other_service/rpc_library.h b/rpc_library/library/include/other_service/rpc_library.h
new file mode 100644
index 00000000..2721f274
--- /dev/null
+++ b/rpc_library/library/include/other_service/rpc_library.h
@@ -0,0 +1,41 @@
+//
+// @copyright Copyright (c) 2017-2019 TOYOTA MOTOR CORPORATION.
+//
+// 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.
+//
+
+/**
+ * @file
+ * @brief \~english include all rpc_library head files
+ */
+/** @addtogroup BaseSystem
+ * @{
+ */
+/** @addtogroup other_service
+ * @ingroup BaseSystem
+ * @{
+ */
+/** @addtogroup rpc_library
+ * @ingroup other_service
+ * @{
+ */
+#ifndef OTHERSERVICE_RPCLIBRARY_H_ // NOLINT(build/header_guard)
+#define OTHERSERVICE_RPCLIBRARY_H_ // NOLINT(build/header_guard)
+
+#include <other_service/rpc.h>
+#include <other_service/rpc_id.h>
+
+#endif // OTHERSERVICE_RPCLIBRARY_H_
+/** @}*/
+/** @}*/
+/** @}*/
diff --git a/rpc_library/library/include/rpc_internal.h b/rpc_library/library/include/rpc_internal.h
new file mode 100644
index 00000000..3c1df98f
--- /dev/null
+++ b/rpc_library/library/include/rpc_internal.h
@@ -0,0 +1,135 @@
+/*
+ * @copyright Copyright (c) 2016-2019 TOYOTA MOTOR CORPORATION.
+ *
+ * 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.
+ */
+
+/**
+ * @file rpc_internal.h
+ * @brief RPC Library Internal Implementation-Type, macro, and function definitions used internally
+ *
+ */
+/** @addtogroup RPClib_in
+ */
+#ifndef OTHERSERVICE_RPCINTERNAL_H_ // NOLINT(build/header_guard)
+#define OTHERSERVICE_RPCINTERNAL_H_ // NOLINT(build/header_guard)
+
+#include <unistd.h>
+#include <stdlib.h>
+
+#if defined(__linux__)
+/* Using unix autobind Features That Are Only Available in linux */
+#define RPC_USE_UNIX_AUTOBIND
+#endif /* __linux__ */
+
+#define RPC_USE_SYSLOG
+
+typedef RPC_ID *RPC_ID_p;
+
+#include "rpc_udp.h"
+#include "rpc_thread.h"
+
+RPC_Result RpcQueueAPIRequestBefore(RpcIdInfo *id,
+ UINT32 size, char **buff);
+RPC_Result RpcQueueAPIRequestAfter(RpcIdInfo *id, RPC_ID client,
+ const char *mesg, UINT32 size,
+ char *args);
+void RpcFreeAPIArgsString(char *args_string);
+UINT16 RpcGetAPIRequest(RpcIdInfo *id, RPC_ID_p client,
+ char **args_string, unsigned int *args_size);
+RPC_Result RpcSetAPIcallReturn(RpcIdInfo *id,
+ const char *mesg, UINT32 size);
+void RpcDiscardAPIcallReturn(RpcIdInfo *id);
+
+RPC_Result RpcDeleteSrvrPid(RpcIdInfo *idinfo, RPC_ID srvr_rpc_id, int wd);
+
+#define StrEqual(a, b) (strcmp((a), (b)) == 0)
+#define MemEqual(a, b, c) (memcmp((a), (b), (c)) == 0)
+
+#define RPC_IS_INVALID_ID(a) ((a) == RPC_NO_ID)
+#define RPC_INVALIDATE_ID(a) ((a) = RPC_NO_ID)
+#define RPC_ID_COPY(a, b) ((a) = (b))
+#define RPC_ID_Equal(a, b) ((a) == (b))
+
+/* inotify Events read Sizes */
+#define EVENT_SIZE ( sizeof(struct inotify_event) ) /* One inotify event size */
+#define BUF_LEN (4 * EVENT_SIZE) /* Read sizes */
+
+#define LESS_THAN <
+
+#define SET_NONBLOCK(fd) { \
+ int flag; \
+ flag = fcntl((fd), F_GETFL, 0); \
+ fcntl((fd), F_SETFL, O_NONBLOCK|flag); \
+ }
+
+#define SET_CLOSE_ON_EXEC(fd) { \
+ int flag; \
+ flag = fcntl((fd), F_GETFD, 0); \
+ fcntl((fd), F_SETFD, FD_CLOEXEC|flag); \
+ }
+
+#if defined(RPC_USE_SYSLOG)
+
+#include <syslog.h>
+
+#define RPC_LOG_CRIT(format, arg...) syslog(LOG_CRIT, format "\n", ##arg)
+#define RPC_LOG_ERR(format, arg...) syslog(LOG_ERR, format "\n", ##arg)
+#define RPC_LOG_STATE(format, arg...) syslog(LOG_INFO, format "\n", ##arg)
+#define RPC_LOG_DEBUG(format, arg...) syslog(LOG_DEBUG, format "\n", ##arg)
+
+#else // defined(RPC_USE_SYSLOG)
+
+#define RPC_LOG_CRIT(format, arg...) fprintf(stderr, "[RPC:CRIT](%d): " format "\n", getpid(), ##arg)
+#define RPC_LOG_ERR(format, arg...) fprintf(stderr, "[RPC:ERR](%d): " format "\n", getpid(), ##arg)
+#define RPC_LOG_STATE(format, arg...) fprintf(stderr, "[RPC:STATE](%d): " format "\n", getpid(), ##arg)
+#define RPC_LOG_DEBUG(format, arg...)
+
+#endif // defined(RPC_USE_SYSLOG)
+
+#include <sys/prctl.h>
+
+#define RPC_LOG_ERR_W_NAME(format, arg...) \
+do { \
+ char name[16]; \
+ prctl(PR_GET_NAME, name); \
+ name[15] = '\0'; \
+ RPC_LOG_ERR("(%s): " format, name, ##arg); \
+} while (0)
+
+#define RPC_LOG_PERROR(format, arg...) RPC_LOG_ERR("[%s:%d] %s : " format, __FILE__, __LINE__, strerror(errno), ##arg);
+
+#include <assert.h>
+#define rpc_assert assert
+
+#define BUG_ASSERT(cond, x) \
+ if (!(cond)) { \
+ rpc_assert("BUG ASSERTION! " #x " @ " __FILE__ ==NULL); \
+ }
+#define CONFIG_ASSERT(s) rpc_assert((s) == NULL)
+
+#define RUNS_IN_CALLERS_THREAD
+#define RUNS_IN_READING_THREAD
+
+#if !defined(RPC_USE_UNIX_AUTOBIND)
+
+#define RPC_SOCKET_NAME "/tmp/RPC/%05d"
+
+static inline void
+rpc_set_socket_name(char *str, RPC_ID id) {
+ sprintf(str, RPC_SOCKET_NAME, id); // NOLINT (readability/nolint)
+}
+
+#endif /* !AUTOBIND */
+
+#endif // OTHERSERVICE_RPCINTERNAL_H_
diff --git a/rpc_library/library/include/rpc_thread.h b/rpc_library/library/include/rpc_thread.h
new file mode 100644
index 00000000..a7e607df
--- /dev/null
+++ b/rpc_library/library/include/rpc_thread.h
@@ -0,0 +1,240 @@
+/*
+ * @copyright Copyright (c) 2016-2019 TOYOTA MOTOR CORPORATION.
+ *
+ * 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 OTHERSERVICE_RPCTHREAD_H_ // NOLINT(build/header_guard)
+#define OTHERSERVICE_RPCTHREAD_H_ // NOLINT(build/header_guard)
+
+#include <pthread.h>
+
+/** @addtogroup RPClib_in
+ * @{
+ */
+
+#define RPC_NO_SOCKET -1
+#define RPC_NO_THREAD 0
+
+#define RPC_MAIN_SUB_COMMAND "%-2d %-16lx"
+#define RPC_MAIN_SUB_COMMAND_SIZE 20
+#define RPC_MAIN_SUB_COMMANDs "%d %lx"
+/** Type of command sent from the main thread to the subthread */
+enum {
+ RPC_COMMAND_ADD_SERVER, /* Addition of RPC_ID */
+ RPC_COMMAND_REMOVE_SERVER, /* Remove RPC_ID */
+ RPC_COMMAND_EXIT, /* Sub-thread termination (when all RPC_ID are exhausted) */
+};
+
+#define APICALL_TIMEOUT_DEFAULT -1
+
+/** Periodic checking timeout (mSec) for detecting deadlocks */
+#define TIMEOUT_FOR_DEADLOCK_CHECK 1000
+
+/** Length of the socket name
+ API request datagram socket = '\0' + "5-digit number associated with RPC_ID"
+ Authentication stream socket = '\0' + "secure_" + "5-digit number associated with RPC_ID" */
+#define SOCK_NAME_LEN (1+5) /* API request datagram socket */
+#define SECURE_SOCK_NAME_LEN (1+12) /* Authentication stream socket */
+
+#define rpc_mutex_lock pthread_mutex_lock
+#define rpc_mutex_unlock pthread_mutex_unlock
+
+/** Upper limit of UID and GID list registration */
+#define CREDENTIAL_LIST_NUM_MAX 32
+
+/** Authentication result to be sent to the client */
+typedef struct {
+ UINT16 certify_res; /**< Client Authentication Result */
+ pid_t srvr_pid; /**< Server PID */
+} RpcCertifyResult;
+
+#define CERTIFY_OK 0
+#define CERTIFY_NG 1
+
+/** Received API call request */
+typedef struct {
+ RPC_ID client; /**< API ID of the requested program */
+ UINT16 api_num; /**< Calling API number */
+ char *args_string; /**< API Call Arguments */
+ UINT32 args_size; /**< Number of bytes in the argument */
+} rpc_apicall_queue;
+
+/** Source Client Socket Name Management Table */
+typedef struct RpcClientSockNameInfoST RpcClientSockNameInfo;
+struct RpcClientSockNameInfoST {
+ char client_sock_name[SOCK_NAME_LEN]; /**< Socket Name List for Source Client */
+ pid_t pid; /**< Source pid */
+ uid_t uid; /**< Source uid */
+ gid_t gid; /**< Source gid */
+ int wd; /**< Non-negative inotify monitored descriptors */
+ RpcClientSockNameInfo *next; /**< Pointer to the next node */
+};
+
+/** Communication server PID management table */
+typedef struct RpcSrvrPidInfoST RpcSrvrPidInfo;
+struct RpcSrvrPidInfoST {
+ RPC_ID srvr_rpc_id; /**< Communication destination server RPC_ID */
+ pid_t srvr_pid; /**< Communication destination server pid */
+ int wd; /**< Non-negative inotify monitored descriptors */
+ RpcSrvrPidInfo *next; /**< Pointer to the next node */
+};
+
+/** Buffer structure for API call acceptance processing.
+ * This function is allocated only when the dispatch function is specified by RPC_start().
+ */
+typedef struct {
+ RPC_dispatch_func_t dispatch_func;/**< Dispatch Functions to APIs (in stub) */
+#define RPC_apicall_dispatch_func(id) \
+ ((id)->apicall ? (id)->apicall->dispatch_func : 0)
+
+ INT32 pipe_sub_main[2];/**< Notification pipe from the subthread to the main thread */
+#define RPC_pipe_sub_main(th) ((th)->srvr_id->apicall->pipe_sub_main)
+
+ UINT16 num_queue;/**< Number of queued API call requests */
+#define RPC_apicall_num_queue(id) \
+ ((id)->apicall ? (id)->apicall->num_queue : 0)
+#define RPC_apicall_num_queue_inc(id) ((id)->apicall->num_queue++)
+#define RPC_apicall_num_queue_dec(id) ((id)->apicall->num_queue--)
+
+ rpc_apicall_queue queue[RPC_MAX_APICALL_QUEUE];/**< Queuing API Call Requests (FIFO) */
+#define RPC_apicall_queue(id, i) ((id)->apicall->queue[(i)])
+#define RPC_apicall_queue_client(id, i) ((id)->apicall->queue[(i)].client)
+#define RPC_apicall_queue_api_num(id, i) ((id)->apicall->queue[(i)].api_num)
+#define RPC_apicall_queue_args(id, i) ((id)->apicall->queue[(i)].args_string)
+#define RPC_apicall_queue_args_size(id, i) ((id)->apicall->queue[(i)].args_size)
+
+ RPC_ID in_process_client;/**< Clients running on ID */
+#define RPC_apicall_in_process_client(id) ((id)->apicall->in_process_client)
+
+ INT32 timeout_sec;/**< API processing timeout */
+#define RPC_apicall_api_timeout_sec(id) ((id)->apicall->timeout_sec)
+
+ INT32 secure_check;/**< Client Authentication Check Enabled/Disabled */
+#define RPC_secure_check(id) ((id)->apicall->secure_check)
+
+ INT32 regist_credential_info;/**< Registration of authentication information */
+#define RPC_regist_credential_info(id) ((id)->apicall->regist_credential_info)
+
+ uid_t *uid_list;/**< List of UIDs that can communicate */
+#define RPC_uid_list(id, i) ((id)->apicall->uid_list[(i)])
+
+ INT32 uid_num;/**< Number of UID list elements that can communicate */
+#define RPC_uid_num(id) ((id)->apicall->uid_num)
+
+ gid_t *gid_list;/**< GID list that can communicate */
+#define RPC_gid_list(id, i) ((id)->apicall->gid_list[(i)])
+
+ INT32 gid_num;/**< Number of GID list elements that can communicate */
+#define RPC_gid_num(id) ((id)->apicall->gid_num)
+
+ RpcClientSockNameInfo *sock_info_head;/**< Leading node of the source client's socket information management table */
+#define RPC_sock_info_head(id) ((id)->apicall->sock_info_head)
+#define RPC_client_sock_name(id) ((id)->apicall->sock_info_head->client_sock_name)
+#define RPC_client_sock_pid(id) ((id)->apicall->sock_info_head->pid)
+#define RPC_client_sock_next_node(id) ((id)->apicall->sock_info_head->next)
+
+ INT32 client_sock_name_num;/**< Number of elements in the source client's socket name list */
+#define RPC_client_sock_name_num(id) ((id)->apicall->client_sock_name_num)
+#define RPC_client_sock_name_num_inc(id) ((id)->apicall->client_sock_name_num++)
+#define RPC_client_sock_name_num_dec(id) ((id)->apicall->client_sock_name_num--)
+} RpcApicallInfo;
+
+struct RpcThreadInfo;
+
+/** Structure that holds information about each RPC_ID */
+typedef struct RpcIdInfo {
+ struct RpcThreadInfo *thread_info;
+
+ RPC_ID port;/**< Port number (=ID) used by the RPC library */
+#define RPC_port(id) ((id)->port)
+#define RPC_my_id(id) RPC_port(id)
+#define rpc_get_port(id) (id)
+
+ INT32 sock;/**< Sockets used by the RPC library */
+#define RPC_my_sock(id) ((id)->sock)
+
+ INT32 secure_sock;/**< Authentication socket used by the RPC library */
+#define RPC_my_secure_sock(id) ((id)->secure_sock)
+
+ int inotify_fd;/**< Server process monitoring inotify */
+#define RPC_clnt_inotify_fd(id) ((id)->inotify_fd)
+
+ INT32 count;/**< Number of clients using the same RPC_ID */
+#define RPC_clnt_count(id) ((id)->count)
+#define RPC_inc_clnt_count(id) ((id)->count++)
+#define RPC_dec_clnt_count(id) ((id)->count--)
+
+ RpcApicallInfo *apicall;/**< Information for API call acceptance processing */
+#define RPC_apicall_info(id) ((id)->apicall)
+
+ RpcSrvrPidInfo *srvr_pid_head;/**< Communication destination server PID management table top node */
+#define RPC_srvr_pid_head(id) ((id)->srvr_pid_head)
+#define RPC_srvr_rpc_id(id) ((id)->srvr_pid_head->srvr_rpc_id)
+#define RPC_srvr_pid(id) ((id)->srvr_pid_head->srvr_pid)
+#define RPC_srvr_pid_next_node(id) ((id)->srvr_pid_head->next)
+
+ UINT32 return_str_len;/**<Number of bytes in the returned string as a result of an API call*/
+ /* Including the terminating '\0' */
+#define RPC_apicall_return_str_len(id) ((id)->return_str_len)
+
+ UINT8 *return_str;/**<String returned as a result of an API call*/
+#define RPC_apicall_return_str(id) ((id)->return_str)
+} RpcIdInfo;
+
+/** Received response packet */
+typedef struct {
+ RPC_ID id;/**< ID of the thread that sent the response */
+ UINT16 type;/**< Response type */
+ UINT32 seq_num;/**< The packet number to which this was sent (the response to this) */
+} RpcResponse;
+
+/** Structure that stores the state of each thread that called the RPC library */
+typedef struct RpcThreadInfo {
+ pthread_mutex_t th_mtx;/**< Mutex for modifying this struct */
+#define RPC_THREAD_MUTEX_LOCK(th) (rpc_mutex_lock(&((th)->th_mtx)))
+#define RPC_THREAD_MUTEX_UNLOCK(th) (rpc_mutex_unlock(&((th)->th_mtx)))
+
+ pthread_t thread;/**< Thread calling the RPC library */
+#define RPC_main_thread(th) ((th)->thread)
+
+ UINT32 sequence_number;/**< Sequence number given to the transmitted packet */
+ /* Send 30 times per second from the beginning of the thread, then wrap around two years.
+ * It is not necessary to wrap around 0 because there is no comparison.
+ */
+ UINT32 magic;/**< Magic number to detect corrupted memories */
+
+ RpcIdInfo *srvr_id;/**< Information by RPC_ID (server) */
+#define RPC_srvr_idinfo(th) ((th)->srvr_id)
+
+ RpcIdInfo *clnt_id;/**< Info by RPC_ID (client) */
+#define RPC_clnt_idinfo(th) ((th)->clnt_id)
+} RpcThreadInfo;
+
+extern pthread_t g_rpc_thread;
+extern UINT32 g_rpc_thread_alive;
+
+#define PIPE_READ 0
+#define PIPE_WRITE 1
+extern int g_rpc_pipe_main_sub[2];
+
+RpcThreadInfo *RpcMyThreadInfo(void);
+RpcThreadInfo *RpcCreateThreadInfo(void);
+int RpcCreateIdInfo(RpcThreadInfo *th, RPC_ID id,
+ RPC_dispatch_func_t dispatch, INT32 secure_check);
+void RpcDestroyIdInfo(RpcThreadInfo *th, RpcIdInfo *idinfo);
+void RpcDestroyThreadInfo(void);
+void RpcUnlinkSocketFiles(void);
+
+/** @} */
+#endif // OTHERSERVICE_RPCTHREAD_H_
diff --git a/rpc_library/library/include/rpc_udp.h b/rpc_library/library/include/rpc_udp.h
new file mode 100644
index 00000000..efd5931e
--- /dev/null
+++ b/rpc_library/library/include/rpc_udp.h
@@ -0,0 +1,162 @@
+/*
+ * @copyright Copyright (c) 2016-2019 TOYOTA MOTOR CORPORATION.
+ *
+ * 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 OTHERSERVICE_RPCUDP_H_ // NOLINT(build/header_guard)
+#define OTHERSERVICE_RPCUDP_H_ // NOLINT(build/header_guard)
+
+/** @addtogroup RPClib_in */
+/** @{ */
+/** Number of bytes of payload that can be stored in a UDP packet */
+#define RPC_UDP_PAYLOAD RPC_MAX_API_ARG_TOTAL_SIZE
+
+/** UDP packet header
+ *
+ * Packet type, source ID, sequence number, packet size, packet position
+ */
+#define RPC_PACKET_HEADER "%-2d %-5x %-8x %-4u %1d "
+/** Number of bytes in the UDP packet header
+ */
+#define RPC_PACKET_HEADER_LEN (2+1 + 5+1 + 8+1 + 4+1 + 1+1)
+
+/** Number of bytes to store in the UDP packet */
+#define RPC_UDP_PACKET_SIZE (RPC_UDP_PAYLOAD + RPC_PACKET_HEADER_LEN)
+
+#define RPC_COMMAND_LEN 3
+
+/** Format string for UDP packet header analysis */
+#define RPC_PACKET_HEADER_scanf "%d %x %x %d"
+
+/** Header (API number) to be added to the API call packet */
+#define RPC_APICALL_FORMAT "%-4d "
+/** Number of bytes in the header of an API call packet */
+#define RPC_APICALL_FORMAT_ARGS_START 5
+
+#define RPC_MAX_RESPONSE_MESSAGE_SIZE 5
+
+#define RPC_SEQ_NUM_START 1
+#define RPC_SEQ_NUM_INVALID 0
+
+/** Internal API call number for checking server existence */
+#define RPC_API_NUM_RPC_ALIVE 0
+
+/** Type of packet that the RPC library sends */
+typedef enum {
+ RPC_PACKET_APICALL = 0,/**< API call request */
+
+ RPC_RESPONSE_APICALL,/**< Responding to API Call Requests */
+#define RPC_RESPONSE_NONE 0x0000
+#define RPC_RESPONSE_API_OK 0x0001
+#define RPC_RESPONSE_API_BUSY 0x0002
+#define RPC_RESPONSE_API_ERR 0x0004
+#define RPC_RESPONSE_API_DEADLOCK 0x0005 /* Server deadlock */
+#define RPC_RESPONSE_API_CERTIFY 0x0006 /* Authentication request */
+
+ RPC_PACKET_APIRETURN,/**< Result of the API call */
+
+ RPC_PACKET_NONE,
+} RPC_packet_type;
+
+/** Packet Location (Multi-Fragment Packet Support) */
+typedef enum {
+ RPC_PACKET_POS_ONEANDONLY = 0,/**< Complete with one packet */
+} rpc_packet_position;
+
+/** Transmitting buffer */
+typedef struct {
+ unsigned int bytes;
+ const void *buf;
+} rpc_send_buf;
+
+/** Valid bytes in the sockaddr_un struct specified for send */
+#define RPC_SOCKET_NAME_LEN 6 /**< Name: 5 characters + first NULL bytes */
+#define RPC_SOCKET_ADDR_LEN (sizeof(short) + RPC_SOCKET_NAME_LEN) // NOLINT (readability/nolint)
+
+enum {
+ RPC_SEND_TO_CLIENT,
+ RPC_SEND_TO_SERVER,
+ RPC_SEND_TO_SERVER_NO_RETRY,
+};
+
+struct RpcIdInfo;
+
+int RpcSendUdp(struct RpcIdInfo *id, RPC_ID receiver, int direction,
+ RPC_packet_type type, const void *mesg, unsigned int bytes);
+int RpcSendUdp2(struct RpcIdInfo *id, RPC_ID receiver, int direction,
+ RPC_packet_type type, unsigned int num, rpc_send_buf *sendbuf);
+RPC_Result RpcSendUdpResponse(struct RpcIdInfo *id, RPC_ID receiver,
+ int direction,
+ RPC_packet_type type,
+ UINT32 seq_num, char *mesg, UINT32 bytes);
+
+int RpcReadUdpPacket(const struct RpcIdInfo *id, UINT8 *buf);
+
+RPC_Result RpcParsePacketHeader(const char *str, RPC_packet_type *command,
+ RPC_ID_p id, UINT32 *seq_num, UINT32 *size);
+
+RPC_Result RpcClientWaitResponse(struct RpcIdInfo *idinfo,
+ UINT32 seq_num,
+ UINT32 timeout_msec, UINT16 *response);
+RPC_Result RpcClientWaitResult(struct RpcIdInfo *idinfo, RPC_ID srvr_id);
+
+#if defined(RPC_USE_UNIX_AUTOBIND)
+/* ===pathname of datagram sockets for API requests=== */
+static inline void
+RpcSetServerName(char *str, RPC_ID id) {
+ *str = '\0';
+ sprintf(str + 1, "S%04x", id); // NOLINT (readability/nolint)
+}
+
+static inline void
+RpcSetClientName(char *str, RPC_ID id) {
+ *str = '\0';
+ sprintf(str + 1, "%05x", id); // NOLINT (readability/nolint)
+}
+
+static inline void
+RpcGetClientName(const char *str, RPC_ID *id) {
+ char buf[6];
+ memcpy(buf, str + 1, 5);
+ buf[5] = '\0';
+ if (buf[1] == 'X') {
+ *id = (RPC_ID)(strtoul(buf + 1, NULL, 16));
+ } else {
+ *id = (RPC_ID)(strtoul(buf, NULL, 16));
+ }
+}
+
+/* ===pathname of stream-socket for authenticating=== */
+static inline void
+RpcSetServerSecureName(char *str, RPC_ID id) {
+ *str = '\0';
+ sprintf(str + 1, "secure_S%04x", id); // NOLINT (readability/nolint)
+}
+
+static inline void
+RpcSetClientSecureName(char *str, RPC_ID id) {
+ *str = '\0';
+ sprintf(str + 1, "secure_%05x", id); // NOLINT (readability/nolint)
+}
+
+static inline void
+RpcGetClientNameFromSock(const char *str, char *client_sock_name) {
+ memcpy(client_sock_name, str + 8, 5);
+ client_sock_name[5] = '\0';
+}
+
+#endif /* !AUTOBIND */
+
+/** @} */
+#endif // OTHERSERVICE_RPCUDP_H_
diff --git a/rpc_library/library/librpc.ver b/rpc_library/library/librpc.ver
new file mode 100644
index 00000000..2cce00e1
--- /dev/null
+++ b/rpc_library/library/librpc.ver
@@ -0,0 +1,29 @@
+/*
+ * @copyright Copyright (c) 2016-2019 TOYOTA MOTOR CORPORATION.
+ *
+ * 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.
+ */
+
+######################
+# rpc version script #
+######################
+{
+ global:
+ ### .text section ###
+ RPC_*;
+ ### .data section ###
+ local:
+ *;
+};
+
+
diff --git a/rpc_library/library/src/rpc_event.c b/rpc_library/library/src/rpc_event.c
new file mode 100644
index 00000000..038900c2
--- /dev/null
+++ b/rpc_library/library/src/rpc_event.c
@@ -0,0 +1,158 @@
+/*
+ * @copyright Copyright (c) 2016-2019 TOYOTA MOTOR CORPORATION.
+ *
+ * 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.
+ */
+
+/**
+ * @file rpc_event.c
+ * @brief RPC Library Internal Implementation--Event Handling
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <native_service/cl_monitor.h>
+
+#include <other_service/rpc.h>
+#include "rpc_internal.h"
+
+/** @ingroup RPClib_in
+ */
+RUNS_IN_READING_THREAD
+RPC_Result
+RpcQueueAPIRequestBefore(RpcIdInfo *id, UINT32 size, char **buff) {
+ RPC_THREAD_MUTEX_LOCK(id->thread_info);
+
+ int n = RPC_apicall_num_queue(id); // LCOV_EXCL_BR_LINE 15: marco defined in rpc_thread.h
+
+ if (n >= RPC_MAX_APICALL_QUEUE) {
+ RPC_THREAD_MUTEX_UNLOCK(id->thread_info);
+ RPC_LOG_STATE("Returned BUSY.");
+ return RPC_ERR_Busy;
+ } else {
+ *buff = rpc_malloc(size);/* malloc */
+ if (*buff == NULL) { // LCOV_EXCL_BR_LINE 5: fail safe for libc function malloc
+ RPC_THREAD_MUTEX_UNLOCK(id->thread_info); // LCOV_EXCL_START 5: fail safe for libc function malloc
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ RPC_LOG_STATE("queue API request: No Memory");
+ return RPC_ERR_Fatal;
+ } // LCOV_EXCL_STOP
+ }
+ return RPC_OK;
+}
+/** @ingroup RPClib_in
+ */
+RUNS_IN_READING_THREAD
+RPC_Result
+RpcQueueAPIRequestAfter(RpcIdInfo *id, RPC_ID client,
+ const char *mesg, UINT32 size, char *args) {
+ int n = RPC_apicall_num_queue(id); // LCOV_EXCL_BR_LINE 15: marco defined in rpc_thread.h
+
+ UINT16 api_num;
+ api_num = (UINT16)strtol(mesg, NULL, 10);
+ memcpy(args, mesg + RPC_APICALL_FORMAT_ARGS_START, size);
+ RPC_ID_COPY(RPC_apicall_queue_client(id, n), client);
+ RPC_apicall_queue_api_num(id, n) = api_num;
+ RPC_apicall_queue_args(id, n) = args;
+ RPC_apicall_queue_args_size(id, n) = size;
+ RPC_apicall_num_queue_inc(id);
+
+ /* set RUN state */
+ CL_MonitorSetEntry(CL_MONITOR_TYPE_RPC,
+ RPC_port(id),
+ CL_MONITOR_STATE_RUN,
+ (uint32_t)(RPC_apicall_api_timeout_sec(id)),
+ api_num);
+
+ RPC_THREAD_MUTEX_UNLOCK(id->thread_info);
+ return RPC_OK;
+}
+
+/** @ingroup RPClib_in
+ */
+RUNS_IN_CALLERS_THREAD
+void
+RpcFreeAPIArgsString(char *args_string) {
+ if (args_string != NULL) { // LCOV_EXCL_BR_LINE 5: free the memory, malloced in RpcQueueAPIRequestBefore(...)
+ rpc_free(args_string);/* free */
+ }
+}
+
+/** @ingroup RPClib_in
+ */
+RUNS_IN_CALLERS_THREAD
+UINT16
+RpcGetAPIRequest(RpcIdInfo *id, RPC_ID_p client,
+ char **args_string, unsigned int *args_size) {
+ UINT16 api_num = 0;
+
+ RPC_THREAD_MUTEX_LOCK(id->thread_info);
+
+ UINT32 n = RPC_apicall_num_queue(id); // LCOV_EXCL_BR_LINE 15: marco defined in rpc_thread.h
+ if (n > 0) {
+ RPC_ID_COPY(*client, RPC_apicall_queue_client(id, 0));
+ api_num = RPC_apicall_queue_api_num(id, 0);
+ *args_string = RPC_apicall_queue_args(id, 0);
+ /* this string must be freed by the caller using discard_APIcall_return()*/
+ *args_size = RPC_apicall_queue_args_size(id, 0);
+
+ if (n > 1) {
+ memmove(&(RPC_apicall_queue(id, 0)), &(RPC_apicall_queue(id, 1)),
+ (n - 1) * sizeof(RPC_apicall_queue(id, 0)));
+ }
+ RPC_apicall_num_queue_dec(id);
+ }
+
+ RPC_THREAD_MUTEX_UNLOCK(id->thread_info);
+ return api_num;
+}
+
+/** @ingroup RPClib_in
+ */
+RUNS_IN_READING_THREAD
+RPC_Result
+RpcSetAPIcallReturn(RpcIdInfo *id, const char *mesg, UINT32 size) {
+ if (RPC_apicall_return_str(id) != NULL) { // LCOV_EXCL_BR_LINE 6: double check
+ RPC_LOG_STATE("previous APIcall return string was not used"); // LCOV_EXCL_START 6: double check
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ RpcDiscardAPIcallReturn(id);
+ } // LCOV_EXCL_STOP
+ RPC_THREAD_MUTEX_LOCK(id->thread_info);
+
+ RPC_apicall_return_str(id) = rpc_malloc(size);/* malloc */
+ if (RPC_apicall_return_str(id) == NULL) { // LCOV_EXCL_BR_LINE 5: fail safe for libc function malloc
+ RPC_THREAD_MUTEX_UNLOCK(id->thread_info); // LCOV_EXCL_START 5: fail safe for libc function malloc
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ RPC_LOG_STATE("set APIcall return: No Memory");
+ return RPC_ERR_Fatal;
+ } // LCOV_EXCL_STOP
+ RPC_apicall_return_str_len(id) = size;
+ memcpy(RPC_apicall_return_str(id), mesg, size);
+ RPC_THREAD_MUTEX_UNLOCK(id->thread_info);
+ return RPC_OK;
+}
+
+/** @ingroup RPClib_in
+ */
+RUNS_IN_CALLERS_THREAD
+void
+RpcDiscardAPIcallReturn(RpcIdInfo *id) {
+ RPC_THREAD_MUTEX_LOCK(id->thread_info);
+ if (RPC_apicall_return_str(id) != NULL) { // LCOV_EXCL_BR_LINE 6: double check
+ rpc_free(RPC_apicall_return_str(id));/* free */
+ RPC_apicall_return_str_len(id) = 0;
+ RPC_apicall_return_str(id) = NULL;
+ }
+ RPC_THREAD_MUTEX_UNLOCK(id->thread_info);
+}
diff --git a/rpc_library/library/src/rpc_lib.c b/rpc_library/library/src/rpc_lib.c
new file mode 100644
index 00000000..b77775fd
--- /dev/null
+++ b/rpc_library/library/src/rpc_lib.c
@@ -0,0 +1,1264 @@
+/*
+ * @copyright Copyright (c) 2016-2019 TOYOTA MOTOR CORPORATION.
+ *
+ * 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.
+ */
+
+/**
+ * @file rpc_lib.c
+ * @brief RPC Library-API Function Implementation
+ *
+ */
+/** @mainpage
+ * This document describes the following API functions, structures,
+ * type declarations, and macros.
+ * - RPC library external specification
+ * - External specifications for RPC tools
+ *
+ * For an overview of other RPC libraries and tools and anomaly processing,
+ * to reference the Word version of the documentation.
+ * (external specifications and programming guides) */
+/** @defgroup RPClib RPC library external specification */
+/** @defgroup RPCtool RPC tool (rpc_apidef) */
+/** @defgroup RPC_ID_assign RPC_ID Assignment */
+/** @defgroup RPClib_in RPC library internal specifications (incomplete) */
+/** @addtogroup RPClib
+ * @{
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/poll.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+#include <sys/inotify.h>
+
+#include <other_service/rpc.h>
+#include "rpc_internal.h"
+
+#include <native_service/cl_process.h> // for CL_INTFY_FILENAME_FORMAT
+#include <native_service/cl_monitor.h>
+
+
+/* Prototype declarations */
+static RPC_Result ProcessAPIcallRequest(RpcIdInfo *idinfo, RPC_ID client,
+ UINT16 api_num, char *args_string,
+ unsigned int args_size);
+static RPC_Result RpcAllDeleteSrvrPid(RpcIdInfo *idinfo);
+static RPC_Result RpcClientWaitCertification(RpcIdInfo *idinfo, pid_t *srvr_pid);
+static RPC_Result RpcRegistSrvrPid(RpcIdInfo *idinfo, RPC_ID srvr_rpc_id, pid_t srvr_pid, int wd);
+
+#define THREAD_INFO_CHECK(th) \
+ if ((th) == NULL) { \
+ RPC_LOG_STATE("No thread info"); \
+ return RPC_ERR_Fatal; \
+ }
+
+#define SUB_THREAD_CHECK() \
+ if (g_rpc_thread_alive == 0) { \
+ RPC_LOG_STATE("No sub thread -- shutdown"); \
+ RpcDestroyThreadInfo(); \
+ return RPC_ERR_Fatal; \
+ }
+
+/**
+ * Waiting for response packet for API call and API result transmission
+ * Timeout time in msec.
+ * If the other program is abnormal (process termination), delay occurs in the meanwhile.
+ * Confirm the operation on the actual machine and set again.
+ */
+#define RESPONSE_WAIT_MSEC_DEFAULT 2000
+static unsigned int Response_wait_msec = RESPONSE_WAIT_MSEC_DEFAULT;
+
+char *RPC_DEBUG = NULL;
+
+#if defined(RPC_USE_UNIX_AUTOBIND)
+
+ static RPC_Result
+CreateClientIdinfo(RpcThreadInfo *th, RPC_ID *pID) {
+ if (RpcCreateIdInfo(th, *pID, NULL, NO_SECURE_CHECK) < 0) {
+ RPC_LOG_ERR("Can't create id_info");
+ return RPC_ERR_Fatal;
+ }
+
+ *pID = RPC_my_id(RPC_clnt_idinfo(th));
+ RPC_LOG_DEBUG("RPC: assigned client ID %d", *pID);
+ if (RPC_DEBUG) { // LCOV_EXCL_BR_LINE 7: debug
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ printf("RPC[%s]: client start finished.\n", RPC_DEBUG); // LCOV_EXCL_LINE 7: debug
+ }
+ return RPC_OK;
+}
+#else /* !AUTOBIND */
+
+#include <sys/file.h>
+
+ static int
+FindUniqClientId(void) {
+#define RPC_ID_FILE_NAME "/tmp/RPC/id"
+#define RPC_MIN_CLIENT_ID 1024
+#define RPC_MAX_CLIENT_ID (1024+32768-1)
+
+ int fd, found;
+ RPC_ID id, next;
+ struct stat statbuf;
+ char fname[32];
+
+ fd = open(RPC_ID_FILE_NAME, O_RDWR|O_CLOEXEC, 0777);
+ if (fd < 0) {
+ id = RPC_MIN_CLIENT_ID;
+ fd = open(RPC_ID_FILE_NAME, O_RDWR|O_CREAT|O_CLOEXEC, 0777);
+ if (fd < 0) {
+ return -1;
+ }
+ flock(fd, LOCK_EX); // Possible sleep here
+ } else {
+ flock(fd, LOCK_EX); // Possible sleep here
+ read(fd, &id, sizeof(id));
+ }
+
+ found = 0;
+ while(found == 0) {
+ rpc_set_socket_name(fname, id);
+ if (stat(fname, &statbuf) < 0) {
+ found = 1;
+ break;
+ }
+ id++;
+ if (id > RPC_MAX_CLIENT_ID) {
+ id = RPC_MIN_CLIENT_ID;
+ }
+ }
+
+ next = id + 1;
+ if (next > RPC_MAX_CLIENT_ID) {
+ next = RPC_MIN_CLIENT_ID;
+ }
+
+ lseek(fd, 0, SEEK_SET);
+ write(fd, &next, sizeof(next));
+ flock(fd, LOCK_UN);
+ close(fd);
+
+ return id;
+}
+
+ static RPC_Result
+CreateClientIdinfo(RpcThreadInfo *th, UINT16 port) {
+ if (RpcCreateIdInfo(th, port, NULL, NO_SECURE_CHECK) < 0) {
+ RPC_LOG_ERR("Can't create id_info");
+ return RPC_ERR_Fatal;
+ }
+ // LCOV_EXCL_BR_START 7: debug
+ if (RPC_DEBUG) {
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ printf("RPC[%s]: client start finished.\n", RPC_DEBUG);
+ }
+ // LCOV_EXCL_BR_STOP
+ return RPC_OK;
+}
+#endif /* AUTOBIND */
+
+/** @fn RPC_START_SERVER(ID)
+ * @brief RPC_start() macro for the server
+ *
+ * Used by RPC-API server programs to activate the RPC library.
+ * ID specifies a symbol of the form XXX_RPC_ID defined in rpc_id.h.
+ * Only one server program per thread is allowed.
+ * When a server program calls an API as a client of another server,
+ * it only needs to call RPC_START_SERVER,
+ * not RPC_START_CLIENT.
+ *
+ * RPC_end() should be called when the RPC library is no longer needed.
+ * @param ID [IN]RPC_ID of the program
+ * @see RPC_start
+ * @see RPC_end
+ */
+/** @fn RPC_START_CLIENT(pID)
+ * @brief RPC_start() macro for clients
+ *
+ * Use only the client functions of the RPC library
+ * (only calling APIs provided by other programs),
+ * This macro is used for the start process.
+ *
+ *
+ * RPC_end() should be called when the RPC library is no longer needed.
+ *
+ * @param pID [OUT]Pointer to the RPC_ID of the program
+ * @see RPC_start
+ * @see RPC_end
+ */
+/** @brief Start processing of the RPC library
+ *
+ * - With an open socket, RPC_ID, and API call dispatching functions
+ * Register in the global variable (managed separately for each thread and RPC_ID)
+ * - Starting use as a server
+ * - func specifies a function pointer (defined in stub) that is not a NULL.
+ * - Specifies a fixed ID defined in rpc_id.h as the ID.
+ * - If the same thread has already started using the server, an error code is returned.
+ * - When the server function is started for the first time in a process,
+ * one subthread is started to process received packets
+ * in the background.
+ * - Starting use as a client
+ * - NULL is specified in the func.
+ * - In principle, an invalid ID value (RPC_NO_PORT) is specified.
+ * This function automatically assigns IDs and returns the assignment result to pID.
+ * - However, if another program has already started using it as a client,
+ * it shares the socket/RPC_ID instead of creating a new socket.
+ * - Exceptionally, it is allowed to specify a fixed ID defined in rpc_id.h as the ID.
+ * This is the only way to use RPC_start() in programs
+ * where it is difficult to always call RPC_end() at the end of use by program structure/design.
+ * - In this case, the pID argument is not referenced.
+ * - The maximum number of threads that use the RPC library in a process is
+ * specified by RPC_MAX_THREADS_IN_PROCESS.
+ *
+ * @param id [IN]RPC_ID of the program (in the case of RPC_NO_PORT, this means automatic assignment)
+ * @param dispatch_func Dispatching functions (defined in stub files for servers,
+ * and NULL specified in programs that do not provide APIs)
+ * @param pID [OUT]RPC_ID of the automatically assigned program
+ *
+ * @retval RPC_OK: normal completion
+ * @retval Otherwise: Abnormal termination (FATAL)
+ *
+ * @note Normally, this function is not called directly, but the following macro is used.
+ * - RPC_START_SERVER(ID)
+ * For programs that provide RPC server functions.
+ * This macro is also used when both server and client functions are used.
+ * - RPC_START_CLIENT(pID)
+ * For programs that use only the RPC client function.
+ */
+ RPC_Result
+RPC_start(RPC_ID id, RPC_dispatch_func_t func, RPC_ID *pID, INT32 secure_check)
+{
+#if defined(RPC_USE_SYSLOG)
+ static int init_syslog = 0;
+
+ if (init_syslog == 0) {
+ openlog("librpc", LOG_PID, LOG_USER);
+ setlogmask(LOG_UPTO(LOG_INFO));
+ /* setlogmask(LOG_MASK(LOG_DEBUG)); */
+ init_syslog = 1;
+ if (func != NULL)
+ RPC_LOG_STATE("RPC_START_SERVER(%#x)\n", id);
+ }
+#endif /* RPC_USE_SYSLOG */
+
+ if (func != NULL && id == RPC_NO_ID) { /* No ID is specified despite as a server */
+ RPC_LOG_ERR("Invalid RPC_start server arg");
+ return RPC_ERR_Fatal;
+ }
+ if (func != NULL && pID != NULL) { /* Requested obtaining pID despite as a server */ // LCOV_EXCL_BR_LINE 200: macro guarantee impossible both not NULL, RPC_START_***
+ RPC_LOG_ERR("Invalid RPC_start server arg"); // LCOV_EXCL_START 200: macro guarantee impossible both not NULL, RPC_START_***
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ return RPC_ERR_Fatal;
+ } // LCOV_EXCL_STOP
+ if (func == NULL && id != RPC_NO_ID) { /* Specified ID despite as a client */
+ RPC_LOG_ERR("Invalid RPC_start server arg");
+ return RPC_ERR_Fatal;
+ }
+#if defined(RPC_USE_UNIX_AUTOBIND)
+ if (func == NULL && pID == NULL) {
+ /* pID is NULL despite as a client (not supported for ID-specified clients) */
+ RPC_LOG_ERR_W_NAME("RPC_Start(ID, NULL, NULL) is no longer supported, ID is auto-assigned");
+ return RPC_ERR_Fatal;
+ }
+#else /* !AUTOBIND */
+ if (func == NULL && id == RPC_NO_ID && pID == NULL) {
+ /* pID is NULL despite as an auto-assigned client */
+ RPC_LOG_ERR("Invalid RPC_start arg");
+ return RPC_ERR_Fatal;
+ }
+#endif /* !AUTOBIND */
+ if ((secure_check != NO_SECURE_CHECK) && (secure_check != NEED_SECURE_CHECK)) { // LCOV_EXCL_BR_LINE 200: macro guarantee only two value, RPC_START_***
+ /* Check Arguments for Client Authentication */
+ RPC_LOG_ERR("Invalid RPC_start arg"); // LCOV_EXCL_START 200: macro guarantee only two value, RPC_START_***
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ return RPC_ERR_Fatal;
+ } // LCOV_EXCL_STOP
+
+ RpcThreadInfo *th = RpcMyThreadInfo();
+ if (th == NULL) {
+ th = RpcCreateThreadInfo();
+ if (th == NULL) { // LCOV_EXCL_BR_LINE 5: fail safe for libc malloc
+ return RPC_ERR_Fatal;
+ }
+ }
+
+ /* RPC_start is already done in the same thread */
+ if (func != NULL) {/* Server start */
+ if (RPC_srvr_idinfo(th) != NULL) {/* Server already started */
+ RPC_LOG_ERR("duplicated RPC_START_SERVER");
+ return RPC_ERR_Fatal;
+ }
+ } else { /* Client start */
+ if (RPC_clnt_idinfo(th) != NULL) {/* Client already started */
+ if (pID != NULL) { // LCOV_EXCL_BR_LINE 6: double check
+ *pID = (RPC_clnt_idinfo(th))->port;
+ RPC_LOG_DEBUG("use existing client ID=%d", *pID);
+ RPC_inc_clnt_count(RPC_clnt_idinfo(th));
+ }
+ /*
+ * When pID == NULL (RPC_ID fixed), there is no guarantee
+ * that RPC_end() will be called as many times as needed, so it does not count up.
+ */
+ return RPC_OK;
+ }
+ }
+
+ if (func == NULL) {/* Client start */
+#if defined(RPC_USE_UNIX_AUTOBIND)
+ /* Automatically assign everything without supporting ID specification */
+ RPC_ID id_local = RPC_NO_ID;
+ RPC_Result ret = CreateClientIdinfo(th, &id_local);
+ if(RPC_OK != ret) return ret;
+
+ if (pID) { // LCOV_EXCL_BR_LINE 6: double check
+ *pID = id_local;
+ }
+ RPC_clnt_inotify_fd(RPC_clnt_idinfo(th)) = inotify_init1(IN_CLOEXEC);
+ return ret;
+#else /* !AUTOBIND */
+ if (id == RPC_NO_ID) {
+ /* No port number specified -> Automatically assign an ID and port number here */
+ /*
+ * FindUniqClientId() returns ID within the range of RPC_MIN_CLIENT_ID(1024) to RPC_MAX_CLIENT_ID(1024+32768-1)
+ */
+ int ret;
+ ret = FindUniqClientId();
+ if (ret < 0) {
+ return RPC_ERR_Fatal;
+ }
+ /* pID != NULL is already checked */
+ *pID = (UINT16)ret;
+ return CreateClientIdinfo(th, *pID);
+ } else {
+ /*
+ * Client start with specified port number
+ * Programs that cannot guarantee an RPC_end() call
+ * at termination specify a fixed RPC_ID from the upper level and use it.
+ * (To avoid memory shortage caused by building up socket-files in /tmp/RPC)
+ */
+ return CreateClientIdinfo(th, id);
+ }
+#endif /* !AUTOBIND */
+ }
+
+ /* Dispatch func specified (servers) -> bind */
+ CL_MonitorInit(CL_MONITOR_INIT_USER); /* Using the API for Error Monitoring */
+
+ if (RpcCreateIdInfo(th, id, func, secure_check) < 0) {
+ RPC_LOG_ERR("Can't create id_info");
+ return RPC_ERR_Fatal;
+ }
+
+ if (RPC_DEBUG) { // LCOV_EXCL_BR_LINE 7: debug
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ printf("RPC[%s]: server thread invoked\n", RPC_DEBUG); // LCOV_EXCL_LINE 7: debug
+ }
+ char *env;
+ if ((env = getenv("RPC_RESPONSE_WAIT")) != NULL) {
+ Response_wait_msec = (unsigned int)strtol(env, NULL, 10);
+ }
+
+ return RPC_OK;
+}
+
+ static void
+RpcEndSub(RpcThreadInfo *th, RpcIdInfo *idinfo) {
+ int sockfd;
+#if !defined(RPC_USE_UNIX_AUTOBIND)
+ char path[120];
+
+ rpc_set_socket_name(path, RPC_my_id(idinfo));
+#endif /* !AUTOBIND */
+ sockfd = idinfo->sock;
+ RpcDestroyIdInfo(th, idinfo);
+ close(sockfd);
+#if !defined(RPC_USE_UNIX_AUTOBIND)
+ unlink(path);
+#endif /* !AUTOBIND */
+}
+
+/** @brief RPC Library End-of-Use Processing
+ *
+ * - Perform termination processing such as closing the opened socket, releasing the memory.
+ * (Server/Client Common)
+ * - If there are no programs in the thread that use RPC_ID,
+ * the subthread started by RPC_start is terminated.
+ * - Each RPC_ID must be called before the program exits.
+ * - RPC_end must be called by the thread that performed the RPC_start.
+ * - Ignored unused or no longer used RPC_ID if specified.
+ *
+ * @param ID [IN]RPC_ID of the program
+ */
+ void
+RPC_end(RPC_ID id) {
+ RpcThreadInfo *th = RpcMyThreadInfo();
+ if (th == NULL) {
+ return;
+ }
+ RpcIdInfo *idinfo;
+ idinfo = RPC_srvr_idinfo(th);
+ if (idinfo != NULL && RPC_my_id(idinfo) == id) {/* srvr */
+ RpcEndSub(th, idinfo);
+ }
+
+ idinfo = RPC_clnt_idinfo(th);
+ if (idinfo != NULL && RPC_my_id(idinfo) == id) {/* client */
+
+ RPC_dec_clnt_count(idinfo);
+ if (RPC_clnt_count(idinfo) == 0) {
+ /* Deleting management table of the communication destination server PID */
+ RpcAllDeleteSrvrPid(idinfo);
+ close(RPC_clnt_inotify_fd(idinfo));
+
+ RpcEndSub(th, idinfo);
+ }
+ }
+ if (RPC_srvr_idinfo(th) == NULL && RPC_clnt_idinfo(th) == NULL) {
+ RPC_LOG_DEBUG("destroy thread info %p", th);
+ RpcDestroyThreadInfo();
+ }
+}
+
+/** @brief RPC library use termination processing (forced cleanup at process termination)
+ *
+ * Deletes the socket file created for RPC communication in the process.
+ * For to release the resources of programs that use the RPC library with RPC_end() in principle,
+ * but this API is an insurance process to eliminate socket file leaks.
+ *
+ * - Since it is assumed that the socket is called immediately before the process terminates,
+ * closing sockets and releasing memory is not performed automatically when the process terminates.
+ * - All RPC processing (both server and client) after this API call cannot be used.
+ * Operation is not guaranteed even if RPC_START is performed again after that.
+ *
+ * No action for versions of the RPC library that use Unix autobind.
+ */
+ void
+RPC_end_all(void) {
+#if !defined(RPC_USE_UNIX_AUTOBIND)
+ RpcUnlinkSocketFiles();
+#endif
+}
+
+/**
+ * @fn RPC_Result RPC_set_API_timeout(RPC_ID id, UINT32 sec)
+ * @brief Setting the timeout period during server API processing
+ *
+ * @param sec [IN] Timeout (sec) Set within the range of 1 to 60 sec.
+ *
+ * @retval RPC_OK: normal completion
+ * @retval RPC_ERR_Configuration: Argument out of range
+ * @retval RPC_ERR_Fatal: Fatal error
+ */
+ RPC_Result
+RPC_set_API_timeout(INT32 sec) {
+ /* param check */
+ if ((sec > 60) || (sec < 1)) {
+ RPC_LOG_ERR( "RPC_set_API_timeout() : Invalid Param." );
+ return RPC_ERR_Configuration;
+ }
+
+ /* thread_info check */
+ RpcThreadInfo *th = RpcMyThreadInfo();
+ THREAD_INFO_CHECK(th);
+
+ /* thread_info->id_info check */
+ if (RPC_srvr_idinfo(th) != NULL ) { // LCOV_EXCL_BR_LINE 200: server start abnormal can't test
+ RpcIdInfo *idinfo = RPC_srvr_idinfo(th);
+
+ /* thread_info->id_info->apicall_info check */
+ if( RPC_apicall_info(idinfo) != NULL ) { // LCOV_EXCL_BR_LINE 200: server start abnormal can't test
+ RPC_apicall_api_timeout_sec(idinfo) = sec;
+ } else { // LCOV_EXCL_START 200: server start abnormal can't test
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ RPC_LOG_ERR( "No apicall_info" );
+ return RPC_ERR_Fatal;
+ }
+
+ } else {
+ RPC_LOG_STATE("No srvr_id info");
+ return RPC_ERR_Fatal;
+ } // LCOV_EXCL_STOP
+ return RPC_OK;
+}
+
+
+/** @brief API call execution function (client side)
+ *
+ * (These functions are called from within a client-facing STUB. Users never use these directly.)
+ */
+ RPC_Result
+RPC_API_call(RPC_ID server, UINT16 api_num,
+ const char *args_string, unsigned int args_size,
+ char **ret_string, unsigned int *ret_size) {
+ *ret_string = NULL;
+
+ RpcThreadInfo *th = RpcMyThreadInfo();
+
+ THREAD_INFO_CHECK(th);
+
+ RpcIdInfo *idinfo;
+ idinfo = RPC_clnt_idinfo(th);
+
+ pid_t srvr_pid;
+
+ if (idinfo == NULL) { // LCOV_EXCL_BR_LINE 8: dead code, idinfo always isn't NULL
+ /*
+ * In the past, the remedy of uninitialized clients has been done here.
+ * However, because it becomes to accumulate garbage in the /tmp/RPC by changing UNIX sockets,
+ * as an error without remedies.
+ */
+ // LCOV_EXCL_START 8: dead code, idinfo always isn't NULL
+ RPC_LOG_ERR_W_NAME("warning!!! RPC call without RPC_start(): server=%d, api_num=%d", server, api_num);
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+#if defined(RPC_USE_UNIX_AUTOBIND)
+ RPC_ID id = RPC_NO_ID;
+ RPC_Result ret = CreateClientIdinfo(th, &id);
+#else /* !AUTOBIND */
+ int id;
+ id = FindUniqClientId();
+ if (id < 0) {
+ return RPC_ERR_Fatal;
+ }
+ RPC_Result ret = CreateClientIdinfo(th, (UINT16)id);
+#endif /* !AUTOBIND */
+ if (ret != RPC_OK) {
+ return ret;
+ }
+ idinfo = RPC_clnt_idinfo(th);
+ if (idinfo == NULL) {
+ return RPC_ERR_Fatal;
+ }
+ } // LCOV_EXCL_STOP
+
+ char api_head[RPC_APICALL_FORMAT_ARGS_START + 1];
+ sprintf(api_head, RPC_APICALL_FORMAT, api_num);
+
+ rpc_send_buf sendbuf[2];
+ sendbuf[0].buf = api_head;
+ sendbuf[0].bytes = RPC_APICALL_FORMAT_ARGS_START;
+ if (args_size > 0) {
+ sendbuf[1].buf = args_string;
+ sendbuf[1].bytes = args_size;
+ }
+
+ int seq_num;
+
+send_api_call:
+ seq_num = RpcSendUdp2(idinfo, server,
+ (api_num == RPC_API_NUM_RPC_ALIVE
+ ? RPC_SEND_TO_SERVER_NO_RETRY
+ : RPC_SEND_TO_SERVER),
+ RPC_PACKET_APICALL,
+ (args_size > 0) ? 2 : 1, sendbuf);
+ if (seq_num < 0) {
+ return RPC_ERR_No_Response;
+ }
+
+ // wait for response
+ UINT16 response;
+ RPC_Result result = RpcClientWaitResponse(idinfo, (UINT32)seq_num, Response_wait_msec,
+ &response);
+ if (result != RPC_OK) {
+ return result;
+ }
+
+ if (response == RPC_RESPONSE_API_BUSY) { /* Server is busy */
+ return RPC_ERR_Busy;
+ } else if (response == RPC_RESPONSE_API_ERR) { /* API call error */
+ RPC_LOG_STATE("APIcall error (can't queue)");
+ return RPC_ERR_Fatal;
+ } else if (response == RPC_RESPONSE_API_DEADLOCK) { /* Server is in deadlock */
+ RPC_LOG_STATE("server DeadLock.");
+ return RPC_ERR_Server_DeadLock;
+ } else if (response == RPC_RESPONSE_API_CERTIFY) { /* Authentication request */
+ struct sockaddr_un srvr_sa_un, secure_sa_un;
+ socklen_t srvr_sa_len, secure_sa_len;
+ int secure_sock_un;
+
+ /* Create client socket for authentication */
+ memset(&secure_sa_un, 0, sizeof(secure_sa_un));
+ secure_sa_un.sun_family = AF_UNIX;
+ secure_sock_un = socket(PF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
+ RpcSetClientSecureName(secure_sa_un.sun_path, RPC_port(idinfo));
+ secure_sa_len = (socklen_t)(sizeof(secure_sa_un.sun_family) + SECURE_SOCK_NAME_LEN);
+ if (bind(secure_sock_un, (struct sockaddr *)&secure_sa_un, secure_sa_len) < 0) {
+ RPC_LOG_PERROR("STREAM : bind(unix), ID:%#x", RPC_port(idinfo));
+ }
+ idinfo->secure_sock = secure_sock_un;
+
+ /* Destination Server Socket Setting */
+ memset(&srvr_sa_un, 0, sizeof(srvr_sa_un));
+ srvr_sa_un.sun_family = AF_UNIX;
+ RpcSetServerSecureName(srvr_sa_un.sun_path, server);
+ srvr_sa_len = (socklen_t)(sizeof(srvr_sa_un.sun_family) + SECURE_SOCK_NAME_LEN);
+
+ /* Connection */
+ int cr = connect(RPC_my_secure_sock(idinfo), (struct sockaddr *)&srvr_sa_un, srvr_sa_len);
+ if (0 > cr) {
+ RPC_LOG_STATE("client connect() is failed.");
+ return RPC_ERR_Fatal;
+ }
+
+ /* Waiting for server authentication */
+ RPC_Result ret_certify = RpcClientWaitCertification(idinfo, &srvr_pid);
+ close(RPC_my_secure_sock(idinfo));
+ if (RPC_OK != ret_certify) {/* Authentication NG */
+ RPC_LOG_STATE("denied the connection.");
+ return ret_certify;
+ }
+
+ /* inotify monitoring of server processes */
+ char intfy_fname[32];
+ snprintf(intfy_fname, sizeof(intfy_fname), CL_INTFY_FILENAME_FORMAT, srvr_pid);
+ int wd = inotify_add_watch(RPC_clnt_inotify_fd(idinfo), intfy_fname, IN_DELETE_SELF);
+ if (0 > wd) {
+ RPC_LOG_STATE("intfy_fname is Not Found [%s].", intfy_fname);
+ }
+
+ /* Register the communication destination server PID in the management table. */
+ if (RPC_OK != RpcRegistSrvrPid(idinfo, server, srvr_pid, wd)) {
+ return RPC_ERR_Fatal;
+ }
+ goto send_api_call; /* Sending the API request again */
+
+ } else if (response == RPC_RESPONSE_NONE) { // LCOV_EXCL_BR_LINE 8: dead code, not implement
+ // Not implemented to cancel processing
+ // LCOV_EXCL_START 8: dead code, not implement
+ RPC_LOG_STATE("No response for API call");
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ return RPC_ERR_No_Response;
+ } // LCOV_EXCL_STOP
+
+ // When the server ALIVE is queried, no result is returned, so return here
+ if (api_num == RPC_API_NUM_RPC_ALIVE) {
+ return RPC_OK;
+ }
+
+ // API call is accepted at server
+ // now wait for the return packet
+ result = RpcClientWaitResult(idinfo, server);
+ if (result != RPC_OK) {
+ RpcDiscardAPIcallReturn(idinfo);
+ return result;
+ }
+
+ /****** Function error and return value must be handled separately *******/
+ UINT8 *return_str = RPC_apicall_return_str(idinfo); /* pgr0689 */
+#ifdef APICALL_RETURN_TIMEOUT
+ if (return_str == NULL) {
+ RPC_LOG_STATE("APIcall return timeout");
+ return RPC_ERR_No_Response;
+ }
+#else
+ rpc_assert(return_str != NULL); // LCOV_EXCL_BR_LINE 6: double check
+#endif
+
+ RPC_THREAD_MUTEX_LOCK(idinfo->thread_info);
+
+ *ret_string = rpc_malloc(RPC_apicall_return_str_len(idinfo));
+ if (*ret_string != NULL) { // LCOV_EXCL_BR_LINE 5: fail safe for libc malloc
+ if (ret_size) {
+ *ret_size = RPC_apicall_return_str_len(idinfo);
+ }
+ memcpy(*ret_string, RPC_apicall_return_str(idinfo),
+ RPC_apicall_return_str_len(idinfo));
+ } else {
+ RPC_LOG_STATE("APIcall: No Memory"); // LCOV_EXCL_START 5: fail safe for libc malloc
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ result = RPC_ERR_Fatal;
+ } // LCOV_EXCL_STOP
+ RPC_THREAD_MUTEX_UNLOCK(idinfo->thread_info);
+ RpcDiscardAPIcallReturn(idinfo);
+
+ return result;
+}
+
+/** @brief Releasing allocated memory while API call is processing
+ *
+ * (These functions are called from within a client-facing STUB. Users never use it directly.)
+ */
+ void
+RPC_free_return_string(void *ptr) {
+ if (ptr != NULL) {
+ rpc_free(ptr);
+ }
+}
+
+/** @brief Retrieving file descriptors for determining whether RPC-API calls are requested
+ *
+ * - This function returns a file descriptor used to determine whether or not there is a request to the server.
+ * - For the FD returned by this function, Don't use the other way than the FD specified
+ * in the poll or select parameter.
+ * - Intended use
+ * - Obtain FD using this function.
+ * - Wait for data to arrive by poll or select.
+ * - Call RPC_process_API_request() when data arrived.
+ * - This procedure performs handling request of the API call from the client.
+ * (Server-side API function is executed.)
+ *
+ * @param id [IN]RPC_ID of the server program.
+ * @param fd [OUT]Storage of file descriptor
+ *
+ * @retval RPC_OK: normal completion
+ * @retval Otherwise: Abnormal termination (FATAL)
+ * @see RPC_process_API_request
+ */
+ RPC_Result
+RPC_get_fd(RPC_ID id, int *fd) {
+ if ((id == RPC_NO_ID) || (fd == NULL)) {
+ return RPC_ERR_Fatal;
+ }
+ rpc_assert(fd != NULL); // LCOV_EXCL_BR_LINE 6: double check
+
+ RpcThreadInfo *th = RpcMyThreadInfo();
+
+ THREAD_INFO_CHECK(th);
+
+ SUB_THREAD_CHECK(); // LCOV_EXCL_BR_LINE 15: macro define in rpc_lib.c
+
+ RpcIdInfo *idinfo = RPC_srvr_idinfo(th);
+
+ rpc_assert(idinfo != NULL && RPC_my_id(idinfo) == id); // LCOV_EXCL_BR_LINE 6: double check
+
+ *fd = RPC_pipe_sub_main(th)[PIPE_READ];
+
+ return RPC_OK;
+}
+
+/** API Call Request Handling
+*/
+ static RPC_Result
+ProcessAPIcallRequest(RpcIdInfo *idinfo, RPC_ID client, UINT16 api_num,
+ char *args_string, unsigned int args_size) {
+ /* ----------------------------
+ * call API dispatch function
+ * ----------------------------
+ */
+
+ /* API Running Client RPC_ID Setting */
+ RPC_apicall_in_process_client(idinfo) = client;
+
+ char *ret_string = NULL;
+ unsigned int ret_size = 0;
+ RPC_dispatch_func_t dispatch = RPC_apicall_dispatch_func(idinfo);
+ rpc_assert(dispatch != NULL); // LCOV_EXCL_BR_LINE 6: double check
+ RPC_Result api_ret;
+ api_ret = dispatch(api_num, args_string, args_size, &ret_string, &ret_size); /* pgr0060 */
+
+ unsigned char retcode[RPC_RETCODE_LEN+1];
+ sprintf((char *)retcode, "%08x ", api_ret);
+
+ rpc_send_buf sendbuf[2];
+ sendbuf[0].buf = retcode;
+ sendbuf[0].bytes = sizeof(retcode) - 1;
+
+ int seq_num;
+
+ if (ret_string != NULL) {
+ sendbuf[1].buf = ret_string;
+ sendbuf[1].bytes = ret_size;
+ seq_num = RpcSendUdp2(idinfo, client, RPC_SEND_TO_CLIENT,
+ RPC_PACKET_APIRETURN, 2, sendbuf);
+ } else {
+ seq_num = RpcSendUdp2(idinfo, client, RPC_SEND_TO_CLIENT,
+ RPC_PACKET_APIRETURN, 1, sendbuf);
+ }
+ RPC_marshall_free(1, ret_string);
+
+ if (seq_num < 0) {
+ RPC_LOG_ERR("send result failed!");
+ return RPC_ERR_Fatal;
+ }
+
+ /* Set API Running Client RPC_ID to None */
+ RPC_apicall_in_process_client(idinfo) = RPC_NO_PORT;
+
+ /* Sleep API-processing entries */
+ RPC_THREAD_MUTEX_LOCK(idinfo->thread_info);
+ CL_MonitorSetEntry(CL_MONITOR_TYPE_RPC, RPC_port(idinfo),
+ CL_MONITOR_STATE_SLEEP, 0, 0);
+ RPC_THREAD_MUTEX_UNLOCK(idinfo->thread_info);
+
+ return api_ret;
+}
+
+/** @brief Executing RPC-API calls
+ *
+ * Process all queued API execution requests from clients.
+ * The API function of the server program is called from here.
+ * If there is no API execution request, the system returns normally immediately without waiting.
+ *
+ * @param id [IN]RPC_ID of the server program
+ * @retval RPC_OK: normal completion
+ * @retval Otherwise: Fatal errors
+ */
+ RPC_Result
+RPC_process_API_request(RPC_ID id) {
+ if (id == RPC_NO_ID) {
+ return RPC_ERR_Fatal;
+ }
+ RpcThreadInfo *th = RpcMyThreadInfo();
+
+ THREAD_INFO_CHECK(th);
+
+ SUB_THREAD_CHECK();
+
+ RpcIdInfo *idinfo = RPC_srvr_idinfo(th);
+
+ rpc_assert(idinfo != NULL && id == RPC_my_id(idinfo)); // LCOV_EXCL_BR_LINE 6: double check
+
+ rpc_assert(RPC_apicall_info(idinfo) != NULL /* pgr0689 */ // LCOV_EXCL_BR_LINE 6: double check
+ && RPC_apicall_dispatch_func(idinfo) != NULL); // LCOV_EXCL_BR_LINE 6: double check
+
+ char c;
+ read(RPC_pipe_sub_main(th)[PIPE_READ], &c, sizeof(c));
+
+ /* Process all API calls here */
+ UINT16 api_num;
+ RPC_ID client = RPC_NO_PORT;
+ RPC_Result result = RPC_OK;
+ char *args_string;
+ unsigned int args_size;
+ do {
+ api_num = RpcGetAPIRequest(idinfo, &client,
+ &args_string, &args_size);
+
+ if (api_num > 0) {/* API calls were queued */
+ result = ProcessAPIcallRequest(idinfo, client, api_num,
+ args_string, args_size);
+
+ RpcFreeAPIArgsString(args_string);
+
+ if (result == RPC_ERR_API_Fatal || result == RPC_ERR_Fatal) {
+ break;
+ } else {
+ result = RPC_OK;
+ }
+ }
+ } while(api_num > 0);
+
+ return result;
+}
+
+/** @brief Returns the operational state of the RPC server
+ *
+ * Returns whether or not the server with the specified RPC_ID is running.
+ *
+ * @param id [IN]RPC_ID of the server program
+ * @retval RPC_OK: Running
+ * @retval RPC_ERR_No_Response: Server is not running
+ */
+ RPC_Result
+RPC_is_server_ready(RPC_ID id) {
+#if defined(RPC_USE_UNIX_AUTOBIND)
+ char *ret_string = NULL;
+ unsigned int ret_size;
+ RPC_Result ret;
+
+ // Invoke Internal-API Calls for Server ALIVE Queries
+ ret = RPC_API_call(id, RPC_API_NUM_RPC_ALIVE, NULL, 0,
+ &ret_string, &ret_size);
+ RPC_free_return_string(ret_string);
+
+ return ret;
+#else /* !AUTOBIND */
+ struct stat statbuf;
+ int err;
+ char sockname[128];
+
+ /* Check if server socket is created */
+ rpc_set_socket_name(sockname, id);
+ err = stat(sockname, &statbuf);
+ if (err == 0) {
+ return RPC_OK;
+ } else {
+ return RPC_ERR_No_Response;
+ }
+#endif /* !AUTOBIND */
+}
+
+/** @brief Registering UIDs and GID Lists
+ *
+ * Register a list of UIDs and GIDs that can be accepted by the RPC server.
+ * A function used by the RPC server after RPC_START_SECURE_SERVER().
+ * Return error if called from an RPC client or an RPC server that has not called RPC_START_SECURE_SERVER().
+ *
+ * @param uid_num [IN] Number of registered UIDs (number of elements in UID list array)
+ * @param *uid_list [IN] Start pointer of registered UID list
+ * @param gid_num [IN] Number of registered GIDs (number of elements in the array of GID lists)
+ * @param *gid_list [IN] Start pointer of registered GID list
+ * @retval RPC_OK: List registration completed
+ * @retval RPC_ERR_Fatal: Failed to save to list
+ */
+RPC_Result
+RPC_regist_credential(int uid_num, uid_t *uid_list, int gid_num, gid_t *gid_list) {
+ RpcThreadInfo *th = RpcMyThreadInfo();
+ THREAD_INFO_CHECK(th);
+
+ if (NULL == RPC_srvr_idinfo(th)) {
+ RPC_LOG_ERR("No server thread info");
+ return RPC_ERR_Fatal;
+ }
+
+ RpcIdInfo *idinfo = RPC_srvr_idinfo(th);
+ if ((NULL == idinfo) || (NULL == RPC_apicall_info(idinfo))) { // LCOV_EXCL_BR_LINE 8: dead code, idinfo always isn't NULL
+ // LCOV_EXCL_START 8: dead code, idinfo always isn't NULL
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ RPC_LOG_ERR("No RPC_ID info");
+ return RPC_ERR_Fatal;
+ } // LCOV_EXCL_STOP
+
+ /* Neither UID nor GID list is specified. */
+ if ((NULL == uid_list) && (NULL == gid_list)) {
+ RPC_LOG_ERR("RPC_regist_credential() : UID and GID list is NULL.");
+ return RPC_ERR_Fatal;
+ }
+
+ /* UID list argument check */
+ if ((NULL == uid_list) && ((0 < uid_num ) && (uid_num <= CREDENTIAL_LIST_NUM_MAX))) {/* UID list is invalid */
+ RPC_LOG_ERR("RPC_regist_credential() : UID list is illegal.");
+ return RPC_ERR_Fatal;
+ } else if ((NULL != uid_list) && ((1 > uid_num) || (uid_num > CREDENTIAL_LIST_NUM_MAX))) {/* Number of UID list elements is invalid */
+ RPC_LOG_ERR("RPC_regist_credential() : UID list num is illegal.");
+ return RPC_ERR_Configuration;
+ }
+
+ /* GID list argument check */
+ if ((NULL == gid_list) && ((0 < gid_num ) && (gid_num <= CREDENTIAL_LIST_NUM_MAX))) {/* GID list is invalid */
+ RPC_LOG_ERR("RPC_regist_credential() : GID list is illegal.");
+ return RPC_ERR_Fatal;
+ } else if ((NULL != gid_list) && ((1 > gid_num) || (gid_num > CREDENTIAL_LIST_NUM_MAX))) {/* Number of GID list elements is invalid */
+ RPC_LOG_ERR("RPC_regist_credential() : GID list num is illegal.");
+ return RPC_ERR_Configuration;
+ }
+
+ if (NO_SECURE_CHECK == RPC_secure_check(idinfo)) {/* Return error if registration is not necessary */
+ RPC_LOG_ERR("Needless secure check.");
+ return RPC_ERR_Fatal;
+ }
+
+ if (REGISTERED == RPC_regist_credential_info(idinfo)) {/* Return error if a list has already been registered */
+ RPC_LOG_ERR("credential info has been registered already.");
+ return RPC_ERR_Fatal;
+ }
+
+ /* Allocate as many memory areas as there are UID and GID lists */
+ RPC_apicall_info(idinfo)->uid_list = rpc_malloc(sizeof(uid_t) * (unsigned int)uid_num);
+ if (NULL == RPC_apicall_info(idinfo)->uid_list) { // LCOV_EXCL_BR_LINE 5: fail safe for libc malloc
+ RPC_LOG_ERR("Can't malloc uid_list."); // LCOV_EXCL_START 5: fail safe for libc malloc
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ return RPC_ERR_Fatal;
+ } // LCOV_EXCL_STOP
+ RPC_apicall_info(idinfo)->gid_list = rpc_malloc(sizeof(gid_t) * (unsigned int)gid_num);
+ if (NULL == RPC_apicall_info(idinfo)->gid_list) { // LCOV_EXCL_BR_LINE 5: fail safe for libc malloc
+ RPC_LOG_ERR("Can't malloc gid_list."); // LCOV_EXCL_START 5: fail safe for libc malloc
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ return RPC_ERR_Fatal;
+ } // LCOV_EXCL_STOP
+
+ /* Copy UID and GID registration list and number of elements */
+ memcpy(RPC_apicall_info(idinfo)->uid_list, uid_list, sizeof(uid_t) * (unsigned int)uid_num); /* UID list */
+ memcpy(RPC_apicall_info(idinfo)->gid_list, gid_list, sizeof(gid_t) * (unsigned int)gid_num); /* GID list */
+ RPC_uid_num(idinfo) = uid_num; /* Number of elements in the UID list */
+ RPC_gid_num(idinfo) = gid_num; /* Number of elements in the GID list */
+
+ /* Set whether to register authentication information to Yes/No */
+ RPC_regist_credential_info(idinfo) = REGISTERED;
+
+ return RPC_OK;
+}
+
+/** @brief Obtain authentication info (UID, GID) of API requesting client
+ *
+ * Obtain the UID and GID of the client that requested the API processing being executed.
+ * Return error if called from an RPC client or to an RPC server that has not called RPC_START_SECURE_SERVER().
+ * This function should be called within an API function (in other words, API is being executed) provided to the client.
+ * if called the other function, error is returned because there is no API being executed.
+ *
+ * @param *client_uid [OUT] Requesting client UID of running API
+ * @param *client_gid [OUT] Requesting client GID of running API
+ * @retval RPC_OK: Succeeded to obtain of authentication info
+ * @retval RPC_ERR_Fatal: Failed to obtain of authentication Info
+ */
+RPC_Result
+RPC_get_client_credential(uid_t *client_uid, gid_t *client_gid) {
+ RpcThreadInfo *th = RpcMyThreadInfo();
+ THREAD_INFO_CHECK(th);
+
+ if (NULL == RPC_srvr_idinfo(th)) {
+ RPC_LOG_ERR("No server thread info");
+ return RPC_ERR_Fatal;
+ }
+
+ RpcIdInfo *idinfo = RPC_srvr_idinfo(th);
+ if ((NULL == idinfo) || (NULL == RPC_apicall_info(idinfo))) { // LCOV_EXCL_BR_LINE 8: dead code, idinfo always isn't NULL
+ // LCOV_EXCL_START 8: dead code, idinfo always isn't NULL
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ RPC_LOG_ERR("No RPC_ID info");
+ return RPC_ERR_Fatal;
+ } // LCOV_EXCL_STOP
+
+ if ((NULL == client_uid) || (NULL == client_gid)) {/* Argument check */
+ RPC_LOG_ERR("RPC_regist_credential() : Invalid Param.");
+ return RPC_ERR_Fatal;
+ }
+
+ if (NO_SECURE_CHECK == RPC_secure_check(idinfo)) {/* Return error if no security */
+ RPC_LOG_ERR("Needless secure check.");
+ return RPC_ERR_Fatal;
+ }
+
+ if (RPC_NO_PORT == RPC_apicall_in_process_client(idinfo)) {/* Return error if the API is not being executed */
+ RPC_LOG_ERR("NOT in process APIcall.");
+ return RPC_ERR_Fatal;
+ }
+
+ char buf[7], client_path_name[SOCK_NAME_LEN]; /* Client socket name */
+
+ /* Converting client_id to the socket name associated with RPC_ID */
+ RpcSetClientName(buf, RPC_apicall_in_process_client(idinfo));
+ memcpy(client_path_name, buf + 1, 5);
+ client_path_name[5] = '\0';
+ RpcClientSockNameInfo *current = RPC_sock_info_head(idinfo);
+
+ /* Search info of running client from the management table */
+ while (NULL != current) {
+ if (0 == strcmp(current->client_sock_name, client_path_name)) {/* Match Running Client Info */
+ *client_uid = current->uid;
+ *client_gid = current->gid;
+ return RPC_OK;
+ }
+ current = current->next;
+ }
+ RPC_LOG_ERR("Nothing client credential info.");
+ return RPC_ERR_Fatal; /* Not found Client info */
+}
+
+/** @brief Waiting for server authentication
+ *
+ * When a client requests an API to the server,
+ * wait for the server to check whether it is allowed to communicate.
+ *
+ * @param *idinfo [IN] Information associated with the client's RPC_ID
+ *
+ * @retval RPC_OK: Authentication OK (communication with the server is permitted)
+ * @retval RPC_ERR_Reject_connect: Authentication NG (Communication denied)
+ */
+static RPC_Result
+RpcClientWaitCertification(RpcIdInfo *idinfo, pid_t *srvr_pid) {
+ fd_set fds;
+ RpcCertifyResult recv_ret; /* Authentication result from the server */
+ RPC_Result ret = RPC_ERR_Fatal;
+
+ for(;;) {
+ FD_ZERO(&fds);
+ FD_SET(RPC_my_secure_sock(idinfo), &fds);
+
+ int sret = select(RPC_my_secure_sock(idinfo) + 1, &fds, NULL, NULL, NULL);
+ if (sret < 0 && errno == EINTR) {/* signal interrupt */ // LCOV_EXCL_BR_LINE 5: fail safe for libc select
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ continue; // LCOV_EXCL_LINE 5: fail safe for libc select
+ } else if (sret > 0 && FD_ISSET(RPC_my_secure_sock(idinfo), &fds)) {
+ /* Check the response from the server */
+ ssize_t rret = recv(RPC_my_secure_sock(idinfo), (char*)&recv_ret, sizeof(RpcCertifyResult), 0);
+ if (0 < rret) { // LCOV_EXCL_BR_LINE 5: fail safe for libc recv
+ switch(recv_ret.certify_res) {
+ case CERTIFY_OK: /* OK */
+ ret = RPC_OK;
+ *srvr_pid = recv_ret.srvr_pid;
+ break;
+
+ case CERTIFY_NG: /* NG */
+ ret = RPC_ERR_Reject_connect;
+ break;
+
+ default:
+ ret = RPC_ERR_Fatal;
+ break;
+ }
+ goto exit_loop_ok;
+ } else if(0 == rret) { // LCOV_EXCL_START 5: fail safe for libc recv
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ RPC_LOG_ERR("server process terminate.");
+ return RPC_ERR_Fatal;
+ } else {
+ RPC_LOG_PERROR("certification_wait recv()");
+ return RPC_ERR_Fatal;
+ } // LCOV_EXCL_STOP
+ }
+ }
+exit_loop_ok:
+ return ret;
+}
+
+/** @brief Register the PID of the communication destination server in the management table.
+ *
+ * Register a pair of the PID and ID of the server in the management table.
+ *
+ * @param *idinfo [IN] Information associated with the client's RPC_ID
+ * @param srvr_rpc_id [IN] RPC_ID of the communication destination server
+ * @param srvr_pid [IN] PID of the communication destination server
+ *
+ * @retval RPC_OK : Registration completed
+ * @retval RPC_ERR_Fatal : Registration failed
+ */
+static RPC_Result
+RpcRegistSrvrPid(RpcIdInfo *idinfo, RPC_ID srvr_rpc_id, pid_t srvr_pid, int wd) {
+ if ((NULL == idinfo) || (srvr_rpc_id == RPC_NO_ID) || (0 > srvr_pid)) { // LCOV_EXCL_START 8: dead code, idinfo always isn't NULL
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ RPC_LOG_ERR("RpcRegistSrvrPid() : Invalid Param.");
+ return RPC_ERR_Fatal;
+ } // LCOV_EXCL_STOP
+
+ RpcSrvrPidInfo *srvr_pid_buf, *current;
+
+ srvr_pid_buf = rpc_malloc(sizeof(RpcSrvrPidInfo));
+ if( srvr_pid_buf == NULL ){ // LCOV_EXCL_START 5: fail safe for libc malloc
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ return RPC_ERR_Fatal;
+ } // LCOV_EXCL_STOP
+
+ srvr_pid_buf->srvr_rpc_id = srvr_rpc_id; /* Server RPC_ID */
+ srvr_pid_buf->srvr_pid = srvr_pid; /* Server PID */
+ srvr_pid_buf->wd = wd; /* wd */
+ srvr_pid_buf->next = NULL; /* Next node in the communication destination server PID management table */
+
+ if (0 == RPC_srvr_pid_head(idinfo)) {
+ RPC_srvr_pid_head(idinfo) = srvr_pid_buf;
+ } else {
+ for (current = RPC_srvr_pid_head(idinfo); current->next != NULL; current = current->next)
+ ;
+ current->next = srvr_pid_buf;
+ }
+ return RPC_OK;
+}
+
+/** @brief Delete Termination Process PID from Management Table
+ *
+ * Check whether the terminated process matches the communicating server process, and delete it from the management table.
+ *
+ * @param *idinfo [IN] Information associated with the client's RPC_ID
+ * @param srvr_rpc_id [IN] Currently communicating server RPC_ID
+ * @param wd [IN] Wd of the termination process
+ *
+ * @retval RPC_OK : Deletion completed
+ * @retval RPC_ERR_Server_Finish: Deletion completed (server process in communication terminated)
+ * @retval RPC_ERR_Fatal : Argument error
+ */
+ RPC_Result
+RpcDeleteSrvrPid(RpcIdInfo *idinfo, RPC_ID srvr_rpc_id, int wd) {
+ if ((NULL == idinfo) || (RPC_NO_ID == srvr_rpc_id)) { // LCOV_EXCL_START 8: dead code, idinfo always isn't NULL
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ RPC_LOG_ERR("rpc_check_srvr_pid() : Invalid Param.");
+ return RPC_ERR_Fatal;
+ } // LCOV_EXCL_STOP
+
+ RPC_Result ret = RPC_OK;
+ int cnt = 0;
+ RpcSrvrPidInfo *current, *previous;
+ current = RPC_srvr_pid_head(idinfo);
+
+ while (NULL != current) {
+ if (wd == current->wd) {
+
+ /* Check whether the termination process matches the communicating server process */
+ if (srvr_rpc_id == current->srvr_rpc_id) {
+ ret = RPC_ERR_Server_Finish;
+ }
+
+ /* Delete info from the Server info table */
+ if (0 == cnt) {/* Delete the start of the management table */
+ RPC_srvr_pid_head(idinfo) = RPC_srvr_pid_head(idinfo)->next;
+ rpc_free(current);
+ current = RPC_srvr_pid_head(idinfo);
+ cnt = -1;
+ } else {/* Delete all but the first element */
+ // LCOV_EXCL_START 8: dead code
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ previous->next = current->next;
+ rpc_free(current);
+ current = previous->next;
+ // LCOV_EXCL_STOP
+ }
+ } else {
+ previous = current;
+ current = current->next;
+ }
+ cnt ++;
+ }
+ return ret;
+}
+
+/** @brief Delete all PID management tables of the communication destination server
+ *
+ * Releases the PID management table and deletes all data when the client terminates with RPC_end().
+ *
+ * @param *idinfo [IN] Information associated with the client's RPC_ID
+ *
+ * @retval RPC_OK : Deletion completed
+ * @retval RPC_ERR_Fatal : Argument error
+ */
+static RPC_Result
+RpcAllDeleteSrvrPid(RpcIdInfo *idinfo) {
+ if (NULL == idinfo) { // LCOV_EXCL_BR_LINE 6: double check in rpc_lib.c --> RPC_end()
+ RPC_LOG_ERR("RpcAllDeleteSrvrPid() : Invalid Param."); // LCOV_EXCL_START 6: double check in rpc_lib.c --> RPC_end()
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ return RPC_ERR_Fatal;
+ } // LCOV_EXCL_STOP
+
+ RpcSrvrPidInfo *current = RPC_srvr_pid_head(idinfo);
+ while (NULL != current) {
+
+ if (0 <= current->wd) {
+ inotify_rm_watch(RPC_clnt_inotify_fd(idinfo), current->wd);
+ }
+
+ RpcSrvrPidInfo *previous = current;
+ current = current->next;
+
+ rpc_free(previous);
+ }
+ RPC_srvr_pid_head(idinfo) = NULL;
+ return RPC_OK;
+}
+
+/** @brief Logging RPC-API calling process
+ *
+ * Receive File name, function name and line-number of the client calling API and API-function-name, and logging them.
+ *
+ * @param filename [IN]Pointer to caller filename string
+ * @param funcname [IN]Pointer to caller function-name string
+ * @param line [IN]Line-number in the source file of the client
+ * @param apiname [IN]Pointer to call-API-function-name string
+ * @retval 0: normal completion
+ * @retval Otherwise: Fatal error
+ */
+ int
+RPC_record_dbg_log( const char *filename, const char *funcname, int line,
+ const char *apiname ) {
+ printf( "[RPC debug log]%s() called from %s() [%s, line %d]\n",
+ apiname, funcname, filename, line );
+ return 0;
+}
+
+/** @}*/
diff --git a/rpc_library/library/src/rpc_marshall.c b/rpc_library/library/src/rpc_marshall.c
new file mode 100644
index 00000000..e4a085c0
--- /dev/null
+++ b/rpc_library/library/src/rpc_marshall.c
@@ -0,0 +1,740 @@
+/*
+ * @copyright Copyright (c) 2016-2019 TOYOTA MOTOR CORPORATION.
+ *
+ * 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.
+ */
+
+/**
+ * @file rpc_marshall.c
+ * @brief RPC Library Internal Implementation--Argument Conversion During API Calls
+ *
+ */
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <math.h>
+
+#include <other_service/rpc.h>
+#include "rpc_internal.h"
+
+#include "apidef.tab.h"
+#include "apidef.h"
+
+/** @addtogroup RPClib_in
+ * @{
+ */
+/** Structures for String Add Operations */
+typedef struct {
+ char *start;
+ char *wp;
+ unsigned int units;
+ unsigned int remain;
+} RpcString;
+
+#ifdef STRETCH_STRING
+#define _STRING_ALLOC_UNIT 512
+#else
+/*
+ * Batch allocate total bytes of arguments + data to be added internally
+ * (maximal 6 bytes per argument)
+ */
+#define _STRING_ALLOC_UNIT \
+ (RPC_MAX_API_ARG_TOTAL_SIZE + RPC_MAX_API_ARG_NUM * (2 + 4))
+#endif
+
+#define _ENOUGH_SPACE_FOR_ALL_TYPES \
+ (sizeof(UINT64) > sizeof(double) ? sizeof(UINT64) : sizeof(double))
+
+static RpcString* NewRpcString(void);
+#ifdef STRETCH_STRING
+static int StretchString(RpcString *str, UINT16 bytes);
+#endif
+static char *CopyString(RpcString *str, unsigned int *size);
+static void DestroyString(RpcString *str);
+static inline int AppendString(RpcString *str,
+ const UINT8 *append, UINT16 applen);
+static inline int MarshallUINT8(RpcString *str, UINT8 uc);
+static inline int MarshallUINT16(RpcString *str, UINT16 uh);
+static inline int MarshallUINT32(RpcString *str, UINT32 ui);
+static inline int MarshallUINT64(RpcString *str, UINT64 ul);
+static inline int Marshallfloat(RpcString *str, float f);
+static inline int Marshalldouble(RpcString *str, double d);
+static inline int MarshallUINT8Stream(RpcString *str, const UINT8 *buf,
+ UINT16 bytes);
+static inline int MarshallString(RpcString *str, char *buf,
+ UINT16 bytes);
+static inline int MarshallNullPointer(RpcString *str);
+static inline int MarshallPointer(RpcString *str);
+
+static RpcString *
+NewRpcString(void) {
+ RpcString *str;
+
+ str = rpc_malloc(sizeof(RpcString));
+ if (str == NULL) { // LCOV_EXCL_START 5: fail safe for libc malloc
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ return NULL;
+ } // LCOV_EXCL_STOP
+
+ str->start = rpc_malloc(_STRING_ALLOC_UNIT);
+ if (str->start == NULL) { // LCOV_EXCL_START 5: fail safe for libc malloc
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ rpc_free(str);
+ return NULL;
+ } // LCOV_EXCL_STOP
+ str->start[0] = '\0';
+ str->wp = str->start;
+ str->units = 1;
+ str->remain = _STRING_ALLOC_UNIT - 1;
+
+ return str;
+}
+
+#ifdef STRETCH_STRING
+static int
+StretchString(RpcString *str, UINT16 bytes) {
+ unsigned int oldunits = str->units;
+ unsigned int units = 1 + (bytes / _STRING_ALLOC_UNIT) + oldunits;
+ if (units == oldunits) {
+ return 0;
+ }
+ unsigned int length = str->wp - str->start;
+ char *newp = rpc_malloc(units * _STRING_ALLOC_UNIT);
+ if (newp == NULL) {
+ return -1;
+ }
+ memcpy(newp, str->start, length);
+ rpc_free(str->start);
+ str->start = newp;
+ str->wp = str->start + length;
+ *(str->wp) = '\0';
+ str->units = units;
+ str->remain += (units - oldunits) * _STRING_ALLOC_UNIT;
+ return 0;
+}
+#endif /* STRETCH_STRING */
+
+static inline int
+AppendString(RpcString *str, const UINT8 *append, UINT16 applen) {
+ rpc_assert(append != NULL); // LCOV_EXCL_BR_LINE 6: double check
+#ifdef STRETCH_STRING
+ if (applen > str->remain) {
+ if (StretchString(str, applen - str->remain) < 0) {
+ return -1;
+ }
+ }
+#else
+ rpc_assert(applen <= str->remain); // LCOV_EXCL_BR_LINE 6: double check
+#endif
+ memcpy(str->wp, append, applen);
+ str->wp += applen;
+ str->remain -= applen;
+ return 0;
+}
+
+static char *
+CopyString(RpcString *str, unsigned int *size) {
+ unsigned int length = (unsigned int)(str->wp - str->start);
+ char *ret = rpc_malloc(length);
+ // LCOV_EXCL_BR_START 5: fail safe for libc malloc
+ if (ret == NULL) {
+ return NULL;
+ }
+ // LCOV_EXCL_BR_STOP
+ memcpy(ret, str->start, length);
+ if (size != NULL) {
+ *size = length;
+ }
+
+ return ret;
+}
+
+static void
+DestroyString(RpcString *str) {
+ rpc_free(str->start);
+ rpc_free(str);
+}
+
+static inline int
+MarshallUINT8(RpcString *str, UINT8 c) {
+ UINT8 buf[1 + sizeof(c)];
+ buf[0] = 'C';
+ buf[1] = c;
+ return AppendString(str, buf, sizeof(buf));
+}
+
+static inline int
+MarshallUINT8Stream(RpcString *str, const UINT8 *buf, UINT16 bytes) {
+ int ret = AppendString(str, (const UINT8 *)"B", 1);
+ if (ret < 0) { // LCOV_EXCL_BR_LINE 15: inline func rpc_marshall.c
+ return -1;
+ }
+ return AppendString(str, buf, bytes);
+}
+
+static inline int
+MarshallVararrayStream(RpcString *str, const UINT8 *buf, UINT16 bytes) {
+ char head_str[1+4+1+1]; /* Area where symbol "V" + size is stored */
+ sprintf(head_str, "V%03d ", bytes);
+ head_str[1+4+1] = '\0';
+
+ if (AppendString(str, (const UINT8 *)head_str, (UINT16)strlen(head_str)) < 0) { // LCOV_EXCL_BR_LINE 15: inline func rpc_marshall.c
+ return -1;
+ }
+
+ if (AppendString(str, buf, bytes) < 0) { // LCOV_EXCL_BR_LINE 15: inline func rpc_marshall.c
+ return -1;
+ }
+ return 0;
+}
+
+static inline int
+MarshallString(RpcString *str, char *buf, UINT16 bytes) {
+ char *p = buf;
+ UINT16 count = 0;
+ /* count the number of bytes in the argument */
+ while(*p != '\0' && count < (UINT16)(bytes - 1)) {
+ count++;
+ p++;
+ }
+
+ char count_str[1+strlen("1024")+1+1];
+ sprintf(count_str, "S%d ", count);
+
+ if (AppendString(str, (const UINT8 *)count_str, (UINT16)strlen(count_str)) < 0 || AppendString(str, (const UINT8 *)buf, count) < 0) { // LCOV_EXCL_BR_LINE 11: Unexpected branch // NOLINT(readability/nolint)
+ return -1;
+ }
+ return 0;
+}
+
+static int
+MarshallUINT16(RpcString *str, UINT16 uh) {
+ UINT8 buf[1 + sizeof(uh)];
+ buf[0] = 'H';
+ memcpy(buf + 1, &uh, sizeof(uh));
+ return AppendString(str, buf, sizeof(buf));
+}
+
+static inline int
+MarshallUINT32(RpcString *str, UINT32 ui) {
+ UINT8 buf[1 + sizeof(ui)];
+ buf[0] = 'I';
+ memcpy(buf + 1, &ui, sizeof(ui));
+ return AppendString(str, buf, sizeof(buf));
+}
+
+static inline int
+Marshallint(RpcString *str, int i) {
+ return MarshallUINT32(str, (UINT32)i);
+}
+
+static inline int
+MarshallUINT64(RpcString *str, UINT64 ul) {
+ UINT8 buf[1 + sizeof(ul)];
+ buf[0] = 'L';
+ memcpy(buf + 1, &ul, sizeof(ul));
+ return AppendString(str, buf, sizeof(buf));
+}
+
+static inline int
+Marshallfloat(RpcString *str, float f) {
+ UINT8 buf[1 + sizeof(f)];
+ buf[0] = 'F';
+ memcpy(buf + 1, &f, sizeof(f));
+ return AppendString(str, buf, sizeof(buf));
+}
+
+static inline int
+Marshalldouble(RpcString *str, double d) {
+ UINT8 buf[1 + sizeof(d)];
+ buf[0] = 'D';
+ memcpy(buf + 1, &d, sizeof(d));
+ return AppendString(str, buf, sizeof(buf));
+}
+
+static inline int
+MarshallPointer(RpcString *str) {
+ /* only to specify that a non-NULL pointer was delivered */
+ return AppendString(str, (const UINT8 *)"P", 1);
+}
+
+static inline int
+MarshallNullPointer(RpcString *str /*, int code*/) {
+ return AppendString(str, (const UINT8 *)"N", 1);
+}
+
+/** @ingroup RPClib_in
+ */
+
+#define MACROMarshallPointer(TYPE) \
+ do { \
+ TYPE *p = (TYPE *)temp; \
+ error = Marshall##TYPE(str, *p); \
+ } while(0)
+
+#define MACROMarshallValue(TYPE, STACK_TYPE) \
+ do { \
+ TYPE value = (TYPE)va_arg(ap, STACK_TYPE); \
+ error = Marshall##TYPE(str, value); \
+ } while(0)
+
+char *
+RPC_marshall_arguments(unsigned int *size, int dont_marshall_out_pointer,
+ int num_args, ...) {
+ rpc_assert(num_args <= RPC_MAX_API_ARG_NUM); // LCOV_EXCL_BR_LINE 6: double check
+ va_list ap;
+
+ RpcString *str;
+ str = NewRpcString();
+ if (str == NULL) { // LCOV_EXCL_BR_LINE 5: fail safe for libc malloc
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ return NULL; // LCOV_EXCL_LINE 5: fail safe for libc malloc
+ }
+
+ va_start(ap, num_args);
+
+ int ii, error;
+ error = 0;
+
+ for(ii = 0 ; ii < num_args && error == 0 ; ii++) {
+ unsigned int code, is_vararray, is_pointer, in_out, out_only;
+ UINT16 bytes;
+ unsigned int val = va_arg(ap, unsigned int);
+
+ RPC_marshall_flag flag;
+ flag.all = ntohl(val);
+ code = flag.bits.code;
+ is_vararray = flag.bits.is_vararray;
+ is_pointer = flag.bits.is_pointer;
+ in_out = flag.bits.in_out;
+ bytes = flag.bits.bytes;
+ rpc_assert(bytes <= RPC_MAX_API_ARG_SIZE); // LCOV_EXCL_BR_LINE 6: double check
+
+
+ out_only = 0;
+ if (in_out == RPC_OUT_ARG) { /* OUT only argument */
+ out_only = 1;
+ }
+
+ if (is_pointer) { /* Argument passed by pointer */
+
+ void *temp = (void *)va_arg(ap, void *);
+ if (temp == NULL) {
+ /* NULL pointer */
+ error = MarshallNullPointer(str);
+ } else if (dont_marshall_out_pointer && out_only) {
+ /* Not refer to the contents of a pointer */
+ error = MarshallPointer(str);
+ } else {/* Marshall the contents of pointers */
+ if (is_vararray) {
+ /* Variable-length array */
+ error = MarshallVararrayStream(str, temp, bytes);
+ } else {
+ switch(code) {
+ case rpc_CHAR:
+ case rpc_INT8:
+ case rpc_UINT8:
+ MACROMarshallPointer(UINT8);
+ break;
+ case rpc_INT16:
+ case rpc_UINT16:
+ MACROMarshallPointer(UINT16);
+ break;
+ case rpc_INT:
+ case rpc_SINT:
+ case rpc_UINT:
+ MACROMarshallPointer(int);
+ break;
+ case rpc_INT32:
+ case rpc_UINT32:
+ MACROMarshallPointer(UINT32);
+ break;
+ case rpc_INT64:
+ case rpc_UINT64:
+ MACROMarshallPointer(UINT64);
+ break;
+ case rpc_FLOAT:
+ MACROMarshallPointer(float);
+ break;
+ case rpc_DOUBLE:
+ MACROMarshallPointer(double);
+ break;
+ case rpc_STRING:
+ error = MarshallString(str, temp, bytes);
+ break;
+ case rpc_USER_DEFINED:
+ error = MarshallUINT8Stream(str, temp, bytes);
+ break;
+ default:
+ error = -1;
+ break;
+ }
+ }
+ }
+ } else {/* Argument passed by value */
+
+ /* Note: In this area, the code depends on the CPU architecture */
+
+ switch(code) {
+ case rpc_CHAR:
+ case rpc_INT8:
+ case rpc_UINT8:
+ MACROMarshallValue(UINT8, unsigned int);
+ break;
+ case rpc_INT16:
+ case rpc_UINT16:
+ MACROMarshallValue(UINT16, unsigned int);
+ break;
+ case rpc_INT:
+ case rpc_SINT:
+ case rpc_UINT:
+ MACROMarshallValue(int, int); // LCOV_EXCL_BR_LINE 15: marco defined in rpc_marshall.c
+ break;
+ case rpc_INT32:
+ case rpc_UINT32:
+ MACROMarshallValue(UINT32, UINT32); // LCOV_EXCL_BR_LINE 15: marco defined in rpc_marshall.c
+ break;
+ case rpc_INT64:
+ case rpc_UINT64:
+ MACROMarshallValue(UINT64, UINT64); // LCOV_EXCL_BR_LINE 15: marco defined in rpc_marshall.c
+ break;
+ case rpc_FLOAT:
+ MACROMarshallValue(float, double); // LCOV_EXCL_BR_LINE 15: marco defined in rpc_marshall.c
+ break;
+ case rpc_DOUBLE:
+ MACROMarshallValue(double, double); // LCOV_EXCL_BR_LINE 15: marco defined in rpc_marshall.c
+ break;
+ case rpc_USER_DEFINED:
+ rpc_assert(bytes <= sizeof(UINT64));
+ /* This area is very architecture-dependent! */
+ if (bytes <= sizeof(UINT32)) {
+ UINT32 value = (UINT32)va_arg(ap, UINT32); // LCOV_EXCL_BR_LINE 15: macro defined in stdarg.h
+ error = MarshallUINT8Stream(str, (UINT8 *)&value, bytes);
+ } else if (bytes <= sizeof(UINT64)) { // LCOV_EXCL_BR_LINE 6: double check
+ UINT64 value = (UINT64)va_arg(ap, UINT64); // LCOV_EXCL_BR_LINE 15: macro defined in stdarg.h
+ error = MarshallUINT8Stream(str, (UINT8 *)&value, bytes);
+ }
+ break;
+ default:
+ error = -1;
+ break;
+ }
+ }
+ }
+ va_end(ap);
+
+ if (error != 0) {
+ DestroyString(str);
+ return NULL;
+ }
+
+ char *ret = CopyString(str, size);
+ DestroyString(str);
+ return ret;
+}
+
+static inline int DeMarshallUINT8(const char *from, UINT8 *ucp);
+static inline int DeMarshallUINT16(const char *from, UINT16 *uhp);
+static inline int DeMarshallUINT32(const char *from, UINT32 *uip);
+static inline int DeMarshallUINT64(const char *from, UINT64 *ulp);
+static inline int DeMarshallfloat(const char *from, float *fp);
+static inline int DeMarshalldouble(const char *from, double *dp);
+static inline int DeMarshallUINT8Stream(const char *from, UINT8 *buffer,
+ UINT16 bytes);
+static inline int DeMarshallString(const char *from, char *buffer,
+ UINT16 bytes);
+
+static inline int
+DeMarshallUINT8(const char *from, UINT8 *ucp) {
+ if (*from == 'C') {
+ *ucp = *(UINT8 *)(from + 1);
+ return 1 + sizeof(*ucp);
+ } else {
+ return -1;
+ }
+}
+
+static inline int
+DeMarshallUINT16(const char *from, UINT16 *uhp) {
+ if (*from == 'H') {
+ memcpy(uhp, from + 1, sizeof(*uhp));
+ return 1 + sizeof(*uhp);
+ } else {
+ return -1;
+ }
+}
+
+static inline int
+DeMarshallUINT32(const char *from, UINT32 *uip) {
+ if (*from == 'I') {
+ memcpy(uip, from + 1, sizeof(*uip));
+ return 1 + sizeof(*uip);
+ } else {
+ return -1;
+ }
+}
+
+static inline int
+DeMarshallint(const char *from, int *ip) {
+ return DeMarshallUINT32(from, (UINT32 *)ip);
+}
+
+static inline int
+DeMarshallUINT64(const char *from, UINT64 *ulp) {
+ if (*from == 'L') {
+ memcpy(ulp, from + 1, sizeof(*ulp));
+ return 1 + sizeof(*ulp);
+ } else {
+ return -1;
+ }
+}
+
+static inline int
+DeMarshallfloat(const char *from, float *fp) {
+ if (*from == 'F') {
+ memcpy(fp, from + 1, sizeof(*fp));
+ return 1 + sizeof(*fp);
+ } else {
+ return -1;
+ }
+}
+
+static inline int
+DeMarshalldouble(const char *from, double *dp) {
+ if (*from == 'D') {
+ memcpy(dp, from + 1, sizeof(*dp));
+
+ return 1 + sizeof(*dp);
+ } else {
+ return -1;
+ }
+}
+
+static inline int
+DeMarshallUINT8Stream(const char *from, UINT8 *buffer, UINT16 bytes) {
+ if (*from == 'B') {
+ memcpy(buffer, from + 1, bytes);
+ return (int)(1 + bytes);
+ } else {
+ return -1;
+ }
+}
+
+static inline int
+DeMarshallString(const char *from, char *buffer, UINT16 bytes) {
+ if (*from == 'S') {
+ char *start;
+ long len = strtol(from + 1, &start, 10);
+ if (len < 0 || len >= bytes) { // LCOV_EXCL_BR_LINE 5: fail safe for libc strtol
+ return -1;
+ }
+ start++; /* skip ' ' */
+ int skip = (int)(start - from);
+ memcpy(buffer, start, (size_t)len);
+ buffer[len] = '\0';
+ return skip + (int)len;
+ } else {
+ return -1;
+ }
+}
+
+/* Variable-length array data */
+static inline int
+DemarshallVararrayInfo(const char *from, UINT16 *bytes/* OUT */) {
+ if (*from == 'V') {
+ char *end;
+ long len = strtol((char *)(from + 1), &end, 10);
+ if (len <= 0 || len > RPC_MAX_API_ARG_SIZE) { // LCOV_EXCL_BR_LINE 5: fail safe for libc strtol
+ return -1;
+ }
+ *bytes = (UINT16)len;
+ return (int)(end - from + 1); /* skip ' ' */
+ } else {
+ return -1;
+ }
+}
+
+/** @ingroup RPClib_in
+ */
+
+#define MACRODemarshall(TYPE) \
+ do {\
+ TYPE *p; \
+ if (need_alloc && is_pointer) { \
+ p = rpc_malloc(sizeof(TYPE)); \
+ *(TYPE **)temp = p; \
+ } else { \
+ p = (TYPE *)temp; \
+ } \
+ if (p != NULL) { \
+ ret = DeMarshall##TYPE(from, p); \
+ } \
+ } while(0)
+
+int
+RPC_demarshall_arguments(const char *from, unsigned int size,
+ int need_alloc, int num_args, ...) {
+ rpc_assert(num_args <= RPC_MAX_API_ARG_NUM); // LCOV_EXCL_BR_LINE 6: double check
+ va_list ap;
+ va_start(ap, num_args);
+
+ int ii, error;
+ error = 0;
+ int remain_len = (int)size;
+
+ for(ii = 0 ; ii < num_args && error == 0 && remain_len > 0 ; ii++) {
+ unsigned int code, is_pointer, is_vararray;
+ UINT16 bytes;
+ unsigned int val = va_arg(ap, unsigned int);
+ RPC_marshall_flag flag;
+ flag.all = ntohl(val);
+ code = flag.bits.code;
+ is_vararray = flag.bits.is_vararray;
+ is_pointer = flag.bits.is_pointer;
+ bytes = flag.bits.bytes;
+ rpc_assert(bytes <= RPC_MAX_API_ARG_SIZE); // LCOV_EXCL_BR_LINE 6: double check
+
+
+ void *temp = va_arg(ap, void *);
+ int ret = -1;
+
+ if (*from == 'N') { /* NULL pointer */
+ if (bytes > 0 || is_pointer != 0) {
+ if (need_alloc) {
+ *(void **)temp = NULL;
+ } else {
+ /* do nothing */
+ }
+ ret = 1;
+ }
+ } else if (*from == 'P') { /* Pointer(no content) */
+ if (need_alloc) {
+ if (bytes > 0) { /* String type or user-defined type */
+ *(void **)temp = rpc_malloc(bytes);
+ } else if (is_pointer != 0) { /* Other pointers */
+ *(void **)temp = rpc_malloc(_ENOUGH_SPACE_FOR_ALL_TYPES);
+ }
+ ret = 1;
+ }
+ } else { /* non-NULL pointer */
+ if ( is_vararray ) { /* Variable-length array */
+ ret = DemarshallVararrayInfo(from, &bytes);
+ if( ret < 0 ) {
+ va_end(ap);
+ return -1; /* pgr0524 */
+ }
+ char *p;
+ if (need_alloc) {
+ p = rpc_malloc(sizeof(char)*bytes);
+ *(char **)temp = p;
+ } else {
+ p = (char *)temp; /* pgr0524 */
+ }
+ if (p != NULL) {
+ memcpy(p, from + ret, bytes);
+ ret += bytes;
+ }
+ } else {
+ switch(code) {
+ case rpc_CHAR:
+ case rpc_INT8:
+ case rpc_UINT8:
+ MACRODemarshall(UINT8); /* pgr0524 */ // LCOV_EXCL_BR_LINE 15: marco defined in rpc_marshall.c
+ break;
+ case rpc_INT16:
+ case rpc_UINT16:
+ MACRODemarshall(UINT16); /* pgr0524 */ // LCOV_EXCL_BR_LINE 15: marco defined in rpc_marshall.c
+ break;
+ case rpc_INT:
+ case rpc_SINT:
+ case rpc_UINT:
+ MACRODemarshall(int); /* pgr0524 */ // LCOV_EXCL_BR_LINE 15: marco defined in rpc_marshall.c
+ break;
+ case rpc_INT32:
+ case rpc_UINT32:
+ MACRODemarshall(UINT32); /* pgr0524 */ // LCOV_EXCL_BR_LINE 15: marco defined in rpc_marshall.c
+ break;
+ case rpc_INT64:
+ case rpc_UINT64:
+ MACRODemarshall(UINT64); /* pgr0524 */ // LCOV_EXCL_BR_LINE 15: marco defined in rpc_marshall.c
+ break;
+ case rpc_FLOAT:
+ MACRODemarshall(float); /* pgr0524 */ // LCOV_EXCL_BR_LINE 15: marco defined in rpc_marshall.c
+ break;
+ case rpc_DOUBLE:
+ MACRODemarshall(double); /* pgr0524 */ // LCOV_EXCL_BR_LINE 15: marco defined in rpc_marshall.c
+ break;
+ case rpc_USER_DEFINED: {
+ UINT8 *p;
+ if (need_alloc && is_pointer) {
+ p = rpc_malloc(bytes);
+ *(UINT8 **)temp = p;
+ } else {
+ p = (UINT8 *)temp; /* pgr0524 */
+ }
+ if (p != NULL) {
+ ret = DeMarshallUINT8Stream(from, p, bytes);
+ }
+ break;
+ }
+ case rpc_STRING: {
+ char *p;
+ if (need_alloc) {
+ p = rpc_malloc(sizeof(char)*bytes);
+ *(char **)temp = p;
+ } else {
+ p = (char *)temp; /* pgr0524 */
+ }
+ if (p != NULL) {
+ ret = DeMarshallString(from, p, bytes);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ if (ret < 0) {
+ error = 1;
+ } else {
+ remain_len -= ret;
+ from += ret;
+ }
+ }
+ va_end(ap);
+
+ if (error) {
+ return -1; /* pgr0524 */
+ } else {
+ return 0; /* pgr0524 */
+ }
+}
+
+void
+RPC_marshall_free(int num, ...) {
+ va_list ap;
+ va_start(ap, num);
+
+ int i;
+ for(i = 0 ; i < num ; i++) {
+ void *ptr = va_arg(ap, void *); // LCOV_EXCL_BR_LINE 15: macro defined in stdarg.h
+ if (ptr != NULL) {
+ rpc_free(ptr);
+ }
+ }
+ va_end(ap);
+}
diff --git a/rpc_library/library/src/rpc_thread.c b/rpc_library/library/src/rpc_thread.c
new file mode 100644
index 00000000..76778e75
--- /dev/null
+++ b/rpc_library/library/src/rpc_thread.c
@@ -0,0 +1,1224 @@
+/*
+ * @copyright Copyright (c) 2016-2019 TOYOTA MOTOR CORPORATION.
+ *
+ * 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.
+ */
+
+/**
+ * @file rpc_thread.c
+ * @brief RPC Library Internal Implementation--Processing of Internally Generated Threads
+ *
+ */
+/** @addtogroup RPClib_in */
+/** @{ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <malloc.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/select.h>
+#include <sys/poll.h>
+#include <sys/prctl.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <sys/inotify.h>
+
+#include <other_service/rpc.h>
+#include "rpc_internal.h"
+
+#include <native_service/cl_monitor.h>
+#include <native_service/cl_process.h>
+
+/** Sub-threads that wake up in the RPC library */
+static RpcThreadInfo *Thread_info[RPC_MAX_THREADS_IN_PROCESS];
+static int Num_thread_info;
+pthread_t g_rpc_thread = RPC_NO_THREAD;
+UINT32 g_rpc_thread_alive;/**< Sub-thread running */
+
+#define RPC_MAGIC_ID (('R'<<24)|('P'<<16)|('C'<<8)|'L')
+
+/** Pipes used for communication with sub-threads
+ * Read: Main thread, Write: Sub-thread */
+int g_rpc_pipe_main_sub[2] = { -1, -1 };
+
+static pthread_mutex_t process_global_mutex = PTHREAD_MUTEX_INITIALIZER;
+#define PROCESS_MUTEX_LOCK rpc_mutex_lock(&process_global_mutex)
+#define PROCESS_MUTEX_UNLOCK rpc_mutex_unlock(&process_global_mutex)
+
+static void *RpcThreadMain(void *ptr);
+static void NotifyMainThread(RpcThreadInfo *th);
+
+static void KillRpcThread(void);
+static void NotifyAddServer(RpcThreadInfo *th);
+static void NotifyRemoveServer(RpcThreadInfo *th);
+
+static RPC_Result RpcRegistSockName(RpcIdInfo *idinfo, char *client_sock_name, const struct ucred *cr, int wd);
+static RPC_Result RpcCheckSockName(RpcIdInfo *idinfo, RPC_ID client_id);
+static RPC_Result RpcDeleteSockName(RpcIdInfo *idinfo, int wd);
+static RPC_Result RpcAllDeleteSockName(RpcIdInfo *idinfo, int inotify_fd);
+static RPC_Result RpcCheckClientCredential(RpcIdInfo *idinfo, const struct ucred *cr);
+
+#define RPC_SUB_THREAD_WAIT_SEC 5
+
+#define WAIT_FOR_SUB_THREAD(loop_cond, sec) \
+{ \
+ struct timeval timeout; \
+ timeout.tv_sec = sec; \
+ timeout.tv_usec = 0; \
+ \
+ int fd = RPC_pipe_sub_main(th)[PIPE_READ]; \
+ fd_set fds; \
+ \
+ while((loop_cond)) { \
+ FD_ZERO(&fds); \
+ FD_SET(fd, &fds); \
+ int sret = select(fd + 1, &fds, NULL, NULL, &timeout); \
+ if (sret < 0 && errno == EINTR) { \
+ continue; \
+ } else if (sret > 0 && FD_ISSET(fd, &fds)) { \
+ char c; \
+ read(fd, &c, sizeof(c)); \
+ } else { \
+ break; \
+ } \
+ } \
+}
+
+RUNS_IN_CALLERS_THREAD
+ RpcThreadInfo *
+RpcMyThreadInfo(void) {
+ RpcThreadInfo *ret = NULL;
+ int i;
+ pthread_t me = pthread_self();
+
+ PROCESS_MUTEX_LOCK;
+ for(i = 0; i < RPC_MAX_THREADS_IN_PROCESS ; i++) {
+ if (Thread_info[i] != NULL
+ && pthread_equal(Thread_info[i]->thread, me)) {
+ ret = Thread_info[i];
+ break;
+ }
+ }
+ PROCESS_MUTEX_UNLOCK;
+ return ret;
+}
+
+RUNS_IN_CALLERS_THREAD
+ RpcThreadInfo *
+RpcCreateThreadInfo(void) {
+ int i;
+ pthread_t me = pthread_self();
+
+ PROCESS_MUTEX_LOCK;
+ /* Look for a free slot to store the thread info pointer */
+ for(i = 0; i < RPC_MAX_THREADS_IN_PROCESS ; i++) {
+ if (Thread_info[i] != NULL) {
+ if (pthread_equal(Thread_info[i]->thread, me)) { // LCOV_EXCL_BR_LINE 6: double check
+ PROCESS_MUTEX_UNLOCK; // LCOV_EXCL_START 6: double check
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ return Thread_info[i];
+ } // LCOV_EXCL_STOP
+ } else {
+ break;
+ }
+ }
+
+ if (i == RPC_MAX_THREADS_IN_PROCESS) {
+ PROCESS_MUTEX_UNLOCK;
+ //CONFIG_ASSERT("Must increase RPC_MAX_THREADS_IN_PROCESS");
+ RPC_LOG_ERR("Must increase RPC_MAX_THREADS_IN_PROCESS");
+ return NULL;
+ }
+
+ /* Allocate area for thread info */
+ // Because there is a timing when the server sub-thread is accessed without being initialized,
+ // corrected so as to fill up to 0 in the MUTEX.
+ RpcThreadInfo *th = rpc_malloc(sizeof(*th));
+ if (th != NULL) { // LCOV_EXCL_BR_LINE 5: fail safe for libc malloc
+ memset(th, 0, sizeof(*th));
+ Thread_info[i] = th;
+ th->magic = RPC_MAGIC_ID;
+ Num_thread_info++;
+ }
+ PROCESS_MUTEX_UNLOCK;
+
+ if (th == NULL) { // LCOV_EXCL_START 5: fail safe for libc malloc
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ RPC_LOG_ERR("Can't alloc thread_info.");
+ return NULL;
+ } // LCOV_EXCL_STOP
+
+ /* Initializing Thread Info */
+ th->thread = me;
+ pthread_mutex_init(&(th->th_mtx), NULL);
+ th->sequence_number = RPC_SEQ_NUM_START;
+
+ return th;
+}
+
+/*
+ * check if the allocated client ID conflicts with the server ID
+ * of the same thread
+ */
+ static int
+RpcCheckIdConflict(RpcThreadInfo *th, RPC_ID id) {
+ RpcIdInfo *idinfo;
+ idinfo = RPC_srvr_idinfo(th);
+ if (idinfo != NULL && RPC_my_id(idinfo) == id) { // LCOV_EXCL_START 6: double check
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ return 1;
+ } // LCOV_EXCL_STOP
+ return 0;
+}
+
+/** Adding IDs with RPC_start()
+ *
+ * - Main: Create and initialize structures and tell sub-threads to add
+ * - Sub: Add pointer to thread info (RpcThreadInfo) and notify it to the main process
+ * - The main process waits for this procedure to finish.
+ * Use id_info->thread_info to determine completion (completed if not NULL)
+ */
+RUNS_IN_CALLERS_THREAD
+ int
+RpcCreateIdInfo(RpcThreadInfo *th,
+ RPC_ID id, RPC_dispatch_func_t dispatch, INT32 secure_check) {
+ RpcIdInfo *id_info = rpc_malloc(sizeof(*id_info));
+ if (id_info == NULL) { // LCOV_EXCL_START 5: fail safe for libc malloc
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ return -1;
+ } // LCOV_EXCL_STOP
+ memset(id_info, 0, sizeof(*id_info));
+
+ /*
+ * Creates a Unix domain socket based on a given number of ports
+ */
+#if defined(RPC_USE_UNIX_AUTOBIND)
+ int sock_un = -1, secure_sock_un = -1;
+ socklen_t sa_len;
+ struct sockaddr_un sa_un;
+
+get_id_retry:
+ sock_un = socket(PF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0); /* Datagram socket for receiving API requests */
+ if (sock_un < 0) {
+ RPC_LOG_PERROR("socket");
+ goto error;
+ }
+ SET_NONBLOCK(sock_un);
+ SET_CLOSE_ON_EXEC(sock_un);
+
+ /*
+ * Naming Rules for Unix domain Sockets
+ * Server:(ID=50000-59999)
+ * sa_un.sun_path[0] = 0x00;
+ * sa_un.sun_path[1] = 'S';
+ * sa_un.sun_path[2-5] = sprintf("%04x", ID);
+ *
+ * Client:(ID=1-0xfffff)
+ * sa_un.sun_path[0] = 0x00;
+ * sa_un.sun_path[1-5] = sprintf("%05x", ID);
+ * ID is autobind by kernel during bind(see linux/net/unix/af_unix.c)
+ * ! Since it depends on the unix socket implementations of Linux, be careful when porting to other operating systems.
+ *
+ * ID=50000-59999 is duplicated in Server and Client,
+ * but generated it according to the above rules when sent in the RPClib (see rpc_udp.c)
+ *
+ * Because file deletion is leaked when the system is forcibly terminated and abnormal process termination
+ * by a traditional way to create and bind files under /tmp/RPC/,
+ * change to the above method(2009.02.04,2012.01.21)
+ */
+ memset(&sa_un, 0, sizeof(sa_un));
+ sa_un.sun_family = AF_UNIX;
+ if (dispatch != NULL) { // server
+ RpcSetServerName(sa_un.sun_path, id);
+ sa_len = sizeof(sa_un.sun_family) + SOCK_NAME_LEN;
+ } else { // client
+ // Automatically assign name (ID) by unix_autobind()
+ sa_len = sizeof(sa_un.sun_family);
+ }
+
+#else /* !AUTOBIND */
+ int sock_un = -1;
+ struct sockaddr_un sa_un;
+ sa_un.sun_family = AF_UNIX;
+ rpc_set_socket_name(sa_un.sun_path, id);
+ sock_un = socket(PF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
+ if (sock_un < 0) {
+ RPC_LOG_PERROR("socket(unix)");
+ goto error;
+ }
+ SET_NONBLOCK(sock_un);
+ SET_CLOSE_ON_EXEC(sock_un);
+ unlink(sa_un.sun_path);
+ sa_len = sizeof(sa_un);
+#endif /* !AUTOBIND */
+ if (bind(sock_un, (struct sockaddr *)&sa_un, sa_len) < 0) {
+ RPC_LOG_PERROR("DGRAM : bind(unix), ID:%#x", id);
+ goto error;
+ }
+
+#if defined(RPC_USE_UNIX_AUTOBIND)
+ if (dispatch == NULL) { // client
+ // Retrieves the assigned name (ID)
+ socklen_t len = sizeof(sa_un);
+ if (getsockname(sock_un, (struct sockaddr *)&sa_un, &len) < 0) {
+ perror("getsockname");
+ goto error;
+ }
+ RpcGetClientName(sa_un.sun_path, &id);
+ if (RpcCheckIdConflict(th, id)) { // LCOV_EXCL_BR_LINE 8: dead code, RpcCheckIdConflict always is false
+ // LCOV_EXCL_START 8: dead code, RpcCheckIdConflict always is false
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ RPC_LOG_STATE("ID %d conflicts with server -- get next one", id);
+ close(sock_un);
+ goto get_id_retry;
+ } // LCOV_EXCL_STOP
+ RPC_LOG_DEBUG("client %s", sa_un.sun_path + 1);
+ }
+#endif /* AUTOBIND */
+
+ id_info->port = id;
+ id_info->sock = sock_un;
+
+ if (dispatch != NULL) { /* server */
+ rpc_assert(th->srvr_id == NULL); // LCOV_EXCL_BR_LINE 6: double check
+ RpcApicallInfo *apicall = rpc_malloc(sizeof(*apicall));
+ if (apicall == NULL) { // LCOV_EXCL_START 5: fail safe for libc malloc
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ goto error;
+ } // LCOV_EXCL_STOP
+
+ /* Create Socket for Authentication */
+ socklen_t secure_sa_len;
+ struct sockaddr_un secure_sa_un;
+
+ secure_sock_un = socket(PF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0); /* stream socket for authentication */
+ if (secure_sock_un < 0) {
+ RPC_LOG_PERROR("socket");
+ rpc_free(apicall);
+ apicall = NULL;
+ goto error;
+ }
+ SET_NONBLOCK(secure_sock_un);
+ SET_CLOSE_ON_EXEC(secure_sock_un);
+
+ memset(&secure_sa_un, 0, sizeof(secure_sa_un));
+ secure_sa_un.sun_family = AF_UNIX;
+ RpcSetServerSecureName(secure_sa_un.sun_path, id);
+ secure_sa_len = sizeof(secure_sa_un.sun_family) + SECURE_SOCK_NAME_LEN;
+
+ /* Bind socket for authentication */
+ if (bind(secure_sock_un, (struct sockaddr *)&secure_sa_un, secure_sa_len) < 0) {
+ RPC_LOG_PERROR("STREAM : bind(unix), ID:%#x", id);
+ rpc_free(apicall);
+ apicall = NULL;
+ goto error;
+ }
+
+ id_info->secure_sock = secure_sock_un;
+
+ memset(apicall, 0, sizeof(*apicall));
+ apicall->dispatch_func = dispatch;
+ apicall->pipe_sub_main[PIPE_READ] = -1;
+ apicall->pipe_sub_main[PIPE_WRITE] = -1;
+ apicall->timeout_sec = 30; /* Server API processing timeout */
+ apicall->secure_check = secure_check; /* Authentication check by UID list */
+ if (NEED_SECURE_CHECK == secure_check) { /* Initializes the UID list with not-registered if secured given. */
+ apicall->regist_credential_info = NO_REGISTERED;
+ }
+ apicall->sock_info_head = NULL; /* Leading Node of Source Client Socket Info */
+ apicall->client_sock_name_num = 0; /* Number of elements in the source client's socket name list */
+ apicall->in_process_client = RPC_NO_PORT; /* Client RPC_ID during API processing */
+
+ id_info->apicall = apicall;
+ th->srvr_id = id_info;
+
+ /* Creating a pipe for communication pipe from sub-thread to main-thread direction */
+ if (pipe(apicall->pipe_sub_main) != 0) {
+ RPC_LOG_PERROR("pipe");
+ goto error;
+ }
+ SET_NONBLOCK(apicall->pipe_sub_main[PIPE_READ]);
+ SET_CLOSE_ON_EXEC(apicall->pipe_sub_main[PIPE_READ]);
+ SET_NONBLOCK(apicall->pipe_sub_main[PIPE_WRITE]);
+ SET_CLOSE_ON_EXEC(apicall->pipe_sub_main[PIPE_WRITE]);
+
+ PROCESS_MUTEX_LOCK;
+ if (g_rpc_thread == RPC_NO_THREAD) { /* There are no sub-threads. */
+ /* Creating a pipe for communication from main-thread to sub-thread direction */
+ if (pipe(g_rpc_pipe_main_sub) != 0) {
+ RPC_LOG_PERROR("pipe");
+ PROCESS_MUTEX_UNLOCK;
+ goto error;
+ }
+
+ SET_NONBLOCK(g_rpc_pipe_main_sub[PIPE_READ]);
+ SET_CLOSE_ON_EXEC(g_rpc_pipe_main_sub[PIPE_READ]);
+ SET_NONBLOCK(g_rpc_pipe_main_sub[PIPE_WRITE]);
+ SET_CLOSE_ON_EXEC(g_rpc_pipe_main_sub[PIPE_WRITE]);
+
+ /* Creating sub-thread */
+ pthread_t read_th;
+ if (pthread_create(&read_th, NULL, RpcThreadMain, 0) != 0) {
+ RPC_LOG_PERROR("pthread_create");
+ PROCESS_MUTEX_UNLOCK;
+ goto error;
+ }
+ g_rpc_thread = read_th;
+ }
+ PROCESS_MUTEX_UNLOCK;
+
+ /* Instruct a sub-thread to add and wait for completion */
+ NotifyAddServer(th);
+ // LCOV_EXCL_BR_START 15: macro define in rpc_thread.c
+ WAIT_FOR_SUB_THREAD((th->srvr_id->thread_info == NULL),
+ RPC_SUB_THREAD_WAIT_SEC);
+ // LCOV_EXCL_BR_STOP
+ rpc_assert(th->srvr_id->thread_info != NULL); // LCOV_EXCL_BR_LINE 6: double check
+
+ } else { /* dispatch == NULL => client */
+ id_info->count = 1;
+ id_info->thread_info = th;
+ th->clnt_id = id_info;
+ }
+ return 0; /* pgr0524 */
+
+error:
+ if (g_rpc_pipe_main_sub[PIPE_READ] >= 0) { // LCOV_EXCL_BR_LINE 5: fail safe for libc socket
+ close(g_rpc_pipe_main_sub[PIPE_READ]);
+ }
+ if (g_rpc_pipe_main_sub[PIPE_WRITE] >= 0) { // LCOV_EXCL_BR_LINE 5: fail safe for libc socket
+ close(g_rpc_pipe_main_sub[PIPE_WRITE]);
+ }
+ if (id_info->apicall != NULL) {
+ if (id_info->apicall->pipe_sub_main[PIPE_READ] >= 0) {
+ close(id_info->apicall->pipe_sub_main[PIPE_READ]);
+ }
+ if (id_info->apicall->pipe_sub_main[PIPE_WRITE] >= 0) {
+ close(id_info->apicall->pipe_sub_main[PIPE_WRITE]);
+ }
+ rpc_free(id_info->apicall);
+ }
+ if (sock_un != -1) {
+ close(sock_un);
+#if !defined(RPC_USE_UNIX_AUTOBIND)
+ unlink(sa_un.sun_path);
+#endif /* !AUTOBIND */
+ }
+ if (secure_sock_un != -1) {
+ close(secure_sock_un);
+#if !defined(RPC_USE_UNIX_AUTOBIND)
+ unlink(secure_sa_un.sun_path);
+#endif /* !AUTOBIND */
+ }
+ rpc_free(id_info);
+ th->srvr_id = NULL;
+ return -1; /* pgr0524 */
+}
+
+/*
+ * Notify an unfinished request of an error at server termination (RPC_end).
+ */
+ static void
+RpcSendErrorToPendingRequest(RpcThreadInfo *th, RpcIdInfo *idinfo) {
+ UINT16 api_num;
+ RPC_ID client;
+ char *args_string;
+ unsigned int args_size;
+ rpc_send_buf sendbuf;
+ char retcode[10];
+
+ do {
+ api_num = RpcGetAPIRequest(idinfo, &client,
+ &args_string, &args_size);
+ if (api_num > 0) { /* API calls are queued */
+
+ sprintf(retcode, "%08x ", RPC_ERR_Fatal);
+ sendbuf.buf = retcode;
+ sendbuf.bytes = sizeof(retcode) - 1;
+ RpcSendUdp2(idinfo, client, RPC_SEND_TO_CLIENT,
+ RPC_PACKET_APIRETURN, 1, &sendbuf);
+ RPC_LOG_STATE("sent error result to pending client %05x", client);
+ RpcFreeAPIArgsString(args_string);
+ }
+ } while(api_num > 0);
+}
+
+/*
+ * Notify unfinished request of deadlock when deadlock of the server is detected.
+ */
+ static void
+RpcSendDeadlockToPendingRequest(RpcThreadInfo *th, RpcIdInfo *idinfo) {
+ UINT16 api_num;
+ RPC_ID client;
+ char *args_string;
+ unsigned int args_size;
+ rpc_send_buf sendbuf;
+ char retcode[10];
+
+ do {
+ api_num = RpcGetAPIRequest(idinfo, &client,
+ &args_string, &args_size);
+ if (api_num > 0) { /* API calls are queued */
+
+ sprintf(retcode, "%08x ", RPC_ERR_Server_DeadLock);
+ sendbuf.buf = retcode;
+ sendbuf.bytes = sizeof(retcode) - 1;
+ RpcSendUdp2(idinfo, client, RPC_SEND_TO_CLIENT,
+ RPC_PACKET_APIRETURN, 1, &sendbuf);
+ RPC_LOG_STATE("sent deadlock result to pending client %05x", client);
+ RpcFreeAPIArgsString(args_string);
+ }
+ } while(api_num > 0);
+
+ if (RPC_NO_PORT != RPC_apicall_in_process_client(idinfo)) {
+ sprintf(retcode, "%08x ", RPC_ERR_Server_DeadLock);
+ sendbuf.buf = retcode;
+ sendbuf.bytes = sizeof(retcode) - 1;
+ RpcSendUdp2(idinfo, RPC_apicall_in_process_client(idinfo), RPC_SEND_TO_CLIENT,
+ RPC_PACKET_APIRETURN, 1, &sendbuf);
+ RPC_LOG_STATE("sent deadlock result to pending client %05x", RPC_apicall_in_process_client(idinfo));
+ RPC_apicall_in_process_client(idinfo) = RPC_NO_PORT;
+ }
+}
+
+/** Delete RPC_ID Info by RPC_end()
+ *
+ * - Main: Notify sub of deletion of RPC_ID info.
+ * - Sub: Delete a pointer from thread info (RpcThreadInfo) and notify main of that.
+ * - Main waits for this procedure to finish.
+ * Use id_info->thread_info to determine completion (completed if NULL).
+ * Then, release the memory related to RPC_ID info and close the socket.
+ */
+RUNS_IN_CALLERS_THREAD
+ void
+RpcDestroyIdInfo(RpcThreadInfo *th, RpcIdInfo *id_info) {
+ rpc_assert(id_info->count == 0); // LCOV_EXCL_BR_LINE 6: double check
+ if (id_info->apicall) {
+ if (g_rpc_thread_alive != 0) {
+ NotifyRemoveServer(th);
+ /* Wait for a sub-thread to recognize IDinfo deletion */
+ // LCOV_EXCL_BR_LINE 15: macro define in rpc_thread.c
+ WAIT_FOR_SUB_THREAD((th->srvr_id->thread_info != NULL),
+ RPC_SUB_THREAD_WAIT_SEC);
+ // LCOV_EXCL_BR_STOP
+ rpc_assert(th->srvr_id->thread_info == NULL); /* not recognized yet */ // LCOV_EXCL_BR_LINE 6: double check
+ }
+
+ if (id_info->apicall->pipe_sub_main[PIPE_READ] >= 0) {
+ close(id_info->apicall->pipe_sub_main[PIPE_READ]);
+ }
+ if (id_info->apicall->pipe_sub_main[PIPE_WRITE] >= 0) {
+ close(id_info->apicall->pipe_sub_main[PIPE_WRITE]);
+ }
+ if (id_info->secure_sock >= 0) {
+ close(id_info->secure_sock);
+ }
+ rpc_free(id_info->apicall);
+ th->srvr_id = NULL;
+ } else {
+ th->clnt_id = NULL;
+ }
+ rpc_free(id_info);
+}
+
+RUNS_IN_CALLERS_THREAD
+ void
+RpcDestroyThreadInfo(void) {
+ unsigned int i;
+ RpcThreadInfo *th = RpcMyThreadInfo();
+ if (th == NULL) {
+ return;
+ }
+
+ RPC_THREAD_MUTEX_LOCK(th);
+ if (th->thread == RPC_NO_THREAD) { // LCOV_EXCL_BR_LINE 6: double check
+ RPC_THREAD_MUTEX_UNLOCK(th); // LCOV_EXCL_START 6: double check
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ return;
+ } // LCOV_EXCL_STOP
+ th->thread = RPC_NO_THREAD;
+ RPC_THREAD_MUTEX_UNLOCK(th);
+
+ PROCESS_MUTEX_LOCK;
+ /*
+ * Remove the pointer from the global variable.
+ * Subsequent calls to RpcMyThreadInfo() return NULL
+ */
+ for(i = 0; i < RPC_MAX_THREADS_IN_PROCESS ; i++) {
+ if (th == Thread_info[i]) {
+ Thread_info[i] = NULL;
+ Num_thread_info--;
+ break;
+ }
+ }
+ PROCESS_MUTEX_UNLOCK;
+ BUG_ASSERT(i < RPC_MAX_THREADS_IN_PROCESS, "No info in Thread_info[]"); // LCOV_EXCL_BR_LINE 15: marco defined in rpc_internal.h
+
+ if (Num_thread_info == 0 && g_rpc_thread_alive != 0) {
+ KillRpcThread();
+ char name[32];
+ prctl(PR_GET_NAME, name);
+ RPC_LOG_DEBUG("[%s]waiting for sub thread to join...", name);
+ pthread_join(g_rpc_thread, NULL);
+ RPC_LOG_DEBUG("[%s]sub thread joined.", name);
+ g_rpc_thread = RPC_NO_THREAD; /* bug fix */
+ rpc_assert(g_rpc_thread_alive == 0); // LCOV_EXCL_BR_LINE 6: double check
+ close(g_rpc_pipe_main_sub[PIPE_READ]);
+ close(g_rpc_pipe_main_sub[PIPE_WRITE]);
+ }
+
+ if (th->srvr_id != NULL) { // LCOV_EXCL_BR_LINE 6: double check
+ RpcDestroyIdInfo(th, th->srvr_id); // LCOV_EXCL_START 6: double check
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ th->srvr_id = NULL;
+ } // LCOV_EXCL_STOP
+ if (th->clnt_id != NULL) { // LCOV_EXCL_BR_LINE 6: double check
+ RpcDestroyIdInfo(th, th->clnt_id); // LCOV_EXCL_START 6: double check
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ th->clnt_id = NULL;
+ } // LCOV_EXCL_STOP
+
+ pthread_mutex_destroy(&(th->th_mtx));
+ rpc_free(th);
+}
+
+#if !defined(RPC_USE_UNIX_AUTOBIND)
+/**
+ * Sub-function of RPC_end_all()
+ *
+ * Assuming releasing memory and closing the socket are processing at immediately after the end of the process,
+ * Suppress socket file leaks by only deleting socket files because to avoid deadlocks and shorten the time
+ * by exclusive processing.
+ */
+ void
+RpcUnlinkSocketFiles(void) {
+ int i;
+ char sock_name[16];
+
+ for(i = 0; i < RPC_MAX_THREADS_IN_PROCESS ; i++) {
+ RpcThreadInfo *th = Thread_info[i];
+ if (th != NULL) {
+ if (th->srvr_id != NULL) {
+ rpc_set_socket_name(sock_name, RPC_port(th->srvr_id));
+ RPC_LOG_STATE("unlink srvr %s", sock_name);
+ unlink(sock_name);
+ }
+ if (th->clnt_id != NULL) {
+ rpc_set_socket_name(sock_name, RPC_port(th->clnt_id));
+ RPC_LOG_STATE("unlink clnt %s", sock_name);
+ unlink(sock_name);
+ }
+ }
+ }
+}
+#endif /* !AUTOBIND */
+
+/*
+ * Deadlock detection check for servers in the thread
+ */
+ static void
+RpcDeadlockCheck(RpcThreadInfo** thread_info, unsigned int num_thread_info) {
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+
+ unsigned int i = 0;
+ for(i = 0 ; i < num_thread_info ; i++) {
+ RpcThreadInfo *th = thread_info[i];
+ RpcIdInfo *idinfo = th->srvr_id;
+ CL_MonitorEntry_t entry;
+
+ if (0 == CL_MonitorGetEntry(CL_MONITOR_TYPE_RPC, RPC_port(idinfo), &entry)) {
+ if (entry.state == CL_MONITOR_STATE_RUN && entry.timeout <= ts.tv_sec) {
+ RPC_LOG_ERR("Time Out : RPC_ID = %#x API_NUM = %#x", entry.id, entry.user_data);
+ fprintf(stderr, "Time Out : RPC_ID = %#x API_NUM = %#x\n", entry.id, entry.user_data);
+ RpcSendDeadlockToPendingRequest(th, idinfo);
+ }
+ }
+ }
+}
+/** Main functions of the sub-threads (READING THREAD)
+*/
+RUNS_IN_READING_THREAD
+ static void *
+RpcThreadMain(void *ptr __attribute__((unused))) {
+ struct pollfd wait_files[RPC_MAX_FD_IN_PROCESS];
+ RpcThreadInfo *thread_info[RPC_MAX_THREADS_IN_PROCESS];
+ unsigned int num_thread_info = 0;
+
+ unsigned int poll_num;
+ int need_reset_sockfd = 1;
+ int normal_exit = 0;
+ RPC_Result result;
+ unsigned int i, j;
+
+ /* Monitoring for clients process with inotify() *//* Monitoring target filename */
+ const int inotify_fd = inotify_init1(IN_CLOEXEC); /* fd for process monitoring with inotify() */
+
+ UINT8 readbuf[RPC_UDP_PACKET_SIZE];
+ memset(readbuf, 0, sizeof(UINT8) * RPC_UDP_PACKET_SIZE);
+
+ g_rpc_thread_alive = 1;
+
+ CL_MonitorInit(CL_MONITOR_INIT_USER); /* Using the API for Error Monitoring */
+
+ // Name the thread created in the RPClib (append "_R")
+#define RPC_APPEND_NAME "_R"
+#ifndef PRF_SIZE_PROCESSNAME
+#define PRF_SIZE_PROCESSNAME 8 /* Limit name length for Profiler Analysis Tools */
+#endif
+ {
+ char *p, name[32];
+ prctl(PR_GET_NAME, name);
+ name[PRF_SIZE_PROCESSNAME] = '\0';
+ if (strlen(name) + strlen(RPC_APPEND_NAME) > PRF_SIZE_PROCESSNAME) {
+ p = name + PRF_SIZE_PROCESSNAME - strlen(RPC_APPEND_NAME);
+ } else {
+ p = name + strlen(name);
+ }
+ strcpy(p, RPC_APPEND_NAME);
+ prctl(PR_SET_NAME, name);
+ }
+
+ /* Set the communication pipe with the main thread to poll fd */
+ poll_num = 1;
+ wait_files[0].fd = g_rpc_pipe_main_sub[PIPE_READ];
+ wait_files[0].events = POLLIN;
+
+restart:
+ for( ; ; ) {
+ if (need_reset_sockfd) {
+ /* Set the UDP socket of each RPC_ID to poll fd */
+ PROCESS_MUTEX_LOCK;
+ for(i = 0, j = 0 ; i < RPC_MAX_THREADS_IN_PROCESS ; i++) {
+ if (Thread_info[i] != NULL) {
+ if (Thread_info[i]->magic != RPC_MAGIC_ID) { // LCOV_EXCL_BR_LINE 6: double check
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ RPC_LOG_ERR("Someone(me?) destroyed my area!"); // LCOV_EXCL_LINE 6: double check
+ }
+ if (Thread_info[i]->srvr_id != NULL
+ && Thread_info[i]->srvr_id->thread_info != NULL) {
+ thread_info[j] = Thread_info[i];
+ j++;
+ }
+ }
+ }
+ PROCESS_MUTEX_UNLOCK;
+ num_thread_info = j;
+
+ poll_num = 1;
+ /* Register fd for monitoring with inotify() in poll() */
+ wait_files[1].fd = inotify_fd;
+ wait_files[1].events = POLLIN;
+
+ poll_num = 2;
+ for(i = 0 ; i < num_thread_info ; i++) {
+ /* Datagram socket for API request */
+ wait_files[poll_num].fd = thread_info[i]->srvr_id->sock; /* pgr0000 */
+ wait_files[poll_num].events = POLLIN;
+ poll_num++;
+ // LCOV_EXCL_BR_START 5: fail safe for libc listen
+ /* Authentication stream socket */
+ if (0 != listen(thread_info[i]->srvr_id->secure_sock, 10)) { /* Number of queues */
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ RPC_LOG_PERROR("listen(unix)"); // LCOV_EXCL_LINE 5: fail safe for libc listen
+ }
+ // LCOV_EXCL_BR_STOP
+ wait_files[poll_num].fd = thread_info[i]->srvr_id->secure_sock;
+ wait_files[poll_num].events = POLLIN;
+ poll_num++;
+ }
+ need_reset_sockfd = 0;
+ }
+
+ int pollret;
+ pollret = poll(wait_files, poll_num, TIMEOUT_FOR_DEADLOCK_CHECK);
+
+ int save_errno = errno;
+
+ RpcDeadlockCheck(thread_info, num_thread_info);
+ if (pollret < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for libc poll
+ if (save_errno == EINTR) { // LCOV_EXCL_START 5: fail safe for libc poll
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ continue;
+ } else {
+ rpc_assert(pollret > 0);
+ goto exit_read_thread;
+ } // LCOV_EXCL_STOP
+ }
+
+ /* Commands from the main thread (via pipe) */
+ if ((wait_files[0].revents & POLLIN) == POLLIN) {
+ char buf[RPC_MAIN_SUB_COMMAND_SIZE];
+ long ret, arg;
+ int cmd;
+ RpcThreadInfo *th;
+ ret = read(wait_files[0].fd, buf, sizeof(buf));
+ if (ret == sizeof(buf)) {
+ sscanf(buf, RPC_MAIN_SUB_COMMANDs, &cmd, &arg);
+ switch(cmd) {
+ case RPC_COMMAND_ADD_SERVER:
+ th = (RpcThreadInfo *)arg;
+ th->srvr_id->thread_info = th; /* Indicate the completion of the processing */
+ NotifyMainThread(th);
+ need_reset_sockfd = 1;
+ goto restart;
+ break;
+
+ case RPC_COMMAND_REMOVE_SERVER:
+ th = (RpcThreadInfo *)arg;
+ RpcSendErrorToPendingRequest(th, th->srvr_id);
+
+ RpcAllDeleteSockName(th->srvr_id, inotify_fd); /* delete client_sock_name_list */
+ rpc_free((th->srvr_id)->apicall->uid_list); /* delete uid_list */
+ rpc_free((th->srvr_id)->apicall->gid_list); /* delete gid_list */
+
+ th->srvr_id->thread_info = NULL;/* Indicate the completion of the processing */
+ NotifyMainThread(th);
+ need_reset_sockfd = 1;
+ goto restart;
+ break;
+
+ case RPC_COMMAND_EXIT:
+ /************ Termination request from the parent thread *************/
+ RPC_LOG_DEBUG("Received exit command from main thread.");
+ normal_exit = 1;
+ goto exit_read_thread;
+ break;
+ } /* switch */
+ } /* if (ret == sizeof(buf)) */
+ } /* Complete the processing of commands from the main thread */
+
+ /* Client Monitoring Events with inotify() */
+ if ((wait_files[1].revents & POLLIN) == POLLIN) {
+ UINT32 read_len = 0;
+ int length = 0;
+ char *buffer;
+ buffer = (char *)rpc_malloc(BUF_LEN);
+ if (NULL == buffer) {// LCOV_EXCL_START 5: fail safe for libc malloc
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ RPC_LOG_ERR("rpc_malloc() ERROR.");
+ goto exit_read_thread;
+ } // LCOV_EXCL_STOP
+
+ if( (length = (int)read( inotify_fd, buffer, BUF_LEN ) ) < 0 ) { // LCOV_EXCL_START 5: fail safe for libc read
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ RPC_LOG_PERROR("inotify read() ERROR.");
+ rpc_free(buffer);
+ buffer = NULL;
+ goto exit_read_thread;
+ } // LCOV_EXCL_STOP
+ while ( read_len < length ) {
+ struct inotify_event *event = ( struct inotify_event * )&buffer[read_len];
+
+ if ( event->mask & IN_DELETE_SELF ) {/* Terminating a Client Process */
+ int i; /* Looping variable */
+
+ /* Delete the source socket name from all RpcThreadInfo in the received thread */
+ for(i = 0 ; i < num_thread_info ; i++) {
+ RpcThreadInfo *th = thread_info[i];
+ RpcDeleteSockName(th->srvr_id, event->wd);
+ }
+ }
+ read_len += (UINT32)(EVENT_SIZE + event->len); /* Size of the inotify_event structure */
+ }
+ rpc_free(buffer);
+ goto restart;
+ } /* Client Monitoring Events Completed with inotify() */
+
+ for(i = 2 ; i < poll_num ; i++) {
+ /* Event to the API request datagram socket */
+ if ((i % 2 == 0) && ((wait_files[i].revents & POLLIN) == POLLIN)) {
+ unsigned int thread_info_num = ((i/2) - 1); /* Compute thread_info[thread_info_num] with events */
+ RpcThreadInfo *th = thread_info[thread_info_num]; /* pgr0000 */
+ RpcIdInfo *idinfo = th->srvr_id;
+ for(;;) {
+ /* RPClib packet received */
+ int readret = RpcReadUdpPacket(idinfo, readbuf);
+ if (readret < 0) { // LCOV_EXCL_BR_LINE 5: fail safe for libc recvfrom
+ rpc_assert(readret >= 0); // LCOV_EXCL_START 5: fail safe for libc recvfrom
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ goto exit_read_thread;
+ // LCOV_EXCL_STOP
+ } else if (readret == 0) {
+ break;
+ }
+ /* successfully read udp packets */
+ /* parse the packet and queue events */
+ RPC_ID sender = RPC_NO_ID;
+ UINT32 seq_num = 0;
+ UINT32 size = 0;
+ RPC_packet_type command = RPC_PACKET_NONE;
+ if (RpcParsePacketHeader((const char *)readbuf, &command, &sender, &seq_num, &size) != RPC_OK) { // LCOV_EXCL_BR_LINE 11: Unexpected branch // NOLINT(readability/nolint)
+ goto exit_read_thread;
+ }
+
+ long int api_num;
+ char *buff;
+
+ switch(command) {
+ case RPC_PACKET_APICALL:
+ if (RPC_DEBUG != NULL) { // LCOV_EXCL_BR_LINE 7: debug
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ printf("RPC[%s]: received APIcall\n", RPC_DEBUG); // LCOV_EXCL_LINE 7: debug
+ }
+ // Return response without queuing for ALIVE query
+ api_num = strtol((const char *)(readbuf + RPC_PACKET_HEADER_LEN), NULL, 10);
+ if (api_num == RPC_API_NUM_RPC_ALIVE) {
+ RpcSendUdpResponse(idinfo, sender, RPC_SEND_TO_CLIENT,
+ RPC_RESPONSE_APICALL,
+ seq_num, "OK", sizeof("OK"));
+ break;
+ }
+
+ /* Return BUSY if secure and unregistered in UID-list */
+ if ((NEED_SECURE_CHECK == RPC_secure_check(idinfo))
+ && (NO_REGISTERED == RPC_regist_credential_info(idinfo))) {
+ RpcSendUdpResponse(idinfo, sender, RPC_SEND_TO_CLIENT,
+ RPC_RESPONSE_APICALL,
+ seq_num, "BUSY", sizeof("BUSY"));
+ RPC_LOG_ERR("Need UID list register.");
+ break;
+ }
+
+ result = RpcQueueAPIRequestBefore(idinfo, size, (char**)&buff);
+ if (result == RPC_OK) {
+ /* Check whether the source has been authenticated */
+ if(RPC_OK == RpcCheckSockName(idinfo, sender)) { /* Registerd the name of the source socket */
+ RpcSendUdpResponse(idinfo, sender, RPC_SEND_TO_CLIENT,
+ RPC_RESPONSE_APICALL,
+ seq_num, "OK", sizeof("OK"));
+ RpcQueueAPIRequestAfter(idinfo, sender,
+ (const char *)(readbuf + RPC_PACKET_HEADER_LEN),
+ size, buff);
+ } else { /* Not registered (in other words, first communication with the source client) */
+ /* Authentication request to the client */
+ RPC_THREAD_MUTEX_UNLOCK(idinfo->thread_info);
+ RpcSendUdpResponse(idinfo, sender, RPC_SEND_TO_CLIENT,
+ RPC_RESPONSE_APICALL,
+ seq_num, "CERT", sizeof("CERT"));
+ rpc_free(buff);
+ break;
+ }
+ } else if (result == RPC_ERR_Busy) { // LCOV_EXCL_BR_LINE 5: fail safe for libc malloc
+ RpcSendUdpResponse(idinfo, sender, RPC_SEND_TO_CLIENT,
+ RPC_RESPONSE_APICALL,
+ seq_num, "BUSY", sizeof("BUSY"));
+ } else { // LCOV_EXCL_START 5: fail safe for libc malloc
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ RpcSendUdpResponse(idinfo, sender, RPC_SEND_TO_CLIENT,
+ RPC_RESPONSE_APICALL,
+ seq_num, "ERR", sizeof("ERR"));
+ RPC_LOG_ERR("queueing APIcall failed.(%d)", result);
+ goto exit_read_thread;
+ } // LCOV_EXCL_STOP
+ NotifyMainThread(th);
+ if (RPC_DEBUG != NULL) { // LCOV_EXCL_BR_LINE 7: debug
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ printf("RPC[%s]: notified APIcall\n", RPC_DEBUG); // LCOV_EXCL_LINE 7: debug
+ }
+ break;
+
+ default:
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ BUG_ASSERT(0, "Unknown UDP packet type"); // LCOV_EXCL_LINE 15: marco defined in rpc_internal.h
+ goto exit_read_thread;
+ break;
+ } /* switch(command) */
+ }/* for(;;) */
+
+ /* Event to the stream socket for authentication */
+ } else if ((i % 2 != 0) && ((wait_files[i].revents & POLLIN) == POLLIN)) {
+ unsigned int thread_info_num = ((i-1)/2 - 1); /* Compute thread_info[thread_info_num] with events */
+ struct sockaddr_un client_sa_un;
+ socklen_t client_len = sizeof(struct sockaddr_un);
+ struct ucred cr; /* Structure of client credit info */
+ RpcCertifyResult send_ret; /* Authentication result to pass to the client */
+ RpcThreadInfo *th = thread_info[thread_info_num];
+ RpcIdInfo *idinfo = th->srvr_id;
+
+ send_ret.certify_res = CERTIFY_NG;
+ send_ret.srvr_pid = 0;
+
+ /* Obtain client credit info from a connected socket */
+ int accept_sock = accept4(wait_files[i].fd, (struct sockaddr *)&client_sa_un, &client_len, SOCK_CLOEXEC);
+ int ret = getsockopt(accept_sock, SOL_SOCKET, SO_PEERCRED, &cr, &client_len);
+ if (ret == 0) { // LCOV_EXCL_BR_LINE 5: fail safe for libc getsockopt
+ client_sa_un = (struct sockaddr_un )client_sa_un;
+ /* Check if UID of client is allowed to communicate */
+ if (RPC_OK == RpcCheckClientCredential(idinfo, &cr)) {
+
+ /* Obtain the socket name associated with the RPC_ID of the client from the socket info */
+ char client_sock_name[SOCK_NAME_LEN];
+ RpcGetClientNameFromSock(client_sa_un.sun_path, client_sock_name);
+
+ /* Monitoring client processes with inotify */
+ char intfy_fname[32];
+ snprintf(intfy_fname, sizeof(intfy_fname), CL_INTFY_FILENAME_FORMAT, cr.pid);
+ int wd = inotify_add_watch(inotify_fd, intfy_fname, IN_DELETE_SELF);
+ if (0 > wd) { // LCOV_EXCL_BR_LINE 5: fail safe for libc inotify_add_watch
+ RPC_LOG_STATE("intfy_fname is Not Found [%s].", intfy_fname);
+ }
+
+ /* Register the source socket name in the management table */
+ RpcRegistSockName(idinfo, client_sock_name, &cr, wd);
+
+ /* Send server credit info to the client */
+ send_ret.certify_res = CERTIFY_OK;
+ send_ret.srvr_pid = getpid();
+ }
+ }
+
+ /* Send authentication result to client */
+ send(accept_sock, (char*)&send_ret, sizeof(RpcCertifyResult), 0);
+ close(accept_sock);
+
+ goto restart;
+
+ } else if ((wait_files[i].revents & ~POLLIN) != 0) { // LCOV_EXCL_START 5: fail safe for libc poll
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ // POLLERR, etc. on UDP port
+ RPC_LOG_STATE("poll error %x", wait_files[i].revents);
+
+ if ((wait_files[i].revents & POLLNVAL) == POLLNVAL) {
+ need_reset_sockfd = 1;
+ goto restart;
+ }
+ } /* if ((wait_files[i].revents & POLLIN) == POLLIN) */ // LCOV_EXCL_STOP
+
+ } /* processing UDP packets finished */
+
+ } /* end of forever loop */
+
+exit_read_thread:
+
+ g_rpc_thread_alive = 0;
+ for(i = 0 ; i < num_thread_info ; i++) { // LCOV_EXCL_BR_LINE 6: double check
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ NotifyMainThread(thread_info[i]); /* pgr0000 */ // LCOV_EXCL_LINE 6: double check
+ }
+
+ close(inotify_fd);
+
+ if (normal_exit == 0) { // LCOV_EXCL_BR_LINE 6: double check
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ RPC_LOG_CRIT("sub thread ABNORMALLY exited."); // LCOV_EXCL_LINE 6: double check
+ } else {
+ RPC_LOG_DEBUG("sub thread normally exited.");
+ }
+ return NULL;
+}
+
+/* Notification of sub-thread -> main-thread (via pipe) */
+RUNS_IN_READING_THREAD
+ static void
+NotifyMainThread(RpcThreadInfo *th) {
+ rpc_assert(th->srvr_id->apicall != NULL); // LCOV_EXCL_BR_LINE 6: double check
+ char c = 0;
+ write(th->srvr_id->apicall->pipe_sub_main[PIPE_WRITE], &c, sizeof(c));
+}
+
+/* Notification of main-thread -> sub-thread(via pipe) */
+/* Termination instruction */
+RUNS_IN_CALLERS_THREAD
+ static void
+KillRpcThread(void) {
+ char buf[RPC_MAIN_SUB_COMMAND_SIZE];
+ sprintf(buf, RPC_MAIN_SUB_COMMAND, RPC_COMMAND_EXIT, (unsigned long)0);
+ write(g_rpc_pipe_main_sub[PIPE_WRITE], buf, sizeof(buf));
+}
+
+/* AddRPC_ID */
+RUNS_IN_CALLERS_THREAD
+ static void
+NotifyAddServer(RpcThreadInfo *th) {
+ char buf[RPC_MAIN_SUB_COMMAND_SIZE];
+ sprintf(buf, RPC_MAIN_SUB_COMMAND, RPC_COMMAND_ADD_SERVER,
+ (unsigned long)th);
+ write(g_rpc_pipe_main_sub[PIPE_WRITE], buf, sizeof(buf));
+}
+
+/* Remove RPC_ID */
+RUNS_IN_CALLERS_THREAD
+ static void
+NotifyRemoveServer(RpcThreadInfo *th) {
+ char buf[RPC_MAIN_SUB_COMMAND_SIZE];
+ sprintf(buf, RPC_MAIN_SUB_COMMAND, RPC_COMMAND_REMOVE_SERVER,
+ (unsigned long)th);
+ write(g_rpc_pipe_main_sub[PIPE_WRITE], buf, sizeof(buf));
+}
+
+/* Register the socket name of the source client in the management table. */
+ static RPC_Result
+RpcRegistSockName(RpcIdInfo *idinfo, char *client_sock_name, const struct ucred *cr, int wd) {
+ if ((NULL == idinfo) || (NULL == client_sock_name) || (NULL == cr) || (0 > cr->pid)) { // LCOV_EXCL_BR_LINE 6: void *RpcThreadMain(void *ptr)
+ RPC_LOG_ERR("RpcRegistSockName() : Invalid Param."); // LCOV_EXCL_START 6: void *RpcThreadMain(void *ptr)
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ return RPC_ERR_Fatal;
+ } // LCOV_EXCL_STOP
+
+ RpcClientSockNameInfo *sock_name_buf, *current;
+
+ sock_name_buf = rpc_malloc(sizeof(RpcClientSockNameInfo));
+ // LCOV_EXCL_BR_START 5: fail safe for libc malloc
+ if( sock_name_buf == NULL ){
+ return RPC_ERR_Fatal;
+ }
+ // LCOV_EXCL_BR_STOP
+ strcpy(sock_name_buf->client_sock_name, client_sock_name); /* Socket name */
+ sock_name_buf->pid = cr->pid; /* PID */
+ sock_name_buf->uid = cr->uid; /* UID */
+ sock_name_buf->gid = cr->gid; /* GID */
+ sock_name_buf->wd = wd; /* Non-negative inotify monitored descriptors */
+ sock_name_buf->next = NULL; /* Pointer to next node (NULL since last node) */
+
+ if (0 == RPC_client_sock_name_num(idinfo)) {
+ RPC_sock_info_head(idinfo) = sock_name_buf;
+ } else {
+ for (current = RPC_sock_info_head(idinfo); current->next != NULL; current = current->next)
+ ;
+ current->next = sock_name_buf;
+ }
+ RPC_client_sock_name_num_inc(idinfo);
+ return RPC_OK;
+}
+
+/* Check if the socket name of the source client is registered in the management table */
+ static RPC_Result
+RpcCheckSockName(RpcIdInfo *idinfo, RPC_ID client_id) {
+ if ((NULL == idinfo) || (client_id == RPC_NO_ID)) { // LCOV_EXCL_BR_LINE 6: void *RpcThreadMain(void *ptr)
+ RPC_LOG_ERR("RpcCheckSockName() : Invalid Param."); // LCOV_EXCL_START 6: void *RpcThreadMain(void *ptr)
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ return RPC_ERR_Fatal;
+ } // LCOV_EXCL_STOP
+
+ char buf[7], client_path_name[SOCK_NAME_LEN]; /* Client socket name */
+
+ /* Converting client_id to the socket name associated with RPC_ID */
+ RpcSetClientName(buf, client_id);
+ memcpy(client_path_name, buf + 1, 5);
+ client_path_name[5] = '\0';
+ RpcClientSockNameInfo *current = RPC_sock_info_head(idinfo);
+
+ /* Search source socket name in management table */
+ while (NULL != current) {
+ if (0 == strcmp(current->client_sock_name, client_path_name)) { /* Registered socket name (authenticated) */
+ return RPC_OK;
+ }
+ current = current->next;
+ }
+ return RPC_ERR_Fatal; /* Not registerd socket name (unauthenticated) */
+}
+
+/* Remove source client socket name from management table */
+ static RPC_Result
+RpcDeleteSockName(RpcIdInfo *idinfo, int wd) {
+ if ((NULL == idinfo) || (0 > wd)) {
+ RPC_LOG_ERR("RpcDeleteSockName() : Invalid Param.");
+ return RPC_ERR_Fatal;
+ }
+
+ RpcClientSockNameInfo *current, *previous;
+ current = RPC_sock_info_head(idinfo);
+ previous = current;
+ int cnt = 0;
+
+ /* Remove Source Socket Name in Management Table */
+ while (NULL != current) {
+ if (wd == current->wd) { /* Delete element */
+ if (0 == cnt) { /* Delete the start element in the management table */
+ RPC_sock_info_head(idinfo) = RPC_sock_info_head(idinfo)->next;
+ rpc_free(current);
+ current = RPC_sock_info_head(idinfo);
+ cnt = -1;
+ } else { /* Delete other than the start element in the management table */
+ previous->next = current->next;
+ rpc_free(current);
+ current = previous->next;
+ }
+ RPC_client_sock_name_num_dec(idinfo);
+ } else { /* Refer to the next node without deleting */
+ previous = current;
+ current = current->next;
+ }
+ cnt ++;
+ }
+
+ return RPC_OK;
+}
+
+/* Remove all source client socket names in the management table */
+ static RPC_Result
+RpcAllDeleteSockName(RpcIdInfo *idinfo, int inotify_fd) {
+ if (NULL == idinfo) { // LCOV_EXCL_BR_LINE 6: double check in void RpcDestroyThreadInfo(void)
+ RPC_LOG_ERR("RpcAllDeleteSockName() : Invalid Param."); // LCOV_EXCL_START 6: void RpcDestroyThreadInfo(void)
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ return RPC_ERR_Fatal;
+ } // LCOV_EXCL_STOP
+
+ RpcClientSockNameInfo *current = RPC_sock_info_head(idinfo);
+
+ while (NULL != current) {
+ RpcClientSockNameInfo *previous = current;
+ current = current->next;
+
+ if (0 <= previous->wd) {
+ inotify_rm_watch(inotify_fd, previous->wd);
+ }
+
+ rpc_free(previous);
+ previous = NULL;
+ RPC_client_sock_name_num_dec(idinfo);
+ }
+
+ return RPC_OK;
+}
+
+
+/* Check if client is allowed to communicate */
+ static RPC_Result
+RpcCheckClientCredential(RpcIdInfo *idinfo, const struct ucred *cr) {
+ if ((NULL == idinfo) || (NULL == cr)) { // LCOV_EXCL_BR_LINE 6: double check in void *RpcThreadMain(void *ptr)
+ RPC_LOG_ERR("RpcCheckClientCredential() : Invalid Param."); // LCOV_EXCL_START 6: void *RpcThreadMain(void *ptr)
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ return RPC_ERR_Fatal;
+ } // LCOV_EXCL_STOP
+
+ /* Retern RPC_OK if authentication is not required */
+ if (NO_SECURE_CHECK == RPC_secure_check(idinfo)) {
+ return RPC_OK;
+ }
+
+ INT32 i = 0; /* Loop counter */
+
+ /* Search client UID in registered UID list */
+ for(i = 0; i < RPC_uid_num(idinfo); i++) {
+ if(RPC_uid_list(idinfo, i) == cr->uid) { /* Found UID in registered UID list */
+ return RPC_OK;
+ }
+ }
+
+ /* Search client GID in registered GID list */
+ for(i = 0; i < RPC_gid_num(idinfo); i++) {
+ if(RPC_gid_list(idinfo, i) == cr->gid) { /* Found GID in registered GID list. */
+ return RPC_OK;
+ }
+ }
+
+ RPC_LOG_ERR("[Client isn't authenticated!!!!]");
+ return RPC_ERR_Fatal; /* Not found UID in registered UID list */
+}
diff --git a/rpc_library/library/src/rpc_udp.c b/rpc_library/library/src/rpc_udp.c
new file mode 100644
index 00000000..d16569dc
--- /dev/null
+++ b/rpc_library/library/src/rpc_udp.c
@@ -0,0 +1,473 @@
+/*
+ * @copyright Copyright (c) 2016-2019 TOYOTA MOTOR CORPORATION.
+ *
+ * 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.
+ */
+
+/**
+ * @file rpc_udp.c
+ * @brief RPC Library Internal Implementation--UDP Communication
+ *
+ */
+/** @addtogroup RPClib_in */
+/** @{ */
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h> // for usleep
+
+#include <fcntl.h>
+#include <sys/un.h>
+
+#include <sys/inotify.h>
+
+#include <other_service/rpc.h>
+#include "rpc_internal.h"
+
+static /*inline*/ UINT32
+RpcGetSequenceNumber(RpcThreadInfo *th) {
+ RPC_THREAD_MUTEX_LOCK(th);
+ UINT32 ret = th->sequence_number;
+ (th->sequence_number)++;
+ if (th->sequence_number == RPC_SEQ_NUM_INVALID) { // LCOV_EXCL_BR_LINE 200: overflow check, but test time is too long
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ th->sequence_number = RPC_SEQ_NUM_START; // LCOV_EXCL_LINE 200: overflow check, but test time is too long
+ }
+ RPC_THREAD_MUTEX_UNLOCK(th);
+ return ret;
+}
+
+/**
+ */
+int
+RpcReadUdpPacket(const RpcIdInfo *id, UINT8 *buf) {
+ struct sockaddr_un sa;
+ socklen_t sa_len = sizeof(sa);
+ // sa passed to recvfrom does not require initialization
+
+ for(;;) {
+
+ ssize_t ret = recvfrom(RPC_my_sock(id), buf, RPC_UDP_PACKET_SIZE,
+ 0, (struct sockaddr *)&sa, &sa_len);
+
+ if (ret < 0) {
+ if (errno == EAGAIN) { // LCOV_EXCL_BR_LINE 5: fail safe for libc recvfrom
+ //RPC_LOG_PERROR("recvfrom port %d", RPC_port(id));
+ return 0;
+ } else if (errno == EINTR) { // LCOV_EXCL_START 5: fail safe for libc recvfrom
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ continue;
+ } else {
+ RPC_LOG_PERROR("recvfrom port %d", RPC_port(id));
+ return -1;
+ } // LCOV_EXCL_STOP
+ } else if (ret == 0) {
+ RPC_LOG_STATE("*** recvfrom ret 0");
+ return 0;
+ } else {
+ return (int)ret;
+ }
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ } // LCOV_EXCL_LINE 10: final line
+}
+
+/** Number of sendto retries */
+#define RPC_SENDTO_RETRY 5
+
+RUNS_IN_CALLERS_THREAD
+RUNS_IN_READING_THREAD
+/**
+ */
+static int
+RpcSendUdpPacket(RpcIdInfo *id,
+ struct sockaddr_un *to, int do_retry,
+ void *mesg, unsigned int bytes) {
+ int nretry = 0;
+ ssize_t ret;
+ int myerr;
+ retry:
+ ret = sendto(RPC_my_sock(id), mesg, bytes, 0,
+ (struct sockaddr *)to, RPC_SOCKET_ADDR_LEN);
+ myerr = errno;
+
+ if (ret < 0) {
+ RPC_LOG_STATE("*** sendto %s ***", to->sun_path + 1);
+ if (myerr == EAGAIN || (do_retry && myerr==ECONNREFUSED && ++nretry <= RPC_SENDTO_RETRY)) { // LCOV_EXCL_BR_LINE 11: Unexpected branch // NOLINT(readability/nolint)
+ usleep(100000);
+#if defined(RPC_USE_UNIX_AUTOBIND)
+ RPC_LOG_DEBUG("*** sendto %s ***", to->sun_path + 1);
+#else /* AUTOBIND */
+ RPC_LOG_DEBUG("**************** sendto retry *********************");
+#endif /* !AUTOBIND */
+ goto retry;
+ }
+ errno = myerr;
+#if defined(RPC_USE_UNIX_AUTOBIND)
+ if (do_retry) {
+ RPC_LOG_PERROR("sendto %s", to->sun_path + 1);
+ }
+#endif /* !AUTOBIND */
+ return -1;
+ } else if ((unsigned int)ret != bytes) {
+ RPC_LOG_STATE("can't send all");
+ return -1;
+ }
+ return 0;
+}
+
+RUNS_IN_CALLERS_THREAD
+RUNS_IN_READING_THREAD
+/**
+ */
+int
+RpcSendUdp(RpcIdInfo *id, const RPC_ID receiver, int direction, RPC_packet_type type, const void *mesg, unsigned int bytes) { // LCOV_EXCL_START 8: dead code
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ rpc_send_buf sendbuf;
+ sendbuf.buf = mesg;
+ sendbuf.bytes = bytes;
+
+ return RpcSendUdp2(id, receiver, direction, type, 1, &sendbuf);
+} // LCOV_EXCL_STOP
+RUNS_IN_CALLERS_THREAD
+RUNS_IN_READING_THREAD
+/** UDP packet transmission process
+ *
+ * UDP packet format
+ * @verbatim
++--------------+--------------+
+|*1|*2|*3|*4|*5| PAYLOAD |
++--------------+--------------+
+@endverbatim
+ *
+ * *1 to *5 indicate the header. @see RPC_PACKET_HEADER
+ *
+ * - *1: [@%-2d] Type of packet
+ * - @see RPC_packet_type
+ * - *2: [@%-5x] Source RPC_ID
+ * - *3: [@%-8x] Sequence number
+ * - Set the value incremented from 1. This value must be unique for each source thread.
+ * - In the case of response packets, this field contains the sequence number of the packet from which the response was received.
+ * - *4: [@%-4u] Size of send data
+ * - In the case of sending data consists of single packet in PAYLOAD, this field contains number of the packet.
+ * - For a multipacket, the first packet contains the sum of the PAYLOAD of all packets,
+ * the last packet contains the PAYLOAD bytes of the packet.
+ * All other intermediate packets are filled with 0.(With up to two packets in the current constraint,
+ * there are no intermediate packets.)
+ * - *5: [@%1d] Position of packet
+ * - @see rpc_packet_position
+ */
+int
+RpcSendUdp2(struct RpcIdInfo *id, RPC_ID receiver, int direction,
+ RPC_packet_type type, unsigned int num, rpc_send_buf *sendbuf) {
+ unsigned char buf[RPC_UDP_PACKET_SIZE];
+ UINT32 seq_num = RpcGetSequenceNumber(id->thread_info);
+ unsigned int bytes = 0;
+ rpc_send_buf *sendbufp = sendbuf;
+ int i, do_retry = 1;
+ for(i = 0 ; i < num ; i++) {
+ bytes += sendbufp->bytes;
+ sendbufp++;
+ }
+ rpc_assert(bytes <= RPC_UDP_PAYLOAD); // LCOV_EXCL_BR_LINE 6: double check
+
+ struct sockaddr_un to;
+ memset(&to, 0, sizeof(to));
+ to.sun_family = AF_UNIX;
+#if defined(RPC_USE_UNIX_AUTOBIND)
+ if (direction != RPC_SEND_TO_CLIENT) {
+ RpcSetServerName(to.sun_path, receiver);
+ if (direction == RPC_SEND_TO_SERVER_NO_RETRY) {
+ do_retry = 0;
+ }
+ } else {
+ RpcSetClientName(to.sun_path, receiver);
+ }
+#else /* !AUTOBIND */
+ rpc_set_socket_name(to.sun_path, rpc_get_port(receiver));
+#endif /* !AUTOBIND */
+
+ sprintf((char *)buf, RPC_PACKET_HEADER,
+ (int)type, RPC_my_id(id), seq_num, bytes,
+ RPC_PACKET_POS_ONEANDONLY);
+
+ unsigned char *bufp = buf + RPC_PACKET_HEADER_LEN;
+ for(i = 0 ; i < num ; i++) {
+ memcpy(bufp, sendbuf->buf, sendbuf->bytes);
+ bufp += sendbuf->bytes;
+ sendbuf++;
+ }
+ if (RpcSendUdpPacket(id, &to, do_retry,
+ buf, RPC_PACKET_HEADER_LEN + bytes) < 0) {
+ return -1;
+ }
+ return (int)seq_num;
+}
+
+RUNS_IN_READING_THREAD
+/**
+ */
+RPC_Result
+RpcSendUdpResponse(RpcIdInfo *id, const RPC_ID receiver, int direction,
+ RPC_packet_type type, UINT32 seq_num,
+ char *mesg, UINT32 bytes) {
+ rpc_assert(bytes <= RPC_MAX_RESPONSE_MESSAGE_SIZE); // LCOV_EXCL_BR_LINE 6: double check
+ char buf[RPC_PACKET_HEADER_LEN + RPC_MAX_RESPONSE_MESSAGE_SIZE];
+ sprintf(buf, RPC_PACKET_HEADER,
+ (int)type, RPC_my_id(id), seq_num, bytes,
+ (int)RPC_PACKET_POS_ONEANDONLY);
+ memcpy(buf + RPC_PACKET_HEADER_LEN, mesg, bytes);
+
+ struct sockaddr_un sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sun_family = AF_UNIX;
+#if defined(RPC_USE_UNIX_AUTOBIND)
+ if (direction != RPC_SEND_TO_CLIENT) {
+ RpcSetServerName(sa.sun_path, receiver);
+ } else {
+ RpcSetClientName(sa.sun_path, receiver);
+ }
+#else /* !AUTOBIND */
+ rpc_set_socket_name(sa.sun_path, rpc_get_port(receiver));
+#endif /* !AUTOBIND */
+ return RpcSendUdpPacket(id, &sa, 0, buf, RPC_PACKET_HEADER_LEN + bytes);
+}
+
+/**
+ */
+RPC_Result
+RpcParsePacketHeader(const char *str, RPC_packet_type *command,
+ RPC_ID_p id, UINT32 *seq_num, UINT32 *size) {
+ // LCOV_EXCL_BR_START 6: double check
+ rpc_assert(str != NULL && command != NULL && id != NULL
+ && seq_num != NULL && size != NULL);
+ // LCOV_EXCL_BR_STOP
+
+ if (sscanf(str, RPC_PACKET_HEADER_scanf, (int *)command, id, seq_num, size) != 4) { // LCOV_EXCL_BR_LINE 11: Unexpected branch // NOLINT(readability/nolint)
+ *command = RPC_PACKET_NONE; // LCOV_EXCL_START 5: fail safe for libc sscanf
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ BUG_ASSERT(0, "Parsing packet failed");
+ // LCOV_EXCL_STOP
+ return RPC_ERR_Fatal;
+ }
+ return RPC_OK;
+}
+
+#include <sys/time.h>
+
+RPC_Result
+RpcClientWaitResponse(RpcIdInfo *idinfo, UINT32 seq_num,
+ UINT32 timeout_msec, UINT16 *response) {
+ unsigned char readbuf[RPC_UDP_PACKET_SIZE];
+ fd_set fds;
+ int fd = idinfo->sock;
+
+ struct timeval timeout;
+ timeout.tv_sec = (__time_t)(timeout_msec / 1000);
+ timeout.tv_usec = (__suseconds_t)((timeout_msec % 1000) * 1000);
+
+ *response = RPC_RESPONSE_NONE;
+
+ for(;;) {
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+ int sret = select(fd + 1, &fds, NULL, NULL, &timeout);
+ if (sret < 0 && errno == EINTR) { /* signal interrupt */ // LCOV_EXCL_START 5: fail safe for libc select
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ continue;
+ // LCOV_EXCL_STOP
+ } else if (sret == 0) { /* timeout */
+ RPC_LOG_ERR("server response timeout");
+ return RPC_ERR_No_Response;
+ } else if (sret > 0 && FD_ISSET(fd, &fds)) { // LCOV_EXCL_BR_LINE 5: fail safe for libc select
+ RPC_ID sender;
+ UINT32 seq;
+ UINT32 size;
+ RPC_packet_type command;
+ int readret = RpcReadUdpPacket(idinfo, readbuf);
+ if (readret <= 0) { // LCOV_EXCL_START 5: fail safe for libc recvfrom
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ /* debug code to see socket status */
+ /* why recvfrom() returned 0 ? */
+ struct pollfd pfd;
+ pfd.fd = fd;
+ pfd.events = POLLIN|POLLHUP|POLLERR;
+ sret = poll(&pfd, 1, 0/* timeout 0 */);
+ RPC_LOG_STATE("** poll revents=%x", pfd.revents);
+ return RPC_ERR_Fatal;
+ } // LCOV_EXCL_STOP
+ if (RpcParsePacketHeader((const char *)readbuf, &command, &sender, &seq, &size) != RPC_OK) { // LCOV_EXCL_BR_LINE 11: Unexpected branch // NOLINT(readability/nolint)
+ return RPC_ERR_Fatal;
+ }
+ unsigned char c;
+ if (seq == seq_num) {
+ switch(command) {
+ case RPC_RESPONSE_APICALL:
+ c = readbuf[RPC_PACKET_HEADER_LEN];
+ switch(c) {
+ case 'O':
+ *response = RPC_RESPONSE_API_OK;
+ goto exit_loop_ok;
+ break;
+ case 'B':
+ *response = RPC_RESPONSE_API_BUSY;
+ goto exit_loop_ok;
+ break;
+ case 'E':
+ *response = RPC_RESPONSE_API_ERR;
+ goto exit_loop_ok;
+ break;
+ case 'D':
+ *response = RPC_RESPONSE_API_DEADLOCK;
+ goto exit_loop_ok;
+ break;
+ case 'C':
+ *response = RPC_RESPONSE_API_CERTIFY;
+ goto exit_loop_ok;
+ break;
+ default:
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ BUG_ASSERT(0, "illegal response\n"); // LCOV_EXCL_LINE 15: marco defined in rpc_internal.h
+ return RPC_ERR_Fatal;
+ break;
+ }
+ break;
+
+ default:
+ RPC_LOG_STATE("Unknown packet command=%d", command);
+ return RPC_ERR_Fatal;
+ break;
+ }
+ } else { /* sequence number mismatch == response to other request */
+ RPC_LOG_DEBUG("unwanted response received(delayed response?)");
+ continue;
+ }
+ } else { /* poll error */
+ RPC_LOG_PERROR("select in wait response");
+ return RPC_ERR_Fatal;
+ }
+ }
+ exit_loop_ok:
+ return RPC_OK;
+}
+
+RPC_Result
+RpcClientWaitResult(RpcIdInfo *idinfo, RPC_ID srvr_id) {
+ unsigned char readbuf[RPC_UDP_PACKET_SIZE];
+ fd_set fds;
+ int fd = idinfo->sock;
+ int inotify_fd = RPC_clnt_inotify_fd(idinfo);
+ int maxfd;
+ RPC_Result result = RPC_OK;
+
+ for(;;) {
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+ FD_SET(inotify_fd, &fds);
+
+ /* Determine the maximum value of fd to wait */
+ if (fd > inotify_fd) {
+ maxfd = fd;
+ } else {
+ maxfd = inotify_fd;
+ }
+
+ int sret = select(maxfd + 1, &fds, NULL, NULL, NULL);
+ if (sret < 0 && errno == EINTR) { /* signal interrupt */ // LCOV_EXCL_START 5: fail safe for libc select
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ continue;
+ // LCOV_EXCL_STOP
+ } else if (sret > 0 && FD_ISSET(fd, &fds)) { /* success */ // LCOV_EXCL_BR_LINE 5: fail safe for libc select
+ RPC_ID sender;
+ UINT32 seq;
+ UINT32 size;
+ RPC_packet_type command;
+ int readret = RpcReadUdpPacket(idinfo, readbuf);
+ if (readret <= 0) { // LCOV_EXCL_START 5: fail safe for libc recvfrom
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ rpc_assert(readret >= 0);
+ result = RPC_ERR_Fatal;
+ goto exit_loop_ok;
+ } // LCOV_EXCL_STOP
+ if (RpcParsePacketHeader((const char *)readbuf, &command, &sender, &seq, &size) != RPC_OK) { // LCOV_EXCL_BR_LINE 11: Unexpected branch // NOLINT(readability/nolint)
+ // LCOV_EXCL_START 5: fail safe for libc sscanf
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ result = RPC_ERR_Fatal;
+ goto exit_loop_ok;
+ } // LCOV_EXCL_STOP
+ switch(command) {
+ case RPC_PACKET_APIRETURN:
+ result = RpcSetAPIcallReturn(idinfo,
+ (const char *)(readbuf + RPC_PACKET_HEADER_LEN),
+ size);
+ if(result == RPC_OK) { // LCOV_EXCL_BR_LINE 5: fail safe for libc malloc
+ if (sscanf((const char *)(readbuf + RPC_PACKET_HEADER_LEN), "%08x ", (unsigned int *)&result) != 1) { // LCOV_EXCL_BR_LINE 5: fail safe for libc sscanf
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ BUG_ASSERT(0, "Parsing packet failed"); // LCOV_EXCL_LINE 15: marco defined in rpc_internal.h
+ return RPC_ERR_Fatal;
+ }
+ }
+ goto exit_loop_ok;
+ default:
+ RPC_LOG_STATE("unwanted packet received while waiting for API return");
+ continue;
+ break;
+ }
+ } else if (sret > 0 && FD_ISSET(inotify_fd, &fds)) { /* server process is terminate. */
+ UINT32 read_len = 0;
+ int length = 0;
+ char *buffer;
+ buffer = (char *)rpc_malloc(BUF_LEN);
+ if (NULL == buffer) { // LCOV_EXCL_START 5: fail safe for libc malloc
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ RPC_LOG_ERR("rpc_malloc() ERROR.");
+ } // LCOV_EXCL_STOP
+
+ if((length = (int)read( inotify_fd, buffer, BUF_LEN )) < 0 ) { // LCOV_EXCL_START 5: fail safe for libc read
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ RPC_LOG_PERROR("inotify read() ERROR.");
+ } // LCOV_EXCL_STOP
+ while (read_len < length) {
+ struct inotify_event *event = ( struct inotify_event * )&buffer[read_len];
+
+ if (event->mask & IN_DELETE_SELF) { /* Terminating a Server Process */
+ if (RPC_ERR_Server_Finish == RpcDeleteSrvrPid(idinfo, srvr_id, event->wd)) {
+ RPC_LOG_PERROR("server process is terminate. : srvr_ID = %x", srvr_id);
+ result = RPC_ERR_Fatal;
+ }
+ }
+ read_len += (UINT32)(EVENT_SIZE + event->len); /* Size of the inotify_event structure */
+ }
+ rpc_free(buffer);
+ if (RPC_OK != result) {
+ goto exit_loop_ok;
+ }
+
+ } else { /* poll error */ // LCOV_EXCL_START 5: fail safe for libc select
+ AGL_ASSERT_NOT_TESTED(); // LCOV_EXCL_LINE 200: test assert
+ RPC_LOG_PERROR("select in wait result");
+ result = RPC_ERR_Fatal;
+ goto exit_loop_ok;
+ // LCOV_EXCL_STOP
+ }
+ }
+exit_loop_ok:
+
+ return result;
+}
+
+/** @} */
diff --git a/rpc_library/tool/Makefile b/rpc_library/tool/Makefile
new file mode 100644
index 00000000..d4d09637
--- /dev/null
+++ b/rpc_library/tool/Makefile
@@ -0,0 +1,62 @@
+#
+# @copyright Copyright (c) 2016-2019 TOYOTA MOTOR CORPORATION.
+#
+# 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.
+#
+
+all: rpc_apidef
+
+clean:
+ rm -rf $(CLEAN_FILES)
+
+YACC := bison
+YFLAGS := -d -t
+LEX := flex
+LFLAGS := -d
+
+CPPFLAGS := -I../library/include -include $(SDKTARGETSYSROOT)/usr/agl/include/agl_types_obsoluted.h
+CFLAGS := -Wall -Wno-unused-function -Wno-unused-variable -include $(SDKTARGETSYSROOT)/usr/agl/include/agl_types_obsoluted.h
+
+rpc_apidef: apidef.tab.o lex.yy.o apidef.o
+ $(CXX) $(CPPFLAGS) -o $@ $^
+
+apidef.tab.o: apidef.tab.h apidef.tab.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) -c $^
+
+lex.yy.o: lex.yy.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) -c $^
+
+apidef.o: apidef.cc
+ $(CXX) $(CPPFLAGS) $(CFLAGS) -c $^
+
+apidef.tab.h apidef.tab.c: apidef.y
+ $(YACC) $(YFLAGS) $<
+
+lex.yy.c: apidef.l apidef.tab.h
+ $(LEX) $(LFLAGS) $<
+
+CLEAN_FILES := rpc_apidef *.o apidef.tab.h apidef.tab.c lex.yy.c
+
+CLEAN_TARGET := clean-all clean-all-sub clean-sub
+INSTALL_TARGET := install-header
+EMPTY_TARGET := install-prog install-data install-lib install-arlib install-shlib
+.PHONY: all install clean $(CLEAN_TARGET) $(INSTALL_TARGET) $(EMPTY_TARGET)
+
+$(CLEAN_TARGET): clean
+
+$(INSTALL_TARGET): install
+
+$(EMPTY_TARGET):
+
+include ../../other_service.mk
+
diff --git a/rpc_library/tool/apidef.cc b/rpc_library/tool/apidef.cc
new file mode 100644
index 00000000..5a5df1c2
--- /dev/null
+++ b/rpc_library/tool/apidef.cc
@@ -0,0 +1,1104 @@
+/*
+ * @copyright Copyright (c) 2016-2019 TOYOTA MOTOR CORPORATION.
+ *
+ * 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.
+ */
+
+/**
+ * @file apidef.cc
+ * @brief RPC tools--Main processing(Implementations of APIDef classes)
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netinet/in.h>
+
+#include <other_service/rpc.h>
+
+#include "apidef.h"
+#include "apidef.tab.h"
+
+static APIDef *API_Def;
+
+extern "C" { // C interface functions
+
+void
+ApidefDefineId(const char *id) {
+ if (id != NULL) {
+ if (API_Def == NULL) {
+ API_Def = new APIDef();
+ }
+ API_Def->DefineId(id);
+ }
+}
+
+void
+ApidefAddHeader(const char *filename) {
+ if (filename != NULL) {
+ if (API_Def == NULL) {
+ API_Def = new APIDef();
+ }
+ API_Def->AddHeader(filename);
+ }
+}
+
+int
+ApidefPushFunctionArg(int arg_code, int buffer_bytes, int is_pointer,
+ int is_vararray, int is_array_size,
+ const char *var_type_name, int in_out,
+ const char *var_name) {
+ if (API_Def == NULL) {
+ API_Def = new APIDef();
+ }
+ return API_Def->AddFunctionArg(arg_code, buffer_bytes, is_pointer,
+ is_vararray, is_array_size,
+ var_type_name, in_out, var_name);
+}
+
+void
+ApidefProcessFunction(const char *name) {
+ if (API_Def == NULL) {
+ API_Def = new APIDef();
+ }
+ API_Def->NameFunction(name);
+}
+
+void
+ApidefListFunctions(int with_args) {
+ if (API_Def != NULL) {
+ API_Def->Print(with_args);
+ }
+}
+
+void
+ApidefFreeAllocation(void) {
+ if (API_Def != NULL) {
+ delete API_Def;
+ API_Def = NULL;
+ }
+}
+
+int
+ApidefMakeStubs(void) {
+ if (API_Def != NULL) {
+ API_Def->MakeStubs();
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+} // extern "C"
+
+/*
+ * Retrieving Argument Names Without Decorators
+ */
+void
+Arg::GetUndecolatedName(string& name /* OUT */, int num) {
+ name = "v";
+ if (num > 0) {
+ /* Making Variable Names Sequential Numbers */
+ char num_str[5];
+ sprintf(num_str, "%d", num);
+ name += num_str;
+ } else {
+ /* Use a user-supplied pseudo-variable name */
+ name = m_name;
+ }
+}
+
+int
+Arg::PrintUndecoratedName(fstream& out, int num) {
+ /* Pointer argument */
+ if (m_is_pointer) {
+ out << "*";
+ }
+
+ if (num > 0) {
+ /* Making Variable Names Sequential Numbers */
+ out << "v" << num;
+ } else {
+ /* Use a user-supplied pseudo-variable name */
+ out << m_name;
+ }
+
+ return 0;
+}
+
+/*
+ * Outputs one argument in a function prototype declaration
+ * out: Destination file
+ * num: Handling of Formal Argument Names
+ * 0 :Formal argument name specified in the API definition file
+ * Non-zero: Use "v" + specified number(Examples: v1, v2, ...)
+ */
+int
+Arg::PrintPrototype(fstream& out, int num) {
+ const char *type = TypeCodeString(m_code);
+ if (type == NULL) {
+ type = m_type_name.c_str();
+ }
+ if (type == NULL) {
+ cout << "Internal Error Occurrence!!\n";
+ return 1;
+ }
+
+ /* Const non-output pointers */
+ if ((m_in_out & RPC_OUT_ARG) == 0 && (m_bytes != 0 || m_is_pointer != 0)) {
+ out << "const ";
+ }
+ out << type << " ";
+ if (m_is_pointer && m_bytes == 0) {/* Non-string pointer arguments */
+ out << "*";
+ }
+
+ if (num > 0) {/* Making variable names sequential numbers */
+ out << "v" << num;
+ } else {/* Use a user-supplied pseudo-variable name */
+ out << m_name;
+ }
+
+ /* Variable-length arrays */
+ if (m_is_vararray != 0) {
+ out << "/* VAR_ARRAY */";
+ }
+
+ /* Variable-length arrays length */
+ if (m_is_array_size != 0) {
+ out << "/* VAR_SIZE */";
+ }
+
+ /*
+ * Commenting on OUT/INOUT Arguments
+ * Maximum number of bytes of a string argument added to a comment
+ */
+ if ((m_in_out & RPC_OUT_ARG) != 0 || m_bytes != 0) {
+ out << "/* ";
+ if ((m_in_out & RPC_OUT_ARG) != 0) {
+ if ((m_in_out & RPC_IN_ARG) != 0) {
+ out << "IN";
+ }
+ out << "OUT ";
+ }
+ if (m_bytes) {
+ out << m_bytes << "Byte ";
+ }
+ out << "*/";
+ }
+
+ return 0;
+}
+
+int
+Arg::CreateMarshallArgs(fstream& out, int num) {
+ return CreateMarshallArgs(out, num, (RPC_IN_ARG|RPC_OUT_ARG));
+}
+
+int
+Arg::CreateMarshallArgs(fstream& out, int num, string &array_size_name) {
+ return CreateMarshallArgs(out, num, (RPC_IN_ARG|RPC_OUT_ARG), array_size_name);
+}
+
+int
+Arg::CreateMarshallArgs(fstream& out, int num, int in_out) {
+ string dummy = "";
+ return CreateMarshallArgs(out, num, in_out, dummy);
+}
+
+/*
+ * The arguments to rpc_marshall_args() are generated for each API argument.
+ * for each API argument.
+ * out: Destination file
+ * num: Number given to the variable name of the argument (Examples: 1 for v1)
+ * in_out: Specifying the IN or OUT Attributes
+ * Output only if the argument has the specified attribute
+ */
+int
+Arg::CreateMarshallArgs(fstream& out, int num, int in_out, string &array_size_name) {
+ if ((m_in_out & in_out) != 0) {
+ /*
+ * Collectively passes the argument type, pointer/non-pointer, IN/OUT attribute,
+ * and the maximum number of bytes of the argument type to one integer.
+ */
+ RPC_marshall_flag flag;
+ flag.bits.code = m_code & ((1<<RPC_MARSHALL_FLAG_BITS_CODE)-1);
+ flag.bits.is_vararray = ((array_size_name.size() != 0) ? 1: 0) &
+ ((1<<RPC_MARSHALL_FLAG_BITS_IS_VARARRAY)-1);
+ flag.bits.is_pointer = m_is_pointer & ((1<<RPC_MARSHALL_FLAG_BITS_IS_POINTER)-1);
+ flag.bits.in_out = m_in_out & ((1<<RPC_MARSHALL_FLAG_BITS_IN_OUT)-1);
+ flag.bits.bytes = (UINT16)(m_bytes);
+ char str[11];
+ sprintf(str, "0x%x", htonl(flag.all));
+ out << "\t\t\t" << str;
+
+ /*
+ * Add size of user-defined type to argument
+ */
+ if (m_code == rpc_USER_DEFINED) {
+ if (array_size_name.size() != 0) {
+ out << " + ntohs(sizeof(" << m_type_name << ") * " << array_size_name << ")";
+ } else {
+ out << " + ntohs(sizeof(" << m_type_name << "))";
+ }
+ } else if (array_size_name.size() != 0) {
+ out << " + ntohs(sizeof(" << TypeCodeString(m_code) << ") * " << array_size_name << ")";
+ }
+
+ out << ", v" << num;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+int
+Arg::CreateDemarshallArgs(fstream& out, int deliver_pointer, int num) {
+ return CreateDemarshallArgs(out, deliver_pointer, num, (RPC_IN_ARG|RPC_OUT_ARG));
+}
+
+int
+Arg::CreateDemarshallArgs(fstream& out, int deliver_pointer, int num, string &array_size_name) {
+ return CreateDemarshallArgs(out, deliver_pointer, num, (RPC_IN_ARG|RPC_OUT_ARG), array_size_name);
+}
+
+int
+Arg::CreateDemarshallArgs(fstream& out, int deliver_pointer, int num, int in_out) {
+ string dummy = "";
+ return CreateDemarshallArgs(out, deliver_pointer, num, in_out, dummy);
+}
+
+/*
+ * The arguments to rpc_demarshall_args() are generated for each API argument.
+ * for each API argument.
+ * out: Destination file
+ * deliver_pointer: Passing a Variable Pointer(non-0)
+ * num: Number given to the variable name of the argument (Examples: 1 for v1)
+ * in_out: Specifying the IN or OUT Attributes
+ * Output only if the argument has the specified attribute
+ */
+int
+Arg::CreateDemarshallArgs(fstream& out, int deliver_pointer, int num, int in_out, string &array_size_name) {
+ if ((m_in_out & in_out) != 0) {
+ /*
+ * Collectively passes the argument type, pointer/non-pointer, IN/OUT attribute,
+ * and the maximum number of bytes of the argument type to one integer.
+ */
+ RPC_marshall_flag flag;
+ flag.bits.code = m_code & ((1<<RPC_MARSHALL_FLAG_BITS_CODE)-1);
+ flag.bits.is_vararray = ((array_size_name.size() != 0) ? 1: 0) &
+ ((1<<RPC_MARSHALL_FLAG_BITS_IS_VARARRAY)-1);
+ flag.bits.is_pointer = m_is_pointer & ((1<<RPC_MARSHALL_FLAG_BITS_IS_POINTER)-1);
+ flag.bits.in_out = m_in_out & ((1<<RPC_MARSHALL_FLAG_BITS_IN_OUT)-1);
+ flag.bits.bytes = (UINT16)(m_bytes);
+ char str[11];
+ sprintf(str, "0x%x", htonl(flag.all));
+ out << "\t\t\t" << str;
+
+ /*
+ * Add size of user-defined type to argument
+ */
+ if (m_code == rpc_USER_DEFINED) {
+ out << " + ntohs(sizeof(" << m_type_name << "))";
+ }
+
+ out << ", ";
+ if (deliver_pointer) {
+ /* Pass a pointer */
+ out << "&";
+ }
+ out << "v" << num;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+int
+Function::AppendArg(int code, int bytes, int is_pointer,
+ int is_vararray, int is_array_size,
+ const char *var_type_name, int in_out, const char *var_name) {
+ if (NumOfArgs() >= RPC_MAX_API_ARG_NUM) {
+ cout << "Too many API function arguments.\n";
+ return -1;
+ }
+ Arg *a = new Arg(code, bytes, is_pointer, is_vararray, is_array_size,
+ var_type_name, in_out, var_name);
+ m_args.push_back(*a);
+ delete a;
+ return 0;
+}
+
+/*
+ * Generate prototype declarations for a single API function
+ * out: Destination file
+ */
+int
+Function::PrintPrototype(fstream& out, int server) {
+ int ret = 0;
+
+ const char *return_type
+ = server ? RPC_API_SERVER_RETURN : RPC_API_CLIENT_RETURN;
+#ifdef DBG_ENABLE
+ if ((server) || (!rpc_log_enable)) {
+ out << return_type << " " << m_name << "(";
+ } else {
+ out << return_type << " __" << m_name << "(";
+ }
+#else
+ out << return_type << " " << m_name << "(";
+#endif
+
+ list<Arg>::size_type num_args = m_args.size();
+ if (num_args > 0) {
+ list<Arg>::iterator a;
+ a = m_args.begin();
+ for (list<Arg>::size_type i = 1; i <= num_args; ++i, ++a) {
+ a->PrintPrototype(out);
+#ifdef DBG_ENABLE
+ if ((server) || (!rpc_log_enable)) {
+ if (i != num_args) {
+ out << ", ";
+ }
+ } else {
+ out << ", ";
+ }
+#else
+ if (i != num_args) {
+ out << ", ";
+ }
+#endif
+ }
+ } else {
+#ifdef DBG_ENABLE
+ if ((server) || (!rpc_log_enable)) {
+ out << "void";
+ }
+#else
+ out << "void";
+#endif
+ }
+#ifdef DBG_ENABLE
+ /* Debug information */
+ if ((!server) && (rpc_log_enable)) {
+ out << "const char *filename, const char *funcname, int line ";
+ }
+#endif
+ out << ");\n";
+ return ret;
+}
+
+#ifdef DBG_ENABLE
+int
+Function::PrintMacro(fstream& out) {
+ int ret = 0;
+ out << "#define " << m_name << "(";
+
+ int num_args = m_args.size();
+ if (num_args > 0) {
+ int i;
+ char c;
+ for (i = 1, c = 'a'; i <= num_args; i++, c++) {
+ out << c;
+ if (i != num_args) {
+ out << ", ";
+ }
+ }
+ out << ") \\\n\t";
+
+ /* Entity */
+ out << "__" << m_name << "(";
+ for (i = 1, c = 'a'; i <= num_args; i++, c++) {
+ out << c << ", ";
+ }
+ out << "__FILE__, __func__, __LINE__)\n";
+ } else { /* Without arguments */
+ out << ") " << "__" << m_name << "(__FILE__, __func__, __LINE__)\n";
+ }
+
+ return ret;
+}
+#endif
+
+int
+APIDef::MakeHeaderFiles(int server) {
+ char filename[MAX_FILENAME_LEN+1];
+ sprintf(filename, "%s%s", m_lowerid.c_str(),
+ (server ? SERVER_HEADER_FILE : CLIENT_HEADER_FILE));
+ int ret = 0;
+
+ fstream out(filename, ios::out);
+ if (!out.is_open()) {
+ cout << "ERROR: File " << filename << " Could not open.\n";
+ return 1;
+ }
+ cout << "info: Header file " << filename << " Creating.\n";
+
+ const char *define_str =
+ server ? SERVER_HEADER_DEFINE : CLIENT_HEADER_DEFINE;
+ const char *title = server ? SERVER_HEADER_TITLE : CLIENT_HEADER_TITLE;
+
+ out << "#ifndef _" << m_lowerid << define_str << "\n";
+ out << "#define _" << m_lowerid << define_str << "\n";
+ out << "/*\n";
+ out << " * " << m_id << " " << title << " " << filename << "\n";
+ out << " *\n";
+ out << RPCTOOL_WARNING_STRING << "\n";
+ out << " */\n\n";
+
+ list<string>::iterator i;
+ for (i = m_headers.begin(); i != m_headers.end(); ++i) {
+ out << "#include <" << *i << ">\n";
+ }
+ out << "\n";
+
+ if (server) {
+
+ out << EXTERN_C_START << "\n";
+
+ out << RPC_API_DISPATCH_RETURN << " "
+ << m_id << RPC_API_DISPATCH_FUNC_FULL << ";\n";
+
+ out << "#ifdef RPC_DISPATCH_FUNC\n"
+ << "#undef RPC_DISPATCH_FUNC\n"
+ << "#define RPC_DISPATCH_FUNC " << m_id << RPC_API_DISPATCH_FUNC_NAME
+ << "\n#else /* !RPC_DISPATCH_FUNC */\n"
+ << "#error \"Please include <rpc.h> first!!\"\n"
+ << "#endif /* !RPC_DISPATCH_FUNC */\n\n";
+
+ out << EXTERN_C_END << "\n";
+
+ }
+#ifdef DBG_ENABLE
+ else if (rpc_log_enable) {
+ /* DEBUG INFORMATION EMBEDDED MACRO */
+ out << "/* Debug information embedded macro definition */\n";
+ list<Function>::iterator f;
+ for (f = m_funcs.begin(); f != m_funcs.end(); ++f) {
+ if (f->PrintMacro(out) != 0) {
+ ret = 1;
+ break;
+ }
+ }
+ out << "\n";
+ }
+#endif
+
+ out << EXTERN_C_START << "\n";
+
+ out << "/* API definitions */\n";
+ list<Function>::iterator f;
+ for (f = m_funcs.begin(); f != m_funcs.end(); ++f) {
+ if (f->PrintPrototype(out, server) != 0) {
+ ret = 1;
+ break;
+ }
+ }
+ out << "\n";
+
+ out << EXTERN_C_END << "\n";
+
+ out << "#endif /* _" << m_lowerid << define_str << " */\n";
+ out.close();
+ return ret;
+}
+
+int
+Function::PrintServerStub(fstream& out) {
+ int num_args = NumOfArgs();
+
+ out << "\tcase " << RPC_API_NUM_PREFIX << m_name << ": {\n";
+
+ list<Arg>::iterator a = m_args.begin();
+ for (int i = 1; i <= num_args; ++i, ++a) {
+ const char *type = TypeCodeString(a->Code());
+ if (type == NULL) {
+ type = (a->TypeName()).c_str();
+ }
+ if (type == NULL) {
+ return 1;
+ }
+ out << "\t\t" << type << " ";
+ if (a->Bytes() > 0 || a->IsPointer()) {/* Pointer-passing argument */
+ if (a->Bytes() > 0) {
+ out << "v" << i << " = NULL;\n";
+ } else if (a->IsPointer()) {
+ out << "*v" << i << " = NULL;\n";
+ }
+ } else {/* Pass-by-value argument */
+ out << "v" << i << ";\n";
+ }
+ }
+ if (num_args > 0) {
+ out << "\t\tif (" << RPC_DEMARSHALL_FUNCTION
+ << " (args_string, args_size, 1, " << num_args << ",\n";
+ /* In the STUB of servers for all pre-call demarshall */
+ /* Passing Pointers to Local Variables in Server STUB */
+ /* Pointer/ Buffer will alloc the required space in demarshall_arguments() */
+
+ a = m_args.begin();
+ for (int i = 1; i <= num_args; ++i, ++a) {
+ if (a->IsVararray() != 0) { /* Variable-length arrays */
+ a->CreateDemarshallArgs(out, 1, i, m_array_size_name);
+ } else {
+ a->CreateDemarshallArgs(out, 1, i);
+ }
+ if (i < num_args) {
+ out << ",";
+ }
+ out << "\n";
+ }
+ out << "\t\t ) < 0) {\n";
+ out << "\t\t\tgoto _" << m_name << "_Error;\n";
+ out << "\t\t}\n";
+ }
+
+ out << "\t\tresult = " << m_name << "(";
+ for (int i = 1; i <= num_args; i++) {
+ out << "v" << i;
+ if (i < num_args) {
+ out << ", ";
+ }
+ }
+ out << ");\n";
+
+ int to_process = NumOfInOutArgs(RPC_OUT_ARG);
+ if (to_process > 0) {
+ /* Only OUT-arguments marshall after the server stub is called. */
+ out << "\t\t/*if (result == RPC_OK) {*/\n";
+ out << "\t\t *ret_string = " << RPC_MARSHALL_FUNCTION
+ << "(ret_size, 0, " << to_process << ",\n";
+
+ a = m_args.begin();
+ int processed = 0;
+ int ret;
+ for (int i = 1; i <= num_args; ++i, ++a) {
+ if (a->IsVararray() != 0) { /* Variable-length arrays */
+ ret = a->CreateMarshallArgs(out, i, RPC_OUT_ARG, m_array_size_name);
+ } else {
+ ret = a->CreateMarshallArgs(out, i, RPC_OUT_ARG);
+ }
+ if (ret) {
+ processed++;
+ if (processed < to_process) {
+ out << ",";
+ }
+ out << "\n";
+ }
+ }
+ out << "\t\t );\n"
+ << "\t\t if (*ret_string == NULL) {\n"
+ << "\t\t\tresult = " << RPC_API_SERVER_ERROR << ";\n"
+ << "\t\t }\n"
+ << "\t\t/*}*/\n";
+ }
+
+ if (num_args > 0) {
+ out << "_" << m_name << "_Error:\n";
+ }
+ int num_pointer_args = 0;
+ a = m_args.begin();
+ for (int i = 1; i <= num_args; ++i, ++a) {
+ if (a->Bytes() || a->IsPointer()) {
+ num_pointer_args++;
+ }
+ }
+ if (num_pointer_args > 0) {
+ int processed = 0;
+ out << "\t\t" << RPC_MARSHALL_FREE_FUNCTION
+ << "(" << num_pointer_args << ", ";
+ a = m_args.begin();
+ for (int i = 1; i <= num_args; ++i, ++a) {
+ if (a->Bytes() || a->IsPointer()) {
+ out << "v" << i;
+ processed++;
+ if (processed < num_pointer_args) {
+ out << ", ";
+ }
+ }
+ }
+ out << ");\n";
+ }
+ out << "\t\tbreak;\n\t}\n";
+ return 0;
+}
+
+int
+APIDef::MakeServerStub(void) {
+ char filename[MAX_FILENAME_LEN+1];
+ sprintf(filename, "%s%s", m_lowerid.c_str(), SERVER_STUB_FILE);
+ int ret = 0;
+
+ fstream out(filename, ios::out);
+ if (!out.is_open()) {
+ cout << "File " << filename << " Could not open.\n";
+ return 1;
+ }
+ cout << "info: Stub file " << filename << " Creating.\n";
+
+ const char *title = SERVER_STUB_TITLE;
+
+ out << "/*\n";
+ out << " * " << m_id << " " << title << " " << filename << "\n";
+ out << " *\n";
+ out << RPCTOOL_WARNING_STRING << "\n";
+ out << " */\n";
+ out << "#include <" RPC_GLOBAL_HEADER_FILE << ">\n";
+ out << "#include \"" << m_lowerid << SERVER_HEADER_FILE << "\"\n";
+ out << "#include <netinet/in.h> /* for ntohs() */\n\n";
+
+ int api_num = 1;
+ list<Function>::iterator f;
+
+ for (f = m_funcs.begin(); f != m_funcs.end(); ++f, ++api_num) {
+ if (api_num >= (1<<16)) {
+ cout << "Too many API functions.(Up to 65535)\n";
+ return 1;
+ }
+ out << "#define " << RPC_API_NUM_PREFIX << f->Name()
+ << " " << api_num << "\n";
+ }
+ out << "\n";
+
+ out << "RPC_Result\n";
+ out << m_id << RPC_API_DISPATCH_FUNC_FULL << "\n";
+ out << "{\n";
+ out << "\tRPC_Result result = " << RPC_API_SERVER_ERROR << ";\n";
+ out << "\t*ret_string = NULL;\n";
+ out << "\tswitch(api_num) {\n";
+
+ for (f = m_funcs.begin(); f != m_funcs.end(); ++f) {
+ if (f->PrintServerStub(out) != 0) {
+ ret = 1;
+ break;
+ }
+ }
+
+ if (ret != 0) {
+ return ret;
+ }
+
+ out << "\tdefault:\n\t\tbreak;\n\t}\n";
+ out << "\treturn result;\n";
+ out << "}\n";
+
+ return ret;
+}
+
+int
+Function::PrintClientStub(const char *moduleid, fstream& out) {
+ int ret = 0;
+
+ list<Arg>::iterator a;
+ /* Function Names and Arguments */
+ out << RPC_API_CLIENT_RETURN << "\n";
+#ifdef DBG_ENABLE
+ if (rpc_log_enable) {
+ out << "__" << m_name << "(";
+ } else {
+ out << m_name << "(";
+ }
+#else
+ out << m_name << "(";
+#endif
+ int num_args = (int)(m_args.size());
+ if (num_args > 0) {
+ a = m_args.begin();
+ for (int i = 1; i <= num_args; ++i, ++a) {
+ if (a->PrintPrototype(out, i)) {
+ return 1;
+ }
+#ifdef DBG_ENABLE
+ if (rpc_log_enable) {
+ out << ", ";
+ } else {
+ if (i < num_args) {
+ out << ", ";
+ }
+ }
+#else
+ if (i < num_args) {
+ out << ", ";
+ }
+#endif
+ }
+ } else {
+#ifndef DBG_ENABLE
+ out << "void";
+#else
+ if (!rpc_log_enable) {
+ out << "void";
+ }
+#endif
+ }
+#ifdef DBG_ENABLE
+ if (rpc_log_enable) {
+ out << "const char *filename, const char *funcname, int line ";
+ }
+#endif
+ out << ")\n";
+
+ out << "{\n";
+
+ /* Contents of stub functions */
+
+ /* If the argument is present and the variable-length array does not exist */
+ if ((num_args > 0) && (m_array_size_pos == 0)) {
+ int is_exist_mytype = 0;
+ /* Restricted specifications */
+ out << "#ifdef RPC_STATIC_ASSERT\n";
+ out << "\tchar RPC_TOTAL_ARGSIZE_ERROR_in_" << m_name << "[\n";
+ out << "\t(((";
+ a = m_args.begin();
+ for (int i = 1; i <= num_args; ++i, ++a) {
+ if (i > 1) {
+ out << " + ";
+ }
+ out << "sizeof(";
+ a->PrintUndecoratedName(out, i);
+ out << ")";
+ /* For user types */
+ if ((!is_exist_mytype) && (NULL == TypeCodeString(a->Code()))) {
+ is_exist_mytype = 1;
+ }
+ }
+ out << ") > RPC_MAX_API_ARG_TOTAL_SIZE) ? -1: 1)\n";
+ out << "\t]__attribute__((unused));\n";
+
+ /* Have a user type */
+ if (is_exist_mytype) {
+ char c[3];
+ a = m_args.begin();
+ for (int i = 1; i <= num_args; ++i, ++a) {
+ if (NULL == TypeCodeString(a->Code())) {
+ sprintf(c, "%d", i);
+ out << "\tchar RPC_ARGSIZE_ERROR_in_" << m_name << "_arg" << c;
+ out << "[\n\t(sizeof(";
+ a->PrintUndecoratedName(out, i);
+ out << ") > RPC_MAX_API_ARG_SIZE) ? -1: 1\n";
+ out << "\t]__attribute__((unused));\n";
+ }
+ }
+ }
+
+ out << "#endif /* RPC_STATIC_ASSERT */\n";
+
+ }
+
+ out << "\tRPC_Result result = " << RPC_API_CLIENT_ERROR << ";\n";
+ out << "\tunsigned int args_size = 0, ret_size;\n";
+ out << "\tchar retcode[9];\n";
+
+ if (num_args > 0) {
+ /* Advance preparation==Marshalling of arguments */
+ out << "\tchar *args_string = " << RPC_MARSHALL_FUNCTION
+ << "(&args_size, 1, " << num_args << ",\n";
+ /* In the clients STUB for all pre-call marshall */
+ a = m_args.begin();
+ for (int i = 1; i <= num_args; ++i, ++a) {
+ if (a->IsVararray() != 0) { /* Variable-length arrays */
+ a->CreateMarshallArgs(out, i, m_array_size_name);
+ } else {
+ a->CreateMarshallArgs(out, i);
+ }
+ if (i < num_args) {
+ out << ",";
+ }
+ out << "\n";
+ }
+ out << "\t);\n";
+ out << "\tif (args_string == NULL) {\n"
+ << "\t\tgoto _" << m_name << "_Error;\n\t}\n";
+ } else {
+ out << "\tchar *args_string = NULL;\n";
+ }
+
+#ifdef DBG_ENABLE
+ if (rpc_log_enable) {
+ out << "\tif (" << moduleid << "_record_dbg_log(filename, funcname, line, \"";
+ out << m_name << "\") != 0) {\n";
+ out << "\t\tgoto _" << m_name << "_Error;\n\t}\n";
+ }
+#endif
+
+ /* RPC API call */
+ out << "\tchar *ret_string = NULL; /* pgr0431 */\n";
+#ifdef RPC_STRING_ID
+ out << "\tresult=RPC_API_call(\"" << moduleid << "\", ";
+#else
+ out << "\tresult=RPC_API_call(" << moduleid << "_RPC_ID, ";
+#endif
+ out << RPC_API_NUM_PREFIX << m_name;
+ out << ", args_string, args_size, &ret_string, &ret_size);\n";
+
+ // 2007.08.25 To avoid over run within the sscanf
+ // Locally copies strings needed for determining return values and uses strtol instead of sscanf
+ // (Since there is no guarantee that the byte sequence to be grabbed by communication is 0-terminated)
+ out << "\n"
+ << "\tif (result == RPC_OK && ret_string != NULL) {\n"
+ << "\t strncpy(retcode, ret_string, 8);\n"
+ << "\t retcode[8] = '\\0';\n"
+ << "\t result = (RPC_Result)strtoul(retcode, NULL, 16);\n";
+
+ /* Post-processing==Arguments de-marshalling, free() */
+ int num_of_out_args = NumOfInOutArgs(RPC_OUT_ARG);
+ if (num_of_out_args > 0) {
+ out << "\t if (" << RPC_DEMARSHALL_FUNCTION
+ << "(ret_string + RPC_RETCODE_LEN, ret_size - RPC_RETCODE_LEN, 0, "
+ << num_of_out_args << ",\n";
+
+ a = m_args.begin();
+ int processed = 0;
+ int ret;
+ for (int i = 1; i <= num_args; ++i, ++a) {
+ if (a->IsVararray() != 0) { /* Variable-length arrays */
+ ret = a->CreateDemarshallArgs(out, 0, i, RPC_OUT_ARG, m_array_size_name);
+ } else {
+ ret = a->CreateDemarshallArgs(out, 0, i, RPC_OUT_ARG);
+ }
+ if (ret) {
+ processed++;
+ if (processed < num_of_out_args) {
+ out << ",";
+ }
+ out << "\n";
+ }
+ }
+ out << "\t ) < 0) {\n"
+ << "\t\tresult = " << RPC_API_CLIENT_ERROR << ";\n"
+ << "\t }\n";
+ }
+
+ out << "\t} else {\n\t //result = " << RPC_API_CLIENT_ERROR << ";\n"
+ << "\t}\n";
+
+ out << "\t" << RPC_RETURN_FREE_FUNCTION << "(ret_string);\n";
+ out << "\t" << RPC_MARSHALL_FREE_FUNCTION << "(1, args_string);\n";
+
+ /* END, RETURN */
+#ifndef DBG_ENABLE
+ if (num_args)
+#else
+ if ((num_args)||(rpc_log_enable))
+#endif
+ {
+ out << "_" << m_name << "_Error:\n";
+ }
+
+ out << "\treturn result;\n}\n";
+
+ return ret;
+}
+
+int
+APIDef::MakeClientStub(void) {
+ char filename[MAX_FILENAME_LEN+1];
+ sprintf(filename, "%s%s", m_lowerid.c_str(), CLIENT_STUB_FILE);
+ int ret = 0;
+
+ fstream out(filename, ios::out);
+ if (!out.is_open()) {
+ cout << "File " << filename << " Could not open.\n";
+ return 1;
+ }
+ cout << "info: Stub file " << filename << " Creating.\n";
+
+ const char *title = CLIENT_STUB_TITLE;
+
+ out << "/*\n";
+ out << " * " << m_id << " " << title << " " << filename << "\n";
+ out << " *\n";
+ out << RPCTOOL_WARNING_STRING << "\n";
+ out << " */\n";
+ out << "#include <" RPC_GLOBAL_HEADER_FILE << ">\n";
+ out << "#include <" << m_lowerid << CLIENT_HEADER_FILE << ">\n\n";
+ out << "#include <stdio.h> /* for sscanf() */\n";
+ out << "#include <stdlib.h> /* for getenv() */\n";
+ out << "#include <string.h> /* for strncpy() */\n";
+ out << "#include <netinet/in.h> /* for ntohs() */\n\n";
+
+ int api_num = 1;
+ list<Function>::iterator f;
+ for (f = m_funcs.begin(); f != m_funcs.end(); ++f, ++api_num) {
+ if (api_num >= (1<<16)) {
+ cout << "Too many API functions.(Up to 65535)\n";
+ return 1;
+ }
+ out << "#define " << RPC_API_NUM_PREFIX << f->Name()
+ << " " << api_num << "\n";
+ }
+ out << "\n";
+
+ /* Specification Restriction Debug Constants */
+ out << "/*#define RPC_STATIC_ASSERT*/\n";
+ out << "\n";
+
+#ifdef DBG_ENABLE
+ if (rpc_log_enable) {
+ int m_id_work_cnt;
+ string m_id_work = m_id;
+ for (m_id_work_cnt = 0; m_id_work_cnt < m_id_work.length(); m_id_work_cnt++) {
+ m_id_work[m_id_work_cnt] = toupper(m_id_work[m_id_work_cnt]);
+ }
+ out << "int\n" << m_id << "_record_dbg_log(const char *filename, " <<
+ "const char *funcname, int line, const char *apiname)\n";
+ out << "{\n\t";
+ out << "if (getenv(\"" << m_id_work << "_RPC_LOG\") != NULL) {\n\t\t";
+ out << "return RPC_record_dbg_log(filename, funcname, line, apiname);\n\t";
+ out << "}\n\t";
+ out << "return 0;\n";
+ out << "}\n\n";
+ }
+#endif
+
+ /* API definitions */
+ for (f = m_funcs.begin(); f != m_funcs.end(); ++f) {
+ if (f->PrintClientStub(m_id.c_str(), out) != 0) {
+ ret = 1;
+ break;
+ }
+ }
+ return ret;
+}
+
+int
+Arg::IsArraySize(void) {
+ if (m_is_array_size != 0) {
+ if (IsTypeCodeNumeric(m_code) == 1) {
+ return 1;
+ } else {
+ cout << "Variable-length array length specification variables must be integers.\n";
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int
+Function::CheckFuncArraySize(void) {
+ int num_args = (int)(m_args.size());
+ list<Arg>::iterator a;
+ a = m_args.begin();
+ for (int i = 1; i <= num_args; ++i, ++a) {
+ int ret = a->IsArraySize();
+ if (ret > 0) {
+ if (m_array_size_pos != 0)
+ {
+ cout << "Two or more variable array length specification arguments exist.\n";
+ return 1;
+ }
+ m_array_size_pos = i;
+ a->GetUndecolatedName(m_array_size_name, i);
+ } else if (ret < 0) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int
+APIDef::CheckAllArraySize(void) {
+ list<Function>::iterator f;
+ for (f = m_funcs.begin(); f != m_funcs.end(); ++f) {
+ if (f->CheckFuncArraySize() != 0) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int
+APIDef::MakeStubs(void) {
+ if (m_id.size() == 0) {
+ cout << "The module name is not specified.\n";
+ return 1;
+ }
+
+ if (m_id.size() > MAX_FILENAME_LEN - strlen(SERVER_STUB_FILE)) {
+ cout << "The module name is too long.\n";
+ return 1;
+ }
+
+ /* Pre-examine the ARRAYSIZE specification */
+ //cout << "<check_all_array_size>\n";
+ if (CheckAllArraySize() != 0) {
+ return 1;
+ }
+
+ //cout << "<MakeHeaderFiles(0)>\n";
+ if (MakeHeaderFiles(1) != 0) {
+ return 1;
+ }
+
+ //cout << "<MakeHeaderFiles(1)>\n";
+ if (MakeHeaderFiles(0) != 0) {
+ return 1;
+ }
+
+ if (MakeServerStub() != 0) {
+ return 1;
+ }
+
+ if (MakeClientStub() != 0) {
+ return 1;
+ }
+
+ return 0;
+}
+
+void
+Arg::Print(void) {
+ cout << "\t";
+ if (m_name.size() > 0) {
+ cout << "Variable name=" << m_name << " ";
+ }
+ cout << "Type=" << TypeCodeString(m_code) << "In bytes=" << m_bytes << " ";
+ if (m_is_pointer) {
+ cout << "Pointer ";
+ }
+ if ((m_in_out & RPC_OUT_ARG) != 0) {
+ cout << "Output ";
+ }
+ cout << "\n";
+}
+
+void
+Function::Print(int with_args) {
+ printf("Function name=%s\n", m_name.c_str());
+ if (with_args) {
+ list<Arg>::iterator a;
+ for (a = m_args.begin(); a != m_args.end(); ++a) {
+ a->Print();
+ }
+ }
+}
+
+void
+APIDef::Print(int with_args) {
+ list<Function>::iterator f;
+ for (f = m_funcs.begin(); f != m_funcs.end(); ++f) {
+ f->Print(with_args);
+ }
+}
+
+void
+APIDef::IdTolower(void) {
+ char *lower = new char[m_id.size() + 1];
+ strcpy(lower, m_id.c_str());
+ char *p;
+ for (p = lower; *p; p++) {
+ *p = (char)(tolower(*p));
+ }
+ m_lowerid = lower;
+ delete[] lower;
+}
diff --git a/rpc_library/tool/apidef.h b/rpc_library/tool/apidef.h
new file mode 100644
index 00000000..a73fc49c
--- /dev/null
+++ b/rpc_library/tool/apidef.h
@@ -0,0 +1,333 @@
+/*
+ * @copyright Copyright (c) 2016-2019 TOYOTA MOTOR CORPORATION.
+ *
+ * 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.
+ */
+
+/**
+ * @file apidef.h
+ * @brief RPC tools--Function/macro definitions and APIDef class definitions
+ */
+/** @addtogroup RPCtool
+ *
+ * @brief Using the RPC Tool (rpc_apidef)
+ *
+ * rpc_apidef [CPP option...] API definition file name
+ *
+ * - CPP option
+ * The RPC tool calls the C preprocessor (CPP) internally
+ * for processing comments and #if directives.
+ * Here, you can specify options to be given to the CPP, such as symbol definitions
+ * for conditional branch descriptions in the API definition file.
+ * - API definition file name
+ * Pathname to the API definition file.
+ * The file name must be thread ID + ".api".
+ *
+ * The output file is as follows.
+ * "*" is a lowercase version of the API definition file name preceding ".api".
+ * - *_api.h(Client header files)
+ * - *_api_stub.c(Client stub file)
+ * - *_srvr.h(Server header file)
+ * - *_srvr_stub.c(Server stub file)
+ *
+ * Examples:
+ * - Examples1: rpc_apidef -DTEST XXX.api
+ * - Examples2: rpc_apidef XXX.api
+ * - => Xxx_api.h, xxx_api_stub.c, ... To the output
+ */
+#ifndef RPC_LIBRARY_TOOL_APIDEF_H_
+#define RPC_LIBRARY_TOOL_APIDEF_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#ifdef DBG_ENABLE
+extern char rpc_log_enable;
+#endif
+
+/* C++ to C I/F functions */
+const char *TypeCodeString(const int code);
+int IsTypeCodeNumeric(const int code);
+
+/*
+ * C to C++ I/F functions (APIDef class)
+ */
+void ApidefDefineId(const char *id);
+void ApidefAddHeader(const char *filename);
+int ApidefPushFunctionArg(int arg_code, int buffer_bytes, int is_pointer,
+ int is_vararray, int is_array_size,
+ const char *var_type_name, int in_out,
+ const char *var_name);
+void ApidefProcessFunction(const char *funcname);
+void ApidefListFunctions(int with_args);
+void ApidefFreeAllocation(void);
+int ApidefMakeStubs(void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#define RPC_IN_ARG 0x01
+#define RPC_OUT_ARG 0x02
+#define RPC_INOUT_ARG (RPC_IN_ARG|RPC_OUT_ARG)
+
+#define MAX_FILENAME_LEN 63
+#define SERVER_HEADER_FILE "_srvr.h"
+#define CLIENT_HEADER_FILE "_api.h"
+#define SERVER_STUB_FILE "_srvr_stub.c"
+#define CLIENT_STUB_FILE "_api_stub.c"
+#define SERVER_HEADER_DEFINE "_srvr_h_"
+#define CLIENT_HEADER_DEFINE "_api_h_"
+
+#define SERVER_HEADER_TITLE "Server header files"
+#define CLIENT_HEADER_TITLE "Client header files"
+#define SERVER_STUB_TITLE "Server stub file"
+#define CLIENT_STUB_TITLE "Client stub file"
+
+#define RPC_MARSHALL_FUNCTION "RPC_marshall_arguments"
+#define RPC_DEMARSHALL_FUNCTION "RPC_demarshall_arguments"
+#define RPC_MARSHALL_FREE_FUNCTION "RPC_marshall_free"
+#define RPC_RETURN_FREE_FUNCTION "RPC_free_return_string"
+
+#define RPC_API_SERVER_RETURN "RPC_Result"
+#define RPC_API_SERVER_ERROR "RPC_ERR_Fatal"
+#define RPC_API_CLIENT_RETURN "RPC_Result"
+#define RPC_API_CLIENT_ERROR "RPC_ERR_Fatal"
+#define RPC_API_DISPATCH_TYPE "RPC_dispatch_func_t"
+#define RPC_API_DISPATCH_RETURN "RPC_Result"
+#define RPC_API_DISPATCH_FUNC_FULL "_API_dispatch(UINT16 api_num, const char *args_string, unsigned int args_size, char **ret_string, unsigned int *ret_size)" // NOLINT (readability/nolint)
+#define RPC_API_DISPATCH_FUNC_NAME "_API_dispatch"
+#define RPC_API_NUM_PREFIX "RPC_API_NUM_"
+#define RPC_GLOBAL_HEADER_FILE "other_service/rpc.h"
+
+#define RPCTOOL_WARNING_STRING \
+" * The file created by the RPC tool.This file should not be edited."
+
+#define EXTERN_C_START \
+"#ifdef __cplusplus\n" \
+"extern \"C\" {\n" \
+"#endif\n"
+
+#define EXTERN_C_END \
+"#ifdef __cplusplus\n" \
+"}\n" \
+"#endif /* __cplusplus */\n"
+
+#ifdef __cplusplus
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <list>
+
+using namespace std; // NOLINT (readability/nolint)
+
+/** @ingroup RPCtool
+ * @class Arg
+ * @brief Class that stores and processes the arguments of functions read from the API definition file
+ */
+class Arg {
+ protected:
+ int m_code;
+ int m_bytes;
+ int m_is_pointer;
+ int m_in_out; /* Bit OR of _IN_ARG and _OUT_ARG */
+ int m_is_vararray;
+ int m_is_array_size;
+ string m_type_name;
+ string m_name;
+
+ public:
+ Arg() {
+ m_code = m_bytes = m_is_pointer = m_in_out = m_is_vararray = m_is_array_size = 0;
+ }
+ Arg(int code, int bytes, int is_pointer,
+ int is_vararray, int is_array_size,
+ const char *type_name, int in_out,
+ const char *var_name) {
+ m_code = code;
+ m_bytes = bytes;
+ m_is_pointer = is_pointer;
+ m_is_vararray = is_vararray;
+ m_is_array_size = is_array_size;
+ m_in_out = in_out;
+ if (type_name) {
+ m_type_name = type_name;
+ }
+ if (var_name) {
+ m_name = var_name;
+ }
+ }
+ ~Arg() {}
+
+ int Code(void) { return m_code; }
+ int Bytes(void) { return m_bytes; }
+ int IsPointer(void) { return m_is_pointer; }
+ int InOut(void) { return m_in_out; }
+ string& TypeName(void) { return m_type_name; }
+ void GetUndecolatedName(string& name, int num); // NOLINT (readability/nolint)
+
+ int PrintUndecoratedName(fstream& out, int num);
+ int PrintPrototype(fstream& out, int num);
+ int PrintPrototype(fstream& out) { return PrintPrototype(out, 0); }
+
+ int CreateMarshallArgs(fstream& out, int num);
+ int CreateMarshallArgs(fstream& out, int num, string &array_size_name); // NOLINT (readability/nolint)
+ int CreateMarshallArgs(fstream& out, int num, int in_out);
+ int CreateMarshallArgs(fstream& out, int num, int in_out, string &array_size_name); // NOLINT (readability/nolint)
+ int CreateDemarshallArgs(fstream& out, int deliver_pointer, int num);
+ int CreateDemarshallArgs(fstream& out, int deliver_pointer, int num, string &array_size_name); // NOLINT (readability/nolint)
+ int CreateDemarshallArgs(fstream& out, int deliver_pointer, int num, int in_out);
+ int CreateDemarshallArgs(fstream& out, int deliver_pointer, int num, int in_out, string &array_size_name); // NOLINT (readability/nolint)
+
+ int IsVararray(void) { return m_is_vararray; }
+ int IsArraySize(void);
+ void Print(void);
+};
+
+/** @ingroup RPCtool
+ * @class Function
+ * @brief Class that stores and processes function definitions read from the API definition file
+ */
+class Function {
+ protected:
+ string m_name;
+ list<Arg> m_args;
+ int m_array_size_pos;
+ string m_array_size_name;
+
+ public:
+ Function():m_array_size_name("") { m_array_size_pos = 0; }
+ ~Function() {
+ list<Arg>::size_type size = m_args.size();
+ for (list<Arg>::size_type i = 0 ; i < size ; i++) {
+ m_args.begin();
+ m_args.pop_front();
+ }
+ }
+
+ const char *Name(void) { return m_name.c_str(); }
+ void SetName(const char *funcname) {
+ m_name = funcname;
+ }
+
+ int NumOfArgs(void) {
+ return (int)(m_args.size()); // NOLINT (readability/nolint)
+ }
+ int NumOfInOutArgs(int in_out) {
+ int count = 0;
+ list<Arg>::iterator a;
+ for (a = m_args.begin(); a != m_args.end(); ++a) {
+ if ((a->InOut() & in_out) != 0) {
+ ++count;
+ }
+ }
+ return count;
+ }
+
+ int AppendArg(int code, int bytes, int is_pointer,
+ int is_vararray, int is_array_size,
+ const char *var_type_name, int in_out, const char *var_name);
+
+ int PrintPrototype(fstream& out);
+ int PrintPrototype(fstream& out, int server);
+#ifdef DBG_ENABLE
+ int PrintMacro(fstream& out);
+#endif
+
+ int PrintServerStub(fstream& out);
+ int PrintClientStub(const char *moduleid, fstream& out);
+
+ int CheckFuncArraySize(void);
+ void Print(int with_args);
+};
+
+/** @ingroup RPCtool
+ * @class APIDef
+ * @brief Class that stores and processes the result of reading the API definition file
+ */
+class APIDef {
+ protected:
+ list<Function> m_funcs;
+ Function *m_work;
+ string m_id;
+ string m_lowerid;
+ list<string> m_headers;
+
+ public:
+ APIDef() { m_work = 0; }
+ ~APIDef() {
+ list<Function>::size_type size = m_funcs.size();
+ for (list<Function>::size_type i = 0; i < size; i++) {
+ m_funcs.begin();
+ m_funcs.pop_front();
+ }
+ if (m_work != NULL) {
+ delete m_work;
+ }
+ size = m_headers.size();
+ for (list<Function>::size_type i = 0; i < size; i++) {
+ m_headers.begin();
+ m_headers.pop_front();
+ }
+ }
+
+ void IdTolower(void);
+ void DefineId(const char *id) {
+ m_id = id;
+ IdTolower();
+ }
+ void AddHeader(const char *filename) {
+ string str = filename;
+ m_headers.push_back(str);
+ }
+
+ int AddFunctionArg(int arg_code, int buffer_bytes, int is_pointer,
+ int is_vararray, int is_array_size,
+ const char *var_type_name, int in_out,
+ const char *var_name) {
+ if (m_work == NULL) {
+ m_work = new Function();
+ }
+ return m_work->AppendArg(arg_code, buffer_bytes, is_pointer,
+ is_vararray, is_array_size,
+ var_type_name, in_out, var_name);
+ }
+ void NameFunction(const char *funcname) {
+ if (m_work == NULL) {
+ m_work = new Function();
+ }
+ m_work->SetName(funcname);
+
+ AppendFunction(m_work);
+ delete m_work;
+ m_work = NULL;
+ }
+
+ void AppendFunction(Function *pfunc) {
+ m_funcs.push_back(*pfunc);
+ }
+
+ int CheckAllArraySize(void);
+
+ int MakeStubs(void);
+ void Print(int with_args);
+
+ private:
+ int MakeHeaderFiles(int server);
+ int MakeServerStub(void);
+ int MakeClientStub(void);
+};
+#endif /* __cplusplus */
+
+#endif // RPC_LIBRARY_TOOL_APIDEF_H_
diff --git a/rpc_library/tool/apidef.l b/rpc_library/tool/apidef.l
new file mode 100644
index 00000000..c2f246a2
--- /dev/null
+++ b/rpc_library/tool/apidef.l
@@ -0,0 +1,136 @@
+/**
+ * @file apidef.l
+ * @brief RPC tools--Defining lexical analysis rules for API definition files
+ *
+ */
+/** @ingroup RPCtool
+ * Defining Lexical Analysis Rules for Use with RPC Tools (apidef)
+ */
+%{
+#include <string.h>
+#include <stdlib.h>
+#include "apidef.tab.h"
+%}
+
+ALPHA [A-Za-z_]
+ALPHANUM [0-9\-A-Za-z_]
+ALPHANUMDOT [0-9.\-A-Za-z_/]
+
+%x include
+%s apidef
+%x str_num
+
+%%
+INCLUDE { BEGIN(include); return rpc_INCLUDE; }
+<include>\< { return '<'; }
+<include>{ALPHANUMDOT}+ {
+ yylval.strval = malloc(strlen(yytext)+1);
+ strcpy(yylval.strval, yytext);
+ return rpc_NAME_DOT;
+ }
+<include>\> { BEGIN(INITIAL); return '>'; }
+<include>. /* ignore */
+
+RPC_Result { BEGIN(apidef); return RPC_RESULT; }
+
+<apidef>STRING/[0-9]+ { BEGIN(str_num);
+ yylval.ival = rpc_STRING; return rpc_STRING; }
+<str_num>[0-9]+ {
+ BEGIN(apidef);
+ sscanf(yytext, "%d", &yylval.ival);
+ return rpc_NUM;
+ }
+<str_num>. /* ignore */
+
+<apidef>{
+char { yylval.ival = rpc_CHAR; return rpc_CHAR; }
+int { yylval.ival = rpc_INT; return rpc_INT; }
+signed[ \t\n]+int { yylval.ival = rpc_SINT; return rpc_SINT; }
+unsigned[ \t\n]+int { yylval.ival = rpc_UINT; return rpc_UINT; }
+INT8 { yylval.ival = rpc_INT8; return rpc_INT8; }
+INT16 { yylval.ival = rpc_INT16; return rpc_INT16; }
+INT32 { yylval.ival = rpc_INT32; return rpc_INT32; }
+INT64 { yylval.ival = rpc_INT64; return rpc_INT64; }
+UINT8 { yylval.ival = rpc_UINT8; return rpc_UINT8; }
+UINT16 { yylval.ival = rpc_UINT16; return rpc_UINT16; }
+UINT32 { yylval.ival = rpc_UINT32; return rpc_UINT32; }
+UINT64 { yylval.ival = rpc_UINT64; return rpc_UINT64; }
+float { yylval.ival = rpc_FLOAT; return rpc_FLOAT; }
+double { yylval.ival = rpc_DOUBLE; return rpc_DOUBLE; }
+void { yylval.ival = rpc_VOID; return rpc_VOID; }
+IN {
+ fprintf(stderr,
+ "Specification change: IN Pointer argument needs to be prefixed \"const\" instead of \"IN\".\n"
+ );
+ return rpc_UNKNOWN;
+ }
+OUT {
+ fprintf(stderr,
+ "Specification change: OUT argument no longer needs to be prefixed with \"OUT\".\n"
+ );
+ /* ignore */
+ }
+INOUT { yylval.ival = rpc_INOUT; return rpc_INOUT; }
+const { yylval.ival = rpc_CONST; return rpc_CONST; }
+VARARRAY { yylval.ival = rpc_VARARRAY; return rpc_VARARRAY; }
+ARRAYSIZE { yylval.ival = rpc_ARRAYSIZE; return rpc_ARRAYSIZE; }
+
+{ALPHA}+{ALPHANUM}* {
+ yylval.strval = malloc(strlen(yytext)+1);
+ strcpy(yylval.strval, yytext);
+ return rpc_NAME;
+ }
+
+\( { return '('; }
+\) { return ')'; }
+\* { return '*'; }
+, { return ','; }
+\; { BEGIN(INITIAL); return ';'; }
+
+} /* end of <apidef> */
+
+#.*\n /* ignore CPP directives */
+
+{ALPHANUMDOT}+ {
+ fprintf(stderr, "Unknown keyword %s\n", yytext);
+ return rpc_UNKNOWN;
+ }
+
+[ \t\n]+ /* eat up whitespace */
+
+%%
+#ifdef OLD_STUFFS
+%x portdef
+%x addr_num
+PORT { BEGIN(portdef); return DEFINE_PORT; }
+<portdef>[0-9]+ {
+ BEGIN(INITIAL);
+ sscanf(yytext, "%d", &yylval.ival);
+ return NUM;
+ }
+
+<apidef>ADDR/[0-9]+ { BEGIN(addr_num); yylval.ival = _ADDR; return _ADDR; }
+<addr_num>[0-9]+ {
+ BEGIN(apidef);
+ sscanf(yytext, "%d", &yylval.ival);
+ return NUM;
+ }
+#endif
+
+/*
+ * function to free the buffer which flex allocates but not frees
+ */
+void
+free_flex_buffer(void)
+{
+ yy_delete_buffer(YY_CURRENT_BUFFER);
+}
+
+/*
+ * dummy function to avoid a warning of not using 'yyunput'
+ */
+void
+dummy(void)
+{
+ yyunput(0, 0);
+}
diff --git a/rpc_library/tool/apidef.y b/rpc_library/tool/apidef.y
new file mode 100644
index 00000000..ce20c9c1
--- /dev/null
+++ b/rpc_library/tool/apidef.y
@@ -0,0 +1,615 @@
+/**
+ * @file apidef.y
+ * @brief RPC tools--API definition file syntax definition and read/front-end processing
+ *
+ */
+
+/*---------------------------------------------------------------------------*/
+/* C declarative statement */
+/*---------------------------------------------------------------------------*/
+%{
+#define YYDEBUG 1
+#define YYERROR_VERBOSE 1
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/*
+ * YACC to C I/F functions
+ */
+extern int yylex(void); /* LEX I/F */
+extern int yyerror(const char *); /* dummy */
+
+#include "apidef.h"
+
+/* YACC to C I/F functions */
+static void AddHeader(const char *header_file);
+static int push_function_arg(int arg_type, int num_of_bytes,
+ int is_pointer,
+ int is_vararray, int is_array_size,
+ const char *var_type_name,
+ int is_out, const char *var_name);
+static void process_function(const char *funcname);
+static void free_string(char *funcname);
+
+static int var_type;
+static int num_of_bytes;
+static int is_pointer;
+static int in_out;
+static int is_vararray;
+static int is_array_size;
+static char *var_type_name = NULL;
+
+%}
+
+/*---------------------------------------------------------------------------*/
+/* Bison declarations */
+/*---------------------------------------------------------------------------*/
+%union {
+ int ival;
+ char *strval;
+}
+
+%token '"'
+%left ','
+%left '('
+%right ')'
+%left '*'
+%token '{'
+%token '}'
+%token ';'
+%token '\n'
+%token <strval> rpc_INCLUDE 257
+%token <strval> RPC_RESULT 258
+%token <strval> rpc_NAME_DOT 259
+%token <strval> rpc_NAME 260
+%type <strval> funcdefs funcdef args
+%type <strval> nonvoid_args arg var_type
+%type <strval> var_primitive_type var_string_type var_user_defined_type
+/*
+%token <strval> rpc_OUT
+*/
+%token <strval> rpc_INOUT 261
+%token <strval> rpc_CONST 262
+%token <strval> rpc_VARARRAY 263
+%token <strval> rpc_ARRAYSIZE 264
+%token <ival> rpc_NUM 265
+%token <strval> rpc_VOID 266
+%token <ival> rpc_CHAR 267
+%token <ival> rpc_INT 268
+%token <ival> rpc_SINT 269
+%token <ival> rpc_UINT 270
+%token <ival> rpc_INT8 271
+%token <ival> rpc_INT16 272
+%token <ival> rpc_INT32 273
+%token <ival> rpc_INT64 274
+%token <ival> rpc_UINT8 275
+%token <ival> rpc_UINT16 276
+%token <ival> rpc_UINT32 277
+%token <ival> rpc_UINT64 278
+%token <ival> rpc_FLOAT 279
+%token <ival> rpc_DOUBLE 280
+%token <ival> rpc_STRING 281
+%token <ival> rpc_USER_DEFINED 282
+%token <ival> rpc_UNKNOWN 283
+
+/*---------------------------------------------------------------------------*/
+/* Grammar rule */
+/*---------------------------------------------------------------------------*/
+%%
+input: includes funcdefs
+;
+
+includes: /* empty input */
+ | includes include
+;
+
+include: rpc_INCLUDE '<' rpc_NAME_DOT '>'
+ { AddHeader($3); free_string($3); }
+;
+
+funcdefs: funcdef
+ | funcdefs funcdef
+;
+
+funcdef: RPC_RESULT rpc_NAME '(' args ')' ';'
+ { process_function($2); free_string($2);}
+;
+
+args: rpc_VOID
+ | nonvoid_args
+;
+
+nonvoid_args: arg
+ | nonvoid_args ',' arg
+;
+
+arg: var_type rpc_NAME
+ {
+ if (push_function_arg(var_type, num_of_bytes, is_pointer,
+ is_vararray, is_array_size,
+ var_type_name, in_out, $2) < 0) {
+ YYERROR;
+ }
+ if (var_type_name) { free_string(var_type_name); }
+ var_type_name = NULL;
+ free_string($2);
+ }
+ | var_type
+ {
+ if (push_function_arg(var_type, num_of_bytes, is_pointer,
+ is_vararray, is_array_size,
+ var_type_name, in_out, NULL) < 0) {
+ YYERROR;
+ }
+ if (var_type_name) { free_string(var_type_name); }
+ var_type_name = NULL;
+ }
+;
+
+/*
+ * Standard IN pointers are not allowed.
+ * When used as an array address, it is not clear how many bytes to copy.
+ * ->You are asked to declare the type and pass the address.
+ * Otherwise, you can simply pass it by value.
+ */
+var_type: var_primitive_type /* INT8, .. DOUBLE */
+ { is_pointer = 0; is_vararray = 0; is_array_size = 0; in_out =RPC_IN_ARG; }
+ | var_primitive_type '*' /* OUT INT8 *, ... OUT DOUBLE * */
+ { is_pointer = 1; is_vararray = 0; is_array_size = 0; in_out = RPC_OUT_ARG; }
+ /* if allow primitive IN pointer
+ | rpc_CONST var_primitive_type '*'
+ { is_pointer = 1; in_out = RPC_IN_ARG; }
+ */
+ | var_string_type
+ /* OUT STRING128, ... */
+ { is_pointer = 1; is_vararray = 0; is_array_size = 0; in_out = RPC_OUT_ARG; }
+ | rpc_CONST var_string_type
+ /* IN STRING128, ... */
+ { is_pointer = 1; is_vararray = 0; is_array_size = 0; in_out = RPC_IN_ARG; }
+ | var_user_defined_type
+ { is_pointer = 0; is_vararray = 0; is_array_size = 0; in_out = RPC_IN_ARG; }
+ | var_user_defined_type '*'
+ { is_pointer = 1; is_vararray = 0; is_array_size = 0; in_out = RPC_OUT_ARG; }
+ | rpc_CONST var_user_defined_type '*'
+ { is_pointer = 1; is_vararray = 0; is_array_size = 0; in_out = RPC_IN_ARG; }
+
+ /* INOUT specification */
+ | rpc_INOUT var_string_type
+ /* IN STRING128, ... */
+ { is_pointer = 1; is_vararray = 0; is_array_size = 0; in_out = RPC_INOUT_ARG; }
+ | rpc_INOUT var_user_defined_type '*'
+ { is_pointer = 1; is_vararray = 0; is_array_size = 0; in_out = RPC_INOUT_ARG; }
+
+ /* Variable-length arrays */
+ | rpc_CONST rpc_VARARRAY var_primitive_type '*'
+ { is_pointer = 1; is_vararray = 1; is_array_size = 0; in_out = RPC_IN_ARG; }
+ | rpc_VARARRAY var_primitive_type '*'
+ { is_pointer = 1; is_vararray = 1; is_array_size = 0; in_out = RPC_OUT_ARG; }
+ | rpc_INOUT rpc_VARARRAY var_primitive_type '*'
+ { is_pointer = 1; is_vararray = 1; is_array_size = 0; in_out = RPC_INOUT_ARG; }
+ | rpc_CONST rpc_VARARRAY var_user_defined_type '*'
+ { is_pointer = 1; is_vararray = 1; is_array_size = 0; in_out = RPC_IN_ARG; }
+ | rpc_VARARRAY var_user_defined_type '*'
+ { is_pointer = 1; is_vararray = 1; is_array_size = 0; in_out = RPC_OUT_ARG; }
+ | rpc_INOUT rpc_VARARRAY var_user_defined_type '*'
+ { is_pointer = 1; is_vararray = 1; is_array_size = 0; in_out = RPC_INOUT_ARG; }
+
+ /* Variable length array size */
+ | rpc_ARRAYSIZE var_primitive_type
+ { is_pointer = 0; is_vararray = 0; is_array_size = 1; in_out = RPC_IN_ARG; }
+;
+
+var_primitive_type:
+ rpc_CHAR { var_type = $1; num_of_bytes = 0; var_type_name = NULL; }
+ | rpc_INT { var_type = $1; num_of_bytes = 0; var_type_name = NULL; }
+ | rpc_SINT { var_type = $1; num_of_bytes = 0; var_type_name = NULL; }
+ | rpc_UINT { var_type = $1; num_of_bytes = 0; var_type_name = NULL; }
+ | rpc_INT8 { var_type = $1; num_of_bytes = 0; var_type_name = NULL; }
+ | rpc_UINT8 { var_type = $1; num_of_bytes = 0; var_type_name = NULL; }
+ | rpc_INT16 { var_type = $1; num_of_bytes = 0; var_type_name = NULL; }
+ | rpc_UINT16 { var_type = $1; num_of_bytes = 0; var_type_name = NULL; }
+ | rpc_INT32 { var_type = $1; num_of_bytes = 0; var_type_name = NULL; }
+ | rpc_UINT32 { var_type = $1; num_of_bytes = 0; var_type_name = NULL; }
+ | rpc_INT64 { var_type = $1; num_of_bytes = 0; var_type_name = NULL; }
+ | rpc_UINT64 { var_type = $1; num_of_bytes = 0; var_type_name = NULL; }
+ | rpc_FLOAT { var_type = $1; num_of_bytes = 0; var_type_name = NULL; }
+ | rpc_DOUBLE { var_type = $1; num_of_bytes = 0; var_type_name = NULL; }
+;
+
+var_string_type: rpc_STRING rpc_NUM
+ { var_type = $1; num_of_bytes = $2; var_type_name = NULL; }
+;
+
+var_user_defined_type: rpc_NAME
+ { var_type = rpc_USER_DEFINED; num_of_bytes = 0; var_type_name = $1; }
+;
+
+%%
+
+/*---------------------------------------------------------------------------*/
+/* C additional code */
+/*---------------------------------------------------------------------------*/
+/* Including an older bison results in an error */
+/*#include "apidef.tab.h"*/
+
+#include <unistd.h>
+#include <assert.h>
+#include <string.h>
+/*
+ * YACC/Lex interface functions/variables
+ */
+extern int yydebug; /* for YACC debug */
+extern int yyparse(void);
+extern FILE *yyin;
+extern int yy_flex_debug; /* for FLEX debug */
+/* my own function to free the buffer flex allocates */
+extern void free_flex_buffer(void);
+
+#ifdef DBG_ENABLE
+char rpc_log_enable;
+#endif
+
+/**/
+static void
+AddHeader(const char *filename)
+{
+ ApidefAddHeader(filename);
+}
+
+static int
+push_function_arg(int arg_type, int num_of_bytes, int is_pointer,
+ int is_vararray, int is_array_size,
+ const char *var_type_name, int in_out, const char *var_name)
+{
+ switch(arg_type) {
+ case rpc_CHAR:
+ case rpc_INT:
+ case rpc_SINT:
+ case rpc_UINT:
+ case rpc_INT8:
+ case rpc_INT16:
+ case rpc_INT32:
+ case rpc_INT64:
+ case rpc_UINT8:
+ case rpc_UINT16:
+ case rpc_UINT32:
+ case rpc_UINT64:
+ case rpc_FLOAT:
+ case rpc_DOUBLE:
+ case rpc_STRING:
+ case rpc_USER_DEFINED:
+ return ApidefPushFunctionArg(arg_type, num_of_bytes, is_pointer,
+ is_vararray, is_array_size,
+ var_type_name, in_out, var_name);
+ break;
+
+ default:
+ return -1;
+ break;
+ }
+}
+
+static void
+process_function(const char *funcname)
+{
+ ApidefProcessFunction(funcname);
+}
+
+static void
+free_string(char *s)
+{
+#ifdef DEBUG
+ fprintf(stderr, "freed %s\n", s);
+#endif
+ free(s);
+}
+
+static void
+extract_id(const char *filename, char **id)
+{
+ char *dotapi;
+ char *slash;
+ const char *start;
+
+ if (id == NULL) {
+ return;
+ }
+ dotapi = strrchr(filename, '.');
+ if (dotapi == NULL) {
+ return;
+ }
+ if (strcmp(dotapi, ".api")) {
+ return;
+ }
+
+ slash = strrchr(filename, '/');
+ start = filename;
+ if (slash != NULL) {
+ start = slash + 1;
+ }
+
+ *id = malloc((size_t)(dotapi - start + 1));
+ if (*id == NULL) {
+ return;
+ }
+ strncpy(*id, start, (size_t)(dotapi - start));
+ (*id)[dotapi - start] = '\0';
+}
+
+static void
+usage(const char *prog)
+{
+ fprintf(stdout,
+ "How to use: %s [CPPFLAGS] ... API definition file name\n",
+ prog);
+ fprintf(stdout, "Examples1: %s XXX.api\n", prog);
+ fprintf(stdout, "Examples2: %s -DSOME_DEFINES XXX.api\n", prog);
+}
+
+#define CPP_PROG "cpp"
+static void free_cpp_argv(char **argv);
+
+static char **
+prepare_cpp_argv(int argc, char *argv[])
+{
+ char **cpp_argv;
+ char **ret;
+
+ cpp_argv = malloc(sizeof(char *) * (long unsigned int)(argc+1));
+ if (cpp_argv == NULL) {
+ return NULL;
+ }
+ memset(cpp_argv, 0, sizeof(char *) * (long unsigned int)(argc+1));
+ ret = cpp_argv;
+
+ cpp_argv[0] = malloc(strlen(CPP_PROG)+1);
+ if (cpp_argv[0] == NULL) {
+ free_cpp_argv(ret);
+ return NULL;
+ }
+ strcpy(cpp_argv[0], CPP_PROG);
+ cpp_argv++;
+
+ for( ; *argv != NULL ; argv++, cpp_argv++) {
+ *cpp_argv = malloc(strlen(*argv)+1);
+ if (*cpp_argv == NULL) {
+ free_cpp_argv(ret);
+ return NULL;
+ }
+ strcpy(*cpp_argv, *argv);
+ }
+ *cpp_argv = NULL;
+ return ret;
+}
+
+static void
+free_cpp_argv(char **argv)
+{
+ char **orig; orig = argv;
+ while(*argv != NULL) {
+ free(*argv);
+ argv++;
+ }
+ free(orig);
+}
+
+/** @ingroup RPCtool
+ * @brief RPCtool main functions
+ *
+ * Perform the following processing.
+ *
+ * - Lexical context analysis of the API definition file(See apidef.y and apidef.l)
+ * - The API function definition read from the definition file is stored in the APIDef class.
+ * - Outputs stub and header files from function definitions stored in APIDef after a successful read
+ */
+int
+main(int argc, char *argv[])
+{
+ int start;
+ char **cpp_argv;
+ int pipefd[2];
+ int pid;
+ int ret;
+
+ if (argc < 2) {
+ usage(argv[0]);
+ return 1;
+ }
+
+ start = 1;
+ yy_flex_debug = 0;
+
+ if (!strcmp(argv[1], "-d")) {
+ yydebug=1;
+ yy_flex_debug = 1;
+ if (argc > 2) {
+ start++;
+ } else {
+ usage(argv[0]);
+ return 1;
+ }
+ }
+
+#ifdef DBG_ENABLE
+ /*
+ * If the second-to-last argument is a log specification
+ */
+ if ( ( argc >= 2 ) && (!strcmp(argv[argc-2], "-log")) ) {
+ rpc_log_enable = 1;
+ } else {
+ rpc_log_enable = 0;
+ }
+#endif
+
+ /*
+ * Extract ID from last argument (API definition file name)
+ */
+ {
+ char *moduleid;
+ moduleid = NULL;
+ extract_id(argv[argc-1], &moduleid);
+ if (moduleid == NULL) {
+ fprintf(stdout, "%s: The API definition file name is invalid.\n", argv[0]);
+ usage(argv[0]);
+ return 1;
+ }
+ ApidefDefineId(moduleid);
+ free(moduleid);
+ }
+
+ /*
+ * Preparing options to exec CPPs
+ */
+ cpp_argv = prepare_cpp_argv(argc, argv + start);
+ if (cpp_argv == NULL) {
+ printf("No Memory!\n");
+ return 1;
+ }
+
+#define PIPE_READ 0
+#define PIPE_WRITE 1
+
+ if (pipe(pipefd) != 0) {
+ perror("pipe");
+ return 1;
+ }
+
+ pid = fork();
+ if (pid < 0) {/* fork error */
+ close(pipefd[PIPE_READ]);
+ close(pipefd[PIPE_WRITE]);
+ perror("fork");
+ return 1;
+ }
+ if (pid == 0) {/* child process */
+ int must_be_1;
+ /*
+ * force stdout to be pipefd[PIPE_WRITE]
+ */
+ close(pipefd[PIPE_READ]);
+ close(1);
+ must_be_1 = dup(pipefd[PIPE_WRITE]);
+ assert(must_be_1 == 1);
+ close(pipefd[PIPE_WRITE]);
+ /*
+ * invoke C preprocessor with flags
+ */
+ execvp(CPP_PROG, cpp_argv);
+ perror("execvp");
+ exit(0);
+ } else {
+ /*
+ * parent process
+ */
+ int must_be_0;
+ free_cpp_argv(cpp_argv);
+
+ /*
+ * force stdin to be pipefd[PIPE_READ]
+ */
+ close(pipefd[PIPE_WRITE]);
+ close(0);
+ must_be_0 = dup(pipefd[PIPE_READ]);
+ assert(must_be_0 == 0);
+ close(pipefd[PIPE_READ]);
+ }
+
+ ret = yyparse();
+
+ free_flex_buffer();
+
+ if (ret == 0) {/* Parsed successfully */
+ //ApidefListFunctions(1);
+ ApidefMakeStubs();
+ } else {/* Parse error occurred */
+ fputs("The APIs that have been analyzed so far are as follows.\n", stdout);
+ fputs("-----start-----\n", stdout);
+ ApidefListFunctions(0);
+ fputs("------end------\n", stdout);
+ fputs("Check this API definition\n", stdout);
+ }
+ ApidefFreeAllocation();
+
+ return ret;
+}
+
+int
+yyerror(const char *s)
+{
+ printf("\nError: %s\n", s);
+ return 0;
+}
+
+int
+yywrap()
+{
+ return 1;
+}
+
+static char const *Types[] = {
+ "char",
+ "int",
+ "signed int",
+ "unsigned int",
+ "INT8",
+ "INT16",
+ "INT32",
+ "INT64",
+ "UINT8",
+ "UINT16",
+ "UINT32",
+ "UINT64",
+ "float",
+ "double",
+ "char *",
+};
+
+static const int TypeCodes[] = {
+ rpc_CHAR,
+ rpc_INT,
+ rpc_SINT,
+ rpc_UINT,
+ rpc_INT8,
+ rpc_INT16,
+ rpc_INT32,
+ rpc_INT64,
+ rpc_UINT8,
+ rpc_UINT16,
+ rpc_UINT32,
+ rpc_UINT64,
+ rpc_FLOAT,
+ rpc_DOUBLE,
+ rpc_STRING,
+};
+
+const char *
+TypeCodeString(const int code)
+{
+ int i;
+ int num;
+ num = sizeof(TypeCodes) / sizeof(int);
+
+ for(i = 0 ; i < num ; i++) {
+ if (code == TypeCodes[i]) {
+ return Types[i];
+ }
+ }
+ return NULL;
+}
+
+int
+IsTypeCodeNumeric( const int code )
+{
+ int i;
+
+ for(i = 0 ; i < sizeof(TypeCodes) / sizeof(TypeCodes[0]) ; i++) {
+ if (TypeCodes[i] == rpc_FLOAT) {
+ break;
+ }
+ if (code == TypeCodes[i]) {
+ return 1;
+ }
+ }
+ return 0;
+}
diff --git a/rpc_library/tool_for_arm/Makefile b/rpc_library/tool_for_arm/Makefile
new file mode 100644
index 00000000..100d6299
--- /dev/null
+++ b/rpc_library/tool_for_arm/Makefile
@@ -0,0 +1,50 @@
+#
+# @copyright Copyright (c) 2016-2019 TOYOTA MOTOR CORPORATION.
+#
+# 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.
+#
+
+all test: apidef.tab.h
+
+clean:
+ rm -rf $(CLEAN_FILES)
+
+YACC := bison
+YFLAGS := -d -t
+
+VPATH += ../tool
+CPPFLAGS += -I../tool
+OUTPUTDIR += ../tool
+
+apidef.tab.h apidef.tab.c: apidef.y
+ cd ../tool; $(YACC) $(YFLAGS) $<
+
+CLEAN_FILES := ../tool/apidef.tab.h ../tool/apidef.tab.c
+
+CLEAN_TARGET := clean-test clean-all clean-all-test \
+clean-self clean-self-test clean-all-sub clean-self-sub #comment out for make clean errorclean-sub
+
+EMPTY_TARGET := install-test build-lib build-prog build-shlib build-arlib \
+build-test-mock-lib build-test-mock-arlib build-test-mock-shlib build-cfg \
+install install-header install-test-mock-header install-test-casename install-lib \
+install-shlib install-arlib install-prog install-data install-cfg install-preload
+
+
+.PHONY: all install test clean $(CLEAN_TARGET) $(EMPTY_TARGET)
+
+$(CLEAN_TARGET): clean
+
+$(EMPTY_TARGET):
+
+
+include ../../other_service.mk