Proximity alert implementation using BLE
[platform/core/location/geofence-server.git] / geofence-server / src / geofence_server_wifi.c
1 /* Copyright 2014 Samsung Electronics Co., Ltd All Rights Reserved
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <stdlib.h>
17 #include <vconf.h>
18 #include <vconf-keys.h>
19 #include <glib.h>
20
21 #include "geofence_server.h"
22 #include "server.h"
23 #include "debug_util.h"
24 #include "geofence_server_private.h"
25 #include "geofence_server_db.h"
26 #include "geofence_server_log.h"
27 #include "geofence_server_internal.h"
28
29 static void emit_wifi_geofence_inout_changed(GeofenceServer *geofence_server, int fence_id, int fence_status)
30 {
31         LOGD_GEOFENCE("emit_wifi_geofence_inout_changed");
32         char *app_id = NULL;
33         int ret = FENCE_ERR_NONE;
34
35         ret = geofence_manager_get_appid_from_geofence(fence_id, &app_id);
36         if (ret != FENCE_ERR_NONE) {
37                 LOGE("Error getting the app_id for fence id[%d]", fence_id);
38                 return;
39         }
40         GeofenceItemData *item_data = __get_item_by_fence_id(fence_id, geofence_server);
41         if (item_data == NULL) {
42                 LOGD_GEOFENCE("getting item data failed. fence_id [%d]", fence_id);
43                 g_free(app_id);
44                 return;
45         }
46         if (fence_status == GEOFENCE_FENCE_STATE_IN) {
47                 if (item_data->common_info.status != GEOFENCE_FENCE_STATE_IN) {
48                         geofence_dbus_server_send_geofence_inout_changed(geofence_server->geofence_dbus_server, app_id, fence_id, item_data->common_info.access_type, GEOFENCE_EMIT_STATE_IN);
49                         item_data->common_info.status = GEOFENCE_FENCE_STATE_IN;
50                 }
51         } else if (fence_status == GEOFENCE_FENCE_STATE_OUT) {
52                 if (item_data->common_info.status != GEOFENCE_FENCE_STATE_OUT) {
53                         geofence_dbus_server_send_geofence_inout_changed(geofence_server->geofence_dbus_server, app_id, fence_id, item_data->common_info.access_type, GEOFENCE_EMIT_STATE_OUT);
54                         item_data->common_info.status = GEOFENCE_FENCE_STATE_OUT;
55                 }
56         }
57         if (app_id)
58                 free(app_id);
59 }
60
61 static bool __check_for_match(char *str1, char *str2)
62 {
63         if (g_strrstr(str1, str2) == NULL)
64                 return false;
65         return true;
66 }
67
68 static void bt_le_scan_result_cb(int result, bt_adapter_le_device_scan_result_info_s *info, void *user_data)
69 {
70         int ret = BT_ERROR_NONE;
71         GeofenceServer *geofence_server = (GeofenceServer *) user_data;
72         LOGI_GEOFENCE("Current addresses: %s", geofence_server->ble_info);
73         LOGI_GEOFENCE("Received address: %s", info->remote_address);
74
75         if (info == NULL) {
76                 LOGI_GEOFENCE("Stopping scan as there is no BLE address found");
77                 ret = bt_adapter_le_stop_scan();
78                 if (ret != BT_ERROR_NONE)
79                         LOGE_GEOFENCE("Unable to stop the BLE scan, error: %d", ret);
80                 return;
81         }
82         if (!g_ascii_strcasecmp(geofence_server->ble_info, "")) {
83                 g_stpcpy(geofence_server->ble_info, info->remote_address);
84         } else if (!__check_for_match(geofence_server->ble_info, info->remote_address)) { /* If duplicate does not exist */
85                 char *p = g_strjoin(";", geofence_server->ble_info, info->remote_address, NULL);
86                 g_stpcpy(geofence_server->ble_info, p);
87                 g_free(p);
88         } else {
89                 LOGI_GEOFENCE("Stopping scan. Address: %s already exist in the string %s", info->remote_address, geofence_server->ble_info);
90                 ret = bt_adapter_le_stop_scan();
91                 if (ret != BT_ERROR_NONE)
92                         LOGE_GEOFENCE("Unable to stop the BLE scan, error: %d", ret);
93                 /* Add the string to the database. */
94                 geofence_manager_set_ble_info_to_geofence(geofence_server->connectedTrackingWifiFenceId, geofence_server->ble_info);
95         }
96 }
97
98 static void emit_wifi_geofence_proximity_changed(GeofenceServer *geofence_server, int fence_id, int fence_proximity_status)
99 {
100         FUNC_ENTRANCE_SERVER
101         LOGD_GEOFENCE("emit_wifi_geofence_proximity_changed");
102         char *app_id = NULL;
103         int ret = FENCE_ERR_NONE;
104
105         ret = geofence_manager_get_appid_from_geofence(fence_id, &app_id);
106         if (ret != FENCE_ERR_NONE) {
107                 LOGE("Error getting the app_id for fence id[%d]", fence_id);
108                 return;
109         }
110         GeofenceItemData *item_data = __get_item_by_fence_id(fence_id, geofence_server);
111         if (item_data == NULL) {
112                 LOGD_GEOFENCE("getting item data failed. fence_id [%d]", fence_id);
113                 g_free(app_id);
114                 return;
115         }
116
117         if (fence_proximity_status != item_data->common_info.proximity_status) {
118                 geofence_dbus_server_send_geofence_proximity_changed(geofence_server->geofence_dbus_server, app_id, fence_id, item_data->common_info.access_type, fence_proximity_status, GEOFENCE_PROXIMITY_PROVIDER_WIFI);
119                 if (geofence_server->connectedTrackingWifiFenceId == fence_id) {
120                         if (fence_proximity_status == GEOFENCE_PROXIMITY_IMMEDIATE) {
121                                 LOGD_GEOFENCE("WIFI Fence. Scanning for BLE and storing in DB");
122                                 g_stpcpy(geofence_server->ble_info, "");
123                                 ret = bt_adapter_le_start_scan(bt_le_scan_result_cb, geofence_server);
124                                 if (ret != BT_ERROR_NONE) {
125                                         LOGE_GEOFENCE("Fail to start ble scan. %d", ret);
126                                 }
127                         } else if (item_data->common_info.proximity_status == GEOFENCE_PROXIMITY_IMMEDIATE) { /* Stopping the scan if state changes from imm to somethingelse */
128                                 ret = bt_adapter_le_stop_scan();
129                                 if (ret != BT_ERROR_NONE)
130                                         LOGE_GEOFENCE("Unable to stop the BLE scan/ Stopped already, error: %d", ret);
131                         }
132                 }
133                 item_data->common_info.proximity_status = fence_proximity_status;
134         }
135         if (app_id)
136                 free(app_id);
137 }
138
139 void wifi_rssi_level_changed(wifi_rssi_level_e rssi_level, void *user_data)
140 {
141         FUNC_ENTRANCE_SERVER
142         GeofenceServer *geofence_server = (GeofenceServer *) user_data;
143         g_return_if_fail(geofence_server);
144         wifi_ap_h ap_h;
145         char *bssid = NULL;
146         geofence_proximity_state_e state = GEOFENCE_PROXIMITY_UNCERTAIN;
147         wifi_error_e rv = WIFI_ERROR_NONE;
148         LOGI_GEOFENCE("running cnt: %d, connected id: %d", geofence_server->running_wifi_cnt, geofence_server->connectedTrackingWifiFenceId);
149         if (geofence_server->running_wifi_cnt > 0 && geofence_server->connectedTrackingWifiFenceId != -1) {
150                 rv = wifi_get_connected_ap(&ap_h);
151                 if (rv != WIFI_ERROR_NONE) {
152                         LOGE_GEOFENCE("Fail to get the connected AP: Error - %d", rv);
153                         return;
154                 }
155                 rv = wifi_ap_get_bssid(ap_h, &bssid);
156                 if (rv != WIFI_ERROR_NONE) {
157                         LOGI_GEOFENCE("Fail to get the bssid: [%d]", rv);
158                 } else {
159                         /*Emit the proximity alert here using mConnectedFenceId*/
160                         if (rssi_level == WIFI_RSSI_LEVEL_4)
161                                 state = GEOFENCE_PROXIMITY_IMMEDIATE;
162                         else if (rssi_level ==  WIFI_RSSI_LEVEL_3)
163                                 state = GEOFENCE_PROXIMITY_NEAR;
164                         else
165                                 state = GEOFENCE_PROXIMITY_FAR;
166                         emit_wifi_geofence_proximity_changed(geofence_server, geofence_server->connectedTrackingWifiFenceId, state);
167                 }
168         }
169 }
170
171 void wifi_device_state_changed(wifi_device_state_e state, void *user_data)
172 {
173         FUNC_ENTRANCE_SERVER
174         GeofenceServer *geofence_server = (GeofenceServer *) user_data;
175         g_return_if_fail(geofence_server);
176
177         int fence_id = 0;
178         geofence_type_e fence_type;
179         GeofenceItemData *item_data = NULL;
180
181         GList *fence_list = g_list_first(geofence_server->tracking_list);
182
183         for (; fence_list != NULL; fence_list = g_list_next(fence_list)) {
184                 fence_id = GPOINTER_TO_INT(fence_list->data);
185                 item_data = NULL;
186                 item_data = __get_item_by_fence_id(fence_id, geofence_server);
187
188                 if (item_data == NULL)
189                         continue;
190
191                 fence_type = item_data->common_info.type;
192
193                 if (fence_type != GEOFENCE_TYPE_WIFI)
194                         continue;
195
196                 if (state == WIFI_DEVICE_STATE_DEACTIVATED) {
197                         LOGD_GEOFENCE("Emitted to fence_id [%d] GEOFENCE_FENCE_STATE_OUT", fence_id);
198                         emit_wifi_geofence_inout_changed(geofence_server, fence_id, GEOFENCE_FENCE_STATE_OUT);
199                         emit_wifi_geofence_proximity_changed(geofence_server, fence_id, GEOFENCE_PROXIMITY_UNCERTAIN);
200                 }
201         }
202
203         LOGD_GEOFENCE("exit");
204 }
205
206 void __geofence_check_wifi_matched_bssid(wifi_connection_state_e state, char *bssid, void *user_data)
207 {
208         LOGD_GEOFENCE("Comparing the matching bssids");
209         GeofenceServer *geofence_server = (GeofenceServer *)user_data;
210         GList *tracking_fences = g_list_first(geofence_server->tracking_list);
211         int tracking_fence_id = 0;
212         bssid_info_s *bssid_info = NULL;
213         geofence_type_e type = -1;
214
215         /*Wifi tracking list has to be traversed here*/
216         while (tracking_fences) {
217                 tracking_fence_id = GPOINTER_TO_INT(tracking_fences->data);
218                 tracking_fences = g_list_next(tracking_fences);
219                 if (FENCE_ERR_NONE != geofence_manager_get_geofence_type(tracking_fence_id, &type)) {
220                         LOGD_GEOFENCE("Error fetching the fence type/ fence does not exist");
221                         return;
222                 }
223                 if (type == GEOFENCE_TYPE_WIFI) {
224                         if (FENCE_ERR_NONE != geofence_manager_get_bssid_info(tracking_fence_id, &bssid_info)) {
225                                 LOGD_GEOFENCE("Error fetching the fence bssid info/ fence does not exist");
226                                 return;
227                         }
228                         if (!g_ascii_strcasecmp(bssid_info->bssid, bssid) || !g_ascii_strcasecmp(g_strdelimit(bssid_info->bssid, "-", ':'), bssid)) {
229                                 LOGI_GEOFENCE("Matched wifi fence: fence_id = %d, bssid = %s", tracking_fence_id, bssid_info->bssid);
230                                 if (state == WIFI_CONNECTION_STATE_CONNECTED) {
231                                         emit_wifi_geofence_inout_changed(geofence_server, tracking_fence_id, GEOFENCE_FENCE_STATE_IN);
232                                         geofence_server->connectedTrackingWifiFenceId = tracking_fence_id;
233                                 } else if (state == WIFI_CONNECTION_STATE_DISCONNECTED) {
234                                         emit_wifi_geofence_inout_changed(geofence_server, tracking_fence_id, GEOFENCE_FENCE_STATE_OUT);
235                                         emit_wifi_geofence_proximity_changed(geofence_server, tracking_fence_id, GEOFENCE_PROXIMITY_UNCERTAIN);
236                                         geofence_server->connectedTrackingWifiFenceId = -1;
237                                 }
238                                 break;  /*Because there cannot be two APs connected at the same time*/
239                         }
240                 }
241         }
242
243 }
244
245 void wifi_conn_state_changed(wifi_connection_state_e state, wifi_ap_h ap, void *user_data)
246 {
247         LOGD_GEOFENCE("wifi_conn_state_changed");
248         GeofenceServer *geofence_server = (GeofenceServer *)user_data;
249         char *ap_bssid = NULL;
250         int rv = 0;
251         g_return_if_fail(geofence_server);
252         rv = wifi_ap_get_bssid(ap, &ap_bssid);
253
254         if (rv != WIFI_ERROR_NONE) {
255                 LOGD_GEOFENCE("Failed to get the bssid");
256                 return;
257         }
258
259         if (state == WIFI_CONNECTION_STATE_CONNECTED) {
260                 LOGD_GEOFENCE("Wifi connected to [%s].", ap_bssid);
261                 __geofence_check_wifi_matched_bssid(state, ap_bssid, user_data);
262         } else if (state == WIFI_CONNECTION_STATE_DISCONNECTED) {
263                 LOGD_GEOFENCE("Wifi disconnected with [%s].", ap_bssid);
264                 __geofence_check_wifi_matched_bssid(state, ap_bssid, user_data);
265         }
266 }