aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeels Hofmeyr <nhofmeyr@sysmocom.de>2015-11-20 00:08:28 +0100
committerNeels Hofmeyr <nhofmeyr@sysmocom.de>2015-12-03 11:39:36 +0100
commit20bd6bfef5417f540e7fdd624832d1f31e38fe42 (patch)
tree7eb7429f10e020c6ebf04bfab0ad48e683edd7a3
parent1ed9a8673d67f4224a0bdbebae012c855c5d7bdc (diff)
gtphub: add explicit cleanup handles.
Clean up functionality is added for the test suite only, to be able to clean out all allocations and test against memory leaks. So far, it was sufficient to expire everything to free a gtphub. In preparation for the upcoming rate counters, which will need to be freed explicitly, add gtphub functions to clean up everything. As added bonus, also close the sockets explicitly -- not really needed upon program exit, neither by the test suite, but *if* we have a cleanup function, it should clean up everything properly. Closing the sockets is however kept separate, for the test suite. gtphub_start() and gtphub_stop() are for normal use (published in gtphub.h), and gtphub_init() and gtphub_free() are for the test suite, without sockets. (gtphub_stop() will probably never be called by anyone, but its existence completes the picture.) In gtphub_test.c, have a function to clean up the testing gtphub struct. First, expire everything by timeout, assert emptiness, then call the cleanup function. Call from each test in the end. Sponsored-by: On-Waves ehi
-rw-r--r--openbsc/include/openbsc/gtphub.h7
-rw-r--r--openbsc/src/gprs/gtphub.c57
-rw-r--r--openbsc/tests/gtphub/gtphub_test.c27
3 files changed, 85 insertions, 6 deletions
diff --git a/openbsc/include/openbsc/gtphub.h b/openbsc/include/openbsc/gtphub.h
index fa63a20cb..b375391dd 100644
--- a/openbsc/include/openbsc/gtphub.h
+++ b/openbsc/include/openbsc/gtphub.h
@@ -200,6 +200,9 @@ void expiring_item_del(struct expiring_item *item);
* count passed to nr_map_add(). A monotonous clock counter should be used. */
int expiry_tick(struct expiry *exq, time_t now);
+/* Expire all items. */
+void expiry_clear(struct expiry *exq);
+
/* number map */
@@ -429,6 +432,10 @@ int gtphub_cfg_read(struct gtphub_cfg *cfg, const char *config_file);
/* Initialize and start gtphub: bind to ports, run expiry timers. */
int gtphub_start(struct gtphub *hub, struct gtphub_cfg *cfg);
+/* Close all sockets, expire all maps and peers and free all allocations. The
+ * struct is then unusable, unless gtphub_start() is run on it again. */
+void gtphub_stop(struct gtphub *hub);
+
time_t gtphub_now(void);
/* Remove expired items, empty peers, ... */
diff --git a/openbsc/src/gprs/gtphub.c b/openbsc/src/gprs/gtphub.c
index 4507e6a14..53152493f 100644
--- a/openbsc/src/gprs/gtphub.c
+++ b/openbsc/src/gprs/gtphub.c
@@ -24,6 +24,7 @@
#include <inttypes.h>
#include <time.h>
#include <limits.h>
+#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
@@ -555,6 +556,14 @@ int expiry_tick(struct expiry *exq, time_t now)
return expired;
}
+void expiry_clear(struct expiry *exq)
+{
+ struct expiring_item *m, *n;
+ llist_for_each_entry_safe(m, n, &exq->items, entry) {
+ expiring_item_del(m);
+ }
+}
+
void expiring_item_init(struct expiring_item *item)
{
ZERO_STRUCT(item);
@@ -769,6 +778,13 @@ static int gtphub_sock_init(struct osmo_fd *ofd,
return 0;
}
+static void gtphub_sock_close(struct osmo_fd *ofd)
+{
+ close(ofd->fd);
+ osmo_fd_unregister(ofd);
+ ofd->cb = NULL;
+}
+
static void gtphub_bind_init(struct gtphub_bind *b)
{
ZERO_STRUCT(b);
@@ -788,6 +804,16 @@ static int gtphub_bind_start(struct gtphub_bind *b,
return 0;
}
+static void gtphub_bind_free(struct gtphub_bind *b)
+{
+ OSMO_ASSERT(llist_empty(&b->peers));
+}
+
+static void gtphub_bind_stop(struct gtphub_bind *b) {
+ gtphub_sock_close(&b->ofd);
+ gtphub_bind_free(b);
+}
+
/* Recv datagram from from->fd, write sender's address to *from_addr.
* Return the number of bytes read, zero on error. */
static int gtphub_read(const struct osmo_fd *from,
@@ -1758,6 +1784,37 @@ void gtphub_init(struct gtphub *hub)
hub->to_ggsns[GTPH_PLANE_USER].label = "GGSN User";
}
+/* For the test suite, this is kept separate from gtphub_stop(), which also
+ * closes sockets. The test suite avoids using sockets and would cause
+ * segfaults when trying to close uninitialized ofds. */
+void gtphub_free(struct gtphub *hub)
+{
+ /* By expiring all mappings, a garbage collection should free
+ * everything else. A gtphub_bind_free() will assert that everything is
+ * indeed empty. */
+ expiry_clear(&hub->expire_seq_maps);
+ expiry_clear(&hub->expire_tei_maps);
+
+ int plane_idx;
+ for (plane_idx = 0; plane_idx < GTPH_PLANE_N; plane_idx++) {
+ gtphub_gc_bind(&hub->to_ggsns[plane_idx]);
+ gtphub_bind_free(&hub->to_ggsns[plane_idx]);
+
+ gtphub_gc_bind(&hub->to_sgsns[plane_idx]);
+ gtphub_bind_free(&hub->to_sgsns[plane_idx]);
+ }
+}
+
+void gtphub_stop(struct gtphub *hub)
+{
+ int plane_idx;
+ for (plane_idx = 0; plane_idx < GTPH_PLANE_N; plane_idx++) {
+ gtphub_bind_stop(&hub->to_ggsns[plane_idx]);
+ gtphub_bind_stop(&hub->to_sgsns[plane_idx]);
+ }
+ gtphub_free(hub);
+}
+
static int gtphub_make_proxy(struct gtphub *hub,
struct gtphub_peer_port **pp,
struct gtphub_bind *bind,
diff --git a/openbsc/tests/gtphub/gtphub_test.c b/openbsc/tests/gtphub/gtphub_test.c
index f983f0615..2dc61eb8e 100644
--- a/openbsc/tests/gtphub/gtphub_test.c
+++ b/openbsc/tests/gtphub/gtphub_test.c
@@ -35,8 +35,6 @@
#include <gtp.h>
#include <gtpie.h>
-#define EXPIRE_ALL ((60 * GTPH_TEI_MAPPING_EXPIRY_MINUTES) + 1)
-
#define ZERO_STRUCT(struct_pointer) memset(struct_pointer, '\0', \
sizeof(*(struct_pointer)))
@@ -55,6 +53,7 @@
printf(label "\n"); }
void gtphub_init(struct gtphub *hub);
+void gtphub_free(struct gtphub *hub);
void *osmo_gtphub_ctx;
@@ -613,6 +612,23 @@ static int setup_test_hub()
return 1;
}
+static int clear_test_hub()
+{
+ /* expire all */
+ gtphub_gc(hub, now + (60 * GTPH_TEI_MAPPING_EXPIRY_MINUTES) + 1);
+
+ int plane_idx;
+ plane_idx = GTPH_PLANE_CTRL;
+ LVL2_ASSERT(llist_empty(&hub->to_ggsns[plane_idx].peers));
+ LVL2_ASSERT(llist_empty(&hub->to_sgsns[plane_idx].peers));
+ plane_idx = GTPH_PLANE_USER;
+ LVL2_ASSERT(llist_empty(&hub->to_ggsns[plane_idx].peers));
+ LVL2_ASSERT(llist_empty(&hub->to_sgsns[plane_idx].peers));
+
+ gtphub_free(hub);
+ return 1;
+}
+
static void test_echo(void)
{
@@ -727,8 +743,7 @@ static void test_echo(void)
OSMO_ASSERT(!pp);
- now += EXPIRE_ALL;
- gtphub_gc(hub, now);
+ OSMO_ASSERT(clear_test_hub());
}
@@ -937,7 +952,7 @@ static void test_create_pdp_ctx(void)
OSMO_ASSERT(nr_map_is(&hub->tei_map[GTPH_PLANE_USER],
"(291->1@21945), (1383->2@21945), "));
- gtphub_gc(hub, now + EXPIRE_ALL);
+ OSMO_ASSERT(clear_test_hub());
}
static void test_user_data(void)
@@ -1013,7 +1028,7 @@ static void test_user_data(void)
u_from_sgsn,
u_to_ggsn));
- gtphub_gc(hub, now + EXPIRE_ALL);
+ OSMO_ASSERT(clear_test_hub());
}