Initial release 72/42972/4 master
authorYoungHun Kim <yh8004.kim@samsung.com>
Mon, 6 Jul 2015 11:38:06 +0000 (20:38 +0900)
committerYoungHun Kim <yh8004.kim@samsung.com>
Fri, 10 Jul 2015 05:13:44 +0000 (14:13 +0900)
Change-Id: Ibbb9e47dee247eef0d0f1d583722a79c986d4f89

29 files changed:
AUTHORS [new file with mode: 0755]
CMakeLists.txt [new file with mode: 0755]
LICENSE.APLv2 [new file with mode: 0755]
NOTICE [new file with mode: 0755]
config/mused.conf [new file with mode: 0644]
include/mmsvc_core.h [new file with mode: 0644]
include/mmsvc_core_config.h [new file with mode: 0644]
include/mmsvc_core_internal.h [new file with mode: 0644]
include/mmsvc_core_ipc.h [new file with mode: 0644]
include/mmsvc_core_log.h [new file with mode: 0755]
include/mmsvc_core_module.h [new file with mode: 0644]
include/mmsvc_core_msg_json.h [new file with mode: 0644]
include/mmsvc_core_private.h [new file with mode: 0644]
include/mmsvc_core_tool.h [new file with mode: 0755]
include/mmsvc_core_workqueue.h [new file with mode: 0644]
mused.manifest [new file with mode: 0755]
mused.pc.in [new file with mode: 0755]
packaging/mused.service [new file with mode: 0644]
packaging/mused.socket [new file with mode: 0644]
packaging/mused.spec [new file with mode: 0644]
src/mmsvc_core.c [new file with mode: 0644]
src/mmsvc_core_config.c [new file with mode: 0644]
src/mmsvc_core_ipc.c [new file with mode: 0644]
src/mmsvc_core_log.c [new file with mode: 0644]
src/mmsvc_core_module.c [new file with mode: 0644]
src/mmsvc_core_msg_json.c [new file with mode: 0644]
src/mmsvc_core_server.c [new file with mode: 0644]
src/mmsvc_core_tool.c [new file with mode: 0644]
src/mmsvc_core_workqueue.c [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
new file mode 100755 (executable)
index 0000000..48abac3
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,3 @@
+YoungHun Kim <yh8004.kim@samsung.com>\r
+Hee Chul Jeon <heechul.jeon@samsung.com>\r
+JongHyuk Choi <jhchoi.choi@samsung.com>\r
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..ef20cae
--- /dev/null
@@ -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 (executable)
index 0000000..bbe9d02
--- /dev/null
@@ -0,0 +1,206 @@
+Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.\r
+\r
+                                 Apache License\r
+                           Version 2.0, January 2004\r
+                        http://www.apache.org/licenses/\r
+\r
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\r
+\r
+   1. Definitions.\r
+\r
+      "License" shall mean the terms and conditions for use, reproduction,\r
+      and distribution as defined by Sections 1 through 9 of this document.\r
+\r
+      "Licensor" shall mean the copyright owner or entity authorized by\r
+      the copyright owner that is granting the License.\r
+\r
+      "Legal Entity" shall mean the union of the acting entity and all\r
+      other entities that control, are controlled by, or are under common\r
+      control with that entity. For the purposes of this definition,\r
+      "control" means (i) the power, direct or indirect, to cause the\r
+      direction or management of such entity, whether by contract or\r
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the\r
+      outstanding shares, or (iii) beneficial ownership of such entity.\r
+\r
+      "You" (or "Your") shall mean an individual or Legal Entity\r
+      exercising permissions granted by this License.\r
+\r
+      "Source" form shall mean the preferred form for making modifications,\r
+      including but not limited to software source code, documentation\r
+      source, and configuration files.\r
+\r
+      "Object" form shall mean any form resulting from mechanical\r
+      transformation or translation of a Source form, including but\r
+      not limited to compiled object code, generated documentation,\r
+      and conversions to other media types.\r
+\r
+      "Work" shall mean the work of authorship, whether in Source or\r
+      Object form, made available under the License, as indicated by a\r
+      copyright notice that is included in or attached to the work\r
+      (an example is provided in the Appendix below).\r
+\r
+      "Derivative Works" shall mean any work, whether in Source or Object\r
+      form, that is based on (or derived from) the Work and for which the\r
+      editorial revisions, annotations, elaborations, or other modifications\r
+      represent, as a whole, an original work of authorship. For the purposes\r
+      of this License, Derivative Works shall not include works that remain\r
+      separable from, or merely link (or bind by name) to the interfaces of,\r
+      the Work and Derivative Works thereof.\r
+\r
+      "Contribution" shall mean any work of authorship, including\r
+      the original version of the Work and any modifications or additions\r
+      to that Work or Derivative Works thereof, that is intentionally\r
+      submitted to Licensor for inclusion in the Work by the copyright owner\r
+      or by an individual or Legal Entity authorized to submit on behalf of\r
+      the copyright owner. For the purposes of this definition, "submitted"\r
+      means any form of electronic, verbal, or written communication sent\r
+      to the Licensor or its representatives, including but not limited to\r
+      communication on electronic mailing lists, source code control systems,\r
+      and issue tracking systems that are managed by, or on behalf of, the\r
+      Licensor for the purpose of discussing and improving the Work, but\r
+      excluding communication that is conspicuously marked or otherwise\r
+      designated in writing by the copyright owner as "Not a Contribution."\r
+\r
+      "Contributor" shall mean Licensor and any individual or Legal Entity\r
+      on behalf of whom a Contribution has been received by Licensor and\r
+      subsequently incorporated within the Work.\r
+\r
+   2. Grant of Copyright License. Subject to the terms and conditions of\r
+      this License, each Contributor hereby grants to You a perpetual,\r
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r
+      copyright license to reproduce, prepare Derivative Works of,\r
+      publicly display, publicly perform, sublicense, and distribute the\r
+      Work and such Derivative Works in Source or Object form.\r
+\r
+   3. Grant of Patent License. Subject to the terms and conditions of\r
+      this License, each Contributor hereby grants to You a perpetual,\r
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r
+      (except as stated in this section) patent license to make, have made,\r
+      use, offer to sell, sell, import, and otherwise transfer the Work,\r
+      where such license applies only to those patent claims licensable\r
+      by such Contributor that are necessarily infringed by their\r
+      Contribution(s) alone or by combination of their Contribution(s)\r
+      with the Work to which such Contribution(s) was submitted. If You\r
+      institute patent litigation against any entity (including a\r
+      cross-claim or counterclaim in a lawsuit) alleging that the Work\r
+      or a Contribution incorporated within the Work constitutes direct\r
+      or contributory patent infringement, then any patent licenses\r
+      granted to You under this License for that Work shall terminate\r
+      as of the date such litigation is filed.\r
+\r
+   4. Redistribution. You may reproduce and distribute copies of the\r
+      Work or Derivative Works thereof in any medium, with or without\r
+      modifications, and in Source or Object form, provided that You\r
+      meet the following conditions:\r
+\r
+      (a) You must give any other recipients of the Work or\r
+          Derivative Works a copy of this License; and\r
+\r
+      (b) You must cause any modified files to carry prominent notices\r
+          stating that You changed the files; and\r
+\r
+      (c) You must retain, in the Source form of any Derivative Works\r
+          that You distribute, all copyright, patent, trademark, and\r
+          attribution notices from the Source form of the Work,\r
+          excluding those notices that do not pertain to any part of\r
+          the Derivative Works; and\r
+\r
+      (d) If the Work includes a "NOTICE" text file as part of its\r
+          distribution, then any Derivative Works that You distribute must\r
+          include a readable copy of the attribution notices contained\r
+          within such NOTICE file, excluding those notices that do not\r
+          pertain to any part of the Derivative Works, in at least one\r
+          of the following places: within a NOTICE text file distributed\r
+          as part of the Derivative Works; within the Source form or\r
+          documentation, if provided along with the Derivative Works; or,\r
+          within a display generated by the Derivative Works, if and\r
+          wherever such third-party notices normally appear. The contents\r
+          of the NOTICE file are for informational purposes only and\r
+          do not modify the License. You may add Your own attribution\r
+          notices within Derivative Works that You distribute, alongside\r
+          or as an addendum to the NOTICE text from the Work, provided\r
+          that such additional attribution notices cannot be construed\r
+          as modifying the License.\r
+\r
+      You may add Your own copyright statement to Your modifications and\r
+      may provide additional or different license terms and conditions\r
+      for use, reproduction, or distribution of Your modifications, or\r
+      for any such Derivative Works as a whole, provided Your use,\r
+      reproduction, and distribution of the Work otherwise complies with\r
+      the conditions stated in this License.\r
+\r
+   5. Submission of Contributions. Unless You explicitly state otherwise,\r
+      any Contribution intentionally submitted for inclusion in the Work\r
+      by You to the Licensor shall be under the terms and conditions of\r
+      this License, without any additional terms or conditions.\r
+      Notwithstanding the above, nothing herein shall supersede or modify\r
+      the terms of any separate license agreement you may have executed\r
+      with Licensor regarding such Contributions.\r
+\r
+   6. Trademarks. This License does not grant permission to use the trade\r
+      names, trademarks, service marks, or product names of the Licensor,\r
+      except as required for reasonable and customary use in describing the\r
+      origin of the Work and reproducing the content of the NOTICE file.\r
+\r
+   7. Disclaimer of Warranty. Unless required by applicable law or\r
+      agreed to in writing, Licensor provides the Work (and each\r
+      Contributor provides its Contributions) on an "AS IS" BASIS,\r
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\r
+      implied, including, without limitation, any warranties or conditions\r
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\r
+      PARTICULAR PURPOSE. You are solely responsible for determining the\r
+      appropriateness of using or redistributing the Work and assume any\r
+      risks associated with Your exercise of permissions under this License.\r
+\r
+   8. Limitation of Liability. In no event and under no legal theory,\r
+      whether in tort (including negligence), contract, or otherwise,\r
+      unless required by applicable law (such as deliberate and grossly\r
+      negligent acts) or agreed to in writing, shall any Contributor be\r
+      liable to You for damages, including any direct, indirect, special,\r
+      incidental, or consequential damages of any character arising as a\r
+      result of this License or out of the use or inability to use the\r
+      Work (including but not limited to damages for loss of goodwill,\r
+      work stoppage, computer failure or malfunction, or any and all\r
+      other commercial damages or losses), even if such Contributor\r
+      has been advised of the possibility of such damages.\r
+\r
+   9. Accepting Warranty or Additional Liability. While redistributing\r
+      the Work or Derivative Works thereof, You may choose to offer,\r
+      and charge a fee for, acceptance of support, warranty, indemnity,\r
+      or other liability obligations and/or rights consistent with this\r
+      License. However, in accepting such obligations, You may act only\r
+      on Your own behalf and on Your sole responsibility, not on behalf\r
+      of any other Contributor, and only if You agree to indemnify,\r
+      defend, and hold each Contributor harmless for any liability\r
+      incurred by, or claims asserted against, such Contributor by reason\r
+      of your accepting any such warranty or additional liability.\r
+\r
+   END OF TERMS AND CONDITIONS\r
+\r
+   APPENDIX: How to apply the Apache License to your work.\r
+\r
+      To apply the Apache License to your work, attach the following\r
+      boilerplate notice, with the fields enclosed by brackets "[]"\r
+      replaced with your own identifying information. (Don't include\r
+      the brackets!)  The text should be enclosed in the appropriate\r
+      comment syntax for the file format. We also recommend that a\r
+      file or class name and description of purpose be included on the\r
+      same "printed page" as the copyright notice for easier\r
+      identification within third-party archives.\r
+\r
+   Copyright [yyyy] [name of copyright owner]\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+\r
+\r
diff --git a/NOTICE b/NOTICE
new file mode 100755 (executable)
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 (file)
index 0000000..0369b22
--- /dev/null
@@ -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 (file)
index 0000000..fbdd71a
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * mmsvc-core
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: YoungHun Kim <yh8004.kim@samsung.com>
+ *
+ * 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 (file)
index 0000000..882d82e
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * mmsvc-core
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: YoungHun Kim <yh8004.kim@samsung.com>
+ *
+ * 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 <iniparser.h>
+
+#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 (file)
index 0000000..ad6afaa
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * mmsvc-core
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: YoungHun Kim <yh8004.kim@samsung.com>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <limits.h>
+#include <errno.h>
+#include <err.h>
+#include <glib.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <gmodule.h>
+#include <stdbool.h>
+#include <dlog.h>
+#include <syslog.h>
+#include <execinfo.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/poll.h>
+#include <sys/un.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <pthread.h>
+
+#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 (file)
index 0000000..e417ba2
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * mmsvc-core
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: YoungHun Kim <yh8004.kim@samsung.com>
+ *
+ * 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 (executable)
index 0000000..929c25f
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * mmsvc-core
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: YoungHun Kim <yh8004.kim@samsung.com>
+ *
+ * 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 <time.h>
+#include <gmodule.h>
+#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 (file)
index 0000000..38d0642
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * mmsvc-core
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: YoungHun Kim <yh8004.kim@samsung.com>
+ *
+ * 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 (file)
index 0000000..dd23222
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * mmsvc-core
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: YoungHun Kim <yh8004.kim@samsung.com>
+ *
+ * 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 <glib.h>
+
+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 (file)
index 0000000..65e7ff7
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * mmsvc-core
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: YoungHun Kim <yh8004.kim@samsung.com>
+ *
+ * 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 <glib.h>
+#include <gmodule.h>
+
+#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 (executable)
index 0000000..5400060
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * mmsvc-core
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: YoungHun Kim <yh8004.kim@samsung.com>
+ *
+ * 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 (file)
index 0000000..655b11f
--- /dev/null
@@ -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 (executable)
index 0000000..b987928
--- /dev/null
@@ -0,0 +1,9 @@
+<manifest>
+       <request>
+               <domain name="_" />
+       </request>
+       <assign>
+               <filesystem path="/usr/bin/mused-server" label="_" exec_label="none" />
+
+       </assign>
+</manifest>
diff --git a/mused.pc.in b/mused.pc.in
new file mode 100755 (executable)
index 0000000..cd88bcc
--- /dev/null
@@ -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 (file)
index 0000000..490f8f7
--- /dev/null
@@ -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 (file)
index 0000000..73a5f6c
--- /dev/null
@@ -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 (file)
index 0000000..7eb7cd2
--- /dev/null
@@ -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 (file)
index 0000000..92ca12b
--- /dev/null
@@ -0,0 +1,501 @@
+/*
+ * mmsvc-core
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: YoungHun Kim <yh8004.kim@samsung.com>
+ *
+ * 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 (file)
index 0000000..fe15e8c
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * mmsvc-core
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: YoungHun Kim <yh8004.kim@samsung.com>
+ *
+ * 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 (file)
index 0000000..d9fbaa5
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * mmsvc-core
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: YoungHun Kim <yh8004.kim@samsung.com>
+ *
+ * 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 (file)
index 0000000..6e0ca3e
--- /dev/null
@@ -0,0 +1,377 @@
+/*
+ * mmsvc-core
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: YoungHun Kim <yh8004.kim@samsung.com>
+ *
+ * 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 <ucontext.h>
+
+/* 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 (file)
index 0000000..e6f7033
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * mmsvc-core
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: YoungHun Kim <yh8004.kim@samsung.com>
+ *
+ * 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 (file)
index 0000000..97052e9
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * mmsvc-core
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: YoungHun Kim <yh8004.kim@samsung.com>
+ *
+ * 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 (file)
index 0000000..19099cd
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * mmsvc-core
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: YoungHun Kim <yh8004.kim@samsung.com>
+ *
+ * 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 (file)
index 0000000..f9fd740
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * mmsvc-core
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: YoungHun Kim <yh8004.kim@samsung.com>
+ *
+ * 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 <fts.h>
+
+#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 (file)
index 0000000..946188c
--- /dev/null
@@ -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