<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>