From 006d9d618412b49068c6aa4c2fc3833e32edc30a Mon Sep 17 00:00:00 2001 From: hyunuktak Date: Thu, 27 Apr 2017 18:37:48 +0900 Subject: [PATCH 02/11] Initialize smart traffic control manager package Change-Id: I099c864838aabaf85ee7f6a41742d78f57910580 Signed-off-by: hyunuktak --- CMakeLists.txt | 9 + LICENSE | 202 +++ README.md | 3 + data/exception_db.sql | 49 + data/traffic_db.sql | 40 + include/stc-error.h | 32 + include/stc-manager-gdbus.h | 86 ++ include/stc-manager-util.h | 361 ++++++ include/stc-manager.h | 164 +++ include/stc-restriction.h | 75 ++ include/stc-statistics.h | 48 + interfaces/stcmanager-iface-restriction.xml | 42 + interfaces/stcmanager-iface-statistics.xml | 27 + packaging/stc-manager.spec | 96 ++ resources/dbus/net.stc.service | 4 + resources/dbus/stc-manager.conf | 13 + resources/systemd/stc-manager.service | 13 + src/CMakeLists.txt | 91 ++ src/configure/include/configure_stub.h | 44 + src/configure/include/counter.h | 60 + src/configure/include/netlink-restriction.h | 53 + src/configure/include/transmission.h | 69 ++ src/configure/nf-restriction.c | 133 ++ src/database/db-common.c | 135 ++ src/database/db-guard.c | 144 +++ src/database/include/db-internal.h | 56 + src/database/include/stc-db.h | 109 ++ src/database/include/table-counters.h | 42 + src/database/include/table-restrictions.h | 65 + src/database/include/table-statistics.h | 73 ++ src/database/tables/table-counters.c | 286 +++++ src/database/tables/table-restrictions.c | 593 +++++++++ src/database/tables/table-statistics.c | 686 +++++++++++ src/helper/helper-cgroup.c | 275 +++++ src/helper/helper-cgroup.h | 119 ++ src/helper/helper-file.c | 67 + src/helper/helper-file.h | 48 + src/helper/helper-net-cls.c | 214 ++++ src/helper/helper-net-cls.h | 63 + src/helper/helper-nfacct-rule.c | 889 ++++++++++++++ src/helper/helper-nfacct-rule.h | 125 ++ src/helper/helper-nl.c | 102 ++ src/helper/helper-nl.h | 112 ++ src/helper/helper-restriction.c | 39 + src/helper/helper-restriction.h | 32 + src/monitor/include/stc-application-lifecycle.h | 29 + src/monitor/include/stc-default-connection.h | 46 + src/monitor/include/stc-monitor.h | 149 +++ src/monitor/stc-application-lifecycle.c | 446 +++++++ src/monitor/stc-default-connection.c | 378 ++++++ src/monitor/stc-monitor.c | 1488 +++++++++++++++++++++++ src/stc-manager-gdbus.c | 300 +++++ src/stc-manager.c | 118 ++ src/stc-restriction.c | 454 +++++++ src/stc-statistics.c | 401 ++++++ src/utils/CMakeLists.txt | 5 + src/utils/net-cls-release.c | 19 + stc-manager.manifest | 6 + 58 files changed, 9827 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 LICENSE create mode 100644 README.md create mode 100755 data/exception_db.sql create mode 100644 data/traffic_db.sql create mode 100755 include/stc-error.h create mode 100755 include/stc-manager-gdbus.h create mode 100755 include/stc-manager-util.h create mode 100755 include/stc-manager.h create mode 100755 include/stc-restriction.h create mode 100755 include/stc-statistics.h create mode 100644 interfaces/stcmanager-iface-restriction.xml create mode 100644 interfaces/stcmanager-iface-statistics.xml create mode 100644 packaging/stc-manager.spec create mode 100755 resources/dbus/net.stc.service create mode 100755 resources/dbus/stc-manager.conf create mode 100755 resources/systemd/stc-manager.service create mode 100644 src/CMakeLists.txt create mode 100755 src/configure/include/configure_stub.h create mode 100755 src/configure/include/counter.h create mode 100755 src/configure/include/netlink-restriction.h create mode 100755 src/configure/include/transmission.h create mode 100755 src/configure/nf-restriction.c create mode 100644 src/database/db-common.c create mode 100644 src/database/db-guard.c create mode 100644 src/database/include/db-internal.h create mode 100644 src/database/include/stc-db.h create mode 100644 src/database/include/table-counters.h create mode 100644 src/database/include/table-restrictions.h create mode 100644 src/database/include/table-statistics.h create mode 100755 src/database/tables/table-counters.c create mode 100755 src/database/tables/table-restrictions.c create mode 100755 src/database/tables/table-statistics.c create mode 100755 src/helper/helper-cgroup.c create mode 100755 src/helper/helper-cgroup.h create mode 100755 src/helper/helper-file.c create mode 100755 src/helper/helper-file.h create mode 100755 src/helper/helper-net-cls.c create mode 100755 src/helper/helper-net-cls.h create mode 100755 src/helper/helper-nfacct-rule.c create mode 100755 src/helper/helper-nfacct-rule.h create mode 100755 src/helper/helper-nl.c create mode 100755 src/helper/helper-nl.h create mode 100755 src/helper/helper-restriction.c create mode 100755 src/helper/helper-restriction.h create mode 100644 src/monitor/include/stc-application-lifecycle.h create mode 100644 src/monitor/include/stc-default-connection.h create mode 100644 src/monitor/include/stc-monitor.h create mode 100755 src/monitor/stc-application-lifecycle.c create mode 100755 src/monitor/stc-default-connection.c create mode 100755 src/monitor/stc-monitor.c create mode 100755 src/stc-manager-gdbus.c create mode 100755 src/stc-manager.c create mode 100755 src/stc-restriction.c create mode 100755 src/stc-statistics.c create mode 100644 src/utils/CMakeLists.txt create mode 100644 src/utils/net-cls-release.c create mode 100644 stc-manager.manifest diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..95356ec --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,9 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(stc-manager C) +SET(PACKAGE ${PROJECT_NAME}) +SET(INTERFACES "${CMAKE_SOURCE_DIR}/interfaces") +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) + +SET(DATA_DIR ${CMAKE_SOURCE_DIR}/data) + +ADD_SUBDIRECTORY(src) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..a435a05 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# stc-manager +STC means Smart Traffic Control. +It provides extensible packet-level control services, including per-app data usage, total data quota, and background app's data saving. diff --git a/data/exception_db.sql b/data/exception_db.sql new file mode 100755 index 0000000..7613769 --- /dev/null +++ b/data/exception_db.sql @@ -0,0 +1,49 @@ +PRAGMA journal_mode = PERSIST; +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("com.samsung.easysignup", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("com.osmeta.runtime", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("com.osmeta.runtime.service", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("com.samsung.email", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("email-composer-efl", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("email-viewer-efl", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("email-conversation-efl", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("email-mailbox-efl", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("email-account-efl", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("email-filter-efl", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("email-block-efl", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("email-locker-efl", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("email-setting-efl", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("com.samsung.email-misc_worker", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("com.samsung.email-record-video-icon", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("com.samsung.samsungaccount", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("com.samsung.samsungaccount.samsungaccountservice", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("com.samsung.samsungaccount.samsungaccountpushefl", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("com.samsung.samsungaccount.samsungaccountupdate", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("com.samsung.special-day-app", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("com.samsung.special-day-widget", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("org.tizen.tizenstore.billingagent", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("org.tizen.inapppurchase", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("org.tizen.inapppurchase.iapclient", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("org.tizen.inapppurchase.iapservice", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("org.tizen.tizenstore", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("org.tizen.tizenstoreservice", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("com.samsung.videos-lite", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("com.samsung.video-player-lite", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("org.tizen.webcontainer", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("com.samsung.themestore", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("ACL111OMWW.AclService", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("ACL111OMWW.AclManager", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("ACL111OMWW.AclAudioProxyService", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("com.samsung.gallery-lite", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("gallery-efl-lite", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("com.samsung.gallery-lite.appcontrol", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("com.samsung.image-viewer.appcontrol.slideshow", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("com.samsung.image-viewer", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("com.samsung.image-viewer-subapp", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("com.samsung.image-viewer-subapp-single", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("image-viewer-efl-lite", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("com.samsung.gallery-lite.dbox", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("com.samsung.music-player-lite", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("com.samsung.sound-player-lite", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("com.samsung.music-chooser-lite", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("com.samsung.music-player-lite.widget", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); +INSERT INTO restrictions (binpath, iftype, ifname, rst_state, roaming, imsi, rcv_limit, send_limit, rcv_warn_limit, send_warn_limit) VALUES("com.samsung.cloud-content-sync", 1, "seth_w0", 3, 2, "noneimsi", 0, 0, 1, 1); diff --git a/data/traffic_db.sql b/data/traffic_db.sql new file mode 100644 index 0000000..045586d --- /dev/null +++ b/data/traffic_db.sql @@ -0,0 +1,40 @@ +PRAGMA journal_mode = PERSIST; +PRAGMA user_version = 1; + +CREATE TABLE IF NOT EXISTS statistics ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + binpath TEXT NOT NULL, + received BIGINT, + sent BIGINT, + time_stamp BIGINT, + iftype INT, + is_roaming INT, + hw_net_protocol_type INT, + ifname TEXT, + imsi TEXT, + ground INT +); + +CREATE TABLE IF NOT EXISTS restrictions ( + restriction_id INTEGER PRIMARY KEY AUTOINCREMENT, + binpath TEXT, + iftype INT, + ifname TEXT, + rst_state INT, + roaming INT, + imsi TEXT NOT NULL, + rcv_limit BIGINT, + send_limit BIGINT, + rcv_warn_limit BIGINT, + send_warn_limit BIGINT +); + +CREATE INDEX IF NOT EXISTS restrictions_index ON restrictions (binpath, iftype, ifname); + +CREATE TABLE IF NOT EXISTS counters ( + restriction_id INTEGER NOT NULL, + sent_bytes BIGINT, + rcv_bytes BIGINT, + PRIMARY KEY (restriction_id) +); + diff --git a/include/stc-error.h b/include/stc-error.h new file mode 100755 index 0000000..ecb4e68 --- /dev/null +++ b/include/stc-error.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __STC_ERROR_H__ +#define __STC_ERROR_H__ + +typedef enum { + STC_ERROR_NOTIMPL = -7, /**< Not implemented yet error */ + STC_ERROR_UNINITIALIZED = -6, /**< Cgroup doen't mounted or daemon not started */ + STC_ERROR_NO_DATA = -5, /**< Success, but no data */ + STC_ERROR_INVALID_PARAMETER = -4, /**< Invalid parameter */ + STC_ERROR_OUT_OF_MEMORY = -3, /**< Out of memory */ + STC_ERROR_DB_FAILED = -2, /**< Database error */ + STC_ERROR_FAIL = -1, /**< General error */ + STC_ERROR_NONE = 0 /**< General success */ +} stc_error_e; + +#endif /* __STC_ERROR_H__ */ + diff --git a/include/stc-manager-gdbus.h b/include/stc-manager-gdbus.h new file mode 100755 index 0000000..c253c18 --- /dev/null +++ b/include/stc-manager-gdbus.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __STC_MANAGER_GDBUS_H__ +#define __STC_MANAGER_GDBUS_H__ + +#include "stc-manager.h" +#include "generated-code.h" + +#define STC_DBUS_SERVICE "net.stc" +#define STC_DBUS_SERVICE_PATH "/net/stc" +#define STC_DBUS_SERVICE_STATISTICS_PATH "/net/stc/statistics" +#define STC_DBUS_SERVICE_RESTRICTION_PATH "/net/stc/restriction" +#define STC_DBUS_SERVICE_QUOTA_PATH "/net/stc/quota" + +#define STC_DBUS_REPLY_ERROR_NONE(invocation) \ + g_dbus_method_invocation_return_value((invocation), \ + g_variant_new("(i)", \ + STC_ERROR_NONE)); + +#define STC_DBUS_REPLY(invocation, parameters) \ + g_dbus_method_invocation_return_value((invocation), parameters); + +#define DEBUG_PARAMS(parameters) do {\ + gchar *params_str = NULL;\ + if (parameters)\ + params_str = g_variant_print((GVariant *)parameters,\ + TRUE);\ + STC_LOGD("Dbus params [%s]", params_str ? params_str : "NULL");\ + g_free(params_str);\ +} while (0) + +#define DEBUG_PARAM_TYPE(parameters) do { \ + STC_LOGD("Dbus params type [%s]", \ + g_variant_get_type_string(parameters)); \ +} while (0) + + +#define RETURN_IF_DBUS_TYPE_MISMATCH(parameters, str) do { \ + DEBUG_PARAM_TYPE(parameters); \ + DEBUG_PARAMS(parameters); \ + if (g_strcmp0(g_variant_get_type_string(parameters), str)) { \ + STC_LOGE("Dbus type not matching, do not process"); \ + __STC_LOG_FUNC_EXIT__; \ + return; \ + } \ +} while (0) + +typedef void(*dbus_dict_cb)(const char *key, GVariant *value, + void *user_data); + +void stc_manager_gdbus_init(gpointer stc_manager); +void stc_manager_gdbus_deinit(gpointer stc_manager); +GVariant *stc_manager_gdbus_call_sync(GDBusConnection *connection, + const char *dest, const char *path, + const char *interface_name, + const char *method, GVariant *params); +guint stc_manager_gdbus_subscribe_signal(GDBusConnection *connection, + const gchar *sender, + const gchar *interface_name, + const gchar *member, + const gchar *object_path, + const gchar *arg0, + GDBusSignalFlags flags, + GDBusSignalCallback callback, + gpointer user_data, + GDestroyNotify user_data_free_func); +void stc_manager_gdbus_unsubscribe_signal(GDBusConnection *connection, + guint subscription_id); +void stc_manager_gdbus_dict_foreach(GVariantIter *iter, dbus_dict_cb cb, + void *user_data); + +#endif /* __STC_MANAGER_GDBUS_H__ */ diff --git a/include/stc-manager-util.h b/include/stc-manager-util.h new file mode 100755 index 0000000..1f8af9a --- /dev/null +++ b/include/stc-manager-util.h @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __STC_MANAGER_UTIL_H__ +#define __STC_MANAGER_UTIL_H__ + +#include +#include +#include +#include +#include /* bool */ +#include /* uint32_t, uint63_t */ +#include +#include /* database handling */ +#include /* time function */ +#include +#include + +#ifdef USE_DLOG +#include + +#undef LOG_TAG +#define LOG_TAG "STC_MANAGER" + +#define STC_LOGD(format, args...) LOGD(format, ##args) +#define STC_LOGI(format, args...) LOGI(format, ##args) +#define STC_LOGW(format, args...) LOGW(format, ##args) +#define STC_LOGE(format, args...) LOGE(format, ##args) + +#define __STC_LOG_FUNC_ENTER__ LOGD("Enter") +#define __STC_LOG_FUNC_EXIT__ LOGD("Quit") + +#else /* USE_DLOG */ + +#define STC_LOGD(format, args...) +#define STC_LOGI(format, args...) +#define STC_LOGW(format, args...) +#define STC_LOGE(format, args...) + +#define __STC_LOG_FUNC_ENTER__ +#define __STC_LOG_FUNC_EXIT__ + +#endif /* USE_DLOG */ + +#define APP_ID_LEN_MAX 1024 + +#define GPOINTER_TO_PID(x) (pid_t)GPOINTER_TO_INT((x)) +#define PID_TO_GPOINTER(x) GINT_TO_POINTER((pid_t)(x)) + +#define MALLOC0(t, n) ((t*) g_try_malloc0((n) * sizeof(t))) +#define FREE(p) do { \ + if (p) { \ + g_free(p); \ + p = NULL; \ + } \ +} while (0) + +#define EXEC(error_code, command) do { \ + if (error_code != command) { \ + __STC_LOG_FUNC_EXIT__; \ + goto handle_error; \ + } \ +} while (0) + +#define DEBUG_GDBUS_VARIANT(str, parameters) do { \ + gchar *params_str = NULL; \ + if (parameters) { \ + params_str = g_variant_print(parameters, \ + TRUE); \ + } \ + STC_LOGD("%s[%s]", str, \ + params_str ? params_str : "NULL"); \ + g_free(params_str); \ +} while (0) + +#define DEBUG_GDBUS_KEY_VALUE(key, value) do { \ + if (key) { \ + STC_LOGD("Key : [%s]", key); \ + } \ + if (value) { \ + DEBUG_GDBUS_VARIANT("Value: ", value); \ + } \ +} while (0) + +#define _pure_ __attribute__ ((pure)) +#define _cleanup_(x) __attribute__((cleanup(x))) + +static inline void freep(void *p) +{ + FREE(*(void**) p); +} + +static inline void closep(int *fd) +{ + if (*fd >= 0) + close(*fd); +} + +static inline void fclosep(FILE **f) +{ + if (*f) + fclose(*f); +} + +static inline void pclosep(FILE **f) +{ + if (*f) + pclose(*f); +} + +static inline void closedirp(DIR **d) +{ + if (*d) + closedir(*d); +} + +#define _cleanup_free_ _cleanup_(freep) +#define _cleanup_close_ _cleanup_(closep) +#define _cleanup_fclose_ _cleanup_(fclosep) +#define _cleanup_pclose_ _cleanup_(pclosep) +#define _cleanup_closedir_ _cleanup_(closedirp) + +#define NUM_DIFF(x, y) ((x > y) ? (x - y) : (y -x)) + +#define BYTE_TO_KBYTE(b) ((b) >> 10) +#define BYTE_TO_MBYTE(b) ((b) >> 20) +#define BYTE_TO_GBYTE(b) ((b) >> 30) +#define BYTE_TO_PAGE(b) ((b) >> 12) + +#define KBYTE_TO_BYTE(k) ((k) << 10) +#define KBYTE_TO_MBYTE(k) ((k) >> 10) +#define KBYTE_TO_GBYTE(k) ((k) >> 20) + +#define MBYTE_TO_BYTE(m) ((m) << 20) +#define MBYTE_TO_KBYTE(m) ((m) << 10) +#define MBYTE_TO_GBYTE(m) ((m) >> 10) + +#define GBYTE_TO_BYTE(g) ((g) << 30) +#define GBYTE_TO_KBYTE(g) ((g) << 20) +#define GBYTE_TO_MBYTE(g) ((g) << 10) + +#define streq(a, b) (strncmp((a), (b), strlen(b)+1) == 0) +#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0) +#define strcaseeq(a, b) (strcasecmp((a), (b)) == 0) +#define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0) + +static inline bool is_empty(const char *p) +{ + return !p || !p[0]; +} + +static inline bool strstart_with(const char *str, const char *with) +{ + return strncmp(str, with, strlen(with)) == 0; +} + +#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state) \ + for ((state) = NULL, (word) = split((s), &(length), (separator), &(state)); \ + (word); \ + (word) = split((s), &(length), (separator), &(state))) + +#define FOREACH_WORD(word, length, s, state) \ + FOREACH_WORD_SEPARATOR(word, length, s, WHITESPACE, state) + +#define FOREACH_DIRENT(de, d, result, on_error) \ + for (errno = readdir_r(d, &de, &result);; errno = readdir_r(d, &de, &result)) \ + if (errno || !result) { \ + if (errno) \ + on_error; \ + break; \ + } else if (streq(de.d_name, ".") || \ + streq(de.d_name, "..")) \ + continue; \ + else + +#define FOREACH_STRV(s, l) \ + for ((s) = (l); (s) && *(s); (s)++) + +#define execute_once \ + static int __func__##guardian; \ + for (; \ + __func__##guardian == 0; \ + __func__##guardian = 1) + +#ifndef API +#define API __attribute__((visibility("default"))) +#endif + +#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) + +#define DECLARE_WRAPPER(fn_name, inner_fn) \ + static void fn_name(void *data, void __attribute__((__unused__)) *not_used) \ + { \ + return inner_fn(data); \ + } + +#define UNUSED __attribute__((__unused__)) + +#define MAX_SIZE2(a, b) sizeof(a) + sizeof(b) - 1 +#define MAX_SIZE3(a, b, c) MAX_SIZE2(a, b) + sizeof(c) - 1 + +/* + * One byte digit has 3 position in decimal representation + * 2 - 5 + * 4 - 10 + * 8 - 20 + * >8 - compile time error + * plus 1 null termination byte + * plus 1 for negative prefix + */ +#define MAX_DEC_SIZE(type) \ + (2 + (sizeof(type) <= 1 ? 3 : \ + sizeof(type) <= 2 ? 5 : \ + sizeof(type) <= 4 ? 10 : \ + sizeof(type) <= 8 ? 20 : \ + sizeof(int[-2*(sizeof(type) > 8)]))) + +#define SET_BIT(a, bit) \ + ((a) |= (bit)) + +#define UNSET_BIT(a, bit) \ + ((a) &= ~(bit)) + +#define CHECK_BIT(a, bit) \ + ((a) & (bit)) + +#define ret_msg_if(expr, fmt, arg...) do { \ + if (expr) { \ + STC_LOGE(fmt, ##arg); \ + return; \ + } \ +} while (0) + +#define ret_value_if(expr, val) do { \ + if (expr) { \ + STC_LOGE("(%s) -> %s():%d return", #expr, __FUNCTION__, __LINE__); \ + return (val); \ + } \ +} while (0) + +#define ret_value_msg_if(expr, val, fmt, arg...) do { \ + if (expr) { \ + STC_LOGE(fmt, ##arg); \ + return val; \ + } \ +} while (0) + +#define ret_value_errno_msg_if(expr, val, fmt, arg...) do { \ + if (expr) { \ + STC_LOGE(fmt, ##arg); \ + return val; \ + } \ +} while (0) + + +/* + * @brief Copy from source to destination + * destination should not be on heap. + * Destination will be null terminated + */ +#define STRING_SAVE_COPY(destination, source) do { \ + if (destination && source) { \ + size_t null_pos = strlen(source); \ + strncpy(destination, source, sizeof(destination)); \ + null_pos = sizeof(destination) - 1 < null_pos ? \ + sizeof(destination) - 1 : null_pos; \ + destination[null_pos] = '\0'; \ + } \ +} while (0) + +/* FIXME: Do we really need pointers? */ +#define array_foreach(key, type, array) \ + guint _array_foreach_index; \ + type *key; \ + for (_array_foreach_index = 0; \ + array && _array_foreach_index < array->len && \ + (key = &g_array_index(array, type, _array_foreach_index)); \ + ++_array_foreach_index) + +#define slist_foreach(key, type, list) \ + type *key; \ + GSList *_slist_foreach_copy_list = list; \ + for (; \ + _slist_foreach_copy_list && \ + ((key = _slist_foreach_copy_list->data) || 1); \ + _slist_foreach_copy_list = _slist_foreach_copy_list->next) + +#define gslist_for_each_item(item, list) \ + for (item = list; item != NULL; item = g_slist_next(item)) + +#define gslist_for_each(head, elem, node) \ + for (elem = head, node = NULL; elem && ((node = elem->data) != NULL); elem = elem->next, node = NULL) + +#define gslist_for_each_safe(head, elem, elem_next, node) \ + for (elem = head, elem_next = g_slist_next(elem), node = NULL; \ + elem && ((node = elem->data) != NULL); \ + elem = elem_next, elem_next = g_slist_next(elem), node = NULL) + +#define TASK_FILE_NAME "tasks" +#define CGROUP_FILE_NAME "cgroup.procs" +#define UNKNOWN_APP "(unknown)" + +#define MAX_PATH_LENGTH 512 +#define MAX_NAME_LENGTH 256 +#define MAX_IFACE_LENGTH 32 +#define MAX_APPID_LENGTH 128 +#define MAX_PKGNAME_LENGTH 128 + +#define PROC_BUF_MAX 64 +#define PROC_NAME_MAX 1024 + +#define COMMA_DELIMETER "," + +#define COUNTER_UPDATE_PERIOD 60 +#define COUNTER_FLUSH_PERIOD 60 + +#define NONE_QUOTA_ID 0 + +#define TIME_TO_SAFE_DATA 1 /* one second */ + +/* + * @desc reserved classid enums + * internal structure, we don't provide it externally + */ +enum stc_reserved_classid { + STC_UNKNOWN_CLASSID, + STC_ALL_APP_CLASSID, /**< kernel expects 1 for + handling restriction for all + applications */ + STC_TETHERING_APP_CLASSID, /**< it uses in user space logic + for counting tethering traffic */ + STC_FOREGROUND_APP_CLASSID, /* it will used for special cgroup, + blocked cgroup */ + STC_BACKGROUND_APP_CLASSID, + STC_NETWORK_RESTRICTION_APP_CLASSID, + STC_RESERVED_CLASSID_MAX, +}; + +enum stc_counter_state { + STC_DEFAULT_STATE = 0, + STC_FORCIBLY_FLUSH_STATE = 1 << 1, + STC_FORCIBLY_QUIT_STATE = 1 << 2, + STC_NET_BLOCKED_STATE = 1 << 3, + STC_CHECK_QUOTA = 1 << 4, + STC_UPDATE_REQUESTED = 1 << 5, +}; + +#endif /* __STC_MANAGER_UTIL_H__ */ diff --git a/include/stc-manager.h b/include/stc-manager.h new file mode 100755 index 0000000..4e952b9 --- /dev/null +++ b/include/stc-manager.h @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __STC_MANAGER_H__ +#define __STC_MANAGER_H__ + +#include "stc-error.h" +#include "stc-manager-util.h" + +#define NET_RELEASE_AGENT "/usr/bin/net-cls-release" +#define NET_CLS_SUBSYS "net_cls" + +#define STC_BACKGROUND_APP_NAME "BACKGROUND" +#define NETWORK_RESTRICTION_APP_NAME "NETWORKRESTRICTION" + +#define STC_ALL_APP "STC_ALL_APPLICATION_IDENTIFIER" +#define TETHERING_APP_NAME "STC_TETHERING_APPLICATION_IDENTIFIER" + +typedef enum { + STC_CANCEL = 0, /**< cancel */ + STC_CONTINUE = 1, /**< continue */ +} stc_cb_ret_e; + +/** + * @brief Monitored application types + */ +typedef enum { + STC_APP_TYPE_NONE, + STC_APP_TYPE_READY, + STC_APP_TYPE_GUI, + STC_APP_TYPE_SERVICE, + STC_APP_TYPE_GROUP, + STC_APP_TYPE_WATCH, + STC_APP_TYPE_WIDGET, + STC_APP_TYPE_MAX, +} stc_app_type_e; + +/** + * @brief State of the statisticsed process + */ +typedef enum { + STC_APP_STATE_UNKNOWN = 0, + STC_APP_STATE_FOREGROUND = 1 << 1, /** < foreground state */ + STC_APP_STATE_BACKGROUND = 1 << 2, /** < background state */ + STC_APP_STATE_LAST_ELEM = 1 << 3 +} stc_app_state_e; + +/** + * @brief Network restriction states + */ +typedef enum { + STC_RESTRICTION_UNKNOWN, + STC_RESTRICTION_ACTIVATED, /** < restriction has been activated */ + STC_RESTRICTION_REMOVED, /** < restriction has been removed */ + STC_RESTRICTION_EXCLUDED, /** < restriction has been excluded */ + STC_RESTRICTION_LAST_ELEM +} stc_restriction_state_e; + +/** + * @brief Network interface types + */ +typedef enum { + STC_IFACE_UNKNOWN, /**< undefined iface */ + STC_IFACE_DATACALL, /**< mobile data */ + STC_IFACE_WIFI, /**< wifi data */ + STC_IFACE_WIRED, /**< wired interface */ + STC_IFACE_BLUETOOTH, /**< bluetooth interface */ + STC_IFACE_ALL, /**< enumerate all network interface types */ + STC_IFACE_LAST_ELEM +} stc_iface_type_e; + +/** + * @brief Network roaming type + */ +typedef enum { + STC_ROAMING_UNKNOWN, /**< can't define roaming - roaming unknown */ + STC_ROAMING_ENABLE, /**< in roaming */ + STC_ROAMING_DISABLE, /**< not in roaming */ + STC_ROAMING_LAST_ELEM, +} stc_roaming_type_e; + +/** + * @brief Hardware network protocol types + */ +typedef enum { + STC_PROTOCOL_NONE, /**< Network unknown */ + STC_PROTOCOL_DATACALL_NOSVC, /**< Network no service */ + STC_PROTOCOL_DATACALL_EMERGENCY, /**< Network emergency */ + STC_PROTOCOL_DATACALL_SEARCH, /**< Network search 1900 */ + STC_PROTOCOL_DATACALL_2G, /**< Network 2G */ + STC_PROTOCOL_DATACALL_2_5G, /**< Network 2.5G */ + STC_PROTOCOL_DATACALL_2_5G_EDGE, /**< Network EDGE */ + STC_PROTOCOL_DATACALL_3G, /**< Network UMTS */ + STC_PROTOCOL_DATACALL_HSDPA, /**< Network HSDPA */ + STC_PROTOCOL_DATACALL_LTE, /**< Network LTE */ + STC_PROTOCOL_MAX_ELEM +} stc_hw_net_protocol_type_e; + +/** + * @desc Description of the boolean option for enabling/disabling + * network interfaces and enabling/disabling some behaviar + */ +typedef enum { + STC_DB_OPTION_UNDEF, + STC_DB_OPTION_ENABLE, + STC_DB_OPTION_DISABLE +} stc_option_state_e; + +/** + * @desc Set of the options. + * version - contains structure version + * wifi - enable/disable wifi, STC_DB_OPTION_UNDEF to leave option as is + * datacall - enable/disable datacall, STC_DB_OPTION_UNDEF to leave option as is + * datausage_timer - set period of the updating data from the kernel, + * 0 to leave option as is + * datacall_logging - enable/disable datacall_logging, + * STC_DB_OPTION_UNDEF to leave option as is + */ +typedef struct { + unsigned char version; + stc_option_state_e wifi; + stc_option_state_e datacall; + time_t datausage_timer; + stc_option_state_e datacall_logging; +} stc_options_s; + +/** + * @brief datausage in bytes + */ +typedef struct { + uint64_t in_bytes; /**< incoming bytes */ + uint64_t out_bytes; /**< outgoing bytes */ +} stc_data_counter_s; + +typedef struct { + GMainLoop *main_loop; + + gpointer statistics_obj; + gpointer restriction_obj; + + GDBusObjectManagerServer *obj_mgr; + GDBusConnection *connection; + guint gdbus_owner_id; + + void *system; /* stc_system_s */ + struct counter_arg *carg; +} stc_s; + +stc_s *stc_get_manager(void); + +#endif /* __STC_MANAGER__ */ diff --git a/include/stc-restriction.h b/include/stc-restriction.h new file mode 100755 index 0000000..81df4bd --- /dev/null +++ b/include/stc-restriction.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __STC_RESTRICTION_H__ +#define __STC_RESTRICTION_H__ + +#include +#include "stc-manager.h" +#include "stc-manager-gdbus.h" +#include "table-restrictions.h" +#include "transmission.h" + +/***************************************************************************** + * Macros and Typedefs + *****************************************************************************/ +typedef struct { + stc_app_state_e rs_type; + stc_iface_type_e iftype; + uint64_t send_limit; + uint64_t rcv_limit; + uint64_t snd_warning_limit; + uint64_t rcv_warning_limit; + stc_roaming_type_e roaming; + char *ifname; + char *imsi; +} stc_restriction_s; + +/***************************************************************************** + * Functions Declaration + *****************************************************************************/ + +gboolean handle_restriction_set(StcRestriction *object, + GDBusMethodInvocation *invocation, + GVariant *parameters, + void *user_data); + +gboolean handle_restriction_exclude(StcRestriction *object, + GDBusMethodInvocation *invocation, + GVariant *parameters, + void *user_data); + +gboolean handle_restriction_get(StcRestriction *object, + GDBusMethodInvocation *invocation, + const gchar *app_id, + void *user_data); + +gboolean handle_restriction_get_all(StcRestriction *object, + GDBusMethodInvocation *invocation, + void *user_data); + +gboolean handle_restriction_get_state(StcRestriction *object, + GDBusMethodInvocation *invocation, + const gchar *app_id, + int iftype, + void *user_data); + +gboolean handle_restriction_remove(StcRestriction *object, + GDBusMethodInvocation *invocation, + GVariant *parameters, + void *user_data); + +#endif /* __STC_RESTRICTION_H__ */ diff --git a/include/stc-statistics.h b/include/stc-statistics.h new file mode 100755 index 0000000..ddb8f4d --- /dev/null +++ b/include/stc-statistics.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __STC_STATISTICS_H__ +#define __STC_STATISTICS_H__ + +#include +#include "stc-manager.h" +#include "stc-manager-gdbus.h" + +/***************************************************************************** + * Macros and Typedefs + *****************************************************************************/ + +/***************************************************************************** + * Functions Declaration + *****************************************************************************/ + +gboolean handle_statistics_get_all(StcStatistics *object, + GDBusMethodInvocation *invocation, + GVariant *select_rule, + void *user_data); + +gboolean handle_statistics_get(StcStatistics *object, + GDBusMethodInvocation *invocation, + const gchar *app_id, + GVariant *select_rule, + void *user_data); + +gboolean handle_statistics_reset(StcStatistics *object, + GDBusMethodInvocation *invocation, + GVariant *reset_rule, + void *user_data); + +#endif /* __STC_STATISTICS_H__ */ diff --git a/interfaces/stcmanager-iface-restriction.xml b/interfaces/stcmanager-iface-restriction.xml new file mode 100644 index 0000000..b765431 --- /dev/null +++ b/interfaces/stcmanager-iface-restriction.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/interfaces/stcmanager-iface-statistics.xml b/interfaces/stcmanager-iface-statistics.xml new file mode 100644 index 0000000..cad1de6 --- /dev/null +++ b/interfaces/stcmanager-iface-statistics.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packaging/stc-manager.spec b/packaging/stc-manager.spec new file mode 100644 index 0000000..352f24b --- /dev/null +++ b/packaging/stc-manager.spec @@ -0,0 +1,96 @@ +Name: stc-manager +Summary: STC(Smart Traffic Control) manager +Version: 0.0.1 +Release: 0 +Group: Network & Connectivity/Other +License: Apache-2.0 +Source0: %{name}-%{version}.tar.gz + +%define enable_database YES +%define enable_statistics YES +%define enable_restriction YES +%define database_full_path /opt/usr/dbspace/.stc-manager-datausage.db + +BuildRequires: cmake +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(gio-2.0) +BuildRequires: pkgconfig(gobject-2.0) +BuildRequires: pkgconfig(gio-unix-2.0) +BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(libtzplatform-config) +BuildRequires: pkgconfig(vconf) + +%if %{?enable_database} == YES +BuildRequires: pkgconfig(sqlite3) +%endif + +BuildRequires: python +BuildRequires: python-xml + +%description +A smart traffic control manager to manage traffic counting and bandwidth limitation + +%prep +%setup -q +chmod 644 %{SOURCE0} + +%build + +export CFLAGS="$CFLAGS -DTIZEN_DEBUG_ENABLE -D_GNU_SOURCE" +export CXXFLAGS="$CXXFLAGS -DTIZEN_DEBUG_ENABLE -D_GNU_SOURCE" +export FFLAGS="$FFLAGS -DTIZEN_DEBUG_ENABLE" + +%cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} \ + -DBIN_DIR=%{_bindir} \ + -DENABLE_DATABASE=%{enable_database} \ + -DDATABASE_FULL_PATH=%{database_full_path} \ + -DENABLE_STATISTICS=%{enable_statistics} \ + -DENABLE_RESTRICTION=%{enable_restriction} + +make %{?_smp_mflags} + +%install +rm -rf %{buildroot} + +%make_install + +#database initialization +%if %{?enable_database} == YES + mkdir -p %{buildroot}/opt/usr/dbspace + sqlite3 %{buildroot}%{database_full_path} < %{buildroot}/usr/share/traffic_db.sql + rm %{buildroot}/usr/share/traffic_db.sql + sqlite3 %{buildroot}%{database_full_path} < %{buildroot}/usr/share/exception_db.sql + rm %{buildroot}/usr/share/exception_db.sql +%endif + +#Systemd service file +mkdir -p %{buildroot}%{_libdir}/systemd/system/ +cp resources/systemd/stc-manager.service %{buildroot}%{_libdir}/systemd/system/stc-manager.service + +mkdir -p %{buildroot}%{_libdir}/systemd/system/multi-user.target.wants/ +ln -s ../stc-manager.service %{buildroot}%{_libdir}/systemd/system/multi-user.target.wants/stc-manager.service + +mkdir -p %{buildroot}%{_datadir}/dbus-1/system-services/ +cp resources/dbus/net.stc.service %{buildroot}%{_datadir}/dbus-1/system-services/ + +#DBus DAC (stc-manager.manifest enables DBus SMACK) +mkdir -p %{buildroot}%{_sysconfdir}/dbus-1/system.d +cp resources/dbus/stc-manager.conf %{buildroot}%{_sysconfdir}/dbus-1/system.d/stc-manager.conf + +%files +%manifest %{name}.manifest +%license LICENSE +%defattr(-,root,root,-) +%attr(500,root,root) %{_bindir}/* + +%attr(644,root,root) %{_libdir}/systemd/system/stc-manager.service +%attr(644,root,root) %{_libdir}/systemd/system/multi-user.target.wants/stc-manager.service + +#DBus DAC +%attr(644,root,root) %{_sysconfdir}/dbus-1/system.d/* +%attr(644,-,-) %{_datadir}/dbus-1/system-services/*.service + +%if %{?enable_database} == YES +%config(noreplace) %attr(660, root, root) %{database_full_path} +%config(noreplace) %attr(660, root, root) %{database_full_path}-journal +%endif diff --git a/resources/dbus/net.stc.service b/resources/dbus/net.stc.service new file mode 100755 index 0000000..68d4a0b --- /dev/null +++ b/resources/dbus/net.stc.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=net.stc +Exec=/usr/bin/stc-manager +User=root diff --git a/resources/dbus/stc-manager.conf b/resources/dbus/stc-manager.conf new file mode 100755 index 0000000..895dfa3 --- /dev/null +++ b/resources/dbus/stc-manager.conf @@ -0,0 +1,13 @@ + + + + + + + + + + + + diff --git a/resources/systemd/stc-manager.service b/resources/systemd/stc-manager.service new file mode 100755 index 0000000..70a9eef --- /dev/null +++ b/resources/systemd/stc-manager.service @@ -0,0 +1,13 @@ +[Unit] +Description=Smart Traffic Control Manager +Requires=dbus.socket +After=dbus.socket + +[Service] +Type=forking +SmackProcessLabel=System +ExecStart=/usr/bin/stc-manager +Restart=always + +[Install] +WantedBy=multi-user.target diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..51245d5 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,91 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) + +SET(REQUIRES_LIST ${REQUIRES_LIST} + glib-2.0 + gio-2.0 + gio-unix-2.0 + dlog + vconf + ) + +IF("${ENABLE_DATABASE}" STREQUAL "YES") + SET(REQUIRES_LIST ${REQUIRES_LIST} sqlite3) +ENDIF() + +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(stc_pkgs REQUIRED "${REQUIRES_LIST}") + +FOREACH(flag ${stc_pkgs_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(SOURCE_DIR ${CMAKE_SOURCE_DIR}/src) +SET(HELPER_SOURCE_DIR ${SOURCE_DIR}/helper) +SET(DATABASE_SOURCE_DIR ${SOURCE_DIR}/database) +SET(MONITOR_SOURCE_DIR ${SOURCE_DIR}/monitor) +SET(CONFIGURE_SOURCE_DIR ${SOURCE_DIR}/configure) +SET(LIMITATION_SOURCE_DIR ${SOURCE_DIR}/limitation) + +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include) +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/interfaces) + +INCLUDE_DIRECTORIES(${SOURCE_DIR}) +INCLUDE_DIRECTORIES(${HELPER_SOURCE_DIR}) + +INCLUDE_DIRECTORIES(${DATABASE_SOURCE_DIR}) +INCLUDE_DIRECTORIES(${DATABASE_SOURCE_DIR}/include) + +INCLUDE_DIRECTORIES(${MONITOR_SOURCE_DIR}) +INCLUDE_DIRECTORIES(${MONITOR_SOURCE_DIR}/include) + +INCLUDE_DIRECTORIES(${CONFIGURE_SOURCE_DIR}) +INCLUDE_DIRECTORIES(${CONFIGURE_SOURCE_DIR}/include) + +INCLUDE_DIRECTORIES(${LIMITATION_SOURCE_DIR}) +INCLUDE_DIRECTORIES(${LIMITATION_SOURCE_DIR}/include) + +FILE(GLOB SOURCE_SRCS ${SOURCE_DIR}/*.c) +FILE(GLOB HELPER_SOURCE_SRCS ${HELPER_SOURCE_DIR}/*.c) +FILE(GLOB MONITOR_SRCS ${MONITOR_SOURCE_DIR}/*.c) +FILE(GLOB CONFIGURE_SRCS ${CONFIGURE_SOURCE_DIR}/*.c) +FILE(GLOB LIMITATION_SRCS ${LIMITATION_SOURCE_DIR}/*.c) + +SET(SRCS ${SRCS} ${SOURCE_SRCS} ${HELPER_SOURCE_SRCS} ${MONITOR_SRCS} ${CONFIGURE_SRCS} ${LIMITATION_SRCS}) + +IF("${ENABLE_DATABASE}" STREQUAL "YES") + FILE(GLOB DATABASE_SRCS ${DATABASE_SOURCE_DIR}/*.c) + FILE(GLOB DATABASE_TABLES_SRCS ${DATABASE_SOURCE_DIR}/tables/*.c) + + SET(SRCS ${SRCS} ${DATABASE_SRCS} ${DATABASE_TABLES_SRCS}) + + INSTALL(FILES ${DATA_DIR}/traffic_db.sql DESTINATION /usr/share) + INSTALL(FILES ${DATA_DIR}/exception_db.sql DESTINATION /usr/share) +ENDIF() + +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fpic -Wall -Werror-implicit-function-declaration -fvisibility=hidden") +SET(ARM_CFLAGS "${ARM_CFLAGS} -mapcs -mabi=aapcs-linux -msoft-float -Uarm -fpic") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") + +SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -pie") + +ADD_DEFINITIONS("-DUSE_DLOG") +ADD_DEFINITIONS("-DDATABASE_FULL_PATH=\"${DATABASE_FULL_PATH}\"") + +ADD_CUSTOM_COMMAND( + WORKING_DIRECTORY + OUTPUT ${CMAKE_SOURCE_DIR}/src/generated-code.c + COMMAND gdbus-codegen --interface-prefix net.stc. + --generate-c-code generated-code + --c-namespace Stc + --c-generate-object-manager + --generate-docbook generated-code-docs + ${INTERFACES}/stcmanager-iface-restriction.xml + ${INTERFACES}/stcmanager-iface-statistics.xml + COMMENT "Generating GDBus .c/.h") + +SET(SRCS ${SRCS} ${SOURCE_DIR}/generated-code.c) +ADD_EXECUTABLE(${PROJECT_NAME} ${SRCS}) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${stc_pkgs_LDFLAGS} -ldl) +INSTALL(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION ${BIN_DIR}) + +ADD_SUBDIRECTORY(utils) diff --git a/src/configure/include/configure_stub.h b/src/configure/include/configure_stub.h new file mode 100755 index 0000000..3cfba39 --- /dev/null +++ b/src/configure/include/configure_stub.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __STC_CONFIGURE_STUB__ +#define __STC_CONFIGURE_STUB__ + +/* iface.c */ +inline stc_iface_type_e get_iftype_by_name(char *name) +{ + return STC_IFACE_UNKNOWN; +} + +/* iface.c */ +inline char *get_iftype_name(stc_error_e iftype) +{ + return "UNKNOWN"; +} + +/* datausage-common.c */ +inline void keep_counter(nfacct_rule_s *counter) +{ + return; +} + +/* datausage-common.c */ +inline void set_finalize_flag(nfacct_rule_s *counter) +{ + return; +} + +#endif /* __STC_CONFIGURE_STUB__ */ diff --git a/src/configure/include/counter.h b/src/configure/include/counter.h new file mode 100755 index 0000000..760a56a --- /dev/null +++ b/src/configure/include/counter.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __STC_DATAUSAGE_COUNTER_H__ +#define __STC_DATAUSAGE_COUNTER_H__ + +#include "stc-db.h" + +#define STC_BACKGROUND_APP_NAME "BACKGROUND" +#define NETWORK_RESTRICTION_APP_NAME "NETWORKRESTRICTION" + +struct counter_arg { + int sock; + int ans_len; + GTree *nf_cntrs; + int initiate; + int noti_fd; + int serialized_counters; /* number of counters which was serialized in + current request */ + struct net_counter_opts *opts; + struct application_stat_tree *result; + time_t last_run_time; +}; + +typedef struct counter_arg counter_arg_s; + +struct net_counter_opts { + sig_atomic_t update_period; + sig_atomic_t flush_period; + sig_atomic_t state; + int app_stat[STC_IFACE_LAST_ELEM - 1]; +}; + +/** + * @desc Reschedule existing traffic counter function + * Rescheduling logic is following, we will postpone + * execution on delay seconds. + */ +void reschedule_count_timer(const struct counter_arg *carg, const double delay); + +struct counter_arg *init_counter_arg(struct net_counter_opts *opts); + +void finalize_carg(struct counter_arg *carg); + +GTree *create_nfacct_tree(void); + +#endif /* __STC_DATAUSAGE_COUNTER_H__ */ diff --git a/src/configure/include/netlink-restriction.h b/src/configure/include/netlink-restriction.h new file mode 100755 index 0000000..2734fbf --- /dev/null +++ b/src/configure/include/netlink-restriction.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file net-restriction.h + * @desc Performance management API. Network restriction. + * @version 1.0 + * + * Created on: Jun 18, 2012 + */ + +#ifndef __STC_NET_RESTRICTION_H__ +#define __STC_NET_RESTRICTION_H__ + +#include + +#include "stc-manager.h" +#include "transmission.h" + +/** + * @brief Send network restriction for specific classid + * rst_type - type of restriction on the basis of which the restriction + * can be applied, removed or excluded. + * classid - id, that generated for each application in the cgroup + * quota_id - quota_id to store in nf_cntr tree + * iftype - network interface type to process restriction + * send_limit - amount number of engress bytes allowed for restriction + * rcv_limit - amount number of ingress bytes allowed for restriction + * snd_warning_limit - threshold for warning notification on engress bytes + * rcv_warning_limit - threshold for warning notification on ingress bytes + */ +int send_net_restriction(const enum traffic_restriction_type rst_type, + const guint32 classid, const int quota_id, + const stc_iface_type_e iftype, + const uint64_t send_limit, const uint64_t rcv_limit, + const uint64_t snd_warning_threshold, + const uint64_t rcv_warning_threshold, + const char *ifname); + +#endif /* __STC_NET_RESTRICTION_H__ */ diff --git a/src/configure/include/transmission.h b/src/configure/include/transmission.h new file mode 100755 index 0000000..297d879 --- /dev/null +++ b/src/configure/include/transmission.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file transmission.h + * @brief Kernel - user space transmition structures + * + */ + +#ifndef __TRAFFIC_CONTROL_TRAFFIC_STAT_TRANSMITION_H__ +#define __TRAFFIC_CONTROL_TRAFFIC_STAT_TRANSMITION_H__ +#ifdef _KERNEL_ +#include +#include +#else +#include +#include +#endif + +/* Used both in kernel module and in control daemon */ + +/* + * @brief Entity for outgoing and incomming packet counter information. + * Used for serialization. + */ +struct traffic_event { + uint32_t sk_classid; + unsigned long bytes; + int ifindex; +}; + +enum traffic_restriction_type { + RST_UNDEFINDED, + RST_SET, + RST_UNSET, + RST_EXCLUDE, + RST_MAX_VALUE +}; + +/* + * @brief Traffic restriction structure for serialization + * type - traffic_restriction_type + */ +struct traffic_restriction { + uint32_t sk_classid; + int type; + int ifindex; + int send_limit; + int rcv_limit; + int snd_warning_threshold; + int rcv_warning_threshold; +}; + +#define STC_ALL_IFINDEX 1 + +#endif /*TRAFFIC_CONTROL_TRAFFIC_STAT_TRANSMITION */ diff --git a/src/configure/nf-restriction.c b/src/configure/nf-restriction.c new file mode 100755 index 0000000..9e65904 --- /dev/null +++ b/src/configure/nf-restriction.c @@ -0,0 +1,133 @@ +/* + * @file nf-restriction.c + * + * @desc Implementation for set up/down restrictions. + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved. + * + */ + +#include "stc-error.h" +#include "stc-manager.h" +#include "netlink-restriction.h" +#include "helper-nfacct-rule.h" +#include "helper-restriction.h" +#include "stc-default-connection.h" +#include "stc-monitor.h" +#include "counter.h" + +static stc_error_e apply_net_restriction(struct nfacct_rule *rule, + const uint64_t send_limit, + const uint64_t rcv_limit) +{ + nfacct_rule_jump jump; + + /* block immediately */ + if (!rcv_limit) { /* for dual nfacct entity for restriction add || !send_limit */ + return produce_net_rule(rule, 0, 0, NFACCT_ACTION_INSERT, + NFACCT_JUMP_REJECT, NFACCT_COUNTER_OUT); + } + + jump = ((rule->intend == NFACCT_WARN) ? + NFACCT_JUMP_ACCEPT : NFACCT_JUMP_REJECT); + + return produce_net_rule(rule, send_limit, rcv_limit, + NFACCT_ACTION_APPEND, jump, + NFACCT_COUNTER_IN | NFACCT_COUNTER_OUT); +} + +static stc_error_e revert_net_restriction(struct nfacct_rule *rule, + const uint64_t send_limit, + const uint64_t rcv_limit) +{ + nfacct_rule_jump jump = ((rule->intend == NFACCT_WARN) ? + NFACCT_JUMP_ACCEPT : NFACCT_JUMP_REJECT); + + return produce_net_rule(rule, send_limit, rcv_limit, + NFACCT_ACTION_DELETE, jump, + NFACCT_COUNTER_IN | NFACCT_COUNTER_OUT); + +} + +static stc_error_e exclude_net_restriction(struct nfacct_rule *rule) +{ + /* Idea to remove old counter and insert new one at first position + * iptables has following architecture: it gets all entries from kernel + * modifies this list and returns it back, without iptables it could be + * done for one step, but with iptables cmd 2 steps is necessary */ + rule->intend = NFACCT_COUNTER; + stc_error_e ret = produce_net_rule(rule, 0, 0, NFACCT_ACTION_DELETE, + NFACCT_JUMP_UNKNOWN, + NFACCT_COUNTER_IN | NFACCT_COUNTER_OUT); + + ret_value_msg_if(ret != STC_ERROR_NONE, ret, "Failed to delete"); + + return produce_net_rule(rule, 0, 0, + NFACCT_ACTION_INSERT, NFACCT_JUMP_UNKNOWN, + NFACCT_COUNTER_IN | NFACCT_COUNTER_OUT); +} + +stc_error_e send_net_restriction(const enum traffic_restriction_type rst_type, + const guint32 classid, const int quota_id, + const stc_iface_type_e iftype, + const uint64_t send_limit, + const uint64_t rcv_limit, + const uint64_t snd_warning_threshold, + const uint64_t rcv_warning_threshold, + const char *ifname) +{ + int ret; + stc_s *stc = stc_get_manager(); + struct counter_arg *carg; + struct nfacct_rule rule = { + .name = {0}, + .ifname = {0}, + .quota_id = quota_id, + }; + + rule.rst_state = convert_to_restriction_state(rst_type); + + ret_value_msg_if(stc == NULL, STC_ERROR_FAIL, "Can't get stc data"); + if (!stc->carg) { + stc->carg = MALLOC0(counter_arg_s, 1); + stc->carg->sock = stc_monitor_get_counter_socket(); + } + + carg = stc->carg; + ret_value_msg_if(carg == NULL, STC_ERROR_FAIL, "Empty counter"); + + rule.classid = classid; + rule.iftype = iftype; + rule.carg = carg; + rule.roaming = stc_default_connection_get_roaming(); + STRING_SAVE_COPY(rule.ifname, ifname); + + if (rst_type == RST_SET) { + /* snd_warning_threshold && */ + if (rcv_warning_threshold) { + rule.intend = NFACCT_WARN; + ret = apply_net_restriction(&rule, + snd_warning_threshold, + rcv_warning_threshold); + ret_value_msg_if(ret != STC_ERROR_NONE, ret, + "Can't apply network restriction"); + } + rule.intend = NFACCT_BLOCK; + ret = apply_net_restriction(&rule, send_limit, rcv_limit); + ret_value_msg_if(ret != STC_ERROR_NONE, ret, + "Can't apply network restriction"); + } else if (rst_type == RST_UNSET) { + rule.intend = NFACCT_WARN; + ret = revert_net_restriction(&rule, + snd_warning_threshold, + rcv_warning_threshold); + ret_value_msg_if(ret != STC_ERROR_NONE, ret, + "Can't revert network restriction"); + rule.intend = NFACCT_BLOCK; + return revert_net_restriction(&rule, send_limit, + rcv_limit); + } else if (rst_type == RST_EXCLUDE) + return exclude_net_restriction(&rule); + + return STC_ERROR_NONE; +} diff --git a/src/database/db-common.c b/src/database/db-common.c new file mode 100644 index 0000000..d2ad1ea --- /dev/null +++ b/src/database/db-common.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "stc-db.h" +#include "db-internal.h" +#include "table-statistics.h" +#include "table-restrictions.h" +#include "table-counters.h" + +#ifndef DATABASE_FULL_PATH +#define DATABASE_FULL_PATH "/opt/usr/dbspace/.stc-manager-datausage.db" +#endif + +#define SQLITE_BUSY_TIMEOUT 500000 + +static sqlite3 *database; + +static int __stc_db_busy(void *user, int attempts) +{ + __STC_LOG_FUNC_ENTER__; + STC_LOGE("DB locked by another process, attempts number %d", + attempts); + + usleep(SQLITE_BUSY_TIMEOUT); /* wait for a half second*/ + __STC_LOG_FUNC_EXIT__; + return 1; +} + +stc_error_e stc_db_initialize_once(void) +{ + __STC_LOG_FUNC_ENTER__; + int res = 0; + int retry_count = 0; + if (database != NULL) { + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_NONE; + } + + do { + res = sqlite3_open(DATABASE_FULL_PATH, &database); + if (res != SQLITE_OK) { + STC_LOGD("Retry[%d] opening database %s: %s\n", + ++retry_count, DATABASE_FULL_PATH, + sqlite3_errmsg(database)); + } else { + break; + } + usleep(MAX_USLEEP_TIMEOUT); + } while (retry_count <= MAX_DB_RETRY_COUNT); + + if (res != SQLITE_OK) { + STC_LOGE("Can't open database %s: %s\n", DATABASE_FULL_PATH, + sqlite3_errmsg(database)); + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_DB_FAILED; + } + + STC_LOGD("Successfully opened database"); + + res = sqlite3_exec(database, "PRAGMA locking_mode = NORMAL", 0, 0, 0); + if (res != SQLITE_OK) { + STC_LOGE("Can't set locking mode %s, skip set busy handler.", + sqlite3_errmsg(database)); + sqlite3_close(database); + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_DB_FAILED; + } + + /* Set how many times we'll repeat our attempts for sqlite_step */ + if (sqlite3_busy_handler(database, __stc_db_busy, NULL) + != SQLITE_OK) + STC_LOGE("Couldn't set busy handler!"); + + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_NONE; +} + +sqlite3 *stc_db_get_database(void) +{ + if (database == NULL) + stc_db_initialize_once(); + + return database; +} + +stc_error_e stc_db_initialize(void) +{ + __STC_LOG_FUNC_ENTER__; + database = NULL; + + stc_db_initialize_once(); + + EXEC(STC_ERROR_NONE, table_statistics_prepare(database)); + EXEC(STC_ERROR_NONE, table_restrictions_prepare(database)); + EXEC(STC_ERROR_NONE, table_counters_prepare(database)); + EXEC(STC_ERROR_NONE, stc_init_db_guard()); + + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_NONE; + +handle_error: + stc_db_deinitialize(); + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_DB_FAILED; +} + +gboolean stc_db_deinitialize(void) +{ + __STC_LOG_FUNC_ENTER__; + if (database == NULL) { + __STC_LOG_FUNC_EXIT__; + return TRUE; + } + + table_statistics_finalize(); + table_restrictions_finalize(); + table_counters_finalize(); + sqlite3_close(database); + + __STC_LOG_FUNC_EXIT__; + return TRUE; +} diff --git a/src/database/db-guard.c b/src/database/db-guard.c new file mode 100644 index 0000000..46a9c32 --- /dev/null +++ b/src/database/db-guard.c @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "stc-db.h" +#include "table-statistics.h" + +#define VCONF_KEY_DB_ENTRIES_COUNT "db/stc-manager/datausage_timer" +#define ENTRY_SIZE 128 + +/* one hour */ +#define ERASE_TIMER_INTERVAL 3600 +/* 40 days */ +#define ERASE_INTERVAL 3600 * 24 * 40 +/* 50 Mb */ +#define DB_SIZE_THRESHOLD 1048576 * 50 + +static guint erase_timer = 0; +static int db_entries = 0; + +static void __change_db_entries_num_num(int num) +{ + __STC_LOG_FUNC_ENTER__; + + db_entries += num; + if (vconf_set_int(VCONF_KEY_DB_ENTRIES_COUNT, db_entries)) + STC_LOGE("Failed to set new db entries number"); + + __STC_LOG_FUNC_EXIT__; +} + +static void __check_erase_db_oversize(void) +{ + __STC_LOG_FUNC_ENTER__; + + struct stat db_stat = {0}; + int del_entry = 0; + + if (stat(DATABASE_FULL_PATH, &db_stat)) { + STC_LOGE("Failed to get statistics for %s errno %d", + DATABASE_FULL_PATH, errno); + __STC_LOG_FUNC_EXIT__; + return; + } + + if (db_stat.st_size < DB_SIZE_THRESHOLD) { + STC_LOGD("Db truncation isn't required!"); + __STC_LOG_FUNC_EXIT__; + return; + } + + /* get approximate number of entries for removing */ + del_entry = (db_stat.st_size - DB_SIZE_THRESHOLD) / ENTRY_SIZE; + if (STC_ERROR_NONE != + table_statistics_reset_first_n_entries(del_entry)) { + STC_LOGE("Failed to remove first %d entries", del_entry); + __STC_LOG_FUNC_EXIT__; + return; + } + + __change_db_entries_num_num(-del_entry); + + __STC_LOG_FUNC_EXIT__; +} + +static void __erase_old_entries(void) +{ + __STC_LOG_FUNC_ENTER__; + char buffer[80] = {0, }; + table_statistics_reset_rule rule = { + .iftype = STC_IFACE_LAST_ELEM, + }; + stc_db_tm_interval_s interval; + time_t until = time(0); + + until -= ERASE_INTERVAL; + + interval.from = 0; + interval.to = until; + rule.interval = &interval; + + strftime(buffer, 80, "%x - %I:%M%p", localtime(&until)); + STC_LOGD("Reset statistics till %s", buffer); + + if (table_statistics_reset(&rule) != STC_ERROR_NONE) + STC_LOGE("Failed to reset statistics"); + + __STC_LOG_FUNC_EXIT__; +} + +static gboolean __erase_func_cb(void *user_data) +{ + __STC_LOG_FUNC_ENTER__; + + __check_erase_db_oversize(); + __erase_old_entries(); + + /* we need to continue the timer */ + __STC_LOG_FUNC_EXIT__; + return TRUE; +} + +stc_error_e stc_init_db_guard(void) +{ + __STC_LOG_FUNC_ENTER__; + + erase_timer = g_timeout_add_seconds(ERASE_TIMER_INTERVAL, + __erase_func_cb, NULL); + if (erase_timer == 0) { + STC_LOGE("Failed to create timer"); + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_FAIL; + } + + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_NONE; +} + +void stc_deinit_db_guard(void) +{ + __STC_LOG_FUNC_ENTER__; + + if (erase_timer > 0) { + g_source_remove(erase_timer); + erase_timer = 0; + } + + __STC_LOG_FUNC_EXIT__; +} diff --git a/src/database/include/db-internal.h b/src/database/include/db-internal.h new file mode 100644 index 0000000..2d8922d --- /dev/null +++ b/src/database/include/db-internal.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * This file declares methods and variables which will be used by + * stc-db module internally. + * + * @file db-internal.h + */ + +#ifndef __STC_DB_INTERNAL_H__ +#define __STC_DB_INTERNAL_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/***************************************************************************** + * Macros and Typedefs + *****************************************************************************/ + +#define DB_ACTION(command) do { \ + if ((command) != SQLITE_OK) { \ + error_code = STC_ERROR_DB_FAILED; \ + __STC_LOG_FUNC_EXIT__; \ + goto handle_error; \ + } \ +} while (0) + +/***************************************************************************** + * Enumerations and Structures + *****************************************************************************/ + +void stc_db_finalize_statistics(void); + +stc_error_e stc_db_initialize_once(void); +sqlite3 *stc_db_get_database(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _STC_DB_INTERNAL_H_ */ diff --git a/src/database/include/stc-db.h b/src/database/include/stc-db.h new file mode 100644 index 0000000..a240994 --- /dev/null +++ b/src/database/include/stc-db.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __STC_DB_H__ +#define __STC_DB_H__ + +#include "stc-manager.h" + +#define MAX_DB_RETRY_COUNT 20 +#define MAX_USLEEP_TIMEOUT 500000 +#define SQLITE_BUSY_TIMEOUT 500000 +#define MAX_IFACE_LENGTH 32 + +/** + * @brief Commulative structure for holding stc storage information + */ +typedef struct { + stc_data_counter_s cnt; +// stc_db_net_restrictions rst; +} stc_db_common_info; + +typedef struct { + time_t from; + time_t to; +} stc_db_tm_interval_s; + +typedef enum { + STC_DB_CON_PERIOD_UNKNOWN, /**< Undefined period */ + STC_DB_CON_PERIOD_LAST_RECEIVED_DATA, /**< Last received data */ + STC_DB_CON_PERIOD_LAST_SENT_DATA, /**< Last sent data */ + STC_DB_CON_PERIOD_TOTAL_RECEIVED_DATA, /**< Total received data */ + STC_DB_CON_PERIOD_TOTAL_SENT_DATA, /**< Total sent data */ + STC_DB_CON_PERIOD_LAST_ELEM +} stc_db_connection_period_type; + +/* + * General structure containing information for storing + * app_id - package name as unique application identifier + * snd_count - sent bytes + * rcv_count - received bytes + * pid - process identifier + * ifindex - network interface index, iftype holds in key @see stc_iface_type + * is_roaming - is traffic consumed at roaming, @see stc_roaming_type + */ +typedef struct { + char *app_id; + unsigned int snd_count; + unsigned int rcv_count; + unsigned int delta_snd; + unsigned int delta_rcv; + +#ifndef CONFIG_DATAUSAGE_NFACCT + pid_t pid; + int ifindex; +#endif + stc_roaming_type_e is_roaming; + + /* foreground/background state is here, + * not in classid_iftype_key, it means + * we'll not able to handle simultaneously + * counter per one application for background and + * foreground within one counting cycle, + * so every time application goes to background/foreground + * we'll request its counter update */ + stc_app_state_e ground; +} stc_db_app_stats; + +typedef struct { + uint32_t classid; + int iftype; + /* pointer to telephony's imsi */ + char *imsi; + char ifname[MAX_IFACE_LENGTH]; +} stc_db_classid_iftype_key; + +/** + * @desc This funciton init db oversize erase timer. + */ +stc_error_e stc_init_db_guard(void); + +/** + * @desc This funciton deinit db oversize erase timer. + */ +void stc_deinit_db_guard(void); + +/** + * @desc This funciton initializes storage module. + */ +gboolean stc_db_initialize(void); + +/** + * @desc This funciton deinitializes storage module. + */ +gboolean stc_db_deinitialize(void); + +#endif /* _STC_DB_H_ */ diff --git a/src/database/include/table-counters.h b/src/database/include/table-counters.h new file mode 100644 index 0000000..556fdba --- /dev/null +++ b/src/database/include/table-counters.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __TABLE_COUNTERS_H__ +#define __TABLE_COUNTERS_H__ + +typedef struct { + uint64_t restriction_id; + uint64_t sent_bytes; + uint64_t rcv_bytes; +} table_counters_info; + +typedef stc_cb_ret_e(*table_counters_info_cb)(const table_counters_info *info, + void *user_data); + +stc_error_e table_counters_get(uint64_t restriction_id, + table_counters_info *info); + +stc_error_e table_counters_update_counters(const table_counters_info *info); + +stc_error_e table_counters_insert(const table_counters_info *info); + +stc_error_e table_counters_delete(uint64_t restriction_id); + +stc_error_e table_counters_prepare(sqlite3 *db); + +void table_counters_finalize(void); + +#endif /*__TABLE_COUNTERS_H__ */ diff --git a/src/database/include/table-restrictions.h b/src/database/include/table-restrictions.h new file mode 100644 index 0000000..ede1439 --- /dev/null +++ b/src/database/include/table-restrictions.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __TABLE_RESTRICTIONS_H__ +#define __TABLE_RESTRICTIONS_H__ + +typedef struct { + char *app_id; + char *ifname; + char *imsi; + stc_iface_type_e iftype; + stc_restriction_state_e rst_state; + stc_roaming_type_e roaming; + uint64_t rcv_limit; + uint64_t send_limit; + uint64_t rcv_warn_limit; + uint64_t send_warn_limit; + uint64_t restriction_id; +} table_restrictions_info; + +typedef stc_cb_ret_e +(*table_restrictions_info_cb)(const table_restrictions_info *info, + void *user_data); + +stc_error_e table_restrictions_foreach(table_restrictions_info_cb info_cb, + void *user_data); + +stc_error_e table_restrictions_per_app(const gchar *app_id, + table_restrictions_info_cb info_cb, + void *user_data); + + +stc_error_e table_restrictions_get_restriction_state_imsi(const char *app_id, + stc_iface_type_e iftype, + const char *imsi_hash, + stc_restriction_state_e *state); + +stc_error_e table_restrictions_get_restriction_state(const char *app_id, + stc_iface_type_e iftype, + stc_restriction_state_e *state); + +stc_error_e table_restrictions_update(table_restrictions_info *info); + +stc_error_e table_restrictions_delete(const char *app_id, + const stc_iface_type_e iftype, + const char *imsi); + +stc_error_e table_restrictions_prepare(sqlite3 *db); + +void table_restrictions_finalize(void); + +#endif /*__TABLE_RESTRICTIONS_H__ */ diff --git a/src/database/include/table-statistics.h b/src/database/include/table-statistics.h new file mode 100644 index 0000000..62a5ef6 --- /dev/null +++ b/src/database/include/table-statistics.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __TABLE_STATISTICS_H__ +#define __TABLE_STATISTICS_H__ + +typedef struct { + char *app_id; + char *ifname; + char *imsi; + stc_iface_type_e iftype; + stc_db_tm_interval_s *interval; + stc_data_counter_s cnt; + stc_roaming_type_e roaming; + stc_hw_net_protocol_type_e hw_net_protocol_type; + stc_app_state_e ground; +} table_statistics_info; + +typedef struct { + unsigned char version; + char *app_id; + char *imsi; + stc_iface_type_e iftype; + stc_db_tm_interval_s *interval; + stc_db_connection_period_type connection_state; +} table_statistics_reset_rule; + +typedef struct { + unsigned char version; + time_t from; + time_t to; + stc_iface_type_e iftype; + int granularity; +} table_statistics_select_rule; + +typedef stc_cb_ret_e +(*table_statistics_info_cb)(const table_statistics_info *info, void *user_data); + +stc_error_e table_statistics_reset_first_n_entries(int num); + +stc_error_e table_statistics_reset(const table_statistics_reset_rule *rule); + +stc_error_e table_statistics_foreach_app(const table_statistics_select_rule *rule, + table_statistics_info_cb info_cb, + void *user_data); + +stc_error_e table_statistics_per_app(const char *app_id, + table_statistics_select_rule *rule, + table_statistics_info_cb info_cb, + void *user_data); + +stc_error_e table_statistics_insert(stc_db_classid_iftype_key *stat_key, + stc_db_app_stats *stat, + time_t last_touch_time); + +stc_error_e table_statistics_prepare(sqlite3 *db); + +void table_statistics_finalize(void); + +#endif /*__TABLE_STATISTICS_H__ */ diff --git a/src/database/tables/table-counters.c b/src/database/tables/table-counters.c new file mode 100755 index 0000000..070ef46 --- /dev/null +++ b/src/database/tables/table-counters.c @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * This file implements counters entity handler methods. + * + * @file table-counter.c + */ + +#include "stc-db.h" +#include "db-internal.h" +#include "table-counters.h" + +#define DELETE_COUNTER "DELETE FROM counters WHERE restriction_id=?" + +#define SELECT_COUNTER "SELECT sent_bytes, rcv_bytes FROM counters WHERE restriction_id=?" + +#define INSERT_COUNTER "INSERT INTO counters (restriction_id, sent_bytes, rcv_bytes) " \ + " VALUES (?, ?, ?)" + +#define UPDATE_COUNTER "REPLACE INTO counters (restriction_id, sent_bytes, rcv_bytes) " \ + " VALUES (?, ?, ?)" + +static void __finalize_delete(void); + +#define PREPARE_DELETE(stm, query) do { \ + rc = sqlite3_prepare_v2(db, query, -1, &stm, NULL); \ + if (rc != SQLITE_OK) { \ + stm = NULL; \ + __finalize_delete(); \ + STC_LOGE("Failed to prepare \"%s\"query" \ + , query); \ + return rc; \ + } \ +} while (0) + +static void __finalize_select(void); + +#define PREPARE_SELECT(stm, query) do { \ + rc = sqlite3_prepare_v2(db, query, -1, &stm, NULL); \ + if (rc != SQLITE_OK) { \ + stm = NULL; \ + __finalize_select(); \ + STC_LOGE("Failed to prepare \"%s\"query" \ + , query); \ + return rc; \ + } \ +} while (0) + +static void __finalize_update(void); + +#define PREPARE_UPDATE(stm, query) do { \ + rc = sqlite3_prepare_v2(db, query, -1, &stm, NULL); \ + if (rc != SQLITE_OK) { \ + stm = NULL; \ + __finalize_update(); \ + STC_LOGE("Failed to prepare \"%s\"query" \ + , query); \ + return rc; \ + } \ +} while (0) + +#define FINALIZE(stm) do { \ + if (stm) { \ + sqlite3_finalize(stm); \ + stm = NULL; \ + } \ +} while (0) + +static sqlite3_stmt *delete_counter; +static sqlite3_stmt *select_counter; +static sqlite3_stmt *update_counter; + +static int __prepare_delete(sqlite3 *db) +{ + __STC_LOG_FUNC_ENTER__; + int rc; + static int initialized; + + if (initialized) { + __STC_LOG_FUNC_EXIT__; + return SQLITE_OK; + } + + PREPARE_DELETE(delete_counter, DELETE_COUNTER); + + initialized = 1; + __STC_LOG_FUNC_EXIT__; + return rc; +} + +static void __finalize_delete(void) +{ + __STC_LOG_FUNC_ENTER__; + + FINALIZE(delete_counter); + + __STC_LOG_FUNC_EXIT__; +} + +static int __prepare_select(sqlite3 *db) +{ + __STC_LOG_FUNC_ENTER__; + int rc; + static int initialized; + + if (initialized) { + __STC_LOG_FUNC_EXIT__; + return SQLITE_OK; + } + + PREPARE_SELECT(select_counter, SELECT_COUNTER); + + initialized = 1; + __STC_LOG_FUNC_EXIT__; + return rc; +} + +static void __finalize_select(void) +{ + __STC_LOG_FUNC_ENTER__; + + FINALIZE(select_counter); + + __STC_LOG_FUNC_EXIT__; +} + +static int __prepare_update(sqlite3 *db) +{ + __STC_LOG_FUNC_ENTER__; + int rc; + static int initialized; + + if (initialized) { + __STC_LOG_FUNC_EXIT__; + return SQLITE_OK; + } + + PREPARE_UPDATE(update_counter, UPDATE_COUNTER); + + initialized = 1; + __STC_LOG_FUNC_EXIT__; + return rc; +} + +static void __finalize_update(void) +{ + __STC_LOG_FUNC_ENTER__; + + FINALIZE(update_counter); + + __STC_LOG_FUNC_EXIT__; +} + +stc_error_e table_counters_get(uint64_t restriction_id, + table_counters_info *info) +{ + stc_error_e error_code = STC_ERROR_NONE; + sqlite3_stmt *stmt = select_counter; + int rc; + + if (info == NULL) + goto handle_error; + + DB_ACTION(sqlite3_bind_int64(stmt, 1, restriction_id)); + + do { + rc = sqlite3_step(stmt); + + switch (rc) { + case SQLITE_DONE: + break; + case SQLITE_ROW: + info->sent_bytes = sqlite3_column_int64(stmt, 0); + info->rcv_bytes = sqlite3_column_int64(stmt, 1); + + STC_LOGD("rstn_id [%llu] counters [sent = %llu rcv = %llu]", + restriction_id, info->sent_bytes, + info->rcv_bytes); + break; + case SQLITE_ERROR: + default: + STC_LOGE("Failed to enumerate counters: %s\n", + sqlite3_errmsg(stc_db_get_database())); + + error_code = STC_ERROR_DB_FAILED; + } + } while (rc == SQLITE_ROW); + +handle_error: + sqlite3_reset(stmt); + return error_code; +} + +stc_error_e table_counters_update_counters(const table_counters_info *info) +{ + stc_error_e error_code = STC_ERROR_NONE; + sqlite3_stmt *stmt = update_counter; + + if (!info->rcv_bytes && !info->sent_bytes) { + error_code = STC_ERROR_INVALID_PARAMETER; + goto handle_error; + } + + DB_ACTION(sqlite3_bind_int64(stmt, 1, info->restriction_id)); + DB_ACTION(sqlite3_bind_int64(stmt, 2, info->sent_bytes)); + DB_ACTION(sqlite3_bind_int64(stmt, 3, info->rcv_bytes)); + + if (sqlite3_step(stmt) != SQLITE_DONE) { + STC_LOGE("Failed to update counter: %s\n", + sqlite3_errmsg(stc_db_get_database())); + error_code = STC_ERROR_DB_FAILED; + __STC_LOG_FUNC_EXIT__; + goto handle_error; + } + + STC_LOGD("Counter updated for restriction_id [%llu]", + info->restriction_id); + +handle_error: + sqlite3_reset(stmt); + return error_code; +} + +stc_error_e table_counters_delete(uint64_t restriction_id) +{ + stc_error_e error_code = STC_ERROR_NONE; + sqlite3_stmt *stmt = delete_counter; + + DB_ACTION(sqlite3_bind_int64(stmt, 1, restriction_id)); + + if (sqlite3_step(stmt) != SQLITE_DONE) { + STC_LOGE("Failed to delete counter: %s\n", + sqlite3_errmsg(stc_db_get_database())); + error_code = STC_ERROR_DB_FAILED; + goto handle_error; + } + + STC_LOGD("Counter deleted for restriction_id [%llu]", restriction_id); + +handle_error: + sqlite3_reset(stmt); + return error_code; +} + +stc_error_e table_counters_prepare(sqlite3 *db) +{ + __STC_LOG_FUNC_ENTER__; + + stc_error_e error_code = STC_ERROR_NONE; + + if (db == NULL) { + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_FAIL; + } + + DB_ACTION(__prepare_delete(db)); + DB_ACTION(__prepare_select(db)); + DB_ACTION(__prepare_update(db)); + +handle_error: + __STC_LOG_FUNC_EXIT__; + return error_code; +} + +void table_counters_finalize(void) +{ + __STC_LOG_FUNC_ENTER__; + __finalize_delete(); + __finalize_select(); + __finalize_update(); + __STC_LOG_FUNC_EXIT__; +} diff --git a/src/database/tables/table-restrictions.c b/src/database/tables/table-restrictions.c new file mode 100755 index 0000000..aec6f08 --- /dev/null +++ b/src/database/tables/table-restrictions.c @@ -0,0 +1,593 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This file implements restrictions entity handler methods. + * + * @file table-restrictions.c + */ + +#include "stc-db.h" +#include "db-internal.h" +#include "table-restrictions.h" + +/* DELETE statements */ +#define DELETE_RESTRICTIONS "DELETE FROM restrictions " \ + "WHERE binpath=? AND iftype=? AND imsi = ?" + +/* SELECT statements */ +#define SELECT_RESTRICTIONS "SELECT binpath, rcv_limit, " \ + "send_limit, iftype, rst_state, roaming, ifname, imsi, " \ + "rcv_warn_limit, send_warn_limit, restriction_id FROM restrictions" + +#define SELECT_RESTRICTIONS_PER_APP "SELECT binpath, rcv_limit, " \ + "send_limit, iftype, rst_state, roaming, ifname, imsi, " \ + "rcv_warn_limit, send_warn_limit, restriction_id " \ + "FROM restrictions INDEXED BY restrictions_index " \ + "WHERE binpath = ?" + +#define SELECT_RESTRICTION_STATE "SELECT rst_state " \ + "FROM restrictions INDEXED BY restrictions_index " \ + "WHERE binpath = ? AND iftype = ?" + +#define SELECT_RESTRICTION_STATE_IMSI "SELECT rst_state " \ + "FROM restrictions INDEXED BY restrictions_index " \ + "WHERE binpath = ? AND iftype = ? AND imsi = ?" + +#define SELECT_RESTRICTION_ID "SELECT restriction_id FROM restrictions " \ + "WHERE binpath = ? AND iftype = ? AND imsi = ? AND send_limit=? " \ + "AND rcv_limit=? AND rcv_warn_limit=? AND send_warn_limit=? " \ + "AND rst_state=? AND roaming=? AND ifname=?" + +/* UPDATE statement */ +#define UPDATE_NET_RESTRICTIONS "UPDATE restrictions " \ + "SET binpath=?, rcv_limit=?, send_limit=?, iftype=?, rst_state=?, " \ + "roaming=?, ifname=?, imsi=?, rcv_warn_limit=?, send_warn_limit=? " \ + "WHERE restriction_id=?" + +/* INSERT statement */ +#define INSERT_NET_RESTRICTIONS "INSERT INTO restrictions " \ + "(binpath, rcv_limit, send_limit, iftype, rst_state, " \ + "roaming, ifname, imsi, rcv_warn_limit, send_warn_limit) " \ + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + +static void __finalize_delete(void); + +#define PREPARE_DELETE(stm, query) do { \ + rc = sqlite3_prepare_v2(db, query, -1, &stm, NULL); \ + if (rc != SQLITE_OK) { \ + stm = NULL; \ + __finalize_delete(); \ + STC_LOGE("Failed to prepare \"%s\"query" \ + , query); \ + return rc; \ + } \ +} while (0) + +static void __finalize_select(void); + +#define PREPARE_SELECT(stm, query) do { \ + rc = sqlite3_prepare_v2(db, query, -1, &stm, NULL); \ + if (rc != SQLITE_OK) { \ + stm = NULL; \ + __finalize_select(); \ + STC_LOGE("Failed to prepare \"%s\"query" \ + , query); \ + return rc; \ + } \ +} while (0) + +static void __finalize_update(void); + +#define PREPARE_UPDATE(stm, query) do { \ + rc = sqlite3_prepare_v2(db, query, -1, &stm, NULL); \ + if (rc != SQLITE_OK) { \ + stm = NULL; \ + __finalize_update(); \ + STC_LOGE("Failed to prepare \"%s\"query" \ + , query); \ + return rc; \ + } \ +} while (0) + +static void __finalize_insert(void); + +#define PREPARE_INSERT(stm, query) do { \ + rc = sqlite3_prepare_v2(db, query, -1, &stm, NULL); \ + if (rc != SQLITE_OK) { \ + stm = NULL; \ + __finalize_insert(); \ + STC_LOGE("Failed to prepare \"%s\"query" \ + , query); \ + return rc; \ + } \ +} while (0) + +#define FINALIZE(stm) do { \ + if (stm) { \ + sqlite3_finalize(stm); \ + stm = NULL; \ + } \ +} while (0) + +/* DELETE statements */ +static sqlite3_stmt *delete_restrictions; + +/* SELECT statements */ +static sqlite3_stmt *select_restriction; +static sqlite3_stmt *select_restriction_per_app; +static sqlite3_stmt *select_restriction_state; +static sqlite3_stmt *select_restriction_state_imsi; +static sqlite3_stmt *select_restriction_id; + +/* REPLACE statements */ +static sqlite3_stmt *update_net_restrictions; + +/* INSERT statements */ +static sqlite3_stmt *insert_net_restrictions; + +static int __prepare_delete(sqlite3 *db) +{ + __STC_LOG_FUNC_ENTER__; + int rc; + static int initialized; + + if (initialized) { + __STC_LOG_FUNC_EXIT__; + return SQLITE_OK; + } + + PREPARE_DELETE(delete_restrictions, DELETE_RESTRICTIONS); + + initialized = 1; + __STC_LOG_FUNC_EXIT__; + return rc; +} + +static void __finalize_delete(void) +{ + __STC_LOG_FUNC_ENTER__; + + FINALIZE(delete_restrictions); + + __STC_LOG_FUNC_EXIT__; +} + +static int __prepare_select(sqlite3 *db) +{ + __STC_LOG_FUNC_ENTER__; + int rc; + static int initialized; + + if (initialized) { + __STC_LOG_FUNC_EXIT__; + return SQLITE_OK; + } + + PREPARE_SELECT(select_restriction, SELECT_RESTRICTIONS); + PREPARE_SELECT(select_restriction_per_app, SELECT_RESTRICTIONS_PER_APP); + PREPARE_SELECT(select_restriction_state, SELECT_RESTRICTION_STATE); + PREPARE_SELECT(select_restriction_state_imsi, SELECT_RESTRICTION_STATE_IMSI); + PREPARE_SELECT(select_restriction_id, SELECT_RESTRICTION_ID); + + initialized = 1; + __STC_LOG_FUNC_EXIT__; + return rc; +} + +static void __finalize_select(void) +{ + __STC_LOG_FUNC_ENTER__; + + FINALIZE(select_restriction); + FINALIZE(select_restriction_per_app); + FINALIZE(select_restriction_state); + FINALIZE(select_restriction_state_imsi); + FINALIZE(select_restriction_id); + + __STC_LOG_FUNC_EXIT__; +} + +static int __prepare_replace(sqlite3 *db) +{ + __STC_LOG_FUNC_ENTER__; + int rc; + static int initialized; + + if (initialized) { + __STC_LOG_FUNC_EXIT__; + return SQLITE_OK; + } + + PREPARE_UPDATE(update_net_restrictions, UPDATE_NET_RESTRICTIONS); + + initialized = 1; + __STC_LOG_FUNC_EXIT__; + return rc; +} + +static void __finalize_update(void) +{ + __STC_LOG_FUNC_ENTER__; + + FINALIZE(update_net_restrictions); + + __STC_LOG_FUNC_EXIT__; +} + +static int __prepare_insert(sqlite3 *db) +{ + __STC_LOG_FUNC_ENTER__; + int rc; + static int initialized; + + if (initialized) { + __STC_LOG_FUNC_EXIT__; + return SQLITE_OK; + } + + PREPARE_UPDATE(insert_net_restrictions, INSERT_NET_RESTRICTIONS); + + initialized = 1; + __STC_LOG_FUNC_EXIT__; + return rc; +} + +static void __finalize_insert(void) +{ + __STC_LOG_FUNC_ENTER__; + + FINALIZE(insert_net_restrictions); + + __STC_LOG_FUNC_EXIT__; +} + +stc_error_e table_restrictions_per_app(const gchar* app_id, + const table_restrictions_info_cb restriction_cb, + void *user_data) +{ + __STC_LOG_FUNC_ENTER__; + table_restrictions_info data; + int rc; + stc_error_e error_code = STC_ERROR_NONE; + sqlite3_stmt *stmt = select_restriction_per_app; + + if (!app_id) { + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_DB_FAILED; + } + + DB_ACTION(sqlite3_bind_text(stmt, 1, app_id, -1, + SQLITE_TRANSIENT)); + data.app_id = (char *)app_id; + + do { + rc = sqlite3_step(stmt); + + memset(&data, 0, sizeof(data)); + + switch (rc) { + case SQLITE_DONE: + break; + case SQLITE_ROW: + data.app_id = (char *)sqlite3_column_text(stmt, 0); + data.rcv_limit = sqlite3_column_int64(stmt, 1); + data.send_limit = sqlite3_column_int64(stmt, 2); + data.iftype = (stc_iface_type_e)sqlite3_column_int(stmt, 3); + data.rst_state = + (stc_restriction_state_e)sqlite3_column_int(stmt, 4); + data.roaming = sqlite3_column_int(stmt, 5); + data.ifname = (char *)sqlite3_column_text(stmt, 6); + data.imsi = (char *)sqlite3_column_text(stmt, 7); + data.rcv_warn_limit = sqlite3_column_int64(stmt, 8); + data.send_warn_limit = sqlite3_column_int64(stmt, 9); + data.restriction_id = sqlite3_column_int64(stmt, 10); + + if (restriction_cb(&data, user_data) == STC_CANCEL) + rc = SQLITE_DONE; + break; + case SQLITE_ERROR: + default: + STC_LOGE("Failed to enumerate restrictions: %s\n", + sqlite3_errmsg(stc_db_get_database())); + + __STC_LOG_FUNC_EXIT__; + error_code = STC_ERROR_DB_FAILED; + } + } while (rc == SQLITE_ROW); + +handle_error: + sqlite3_reset(stmt); + __STC_LOG_FUNC_EXIT__; + return error_code; +} + +stc_error_e table_restrictions_foreach(const table_restrictions_info_cb restriction_cb, + void *user_data) +{ + __STC_LOG_FUNC_ENTER__; + table_restrictions_info data; + int rc; + stc_error_e error_code = STC_ERROR_NONE; + sqlite3_stmt *stmt = select_restriction; + + do { + rc = sqlite3_step(stmt); + + memset(&data, 0, sizeof(data)); + + switch (rc) { + case SQLITE_DONE: + break; + case SQLITE_ROW: + data.app_id = (char *)sqlite3_column_text(stmt, 0); + data.rcv_limit = sqlite3_column_int64(stmt, 1); + data.send_limit = sqlite3_column_int64(stmt, 2); + data.iftype = (stc_iface_type_e)sqlite3_column_int(stmt, 3); + data.rst_state = + (stc_restriction_state_e)sqlite3_column_int(stmt, 4); + data.roaming = sqlite3_column_int(stmt, 5); + data.ifname = (char *)sqlite3_column_text(stmt, 6); + data.imsi = (char *)sqlite3_column_text(stmt, 7); + data.rcv_warn_limit = sqlite3_column_int64(stmt, 8); + data.send_warn_limit = sqlite3_column_int64(stmt, 9); + data.restriction_id = sqlite3_column_int64(stmt, 10); + + if (restriction_cb(&data, user_data) == STC_CANCEL) + rc = SQLITE_DONE; + break; + case SQLITE_ERROR: + default: + STC_LOGE("Failed to enumerate restrictions: %s\n", + sqlite3_errmsg(stc_db_get_database())); + + __STC_LOG_FUNC_EXIT__; + error_code = STC_ERROR_DB_FAILED; + } + } while (rc == SQLITE_ROW); + + sqlite3_reset(stmt); + __STC_LOG_FUNC_EXIT__; + return error_code; +} + +stc_error_e table_restrictions_get_restriction_state_imsi(const char *app_id, + stc_iface_type_e iftype, + const char *imsi_hash, + stc_restriction_state_e *state) +{ + __STC_LOG_FUNC_ENTER__; + int error_code = STC_ERROR_NONE; + int ret; + bool state_imsi = 0; + + if (state == NULL) { + STC_LOGE("Please provide valid argument!"); + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_INVALID_PARAMETER; + } + + *state = STC_RESTRICTION_UNKNOWN; + sqlite3_reset(select_restriction_state_imsi); + sqlite3_reset(select_restriction_state); + + if (imsi_hash == NULL) { + state_imsi = 0; + DB_ACTION(sqlite3_bind_text(select_restriction_state, 1, + app_id ? app_id : "", -1, + SQLITE_STATIC)); + DB_ACTION(sqlite3_bind_int(select_restriction_state, 2, + iftype)); + ret = sqlite3_step(select_restriction_state); + } else { + state_imsi = 1; + DB_ACTION(sqlite3_bind_text(select_restriction_state_imsi, 1, + app_id ? app_id : "", -1, + SQLITE_STATIC)); + DB_ACTION(sqlite3_bind_int(select_restriction_state_imsi, 2, + iftype)); + DB_ACTION(sqlite3_bind_text(select_restriction_state_imsi, 3, + imsi_hash, -1, SQLITE_STATIC)); + ret = sqlite3_step(select_restriction_state_imsi); + } + + switch (ret) { + case SQLITE_DONE: + break; + case SQLITE_ROW: + if (state_imsi) + *state = (stc_restriction_state_e)sqlite3_column_int(select_restriction_state_imsi, 0); + else + *state = (stc_restriction_state_e)sqlite3_column_int(select_restriction_state, 0); + break; + case SQLITE_ERROR: + default: + STC_LOGE("Can't perform sql query: %s \n%s", + SELECT_RESTRICTION_STATE, + sqlite3_errmsg(stc_db_get_database())); + error_code = STC_ERROR_DB_FAILED; + } + +handle_error: + sqlite3_reset(select_restriction_state); + sqlite3_reset(select_restriction_state_imsi); + return error_code; +} + +stc_error_e table_restrictions_get_restriction_state(const char *app_id, + stc_iface_type_e iftype, + stc_restriction_state_e *state) +{ + __STC_LOG_FUNC_ENTER__; + __STC_LOG_FUNC_EXIT__; + return table_restrictions_get_restriction_state_imsi(app_id, iftype, + NULL, state); +} + +stc_error_e table_restrictions_delete(const char *app_id, + const stc_iface_type_e iftype, + const char *imsi) +{ + stc_error_e error_code = STC_ERROR_NONE; + sqlite3_stmt *stmt = delete_restrictions; + + STC_LOGD("app_id [%s], iftype [%d], imsi [%s]", + app_id, iftype, imsi); + + DB_ACTION(sqlite3_bind_text(stmt, 1, app_id ? app_id : "", + -1, SQLITE_TRANSIENT)); + DB_ACTION(sqlite3_bind_int(stmt, 2, iftype)); + DB_ACTION(sqlite3_bind_text(stmt, 3, imsi ? imsi : "", -1, + SQLITE_TRANSIENT)); + + if (sqlite3_step(stmt) != SQLITE_DONE) { + STC_LOGE("Failed to remove restrictions by network interface %s\n", + sqlite3_errmsg(stc_db_get_database())); + error_code = STC_ERROR_DB_FAILED; + goto handle_error; + } + + STC_LOGD("Restriction deleted for app_id [%s]", app_id); + +handle_error: + + sqlite3_reset(stmt); + return error_code; +} + +stc_error_e __get_restriction_id(table_restrictions_info *info) +{ + __STC_LOG_FUNC_ENTER__; + int rc; + stc_error_e error_code = STC_ERROR_NONE; + sqlite3_stmt *stmt = select_restriction_id; + + DB_ACTION(sqlite3_bind_text(stmt, 1, info->app_id ? info->app_id : "", + -1, SQLITE_TRANSIENT)); + DB_ACTION(sqlite3_bind_int(stmt, 2, info->iftype)); + DB_ACTION(sqlite3_bind_text(stmt, 3, info->imsi ? info->imsi : "", + -1, SQLITE_TRANSIENT)); + DB_ACTION(sqlite3_bind_int64(stmt, 4, info->send_limit)); + DB_ACTION(sqlite3_bind_int64(stmt, 5, info->rcv_limit)); + DB_ACTION(sqlite3_bind_int64(stmt, 6, info->rcv_warn_limit)); + DB_ACTION(sqlite3_bind_int64(stmt, 7, info->send_warn_limit)); + + DB_ACTION(sqlite3_bind_int(stmt, 8, info->rst_state)); + DB_ACTION(sqlite3_bind_int(stmt, 9, info->roaming)); + DB_ACTION(sqlite3_bind_text(stmt, 10, info->ifname ? info->ifname : "", + -1, SQLITE_TRANSIENT)); + + rc = sqlite3_step(stmt); + + switch (rc) { + case SQLITE_DONE: + break; + case SQLITE_ROW: + info->restriction_id = sqlite3_column_int64(stmt, 0); + STC_LOGD("restriction id [%llu]", info->restriction_id); + break; + case SQLITE_ERROR: + default: + STC_LOGE("Failed to get restriction id: %s\n", + sqlite3_errmsg(stc_db_get_database())); + } + +handle_error: + sqlite3_reset(stmt); + __STC_LOG_FUNC_EXIT__; + return error_code; +} + +stc_error_e table_restrictions_update(table_restrictions_info *info) +{ + stc_error_e error_code = STC_ERROR_NONE; + sqlite3_stmt *stmt = insert_net_restrictions; + + if (!info) { + error_code = STC_ERROR_INVALID_PARAMETER; + goto handle_error; + } + + if (info->restriction_id) + stmt = update_net_restrictions; + + DB_ACTION(sqlite3_bind_text(stmt, 1, info->app_id ? info->app_id : "", + -1, SQLITE_TRANSIENT)); + DB_ACTION(sqlite3_bind_int64(stmt, 2, info->rcv_limit)); + DB_ACTION(sqlite3_bind_int64(stmt, 3, info->send_limit)); + DB_ACTION(sqlite3_bind_int(stmt, 4, info->iftype)); + DB_ACTION(sqlite3_bind_int(stmt, 5, info->rst_state)); + DB_ACTION(sqlite3_bind_int(stmt, 6, info->roaming)); + DB_ACTION(sqlite3_bind_text(stmt, 7, info->ifname ? info->ifname : "", + -1, SQLITE_TRANSIENT)); + DB_ACTION(sqlite3_bind_text(stmt, 8, info->imsi ? info->imsi : "", + -1, SQLITE_TRANSIENT)); + DB_ACTION(sqlite3_bind_int64(stmt, 9, info->rcv_warn_limit)); + DB_ACTION(sqlite3_bind_int64(stmt, 10, info->send_warn_limit)); + + if (info->restriction_id) + DB_ACTION(sqlite3_bind_int64(stmt, 11, info->restriction_id)); + + if (sqlite3_step(stmt) != SQLITE_DONE) { + STC_LOGE("Failed to set network restriction: %s\n", + sqlite3_errmsg(stc_db_get_database())); + error_code = STC_ERROR_DB_FAILED; + goto handle_error; + } + + if (info->restriction_id) { + STC_LOGD("Restriction updated app_id [%s]", info->app_id); + } else { + STC_LOGD("Restriction inserted app_id [%s]", info->app_id); + __get_restriction_id(info); + } + +handle_error: + sqlite3_reset(stmt); + return error_code; +} + +stc_error_e table_restrictions_prepare(sqlite3 *db) +{ + __STC_LOG_FUNC_ENTER__; + + stc_error_e error_code = STC_ERROR_NONE; + + if (db == NULL) { + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_FAIL; + } + + DB_ACTION(__prepare_delete(db)); + DB_ACTION(__prepare_select(db)); + DB_ACTION(__prepare_replace(db)); + DB_ACTION(__prepare_insert(db)); + +handle_error: + + __STC_LOG_FUNC_EXIT__; + return error_code; +} + +void table_restrictions_finalize(void) +{ + __STC_LOG_FUNC_ENTER__; + __finalize_delete(); + __finalize_select(); + __finalize_update(); + __finalize_insert(); + __STC_LOG_FUNC_EXIT__; +} diff --git a/src/database/tables/table-statistics.c b/src/database/tables/table-statistics.c new file mode 100755 index 0000000..05e66f6 --- /dev/null +++ b/src/database/tables/table-statistics.c @@ -0,0 +1,686 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This file implements statistics entity handler methods. + * + * @file table-statistics.c + */ + +#include "stc-db.h" +#include "table-statistics.h" +#include "db-internal.h" + +/* DELETE statements */ +#define DELETE_ALL "delete from statistics where time_stamp between ? and ?" + +#define DELETE_APP "delete from statistics where binpath=? and " \ + "time_stamp between ? and ? " + +#define DELETE_IFACE "delete from statistics where iftype=? and " \ + "time_stamp between ? and ?" + +#define DELETE_APP_IFACE "delete from statistics where binpath=? and " \ + "iftype=? and time_stamp between ? and ?" + +#define DELETE_FIRST_BY_NUMBER "delete from statistics where time_stamp in " \ + "(select time_stamp from statistics desc limit ?)" + +/* SELECT statements */ +#define SELECT_FOR_PERIOD "select binpath, hw_net_protocol_type, " \ + "is_roaming, sum(received) as received, " \ + "sum(sent) as sent, imsi, ground from statistics " \ + "where time_stamp between ? and ? " \ + "group by binpath, is_roaming, imsi order by received desc" + +#define SELECT_FOR_PERIOD_IFACE "select binpath, hw_net_protocol_type, " \ + "is_roaming, sum(received) as received, " \ + "sum(sent) as sent, imsi, ground from statistics " \ + "where time_stamp between ? and ? " \ + "and iftype=? group by binpath, is_roaming, imsi order by received desc" + +#define SELECT_CHUNKS "select binpath, hw_net_protocol_type, " \ + "is_roaming, sum(received) as received, " \ + "sum(sent) as sent, time_stamp - time_stamp % ? as time_stamp, imsi, " \ + "ground " \ + "from statistics where time_stamp between ? and ? " \ + "group by binpath, time_stamp, imsi order by time_stamp" + +#define SELECT_CHUNKS_IFACE "select binpath, hw_net_protocol_type, " \ + "is_roaming, sum(received) as received, " \ + "sum(sent) as sent, imsi, ground, " \ + "time_stamp - time_stamp % ? as time_stamp " \ + "from statistics where time_stamp between ? and ? and iftype=?" \ + "group by binpath, time_stamp, imsi order by time_stamp" + +#define SELECT_APP_DETAILS "select iftype, hw_net_protocol_type, " \ + "is_roaming, sum(received) as received, sum(sent) as sent, " \ + "ifname, imsi, ground from statistics " \ + "where time_stamp between ? and ? and binpath=? " \ + "group by binpath, iftype, ifname, imsi, hw_net_protocol_type, " \ + "is_roaming " \ + "order by time_stamp, binpath, iftype, ifname, imsi, " \ + "hw_net_protocol_type, is_roaming" + +#define SELECT_APP_DETAILS_IFACE "select iftype, hw_net_protocol_type, " \ + "is_roaming, sum(received) as received, sum(sent) as sent, " \ + "ifname, imsi, ground from statistics " \ + "where time_stamp between ? and ? and binpath=? and iftype=?" \ + "group by hw_net_protocol_type, is_roaming, iftype, ifname, imsi " \ + "order by time_stamp, hw_net_protocol_type, is_roaming, iftype, " \ + "ifname, imsi" + +#define SELECT_CHUNKS_APP "select iftype, hw_net_protocol_type, " \ + "is_roaming, sum(received) as received, sum(sent) as sent, " \ + "ifname, imsi, ground, time_stamp - time_stamp % ? as time_stamp " \ + "from statistics " \ + "group by iftype, ifname, time_stamp, hw_net_protocol_type, is_roaming " \ + "order by time_stamp, iftype, ifname, hw_net_protocol_type, is_roaming" + +#define SELECT_CHUNKS_APP_IFACE "select iftype, hw_net_protocol_type, " \ + "is_roaming, sum(received) as received, sum(sent) as sent, " \ + "ifname, imsi, ground, time_stamp - time_stamp % ? as time_stamp " \ + "from statistics where time_stamp between ? and ? and binpath = ? " \ + "and iftype = ? " \ + "group by time_stamp, hw_net_protocol_type, is_roaming, " \ + "iftype, ifname, imsi " \ + "order by time_stamp, iftype, ifname, imsi, hw_net_protocol_type, " \ + "is_roaming" + +#define SELECT_TOTAL "select iftype, hw_net_protocol_type, " \ + "is_roaming, sum(received) as received, sum(sent) as sent, " \ + "ifname, imsi, ground from statistics " \ + " where binpath='STC_ALL_APPLICATION_IDENTIFIER' AND (time_stamp between ? and ?) " \ + "group by iftype, ifname, imsi, hw_net_protocol_type, is_roaming " \ + "order by time_stamp, iftype, ifname, imsi, hw_net_protocol_type, " \ + "is_roaming" + +#define SELECT_TOTAL_IFACE "select iftype, hw_net_protocol_type, " \ + "is_roaming, sum(received) as received, sum(sent) as sent, " \ + "ifname, imsi, ground from statistics " \ + " where binpath='STC_ALL_APPLICATION_IDENTIFIER' AND (time_stamp between ? and ?) " \ + "and iftype=? " \ + "group by hw_net_protocol_type, is_roaming, " \ + "iftype, ifname, imsi " \ + "order by time_stamp, iftype, ifname, imsi, hw_net_protocol_type, " \ + "is_roaming" + +#define SELECT_CHUNKS_TOTAL "select iftype, hw_net_protocol_type, " \ + "is_roaming, sum(received) as received, sum(sent) as sent, " \ + "ifname, imsi, ground, time_stamp - time_stamp % ? as time_stamp " \ + "from statistics where time_stamp between ? and ? " \ + "group by time_stamp, iftype, ifname, imsi, hw_net_protocol_type, " \ + "is_roaming " \ + "order by time_stamp, iftype, ifname, imsi, hw_net_protocol_type, " \ + "is_roaming" + +#define SELECT_CHUNKS_TOTAL_IFACE "select iftype, hw_net_protocol_type, " \ + "is_roaming, sum(received) as received, sum(sent) as sent, " \ + "ifname, imsi, ground, time_stamp - time_stamp % ? as time_stamp " \ + "from statistics where time_stamp between ? and ? " \ + "and iftype = ? " \ + "group by time_stamp, hw_net_protocol_type, is_roaming, iftype, ifname, imsi " \ + "order by time_stamp, hw_net_protocol_type, is_roaming, iftype, " \ + "ifname, imsi" + +/* INSERT statement */ +#define INSERT_VALUES "insert into statistics " \ + "(binpath, received, sent, time_stamp, " \ + "iftype, is_roaming, hw_net_protocol_type, " \ + "ifname, imsi, ground) " \ + "values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + +static void __finalize_delete(void); + +#define PREPARE_DELETE(stm, query) do { \ + rc = sqlite3_prepare_v2(db, query, -1, &stm, NULL); \ + if (rc != SQLITE_OK) { \ + stm = NULL; \ + __finalize_delete(); \ + STC_LOGE("Failed to prepare \"%s\"query" \ + , query); \ + return rc; \ + } \ +} while (0) + +static void __finalize_select(void); + +#define PREPARE_SELECT(stm, query) do { \ + rc = sqlite3_prepare_v2(db, query, -1, &stm, NULL); \ + if (rc != SQLITE_OK) { \ + stm = NULL; \ + __finalize_select(); \ + STC_LOGE("Failed to prepare \"%s\"query" \ + , query); \ + return rc; \ + } \ +} while (0) + +static void __finalize_insert(void); + +#define PREPARE_INSERT(stm, query) do { \ + rc = sqlite3_prepare_v2(db, query, -1, &stm, NULL); \ + if (rc != SQLITE_OK) { \ + stm = NULL; \ + __finalize_insert(); \ + STC_LOGE("Failed to prepare \"%s\"query" \ + , query); \ + return rc; \ + } \ +} while (0) + +#define FINALIZE(stm) do { \ + if (stm) { \ + sqlite3_finalize(stm); \ + stm = NULL; \ + } \ +} while (0) + +/* DELETE statements */ +/* the following array is strictly ordered + * to find required statement the following code will be used: + * (app ? 1 : 0) | (iftype ? 2 : 0) + */ +static sqlite3_stmt *delete_query[5]; + +/* SELECT statements */ +static sqlite3_stmt *select_for_period; +static sqlite3_stmt *select_for_period_iface; +static sqlite3_stmt *select_chunks; +static sqlite3_stmt *select_chunks_iface; +static sqlite3_stmt *select_app_details; +static sqlite3_stmt *select_app_details_iface; +static sqlite3_stmt *select_chunks_app; +static sqlite3_stmt *select_chunks_app_iface; +static sqlite3_stmt *select_total; +static sqlite3_stmt *select_total_iface; +static sqlite3_stmt *select_chunks_total; +static sqlite3_stmt *select_chunks_total_iface; + +/* INSERT statements */ +static sqlite3_stmt *update_statistics_query; + +static int __prepare_delete(sqlite3 *db) +{ + __STC_LOG_FUNC_ENTER__; + int rc; + static int initialized; + + if (initialized) { + __STC_LOG_FUNC_EXIT__; + return SQLITE_OK; + } + + PREPARE_DELETE(delete_query[0], DELETE_ALL); + PREPARE_DELETE(delete_query[1], DELETE_APP); + PREPARE_DELETE(delete_query[2], DELETE_IFACE); + PREPARE_DELETE(delete_query[3], DELETE_APP_IFACE); + PREPARE_DELETE(delete_query[4], DELETE_FIRST_BY_NUMBER); + + initialized = 1; + __STC_LOG_FUNC_EXIT__; + return rc; +} + +static void __finalize_delete(void) +{ + __STC_LOG_FUNC_ENTER__; + + unsigned int i; + for (i = 0; i < sizeof(delete_query) / sizeof(*delete_query); i++) + FINALIZE(delete_query[i]); + + __STC_LOG_FUNC_EXIT__; +} + +static int __prepare_select(sqlite3 *db) +{ + __STC_LOG_FUNC_ENTER__; + int rc; + static int initialized; + + if (initialized) { + __STC_LOG_FUNC_EXIT__; + return SQLITE_OK; + } + + PREPARE_SELECT(select_for_period, SELECT_FOR_PERIOD); + PREPARE_SELECT(select_for_period_iface, SELECT_FOR_PERIOD_IFACE); + PREPARE_SELECT(select_chunks, SELECT_CHUNKS); + PREPARE_SELECT(select_chunks_iface, SELECT_CHUNKS_IFACE); + PREPARE_SELECT(select_app_details, SELECT_APP_DETAILS); + PREPARE_SELECT(select_app_details_iface, SELECT_APP_DETAILS_IFACE); + PREPARE_SELECT(select_chunks_app, SELECT_CHUNKS_APP); + PREPARE_SELECT(select_chunks_app_iface, SELECT_CHUNKS_APP_IFACE); + PREPARE_SELECT(select_total, SELECT_TOTAL); + PREPARE_SELECT(select_total_iface, SELECT_TOTAL_IFACE); + PREPARE_SELECT(select_chunks_total, SELECT_CHUNKS_TOTAL); + PREPARE_SELECT(select_chunks_total_iface, SELECT_CHUNKS_TOTAL_IFACE); + + initialized = 1; + __STC_LOG_FUNC_EXIT__; + return rc; +} + +static void __finalize_select(void) +{ + __STC_LOG_FUNC_ENTER__; + + FINALIZE(select_for_period); + FINALIZE(select_for_period_iface); + FINALIZE(select_chunks); + FINALIZE(select_chunks_iface); + FINALIZE(select_app_details); + FINALIZE(select_app_details_iface); + FINALIZE(select_chunks_app); + FINALIZE(select_chunks_app_iface); + FINALIZE(select_total); + FINALIZE(select_total_iface); + FINALIZE(select_chunks_total); + FINALIZE(select_chunks_total_iface); + + __STC_LOG_FUNC_EXIT__; +} + +static int __prepare_insert(sqlite3 *db) +{ + __STC_LOG_FUNC_ENTER__; + int rc; + static int initialized; + + if (initialized) { + __STC_LOG_FUNC_EXIT__; + return SQLITE_OK; + } + + PREPARE_INSERT(update_statistics_query, INSERT_VALUES); + + initialized = 1; + __STC_LOG_FUNC_EXIT__; + return rc; +} + +static void __finalize_insert(void) +{ + __STC_LOG_FUNC_ENTER__; + + FINALIZE(update_statistics_query); + + __STC_LOG_FUNC_EXIT__; +} + +static int __is_iftype_defined(const stc_iface_type_e iftype) +{ + __STC_LOG_FUNC_ENTER__; + __STC_LOG_FUNC_EXIT__; + return iftype < STC_IFACE_LAST_ELEM && + iftype > STC_IFACE_UNKNOWN && + iftype != STC_IFACE_ALL; +} + +/* the following array is strictly ordered + * to find required statement the following code will be used: + * (iface ? 1 : 0) | (total ? 2 : 0) | (chunks ? 4 : 0) + */ +static sqlite3_stmt **details_stms[] = { + &select_app_details, + &select_app_details_iface, + &select_total, + &select_total_iface, + &select_chunks_app, + &select_chunks_app_iface, + &select_chunks_total, + &select_chunks_total_iface +}; + +static sqlite3_stmt *__select_statement(const char *app_id, + const table_statistics_select_rule *rule) +{ + __STC_LOG_FUNC_ENTER__; + const int stm_index = __is_iftype_defined(rule->iftype) | + ((strlen(app_id) > 0) ? 0 : 2) | (rule->granularity ? 4 : 0); + STC_LOGD("stm index %d", stm_index); + __STC_LOG_FUNC_EXIT__; + return *details_stms[stm_index]; +} + +stc_error_e table_statistics_reset_first_n_entries(int num) +{ + __STC_LOG_FUNC_ENTER__; + stc_error_e error_code = STC_ERROR_NONE; + + if (!num) { + STC_LOGE("Invalid number of entries"); + return STC_ERROR_INVALID_PARAMETER; + } + + DB_ACTION(sqlite3_bind_int(delete_query[4], 1, num)); + + if (sqlite3_step(delete_query[4]) != SQLITE_DONE) { + STC_LOGE("Failed to drop collected statistics."); + error_code = STC_ERROR_DB_FAILED; + __STC_LOG_FUNC_EXIT__; + } +handle_error: + sqlite3_reset(delete_query[4]); + return error_code; +} + +stc_error_e table_statistics_reset(const table_statistics_reset_rule *rule) +{ + __STC_LOG_FUNC_ENTER__; + sqlite3_stmt *stmt; + stc_error_e error_code = STC_ERROR_NONE; + int pos = 1;/* running through positions where to + bind parameters in the query */ + + if (!rule || !rule->interval) { + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_INVALID_PARAMETER; + } + + /* pick a statement depending on parameters. + See comment for delete_query */ + stmt = delete_query[(rule->app_id ? 1 : 0) | + (rule->iftype != STC_IFACE_UNKNOWN && + rule->iftype != STC_IFACE_LAST_ELEM ? 2 : 0)]; + + if (rule->app_id) + DB_ACTION(sqlite3_bind_text(stmt, pos++, rule->app_id, -1, + SQLITE_TRANSIENT)); + + if (rule->iftype != STC_IFACE_LAST_ELEM && + rule->iftype != STC_IFACE_UNKNOWN) + DB_ACTION(sqlite3_bind_int(stmt, pos++, rule->iftype)); + + DB_ACTION(sqlite3_bind_int64(stmt, pos++, rule->interval->from)); + DB_ACTION(sqlite3_bind_int64(stmt, pos++, rule->interval->to)); + + if (sqlite3_step(stmt) != SQLITE_DONE) { + STC_LOGE("Failed to drop collected statistics."); + error_code = STC_ERROR_DB_FAILED; + __STC_LOG_FUNC_EXIT__; + goto handle_error; + } + + STC_LOGD("Entry deleted successfully."); +handle_error: + sqlite3_reset(stmt); + return error_code; +} + +stc_error_e table_statistics_foreach_app(const table_statistics_select_rule *rule, + table_statistics_info_cb info_cb, + void *user_data) +{ + __STC_LOG_FUNC_ENTER__; + table_statistics_info data; + sqlite3_stmt *stmt; + stc_error_e error_code = STC_ERROR_NONE; + int rc; + int pos = 1;/* running through positions where to + bind parameters in the query */ + stc_db_tm_interval_s interval; + + memset(&data, 0, sizeof(data)); + + if (!rule || !info_cb) { + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_INVALID_PARAMETER; + } + + /* pick a statement depending on parameters */ + if (rule->granularity) { + stmt = __is_iftype_defined(rule->iftype) ? + select_chunks_iface : select_chunks; + + DB_ACTION(sqlite3_bind_int64(stmt, pos++, rule->granularity)); + data.interval = &interval; + } else { + stmt = __is_iftype_defined(rule->iftype) + ? select_for_period_iface : select_for_period; + } + + DB_ACTION(sqlite3_bind_int64(stmt, pos++, rule->from)); + DB_ACTION(sqlite3_bind_int64(stmt, pos++, rule->to)); + + if (__is_iftype_defined(rule->iftype)) { + data.iftype = rule->iftype; + DB_ACTION(sqlite3_bind_int(stmt, pos++, rule->iftype)); + } + + do { + rc = sqlite3_step(stmt); + switch (rc) { + case SQLITE_ROW: + data.app_id = (char *)sqlite3_column_text(stmt, 0); + data.hw_net_protocol_type = sqlite3_column_int(stmt, 1); + data.roaming = sqlite3_column_int(stmt, 2); + data.ground = sqlite3_column_int(stmt, 6); + data.cnt.in_bytes = sqlite3_column_int64(stmt, 3); + data.cnt.out_bytes = sqlite3_column_int64(stmt, 4); + data.imsi = (char *)sqlite3_column_text(stmt, 5); + if (rule->granularity) { + interval.from = sqlite3_column_int64(stmt, 7); + interval.to = interval.from + rule->granularity; + } + + if (info_cb(&data, user_data) == STC_CANCEL) + rc = SQLITE_DONE;/* emulate end of data */ + __STC_LOG_FUNC_EXIT__; + break; + case SQLITE_DONE: + __STC_LOG_FUNC_EXIT__; + break; + case SQLITE_ERROR: + default: + error_code = STC_ERROR_DB_FAILED; + __STC_LOG_FUNC_EXIT__; + break; + } + } while (rc == SQLITE_ROW); + +handle_error: + sqlite3_reset(stmt); + __STC_LOG_FUNC_EXIT__; + return error_code; +} + +stc_error_e table_statistics_per_app(const char *app_id, + table_statistics_select_rule *rule, + table_statistics_info_cb info_cb, + void *user_data) +{ + __STC_LOG_FUNC_ENTER__; + table_statistics_info data; + sqlite3_stmt *stmt; + stc_error_e error_code = STC_ERROR_NONE; + int rc; + int pos = 1;/* running through positions + where to bind parameters in the query */ + stc_db_tm_interval_s interval; + + memset(&data, 0, sizeof(data)); + + if (!rule || !info_cb) { + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_INVALID_PARAMETER; + } + + /* pick a statement depending on parameters. + See comment for details_stms */ + stmt = __select_statement(app_id, rule); + + if (rule->granularity) { + DB_ACTION(sqlite3_bind_int64(stmt, pos++, rule->granularity)); + data.interval = &interval; + } + + DB_ACTION(sqlite3_bind_int64(stmt, pos++, rule->from)); + DB_ACTION(sqlite3_bind_int64(stmt, pos++, rule->to)); + + if (strlen(app_id) > 0) { + DB_ACTION(sqlite3_bind_text(stmt, pos++, app_id, -1, + SQLITE_TRANSIENT)); + data.app_id = (char *)app_id; + } + + if (__is_iftype_defined(rule->iftype)) + DB_ACTION(sqlite3_bind_int(stmt, pos++, rule->iftype)); + + do { + rc = sqlite3_step(stmt); + switch (rc) { + case SQLITE_ROW: + data.iftype = sqlite3_column_int(stmt, 0); + data.hw_net_protocol_type = sqlite3_column_int(stmt, 1); + data.roaming = sqlite3_column_int(stmt, 2); + data.cnt.in_bytes = sqlite3_column_int64(stmt, 3); + data.cnt.out_bytes = sqlite3_column_int64(stmt, 4); + data.ifname = (char *)sqlite3_column_text(stmt, 5); + data.imsi = (char *)sqlite3_column_text(stmt, 6); + + if (rule->granularity) { + interval.from = sqlite3_column_int64(stmt, 7); + interval.to = interval.from + rule->granularity; + } + + if (info_cb(&data, user_data) == STC_CANCEL) + rc = SQLITE_DONE; /* emulate end of data */ + __STC_LOG_FUNC_EXIT__; + break; + case SQLITE_DONE: + __STC_LOG_FUNC_EXIT__; + break; + case SQLITE_ERROR: + default: + error_code = STC_ERROR_DB_FAILED; + __STC_LOG_FUNC_EXIT__; + break; + } + } while (rc == SQLITE_ROW); + +handle_error: + sqlite3_reset(stmt); + __STC_LOG_FUNC_EXIT__; + return error_code; +} + +stc_error_e table_statistics_insert(stc_db_classid_iftype_key *stat_key, + stc_db_app_stats *stat, + time_t last_touch_time) +{ + stc_error_e error_code = STC_ERROR_NONE; + sqlite3_stmt *stmt = update_statistics_query; + stc_hw_net_protocol_type_e hw_net_protocol_type = STC_PROTOCOL_NONE; + + if (!stat->rcv_count && !stat->snd_count) { + error_code = STC_ERROR_INVALID_PARAMETER; + goto handle_error; + } + + DB_ACTION(sqlite3_bind_text(stmt, 1, stat->app_id, -1, + SQLITE_STATIC)); + DB_ACTION(sqlite3_bind_int(stmt, 2, stat->rcv_count)); + DB_ACTION(sqlite3_bind_int(stmt, 3, stat->snd_count)); + DB_ACTION(sqlite3_bind_int64(stmt, 4, + (sqlite3_int64)(last_touch_time))); + DB_ACTION(sqlite3_bind_int(stmt, 5, (int)(stat_key->iftype))); + DB_ACTION(sqlite3_bind_int(stmt, 6, (int)(stat->is_roaming))); + DB_ACTION(sqlite3_bind_int(stmt, 7, (int)hw_net_protocol_type)); + DB_ACTION(sqlite3_bind_text(stmt, 8, stat_key->ifname, -1, + SQLITE_STATIC)); + DB_ACTION(sqlite3_bind_text(stmt, 9, + stat_key->imsi ? stat_key->imsi : "" , -1, + SQLITE_STATIC)); + DB_ACTION(sqlite3_bind_int(stmt, 10, (int)stat->ground)); + + /*we want to reuse tree*/ + stat->rcv_count = 0; + stat->snd_count = 0; + if (sqlite3_step(stmt) != SQLITE_DONE) { + STC_LOGE("Failed to record appstat. %s", + sqlite3_errmsg(stc_db_get_database())); + error_code = STC_ERROR_DB_FAILED; + __STC_LOG_FUNC_EXIT__; + goto handle_error; + } + + STC_LOGE("App stat recorded [%s]", stat->app_id); + +handle_error: + sqlite3_reset(stmt); + return error_code; +} + +/** + * This function will be somewhere consumer and will not be placed in this file. + */ +#if 0 +stc_error_e table_statistics_store_result(app_stat_tree *stats) +{ + time_t current_time; + + pthread_rwlock_rdlock(&stats->guard); + WALK_TREE(stats->tree, print_appstat); + pthread_rwlock_unlock(&stats->guard); + + time(¤t_time); + stats->last_touch_time = current_time; + + /* it's reader only, we don't modify tree, don't reduce it, + * due we want to reuse it in next iteration */ + pthread_rwlock_rdlock(&stats->guard); + g_tree_foreach((GTree *) stats->tree, __store_application_stat, + &stats->last_touch_time); + + pthread_rwlock_unlock(&stats->guard); + flush_quota_table(); + change_db_entries_num_num(g_tree_nnodes((GTree *)stats->tree)); + + return STC_ERROR_NONE; +} +#endif + +stc_error_e table_statistics_prepare(sqlite3 *db) +{ + __STC_LOG_FUNC_ENTER__; + + stc_error_e error_code = STC_ERROR_NONE; + + if (db == NULL) { + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_DB_FAILED; + } + + DB_ACTION(__prepare_delete(db)); + DB_ACTION(__prepare_select(db)); + DB_ACTION(__prepare_insert(db)); + +handle_error: + + __STC_LOG_FUNC_EXIT__; + return error_code; +} + +void table_statistics_finalize(void) +{ + __STC_LOG_FUNC_ENTER__; + __finalize_delete(); + __finalize_select(); + __finalize_insert(); + __STC_LOG_FUNC_EXIT__; +} diff --git a/src/helper/helper-cgroup.c b/src/helper/helper-cgroup.c new file mode 100755 index 0000000..fe05ea1 --- /dev/null +++ b/src/helper/helper-cgroup.c @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "helper-cgroup.h" + +#define RELEASE_AGENT "release_agent" +#define NOTIFY_ON_RELEASE "notify_on_release" + +#define CGROUP_FILE_NAME "cgroup.procs" +#define MAX_PATH_LENGTH 512 + +static int read_uint(FILE *handler, uint32_t *out) +{ + return fscanf(handler, "%u", out); +} + +static int write_uint(FILE *handler, uint32_t number) +{ + _cleanup_free_ char *digit_buf = NULL; + int ret; + + ret = asprintf(&digit_buf, "%u\n", number); + ret_value_errno_msg_if(ret < 0, -ENOMEM, "asprintf failed\n"); + + ret = fputs(digit_buf, handler); + ret_value_errno_msg_if(ret == EOF, errno ? -errno : -EIO, + "Fail to write file"); + + return 0; +} + +static bool cgroup_is_exists(const char *cgroup_full_path) +{ + struct stat stat_buf; + return stat(cgroup_full_path, &stat_buf) == 0; +} + +static int cgroup_create(const char *cgroup_full_path) +{ + if (mkdir(cgroup_full_path, + S_IRUSR | S_IWUSR | S_IRGRP) < 0) + return -errno; + + return 0; +} + +/* + * @desc place pid to cgroup.procs file + * @return 0 in case of success, errno value in case of failure + */ +stc_error_e cgroup_write_pid_fullpath(const char *cgroup_full_path, + const int pid) +{ + int ret; + + if (pid <= 0) { + STC_LOGE("try to write empty pid to %s", cgroup_full_path); + return STC_ERROR_NO_DATA; + } + + ret = cgroup_write_node_uint32(cgroup_full_path, CGROUP_FILE_NAME, + (uint32_t)pid); + + ret_value_msg_if(ret < 0, STC_ERROR_FAIL, + "Failed place all pid to cgroup %s", cgroup_full_path); + return STC_ERROR_NONE; +} + +stc_error_e cgroup_write_pid(const char *cgroup_subsystem, + const char *cgroup_name, const int pid) +{ + char buf[MAX_PATH_LENGTH]; + snprintf(buf, sizeof(buf), "%s/%s", cgroup_subsystem, cgroup_name); + return cgroup_write_pid_fullpath(buf, pid); +} + +stc_error_e cgroup_write_pidtree(const char *cgroup_subsystem, + const char *cgroup_name, const int pid) +{ + char buf[MAX_PATH_LENGTH]; + + /*/proc/%d/task/%d/children */ + char child_buf[21 + MAX_DEC_SIZE(int) + MAX_DEC_SIZE(int)]; + char pidbuf[MAX_DEC_SIZE(int)]; + stc_error_e ret; + + FILE *f; + + snprintf(buf, sizeof(buf), "%s/%s", cgroup_subsystem, cgroup_name); + /* place parent */ + ret = cgroup_write_pid_fullpath(buf, pid); + ret_value_msg_if(ret != STC_ERROR_NONE, ret, + "Failed to put parent process %d into %s cgroup", + pid, cgroup_name); + + snprintf(child_buf, sizeof(child_buf), PROC_TASK_CHILDREN, + pid, pid); + f = fopen(child_buf, "r"); + ret_value_msg_if(!f, STC_ERROR_FAIL, "Failed to get child pids!"); + while (fgets(pidbuf, sizeof(pidbuf), f) != NULL) { + int child_pid = atoi(pidbuf); + if (child_pid < 0) { + STC_LOGE("Invalid child pid!"); + fclose(f); + return STC_ERROR_FAIL; + } + stc_error_e ret = cgroup_write_pid_fullpath(buf, child_pid); + if (ret != STC_ERROR_NONE) { + STC_LOGE("Failed to put parent process %d into %s cgroup", + pid, cgroup_name); + fclose(f); + return ret; + } + } + fclose(f); + return STC_ERROR_NONE; +} + +int cgroup_write_node_uint32(const char *cgroup_name, + const char *file_name, uint32_t value) +{ + char buf[MAX_PATH_LENGTH]; + snprintf(buf, sizeof(buf), "%s/%s", cgroup_name, file_name); + STC_LOGD("cgroup_buf %s, value %d\n", buf, value); + return fwrite_uint(buf, value); +} + +int cgroup_write_node_str(const char *cgroup_name, + const char *file_name, const char *string) +{ + char buf[MAX_PATH_LENGTH]; + snprintf(buf, sizeof(buf), "%s/%s", cgroup_name, file_name); + STC_LOGD("cgroup_buf %s, string %s\n", buf, string); + return fwrite_str(buf, string); +} + +int cgroup_read_node_uint32(const char *cgroup_name, + const char *file_name, uint32_t *value) +{ + char buf[MAX_PATH_LENGTH]; + int ret; + snprintf(buf, sizeof(buf), "%s/%s", cgroup_name, file_name); + ret = fread_uint(buf, value); + STC_LOGD("cgroup_buf %s, value %d\n", buf, *value); + return ret; +} + +int cgroup_make_subdir(const char *parentdir, const char *cgroup_name, + bool *already) +{ + char buf[MAX_PATH_LENGTH]; + bool cgroup_exists; + int ret = 0; + + if (parentdir) + ret = snprintf(buf, sizeof(buf), "%s/%s", + parentdir, cgroup_name); + else + ret = snprintf(buf, sizeof(buf), "%s", + cgroup_name); + + ret_value_msg_if(ret > sizeof(buf), STC_ERROR_FAIL, + "Not enought buffer size for %s%s", + parentdir, cgroup_name); + + cgroup_exists = cgroup_is_exists(buf); + if (!cgroup_exists) { + bool cgroup_remount = false; + + if (parentdir && !strncmp(parentdir, DEFAULT_CGROUP, + sizeof(DEFAULT_CGROUP))) { + ret = mount("tmpfs", DEFAULT_CGROUP, "tmpfs", + MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME, + "mode=755"); + if (ret < 0) { + STC_LOGE("Fail to RW mount cgroup directory. Can't make %s cgroup", cgroup_name); + return STC_ERROR_FAIL; + } + cgroup_remount = true; + } + + ret = cgroup_create(buf); + ret_value_msg_if(ret < 0, STC_ERROR_FAIL, + "Fail to create cgroup %s : err %d", + cgroup_name, errno); + + if (cgroup_remount) { + ret = mount("tmpfs", DEFAULT_CGROUP, "tmpfs", + MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY, + "mode=755"); + if (ret < 0) + STC_LOGD("Fail to RO mount"); + } + } + + if (already) + *already = cgroup_exists; + + return STC_ERROR_NONE; +} + +/* FIXME: tasks is not removed from tasks list */ +int cgroup_remove_pid(const char *cgroup_subsystem, const char *cgroup_name, + const int pid) +{ + char cgroup_tasks_file_path[MAX_PATH_LENGTH]; + FILE *handler = 0; + guint i = 0; + pid_t pid_for_read = 0; + GArray *pids = NULL; + guint pid_count = 0;; + + snprintf(cgroup_tasks_file_path, sizeof(cgroup_tasks_file_path), + "%s/%s/tasks", cgroup_subsystem, cgroup_name); + + handler = fopen(cgroup_tasks_file_path, "r"); + if (!handler) { + STC_LOGE("Read file open failed"); + return -1; + } + + pids = g_array_new(FALSE, FALSE, sizeof(pid_t)); + + while (read_uint(handler, (uint32_t *)&pid_for_read) >= 0) { + if (pid_for_read != pid) { + pids = g_array_append_val(pids, pid_for_read); + ++pid_count; + } + } + + fclose(handler); + + handler = fopen(cgroup_tasks_file_path, "w"); + if (!handler) { + STC_LOGE("Write file open failed"); + return -1; + } + + for (i = 0; i < pid_count; i++) + write_uint(handler, g_array_index(pids, pid_t, i)); + + fclose(handler); + g_array_free(pids, TRUE); + return 0; +} + +int cgroup_set_release_agent(const char *cgroup_subsys, + const char *release_agent) +{ + _cleanup_free_ char *buf = NULL; + int r; + + r = asprintf(&buf, "%s/%s", DEFAULT_CGROUP, cgroup_subsys); + if (r < 0) + return -ENOMEM; + + r = cgroup_write_node_str(buf, RELEASE_AGENT, release_agent); + if (r < 0) + return r; + + return cgroup_write_node_str(buf, NOTIFY_ON_RELEASE, "1"); +} diff --git a/src/helper/helper-cgroup.h b/src/helper/helper-cgroup.h new file mode 100755 index 0000000..e3398af --- /dev/null +++ b/src/helper/helper-cgroup.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Cgroup creation interface + */ +#ifndef __STC_HELPER_CGROUP_H__ +#define __STC_HELPER_CGROUP_H__ + +#include +#include +#include +#include + +#include "stc-manager.h" +#include "helper-file.h" + +#define DEFAULT_CGROUP "/sys/fs/cgroup" +#define CGROUP_NETWORK DEFAULT_CGROUP "/net_cls" +#define PROC_TASK_CHILDREN "/proc/%d/task/%d/children" + +/** + * @desc Get one unsigned int32 value from cgroup + * @param cgroup_name - cgroup path + * @param file_name - cgroup content to write + * @param value - out parameter, value to fill + * @return negative value if error + */ +int cgroup_read_node_uint32(const char *cgroup_name, const char *file_name, + uint32_t *value); + +/** + * @desc Put unsigned int32 value to cgroup, + * @param cgroup_name - cgroup path + * @param file_name - cgroup content to write + * @param value - unsigned int32 data to write + * @return negative value if error + */ +int cgroup_write_node_uint32(const char *cgroup_name, const char *file_name, + uint32_t value); + +/** + * @desc Put value to cgroup, + * @param cgroup_name - cgroup path + * @param file_name - cgroup content to write + * @param string -string to write + * @return negative value if error + */ +int cgroup_write_node_str(const char *cgroup_name, const char *file_name, + const char *string); + +/** + * @desc make cgroup, + * @param parentdir - parent cgroup path + * @param cgroup_name - cgroup subdirectory to write + * @param already - true if subdir already exists, NULL pointer is possible + * as formal argument, in this case it will not be filled + * @return negative value if error + */ +int cgroup_make_subdir(const char *parentdir, const char *cgroup_name, + bool *already); + +/** + * @desc write pid into cgroup_subsystem/cgroup_name file, + * @param cgroup_subsystem path to /sys/fs/cgroup/subsystem + * @param cgroup_name - name in /sys/fs/cgroup/subsystem/ + * @return negative value if error + */ +stc_error_e cgroup_write_pid(const char *cgroup_subsystem, + const char *cgroup_name, const int pid); + +stc_error_e cgroup_write_pid_fullpath(const char *cgroup_full_path, + const int pid); + +/** + * @desc doing the same as @see cgroup_write_pid, + * but also put into cgroup first level child processes + */ +stc_error_e cgroup_write_pidtree(const char *cgroup_subsystem, + const char *cgroup_name, const int pid); + +/** + * @desc this function sets release agent path into cgroup subsystem + * and enables this mechanism + * @param cgroup_sussys - cgroup subsystem name, it's relative path to cgroup, + * relativelly default cgroup path (DEFAULT_CGROUP) + * @param release_agent full path to release agent executable + * @return negative value if error + */ +int cgroup_set_release_agent(const char *cgroup_subsys, + const char *release_agent); + +/** + * @desc get PIDs of processes in a certain cgroup, an allocated array must be provided + * @return 0 if pids were read and array filled + */ +int cgroup_get_pids(const char *name, GArray **pids); + +/** + * @desc remove PID from a certain cgroup tasks file. + * @return 0 if pid removed + */ +int cgroup_remove_pid(const char *cgroup_subsystem, const char *cgroup_name, + const int pid); + +#endif /*__STC_HELPER_CGROUP_H__*/ diff --git a/src/helper/helper-file.c b/src/helper/helper-file.c new file mode 100755 index 0000000..63ad2bd --- /dev/null +++ b/src/helper/helper-file.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "helper-file.h" + +#define BUF_MAX (BUFSIZ) +#define BUF_INC_SIZE (512 << 10) + +int fwrite_str(const char *path, const char *str) +{ + _cleanup_fclose_ FILE *f = NULL; + int ret; + + assert(path); + assert(str); + + f = fopen(path, "w"); + ret_value_errno_msg_if(!f, -errno, + "Fail to open file %s", path); + + ret = fputs(str, f); + ret_value_errno_msg_if(ret == EOF, errno ? -errno : -EIO, + "Fail to write file"); + + return STC_ERROR_NONE; +} + +int fwrite_uint(const char *path, const uint32_t number) +{ + _cleanup_free_ char *digit_buf = NULL; + int ret; + + ret = asprintf(&digit_buf, "%d", number); + ret_value_errno_msg_if(ret < 0, -ENOMEM, + "sprintf failed\n"); + + return fwrite_str(path, digit_buf); +} + +int fread_uint(const char *path, uint32_t *number) +{ + _cleanup_fclose_ FILE *f = NULL; + int ret; + + f = fopen(path, "r"); + ret_value_errno_msg_if(!f, -errno, + "Fail to open %s file.", path); + + ret = fscanf(f, "%u", number); + ret_value_errno_msg_if(ret == EOF, -errno, + "Fail to read file\n"); + + return STC_ERROR_NONE; +} diff --git a/src/helper/helper-file.h b/src/helper/helper-file.h new file mode 100755 index 0000000..c5ff1b8 --- /dev/null +++ b/src/helper/helper-file.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __STC_HELPER_FILE_H__ +#define __STC_HELPER_FILE_H__ + +#include +#include +#include +#include + +#include "stc-manager.h" + +/** + * @desc write string to the file + * @param path - path to the file, str - string is written to the file + * @return negative value if error + */ +int fwrite_str(const char *path, const char *str); + +int fwrite_uint(const char *path, const uint32_t number); + +int fwrite_ulong(const char *path, const unsigned long number); + +int fread_str(const char *path, char **str); + +int fread_uint(const char *path, uint32_t *number); + +int fread_ulong(const char *path, unsigned long *number); + +int fwrite_array(const char *path, const void *array, + const size_t size_of_elem, + const size_t numb_of_elem); + +#endif /*__STC_HELPER_FILE_H__*/ diff --git a/src/helper/helper-net-cls.c b/src/helper/helper-net-cls.c new file mode 100755 index 0000000..a3099bd --- /dev/null +++ b/src/helper/helper-net-cls.c @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#include "helper-cgroup.h" +#include "counter.h" +#include "stc-db.h" +#include "helper-file.h" +#include "helper-net-cls.h" + +#define CUR_CLASSID_PATH "/tmp/cur_classid" +#define CLASSID_FILE_NAME "net_cls.classid" + +typedef GArray task_classid_array; + +static uint32_t __produce_classid(check_classid_used_cb check_classid_cb) +{ + uint32_t classid = STC_RESERVED_CLASSID_MAX; + int classid_test_count; + int ret = fread_uint(CUR_CLASSID_PATH, &classid); + if (ret < 0) + STC_LOGE("Can not read current classid"); + classid += 1; + if (check_classid_cb) + for (classid_test_count = 0; classid_test_count < UINT32_MAX; + ++classid) { + if (!check_classid_cb(classid)) + break; + } + + if (classid_test_count == UINT32_MAX) { + STC_LOGE("there is no available classid due to kernel limitation"); + return STC_UNKNOWN_CLASSID; + } + + ret = fwrite_uint(CUR_CLASSID_PATH, ++classid); + if (ret < 0) + STC_LOGE("Can not write classid"); + + return classid; +} + +static int __place_classid_to_cgroup(const char *cgroup, const char *subdir, + uint32_t *classid, + check_classid_used_cb cb) +{ + char buf[MAX_PATH_LENGTH]; + uint32_t result_classid = (classid && *classid) ? *classid : + __produce_classid(cb); + + /* set classid as out argument */ + if (classid && !*classid) + *classid = result_classid; + + snprintf(buf, sizeof(buf), "%s/%s", cgroup, subdir); + return cgroup_write_node_uint32(buf, CLASSID_FILE_NAME, result_classid); +} + +static uint32_t __get_classid_from_cgroup(const char *cgroup, + const char *subdir) +{ + char buf[MAX_PATH_LENGTH]; + uint32_t classid = STC_UNKNOWN_CLASSID; + snprintf(buf, sizeof(buf), "%s/%s", cgroup, subdir); + + int ret = cgroup_read_node_uint32(buf, CLASSID_FILE_NAME, &classid); + if (ret < 0) + STC_LOGE("Can't read classid from cgroup %s", buf); + return classid; +} + +/* TODO: background tasks update from list */ +static void __add_background_apps(GSList *background_pid_list) +{ + if (background_pid_list == NULL) + return; + + /* remove old list */ + /* add new list */ +} + +static stc_error_e __make_net_cls_cgroup(const char *pkg_name, uint32_t classid, + check_classid_used_cb cb) +{ + stc_error_e ret = STC_ERROR_NONE; + bool exists = false; + + if (pkg_name == NULL) { + STC_LOGE("package name must be not empty"); + return STC_ERROR_INVALID_PARAMETER; + } + + ret = cgroup_make_subdir(PATH_TO_NET_CGROUP_DIR, (char *)pkg_name, + &exists); + ret_value_if(ret < 0, STC_ERROR_FAIL); + + if (!exists) { + ret = __place_classid_to_cgroup(PATH_TO_NET_CGROUP_DIR, + pkg_name, + classid ? &classid : NULL, cb); + ret_value_if(ret < 0, STC_ERROR_FAIL); + } + return ret; +} + +uint32_t get_classid_by_app_id(const char *app_id, int create) +{ + int ret = 0; + bool exists; + uint32_t classid = STC_UNKNOWN_CLASSID; + + if (app_id == NULL) { + STC_LOGE("app_id must be not empty"); + return STC_UNKNOWN_CLASSID; + } + + if (!strcmp(app_id, STC_ALL_APP)) + return STC_ALL_APP_CLASSID; + + if (!strcmp(app_id, TETHERING_APP_NAME)) + return STC_TETHERING_APP_CLASSID; + + if (!strcmp(app_id, STC_BACKGROUND_APP_NAME)) + return STC_BACKGROUND_APP_CLASSID; + + if (!strcmp(app_id, NETWORK_RESTRICTION_APP_NAME)) + return STC_NETWORK_RESTRICTION_APP_CLASSID; + + /* just read */ + if (!create) + classid = __get_classid_from_cgroup(PATH_TO_NET_CGROUP_DIR, + app_id); + + if (classid != STC_UNKNOWN_CLASSID) + return classid; + + ret = cgroup_make_subdir(PATH_TO_NET_CGROUP_DIR, (char *)app_id, + &exists); + if (ret) + goto handle_error; + + if (exists) + classid = __get_classid_from_cgroup(PATH_TO_NET_CGROUP_DIR, + app_id); + else + ret = __place_classid_to_cgroup(PATH_TO_NET_CGROUP_DIR, + (char *)app_id, &classid, NULL); + if (ret) + goto handle_error; + + return classid; + +handle_error: + + STC_LOGE("error_code: [%d]", ret); + return STC_UNKNOWN_CLASSID; +} + +stc_error_e place_pids_to_net_cgroup(const int pid, const char *pkg_name) +{ + char child_buf[21 + MAX_DEC_SIZE(int) + MAX_DEC_SIZE(int)]; + snprintf(child_buf, sizeof(child_buf), PROC_TASK_CHILDREN, pid, pid); + + if (pkg_name == NULL) { + STC_LOGE("package name must be not empty"); + return STC_ERROR_INVALID_PARAMETER; + } + + if (access(child_buf, F_OK)) { + STC_LOGD("%s of %s is not existed", child_buf, pkg_name); + return cgroup_write_pid(PATH_TO_NET_CGROUP_DIR, pkg_name, pid); + } + + return cgroup_write_pidtree(PATH_TO_NET_CGROUP_DIR, pkg_name, pid); +} + +void create_net_background_cgroup(GSList *background_pid_list) +{ + stc_error_e ret = __make_net_cls_cgroup(STC_BACKGROUND_APP_NAME, + STC_BACKGROUND_APP_CLASSID, + NULL); + if (ret == STC_ERROR_NONE) + __add_background_apps(background_pid_list); + else + STC_LOGD("Could not support quota for background applications"); +} + +void add_pid_to_background_cgroup(pid_t pid) +{ + place_pids_to_net_cgroup(pid, STC_BACKGROUND_APP_NAME); +} + +void remove_pid_from_background_cgroup(pid_t pid) +{ + cgroup_remove_pid(PATH_TO_NET_CGROUP_DIR, STC_BACKGROUND_APP_NAME, pid); +} diff --git a/src/helper/helper-net-cls.h b/src/helper/helper-net-cls.h new file mode 100755 index 0000000..b809716 --- /dev/null +++ b/src/helper/helper-net-cls.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __STC_HELPER_NET_CLS_H__ +#define __STC_HELPER_NET_CLS_H__ + +#include +#include +#include + +#include "stc-manager.h" + +#define PATH_TO_NET_CGROUP_DIR CGROUP_NETWORK + +enum { + ERROR_CANT_CREATE_NL_SOCKET = 1, + ERROR_UPDATE_PID_LIST = 2, + ERROR_UPDATE_CLASSIDS_LIST = 3, +}; + +typedef GArray int_array; + +/** + * @desc Get appid from classid task table. At present it is package name. + */ +char *get_app_id_by_pid(const pid_t pid); + +/** + * @desc take classid from net_cls cgroup by appid + * This function converts appid to pkgname. + * @param pkg_name - name of the cgroup + * @param create - in case of true - create cgroup if it's not exists + * @return classid + */ +uint32_t get_classid_by_app_id(const char *app_id, int create); + +typedef gboolean(*check_classid_used_cb)(guint32 classid); + +stc_error_e place_pids_to_net_cgroup(const int pid, const char *pkg_name); + +/** + * @desc this function makes net_cls cgroup and put pids into it. + */ +void create_net_background_cgroup(GSList *background_pid_list); + +void add_pid_to_background_cgroup(pid_t pid); + +void remove_pid_from_background_cgroup(pid_t pid); + +#endif /*__STC_HELPER_NET_CLS_H__*/ diff --git a/src/helper/helper-nfacct-rule.c b/src/helper/helper-nfacct-rule.c new file mode 100755 index 0000000..f2b819f --- /dev/null +++ b/src/helper/helper-nfacct-rule.c @@ -0,0 +1,889 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "counter.h" +#include "helper-nfacct-rule.h" + +#include "configure_stub.h" + +#define IPTABLES "/usr/sbin/iptables" +#define IP6TABLES "/usr/sbin/ip6tables" +#define IPTABLES_CHECK "-C" +#define APPEND "-A" +#define DELETE "-D" +#define INSERT "-I" + +#define NFACCT_NAME_MOD " -m nfacct --nfacct-name %s" +#define REJECT_RULE " -j REJECT" +#define ACCEPT_RULE " -j ACCEPT" +#define OUT_RULE "OUTPUT" +#define IN_RULE "INPUT" +#define FORWARD_RULE "FORWARD" + +/* TODO idea to use the same rule both for BLOCK (REJECT) and WARNING (ACCEPT) */ +#define RULE_APP_OUT "%s -w %s OUTPUT -o %s -m cgroup --cgroup %u %s %s" +#define RULE_APP_IN "%s -w %s INPUT -i %s -m cgroup --cgroup %u %s %s" + + +/* iptables -w [I/A/D] [OUTPUT/FORWARD/INPUT] -o/-i iface -m nfacct --nfacct-name name -j ACCEPT/REJECT */ + +#define RULE_IFACE_OUT "%s -w %s %s -o %s %s %s" +#define RULE_IFACE_IN "%s -w %s %s -i %s %s %s" + + +#define NFNL_SUBSYS_ACCT 7 + +static void prepare_netlink_msg(struct genl *req, int type, int flag) +{ + int seq = time(NULL); + memset(req, 0, sizeof(struct genl)); + req->n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); + req->n.nlmsg_type = (NFNL_SUBSYS_ACCT << 8) | type; + req->n.nlmsg_flags = NLM_F_REQUEST | flag; + req->n.nlmsg_seq = seq; +} + +static void add_value_attr(struct genl *req, const void *data, int len, + int type) +{ + int payload; + /* get tail */ + struct nlattr *na = (struct nlattr *)((char *)req + + NLMSG_ALIGN(req->n.nlmsg_len)); + + na->nla_type = type; + payload = len + NLA_HDRLEN; + na->nla_len = payload; + memcpy(NLA_DATA(na), data, len); + req->n.nlmsg_len += NLMSG_ALIGN(payload); +} + +/* + * following 2 function should be used in combination. + * start_nest_attr returns nlattr structure, which should be completed by + * end_nest_attr, + * before these invocations any number of netlink arguments could be inserted + * */ +static struct nlattr *start_nest_attr(struct genl *req, uint16_t type) +{ + struct nlattr *start = (struct nlattr *)((char *)req + + NLMSG_ALIGN(req->n.nlmsg_len)); + + start->nla_type = NLA_F_NESTED | type; + req->n.nlmsg_len += NLMSG_ALIGN(sizeof(struct nlattr)); + return start; +} + +static void end_nest_attr(struct genl *req, struct nlattr *start) +{ + start->nla_len = (__u16)((char *)req + + NLMSG_ALIGN(req->n.nlmsg_len) - (char *)start); +} + +static void add_string_attr(struct genl *req, const char *str, int type) +{ + add_value_attr(req, str, strlen(str) + 1, type); +} + +static void add_uint64_attr(struct genl *req, const uint64_t v, int type) +{ + add_value_attr(req, &v, sizeof(v), type); +} + +/* macros or templare, due uint64 and uint32 is the same functions */ +static void add_uint32_attr(struct genl *req, const uint32_t v, int type) +{ + add_value_attr(req, &v, sizeof(v), type); +} + +static stc_error_e send_nfacct_request(int sock, struct genl *req) +{ + struct sockaddr_nl nladdr = {.nl_family = AF_NETLINK}; + int ret = sendto(sock, (char *)(&req->n), req->n.nlmsg_len, 0, + (struct sockaddr *)&nladdr, sizeof(nladdr)); + ret_value_msg_if(ret < 0, STC_ERROR_FAIL, + "Failed to send command to get outgoing traffic"); + + return STC_ERROR_NONE; +} + +static stc_error_e nfacct_send_new(nfacct_rule_s *counter) +{ + struct genl req; + + prepare_netlink_msg(&req, NFNL_MSG_ACCT_NEW, NLM_F_CREATE | NLM_F_ACK); + add_string_attr(&req, counter->name, NFACCT_NAME); + + STC_LOGD("counter name %s", counter->name); + + /* padding */ + add_uint64_attr(&req, 0, NFACCT_PKTS); + add_uint64_attr(&req, 0, NFACCT_BYTES); + if (counter->quota) { + STC_LOGD("quota bytes %"PRId64, counter->quota); + + add_uint32_attr(&req, htobe32(NFACCT_F_QUOTA_BYTES), + NFACCT_FLAGS); + add_uint64_attr(&req, htobe64(counter->quota), NFACCT_QUOTA); + } + + return send_nfacct_request(counter->carg->sock, &req); +} + +stc_error_e nfacct_send_del(nfacct_rule_s *counter) +{ + struct genl req; + + STC_LOGD("send remove request for %s", counter->name); + + prepare_netlink_msg(&req, NFNL_MSG_ACCT_DEL, NLM_F_ACK); + add_string_attr(&req, counter->name, NFACCT_NAME); + return send_nfacct_request(counter->carg->sock, &req); +} +#define NFACCT_F_QUOTAS (NFACCT_F_QUOTA_BYTES | NFACCT_F_QUOTA_PKTS) + +static stc_error_e internal_nfacct_send_get(struct counter_arg *carg, + enum nfnl_acct_msg_types get_type, + const char *name, + int mask, int filter) +{ + struct genl req; + struct nlattr *na; + int flag = !name ? NLM_F_DUMP : 0; + prepare_netlink_msg(&req, get_type, + flag); + /* due we don't get counter with quota any where else, + * here we will request just counters by default */ + if (name) + add_string_attr(&req, name, NFACCT_NAME); + + na = start_nest_attr(&req, NFACCT_FILTER); + add_uint32_attr(&req, htonl(mask), + NFACCT_FILTER_ATTR_MASK); + add_uint32_attr(&req, htonl(filter), NFACCT_FILTER_ATTR_VALUE); + end_nest_attr(&req, na); + return send_nfacct_request(carg->sock, &req); +} + +stc_error_e nfacct_send_get_counters(struct counter_arg *carg, const char *name) +{ + /* get and reset countes value */ + return internal_nfacct_send_get(carg, NFNL_MSG_ACCT_GET_CTRZERO, name, + NFACCT_F_QUOTAS, 0); +} + +stc_error_e nfacct_send_get_quotas(struct counter_arg *carg, const char *name) +{ + /* just get counters */ + return internal_nfacct_send_get(carg, NFNL_MSG_ACCT_GET, name, + NFACCT_F_QUOTA_BYTES, + NFACCT_F_QUOTA_BYTES); +} + +stc_error_e nfacct_send_get_all(struct counter_arg *carg) +{ + /* get and reset everything, used when quiting */ + return internal_nfacct_send_get(carg, NFNL_MSG_ACCT_GET_CTRZERO, NULL, + 0, 0); +} + +stc_error_e nfacct_send_get(nfacct_rule_s *rule) +{ + if (rule->intend == NFACCT_BLOCK || rule->intend == NFACCT_WARN) + return nfacct_send_get_quotas(rule->carg, rule->name); + else if (rule->intend == NFACCT_COUNTER) + return nfacct_send_get_counters(rule->carg, rule->name); + + return STC_ERROR_INVALID_PARAMETER; +} + +static nfacct_rule_direction convert_to_iotype(int type) +{ + return (type < NFACCT_COUNTER_LAST_ELEM && + type > NFACCT_COUNTER_UNKNOWN) ? type : NFACCT_COUNTER_UNKNOWN; +} + +static stc_iface_type_e convert_to_iftype(int type) +{ + return (type < STC_IFACE_LAST_ELEM && + type > STC_IFACE_UNKNOWN) ? type : STC_IFACE_UNKNOWN; +} + +bool recreate_counter_by_name(char *cnt_name, nfacct_rule_s *cnt) +{ + char *iftype_part; + char *classid_part; + char *io_part; + char *ifname_part; + char name[NFACCT_NAME_MAX] = {0}; /* parse buffer to avoid cnt_name modification */ + + strncpy(name, cnt_name, sizeof(name) - 1); + + switch (name[0]) { + case 'c': + cnt->intend = NFACCT_COUNTER; + break; + case 'w': + cnt->intend = NFACCT_WARN; + break; + case 'r': + cnt->intend = NFACCT_BLOCK; + break; + case 't': + cnt->intend = NFACCT_TETH_COUNTER; + break; + default: + return false; + } + + STRING_SAVE_COPY(cnt->name, cnt_name); + + if (cnt->intend == NFACCT_TETH_COUNTER) { + char ifname_buf[MAX_IFACE_LENGTH]; + int ifname_len; + stc_iface_type_e iface; + /* tbnep+:seth_w0; means comes by bt go away by mobile interface, + * it's outgoing traffic, due all tethering is mobile databased */ + iftype_part = strchr(name, ':'); + ret_value_msg_if(iftype_part == NULL, + false, "Invalid format of the tethering counter %s", name); + ifname_len = iftype_part - name - 1; + strncpy(ifname_buf, name + 1, ifname_len); /* skip first t */ + ifname_buf[ifname_len] = '\0'; + iface = get_iftype_by_name(ifname_buf); + /* check first part is it datacall */ + if (iface == STC_IFACE_DATACALL) { + strcpy(cnt->ifname, ifname_buf); + cnt->iotype = NFACCT_COUNTER_IN; + } else { + /* +1, due : symbol and till the end of cnt_name */ + strncpy(ifname_buf, iftype_part + 1, MAX_IFACE_LENGTH); + iface = get_iftype_by_name(ifname_buf); + if (iface == STC_IFACE_DATACALL) { + cnt->iotype = NFACCT_COUNTER_OUT; + strcpy(cnt->ifname, ifname_buf); + } + } + + if (cnt->iotype == NFACCT_COUNTER_UNKNOWN) { + STC_LOGE("can't determine tethering direction %s", name); + return false; + } + cnt->iftype = STC_IFACE_DATACALL; + cnt->classid = STC_TETHERING_APP_CLASSID; + return true; + } + + io_part = strtok(name, "_"); + if (io_part != NULL) + cnt->iotype = convert_to_iotype(atoi(io_part + 1)); + else + return false; + + iftype_part = strtok(NULL, "_"); + if (iftype_part != NULL) + cnt->iftype = convert_to_iftype(atoi(iftype_part)); + else + return false; + + classid_part = strtok(NULL, "_"); + if (classid_part != NULL) + cnt->classid = atoi(classid_part); + else { + cnt->classid = STC_ALL_APP_CLASSID; + return cnt->intend == NFACCT_BLOCK ? true : false; + } + + ifname_part = strtok(NULL, "\0"); + if (ifname_part != NULL) + STRING_SAVE_COPY(cnt->ifname, ifname_part); + else + return false; + + return true; +} + +static void _process_answer(struct netlink_serialization_params *params) +{ + struct rtattr *na; + struct rtattr *attr_list[__NFACCT_MAX] = {0}; + struct counter_arg *carg = params->carg; + struct genl *ans = params->ans;; + struct nlmsghdr *nlhdr = &ans->n; + int len = GENLMSG_PAYLOAD(nlhdr); + int ans_len = carg->ans_len; + + if (len == 0) + return; + + /* parse reply message */ + na = (struct rtattr *)GENLMSG_DATA(ans); + + while (NLMSG_OK(nlhdr, ans_len)) { + fill_attribute_list(attr_list, NFACCT_MAX, + na, len); + if (!attr_list[NFACCT_NAME] || + !attr_list[NFACCT_BYTES]) + goto next; + params->eval_attr(attr_list, carg); + +next: + nlhdr = NLMSG_NEXT(nlhdr, ans_len); + if (ans_len < 0) + break; + na = (struct rtattr *)GENLMSG_DATA(nlhdr); + } + + if (params->post_eval_attr) + params->post_eval_attr(carg); +} + +netlink_serialization_command * +netlink_create_command(struct netlink_serialization_params *params) +{ + static netlink_serialization_command command = {0,}; + command.deserialize_answer = _process_answer; + command.params = *params; + return &command; +} + +static unsigned int get_args_number(const char *cmd_buf) +{ + char *str; + unsigned int count = 0; + + for (str = (char *)cmd_buf; *str != '\0'; ++str) { + if (*str == ' ') + ++count; + } + return count; +} + +static void wait_for_rule_cmd(pid_t pid) +{ + int status; + pid_t ret_pid; + if (!pid) { + STC_LOGD("no need to wait"); + return; + } + ret_pid = waitpid(pid, &status, 0); + if (ret_pid < 0) + STC_LOGD("can't wait for a pid %d %d %s", pid, status, + strerror(errno)); +} + +static char* get_cmd_pos(const char *cmd_buf) +{ + char *cmd_pos = strstr(cmd_buf, APPEND); + if (!cmd_pos) + cmd_pos = strstr(cmd_buf, INSERT); + + return cmd_pos; +} + +static bool is_rule_exists(const char *cmd_buf) +{ + size_t buf_len; + char *exec_buf; + char *cmd_pos = get_cmd_pos(cmd_buf); + bool ret = false; + if (!cmd_pos) + return false; + + buf_len = strlen(cmd_buf) + 1; + exec_buf = (char *)malloc(buf_len); + if (!exec_buf) + return false; + + strncpy(exec_buf, cmd_buf, buf_len); + strncpy(exec_buf + (cmd_pos - cmd_buf), IPTABLES_CHECK, + sizeof(IPTABLES_CHECK) - 1); + + STC_LOGD("check rule %s", exec_buf); + + ret = system(exec_buf) == 0; + free(exec_buf); + return ret; +} + +stc_error_e exec_iptables_cmd(const char *cmd_buf, pid_t *cmd_pid) +{ + pid_t pid = fork(); + + if (pid == 0) { + char *cmd; + unsigned int i; + const size_t args_number = get_args_number(cmd_buf); + char *args[args_number + 2]; + int ret; + + STC_LOGD("executing iptables cmd %s in forked process", + cmd_buf); + + ret_value_msg_if(args_number == 0, STC_ERROR_FAIL, "no arguments"); + + if (is_rule_exists(cmd_buf)) { + STC_LOGD("Rule %s already exists", cmd_buf); + exit(0); + } + args[0] = "iptables"; + cmd = strtok((char *)cmd_buf, " "); + ret_value_msg_if(cmd == NULL, STC_ERROR_FAIL, "no arguments"); + for (i = 1; i <= args_number; ++i) + args[i] = strtok(NULL, " "); + + args[i] = NULL; + + ret = execv(cmd, args); + if (ret) + STC_LOGE("Can't execute %s: %s", + cmd_buf, strerror(errno)); + exit(ret); + } + + *cmd_pid = pid; + return STC_ERROR_NONE; +} + +stc_error_e exec_ip6tables_cmd(const char *cmd_buf, pid_t *cmd_pid) +{ + pid_t pid = fork(); + + if (pid == 0) { + char *cmd; + unsigned int i; + const size_t args_number = get_args_number(cmd_buf); + char *args[args_number + 2]; + int ret; + + STC_LOGD("executing ip6tables cmd %s in forked process", + cmd_buf); + + ret_value_msg_if(args_number == 0, STC_ERROR_FAIL, "no arguments"); + + if (is_rule_exists(cmd_buf)) { + STC_LOGD("Rule %s already exists", cmd_buf); + exit(0); + } + args[0] = "ip6tables"; + cmd = strtok((char *)cmd_buf, " "); + ret_value_msg_if(cmd == NULL, STC_ERROR_FAIL, "no arguments"); + for (i = 1; i <= args_number; ++i) + args[i] = strtok(NULL, " "); + + args[i] = NULL; + + ret = execv(cmd, args); + if (ret) + STC_LOGE("Can't execute %s: %s", + cmd_buf, strerror(errno)); + exit(ret); + } + + *cmd_pid = pid; + return STC_ERROR_NONE; +} + +static char *choose_iftype_name(nfacct_rule_s *rule) +{ + return strlen(rule->ifname) != 0 ? rule->ifname : + get_iftype_name(rule->iftype); +} + +static stc_error_e exec_iface_cmd(const char *pattern, const char *cmd, + const char *chain, const char *nfacct, + const char *jump, char *iftype_name, + pid_t *pid) +{ + char block_buf[MAX_PATH_LENGTH]; + int ret; + + ret_value_msg_if(iftype_name == NULL, STC_ERROR_FAIL, + "Invalid network interface name argument"); + + /* iptables rule */ + ret = sprintf(block_buf, pattern, IPTABLES, cmd, chain, + iftype_name, nfacct, jump); + ret_value_msg_if(ret > sizeof(block_buf), STC_ERROR_FAIL, + "Not enough buffer"); + exec_iptables_cmd(block_buf, pid); + + /* ip6tables rule */ + ret = sprintf(block_buf, pattern, IP6TABLES, cmd, chain, + iftype_name, nfacct, jump); + ret_value_msg_if(ret > sizeof(block_buf), STC_ERROR_FAIL, + "Not enough buffer"); + return exec_ip6tables_cmd(block_buf, pid); +} + +static stc_error_e exec_app_cmd(const char *pattern, const char *cmd, + const char *nfacct, const char *jump, + const uint32_t classid, char *iftype_name, + pid_t *pid) +{ + char block_buf[MAX_PATH_LENGTH]; + int ret; + ret_value_msg_if(iftype_name == NULL, STC_ERROR_FAIL, + "Invalid network interface name argument"); + + /* iptables rules */ + ret = sprintf(block_buf, pattern, IPTABLES, cmd, + iftype_name, classid, nfacct, jump); + ret_value_msg_if(ret > sizeof(block_buf), STC_ERROR_FAIL, + "Not enough buffer"); + exec_iptables_cmd(block_buf, pid); + + /* ip6tables rules */ + ret = sprintf(block_buf, pattern, IP6TABLES, cmd, + iftype_name, classid, nfacct, jump); + ret_value_msg_if(ret > sizeof(block_buf), STC_ERROR_FAIL, + "Not enough buffer"); + return exec_ip6tables_cmd(block_buf, pid); +} + +static char *get_iptables_cmd(const nfacct_rule_action action) +{ + if (action == NFACCT_ACTION_APPEND) + return APPEND; + else if (action == NFACCT_ACTION_DELETE) + return DELETE; + else if (action == NFACCT_ACTION_INSERT) + return INSERT; + + return ""; +} + +static char *get_iptables_chain(const nfacct_rule_direction iotype) +{ + if (iotype == NFACCT_COUNTER_IN) + return IN_RULE; + else if (iotype == NFACCT_COUNTER_OUT) + return OUT_RULE; + + return ""; +} + +static char *get_iptables_jump(const nfacct_rule_jump jump) +{ + if (jump == NFACCT_JUMP_ACCEPT) + return ACCEPT_RULE; + else if (jump == NFACCT_JUMP_REJECT) + return REJECT_RULE; + + return ""; +} + +static stc_error_e produce_app_rule(nfacct_rule_s *rule, + const uint64_t send_limit, + const uint64_t rcv_limit, + const nfacct_rule_action action, + const nfacct_rule_jump jump, + const nfacct_rule_direction iotype) +{ + char *set_cmd = get_iptables_cmd(action); + char *jump_cmd = get_iptables_jump(jump); + char nfacct_buf[sizeof(NFACCT_NAME_MOD) + + 3*MAX_DEC_SIZE(int) + 4]; + stc_error_e ret = STC_ERROR_NONE; + pid_t pid = 0; + + /* income part */ + if (iotype & NFACCT_COUNTER_IN) { + rule->quota = rcv_limit; + rule->iotype = NFACCT_COUNTER_IN; + generate_counter_name(rule); + + /* to support quated counter we need nfacct, + * don't use it in case of just block without a limit + * iow, send_limit = 0 and rcv_limit 0 */ + if (action != NFACCT_ACTION_DELETE) { + ret = nfacct_send_del(rule); + ret_value_msg_if(ret != STC_ERROR_NONE, ret, + "can't del quota counter"); + + ret = nfacct_send_new(rule); + ret_value_msg_if(ret != STC_ERROR_NONE, ret, + "can't set nfacct counter"); + keep_counter(rule); + } + + /* we have a counter, let's key in a rule, drop in case of + * send_limit/rcv_limit */ + ret = snprintf(nfacct_buf, sizeof(nfacct_buf), NFACCT_NAME_MOD, + rule->name); + ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0, + STC_ERROR_FAIL, "Not enought buffer"); + + ret = exec_app_cmd(RULE_APP_IN, set_cmd, nfacct_buf, jump_cmd, + rule->classid, choose_iftype_name(rule), + &pid); + ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL, + "Can't set conditional block for ingress" + " traffic, for classid %u, cmd %s, j %s", + rule->classid, set_cmd, jump_cmd); + + /* remove in any case */ + if (action == NFACCT_ACTION_DELETE) { + /* TODO here and everywhere should be not just a del, + * here should be get counted value and than + * set new counter with that value, but it's minor issue, + * due it's not clear when actual counters was stored, + * and based on which value settings made such decition */ + wait_for_rule_cmd(pid); + rule->iptables_rule = nfacct_send_del; + set_finalize_flag(rule); + nfacct_send_get(rule); + ret = nfacct_send_del(rule); + ret_value_msg_if(ret != STC_ERROR_NONE, ret, + "can't del quota counter"); + } + } + + if (iotype & NFACCT_COUNTER_OUT) { + /* outcome part */ + rule->iotype = NFACCT_COUNTER_OUT; + rule->quota = send_limit; + generate_counter_name(rule); + if (action != NFACCT_ACTION_DELETE) { + ret = nfacct_send_del(rule); + ret_value_msg_if(ret != STC_ERROR_NONE, ret, + "can't del quota counter"); + + ret = nfacct_send_new(rule); + ret_value_msg_if(ret != STC_ERROR_NONE, ret, + "can't set quota counter"); + keep_counter(rule); + } + + ret = snprintf(nfacct_buf, sizeof(nfacct_buf), NFACCT_NAME_MOD, + rule->name); + ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0, + STC_ERROR_FAIL, "Not enought buffer"); + + ret = exec_app_cmd(RULE_APP_OUT, set_cmd, nfacct_buf, jump_cmd, + rule->classid, choose_iftype_name(rule), + &pid); + ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL, + "Can't set conditional block for engress" + " traffic, for classid %u, cmd %s, j %s", + rule->classid, set_cmd, jump_cmd); + if (action == NFACCT_ACTION_DELETE) { + wait_for_rule_cmd(pid); + rule->iptables_rule = nfacct_send_del; + /* not effective, it's better to replace + * set_finalize_flag by set_property, + * due keep_counter it necessary only for + * setting iptables_rule */ + set_finalize_flag(rule); + nfacct_send_get(rule); + ret = nfacct_send_del(rule); + ret_value_msg_if(ret != STC_ERROR_NONE, ret, + "can't del quota counter"); + } + } + return STC_ERROR_NONE; +} + +static stc_error_e produce_iface_rule(nfacct_rule_s *rule, + const uint64_t send_limit, + const uint64_t rcv_limit, + const nfacct_rule_action action, + const nfacct_rule_jump jump, + const nfacct_rule_direction iotype) +{ + char *set_cmd = get_iptables_cmd(action); + char *jump_cmd = get_iptables_jump(jump); + char nfacct_buf[sizeof(NFACCT_NAME_MOD) + + 3*MAX_DEC_SIZE(int) + 4]; + stc_error_e ret; + pid_t pid = 0; + + if (iotype & NFACCT_COUNTER_IN) { + /* income part */ + rule->iotype = NFACCT_COUNTER_IN; + rule->quota = rcv_limit; + generate_counter_name(rule); + + if (action != NFACCT_ACTION_DELETE) { + /* send delete comman in case of creation, + * because nfacct doesn't reset value for nfacct quota + * in case of quota existing */ + ret = nfacct_send_del(rule); + ret_value_msg_if(ret != STC_ERROR_NONE, ret, + "can't del quota counter"); + + ret = nfacct_send_new(rule); + ret_value_msg_if(ret != STC_ERROR_NONE, ret, + "can't set quota counter"); + keep_counter(rule); + } + + ret = snprintf(nfacct_buf, sizeof(nfacct_buf), + NFACCT_NAME_MOD, rule->name); + ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0, + STC_ERROR_FAIL, "Not enought buffer"); + + ret = exec_iface_cmd(RULE_IFACE_IN, set_cmd, + get_iptables_chain(rule->iotype), + nfacct_buf, jump_cmd, + choose_iftype_name(rule), &pid); + ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL, + "Can't set conditional block for ingress" + " traffic, for iftype %d, cmd %s, j %s", + rule->iftype, set_cmd, jump_cmd); + + /* for tethering */ + if (rule->intend == NFACCT_WARN || + rule->intend == NFACCT_BLOCK) { + /* RULE_IFACE_OUT is not a misprint here */ + wait_for_rule_cmd(pid); + ret = exec_iface_cmd(RULE_IFACE_IN, set_cmd, + FORWARD_RULE, nfacct_buf, jump_cmd, + choose_iftype_name(rule), &pid); + ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL, + "Can't set forward rule for ingress " + "traffic, for iftype %d, cmd %s, j %s", + rule->iftype, set_cmd, jump_cmd); + } + /* tethering */ + + if (action == NFACCT_ACTION_DELETE) { + wait_for_rule_cmd(pid); + rule->iptables_rule = nfacct_send_del; + set_finalize_flag(rule); + nfacct_send_get(rule); + ret = nfacct_send_del(rule); + ret_value_msg_if(ret != STC_ERROR_NONE, ret, + "can't del quota counter"); + } + } + + if (iotype & NFACCT_COUNTER_OUT) { + /* outcome part */ + rule->iotype = NFACCT_COUNTER_OUT; + rule->quota = send_limit; + generate_counter_name(rule); + + if (action != NFACCT_ACTION_DELETE) { + /* send delete comman in case of creation, + * because nfacct doesn't reset value for nfacct quota + * in case of quota existing */ + ret = nfacct_send_del(rule); + ret_value_msg_if(ret != STC_ERROR_NONE, ret, + "can't del quota counter"); + + ret = nfacct_send_new(rule); + ret_value_msg_if(ret != STC_ERROR_NONE, ret, + "can't set quota counter"); + keep_counter(rule); + } + + ret = snprintf(nfacct_buf, sizeof(nfacct_buf), + NFACCT_NAME_MOD, rule->name); + ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0, + STC_ERROR_FAIL, "Not enough buffer"); + + wait_for_rule_cmd(pid); + ret = exec_iface_cmd(RULE_IFACE_OUT, set_cmd, OUT_RULE, + nfacct_buf, jump_cmd, + choose_iftype_name(rule), &pid); + ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL, + "Can't set conditional block for " + "engress traffic, for iftype %d, cmd %s, j %s", + rule->iftype, set_cmd, jump_cmd); + /* for tethering */ + if (rule->intend == NFACCT_WARN || + rule->intend == NFACCT_BLOCK) { + wait_for_rule_cmd(pid); + ret = exec_iface_cmd(RULE_IFACE_OUT, set_cmd, + FORWARD_RULE, nfacct_buf, jump_cmd, + choose_iftype_name(rule), &pid); + ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL, + "Can't set forward rule for engress " + "traffic, for iftype %d, cmd %s, j %s", + rule->iftype, set_cmd, jump_cmd); + } + /* tethering */ + + if (action == NFACCT_ACTION_DELETE) { + wait_for_rule_cmd(pid); + rule->iptables_rule = nfacct_send_del; + set_finalize_flag(rule); + nfacct_send_get(rule); + ret = nfacct_send_del(rule); + ret_value_msg_if(ret != STC_ERROR_NONE, ret, + "can't del quota counter"); + } + } + return STC_ERROR_NONE; +} + +stc_error_e produce_net_rule(nfacct_rule_s *rule, + const uint64_t send_limit, + const uint64_t rcv_limit, + const nfacct_rule_action action, + const nfacct_rule_jump jump, + const nfacct_rule_direction iotype) +{ + stc_error_e ret = STC_ERROR_NONE; + + if (action == NFACCT_ACTION_APPEND && rule->intend == NFACCT_WARN + && !send_limit && !rcv_limit) + return STC_ERROR_NONE; + + if (rule->classid != STC_ALL_APP_CLASSID && + rule->classid != STC_TETHERING_APP_CLASSID) + ret = produce_app_rule(rule, send_limit, + rcv_limit, action, jump, iotype); + else + ret = produce_iface_rule(rule, send_limit, rcv_limit, + action, jump, iotype); + + return ret; +} + +void generate_counter_name(nfacct_rule_s *counter) +{ + char warn_symbol = 'c'; + if (!strlen(counter->ifname)) { + char *iftype_name = get_iftype_name(counter->iftype); + /* trace counter name, maybe name was already generated */ + ret_msg_if(iftype_name == NULL, + "Can't get interface name for counter %s, iftype %d)!", + counter->name, counter->iftype); + STRING_SAVE_COPY(counter->ifname, iftype_name); + } + + if (counter->intend == NFACCT_WARN) + warn_symbol = 'w'; + else if (counter->intend == NFACCT_BLOCK) + warn_symbol = 'r'; + snprintf(counter->name, NFACCT_NAME_MAX, "%c%d_%d_%d_%s", + warn_symbol, counter->iotype, counter->iftype, + counter->classid, counter->ifname); +} + diff --git a/src/helper/helper-nfacct-rule.h b/src/helper/helper-nfacct-rule.h new file mode 100755 index 0000000..7ce4ed7 --- /dev/null +++ b/src/helper/helper-nfacct-rule.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __STC_NFACCT_RULE_H__ +#define __STC_NFACCT_RULE_H__ + +#include "stc-db.h" + +#include +#include +#include + +#include "helper-nl.h" + +#define NFACCT_NAME_MAX 32 + +typedef enum { + NFACCT_COUNTER_UNKNOWN, + NFACCT_COUNTER_IN = (1 << 1), + NFACCT_COUNTER_OUT = (1 << 2), + NFACCT_COUNTER_LAST_ELEM +} nfacct_rule_direction; + +typedef enum { + NFACCT_ACTION_UNKNOWN, + NFACCT_ACTION_APPEND, + NFACCT_ACTION_DELETE, + NFACCT_ACTION_INSERT, + NFACCT_ACTION_LAST_ELEM, +} nfacct_rule_action; + +typedef enum { + NFACCT_JUMP_UNKNOWN, + NFACCT_JUMP_ACCEPT, + NFACCT_JUMP_REJECT, + NFACCT_JUMP_LAST_ELEM, +} nfacct_rule_jump; + +typedef enum { + NFACCT_COUNTER, + NFACCT_WARN, + NFACCT_BLOCK, + NFACCT_TETH_COUNTER, + NFACCT_RULE_LAST_ELEM, +} nfacct_rule_intend; + +enum nfnl_acct_flags { + NFACCT_F_QUOTA_PKTS = (1 << 0), + NFACCT_F_QUOTA_BYTES = (1 << 1), + NFACCT_F_OVERQUOTA = (1 << 2), /* can't be set from userspace */ +}; + +/** + * it's better to have + * base nfacct_rule with following fields: + * name, ifname, pid, classid, iftype, intend, carg, iptables_rule + * + * and inherited nfacct_rule_counter and nfacct_rule_restriction + * with additional field: + * quota, quota_id, roaming, rst_state + * + * But ANSI C doesn't support inheritance. + */ +struct nfacct_rule { + char name[NFACCT_NAME_MAX]; + char ifname[MAX_IFACE_LENGTH]; + + pid_t pid; + uint32_t classid; + stc_iface_type_e iftype; + nfacct_rule_direction iotype; + nfacct_rule_intend intend; + struct counter_arg *carg; + stc_error_e(*iptables_rule)(struct nfacct_rule *counter); + uint64_t quota; + int quota_id; + stc_roaming_type_e roaming; + stc_restriction_state_e rst_state; + + /** + * in most cases jump is evalutation based + * on intend, but not always + */ + nfacct_rule_jump jump; +}; + +typedef struct nfacct_rule nfacct_rule_s; + +struct counter_arg; + +void generate_counter_name(nfacct_rule_s *counter); +bool recreate_counter_by_name(char *cnt_name, nfacct_rule_s *counter); + +stc_error_e nfacct_send_get_all(struct counter_arg *carg); +stc_error_e nfacct_send_get_counters(struct counter_arg *carg, + const char *name); +stc_error_e nfacct_send_get(nfacct_rule_s *rule); +stc_error_e nfacct_send_del(nfacct_rule_s *counter); + +stc_error_e exec_iptables_cmd(const char *cmd_buf, pid_t *pid); +stc_error_e produce_net_rule(nfacct_rule_s *rule, + const uint64_t send_limit, + const uint64_t rcv_limit, + const nfacct_rule_action action, + const nfacct_rule_jump jump, + const nfacct_rule_direction iotype); + +netlink_serialization_command * +netlink_create_command(struct netlink_serialization_params *params); + +#endif /* __STC_NFACCT_RULE_H__ */ + diff --git a/src/helper/helper-nl.c b/src/helper/helper-nl.c new file mode 100755 index 0000000..b43ff2f --- /dev/null +++ b/src/helper/helper-nl.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "helper-nl.h" + +#include +#include +#include +#include + +/** + * create_netlink(): Create netlink socket and returns it. + * Returns: Created socket on success and -1 on failure. + */ +int create_netlink(int protocol, uint32_t groups) +{ + /** + * TODO it's one socket, in future make set of sockets + * unique for protocol and groups + */ + int sock; + sock = socket(PF_NETLINK, SOCK_RAW, protocol); + if (sock < 0) + return -EINVAL; + + struct sockaddr_nl src_addr = { 0, }; + + src_addr.nl_family = AF_NETLINK; + src_addr.nl_groups = groups; + + if (bind(sock, (struct sockaddr *)&src_addr, sizeof(src_addr)) < 0) { + close(sock); + return -1; + } + + return sock; +} + +void fill_attribute_list(struct rtattr **atb, const int max_len, + struct rtattr *rt_na, int rt_len) +{ + int i = 0; + while (RTA_OK(rt_na, rt_len)) { + if (rt_na->rta_type <= max_len) + atb[rt_na->rta_type] = rt_na; + + rt_na = RTA_NEXT(rt_na, rt_len); + ++i; + if (i >= max_len) + break; + } +} + +/* read netlink message from socket + * return opaque pointer to genl structure + */ +int read_netlink(int sock, void *buf, size_t len) +{ + ssize_t ret; + struct sockaddr_nl addr; + struct iovec iov = { + .iov_base = buf, + .iov_len = len, + }; + struct msghdr msg = { + .msg_name = &addr, + .msg_namelen = sizeof(struct sockaddr_nl), + .msg_iov = &iov, + .msg_iovlen = 1, + .msg_control = NULL, + .msg_controllen = 0, + .msg_flags = 0, + }; + ret = recvmsg(sock, &msg, 0); + if (ret == -1) + return ret; + + if (msg.msg_flags & MSG_TRUNC) { + errno = ENOSPC; + return -1; + } + + if (msg.msg_namelen != sizeof(struct sockaddr_nl)) { + errno = EINVAL; + return -1; + } + + return ret; +} diff --git a/src/helper/helper-nl.h b/src/helper/helper-nl.h new file mode 100755 index 0000000..fddb2aa --- /dev/null +++ b/src/helper/helper-nl.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __STC_HELPER_NL_H__ +#define __STC_HELPER_NL_H__ + +//#include "app-stat.h" + +#include +#include +#include +#include +#include +#include + +#define NLA_BUF_MAX 65560 /*(65 * 1024) - used in tc_common, + we'll do the same */ + +/*TODO: move to common place and rewrite because it's from TC*/ +#define NLMSG_TAIL(nmsg) \ + ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) + +/*TODO remove unused code */ +typedef struct { + struct nlmsghdr n; + struct tcmsg t; + char buf[NLA_BUF_MAX]; +} rt_param; + +void put_attr(rt_param *arg, int type, const void *data, int data_len); + +/* + * Generic macros for dealing with netlink sockets. Might be duplicated + * elsewhere. It is recommended that commercial grade applications use + * libnl or libnetlink and use the interfaces provided by the library + */ +#define GENLMSG_PAYLOAD(glh) (NLMSG_PAYLOAD(glh, 0) - GENL_HDRLEN) +#define GENLMSG_DATA(glh) ((void *)(NLMSG_DATA(glh) + GENL_HDRLEN)) +#define NLA_DATA(na) ((void *)((char*)(na) + NLA_HDRLEN)) + +#define NETLINK_BUF_SIZE 16536 + +enum nfnl_acct_msg_types { + NFNL_MSG_ACCT_NEW, + NFNL_MSG_ACCT_GET, + NFNL_MSG_ACCT_GET_CTRZERO, + NFNL_MSG_ACCT_DEL, + NFNL_MSG_ACCT_MAX +}; + +enum nfnl_acct_type { + NFACCT_UNSPEC, + NFACCT_NAME, + NFACCT_PKTS, + NFACCT_BYTES, + NFACCT_USE, + NFACCT_FLAGS, + NFACCT_QUOTA, + NFACCT_FILTER, + __NFACCT_MAX +}; + +enum nfnl_attr_filter_type { + NFACCT_FILTER_ATTR_UNSPEC, + NFACCT_FILTER_ATTR_MASK, + NFACCT_FILTER_ATTR_VALUE, + __NFACCT_FILTER_ATTR_MAX +}; + +#define NFACCT_MAX (__NFACCT_MAX - 1) + +struct genl { + struct nlmsghdr n; + struct genlmsghdr g; + char buf[NETLINK_BUF_SIZE]; +}; + +struct netlink_serialization_params { + int direction; + struct genl *ans; + struct counter_arg *carg; + int (*eval_attr)(struct rtattr *attr_list[__NFACCT_MAX], + void *user_data); + int (*post_eval_attr)(void *user_data); +}; + +typedef struct { + void (*deserialize_answer)(struct netlink_serialization_params *params); + void (*finalize)(struct netlink_serialization_params *params); + struct netlink_serialization_params params; +} netlink_serialization_command; + +int create_netlink(int protocol, uint32_t groups); +int read_netlink(int sock, void *buf, size_t len); + +void fill_attribute_list(struct rtattr **atb, const int max_len, + struct rtattr *rt_na, int rt_len); + +#endif /* __STC_HELPER_NL_H__ */ diff --git a/src/helper/helper-restriction.c b/src/helper/helper-restriction.c new file mode 100755 index 0000000..fb15856 --- /dev/null +++ b/src/helper/helper-restriction.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file restriction-helper.c + * @desc Helper restriction functions + */ + +#include "stc-manager.h" +#include "stc-restriction.h" +#include "transmission.h" + +stc_restriction_state_e +convert_to_restriction_state(const enum traffic_restriction_type rst_type) +{ + switch (rst_type) { + case RST_SET: + return STC_RESTRICTION_ACTIVATED; + case RST_UNSET: + return STC_RESTRICTION_REMOVED; + case RST_EXCLUDE: + return STC_RESTRICTION_EXCLUDED; + default: + return STC_RESTRICTION_UNKNOWN; + } +} diff --git a/src/helper/helper-restriction.h b/src/helper/helper-restriction.h new file mode 100755 index 0000000..51b959e --- /dev/null +++ b/src/helper/helper-restriction.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file helper-restriction.h + * @desc Helper restriction functions + */ + +#ifndef __STC_HELPER_RESTRICTION_H__ +#define __STC_HELPER_RESTRICTION_H__ + +#include "stc-manager.h" +#include "stc-restriction.h" +#include "transmission.h" + +stc_restriction_state_e +convert_to_restriction_state(const enum traffic_restriction_type rst_type); + +#endif /* __STC_HELPER_RESTRICTION_H__ */ diff --git a/src/monitor/include/stc-application-lifecycle.h b/src/monitor/include/stc-application-lifecycle.h new file mode 100644 index 0000000..8fa34af --- /dev/null +++ b/src/monitor/include/stc-application-lifecycle.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __STC_APPLICATION_LIFECYCLE_H__ +#define __STC_APPLICATION_LIFECYCLE_H__ + +#include "stc-error.h" +#include "stc-manager.h" +#include "stc-manager-gdbus.h" +#include "stc-manager-util.h" +#include "stc-monitor.h" + +stc_error_e stc_application_lifecycle_monitor_init(stc_s *stc); +stc_error_e stc_application_lifecycle_monitor_deinit(stc_s *stc); + +#endif /* __STC_APPLICATION_LIFECYCLE_H__ */ diff --git a/src/monitor/include/stc-default-connection.h b/src/monitor/include/stc-default-connection.h new file mode 100644 index 0000000..ec5b2dc --- /dev/null +++ b/src/monitor/include/stc-default-connection.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __STC_DEFAULT_CONNECTION_H__ +#define __STC_DEFAULT_CONNECTION_H__ + +#include +#include "stc-error.h" +#include "stc-manager.h" +#include "stc-manager-gdbus.h" +#include "stc-manager-util.h" + +/** + * @brief default connection information will be fetched from net-config + */ +typedef struct { + gchar *path; /* to identify each connection uniquely */ + + /* profile info */ + stc_iface_type_e type; + gchar *ifname; + gboolean roaming; /* cellular profile only else it is always false */ +} default_connection_s; + +stc_error_e stc_default_connection_monitor_init(stc_s *stc); +stc_error_e stc_default_connection_monitor_deinit(stc_s *stc); + +stc_iface_type_e stc_default_connection_get_type(void); +gchar *stc_default_connection_get_ifname(void); +gboolean stc_default_connection_get_roaming(void); +default_connection_s *stc_get_default_connection(void); + +#endif /* __STC_DEFAULT_CONNECTION_H__ */ diff --git a/src/monitor/include/stc-monitor.h b/src/monitor/include/stc-monitor.h new file mode 100644 index 0000000..c3d2db9 --- /dev/null +++ b/src/monitor/include/stc-monitor.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __STC_MONITOR_H__ +#define __STC_MONITOR_H__ + +#include +#include "stc-error.h" +#include "stc-manager.h" +#include "stc-restriction.h" +#include "stc-manager-util.h" +#include "table-restrictions.h" +#include "helper-nl.h" +#include "netlink-restriction.h" + +/* 10 seconds */ +#define CONTR_TIMER_INTERVAL 10 + +/** + * @brief key for processes tree + */ +typedef struct { + stc_app_state_e ground; /**< application state foreground/background */ +} stc_process_value_s; + +/** + * @brief value for processes tree + */ +typedef struct { + pid_t pid; /**< process id */ + GArray *childs; /**< child pids */ +} stc_process_key_s; + +/** + * @brief key for apps tree + */ +typedef struct { + gchar *pkg_id; /**< package id */ + gchar *app_id; /**< application id */ +} stc_app_key_s; + +/** + * @brief value for apps tree + */ +typedef struct { + uint32_t classid; /**< classid for a package */ + stc_app_type_e type; /**< type of application */ + stc_data_counter_s data_usage; + stc_data_counter_s counter; + GTree *processes; /**< applications instances */ +} stc_app_value_s; + +/** + * @brief key for rstn_rules tree + */ +typedef struct { + gchar *app_id; + gchar *ifname; + gchar *imsi; + stc_iface_type_e iftype; + stc_roaming_type_e roaming; +} stc_rstn_key_s; + +/** + * @brief value for rstn_rules tree + */ +typedef struct { + uint64_t restriction_id; + uint32_t classid; + stc_restriction_state_e rst_state; + stc_data_counter_s limit; + stc_data_counter_s warn_limit; + stc_data_counter_s counter; + gboolean in_limit_reached; + gboolean out_limit_reached; +} stc_rstn_value_s; + +/** + * @brief structure to store system info + */ +typedef struct { + int contr_sock; /**< socket used for getting kernel counters */ + guint contr_timer_id; /**< timer id for periodically getting kernel counters */ + guint contr_gsource_id; + stc_data_counter_s du_curr; /**< current data usage */ + GTree *rstns; /**< restriction rules */ + gboolean rstns_tree_updated; + GTree *apps; /**< monitored applications */ + gboolean apps_tree_updated; + GSList *background_pids; /**< list of background pids */ +} stc_system_s; + +/** + * @brief initializes stc monitor module + */ +stc_error_e stc_monitor_init(void); + +/** + * @brief deinitializes stc monitor module + */ +stc_error_e stc_monitor_deinit(void); + +/** + * @brief creates an application entry + */ +stc_error_e stc_monitor_application_add(const stc_app_key_s app_key, + const stc_app_value_s app_value); + +/** + * @brief associates process to an application + */ +stc_error_e stc_monitor_process_add(const stc_app_key_s app_key, + const stc_process_key_s proc_key, + const stc_process_value_s proc_value); + +/** + * @brief removes associated process from respective application + */ +stc_error_e stc_monitor_process_remove(pid_t pid); + +/** + * @brief updates process's ground attribute + */ +stc_error_e stc_monitor_process_update_ground(const stc_app_key_s app_key, + const stc_process_key_s proc_key, + stc_app_state_e ground); + +void stc_monitor_update_rstn_by_default_connection(void *default_connection); + +stc_error_e stc_monitor_rstns_tree_add(const table_restrictions_info *info); + +stc_error_e stc_monitor_rstns_tree_remove(const table_restrictions_info *info); + +int stc_monitor_get_counter_socket(void); + +#endif /* __STC_MONITOR_H__ */ diff --git a/src/monitor/stc-application-lifecycle.c b/src/monitor/stc-application-lifecycle.c new file mode 100755 index 0000000..2b1243c --- /dev/null +++ b/src/monitor/stc-application-lifecycle.c @@ -0,0 +1,446 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "stc-application-lifecycle.h" + +/* + * AUL + */ +#define AUL_APP_STATUS_DBUS_PATH "/Org/Tizen/Aul/AppStatus" +#define AUL_APP_STATUS_DBUS_SIGNAL_INTERFACE "org.tizen.aul.AppStatus" +#define AUL_APP_STATUS_BUS_NAME AUL_APP_STATUS_DBUS_SIGNAL_INTERFACE + +#define AUL_APP_STATUS_DBUS_LAUNCH_REQUEST "AppLaunch" +#define AUL_APP_STATUS_DBUS_LAUNCH_REQUEST_TYPE "(isss)" + +#define AUL_APP_STATUS_DBUS_STATUS_CHANGE "AppStatusChange" +#define AUL_APP_STATUS_DBUS_STATUS_CHANGE_TYPE "(issss)" + +#define AUL_APP_STATUS_DBUS_GROUP "AppGroup" +#define AUL_APP_STATUS_DBUS_GROUP_TYPE "(iis)" + +#define AUL_APP_STATUS_DBUS_TERMINATED "AppTerminated" +#define AUL_APP_STATUS_DBUS_TERMINATED_TYPE "(i)" + +typedef enum { + STC_CMD_NONE, + STC_CMD_SET_FOREGRD, + STC_CMD_SET_BACKGRD, + STC_CMD_SET_APP_LAUNCHED, + STC_CMD_SET_SERVICE_LAUNCHED, + STC_CMD_SET_TERMINATED, + STC_CMD_MAX_ELEM +} stc_cmd_type_e; + +typedef struct { + guint sub_id; + const gchar *path; + const gchar *interface; + const gchar *member; + const gchar *param_type; + GDBusSignalCallback callback; + gpointer user_data; +} signal_map_s; + +static stc_error_e __stc_manager_app_status_changed(stc_cmd_type_e cmd, + pid_t pid, + gchar *app_id, + gchar *pkg_id, + stc_app_type_e app_type) +{ + __STC_LOG_FUNC_ENTER__; + stc_error_e ret = STC_ERROR_NONE; + + switch (cmd) { + case STC_CMD_SET_FOREGRD: + { + stc_app_key_s app_key; + stc_app_value_s app_value; + stc_process_key_s proc_key; + stc_process_value_s proc_value; + + memset(&app_key, 0, sizeof(stc_app_key_s)); + memset(&app_value, 0, sizeof(stc_app_value_s)); + memset(&proc_key, 0, sizeof(stc_process_key_s)); + memset(&proc_value, 0, sizeof(stc_process_value_s)); + + app_key.pkg_id = g_strdup(pkg_id); + app_key.app_id = g_strdup(app_id); + + app_value.type = app_type; + app_value.processes = NULL; + + proc_key.pid = pid; + + proc_value.ground = STC_APP_STATE_FOREGROUND; + + stc_monitor_application_add(app_key, app_value); + stc_monitor_process_add(app_key, proc_key, proc_value); + stc_monitor_process_update_ground(app_key, proc_key, + STC_APP_STATE_FOREGROUND); + FREE(app_key.pkg_id); + FREE(app_key.app_id); + break; + } + case STC_CMD_SET_BACKGRD: + { + stc_app_key_s app_key; + stc_app_value_s app_value; + stc_process_key_s proc_key; + stc_process_value_s proc_value; + + memset(&app_key, 0, sizeof(stc_app_key_s)); + memset(&app_value, 0, sizeof(stc_app_value_s)); + memset(&proc_key, 0, sizeof(stc_process_key_s)); + memset(&proc_value, 0, sizeof(stc_process_value_s)); + + app_key.pkg_id = g_strdup(pkg_id); + app_key.app_id = g_strdup(app_id); + + app_value.type = app_type; + app_value.processes = NULL; + + proc_key.pid = pid; + + proc_value.ground = STC_APP_STATE_BACKGROUND; + + stc_monitor_application_add(app_key, app_value); + stc_monitor_process_add(app_key, proc_key, proc_value); + stc_monitor_process_update_ground(app_key, proc_key, + STC_APP_STATE_BACKGROUND); + + FREE(app_key.pkg_id); + FREE(app_key.app_id); + break; + } + case STC_CMD_SET_APP_LAUNCHED: + { + stc_app_key_s app_key; + stc_app_value_s app_value; + stc_process_key_s proc_key; + stc_process_value_s proc_value; + + memset(&app_key, 0, sizeof(stc_app_key_s)); + memset(&app_value, 0, sizeof(stc_app_value_s)); + memset(&proc_key, 0, sizeof(stc_process_key_s)); + memset(&proc_value, 0, sizeof(stc_process_value_s)); + + app_key.pkg_id = g_strdup(pkg_id); + app_key.app_id = g_strdup(app_id); + + app_value.type = app_type; + app_value.processes = NULL; + + proc_key.pid = pid; + + proc_value.ground = STC_APP_STATE_UNKNOWN; + + stc_monitor_application_add(app_key, app_value); + stc_monitor_process_add(app_key, proc_key, proc_value); + + FREE(app_key.pkg_id); + FREE(app_key.app_id); + break; + } + case STC_CMD_SET_SERVICE_LAUNCHED: + { + stc_app_key_s app_key; + stc_app_value_s app_value; + stc_process_key_s proc_key; + stc_process_value_s proc_value; + + memset(&app_key, 0, sizeof(stc_app_key_s)); + memset(&app_value, 0, sizeof(stc_app_value_s)); + memset(&proc_key, 0, sizeof(stc_process_key_s)); + memset(&proc_value, 0, sizeof(stc_process_value_s)); + + app_key.pkg_id = g_strdup(pkg_id); + app_key.app_id = g_strdup(app_id); + + app_value.type = app_type; + app_value.processes = NULL; + + proc_key.pid = pid; + + proc_value.ground = STC_APP_STATE_BACKGROUND; + + stc_monitor_application_add(app_key, app_value); + stc_monitor_process_add(app_key, proc_key, proc_value); + + FREE(app_key.pkg_id); + FREE(app_key.app_id); + break; + } + case STC_CMD_SET_TERMINATED: + { + stc_monitor_process_remove(pid); + break; + } + default: + STC_LOGE("Unhandled command"); + ret = STC_ERROR_INVALID_PARAMETER; + } + + __STC_LOG_FUNC_EXIT__; + return ret; +} + +static void __stc_gdbus_handle_aul_launch(GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + __STC_LOG_FUNC_ENTER__; + pid_t pid; + stc_cmd_type_e status; + stc_app_type_e apptype; + gchar *appid, *pkgid, *pkgtype; + + RETURN_IF_DBUS_TYPE_MISMATCH(parameters, + AUL_APP_STATUS_DBUS_LAUNCH_REQUEST_TYPE); + + g_variant_get(parameters, AUL_APP_STATUS_DBUS_LAUNCH_REQUEST_TYPE, + &pid, &appid, &pkgid, &pkgtype); + + if (!strncmp(pkgtype, "svc", 3)) { + apptype = STC_APP_TYPE_SERVICE; + status = STC_CMD_SET_SERVICE_LAUNCHED; + + } else if (!strncmp(pkgtype, "ui", 2)) { + apptype = STC_APP_TYPE_GUI; + status = STC_CMD_SET_APP_LAUNCHED; + + } else if (!strncmp(pkgtype, "widget", 6)) { + apptype = STC_APP_TYPE_WIDGET; + status = STC_CMD_SET_APP_LAUNCHED; + + } else if (!strncmp(pkgtype, "watch", 5)) { + apptype = STC_APP_TYPE_WATCH; + status = STC_CMD_SET_APP_LAUNCHED; + + } else { + __STC_LOG_FUNC_EXIT__; + goto handle_error; + } + + __stc_manager_app_status_changed(status, pid, appid, pkgid, apptype); + + __STC_LOG_FUNC_EXIT__; +handle_error: + FREE(appid); + FREE(pkgid); + FREE(pkgtype); +} + +static void __stc_gdbus_handle_aul_changestate(GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + __STC_LOG_FUNC_ENTER__; + pid_t pid; + stc_cmd_type_e status; + stc_app_type_e apptype; + gchar *appid, *pkgid, *statstr, *pkgtype; + + RETURN_IF_DBUS_TYPE_MISMATCH(parameters, + AUL_APP_STATUS_DBUS_STATUS_CHANGE_TYPE); + + g_variant_get(parameters, AUL_APP_STATUS_DBUS_STATUS_CHANGE_TYPE, + &pid, &appid, &pkgid, &statstr, &pkgtype); + + if (!strncmp(statstr, "fg", 2)) { + status = STC_CMD_SET_FOREGRD; + } else if (!strncmp(statstr, "bg", 2)) { + status = STC_CMD_SET_BACKGRD; + } else { + __STC_LOG_FUNC_EXIT__; + goto handle_error; + } + + if (!strncmp(pkgtype, "svc", 3)) + apptype = STC_APP_TYPE_SERVICE; + else if (!strncmp(pkgtype, "widget", 6)) + apptype = STC_APP_TYPE_WIDGET; + else if (!strncmp(pkgtype, "watch", 5)) + apptype = STC_APP_TYPE_WATCH; + else + apptype = STC_APP_TYPE_GUI; + + __stc_manager_app_status_changed(status, pid, appid, pkgid, apptype); + + __STC_LOG_FUNC_EXIT__; +handle_error: + FREE(appid); + FREE(pkgid); + FREE(statstr); + FREE(pkgtype); +} + +static void __stc_gdbus_handle_aul_group(GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + __STC_LOG_FUNC_ENTER__; + pid_t ownerpid, childpid; + gchar *appid; + + RETURN_IF_DBUS_TYPE_MISMATCH(parameters, + AUL_APP_STATUS_DBUS_GROUP_TYPE); + + g_variant_get(parameters, AUL_APP_STATUS_DBUS_GROUP_TYPE, + &ownerpid, &childpid, &appid); + + if (ownerpid == childpid) { + STC_LOGD("Skip merge, when one app %d makes multiple window.", + ownerpid); + __STC_LOG_FUNC_EXIT__; + goto handle_error; + } + + STC_LOGD("received process grouping : owner %d, child %d, previous appid %s", + ownerpid, childpid, appid); + + /** + * TODO: app_set_group(ownerpid, childpid, appid) + */ + + __STC_LOG_FUNC_EXIT__; +handle_error: + FREE(appid); +} + +static void __stc_gdbus_handle_aul_terminated(GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + __STC_LOG_FUNC_ENTER__; + pid_t pid; + stc_cmd_type_e status = STC_CMD_SET_TERMINATED; + + RETURN_IF_DBUS_TYPE_MISMATCH(parameters, + AUL_APP_STATUS_DBUS_TERMINATED_TYPE); + + g_variant_get(parameters, AUL_APP_STATUS_DBUS_TERMINATED_TYPE, + &pid); + + __stc_manager_app_status_changed(status, pid, NULL, NULL, + STC_APP_TYPE_NONE); + + __STC_LOG_FUNC_EXIT__; +} + +signal_map_s signal_map[] = { + + /* AMD DBUS */ + { + 0, + AUL_APP_STATUS_DBUS_PATH, + AUL_APP_STATUS_DBUS_SIGNAL_INTERFACE, + AUL_APP_STATUS_DBUS_LAUNCH_REQUEST, + AUL_APP_STATUS_DBUS_LAUNCH_REQUEST_TYPE, + __stc_gdbus_handle_aul_launch, + NULL + }, + { + 0, + AUL_APP_STATUS_DBUS_PATH, + AUL_APP_STATUS_DBUS_SIGNAL_INTERFACE, + AUL_APP_STATUS_DBUS_STATUS_CHANGE, + AUL_APP_STATUS_DBUS_STATUS_CHANGE_TYPE, + __stc_gdbus_handle_aul_changestate, + NULL + }, + { + 0, + AUL_APP_STATUS_DBUS_PATH, + AUL_APP_STATUS_DBUS_SIGNAL_INTERFACE, + AUL_APP_STATUS_DBUS_GROUP, + AUL_APP_STATUS_DBUS_GROUP_TYPE, + __stc_gdbus_handle_aul_group, + NULL + }, + { + 0, + AUL_APP_STATUS_DBUS_PATH, + AUL_APP_STATUS_DBUS_SIGNAL_INTERFACE, + AUL_APP_STATUS_DBUS_TERMINATED, + AUL_APP_STATUS_DBUS_TERMINATED_TYPE, + __stc_gdbus_handle_aul_terminated, + NULL + }, + { + 0, + NULL, + NULL, + NULL, + NULL + } +}; + +stc_error_e stc_application_lifecycle_monitor_init(stc_s *stc) +{ + guint i = 0; + ret_value_msg_if(stc == NULL, STC_ERROR_INVALID_PARAMETER, "failed to get stc data"); + + for (i = 0; signal_map[i].member != NULL; i++) { + signal_map[i].sub_id = + stc_manager_gdbus_subscribe_signal(stc->connection, + NULL, + signal_map[i].interface, + signal_map[i].member, + signal_map[i].path, + NULL, + G_DBUS_SIGNAL_FLAGS_NONE, + signal_map[i].callback, + signal_map[i].user_data, + NULL); + STC_LOGI("Successfully subscribed [%s] signal", + signal_map[i].member); + } + + return STC_ERROR_NONE; +} + +stc_error_e stc_application_lifecycle_monitor_deinit(stc_s *stc) +{ + guint i = 0; + ret_value_msg_if(stc == NULL, STC_ERROR_INVALID_PARAMETER, "failed to get stc data"); + + for (i = 0; signal_map[i].member != NULL; i++) { + stc_manager_gdbus_unsubscribe_signal(stc->connection, + signal_map[i].sub_id); + signal_map[i].sub_id = 0; + STC_LOGD("Successfully unsubscribed [%s] signal", + signal_map[i].member); + } + + return STC_ERROR_NONE; +} diff --git a/src/monitor/stc-default-connection.c b/src/monitor/stc-default-connection.c new file mode 100755 index 0000000..9aad6fb --- /dev/null +++ b/src/monitor/stc-default-connection.c @@ -0,0 +1,378 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "stc-monitor.h" +#include "stc-default-connection.h" + +#define CONNMAN_SERVICE "net.connman" +#define CONNMAN_PATH "/net/connman" + +#define CONNMAN_MANAGER_PATH "/" +#define CONNMAN_MANAGER_INTERFACE CONNMAN_SERVICE ".Manager" +#define CONNMAN_SERVICE_INTERFACE CONNMAN_SERVICE ".Service" + +#define CONNMAN_CELLULAR_SERVICE_PROFILE_PREFIX CONNMAN_PATH "/service/cellular_" +#define CONNMAN_WIFI_SERVICE_PROFILE_PREFIX CONNMAN_PATH "/service/wifi_" +#define CONNMAN_ETHERNET_SERVICE_PROFILE_PREFIX CONNMAN_PATH "/service/ethernet_" +#define CONNMAN_BLUETOOTH_SERVICE_PROFILE_PREFIX CONNMAN_PATH "/service/bluetooth_" + +#define CONNMAN_SIGNAL_PROPERTY_CHANGED "PropertyChanged" + +default_connection_s g_default_connection; +guint g_default_connection_sub_id = 0; + +static void __print_default_connection_info(void) +{ + STC_LOGI("============= default connection info ============"); + STC_LOGI("path [%s]", g_default_connection.path); + STC_LOGI("type [%d]", g_default_connection.type); + STC_LOGI("ifname [%s]", g_default_connection.ifname); + STC_LOGI("roaming [%u]", g_default_connection.roaming ? TRUE : FALSE); + STC_LOGI("=================================================="); +} + +static void __reset_default_connection_data(void) +{ + FREE(g_default_connection.path); + FREE(g_default_connection.ifname); + g_default_connection.type = STC_IFACE_UNKNOWN; + g_default_connection.roaming = FALSE; +} + +static gboolean __is_cellular_internet_profile(const char *profile) +{ + const char internet_suffix[] = "_1"; + + if (profile == NULL) + return FALSE; + + if (g_str_has_prefix(profile, CONNMAN_CELLULAR_SERVICE_PROFILE_PREFIX) + == TRUE) { + char *suffix = strrchr(profile, '_'); + if (g_strcmp0(suffix, internet_suffix) == 0) + return TRUE; + } + + return FALSE; +} + +static gboolean __is_cellular_profile(const char *profile) +{ + if (profile == NULL) + return FALSE; + + return g_str_has_prefix(profile, + CONNMAN_CELLULAR_SERVICE_PROFILE_PREFIX); +} + +static gboolean __is_wifi_profile(const char *profile) +{ + if (profile == NULL) + return FALSE; + + return g_str_has_prefix(profile, CONNMAN_WIFI_SERVICE_PROFILE_PREFIX); +} + +static gboolean __is_ethernet_profile(const char *profile) +{ + if (profile == NULL) + return FALSE; + + return g_str_has_prefix(profile, + CONNMAN_ETHERNET_SERVICE_PROFILE_PREFIX); +} + +static gboolean __is_bluetooth_profile(const char *profile) +{ + if (profile == NULL) + return FALSE; + + return g_str_has_prefix(profile, + CONNMAN_BLUETOOTH_SERVICE_PROFILE_PREFIX); +} + +static gboolean __is_connected(GVariantIter *array) +{ + gboolean is_connected = FALSE; + GVariant *variant = NULL; + gchar *key = NULL; + + while (g_variant_iter_loop(array, "{sv}", &key, &variant)) { + if (g_strcmp0(key, "State") != 0) + continue; + + if (g_variant_is_of_type(variant, G_VARIANT_TYPE_STRING)) { + const gchar *state = NULL; + + state = g_variant_get_string(variant, NULL); + if (g_strcmp0(state, "ready") == 0 || + g_strcmp0(state, "online") == 0) + is_connected = TRUE; + } + + g_free(key); + g_variant_unref(variant); + break; + } + + return is_connected; +} + +static void __get_default_connection_info(GDBusConnection *connection, + const char *object_path) +{ + GVariant *message = NULL; + GVariantIter *iter = NULL; + GVariant *variant = NULL; + gchar *key = NULL; + + if (object_path == NULL) { + STC_LOGE("Object path is NULL"); + return; + } + + message = stc_manager_gdbus_call_sync(connection, + CONNMAN_SERVICE, + object_path, + CONNMAN_SERVICE_INTERFACE, + "GetProperties", NULL); + if (message == NULL) { + STC_LOGE("Failed to get services informations"); + goto done; + } + + g_variant_get(message, "(a{sv})", &iter); + if (iter == NULL) { + STC_LOGE("Profile %s doesn't exist", object_path); + goto done; + } + + while (g_variant_iter_loop(iter, "{sv}", &key, &variant)) { + if (g_strcmp0(key, "Ethernet") == 0) { + GVariantIter *iter1 = NULL; + GVariant *variant1 = NULL; + gchar *key1 = NULL; + + g_variant_get(variant, "a{sv}", &iter1); + if (iter1 == NULL) + continue; + + while (g_variant_iter_loop(iter1, "{sv}", &key1, + &variant1)) { + if (g_strcmp0(key1, "Interface") == 0) { + const gchar *value = + g_variant_get_string(variant1, + NULL); + g_default_connection.ifname = + g_strdup(value); + } + } + + g_variant_iter_free(iter1); + + } else if (g_strcmp0(key, "Roaming") == 0) { + gboolean roaming = 0; + + if (g_variant_is_of_type(variant, + G_VARIANT_TYPE_BOOLEAN)) { + roaming = g_variant_get_boolean(variant); + g_default_connection.roaming = roaming; + } + } + } + +done: + if (iter) + g_variant_iter_free(iter); + + if (message) + g_variant_unref(message); + + return; +} + +static stc_error_e __get_default_profile(GDBusConnection *connection) +{ + GVariant *message = NULL; + GVariantIter *iter = NULL; + GVariantIter *next; + gchar *object_path; + + message = stc_manager_gdbus_call_sync(connection, + CONNMAN_SERVICE, + CONNMAN_MANAGER_PATH, + CONNMAN_MANAGER_INTERFACE, + "GetServices", NULL); + if (message == NULL) { + STC_LOGE("Failed to get profiles"); + return STC_ERROR_FAIL; + } + + g_variant_get(message, "(a(oa{sv}))", &iter); + while (g_variant_iter_loop(iter, "(oa{sv})", &object_path, &next)) { + if (object_path == NULL) + continue; + + if (__is_cellular_profile(object_path) && + !__is_cellular_internet_profile(object_path)) + continue; + + if (__is_connected(next) == TRUE) { + /* reset old default connection data */ + FREE(g_default_connection.path); + FREE(g_default_connection.ifname); + g_default_connection.type = STC_IFACE_UNKNOWN; + g_default_connection.roaming = FALSE; + + g_default_connection.path = g_strdup(object_path); + g_free(object_path); + g_variant_iter_free(next); + break; + } + } + + g_variant_iter_free(iter); + g_variant_unref(message); + + if (__is_cellular_profile(g_default_connection.path)) + g_default_connection.type = STC_IFACE_DATACALL; + else if (__is_wifi_profile(g_default_connection.path)) + g_default_connection.type = STC_IFACE_WIFI; + else if (__is_ethernet_profile(g_default_connection.path)) + g_default_connection.type = STC_IFACE_WIRED; + else if (__is_bluetooth_profile(g_default_connection.path)) + g_default_connection.type = STC_IFACE_BLUETOOTH; + else + g_default_connection.type = STC_IFACE_UNKNOWN; + + __get_default_connection_info(connection, g_default_connection.path); + + __print_default_connection_info(); + + stc_monitor_update_rstn_by_default_connection(&g_default_connection); + + return STC_ERROR_NONE; +} + +static void _service_signal_cb(GDBusConnection *conn, + const gchar *name, const gchar *path, + const gchar *interface, const gchar *sig, + GVariant *param, gpointer user_data) +{ + gchar *sigvalue = NULL; + GVariant *variant = NULL; + stc_s *stc = (stc_s *)stc_get_manager(); + ret_msg_if(stc == NULL, "failed to get stc data"); + + if (path == NULL || param == NULL) + goto done; + + g_variant_get(param, "(sv)", &sigvalue, &variant); + if (sigvalue == NULL) + goto done; + + if (g_strcmp0(sig, CONNMAN_SIGNAL_PROPERTY_CHANGED) != 0) + goto done; + + if (g_strcmp0(sigvalue, "State") == 0 && + g_variant_is_of_type(variant, G_VARIANT_TYPE_STRING)) { + const gchar *state = NULL; + + state = g_variant_get_string(variant, NULL); + if (g_strcmp0(state, "ready") == 0 || + g_strcmp0(state, "online") == 0) { + if (g_strcmp0(g_default_connection.path, path)) { + __reset_default_connection_data(); + __get_default_profile(stc->connection); + } + } else { + if (g_strcmp0(g_default_connection.path, path) == 0) { + __reset_default_connection_data(); + __get_default_profile(stc->connection); + } + } + } else if (g_strcmp0(sigvalue, "Roaming") == 0) { + if (g_strcmp0(g_default_connection.path, path) == 0) { + gboolean roaming = 0; + + if (g_variant_is_of_type(variant, + G_VARIANT_TYPE_BOOLEAN)) { + roaming = g_variant_get_boolean(variant); + g_default_connection.roaming = roaming; + } + } + } else { + ;//Do nothing + } +done: + if (sigvalue) + g_free(sigvalue); + + if (variant) + g_variant_unref(variant); + + return; +} + +stc_error_e stc_default_connection_monitor_init(stc_s *stc) +{ + ret_value_msg_if(stc == NULL, STC_ERROR_INVALID_PARAMETER, "failed to get stc data"); + + __get_default_profile(stc->connection); + g_default_connection_sub_id = + stc_manager_gdbus_subscribe_signal(stc->connection, + CONNMAN_SERVICE, + CONNMAN_SERVICE_INTERFACE, + CONNMAN_SIGNAL_PROPERTY_CHANGED, + NULL, NULL, + G_DBUS_SIGNAL_FLAGS_NONE, + _service_signal_cb, + NULL, NULL); + + STC_LOGI("Successfully subscribed connman [%s] signal", CONNMAN_SIGNAL_PROPERTY_CHANGED); + return STC_ERROR_NONE; +} + +stc_error_e stc_default_connection_monitor_deinit(stc_s *stc) +{ + ret_value_msg_if(stc == NULL, STC_ERROR_INVALID_PARAMETER, "failed to get stc data"); + + stc_manager_gdbus_unsubscribe_signal(stc->connection, + g_default_connection_sub_id); + FREE(g_default_connection.path); + FREE(g_default_connection.ifname); + return STC_ERROR_NONE; +} + +stc_iface_type_e stc_default_connection_get_type(void) +{ + return g_default_connection.type; +} + +gchar *stc_default_connection_get_ifname(void) +{ + return g_strdup(g_default_connection.ifname); +} + +gboolean stc_default_connection_get_roaming(void) +{ + return g_default_connection.roaming; +} + +default_connection_s *stc_get_default_connection(void) +{ + return &g_default_connection; +} diff --git a/src/monitor/stc-monitor.c b/src/monitor/stc-monitor.c new file mode 100755 index 0000000..a2b662e --- /dev/null +++ b/src/monitor/stc-monitor.c @@ -0,0 +1,1488 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "stc-default-connection.h" +#include "helper-nl.h" +#include "helper-nfacct-rule.h" +#include "helper-net-cls.h" +#include "counter.h" +#include "table-statistics.h" +#include "table-counters.h" +#include "stc-monitor.h" + +typedef struct { + stc_app_key_s *app_key; + stc_process_key_s *proc_key; + gboolean entry_removed; +} remove_pid_context_s; + +typedef struct { + struct nfacct_rule *counter; + uint64_t bytes; + gboolean in_limit_reached; + gboolean out_limit_reached; +} classid_bytes_context_s; + +static stc_system_s *g_system = NULL; + +static nfacct_rule_jump __get_jump_by_intend(struct nfacct_rule *counter) +{ + if (counter->intend == NFACCT_WARN) + return NFACCT_JUMP_ACCEPT; + else if (counter->intend == NFACCT_BLOCK) + return NFACCT_JUMP_REJECT; + + return NFACCT_JUMP_UNKNOWN; +} + +static stc_error_e __add_iptables_in(struct nfacct_rule *counter) +{ + return produce_net_rule(counter, 0, 0, + NFACCT_ACTION_INSERT, __get_jump_by_intend(counter), + NFACCT_COUNTER_IN); +} + +static stc_error_e __add_iptables_out(struct nfacct_rule *counter) +{ + return produce_net_rule(counter, 0, 0, + NFACCT_ACTION_INSERT, __get_jump_by_intend(counter), + NFACCT_COUNTER_OUT); +} + +static stc_error_e __del_iptables_in(struct nfacct_rule *counter) +{ + return produce_net_rule(counter, 0, 0, + NFACCT_ACTION_DELETE, __get_jump_by_intend(counter), + NFACCT_COUNTER_IN); +} + +static stc_error_e __del_iptables_out(struct nfacct_rule *counter) +{ + return produce_net_rule(counter, 0, 0, + NFACCT_ACTION_DELETE, __get_jump_by_intend(counter), + NFACCT_COUNTER_OUT); +} + +static int __processes_tree_key_compare(gconstpointer a, gconstpointer b, + gpointer UNUSED user_data) +{ + stc_process_key_s *key_a = (stc_process_key_s *)a; + stc_process_key_s *key_b = (stc_process_key_s *)b; + + return key_a->pid - key_b->pid; +} + +static void __processes_tree_value_free(gpointer data) +{ + stc_process_value_s *value = (stc_process_value_s *)data; + + FREE(value); +} + +static void __processes_tree_key_free(gpointer data) +{ + stc_process_key_s *key = (stc_process_key_s *)data; + + FREE(key); +} + +static int __apps_tree_key_compare(gconstpointer a, gconstpointer b, + gpointer UNUSED user_data) +{ + stc_app_key_s *key_a = (stc_app_key_s *)a; + stc_app_key_s *key_b = (stc_app_key_s *)b; + gint ret; + + ret = g_strcmp0(key_a->pkg_id, key_b->pkg_id); + if (ret) + return ret; + + return g_strcmp0(key_a->app_id, key_b->app_id); +} + +static void __apps_tree_value_free(gpointer data) +{ + stc_app_value_s *value = (stc_app_value_s *)data; + + g_tree_destroy(value->processes); + value->processes = NULL; + + FREE(value); +} + +static void __apps_tree_key_free(gpointer data) +{ + stc_app_key_s *key = (stc_app_key_s *)data; + + g_free(key->pkg_id); + g_free(key->app_id); + FREE(key); +} + +static int __rstns_tree_key_compare(gconstpointer a, gconstpointer b, + gpointer UNUSED user_data) +{ + stc_rstn_key_s *key_a = (stc_rstn_key_s *)a; + stc_rstn_key_s *key_b = (stc_rstn_key_s *)b; + int ret; + + ret = g_strcmp0(key_a->app_id, key_b->app_id); + if (ret != 0) + return ret; + + ret = g_strcmp0(key_a->ifname, key_b->ifname); + if (ret != 0) + return ret; + + ret = g_strcmp0(key_a->imsi, key_b->imsi); + if (ret != 0) + return ret; + + ret = key_a->iftype - key_b->iftype; + if (ret != 0) + return ret; + + return 0; +} + +static void __rstns_tree_value_free(gpointer data) +{ + stc_rstn_value_s *value = (stc_rstn_value_s *)data; + + FREE(value); +} + +static void __rstns_tree_key_free(gpointer data) +{ + stc_rstn_key_s *key = (stc_rstn_key_s *)data; + + FREE(key->app_id); + FREE(key->ifname); + FREE(key->imsi); + FREE(key); +} + +static gboolean __processes_tree_foreach_print(gpointer key, gpointer value, + gpointer data) +{ + stc_process_key_s *proc_key = (stc_process_key_s *)key; + stc_process_value_s *proc_value = (stc_process_value_s *)value; + + STC_LOGD("Process entry => PID [%d], Ground state [%d]", + proc_key->pid, proc_value->ground); + return FALSE; +} + +static void __processes_tree_printall(GTree *processes) +{ + g_tree_foreach(processes, __processes_tree_foreach_print, NULL); +} + +static gboolean __apps_tree_foreach_print(gpointer key, gpointer value, + gpointer data) +{ + stc_app_key_s *app_key = (stc_app_key_s *)key; + stc_app_value_s *app_value = (stc_app_value_s *)value; + + STC_LOGD("Application info => Pkg ID [%s], App ID [%s]," + " Type [%d], classid [%d]," + " counter [ in (%llu), out (%llu)]", + app_key->pkg_id, app_key->app_id, + app_value->type, app_value->classid, + app_value->data_usage.in_bytes, app_value->data_usage.out_bytes); + + __processes_tree_printall(app_value->processes); + return FALSE; +} + +static void __apps_tree_printall(void) +{ + g_tree_foreach(g_system->apps, __apps_tree_foreach_print, NULL); +} + +static gboolean __apps_tree_foreach_remove_pid(gpointer key, gpointer value, + gpointer data) +{ + remove_pid_context_s *context = (remove_pid_context_s *)data; + stc_app_value_s *app_value = (stc_app_value_s *)value; + + if (!g_tree_remove(app_value->processes, context->proc_key)) { + STC_LOGD("key not found"); + return FALSE; + } + + context->entry_removed = TRUE; + context->app_key = (stc_app_key_s *)key; + + return TRUE; +} + +static stc_app_value_s * __application_lookup(GTree *apps, + const stc_app_key_s *key) +{ + stc_app_value_s *lookup; + + ret_value_msg_if(apps == NULL, NULL, "apps is null!"); + + lookup = g_tree_lookup(apps, key); + + return lookup; +} + +static stc_process_value_s * __process_lookup(GTree *processes, + const stc_process_key_s *key) +{ + stc_process_value_s *lookup; + + ret_value_msg_if(processes == NULL, NULL, "processes is null!"); + + lookup = g_tree_lookup(processes, key); + + return lookup; +} + +static gboolean __processes_tree_check_empty(gpointer key, gpointer value, + gpointer data) +{ + guint *pid_count = (guint *)data; + (*pid_count)++; + return TRUE; +} + +static gboolean __add_application_monitor(gpointer key, gpointer value, + gpointer data) +{ + stc_app_value_s *app_value = (stc_app_value_s *)value; + default_connection_s *connection = (default_connection_s *)data; + stc_s *stc = stc_get_manager(); + + if (stc && connection && connection->ifname) { + struct nfacct_rule counter; + + if (!stc->carg) { + stc->carg = MALLOC0(counter_arg_s, 1); + stc->carg->sock = stc_monitor_get_counter_socket(); + } + + memset(&counter, 0, sizeof(struct nfacct_rule)); + + counter.carg = stc->carg; + counter.classid = app_value->classid; + counter.intend = NFACCT_COUNTER; + g_strlcpy(counter.ifname, connection->ifname, MAX_IFACE_LENGTH); + + __add_iptables_in(&counter); + __add_iptables_out(&counter); + } + + return FALSE; +} + +static gboolean __remove_application_monitor(gpointer key, gpointer value, + gpointer data) +{ + stc_app_value_s *app_value = (stc_app_value_s *)value; + default_connection_s *connection = (default_connection_s *)data; + stc_s *stc = stc_get_manager(); + + if (stc && connection && connection->ifname) { + struct nfacct_rule counter; + + if (!stc->carg) { + stc->carg = MALLOC0(counter_arg_s, 1); + stc->carg->sock = stc_monitor_get_counter_socket(); + } + + memset(&counter, 0, sizeof(struct nfacct_rule)); + + counter.carg = stc->carg; + counter.classid = app_value->classid; + counter.intend = NFACCT_COUNTER; + g_strlcpy(counter.ifname, connection->ifname, MAX_IFACE_LENGTH); + + __del_iptables_in(&counter); + __del_iptables_out(&counter); + } + + return FALSE; +} + +static void __print_rstn(stc_rstn_key_s *rstn_key, stc_rstn_value_s *rstn_value) +{ + STC_LOGI("rstn info => rstn_id [%llu], " + "app_id [%s], classid [%lu], ifname [%s], " + "iftype [%d], rst_state [%d], " + "limit [ in (%llu), out (%llu)], " + "warn_limit [ in (%llu), out (%llu)], " + "counter [ in (%llu), out (%llu)], " + "roaming [%d], imsi [%s]", + rstn_value->restriction_id, + rstn_key->app_id, rstn_value->classid , rstn_key->ifname, + rstn_key->iftype, rstn_value->rst_state, + rstn_value->limit.in_bytes, rstn_value->limit.out_bytes, + rstn_value->warn_limit.in_bytes, + rstn_value->warn_limit.out_bytes, + rstn_value->counter.in_bytes, rstn_value->counter.out_bytes, + rstn_key->roaming, rstn_key->imsi); +} + +static void __process_restriction(enum traffic_restriction_type rst_type, + stc_rstn_key_s *rstn_key, + stc_rstn_value_s *rstn_value, void *data) +{ + stc_data_counter_s effective_limit, effective_warn_limit; + default_connection_s *old_connection = (default_connection_s *)data; + default_connection_s *connection = NULL; + + if (old_connection != NULL) + connection = old_connection; + else + connection = stc_get_default_connection(); + + /* no default ifname */ + if (connection->ifname == NULL) + return; + + /* rstn not applicable for this interface */ + if (rstn_key->ifname != NULL && g_strcmp0("", rstn_key->ifname) != 0 && + g_strcmp0(connection->ifname, rstn_key->ifname) != 0) + return; + + /* classid is invalid */ + if (rstn_value->classid == STC_UNKNOWN_CLASSID) + return; + + effective_limit.out_bytes = rstn_value->limit.out_bytes; + effective_limit.in_bytes = rstn_value->limit.in_bytes; + effective_warn_limit.out_bytes = rstn_value->warn_limit.out_bytes; + effective_warn_limit.in_bytes = rstn_value->warn_limit.in_bytes; + + if (rst_type == RST_SET) { + /* TODO: Change this to runtime memory */ + table_counters_info info; + + memset(&info, 0, sizeof(table_counters_info)); + table_counters_get(rstn_value->restriction_id, &info); + + effective_limit.out_bytes -= info.sent_bytes; + effective_limit.in_bytes -= info.rcv_bytes; + effective_warn_limit.out_bytes -= info.sent_bytes; + effective_warn_limit.in_bytes -= info.rcv_bytes; + + if (effective_limit.in_bytes < 0) { + effective_limit.in_bytes = 0; + rstn_value->in_limit_reached = TRUE; + } + + if (effective_limit.out_bytes < 0) { + effective_limit.out_bytes = 0; + rstn_value->out_limit_reached = TRUE; + } + + if (effective_warn_limit.in_bytes < 0) + effective_warn_limit.in_bytes = 0; + + if (effective_warn_limit.out_bytes < 0) + effective_warn_limit.out_bytes = 0; + STC_LOGD("datausage [in: %llu, out: %llu]", + info.rcv_bytes, info.sent_bytes); + } + + STC_LOGD("rstn_id [%llu], effective limit [in: %llu, out: %llu], " + "effective warn limit [in: %llu, out: %llu], " + "datausage [in: %llu, out: %llu]", + rstn_value->restriction_id, + effective_limit.in_bytes, effective_limit.out_bytes, + effective_warn_limit.in_bytes, effective_warn_limit.out_bytes); + + send_net_restriction(rst_type, + rstn_value->classid, + 0 /*quota_id*/, + connection->type, + effective_limit.out_bytes, + effective_limit.in_bytes, + effective_warn_limit.out_bytes, + effective_warn_limit.in_bytes, + connection->ifname); + switch (rst_type) { + case RST_SET: + rstn_value->rst_state = STC_RESTRICTION_ACTIVATED; + rstn_value->in_limit_reached = FALSE; + rstn_value->out_limit_reached = FALSE; + break; + case RST_EXCLUDE: + ;//Do Nothing + break; + case RST_UNSET: + rstn_value->rst_state = STC_RESTRICTION_REMOVED; + rstn_value->in_limit_reached = FALSE; + rstn_value->out_limit_reached = FALSE; + break; + default: + ;//Do Nothing + } +} + +static gboolean __remove_rstns_foreach_application(gpointer key, + gpointer value, + gpointer data) +{ + stc_rstn_key_s *rstn_key = (stc_rstn_key_s *)key; + stc_rstn_value_s *rstn_value = (stc_rstn_value_s *)value; + gchar *app_id = (gchar *)data; + + /* rstn rule is not for applications */ + if (rstn_key->app_id == NULL) + goto out; + + /* rstn rule is not for this application */ + if (g_strcmp0(rstn_key->app_id, app_id) != 0) + goto out; + + /* rstn rule is already removed */ + if (rstn_value->rst_state == STC_RESTRICTION_REMOVED) + goto out; + + /* remove restriction from system */ + __process_restriction(RST_UNSET, rstn_key, rstn_value, data); + + __print_rstn(rstn_key, rstn_value); +out: + return FALSE; +} + +static void __remove_rstns_for_application(gchar *app_id) +{ + g_tree_foreach(g_system->rstns, __remove_rstns_foreach_application, + app_id); +} + +static stc_error_e __application_remove_if_empty(const stc_app_key_s *app_key) +{ + stc_error_e ret = STC_ERROR_NONE; + guint pid_count = 0; + stc_app_value_s *lookup; + + ret_value_msg_if(g_system == NULL, STC_ERROR_FAIL, "stc monitor not initialized!"); + + lookup = __application_lookup(g_system->apps, app_key); + if (!lookup) { + STC_LOGE("app_key not found"); + return STC_ERROR_NO_DATA; + } + + g_tree_foreach(lookup->processes, __processes_tree_check_empty, + &pid_count); + + if (!pid_count) { + /* remove nfacct rule for this classid */ + __remove_application_monitor((gpointer) app_key, lookup, + stc_get_default_connection()); + __remove_rstns_for_application(app_key->app_id); + } + + if (!g_tree_remove(g_system->apps, app_key)) { + ret = STC_ERROR_NO_DATA; + STC_LOGE("key not found"); + } + + return ret; +} + +static stc_error_e __close_contr_sock(stc_system_s *system) +{ + ret_value_msg_if(system == NULL, STC_ERROR_INVALID_PARAMETER, "invalid parameter"); + + /* close netlink socket for updating kernel counters */ + if (g_system->contr_sock != -1) { + close(g_system->contr_sock); + g_system->contr_sock = -1; + } + + if (g_system->contr_gsource_id != 0) { + g_source_remove(g_system->contr_gsource_id); + g_system->contr_gsource_id = 0; + } + + return STC_ERROR_NONE; +} + +static gboolean __rstn_counter_update_foreach_classid(gpointer key, + gpointer value, + gpointer data) +{ + stc_rstn_key_s *rstn_key = (stc_rstn_key_s *)key; + stc_rstn_value_s *rstn_value = (stc_rstn_value_s *)value; + classid_bytes_context_s *context = (classid_bytes_context_s *)data; + + if (context->counter->intend != NFACCT_COUNTER) + goto try_next_callback; + + if (rstn_value->classid != context->counter->classid) + goto try_next_callback; + + if (rstn_value->in_limit_reached == TRUE) { + context->in_limit_reached = TRUE; + goto try_next_callback; + } + + if (rstn_value->out_limit_reached == TRUE) { + context->out_limit_reached = TRUE; + goto try_next_callback; + } + + switch (context->counter->iotype) { + case NFACCT_COUNTER_IN: + rstn_value->counter.in_bytes += context->bytes; + + /* block immediately */ + if (rstn_value->counter.in_bytes >= rstn_value->limit.in_bytes) { + __del_iptables_in(context->counter); + __add_iptables_in(context->counter); + rstn_value->in_limit_reached = TRUE; + //context->in_limit_reached = TRUE; + } + + g_system->rstns_tree_updated = TRUE; + __print_rstn(rstn_key, rstn_value); + break; + case NFACCT_COUNTER_OUT: + rstn_value->counter.out_bytes += context->bytes; + + /* block immediately */ + if (rstn_value->counter.out_bytes >= rstn_value->limit.out_bytes) { + __del_iptables_out(context->counter); + __add_iptables_out(context->counter); + rstn_value->out_limit_reached = TRUE; + //context->out_limit_reached = TRUE; + } + + g_system->rstns_tree_updated = TRUE; + __print_rstn(rstn_key, rstn_value); + break; + default: + STC_LOGE("unknown iotype"); + } + + +try_next_callback: + return FALSE; +} + +static gboolean __update_app_statistics(gpointer key, gpointer value, + gpointer data) +{ + stc_app_key_s *app_key = (stc_app_key_s *)key; + stc_app_value_s *app_value = (stc_app_value_s *)value; + time_t *touch_time = (time_t *)data; + stc_db_classid_iftype_key stat_key; + stc_db_app_stats stat; + char *default_ifname = stc_default_connection_get_ifname(); + + memset(&stat_key, 0, sizeof(stc_db_classid_iftype_key)); + memset(&stat, 0 , sizeof(stc_db_app_stats)); + + stat_key.classid = app_value->classid; + stat_key.iftype = stc_default_connection_get_type(); + if (STC_IFACE_DATACALL == stat_key.iftype) + stat_key.imsi = g_strdup("unknown"); + else + stat_key.imsi = g_strdup("noneimsi"); + g_strlcpy(stat_key.ifname, default_ifname, MAX_IFACE_LENGTH); + + stat.app_id = g_strdup(app_key->app_id); + stat.snd_count = app_value->counter.out_bytes; + stat.rcv_count = app_value->counter.in_bytes; + stat.delta_snd = 0; + stat.delta_rcv = 0; + stat.is_roaming = stc_default_connection_get_roaming(); + stat.ground = STC_APP_STATE_UNKNOWN; + + table_statistics_insert(&stat_key, &stat, *touch_time); + + app_value->counter.out_bytes = 0; + app_value->counter.in_bytes = 0; + + FREE(stat.app_id); + FREE(stat_key.imsi); + FREE(default_ifname); + + return FALSE; +} + +static gboolean __flush_apps_stats_to_database(gpointer user_data) +{ + time_t current_time = time(0); + + if (g_system->apps_tree_updated == FALSE) + return G_SOURCE_REMOVE; + + g_system->apps_tree_updated = FALSE; + + if (g_system->apps) + g_tree_foreach(g_system->apps, + __update_app_statistics, + ¤t_time); + + STC_LOGI("Flushed app stats to database"); + return G_SOURCE_REMOVE; +} + +static gboolean __update_counter_statistics(gpointer key, gpointer value, + gpointer data) +{ + stc_rstn_value_s *rstn_value = (stc_rstn_value_s *)value; + table_counters_info info = { + .restriction_id = rstn_value->restriction_id, + .sent_bytes = rstn_value->counter.out_bytes, + .rcv_bytes = rstn_value->counter.in_bytes + }; + + table_counters_update_counters(&info); + + return FALSE; +} + +static gboolean __flush_rstns_counter_to_database(gpointer user_data) +{ + time_t current_time = time(0); + + if (g_system->rstns_tree_updated == FALSE) + return G_SOURCE_REMOVE; + + g_system->rstns_tree_updated = FALSE; + + if (g_system->rstns) + g_tree_foreach(g_system->rstns, + __update_counter_statistics, + ¤t_time); + + STC_LOGI("Flushed rstns counters to database"); + return G_SOURCE_REMOVE; +} + +static gboolean __apps_counter_update_foreach_classid(gpointer key, + gpointer value, + gpointer data) +{ + stc_app_key_s *app_key = (stc_app_key_s *)key; + stc_app_value_s *app_value = (stc_app_value_s *)value; + classid_bytes_context_s *context = (classid_bytes_context_s *)data; + + if (context->counter->intend != NFACCT_COUNTER) + goto try_next_callback; + + if (app_value->classid != context->counter->classid) + goto try_next_callback; + + switch (context->counter->iotype) { + case NFACCT_COUNTER_IN: + app_value->data_usage.in_bytes += context->bytes; + app_value->counter.in_bytes = context->bytes; + g_system->apps_tree_updated = TRUE; + + __apps_tree_foreach_print(app_key, app_value, NULL); + break; + case NFACCT_COUNTER_OUT: + app_value->data_usage.out_bytes += context->bytes; + app_value->counter.out_bytes = context->bytes; + g_system->apps_tree_updated = TRUE; + + __apps_tree_foreach_print(app_key, app_value, NULL); + break; + default: + STC_LOGE("unknown iotype"); + } + +try_next_callback: + return FALSE; +} + +static void __fill_nfacct_result(char *cnt_name, uint64_t bytes, + struct counter_arg *carg) +{ + struct nfacct_rule counter = { + .carg = carg, + .name = {0}, + .ifname = {0}, + 0 + }; + + classid_bytes_context_s context = { + .counter = &counter, + .bytes = bytes, + .in_limit_reached = FALSE, + .out_limit_reached = FALSE + }; + + STC_LOGD("cnt_name %s", cnt_name); + + if (!recreate_counter_by_name(cnt_name, &counter)) { + STC_LOGE("Can't parse counter name %s", cnt_name); + return; + } + + STC_LOGI("classid %lu, iftype %u, iotype %d, intend %d, ifname %s, bytes %llu", + context.counter->classid, context.counter->iftype, + context.counter->iotype, context.counter->intend, + context.counter->ifname, context.bytes); + + if (g_system->rstns) + g_tree_foreach(g_system->rstns, + __rstn_counter_update_foreach_classid, + &context); + + if (g_system->apps) + g_tree_foreach(g_system->apps, + __apps_counter_update_foreach_classid, + &context); +} + +static int __fill_counters(struct rtattr *attr_list[__NFACCT_MAX], + void *user_data) +{ + struct counter_arg *carg = user_data; + char *cnt_name = (char *)RTA_DATA(attr_list[NFACCT_NAME]); + if (carg->initiate) { + /** + * TODO: this will be used when daemon starts to update existing + * counter data if present. + * + populate_counters(cnt_name, carg); + */ + } else { + uint64_t *bytes_p = + (uint64_t *)RTA_DATA(attr_list[NFACCT_BYTES]); + int bytes = be64toh(*bytes_p); + if (bytes) { + ++carg->serialized_counters; + __fill_nfacct_result(cnt_name, bytes, carg); + } + } + + return 0; +} + +static int __post_fill_counters(void *user_data) +{ + struct counter_arg *carg = user_data; + + if (carg->initiate) + carg->initiate = 0; + + return 0; +} + +static void __process_network_counter(struct genl *ans, + struct counter_arg *carg) +{ + struct netlink_serialization_params ser_params = { + .carg = carg, + .ans = ans, + .eval_attr = __fill_counters, + .post_eval_attr = __post_fill_counters, + }; + + netlink_serialization_command *netlink = + netlink_create_command(&ser_params); + if (!netlink) { + STC_LOGE("Can not create command"); + return; + } + + netlink->deserialize_answer(&(netlink->params)); +} + +static gboolean __process_contr_reply(GIOChannel *source, + GIOCondition condition, + gpointer user_data) +{ + int sock = g_io_channel_unix_get_fd(source); + struct genl ans; + int ret; + stc_s *stc = stc_get_manager(); + + if ((condition & G_IO_ERR) || + (condition & G_IO_HUP) || + (condition & G_IO_NVAL)) { + /* G_IO_ERR/G_IO_HUP/G_IO_NVAL received */ + + __close_contr_sock(g_system); + return FALSE; + } + + if (stc == NULL) { + STC_LOGE("Can't get stc data"); + goto out; + } + + ret = read_netlink(sock, + &ans, sizeof(struct genl)); + STC_LOGD("Counter data received ret [%d]", ret); + if (ret == 0) + goto out; + + stc->carg->ans_len = ret; + __process_network_counter(&ans, stc->carg); + + g_idle_add(__flush_apps_stats_to_database, NULL); + g_idle_add(__flush_rstns_counter_to_database, NULL); +out: + return TRUE; +} + +static gboolean __update_contr_cb(void *user_data) +{ + /* Here we just sent command, answer we receive in another callback */ + stc_s *stc = stc_get_manager(); + ret_value_msg_if(stc == NULL, STC_ERROR_FAIL, "Can't get stc data"); + if (!stc->carg) { + stc->carg = MALLOC0(counter_arg_s, 1); + stc->carg->sock = stc_monitor_get_counter_socket(); + } + + STC_LOGD("Get all counters"); + nfacct_send_get_all(stc->carg); + + /* we need to continue the timer */ + return TRUE; +} +#if 0 +static gboolean __rstn_tree_foreach_print(gpointer key, gpointer value, + gpointer data) +{ + stc_rstn_key_s *rstn_key = (stc_rstn_key_s *)key; + stc_rstn_value_s *rstn_value = (stc_rstn_value_s *)value; + + __print_rstn(rstn_key, rstn_value); + return FALSE; +} + +static void __rstn_tree_printall(void) +{ + g_tree_foreach(g_system->rstns, __rstn_tree_foreach_print, NULL); +} +#endif +static stc_rstn_value_s * __rstn_lookup(GTree *rstns_tree, + const stc_rstn_key_s *key) +{ + stc_rstn_value_s *lookup; + + ret_value_msg_if(rstns_tree == NULL, NULL, "rstns_tree is null!"); + + lookup = g_tree_lookup(rstns_tree, key); + + return lookup; +} + +static gboolean __remove_restriction(gpointer key, gpointer value, + gpointer data) +{ + stc_rstn_key_s *rstn_key = (stc_rstn_key_s *)key; + stc_rstn_value_s *rstn_value = (stc_rstn_value_s *)value; + + /* rstn rule is already removed */ + if (rstn_value->rst_state == STC_RESTRICTION_REMOVED) + return FALSE; + + __process_restriction(RST_UNSET, rstn_key, rstn_value, data); + __print_rstn(rstn_key, rstn_value); + return FALSE; +} + +static gboolean __add_restriction_debug(gpointer key, gpointer value, + gpointer data) +{ + stc_rstn_key_s *rstn_key = (stc_rstn_key_s *)key; + stc_rstn_value_s *rstn_value = (stc_rstn_value_s *)value; + + /* rstn rule is activated */ + if (rstn_value->rst_state == STC_RESTRICTION_ACTIVATED) + return FALSE; + + if (rstn_value->rst_state == STC_RESTRICTION_EXCLUDED) + __process_restriction(RST_EXCLUDE, rstn_key, rstn_value, data); + else + __process_restriction(RST_SET, rstn_key, rstn_value, data); + + __print_rstn(rstn_key, rstn_value); + + return FALSE; +} + +static gboolean __add_restriction(gpointer key, gpointer value, gpointer data) +{ + stc_rstn_key_s *rstn_key = (stc_rstn_key_s *)key; + stc_rstn_value_s *rstn_value = (stc_rstn_value_s *)value; + + /* rstn rule is activated */ + if (rstn_value->rst_state == STC_RESTRICTION_ACTIVATED) + return FALSE; + + if (rstn_value->rst_state == STC_RESTRICTION_EXCLUDED) + __process_restriction(RST_EXCLUDE, rstn_key, rstn_value, data); + else + __process_restriction(RST_SET, rstn_key, rstn_value, data); + + return FALSE; +} + +static stc_error_e __rstn_tree_remove(stc_rstn_key_s *key) +{ + stc_rstn_value_s *lookup_value; + + ret_value_msg_if(g_system == NULL, STC_ERROR_FAIL, "stc monitor not initialized!"); + + lookup_value = __rstn_lookup(g_system->rstns, key); + if (!lookup_value) { + STC_LOGE("key not found"); + return STC_ERROR_NO_DATA; + } + + __remove_restriction(key, lookup_value, NULL); + + /* remove counter also */ + table_counters_delete(lookup_value->restriction_id); + + if (!g_tree_remove(g_system->rstns, key)) { + STC_LOGD("key not found"); + return STC_ERROR_NO_DATA; + } + + return STC_ERROR_NONE; +} + +static stc_error_e __rstn_tree_add(stc_rstn_key_s *key, + stc_rstn_value_s *value, gboolean debug) +{ + stc_rstn_value_s *rstn_value; + + ret_value_msg_if(g_system == NULL, STC_ERROR_FAIL, "stc monitor not initialized!"); + + rstn_value = __rstn_lookup(g_system->rstns, key); + if (!rstn_value) { + stc_rstn_key_s *rstn_key = MALLOC0(stc_rstn_key_s, 1); + if (!rstn_key) { + STC_LOGE("rstn_key allocation failed"); + return STC_ERROR_OUT_OF_MEMORY; + } + + rstn_value = MALLOC0(stc_rstn_value_s, 1); + if (!rstn_value) { + STC_LOGE("rstn_value allocation failed"); + FREE(rstn_key); + return STC_ERROR_OUT_OF_MEMORY; + } + + rstn_key->app_id = g_strdup(key->app_id); + rstn_key->ifname = g_strdup(key->ifname); + rstn_key->imsi = g_strdup(key->imsi); + rstn_key->iftype = key->iftype; + rstn_key->roaming = key->roaming; + + g_tree_insert(g_system->rstns, rstn_key, rstn_value); + } + + rstn_value->restriction_id = value->restriction_id; + rstn_value->rst_state = value->rst_state; + rstn_value->classid = value->classid; + rstn_value->limit.in_bytes = value->limit.in_bytes; + rstn_value->limit.out_bytes = value->limit.out_bytes; + rstn_value->warn_limit.in_bytes = value->warn_limit.in_bytes; + rstn_value->warn_limit.out_bytes = value->warn_limit.out_bytes; + rstn_value->counter.in_bytes = 0; + rstn_value->counter.out_bytes = 0; + + if (debug == TRUE) + __add_restriction_debug(key, rstn_value, NULL); + else + __add_restriction(key, rstn_value, NULL); + + return STC_ERROR_NONE; +} + +static stc_cb_ret_e __insert_restriction_cb(const table_restrictions_info *info, + void *user_data) +{ + stc_cb_ret_e ret = STC_CONTINUE; + + stc_rstn_key_s key; + stc_rstn_value_s value; + + memset(&key, 0, sizeof(stc_rstn_key_s)); + memset(&value, 0, sizeof(stc_rstn_value_s)); + + key.app_id = g_strdup(info->app_id); + key.ifname = g_strdup(info->ifname); + key.imsi = g_strdup(info->imsi); + key.iftype = info->iftype; + key.roaming = info->roaming; + + value.rst_state = info->rst_state; + value.restriction_id = info->restriction_id; + + if (value.rst_state != STC_RESTRICTION_EXCLUDED) + value.classid = get_classid_by_app_id(info->app_id ? + info->app_id : + STC_ALL_APP, TRUE); + else + value.classid = STC_UNKNOWN_CLASSID; + + value.limit.in_bytes = info->rcv_limit; + value.limit.out_bytes = info->send_limit; + value.warn_limit.in_bytes = info->rcv_warn_limit; + value.warn_limit.out_bytes = info->send_warn_limit; + + if (__rstn_tree_add(&key, &value, FALSE) != STC_ERROR_NONE) + ret = STC_CANCEL; + + FREE(key.app_id); + FREE(key.ifname); + FREE(key.imsi); + return ret; +} + +static void __fill_restritions_list(void) +{ + table_restrictions_foreach(__insert_restriction_cb, NULL); + //__rstn_tree_printall(); +} + +static gboolean __add_rstn_foreach_application(gpointer key, + gpointer value, + gpointer data) +{ + stc_rstn_key_s *rstn_key = (stc_rstn_key_s *)key; + stc_rstn_value_s *rstn_value = (stc_rstn_value_s *)value; + gchar *app_id = (gchar *)data; + + /* rstn rule is not for applications */ + if (rstn_key->app_id == NULL) + goto out; + + /* rstn rule is not for this application */ + if (g_strcmp0(rstn_key->app_id, app_id) != 0) + goto out; + + /* rstn rule is already applied */ + if (rstn_value->rst_state == STC_RESTRICTION_ACTIVATED) + goto out; + + /* add restriction to system */ + if (rstn_value->rst_state == STC_RESTRICTION_EXCLUDED) + __process_restriction(RST_EXCLUDE, rstn_key, rstn_value, data); + else + __process_restriction(RST_SET, rstn_key, rstn_value, data); + + __print_rstn(rstn_key, rstn_value); +out: + return FALSE; +} + +static void __add_rstns_for_application(gchar *app_id) +{ + g_tree_foreach(g_system->rstns, __add_rstn_foreach_application, + app_id); +} + +/* used only for (STC_ALL_APP/STC_BACKGROUND_APP_NAME) */ +static void __stc_monitor_add_application_by_app_id(const char *app_id) +{ + stc_app_key_s app_key; + stc_app_value_s app_value; + + if (app_id == NULL) + return; + + memset(&app_key, 0, sizeof(stc_app_key_s)); + memset(&app_value, 0, sizeof(stc_app_value_s)); + + app_key.pkg_id = g_strdup(app_id); + app_key.app_id = g_strdup(app_id); + + app_value.type = STC_APP_TYPE_NONE; + app_value.processes = NULL; + app_value.counter.in_bytes = 0; + app_value.counter.out_bytes = 0; + + stc_monitor_application_add(app_key, app_value); + + FREE(app_key.pkg_id); + FREE(app_key.app_id); + + __apps_tree_printall(); +} + +stc_error_e stc_monitor_init(void) +{ + stc_system_s *system = MALLOC0(stc_system_s, 1); + GIOChannel *gio = NULL; + + ret_value_msg_if(system == NULL, STC_ERROR_OUT_OF_MEMORY, "stc_system_s malloc fail!"); + + /* creating monitored application tree */ + system->apps = g_tree_new_full(__apps_tree_key_compare, NULL, + __apps_tree_key_free, + __apps_tree_value_free); + + system->rstns = g_tree_new_full(__rstns_tree_key_compare, NULL, + __rstns_tree_key_free, + __rstns_tree_value_free); + + /* create netlink socket for updating kernel counters */ + system->contr_sock = create_netlink(NETLINK_NETFILTER, 0); + if (!(system->contr_sock)) { + STC_LOGE("failed to open socket"); + FREE(system); + return STC_ERROR_FAIL; + } + + gio = g_io_channel_unix_new(system->contr_sock); + system->contr_gsource_id = + g_io_add_watch(gio, G_IO_IN | G_IO_ERR | G_IO_HUP, + (GIOFunc) __process_contr_reply, + NULL); + g_io_channel_unref(gio); + + g_system = system; + + /* create entry for STC_ALL_APP */ + __stc_monitor_add_application_by_app_id(STC_ALL_APP); + + /* create entry for STC_BACKGROUND_APP_NAME */ + __stc_monitor_add_application_by_app_id(STC_BACKGROUND_APP_NAME); + + /* create background cgroup */ + g_system->background_pids = NULL; + create_net_background_cgroup(g_system->background_pids); + + /* creating restriction rules tree */ + __update_contr_cb(NULL); + + /* registering periodic kernel counters update callback */ + g_system->contr_timer_id = g_timeout_add_seconds(CONTR_TIMER_INTERVAL, + __update_contr_cb, + NULL); + if (g_system->contr_timer_id == 0) { + STC_LOGE("Failed to register kernel counters update timer"); + __close_contr_sock(g_system); + return STC_ERROR_FAIL; + } + + __fill_restritions_list(); + + return STC_ERROR_NONE; +} + +stc_error_e stc_monitor_deinit(void) +{ + ret_value_msg_if(g_system == NULL, STC_ERROR_FAIL, "stc monitor not initialized!"); + + /* close netlink socket for updating kernel counters */ + __close_contr_sock(g_system); + + /* remove kernel counters update timer */ + if (g_system->contr_timer_id > 0) { + g_source_remove(g_system->contr_timer_id); + g_system->contr_timer_id = 0; + } + + /* free background pid list */ + g_slist_free(g_system->background_pids); + g_system->background_pids = NULL; + + /* destroy monitored application tree */ + g_tree_destroy(g_system->apps); + g_system->apps = NULL; + + /* destroy restriction rules tree */ + g_tree_destroy(g_system->rstns); + g_system->rstns = NULL; + + FREE(g_system); + + return STC_ERROR_NONE; +} + +stc_error_e stc_monitor_application_add(const stc_app_key_s app_key, + const stc_app_value_s app_value) +{ + stc_error_e ret = STC_ERROR_NONE; + stc_app_key_s *key; + stc_app_value_s *value; + stc_app_value_s *lookup; + + ret_value_msg_if(g_system == NULL, STC_ERROR_FAIL, "stc monitor not initialized!"); + + lookup = __application_lookup(g_system->apps, &app_key); + if (lookup) { + STC_LOGD("app_key already present"); + return STC_ERROR_NONE; + } + + key = MALLOC0(stc_app_key_s, 1); + if (!key) { + STC_LOGE("key allocation failed"); + return STC_ERROR_OUT_OF_MEMORY; + } + + value = MALLOC0(stc_app_value_s, 1); + if (!value) { + STC_LOGE("value allocation failed"); + FREE(key); + return STC_ERROR_OUT_OF_MEMORY; + } + + key->app_id = g_strdup(app_key.app_id); + key->pkg_id = g_strdup(app_key.pkg_id); + + value->type = app_value.type; + value->counter.in_bytes = app_value.counter.in_bytes; + value->counter.out_bytes = app_value.counter.out_bytes; + + value->processes = g_tree_new_full(__processes_tree_key_compare, NULL, + __processes_tree_key_free, + __processes_tree_value_free); + + /* create cgroup and update classid */ + value->classid = get_classid_by_app_id(app_key.app_id, TRUE); + + g_tree_insert(g_system->apps, key, value); + + /* add nfacct rule for this classid */ + __add_application_monitor(key, value, stc_get_default_connection()); + __add_rstns_for_application(app_key.app_id); + + return ret; +} + +stc_error_e stc_monitor_process_add(const stc_app_key_s app_key, + const stc_process_key_s proc_key, + const stc_process_value_s proc_value) +{ + stc_error_e ret = STC_ERROR_NONE; + stc_app_value_s *app_lookup; + stc_process_key_s *key; + stc_process_value_s *value; + stc_process_value_s *proc_lookup; + + ret_value_msg_if(g_system == NULL, STC_ERROR_FAIL, "stc monitor not initialized!"); + + app_lookup = __application_lookup(g_system->apps, &app_key); + if (!app_lookup) { + STC_LOGD("app_key not found"); + return STC_ERROR_FAIL; + } + + proc_lookup = __process_lookup(app_lookup->processes, &proc_key); + if (proc_lookup) { + STC_LOGD("proc_key already present"); + return STC_ERROR_NONE; + } + + key = MALLOC0(stc_process_key_s, 1); + if (!key) { + STC_LOGE("key allocation failed"); + return STC_ERROR_OUT_OF_MEMORY; + } + + value = MALLOC0(stc_process_value_s, 1); + if (!value) { + STC_LOGE("value allocation failed"); + FREE(key); + return STC_ERROR_OUT_OF_MEMORY; + } + + key->pid = proc_key.pid; + + value->ground = proc_value.ground; + + g_tree_insert(app_lookup->processes, key, value); + + /* add pid to application cgroup */ + place_pids_to_net_cgroup(proc_key.pid, app_key.app_id); + + /* add pid to background cgroup if gound state is background */ + if (proc_value.ground == STC_APP_STATE_BACKGROUND) + add_pid_to_background_cgroup(proc_key.pid); + + return ret; +} + +stc_error_e stc_monitor_process_remove(pid_t pid) +{ + stc_error_e ret = STC_ERROR_NONE; + stc_process_key_s proc_key = { + .pid = pid + }; + + remove_pid_context_s context = { + .app_key = NULL, + .proc_key = &proc_key, + .entry_removed = FALSE, + }; + + ret_value_msg_if(g_system == NULL, STC_ERROR_FAIL, "stc monitor not initialized!"); + + /* remove pid from background cgroup */ + remove_pid_from_background_cgroup(pid); + + g_tree_foreach(g_system->apps, __apps_tree_foreach_remove_pid, + &context); + + if (context.entry_removed) + __application_remove_if_empty(context.app_key); + + return ret; +} + +stc_error_e stc_monitor_process_update_ground(const stc_app_key_s app_key, + const stc_process_key_s proc_key, + stc_app_state_e ground) +{ + stc_error_e ret = STC_ERROR_NONE; + stc_app_value_s *app_lookup; + stc_process_value_s *proc_lookup; + + ret_value_msg_if(g_system == NULL, STC_ERROR_FAIL, "stc monitor not initialized!"); + + app_lookup = __application_lookup(g_system->apps, &app_key); + if (!app_lookup) { + STC_LOGD("app_key not found"); + return STC_ERROR_FAIL; + } + + proc_lookup = __process_lookup(app_lookup->processes, &proc_key); + if (!proc_lookup) { + STC_LOGD("proc_key not found"); + return STC_ERROR_FAIL; + } + + if (proc_lookup->ground != ground) + proc_lookup->ground = ground; + + if (ground == STC_APP_STATE_BACKGROUND) + add_pid_to_background_cgroup(proc_key.pid); + else + place_pids_to_net_cgroup(proc_key.pid, app_key.app_id); + + return ret; +} + +void stc_monitor_update_rstn_by_default_connection(void *data) +{ + static default_connection_s old_connection; + default_connection_s *new_connection = (default_connection_s *)data; + + if (old_connection.path != NULL) { + if (g_system->apps) + g_tree_foreach(g_system->apps, + __remove_application_monitor, + (gpointer)&old_connection); + + if (g_system->rstns) + g_tree_foreach(g_system->rstns, + __remove_restriction, + (gpointer)&old_connection); + } + + FREE(old_connection.path); + FREE(old_connection.ifname); + old_connection.type = 0; + old_connection.roaming = 0; + + if (new_connection != NULL && new_connection->path != NULL) { + if (g_system->apps) + g_tree_foreach(g_system->apps, + __add_application_monitor, + (gpointer)new_connection); + + if (g_system->rstns) + g_tree_foreach(g_system->rstns, __add_restriction, + NULL); + + old_connection.path = g_strdup(new_connection->path); + old_connection.ifname = g_strdup(new_connection->ifname); + old_connection.type = new_connection->type; + old_connection.roaming = new_connection->roaming; + } +} + +stc_error_e stc_monitor_rstns_tree_add(const table_restrictions_info *info) +{ + stc_error_e ret; + + stc_rstn_key_s key; + stc_rstn_value_s value; + + memset(&key, 0, sizeof(stc_rstn_key_s)); + memset(&value, 0, sizeof(stc_rstn_value_s)); + + key.app_id = g_strdup(info->app_id); + key.ifname = g_strdup(info->ifname); + key.imsi = g_strdup(info->imsi); + key.iftype = info->iftype; + key.roaming = info->roaming; + + value.rst_state = info->rst_state; + value.restriction_id = info->restriction_id; + + if (value.rst_state != STC_RESTRICTION_EXCLUDED) + value.classid = get_classid_by_app_id(info->app_id ? + info->app_id : + STC_ALL_APP, TRUE); + else + value.classid = STC_UNKNOWN_CLASSID; + + value.limit.in_bytes = info->rcv_limit; + value.limit.out_bytes = info->send_limit; + value.warn_limit.in_bytes = info->rcv_warn_limit; + value.warn_limit.out_bytes = info->send_warn_limit; + + ret = __rstn_tree_add(&key, &value, TRUE); + + FREE(key.app_id); + FREE(key.ifname); + FREE(key.imsi); + return ret; +} + +stc_error_e stc_monitor_rstns_tree_remove(const table_restrictions_info *info) +{ + stc_error_e ret; + + stc_rstn_key_s key = { + .app_id = g_strdup(info->app_id), + .ifname = g_strdup(info->ifname), + .imsi = g_strdup(info->imsi), + .iftype = info->iftype, + .roaming = info->roaming, + }; + + ret = __rstn_tree_remove(&key); + + FREE(key.app_id); + FREE(key.ifname); + FREE(key.imsi); + return ret; +} + +int stc_monitor_get_counter_socket(void) +{ + return g_system->contr_sock; +} diff --git a/src/stc-manager-gdbus.c b/src/stc-manager-gdbus.c new file mode 100755 index 0000000..8352d6d --- /dev/null +++ b/src/stc-manager-gdbus.c @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "stc-manager-gdbus.h" +#include "stc-statistics.h" +#include "stc-restriction.h" +#include "stc-default-connection.h" +#include "stc-application-lifecycle.h" + +static gboolean __stc_manager_gdbus_statistics_init(stc_s *stc) +{ + __STC_LOG_FUNC_ENTER__; + gboolean ret = TRUE; + gchar *s = NULL; + + StcObjectSkeleton *object = NULL; + StcStatistics *statistics = NULL; + s = g_strdup_printf(STC_DBUS_SERVICE_STATISTICS_PATH); + + /* Add interface to default object path */ + object = stc_object_skeleton_new(s); + g_free(s); + + /* Make the newly created object export the interface + * net.stc.statistics (note + * that @object takes its own reference to @statistics). + */ + + statistics = stc_statistics_skeleton_new(); + stc_object_skeleton_set_statistics(object, statistics); + g_object_unref(statistics); + + /* Register for method callbacks as signal callbacks */ + + g_signal_connect(statistics, "handle-get", + G_CALLBACK(handle_statistics_get), + stc); + + g_signal_connect(statistics, "handle-get-all", + G_CALLBACK(handle_statistics_get_all), + stc); + + g_signal_connect(statistics, "handle-reset", + G_CALLBACK(handle_statistics_reset), + stc); + + /* Export the object (@manager takes its own reference to @object) */ + g_dbus_object_manager_server_export(stc->obj_mgr, + G_DBUS_OBJECT_SKELETON(object)); + g_object_unref(object); + + stc->statistics_obj = (gpointer)statistics; + + __STC_LOG_FUNC_EXIT__; + return ret; +} + +static gboolean __stc_manager_gdbus_restriction_init(stc_s *stc) +{ + __STC_LOG_FUNC_ENTER__; + gboolean ret = TRUE; + gchar *s = NULL; + + StcObjectSkeleton *object = NULL; + StcRestriction *restriction = NULL; + s = g_strdup_printf(STC_DBUS_SERVICE_RESTRICTION_PATH); + + /* Add interface to default object path */ + object = stc_object_skeleton_new(s); + g_free(s); + + /* Make the newly created object export the interface + * net.stc.restriction (note + * that @object takes its own reference to @restriction). + */ + + restriction = stc_restriction_skeleton_new(); + stc_object_skeleton_set_restriction(object, restriction); + g_object_unref(restriction); + + /* Register for method callbacks as signal callbacks */ + + g_signal_connect(restriction, "handle-set", + G_CALLBACK(handle_restriction_set), stc); + + g_signal_connect(restriction, "handle-exclude", + G_CALLBACK(handle_restriction_exclude), stc); + + g_signal_connect(restriction, "handle-get", + G_CALLBACK(handle_restriction_get), stc); + + g_signal_connect(restriction, "handle-get-all", + G_CALLBACK(handle_restriction_get_all), stc); + + g_signal_connect(restriction, "handle-get-state", + G_CALLBACK(handle_restriction_get_state), + stc); + + g_signal_connect(restriction, "handle-remove", + G_CALLBACK(handle_restriction_remove), stc); + + /* Export the object (@manager takes its own reference to @object) */ + g_dbus_object_manager_server_export(stc->obj_mgr, + G_DBUS_OBJECT_SKELETON(object)); + g_object_unref(object); + + stc->restriction_obj = (gpointer)restriction; + + __STC_LOG_FUNC_EXIT__; + return ret; +} + +static void __stc_manager_gdbus_on_bus_acquired(GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + __STC_LOG_FUNC_ENTER__; + stc_s* stc = (stc_s*)user_data; + + stc->obj_mgr = g_dbus_object_manager_server_new("/net/stc"); + + STC_LOGD("path : %s", name); + + stc->connection = connection; + + if (__stc_manager_gdbus_statistics_init(stc) == FALSE) { + STC_LOGE("Can not signal connect to statistics"); + /* Deinitialize and quit manager */ + } + + if (__stc_manager_gdbus_restriction_init(stc) == FALSE) { + STC_LOGE("Cannot signal connect to restriction"); + /* Deinitialize and quit manager */ + } + + g_dbus_object_manager_server_set_connection(stc->obj_mgr, + stc->connection); + + stc_application_lifecycle_monitor_init(stc); + stc_default_connection_monitor_init(stc); + + __STC_LOG_FUNC_EXIT__; +} + +static void __stc_manager_gdbus_on_name_acquired(GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + STC_LOGD("name : %s", name); +} + +static void __stc_manager_gdbus_on_name_lost(GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + STC_LOGD("name : %s", name); +} + +void stc_manager_gdbus_init(gpointer stc_data) +{ + __STC_LOG_FUNC_ENTER__; + stc_s *stc = (stc_s *)stc_data; + + stc->gdbus_owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM, + STC_DBUS_SERVICE, + G_BUS_NAME_OWNER_FLAGS_NONE, + __stc_manager_gdbus_on_bus_acquired, + __stc_manager_gdbus_on_name_acquired, + __stc_manager_gdbus_on_name_lost, + stc, + NULL); + + __STC_LOG_FUNC_EXIT__; +} + +void stc_manager_gdbus_deinit(gpointer stc_data) +{ + __STC_LOG_FUNC_ENTER__; + stc_s *stc = (stc_s *)stc_data; + stc_application_lifecycle_monitor_deinit(stc); + stc_default_connection_monitor_deinit(stc); + g_bus_unown_name(stc->gdbus_owner_id); + stc->statistics_obj = NULL; + stc->restriction_obj = NULL; + __STC_LOG_FUNC_EXIT__; +} + +GVariant *stc_manager_gdbus_call_sync(GDBusConnection *connection, + const char *dest, const char *path, + const char *interface_name, + const char *method, GVariant *params) +{ + GError *error = NULL; + GVariant *reply = NULL; + + if (connection == NULL) { + STC_LOGE("Failed to get GDBusconnection"); + return reply; + } + + reply = g_dbus_connection_call_sync(connection, + dest, + path, + interface_name, + method, + params, + NULL, + G_DBUS_CALL_FLAGS_NONE, + (5 * 1000), /* 5 seconds timeout */ + NULL, + &error); + + if (reply == NULL) { + if (error != NULL) { + STC_LOGE("g_dbus_connection_call_sync() failed" + "error [%d: %s]", error->code, error->message); + g_error_free(error); + } else { + STC_LOGE("g_dbus_connection_call_sync() failed"); + } + + return NULL; + } + + return reply; +} + +guint stc_manager_gdbus_subscribe_signal(GDBusConnection *connection, + const gchar *sender, + const gchar *interface_name, + const gchar *member, + const gchar *object_path, + const gchar *arg0, + GDBusSignalFlags flags, + GDBusSignalCallback callback, + gpointer user_data, + GDestroyNotify user_data_free_func) +{ + if (connection == NULL) { + STC_LOGE("Failed to get GDBusconnection"); + return 0; + } + + return g_dbus_connection_signal_subscribe(connection, + sender, + interface_name, + member, + object_path, + NULL, + G_DBUS_SIGNAL_FLAGS_NONE, + callback, + user_data, + user_data_free_func); +} + +void stc_manager_gdbus_unsubscribe_signal(GDBusConnection *connection, + guint subscription_id) +{ + if (connection == NULL) { + STC_LOGE("Failed to get GDBusconnection"); + return; + } + + g_dbus_connection_signal_unsubscribe(connection, subscription_id); +} + +void stc_manager_gdbus_dict_foreach(GVariantIter *iter, dbus_dict_cb cb, + void *user_data) +{ + __STC_LOG_FUNC_ENTER__; + + gchar *key = NULL; + GVariant *value = NULL; + + if (!cb) { + __STC_LOG_FUNC_EXIT__; + return; + } + + while (g_variant_iter_loop(iter, "{sv}", &key, &value)) { + DEBUG_GDBUS_KEY_VALUE(key, value); + if (key && cb) + cb(key, value, user_data); + } + + __STC_LOG_FUNC_EXIT__; +} diff --git a/src/stc-manager.c b/src/stc-manager.c new file mode 100755 index 0000000..bbabfa9 --- /dev/null +++ b/src/stc-manager.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "stc-manager.h" +#include "stc-statistics.h" +#include "stc-restriction.h" +#include "stc-manager-gdbus.h" +#include "stc-db.h" +#include "counter.h" +#include "table-restrictions.h" +#include "helper-cgroup.h" +#include "helper-nfacct-rule.h" +#include "stc-monitor.h" + +static stc_s *g_stc = NULL; + +static void __stc_manager_deinit(void) +{ + __STC_LOG_FUNC_ENTER__; + + if (!g_stc) { + STC_LOGE("Memory for manager structure is not allocated"); + return; + } + + stc_monitor_deinit(); + stc_deinit_db_guard(); + stc_db_deinitialize(); + stc_manager_gdbus_deinit((gpointer)g_stc); + + STC_LOGI("stc manager deinitialized"); + FREE(g_stc); + __STC_LOG_FUNC_EXIT__; +} + +static stc_s *__stc_manager_init(void) +{ + __STC_LOG_FUNC_ENTER__; + stc_s *stc; + + stc = MALLOC0(stc_s, 1); + if (!stc) { + STC_LOGE("Failed to allocate memory for manager structure"); + return NULL; + } + g_stc = stc; + + cgroup_set_release_agent(NET_CLS_SUBSYS, NET_RELEASE_AGENT); + + EXEC(STC_ERROR_NONE, stc_db_initialize()); + + stc_monitor_init(); + stc_manager_gdbus_init((gpointer)stc); + + STC_LOGI("stc manager initialized"); + __STC_LOG_FUNC_EXIT__; + return stc; + +handle_error: + STC_LOGD("Failed to initialize stc manager"); + __stc_manager_deinit(); + return NULL; +} + +stc_s *stc_get_manager(void) +{ + return g_stc; +} + +gint32 main(gint32 argc, gchar *argv[]) +{ + GMainLoop *main_loop = NULL; + gint32 ret = -1; + + STC_LOGI("Smart Traffic Control Manager"); + + if (daemon(0, 0) != 0) + STC_LOGE("Can't start daemon"); + + /* Initialize required subsystems */ +#if !GLIB_CHECK_VERSION(2, 35, 0) + g_type_init(); +#endif + + g_stc = __stc_manager_init(); + if (!g_stc) + goto fail; + + /* Crate the GLIB main loop */ + main_loop = g_main_loop_new(NULL, FALSE); + g_stc->main_loop = main_loop; + + /* Run the main loop */ + g_main_loop_run(main_loop); + + ret = 0; + +fail: + __stc_manager_deinit(); + + if (main_loop) + g_main_loop_unref(main_loop); + + return ret; +} diff --git a/src/stc-restriction.c b/src/stc-restriction.c new file mode 100755 index 0000000..fc1d6b4 --- /dev/null +++ b/src/stc-restriction.c @@ -0,0 +1,454 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "stc-db.h" +#include "table-restrictions.h" +#include "stc-restriction.h" +#include "stc-manager-gdbus.h" +#include "stc-monitor.h" + +#define RESTRICTION_DBUS_ERROR_NAME "net.stc.restriction.Error.Failed" + +#define STC_RESTRICTION_DBUS_REPLY_ERROR(invocation, err_num) \ + g_dbus_method_invocation_return_dbus_error((invocation), \ + RESTRICTION_DBUS_ERROR_NAME, \ + stc_err_strs[-(err_num)]) + +static const gchar *stc_err_strs[] = { + "ERROR_NONE", + "FAIL", + "DB_FAILED", + "OUT_OF_MEMORY", + "INVALID_PARAMETER", + "NO_DATA", + "UNINITIALIZED", + "NOTIMPL" +}; + +void __initialize_rstn_rule(table_restrictions_info *rule) +{ + rule->app_id = NULL; + rule->ifname = NULL; + rule->iftype = STC_IFACE_ALL; + rule->rst_state = STC_RESTRICTION_REMOVED; + rule->rcv_limit = 0; + rule->send_limit = 0; + rule->rcv_warn_limit = 0; + rule->send_warn_limit = 0; + rule->roaming = STC_ROAMING_DISABLE; + rule->imsi = NULL; +} + +gboolean __validate_rstn_rule(table_restrictions_info *rule, + enum traffic_restriction_type rst_type) +{ + __STC_LOG_FUNC_ENTER__; + + if (rule == NULL) { + __STC_LOG_FUNC_EXIT__; + return FALSE; + } + + if (rst_type <= RST_UNDEFINDED || rst_type >= RST_MAX_VALUE) { + __STC_LOG_FUNC_EXIT__; + return FALSE; + } + + if (rule->iftype <= STC_IFACE_UNKNOWN || + rule->iftype >= STC_IFACE_LAST_ELEM) { + __STC_LOG_FUNC_EXIT__; + return FALSE; + } + + if (rst_type == RST_SET) { + if (rule->rcv_limit < 0) { + __STC_LOG_FUNC_EXIT__; + return FALSE; + } + + if (rule->send_limit < 0) { + __STC_LOG_FUNC_EXIT__; + return FALSE; + } + + if (rule->rcv_warn_limit < 0) { + __STC_LOG_FUNC_EXIT__; + return FALSE; + } + + if (rule->send_warn_limit < 0) { + __STC_LOG_FUNC_EXIT__; + return FALSE; + } + } + + if (rule->roaming >= STC_ROAMING_LAST_ELEM) { + __STC_LOG_FUNC_EXIT__; + return FALSE; + } + + if (rule->imsi == NULL) { + __STC_LOG_FUNC_EXIT__; + return FALSE; + } + + if (rule->app_id == NULL) { + __STC_LOG_FUNC_EXIT__; + return FALSE; + } + + __STC_LOG_FUNC_EXIT__; + return TRUE; +} + +void __stc_restriction_app_info_builder_add(GVariantBuilder *builder, + const table_restrictions_info *info) +{ + __STC_LOG_FUNC_ENTER__; + + if (!builder || !info) { + __STC_LOG_FUNC_EXIT__; + return; + } + + g_variant_builder_add(builder, "{sv}", "app_id", + g_variant_new_string(info->app_id)); + + g_variant_builder_add(builder, "{sv}", "ifname", + g_variant_new_string(info->ifname)); + + g_variant_builder_add(builder, "{sv}", "iftype", + g_variant_new_uint16(info->iftype)); + + g_variant_builder_add(builder, "{sv}", "rst_state", + g_variant_new_uint16(info->rst_state)); + + g_variant_builder_add(builder, "{sv}", "rcv_limit", + g_variant_new_uint64(info->rcv_limit)); + + g_variant_builder_add(builder, "{sv}", "send_limit", + g_variant_new_uint64(info->send_limit)); + + g_variant_builder_add(builder, "{sv}", "rcv_warn_limit", + g_variant_new_uint64(info->rcv_warn_limit)); + + g_variant_builder_add(builder, "{sv}", "send_warn_limit", + g_variant_new_uint64(info->send_warn_limit)); + + g_variant_builder_add(builder, "{sv}", "roaming", + g_variant_new_uint16(info->roaming)); + + g_variant_builder_add(builder, "{sv}", "imsi", + g_variant_new_string(info->imsi)); + + __STC_LOG_FUNC_EXIT__; +} + +stc_cb_ret_e __table_restrictions_foreach_app_cb(const table_restrictions_info *info, + void *user_data) +{ + __STC_LOG_FUNC_ENTER__; + GVariantBuilder *builder = (GVariantBuilder *)user_data; + GVariantBuilder sub_builder; + + if (!info || !builder) { + __STC_LOG_FUNC_EXIT__; + return STC_CANCEL; + } + + g_variant_builder_init(&sub_builder, G_VARIANT_TYPE("a{sv}")); + __stc_restriction_app_info_builder_add(&sub_builder, info); + + g_variant_builder_add_value(builder, + g_variant_builder_end(&sub_builder)); + + __STC_LOG_FUNC_EXIT__; + return STC_CONTINUE; +} + +stc_cb_ret_e __table_restrictions_per_app_cb(const table_restrictions_info *info, + void *user_data) +{ + __STC_LOG_FUNC_ENTER__; + GVariantBuilder *builder = (GVariantBuilder *)user_data; + + if (!info || !builder) { + __STC_LOG_FUNC_EXIT__; + return STC_CANCEL; + } + + __stc_restriction_app_info_builder_add(builder, info); + + __STC_LOG_FUNC_EXIT__; + return STC_CONTINUE; +} + +static void __stc_extract_restriction_rule(const char *key, GVariant *value, + void *user_data) +{ + __STC_LOG_FUNC_ENTER__; + + table_restrictions_info *rule = + (table_restrictions_info *) user_data; + if (rule == NULL) { + __STC_LOG_FUNC_EXIT__; + return; + } + + if (!g_strcmp0(key, "app_id")) { + guint str_length; + const gchar *str = g_variant_get_string(value, &str_length); + rule->app_id = g_strdup(str); + STC_LOGD("app_id: [%s]", (unsigned int) rule->app_id); + + } else if (!g_strcmp0(key, "ifname")) { + guint str_length; + const gchar *str = g_variant_get_string(value, &str_length); + rule->ifname = g_strdup(str); + STC_LOGD("ifname: [%s]", rule->ifname); + + } else if (!g_strcmp0(key, "iftype")) { + rule->iftype = g_variant_get_uint16(value); + STC_LOGD("iftype: [%u]", (unsigned int) rule->iftype); + + } else if (!g_strcmp0(key, "rcv_limit")) { + rule->rcv_limit = g_variant_get_uint64(value); + STC_LOGD("rcv_limit: [%llu]", rule->rcv_limit); + + } else if (!g_strcmp0(key, "send_limit")) { + rule->send_limit = g_variant_get_uint64(value); + STC_LOGD("send_limit: [%llu]", rule->send_limit); + + } else if (!g_strcmp0(key, "rcv_warn_limit")) { + rule->rcv_warn_limit = g_variant_get_uint64(value); + STC_LOGD("rcv_warn_limit: [%llu]", rule->rcv_warn_limit); + + } else if (!g_strcmp0(key, "send_warn_limit")) { + rule->send_warn_limit = g_variant_get_uint64(value); + STC_LOGD("send_warn_limit: [%llu]", rule->send_warn_limit); + + } else if (!g_strcmp0(key, "roaming")) { + rule->roaming = g_variant_get_uint16(value); + STC_LOGD("roaming: [%u]", rule->roaming); + + } else if (!g_strcmp0(key, "imsi")) { + guint str_length; + const gchar *str = g_variant_get_string(value, &str_length); + rule->imsi = g_strdup(str); + STC_LOGD("imsi: [%s]", rule->imsi); + + } else { + STC_LOGD("Unknown select rule"); + } + + __STC_LOG_FUNC_EXIT__; +} + +gboolean handle_restriction_set(StcRestriction *object, + GDBusMethodInvocation *invocation, + GVariant *parameters, + void *user_data) +{ + __STC_LOG_FUNC_ENTER__; + GVariantIter *iter = NULL; + table_restrictions_info rule; + + memset(&rule, 0, sizeof(table_restrictions_info)); + __initialize_rstn_rule(&rule); + + g_variant_get(parameters, "a{sv}", &iter); + if (iter != NULL) { + stc_manager_gdbus_dict_foreach(iter, + __stc_extract_restriction_rule, + &rule); + g_variant_iter_free(iter); + } + + rule.rst_state = STC_RESTRICTION_REMOVED; + + if (__validate_rstn_rule(&rule, RST_SET) == FALSE) { + STC_RESTRICTION_DBUS_REPLY_ERROR(invocation, + STC_ERROR_INVALID_PARAMETER); + __STC_LOG_FUNC_EXIT__; + return TRUE; + } + + table_restrictions_update(&rule); + /* update restriction rule in runtime structure */ + stc_monitor_rstns_tree_add(&rule); + + STC_DBUS_REPLY_ERROR_NONE(invocation); + __STC_LOG_FUNC_EXIT__; + return TRUE; +} + +gboolean handle_restriction_exclude(StcRestriction *object, + GDBusMethodInvocation *invocation, + GVariant *parameters, + void *user_data) +{ + __STC_LOG_FUNC_ENTER__; + GVariantIter *iter = NULL; + table_restrictions_info rule; + + memset(&rule, 0, sizeof(table_restrictions_info)); + __initialize_rstn_rule(&rule); + + g_variant_get(parameters, "a{sv}", &iter); + if (iter != NULL) { + stc_manager_gdbus_dict_foreach(iter, + __stc_extract_restriction_rule, + &rule); + g_variant_iter_free(iter); + } + + rule.rst_state = STC_RESTRICTION_EXCLUDED; + + if (__validate_rstn_rule(&rule, RST_EXCLUDE) == FALSE) { + STC_RESTRICTION_DBUS_REPLY_ERROR(invocation, + STC_ERROR_INVALID_PARAMETER); + __STC_LOG_FUNC_EXIT__; + return TRUE; + } + + table_restrictions_update(&rule); + /* update restriction rule in runtime structure */ + stc_monitor_rstns_tree_add(&rule); + + STC_DBUS_REPLY_ERROR_NONE(invocation); + __STC_LOG_FUNC_EXIT__; + return TRUE; +} + +gboolean handle_restriction_remove(StcRestriction *object, + GDBusMethodInvocation *invocation, + GVariant *parameters, + void *user_data) +{ + __STC_LOG_FUNC_ENTER__; + GVariantIter *iter = NULL; + table_restrictions_info rule; + + memset(&rule, 0, sizeof(table_restrictions_info)); + __initialize_rstn_rule(&rule); + + g_variant_get(parameters, "a{sv}", &iter); + if (iter != NULL) { + stc_manager_gdbus_dict_foreach(iter, + __stc_extract_restriction_rule, + &rule); + g_variant_iter_free(iter); + } + + if (__validate_rstn_rule(&rule, RST_UNSET) == FALSE) { + STC_RESTRICTION_DBUS_REPLY_ERROR(invocation, + STC_ERROR_INVALID_PARAMETER); + __STC_LOG_FUNC_EXIT__; + return TRUE; + } + + table_restrictions_delete(rule.app_id, rule.iftype, rule.imsi); + /* remove restriction rule from runtime structure */ + stc_monitor_rstns_tree_remove(&rule); + + STC_DBUS_REPLY_ERROR_NONE(invocation); + __STC_LOG_FUNC_EXIT__; + return TRUE; +} + +gboolean handle_restriction_get(StcRestriction *object, + GDBusMethodInvocation *invocation, + const gchar *app_id, + void *user_data) +{ + __STC_LOG_FUNC_ENTER__; + GVariantBuilder *builder = NULL; + GVariant *return_parameters = NULL; + stc_error_e ret; + + builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}")); + + ret = table_restrictions_per_app(app_id, + __table_restrictions_per_app_cb, + builder); + if (ret < STC_ERROR_NONE) { + g_variant_builder_unref(builder); + STC_RESTRICTION_DBUS_REPLY_ERROR(invocation, ret); + __STC_LOG_FUNC_EXIT__; + return TRUE; + } + + return_parameters = g_variant_new("(ia{sv})", STC_ERROR_NONE, builder); + g_variant_builder_unref(builder); + + DEBUG_GDBUS_VARIANT("Return parameters: ", return_parameters); + STC_DBUS_REPLY(invocation, return_parameters); + __STC_LOG_FUNC_EXIT__; + return TRUE; +} + +gboolean handle_restriction_get_all(StcRestriction *object, + GDBusMethodInvocation *invocation, + void *user_data) +{ + __STC_LOG_FUNC_ENTER__; + GVariantBuilder *builder = NULL; + GVariant *return_parameters = NULL; + stc_error_e ret; + + builder = g_variant_builder_new(G_VARIANT_TYPE("aa{sv}")); + + ret = table_restrictions_foreach(__table_restrictions_foreach_app_cb, + builder); + if (ret < STC_ERROR_NONE) { + g_variant_builder_unref(builder); + STC_RESTRICTION_DBUS_REPLY_ERROR(invocation, ret); + __STC_LOG_FUNC_EXIT__; + return TRUE; + } + + return_parameters = g_variant_new("(iaa{sv})", STC_ERROR_NONE, builder); + g_variant_builder_unref(builder); + + DEBUG_GDBUS_VARIANT("Return parameters: ", return_parameters); + STC_DBUS_REPLY(invocation, return_parameters); + __STC_LOG_FUNC_EXIT__; + return TRUE; +} + +gboolean handle_restriction_get_state(StcRestriction *object, + GDBusMethodInvocation *invocation, + const gchar *app_id, + int iftype, + void *user_data) +{ + __STC_LOG_FUNC_ENTER__; + GVariant *return_parameters = NULL; + stc_restriction_state_e state = STC_RESTRICTION_UNKNOWN; + stc_error_e ret; + + ret = table_restrictions_get_restriction_state(app_id, iftype, &state); + if (ret < STC_ERROR_NONE) { + STC_RESTRICTION_DBUS_REPLY_ERROR(invocation, ret); + __STC_LOG_FUNC_EXIT__; + return TRUE; + } + + return_parameters = g_variant_new("(ii)", STC_ERROR_NONE, state); + STC_DBUS_REPLY(invocation, return_parameters); + __STC_LOG_FUNC_EXIT__; + return TRUE; +} diff --git a/src/stc-statistics.c b/src/stc-statistics.c new file mode 100755 index 0000000..a2a72fd --- /dev/null +++ b/src/stc-statistics.c @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "stc-db.h" +#include "table-statistics.h" +#include "stc-statistics.h" +#include "stc-manager-gdbus.h" + +#define STATISTICS_DBUS_ERROR_NAME "net.stc.statistics.Error.Failed" + +#define STC_DBUS_REPLY(invocation, parameters) \ + g_dbus_method_invocation_return_value((invocation), parameters); + +#define STC_STATISTICS_DBUS_REPLY_ERROR(invocation, err_num) \ + g_dbus_method_invocation_return_dbus_error((invocation), \ + STATISTICS_DBUS_ERROR_NAME, \ + stc_err_strs[-(err_num)]) + +static const gchar *stc_err_strs[] = { + "ERROR_NONE", + "FAIL", + "DB_FAILED", + "OUT_OF_MEMORY", + "INVALID_PARAMETER", + "NO_DATA", + "UNINITIALIZED", + "NOTIMPL" +}; + +void __stc_statistics_print_app_info(const table_statistics_info *info) +{ + if (!info) + return; + + STC_LOGD("========== App data (Statistics) =========="); + STC_LOGD("app_id : [%s]", info->app_id ? info->app_id : "NULL"); + STC_LOGD("ifname : [%s]", info->ifname ? info->ifname : "NULL"); + STC_LOGD("Sent : [%llu] bytes", info->cnt.out_bytes); + STC_LOGD("Received : [%llu] bytes", info->cnt.in_bytes); + STC_LOGD("==========================================="); +} + +void __stc_extract_select_rule(const char *key, GVariant *value, + void *user_data) +{ + __STC_LOG_FUNC_ENTER__; + + table_statistics_select_rule *rule = + (table_statistics_select_rule *) user_data; + if (rule == NULL) { + __STC_LOG_FUNC_EXIT__; + return; + } + + if (!g_strcmp0(key, "version")) { + rule->version = g_variant_get_byte(value); + STC_LOGD("version: [%u]", (unsigned int) rule->version); + + } else if (!g_strcmp0(key, "from")) { + rule->from = g_variant_get_uint64(value); + STC_LOGD("from: [%lu]", rule->from); + + } else if (!g_strcmp0(key, "to")) { + rule->to = g_variant_get_uint64(value); + STC_LOGD("to: [%lu]", rule->to); + + } else if (!g_strcmp0(key, "iftype")) { + rule->iftype = g_variant_get_uint16(value); + STC_LOGD("iftype: [%u]", (unsigned int) rule->iftype); + + } else if (!g_strcmp0(key, "granularity")) { + rule->granularity = g_variant_get_int32(value); + STC_LOGD("granularity: [%d]", rule->granularity); + + } else { + STC_LOGD("Unknown select rule"); + } + + __STC_LOG_FUNC_EXIT__; +} + +void __stc_extract_reset_rule(const char *key, GVariant *value, + void *user_data) +{ + __STC_LOG_FUNC_ENTER__; + + table_statistics_reset_rule *rule = + (table_statistics_reset_rule *) user_data; + if (rule == NULL) { + __STC_LOG_FUNC_EXIT__; + return; + } + + if (!g_strcmp0(key, "version")) { + rule->version = g_variant_get_byte(value); + STC_LOGD("version: [%u]", (unsigned int) rule->version); + + } else if (!g_strcmp0(key, "app_id")) { + gsize len = 0; + rule->app_id = g_variant_dup_string(value, &len); + STC_LOGD("app_id: [%s]", rule->app_id); + + } else if (!g_strcmp0(key, "imsi")) { + gsize len = 0; + rule->imsi = g_variant_dup_string(value, &len); + STC_LOGD("imsi: [%s]", rule->imsi); + + } else if (!g_strcmp0(key, "iftype")) { + rule->iftype = g_variant_get_uint16(value); + STC_LOGD("iftype: [%u]", (unsigned int) rule->iftype); + + } else if (!g_strcmp0(key, "from")) { + if (!(rule->interval)) { + rule->interval = MALLOC0(stc_db_tm_interval_s, 1); + if (!(rule->interval)) { + __STC_LOG_FUNC_EXIT__; + return; + } + } + + rule->interval->from = g_variant_get_uint64(value); + STC_LOGD("from: [%lu]", rule->interval->from); + + } else if (!g_strcmp0(key, "to")) { + if (!(rule->interval)) { + rule->interval = MALLOC0(stc_db_tm_interval_s, 1); + if (!(rule->interval)) { + __STC_LOG_FUNC_EXIT__; + return; + } + } + + rule->interval->to = g_variant_get_uint64(value); + STC_LOGD("to: [%lu]", rule->interval->to); + + } else if (!g_strcmp0(key, "connection_state")) { + rule->connection_state = g_variant_get_int32(value); + STC_LOGD("connection_state: [%d]", rule->connection_state); + + } else { + STC_LOGD("Unknown reset rule"); + } + + __STC_LOG_FUNC_EXIT__; +} + +void __stc_statistics_app_info_builder_add(GVariantBuilder *builder, + const table_statistics_info *info) +{ + __STC_LOG_FUNC_ENTER__; + + if (!builder || !info) { + __STC_LOG_FUNC_EXIT__; + return; + } + + g_variant_builder_add(builder, "{sv}", "app_id", + g_variant_new_string(info->app_id)); + + g_variant_builder_add(builder, "{sv}", "ifname", + g_variant_new_string(info->ifname)); + + g_variant_builder_add(builder, "{sv}", "imsi", + g_variant_new_string(info->imsi)); + + g_variant_builder_add(builder, "{sv}", "iftype", + g_variant_new_uint16(info->iftype)); + + if (info->interval != NULL) { + g_variant_builder_add(builder, "{sv}", "interval_to", + g_variant_new_uint64(info->interval->to)); + + g_variant_builder_add(builder, "{sv}", "interval_from", + g_variant_new_uint64(info->interval->from)); + } + + g_variant_builder_add(builder, "{sv}", "cnt_out_bytes", + g_variant_new_uint64(info->cnt.out_bytes)); + + g_variant_builder_add(builder, "{sv}", "cnt_in_bytes", + g_variant_new_uint64(info->cnt.in_bytes)); + + g_variant_builder_add(builder, "{sv}", "roaming", + g_variant_new_uint16(info->roaming)); + + g_variant_builder_add(builder, "{sv}", "hw_net_protocol_type", + g_variant_new_uint16(info->hw_net_protocol_type)); + + g_variant_builder_add(builder, "{sv}", "ground", + g_variant_new_uint16(info->ground)); + + __STC_LOG_FUNC_EXIT__; +} + +stc_cb_ret_e __table_statistics_foreach_app_cb(const table_statistics_info *info, + void *user_data) +{ + __STC_LOG_FUNC_ENTER__; + GVariantBuilder *builder = (GVariantBuilder *)user_data; + GVariantBuilder sub_builder; + + if (!info || !builder) { + __STC_LOG_FUNC_EXIT__; + return STC_CANCEL; + } + + g_variant_builder_init(&sub_builder, G_VARIANT_TYPE("a{sv}")); + __stc_statistics_app_info_builder_add(&sub_builder, info); + __stc_statistics_print_app_info(info); + g_variant_builder_add_value(builder, + g_variant_builder_end(&sub_builder)); + + __STC_LOG_FUNC_EXIT__; + return STC_CONTINUE; +} + +stc_cb_ret_e __table_statistics_per_app_cb(const table_statistics_info *info, + void *user_data) +{ + __STC_LOG_FUNC_ENTER__; + GVariantBuilder *builder = (GVariantBuilder *)user_data; + + if (!info || !builder) { + __STC_LOG_FUNC_EXIT__; + return STC_CANCEL; + } + + __stc_statistics_app_info_builder_add(builder, info); + __stc_statistics_print_app_info(info); + + __STC_LOG_FUNC_EXIT__; + return STC_CONTINUE; +} + +gboolean handle_statistics_get_all(StcStatistics *object, + GDBusMethodInvocation *invocation, + GVariant *select_rule, + void *user_data) +{ + __STC_LOG_FUNC_ENTER__; + table_statistics_select_rule rule = {0, }; + const time_t cur_time = time(0); + const time_t epoch = 0; + GVariantBuilder *builder = NULL; + GVariant *return_parameters = NULL; + stc_error_e ret; + + /* Total statistics since epoch */ + rule.from = epoch; + rule.to = cur_time; + rule.iftype = STC_IFACE_ALL; + + if (select_rule != NULL) { + DEBUG_GDBUS_VARIANT("Selection rule: ", select_rule); + GVariantIter *iter = NULL; + + g_variant_get(select_rule, "a{sv}", &iter); + if (iter != NULL) { + stc_manager_gdbus_dict_foreach(iter, + __stc_extract_select_rule, + &rule); + g_variant_iter_free(iter); + } + } else { + STC_LOGD("No selection rule, using default selection rule."); + } + + builder = g_variant_builder_new(G_VARIANT_TYPE("aa{sv}")); + + ret = table_statistics_foreach_app(&rule, + __table_statistics_foreach_app_cb, + builder); + if (ret < STC_ERROR_NONE) { + g_variant_builder_unref(builder); + STC_STATISTICS_DBUS_REPLY_ERROR(invocation, ret); + __STC_LOG_FUNC_EXIT__; + return TRUE; + } + + return_parameters = g_variant_new("(iaa{sv})", STC_ERROR_NONE, builder); + g_variant_builder_unref(builder); + + DEBUG_GDBUS_VARIANT("Return parameters: ", return_parameters); + STC_DBUS_REPLY(invocation, return_parameters); + + __STC_LOG_FUNC_EXIT__; + return TRUE; +} + +gboolean handle_statistics_get(StcStatistics *object, + GDBusMethodInvocation *invocation, + const gchar *app_id, + GVariant *select_rule, + void *user_data) +{ + __STC_LOG_FUNC_ENTER__; + table_statistics_select_rule rule = {0, }; + const time_t cur_time = time(0); + const time_t epoch = 0; + GVariantBuilder *builder = NULL; + GVariant *return_parameters = NULL; + stc_error_e ret; + + /* Total statistics since epoch */ + rule.from = epoch; + rule.to = cur_time; + rule.iftype = STC_IFACE_ALL; + + if (select_rule != NULL) { + DEBUG_GDBUS_VARIANT("Selection rule: ", select_rule); + GVariantIter *iter = NULL; + + g_variant_get(select_rule, "a{sv}", &iter); + if (iter != NULL) { + stc_manager_gdbus_dict_foreach(iter, + __stc_extract_select_rule, + &rule); + g_variant_iter_free(iter); + } + } else { + STC_LOGD("No selection rule, using default selection rule."); + } + + builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}")); + + ret = table_statistics_per_app(app_id, &rule, + __table_statistics_per_app_cb, + builder); + if (ret < STC_ERROR_NONE) { + g_variant_builder_unref(builder); + STC_STATISTICS_DBUS_REPLY_ERROR(invocation, ret); + __STC_LOG_FUNC_EXIT__; + return TRUE; + } + + return_parameters = g_variant_new("(ia{sv})", STC_ERROR_NONE, builder); + g_variant_builder_unref(builder); + + DEBUG_GDBUS_VARIANT("Return parameters: ", return_parameters); + STC_DBUS_REPLY(invocation, return_parameters); + + __STC_LOG_FUNC_EXIT__; + return TRUE; +} + +gboolean handle_statistics_reset(StcStatistics *object, + GDBusMethodInvocation *invocation, + GVariant *reset_rule, + void *user_data) +{ + __STC_LOG_FUNC_ENTER__; + table_statistics_reset_rule rule = {0, }; + GVariant *return_parameters = NULL; + stc_error_e ret; + + if (reset_rule != NULL) { + DEBUG_GDBUS_VARIANT("Selection rule: ", reset_rule); + GVariantIter *iter = NULL; + + g_variant_get(reset_rule, "a{sv}", &iter); + if (iter != NULL) { + stc_manager_gdbus_dict_foreach(iter, + __stc_extract_reset_rule, + &rule); + g_variant_iter_free(iter); + } + } else { + STC_LOGD("No selection rule, using default selection rule."); + } + + ret = table_statistics_reset(&rule); + if (ret < STC_ERROR_NONE) { + STC_STATISTICS_DBUS_REPLY_ERROR(invocation, ret); + goto handle_error; + } + + return_parameters = g_variant_new("(i)", STC_ERROR_NONE); + + DEBUG_GDBUS_VARIANT("Return parameters: ", return_parameters); + STC_DBUS_REPLY(invocation, return_parameters); + +handle_error: + FREE(rule.app_id); + FREE(rule.imsi); + FREE(rule.interval); + __STC_LOG_FUNC_EXIT__; + return TRUE; +} diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt new file mode 100644 index 0000000..c9ca10b --- /dev/null +++ b/src/utils/CMakeLists.txt @@ -0,0 +1,5 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) + +SET(NET_CLS_RELEASE "net-cls-release") +ADD_EXECUTABLE(${NET_CLS_RELEASE} ${CMAKE_CURRENT_SOURCE_DIR}/${NET_CLS_RELEASE}.c) +INSTALL(TARGETS ${NET_CLS_RELEASE} RUNTIME DESTINATION ${BIN_DIR}) diff --git a/src/utils/net-cls-release.c b/src/utils/net-cls-release.c new file mode 100644 index 0000000..8f75dc8 --- /dev/null +++ b/src/utils/net-cls-release.c @@ -0,0 +1,19 @@ +#include +#include +#include + +#define MAX_PATH_LENGTH 512 +#define DEFAULT_CGROUP "/sys/fs/cgroup" +#define CGROUP_NETWORK DEFAULT_CGROUP "/net_cls" +#define PATH_TO_NET_CGROUP_DIR CGROUP_NETWORK + +int main(int argc, char *argv[]) +{ + char buf[MAX_PATH_LENGTH]; + if (argc < 2) + return 1; + + /* kernel already adds symbol '/' before cgroup name */ + sprintf(buf, "%s/%s", PATH_TO_NET_CGROUP_DIR, argv[1]); + return rmdir(buf); +} diff --git a/stc-manager.manifest b/stc-manager.manifest new file mode 100644 index 0000000..81ace0c --- /dev/null +++ b/stc-manager.manifest @@ -0,0 +1,6 @@ + + + + + + -- 2.7.4 From 8cf8059a714d925d9f8ccdd56eedb2648f0c7c90 Mon Sep 17 00:00:00 2001 From: hyunuktak Date: Wed, 10 May 2017 17:23:58 +0900 Subject: [PATCH 03/11] Fixed some svace issues Change-Id: I1e02c3655b3601b6b855c33f5660940c696595c6 Signed-off-by: hyunuktak --- packaging/stc-manager.spec | 2 +- src/database/db-common.c | 0 src/database/db-guard.c | 3 ++- src/helper/helper-net-cls.c | 2 +- src/helper/helper-nfacct-rule.c | 40 ++++++++++++++++++++++++---------------- src/stc-restriction.c | 22 ---------------------- src/utils/net-cls-release.c | 2 +- 7 files changed, 29 insertions(+), 42 deletions(-) mode change 100644 => 100755 src/database/db-common.c mode change 100644 => 100755 src/database/db-guard.c mode change 100644 => 100755 src/utils/net-cls-release.c diff --git a/packaging/stc-manager.spec b/packaging/stc-manager.spec index 352f24b..686702f 100644 --- a/packaging/stc-manager.spec +++ b/packaging/stc-manager.spec @@ -1,6 +1,6 @@ Name: stc-manager Summary: STC(Smart Traffic Control) manager -Version: 0.0.1 +Version: 0.0.2 Release: 0 Group: Network & Connectivity/Other License: Apache-2.0 diff --git a/src/database/db-common.c b/src/database/db-common.c old mode 100644 new mode 100755 diff --git a/src/database/db-guard.c b/src/database/db-guard.c old mode 100644 new mode 100755 index 46a9c32..5d03183 --- a/src/database/db-guard.c +++ b/src/database/db-guard.c @@ -87,6 +87,7 @@ static void __erase_old_entries(void) }; stc_db_tm_interval_s interval; time_t until = time(0); + struct tm result = {0, }; until -= ERASE_INTERVAL; @@ -94,7 +95,7 @@ static void __erase_old_entries(void) interval.to = until; rule.interval = &interval; - strftime(buffer, 80, "%x - %I:%M%p", localtime(&until)); + strftime(buffer, 80, "%x - %I:%M%p", localtime_r(&until, &result)); STC_LOGD("Reset statistics till %s", buffer); if (table_statistics_reset(&rule) != STC_ERROR_NONE) diff --git a/src/helper/helper-net-cls.c b/src/helper/helper-net-cls.c index a3099bd..63f7b2d 100755 --- a/src/helper/helper-net-cls.c +++ b/src/helper/helper-net-cls.c @@ -34,7 +34,7 @@ typedef GArray task_classid_array; static uint32_t __produce_classid(check_classid_used_cb check_classid_cb) { uint32_t classid = STC_RESERVED_CLASSID_MAX; - int classid_test_count; + int classid_test_count = 0; int ret = fread_uint(CUR_CLASSID_PATH, &classid); if (ret < 0) STC_LOGE("Can not read current classid"); diff --git a/src/helper/helper-nfacct-rule.c b/src/helper/helper-nfacct-rule.c index f2b819f..94ad5d1 100755 --- a/src/helper/helper-nfacct-rule.c +++ b/src/helper/helper-nfacct-rule.c @@ -55,6 +55,7 @@ #define NFNL_SUBSYS_ACCT 7 +#define BUF_SIZE_FOR_ERR 100 static void prepare_netlink_msg(struct genl *req, int type, int flag) { @@ -238,6 +239,7 @@ bool recreate_counter_by_name(char *cnt_name, nfacct_rule_s *cnt) char *classid_part; char *io_part; char *ifname_part; + char *save_ptr = NULL; char name[NFACCT_NAME_MAX] = {0}; /* parse buffer to avoid cnt_name modification */ strncpy(name, cnt_name, sizeof(name) - 1); @@ -276,7 +278,7 @@ bool recreate_counter_by_name(char *cnt_name, nfacct_rule_s *cnt) iface = get_iftype_by_name(ifname_buf); /* check first part is it datacall */ if (iface == STC_IFACE_DATACALL) { - strcpy(cnt->ifname, ifname_buf); + strncpy(cnt->ifname, ifname_buf, MAX_IFACE_LENGTH); cnt->iotype = NFACCT_COUNTER_IN; } else { /* +1, due : symbol and till the end of cnt_name */ @@ -297,19 +299,19 @@ bool recreate_counter_by_name(char *cnt_name, nfacct_rule_s *cnt) return true; } - io_part = strtok(name, "_"); + io_part = strtok_r(name, "_", &save_ptr); if (io_part != NULL) cnt->iotype = convert_to_iotype(atoi(io_part + 1)); else return false; - iftype_part = strtok(NULL, "_"); + iftype_part = strtok_r(NULL, "_", &save_ptr); if (iftype_part != NULL) cnt->iftype = convert_to_iftype(atoi(iftype_part)); else return false; - classid_part = strtok(NULL, "_"); + classid_part = strtok_r(NULL, "_", &save_ptr); if (classid_part != NULL) cnt->classid = atoi(classid_part); else { @@ -317,7 +319,7 @@ bool recreate_counter_by_name(char *cnt_name, nfacct_rule_s *cnt) return cnt->intend == NFACCT_BLOCK ? true : false; } - ifname_part = strtok(NULL, "\0"); + ifname_part = strtok_r(NULL, "\0", &save_ptr); if (ifname_part != NULL) STRING_SAVE_COPY(cnt->ifname, ifname_part); else @@ -386,6 +388,8 @@ static void wait_for_rule_cmd(pid_t pid) { int status; pid_t ret_pid; + char buf[BUF_SIZE_FOR_ERR] = { 0 }; + if (!pid) { STC_LOGD("no need to wait"); return; @@ -393,7 +397,7 @@ static void wait_for_rule_cmd(pid_t pid) ret_pid = waitpid(pid, &status, 0); if (ret_pid < 0) STC_LOGD("can't wait for a pid %d %d %s", pid, status, - strerror(errno)); + strerror_r(errno, buf, BUF_SIZE_FOR_ERR)); } static char* get_cmd_pos(const char *cmd_buf) @@ -440,6 +444,8 @@ stc_error_e exec_iptables_cmd(const char *cmd_buf, pid_t *cmd_pid) const size_t args_number = get_args_number(cmd_buf); char *args[args_number + 2]; int ret; + char *save_ptr = NULL; + char buf[BUF_SIZE_FOR_ERR] = { 0 }; STC_LOGD("executing iptables cmd %s in forked process", cmd_buf); @@ -451,17 +457,17 @@ stc_error_e exec_iptables_cmd(const char *cmd_buf, pid_t *cmd_pid) exit(0); } args[0] = "iptables"; - cmd = strtok((char *)cmd_buf, " "); + cmd = strtok_r((char *)cmd_buf, " ", &save_ptr); ret_value_msg_if(cmd == NULL, STC_ERROR_FAIL, "no arguments"); for (i = 1; i <= args_number; ++i) - args[i] = strtok(NULL, " "); + args[i] = strtok_r(NULL, " ", &save_ptr); args[i] = NULL; ret = execv(cmd, args); if (ret) STC_LOGE("Can't execute %s: %s", - cmd_buf, strerror(errno)); + cmd_buf, strerror_r(errno, buf, BUF_SIZE_FOR_ERR)); exit(ret); } @@ -479,6 +485,8 @@ stc_error_e exec_ip6tables_cmd(const char *cmd_buf, pid_t *cmd_pid) const size_t args_number = get_args_number(cmd_buf); char *args[args_number + 2]; int ret; + char *save_ptr = NULL; + char buf[BUF_SIZE_FOR_ERR] = { 0 }; STC_LOGD("executing ip6tables cmd %s in forked process", cmd_buf); @@ -490,17 +498,17 @@ stc_error_e exec_ip6tables_cmd(const char *cmd_buf, pid_t *cmd_pid) exit(0); } args[0] = "ip6tables"; - cmd = strtok((char *)cmd_buf, " "); + cmd = strtok_r((char *)cmd_buf, " ", &save_ptr); ret_value_msg_if(cmd == NULL, STC_ERROR_FAIL, "no arguments"); for (i = 1; i <= args_number; ++i) - args[i] = strtok(NULL, " "); + args[i] = strtok_r(NULL, " ", &save_ptr); args[i] = NULL; ret = execv(cmd, args); if (ret) STC_LOGE("Can't execute %s: %s", - cmd_buf, strerror(errno)); + cmd_buf, strerror_r(errno, buf, BUF_SIZE_FOR_ERR)); exit(ret); } @@ -526,14 +534,14 @@ static stc_error_e exec_iface_cmd(const char *pattern, const char *cmd, "Invalid network interface name argument"); /* iptables rule */ - ret = sprintf(block_buf, pattern, IPTABLES, cmd, chain, + ret = snprintf(block_buf, sizeof(block_buf), pattern, IPTABLES, cmd, chain, iftype_name, nfacct, jump); ret_value_msg_if(ret > sizeof(block_buf), STC_ERROR_FAIL, "Not enough buffer"); exec_iptables_cmd(block_buf, pid); /* ip6tables rule */ - ret = sprintf(block_buf, pattern, IP6TABLES, cmd, chain, + ret = snprintf(block_buf, sizeof(block_buf), pattern, IP6TABLES, cmd, chain, iftype_name, nfacct, jump); ret_value_msg_if(ret > sizeof(block_buf), STC_ERROR_FAIL, "Not enough buffer"); @@ -551,14 +559,14 @@ static stc_error_e exec_app_cmd(const char *pattern, const char *cmd, "Invalid network interface name argument"); /* iptables rules */ - ret = sprintf(block_buf, pattern, IPTABLES, cmd, + ret = snprintf(block_buf, sizeof(block_buf), pattern, IPTABLES, cmd, iftype_name, classid, nfacct, jump); ret_value_msg_if(ret > sizeof(block_buf), STC_ERROR_FAIL, "Not enough buffer"); exec_iptables_cmd(block_buf, pid); /* ip6tables rules */ - ret = sprintf(block_buf, pattern, IP6TABLES, cmd, + ret = snprintf(block_buf, sizeof(block_buf), pattern, IP6TABLES, cmd, iftype_name, classid, nfacct, jump); ret_value_msg_if(ret > sizeof(block_buf), STC_ERROR_FAIL, "Not enough buffer"); diff --git a/src/stc-restriction.c b/src/stc-restriction.c index fc1d6b4..462f503 100755 --- a/src/stc-restriction.c +++ b/src/stc-restriction.c @@ -73,28 +73,6 @@ gboolean __validate_rstn_rule(table_restrictions_info *rule, return FALSE; } - if (rst_type == RST_SET) { - if (rule->rcv_limit < 0) { - __STC_LOG_FUNC_EXIT__; - return FALSE; - } - - if (rule->send_limit < 0) { - __STC_LOG_FUNC_EXIT__; - return FALSE; - } - - if (rule->rcv_warn_limit < 0) { - __STC_LOG_FUNC_EXIT__; - return FALSE; - } - - if (rule->send_warn_limit < 0) { - __STC_LOG_FUNC_EXIT__; - return FALSE; - } - } - if (rule->roaming >= STC_ROAMING_LAST_ELEM) { __STC_LOG_FUNC_EXIT__; return FALSE; diff --git a/src/utils/net-cls-release.c b/src/utils/net-cls-release.c old mode 100644 new mode 100755 index 8f75dc8..11f5040 --- a/src/utils/net-cls-release.c +++ b/src/utils/net-cls-release.c @@ -14,6 +14,6 @@ int main(int argc, char *argv[]) return 1; /* kernel already adds symbol '/' before cgroup name */ - sprintf(buf, "%s/%s", PATH_TO_NET_CGROUP_DIR, argv[1]); + snprintf(buf, sizeof(buf), "%s/%s", PATH_TO_NET_CGROUP_DIR, argv[1]); return rmdir(buf); } -- 2.7.4 From f29609fd118f106e8526cbb65db912c9a87b868d Mon Sep 17 00:00:00 2001 From: hyunuktak Date: Thu, 11 May 2017 16:59:18 +0900 Subject: [PATCH 04/11] Modified properly data type Change-Id: Ie0e775abb7c349847aa5d43fce211c0b60b6c8d1 Signed-off-by: hyunuktak --- include/stc-manager.h | 4 ++-- include/stc-restriction.h | 8 ++++---- packaging/stc-manager.spec | 2 +- src/configure/include/netlink-restriction.h | 6 +++--- src/configure/nf-restriction.c | 16 ++++++++-------- src/database/include/db-internal.h | 0 src/database/include/stc-db.h | 0 src/database/include/table-counters.h | 4 ++-- src/database/include/table-restrictions.h | 8 ++++---- src/database/include/table-statistics.h | 0 src/database/tables/table-counters.c | 2 +- src/helper/helper-nfacct-rule.c | 12 ++++++------ src/helper/helper-nfacct-rule.h | 6 +++--- src/monitor/stc-monitor.c | 26 +++++++++++++------------- src/stc-restriction.c | 16 ++++++++-------- src/stc-statistics.c | 8 ++++---- 16 files changed, 59 insertions(+), 59 deletions(-) mode change 100644 => 100755 src/database/include/db-internal.h mode change 100644 => 100755 src/database/include/stc-db.h mode change 100644 => 100755 src/database/include/table-counters.h mode change 100644 => 100755 src/database/include/table-restrictions.h mode change 100644 => 100755 src/database/include/table-statistics.h diff --git a/include/stc-manager.h b/include/stc-manager.h index 4e952b9..6df86af 100755 --- a/include/stc-manager.h +++ b/include/stc-manager.h @@ -141,8 +141,8 @@ typedef struct { * @brief datausage in bytes */ typedef struct { - uint64_t in_bytes; /**< incoming bytes */ - uint64_t out_bytes; /**< outgoing bytes */ + int64_t in_bytes; /**< incoming bytes */ + int64_t out_bytes; /**< outgoing bytes */ } stc_data_counter_s; typedef struct { diff --git a/include/stc-restriction.h b/include/stc-restriction.h index 81df4bd..219dad8 100755 --- a/include/stc-restriction.h +++ b/include/stc-restriction.h @@ -29,10 +29,10 @@ typedef struct { stc_app_state_e rs_type; stc_iface_type_e iftype; - uint64_t send_limit; - uint64_t rcv_limit; - uint64_t snd_warning_limit; - uint64_t rcv_warning_limit; + int64_t send_limit; + int64_t rcv_limit; + int64_t snd_warning_limit; + int64_t rcv_warning_limit; stc_roaming_type_e roaming; char *ifname; char *imsi; diff --git a/packaging/stc-manager.spec b/packaging/stc-manager.spec index 686702f..df4b9c9 100644 --- a/packaging/stc-manager.spec +++ b/packaging/stc-manager.spec @@ -1,6 +1,6 @@ Name: stc-manager Summary: STC(Smart Traffic Control) manager -Version: 0.0.2 +Version: 0.0.3 Release: 0 Group: Network & Connectivity/Other License: Apache-2.0 diff --git a/src/configure/include/netlink-restriction.h b/src/configure/include/netlink-restriction.h index 2734fbf..069a4a3 100755 --- a/src/configure/include/netlink-restriction.h +++ b/src/configure/include/netlink-restriction.h @@ -45,9 +45,9 @@ int send_net_restriction(const enum traffic_restriction_type rst_type, const guint32 classid, const int quota_id, const stc_iface_type_e iftype, - const uint64_t send_limit, const uint64_t rcv_limit, - const uint64_t snd_warning_threshold, - const uint64_t rcv_warning_threshold, + const int64_t send_limit, const int64_t rcv_limit, + const int64_t snd_warning_threshold, + const int64_t rcv_warning_threshold, const char *ifname); #endif /* __STC_NET_RESTRICTION_H__ */ diff --git a/src/configure/nf-restriction.c b/src/configure/nf-restriction.c index 9e65904..2423ee0 100755 --- a/src/configure/nf-restriction.c +++ b/src/configure/nf-restriction.c @@ -17,8 +17,8 @@ #include "counter.h" static stc_error_e apply_net_restriction(struct nfacct_rule *rule, - const uint64_t send_limit, - const uint64_t rcv_limit) + const int64_t send_limit, + const int64_t rcv_limit) { nfacct_rule_jump jump; @@ -37,8 +37,8 @@ static stc_error_e apply_net_restriction(struct nfacct_rule *rule, } static stc_error_e revert_net_restriction(struct nfacct_rule *rule, - const uint64_t send_limit, - const uint64_t rcv_limit) + const int64_t send_limit, + const int64_t rcv_limit) { nfacct_rule_jump jump = ((rule->intend == NFACCT_WARN) ? NFACCT_JUMP_ACCEPT : NFACCT_JUMP_REJECT); @@ -70,10 +70,10 @@ static stc_error_e exclude_net_restriction(struct nfacct_rule *rule) stc_error_e send_net_restriction(const enum traffic_restriction_type rst_type, const guint32 classid, const int quota_id, const stc_iface_type_e iftype, - const uint64_t send_limit, - const uint64_t rcv_limit, - const uint64_t snd_warning_threshold, - const uint64_t rcv_warning_threshold, + const int64_t send_limit, + const int64_t rcv_limit, + const int64_t snd_warning_threshold, + const int64_t rcv_warning_threshold, const char *ifname) { int ret; diff --git a/src/database/include/db-internal.h b/src/database/include/db-internal.h old mode 100644 new mode 100755 diff --git a/src/database/include/stc-db.h b/src/database/include/stc-db.h old mode 100644 new mode 100755 diff --git a/src/database/include/table-counters.h b/src/database/include/table-counters.h old mode 100644 new mode 100755 index 556fdba..70e545c --- a/src/database/include/table-counters.h +++ b/src/database/include/table-counters.h @@ -19,8 +19,8 @@ typedef struct { uint64_t restriction_id; - uint64_t sent_bytes; - uint64_t rcv_bytes; + int64_t sent_bytes; + int64_t rcv_bytes; } table_counters_info; typedef stc_cb_ret_e(*table_counters_info_cb)(const table_counters_info *info, diff --git a/src/database/include/table-restrictions.h b/src/database/include/table-restrictions.h old mode 100644 new mode 100755 index ede1439..2814199 --- a/src/database/include/table-restrictions.h +++ b/src/database/include/table-restrictions.h @@ -24,10 +24,10 @@ typedef struct { stc_iface_type_e iftype; stc_restriction_state_e rst_state; stc_roaming_type_e roaming; - uint64_t rcv_limit; - uint64_t send_limit; - uint64_t rcv_warn_limit; - uint64_t send_warn_limit; + int64_t rcv_limit; + int64_t send_limit; + int64_t rcv_warn_limit; + int64_t send_warn_limit; uint64_t restriction_id; } table_restrictions_info; diff --git a/src/database/include/table-statistics.h b/src/database/include/table-statistics.h old mode 100644 new mode 100755 diff --git a/src/database/tables/table-counters.c b/src/database/tables/table-counters.c index 070ef46..9fb6fba 100755 --- a/src/database/tables/table-counters.c +++ b/src/database/tables/table-counters.c @@ -187,7 +187,7 @@ stc_error_e table_counters_get(uint64_t restriction_id, info->sent_bytes = sqlite3_column_int64(stmt, 0); info->rcv_bytes = sqlite3_column_int64(stmt, 1); - STC_LOGD("rstn_id [%llu] counters [sent = %llu rcv = %llu]", + STC_LOGD("rstn_id [%llu] counters [sent = %lld rcv = %lld]", restriction_id, info->sent_bytes, info->rcv_bytes); break; diff --git a/src/helper/helper-nfacct-rule.c b/src/helper/helper-nfacct-rule.c index 94ad5d1..7e7f5cb 100755 --- a/src/helper/helper-nfacct-rule.c +++ b/src/helper/helper-nfacct-rule.c @@ -606,8 +606,8 @@ static char *get_iptables_jump(const nfacct_rule_jump jump) } static stc_error_e produce_app_rule(nfacct_rule_s *rule, - const uint64_t send_limit, - const uint64_t rcv_limit, + const int64_t send_limit, + const int64_t rcv_limit, const nfacct_rule_action action, const nfacct_rule_jump jump, const nfacct_rule_direction iotype) @@ -717,8 +717,8 @@ static stc_error_e produce_app_rule(nfacct_rule_s *rule, } static stc_error_e produce_iface_rule(nfacct_rule_s *rule, - const uint64_t send_limit, - const uint64_t rcv_limit, + const int64_t send_limit, + const int64_t rcv_limit, const nfacct_rule_action action, const nfacct_rule_jump jump, const nfacct_rule_direction iotype) @@ -851,8 +851,8 @@ static stc_error_e produce_iface_rule(nfacct_rule_s *rule, } stc_error_e produce_net_rule(nfacct_rule_s *rule, - const uint64_t send_limit, - const uint64_t rcv_limit, + const int64_t send_limit, + const int64_t rcv_limit, const nfacct_rule_action action, const nfacct_rule_jump jump, const nfacct_rule_direction iotype) diff --git a/src/helper/helper-nfacct-rule.h b/src/helper/helper-nfacct-rule.h index 7ce4ed7..2220868 100755 --- a/src/helper/helper-nfacct-rule.h +++ b/src/helper/helper-nfacct-rule.h @@ -85,7 +85,7 @@ struct nfacct_rule { nfacct_rule_intend intend; struct counter_arg *carg; stc_error_e(*iptables_rule)(struct nfacct_rule *counter); - uint64_t quota; + int64_t quota; int quota_id; stc_roaming_type_e roaming; stc_restriction_state_e rst_state; @@ -112,8 +112,8 @@ stc_error_e nfacct_send_del(nfacct_rule_s *counter); stc_error_e exec_iptables_cmd(const char *cmd_buf, pid_t *pid); stc_error_e produce_net_rule(nfacct_rule_s *rule, - const uint64_t send_limit, - const uint64_t rcv_limit, + const int64_t send_limit, + const int64_t rcv_limit, const nfacct_rule_action action, const nfacct_rule_jump jump, const nfacct_rule_direction iotype); diff --git a/src/monitor/stc-monitor.c b/src/monitor/stc-monitor.c index a2b662e..8633c84 100755 --- a/src/monitor/stc-monitor.c +++ b/src/monitor/stc-monitor.c @@ -33,7 +33,7 @@ typedef struct { typedef struct { struct nfacct_rule *counter; - uint64_t bytes; + int64_t bytes; gboolean in_limit_reached; gboolean out_limit_reached; } classid_bytes_context_s; @@ -201,7 +201,7 @@ static gboolean __apps_tree_foreach_print(gpointer key, gpointer value, STC_LOGD("Application info => Pkg ID [%s], App ID [%s]," " Type [%d], classid [%d]," - " counter [ in (%llu), out (%llu)]", + " counter [ in (%lld), out (%lld)]", app_key->pkg_id, app_key->app_id, app_value->type, app_value->classid, app_value->data_usage.in_bytes, app_value->data_usage.out_bytes); @@ -327,9 +327,9 @@ static void __print_rstn(stc_rstn_key_s *rstn_key, stc_rstn_value_s *rstn_value) STC_LOGI("rstn info => rstn_id [%llu], " "app_id [%s], classid [%lu], ifname [%s], " "iftype [%d], rst_state [%d], " - "limit [ in (%llu), out (%llu)], " - "warn_limit [ in (%llu), out (%llu)], " - "counter [ in (%llu), out (%llu)], " + "limit [ in (%lld), out (%lld)], " + "warn_limit [ in (%lld), out (%lld)], " + "counter [ in (%lld), out (%lld)], " "roaming [%d], imsi [%s]", rstn_value->restriction_id, rstn_key->app_id, rstn_value->classid , rstn_key->ifname, @@ -399,13 +399,13 @@ static void __process_restriction(enum traffic_restriction_type rst_type, if (effective_warn_limit.out_bytes < 0) effective_warn_limit.out_bytes = 0; - STC_LOGD("datausage [in: %llu, out: %llu]", + STC_LOGD("datausage [in: %lld, out: %lld]", info.rcv_bytes, info.sent_bytes); } - STC_LOGD("rstn_id [%llu], effective limit [in: %llu, out: %llu], " - "effective warn limit [in: %llu, out: %llu], " - "datausage [in: %llu, out: %llu]", + STC_LOGD("rstn_id [%llu], effective limit [in: %lld, out: %lld], " + "effective warn limit [in: %lld, out: %lld], " + "datausage [in: %lld, out: %lld]", rstn_value->restriction_id, effective_limit.in_bytes, effective_limit.out_bytes, effective_warn_limit.in_bytes, effective_warn_limit.out_bytes); @@ -713,7 +713,7 @@ try_next_callback: return FALSE; } -static void __fill_nfacct_result(char *cnt_name, uint64_t bytes, +static void __fill_nfacct_result(char *cnt_name, int64_t bytes, struct counter_arg *carg) { struct nfacct_rule counter = { @@ -737,7 +737,7 @@ static void __fill_nfacct_result(char *cnt_name, uint64_t bytes, return; } - STC_LOGI("classid %lu, iftype %u, iotype %d, intend %d, ifname %s, bytes %llu", + STC_LOGI("classid %lu, iftype %u, iotype %d, intend %d, ifname %s, bytes %lld", context.counter->classid, context.counter->iftype, context.counter->iotype, context.counter->intend, context.counter->ifname, context.bytes); @@ -766,8 +766,8 @@ static int __fill_counters(struct rtattr *attr_list[__NFACCT_MAX], populate_counters(cnt_name, carg); */ } else { - uint64_t *bytes_p = - (uint64_t *)RTA_DATA(attr_list[NFACCT_BYTES]); + int64_t *bytes_p = + (int64_t *)RTA_DATA(attr_list[NFACCT_BYTES]); int bytes = be64toh(*bytes_p); if (bytes) { ++carg->serialized_counters; diff --git a/src/stc-restriction.c b/src/stc-restriction.c index 462f503..721d25c 100755 --- a/src/stc-restriction.c +++ b/src/stc-restriction.c @@ -115,16 +115,16 @@ void __stc_restriction_app_info_builder_add(GVariantBuilder *builder, g_variant_new_uint16(info->rst_state)); g_variant_builder_add(builder, "{sv}", "rcv_limit", - g_variant_new_uint64(info->rcv_limit)); + g_variant_new_int64(info->rcv_limit)); g_variant_builder_add(builder, "{sv}", "send_limit", - g_variant_new_uint64(info->send_limit)); + g_variant_new_int64(info->send_limit)); g_variant_builder_add(builder, "{sv}", "rcv_warn_limit", - g_variant_new_uint64(info->rcv_warn_limit)); + g_variant_new_int64(info->rcv_warn_limit)); g_variant_builder_add(builder, "{sv}", "send_warn_limit", - g_variant_new_uint64(info->send_warn_limit)); + g_variant_new_int64(info->send_warn_limit)); g_variant_builder_add(builder, "{sv}", "roaming", g_variant_new_uint16(info->roaming)); @@ -204,19 +204,19 @@ static void __stc_extract_restriction_rule(const char *key, GVariant *value, } else if (!g_strcmp0(key, "rcv_limit")) { rule->rcv_limit = g_variant_get_uint64(value); - STC_LOGD("rcv_limit: [%llu]", rule->rcv_limit); + STC_LOGD("rcv_limit: [%lld]", rule->rcv_limit); } else if (!g_strcmp0(key, "send_limit")) { rule->send_limit = g_variant_get_uint64(value); - STC_LOGD("send_limit: [%llu]", rule->send_limit); + STC_LOGD("send_limit: [%lld]", rule->send_limit); } else if (!g_strcmp0(key, "rcv_warn_limit")) { rule->rcv_warn_limit = g_variant_get_uint64(value); - STC_LOGD("rcv_warn_limit: [%llu]", rule->rcv_warn_limit); + STC_LOGD("rcv_warn_limit: [%lld]", rule->rcv_warn_limit); } else if (!g_strcmp0(key, "send_warn_limit")) { rule->send_warn_limit = g_variant_get_uint64(value); - STC_LOGD("send_warn_limit: [%llu]", rule->send_warn_limit); + STC_LOGD("send_warn_limit: [%lld]", rule->send_warn_limit); } else if (!g_strcmp0(key, "roaming")) { rule->roaming = g_variant_get_uint16(value); diff --git a/src/stc-statistics.c b/src/stc-statistics.c index a2a72fd..ba65f7e 100755 --- a/src/stc-statistics.c +++ b/src/stc-statistics.c @@ -48,8 +48,8 @@ void __stc_statistics_print_app_info(const table_statistics_info *info) STC_LOGD("========== App data (Statistics) =========="); STC_LOGD("app_id : [%s]", info->app_id ? info->app_id : "NULL"); STC_LOGD("ifname : [%s]", info->ifname ? info->ifname : "NULL"); - STC_LOGD("Sent : [%llu] bytes", info->cnt.out_bytes); - STC_LOGD("Received : [%llu] bytes", info->cnt.in_bytes); + STC_LOGD("Sent : [%lld] bytes", info->cnt.out_bytes); + STC_LOGD("Received : [%lld] bytes", info->cnt.in_bytes); STC_LOGD("==========================================="); } @@ -188,10 +188,10 @@ void __stc_statistics_app_info_builder_add(GVariantBuilder *builder, } g_variant_builder_add(builder, "{sv}", "cnt_out_bytes", - g_variant_new_uint64(info->cnt.out_bytes)); + g_variant_new_int64(info->cnt.out_bytes)); g_variant_builder_add(builder, "{sv}", "cnt_in_bytes", - g_variant_new_uint64(info->cnt.in_bytes)); + g_variant_new_int64(info->cnt.in_bytes)); g_variant_builder_add(builder, "{sv}", "roaming", g_variant_new_uint16(info->roaming)); -- 2.7.4 From ba9b8a4a1c72e8f25075a2454a76a593c5d737e3 Mon Sep 17 00:00:00 2001 From: hyunuktak Date: Fri, 12 May 2017 15:37:56 +0900 Subject: [PATCH 05/11] Added init service method Change-Id: I4afe3bf1c75119e97f3e27264db1239d44a8bbbf Signed-off-by: hyunuktak --- include/stc-statistics.h | 3 +++ interfaces/stcmanager-iface-statistics.xml | 2 ++ packaging/stc-manager.spec | 2 +- resources/dbus/stc-manager.conf | 2 ++ src/stc-manager-gdbus.c | 4 ++++ src/stc-statistics.c | 12 ++++++++++++ 6 files changed, 24 insertions(+), 1 deletion(-) diff --git a/include/stc-statistics.h b/include/stc-statistics.h index ddb8f4d..a76607e 100755 --- a/include/stc-statistics.h +++ b/include/stc-statistics.h @@ -29,6 +29,9 @@ * Functions Declaration *****************************************************************************/ +gboolean handle_statistics_init(StcStatistics *object, + GDBusMethodInvocation *invocation); + gboolean handle_statistics_get_all(StcStatistics *object, GDBusMethodInvocation *invocation, GVariant *select_rule, diff --git a/interfaces/stcmanager-iface-statistics.xml b/interfaces/stcmanager-iface-statistics.xml index cad1de6..9c5b6ec 100644 --- a/interfaces/stcmanager-iface-statistics.xml +++ b/interfaces/stcmanager-iface-statistics.xml @@ -1,5 +1,7 @@ + + diff --git a/packaging/stc-manager.spec b/packaging/stc-manager.spec index df4b9c9..e110264 100644 --- a/packaging/stc-manager.spec +++ b/packaging/stc-manager.spec @@ -1,6 +1,6 @@ Name: stc-manager Summary: STC(Smart Traffic Control) manager -Version: 0.0.3 +Version: 0.0.4 Release: 0 Group: Network & Connectivity/Other License: Apache-2.0 diff --git a/resources/dbus/stc-manager.conf b/resources/dbus/stc-manager.conf index 895dfa3..2982db8 100755 --- a/resources/dbus/stc-manager.conf +++ b/resources/dbus/stc-manager.conf @@ -9,5 +9,7 @@ + + diff --git a/src/stc-manager-gdbus.c b/src/stc-manager-gdbus.c index 8352d6d..42f7697 100755 --- a/src/stc-manager-gdbus.c +++ b/src/stc-manager-gdbus.c @@ -45,6 +45,10 @@ static gboolean __stc_manager_gdbus_statistics_init(stc_s *stc) /* Register for method callbacks as signal callbacks */ + g_signal_connect(statistics, "handle-init", + G_CALLBACK(handle_statistics_init), + stc); + g_signal_connect(statistics, "handle-get", G_CALLBACK(handle_statistics_get), stc); diff --git a/src/stc-statistics.c b/src/stc-statistics.c index ba65f7e..ec52aeb 100755 --- a/src/stc-statistics.c +++ b/src/stc-statistics.c @@ -300,6 +300,18 @@ gboolean handle_statistics_get_all(StcStatistics *object, return TRUE; } +gboolean handle_statistics_init(StcStatistics *object, + GDBusMethodInvocation *invocation) +{ + __STC_LOG_FUNC_ENTER__; + + STC_LOGI("stc statistics initialized"); + stc_statistics_complete_init(object, invocation); + + __STC_LOG_FUNC_EXIT__; + return TRUE; +} + gboolean handle_statistics_get(StcStatistics *object, GDBusMethodInvocation *invocation, const gchar *app_id, -- 2.7.4 From 1d485fae6fb9826926cd8c942a8682a7ba9f12a6 Mon Sep 17 00:00:00 2001 From: hyunuktak Date: Wed, 17 May 2017 10:03:39 +0900 Subject: [PATCH 06/11] Modified the privilege to network.get from network.stc Change-Id: I829eb23e7eaaa993c544e902b6636082addd6f21 Signed-off-by: hyunuktak --- packaging/stc-manager.spec | 2 +- resources/dbus/stc-manager.conf | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packaging/stc-manager.spec b/packaging/stc-manager.spec index e110264..c4872c6 100644 --- a/packaging/stc-manager.spec +++ b/packaging/stc-manager.spec @@ -1,6 +1,6 @@ Name: stc-manager Summary: STC(Smart Traffic Control) manager -Version: 0.0.4 +Version: 0.0.5 Release: 0 Group: Network & Connectivity/Other License: Apache-2.0 diff --git a/resources/dbus/stc-manager.conf b/resources/dbus/stc-manager.conf index 2982db8..6732e96 100755 --- a/resources/dbus/stc-manager.conf +++ b/resources/dbus/stc-manager.conf @@ -8,8 +8,8 @@ - - - + + + -- 2.7.4 From 7e189f6e09133b3205b24b6388d4b6e7dbc46420 Mon Sep 17 00:00:00 2001 From: hyunuktak Date: Wed, 17 May 2017 10:13:33 +0900 Subject: [PATCH 07/11] Fixed a svace for 212550 Change-Id: I8d0fc13c0ac76e477393079fd5533d4f2de8db6c Signed-off-by: hyunuktak --- packaging/stc-manager.spec | 2 +- src/helper/helper-nfacct-rule.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packaging/stc-manager.spec b/packaging/stc-manager.spec index c4872c6..27201b8 100644 --- a/packaging/stc-manager.spec +++ b/packaging/stc-manager.spec @@ -1,6 +1,6 @@ Name: stc-manager Summary: STC(Smart Traffic Control) manager -Version: 0.0.5 +Version: 0.0.6 Release: 0 Group: Network & Connectivity/Other License: Apache-2.0 diff --git a/src/helper/helper-nfacct-rule.c b/src/helper/helper-nfacct-rule.c index 7e7f5cb..1eb140b 100755 --- a/src/helper/helper-nfacct-rule.c +++ b/src/helper/helper-nfacct-rule.c @@ -286,7 +286,7 @@ bool recreate_counter_by_name(char *cnt_name, nfacct_rule_s *cnt) iface = get_iftype_by_name(ifname_buf); if (iface == STC_IFACE_DATACALL) { cnt->iotype = NFACCT_COUNTER_OUT; - strcpy(cnt->ifname, ifname_buf); + strncpy(cnt->ifname, ifname_buf, MAX_IFACE_LENGTH); } } -- 2.7.4 From 9a5515771d535fa92226ff16e95ea9de22c324c4 Mon Sep 17 00:00:00 2001 From: hyunuktak Date: Fri, 19 May 2017 15:45:06 +0900 Subject: [PATCH 08/11] Fixed some svaces for unreachable Change-Id: I2612fe4c4fa063d36fca79ad7a423b27b3fbad63 Signed-off-by: hyunuktak --- packaging/stc-manager.spec | 2 +- src/helper/helper-net-cls.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packaging/stc-manager.spec b/packaging/stc-manager.spec index 27201b8..1dc1552 100644 --- a/packaging/stc-manager.spec +++ b/packaging/stc-manager.spec @@ -1,6 +1,6 @@ Name: stc-manager Summary: STC(Smart Traffic Control) manager -Version: 0.0.6 +Version: 0.0.7 Release: 0 Group: Network & Connectivity/Other License: Apache-2.0 diff --git a/src/helper/helper-net-cls.c b/src/helper/helper-net-cls.c index 63f7b2d..c057527 100755 --- a/src/helper/helper-net-cls.c +++ b/src/helper/helper-net-cls.c @@ -40,13 +40,13 @@ static uint32_t __produce_classid(check_classid_used_cb check_classid_cb) STC_LOGE("Can not read current classid"); classid += 1; if (check_classid_cb) - for (classid_test_count = 0; classid_test_count < UINT32_MAX; + for (classid_test_count = 0; classid_test_count < INT32_MAX; ++classid) { if (!check_classid_cb(classid)) break; } - if (classid_test_count == UINT32_MAX) { + if (classid_test_count == INT32_MAX) { STC_LOGE("there is no available classid due to kernel limitation"); return STC_UNKNOWN_CLASSID; } -- 2.7.4 From 083fabac957ef926919536bd29af329a0d3b6c26 Mon Sep 17 00:00:00 2001 From: hyunuktak Date: Mon, 22 May 2017 16:32:41 +0900 Subject: [PATCH 09/11] Removed unreachable code Change-Id: Iac675e67967222ab7626b8ab0633a330685d8bf0 Signed-off-by: hyunuktak --- packaging/stc-manager.spec | 2 +- src/helper/helper-net-cls.c | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/packaging/stc-manager.spec b/packaging/stc-manager.spec index 1dc1552..d3fdb69 100644 --- a/packaging/stc-manager.spec +++ b/packaging/stc-manager.spec @@ -1,6 +1,6 @@ Name: stc-manager Summary: STC(Smart Traffic Control) manager -Version: 0.0.7 +Version: 0.0.8 Release: 0 Group: Network & Connectivity/Other License: Apache-2.0 diff --git a/src/helper/helper-net-cls.c b/src/helper/helper-net-cls.c index c057527..d08f559 100755 --- a/src/helper/helper-net-cls.c +++ b/src/helper/helper-net-cls.c @@ -46,11 +46,6 @@ static uint32_t __produce_classid(check_classid_used_cb check_classid_cb) break; } - if (classid_test_count == INT32_MAX) { - STC_LOGE("there is no available classid due to kernel limitation"); - return STC_UNKNOWN_CLASSID; - } - ret = fwrite_uint(CUR_CLASSID_PATH, ++classid); if (ret < 0) STC_LOGE("Can not write classid"); -- 2.7.4 From a6cf4f02af073daef2a0cce1ef556ce3a5090afc Mon Sep 17 00:00:00 2001 From: Nishant Chaprana Date: Mon, 22 May 2017 16:58:35 +0530 Subject: [PATCH 10/11] Extract send_limit, rcv_limit, rcv_warn_limit and send_warn_limit as int64 Description: smart-traffic-control library sends limits as int64 but manager was extracting these values as uint64, due to which values were not extracted and limits were not updated. Below is the error log:- D/STC_MANAGER( 386): stc-manager-gdbus.c: stc_manager_gdbus_dict_foreach(298) > Key : [rcv_limit] D/STC_MANAGER( 386): stc-manager-gdbus.c: stc_manager_gdbus_dict_foreach(298) > Value: [int64 1024000] D/STC_MANAGER( 386): stc-restriction.c: __stc_extract_restriction_rule(180) > Enter D/STC_MANAGER( 386): stc-restriction.c: __stc_extract_restriction_rule(207) > rcv_limit: [0] D/STC_MANAGER( 386): stc-restriction.c: __stc_extract_restriction_rule(235) > Quit D/STC_MANAGER( 386): stc-manager-gdbus.c: stc_manager_gdbus_dict_foreach(298) > Key : [send_limit] D/STC_MANAGER( 386): stc-manager-gdbus.c: stc_manager_gdbus_dict_foreach(298) > Value: [int64 1024000] D/STC_MANAGER( 386): stc-restriction.c: __stc_extract_restriction_rule(180) > Enter D/STC_MANAGER( 386): stc-restriction.c: __stc_extract_restriction_rule(211) > send_limit: [0] D/STC_MANAGER( 386): stc-restriction.c: __stc_extract_restriction_rule(235) > Quit D/STC_MANAGER( 386): stc-manager-gdbus.c: stc_manager_gdbus_dict_foreach(298) > Key : [rcv_warn_limit] D/STC_MANAGER( 386): stc-manager-gdbus.c: stc_manager_gdbus_dict_foreach(298) > Value: [int64 1020000] D/STC_MANAGER( 386): stc-restriction.c: __stc_extract_restriction_rule(180) > Enter D/STC_MANAGER( 386): stc-restriction.c: __stc_extract_restriction_rule(215) > rcv_warn_limit: [0] D/STC_MANAGER( 386): stc-restriction.c: __stc_extract_restriction_rule(235) > Quit D/STC_MANAGER( 386): stc-manager-gdbus.c: stc_manager_gdbus_dict_foreach(298) > Key : [send_warn_limit] D/STC_MANAGER( 386): stc-manager-gdbus.c: stc_manager_gdbus_dict_foreach(298) > Value: [int64 1020000] Change-Id: I2e5ea475bc5545f631b7c74d208b2b1a27d41308 Signed-off-by: Nishant Chaprana --- packaging/stc-manager.spec | 2 +- src/stc-restriction.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packaging/stc-manager.spec b/packaging/stc-manager.spec index d3fdb69..074ac00 100644 --- a/packaging/stc-manager.spec +++ b/packaging/stc-manager.spec @@ -1,6 +1,6 @@ Name: stc-manager Summary: STC(Smart Traffic Control) manager -Version: 0.0.8 +Version: 0.0.9 Release: 0 Group: Network & Connectivity/Other License: Apache-2.0 diff --git a/src/stc-restriction.c b/src/stc-restriction.c index 721d25c..ba4e9ea 100755 --- a/src/stc-restriction.c +++ b/src/stc-restriction.c @@ -203,19 +203,19 @@ static void __stc_extract_restriction_rule(const char *key, GVariant *value, STC_LOGD("iftype: [%u]", (unsigned int) rule->iftype); } else if (!g_strcmp0(key, "rcv_limit")) { - rule->rcv_limit = g_variant_get_uint64(value); + rule->rcv_limit = g_variant_get_int64(value); STC_LOGD("rcv_limit: [%lld]", rule->rcv_limit); } else if (!g_strcmp0(key, "send_limit")) { - rule->send_limit = g_variant_get_uint64(value); + rule->send_limit = g_variant_get_int64(value); STC_LOGD("send_limit: [%lld]", rule->send_limit); } else if (!g_strcmp0(key, "rcv_warn_limit")) { - rule->rcv_warn_limit = g_variant_get_uint64(value); + rule->rcv_warn_limit = g_variant_get_int64(value); STC_LOGD("rcv_warn_limit: [%lld]", rule->rcv_warn_limit); } else if (!g_strcmp0(key, "send_warn_limit")) { - rule->send_warn_limit = g_variant_get_uint64(value); + rule->send_warn_limit = g_variant_get_int64(value); STC_LOGD("send_warn_limit: [%lld]", rule->send_warn_limit); } else if (!g_strcmp0(key, "roaming")) { -- 2.7.4 From 732cd0e5a7e53f22d5f7a36451c92c433f34c984 Mon Sep 17 00:00:00 2001 From: Nishant Chaprana Date: Mon, 22 May 2017 16:59:59 +0530 Subject: [PATCH 11/11] Added WarnThresholdCrossed signal on restriction interface. Change-Id: I0cee09ac57abe21b64454968ef3e7644f12fe7dc Signed-off-by: Nishant Chaprana --- include/stc-manager-gdbus.h | 6 +++++ interfaces/stcmanager-iface-restriction.xml | 4 ++++ packaging/stc-manager.spec | 2 +- src/monitor/include/stc-monitor.h | 1 + src/monitor/stc-monitor.c | 31 +++++++++++++++++++++++++ src/stc-manager-gdbus.c | 35 +++++++++++++++++++++++++++++ 6 files changed, 78 insertions(+), 1 deletion(-) diff --git a/include/stc-manager-gdbus.h b/include/stc-manager-gdbus.h index c253c18..cafca77 100755 --- a/include/stc-manager-gdbus.h +++ b/include/stc-manager-gdbus.h @@ -21,6 +21,7 @@ #include "generated-code.h" #define STC_DBUS_SERVICE "net.stc" +#define STC_DBUS_INTERFACE_RESTRICTION STC_DBUS_SERVICE ".restriction" #define STC_DBUS_SERVICE_PATH "/net/stc" #define STC_DBUS_SERVICE_STATISTICS_PATH "/net/stc/statistics" #define STC_DBUS_SERVICE_RESTRICTION_PATH "/net/stc/restriction" @@ -82,5 +83,10 @@ void stc_manager_gdbus_unsubscribe_signal(GDBusConnection *connection, guint subscription_id); void stc_manager_gdbus_dict_foreach(GVariantIter *iter, dbus_dict_cb cb, void *user_data); +gboolean stc_manager_dbus_emit_signal(GDBusConnection *connection, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters); #endif /* __STC_MANAGER_GDBUS_H__ */ diff --git a/interfaces/stcmanager-iface-restriction.xml b/interfaces/stcmanager-iface-restriction.xml index b765431..6dba33d 100644 --- a/interfaces/stcmanager-iface-restriction.xml +++ b/interfaces/stcmanager-iface-restriction.xml @@ -38,5 +38,9 @@ + + + + diff --git a/packaging/stc-manager.spec b/packaging/stc-manager.spec index 074ac00..c50f783 100644 --- a/packaging/stc-manager.spec +++ b/packaging/stc-manager.spec @@ -1,6 +1,6 @@ Name: stc-manager Summary: STC(Smart Traffic Control) manager -Version: 0.0.9 +Version: 0.0.10 Release: 0 Group: Network & Connectivity/Other License: Apache-2.0 diff --git a/src/monitor/include/stc-monitor.h b/src/monitor/include/stc-monitor.h index c3d2db9..eaf3530 100644 --- a/src/monitor/include/stc-monitor.h +++ b/src/monitor/include/stc-monitor.h @@ -86,6 +86,7 @@ typedef struct { stc_data_counter_s counter; gboolean in_limit_reached; gboolean out_limit_reached; + gboolean warn_limit_crossed_notified; } stc_rstn_value_s; /** diff --git a/src/monitor/stc-monitor.c b/src/monitor/stc-monitor.c index 8633c84..ff5803a 100755 --- a/src/monitor/stc-monitor.c +++ b/src/monitor/stc-monitor.c @@ -550,6 +550,21 @@ static gboolean __rstn_counter_update_foreach_classid(gpointer key, case NFACCT_COUNTER_IN: rstn_value->counter.in_bytes += context->bytes; + if (rstn_value->counter.in_bytes >= rstn_value->warn_limit.in_bytes + && rstn_value->warn_limit_crossed_notified == FALSE) { + gboolean rv = FALSE; + stc_s *stc = (stc_s *)stc_get_manager(); + ret_value_msg_if(stc == NULL, FALSE, "failed to get stc data"); + + rv = stc_manager_dbus_emit_signal(stc->connection, + STC_DBUS_SERVICE_RESTRICTION_PATH, + STC_DBUS_INTERFACE_RESTRICTION, + "WarnThresholdCrossed", + g_variant_new("(s)", rstn_key->app_id)); + if (rv == TRUE) + rstn_value->warn_limit_crossed_notified = TRUE; + } + /* block immediately */ if (rstn_value->counter.in_bytes >= rstn_value->limit.in_bytes) { __del_iptables_in(context->counter); @@ -564,6 +579,21 @@ static gboolean __rstn_counter_update_foreach_classid(gpointer key, case NFACCT_COUNTER_OUT: rstn_value->counter.out_bytes += context->bytes; + if (rstn_value->counter.out_bytes >= rstn_value->limit.out_bytes + && rstn_value->warn_limit_crossed_notified == FALSE) { + gboolean rv = FALSE; + stc_s *stc = (stc_s *)stc_get_manager(); + ret_value_msg_if(stc == NULL, FALSE, "failed to get stc data"); + + rv = stc_manager_dbus_emit_signal(stc->connection, + STC_DBUS_SERVICE_RESTRICTION_PATH, + STC_DBUS_INTERFACE_RESTRICTION, + "WarnThresholdCrossed", + g_variant_new("(s)", rstn_key->app_id)); + if (rv == TRUE) + rstn_value->warn_limit_crossed_notified = TRUE; + } + /* block immediately */ if (rstn_value->counter.out_bytes >= rstn_value->limit.out_bytes) { __del_iptables_out(context->counter); @@ -1007,6 +1037,7 @@ static stc_error_e __rstn_tree_add(stc_rstn_key_s *key, rstn_value->warn_limit.out_bytes = value->warn_limit.out_bytes; rstn_value->counter.in_bytes = 0; rstn_value->counter.out_bytes = 0; + rstn_value->warn_limit_crossed_notified = FALSE; if (debug == TRUE) __add_restriction_debug(key, rstn_value, NULL); diff --git a/src/stc-manager-gdbus.c b/src/stc-manager-gdbus.c index 42f7697..5b3cc71 100755 --- a/src/stc-manager-gdbus.c +++ b/src/stc-manager-gdbus.c @@ -302,3 +302,38 @@ void stc_manager_gdbus_dict_foreach(GVariantIter *iter, dbus_dict_cb cb, __STC_LOG_FUNC_EXIT__; } + +gboolean stc_manager_dbus_emit_signal(GDBusConnection *connection, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters) +{ + gboolean rv = FALSE; + GError *error = NULL; + + if (connection == NULL) { + STC_LOGE("GDBusconnection is NULL"); + return 0; + } + + DEBUG_GDBUS_VARIANT("Signal params: ", parameters); + + rv = g_dbus_connection_emit_signal(connection, + NULL, + object_path, + interface_name, + signal_name, + parameters, + &error); + if (rv != TRUE) { + STC_LOGE("Failed to emit signal [%s] interface [%s] Error [%s]", + signal_name, interface_name, error->message); + g_error_free(error); + } else { + STC_LOGD("[%s] signal sent on [%s] interface", signal_name, + interface_name); + } + + return rv; +} -- 2.7.4