<p>pespin has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-ggsn/+/15309">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">gtp: Manage queue timers internally<br><br>Currently each user (application) of libgtp needs to manage its own<br>timers in order to call gtp_retrans_timeout() and gtp_retrans() and<br>maintain retransmit and duplicate queues working correctly. This adds<br>unnecesary complexity to applications since nowadays, as a libosmocore<br>user, libgtp can handle this internally in an easy way.<br>Furthermore, keeping the timers internal to the library allows for<br>easier extension of features as well as re-implementation of related<br>code in the future.<br>Last but not least, it was detected that existing known applications<br>(osmo-sgsn, osmo-ggsn, sgsnemu) are not using correctly the API, since<br>they should be updating their timers through gtp_retrans_timeout()<br>everytime a message is enqueued/transmitted, otherwise they may fire<br>gtp_retrans() for retransmition too late in some cases.<br><br>Related: OS#4178<br>Change-Id: Ife7cfd66d6356f413263fe5bda9e43091f5c9e98<br>---<br>M gtp/gtp.c<br>M gtp/gtp.h<br>2 files changed, 128 insertions(+), 72 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-ggsn refs/changes/09/15309/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/gtp/gtp.c b/gtp/gtp.c</span><br><span>index 2ea949d..66aedb8 100644</span><br><span>--- a/gtp/gtp.c</span><br><span>+++ b/gtp/gtp.c</span><br><span>@@ -386,6 +386,109 @@</span><br><span> }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static int queue_timer_retrans(struct gsn_t *gsn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Retransmit any outstanding packets */</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Remove from queue if maxretrans exceeded */</span><br><span style="color: hsl(120, 100%, 40%);">+ time_t now;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct qmsg_t *qmsg;</span><br><span style="color: hsl(120, 100%, 40%);">+ now = time(NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ /*printf("Retrans: New beginning %d\n", (int) now); */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* get first element in queue, as long as the timeout of that</span><br><span style="color: hsl(120, 100%, 40%);">+ * element has expired */</span><br><span style="color: hsl(120, 100%, 40%);">+ while ((!queue_getfirst(gsn->queue_req, &qmsg)) &&</span><br><span style="color: hsl(120, 100%, 40%);">+ (qmsg->timeout <= now)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /*printf("Retrans timeout found: %d\n", (int) time(NULL)); */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (qmsg->retrans > N3_REQUESTS) { /* To many retrans */</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DLGTP, LOGL_NOTICE, "Timeout of seq %" PRIu16 "\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ qmsg->seq);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (gsn->cb_conf)</span><br><span style="color: hsl(120, 100%, 40%);">+ gsn->cb_conf(qmsg->type, EOF, NULL, qmsg->cbp);</span><br><span style="color: hsl(120, 100%, 40%);">+ queue_freemsg(gsn->queue_req, qmsg);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DLGTP, LOGL_INFO, "Retransmit (%d) of seq %" PRIu16 "\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ qmsg->retrans, qmsg->seq);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (sendto(qmsg->fd, &qmsg->p, qmsg->l, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ (struct sockaddr *)&qmsg->peer,</span><br><span style="color: hsl(120, 100%, 40%);">+ sizeof(struct sockaddr_in)) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ gsn->err_sendto++;</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DLGTP, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Sendto(fd0=%d, msg=%lx, len=%d) failed: Error = %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ gsn->fd0, (unsigned long)&qmsg->p,</span><br><span style="color: hsl(120, 100%, 40%);">+ qmsg->l, strerror(errno));</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ queue_back(gsn->queue_req, qmsg);</span><br><span style="color: hsl(120, 100%, 40%);">+ qmsg->timeout = now + T3_REQUEST;</span><br><span style="color: hsl(120, 100%, 40%);">+ qmsg->retrans++;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Also clean up reply timeouts */</span><br><span style="color: hsl(120, 100%, 40%);">+ while ((!queue_getfirst(gsn->queue_resp, &qmsg)) &&</span><br><span style="color: hsl(120, 100%, 40%);">+ (qmsg->timeout < now)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /*printf("Retrans (reply) timeout found: %d\n", (int) time(NULL)); */</span><br><span style="color: hsl(120, 100%, 40%);">+ queue_freemsg(gsn->queue_resp, qmsg);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int queue_timer_retranstimeout(struct gsn_t *gsn, struct timeval *timeout)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ time_t now, later, diff;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct qmsg_t *qmsg;</span><br><span style="color: hsl(120, 100%, 40%);">+ timeout->tv_usec = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (queue_getfirst(gsn->queue_req, &qmsg)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ timeout->tv_sec = 10;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ now = time(NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ later = qmsg->timeout;</span><br><span style="color: hsl(120, 100%, 40%);">+ timeout->tv_sec = later - now;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (timeout->tv_sec < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ timeout->tv_sec = 0; /* No negative allowed */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (timeout->tv_sec > 10)</span><br><span style="color: hsl(120, 100%, 40%);">+ timeout->tv_sec = 10; /* Max sleep for 10 sec */</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (queue_getfirst(gsn->queue_resp, &qmsg)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* already set by queue_req, do nothing */</span><br><span style="color: hsl(120, 100%, 40%);">+ } else { /* trigger faster if earlier timeout exists in queue_resp */</span><br><span style="color: hsl(120, 100%, 40%);">+ now = time(NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ later = qmsg->timeout;</span><br><span style="color: hsl(120, 100%, 40%);">+ diff = later - now;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (diff < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ diff = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (diff < timeout->tv_sec)</span><br><span style="color: hsl(120, 100%, 40%);">+ timeout->tv_sec = diff;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void queue_timer_start(struct gsn_t *gsn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct timeval next;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Retrieve next retransmission as timeval */</span><br><span style="color: hsl(120, 100%, 40%);">+ queue_timer_retranstimeout(gsn, &next);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* re-schedule the timer */</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_timer_schedule(&gsn->queue_timer, next.tv_sec, next.tv_usec/1000);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* timer callback for libgtp retransmission and ping */</span><br><span style="color: hsl(120, 100%, 40%);">+static void queue_timer_cb(void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gsn_t *gsn = data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* do all the retransmissions as needed */</span><br><span style="color: hsl(120, 100%, 40%);">+ queue_timer_retrans(gsn);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ queue_timer_start(gsn);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* ***********************************************************</span><br><span> * Reliable delivery of signalling messages</span><br><span> *</span><br><span>@@ -532,6 +635,10 @@</span><br><span> qmsg->fd = fd;</span><br><span> if (pdp) /* echo requests are not pdp-bound */</span><br><span> llist_add(&qmsg->entry, &pdp->qmsg_list_req);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Rearm timer: Retrans time for qmsg just queued may be required</span><br><span style="color: hsl(120, 100%, 40%);">+ before an existing one (for instance a gtp echo req) */</span><br><span style="color: hsl(120, 100%, 40%);">+ queue_timer_start(gsn);</span><br><span> }</span><br><span> gsn->seq_next++; /* Count up this time */</span><br><span> return 0;</span><br><span>@@ -587,82 +694,15 @@</span><br><span> </span><br><span> int gtp_retrans(struct gsn_t *gsn)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- /* Retransmit any outstanding packets */</span><br><span style="color: hsl(0, 100%, 40%);">- /* Remove from queue if maxretrans exceeded */</span><br><span style="color: hsl(0, 100%, 40%);">- time_t now;</span><br><span style="color: hsl(0, 100%, 40%);">- struct qmsg_t *qmsg;</span><br><span style="color: hsl(0, 100%, 40%);">- now = time(NULL);</span><br><span style="color: hsl(0, 100%, 40%);">- /*printf("Retrans: New beginning %d\n", (int) now); */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* get first element in queue, as long as the timeout of that</span><br><span style="color: hsl(0, 100%, 40%);">- * element has expired */</span><br><span style="color: hsl(0, 100%, 40%);">- while ((!queue_getfirst(gsn->queue_req, &qmsg)) &&</span><br><span style="color: hsl(0, 100%, 40%);">- (qmsg->timeout <= now)) {</span><br><span style="color: hsl(0, 100%, 40%);">- /*printf("Retrans timeout found: %d\n", (int) time(NULL)); */</span><br><span style="color: hsl(0, 100%, 40%);">- if (qmsg->retrans > N3_REQUESTS) { /* To many retrans */</span><br><span style="color: hsl(0, 100%, 40%);">- LOGP(DLGTP, LOGL_NOTICE, "Timeout of seq %" PRIu16 "\n",</span><br><span style="color: hsl(0, 100%, 40%);">- qmsg->seq);</span><br><span style="color: hsl(0, 100%, 40%);">- if (gsn->cb_conf)</span><br><span style="color: hsl(0, 100%, 40%);">- gsn->cb_conf(qmsg->type, EOF, NULL, qmsg->cbp);</span><br><span style="color: hsl(0, 100%, 40%);">- queue_freemsg(gsn->queue_req, qmsg);</span><br><span style="color: hsl(0, 100%, 40%);">- } else {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGP(DLGTP, LOGL_INFO, "Retransmit (%d) of seq %" PRIu16 "\n",</span><br><span style="color: hsl(0, 100%, 40%);">- qmsg->retrans, qmsg->seq);</span><br><span style="color: hsl(0, 100%, 40%);">- if (sendto(qmsg->fd, &qmsg->p, qmsg->l, 0,</span><br><span style="color: hsl(0, 100%, 40%);">- (struct sockaddr *)&qmsg->peer,</span><br><span style="color: hsl(0, 100%, 40%);">- sizeof(struct sockaddr_in)) < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">- gsn->err_sendto++;</span><br><span style="color: hsl(0, 100%, 40%);">- LOGP(DLGTP, LOGL_ERROR,</span><br><span style="color: hsl(0, 100%, 40%);">- "Sendto(fd0=%d, msg=%lx, len=%d) failed: Error = %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">- gsn->fd0, (unsigned long)&qmsg->p,</span><br><span style="color: hsl(0, 100%, 40%);">- qmsg->l, strerror(errno));</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- queue_back(gsn->queue_req, qmsg);</span><br><span style="color: hsl(0, 100%, 40%);">- qmsg->timeout = now + T3_REQUEST;</span><br><span style="color: hsl(0, 100%, 40%);">- qmsg->retrans++;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* Also clean up reply timeouts */</span><br><span style="color: hsl(0, 100%, 40%);">- while ((!queue_getfirst(gsn->queue_resp, &qmsg)) &&</span><br><span style="color: hsl(0, 100%, 40%);">- (qmsg->timeout < now)) {</span><br><span style="color: hsl(0, 100%, 40%);">- /*printf("Retrans (reply) timeout found: %d\n", (int) time(NULL)); */</span><br><span style="color: hsl(0, 100%, 40%);">- queue_freemsg(gsn->queue_resp, qmsg);</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+ /* dummy API, deprecated. */</span><br><span> return 0;</span><br><span> }</span><br><span> </span><br><span> int gtp_retranstimeout(struct gsn_t *gsn, struct timeval *timeout)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- time_t now, later, diff;</span><br><span style="color: hsl(0, 100%, 40%);">- struct qmsg_t *qmsg;</span><br><span style="color: hsl(120, 100%, 40%);">+ timeout->tv_sec = 24*60*60;</span><br><span> timeout->tv_usec = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (queue_getfirst(gsn->queue_req, &qmsg)) {</span><br><span style="color: hsl(0, 100%, 40%);">- timeout->tv_sec = 10;</span><br><span style="color: hsl(0, 100%, 40%);">- } else {</span><br><span style="color: hsl(0, 100%, 40%);">- now = time(NULL);</span><br><span style="color: hsl(0, 100%, 40%);">- later = qmsg->timeout;</span><br><span style="color: hsl(0, 100%, 40%);">- timeout->tv_sec = later - now;</span><br><span style="color: hsl(0, 100%, 40%);">- if (timeout->tv_sec < 0)</span><br><span style="color: hsl(0, 100%, 40%);">- timeout->tv_sec = 0; /* No negative allowed */</span><br><span style="color: hsl(0, 100%, 40%);">- if (timeout->tv_sec > 10)</span><br><span style="color: hsl(0, 100%, 40%);">- timeout->tv_sec = 10; /* Max sleep for 10 sec */</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (queue_getfirst(gsn->queue_resp, &qmsg)) {</span><br><span style="color: hsl(0, 100%, 40%);">- /* already set by queue_req, do nothing */</span><br><span style="color: hsl(0, 100%, 40%);">- } else { /* trigger faster if earlier timeout exists in queue_resp */</span><br><span style="color: hsl(0, 100%, 40%);">- now = time(NULL);</span><br><span style="color: hsl(0, 100%, 40%);">- later = qmsg->timeout;</span><br><span style="color: hsl(0, 100%, 40%);">- diff = later - now;</span><br><span style="color: hsl(0, 100%, 40%);">- if (diff < 0)</span><br><span style="color: hsl(0, 100%, 40%);">- diff = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- if (diff < timeout->tv_sec)</span><br><span style="color: hsl(0, 100%, 40%);">- timeout->tv_sec = diff;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+ /* dummy API, deprecated. Return a huge timer to do nothing */</span><br><span> return 0;</span><br><span> }</span><br><span> </span><br><span>@@ -723,6 +763,10 @@</span><br><span> /* No need to add to pdp list here, because even on pdp ctx free</span><br><span> we want to leave messages in queue_resp until timeout to</span><br><span> detect duplicates */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Rearm timer: Retrans time for qmsg just queued may be required</span><br><span style="color: hsl(120, 100%, 40%);">+ before an existing one (for instance a gtp echo req) */</span><br><span style="color: hsl(120, 100%, 40%);">+ queue_timer_start(gsn);</span><br><span> }</span><br><span> return 0;</span><br><span> }</span><br><span>@@ -872,6 +916,9 @@</span><br><span> /* Initialise pdp table */</span><br><span> pdp_init(*gsn);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Initialize internal queue timer */</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_timer_setup(&(*gsn)->queue_timer, queue_timer_cb, *gsn);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Initialise call back functions */</span><br><span> (*gsn)->cb_create_context_ind = 0;</span><br><span> (*gsn)->cb_delete_context = 0;</span><br><span>@@ -959,12 +1006,18 @@</span><br><span> return -errno;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Start internal queue timer */</span><br><span style="color: hsl(120, 100%, 40%);">+ queue_timer_start(*gsn);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> return 0;</span><br><span> }</span><br><span> </span><br><span> int gtp_free(struct gsn_t *gsn)</span><br><span> {</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Cleanup internal queue timer */</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_timer_del(&gsn->queue_timer);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Clean up retransmit queues */</span><br><span> queue_free(gsn->queue_req);</span><br><span> queue_free(gsn->queue_resp);</span><br><span>diff --git a/gtp/gtp.h b/gtp/gtp.h</span><br><span>index f2a4e1d..e03d77d 100644</span><br><span>--- a/gtp/gtp.h</span><br><span>+++ b/gtp/gtp.h</span><br><span>@@ -14,6 +14,7 @@</span><br><span> </span><br><span> #include <osmocom/core/utils.h></span><br><span> #include <osmocom/core/defs.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/timer.h></span><br><span> </span><br><span> #include "pdp.h"</span><br><span> </span><br><span>@@ -268,6 +269,8 @@</span><br><span> struct pdp_t pdpa[PDP_MAX]; /* PDP storage */</span><br><span> struct pdp_t *hashtid[PDP_MAX]; /* Hash table for IMSI + NSAPI */</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_timer_list queue_timer; /* internal queue_{req,resp} timer */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Call back functions */</span><br><span> int (*cb_delete_context) (struct pdp_t *);</span><br><span> int (*cb_create_context_ind) (struct pdp_t *);</span><br><span>@@ -348,8 +351,8 @@</span><br><span> extern int gtp_decaps0(struct gsn_t *gsn);</span><br><span> extern int gtp_decaps1c(struct gsn_t *gsn);</span><br><span> extern int gtp_decaps1u(struct gsn_t *gsn);</span><br><span style="color: hsl(0, 100%, 40%);">-extern int gtp_retrans(struct gsn_t *gsn);</span><br><span style="color: hsl(0, 100%, 40%);">-extern int gtp_retranstimeout(struct gsn_t *gsn, struct timeval *timeout);</span><br><span style="color: hsl(120, 100%, 40%);">+extern int gtp_retrans(struct gsn_t *gsn) OSMO_DEPRECATED("This API is a no-op, libgtp already does the job internally");</span><br><span style="color: hsl(120, 100%, 40%);">+extern int gtp_retranstimeout(struct gsn_t *gsn, struct timeval *timeout) OSMO_DEPRECATED("This API is a no-op and will return a 1 day timeout");</span><br><span> </span><br><span> extern int gtp_set_cb_delete_context(struct gsn_t *gsn,</span><br><span> int (*cb_delete_context) (struct pdp_t *</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-ggsn/+/15309">change 15309</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmo-ggsn/+/15309"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: osmo-ggsn </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Ife7cfd66d6356f413263fe5bda9e43091f5c9e98 </div>
<div style="display:none"> Gerrit-Change-Number: 15309 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>