00001 #include "kr_controller_private.h" 00002 00003 #include "cf_query.h" 00004 #include "epoc-iap.h" 00005 #include "kr_diskspace.h" 00006 #include "utils_cl2.h" 00007 00008 #include "common/assertions.h" 00009 #include "common/error_list.h" 00010 #include "common/logging.h" 00011 #include "common/platform_config.h" 00012 #include "common/utilities.h" 00013 00014 #if __WITH_LIBEV__ 00015 #include <ev.h> 00016 #endif 00017 00018 // -------------------------------------------------- 00019 // internal 00020 // -------------------------------------------------- 00021 00022 #if __FEATURE_UPLOADER__ 00023 static gboolean start_uploader(kr_Controller* self, GError** error) 00024 { 00025 assert(!self->uploader); 00026 self->uploader = up_Uploader_new(self->appContext, error); 00027 if (!self->uploader) { 00028 return FALSE; 00029 } 00030 return TRUE; 00031 } 00032 #endif 00033 00034 #if __FEATURE_UPLOADER__ 00035 static void stop_uploader(kr_Controller* self) 00036 { 00037 up_Uploader_destroy(self->uploader); // safe if NULL 00038 self->uploader = NULL; 00039 //logt("uploader destroyed"); 00040 } 00041 #endif 00042 00043 // -------------------------------------------------- 00044 // uploads allowed flag 00045 // -------------------------------------------------- 00046 00047 static gboolean current_iap_is_cellular() 00048 { 00049 #if defined(__SYMBIAN32__) && __CAN_GET_NETWORK_INFO__ 00050 int value = get_config_iap_id(); 00051 if (value < 0) { 00052 // No IAP configured. User can manually choose IAP or not. 00053 return FALSE; 00054 } 00055 guint32 iapId = (guint32)value; 00056 gboolean found = FALSE; 00057 gboolean yes = FALSE; 00058 GError* error = NULL; 00059 LogDb* logDb = ac_global_LogDb; 00060 if (!epoc_iap_is_modem(iapId, &found, &yes, &error)) { 00061 log_db_log_status(logDb, NULL, "could not look up bearer for IAP ID %u", iapId); 00062 gx_dblog_error_free(logDb, error); 00063 return TRUE; // play it safe 00064 } 00065 if (!found) { 00066 log_db_log_status(logDb, NULL, "WARNING: no IAP ID %u", iapId); 00067 return TRUE; // play it safe 00068 } 00069 logg("iap %u is modem bearer: %d", iapId, yes); 00070 return yes; 00071 #else 00072 return FALSE; 00073 #endif /* __SYMBIAN32__ */ 00074 } 00075 00076 static void log_uploads_allowed(kr_Controller* self) 00077 { 00078 //logg("uploads allowed: %d", self->are_uploads_allowed); 00079 LogDb* logDb = ac_global_LogDb; 00080 // http://en.wikipedia.org/wiki/Signal_strength says 00081 // "decibels above a reference level of one milliwatt (dBm)" 00082 log_db_log_status(logDb, NULL, "CHANGE: uploads allowed = %s (modem IAP %s, MCC %d at %d dBm)", boolstr_yes(self->are_uploads_allowed), boolstr_yes(self->is_cellular_ap), self->current_mcc, self->current_signal_strength); 00083 } 00084 00085 static void uploads_allowed_update_board(gboolean value) 00086 { 00087 bb_Blackboard* bb = ac_global_Blackboard; 00088 assert(bb); 00089 bb_Board* bd = bb_Blackboard_board(bb); 00090 bd->uploads_allowed = value; 00091 bb_Blackboard_notify(bb, bb_dt_uploads_allowed, 00092 (gpointer)&(bd->uploads_allowed), 0); 00093 } 00094 00095 static void uploads_allowed_changed(kr_Controller* self) 00096 { 00097 log_uploads_allowed(self); 00098 uploads_allowed_update_board(self->are_uploads_allowed); 00099 } 00100 00101 static void netpos_allowed_update_board(gboolean value) 00102 { 00103 log_db_log_status(ac_global_LogDb, NULL, 00104 "CHANGE: network positioning allowed = %s", 00105 boolstr_yes(value)); 00106 bb_Blackboard* bb = ac_global_Blackboard; 00107 bb_Board* bd = bb_Blackboard_board(bb); 00108 bd->netpos_allowed = value; // mirrored here 00109 bb_Blackboard_notify(ac_global_Blackboard, bb_dt_netpos_allowed, 00110 GINT_TO_POINTER(value), 0); 00111 } 00112 00113 static void recompute_netpos_allowed(kr_Controller* self); 00114 00115 static void init_uploads_allowed_state(kr_Controller* self) 00116 { 00117 //WHEN_SYMBIAN(epoc_log_bearer_types()); 00118 00119 self->is_cellular_ap = current_iap_is_cellular(); 00120 self->non_roaming_mcc = cf_RcFile_get_mcc(self->rcFile); 00121 self->non_roaming_operator_name = cf_RcFile_get_operator_name(self->rcFile); 00122 self->current_signal_strength = 1; // no reading yet 00123 self->current_mcc = -1; // no reading yet 00124 GMaybeString_init(&self->current_operator_name); 00125 00126 // Initial value, until more information about any mobile network 00127 // becomes available. 00128 self->are_uploads_allowed = !self->is_cellular_ap; 00129 00130 logg("non-roaming MCC: %d", self->non_roaming_mcc); 00131 WHEN_LOGGING({if (self->non_roaming_operator_name) logg("non-roaming operator: '%s'", self->non_roaming_operator_name);}); 00132 uploads_allowed_changed(self); 00133 00134 self->is_netpos_allowed = FALSE; 00135 recompute_netpos_allowed(self); 00136 } 00137 00138 static void free_uploads_allowed_state(kr_Controller* self) 00139 { 00140 GMaybeString_free(&self->current_operator_name); 00141 } 00142 00143 static void recompute_netpos_allowed(kr_Controller* self) 00144 { 00145 gboolean oldval = self->is_netpos_allowed; 00146 gboolean newval = TRUE; 00147 00148 if (self->current_mcc == -1) { 00149 // no network 00150 newval = FALSE; 00151 } 00152 else 00153 if (self->non_roaming_mcc != -1) { 00154 // have a roaming restriction 00155 if (self->current_mcc != self->non_roaming_mcc) 00156 // is roaming 00157 newval = FALSE; 00158 } 00159 else 00160 if (self->non_roaming_operator_name) { 00161 // have a roaming restriction 00162 if (GMaybeString_is_nothing(&self->current_operator_name) || 00163 !GMaybeString_is(&self->current_operator_name, 00164 self->non_roaming_operator_name)) 00165 // is roaming 00166 newval = FALSE; 00167 } 00168 00169 if (oldval != newval) { 00170 self->is_netpos_allowed = newval; 00171 netpos_allowed_update_board(newval); 00172 } 00173 } 00174 00175 static void recompute_uploads_allowed(kr_Controller* self) 00176 { 00177 gboolean old_flag = self->are_uploads_allowed; 00178 //logg("recomputing uploads allowed (now %d)", old_flag); 00179 self->are_uploads_allowed = TRUE; 00180 if (self->is_cellular_ap) { 00181 if ((self->current_signal_strength == 1) || 00182 (self->current_mcc == -1)) { 00183 // no network 00184 self->are_uploads_allowed = FALSE; 00185 } else { 00186 if (self->non_roaming_mcc != -1) { 00187 // have a roaming restriction 00188 if (self->current_mcc != self->non_roaming_mcc) 00189 // is roaming 00190 self->are_uploads_allowed = FALSE; 00191 } 00192 00193 if (self->non_roaming_operator_name) { 00194 // have a roaming restriction 00195 if (GMaybeString_is_nothing(&self->current_operator_name) || 00196 !GMaybeString_is(&self->current_operator_name, 00197 self->non_roaming_operator_name)) 00198 // is roaming 00199 self->are_uploads_allowed = FALSE; 00200 } 00201 00202 // strength is from -123 dBm to -1 dBm (inclusive), 00203 // but apparently can also be 0 in flight mode 00204 if ((self->current_signal_strength < -110) || 00205 (self->current_signal_strength == 0)) 00206 // poor signal 00207 self->are_uploads_allowed = FALSE; 00208 } 00209 } 00210 if (old_flag != self->are_uploads_allowed) { 00211 uploads_allowed_changed(self); 00212 } 00213 } 00214 00215 // Called after "iap" configuration changes. 00216 static void iap_config_changed(kr_Controller* self) 00217 { 00218 gboolean nval = current_iap_is_cellular(); 00219 if (nval != self->is_cellular_ap) { 00220 self->is_cellular_ap = nval; 00221 recompute_uploads_allowed(self); 00222 } 00223 } 00224 00225 // pass +1 for no network 00226 void kr_Controller_set_signal_strength(kr_Controller* self, int strength) 00227 { 00228 //logg("setting strength to %d", strength); 00229 if (strength != self->current_signal_strength) { 00230 self->current_signal_strength = strength; 00231 recompute_uploads_allowed(self); 00232 } 00233 } 00234 00235 // pass -1 for no network 00236 void kr_Controller_set_current_mcc(kr_Controller* self, int mcc) 00237 { 00238 logg("setting mcc to %d", mcc); 00239 if (mcc != self->current_mcc) { 00240 self->current_mcc = mcc; 00241 recompute_uploads_allowed(self); 00242 recompute_netpos_allowed(self); 00243 } 00244 } 00245 00246 // pass NULL for no network or no name 00247 void kr_Controller_set_operator_name(kr_Controller* self, const char* name) 00248 { 00249 // As an optimization, we do not care unless the operator name 00250 // affects our roaming analysis. 00251 if (self->non_roaming_operator_name) { 00252 if (!GMaybeString_is(&self->current_operator_name, name)) { 00253 logg("setting operator to %s", name ? name : "<none>"); 00254 er_log_oom_on_false(GMaybeString_assign(&self->current_operator_name, name, NULL)); 00255 recompute_uploads_allowed(self); 00256 recompute_netpos_allowed(self); 00257 } 00258 } 00259 } 00260 00261 // -------------------------------------------------- 00262 // exported interface 00263 // -------------------------------------------------- 00264 00265 kr_Controller* kr_Controller_new(GError** error) 00266 { 00267 assert_error_unset(error); 00268 00269 //er_log_none(er_FATAL, "terrible error (%d)", 555); 00270 00271 kr_Controller* self = g_try_new0(kr_Controller, 1); 00272 if (G_UNLIKELY(!self)) { 00273 if (error) *error = gx_error_no_memory; 00274 return NULL; 00275 } 00276 00277 self->appContext = ac_get_global_AppContext(); 00278 // A controller reference kept here whenever it exists. Querying 00279 // AppContext at any time will tell you which objects exist. 00280 ac_AppContext_set_controller(self->appContext, self); 00281 00282 #if __WITH_LIBEV__ 00283 // Creates the default event loop, unless already created. 00284 struct ev_loop* loop = ev_default_loop(0); 00285 if (!loop) { 00286 if (error) *error = gx_error_no_memory; 00287 kr_Controller_destroy(self); 00288 return NULL; 00289 } 00290 #endif 00291 00292 self->rcFile = cf_RcFile_new(error); 00293 if (!(self->rcFile)) { 00294 kr_Controller_destroy(self); 00295 return NULL; 00296 } 00297 00298 if (!ac_AppContext_configure(self->appContext, error)) { 00299 kr_Controller_destroy(self); 00300 return NULL; 00301 } 00302 00303 #if LOGGING_MEDIUM_CHECK_SUPPORTED 00304 // Must be done after config file reading, as the threshold is 00305 // configurable. We do want to do this as early as possible, though, 00306 // to avoid doing a lot of work when the watchdog repeatedly tries 00307 // to launch us. 00308 if (!check_logging_medium_ready(error)) { 00309 kr_Controller_destroy(self); 00310 return NULL; 00311 } 00312 logt("logging medium ready"); 00313 #endif 00314 00315 self->configDb = ConfigDb_new(error); 00316 if (!(self->configDb)) { 00317 kr_Controller_destroy(self); 00318 return NULL; 00319 } 00320 00321 LogDb* log = LogDb_new(error); 00322 if (G_UNLIKELY(!log)) { 00323 kr_Controller_destroy(self); 00324 return NULL; 00325 } 00326 self->log = log; 00327 00328 init_uploads_allowed_state(self); 00329 00330 #if __FEATURE_UPLOADER__ 00331 // This is a bit different in that Uploader is not affected by 00332 // controller start/stop. Even though Uploader typically does not 00333 // consume much resources (i.e., connections are only made when 00334 // there is something to upload), this is still somewhat 00335 // questionable. Consider uploader/start stop in the start stop 00336 // methods, but remember that then self->uploader will be NULL at 00337 // times. 00338 if (!start_uploader(self, error)) { 00339 kr_Controller_destroy(self); 00340 return NULL; 00341 } 00342 #endif 00343 00344 sa_Array* scanner = sa_Array_new(self->appContext, error); 00345 if (!scanner) { 00346 kr_Controller_destroy(self); 00347 return NULL; 00348 } 00349 self->scanner = scanner; 00350 00351 #if __FEATURE_LOCALSERVER__ 00352 LocalServer* localServer = LocalServer_new(error); 00353 if (!localServer) { 00354 kr_Controller_destroy(self); 00355 return NULL; 00356 } 00357 self->localServer = localServer; 00358 #endif 00359 00360 #if __FEATURE_REMOKON__ 00361 self->remokon = rk_Remokon_new(error); 00362 if (!self->remokon) { 00363 kr_Controller_destroy(self); 00364 return NULL; 00365 } 00366 #endif 00367 00368 #if HAVE_PLAT_AO 00369 self->platAo = kr_PlatAo_new(error); 00370 if (!self->platAo) { 00371 kr_Controller_destroy(self); 00372 return NULL; 00373 } 00374 #endif 00375 00376 return self; 00377 00378 #if 0 00379 fail: 00380 kr_Controller_destroy(self); 00381 if (error) *error = gx_error_no_memory; 00382 return NULL; 00383 #endif 00384 } 00385 00386 void kr_Controller_destroy(kr_Controller* self) 00387 { 00388 if (self) { 00389 // Note that we are not destroying any event loop here, with 00390 // ev_default_destroy(), so any components signed up with it are 00391 // responsible for deregistering. 00392 00393 #if HAVE_PLAT_AO 00394 kr_PlatAo_destroy(self->platAo); 00395 #endif 00396 00397 #if __FEATURE_REMOKON__ 00398 FREE_Z(self->remokon, rk_Remokon_destroy); 00399 #endif 00400 00401 #if __FEATURE_LOCALSERVER__ 00402 LocalServer_destroy(self->localServer); // safe if NULL 00403 self->localServer = NULL; 00404 #endif 00405 00406 #if __FEATURE_UPLOADER__ 00407 stop_uploader(self); 00408 #endif 00409 00410 // We sometimes get USER 42 here. Say the cellid sensor is 00411 // enough to make this happen, but uploader may also be 00412 // required. 00413 sa_Array_destroy(self->scanner); 00414 self->scanner = NULL; 00415 //logt("scanner array destroyed"); 00416 00417 LogDb_destroy(self->log); 00418 self->log = NULL; 00419 //logt("LogDb session destroyed"); 00420 00421 ConfigDb_destroy(self->configDb); 00422 self->configDb = NULL; 00423 00424 cf_RcFile_destroy(self->rcFile); 00425 self->rcFile = NULL; 00426 00427 free_uploads_allowed_state(self); 00428 00429 ac_AppContext_set_controller(self->appContext, NULL); 00430 00431 g_free(self); 00432 //logt("logger controller destroyed"); 00433 } 00434 } 00435 00436 // Starts the client "active object". This starts the activities 00437 // (such as sensor scanning) of this component, but this does not 00438 // start event handling. 00439 gboolean kr_Controller_start(kr_Controller* self, GError** error) 00440 { 00441 (void)error; 00442 sa_Array_start(self->scanner); 00443 #if __FEATURE_LOCALSERVER__ 00444 if (!LocalServer_start(self->localServer, error)) { 00445 return FALSE; 00446 } 00447 #endif 00448 #if __FEATURE_REMOKON__ 00449 if (rk_Remokon_is_autostart_enabled(self->remokon)) { 00450 logt("controller: auto-starting remokon"); 00451 if (!rk_Remokon_start(self->remokon, error)) { 00452 return FALSE; 00453 } 00454 } 00455 #endif 00456 return TRUE; 00457 } 00458 00459 // Stops the client "active object". Stops the activities of this 00460 // component (apart from Uploader and any PlatAo), but does not affect 00461 // event handling, which is handled separately. 00462 void kr_Controller_stop(kr_Controller* self) 00463 { 00464 #if __FEATURE_REMOKON__ 00465 rk_Remokon_stop(self->remokon); 00466 #endif 00467 #if __FEATURE_LOCALSERVER__ 00468 LocalServer_stop(self->localServer); 00469 #endif 00470 sa_Array_stop(self->scanner); 00471 } 00472 00473 // A convenience method for running the event loop until an 00474 // interrupt event is delivered. 00475 gboolean kr_Controller_run(kr_Controller* self, GError** error) 00476 { 00477 (void)self; 00478 (void)error; 00479 #if __WITH_LIBEV__ 00480 ev_loop(EV_DEFAULT, 0); 00481 #else 00482 assert(0 && "explicit running of event loop unsupported"); 00483 #endif 00484 return TRUE; 00485 } 00486 00487 #define NAME_STARTS_WITH(lit) \ 00488 (pfx = lit, strncmp(pfx, name, strlen(pfx)) == 0) 00489 00490 #define NAME_EQUALS(lit) \ 00491 (strcmp(lit, name) == 0) 00492 00493 gboolean kr_Controller_reconfigure(kr_Controller* self, 00494 const gchar* name, 00495 const gchar* value, 00496 GError** error) 00497 { 00498 const char* pfx; 00499 00500 if (NAME_STARTS_WITH("sensor.") || 00501 NAME_STARTS_WITH("array.")) { 00502 sa_Array* obj = self->scanner; 00503 if (!sa_Array_reconfigure(obj, name, value, error)) 00504 return FALSE; 00505 } 00506 00507 else if (NAME_EQUALS("iap")) { 00508 #if __FEATURE_UPLOADER__ 00509 if (!up_Uploader_reconfigure(self->uploader, name, value, error)) 00510 return FALSE; 00511 #endif 00512 #if __FEATURE_REMOKON__ 00513 if (!rk_Remokon_reconfigure(self->remokon, name, value, error)) 00514 return FALSE; 00515 #endif 00516 iap_config_changed(self); 00517 } 00518 00519 #if __FEATURE_UPLOADER__ 00520 else if (NAME_STARTS_WITH("uploader.")) { 00521 if (!up_Uploader_reconfigure(self->uploader, name, value, error)) 00522 return FALSE; 00523 } 00524 #endif 00525 00526 #if __FEATURE_REMOKON__ 00527 else if (NAME_STARTS_WITH("remokon.")) { 00528 if (!rk_Remokon_reconfigure(self->remokon, name, value, error)) 00529 return FALSE; 00530 } 00531 #endif 00532 00533 return TRUE; 00534 } 00535 00536 /** 00537 00538 Copyright 2009 Helsinki Institute for Information Technology (HIIT) 00539 and the authors. All rights reserved. 00540 00541 Authors: Tero Hasu <tero.hasu@hut.fi> 00542 00543 Permission is hereby granted, free of charge, to any person 00544 obtaining a copy of this software and associated documentation files 00545 (the "Software"), to deal in the Software without restriction, 00546 including without limitation the rights to use, copy, modify, merge, 00547 publish, distribute, sublicense, and/or sell copies of the Software, 00548 and to permit persons to whom the Software is furnished to do so, 00549 subject to the following conditions: 00550 00551 The above copyright notice and this permission notice shall be 00552 included in all copies or substantial portions of the Software. 00553 00554 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 00555 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00556 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00557 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 00558 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 00559 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 00560 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 00561 SOFTWARE. 00562 00563 **/
ContextLogger2—ContextLogger2 Logger Daemon Internals—Generated on Mon May 2 13:49:54 2011 by Doxygen 1.6.1