kr_controller.c

Go to the documentation of this file.
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