From: YoungHun Kim Date: Mon, 6 Jul 2015 11:38:06 +0000 (+0900) Subject: Initial release X-Git-Tag: accepted/tizen/mobile/20150713.060807~3 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fheads%2Fmaster;p=platform%2Fcore%2Fmultimedia%2Fmmsvc-core.git Initial release Change-Id: Ibbb9e47dee247eef0d0f1d583722a79c986d4f89 --- diff --git a/AUTHORS b/AUTHORS new file mode 100755 index 0000000..48abac3 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,3 @@ +YoungHun Kim +Hee Chul Jeon +JongHyuk Choi diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100755 index 0000000..ef20cae --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,118 @@ + +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +SET(fw_name "mused") + +PROJECT(${fw_name}) + +SET(SRCS + src/mmsvc_core.c + src/mmsvc_core_config.c + src/mmsvc_core_ipc.c + src/mmsvc_core_log.c + src/mmsvc_core_module.c + src/mmsvc_core_msg_json.c + src/mmsvc_core_tool.c + src/mmsvc_core_workqueue.c + ) +SET(SRC-SERVER + src/mmsvc_core_server.c + ) + +SET(CMAKE_INSTALL_PREFIX /usr) +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) + +SET(BINDIR "${PREFIX}/bin") +SET(INC_DIR include) +INCLUDE_DIRECTORIES(${INC_DIR}) + +SET(dependents "dlog json-c glib-2.0 mm-common gmodule-2.0 iniparser") +SET(pc_dependents "dlog mm-common") + +INCLUDE(FindPkgConfig) +pkg_check_modules(${fw_name} REQUIRED ${dependents}) +FOREACH(flag ${${fw_name}_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(CMAKE_C_FLAGS "-I./include ${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIC -Wall -Werror -std=gnu99") +SET(CMAKE_C_FLAGS_DEBUG "-O0 -g") + +IF("${ARCH}" STREQUAL "arm") + ADD_DEFINITIONS("-DTARGET") +ENDIF("${ARCH}" STREQUAL "arm") + +ADD_DEFINITIONS("-DPREFIX=\"${CMAKE_INSTALL_PREFIX}\"") +ADD_DEFINITIONS("-DTIZEN_DEBUG") + +SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=/usr/lib") + +aux_source_directory(src SOURCES) +#ADD_LIBRARY(${fw_name} SHARED ${SOURCES}) +ADD_LIBRARY(${fw_name} SHARED ${SRCS}) + +TARGET_LINK_LIBRARIES(${fw_name} ${${fw_name}_LDFLAGS}) + +SET_TARGET_PROPERTIES(${fw_name} + PROPERTIES + VERSION ${FULLVER} + SOVERSION ${MAJORVER} + CLEAN_DIRECT_OUTPUT 1 +) + +ADD_EXECUTABLE(mused-server ${SRC-SERVER}) +TARGET_LINK_LIBRARIES(mused-server ${pkgs_LDFLAGS} ${fw_name} ${CMAKE_DL_LIBS}) +INSTALL(TARGETS mused-server DESTINATION ${BINDIR}) + +INSTALL(TARGETS ${fw_name} DESTINATION lib) +INSTALL( + DIRECTORY ${INC_DIR}/ DESTINATION include/media + FILES_MATCHING + PATTERN "*_private.h" EXCLUDE + PATTERN "${INC_DIR}/*.h" + ) + +SET(PC_NAME ${fw_name}) +SET(PC_REQUIRED ${pc_dependents}) +SET(PC_LDFLAGS -l${fw_name}) +SET(PC_CFLAGS -I\${includedir}/media) + +CONFIGURE_FILE( + ${fw_name}.pc.in + ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc + ${CMAKE_CURRENT_SOURCE_DIR}/config/${fw_name}.conf + @ONLY +) +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc DESTINATION lib/pkgconfig) +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/config/${fw_name}.conf DESTINATION /usr/share/${fw_name}) + +IF(UNIX) + +ADD_CUSTOM_TARGET (distclean @echo cleaning for source distribution) +ADD_CUSTOM_COMMAND( + DEPENDS clean + COMMENT "distribution clean" + COMMAND find + ARGS . + -not -name config.cmake -and \( + -name tester.c -or + -name Testing -or + -name CMakeFiles -or + -name cmake.depends -or + -name cmake.check_depends -or + -name CMakeCache.txt -or + -name cmake.check_cache -or + -name *.cmake -or + -name Makefile -or + -name core -or + -name core.* -or + -name gmon.out -or + -name install_manifest.txt -or + -name *.pc -or + -name *~ \) + | grep -v TC | xargs rm -rf + TARGET distclean + VERBATIM +) + +ENDIF(UNIX) + diff --git a/LICENSE.APLv2 b/LICENSE.APLv2 new file mode 100755 index 0000000..bbe9d02 --- /dev/null +++ b/LICENSE.APLv2 @@ -0,0 +1,206 @@ +Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + + 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 + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. + + + diff --git a/NOTICE b/NOTICE new file mode 100755 index 0000000..ccdad52 --- /dev/null +++ b/NOTICE @@ -0,0 +1,3 @@ +Copyright (c) Samsung Electronics Co., Ltd. All rights reserved. +Except as noted, this software is licensed under Apache License, Version 2. +Please, see the LICENSE file for Apache License terms and conditions. diff --git a/config/mused.conf b/config/mused.conf new file mode 100644 index 0000000..0369b22 --- /dev/null +++ b/config/mused.conf @@ -0,0 +1,21 @@ +[mused] +; The 'hosts' parameter defines the modules, +; which the user would like to connect to the museD. +hosts=player, camera, recorder +logfile=/var/log/mused.log + +[player] +; The 'player' parameter represents the mused-player. +; This module recovers the "capi-media-player". +path=/usr/lib/libmused-player.so + +[camera] +; The 'camera' parameter represents the mused-camera. +; This module recovers the "capi-media-camera". +path=/usr/lib/libmused-camera.so + +[recorder] +; The 'recorder' parameter represents the mused-recorder. +; This module recovers the "capi-media-recorder". +; This one should be paired with the 'camera' module. +path=/usr/lib/libmused-recorder.so diff --git a/include/mmsvc_core.h b/include/mmsvc_core.h new file mode 100644 index 0000000..fbdd71a --- /dev/null +++ b/include/mmsvc_core.h @@ -0,0 +1,49 @@ +/* + * mmsvc-core + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: YoungHun Kim + * + * 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 __MMSVC_CORE_H__ +#define __MMSVC_CORE_H__ + +#ifdef _cplusplus +extern "C" { +#endif + +#define MM_URI_MAX_LENGTH 100 +#define MM_MSG_MAX_LENGTH 1024*1024 + +typedef struct __Client * Client; + +int mmsvc_core_run(); +void mmsvc_core_connection_close(int sock_fd); +int mmsvc_core_client_new(void); +int mmsvc_core_client_new_data_ch(void); +int mmsvc_core_client_get_msg_fd(Client client); +int mmsvc_core_client_get_data_fd(Client client); +void mmsvc_core_client_set_cust_data(Client client, void *data); +void *mmsvc_core_client_get_cust_data(Client client); +char *mmsvc_core_client_get_msg(Client client); +int mmsvc_core_client_get_capi(Client client); +void mmsvc_core_worker_exit(Client client); + +#ifdef __cplusplus +} +#endif +#endif /*__MMSVC_CORE_H__*/ diff --git a/include/mmsvc_core_config.h b/include/mmsvc_core_config.h new file mode 100644 index 0000000..882d82e --- /dev/null +++ b/include/mmsvc_core_config.h @@ -0,0 +1,62 @@ +/* + * mmsvc-core + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: YoungHun Kim + * + * 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 __MMSVC_CORE_CONFIG_H__ +#define __MMSVC_CORE_CONFIG_H__ + +#ifdef _cplusplus +extern "C" { +#endif + +#include + +#define CONFFILE "/usr/share/mused/mused.conf" +#define HOST_MAX_COUNT 1024 +#define MUSEDHOST "mused:hosts" +#define MUSEDLOG "mused:logfile" +#define COLON ":" +#define COMMA "," +#define PATH "path" + +typedef struct host_info +{ + char *path; +} host_info_t; + +typedef struct config +{ + char *hosts; + int type; + char *logfile; + host_info_t *host_infos[HOST_MAX_COUNT]; + dictionary *mmsvc_dict; + void (*free)(void); + char* (*get_path)(int); +} config_t; + +/*mmsvc_core_config_init must be called before mmsvc_core_config_get_instance*/ +config_t *mmsvc_core_config_get_instance(void); +void mmsvc_core_config_init(void); + +#ifdef __cplusplus +} +#endif +#endif /* __MMSVC_CORE_CONFIG_H__ */ diff --git a/include/mmsvc_core_internal.h b/include/mmsvc_core_internal.h new file mode 100644 index 0000000..ad6afaa --- /dev/null +++ b/include/mmsvc_core_internal.h @@ -0,0 +1,87 @@ +/* + * mmsvc-core + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: YoungHun Kim + * + * 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 __MMSVC_CORE_INTERNAL_H__ +#define __MMSVC_CORE_INTERNAL_H__ + +#ifdef _cplusplus +extern "C" { +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef LOG_TAG +#define LOG_TAG "TIZEN_N_MUSED" +#define MUSED_DIR "/var/run/mused" +#define LOGFILE "/tmp/mmsvc_core_log" +#define LOCKFILE "/tmp/.mmsvc-core.lock" +#define SOCKFILE0 "/tmp/mmsvc_core_socket" +#define SOCKFILE1 "/tmp/mmsvc_core_data_socket" + +#define TIMEOUT 0x01 +/** Wait for a socket or FD to become readable */ +#define READ 0x02 +/** Wait for a socket or FD to become writeable */ +#define WRITE 0x04 +/** Wait for a POSIX signal to be raised*/ +#define SIGNAL 0x08 +#define PERSIST 0x10 +/** Select edge-triggered behavior, if supported by the backend. */ +#define EDGETRIGGERED 0x20 + +#define DISPATCHER "dispatcher" +#define MMSVC_FREE(src) { if(src) {g_free(src); src = NULL;} } + +#ifdef __cplusplus +} +#endif +#endif /*__MMSVC_CORE_INTERNAL_H__*/ diff --git a/include/mmsvc_core_ipc.h b/include/mmsvc_core_ipc.h new file mode 100644 index 0000000..e417ba2 --- /dev/null +++ b/include/mmsvc_core_ipc.h @@ -0,0 +1,73 @@ +/* + * mmsvc-core + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: YoungHun Kim + * + * 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 __MMSVC_CORE_IPC_H__ +#define __MMSVC_CORE_IPC_H__ + +#ifdef _cplusplus +extern "C" { +#endif + +#include "mmsvc_core.h" +#include "mmsvc_core_workqueue.h" + +#define MUSED_DATA_HEAD 0xda1a6ead + +typedef enum { + API_CREATE, + API_DESTROY, + API_MAX +} api_type_e; + +gboolean mmsvc_core_ipc_job_function(struct mmsvc_core_workqueue_job * job); +int mmsvc_core_ipc_send_msg(int sock_fd, const char *msg); +int mmsvc_core_ipc_recv_msg(int sock_fd, char *msg); + +gboolean mmsvc_core_ipc_data_job_function(mmsvc_core_workqueue_job_t * job); +int mmsvc_core_ipc_push_data(int sock_fd, const char *data, int size, int data_id); +char *mmsvc_core_ipc_get_data(Client client); +void mmsvc_core_ipc_delete_data(char *data); + +/** + * @brief Create and send address of server side client infomation structure. + * @remarks Does NOT guarantee thread safe. + * @param[in] client The server side client infomation. + * @param[in] fd socket fd + */ +#define mmsvc_core_send_client_addr(client, fd) \ + do{ \ + char *__sndMsg__; \ + int __len__; \ + __sndMsg__ = mmsvc_core_msg_json_factory_new(0, #client, client, \ + 0); \ + __len__ = mmsvc_core_ipc_send_msg(fd, __sndMsg__); \ + mmsvc_core_msg_json_factory_free(__sndMsg__); \ + if (__len__ <= 0) { \ + LOGE("sending message failed"); \ + return PLAYER_ERROR_INVALID_OPERATION; \ + } \ + }while(0) + + +#ifdef _cplusplus +} +#endif + +#endif /*__MMSVC_CORE_IPC_H__*/ diff --git a/include/mmsvc_core_log.h b/include/mmsvc_core_log.h new file mode 100755 index 0000000..929c25f --- /dev/null +++ b/include/mmsvc_core_log.h @@ -0,0 +1,57 @@ +/* + * mmsvc-core + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: YoungHun Kim + * + * 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 __MMSVC_CORE_LOG_H__ +#define __MMSVC_CORE_LOG_H__ + +#ifdef _cplusplus +extern "C" { +#endif + +#include +#include +#include "mmsvc_core_msg_json.h" + +typedef struct mmsvc_core_log { + int type; + unsigned refs; + char *buf; + size_t len; + int log_fd; + int count; + GTimer *timer; + void (*log)(char *); + void (*fatal)(char *); + void (*set_module_value) (int, GModule *, gboolean); + gboolean (*get_module_opened) (int); + GModule* (*get_module_value) (int); + gboolean module_opened[MMSVC_CLIENT_MAX]; + GModule *module[MMSVC_CLIENT_MAX]; +} mmsvc_core_log_t; + +/*mmsvc_core_log_init must be called before mmsvc_core_log_get_instance*/ +mmsvc_core_log_t *mmsvc_core_log_get_instance(void); +void mmsvc_core_log_init(void); + +#ifdef _cplusplus +} +#endif + +#endif /*__MMSVC_CORE_LOG_H__*/ \ No newline at end of file diff --git a/include/mmsvc_core_module.h b/include/mmsvc_core_module.h new file mode 100644 index 0000000..38d0642 --- /dev/null +++ b/include/mmsvc_core_module.h @@ -0,0 +1,41 @@ +/* + * mmsvc-core + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: YoungHun Kim + * + * 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 __MMSVC_CORE_MODULE_H__ +#define __MMSVC_CORE_MODULE_H__ + +#ifdef _cplusplus +extern "C" { +#endif + +#include "mmsvc_core.h" +#include "mmsvc_core_internal.h" + +typedef gboolean (*MMSVC_MODULE_DispatchFunc) (Client client); + +GModule * mmsvc_core_module_load(int api_client); +void mmsvc_core_module_dll_symbol(int cmd, Client client); +gboolean mmsvc_core_module_close(Client client); + +#ifdef _cplusplus +} +#endif + +#endif /*__MMSVC_CORE_MODULE_H__*/ diff --git a/include/mmsvc_core_msg_json.h b/include/mmsvc_core_msg_json.h new file mode 100644 index 0000000..dd23222 --- /dev/null +++ b/include/mmsvc_core_msg_json.h @@ -0,0 +1,62 @@ +/* + * mmsvc-core + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: YoungHun Kim + * + * 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 __MMSVC_CORE_MSG_JSON_H__ +#define __MMSVC_CORE_MSG_JSON_H__ + +#ifdef _cplusplus +extern "C" { +#endif + +#include + +typedef enum { + MMSVC_PLAYER, + MMSVC_CAMERA, + MMSVC_RECORDER, + MMSVC_CLIENT_MAX +} mmsvc_api_client_e; + +enum { + MUSED_TYPE_INT = 1, + MUSED_TYPE_DOUBLE, + MUSED_TYPE_STRING, + MUSED_TYPE_ARRAY, + MUSED_TYPE_MAX +}; + +typedef enum { + MUSED_MSG_PARSE_ERROR_NONE, + MUSED_MSG_PARSE_ERROR_CONTINUE, + MUSED_MSG_PARSE_ERROR_OTHER, + MUSED_MSG_PARSE_ERROR_MAX +} mused_msg_parse_err_e; + +char * mmsvc_core_msg_json_factory_new(int api, const char *arg_name, int arg, ...); +void mmsvc_core_msg_json_factory_free(char * msg); +gboolean mmsvc_core_msg_json_deserialize(char *key, char* buf, void *data, mused_msg_parse_err_e *err); +gboolean mmsvc_core_msg_json_deserialize_len(char *key, char* buf, int *parse_len, void *data, mused_msg_parse_err_e *err); + +#ifdef _cplusplus +} +#endif + +#endif /*__MMSVC_CORE_MSG_JSON_H__*/ diff --git a/include/mmsvc_core_private.h b/include/mmsvc_core_private.h new file mode 100644 index 0000000..65e7ff7 --- /dev/null +++ b/include/mmsvc_core_private.h @@ -0,0 +1,77 @@ +/* + * mmsvc-core + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: YoungHun Kim + * + * 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 __MMSVC_CORE_PRIVATE_H__ +#define __MMSVC_CORE_PRIVATE_H__ + +#include +#include + +#ifdef _cplusplus +extern "C" { +#endif + +typedef gboolean(*MMSVC_CORE_ClientCallback) (GIOChannel * source, GIOCondition condition, gpointer data); + +typedef enum { + MUSED_CHANNEL_MSG, + MUSED_CHANNEL_DATA, + MUSED_CHANNEL_MAX +} mused_channel_e; + +typedef struct { + GThread * p_gthread; + int fd; + union { + GModule *module; + struct { + GQueue *queue; + GMutex mutex; + GCond cond; + }; + }; +} channel_info; + +typedef struct __Client{ + channel_info ch[MUSED_CHANNEL_MAX]; + char recvMsg[MM_MSG_MAX_LENGTH]; + int msg_offset; + int api_client; + gpointer cust_data; +} _Client; + +typedef struct { + int fd; + int data_fd; + int type; + int stop; + int retval; + gint running; +} MMServer; + +gpointer mmsvc_core_main_loop(gpointer data); +MMServer *mmsvc_core_new(); +gboolean mmsvc_core_connection_handler(GIOChannel * source, GIOCondition condition, gpointer data); + +#ifdef __cplusplus +} +#endif +#endif /*__MMSVC_CORE_PRIVATE_H__*/ diff --git a/include/mmsvc_core_tool.h b/include/mmsvc_core_tool.h new file mode 100755 index 0000000..5400060 --- /dev/null +++ b/include/mmsvc_core_tool.h @@ -0,0 +1,35 @@ +/* + * mmsvc-core + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: YoungHun Kim + * + * 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 __MMSVC_CORE_TOOL_H__ +#define __MMSVC_CORE_TOOL_H__ + +#ifdef _cplusplus +extern "C" { +#endif + +void mmsvc_core_tool_parse_params(int argc, char **argv); +void mmsvc_core_tool_recursive_rmdir(const char *path); + +#ifdef _cplusplus +} +#endif + +#endif /*__MMSVC_CORE_TOOL_H__*/ diff --git a/include/mmsvc_core_workqueue.h b/include/mmsvc_core_workqueue.h new file mode 100644 index 0000000..655b11f --- /dev/null +++ b/include/mmsvc_core_workqueue.h @@ -0,0 +1,48 @@ +/** +* Multithreaded work queue. +* Copyright (c) 2012 Ronald Bennett Cemer +* This software is licensed under the BSD license. +* See the accompanying LICENSE.txt for details. +*/ + +#ifndef __MMSVC_CORE_WORKQUEUE_H__ +#define __MMSVC_CORE_WORKQUEUE_H__ + +#ifdef _cplusplus +extern "C" { +#endif + +#include "mmsvc_core_internal.h" +#include "mmsvc_core_log.h" + +typedef struct mmsvc_core_workqueue_job { + gboolean(*job_function) (struct mmsvc_core_workqueue_job * job); + void *user_data; + struct mmsvc_core_workqueue_job *prev; + struct mmsvc_core_workqueue_job *next; +} mmsvc_core_workqueue_job_t; + +typedef struct mmsvc_core_workqueue_workqueue { + struct mmsvc_core_workqueue_worker *workers; + struct mmsvc_core_workqueue_job *waiting_jobs; + pthread_mutex_t jobs_mutex; + pthread_cond_t jobs_cond; + void (*shutdown)(void); + void (*add_job)(mmsvc_core_workqueue_job_t *); +} mmsvc_core_workqueue_workqueue_t; + +typedef struct mmsvc_core_workqueue_worker { + pthread_t thread; + int terminate; + struct mmsvc_core_workqueue_workqueue *workqueue; + struct mmsvc_core_workqueue_worker *prev; + struct mmsvc_core_workqueue_worker *next; +} mmsvc_core_workqueue_worker_t; + +mmsvc_core_workqueue_workqueue_t *mmsvc_core_workqueue_get_instance(void); +int mmsvc_core_workqueue_init(int numWorkers); + +#ifdef __cplusplus +} +#endif +#endif /* __MMSVC_CORE_WORKQUEUE_H__ */ diff --git a/mused.manifest b/mused.manifest new file mode 100755 index 0000000..b987928 --- /dev/null +++ b/mused.manifest @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/mused.pc.in b/mused.pc.in new file mode 100755 index 0000000..cd88bcc --- /dev/null +++ b/mused.pc.in @@ -0,0 +1,15 @@ + +# Package Information for pkg-config + +prefix=@PREFIX@ +exec_prefix=/usr +libdir=/usr/lib +includedir=/usr/include/media + +Name: @PC_NAME@ +Description: @PACKAGE_DESCRIPTION@ +Version: @VERSION@ +Requires: @PC_REQUIRED@ mm-common iniparser +Libs: -L${libdir} @PC_LDFLAGS@ +Cflags: -I${includedir} + diff --git a/packaging/mused.service b/packaging/mused.service new file mode 100644 index 0000000..490f8f7 --- /dev/null +++ b/packaging/mused.service @@ -0,0 +1,16 @@ +[Unit] +Description=Mused server +After=vconf-setup.service + +[Service] +Type=simple +ExecStart=/usr/bin/mused-server +Restart=always +RestartSec=0 +MemoryLimit=100M +User=system +Group=system +SmackProcessLabel=mused-server + +[Install] +WantedBy=multi-user.target diff --git a/packaging/mused.socket b/packaging/mused.socket new file mode 100644 index 0000000..73a5f6c --- /dev/null +++ b/packaging/mused.socket @@ -0,0 +1,10 @@ +[Socket] +SocketUser=system +SocketGroup=system +ListenStream=/tmp/.mmsvc_core_socket +SmackLabelIPIn=mused-server +SmackLabelIPOut=mused-server +Service=mused.service + +[Install] +WantedBy=sockets.target diff --git a/packaging/mused.spec b/packaging/mused.spec new file mode 100644 index 0000000..7eb7cd2 --- /dev/null +++ b/packaging/mused.spec @@ -0,0 +1,111 @@ +Name: mused +Summary: A Media Daemon library in Tizen Native API +Version: 0.1.1 +Release: 0 +Group: TO_BE/FILLED_IN +License: TO BE FILLED IN +Source0: %{name}-%{version}.tar.gz +Source1: mused.service +Source2: mused.socket +BuildRequires: cmake +BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(mm-common) +BuildRequires: pkgconfig(iniparser) +BuildRequires: pkgconfig(json-c) +#BuildRequires: pkgconfig(mm-session) +#BuildRequires: pkgconfig(mm-sound) +#BuildRequires: pkgconfig(mm-player) +#BuildRequires: pkgconfig(mm-ta) +#BuildRequires: pkgconfig(capi-base-common) +#BuildRequires: pkgconfig(capi-media-sound-manager) +#BuildRequires: pkgconfig(gstreamer-0.10) +#BuildRequires: pkgconfig(gstreamer-plugins-base-0.10) +#BuildRequires: pkgconfig(gstreamer-interfaces-0.10) +#BuildRequires: pkgconfig(gstreamer-app-0.10) +#BuildRequires: pkgconfig(appcore-efl) +#BuildRequires: pkgconfig(elementary) +#BuildRequires: pkgconfig(ecore) +#BuildRequires: pkgconfig(evas) +#BuildRequires: pkgconfig(ecore-x) +#BuildRequires: pkgconfig(capi-media-tool) +#BuildRequires: pkgconfig(libtbm) +#BuildRequires: pkgconfig(mmutil-imgp) +#BuildRequires: pkgconfig(audio-session-mgr) +#BuildRequires: pkgconfig(vconf) +#BuildRequires: pkgconfig(icu-i18n) +#BuildRequires: pkgconfig(utilX) + +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig + +%description + + +%package devel +Summary: A Media Daemon library in Tizen (Development) +Group: TO_BE/FILLED_IN +Requires: %{name} = %{version}-%{release} +Requires: pkgconfig(mm-common) +Requires: pkgconfig(iniparser) +%description devel + +%prep +%setup -q + + +%build +%if 0%{?sec_build_binary_debug_enable} +export CFLAGS="$CFLAGS -DTIZEN_DEBUG_ENABLE -D_GNU_SOURCE" +export CXXFLAGS="$CXXFLAGS -DTIZEN_DEBUG_ENABLE -D_GNU_SOURCE" +export FFLAGS="$FFLAGS -DTIZEN_DEBUG_ENABLE -D_GNU_SOURCE" +%endif +MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'` +cmake . -DCMAKE_INSTALL_PREFIX=/usr -DFULLVER=%{version} -DMAJORVER=${MAJORVER} + + +make %{?jobs:-j%jobs} + +%install +rm -rf %{buildroot} +mkdir -p %{buildroot}/usr/share/license +#mkdir -p %{buildroot}/opt/usr/devel +cp LICENSE.APLv2 %{buildroot}/usr/share/license/%{name} +mkdir -p %{buildroot}/usr/bin +cp mused-server %{buildroot}/usr/bin + +%make_install + +mkdir -p %{buildroot}%{_libdir}/systemd/system/multi-user.target.wants +install -m 0644 %SOURCE1 %{buildroot}%{_libdir}/systemd/system/mused.service +ln -s ../mused.service %{buildroot}%{_libdir}/systemd/system/multi-user.target.wants/mused.service + +mkdir -p %{buildroot}%{_libdir}/systemd/system/sockets.target.wants +install -m 0644 %SOURCE2 %{buildroot}%{_libdir}/systemd/system/mused.socket +ln -s ../mused.socket %{buildroot}%{_libdir}/systemd/system/sockets.target.wants/mused.socket + +%post +/sbin/ldconfig +chown 200:200 %{_libdir}/systemd/system/mused.socket + +%postun -p /sbin/ldconfig + + +%files +%manifest mused.manifest +%defattr(-,system,system,-) +%{_libdir}/libmused.so.* +%{_datadir}/license/%{name} +%{_libdir}/systemd/system/mused.service +%{_libdir}/systemd/system/multi-user.target.wants/mused.service +%{_libdir}/systemd/system/sockets.target.wants/mused.socket +%{_libdir}/systemd/system/mused.socket +%{_datadir}/mused/mused.conf +/usr/bin/* + + +%files devel +%defattr(-,system,system,-) +%{_includedir}/media/*.h +%{_libdir}/pkgconfig/*.pc +%{_libdir}/libmused.so diff --git a/src/mmsvc_core.c b/src/mmsvc_core.c new file mode 100644 index 0000000..92ca12b --- /dev/null +++ b/src/mmsvc_core.c @@ -0,0 +1,501 @@ +/* + * mmsvc-core + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: YoungHun Kim + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "mmsvc_core.h" +#include "mmsvc_core_private.h" +#include "mmsvc_core_config.h" +#include "mmsvc_core_internal.h" +#include "mmsvc_core_ipc.h" +#include "mmsvc_core_log.h" +#include "mmsvc_core_workqueue.h" + +#define FILENAMELEN 32 +#define WORK_THREAD_NUM 8 +#define LOG_SLEEP_TIMER 10 + +static MMServer *server; +static GMainLoop *g_loop; +static GThread *g_thread; +static char *UDS_files[MUSED_CHANNEL_MAX] = {SOCKFILE0, SOCKFILE1}; + +static gboolean (*job_functions[MUSED_CHANNEL_MAX]) + (mmsvc_core_workqueue_job_t *job) = { + mmsvc_core_ipc_job_function, + mmsvc_core_ipc_data_job_function + }; + +static int _mmsvc_core_set_nonblocking(int fd); +static int _mmsvc_core_check_server_is_running(void); +static MMServer *_mmsvc_core_create_new_server_from_fd(int fd[], int type); +static gboolean _mmsvc_core_connection_handler(GIOChannel *source, + GIOCondition condition, gpointer data); +static int _mmsvc_core_free(MMServer *server); + +static int _mmsvc_core_set_nonblocking(int fd) +{ + int flags = fcntl(fd, F_GETFL, NULL); + + if (flags >= 0) { + LOGD("fcntl nonblocking"); + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) { + LOGE("fcntl(%d, F_SETFL)", fd); + return -1; + } else { + LOGD("fcntl(%d, F_SETFL)"); + } + } + + return 0; +} + +static int _mmsvc_core_check_server_is_running(void) +{ + int fd, already_running; + int ret = -1; + + LOGD("Enter"); + + /* First, check whether the existing file is locked. */ + fd = open(LOCKFILE, O_RDONLY); + if (fd == -1 && errno != ENOENT) { + /* Cannot open file, but it's not because the file doesn't exist. */ + char msg[1024]; + snprintf(msg, sizeof(msg), "datserver: Cannot open lock file %s", LOCKFILE); + LOGE("open failed: %s ", msg); + return ret; + } else if (fd != -1) { + already_running = flock(fd, LOCK_EX | LOCK_NB) == -1; + close(fd); + if (already_running) { + LOGE("File already locked. There's already a server running"); + return 0; + } + } + + /* Lock file does not exist, or is not locked. Create a new lockfile and lock it. */ + fd = open(LOCKFILE, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (fd == -1) { + LOGE("dataserver: Cannot create lock file"); + return ret; + } + + if (flock(fd, LOCK_EX | LOCK_NB) != 0) { + LOGE("Can't lock the lock file \"%s\". " "Is another instance running?", LOCKFILE); + return ret; + } + + /* Close out the standard file descriptors */ + close(STDIN_FILENO); + close(STDOUT_FILENO); + + LOGD("Leave"); + return 1; +} + +static bool _mmsvc_core_attach_server(int fd, MMSVC_CORE_ClientCallback callback, gpointer param) +{ + GIOChannel *channel; + GSource *src = NULL; + + LOGD("Enter"); + + channel = g_io_channel_unix_new(fd); + if (!channel) { + return false; + } + + src = g_io_create_watch(channel, G_IO_IN); + if (!src) { + return false; + } + + g_source_set_callback(src, (GSourceFunc) callback, param, NULL); + + g_source_attach(src, g_main_loop_get_context(g_loop)); + g_source_unref(src); + + return true; +} + +static MMServer *_mmsvc_core_create_new_server_from_fd(int fd[], int type) +{ + MMServer *server; + int i; + + LOGD("Enter"); + server = malloc(sizeof(MMServer)); + g_return_val_if_fail(server != NULL, NULL); + + server->fd = fd[MUSED_CHANNEL_MSG]; + server->data_fd = fd[MUSED_CHANNEL_DATA]; + server->type = type; + server->stop = 0; + server->retval = 0; + + /*initiate server */ + g_atomic_int_set(&server->running, 1); + + for (i = 0; i < MUSED_CHANNEL_MAX; i++) { + if (!_mmsvc_core_attach_server(fd[i], + _mmsvc_core_connection_handler, (gpointer) i)) { + LOGD("Fail to attach server fd %d", fd[i]); + MMSVC_FREE(server); + return NULL; + } + } + + LOGD("Leave"); + return server; +} + +static int _mmsvc_core_free(MMServer *server) +{ + int retval = -1; + int i; + LOGD("Enter"); + + g_return_val_if_fail(server != NULL, retval); + + retval = server->retval; + close(server->fd); + for (i = 0; i < MUSED_CHANNEL_MAX; i++) + remove(UDS_files[i]); + remove(LOCKFILE); + MMSVC_FREE(server); + mmsvc_core_workqueue_get_instance()->shutdown(); + LOGD("Leave"); + return retval; +} + +gpointer mmsvc_core_main_loop(gpointer data) +{ + while (1) { + sleep(LOG_SLEEP_TIMER); + LOGD("polling %d\n", g_main_loop_is_running(g_loop)); + } + + return NULL; +} + +int _mmsvc_core_server_new(mused_channel_e channel) +{ + int fd; + struct sockaddr *address; + struct sockaddr_un addr_un; + socklen_t address_len; + + if (channel >= MUSED_CHANNEL_MAX) + return -1; + + unlink(UDS_files[channel]); + LOGD("Enter"); + + /* Create Socket */ + fd = socket(AF_UNIX, SOCK_STREAM, 0); /* Unix Domain Socket */ + if (fd < 0) { + LOGE("socket failed sock: %s", strerror(errno)); + return -1; + } else { + LOGD("fd: %d", fd); + } + + memset(&addr_un, 0, sizeof(addr_un)); + addr_un.sun_family = AF_UNIX; + strncpy(addr_un.sun_path, UDS_files[channel], sizeof(addr_un.sun_path)); + address_len = sizeof(addr_un); + address = (struct sockaddr *)(&addr_un); + + /* Bind to filename */ + if (bind(fd, address, address_len) < 0) { + if (errno == EADDRINUSE) { + LOGE("%d is address in using so remove the file of %s", fd, addr_un.sun_path); + unlink(addr_un.sun_path); + } + + if (bind(fd, (struct sockaddr *)&addr_un, sizeof(addr_un)) != 0) + LOGE("bind failed sock: %s", strerror(errno)); + else + LOGE("bind failed sock: %s", strerror(errno)); + close(fd); + return -1; + } + + /* Setup listen queue */ + if (listen(fd, 5) == -1) { + LOGE("listen failed"); + close(fd); + return -1; + } + + if (_mmsvc_core_set_nonblocking(fd) < 0) + LOGE("failed to set server socket to non-blocking"); + + LOGD("Leave"); + + return fd; +} + + +MMServer *mmsvc_core_new() +{ + int fd[MUSED_CHANNEL_MAX]; + int i; + LOGD("Enter"); + + for (i = 0; i < MUSED_CHANNEL_MAX; i++) { + fd[i] = _mmsvc_core_server_new(i); + if (fd[i] < 0) { + LOGE("Failed to create socket server %d", i); + return NULL; + } + } + + /* Initialize work queue */ + if (mmsvc_core_workqueue_init(WORK_THREAD_NUM)) { + LOGE("mmsvc_core_new : Failed to initialize the workqueue"); + for (i = 0; i < MUSED_CHANNEL_MAX; i++) + close(fd[i]); + mmsvc_core_workqueue_get_instance()->shutdown(); + return NULL; + } + + LOGD("Leave"); + + return _mmsvc_core_create_new_server_from_fd(fd, READ|PERSIST); +} + +static gboolean _mmsvc_core_connection_handler(GIOChannel *source, + GIOCondition condition, gpointer data) +{ + int client_sockfd, server_sockfd; + socklen_t client_len; + struct sockaddr_un client_address; + mused_channel_e channel = (mused_channel_e)data; + + LOGD("Enter"); + + Client client = NULL; + mmsvc_core_workqueue_job_t *job = NULL; + + server_sockfd = g_io_channel_unix_get_fd(source); + + client_len = sizeof(client_address); + client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_address, &client_len); + LOGD("server: %d client: %d", server_sockfd, client_sockfd); + + if (client_sockfd < 0) { + LOGE("failed to accept"); + goto out; + } + + if (channel == MUSED_CHANNEL_MSG) { + if ((client = malloc(sizeof(_Client))) == NULL) { + LOGE("failed to allocated memory for client stat"); + goto out; + } + + memset(client, 0, sizeof(_Client)); + client->ch[channel].fd = client_sockfd; + } + + if ((job = malloc(sizeof(mmsvc_core_workqueue_job_t))) == NULL) { + LOGE("failed to allocate memory for job state"); + goto out; + } + + job->job_function = job_functions[channel]; + if (channel == MUSED_CHANNEL_MSG) + job->user_data = client; + else + job->user_data = (void *)client_sockfd; + + mmsvc_core_workqueue_get_instance()->add_job(job); + + LOGD("Leave"); + return TRUE; +out: + if (client_sockfd) + close(client_sockfd); + + MMSVC_FREE(client); + MMSVC_FREE(job); + + LOGE("FALSE"); + return FALSE; +} + +int mmsvc_core_run() +{ + int ret = -1; + + LOGD("Enter"); + + ret = _mmsvc_core_check_server_is_running(); + if (ret == -1) { + return -1; + } else if (ret == 0) { + LOGE("Server is already running"); + return 2; + } + + /* Sigaction */ + g_loop = g_main_loop_new(NULL, FALSE); + + g_thread = g_thread_new("mmsvc_thread", mmsvc_core_main_loop, g_loop); + + server = mmsvc_core_new(); + if (!server) { + g_main_loop_unref(g_loop); + return 1; + } + + LOGD("g_main_loop_run"); + g_main_loop_run(g_loop); + + LOGD("Leave"); + return _mmsvc_core_free(server); +} + +static int _mmsvc_core_client_new(mused_channel_e channel) +{ + struct sockaddr_un address; + int len, ret = -1; + int sockfd; + + if (channel >= MUSED_CHANNEL_MAX) + return -1; + + LOGD("Enter"); + + /*Create socket*/ + if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { + LOGE("[socket failure] sock: %s", strerror(errno)); + return ret; + } else { + LOGD("sockfd: %d", sockfd); + if (fcntl(sockfd, F_SETFD, FD_CLOEXEC) < 0) { + LOGE("unable to set on ctrls socket fd %d: %s", sockfd, strerror(errno)); + (void) close(sockfd); + return -1; + } + LOGD("fcntl"); + } + + memset(&address, 0, sizeof(address)); + address.sun_family = AF_UNIX; + strncpy(address.sun_path, UDS_files[channel], sizeof(address.sun_path)); + len = sizeof(address); + + if ((ret = connect(sockfd, (struct sockaddr *)&address, len)) < 0) { + LOGE("connect failure"); + if (sockfd) + (void) close(sockfd); + return ret; + } + + LOGD("Leave"); + return sockfd; +} + +int mmsvc_core_client_new(void) +{ + return _mmsvc_core_client_new(MUSED_CHANNEL_MSG); +} + +int mmsvc_core_client_new_data_ch(void) +{ + return _mmsvc_core_client_new(MUSED_CHANNEL_DATA); +} + +int mmsvc_core_client_get_msg_fd(Client client) +{ + g_return_val_if_fail(client, -1); + + return client->ch[MUSED_CHANNEL_MSG].fd; +} + +int mmsvc_core_client_get_data_fd(Client client) +{ + g_return_val_if_fail(client, -1); + + return client->ch[MUSED_CHANNEL_DATA].fd; +} +void mmsvc_core_client_set_cust_data(Client client, void *data) +{ + g_return_if_fail(client); + client->cust_data = data; +} + +void *mmsvc_core_client_get_cust_data(Client client) +{ + g_return_val_if_fail(client, NULL); + return client->cust_data; +} + +char *mmsvc_core_client_get_msg(Client client) +{ + g_return_val_if_fail(client, NULL); + return (client->recvMsg + client->msg_offset); +} + +int mmsvc_core_client_get_capi(Client client) +{ + g_return_val_if_fail(client, -1); + return client->api_client; +} + +void mmsvc_core_connection_close(int sock_fd) +{ + LOGD("Enter"); + if (sock_fd > 0) { + shutdown(sock_fd, SHUT_RDWR); + close(sock_fd); + } + + LOGD("Leave"); +} + +void mmsvc_core_worker_exit(Client client) +{ + LOGD("Enter"); + if (!client) { + LOGE("Error - null client"); + return; + } + + mmsvc_core_connection_close(client->ch[MUSED_CHANNEL_MSG].fd); + mmsvc_core_connection_close(client->ch[MUSED_CHANNEL_DATA].fd); + if (!client->ch[MUSED_CHANNEL_MSG].p_gthread) { + LOGE("Error - null p_gthread"); + return; + } + LOGD("%p thread exit\n", client->ch[MUSED_CHANNEL_MSG].p_gthread); + g_thread_unref(client->ch[MUSED_CHANNEL_MSG].p_gthread); + + if (client->ch[MUSED_CHANNEL_DATA].p_gthread) + g_thread_unref(client->ch[MUSED_CHANNEL_DATA].p_gthread); + MMSVC_FREE(client); + + mmsvc_core_config_get_instance()->free(); + + LOGD("Leave"); + g_thread_exit(NULL); +} diff --git a/src/mmsvc_core_config.c b/src/mmsvc_core_config.c new file mode 100644 index 0000000..fe15e8c --- /dev/null +++ b/src/mmsvc_core_config.c @@ -0,0 +1,181 @@ +/* + * mmsvc-core + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: YoungHun Kim + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "mmsvc_core_config.h" +#include "mmsvc_core_internal.h" + +static config_t *g_conf = NULL; + +static int _mmsvc_core_config_parser(void); +static void _mmsvc_core_config_free(void); +static void _mmsvc_core_config_init_instance(void (*free)(void), char* (*get_path)(int)); +static char *_mmsvc_core_config_get_path(int api_client); + +static int _mmsvc_core_config_parser(void) +{ + char *host; + char *str; + int ret = -1; + + g_return_val_if_fail(g_conf != NULL, ret); + + g_conf->mmsvc_dict = iniparser_load(CONFFILE); + g_return_val_if_fail(g_conf->mmsvc_dict != NULL, ret); + + str = iniparser_getstring(g_conf->mmsvc_dict, MUSEDHOST, NULL); + g_return_val_if_fail(str != NULL, ret); + + g_conf->hosts = (char *) malloc(1 + strlen(str)); + if (!g_conf->hosts) { + LOGE("Error - hosts allocation"); + iniparser_freedict(g_conf->mmsvc_dict); + MMSVC_FREE(g_conf); + } + strcpy(g_conf->hosts, str); + + str = iniparser_getstring(g_conf->mmsvc_dict, MUSEDLOG, NULL); + g_return_val_if_fail(str != NULL, ret); + + g_conf->logfile = (char *) malloc(1 + strlen(str)); + if (!g_conf->logfile) { + LOGE("Error - hosts allocation"); + iniparser_freedict(g_conf->mmsvc_dict); + MMSVC_FREE(g_conf->hosts); + MMSVC_FREE(g_conf); + } + strcpy(g_conf->logfile, str); + + g_conf->type = 0; + host = strtok(g_conf->hosts, COMMA); + + while (host != NULL) { + char *host_name = (char *) malloc(HOST_MAX_COUNT); + if (!host_name) { + LOGE("Error - null host_name"); + iniparser_freedict(g_conf->mmsvc_dict); + MMSVC_FREE(g_conf->hosts); + MMSVC_FREE(g_conf); + return ret; + } + + LOGD("host: %s", host); + /* path */ + strcpy(host_name, host); + strcat(host_name, COLON); + strcat(host_name, PATH); + g_strstrip(host_name); /*Removes leading and trailing whitespace from a string*/ + + g_conf->host_infos[g_conf->type] = (host_info_t *) malloc(sizeof(host_info_t)); + if (!g_conf->host_infos[g_conf->type]) { + LOGE("Error - null type"); + iniparser_freedict(g_conf->mmsvc_dict); + MMSVC_FREE(g_conf->hosts); + MMSVC_FREE(host_name); + MMSVC_FREE(g_conf->host_infos[g_conf->type]); + MMSVC_FREE(g_conf); + return ret; + } + + g_conf->host_infos[g_conf->type]->path = (char *) malloc(1 + strlen(iniparser_getstring(g_conf->mmsvc_dict, host_name, NULL))); + if(!g_conf->host_infos[g_conf->type]->path) { + LOGE("Error - null path"); + iniparser_freedict(g_conf->mmsvc_dict); + MMSVC_FREE(g_conf->hosts); + MMSVC_FREE(host_name); + MMSVC_FREE(g_conf->host_infos[g_conf->type]); + MMSVC_FREE(g_conf); + return ret; + } + + strcpy(g_conf->host_infos[g_conf->type]->path, iniparser_getstring(g_conf->mmsvc_dict, host_name, NULL)); + LOGD("[%d] %s", g_conf->type, g_conf->host_infos[g_conf->type]->path); + + host = strtok(NULL, COMMA); + g_conf->type++; + MMSVC_FREE(host_name); + } + + iniparser_freedict(g_conf->mmsvc_dict); + return 0; +} + +static void _mmsvc_core_config_free(void) +{ + char *host; + + g_return_if_fail(g_conf != NULL); + + host = strtok(g_conf->hosts, COMMA); + g_conf->type = 0; + + while (host != NULL) { + LOGD("host: %s", host); + MMSVC_FREE(g_conf->host_infos[g_conf->type]->path); + MMSVC_FREE(g_conf->host_infos[g_conf->type]); + host = strtok(NULL, COMMA); + g_conf->type++; + } + MMSVC_FREE(g_conf->hosts); + MMSVC_FREE(g_conf); +} + +static void _mmsvc_core_config_init_instance(void (*free)(void), char* (*get_path)(int)) +{ + g_return_if_fail(free != NULL); + g_return_if_fail(get_path != NULL); + g_return_if_fail(g_conf == NULL); + + g_conf = calloc(1, sizeof(*g_conf)); + g_conf->hosts = NULL; + g_conf->type = 0; + g_conf->logfile = NULL; + g_conf->mmsvc_dict = NULL; + g_conf->free = free; + g_conf->get_path = get_path; + LOGD("conf: %0x2x", g_conf); + + if (_mmsvc_core_config_parser() != 0) + LOGE("parser() error"); +} + +static char *_mmsvc_core_config_get_path(int api_client) +{ + g_return_val_if_fail(g_conf->host_infos[api_client]->path != NULL, NULL); + + LOGD("%s", g_conf->host_infos[api_client]->path); + return g_conf->host_infos[api_client]->path; +} + +config_t *mmsvc_core_config_get_instance(void) +{ + if (g_conf == NULL) + _mmsvc_core_config_init_instance(_mmsvc_core_config_free, _mmsvc_core_config_get_path); + + return g_conf; +} + +void mmsvc_core_config_init(void) +{ + LOGD("Enter"); + if (g_conf == NULL) + _mmsvc_core_config_init_instance(_mmsvc_core_config_free, _mmsvc_core_config_get_path); + LOGD("Leave"); +} diff --git a/src/mmsvc_core_ipc.c b/src/mmsvc_core_ipc.c new file mode 100644 index 0000000..d9fbaa5 --- /dev/null +++ b/src/mmsvc_core_ipc.c @@ -0,0 +1,348 @@ +/* + * mmsvc-core + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: YoungHun Kim + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "mmsvc_core.h" +#include "mmsvc_core_private.h" +#include "mmsvc_core_config.h" +#include "mmsvc_core_internal.h" +#include "mmsvc_core_log.h" +#include "mmsvc_core_ipc.h" +#include "mmsvc_core_msg_json.h" +#include "mmsvc_core_module.h" + +typedef struct { + int marker; + int id; + int size; +} RecvDataHead_t; + +typedef struct { + RecvDataHead_t header; + /* Dynamic allocated data area */ +} RecvData_t; + +static gpointer _mmsvc_core_ipc_dispatch_worker(gpointer data); +static gpointer _mmsvc_core_ipc_data_worker(gpointer data); +static RecvData_t *_mmsvc_core_ipc_new_qdata(char **recvBuff, int recvSize, int *allocSize); + +static gpointer _mmsvc_core_ipc_dispatch_worker(gpointer data) +{ + int len, parse_len, cmd, api_client; + Client client = NULL; + int handle = 0; + mused_msg_parse_err_e err = MUSED_MSG_PARSE_ERROR_NONE; + g_return_val_if_fail(data != NULL, NULL); + + client = (Client)data; + g_return_val_if_fail(client != NULL, NULL); + + while (1) { + memset(client->recvMsg, 0x00, sizeof(client->recvMsg)); + len = mmsvc_core_ipc_recv_msg(client->ch[MUSED_CHANNEL_MSG].fd, client->recvMsg); + if (len <= 0) { + LOGE("recv : %s (%d)", strerror(errno), errno); + + LOGD("close module"); + mmsvc_core_module_close(client); + + LOGD("worker exit"); + mmsvc_core_worker_exit(client); + break; + } else { + parse_len = len; + LOGD("Message In"); + cmd = 0; + api_client = 0; + client->msg_offset = 0; + + mmsvc_core_log_get_instance()->log(client->recvMsg); + + while (client->msg_offset < len) { + if (mmsvc_core_msg_json_deserialize_len("api", client->recvMsg + client->msg_offset, &parse_len, &cmd, &err)) { + if (mmsvc_core_msg_json_deserialize_len("handle", client->recvMsg + client->msg_offset, &parse_len, &handle, &err)) + LOGD("cmd: %d len: %d Message: %s", cmd, len, client->recvMsg); + switch (cmd) { + case API_CREATE: + if (mmsvc_core_msg_json_deserialize_len("client", client->recvMsg + client->msg_offset, &parse_len, &api_client, &err)) { + client->api_client = api_client; + client->ch[MUSED_CHANNEL_MSG].module = mmsvc_core_module_load(api_client); + client->ch[MUSED_CHANNEL_DATA].queue = g_queue_new(); + g_mutex_init(&client->ch[MUSED_CHANNEL_DATA].mutex); + g_cond_init(&client->ch[MUSED_CHANNEL_DATA].cond); + LOGD("client fd: %d module: %p", + client->ch[MUSED_CHANNEL_MSG].fd, + client->ch[MUSED_CHANNEL_MSG].module); + mmsvc_core_module_dll_symbol(cmd, client); + break; + } + case API_DESTROY: + LOGD("DESTROY"); + mmsvc_core_module_dll_symbol(cmd, client); + g_queue_free(client->ch[MUSED_CHANNEL_DATA].queue); + g_mutex_clear(&client->ch[MUSED_CHANNEL_DATA].mutex); + g_cond_clear(&client->ch[MUSED_CHANNEL_DATA].cond); + mmsvc_core_module_close(client); + mmsvc_core_worker_exit(client); + break; + default: + LOGD("[default] client->module: %p", client->ch[MUSED_CHANNEL_MSG].module); + mmsvc_core_module_dll_symbol(cmd, client); + break; + } + } else { + LOGE("Parsing status : %d", err); + break; + } + + if (parse_len == 0) + break; + + client->msg_offset += parse_len; + parse_len = len - parse_len; + } + } + } + + LOGD("Leave"); + return NULL; +} + +static gpointer _mmsvc_core_ipc_data_worker(gpointer data) +{ + int recvLen = 0; + int currLen = 0; + int fd = (int) data; + Client client = NULL; + char *recvBuff = NULL; + int allocSize = 0; + + g_return_val_if_fail(fd > 0, NULL); + + while(1) { + if (!recvBuff) { + allocSize = MM_MSG_MAX_LENGTH; + recvBuff = g_new(char, allocSize); + } + if (!recvBuff) { + LOGE("Out of memory"); + break; + } + recvLen = mmsvc_core_ipc_recv_msg(fd, recvBuff + currLen); + currLen += recvLen; + LOGD("buff %p, recvLen %d, currLen %d, allocSize %d", + recvBuff, recvLen, currLen, allocSize); + if (recvLen <= 0) { + LOGE("recv : %s (%d)", strerror(errno), errno); + break; + } else { + if (client) { + RecvData_t *qData; + while ((qData = _mmsvc_core_ipc_new_qdata(&recvBuff, currLen, &allocSize)) + != NULL) { + int qDataSize = qData->header.size + sizeof(RecvDataHead_t); + if (currLen > qDataSize) { + allocSize = allocSize - qDataSize; + char *newBuff = g_new(char, allocSize); + memcpy(newBuff, recvBuff + qDataSize, currLen - qDataSize); + recvBuff = newBuff; + } + g_queue_push_tail(client->ch[MUSED_CHANNEL_DATA].queue, qData); + g_cond_signal(&client->ch[MUSED_CHANNEL_DATA].cond); + + currLen = currLen - qDataSize; + if (!currLen) + break; + } + if (!currLen) { + recvBuff = NULL; + } else if (allocSize < MM_MSG_MAX_LENGTH + currLen) { + allocSize = MM_MSG_MAX_LENGTH + currLen; + recvBuff = g_renew(char, recvBuff, allocSize); + } + } else { + int data = 0; + if (mmsvc_core_msg_json_deserialize("client_addr", recvBuff, &data, NULL)) { + client = (Client)data; + if (client) { + client->ch[MUSED_CHANNEL_DATA].p_gthread = g_thread_self(); + } + } + MMSVC_FREE(recvBuff); + recvBuff = NULL; + currLen = 0; + } + } + } + + MMSVC_FREE(recvBuff); + + LOGD("Leave"); + return NULL; +} + +gboolean mmsvc_core_ipc_job_function(mmsvc_core_workqueue_job_t *job) +{ + LOGD("Enter"); + Client client = NULL; + + g_return_val_if_fail(job != NULL, FALSE); + + client = (Client) job->user_data; + g_return_val_if_fail(client != NULL, FALSE); + + LOGD("[%p] client->fd : %d", client, client->ch[MUSED_CHANNEL_MSG].fd); + + client->ch[MUSED_CHANNEL_MSG].p_gthread = g_thread_new(NULL, _mmsvc_core_ipc_dispatch_worker, (gpointer)client); + if (!client->ch[MUSED_CHANNEL_MSG].p_gthread) { + LOGE("Error - g_thread_new"); + return FALSE; + } + + MMSVC_FREE(job); + + LOGD("Leave"); + return TRUE; +} + +gboolean mmsvc_core_ipc_data_job_function(mmsvc_core_workqueue_job_t *job) +{ + LOGD("Enter"); + int fd; + + g_return_val_if_fail(job != NULL, FALSE); + + fd = (int) job->user_data; + g_return_val_if_fail(fd > 0, FALSE); + + LOGD("data channel fd : %d", fd); + + g_thread_new(NULL, _mmsvc_core_ipc_data_worker, (gpointer)fd); +#if 0 + if (!client->p_gthread) { + LOGE("Error - g_thread_new"); + return FALSE; + } +#endif + MMSVC_FREE(job); + + LOGD("Leave"); + return TRUE; +} + +int mmsvc_core_ipc_send_msg(int sock_fd, const char *msg) +{ + int ret = -1; + + g_return_val_if_fail(msg != NULL, ret); + + if ((ret = send(sock_fd, msg, strlen(msg), 0)) < 0) + LOGE("send msg failed"); + + return ret; +} + +int mmsvc_core_ipc_recv_msg(int sock_fd, char *msg) +{ + int ret = -1; + + g_return_val_if_fail(msg != NULL, ret); + + if ((ret = recv(sock_fd, msg, MM_MSG_MAX_LENGTH, 0)) < 0) + LOGE("received msg"); + + return ret; +} + +int mmsvc_core_ipc_push_data(int sock_fd, const char *data, int size, int data_id) +{ + int ret = -1; + RecvDataHead_t header; + g_return_val_if_fail(data != NULL, ret); + + header.marker = MUSED_DATA_HEAD; + header.id = data_id; + header.size = size; + + if ((ret = send(sock_fd, &header, sizeof(RecvDataHead_t), 0)) < 0) + LOGE("send msg failed"); + if ((ret += send(sock_fd, data, size, 0)) < 0) + LOGE("send msg failed"); + + return ret; +} + +static RecvData_t *_mmsvc_core_ipc_new_qdata(char **recvBuff, int recvSize, int *allocSize) +{ + int qDataSize; + RecvData_t *qData = (RecvData_t *)*recvBuff; + g_return_if_fail(recvBuff); + + if (qData->header.marker != MUSED_DATA_HEAD) { + LOGE("Invalid data header"); + return NULL; + } + qDataSize = qData->header.size + sizeof(RecvDataHead_t); + if (qDataSize > recvSize) { + LOGD("not complated recv"); + if (qDataSize > *allocSize) { + LOGD("Realloc %d -> %d", *allocSize, qDataSize); + *allocSize = qDataSize; + *recvBuff = g_renew(char, *recvBuff, *allocSize); + } + return NULL; + } + + return qData; +} + +void mmsvc_core_ipc_delete_data(char *data) +{ + RecvData_t *qData; + g_return_if_fail(data); + + qData = (RecvData_t *)(data - sizeof(RecvDataHead_t)); + if (qData && qData->header.marker == MUSED_DATA_HEAD) { + MMSVC_FREE(qData); + } +} + +char *mmsvc_core_ipc_get_data(Client client) +{ + RecvData_t *qData; + char *rawData; + channel_info *ch; + gint64 end_time = g_get_monotonic_time() + 100 * G_TIME_SPAN_MILLISECOND; + g_return_val_if_fail(client, NULL); + ch = &client->ch[MUSED_CHANNEL_DATA]; + + g_mutex_lock(&ch->mutex); + if (g_queue_is_empty(ch->queue)) + g_cond_wait_until(&ch->cond, &ch->mutex, end_time); + g_mutex_unlock(&ch->mutex); + + qData = g_queue_pop_head(ch->queue); + if (qData) { + rawData = (char *)qData + sizeof(RecvDataHead_t); + return rawData; + } + + return NULL; +} diff --git a/src/mmsvc_core_log.c b/src/mmsvc_core_log.c new file mode 100644 index 0000000..6e0ca3e --- /dev/null +++ b/src/mmsvc_core_log.c @@ -0,0 +1,377 @@ +/* + * mmsvc-core + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: YoungHun Kim + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "mmsvc_core_internal.h" +#include "mmsvc_core_log.h" +#include + +/* Signals */ +#define RECEIVED_SIG_RESTART 0x0001 +#define RECEIVED_SIG_EXIT 0x0002 +#define RECEIVED_SIG_SHUTDOWN 0x0004 +#define RECEIVED_SIG_SEGV 0x0008 +#define RECEIVED_SIG_TERMINATE 0x0010 +#define RECEIVED_SIG_XCPU 0x0020 +#define RECEIVED_SIG_TERM_OTHER 0x0040 +#define RECEIVED_SIG_ABORT 0x0080 +#define RECEIVED_SIG_EVENT 0x0100 +#define RECEIVED_SIG_CHLD 0x0200 +#define RECEIVED_SIG_ALRM 0x0400 +#define TUNABLE_CALLER_DEPTH 32 +#define MSG_LENGTH 1024 * 1024 +#define U32BITS 0xffffffff +#define FILESYSTEMIO_MAX_DUPFDS 512 + +static mmsvc_core_log_t *g_mused_log = NULL; +volatile unsigned int received_signal_flags = 0; + +static void _mmsvc_core_log_sig_child(int signo); +static char *_mmsvc_core_log_prepare_core(void); +static void _mmsvc_core_log_sig_abort(int signo); +static void _mmsvc_core_log_sig_terminate(int signo); +static void _mmsvc_core_log_sig_restart(int signo); +static int _mmsvc_core_log_init_signal_set(void); +static void _mmsvc_core_log_init_signals(void); +static int _mmsvc_core_log_fd_set_block(int fd); +static void _mmsvc_core_log_sigaction(int signo, siginfo_t *si, void *arg); +static void _mmsvc_core_log_set_log_fd(void); +static void _mmsvc_core_log_init_instance(void (*log)(char *), void (*fatal)(char *), void (*set_module_value) (int, GModule *, gboolean), gboolean(*get_module_opened) (int), GModule * (*get_module_value) (int)); +static void _mmsvc_core_log_monitor(char *msg); +static void _mmsvc_core_log_fatal(char *msg); +static int _mmsvc_core_log_init_signal_set(void); +static void _mmsvc_core_log_set_module_value(int index, GModule *module, gboolean value); +static gboolean _mmsvc_core_log_get_module_opened(int index); +static GModule *_mmsvc_core_log_get_module_value(int index); + +static void _mmsvc_core_log_sig_child(int signo) +{ + received_signal_flags |= RECEIVED_SIG_CHLD; + + if (SIG_ERR == signal(SIGCHLD, _mmsvc_core_log_sig_child)) + LOGE("SIGCHLD handler: %s", strerror(errno)); +} + +static char *_mmsvc_core_log_prepare_core(void) +{ + int result = chdir("/"); + static char dir[256]; + + memset(dir, '\0', sizeof(dir)); + snprintf(dir, sizeof(dir)-1, "%s/mused_%lu", MUSED_DIR, (unsigned long) getpid()); + + if (mkdir(dir, 0700) < 0) { + LOGE("unable to create directory '%s' for coredump: %s", dir, strerror(errno)); + } else { + result = chdir(dir); + LOGD("result = %d", result); + } + + return dir; +} + +static void _mmsvc_core_log_sig_abort(int signo) +{ + received_signal_flags |= RECEIVED_SIG_ABORT; + + if (SIG_ERR == signal(SIGABRT, SIG_DFL)) + LOGE("SIGABRT andler: %s", strerror(errno)); + + LOGD("mused received SIGABRT signal, generating core file in %s", _mmsvc_core_log_prepare_core()); + abort(); +} + +static void _mmsvc_core_log_sig_terminate(int signo) +{ + if (signo == SIGSEGV || signo == SIGXCPU || signo == SIGBUS) { + if (signo == SIGXCPU) { + received_signal_flags |= RECEIVED_SIG_XCPU; + } else { + received_signal_flags |= RECEIVED_SIG_SEGV; + } + + LOGD("mused terminating (%d)", signo); + + } else if (signo == SIGTERM) { + received_signal_flags |= RECEIVED_SIG_TERMINATE; + + } else { + received_signal_flags |= RECEIVED_SIG_TERM_OTHER; + } + + if (SIG_ERR == signal(signo, SIG_IGN)) + LOGE("handler for %d: %s", signo, strerror(errno)); +} + +static void _mmsvc_core_log_sig_restart(int signo) +{ + received_signal_flags |= RECEIVED_SIG_RESTART; + + if (SIG_ERR == signal(SIGHUP, _mmsvc_core_log_sig_restart)) + LOGE("SIGHUP andler: %s", strerror(errno)); +} + +static void _mmsvc_core_log_signals_handle_event(int signo) +{ + received_signal_flags |= RECEIVED_SIG_EVENT; + + if (SIG_ERR == signal(SIGUSR2, _mmsvc_core_log_signals_handle_event)) + LOGE(" SIGUSR2 handler: %s", strerror(errno)); +} + +static int _mmsvc_core_log_init_signal_set(void) +{ + sigset_t mmsvc_core_log_sig_set; + + sigemptyset(&mmsvc_core_log_sig_set); + + sigaddset(&mmsvc_core_log_sig_set, SIGCHLD); + sigaddset(&mmsvc_core_log_sig_set, SIGINT); + sigaddset(&mmsvc_core_log_sig_set, SIGQUIT); + sigaddset(&mmsvc_core_log_sig_set, SIGILL); + sigaddset(&mmsvc_core_log_sig_set, SIGABRT); + sigaddset(&mmsvc_core_log_sig_set, SIGFPE); + sigaddset(&mmsvc_core_log_sig_set, SIGSEGV); + sigaddset(&mmsvc_core_log_sig_set, SIGALRM); + sigaddset(&mmsvc_core_log_sig_set, SIGTERM); + sigaddset(&mmsvc_core_log_sig_set, SIGHUP); + sigaddset(&mmsvc_core_log_sig_set, SIGUSR2); + sigaddset(&mmsvc_core_log_sig_set, SIGSTKFLT); + sigaddset(&mmsvc_core_log_sig_set, SIGIO); + sigaddset(&mmsvc_core_log_sig_set, SIGBUS); + + if (SIG_ERR == signal(SIGCHLD, _mmsvc_core_log_sig_child) || SIG_ERR == signal(SIGHUP, _mmsvc_core_log_sig_restart) + || SIG_ERR == signal(SIGINT, _mmsvc_core_log_sig_terminate) || SIG_ERR == signal(SIGQUIT, _mmsvc_core_log_sig_terminate) + || SIG_ERR == signal(SIGILL, _mmsvc_core_log_sig_terminate) || SIG_ERR == signal(SIGFPE, _mmsvc_core_log_sig_terminate) + || SIG_ERR == signal(SIGABRT, _mmsvc_core_log_sig_abort) || SIG_ERR == signal(SIGSEGV, _mmsvc_core_log_sig_terminate) + || SIG_ERR == signal(SIGXCPU, _mmsvc_core_log_sig_terminate) || SIG_ERR == signal(SIGBUS, _mmsvc_core_log_sig_terminate) + || SIG_ERR == signal(SIGALRM, SIG_IGN) || SIG_ERR == signal(SIGTERM, _mmsvc_core_log_sig_terminate) + || SIG_ERR == signal(SIGURG, SIG_IGN) || SIG_ERR == signal(SIGSTKFLT, _mmsvc_core_log_sig_terminate) + || SIG_ERR == signal(SIGIO, SIG_IGN) || SIG_ERR == signal(SIGUSR2, _mmsvc_core_log_signals_handle_event) + || 0 > sigprocmask(SIG_UNBLOCK, &mmsvc_core_log_sig_set, NULL)) { + LOGE("signal : %s", strerror(errno)); + } + + return 0; +} + +static void _mmsvc_core_log_init_signals(void) +{ + struct sigaction action; + + _mmsvc_core_log_init_signal_set(); + + memset(&action, 0, sizeof(sigaction)); + sigemptyset(&action.sa_mask); + action.sa_sigaction = _mmsvc_core_log_sigaction; + action.sa_flags = SA_RESTART | SA_SIGINFO; + + sigaction(SIGSEGV, &action, NULL); + sigaction(SIGBUS, &action, NULL); + sigaction(SIGXCPU, &action, NULL); + sigaction(SIGUSR1, &action, NULL); +} + +static int _mmsvc_core_log_fd_set_block(int fd) +{ + int flags; + int ret; + + flags = fcntl(fd, F_GETFL); + ret = fcntl(fd, F_SETFL, flags & (U32BITS ^ O_NONBLOCK)); + + return ret; +} + +static void _mmsvc_core_log_sigaction(int signo, siginfo_t *si, void *arg) +{ + void *trace[TUNABLE_CALLER_DEPTH]; + int tracesize; + + g_return_if_fail(si != NULL); + g_return_if_fail(arg != NULL); + + _mmsvc_core_log_sig_terminate(signo); + + LOGE("----------BEGIN MUSED DYING MESSAGE----------"); + + tracesize = backtrace(trace, TUNABLE_CALLER_DEPTH); + if (tracesize < 0) + LOGE("backtrace error: %s", strerror(errno)); + + #if defined(REG_EIP) + int i; + char **strings = NULL; + /* overwrite sigaction with caller's address for x86*/ + ucontext_t *uctxt = NULL; + uctxt = (ucontext_t *) arg; + + if (!uctxt) { + LOGE("Error - null uctxt"); + return; + } + + trace[1] = (void *) uctxt->uc_mcontext.gregs[REG_EIP]; + strings = backtrace_symbols(trace, tracesize); + if (strings == NULL) + LOGE("backtrace_symbols error: %s", strerror(errno)); + + /* skip the first stack frame because it just points here. */ + for (i = 1; i < tracesize; ++i) { + LOGE("[%u] %s", i-1, strings[i]); + if (g_mused_log) + g_mused_log->fatal(strings[i]); + } + #endif + + LOGE("----------END MUSED DYING MESSAGE----------"); + + LOGE("exit(0) - caught segfault at address %p", si->si_addr); + + exit(0); +} + +static void _mmsvc_core_log_set_log_fd(void) +{ + LOGD("Enter"); + + g_return_if_fail(g_mused_log != NULL); + + g_mused_log->log_fd = open(LOGFILE, O_CREAT | O_APPEND | O_WRONLY | O_NONBLOCK, 0666); + if (g_mused_log->log_fd < 0) { + LOGE("error: %s is not a regular file", LOGFILE); + return; + } + + if (fcntl(g_mused_log->log_fd, F_SETFD, FD_CLOEXEC) < 0) + LOGE("unable to set CLO_EXEC on log fd %d: %s", g_mused_log->log_fd, strerror(errno)); + + (void) _mmsvc_core_log_fd_set_block(g_mused_log->log_fd); + + LOGD("Leave"); +} + +static void _mmsvc_core_log_init_instance(void (*log)(char *), void (*fatal)(char *), void (*set_module_value) (int, GModule *, gboolean), gboolean(*get_module_opened) (int), GModule * (*get_module_value) (int)) +{ + g_return_if_fail(log != NULL); + g_return_if_fail(fatal != NULL); + g_return_if_fail(g_mused_log == NULL); + + int idx = 0; + + g_mused_log = calloc(1, sizeof(*g_mused_log)); + g_mused_log->buf = NULL; + g_mused_log->len = 0; + g_mused_log->log = log; + g_mused_log->fatal = fatal; + g_mused_log->set_module_value = set_module_value; + g_mused_log->get_module_opened = get_module_opened; + g_mused_log->get_module_value = get_module_value; + g_mused_log->timer = g_timer_new(); + g_mused_log->count = 0; + g_timer_stop(g_mused_log->timer); + for (idx = 0; idx < MMSVC_CLIENT_MAX; idx++) { + g_mused_log->module_opened[idx] = false; + } +} + +static void _mmsvc_core_log_monitor(char *msg) +{ + g_return_if_fail(msg != NULL); + g_return_if_fail(g_mused_log != NULL); + + if (g_mused_log->count != 0) + g_timer_continue(g_mused_log->timer); + + if (g_mused_log->log_fd < 0) { + LOGE("Error - log fd"); + return; + } + + if (write(g_mused_log->log_fd, msg, strlen(msg)) != strlen(msg)) { + LOGE("There was an error writing to testfile"); + } else { + if (write(g_mused_log->log_fd, "\n", 1) == 1) + LOGD("write %s", msg); + } + + if (g_mused_log->count != 0) + g_timer_stop(g_mused_log->timer); +} + +static void _mmsvc_core_log_fatal(char *msg) +{ + if (!msg) { + LOGE("Error - null msg"); + return; + } + + _mmsvc_core_log_monitor(msg); + + exit(-1); +} + +static void _mmsvc_core_log_set_module_value(int index, GModule *module, gboolean value) +{ + g_return_if_fail(g_mused_log != NULL); + g_return_if_fail(module != NULL); + + g_mused_log->module_opened[index] = value; + g_mused_log->module[index] = module; + LOGD("module: %p", g_mused_log->module[index]); +} + +static gboolean _mmsvc_core_log_get_module_opened(int index) +{ + g_return_val_if_fail(g_mused_log != NULL, false); + + return g_mused_log->module_opened[index]; +} + +static GModule *_mmsvc_core_log_get_module_value(int index) +{ + g_return_val_if_fail(g_mused_log != NULL, NULL); + + LOGD("module: %p", g_mused_log->module[index]); + return g_mused_log->module[index]; +} + +mmsvc_core_log_t *mmsvc_core_log_get_instance(void) +{ + if (g_mused_log == NULL) + _mmsvc_core_log_init_instance(_mmsvc_core_log_monitor, _mmsvc_core_log_fatal, _mmsvc_core_log_set_module_value, + _mmsvc_core_log_get_module_opened, _mmsvc_core_log_get_module_value); + + return g_mused_log; +} + +void mmsvc_core_log_init(void) +{ + LOGD("Enter"); + + if (g_mused_log == NULL) + _mmsvc_core_log_init_instance(_mmsvc_core_log_monitor, _mmsvc_core_log_fatal, _mmsvc_core_log_set_module_value, + _mmsvc_core_log_get_module_opened, _mmsvc_core_log_get_module_value); + + _mmsvc_core_log_set_log_fd(); + _mmsvc_core_log_init_signals(); + + LOGD("Leave"); +} diff --git a/src/mmsvc_core_module.c b/src/mmsvc_core_module.c new file mode 100644 index 0000000..e6f7033 --- /dev/null +++ b/src/mmsvc_core_module.c @@ -0,0 +1,81 @@ +/* + * mmsvc-core + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: YoungHun Kim + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "mmsvc_core_config.h" +#include "mmsvc_core_log.h" +#include "mmsvc_core_internal.h" +#include "mmsvc_core_module.h" +#include "mmsvc_core_private.h" + +GModule *mmsvc_core_module_load(int api_client) +{ + GModule *module = NULL; + + if (mmsvc_core_log_get_instance()->get_module_opened(api_client) == false) { + LOGD("api client : %d", api_client); + module = g_module_open(mmsvc_core_config_get_instance()->get_path(api_client), G_MODULE_BIND_LAZY); + + if (!module) { + LOGE("%s", g_module_error()); + return NULL; + } else { + mmsvc_core_log_get_instance()->set_module_value(api_client, module, true); + } + } else if (mmsvc_core_log_get_instance()->get_module_opened(api_client) == true) { + module = mmsvc_core_log_get_instance()->get_module_value(api_client); + LOGW("already module is opened: %p", module); + } + + return module; +} + +void mmsvc_core_module_dll_symbol(int cmd, Client client) +{ + MMSVC_MODULE_DispatchFunc *dispatcher = NULL; + + g_return_if_fail(client->ch[MUSED_CHANNEL_MSG].module != NULL); + + LOGD("cmd: %d\t client->module: %p", cmd, client->ch[MUSED_CHANNEL_MSG].module); + g_module_symbol(client->ch[MUSED_CHANNEL_MSG].module, DISPATCHER, (gpointer *)&dispatcher); + + if (dispatcher && dispatcher[cmd]) { + LOGD("dispatcher: %p", dispatcher); + dispatcher[cmd](client); + } else { + LOGE("error - dispatcher"); + return; + } +} + +gboolean mmsvc_core_module_close(Client client) +{ + g_return_val_if_fail(client != NULL, FALSE); + + mmsvc_core_log_get_instance()->set_module_value(client->api_client, client->ch[MUSED_CHANNEL_MSG].module, false); + + LOGD("Closing module %s", g_module_name(client->ch[MUSED_CHANNEL_MSG].module)); + if (!g_module_close(client->ch[MUSED_CHANNEL_MSG].module)) { + LOGE("Couldn't close module %s: %s", g_module_name(client->ch[MUSED_CHANNEL_MSG].module), g_module_error()); + return FALSE; + } + + return TRUE; +} \ No newline at end of file diff --git a/src/mmsvc_core_msg_json.c b/src/mmsvc_core_msg_json.c new file mode 100644 index 0000000..97052e9 --- /dev/null +++ b/src/mmsvc_core_msg_json.c @@ -0,0 +1,226 @@ +/* + * mmsvc-core + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: YoungHun Kim + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "json.h" +#include "json_tokener.h" +#include "mmsvc_core_msg_json.h" +#include "mmsvc_core_internal.h" + +static json_object *_mmsvc_core_msg_json_find_obj(json_object * jobj, char *find_key) +{ + size_t key_len = 0; + + g_return_val_if_fail(jobj != NULL, NULL); + + g_return_val_if_fail(find_key != NULL, NULL); + + key_len = strlen(find_key); + + json_object_object_foreach(jobj, key, val) { + if (strlen(key) == key_len && !memcmp(key, find_key, key_len)) + return val; + } + + return NULL; +} + +static void _mmsvc_core_msg_json_set_error(mused_msg_parse_err_e *err, int jerr) +{ + if (err != NULL) { + switch (jerr) { + case json_tokener_success: + *err = MUSED_MSG_PARSE_ERROR_NONE; + break; + case json_tokener_continue: + *err = MUSED_MSG_PARSE_ERROR_CONTINUE; + break; + default: + *err = MUSED_MSG_PARSE_ERROR_OTHER; + break; + } + } +} + +static json_object *_mmsvc_core_msg_json_tokener_parse_len(const char *str, int *len, mused_msg_parse_err_e *err) +{ + struct json_tokener *tok; + struct json_object *obj; + + g_return_val_if_fail(str != NULL, NULL); + g_return_val_if_fail(len != NULL, NULL); + + tok = json_tokener_new(); + + g_return_val_if_fail(tok != NULL, NULL); + + obj = json_tokener_parse_ex(tok, str, *len); + g_return_val_if_fail(obj != NULL, NULL); + + *len = tok->char_offset; + + if (tok->err != json_tokener_success) { + LOGE("Json Error(%d) : %s", tok->err, json_tokener_error_desc(tok->err)); + json_object_put(obj); + obj = NULL; + } + _mmsvc_core_msg_json_set_error(err, tok->err); + + json_tokener_free(tok); + return obj; +} + +static void _mmsvc_core_msg_json_factory_args(json_object *jobj, va_list ap) +{ + int type; + char *name; + + while ((type = va_arg(ap, int)) != 0) { + name = va_arg(ap, char *); + LOGD("name: %s ", name); + switch (type) { + case MUSED_TYPE_INT: + json_object_object_add(jobj, name, json_object_new_int(va_arg(ap, int))); + break; + case MUSED_TYPE_DOUBLE: + json_object_object_add(jobj, name, json_object_new_double(va_arg(ap, double))); + break; + case MUSED_TYPE_STRING: + json_object_object_add(jobj, name, json_object_new_string(va_arg(ap, char *))); + break; + case MUSED_TYPE_ARRAY: + { + int len = va_arg(ap, int); + int *value = va_arg(ap, int *); + int i; + json_object *jarr = json_object_new_array(); + + for (i = 0; i < len; i++) + json_object_array_add(jarr, json_object_new_int(value[i])); + json_object_object_add(jobj, name, jarr); + } + break; + default: + LOGE("Unexpected type"); + } + } +} + +char *mmsvc_core_msg_json_factory_new(int api, const char *arg_name, int arg, ...) +{ + json_object *jobj; + const char *jsonMsg; + char *sndMsg; + va_list ap; + + jobj = json_object_new_object(); + + g_return_val_if_fail(jobj != NULL, NULL); + + json_object_object_add(jobj, "api", json_object_new_int(api)); + if (arg_name) + json_object_object_add(jobj, arg_name, json_object_new_int(arg)); + else + LOGE("Error - null arg_name"); + + va_start(ap, arg); + _mmsvc_core_msg_json_factory_args(jobj, ap); + va_end(ap); + + jsonMsg = json_object_to_json_string(jobj); + sndMsg = g_strdup(jsonMsg); + LOGD("json msg : %s\n", sndMsg); + + json_object_put(jobj); + + return sndMsg; +} + +void mmsvc_core_msg_json_factory_free(char *msg) +{ + if (msg) + MMSVC_FREE(msg); +} + +gboolean mmsvc_core_msg_json_deserialize(char *key, char* buf, void *data, mused_msg_parse_err_e *err) +{ + int len = 0; + + g_return_val_if_fail(buf != NULL, FALSE); + g_return_val_if_fail(data != NULL, FALSE); + + len = strlen(buf); + return mmsvc_core_msg_json_deserialize_len(key, buf, &len, data, err); +} + +gboolean mmsvc_core_msg_json_deserialize_len(char *key, char* buf, int *parse_len, void *data, mused_msg_parse_err_e *err) +{ + int type; + json_object *val, *jobj; + + g_return_val_if_fail(key != NULL, FALSE); + g_return_val_if_fail(buf != NULL, FALSE); + g_return_val_if_fail(data != NULL, FALSE); + g_return_val_if_fail(parse_len != NULL, FALSE); + + jobj = _mmsvc_core_msg_json_tokener_parse_len(buf, parse_len, err); + g_return_val_if_fail(jobj != NULL, FALSE); + + val = _mmsvc_core_msg_json_find_obj(jobj, key); + if (!val) { + LOGE("\"%s\" key is not founded", key); + return FALSE; + } + + type = json_object_get_type(val); + switch (type) { + case json_type_null: + LOGD("json_type_null\n"); + break; + case json_type_boolean: + LOGD("json_type_boolean (%s) value: %d", key, json_object_get_boolean(val)); + break; + case json_type_double: + *(double *)data = json_object_get_double(val); + LOGD("json_type_double (%s) value: %p", key, (double *)data); + break; + case json_type_int: + *(int *)data = json_object_get_int(val); + LOGD("json_type_int (%s) value: %p", key, (int *)data); + break; + case json_type_object: + LOGD("json_type_object (%s) value: %d", key, json_object_get_object(val)); + break; + case json_type_string: + strncpy((char *)data, json_object_get_string(val), strlen(json_object_get_string(val))); + LOGD("json_type_string (%s) value: %s", key, (char *)data); + break; + case json_type_array: + LOGD("json_type_array (%s)", key); + int i, len; + int *int_data = (int *)data; + len = json_object_array_length(val); + for (i = 0; i < len; i++) + int_data[i] = json_object_get_int(json_object_array_get_idx(val, i)); + break; + } + json_object_put(jobj); + return TRUE; +} diff --git a/src/mmsvc_core_server.c b/src/mmsvc_core_server.c new file mode 100644 index 0000000..19099cd --- /dev/null +++ b/src/mmsvc_core_server.c @@ -0,0 +1,81 @@ +/* + * mmsvc-core + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: YoungHun Kim + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "mmsvc_core.h" +#include "mmsvc_core_internal.h" +#include "mmsvc_core_config.h" +#include "mmsvc_core_log.h" +#include "mmsvc_core_tool.h" + +static void _mmsvc_core_server_setup_syslog(void); +extern int mmsvc_core_run(); + +static void _mmsvc_core_server_setup_syslog(void) +{ + int flags = LOG_CONS|LOG_NDELAY|LOG_PID; + if (isatty(1)) + flags |= LOG_PERROR; + + openlog("mused", flags, LOG_DAEMON); + LOGD("openlog - mused"); +} + +int main(int argc, char **argv) +{ + int result; + pid_t pid, sid; + + _mmsvc_core_server_setup_syslog(); + mmsvc_core_log_init(); + mmsvc_core_config_init(); + + if (argc > 1 && argv) + mmsvc_core_tool_parse_params(argc, argv); + + /* daemon_init */ + if (getpid() == 1) { + LOGE("already a daemon"); + exit(0); + } + + if ((pid = fork()) < 0) { + LOGE("Could not fork child."); + exit(0); + } else if (pid != 0) { + LOGD("PID : %d, PID CLOSE!!", pid); + exit(0); + } + + /* create new session */ + sid = setsid(); + if (sid < 0) { + LOGE("sid SID : %d, PID CLOSE!!", pid); + exit(0); + } + + /* Change the file mode mask */ + umask(0); + + result = chdir("/"); + LOGD("result = %d", result); + + return mmsvc_core_run(); +} diff --git a/src/mmsvc_core_tool.c b/src/mmsvc_core_tool.c new file mode 100644 index 0000000..f9fd740 --- /dev/null +++ b/src/mmsvc_core_tool.c @@ -0,0 +1,180 @@ +/* + * mmsvc-core + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: YoungHun Kim + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "mmsvc_core_internal.h" +#include "mmsvc_core_log.h" +#include "mmsvc_core_tool.h" +#include + +#define VERSION "0.0.1" + +static int _mmsvc_core_tool_getopt(int argc, char **argv, const char *opts); + +int mmsvc_tool_optind = 1; +int mmsvc_tool_optopt; +char *mmsvc_tool_optarg; + +static const char *pid_file = NULL; +static const char *out_file = NULL; +static const char *err_file = NULL; +static const char *lock_file = NULL; +static bool be_verbose = FALSE; +static const char *user = NULL; +static char **mmsvc_cmd = NULL; +static const char *cwd = "/"; +static int append = 0; + +static int _mmsvc_core_tool_getopt(int argc, char **argv, const char *opts) +{ + static int si = 1; + register int ri; + register char *cp; + + if (si == 1) { + if (mmsvc_tool_optind >= argc ||argv[mmsvc_tool_optind][0] != '-' || argv[mmsvc_tool_optind][1] == '\0') { + return(EOF); + } else if (strcmp(argv[mmsvc_tool_optind], "--") == 0) { + mmsvc_tool_optind++; + return(EOF); + } + } + mmsvc_tool_optopt = ri = argv[mmsvc_tool_optind][si]; + if (ri == ':' || (cp=strchr(opts, ri)) == NULL) { + if (argv[mmsvc_tool_optind][++si] == '\0') { + mmsvc_tool_optind++; + si = 1; + } + return('?'); + } + if (*++cp == ':') { + if (argv[mmsvc_tool_optind][si+1] != '\0') { + mmsvc_tool_optarg = &argv[mmsvc_tool_optind++][si+1]; + LOGD("%s", mmsvc_tool_optarg); + } else if (++mmsvc_tool_optind >= argc) { + LOGE(": option requires an argument - %c", ri); + si = 1; + return('?'); + } else { + mmsvc_tool_optarg = argv[mmsvc_tool_optind++]; + LOGD("%s", mmsvc_tool_optarg); + } + si = 1; + } else { + if (argv[mmsvc_tool_optind][++si] == '\0') { + si = 1; + mmsvc_tool_optind++; + } + mmsvc_tool_optarg = NULL; + } + LOGD("mmsvc_tool_optind: %d", mmsvc_tool_optind); + return(ri); +} + +/** + * Parse the command-line parameters, setting the various globals that are affected by them. + * + * Parameters: + * argc - argument count, as passed to main() + * argv - argument vector, as passed to main() + */ +void mmsvc_core_tool_parse_params(int argc, char **argv) +{ + int opt; + int argsLeft; + + LOGD("Enter"); + opterr = 0; + + while ((opt = _mmsvc_core_tool_getopt(argc, argv, "ac:u:p:vo:e:l:")) != -1) { + switch (opt) { + case 'a': + append = 1; + break; + + case 'c': + cwd = mmsvc_tool_optarg; + break; + + case 'p': + + pid_file = mmsvc_tool_optarg; + break; + + case 'v': + be_verbose = TRUE; + break; + + case 'u': + user = mmsvc_tool_optarg; + break; + + case 'o': + out_file = mmsvc_tool_optarg; + LOGD("out file: %s", out_file); + break; + + case 'e': + err_file = mmsvc_tool_optarg; + break; + + case 'l': + lock_file = mmsvc_tool_optarg; + break; + + default: + break; + } + } + + LOGD("mmsvc_tool_optind: %d", mmsvc_tool_optind); + argsLeft = argc - mmsvc_tool_optind; + LOGD("argsLeft : %d", argsLeft); + + mmsvc_cmd = &argv[mmsvc_tool_optind]; + LOGD("cmd: %s", *mmsvc_cmd); + LOGD("Leave"); + return; +} + +void mmsvc_core_tool_recursive_rmdir(const char *path) +{ + FTS *fts; + FTSENT *ftsent; + + g_return_if_fail (path != NULL); + + char *const paths[] = { (char *)path, NULL }; + + /* This means there can't be any autofs mounts yet, so this is the first time we're being run since a reboot. Clean out any stuff left in /Network from the reboot. */ + fts = fts_open(paths, FTS_NOCHDIR | FTS_PHYSICAL, NULL); + if (fts != NULL) { + while ((ftsent = fts_read(fts)) != NULL) { + /* We only remove directories - if there are files, we assume they're there for a purpose. + * We remove directories after we've removed their children, so we want to process directories visited in post-order.*/ + if (ftsent->fts_info == FTS_DP && ftsent->fts_level >= FTS_ROOTLEVEL) + rmdir(ftsent->fts_accpath); + } + fts_close(fts); + } else { + LOGE("Error - null fts"); + return; + } +} diff --git a/src/mmsvc_core_workqueue.c b/src/mmsvc_core_workqueue.c new file mode 100644 index 0000000..946188c --- /dev/null +++ b/src/mmsvc_core_workqueue.c @@ -0,0 +1,169 @@ +/** +* Multithreaded work queue. +* Copyright (c) 2012 Ronald Bennett Cemer +* This software is licensed under the BSD license. +* See the accompanying LICENSE.txt for details. +*/ + +#include "mmsvc_core_workqueue.h" +#define WORK_THREAD_NUM 8 +#define LL_ADD(item, list) { \ + item->prev = NULL; \ + item->next = list; \ + list = item; \ +} + +#define LL_REMOVE(item, list) { \ + if (item->prev != NULL) item->prev->next = item->next; \ + if (item->next != NULL) item->next->prev = item->prev; \ + if (list == item) list = item->next; \ + item->prev = item->next = NULL; \ +} + +static mmsvc_core_workqueue_workqueue_t *g_workqueue; + +static void *_mmsvc_core_workqueue_worker_function(void *ptr); +static void _mmsvc_core_workqueue_shutdown(void); +static void _mmsvc_core_workqueue_add_job(mmsvc_core_workqueue_job_t *job); +static void _mmsvc_core_workqueue_init_instance(void (*shutdown)(void), void (*add_job)(mmsvc_core_workqueue_job_t *)); + +static void *_mmsvc_core_workqueue_worker_function(void *ptr) +{ + LOGD("Enter"); + mmsvc_core_workqueue_worker_t *worker = (mmsvc_core_workqueue_worker_t *) ptr; + mmsvc_core_workqueue_job_t *job; + + while (1) { + /* Wait until we get notified. */ + pthread_mutex_lock(&worker->workqueue->jobs_mutex); + while (worker->workqueue->waiting_jobs == NULL) { + /* If we're supposed to terminate, break out of our continuous loop. */ + if (worker->terminate) { + LOGD("worker is terminated"); + break; + } + + pthread_cond_wait(&worker->workqueue->jobs_cond, &worker->workqueue->jobs_mutex); + } + + /* If we're supposed to terminate, break out of our continuous loop. */ + if (worker->terminate) { + LOGD("worker is terminated"); + break; + } + + job = worker->workqueue->waiting_jobs; + if (job != NULL) + LL_REMOVE(job, worker->workqueue->waiting_jobs); + + pthread_mutex_unlock(&worker->workqueue->jobs_mutex); + + /* If we didn't get a job, then there's nothing to do at this time. */ + if (job == NULL) + continue; + + /* Execute the job. */ + job->job_function(job); + } + + pthread_mutex_unlock(&worker->workqueue->jobs_mutex); + MMSVC_FREE(worker); + + LOGD("Leave"); + + pthread_exit(NULL); +} + +static void _mmsvc_core_workqueue_shutdown(void) +{ + mmsvc_core_workqueue_worker_t *worker = NULL; + g_return_if_fail(g_workqueue != NULL); + LOGD("Enter"); + + /* Set all workers to terminate. */ + for (worker = g_workqueue->workers; worker != NULL; worker = worker->next) { + worker->terminate = 1; + } + + /* Remove all workers and jobs from the work queue. + * wake up all workers so that they will terminate. */ + pthread_mutex_lock(&g_workqueue->jobs_mutex); + g_workqueue->workers = NULL; + g_workqueue->waiting_jobs = NULL; + pthread_cond_broadcast(&g_workqueue->jobs_cond); + pthread_mutex_unlock(&g_workqueue->jobs_mutex); + LOGD("Leave"); +} + +static void _mmsvc_core_workqueue_add_job(mmsvc_core_workqueue_job_t *job) +{ + LOGD("Enter"); + /* Add the job to the job queue, and notify a worker. */ + pthread_mutex_lock(&g_workqueue->jobs_mutex); + LL_ADD(job, g_workqueue->waiting_jobs); + pthread_cond_signal(&g_workqueue->jobs_cond); + pthread_mutex_unlock(&g_workqueue->jobs_mutex); + LOGD("Leave"); +} + +static void _mmsvc_core_workqueue_init_instance(void (*shutdown)(void), void (*add_job)(mmsvc_core_workqueue_job_t *)) +{ + g_return_if_fail(shutdown != NULL); + g_return_if_fail(add_job != NULL); + g_return_if_fail(g_workqueue != NULL); + + g_workqueue->shutdown = shutdown; + g_workqueue->add_job = add_job; +} + +mmsvc_core_workqueue_workqueue_t *mmsvc_core_workqueue_get_instance(void) +{ + LOGD("Enter"); + if (g_workqueue == NULL) + mmsvc_core_workqueue_init(WORK_THREAD_NUM); + + LOGD("Leave"); + return g_workqueue; +} + +int mmsvc_core_workqueue_init(int numWorkers) +{ + int i; + mmsvc_core_workqueue_worker_t *worker; + LOGD("Enter"); + pthread_cond_t blank_cond = PTHREAD_COND_INITIALIZER; + pthread_mutex_t blank_mutex = PTHREAD_MUTEX_INITIALIZER; + + g_workqueue = calloc(1, sizeof(mmsvc_core_workqueue_workqueue_t)); + if (!g_workqueue) { + LOGE("workqueue allocation failed"); + return 1; + } + + if (numWorkers < 1) + numWorkers = 1; + memset(g_workqueue, 0, sizeof(*g_workqueue)); + memcpy(&g_workqueue->jobs_mutex, &blank_mutex, sizeof(g_workqueue->jobs_mutex)); + memcpy(&g_workqueue->jobs_cond, &blank_cond, sizeof(g_workqueue->jobs_cond)); + + for (i = 0; i < numWorkers; i++) { + worker = malloc(sizeof(mmsvc_core_workqueue_worker_t)); + if (worker == NULL) { + LOGE("Failed to allocate all workers"); + return 1; + } + memset(worker, 0, sizeof(*worker)); + worker->workqueue = g_workqueue; + if (pthread_create(&worker->thread, NULL, _mmsvc_core_workqueue_worker_function, (void *)worker)) { + LOGE("Failed to start all worker threads"); + MMSVC_FREE(worker); + return 1; + } + LL_ADD(worker, worker->workqueue->workers); + } + + _mmsvc_core_workqueue_init_instance(_mmsvc_core_workqueue_shutdown, _mmsvc_core_workqueue_add_job); + + LOGD("Leave"); + return 0; +} \ No newline at end of file