All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Cache EF-PNN, EF-OPL sim files on disk.
@ 2009-07-05  3:14 Andrzej Zaborowski
  2009-07-14 20:54 ` Denis Kenzior
  0 siblings, 1 reply; 13+ messages in thread
From: Andrzej Zaborowski @ 2009-07-05  3:14 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 9950 bytes --]

This uses plain files in /var/cache/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.
---
 bootstrap-configure |    3 +-
 configure.ac        |    5 +
 src/sim.c           |  233 +++++++++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 233 insertions(+), 8 deletions(-)

diff --git a/bootstrap-configure b/bootstrap-configure
index 2519f22..2c4d9a2 100755
--- a/bootstrap-configure
+++ b/bootstrap-configure
@@ -10,4 +10,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 2d16fae..dd1d7aa 100644
--- a/configure.ac
+++ b/configure.ac
@@ -87,6 +87,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 13557bf..f7992c7 100644
--- a/src/sim.c
+++ b/src/sim.c
@@ -25,6 +25,10 @@
 
 #include <string.h>
 #include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
 
 #include <dbus/dbus.h>
 #include <glib.h>
@@ -70,6 +74,219 @@ struct sim_manager_data {
 	int pnn_current;
 };
 
+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;
+}
+
+#define SIM_CACHE_MODE 0600
+#define SIM_CACHE_PATH CONFIG_LOCALSTATEDIR "/cache/ofono/%s/%04x"
+#define SIM_CACHE_PATH_LEN(imsilen) (strlen(SIM_CACHE_PATH) - 2 + imsilen)
+
+struct sim_cache_callback {
+	struct sim_manager_data *sim;
+	void *cb;
+	void *data;
+	int fileid;
+	int record;
+};
+
+static void read_file_info_cached_cb(const struct ofono_error *error,
+		int file_length, enum ofono_sim_file_structure structure,
+		int record_length, void *data)
+{
+	struct sim_cache_callback *cbs = data;
+	ofono_sim_file_info_cb_t cb = cbs->cb;
+	char *path;
+	char *imsi = cbs->sim->imsi;
+	unsigned char fileinfo[6];
+	int fd = -1, fileid, ret;
+
+	cb(error, file_length, structure, record_length, cbs->data);
+
+	fileid = cbs->fileid;
+	g_free(cbs);
+
+	/* Even if the file doesn't exist, cache this fact so we don't
+	 * try and fail every time.  */
+	if (imsi) {
+		path = g_strdup_printf(SIM_CACHE_PATH ".info", imsi, fileid);
+		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, fileid, imsi);
+			return;
+		}
+
+		fileinfo[0] = error->type;
+		fileinfo[1] = file_length >> 8;
+		fileinfo[2] = file_length & 0xff;
+		fileinfo[3] = structure;
+		fileinfo[4] = record_length >> 8;
+		fileinfo[5] = record_length & 0xff;
+
+		write(fd, fileinfo, 6);
+		close(fd);
+	}
+}
+
+static void read_file_info_cached(struct ofono_modem *modem, int fileid,
+		ofono_sim_file_info_cb_t cb, void *data)
+{
+	char *path;
+	char *imsi = modem->sim_manager->imsi;
+	int fd;
+	unsigned char fileinfo[6];
+	ssize_t len;
+	struct ofono_error error;
+	int file_length;
+	enum ofono_sim_file_structure structure;
+	int record_length;
+	struct sim_cache_callback *cbs;
+
+	if (!imsi)
+		goto uncached;
+
+	path = g_strdup_printf(SIM_CACHE_PATH ".info", 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);
+
+		goto uncached;
+	}
+
+	len = read(fd, fileinfo, 6);
+	close(fd);
+
+	if (len == 6) {
+		error.type = fileinfo[0];
+		file_length = (fileinfo[1] << 8) | fileinfo[2];
+		structure = fileinfo[3];
+		record_length = (fileinfo[4] << 8) | fileinfo[5];
+
+		return cb(&error, file_length, structure, record_length, data);
+	}
+
+uncached:
+	cbs = g_new(struct sim_cache_callback, 1);
+	cbs->sim = modem->sim_manager;
+	cbs->cb = cb;
+	cbs->data = data;
+	cbs->fileid = fileid;
+	return modem->sim_manager->ops->read_file_info(modem,
+			fileid, read_file_info_cached_cb, cbs);
+}
+
+static void read_file_linear_cached_cb(const struct ofono_error *error,
+		const unsigned char *buffer, int length, void *data)
+{
+	struct sim_cache_callback *cbs = data;
+	ofono_sim_read_cb_t cb = cbs->cb;
+	char *path;
+	char *imsi = cbs->sim->imsi;
+	int fd = -1, fileid, ret, record;
+
+	cb(error, buffer, length, cbs->data);
+
+	fileid = cbs->fileid;
+	record = cbs->record;
+	g_free(cbs);
+
+	/* If read was successful, store the record contents */
+	if (error->type == OFONO_ERROR_TYPE_NO_ERROR && imsi) {
+		path = g_strdup_printf(SIM_CACHE_PATH, imsi, fileid);
+		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)
+			return;
+
+		if (!record || lseek(fd, length * record, SEEK_SET) !=
+				(off_t) -1)
+			write(fd, buffer, length);
+		close(fd);
+	}
+}
+
+static void read_file_linear_cached(struct ofono_modem *modem, int fileid,
+		int record, int length, ofono_sim_read_cb_t cb, void *data)
+{
+	char *path;
+	char *imsi = modem->sim_manager->imsi;
+	int fd;
+	unsigned char buffer[length];
+	ssize_t rlength = 0;
+	struct ofono_error error;
+	struct sim_cache_callback *cbs;
+
+	if (!imsi)
+		goto uncached;
+
+	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", fileid, imsi);
+
+		goto uncached;
+	}
+
+	if (!record || lseek(fd, length * record, SEEK_SET) != (off_t) -1)
+		rlength = read(fd, buffer, length);
+	close(fd);
+
+	if (rlength == length) {
+		error.type = OFONO_ERROR_TYPE_NO_ERROR;
+		return cb(&error, buffer, length, data);
+	}
+
+uncached:
+	cbs = g_new(struct sim_cache_callback, 1);
+	cbs->sim = modem->sim_manager;
+	cbs->cb = cb;
+	cbs->data = data;
+	cbs->fileid = fileid;
+	cbs->record = record;
+	return modem->sim_manager->ops->read_file_linear(modem, fileid,
+			record, length, read_file_linear_cached_cb, cbs);
+}
+
 static char **get_own_numbers(GSList *own_numbers)
 {
 	int nelem = 0;
@@ -762,7 +979,7 @@ static void sim_opl_read_cb(const struct ofono_error *error,
 skip:
 	sim->opl_current ++;
 	if (sim->opl_current < sim->opl_num)
-		sim->ops->read_file_linear(modem, SIM_EFOPL_FILEID,
+		read_file_linear_cached(modem, SIM_EFOPL_FILEID,
 						sim->opl_current,
 						sim->opl_size,
 						sim_opl_read_cb, modem);
@@ -787,7 +1004,7 @@ static void sim_opl_info_cb(const struct ofono_error *error, int length,
 	sim->opl_current = 0;
 	sim->opl_size = record_length;
 	sim->opl_num = length / record_length;
-	sim->ops->read_file_linear(modem, SIM_EFOPL_FILEID, 0,
+	read_file_linear_cached(modem, SIM_EFOPL_FILEID, 0,
 			record_length, sim_opl_read_cb, modem);
 }
 
@@ -796,7 +1013,7 @@ static gboolean sim_retrieve_opl(void *user_data)
 	struct ofono_modem *modem = user_data;
 	struct sim_manager_data *sim = modem->sim_manager;
 
-	sim->ops->read_file_info(modem, SIM_EFOPL_FILEID,
+	read_file_info_cached(modem, SIM_EFOPL_FILEID,
 			sim_opl_info_cb, modem);
 
 	return FALSE;
@@ -861,7 +1078,7 @@ static void sim_pnn_read_cb(const struct ofono_error *error,
 skip:
 	sim->pnn_current ++;
 	if (sim->pnn_current < sim->pnn_num)
-		sim->ops->read_file_linear(modem, SIM_EFPNN_FILEID,
+		read_file_linear_cached(modem, SIM_EFPNN_FILEID,
 						sim->pnn_current,
 						sim->pnn_size,
 						sim_pnn_read_cb, modem);
@@ -892,7 +1109,7 @@ static void sim_pnn_info_cb(const struct ofono_error *error, int length,
 	sim->pnn_size = record_length;
 	sim->pnn_num = length / record_length;
 	sim->pnn = g_new0(struct pnn_operator, sim->pnn_num);
-	sim->ops->read_file_linear(modem, SIM_EFPNN_FILEID, 0,
+	read_file_linear_cached(modem, SIM_EFPNN_FILEID, 0,
 			record_length, sim_pnn_read_cb, modem);
 }
 
@@ -901,7 +1118,7 @@ static gboolean sim_retrieve_pnn(void *user_data)
 	struct ofono_modem *modem = user_data;
 	struct sim_manager_data *sim = modem->sim_manager;
 
-	sim->ops->read_file_info(modem, SIM_EFPNN_FILEID,
+	read_file_info_cached(modem, SIM_EFPNN_FILEID,
 			sim_pnn_info_cb, modem);
 
 	return FALSE;
@@ -940,8 +1157,10 @@ static void initialize_sim_manager(struct ofono_modem *modem)
 	if (modem->sim_manager->ops->read_file_transparent)
 		g_timeout_add(0, sim_retrieve_spdi, modem);
 
+	/* Schedule later than IMSI so that there's a chance we can
+	 * use SIM cache, which is IMSI-indexed.  */
 	if (modem->sim_manager->ops->read_file_linear)
-		g_timeout_add(0, sim_retrieve_pnn, modem);
+		g_timeout_add_seconds(1, sim_retrieve_pnn, modem);
 }
 
 int ofono_sim_manager_register(struct ofono_modem *modem,
-- 
1.6.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2009-07-29 22:24 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-07-05  3:14 [PATCH] Cache EF-PNN, EF-OPL sim files on disk Andrzej Zaborowski
2009-07-14 20:54 ` Denis Kenzior
2009-07-18  4:34   ` Andrzej Zaborowski
2009-07-18  6:02     ` Denis Kenzior
2009-07-18 11:32       ` andrzej zaborowski
2009-07-18 11:39         ` Marcel Holtmann
2009-07-18 12:42         ` andrzej zaborowski
2009-07-20 16:12           ` Andrzej Zaborowski
2009-07-20 14:24             ` Marcel Holtmann
2009-07-20 14:56               ` andrzej zaborowski
2009-07-27 23:13             ` Denis Kenzior
2009-07-28  1:39               ` Andrzej Zaborowski
2009-07-29 22:24                 ` Denis Kenzior

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.