summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrzej Zaborowski <andrew.zaborowski@intel.com>2009-07-20 18:12:02 +0200
committerDenis Kenzior <denkenz@gmail.com>2009-07-27 17:09:48 -0500
commitaa71d0951600f1b415d8b0f03a3ed68033d9af08 (patch)
treee1de9af1be546e8a5ef70bd8ab0b3d29070c7369
parent5c981d421eacef2644a39b4f1fbe68cea2a04fee (diff)
downloadofono-aa71d0951600f1b415d8b0f03a3ed68033d9af08.tar.bz2
Cache EF-PNN, EF-OPL sim files on disk.
This uses plain files in /var/lib/ofono for storing contents of the operator lists to avoid possibly numerous queries to the SIM on every startup. Files are indexed with IMSI. I'm not 100% sure about the autoconf magic. Users need to rerun bootstrap-configure after applying this. Depends on [PATCH] Return SIM file access conditions from read_file_info.
-rwxr-xr-xbootstrap-configure3
-rw-r--r--configure.ac5
-rw-r--r--src/sim.c197
3 files changed, 204 insertions, 1 deletions
diff --git a/bootstrap-configure b/bootstrap-configure
index cc82e1a9..cea17bfa 100755
--- a/bootstrap-configure
+++ b/bootstrap-configure
@@ -12,4 +12,5 @@ fi
--prefix=/usr \
--mandir=/usr/share/man \
--sysconfdir=/etc \
- --disable-datafiles
+ --disable-datafiles \
+ --localstatedir=/var
diff --git a/configure.ac b/configure.ac
index bb52d9d0..f829b470 100644
--- a/configure.ac
+++ b/configure.ac
@@ -96,6 +96,11 @@ AC_ARG_ENABLE(datafiles, AC_HELP_STRING([--disable-datafiles],
AM_CONDITIONAL(DATAFILES, test "${enable_datafiles}" != "no")
+eval "eval LOCALSTATE_DIR=$localstatedir"
+AC_SUBST(LOCALSTATE_DIR)
+AC_DEFINE_UNQUOTED(CONFIG_LOCALSTATEDIR, "$LOCALSTATE_DIR",
+ [Define to the location where state is stored.])
+
COMPILER_FLAGS
AC_OUTPUT(Makefile gdbus/Makefile gatchat/Makefile gisi/Makefile
diff --git a/src/sim.c b/src/sim.c
index 787ebc7f..7f905b1a 100644
--- a/src/sim.c
+++ b/src/sim.c
@@ -29,6 +29,10 @@
#include <dbus/dbus.h>
#include <glib.h>
#include <gdbus.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
#include "ofono.h"
@@ -48,6 +52,7 @@ static gboolean sim_op_retrieve_next(gpointer user);
struct sim_file_op {
int id;
+ int cache;
enum ofono_sim_file_structure structure;
int length;
int record_length;
@@ -267,6 +272,34 @@ static gboolean sim_retrieve_imsi(void *user_data)
return FALSE;
}
+static int create_dirs(const char *filename, const mode_t mode)
+{
+ struct stat st;
+ char *dir;
+ const char *prev, *next;
+ int err;
+
+ err = stat(filename, &st);
+ if (!err && S_ISREG(st.st_mode))
+ return 0;
+
+ dir = g_malloc(strlen(filename) + 1);
+ strcpy(dir, "/");
+
+ for (prev = filename; next = strchr(prev + 1, '/'); prev = next)
+ if (next > prev + 1) {
+ strncat(dir, prev + 1, next - prev);
+
+ if (mkdir(dir, mode) && errno != EEXIST) {
+ g_free(dir);
+ return -1;
+ }
+ }
+
+ g_free(dir);
+ return 0;
+}
+
static void sim_op_error(struct ofono_modem *modem)
{
struct sim_manager_data *sim = modem->sim_manager;
@@ -280,6 +313,11 @@ static void sim_op_error(struct ofono_modem *modem)
g_timeout_add(0, sim_op_next, modem);
}
+#define SIM_CACHE_MODE 0600
+#define SIM_CACHE_PATH CONFIG_LOCALSTATEDIR "/lib/ofono/%s/%04x"
+#define SIM_CACHE_PATH_LEN(imsilen) (strlen(SIM_CACHE_PATH) - 2 + imsilen)
+#define SIM_CACHE_HEADER_SIZE 6
+
static void sim_op_retrieve_cb(const struct ofono_error *error,
const unsigned char *data, int len, void *user)
{
@@ -288,6 +326,10 @@ static void sim_op_retrieve_cb(const struct ofono_error *error,
struct sim_file_op *op = g_queue_peek_head(sim->simop_q);
int total = op->length / op->record_length;
+ char *imsi = sim->imsi;
+ char *path;
+ int fd, ret;
+
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
if (op->current == 1)
sim_op_error(modem);
@@ -298,6 +340,23 @@ static void sim_op_retrieve_cb(const struct ofono_error *error,
op->cb(modem, 1, op->structure, op->length, op->current,
data, op->record_length, op->userdata);
+ if (op->cache && imsi) {
+ /* Cache the record */
+ path = g_strdup_printf(SIM_CACHE_PATH, imsi, op->id);
+ fd = open(path, O_WRONLY);
+ g_free(path);
+
+ if (fd == -1)
+ goto next;
+
+ if (lseek(fd, (op->current - 1) * op->record_length +
+ SIM_CACHE_HEADER_SIZE, SEEK_SET) !=
+ (off_t) -1)
+ write(fd, data, op->record_length);
+ close(fd);
+ }
+
+next:
if (op->current == total) {
op = g_queue_pop_head(sim->simop_q);
@@ -363,6 +422,11 @@ static void sim_op_info_cb(const struct ofono_error *error, int length,
struct sim_manager_data *sim = modem->sim_manager;
struct sim_file_op *op = g_queue_peek_head(sim->simop_q);
+ char *imsi = sim->imsi;
+ char *path;
+ unsigned char fileinfo[6];
+ int fd = -1;
+
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
sim_op_error(modem);
return;
@@ -370,6 +434,12 @@ static void sim_op_info_cb(const struct ofono_error *error, int length,
op->structure = structure;
op->length = length;
+ /* Never cache card holder writable files */
+ op->cache = (
+ access[OFONO_SIM_FILE_CONDITION_UPDATE] ==
+ OFONO_SIM_FILE_ACCESS_ADM ||
+ access[OFONO_SIM_FILE_CONDITION_UPDATE] ==
+ OFONO_SIM_FILE_ACCESS_NEVER);
if (structure == OFONO_SIM_FILE_STRUCTURE_TRANSPARENT)
op->record_length = length;
@@ -379,6 +449,30 @@ static void sim_op_info_cb(const struct ofono_error *error, int length,
op->current = 1;
g_timeout_add(0, sim_op_retrieve_next, modem);
+
+ if (op->cache && imsi) {
+ path = g_strdup_printf(SIM_CACHE_PATH, imsi, op->id);
+ if (create_dirs(path, SIM_CACHE_MODE | S_IXUSR) == 0)
+ fd = open(path, O_WRONLY | O_CREAT, SIM_CACHE_MODE);
+ g_free(path);
+
+ if (fd == -1) {
+ ofono_debug("Error %i creating cache file for "
+ "fileid %04x, IMSI %s",
+ errno, op->id, imsi);
+ return;
+ }
+
+ fileinfo[0] = error->type;
+ fileinfo[1] = length >> 8;
+ fileinfo[2] = length & 0xff;
+ fileinfo[3] = structure;
+ fileinfo[4] = record_length >> 8;
+ fileinfo[5] = record_length & 0xff;
+
+ write(fd, fileinfo, 6);
+ close(fd);
+ }
}
static gboolean sim_op_next(gpointer user_data)
@@ -397,6 +491,106 @@ static gboolean sim_op_next(gpointer user_data)
return FALSE;
}
+struct sim_cache_callback {
+ ofono_sim_file_read_cb_t cb;
+ void *userdata;
+ struct ofono_modem *modem;
+ int error;
+ int fd;
+ enum ofono_sim_file_structure structure;
+ unsigned int record_length;
+ unsigned int total;
+};
+
+static gboolean sim_op_cached_callback(gpointer user)
+{
+ struct sim_cache_callback *cbs = user;
+ guint8 buffer[cbs->record_length];
+ unsigned int record;
+
+ if (cbs->error != OFONO_ERROR_TYPE_NO_ERROR) {
+ cbs->cb(cbs->modem, 0, 0, 0, 0, 0, 0, 0);
+ goto cleanup;
+ }
+
+ for (record = 0; record < cbs->total; record++) {
+ if (read(cbs->fd, buffer, cbs->record_length) <
+ (int) cbs->record_length) {
+ cbs->cb(cbs->modem, 0, 0, 0, 0, 0, 0, 0);
+ break;
+ }
+
+ cbs->cb(cbs->modem, 1, cbs->structure,
+ cbs->record_length * cbs->total, record + 1,
+ buffer, cbs->record_length, cbs->userdata);
+ }
+
+cleanup:
+ close(cbs->fd);
+ g_free(cbs);
+
+ return FALSE;
+}
+
+static gboolean sim_op_check_cached(struct ofono_modem *modem, int fileid,
+ ofono_sim_file_read_cb_t cb, void *data)
+{
+ struct sim_manager_data *sim = modem->sim_manager;
+ char *imsi = sim->imsi;
+ char *path;
+ int fd;
+ unsigned char fileinfo[SIM_CACHE_HEADER_SIZE];
+ ssize_t len;
+ struct ofono_error error;
+ unsigned int file_length;
+ enum ofono_sim_file_structure structure;
+ unsigned int record_length;
+ struct sim_cache_callback *cbs;
+
+ if (!imsi)
+ return FALSE;
+
+ path = g_strdup_printf(SIM_CACHE_PATH, imsi, fileid);
+ fd = open(path, O_RDONLY);
+ g_free(path);
+
+ if (fd == -1) {
+ if (errno != ENOENT)
+ ofono_debug("Error %i opening cache file for "
+ "fileid %04x, IMSI %s",
+ errno, fileid, imsi);
+
+ return FALSE;
+ }
+
+ len = read(fd, fileinfo, SIM_CACHE_HEADER_SIZE);
+ if (len != SIM_CACHE_HEADER_SIZE)
+ return FALSE;
+
+ error.type = fileinfo[0];
+ file_length = (fileinfo[1] << 8) | fileinfo[2];
+ structure = fileinfo[3];
+ record_length = (fileinfo[4] << 8) | fileinfo[5];
+
+ if (structure == OFONO_SIM_FILE_STRUCTURE_TRANSPARENT)
+ record_length = file_length;
+ if (record_length == 0 || file_length < record_length)
+ return FALSE;
+
+ cbs = g_new(struct sim_cache_callback, 1);
+ cbs->cb = cb;
+ cbs->userdata = data;
+ cbs->modem = modem;
+ cbs->error = error.type;
+ cbs->fd = fd;
+ cbs->structure = structure;
+ cbs->record_length = record_length;
+ cbs->total = file_length / record_length;
+ g_timeout_add(0, sim_op_cached_callback, cbs);
+
+ return TRUE;
+}
+
int ofono_sim_read(struct ofono_modem *modem, int id,
ofono_sim_file_read_cb_t cb, void *data)
{
@@ -409,6 +603,9 @@ int ofono_sim_read(struct ofono_modem *modem, int id,
if (modem->sim_manager == NULL)
return -1;
+ if (sim_op_check_cached(modem, id, cb, data))
+ return 0;
+
if (!sim->ops)
return -1;