sync with master
authorJinkun Jang <jinkun.jang@samsung.com>
Sat, 16 Mar 2013 12:33:50 +0000 (21:33 +0900)
committerJinkun Jang <jinkun.jang@samsung.com>
Sat, 16 Mar 2013 12:33:50 +0000 (21:33 +0900)
23 files changed:
CMakeLists.txt [new file with mode: 0644]
LICENSE [new file with mode: 0644]
com-core.pc.in [new file with mode: 0644]
include/com-core.h [new file with mode: 0644]
include/com-core_internal.h [new file with mode: 0644]
include/com-core_packet-router.h [new file with mode: 0644]
include/com-core_packet.h [new file with mode: 0644]
include/com-core_thread.h [new file with mode: 0644]
include/debug.h [new file with mode: 0644]
include/dlist.h [new file with mode: 0644]
include/packet.h [new file with mode: 0644]
include/secure_socket.h [new file with mode: 0644]
include/util.h [new file with mode: 0644]
libcom-core.manifest [new file with mode: 0644]
packaging/libcom-core.spec [new file with mode: 0644]
src/com-core.c [new file with mode: 0644]
src/com-core_packet-router.c [new file with mode: 0644]
src/com-core_packet.c [new file with mode: 0644]
src/com-core_thread.c [new file with mode: 0644]
src/dlist.c [new file with mode: 0644]
src/packet.c [new file with mode: 0644]
src/secure_socket.c [new file with mode: 0644]
src/util.c [new file with mode: 0644]

diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..584bf53
--- /dev/null
@@ -0,0 +1,57 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(com-core C)
+
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+SET(EXEC_PREFIX "\${prefix}")
+SET(PROJECT_NAME "${PROJECT_NAME}")
+SET(LIBDIR "\${exec_prefix}/lib")
+SET(INCLUDEDIR "\${prefix}/include/${PROJECT_NAME}")
+SET(VERSION_MAJOR 0)
+SET(VERSION "${VERSION_MAJOR}.0.1")
+
+set(CMAKE_SKIP_BUILD_RPATH true)
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include)
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(pkgs REQUIRED
+       glib-2.0
+       dlog
+)
+
+FOREACH(flag ${pkgs_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden -g -Wall -Werror -Winline")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+
+ADD_DEFINITIONS("-DPREFIX=\"${PREFIX}\"")
+ADD_DEFINITIONS("-DLOG_TAG=\"COM_CORE\"")
+ADD_DEFINITIONS("-DNDEBUG")
+
+ADD_LIBRARY(${PROJECT_NAME} SHARED
+       src/dlist.c
+       src/com-core.c
+       src/util.c
+       src/packet.c
+       src/com-core_packet.c
+       src/secure_socket.c
+       src/com-core_thread.c
+       src/com-core_packet-router.c
+)
+SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SOVERSION ${VERSION_MAJOR})
+SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES VERSION ${VERSION})
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS})
+
+CONFIGURE_FILE(${PROJECT_NAME}.pc.in ${PROJECT_NAME}.pc @ONLY)
+SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${PROJECT_NAME}.pc")
+
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION lib)
+INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc DESTINATION lib/pkgconfig)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/include/secure_socket.h DESTINATION include/${PROJECT_NAME})
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/include/com-core.h DESTINATION include/${PROJECT_NAME})
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/include/com-core_packet.h DESTINATION include/${PROJECT_NAME})
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/include/com-core_thread.h DESTINATION include/${PROJECT_NAME})
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/include/packet.h DESTINATION include/${PROJECT_NAME})
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/LICENSE DESTINATION /usr/share/license RENAME "lib${PROJECT_NAME}")
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..9c13a9b
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,204 @@
+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
diff --git a/com-core.pc.in b/com-core.pc.in
new file mode 100644 (file)
index 0000000..e1f99da
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@PREFIX@
+exec_prefix=@EXEC_PREFIX@
+libdir=@LIBDIR@
+includedir=@INCLUDEDIR@
+
+Name: com-core
+Description: Light-weight IPC supporting library
+Version: @VERSION@
+Libs: -L${libdir} -lcom-core
+Cflags: -I${includedir}
+cppflags: -I${includedir}
diff --git a/include/com-core.h b/include/com-core.h
new file mode 100644 (file)
index 0000000..5737b83
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 _COM_CORE_H
+#define _COM_CORE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum com_core_event_type {
+       CONNECTOR_CONNECTED,
+       CONNECTOR_DISCONNECTED,
+};
+
+extern int com_core_server_create(const char *addr, int is_sync, int (*service_cb)(int fd, void *data), void *data);
+extern int com_core_client_create(const char *addr, int is_sync, int (*service_cb)(int fd, void *data), void *data);
+extern int com_core_server_destroy(int handle);
+extern int com_core_client_destroy(int handle);
+
+/*!
+ * \brief Used to handling the changing event of connection status.
+ *        These two functions can be work with com_core_thread series functions.
+ */
+extern int com_core_add_event_callback(enum com_core_event_type type, int (*service_cb)(int handle, void *data), void *data);
+extern void *com_core_del_event_callback(enum com_core_event_type type, int (*service_cb)(int handle, void *data), void *data);
+
+/*!
+ * \brief If the connection is lost, this recv function will call the disconnected callback.
+ */
+extern int com_core_recv(int handle, char *buffer, int size, int *sender_pid, double timeout);
+extern int com_core_send(int handle, const char *buffer, int size, double timeout);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+/* End of a file */
diff --git a/include/com-core_internal.h b/include/com-core_internal.h
new file mode 100644 (file)
index 0000000..6ba36c2
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+*/
+
+extern void invoke_con_cb_list(int handle);
+extern void invoke_disconn_cb_list(int handle);
+
+/* End of a file */
diff --git a/include/com-core_packet-router.h b/include/com-core_packet-router.h
new file mode 100644 (file)
index 0000000..a484281
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 _COM_CORE_PACKET_ROUTER_H
+#define _COM_CORE_PACKET_ROUTER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum com_core_route_event_type {
+       COM_CORE_ROUTE_CONNECTED,
+       COM_CORE_ROUTE_DISCONNECTED,
+       COM_CORE_ROUTE_ERROR,
+};
+
+extern int com_core_packet_router_add_route(int handle, unsigned long address, int to);
+extern int com_core_packet_router_del_route(int handle, unsigned long address);
+extern int com_core_packet_router_update_route(int handle, unsigned long address, int to);
+
+extern int com_core_packet_router_add_event_callback(enum com_core_route_event_type type, int (*evt_cb)(int handle, void *data), void *data);
+extern int com_core_packet_router_del_event_callback(enum com_core_route_event_type type, int (*evt_cb)(int handle, void *data), void *data);
+
+extern int com_core_packet_router_server_init(const char *sock, double timeout, struct method *table);
+extern void *com_core_packet_router_server_fini(int handle);
+
+extern int com_core_packet_router_client_init(const char *sock, double timeout, struct method *table);
+extern void *com_core_packet_router_client_fini(int handle);
+
+extern int com_core_packet_router_async_send(int handle, struct packet *packet, double timeout, int (*recv_cb)(pid_t pid, int handle, const struct packet *packet, void *data), void *data);
+extern int com_core_packet_router_send_only(int handle, struct packet *packet);
+extern struct packet *com_core_packet_router_oneshot_send(const char *addr, struct packet *packet, double timeout);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+/* End of a file */
diff --git a/include/com-core_packet.h b/include/com-core_packet.h
new file mode 100644 (file)
index 0000000..ddb18f8
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 _COM_CORE_PACKET_H
+#define _COM_CORE_PACKET_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct method {
+       const char *cmd;
+       struct packet *(*handler)(pid_t pid, int handle, const struct packet *packet);
+};
+
+extern int com_core_packet_async_send(int handle, struct packet *packet, double timeout, int (*recv_cb)(pid_t pid, int handle, const struct packet *packet, void *data), void *data);
+extern int com_core_packet_send_only(int handle, struct packet *packet);
+extern struct packet *com_core_packet_oneshot_send(const char *addr, struct packet *packet, double timeout);
+extern int com_core_packet_client_init(const char *addr, int is_sync, struct method *table);
+extern int com_core_packet_client_fini(int handle);
+extern int com_core_packet_server_init(const char *addr, struct method *table);
+extern int com_core_packet_server_fini(int handle);
+extern void com_core_packet_use_thread(int flag);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+/* End of a file */
diff --git a/include/com-core_thread.h b/include/com-core_thread.h
new file mode 100644 (file)
index 0000000..0a6b375
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 _COM_CORE_THREAD_H
+#define _COM_CORE_THREAD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int com_core_thread_client_create(const char *addr, int is_sync, int (*service_cb)(int fd, void *data), void *data);
+extern int com_core_thread_server_create(const char *addr, int is_sync, int (*service_cb)(int fd, void *data), void *data);
+
+extern int com_core_thread_server_destroy(int handle);
+extern int com_core_thread_client_destroy(int handle);
+
+extern int com_core_thread_recv(int handle, char *buffer, int size, int *sender_pid, double timeout);
+extern int com_core_thread_send(int handle, const char *buffer, int size, double timeout);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+/* End of a file */
diff --git a/include/debug.h b/include/debug.h
new file mode 100644 (file)
index 0000000..4de89c5
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+*/
+
+#if !defined(FLOG)
+#define DbgPrint(format, arg...)       LOGD("[\e[32m%s/%s\e[0m:%d] " format, util_basename(__FILE__), __func__, __LINE__, ##arg)
+#define ErrPrint(format, arg...)       LOGE("[\e[32m%s/%s\e[0m:%d] " format, util_basename(__FILE__), __func__, __LINE__, ##arg)
+#else
+extern FILE *__file_log_fp;
+#define DbgPrint(format, arg...) do { fprintf(__file_log_fp, "[LOG] [\e[32m%s/%s\e[0m:%d] " format, util_basename(__FILE__), __func__, __LINE__, ##arg); fflush(__file_log_fp); } while (0)
+
+#define ErrPrint(format, arg...) do { fprintf(__file_log_fp, "[ERR] [\e[32m%s/%s\e[0m:%d] " format, util_basename(__FILE__), __func__, __LINE__, ##arg); fflush(__file_log_fp); } while (0)
+#endif
+
+#define EAPI __attribute__((visibility("default")))
+#define HAPI __attribute__((visibility("hidden")))
+
+/* End of a file */
diff --git a/include/dlist.h b/include/dlist.h
new file mode 100644 (file)
index 0000000..f840f92
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+*/
+
+#define dlist_remove_data(list, data) do { \
+       struct dlist *l; \
+       l = dlist_find_data(list, data); \
+       list = dlist_remove(list, l); \
+} while (0)
+
+#define dlist_foreach(list, l, data) \
+       for ((l) = (list); (l) && ((data) = dlist_data(l)); (l) = dlist_next(l))
+
+#define dlist_foreach_safe(list, l, n, data) \
+       for ((l) = (list), (n) = dlist_next(l); \
+               (l) && ((data) = dlist_data(l)); \
+               (l) = (n), (n) = dlist_next(l))
+
+struct dlist;
+
+extern struct dlist *dlist_append(struct dlist *list, void *data);
+extern struct dlist *dlist_prepend(struct dlist *list, void *data);
+extern struct dlist *dlist_remove(struct dlist *list, struct dlist *l);
+extern struct dlist *dlist_find_data(struct dlist *list, void *data);
+extern void *dlist_data(struct dlist *l);
+extern struct dlist *dlist_next(struct dlist *l);
+extern struct dlist *dlist_prev(struct dlist *l);
+extern int dlist_count(struct dlist *l);
+extern struct dlist *dlist_nth(struct dlist *l, int nth);
+
+/* End of a file */
diff --git a/include/packet.h b/include/packet.h
new file mode 100644 (file)
index 0000000..9881ce5
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 _PACKET_H
+#define _PACKET_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct packet;
+
+enum packet_type {
+       PACKET_REQ,
+       PACKET_ACK,
+       PACKET_REQ_NOACK,
+       PACKET_ERROR,
+};
+
+enum packet_flag {
+       PACKET_FLAG_NOROUTE = 0x00, /*!< If possible, route this packet without care of the server */
+       PACKET_FLAG_ROUTE = 0x01, /*!< This packet must has to be cared by the server */
+
+       PACKET_FLAG_ERROR = 0xFF, /*!< Invalid flag */
+};
+
+#define PACKET_VERSION 2
+#define PACKET_MAX_CMD 24
+
+extern struct packet *packet_create(const char *command, const char *fmt, ...);
+extern struct packet *packet_create_noack(const char *command, const char *fmt, ...);
+extern struct packet *packet_create_reply(const struct packet *packet, const char *fmt, ...);
+extern int packet_get(const struct packet *packet, const char *fmt, ...);
+extern int packet_destroy(struct packet *packet);
+extern struct packet *packet_ref(struct packet *packet);
+extern struct packet *packet_unref(struct packet *packet);
+
+extern const void * const packet_data(const struct packet *packet);
+extern const double const packet_seq(const struct packet *packet);
+extern const enum packet_type const packet_type(const struct packet *packet);
+
+extern const enum packet_flag const packet_flag(const struct packet *packet);
+extern int packet_set_flag(struct packet *packet, enum packet_flag flag);
+extern const unsigned long const packet_source(const struct packet *packet);
+extern int packet_set_source(struct packet *packet, unsigned long source);
+extern const unsigned long const packet_destination(const struct packet *packet);
+extern int packet_set_destination(struct packet *packet, unsigned long destination);
+extern int packet_set_mask(struct packet *packet, unsigned long mask);
+extern unsigned long packet_mask(const struct packet *packet);
+extern int packet_swap_address(struct packet *packet);
+
+extern const int const packet_version(const struct packet *packet);
+extern const int const packet_payload_size(const struct packet *packet);
+extern const char * const packet_command(const const struct packet *packet);
+extern const int const packet_header_size(void);
+extern const int const packet_size(const struct packet *packet);
+
+extern struct packet *packet_build(struct packet *packet, int offset, void *data, int size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+/* End of a file */
diff --git a/include/secure_socket.h b/include/secure_socket.h
new file mode 100644 (file)
index 0000000..24039bb
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 _SECURE_SOCKET_H
+#define _SECURE_SOCKET_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * Create client connection
+ */
+extern int secure_socket_create_client(const char *peer);
+
+/*
+ * Create server connection
+ */
+extern int secure_socket_create_server(const char *peer);
+
+/*
+ * Get the raw handle to use it for non-blocking mode.
+ */
+extern int secure_socket_get_connection_handle(int server_handle);
+
+/*
+ * Send data to the connected peer.
+ */
+extern int secure_socket_send(int conn, const char *buffer, int size);
+
+/*
+ * Recv data from the connected peer. and its PID value
+ */
+extern int secure_socket_recv(int conn, char *buffer, int size, int *sender_pid);
+
+/*
+ * Destroy a connection
+ */
+extern int secure_socket_destroy_handle(int conn);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+/* End of a file */
diff --git a/include/util.h b/include/util.h
new file mode 100644 (file)
index 0000000..0dfa576
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+*/
+
+extern const char *util_basename(const char *name);
+
+#define CRITICAL_SECTION_BEGIN(handle) \
+do { \
+       int ret; \
+       ret = pthread_mutex_lock(handle); \
+       if (ret != 0) \
+               ErrPrint("Failed to lock: %s\n", strerror(ret)); \
+} while (0)
+
+#define CRITICAL_SECTION_END(handle) \
+do { \
+       int ret; \
+       ret = pthread_mutex_unlock(handle); \
+       if (ret != 0) \
+               ErrPrint("Failed to unlock: %s\n", strerror(ret)); \
+} while (0)
+
+/* End of a file */
diff --git a/libcom-core.manifest b/libcom-core.manifest
new file mode 100644 (file)
index 0000000..a76fdba
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+       <request>
+               <domain name="_" />
+       </request>
+</manifest>
diff --git a/packaging/libcom-core.spec b/packaging/libcom-core.spec
new file mode 100644 (file)
index 0000000..4edc40b
--- /dev/null
@@ -0,0 +1,52 @@
+Name: libcom-core
+Summary: Library for the light-weight IPC 
+Version: 0.3.12
+Release: 1
+Group: main/util
+License: Apache License
+Source0: %{name}-%{version}.tar.gz
+BuildRequires: cmake, gettext-tools, coreutils
+BuildRequires: pkgconfig(dlog)
+BuildRequires: pkgconfig(glib-2.0)
+
+%description
+Light-weight IPC supporting library
+
+%package devel
+Summary: Files for using API for light-weight IPC.
+Group: Development/Libraries
+Requires: %{name} = %{version}-%{release}
+
+%description devel
+Light-weight IPC supporting library (dev)
+
+%prep
+%setup -q
+
+%build
+cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix}
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+%make_install
+mkdir -p %{buildroot}/%{_datarootdir}/license
+
+%post
+
+%files -n libcom-core
+%manifest libcom-core.manifest
+%defattr(-,root,root,-)
+%{_libdir}/*.so*
+%{_datarootdir}/license/*
+
+%files devel
+%defattr(-,root,root,-)
+%{_includedir}/com-core/com-core.h
+%{_includedir}/com-core/packet.h
+%{_includedir}/com-core/com-core_packet.h
+%{_includedir}/com-core/com-core_thread.h
+%{_includedir}/com-core/secure_socket.h
+%{_libdir}/pkgconfig/*.pc
+
+# End of a file
diff --git a/src/com-core.c b/src/com-core.c
new file mode 100644 (file)
index 0000000..b1ed65f
--- /dev/null
@@ -0,0 +1,495 @@
+/*
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+#include <glib.h>
+
+#include <dlog.h>
+
+#include "dlist.h"
+#include "secure_socket.h"
+#include "debug.h"
+#include "com-core.h"
+#include "com-core_internal.h"
+#include "util.h"
+
+static struct {
+       struct dlist *conn_cb_list;
+       struct dlist *disconn_cb_list;
+} s_info = {
+       .conn_cb_list = NULL,
+       .disconn_cb_list = NULL,
+};
+
+struct cbdata {
+       int (*service_cb)(int fd, void *data);
+       void *data;
+};
+
+struct evtdata {
+       int (*evt_cb)(int fd, void *data);
+       void *data;
+};
+
+HAPI void invoke_con_cb_list(int handle)
+{
+       struct dlist *l;
+       struct dlist *n;
+       struct evtdata *cbdata;
+
+       dlist_foreach_safe(s_info.conn_cb_list, l, n, cbdata) {
+               if (cbdata->evt_cb(handle, cbdata->data) < 0) {
+                       if (dlist_find_data(s_info.conn_cb_list, cbdata)) {
+                               s_info.conn_cb_list = dlist_remove(s_info.conn_cb_list, l);
+                               free(cbdata);
+                       }
+               }
+       }
+}
+
+HAPI void invoke_disconn_cb_list(int handle)
+{
+       struct dlist *l;
+       struct dlist *n;
+       struct evtdata *cbdata;
+
+       dlist_foreach_safe(s_info.disconn_cb_list, l, n, cbdata) {
+               if (cbdata->evt_cb(handle, cbdata->data) < 0) {
+                       if (dlist_find_data(s_info.disconn_cb_list, cbdata)) {
+                               s_info.disconn_cb_list = dlist_remove(s_info.disconn_cb_list, l);
+                               free(cbdata);
+                       }
+               }
+       }
+}
+
+static gboolean client_cb(GIOChannel *src, GIOCondition cond, gpointer data)
+{
+       int client_fd;
+       struct cbdata *cbdata = data;
+       int ret;
+
+       client_fd = g_io_channel_unix_get_fd(src);
+
+       if (!(cond & G_IO_IN)) {
+               DbgPrint("Client is disconencted\n");
+               invoke_disconn_cb_list(client_fd);
+               secure_socket_destroy_handle(client_fd);
+               return FALSE;
+       }
+
+       if ((cond & G_IO_ERR) || (cond & G_IO_HUP) || (cond & G_IO_NVAL)) {
+               DbgPrint("Client connection is lost\n");
+               invoke_disconn_cb_list(client_fd);
+               secure_socket_destroy_handle(client_fd);
+               return FALSE;
+       }
+
+       ret = cbdata->service_cb(client_fd, cbdata->data);
+       if (ret < 0) {
+               DbgPrint("service callback returns %d < 0\n", ret);
+               invoke_disconn_cb_list(client_fd);
+               secure_socket_destroy_handle(client_fd);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+static gboolean accept_cb(GIOChannel *src, GIOCondition cond, gpointer cbdata)
+{
+       int socket_fd;
+       int client_fd;
+       GIOChannel *gio;
+       guint id;
+
+       socket_fd = g_io_channel_unix_get_fd(src);
+       if (!(cond & G_IO_IN)) {
+               ErrPrint("Accept socket closed\n");
+               secure_socket_destroy_handle(socket_fd);
+               free(cbdata);
+               return FALSE;
+       }
+
+       if ((cond & G_IO_ERR) || (cond & G_IO_HUP) || (cond & G_IO_NVAL)) {
+               DbgPrint("Client connection is lost\n");
+               secure_socket_destroy_handle(socket_fd);
+               free(cbdata);
+               return FALSE;
+       }
+
+       DbgPrint("New connectino arrived: socket(%d)\n", socket_fd);
+       client_fd = secure_socket_get_connection_handle(socket_fd);
+       if (client_fd < 0) {
+               free(cbdata);
+               return FALSE;
+       }
+       DbgPrint("New client: %d\n", client_fd);
+
+       if (fcntl(client_fd, F_SETFD, FD_CLOEXEC) < 0)
+               ErrPrint("Error: %s\n", strerror(errno));
+
+       if (fcntl(client_fd, F_SETFL, O_NONBLOCK) < 0)
+               ErrPrint("Error: %s\n", strerror(errno));
+
+       gio = g_io_channel_unix_new(client_fd);
+       if (!gio) {
+               ErrPrint("Failed to get gio\n");
+               secure_socket_destroy_handle(client_fd);
+               free(cbdata);
+               return FALSE;
+       }
+
+       g_io_channel_set_close_on_unref(gio, FALSE);
+
+       id = g_io_add_watch(gio, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, (GIOFunc)client_cb, cbdata);
+       if (id <= 0) {
+               GError *err = NULL;
+               ErrPrint("Failed to add IO watch\n");
+               g_io_channel_shutdown(gio, TRUE, &err);
+               if (err) {
+                       ErrPrint("Shutdown: %s\n", err->message);
+                       g_error_free(err);
+               }
+               g_io_channel_unref(gio);
+               secure_socket_destroy_handle(client_fd);
+               free(cbdata);
+               return FALSE;
+       }
+
+       g_io_channel_unref(gio);
+
+       invoke_con_cb_list(client_fd);
+       DbgPrint("New client is connected with %d\n", client_fd);
+       return TRUE;
+}
+
+EAPI int com_core_server_create(const char *addr, int is_sync, int (*service_cb)(int fd, void *data), void *data)
+{
+       GIOChannel *gio;
+       guint id;
+       int fd;
+       struct cbdata *cbdata;
+
+       cbdata = malloc(sizeof(*cbdata));
+       if (!cbdata) {
+               ErrPrint("Heap: %s\n", strerror(errno));
+               return -ENOMEM;
+       }
+
+       cbdata->service_cb = service_cb;
+       cbdata->data = data;
+
+       fd = secure_socket_create_server(addr);
+       if (fd < 0) {
+               free(cbdata);
+               return fd;
+       }
+
+       if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0)
+               ErrPrint("fcntl: %s\n", strerror(errno));
+
+       if (!is_sync && fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
+               ErrPrint("fcntl: %s\n", strerror(errno));
+
+       DbgPrint("Create new IO channel for socket FD: %d\n", fd);
+       gio = g_io_channel_unix_new(fd);
+       if (!gio) {
+               ErrPrint("Failed to create new io channel\n");
+               free(cbdata);
+               secure_socket_destroy_handle(fd);
+               return -EIO;
+       }
+
+       g_io_channel_set_close_on_unref(gio, FALSE);
+
+       id = g_io_add_watch(gio, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc)accept_cb, cbdata);
+       if (id <= 0) {
+               GError *err = NULL;
+               ErrPrint("Failed to add IO watch\n");
+               free(cbdata);
+               g_io_channel_shutdown(gio, TRUE, &err);
+               if (err) {
+                       ErrPrint("Shutdown: %s\n", err->message);
+                       g_error_free(err);
+               }
+               g_io_channel_unref(gio);
+               secure_socket_destroy_handle(fd);
+               return -EIO;
+       }
+
+       g_io_channel_unref(gio);
+       return fd;
+}
+
+EAPI int com_core_client_create(const char *addr, int is_sync, int (*service_cb)(int fd, void *data), void *data)
+{
+       GIOChannel *gio;
+       guint id;
+       int client_fd;
+       struct cbdata *cbdata;
+
+       cbdata = malloc(sizeof(*cbdata));
+       if (!cbdata) {
+               ErrPrint("Heap: %s\n", strerror(errno));
+               return -ENOMEM;
+       }
+
+       cbdata->service_cb = service_cb;
+       cbdata->data = data;
+
+       client_fd = secure_socket_create_client(addr);
+       if (client_fd < 0) {
+               free(cbdata);
+               return client_fd;
+       }
+
+       if (fcntl(client_fd, F_SETFD, FD_CLOEXEC) < 0)
+               ErrPrint("Error: %s\n", strerror(errno));
+
+       if (!is_sync && fcntl(client_fd, F_SETFL, O_NONBLOCK) < 0)
+               ErrPrint("Error: %s\n", strerror(errno));
+
+       gio = g_io_channel_unix_new(client_fd);
+       if (!gio) {
+               ErrPrint("Failed to create a new IO channel\n");
+               free(cbdata);
+               secure_socket_destroy_handle(client_fd);
+               return -EIO;
+       }
+
+       g_io_channel_set_close_on_unref(gio, FALSE);
+
+       id = g_io_add_watch(gio, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, (GIOFunc)client_cb, cbdata);
+       if (id <= 0) {
+               GError *err = NULL;
+               ErrPrint("Failed to add IO watch\n");
+               free(cbdata);
+               g_io_channel_shutdown(gio, TRUE, &err);
+               if (err) {
+                       ErrPrint("Shutdown: %s\n", err->message);
+                       g_error_free(err);
+               }
+               g_io_channel_unref(gio);
+               secure_socket_destroy_handle(client_fd);
+               return -EIO;
+       }
+
+       g_io_channel_unref(gio);
+       invoke_con_cb_list(client_fd);
+       return client_fd;
+}
+
+EAPI int com_core_add_event_callback(enum com_core_event_type type, int (*evt_cb)(int handle, void *data), void *data)
+{
+       struct evtdata *cbdata;
+       cbdata = malloc(sizeof(*cbdata));
+       if (!cbdata) {
+               ErrPrint("Heap: %s\n", strerror(errno));
+               return -ENOMEM;
+       }
+
+       cbdata->evt_cb = evt_cb;
+       cbdata->data = data;
+
+       if (type == CONNECTOR_CONNECTED)
+               s_info.conn_cb_list = dlist_append(s_info.conn_cb_list, cbdata);
+       else
+               s_info.disconn_cb_list = dlist_append(s_info.disconn_cb_list, cbdata);
+       return 0;
+}
+
+EAPI int com_core_recv(int handle, char *buffer, int size, int *sender_pid, double timeout)
+{
+       int readsize;
+       int ret;
+
+       fd_set set;
+
+       readsize = 0;
+       while (size > 0) {
+               FD_ZERO(&set);
+               FD_SET(handle, &set);
+
+               if (timeout > 0.0f) {
+                       struct timeval tv;
+
+                       tv.tv_sec = (unsigned long)timeout;
+                       tv.tv_usec = (timeout - (unsigned long)timeout) * 1000000u;
+                       ret = select(handle + 1, &set, NULL, NULL, &tv);
+               } else if (timeout == 0.0f) {
+                       ret = select(handle + 1, &set, NULL, NULL, NULL);
+               } else {
+                       ErrPrint("Invalid timeout: %lf (it must be greater than 0.0)\n", timeout);
+                       return -EINVAL;
+               }
+
+               if (ret < 0) {
+                       ret = -errno;
+                       if (errno == EINTR) {
+                               DbgPrint("Select receives INTR\n");
+                               continue;
+                       }
+                       ErrPrint("Error: %s\n", strerror(errno));
+                       return ret;
+               } else if (ret == 0) {
+                       ErrPrint("Timeout expired\n");
+                       break;
+               }
+
+               if (!FD_ISSET(handle, &set)) {
+                       ErrPrint("Unexpected handle is toggled\n");
+                       return -EINVAL;
+               }
+
+               ret = secure_socket_recv(handle, buffer + readsize, size, sender_pid);
+               if (ret < 0) {
+                       if (ret == -EAGAIN) {
+                               DbgPrint("Retry to get data (%d:%d)\n", readsize, size);
+                               continue;
+                       }
+                       return ret;
+               } else if (ret == 0) {
+                       return 0;
+               }
+
+               size -= ret;
+               readsize += ret;
+       }
+
+       return readsize;
+}
+
+EAPI int com_core_send(int handle, const char *buffer, int size, double timeout)
+{
+       int writesize;
+       int ret;
+
+       fd_set set;
+
+       writesize = 0;
+       while (size > 0) {
+
+               FD_ZERO(&set);
+               FD_SET(handle, &set);
+
+               if (timeout > 0.0f) {
+                       struct timeval tv;
+
+                       tv.tv_sec = (unsigned long)timeout;
+                       tv.tv_usec = (timeout - (unsigned long)timeout) * 1000000u;
+
+                       ret = select(handle + 1, NULL, &set, NULL, &tv);
+               } else if (timeout == 0.0f) {
+                       ret = select(handle + 1, NULL, &set, NULL, NULL);
+               } else {
+                       ErrPrint("Invalid timeout: %lf (it must be greater than 0.0)\n", timeout);
+                       return -EINVAL;
+               }
+
+               if (ret < 0) {
+                       ret = -errno;
+                       if (errno == EINTR) {
+                               DbgPrint("Select receives INTR\n");
+                               continue;
+                       }
+                       ErrPrint("Error: %s\n", strerror(errno));
+                       return ret;
+               } else if (ret == 0) {
+                       ErrPrint("Timeout expired\n");
+                       break;
+               }
+
+               if (!FD_ISSET(handle, &set)) {
+                       ErrPrint("Unexpected handle is toggled\n");
+                       return -EINVAL;
+               }
+
+               ret = secure_socket_send(handle, buffer + writesize, size);
+               if (ret < 0) {
+                       if (ret == -EAGAIN) {
+                               DbgPrint("Retry to send data (%d:%d)\n", writesize, size);
+                               continue;
+                       }
+                       DbgPrint("Failed to send: %d\n", ret);
+                       return ret;
+               } else if (ret == 0) {
+                       DbgPrint("Disconnected? : Send bytes: 0\n");
+                       return 0;
+               }
+
+               size -= ret;
+               writesize += ret;
+       }
+
+       return writesize;
+}
+
+EAPI void *com_core_del_event_callback(enum com_core_event_type type, int (*cb)(int handle, void *data), void *data)
+{
+       struct dlist *l;
+       struct dlist *n;
+       struct evtdata *cbdata;
+
+       if (type == CONNECTOR_CONNECTED) {
+               dlist_foreach_safe(s_info.conn_cb_list, l, n, cbdata) {
+                       if (cbdata->evt_cb == cb && cbdata->data == data) {
+                               void *data;
+                               data = cbdata->data;
+                               dlist_remove_data(s_info.conn_cb_list, cbdata);
+                               free(cbdata);
+                               return data;
+                       }
+               }
+       } else {
+               dlist_foreach_safe(s_info.disconn_cb_list, l, n, cbdata) {
+                       if (cbdata->evt_cb == cb && cbdata->data == data) {
+                               void *data;
+                               data = cbdata->data;
+                               dlist_remove_data(s_info.disconn_cb_list, cbdata);
+                               free(cbdata);
+                               return data;
+                       }
+               }
+       }
+
+       return NULL;
+}
+
+EAPI int com_core_server_destroy(int handle)
+{
+       DbgPrint("Close server handle[%d]\n", handle);
+       secure_socket_destroy_handle(handle);
+       return 0;
+}
+
+EAPI int com_core_client_destroy(int handle)
+{
+       DbgPrint("Close client handle[%d]\n", handle);
+       secure_socket_destroy_handle(handle);
+       return 0;
+}
+
+/* End of a file */
diff --git a/src/com-core_packet-router.c b/src/com-core_packet-router.c
new file mode 100644 (file)
index 0000000..2e7b736
--- /dev/null
@@ -0,0 +1,1813 @@
+/*
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+*/
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <pthread.h>
+#include <fcntl.h> /* Obtain O_* constant definitions */
+#include <unistd.h>
+#include <sys/select.h>
+
+#include <glib.h>
+#include <dlog.h>
+
+#include "secure_socket.h"
+#include "dlist.h"
+#include "packet.h"
+#include "com-core.h"
+#include "com-core_packet.h"
+#include "debug.h"
+#include "util.h"
+#include "com-core_packet-router.h"
+
+#define PIPE_READ 0
+#define PIPE_WRITE 1
+
+struct packet_item {
+       pid_t pid;
+       struct packet *packet;
+};
+
+struct route {
+       unsigned long address;
+       int handle;
+       int invalid;
+};
+
+struct client {
+       struct router *router;
+       int handle;
+
+       pthread_t thid;
+};
+
+struct recv_ctx {
+       enum state {
+               RECV_STATE_INIT,
+               RECV_STATE_HEADER,
+               RECV_STATE_BODY,
+               RECV_STATE_READY,
+       } state;
+
+       struct packet *packet;
+       unsigned long offset;
+       pid_t pid;
+
+       double timeout;
+};
+
+struct request_ctx {
+       pid_t pid;
+       int handle;
+
+       struct packet *packet;
+       int (*recv_cb)(pid_t pid, int handle, const struct packet *packet, void *data);
+       void *data;
+};
+
+struct router {
+       int handle;
+
+       char *sock;
+       struct packet *(*service)(int handle, pid_t pid, const struct packet *packet, void *data);
+       void *data;
+
+       double timeout;
+
+       pthread_mutex_t recv_packet_list_lock;
+       struct dlist *recv_packet_list;
+
+       pthread_mutex_t route_list_lock;
+       struct dlist *route_list;
+
+       pthread_mutex_t send_packet_list_lock;
+       struct dlist *send_packet_list;
+
+       int recv_pipe[2];
+       int send_pipe[2];
+
+       pthread_t send_thid;
+
+       guint id;
+
+       unsigned long count_of_dropped_packet;
+
+       int is_server;
+       union {
+               struct {
+                       struct dlist *client_list;
+                       guint accept_id;
+               } server; /*!< Only used by the server */
+
+               struct {
+                       pthread_t thid;
+               } client; /*!< Only used by the client */
+       } info;
+};
+
+struct event_item {
+       int (*evt_cb)(int handle, void *data);
+       void *data;
+};
+
+static struct info {
+       struct dlist *router_list;
+       struct dlist *request_list;
+
+       struct dlist *disconnected_list;
+       struct dlist *connected_list;
+       struct dlist *error_list;
+} s_info = {
+       .router_list = NULL,
+       .request_list = NULL,
+
+       .disconnected_list = NULL,
+       .connected_list = NULL,
+       .error_list = NULL,
+};
+
+static inline struct packet *get_recv_packet(struct router *router, int *handle, pid_t *pid);
+static inline int put_recv_packet(struct router *router, int handle, struct packet *packet, pid_t pid);
+
+static inline struct packet *get_send_packet(struct router *router, int *handle);
+static inline int put_send_packet(struct router *router, int handle, struct packet *packet);
+
+/*!
+ * \note
+ * Running thread: Main
+ */
+static inline int invoke_disconnected_cb(struct router *router, int handle)
+{
+       struct dlist *l;
+       struct dlist *n;
+       struct event_item *item;
+       struct route *route;
+       int ret;
+
+       CRITICAL_SECTION_BEGIN(&router->route_list_lock);
+
+       dlist_foreach(router->route_list, l, route) {
+               if (route->handle == handle) {
+                       /*!
+                        * \NOTE
+                        * Invalidate an entry in the routing table.
+                        * Do not this entry from the routing table from here,.
+                        * Because a user may not want to delete the entry without any notification.
+                        * So we just left this invalid entry on the table.
+                        * Then the user has to manage the routing table correctly 
+                        * via connected/disconnected event callbacks.
+                        */
+                       route->invalid = 1;
+               }
+       }
+
+       CRITICAL_SECTION_END(&router->route_list_lock);
+
+       /*!
+        * \NOTE
+        * Invoke the disconnected callback
+        */
+       dlist_foreach_safe(s_info.disconnected_list, l, n, item) {
+               ret = item->evt_cb(handle, item->data);
+               if (ret < 0 && dlist_find_data(s_info.disconnected_list, item)) {
+                       s_info.disconnected_list = dlist_remove(s_info.disconnected_list, l);
+                       free(item);
+               }
+       }
+
+       return 0;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+static inline int invoke_connected_cb(struct router *router, int handle)
+{
+       struct dlist *l;
+       struct dlist *n;
+       struct event_item *item;
+       int ret;
+
+       dlist_foreach_safe(s_info.connected_list, l, n, item) {
+               ret = item->evt_cb(handle, item->data);
+               if (ret < 0 && dlist_find_data(s_info.connected_list, item)) {
+                       s_info.connected_list = dlist_remove(s_info.connected_list, l);
+                       free(item);
+               }
+       }
+
+       return 0;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+static inline int invoke_error_cb(struct router *router, int handle)
+{
+       struct dlist *l;
+       struct dlist *n;
+       struct event_item *item;
+       int ret;
+
+       dlist_foreach_safe(s_info.error_list, l, n, item) {
+               ret = item->evt_cb(handle, item->data);
+               if (ret < 0 && dlist_find_data(s_info.error_list, item)) {
+                       s_info.error_list = dlist_remove(s_info.error_list, l);
+                       free(item);
+               }
+       }
+
+       return 0;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+static inline struct request_ctx *find_request_ctx(int handle, double seq)
+{
+       struct request_ctx *ctx;
+       struct dlist *l;
+
+       dlist_foreach(s_info.request_list, l, ctx) {
+               if (ctx->handle == handle && packet_seq(ctx->packet) == seq) {
+                       return ctx;
+               }
+       }
+
+       return NULL;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+static inline void destroy_request_ctx(struct request_ctx *ctx)
+{
+       packet_unref(ctx->packet);
+       dlist_remove_data(s_info.request_list, ctx);
+       free(ctx);
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+static inline void clear_request_ctx(int handle)
+{
+       struct request_ctx *ctx;
+       struct dlist *l;
+       struct dlist *n;
+
+       dlist_foreach_safe(s_info.request_list, l, n, ctx) {
+               if (ctx->handle != handle)
+                       continue;
+
+               if (ctx->recv_cb)
+                       ctx->recv_cb(-1, handle, NULL, ctx->data);
+
+               destroy_request_ctx(ctx);
+       }
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+static inline struct request_ctx *create_request_ctx(int handle)
+{
+       struct request_ctx *ctx;
+
+       ctx = malloc(sizeof(*ctx));
+       if (!ctx) {
+               ErrPrint("Heap: %s\n", strerror(errno));
+               return NULL;
+       }
+
+       ctx->handle = handle;
+       ctx->pid = (pid_t)-1;
+       ctx->packet = NULL;
+       ctx->recv_cb = NULL;
+       ctx->data = NULL;
+
+       s_info.request_list = dlist_append(s_info.request_list, ctx);
+       return ctx;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+static inline struct router *find_router_by_handle(int handle)
+{
+       struct dlist *l;
+       struct router *router;
+
+       dlist_foreach(s_info.router_list, l, router) {
+               if (router->is_server) {
+                       struct dlist *cl;
+                       struct client *client;
+                       /*!
+                        * Find the client list
+                        */
+                       dlist_foreach(router->info.server.client_list, cl, client) {
+                               if (client->handle == handle)
+                                       return router;
+                       }
+               } else if (router->handle == handle) {
+                       return router;
+               }
+       }
+
+       return NULL;
+}
+
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+static gboolean packet_cb(GIOChannel *src, GIOCondition cond, gpointer data)
+{
+       struct router *router = data;
+       struct packet *packet;
+       struct packet *result_packet;
+       struct request_ctx *request;
+       int evt_handle;
+       int handle = -1;
+       pid_t pid = (pid_t)-1;
+
+       evt_handle = g_io_channel_unix_get_fd(src);
+       if (evt_handle != router->recv_pipe[PIPE_READ]) {
+               ErrPrint("Invalid FD\n");
+               goto errout;
+       }
+
+       if (!(cond & G_IO_IN)) {
+               DbgPrint("PIPE is not valid\n");
+               goto errout;
+       }
+
+       if ((cond & G_IO_ERR) || (cond & G_IO_HUP) || (cond & G_IO_NVAL)) {
+               DbgPrint("PIPE is not valid\n");
+               goto errout;
+       }
+
+       packet = get_recv_packet(router, &handle, &pid);
+       if (!packet) {
+               (void)invoke_disconnected_cb(router, handle);
+               clear_request_ctx(handle);
+       } else {
+               int ret;
+
+               switch (packet_type(packet)) {
+               case PACKET_ACK:
+                       request = find_request_ctx(handle, packet_seq(packet));
+                       if (!request) {
+                               ErrPrint("Unknown ack packet\n");
+                               packet_destroy(packet);
+                               break;
+                       }
+
+                       if (request->recv_cb)
+                               request->recv_cb(pid, handle, packet, request->data);
+
+                       destroy_request_ctx(request);
+                       break;
+               case PACKET_REQ_NOACK:
+                       if (!router->service) {
+                               ErrPrint("Service callback is not registered\n");
+                               break;
+                       }
+
+                       result_packet = router->service(handle, pid, packet, router->data);
+                       if (result_packet) {
+                               ErrPrint("Invalid result packet\n");
+                               packet_destroy(result_packet);
+                       }
+                       break;
+               case PACKET_REQ:
+                       if (!router->service) {
+                               ErrPrint("Service callback is not registered, client can be block\n");
+                               break;
+                       }
+
+                       result_packet = router->service(handle, pid, packet, router->data);
+                       if (!result_packet) {
+                               ErrPrint("REQUEST Packet has no ACK Packet, client can be block\n");
+                               break;
+                       }
+
+                       ret = put_send_packet(router, handle, packet);
+                       if (ret < 0)
+                               ErrPrint("Failed to send a packet\n");
+                       break;
+               case PACKET_ERROR:
+               default:
+                       ErrPrint("Invalid packet arrived\n");
+                       router->count_of_dropped_packet++;
+                       break;
+               }
+       }
+
+       /*!
+        * \TODO:
+        * How could we disconnect from the client?
+        */
+       packet_destroy(packet);
+       return TRUE;
+
+errout:
+       router->service(handle, pid, NULL, router->data);
+       return FALSE;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+static struct packet *service_handler(int handle, pid_t pid, const struct packet *packet, void *data)
+{
+       struct method *table = data;
+       struct packet *result;
+       register int i;
+
+       if (!packet) {
+               DbgPrint("Connection is lost [%d] [%d]\n", handle, pid);
+               return NULL;
+       }
+
+       result = NULL;
+       for (i = 0; table[i].cmd; i++) {
+               if (strcmp(table[i].cmd, packet_command(packet)))
+                       continue;
+
+               result = table[i].handler(pid, handle, packet);
+               break;
+       }
+
+       return result;
+}
+
+/*!
+ * \NOTE:
+ * Running thread: Server or Client or Send thread
+ */
+static inline int select_event(int handle, double timeout)
+{
+       fd_set set;
+       int status;
+       int ret;
+
+       FD_ZERO(&set);
+       FD_SET(handle, &set);
+
+       status = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+       if (status != 0)
+               ErrPrint("Failed to set cancelstate: %s\n", strerror(status));
+       if (timeout > 0.0f) {
+               struct timeval tv;
+
+               tv.tv_sec = (unsigned long)timeout;
+               tv.tv_usec = (timeout - (unsigned long)timeout) * 1000000u;
+
+               ret = select(handle + 1, NULL, &set, NULL, &tv);
+       } else if (timeout == 0.0f) {
+               ret = select(handle + 1, NULL, &set, NULL, NULL);
+       } else {
+               ErrPrint("Invalid timeout: %lf (it must be greater than 0.0)\n", timeout);
+               status = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+               if (status != 0)
+                       ErrPrint("Failed to set cancelstate: %s\n", strerror(status));
+               return -EINVAL;
+       }
+
+       if (ret < 0) {
+               ret = -errno;
+               if (errno == EINTR) {
+                       DbgPrint("Select receives INTR\n");
+                       status = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+                       return -EAGAIN;
+               }
+
+               ErrPrint("Error: %s\n", strerror(errno));
+               status = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+               if (status != 0)
+                       ErrPrint("Failed to set cancelstate: %s\n", strerror(status));
+               return ret;
+       } else if (ret == 0) {
+               ErrPrint("Timeout expired\n");
+               status = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+               if (status != 0)
+                       ErrPrint("Failed to set cancelstate: %s\n", strerror(status));
+               return -ETIMEDOUT;
+       }
+       status = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+       if (status != 0)
+               ErrPrint("Failed to set cancelstate: %s\n", strerror(status));
+
+       if (!FD_ISSET(handle, &set)) {
+               ErrPrint("Unexpected handle is toggled\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Send thread
+ */
+static void *send_main(void *data)
+{
+       struct router *router = data;
+       struct packet *packet;
+       int handle;
+       int ret;
+
+       while (1) {
+               /*!
+                * \note
+                * select event has cancel point
+                */
+               ret = select_event(router->send_pipe[PIPE_READ], 0.0f);
+               if (ret == -EAGAIN)
+                       continue;
+
+               if (ret < 0)
+                       break;
+
+               packet = get_send_packet(router, &handle);
+               if (!packet) {
+                       DbgPrint("NULL Packet. Terminate thread\n");
+                       break;
+               }
+
+               switch (packet_type(packet)) {
+               case PACKET_REQ:
+               case PACKET_REQ_NOACK:
+                       ret = com_core_send(handle, (void *)packet_data(packet), packet_size(packet), router->timeout);
+                       break;
+               default:
+                       ret = -EINVAL;
+                       break;
+               }
+
+               packet_destroy(packet);
+       }
+
+       return (void *)ret;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+static struct router *create_router(const char *sock, int handle, struct method *table)
+{
+       struct router *router;
+       GIOChannel *gio;
+       int ret;
+
+       router = calloc(1, sizeof(*router));
+       if (!router) {
+               ErrPrint("Heap: %s\n", strerror(errno));
+               return NULL;
+       }
+
+       ret = pthread_mutex_init(&router->recv_packet_list_lock, NULL);
+       if (ret != 0) {
+               ErrPrint("Mutex creation failed: %s\n", strerror(ret));
+               free(router);
+               return NULL;
+       }
+
+       ret = pthread_mutex_init(&router->route_list_lock, NULL);
+       if (ret != 0) {
+               ErrPrint("Mutex craetion failed: %s\n", strerror(ret));
+               ret = pthread_mutex_destroy(&router->recv_packet_list_lock);
+               if (ret != 0)
+                       ErrPrint("Mutex destroy failed: %s\n", strerror(ret));
+
+               free(router);
+               return NULL;
+       }
+
+       ret = pthread_mutex_init(&router->send_packet_list_lock, NULL);
+       if (ret != 0) {
+               ErrPrint("Mutex creation failed: %s\n", strerror(ret));
+
+               ret = pthread_mutex_destroy(&router->recv_packet_list_lock);
+               if (ret != 0)
+                       ErrPrint("Mutex destroy failed: %s\n", strerror(ret));
+
+               ret = pthread_mutex_destroy(&router->route_list_lock);
+               if (ret != 0)
+                       ErrPrint("Mutex destroy failed: %s\n", strerror(ret));
+
+               free(router);
+               return NULL;
+       }
+
+       router->sock = strdup(sock);
+       if (!router->sock) {
+               ErrPrint("Heap: %s\n", strerror(errno));
+               ret = pthread_mutex_destroy(&router->send_packet_list_lock);
+               if (ret != 0)
+                       ErrPrint("Mutex destroy failed: %s\n", strerror(ret));
+
+               ret = pthread_mutex_destroy(&router->recv_packet_list_lock);
+               if (ret != 0)
+                       ErrPrint("Mutex destroy failed: %s\n", strerror(ret));
+
+               ret = pthread_mutex_destroy(&router->route_list_lock);
+               if (ret != 0)
+                       ErrPrint("Mutex destroy failed: %s\n", strerror(ret));
+
+               free(router);
+               return NULL;
+       }
+
+       ret = pipe2(router->recv_pipe, O_NONBLOCK | O_CLOEXEC);
+       if (ret < 0) {
+               ErrPrint("pipe2: %s\n", strerror(errno));
+               free(router->sock);
+
+               ret = pthread_mutex_destroy(&router->send_packet_list_lock);
+               if (ret != 0)
+                       ErrPrint("Mutex destroy failed: %s\n", strerror(ret));
+
+               ret = pthread_mutex_destroy(&router->recv_packet_list_lock);
+               if (ret != 0)
+                       ErrPrint("Mutex destroy failed: %s\n", strerror(ret));
+
+               ret = pthread_mutex_destroy(&router->route_list_lock);
+               if (ret != 0)
+                       ErrPrint("Mutex destroy failed: %s\n", strerror(ret));
+
+               free(router);
+               return NULL;
+       }
+
+       ret = pipe2(router->send_pipe, O_NONBLOCK | O_CLOEXEC);
+       if (ret < 0) {
+               ErrPrint("pipe2: %s\n", strerror(errno));
+               free(router->sock);
+
+               if (close(router->recv_pipe[0]) < 0)
+                       ErrPrint("close: %s\n", strerror(errno));
+
+               if (close(router->recv_pipe[1]) < 0)
+                       ErrPrint("close: %s\n", strerror(errno));
+
+               ret = pthread_mutex_destroy(&router->send_packet_list_lock);
+               if (ret != 0)
+                       ErrPrint("Mutex destroy failed: %s\n", strerror(ret));
+
+               ret = pthread_mutex_destroy(&router->recv_packet_list_lock);
+               if (ret != 0)
+                       ErrPrint("Mutex destroy failed: %s\n", strerror(ret));
+
+               ret = pthread_mutex_destroy(&router->route_list_lock);
+               if (ret != 0)
+                       ErrPrint("Mutex destroy failed: %s\n", strerror(ret));
+
+               free(router);
+               return NULL;
+       }
+
+       router->handle = handle;
+       router->service = service_handler;
+       router->data = table;
+
+       gio = g_io_channel_unix_new(router->recv_pipe[PIPE_READ]);
+       if (!gio) {
+               if (close(router->recv_pipe[PIPE_READ]) < 0)
+                       ErrPrint("close: %s\n", strerror(errno));
+
+               if (close(router->recv_pipe[PIPE_WRITE]) < 0)
+                       ErrPrint("close: %s\n", strerror(errno));
+
+               if (close(router->send_pipe[PIPE_READ]) < 0)
+                       ErrPrint("close: %s\n", strerror(errno));
+
+               if (close(router->send_pipe[PIPE_WRITE]) < 0)
+                       ErrPrint("close: %s\n", strerror(errno));
+
+               free(router->sock);
+
+               ret = pthread_mutex_destroy(&router->send_packet_list_lock);
+               if (ret != 0)
+                       ErrPrint("Mutex destroy failed: %s\n", strerror(ret));
+
+               ret = pthread_mutex_destroy(&router->recv_packet_list_lock);
+               if (ret != 0)
+                       ErrPrint("Mutex destroy failed: %s\n", strerror(ret));
+
+               ret = pthread_mutex_destroy(&router->route_list_lock);
+               if (ret != 0)
+                       ErrPrint("Mutex destroy failed: %s\n", strerror(ret));
+
+               free(router);
+               return NULL;
+       }
+       g_io_channel_set_close_on_unref(gio, FALSE);
+
+       router->id = g_io_add_watch(gio, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc)packet_cb, router);
+       if (router->id == 0) {
+               GError *err = NULL;
+               g_io_channel_shutdown(gio, TRUE, &err);
+               if (err) {
+                       ErrPrint("Shutdown: %s\n", err->message);
+                       g_error_free(err);
+               }
+               g_io_channel_unref(gio);
+
+               if (close(router->recv_pipe[PIPE_READ]) < 0)
+                       ErrPrint("close: %s\n", strerror(errno));
+
+               if (close(router->recv_pipe[PIPE_WRITE]) < 0)
+                       ErrPrint("close: %s\n", strerror(errno));
+
+               if (close(router->send_pipe[PIPE_READ]) < 0)
+                       ErrPrint("close: %s\n", strerror(errno));
+
+               if (close(router->send_pipe[PIPE_WRITE]) < 0)
+                       ErrPrint("close: %s\n", strerror(errno));
+
+               free(router->sock);
+
+               ret = pthread_mutex_destroy(&router->send_packet_list_lock);
+               if (ret != 0)
+                       ErrPrint("Mutex destroy failed: %s\n", strerror(ret));
+
+               ret = pthread_mutex_destroy(&router->recv_packet_list_lock);
+               if (ret != 0)
+                       ErrPrint("Mutex destroy failed: %s\n", strerror(ret));
+
+               ret = pthread_mutex_destroy(&router->route_list_lock);
+               if (ret != 0)
+                       ErrPrint("Mutex destroy failed: %s\n", strerror(ret));
+
+               free(router);
+               return NULL;
+       }
+
+       g_io_channel_unref(gio);
+
+       s_info.router_list = dlist_append(s_info.router_list, router);
+
+       ret = pthread_create(&router->send_thid, NULL, send_main, router);
+       if (ret != 0) {
+               ErrPrint("Failed to create a send thread: %s\n", strerror(ret));
+               dlist_remove_data(s_info.router_list, router);
+
+               g_source_remove(router->id);
+
+               if (close(router->recv_pipe[PIPE_READ]) < 0)
+                       ErrPrint("Close: %s\n", strerror(errno));
+
+               if (close(router->recv_pipe[PIPE_WRITE]) < 0)
+                       ErrPrint("Close: %s\n", strerror(errno));
+
+               if (close(router->send_pipe[PIPE_READ]) < 0)
+                       ErrPrint("Close: %s\n", strerror(errno));
+
+               if (close(router->send_pipe[PIPE_WRITE]) < 0)
+                       ErrPrint("Close: %s\n", strerror(errno));
+
+               free(router->sock);
+
+               ret = pthread_mutex_destroy(&router->send_packet_list_lock);
+               if (ret != 0)
+                       ErrPrint("Mutex destroy failed: %s\n", strerror(ret));
+
+               ret = pthread_mutex_destroy(&router->recv_packet_list_lock);
+               if (ret != 0)
+                       ErrPrint("Mutex destroy failed: %s\n", strerror(ret));
+
+               ret = pthread_mutex_destroy(&router->route_list_lock);
+               if (ret != 0)
+                       ErrPrint("Mutex destroy failed: %s\n", strerror(ret));
+
+               free(router);
+               return NULL;
+       }
+
+       return router;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ *
+ * Before call this, every thread which uses this router object must has to be terminated.
+ */
+static inline __attribute__((always_inline)) int destroy_router(struct router *router)
+{
+       int handle;
+       int ret;
+
+       ret = put_send_packet(router, -1, NULL);
+       DbgPrint("Put NULL Packet to terminate send thread (%d)\n", ret);
+
+       ret = pthread_join(router->send_thid, NULL);
+       if (ret != 0)
+               ErrPrint("Join: %s\n", strerror(ret));
+
+       dlist_remove_data(s_info.router_list, router);
+
+       if (router->id > 0)
+               g_source_remove(router->id);
+
+       if (close(router->recv_pipe[PIPE_READ]) < 0)
+               ErrPrint("close: %s\n", strerror(errno));
+
+       if (close(router->recv_pipe[PIPE_WRITE]) < 0)
+               ErrPrint("close: %s\n", strerror(errno));
+
+       if (close(router->send_pipe[PIPE_READ]) < 0)
+               ErrPrint("close: %s\n", strerror(errno));
+
+       if (close(router->send_pipe[PIPE_WRITE]) < 0)
+               ErrPrint("close: %s\n", strerror(errno));
+
+       free(router->sock);
+
+       ret = pthread_mutex_destroy(&router->send_packet_list_lock);
+       if (ret != 0)
+               ErrPrint("Mutex destroy failed: %s\n", strerror(ret));
+
+       ret = pthread_mutex_destroy(&router->recv_packet_list_lock);
+       if (ret != 0)
+               ErrPrint("Mutex destroy failed: %s\n", strerror(ret));
+
+       ret = pthread_mutex_destroy(&router->route_list_lock);
+       if (ret != 0)
+               ErrPrint("Mutex destroy failed: %s\n", strerror(ret));
+
+       handle = router->handle;
+       free(router);
+
+       return handle;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Client / Server leaf thread
+ */
+static inline int route_packet(struct router *router, int handle, struct packet *packet)
+{
+       struct dlist *l;
+       struct route *route;
+       unsigned long destination;
+       unsigned long source;
+       unsigned long mask;
+       int processed = 0;
+
+       destination = packet_destination(packet);
+       source = packet_source(packet);
+       mask = packet_mask(packet);
+
+       /*!
+        * \TODO
+        * Can we believe this source?
+        * Validate this source address if possible.
+        */
+
+       if (destination && source) {
+               CRITICAL_SECTION_BEGIN(&router->route_list_lock);
+
+               dlist_foreach(router->route_list, l, route) {
+                       if (!route->invalid && (route->address & mask) == (destination & mask)) {
+                               /*!
+                                * \NOTE
+                                * This code is executed in the CRITICAL SECTION
+                                * If possible, we have to do this from the out of the CRITICAL SECTION
+                                * 
+                                * This code can makes the system slow.
+                                *
+                                * We have to optimize the processing time in the CRITICAL SECTION
+                                */
+                               if (put_send_packet(router, route->handle, packet) < 0)
+                                       ErrPrint("Failed to send whole packet\n");
+
+                               processed++;
+                       }
+               }
+
+               CRITICAL_SECTION_END(&router->route_list_lock);
+       }
+
+       if (processed == 0) {
+               DbgPrint("Drop a packet\n");
+               router->count_of_dropped_packet++;
+       }
+
+       packet_destroy(packet);
+       return 0;
+}
+
+/*!
+ * \NOTE
+ * Running Threads: Main / Client / Server
+ */
+static inline int put_send_packet(struct router *router, int handle, struct packet *packet)
+{
+       if (packet) {
+               struct packet_item *item;
+
+               item = malloc(sizeof(*item));
+               if (!item) {
+                       packet_destroy(packet);
+                       return -ENOMEM;
+               }
+
+               item->packet = packet;
+               item->pid = (pid_t)-1;
+
+               CRITICAL_SECTION_BEGIN(&router->send_packet_list_lock);
+
+               router->send_packet_list = dlist_append(router->send_packet_list, item);
+
+               CRITICAL_SECTION_END(&router->send_packet_list_lock);
+       }
+
+       /*!
+        * \note
+        * Producing an event on event pipe
+        */
+       if (write(router->send_pipe[PIPE_WRITE], &handle, sizeof(handle)) != sizeof(handle))
+               ErrPrint("Failed to put an event: %s\n", strerror(errno));
+
+       return 0;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Client / Server leaf thread
+ */
+static inline int put_recv_packet(struct router *router, int handle, struct packet *packet, pid_t pid)
+{
+       /*!
+        * If a packet is NULL, the connection is terminated
+        */
+       if (packet) {
+               struct packet_item *item;
+
+               item = malloc(sizeof(*item));
+               if (!item) {
+                       packet_destroy(packet);
+                       return -ENOMEM;
+               }
+
+               item->packet = packet;
+               item->pid = pid;
+
+               CRITICAL_SECTION_BEGIN(&router->recv_packet_list_lock);
+
+               router->recv_packet_list = dlist_append(router->recv_packet_list, item);
+
+               CRITICAL_SECTION_END(&router->recv_packet_list_lock);
+       }
+
+       /*!
+        * \note
+        * Producing an event on event pipe
+        */
+       if (write(router->recv_pipe[PIPE_WRITE], &handle, sizeof(handle)) != sizeof(handle))
+               ErrPrint("Failed to put an event: %s\n", strerror(errno));
+
+       return 0;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Send thread
+ */
+static inline struct packet *get_send_packet(struct router *router, int *handle)
+{
+       struct packet *packet = NULL;
+       struct dlist *l;
+       struct packet_item *item;
+
+       CRITICAL_SECTION_BEGIN(&router->send_packet_list_lock);
+
+       l = dlist_nth(router->send_packet_list, 0);
+       if (l) {
+               item = dlist_data(l);
+               router->send_packet_list = dlist_remove(router->send_packet_list, l);
+               packet = item->packet;
+               free(item);
+       }
+
+       CRITICAL_SECTION_END(&router->send_packet_list_lock);
+
+       if (read(router->send_pipe[PIPE_READ], handle, sizeof(*handle)) != sizeof(*handle))
+               ErrPrint("Failed to get an event: %s\n", strerror(errno));
+
+       return packet;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main thread
+ */
+static inline struct packet *get_recv_packet(struct router *router, int *handle, pid_t *pid)
+{
+       struct packet *packet = NULL;
+       struct dlist *l;
+       struct packet_item *item;
+
+       CRITICAL_SECTION_BEGIN(&router->recv_packet_list_lock);
+
+       l = dlist_nth(router->recv_packet_list, 0);
+       if (l) {
+               item = dlist_data(l);
+               router->recv_packet_list = dlist_remove(router->recv_packet_list, l);
+
+               packet = item->packet;
+               if (pid)
+                       *pid = item->pid;
+
+               free(item);
+       }
+
+       CRITICAL_SECTION_END(&router->recv_packet_list_lock);
+
+       /*!
+        * \note
+        * Consuming an event from event pipe
+        * Even if we cannot get the packet(NULL), we should consuming event
+        * Because the NULL packet means disconnected
+        */
+       if (read(router->recv_pipe[PIPE_READ], handle, sizeof(*handle)) != sizeof(*handle))
+               ErrPrint("Failed to get an event: %s\n", strerror(errno));
+
+       return packet;
+}
+
+static inline int build_packet(int handle, struct recv_ctx *ctx)
+{
+       char *ptr;
+       int size;
+       int ret;
+
+       switch (ctx->state) {
+       case RECV_STATE_INIT:
+               ctx->offset = 0;
+               ctx->packet = NULL;
+       case RECV_STATE_HEADER:
+               size = packet_header_size() - ctx->offset;
+
+               ptr = malloc(size);
+               if (!ptr) {
+                       ErrPrint("Heap: %s\n", strerror(errno));
+                       return -ENOMEM;
+               }
+
+               ret = com_core_recv(handle, ptr, size, &ctx->pid, ctx->timeout);
+               if (ret == 0) {
+                       free(ptr);
+                       return -ECONNRESET;
+               } else if (ret < 0) {
+                       free(ptr);
+                       return ret;
+               }
+
+               ctx->packet = packet_build(ctx->packet, ctx->offset, ptr, ret);
+               free(ptr);
+
+               if (!ctx->packet)
+                       return -EFAULT;
+
+               ctx->offset += ret;
+
+               if (ctx->offset == packet_header_size()) {
+                       if (packet_size(ctx->packet) == ctx->offset)
+                               ctx->state = RECV_STATE_READY;
+                       else
+                               ctx->state = RECV_STATE_BODY;
+               }
+               break;
+       case RECV_STATE_BODY:
+               size = packet_size(ctx->packet) - ctx->offset;
+               if (size == 0) {
+                       ctx->state = RECV_STATE_READY;
+                       break;
+               }
+
+               ptr = malloc(size);
+               if (!ptr) {
+                       ErrPrint("Heap: %s\n", strerror(errno));
+                       return -ENOMEM;
+               }
+
+               ret = com_core_recv(handle, ptr, size, &ctx->pid, ctx->timeout);
+               if (ret == 0) {
+                       free(ptr);
+                       return -ECONNRESET;
+               } else if (ret < 0) {
+                       free(ptr);
+                       return ret;
+               }
+
+               ctx->packet = packet_build(ctx->packet, ctx->offset, ptr, ret);
+               free(ptr);
+               if (!ctx->packet)
+                       return -EFAULT;
+
+               ctx->offset += ret;
+               if (ctx->offset == packet_size(ctx->packet))
+                       ctx->state = RECV_STATE_READY;
+
+               break;
+       case RECV_STATE_READY:
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int router_common_main(struct router *router, int handle, struct recv_ctx *ctx)
+{
+       int ret;
+       while (1) {
+               /*!
+                * \note
+                * select event has cancel point
+                */
+               ret = select_event(handle, ctx->timeout);
+               if (ret == -EAGAIN)
+                       continue;
+
+               if (ret < 0) {
+                       packet_destroy(ctx->packet);
+                       break;
+               }
+               /*!
+                * Build a packet
+                * And push it to the packet list
+                */
+               ret = build_packet(handle, ctx);
+               if (ret != 0) {
+                       packet_destroy(ctx->packet);
+                       break;
+               }
+
+               if (ctx->state == RECV_STATE_READY) {
+                       /*!
+                        * \NOTE
+                        *
+                        * If the destination address is ZERO,
+                        * Pull up the packet to this server.
+                        */
+                       if (packet_destination(ctx->packet))
+                               route_packet(router, handle, ctx->packet);
+                       else
+                               put_recv_packet(router, handle, ctx->packet, ctx->pid);
+
+                       ctx->state = RECV_STATE_INIT;
+               }
+       }
+
+       put_recv_packet(router, handle, NULL, ctx->pid);
+       return ret;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Server thread
+ */
+static void *server_main(void *data)
+{
+       struct client *client = data;
+       struct router *router = client->router;
+       struct recv_ctx ctx;
+       int ret;
+
+       ctx.state = RECV_STATE_INIT;
+       ctx.packet = NULL;
+       ctx.timeout = router->timeout;
+       ctx.pid = (pid_t)-1;
+
+       ret = router_common_main(router, client->handle, &ctx);
+       return (void *)ret;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Client thread
+ */
+static void *client_main(void *data)
+{
+       struct router *router = data;
+       struct recv_ctx ctx;
+       int ret;
+
+       ctx.state = RECV_STATE_INIT;
+       ctx.packet = NULL;
+       ctx.timeout = router->timeout;
+       ctx.offset = 0;
+       ctx.pid = (pid_t)-1;
+
+       ret = router_common_main(router, router->handle, &ctx);
+       return (void *)ret;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+static gboolean accept_cb(GIOChannel *src, GIOCondition cond, gpointer data)
+{
+       int handle;
+       int fd;
+       struct router *router = data;
+       struct client *client;
+       int status;
+
+       handle = g_io_channel_unix_get_fd(src);
+
+       if (!(cond & G_IO_IN)) {
+               ErrPrint("Accept socket closed\n");
+               (void)invoke_error_cb(router, handle);
+               return FALSE;
+       }
+
+       if ((cond & G_IO_ERR) || (cond & G_IO_HUP) || (cond & G_IO_NVAL)) {
+               DbgPrint("Socket connection is lost\n");
+               (void)invoke_error_cb(router, handle);
+               return FALSE;
+       }
+
+       DbgPrint("New connection is made: socket(%d)\n", handle);
+       fd = secure_socket_get_connection_handle(handle);
+       if (fd < 0) {
+               ErrPrint("Failed to get client fd from socket\n");
+               (void)invoke_error_cb(router, handle);
+               return FALSE;
+       }
+
+       if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0)
+               ErrPrint("Error: %s\n", strerror(errno));
+
+       if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
+               ErrPrint("Error: %s\n", strerror(errno));
+
+       client = calloc(1, sizeof(*client));
+       if (!client) {
+               ErrPrint("Heap: %s\n", strerror(errno));
+               secure_socket_destroy_handle(fd);
+               /*!
+                * \NOTE
+                * Just return TRUE to keep this accept handler
+                */
+               return TRUE;
+       }
+
+       client->handle = fd;
+       client->router = router;
+       router->info.server.client_list = dlist_append(router->info.server.client_list, client);
+
+       status = pthread_create(&client->thid, NULL, server_main, client);
+       if (status != 0) {
+               ErrPrint("Thread creation failed: %s\n", strerror(status));
+               dlist_remove_data(router->info.server.client_list, client);
+               secure_socket_destroy_handle(client->handle);
+               free(client);
+               /*!
+                * \NOTE
+                * Just return TRUE to keep this accept handler
+                */
+               return TRUE;
+       }
+
+       (void)invoke_connected_cb(router, fd);
+       return TRUE;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+EAPI int com_core_packet_router_server_init(const char *sock, double timeout, struct method *table)
+{
+       int handle;
+       struct router *router;
+       GIOChannel *gio;
+
+       handle = secure_socket_create_server(sock);
+       if (handle < 0)
+               return handle;
+
+       router = create_router(sock, handle, table);
+       if (!router) {
+               secure_socket_destroy_handle(handle);
+               return -ENOMEM;
+       }
+
+       router->timeout = timeout;
+       router->is_server = 1;
+
+       gio = g_io_channel_unix_new(router->handle);
+       if (!gio) {
+               handle = destroy_router(router);
+               secure_socket_destroy_handle(handle);
+               return -EIO;
+       }
+
+       g_io_channel_set_close_on_unref(gio, FALSE);
+
+       router->info.server.accept_id = g_io_add_watch(gio, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc)accept_cb, router);
+       if (router->info.server.accept_id == 0) {
+               GError *err = NULL;
+               g_io_channel_shutdown(gio, TRUE, &err);
+               if (err) {
+                       ErrPrint("Shutdown: %s\n", err->message);
+                       g_error_free(err);
+               }
+               g_io_channel_unref(gio);
+
+               handle = destroy_router(router);
+               secure_socket_destroy_handle(handle);
+               return -EIO;
+       }
+
+       g_io_channel_unref(gio);
+       return router->handle;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+EAPI int com_core_packet_router_client_init(const char *sock, double timeout, struct method *table)
+{
+       struct router *router;
+       int handle;
+       int status;
+
+       handle = secure_socket_create_client(sock);
+       if (handle < 0)
+               return handle;
+
+       router = create_router(sock, handle, table);
+       if (!router) {
+               secure_socket_destroy_handle(handle);
+               return -ENOMEM;
+       }
+
+       router->timeout = timeout;
+       router->is_server = 0;
+
+       status = pthread_mutex_init(&router->recv_packet_list_lock, NULL);
+       if (status != 0) {
+               ErrPrint("Mutex creation failed: %s\n", strerror(status));
+
+               handle = destroy_router(router);
+               secure_socket_destroy_handle(handle);
+               return -EFAULT;
+       }
+
+       status = pthread_mutex_init(&router->route_list_lock, NULL);
+       if (status != 0) {
+               ErrPrint("Mutex creation failed: %s\n", strerror(status));
+               handle = destroy_router(router);
+               secure_socket_destroy_handle(handle);
+               return -EFAULT;
+       }
+
+       status = pthread_create(&router->info.client.thid, NULL, client_main, router);
+       if (status != 0) {
+               ErrPrint("Thread creation failed: %s\n", strerror(status));
+               handle = destroy_router(router);
+               secure_socket_destroy_handle(handle);
+               return -EFAULT;
+       }
+
+       (void)invoke_connected_cb(router, router->handle);
+       return router->handle;
+}
+
+EAPI void *com_core_packet_router_server_fini(int handle)
+{
+       struct router *router;
+       void *data;
+       int status;
+       struct dlist *l;
+       struct dlist *n;
+
+       struct client *client;
+       struct route *route;
+
+       void *ret;
+
+       router = find_router_by_handle(handle);
+       if (!router) {
+               ErrPrint("No such router\n");
+               return NULL;
+       }
+
+       if (!router->is_server) {
+               ErrPrint("Invalid object\n");
+               return NULL;
+       }
+
+       if(router->info.server.accept_id > 0)
+               g_source_remove(router->info.server.accept_id);
+
+       dlist_foreach_safe(router->info.server.client_list, l, n, client) {
+               router->info.server.client_list = dlist_remove(router->info.server.client_list, l);
+
+               status = pthread_cancel(client->thid);
+               if (status != 0)
+                       ErrPrint("Failed to cacnel a thread: %s\n", strerror(errno));
+
+               ret = NULL;
+               status = pthread_join(client->thid, &ret);
+               if (status != 0)
+                       ErrPrint("Failed to cancel a thread: %s\n", strerror(errno));
+
+               if (ret == PTHREAD_CANCELED) {
+                       DbgPrint("Thread is canceled\n");
+                       clear_request_ctx(client->handle);
+               }
+
+               secure_socket_destroy_handle(client->handle);
+               free(client);
+       }
+
+       dlist_foreach_safe(router->route_list, l, n, route) {
+               router->route_list = dlist_remove(router->route_list, l);
+               free(route);
+       }
+
+       data = router->data;
+
+       handle = destroy_router(router);
+       secure_socket_destroy_handle(handle);
+
+       return data;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+EAPI void *com_core_packet_router_client_fini(int handle)
+{
+       struct router *router;
+       void *data;
+       int status;
+       struct dlist *l;
+       struct dlist *n;
+
+       struct route *route;
+
+       void *ret = NULL;
+
+       router = find_router_by_handle(handle);
+       if (!router) {
+               ErrPrint("No such router\n");
+               return NULL;
+       }
+
+       if (router->is_server) {
+               ErrPrint("Invalid object\n");
+               return NULL;
+       }
+
+       status = pthread_cancel(router->info.client.thid);
+       if (status != 0)
+               ErrPrint("Failed to cancel a thread: %s\n", strerror(errno));
+
+       status = pthread_join(router->info.client.thid, &ret);
+       if (status != 0)
+               ErrPrint("Failed to join a thread: %s\n", strerror(errno));
+
+       if (ret == PTHREAD_CANCELED) {
+               DbgPrint("Thread is canceled\n");
+               clear_request_ctx(router->handle);
+       }
+
+       dlist_foreach_safe(router->route_list, l, n, route) {
+               router->route_list = dlist_remove(router->route_list, l);
+               free(route);
+       }
+
+       data = router->data;
+
+       handle = destroy_router(router);
+       secure_socket_destroy_handle(handle);
+
+       return data;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+EAPI int com_core_packet_router_async_send(int handle, struct packet *packet, double timeout, int (*recv_cb)(pid_t pid, int handle, const struct packet *packet, void *data), void *data)
+{
+       struct request_ctx *ctx;
+       struct router *router;
+       int ret;
+
+       if (handle < 0 || !packet)
+               return -EINVAL;
+
+       if (packet_type(packet) != PACKET_REQ) {
+               ErrPrint("Invalid packet - should be PACKET_REQ\n");
+               return -EINVAL;
+       }
+
+       router = find_router_by_handle(handle);
+       if (!router) {
+               ErrPrint("Router is not available\n");
+               return -EINVAL;
+       }
+
+       ctx = create_request_ctx(handle);
+       if (!ctx)
+               return -ENOMEM;
+
+       ctx->recv_cb = recv_cb;
+       ctx->data = data;
+       ctx->packet = packet_ref(packet);
+
+       ret = put_send_packet(router, handle, packet);
+       if (ret < 0)
+               destroy_request_ctx(ctx);
+
+       return ret;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+EAPI int com_core_packet_router_send_only(int handle, struct packet *packet)
+{
+       struct router *router;
+
+       if (handle < 0 || !packet || packet_type(packet) != PACKET_REQ_NOACK)
+               return -EINVAL;
+
+       router = find_router_by_handle(handle);
+       if (!router) {
+               ErrPrint("Rouer is not available\n");
+               return -EINVAL;
+       }
+
+       return put_send_packet(router, handle, packet);
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+EAPI struct packet *com_core_packet_router_oneshot_send(const char *addr, struct packet *packet, double timeout)
+{
+       return com_core_packet_oneshot_send(addr, packet, timeout);
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+EAPI int com_core_packet_router_add_route(int handle, unsigned long address, int h)
+{
+       struct router *router;
+       struct route *route;
+       struct route *tmp;
+       struct dlist *l;
+       int found = 0;
+
+       if (handle < 0 || !address || h < 0)
+               return -EINVAL;
+
+       router = find_router_by_handle(handle);
+       if (!router) {
+               ErrPrint("Router is not exists\n");
+               return -ENOENT;
+       }
+
+       route = malloc(sizeof(*route));
+       if (!route) {
+               ErrPrint("Heap: %s\n", strerror(errno));
+               return -ENOMEM;
+       }
+
+       route->address = address;
+       route->handle = h;
+       route->invalid = 0;
+
+       CRITICAL_SECTION_BEGIN(&router->route_list_lock);
+
+       dlist_foreach(router->route_list, l, tmp) {
+               if (tmp->address == address) {
+                       found = 1;
+                       break;
+               }
+       }
+
+       if (!found)
+               router->route_list = dlist_append(router->route_list, route);
+
+       CRITICAL_SECTION_END(&router->route_list_lock);
+
+       if (found) {
+               free(route);
+               return -EEXIST;
+       }
+
+       return 0;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+EAPI int com_core_packet_router_del_route(int handle, unsigned long address)
+{
+       struct router *router;
+       struct route *route;
+       struct dlist *l;
+       struct dlist *n;
+       int found = 0;
+
+       if (handle < 0 || !address)
+               return -EINVAL;
+
+       router = find_router_by_handle(handle);
+       if (!router) {
+               ErrPrint("Router is not exists\n");
+               return -ENOENT;
+       }
+
+       CRITICAL_SECTION_BEGIN(&router->route_list_lock);
+
+       dlist_foreach_safe(router->route_list, l, n, route) {
+               if (route->address != address)
+                       continue;
+
+               router->route_list = dlist_remove(router->route_list, l);
+
+               DbgPrint("Delete an entry from the table (%lu : %d)\n", route->address, route->handle);
+               free(route);
+
+               found = 1;
+               break;
+       }
+
+       CRITICAL_SECTION_END(&router->route_list_lock);
+
+       return found ? 0 : -ENOENT;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+EAPI int com_core_packet_router_update_route(int handle, unsigned long address, int h)
+{
+       struct router *router;
+       struct route *route;
+       struct dlist *l;
+       int found = 0;
+
+       if (handle < 0 || !address || h < 0)
+               return -EINVAL;
+
+       router = find_router_by_handle(handle);
+       if (!router) {
+               ErrPrint("Router is not exists\n");
+               return -ENOENT;
+       }
+
+       CRITICAL_SECTION_BEGIN(&router->route_list_lock);
+
+       dlist_foreach(router->route_list, l, route) {
+               if (route->address != address)
+                       continue;
+
+               route->handle = h;
+               route->invalid = 0;
+               found = 1;
+               break;
+       }
+
+       CRITICAL_SECTION_END(&router->route_list_lock);
+
+       return found ? 0 : -ENOENT;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+EAPI int com_core_packet_router_add_event_callback(enum com_core_route_event_type type, int (*evt_cb)(int handle, void *data), void *data)
+{
+       struct event_item *item;
+
+       if (!evt_cb) {
+               ErrPrint("Invalid event callback\n");
+               return -EINVAL;
+       }
+
+       item = malloc(sizeof(*item));
+       if (!item) {
+               ErrPrint("Heap: %s\n", strerror(errno));
+               return -ENOMEM;
+       }
+
+       item->evt_cb = evt_cb;
+       item->data = data;
+
+       switch (type) {
+       case COM_CORE_ROUTE_CONNECTED:
+               s_info.connected_list = dlist_prepend(s_info.connected_list, item);
+               break;
+       case COM_CORE_ROUTE_DISCONNECTED:
+               s_info.disconnected_list = dlist_prepend(s_info.disconnected_list, item);
+               break;
+       case COM_CORE_ROUTE_ERROR:
+               s_info.error_list = dlist_prepend(s_info.error_list, item);
+               break;
+       default:
+               free(item);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+EAPI int com_core_packet_router_del_event_callback(enum com_core_route_event_type type, int (*evt_cb)(int handle, void *data), void *data)
+{
+       struct dlist *l;
+       struct dlist *n;
+       struct event_item *item;
+
+       switch (type) {
+       case COM_CORE_ROUTE_CONNECTED:
+               dlist_foreach_safe(s_info.connected_list, l, n, item) {
+                       if (item->evt_cb == evt_cb && item->data == data) {
+                               s_info.connected_list = dlist_remove(s_info.connected_list, l);
+                               free(item);
+                               return 0;
+                       }
+               }
+               break;
+       case COM_CORE_ROUTE_DISCONNECTED:
+               dlist_foreach_safe(s_info.disconnected_list, l, n, item) {
+                       if (item->evt_cb == evt_cb && item->data == data) {
+                               s_info.disconnected_list = dlist_remove(s_info.disconnected_list, l);
+                               free(item);
+                               return 0;
+                       }
+               }
+               break;
+       case COM_CORE_ROUTE_ERROR:
+               dlist_foreach_safe(s_info.error_list, l, n, item) {
+                       if (item->evt_cb == evt_cb && item->data == data) {
+                               s_info.error_list = dlist_remove(s_info.error_list, l);
+                               free(item);
+                               return 0;
+                       }
+               }
+               break;
+       default:
+               ErrPrint("Invalid event type\n");
+               return -EINVAL;
+       }
+
+       return -ENOENT;
+}
+
+#undef _GNU_SOURCE
+/* End of a file */
diff --git a/src/com-core_packet.c b/src/com-core_packet.c
new file mode 100644 (file)
index 0000000..2d69011
--- /dev/null
@@ -0,0 +1,635 @@
+/*
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+#include <glib.h>
+#include <dlog.h>
+
+#include "debug.h"
+#include "com-core.h"
+#include "com-core_thread.h"
+#include "packet.h"
+#include "secure_socket.h"
+#include "dlist.h"
+#include "com-core_packet.h"
+#include "util.h"
+
+#define DEFAULT_TIMEOUT 2.0f
+
+static struct info {
+       struct dlist *recv_list;
+       struct dlist *request_list;
+       char *addr;
+
+       struct {
+               int (*server_create)(const char *addr, int is_sync, int (*service_cb)(int fd, void *data), void *data);
+               int (*client_create)(const char *addr, int is_sync, int (*service_cb)(int fd, void *data), void *data);
+               int (*server_destroy)(int handle);
+               int (*client_destroy)(int handle);
+
+               int (*recv)(int handle, char *buffer, int size, int *sender_pid, double timeout);
+               int (*send)(int handle, const char *buffer, int size, double timeout);
+       } vtable;
+
+       int initialized;
+} s_info = {
+       .recv_list = NULL,
+       .request_list = NULL,
+       .addr = NULL,
+       .vtable = {
+               .server_create = com_core_server_create,
+               .client_create = com_core_client_create,
+               .server_destroy = com_core_server_destroy,
+               .client_destroy = com_core_client_destroy,
+               .recv = com_core_recv,
+               .send = com_core_send,
+       },
+       .initialized = 0,
+};
+
+struct request_ctx {
+       pid_t pid;
+       int handle;
+
+       struct packet *packet;
+       int (*recv_cb)(pid_t pid, int handle, const struct packet *packet, void *data);
+       void *data;
+};
+
+struct recv_ctx {
+       enum {
+               RECV_STATE_INIT,
+               RECV_STATE_HEADER,
+               RECV_STATE_BODY,
+               RECV_STATE_READY,
+       } state;
+       int handle;
+       int offset;
+       pid_t pid;
+       struct packet *packet;
+       double timeout;
+};
+
+static inline struct request_ctx *find_request_ctx(int handle, double seq)
+{
+       struct request_ctx *ctx;
+       struct dlist *l;
+
+       dlist_foreach(s_info.request_list, l, ctx) {
+               if (ctx->handle == handle && packet_seq(ctx->packet) == seq) {
+                       return ctx;
+               }
+       }
+
+       return NULL;
+}
+
+static inline void destroy_request_ctx(struct request_ctx *ctx)
+{
+       packet_unref(ctx->packet);
+       dlist_remove_data(s_info.request_list, ctx);
+       free(ctx);
+}
+
+static inline struct request_ctx *create_request_ctx(int handle)
+{
+       struct request_ctx *ctx;
+
+       ctx = malloc(sizeof(*ctx));
+       if (!ctx) {
+               ErrPrint("Heap: %s\n", strerror(errno));
+               return NULL;
+       }
+
+       ctx->handle = handle;
+       ctx->pid = (pid_t)-1;
+       ctx->packet = NULL;
+       ctx->recv_cb = NULL;
+       ctx->data = NULL;
+
+       s_info.request_list = dlist_append(s_info.request_list, ctx);
+       return ctx;
+}
+
+static inline struct recv_ctx *find_recv_ctx(int handle)
+{
+       struct recv_ctx *ctx;
+       struct dlist *l;
+
+       dlist_foreach(s_info.recv_list, l, ctx) {
+               if (ctx->handle == handle)
+                       return ctx;
+       }
+
+       return NULL;
+}
+
+static inline void destroy_recv_ctx(struct recv_ctx *ctx)
+{
+       dlist_remove_data(s_info.recv_list, ctx);
+       packet_destroy(ctx->packet);
+       free(ctx);
+}
+
+static inline struct recv_ctx *create_recv_ctx(int handle, double timeout)
+{
+       struct recv_ctx *ctx;
+
+       ctx = malloc(sizeof(*ctx));
+       if (!ctx) {
+               ErrPrint("heap: %s\n", strerror(errno));
+               return NULL;
+       }
+
+       ctx->state = RECV_STATE_INIT,
+       ctx->offset = 0;
+       ctx->packet = NULL;
+       ctx->handle = handle;
+       ctx->pid = (pid_t)-1;
+       ctx->timeout = timeout;
+
+       s_info.recv_list = dlist_append(s_info.recv_list, ctx);
+       return ctx;
+}
+
+static inline int packet_ready(int handle, const struct recv_ctx *receive, struct method *table)
+{
+       struct request_ctx *request;
+       double sequence;
+       struct packet *result;
+       register int i;
+       int ret;
+
+       ret = 0;
+
+       switch (packet_type(receive->packet)) {
+       case PACKET_ACK:
+               sequence = packet_seq(receive->packet);
+               request = find_request_ctx(handle, sequence);
+               if (!request) {
+                       ErrPrint("This is not requested packet (%s)\n", packet_command(receive->packet));
+                       break;
+               }
+
+               if (request->recv_cb)
+                       request->recv_cb(receive->pid, handle, receive->packet, request->data);
+
+               destroy_request_ctx(request);
+               break;
+       case PACKET_REQ:
+               for (i = 0; table[i].cmd; i++) {
+                       if (strcmp(table[i].cmd, packet_command(receive->packet)))
+                               continue;
+
+                       result = table[i].handler(receive->pid, handle, receive->packet);
+                       if (result) {
+                               ret = s_info.vtable.send(handle, (void *)packet_data(result), packet_size(result), DEFAULT_TIMEOUT);
+                               if (ret < 0) {
+                                       ErrPrint("Failed to send an ack packet\n");
+                               } else {
+                                       ret = 0;
+                               }
+                               packet_destroy(result);
+                       }
+                       break;
+               }
+
+               break;
+       case PACKET_REQ_NOACK:
+               for (i = 0; table[i].cmd; i++) {
+                       if (strcmp(table[i].cmd, packet_command(receive->packet)))
+                               continue;
+
+                       result = table[i].handler(receive->pid, handle, receive->packet);
+                       if (result)
+                               packet_destroy(result);
+               }
+               break;
+       default:
+               break;
+       }
+
+       /*!
+        * Return negative value will make call the disconnected_cb
+        */
+       return ret;
+}
+
+static int client_disconnected_cb(int handle, void *data)
+{
+       struct recv_ctx *receive;
+       struct request_ctx *request;
+       struct dlist *l;
+       struct dlist *n;
+       pid_t pid = (pid_t)-1;
+
+       receive = find_recv_ctx(handle);
+       if (receive) {
+               pid = receive->pid;
+               destroy_recv_ctx(receive);
+       }
+
+       DbgPrint("Clean up all requests and a receive context for handle(%d) for pid(%d)\n", handle, pid);
+
+       dlist_foreach_safe(s_info.request_list, l, n, request) {
+               if (request->handle != handle)
+                       continue;
+
+               if (request->recv_cb)
+                       request->recv_cb(pid, handle, NULL, request->data);
+
+               destroy_request_ctx(request);
+       }
+
+       return 0;
+}
+
+static int service_cb(int handle, void *data)
+{
+       struct recv_ctx *receive;
+       pid_t pid;
+       int ret;
+       int size;
+       char *ptr;
+
+       receive = find_recv_ctx(handle);
+       if (!receive) {
+               receive = create_recv_ctx(handle, DEFAULT_TIMEOUT);
+               if (!receive) {
+                       ErrPrint("Couldn't find or create a receive context\n");
+                       return -EIO;
+               }
+       }
+
+       switch (receive->state) {
+       case RECV_STATE_INIT:
+               receive->state = RECV_STATE_HEADER;
+               receive->offset = 0;
+       case RECV_STATE_HEADER:
+               size = packet_header_size() - receive->offset;
+               /*!
+                * \note
+                * Getting header
+                */
+               ptr = malloc(size);
+               if (!ptr) {
+                       ErrPrint("Heap: %s\n", strerror(errno));
+                       return -ENOMEM;
+               }
+
+               ret = s_info.vtable.recv(handle, ptr, size, &pid, receive->timeout);
+               if (ret < 0) {
+                       ErrPrint("Recv[%d], pid[%d :: %d]\n", ret, receive->pid, pid);
+                       free(ptr);
+                       return -EIO; /*!< Return negative value will invoke the client_disconnected_cb */
+               } else if (ret > 0) {
+                       if (receive->pid != -1 && receive->pid != pid) {
+                               ErrPrint("Recv[%d], pid[%d :: %d]\n", ret, receive->pid, pid);
+                               free(ptr);
+                               return -EIO; /*!< Return negative value will invoke the client_disconnected_cb */
+                       }
+
+                       receive->pid = pid;
+                       receive->packet = packet_build(receive->packet, receive->offset, ptr, ret);
+                       free(ptr);
+
+                       if (!receive->packet) {
+                               ErrPrint("Built packet is not valid\n");
+                               return -EFAULT; /*!< Return negative value will invoke the client_disconnected_cb */
+                       }
+
+                       receive->offset += ret;
+
+                       if (receive->offset == packet_header_size()) {
+                               if (packet_size(receive->packet) == receive->offset)
+                                       receive->state = RECV_STATE_READY;
+                               else
+                                       receive->state = RECV_STATE_BODY;
+                       }
+               } else {
+                       DbgPrint("ZERO bytes receives(%d)\n", pid);
+                       free(ptr);
+                       return -ECONNRESET;
+               }
+               break;
+       case RECV_STATE_BODY:
+               size = packet_size(receive->packet) - receive->offset;
+               if (size == 0) {
+                       receive->state = RECV_STATE_READY;
+                       break;
+               }
+               /*!
+                * \note
+                * Getting body
+                */
+               ptr = malloc(size);
+               if (!ptr) {
+                       ErrPrint("Heap: %s\n", strerror(errno));
+                       return -ENOMEM;
+               }
+
+               ret = s_info.vtable.recv(handle, ptr, size, &pid, receive->timeout);
+               if (ret < 0) {
+                       ErrPrint("Recv[%d], pid[%d :: %d]\n", ret, receive->pid, pid);
+                       free(ptr);
+                       return -EIO;
+               } else if (ret > 0) {
+                       if (receive->pid != pid) {
+                               ErrPrint("Recv[%d], pid[%d :: %d]\n", ret, receive->pid, pid);
+                               free(ptr);
+                               return -EIO;
+                       }
+
+                       receive->packet = packet_build(receive->packet, receive->offset, ptr, ret);
+                       free(ptr);
+
+                       if (!receive->packet) {
+                               ErrPrint("Built packet is not valid\n");
+                               return -EFAULT;
+                       }
+
+                       receive->offset += ret;
+
+                       if (receive->offset == packet_size(receive->packet)) {
+                               receive->state = RECV_STATE_READY;
+                       }
+               } else {
+                       DbgPrint("ZERO bytes receives(%d)\n", pid);
+                       free(ptr);
+                       return -ECONNRESET;
+               }
+
+               break;
+       case RECV_STATE_READY:
+       default:
+               break;
+       }
+
+       if (receive->state == RECV_STATE_READY) {
+               ret = packet_ready(handle, receive, data);
+               if (ret == 0)
+                       destroy_recv_ctx(receive);
+               /*!
+                * if ret is negative value, disconnected_cb will be called after this function
+                */
+       } else {
+               ret = 0;
+       }
+
+       return ret;
+}
+
+EAPI int com_core_packet_async_send(int handle, struct packet *packet, double timeout, int (*recv_cb)(pid_t pid, int handle, const struct packet *packet, void *data), void *data)
+{
+       int ret;
+       struct request_ctx *ctx;
+
+       if (handle < 0 || !packet) {
+               ErrPrint("Invalid argument\n");
+               return -EINVAL;
+       }
+
+       if (packet_type(packet) != PACKET_REQ) {
+               ErrPrint("Invalid packet - should be PACKET_REQ\n");
+               return -EINVAL;
+       }
+
+       ctx = create_request_ctx(handle);
+       if (!ctx)
+               return -ENOMEM;
+
+       ctx->recv_cb = recv_cb;
+       ctx->data = data;
+       ctx->packet = packet_ref(packet);
+
+       ret = s_info.vtable.send(handle, (void *)packet_data(packet), packet_size(packet), DEFAULT_TIMEOUT);
+       if (ret != packet_size(packet)) {
+               ErrPrint("Send failed. %d <> %d (handle: %d)\n", ret, packet_size(packet), handle);
+               destroy_request_ctx(ctx);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+EAPI int com_core_packet_send_only(int handle, struct packet *packet)
+{
+       int ret;
+
+       if (packet_type(packet) != PACKET_REQ_NOACK) {
+               ErrPrint("Invalid type - should be PACKET_REQ_NOACK (%p)\n", packet);
+               return -EINVAL;
+       }
+
+       ret = s_info.vtable.send(handle, (void *)packet_data(packet), packet_size(packet), DEFAULT_TIMEOUT);
+       if (ret != packet_size(packet)) {
+               ErrPrint("Failed to send whole packet\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+EAPI struct packet *com_core_packet_oneshot_send(const char *addr, struct packet *packet, double timeout)
+{
+       int ret;
+       int fd;
+       pid_t pid;
+       int offset;
+       struct packet *result = NULL;
+       void *ptr;
+       int size;
+
+       if (!addr || !packet) {
+               ErrPrint("Invalid argument\n");
+               return NULL;
+       }
+
+       fd = secure_socket_create_client(addr);
+       if (fd < 0)
+               return NULL;
+
+       DbgPrint("FD: %d\n", fd);
+
+       if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0)
+               ErrPrint("fcntl: %s\n", strerror(errno));
+
+       if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
+               ErrPrint("Error: %s\n", strerror(errno));
+
+       ret = com_core_send(fd, (char *)packet_data(packet), packet_size(packet), DEFAULT_TIMEOUT);
+       if (ret < 0)
+               goto out;
+
+       DbgPrint("Sent: %d bytes (%d bytes)\n", ret, packet_size(packet));
+
+       ptr = malloc(packet_header_size());
+       if (!ptr) {
+               ErrPrint("Heap: %s\n", strerror(errno));
+               goto out;
+       }
+
+       offset = 0;
+       ret = com_core_recv(fd, (char *)ptr, packet_header_size(), &pid, timeout);
+       if (ret <= 0) {
+               DbgPrint("Recv returns %s\n", ret);
+               free(ptr);
+               goto out;
+       } else {
+               DbgPrint("Recv'd size: %d (header: %d) pid: %d\n", ret, packet_header_size(), pid);
+               result = packet_build(result, offset, ptr, ret);
+               offset += ret;
+               free(ptr);
+               if (!result) {
+                       ErrPrint("Failed to build a packet\n");
+                       goto out;
+               }
+       }
+
+       size = packet_payload_size(result);
+       DbgPrint("Payload size: %d\n", size);
+       if (size < 0) {
+               packet_destroy(result);
+               result = NULL;
+               goto out;
+       }
+
+       if (size == 0) {
+               DbgPrint("Has no payload\n");
+               goto out;
+       }
+
+       ptr = malloc(size);
+       if (!ptr) {
+               ErrPrint("Heap: %s\n", strerror(errno));
+               packet_destroy(result);
+               result = NULL;
+               goto out;
+       }
+
+       ret = com_core_recv(fd, (char *)ptr, size, &pid, timeout);
+       if (ret <= 0) {
+               DbgPrint("Recv returns %s\n", ret);
+               free(ptr);
+               packet_destroy(result);
+               result = NULL;
+       } else {
+               DbgPrint("Recv'd %d bytes (pid: %d)\n", ret, pid);
+               result = packet_build(result, offset, ptr, ret);
+               offset += ret;
+               free(ptr);
+       }
+
+out:
+       secure_socket_destroy_handle(fd);
+       DbgPrint("Close connection: %d\n", fd);
+       return result;
+}
+
+static inline int com_core_packet_init(void)
+{
+       int ret;
+       if (s_info.initialized)
+               return 0;
+
+       ret = com_core_add_event_callback(CONNECTOR_DISCONNECTED, client_disconnected_cb, NULL);
+       s_info.initialized = (ret == 0);
+       return ret;
+}
+
+static inline int com_core_packet_fini(void)
+{
+       if (!s_info.initialized)
+               return 0;
+
+       s_info.initialized = 0;
+       com_core_del_event_callback(CONNECTOR_DISCONNECTED, client_disconnected_cb, NULL);
+       return 0;
+}
+
+EAPI int com_core_packet_client_init(const char *addr, int is_sync, struct method *table)
+{
+       int ret;
+
+       ret = com_core_packet_init();
+       if (ret < 0)
+               return ret;
+
+       ret = s_info.vtable.client_create(addr, is_sync, service_cb, table);
+       if (ret < 0)
+               com_core_packet_fini();
+
+       return ret;
+}
+
+EAPI int com_core_packet_client_fini(int handle)
+{
+       s_info.vtable.client_destroy(handle);
+       com_core_packet_fini();
+       return 0;
+}
+
+EAPI int com_core_packet_server_init(const char *addr, struct method *table)
+{
+       int ret;
+
+       ret = com_core_packet_init();
+       if (ret < 0)
+               return ret;
+
+       ret = s_info.vtable.server_create(addr, 0, service_cb, table);
+       if (ret < 0)
+               com_core_packet_fini();
+
+       return ret;
+}
+
+EAPI int com_core_packet_server_fini(int handle)
+{
+       s_info.vtable.server_destroy(handle);
+       com_core_packet_fini();
+       return 0;
+}
+
+EAPI void com_core_packet_use_thread(int flag)
+{
+       if (!!flag) {
+               s_info.vtable.server_create = com_core_thread_server_create;
+               s_info.vtable.client_create = com_core_thread_client_create;
+               s_info.vtable.server_destroy = com_core_thread_server_destroy;
+               s_info.vtable.client_destroy = com_core_thread_client_destroy;
+               s_info.vtable.recv = com_core_thread_recv;
+               s_info.vtable.send = com_core_thread_send;
+       } else {
+               s_info.vtable.server_create = com_core_server_create;
+               s_info.vtable.client_create = com_core_client_create;
+               s_info.vtable.server_destroy = com_core_server_destroy;
+               s_info.vtable.client_destroy = com_core_client_destroy;
+               s_info.vtable.recv = com_core_recv;
+               s_info.vtable.send = com_core_send;
+       }
+}
+
+/* End of a file */
diff --git a/src/com-core_thread.c b/src/com-core_thread.c
new file mode 100644 (file)
index 0000000..64d09e1
--- /dev/null
@@ -0,0 +1,948 @@
+/*
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+*/
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <pthread.h>
+
+#include <glib.h>
+
+#include <dlog.h>
+
+#include "dlist.h"
+#include "secure_socket.h"
+#include "debug.h"
+#include "com-core.h"
+#include "com-core_internal.h"
+#include "util.h"
+
+int errno;
+#define PIPE_READ 0
+#define PIPE_WRITE 1
+#define EVENT_READY 'a'
+#define EVENT_TERM 'e'
+
+static struct {
+       struct dlist *tcb_list;
+       struct dlist *server_list;
+} s_info = {
+       .tcb_list = NULL,
+       .server_list = NULL,
+};
+
+/*!
+ * \brief Representing the Server Object
+ */
+struct server {
+       int (*service_cb)(int fd, void *data);
+       void *data;
+
+       guint id;
+       int handle;
+};
+
+/*!
+ * \brief This is used to holds a packet
+ */
+struct chunk {
+       char *data;
+       int offset;
+       int size;
+       pid_t pid;
+};
+
+/*!
+ * \brief Thread Control Block
+ */
+struct tcb {
+       pthread_t thid;
+       int handle;
+       struct dlist *chunk_list;
+       int evt_pipe[2];
+       pthread_mutex_t chunk_lock;
+       guint id; /*!< g_io_watch */
+
+       int server_handle;
+
+       int (*service_cb)(int fd, void *data);
+       void *data;
+
+       int terminated;
+};
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+static inline void server_destroy(struct server *server)
+{
+       dlist_remove_data(s_info.server_list, server);
+
+       if (server->id > 0)
+               g_source_remove(server->id);
+
+       if (server->handle > 0)
+               secure_socket_destroy_handle(server->handle);
+
+       free(server);
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+static inline struct server *server_create(int handle, int (*service_cb)(int fd, void *data), void *data)
+{
+       struct server *server;
+
+       server = malloc(sizeof(*server));
+       if (!server) {
+               ErrPrint("Heap: %s\n", strerror(errno));
+               return NULL;
+       }
+
+       server->handle = handle;
+       server->service_cb = service_cb;
+       server->data = data;
+
+       s_info.server_list = dlist_append(s_info.server_list, server);
+       return server;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+static inline void destroy_chunk(struct chunk *chunk)
+{
+       free(chunk->data);
+       free(chunk);
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+static inline void terminate_thread(struct tcb *tcb)
+{
+       void *res = NULL;
+       int status;
+
+       status = pthread_cancel(tcb->thid);
+       if (status != 0)
+               ErrPrint("Failed to cancel the thread: %s\n", strerror(status));
+
+       status = pthread_join(tcb->thid, &res);
+       if (status != 0)
+               ErrPrint("Join: %s\n", strerror(status));
+
+       if (res == PTHREAD_CANCELED) {
+               struct dlist *l;
+               struct dlist *n;
+               struct chunk *chunk;
+
+               dlist_foreach_safe(tcb->chunk_list, l, n, chunk) {
+                       /*!
+                        * Discarding all packets
+                        */
+                       tcb->chunk_list = dlist_remove(tcb->chunk_list, l);
+                       destroy_chunk(chunk);
+               }
+       }
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+static inline void chunk_remove(struct tcb *tcb, struct chunk *chunk)
+{
+       char event_ch;
+
+       /* Consuming the event */
+       if (read(tcb->evt_pipe[PIPE_READ], &event_ch, sizeof(event_ch)) != sizeof(event_ch)) {
+               ErrPrint("Failed to get readsize\n");
+               return;
+       }
+
+       CRITICAL_SECTION_BEGIN(&tcb->chunk_lock);
+
+       dlist_remove_data(tcb->chunk_list, chunk);
+
+       CRITICAL_SECTION_END(&tcb->chunk_lock);
+
+       destroy_chunk(chunk);
+}
+
+/*!
+ * \NOTE
+ * Running thread: Other
+ */
+static inline void chunk_append(struct tcb *tcb, struct chunk *chunk)
+{
+       char event_ch = EVENT_READY;
+       int ret;
+
+       CRITICAL_SECTION_BEGIN(&tcb->chunk_lock);
+
+       tcb->chunk_list = dlist_append(tcb->chunk_list, chunk);
+
+       CRITICAL_SECTION_END(&tcb->chunk_lock);
+
+       ret = write(tcb->evt_pipe[PIPE_WRITE], &event_ch, sizeof(event_ch));
+       if (ret < 0) {
+               ErrPrint("write: %s\n", strerror(errno));
+               return;
+       }
+
+       if (ret != sizeof(event_ch))
+               ErrPrint("Failed to trigger reader\n");
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+static inline int wait_event(struct tcb *tcb, double timeout)
+{
+       fd_set set;
+       int ret;
+
+       if (tcb->terminated)
+               return -ECONNRESET;
+
+       FD_ZERO(&set);
+       FD_SET(tcb->evt_pipe[PIPE_READ], &set);
+
+       if (timeout > 0.0f) {
+               struct timeval tv;
+               tv.tv_sec = (unsigned long)timeout;
+               tv.tv_usec = (timeout - (unsigned long)timeout) * 1000000u;
+               ret = select(tcb->evt_pipe[PIPE_READ] + 1, &set, NULL, NULL, &tv);
+       } else if (timeout == 0.0f) {
+               ret = select(tcb->evt_pipe[PIPE_READ] + 1, &set, NULL, NULL, NULL);
+       } else {
+               ErrPrint("Invalid timeout: %lf (it must be greater than 0.0)\n", timeout);
+               return -EINVAL;
+       }
+
+       if (ret < 0) {
+               ret = -errno;
+               if (errno == EINTR) {
+                       DbgPrint("Select receives INTR\n");
+                       return -EAGAIN;
+               }
+
+               ErrPrint("Error: %s\n", strerror(errno));
+               return ret;
+       } else if (ret == 0) {
+               ErrPrint("Timeout expired\n");
+               return -ETIMEDOUT;
+       }
+
+       if (!FD_ISSET(tcb->evt_pipe[PIPE_READ], &set)) {
+               ErrPrint("Unexpected handle is toggled\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+static inline struct chunk *create_chunk(int size)
+{
+       struct chunk *chunk;
+
+       chunk = malloc(sizeof(*chunk));
+       if (!chunk) {
+               ErrPrint("Heap: %s\n", strerror(errno));
+               return NULL;
+       }
+
+       chunk->data = malloc(size);
+       if (!chunk->data) {
+               ErrPrint("Heap: %s\n", strerror(errno));
+               free(chunk);
+               return NULL;
+       }
+
+       chunk->pid = (pid_t)-1;
+       chunk->size = size;
+       chunk->offset = 0;
+       return chunk;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Other
+ */
+static void *client_cb(void *data)
+{
+       struct tcb *tcb = data;
+       struct chunk *chunk;
+       int ret = 0;
+       fd_set set;
+       int readsize;
+       char event_ch;
+       int status;
+
+       DbgPrint("Thread is created for %d (server: %d)\n", tcb->handle, tcb->server_handle);
+       /*!
+        * \NOTE
+        * Read all data from the socket as possible as it can do
+        */
+       while (1) {
+               FD_ZERO(&set);
+               FD_SET(tcb->handle, &set);
+
+               status = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+               if (status != 0)
+                       ErrPrint("Error: %s\n", strerror(status));
+
+               ret = select(tcb->handle + 1, &set, NULL, NULL, NULL);
+               if (ret < 0) {
+                       ret = -errno;
+                       if (errno == EINTR) {
+                               DbgPrint("Select receives INTR\n");
+                               status = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+                               if (status != 0)
+                                       ErrPrint("Error: %s\n", strerror(status));
+                               continue;
+                       }
+
+                       /*!< Error */
+                       ErrPrint("Error: %s\n", strerror(errno));
+                       status = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+                       if (status != 0)
+                               ErrPrint("Error: %s\n", strerror(status));
+                       break;
+               } else if (ret == 0) {
+                       ErrPrint("What happens? [%d]\n", tcb->handle);
+                       status = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+                       if (status != 0)
+                               ErrPrint("Error: %s\n", strerror(status));
+                       continue;
+               }
+               status = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+               if (status != 0)
+                       ErrPrint("Error: %s\n", strerror(status));
+
+               if (!FD_ISSET(tcb->handle, &set)) {
+                       ErrPrint("Unexpected handle is toggled\n");
+                       ret = -EINVAL;
+                       break;
+               }
+
+               readsize = 0;
+               ret = ioctl(tcb->handle, FIONREAD, &readsize);
+               if (ret < 0) {
+                       ErrPrint("ioctl: %s\n", strerror(errno));
+                       break;
+               }
+
+               if (readsize <= 0) {
+                       ErrPrint("Available data: %d\n", readsize);
+                       ret = -ECONNRESET;
+                       break;
+               }
+
+               chunk = create_chunk(readsize);
+               if (!chunk) {
+                       ErrPrint("Failed to create a new chunk: %d\n", readsize);
+                       ret = -ENOMEM;
+                       break;
+               }
+
+               chunk->size = secure_socket_recv(tcb->handle, chunk->data, chunk->size, &chunk->pid);
+               if (chunk->size < 0) {
+                       ret = chunk->size;
+                       destroy_chunk(chunk);
+                       if (ret == -EAGAIN) {
+                               DbgPrint("Retry to get data (%d)\n", readsize);
+                               continue;
+                       }
+
+                       ErrPrint("Recv returns: %d\n", ret);
+                       break;
+               }
+
+               /*!
+                * Count of chunk elements are same with PIPE'd data
+                */
+               chunk_append(tcb, chunk);
+       }
+
+       /* Wake up main thread to get disconnected event */
+       tcb->terminated = 1;
+       event_ch = EVENT_TERM;
+       if (write(tcb->evt_pipe[PIPE_WRITE], &event_ch, sizeof(event_ch)) != sizeof(event_ch)) {
+               ErrPrint("write: %s\n", strerror(errno));
+       }
+
+       return (void *)ret;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+static inline void tcb_destroy(struct tcb *tcb)
+{
+       int status;
+
+       dlist_remove_data(s_info.tcb_list, tcb);
+
+       if (tcb->id > 0)
+               g_source_remove(tcb->id);
+
+       secure_socket_destroy_handle(tcb->handle);
+
+       if (tcb->evt_pipe[PIPE_WRITE] > 0)
+               close(tcb->evt_pipe[PIPE_WRITE]);
+
+       if (tcb->evt_pipe[PIPE_READ] > 0)
+               close(tcb->evt_pipe[PIPE_READ]);
+
+       status = pthread_mutex_destroy(&tcb->chunk_lock);
+       if (status != 0)
+               ErrPrint("Failed to destroy mutex: %s\n", strerror(status));
+
+       free(tcb);
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+static gboolean evt_pipe_cb(GIOChannel *src, GIOCondition cond, gpointer data)
+{
+       int pipe_read;
+       struct tcb *tcb = data;
+       int ret;
+
+       pipe_read = g_io_channel_unix_get_fd(src);
+
+       if (tcb->evt_pipe[PIPE_READ] != pipe_read) {
+               ErrPrint("Closed handle (%d <> %d)\n", tcb->evt_pipe[PIPE_READ], pipe_read);
+               goto errout;
+       }
+
+       if (!(cond & G_IO_IN)) {
+               DbgPrint("PIPE is not valid\n");
+               goto errout;
+       }
+
+       if ((cond & G_IO_ERR) || (cond & G_IO_HUP) || (cond & G_IO_NVAL)) {
+               DbgPrint("PIPE is not valid\n");
+               goto errout;
+       }
+
+       ret = tcb->service_cb(tcb->handle, tcb->data);
+       if (ret < 0) {
+               DbgPrint("Service callback returns %d < 0\n", ret);
+               goto errout;
+       }
+
+       return TRUE;
+
+errout:
+       invoke_disconn_cb_list(tcb->handle);
+       terminate_thread(tcb);
+       tcb_destroy(tcb);
+       return FALSE;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+static inline struct tcb *tcb_create(int client_fd, int is_sync, int (*service_cb)(int fd, void *data), void *data)
+{
+       struct tcb *tcb;
+       int status;
+
+       tcb = malloc(sizeof(*tcb));
+       if (!tcb) {
+               ErrPrint("Error: %s\n", strerror(errno));
+               return NULL;
+       }
+
+       tcb->handle = client_fd;
+       tcb->chunk_list = NULL;
+       tcb->service_cb = service_cb;
+       tcb->data = data;
+       tcb->id = 0;
+       tcb->terminated = 0;
+
+       status = pthread_mutex_init(&tcb->chunk_lock, NULL);
+       if (status != 0) {
+               ErrPrint("Error: %s\n", strerror(status));
+               free(tcb);
+               return NULL;
+       }
+
+       if (pipe2(tcb->evt_pipe, (is_sync ? 0 : O_NONBLOCK) | O_CLOEXEC) < 0) {
+               ErrPrint("Error: %s\n", strerror(errno));
+               status = pthread_mutex_destroy(&tcb->chunk_lock);
+               if (status != 0)
+                       ErrPrint("Error: %s\n", strerror(status));
+               free(tcb);
+               return NULL;
+       }
+
+       DbgPrint("[%d] New TCB created: %d, %d\n", client_fd, tcb->evt_pipe[0], tcb->evt_pipe[1]);
+       return tcb;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+static gboolean accept_cb(GIOChannel *src, GIOCondition cond, gpointer data)
+{
+       int socket_fd;
+       int fd;
+       int ret;
+       struct tcb *tcb;
+       GIOChannel *gio;
+       struct server *server = data;
+
+       socket_fd = g_io_channel_unix_get_fd(src);
+       if (!(cond & G_IO_IN)) {
+               ErrPrint("Accept socket closed\n");
+               server_destroy(server);
+               return FALSE;
+       }
+
+       if ((cond & G_IO_ERR) || (cond & G_IO_HUP) || (cond & G_IO_NVAL)) {
+               DbgPrint("Socket connection is lost\n");
+               server_destroy(server);
+               return FALSE;
+       }
+
+       DbgPrint("New connection is made: socket(%d)\n", socket_fd);
+       fd = secure_socket_get_connection_handle(socket_fd);
+       if (fd < 0) {
+               ErrPrint("Failed to get client fd from socket\n");
+               server_destroy(server);
+               return FALSE;
+       }
+
+       DbgPrint("New client: %d\n", fd);
+       if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0)
+               ErrPrint("Error: %s\n", strerror(errno));
+
+       if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
+               ErrPrint("Error: %s\n", strerror(errno));
+
+       tcb = tcb_create(fd, 0, server->service_cb, server->data);
+       if (!tcb) {
+               ErrPrint("Failed to create a TCB\n");
+               secure_socket_destroy_handle(fd);
+               server_destroy(server);
+               return FALSE;
+       }
+
+       tcb->server_handle = socket_fd;
+
+       s_info.tcb_list = dlist_append(s_info.tcb_list, tcb);
+
+       gio = g_io_channel_unix_new(tcb->evt_pipe[PIPE_READ]);
+       if (!gio) {
+               ErrPrint("Failed to get gio\n");
+               tcb_destroy(tcb);
+               server_destroy(server);
+               return FALSE;
+       }
+
+       g_io_channel_set_close_on_unref(gio, FALSE);
+       tcb->id = g_io_add_watch(gio, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, (GIOFunc)evt_pipe_cb, tcb);
+       if (tcb->id == 0) {
+               GError *err = NULL;
+               ErrPrint("Failed to add IO Watch\n");
+               g_io_channel_shutdown(gio, TRUE, &err);
+               if (err) {
+                       ErrPrint("Shutdown: %s\n", err->message);
+                       g_error_free(err);
+               }
+               g_io_channel_unref(gio);
+               tcb_destroy(tcb);
+               server_destroy(server);
+               return FALSE;
+       }
+       g_io_channel_unref(gio);
+
+       DbgPrint("New client is connected with %d\n", tcb->handle);
+       invoke_con_cb_list(tcb->handle);
+
+       ret = pthread_create(&tcb->thid, NULL, client_cb, tcb);
+       if (ret != 0) {
+               ErrPrint("Thread creation failed: %s\n", strerror(ret));
+               invoke_disconn_cb_list(tcb->handle);
+               tcb_destroy(tcb);
+               server_destroy(server);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+EAPI int com_core_thread_client_create(const char *addr, int is_sync, int (*service_cb)(int fd, void *data), void *data)
+{
+       GIOChannel *gio;
+       int client_fd;
+       struct tcb *tcb;
+       int ret;
+
+       client_fd = secure_socket_create_client(addr);
+       if (client_fd < 0)
+               return client_fd;
+
+       if (fcntl(client_fd, F_SETFD, FD_CLOEXEC) < 0)
+               ErrPrint("Error: %s\n", strerror(errno));
+
+       if (fcntl(client_fd, F_SETFL, O_NONBLOCK) < 0)
+               ErrPrint("Error: %s\n", strerror(errno));
+
+       tcb = tcb_create(client_fd, is_sync, service_cb, data);
+       if (!tcb) {
+               ErrPrint("Failed to create a new TCB\n");
+               secure_socket_destroy_handle(client_fd);
+               return -EFAULT;
+       }
+
+       tcb->server_handle = -1;
+
+       s_info.tcb_list = dlist_append(s_info.tcb_list, tcb);
+
+       gio = g_io_channel_unix_new(tcb->evt_pipe[PIPE_READ]);
+       if (!gio) {
+               ErrPrint("Failed to get gio\n");
+               tcb_destroy(tcb);
+               return -EIO;
+       }
+
+       g_io_channel_set_close_on_unref(gio, FALSE);
+
+       tcb->id = g_io_add_watch(gio, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, (GIOFunc)evt_pipe_cb, tcb);
+       if (tcb->id == 0) {
+               GError *err = NULL;
+               ErrPrint("Failed to add IO Watch\n");
+               g_io_channel_shutdown(gio, TRUE, &err);
+               if (err) {
+                       ErrPrint("Shutdown: %s\n", err->message);
+                       g_error_free(err);
+               }
+               g_io_channel_unref(gio);
+               tcb_destroy(tcb);
+               return -EIO;
+       }
+
+       g_io_channel_unref(gio);
+
+       DbgPrint("New client is connected with %d\n", client_fd);
+       invoke_con_cb_list(tcb->handle);
+
+       ret = pthread_create(&tcb->thid, NULL, client_cb, tcb);
+       if (ret != 0) {
+               ErrPrint("Thread creation failed: %s\n", strerror(ret));
+               invoke_disconn_cb_list(tcb->handle);
+               tcb_destroy(tcb);
+               return -EFAULT;
+       }
+
+       return tcb->handle;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+EAPI int com_core_thread_server_create(const char *addr, int is_sync, int (*service_cb)(int fd, void *data), void *data)
+{
+       GIOChannel *gio;
+       int fd;
+       struct server *server;
+
+       fd = secure_socket_create_server(addr);
+       if (fd < 0)
+               return fd;
+
+       if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0)
+               ErrPrint("fcntl: %s\n", strerror(errno));
+
+       if (!is_sync && fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
+               ErrPrint("fcntl: %s\n", strerror(errno));
+
+       server = server_create(fd, service_cb, data);
+       if (!server) {
+               secure_socket_destroy_handle(fd);
+               return -ENOMEM;
+       }
+
+       DbgPrint("Create new IO channel for socket FD: %d\n", fd);
+       gio = g_io_channel_unix_new(server->handle);
+       if (!gio) {
+               ErrPrint("Failed to create new io channel\n");
+               server_destroy(server);
+               return -EIO;
+       }
+
+       g_io_channel_set_close_on_unref(gio, FALSE);
+
+       server->id = g_io_add_watch(gio, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc)accept_cb, server);
+       if (server->id == 0) {
+               GError *err = NULL;
+               ErrPrint("Failed to add IO watch\n");
+               g_io_channel_shutdown(gio, TRUE, &err);
+               if (err) {
+                       ErrPrint("Shutdown: %s\n", err->message);
+                       g_error_free(err);
+               }
+               g_io_channel_unref(gio);
+               server_destroy(server);
+               return -EIO;
+       }
+
+       g_io_channel_unref(gio);
+       return server->handle;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+static inline struct tcb *find_tcb_by_handle(int handle)
+{
+       struct dlist *l;
+       struct tcb *tcb;
+
+       dlist_foreach(s_info.tcb_list, l, tcb) {
+               if (tcb->handle == handle)
+                       return tcb;
+       }
+
+       return NULL;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+EAPI int com_core_thread_send(int handle, const char *buffer, int size, double timeout)
+{
+       int writesize;
+       int ret;
+       struct tcb *tcb;
+
+       fd_set set;
+
+       tcb = find_tcb_by_handle(handle);
+       if (!tcb) {
+               ErrPrint("TCB is not found\n");
+               return -EINVAL;
+       }
+
+       writesize = 0;
+       while (size > 0) {
+               FD_ZERO(&set);
+               FD_SET(tcb->handle, &set);
+
+               if (timeout > 0.0f) {
+                       struct timeval tv;
+
+                       tv.tv_sec = (unsigned long)timeout;
+                       tv.tv_usec = (timeout - (unsigned long)timeout) * 1000000u;
+
+                       ret = select(tcb->handle + 1, NULL, &set, NULL, &tv);
+               } else if (timeout == 0.0f) {
+                       ret = select(tcb->handle + 1, NULL, &set, NULL, NULL);
+               } else {
+                       ErrPrint("Invalid timeout: %lf (it must be greater than 0.0)\n", timeout);
+                       return -EINVAL;
+               }
+
+               if (ret < 0) {
+                       ret = -errno;
+                       if (errno == EINTR) {
+                               DbgPrint("Select receives INTR\n");
+                               continue;
+                       }
+
+                       ErrPrint("Error: %s\n", strerror(errno));
+                       return ret;
+               } else if (ret == 0) {
+                       ErrPrint("Timeout expired\n");
+                       break;
+               }
+
+               if (!FD_ISSET(tcb->handle, &set)) {
+                       ErrPrint("Unexpected handle is toggled\n");
+                       return -EINVAL;
+               }
+
+               ret = secure_socket_send(tcb->handle, buffer + writesize, size);
+               if (ret < 0) {
+                       if (ret == -EAGAIN) {
+                               DbgPrint("Retry to send data (%d:%d)\n", writesize, size);
+                               continue;
+                       }
+                       DbgPrint("Failed to send: %d\n", ret);
+                       return ret;
+               } else if (ret == 0) {
+                       DbgPrint("Disconnected? : Send bytes: 0\n");
+                       return 0;
+               }
+
+               size -= ret;
+               writesize += ret;
+       }
+
+       return writesize;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+EAPI int com_core_thread_recv(int handle, char *buffer, int size, int *sender_pid, double timeout)
+{
+       int readsize;
+       int ret;
+       struct chunk *chunk;
+       struct dlist *l;
+       struct tcb *tcb;
+
+       tcb = find_tcb_by_handle(handle);
+       if (!tcb) {
+               ErrPrint("TCB is not exists\n");
+               return -EINVAL;
+       }
+
+       readsize = 0;
+       while (readsize < size) {
+               l = dlist_nth(tcb->chunk_list, 0);
+               chunk = dlist_data(l);
+               /*!
+                * \note
+                * Pumping up the pipe data
+                * This is the first time to use a chunk
+                */
+               if (!chunk || chunk->offset == 0) {
+                       ret = wait_event(tcb, timeout);
+                       if (ret == -EAGAIN) {
+                               /* Log is printed from wait_event */
+                               continue;
+                       } else if (ret == -ECONNRESET) {
+                               DbgPrint("Connection is lost\n");
+                               break;
+                       } else if (ret < 0) {
+                               /* Log is printed from wait_event */
+                               return ret;
+                       }
+
+                       l = dlist_nth(tcb->chunk_list, 0);
+                       chunk = dlist_data(l);
+                       if (!chunk) {
+                               char event_ch;
+
+                               /* Consuming the event */
+                               if (read(tcb->evt_pipe[PIPE_READ], &event_ch, sizeof(event_ch)) != sizeof(event_ch)) {
+                                       ErrPrint("Failed to get readsize: %s\n", strerror(errno));
+                               } else if (event_ch == EVENT_READY) {
+                                       ErrPrint("Failed to get a new chunk\n");
+                               }
+
+                               break;
+                       }
+               }
+
+               ret = chunk->size - chunk->offset;
+               ret = ret > (size - readsize) ? (size - readsize) : ret;
+               memcpy(buffer + readsize, chunk->data + chunk->offset, ret);
+               readsize += ret;
+               chunk->offset += ret;
+
+               *sender_pid = chunk->pid;
+
+               if (chunk->offset == chunk->size)
+                       chunk_remove(tcb, chunk);
+       }
+
+       return readsize;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+EAPI int com_core_thread_server_destroy(int handle)
+{
+       struct dlist *l;
+       struct dlist *n;
+       struct tcb *tcb;
+       struct server *server;
+
+       dlist_foreach_safe(s_info.tcb_list, l, n, tcb) {
+               if (tcb->server_handle != handle)
+                       continue;
+
+               terminate_thread(tcb);
+               tcb_destroy(tcb);
+       }
+
+       dlist_foreach_safe(s_info.server_list, l, n, server) {
+               if (server->handle == handle) {
+                       server_destroy(server);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+/*!
+ * \NOTE
+ * Running thread: Main
+ */
+EAPI int com_core_thread_client_destroy(int handle)
+{
+       struct tcb *tcb;
+
+       tcb = find_tcb_by_handle(handle);
+       if (!tcb)
+               return -ENOENT;
+
+       terminate_thread(tcb);
+       tcb_destroy(tcb);
+       return 0;
+}
+
+/* End of a file */
diff --git a/src/dlist.c b/src/dlist.c
new file mode 100644 (file)
index 0000000..a212608
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "dlist.h"
+
+/*!
+ * \brief
+ * This dlist is called Modified Doubly Linked List.
+ *
+ * Noramlly, The dobule linked list contains address of previous and next element.
+ * This dlist also contains them, but the tail element only contains prev address.
+ *
+ * The head element's prev pointer indicates the last element.
+ * But the last element's next pointer indicates NIL.
+ *
+ * So we can find the last element while crawling this DList
+ * But we have to remember the address of the head element.
+ */
+
+struct dlist {
+       struct dlist *next;
+       struct dlist *prev;
+       void *data;
+};
+
+struct dlist *dlist_append(struct dlist *list, void *data)
+{
+       struct dlist *item;
+
+       item = malloc(sizeof(*item));
+       if (!item)
+               return NULL;
+
+       item->next = NULL;
+       item->data = data;
+
+       if (!list) {
+               item->prev = item;
+
+               list = item;
+       } else {
+               item->prev = list->prev;
+               item->prev->next = item;
+               list->prev = item;
+       }
+
+       assert(!list->prev->next && "item NEXT");
+
+       return list;
+}
+
+struct dlist *dlist_prepend(struct dlist *list, void *data)
+{
+       struct dlist *item;
+
+       item = malloc(sizeof(*item));
+       if (!item)
+               return NULL;
+
+       item->data = data;
+
+       if (!list) {
+               item->prev = item;
+               item->next = NULL;
+       } else {
+               if (list->prev->next)
+                       list->prev->next = item;
+
+               item->prev = list->prev;
+               item->next = list;
+
+               list->prev = item;
+
+       }
+
+       return item;
+}
+
+struct dlist *dlist_remove(struct dlist *list, struct dlist *l)
+{
+       if (!list || !l)
+               return NULL;
+
+       if (l == list)
+               list = l->next;
+       else
+               l->prev->next = l->next;
+
+       if (l->next)
+               l->next->prev = l->prev;
+       /*!
+        * \note
+        * If the removed entry 'l' has no next element, it is the last element.
+        * In this case, check the existence of the list first,
+        * and if the list is not empty, update the 'prev' of the list (which is a head element of the list) 
+        *
+        * If we didn't care about this, the head element(list) can indicates the invalid element.
+        */
+       else if (list)
+               list->prev = l->prev;
+
+       free(l);
+       return list;
+}
+
+struct dlist *dlist_find_data(struct dlist *list, void *data)
+{
+       struct dlist *l;
+       void *_data;
+
+       dlist_foreach(list, l, _data) {
+               if (data == _data)
+                       return l;
+       }
+
+       return NULL;
+}
+
+void *dlist_data(struct dlist *l)
+{
+       return l ? l->data : NULL;
+}
+
+struct dlist *dlist_next(struct dlist *l)
+{
+       return l ? l->next : NULL;
+}
+
+struct dlist *dlist_prev(struct dlist *l)
+{
+       return l ? l->prev : NULL;
+}
+
+int dlist_count(struct dlist *l)
+{
+       register int i;
+       struct dlist *n;
+       void *data;
+
+       i = 0;
+       dlist_foreach(l, n, data) {
+               i++;
+       }
+
+       return i;
+}
+
+struct dlist *dlist_nth(struct dlist *l, int nth)
+{
+       register int i;
+       struct dlist *n;
+
+       i = 0;
+       for (n = l; n; n = n->next) {
+               if (i == nth)
+                       return n;
+               i++;
+       }
+
+       return NULL;
+}
+
+/* End of a file */
diff --git a/src/packet.c b/src/packet.c
new file mode 100644 (file)
index 0000000..061184e
--- /dev/null
@@ -0,0 +1,573 @@
+/*
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include <dlog.h>
+
+#include "debug.h"
+#include "packet.h"
+#include "util.h"
+
+int errno;
+
+struct data {
+       struct {
+               int version;
+               int payload_size;
+               char command[PACKET_MAX_CMD];
+               enum packet_type type;
+               enum packet_flag flag;
+               double seq;
+               unsigned long source;
+               unsigned long destination;
+               unsigned long mask;
+       } head;
+
+       char payload[];
+};
+
+struct packet {
+       enum {
+               VALID = 0xbeefbeef,
+               INVALID = 0xdeaddead,
+       } state;
+       int refcnt;
+       struct data *data;
+};
+
+EAPI const enum packet_type const packet_type(const struct packet *packet)
+{
+       if (!packet || packet->state != VALID || !packet->data)
+               return PACKET_ERROR;
+
+       return packet->data->head.type;
+}
+
+EAPI unsigned long packet_mask(const struct packet *packet)
+{
+       if (!packet || packet->state != VALID || !packet->data)
+               return 0;
+
+       return packet->data->head.mask;
+}
+
+EAPI int packet_set_mask(struct packet *packet, unsigned long mask)
+{
+       if (!packet || packet->state != VALID || !packet->data)
+               return -EINVAL;
+
+       packet->data->head.mask = mask;
+       return 0;
+}
+
+EAPI const enum packet_flag const packet_flag(const struct packet *packet)
+{
+       if (!packet || packet->state != VALID || !packet->data)
+               return PACKET_FLAG_ERROR;
+
+       return packet->data->head.flag;
+}
+
+EAPI int packet_set_flag(struct packet *packet, enum packet_flag flag)
+{
+       if (!packet || packet->state != VALID || !packet->data)
+               return -EINVAL;
+
+       packet->data->head.flag = flag;
+       return 0;
+}
+
+EAPI const unsigned long const packet_source(const struct packet *packet)
+{
+       if (!packet || packet->state != VALID || !packet->data)
+               return 0;
+
+       return packet->data->head.source;
+}
+
+EAPI int packet_set_source(struct packet *packet, unsigned long source)
+{
+       if (!packet || packet->state != VALID || !packet->data || !source)
+               return -EINVAL;
+
+       packet->data->head.source = source;
+       return 0;
+}
+
+EAPI const unsigned long const packet_destination(const struct packet *packet)
+{
+       if (!packet || packet->state != VALID || !packet->data)
+               return 0;
+
+       return packet->data->head.destination;
+}
+
+EAPI int packet_set_destination(struct packet *packet, unsigned long destination)
+{
+       if (!packet || packet->state != VALID || !packet->data || !destination)
+               return -EINVAL;
+
+       packet->data->head.destination = destination;
+       return 0;
+}
+
+EAPI const int const packet_version(const struct packet *packet)
+{
+       if (!packet || packet->state != VALID || !packet->data)
+               return PACKET_ERROR;
+
+       return packet->data->head.version;
+}
+
+EAPI const int const packet_header_size(void)
+{
+       struct data payload; /* Only for getting the size of header of packet */
+
+       return sizeof(payload.head);
+}
+
+EAPI const int const packet_size(const struct packet *packet)
+{
+       if (!packet || packet->state != VALID || !packet->data)
+               return -EINVAL;
+
+       return sizeof(*packet->data) + packet->data->head.payload_size;
+}
+
+EAPI const double const packet_seq(const struct packet *packet)
+{
+       if (!packet || packet->state != VALID || !packet->data)
+               return 0;
+
+       return packet->data->head.seq;
+}
+
+EAPI const int const packet_payload_size(const struct packet *packet)
+{
+       if (!packet || packet->state != VALID || !packet->data)
+               return -EINVAL;
+
+       return packet->data->head.payload_size;
+}
+
+EAPI const char * const packet_command(const struct packet *packet)
+{
+       if (!packet || packet->state != VALID || !packet->data)
+               return NULL;
+
+       return packet->data->head.command;
+}
+
+EAPI const void * const packet_data(const struct packet *packet)
+{
+       if (!packet || packet->state != VALID)
+               return NULL;
+
+       return packet->data;
+}
+
+static inline __attribute__((always_inline)) struct data *check_and_expand_packet(struct data *packet, int *payload_size)
+{
+       struct data *new_packet;
+
+       if (packet->head.payload_size < *payload_size)
+               return packet;
+
+       new_packet = realloc(packet, sizeof(*packet) + *payload_size + BUFSIZ); /*!< Expanding to +BUFSIZ */
+       if (!new_packet) {
+               ErrPrint("Heap: %s\n", strerror(errno));
+               free(packet);
+               return NULL;
+       }
+
+       *payload_size += BUFSIZ;
+       return new_packet;
+}
+
+static inline struct packet *packet_body_filler(struct packet *packet, int payload_size, const char *ptr, va_list va)
+{
+       char *payload;
+       char *str;
+
+       while (*ptr) {
+               payload = packet->data->payload + packet->data->head.payload_size;
+
+               switch (*ptr) {
+               case 'i':
+               case 'I':
+                       packet->data->head.payload_size += sizeof(int);
+                       packet->data = check_and_expand_packet(packet->data, &payload_size);
+                       if (!packet->data) {
+                               packet->state = INVALID;
+                               free(packet);
+                               packet = NULL;
+                               goto out;
+                       }
+
+                       *((int *)payload) = (int)va_arg(va, int);
+                       break;
+               case 's':
+               case 'S':
+                       str = (char *)va_arg(va, char *);
+
+                       if (str) {
+                               packet->data->head.payload_size += strlen(str) + 1; /*!< Including NIL */
+                               packet->data = check_and_expand_packet(packet->data, &payload_size);
+                               if (!packet->data) {
+                                       packet->state = INVALID;
+                                       free(packet);
+                                       packet = NULL;
+                                       goto out;
+                               }
+
+                               strcpy(payload, str); /*!< Including NIL */
+                       } else {
+                               packet->data->head.payload_size += 1;
+                               packet->data = check_and_expand_packet(packet->data, &payload_size);
+                               if (!packet->data) {
+                                       packet->state = INVALID;
+                                       free(packet);
+                                       packet = NULL;
+                                       goto out;
+                               }
+
+                               payload[0] = '\0';
+                       }
+                       break;
+               case 'd':
+               case 'D':
+                       packet->data->head.payload_size += sizeof(double);
+                       packet->data = check_and_expand_packet(packet->data, &payload_size);
+                       if (!packet->data) {
+                               packet->state = INVALID;
+                               free(packet);
+                               packet = NULL;
+                               goto out;
+                       }
+
+                       *((double *)payload) = (double)va_arg(va, double);
+                       break;
+               default:
+                       ErrPrint("Invalid type [%c]\n", *ptr);
+                       packet->state = INVALID;
+                       free(packet->data);
+                       free(packet);
+                       packet = NULL;
+                       goto out;
+               }
+
+               ptr++;
+       }
+
+out:
+       return packet;
+}
+
+EAPI struct packet *packet_create_reply(const struct packet *packet, const char *fmt, ...)
+{
+       int payload_size;
+       struct packet *result;
+       va_list va;
+
+       if (!packet || packet->state != VALID)
+               return NULL;
+
+       result = malloc(sizeof(*result));
+       if (!result) {
+               ErrPrint("Heap: %s\n", strerror(errno));
+               return NULL;
+       }
+
+       payload_size = sizeof(*result->data) + BUFSIZ;
+       result->refcnt = 0;
+       result->data = malloc(payload_size);
+       if (!packet->data) {
+               ErrPrint("Heap: %s\n", strerror(errno));
+               result->state = INVALID;
+               free(result);
+               return NULL;
+       }
+
+       result->state = VALID;
+       result->data->head.source = packet->data->head.destination;
+       result->data->head.destination = packet->data->head.source;
+       result->data->head.mask = 0xFFFFFFFF;
+
+       result->data->head.seq = packet->data->head.seq;
+       result->data->head.type = PACKET_ACK;
+       result->data->head.version = packet->data->head.version;
+       strcpy(result->data->head.command, packet->data->head.command); /* we don't need to use strncmp */
+       result->data->head.payload_size = 0;
+       payload_size -= sizeof(*result->data);
+
+       va_start(va, fmt);
+       result = packet_body_filler(result, payload_size, fmt, va);
+       va_end(va);
+
+       return packet_ref(result);
+}
+
+EAPI int packet_swap_address(struct packet *packet)
+{
+       unsigned long tmp;
+
+       if (!packet || packet->state != VALID)
+               return -EINVAL;
+
+       tmp = packet->data->head.source;
+       packet->data->head.source = packet->data->head.destination;
+       packet->data->head.destination = tmp;
+
+       return 0;
+}
+
+EAPI struct packet *packet_create(const char *cmd, const char *fmt, ...)
+{
+       struct packet *packet;
+       int payload_size;
+       va_list va;
+       struct timeval tv;
+
+       if (strlen(cmd) >= PACKET_MAX_CMD) {
+               ErrPrint("Command is too long\n");
+               return NULL;
+       }
+
+       packet = malloc(sizeof(*packet));
+       if (!packet) {
+               ErrPrint("Heap: %s\n", strerror(errno));
+               return NULL;
+       }
+
+       payload_size = sizeof(*packet->data) + BUFSIZ;
+       packet->refcnt = 0;
+       packet->data = malloc(payload_size);
+       if (!packet->data) {
+               ErrPrint("Heap: %s\n", strerror(errno));
+               packet->state = INVALID;
+               free(packet);
+               return NULL;
+       }
+
+       packet->state = VALID;
+       gettimeofday(&tv, NULL);
+       packet->data->head.source = 0lu;
+       packet->data->head.destination = 0lu;
+       packet->data->head.mask = 0xFFFFFFFF;
+       packet->data->head.seq = tv.tv_sec + tv.tv_usec / 1000000.0f;
+       packet->data->head.type = PACKET_REQ;
+       packet->data->head.version = PACKET_VERSION;
+       strncpy(packet->data->head.command, cmd, sizeof(packet->data->head.command));
+       packet->data->head.payload_size = 0;
+       payload_size -= sizeof(*packet->data); /*!< Usable payload size (except head size) */
+
+       va_start(va, fmt);
+       packet = packet_body_filler(packet, payload_size, fmt, va);
+       va_end(va);
+
+       return packet_ref(packet);
+}
+
+EAPI struct packet *packet_create_noack(const char *cmd, const char *fmt, ...)
+{
+       int payload_size;
+       struct packet *result;
+       va_list va;
+       struct timeval tv;
+
+       if (strlen(cmd) >= PACKET_MAX_CMD) {
+               ErrPrint("Command is too long\n");
+               return NULL;
+       }
+
+       result = malloc(sizeof(*result));
+       if (!result) {
+               ErrPrint("Heap: %s\n", strerror(errno));
+               return NULL;
+       }
+
+       payload_size = sizeof(*result->data) + BUFSIZ;
+       result->refcnt = 0;
+       result->data = malloc(payload_size);
+       if (!result->data) {
+               ErrPrint("Heap: %s\n", strerror(errno));
+               result->state = INVALID;
+               free(result);
+               return NULL;
+       }
+
+       result->state = VALID;
+       gettimeofday(&tv, NULL);
+       result->data->head.source = 0lu;
+       result->data->head.destination = 0lu;
+       result->data->head.mask = 0xFFFFFFFF;
+       result->data->head.seq = tv.tv_sec + tv.tv_usec / 1000000.0f;
+       result->data->head.type = PACKET_REQ_NOACK;
+       result->data->head.version = PACKET_VERSION;
+       strncpy(result->data->head.command, cmd, sizeof(result->data->head.command));
+       result->data->head.payload_size = 0;
+       payload_size -= sizeof(*result->data);
+
+       va_start(va, fmt);
+       result = packet_body_filler(result, payload_size, fmt, va);
+       va_end(va);
+
+       return packet_ref(result);
+}
+
+EAPI int packet_get(const struct packet *packet, const char *fmt, ...)
+{
+       const char *ptr;
+       va_list va;
+       int ret = 0;
+       char *payload;
+       int offset = 0;
+       int *int_ptr;
+       double *double_ptr;
+       char **str_ptr;
+
+       if (!packet || packet->state != VALID)
+               return -EINVAL;
+
+       va_start(va, fmt);
+
+       ptr = fmt;
+       while (*ptr && offset < packet->data->head.payload_size) {
+               payload = packet->data->payload + offset;
+               switch (*ptr) {
+               case 'i':
+               case 'I':
+                       int_ptr = (int *)va_arg(va, int *);
+                       *int_ptr = *((int *)payload);
+                       offset += sizeof(int);
+                       ret++;
+                       break;
+               case 'd':
+               case 'D':
+                       double_ptr = (double *)va_arg(va, double *);
+                       *double_ptr = *((double *)payload);
+                       offset += sizeof(double);
+                       ret++;
+                       break;
+               case 's':
+               case 'S':
+                       str_ptr = (char **)va_arg(va, char **);
+                       *str_ptr = payload;
+                       offset += (strlen(*str_ptr) + 1); /*!< Including NIL */
+                       ret++;
+                       break;
+               default:
+                       ret = -EINVAL;
+                       goto out;
+               }
+               ptr++;
+       }
+
+out:
+       va_end(va);
+       return ret;
+}
+
+EAPI struct packet *packet_ref(struct packet *packet)
+{
+       if (!packet || packet->state != VALID)
+               return NULL;
+
+       packet->refcnt++;
+       return packet;
+}
+
+EAPI struct packet *packet_unref(struct packet *packet)
+{
+       if (!packet || packet->state != VALID)
+               return NULL;
+
+       packet->refcnt--;
+       if (packet->refcnt < 0) {
+               ErrPrint("Invalid refcnt\n");
+               return NULL;
+       }
+
+       if (packet->refcnt == 0) {
+               packet->state = INVALID;
+               free(packet->data);
+               free(packet);
+               return NULL;
+       }
+
+       return packet;
+}
+
+EAPI int packet_destroy(struct packet *packet)
+{
+       packet_unref(packet);
+       return 0;
+}
+
+EAPI struct packet *packet_build(struct packet *packet, int offset, void *data, int size)
+{
+       char *ptr;
+
+       if (packet == NULL) {
+               if (offset) {
+                       ErrPrint("Invalid argument\n");
+                       return NULL;
+               }
+
+               packet = malloc(sizeof(*packet));
+               if (!packet) {
+                       ErrPrint("Heap: %s\n", strerror(errno));
+                       return NULL;
+               }
+
+               packet->refcnt = 1;
+               packet->data = malloc(size);
+               if (!packet->data) {
+                       ErrPrint("Heap: %s\n", strerror(errno));
+                       packet->state = INVALID;
+                       free(packet);
+                       return NULL;
+               }
+
+               packet->state = VALID;
+               memcpy(packet->data, data, size);
+               packet->data->head.mask = 0xFFFFFFFF;
+               return packet;
+       }
+
+       ptr = realloc(packet->data, offset + size);
+       if (!ptr) {
+               ErrPrint("Heap: %s\n", strerror(errno));
+               packet->state = INVALID;
+               free(packet->data);
+               free(packet);
+               return NULL;
+       }
+
+       packet->data = (struct data *)ptr;
+       memcpy(ptr + offset, data, size);
+
+       return packet;
+}
+
+/* End of a file */
diff --git a/src/secure_socket.c b/src/secure_socket.c
new file mode 100644 (file)
index 0000000..95b419b
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+*/
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <errno.h>
+
+#include <dlog.h>
+
+#include "secure_socket.h"
+#include "debug.h"
+#include "util.h"
+
+#define BACKLOG 50     /*!< Accept only 50 connections as default */
+
+int errno;
+
+static inline int create_socket(const char *peer, struct sockaddr_un *addr)
+{
+       int len;
+       int handle;
+
+       len = sizeof(*addr);
+       bzero(addr, len);
+
+       if (strlen(peer) >= sizeof(addr->sun_path)) {
+               ErrPrint("peer %s is too long to remember it\\n", peer);
+               return -1;
+       }
+
+       /* We can believe this has no prob, because
+        * we already check the size of add.rsun_path
+        */
+       strcpy(addr->sun_path, peer);
+       addr->sun_family = AF_UNIX;
+
+       handle = socket(PF_UNIX, SOCK_STREAM, 0);
+       if (handle < 0) {
+               ErrPrint("Failed to create a socket %s\n", strerror(errno));
+               return -1;
+       }
+
+       return handle;
+}
+
+EAPI int secure_socket_create_client(const char *peer)
+{
+       struct sockaddr_un addr;
+       int handle;
+       int state;
+       int on = 1;
+
+       handle = create_socket(peer, &addr);
+       if (handle < 0)
+               return handle;
+
+       state = connect(handle, (struct sockaddr *)&addr, sizeof(addr));
+       if (state < 0) {
+               ErrPrint("Failed to connect to server [%s] %s\n",
+                                                       peer, strerror(errno));
+               if (close(handle) < 0)
+                       ErrPrint("close a handle: %s\n", strerror(errno));
+
+               return -ENOTCONN;
+       }
+
+       if (setsockopt(handle, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
+               ErrPrint("Failed to change sock opt : %s\n", strerror(errno));
+               if (close(handle) < 0)
+                       ErrPrint("close a handle: %s\n", strerror(errno));
+               return -EFAULT;
+       }
+
+       return handle;
+}
+
+EAPI int secure_socket_create_server(const char *peer)
+{
+       int handle;
+       int state;
+       struct sockaddr_un addr;
+
+       handle = create_socket(peer, &addr);
+       if (handle < 0)
+               return handle;
+
+       state = bind(handle, &addr, sizeof(addr));
+       if (state < 0) {
+               state = -errno;
+
+               ErrPrint("Failed to bind a socket %s\n", strerror(errno));
+               if (close(handle) < 0)
+                       ErrPrint("Close a handle : %s\n", strerror(errno));
+
+               return state;
+       }
+
+       state = listen(handle, BACKLOG);
+       if (state < 0) {
+               state = -errno;
+               ErrPrint("Failed to listen a socket %s\n", strerror(errno));
+
+               if (close(handle) < 0)
+                       ErrPrint("Close a handle : %s\n", strerror(errno));
+
+               return state;
+       }
+
+       if (chmod(peer, 0666) < 0)
+               ErrPrint("Failed to change the permission of a socket (%s)\n",
+                                                       strerror(errno));
+
+       return handle;
+}
+
+EAPI int secure_socket_get_connection_handle(int server_handle)
+{
+       struct sockaddr_un addr;
+       int handle;
+       int on = 1;
+       socklen_t size = sizeof(addr);
+
+       handle = accept(server_handle, (struct sockaddr *)&addr, &size);
+       if (handle < 0) {
+               handle = -errno;
+               ErrPrint("Failed to accept a new client %s\n", strerror(errno));
+               return handle;
+       }
+
+       if (setsockopt(handle, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
+               int ret;
+               ret = -errno;
+               ErrPrint("Failed to change sock opt : %s\n", strerror(errno));
+               if (close(handle) < 0)
+                       ErrPrint("Close a handle: %s\n", strerror(errno));
+               return ret;
+       }
+
+       return handle;
+}
+
+EAPI int secure_socket_send(int handle, const char *buffer, int size)
+{
+       struct msghdr msg;
+       struct iovec iov;
+       int ret;
+
+       if (!buffer || size <= 0) {
+               ErrPrint("Reject: 0 byte data sending\n");
+               return -EINVAL;
+       }
+
+       memset(&msg, 0, sizeof(msg));
+       iov.iov_base = (char *)buffer;
+       iov.iov_len = size;
+       msg.msg_iov = &iov;
+       msg.msg_iovlen = 1;
+
+       ret = sendmsg(handle, &msg, 0);
+       if (ret < 0) {
+               ret = -errno;
+               if (errno == EAGAIN || errno == EWOULDBLOCK) {
+                       ErrPrint("handle[%d] size[%d] Try again [%s]\n", handle, size, strerror(errno));
+                       return -EAGAIN;
+               }
+               ErrPrint("Failed to send message [%s]\n", strerror(errno));
+               return ret;
+       }
+
+       return iov.iov_len;
+}
+
+EAPI int secure_socket_recv(int handle, char *buffer, int size, int *sender_pid)
+{
+       struct msghdr msg;
+       struct cmsghdr *cmsg;
+       struct iovec iov;
+       char control[1024];
+       int ret;
+
+       if (!sender_pid || size <= 0 || !buffer)
+               return -EINVAL;
+
+       memset(&msg, 0, sizeof(msg));
+       iov.iov_base = buffer;
+       iov.iov_len = size;
+       msg.msg_iov = &iov;
+       msg.msg_iovlen = 1;
+       msg.msg_control = control;
+       msg.msg_controllen = sizeof(control);
+
+       ret = recvmsg(handle, &msg, 0);
+       if (ret == 0) {
+               /*!< Disconnected */
+               DbgPrint("Disconnected\n");
+               return 0;
+       }
+
+       if (ret < 0) {
+               ret = -errno;
+               if (errno == EAGAIN || errno == EWOULDBLOCK) {
+                       ErrPrint("handle[%d] size[%d] Try again [%s]\n", handle, size, strerror(errno));
+                       return -EAGAIN;
+               }
+
+               ErrPrint("Failed to recvmsg [%s]\n", strerror(errno));
+               return ret;
+       }
+
+       cmsg = CMSG_FIRSTHDR(&msg);
+       while (cmsg) {
+               if (cmsg->cmsg_level == SOL_SOCKET
+                       && cmsg->cmsg_type == SCM_CREDENTIALS)  {
+                       struct ucred *cred;
+                       cred = (struct ucred *)CMSG_DATA(cmsg);
+                       *sender_pid = cred->pid;
+               }
+
+               cmsg = CMSG_NXTHDR(&msg, cmsg);
+       }
+
+       return iov.iov_len;
+}
+
+EAPI int secure_socket_destroy_handle(int handle)
+{
+       DbgPrint("Close socket handle %d\n", handle);
+       if (close(handle) < 0) {
+               ErrPrint("Failed to close a handle: %s\n", strerror(errno));
+               return -1;
+       }
+       return 0;
+}
+
+#undef _GNU_SOURCE
+
+/* End of a file */
diff --git a/src/util.c b/src/util.c
new file mode 100644 (file)
index 0000000..2471987
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <errno.h>
+
+#include "util.h"
+
+int errno;
+
+const char *util_basename(const char *name)
+{
+       int length;
+       length = name ? strlen(name) : 0;
+       if (!length)
+               return ".";
+
+       while (--length > 0 && name[length] != '/');
+
+       return length <= 0 ? name : name + length + (name[length] == '/');
+}
+
+/* End of a file */