REST/NAMESTORE: rework API
[oweals/gnunet.git] / src / cadet / gnunet-service-cadet_channel.c
index 06711dc8b369f121e7fb16ef8d6af4023ec0245e..bd95428be107b32734f8e378b95634ba8b7504d2 100644 (file)
      WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      Affero General Public License for more details.
-    
+
      You should have received a copy of the GNU Affero General Public License
      along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+     SPDX-License-Identifier: AGPL3.0-or-later
 */
 /**
  * @file cadet/gnunet-service-cadet_channel.c
@@ -500,6 +502,11 @@ channel_destroy (struct CadetChannel *ch)
     GNUNET_free (crm->data_message);
     GNUNET_free (crm);
   }
+  if (CADET_CHANNEL_LOOSE == ch->state)
+  {
+    GSC_drop_loose_channel (&ch->h_port,
+                           ch);
+  }
   if (NULL != ch->owner)
   {
     free_channel_client (ch->owner);
@@ -672,9 +679,8 @@ GCCH_channel_local_new (struct CadetClient *owner,
   GCCH_hash_port (&ch->h_port,
                  port,
                  GCP_get_id (destination));
-  if (0 == memcmp (&my_full_id,
-                   GCP_get_id (destination),
-                   sizeof (struct GNUNET_PeerIdentity)))
+  if (0 == GNUNET_memcmp (&my_full_id,
+                   GCP_get_id (destination)))
   {
     struct OpenPort *op;
 
@@ -1136,8 +1142,6 @@ GCCH_channel_local_destroy (struct CadetChannel *ch,
          target, but that never went anywhere. Nothing to do here. */
       break;
     case CADET_CHANNEL_LOOSE:
-      GSC_drop_loose_channel (&ch->h_port,
-                              ch);
       break;
     default:
       GCT_send_channel_destroy (ch->t,
@@ -1180,9 +1184,8 @@ GCCH_handle_channel_open_ack (struct CadetChannel *ch,
       GNUNET_break_op (0);
       return;
     }
-    if (0 != memcmp (&ch->port,
-                    port,
-                    sizeof (struct GNUNET_HashCode)))
+    if (0 != GNUNET_memcmp (&ch->port,
+                    port))
     {
       /* Other peer failed to provide the right port,
         refuse connection. */
@@ -1301,23 +1304,51 @@ GCCH_handle_channel_plaintext_data (struct CadetChannel *ch,
                  &msg[1],
                  payload_size);
   ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
-  if ( (GNUNET_YES == ccc->client_ready) &&
-       ( (GNUNET_YES == ch->out_of_order) ||
-         (msg->mid.mid == ch->mid_recv.mid) ) )
+  if (GNUNET_YES == ccc->client_ready)
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Giving %u bytes of payload with MID %u from %s to client %s\n",
-         (unsigned int) payload_size,
-         ntohl (msg->mid.mid),
-         GCCH_2s (ch),
-         GSC_2s (ccc->c));
-    ccc->client_ready = GNUNET_NO;
-    GSC_send_to_client (ccc->c,
-                        env);
-    ch->mid_recv.mid = htonl (1 + ntohl (ch->mid_recv.mid));
-    ch->mid_futures >>= 1;
-    send_channel_data_ack (ch);
-    return;
+    /*
+     * We ad-hoc send the message if
+     * - The channel is out-of-order
+     * - The channel is reliable and MID matches next expected MID
+     * - The channel is unreliable and MID is before lowest seen MID
+     */
+    if ( (GNUNET_YES == ch->out_of_order) ||
+         ((msg->mid.mid == ch->mid_recv.mid) &&
+          (GNUNET_YES == ch->reliable)) ||
+         ((GNUNET_NO == ch->reliable) &&
+          (ntohl (msg->mid.mid) >= ntohl (ch->mid_recv.mid)) &&
+          ((NULL == ccc->head_recv) ||
+           (ntohl (msg->mid.mid) < ntohl (ccc->head_recv->mid.mid)))) )
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Giving %u bytes of payload with MID %u from %s to client %s\n",
+           (unsigned int) payload_size,
+           ntohl (msg->mid.mid),
+           GCCH_2s (ch),
+           GSC_2s (ccc->c));
+      ccc->client_ready = GNUNET_NO;
+      GSC_send_to_client (ccc->c,
+                          env);
+      if (GNUNET_NO == ch->out_of_order)
+        ch->mid_recv.mid = htonl (1 + ntohl (msg->mid.mid));
+      else
+        ch->mid_recv.mid = htonl (1 + ntohl (ch->mid_recv.mid));
+      ch->mid_futures >>= 1;
+      if ( (GNUNET_YES == ch->out_of_order) &&
+          (GNUNET_NO == ch->reliable) )
+      {
+       /* possibly shift by more if we skipped messages */
+       uint64_t delta = htonl (msg->mid.mid) - 1 - ntohl (ch->mid_recv.mid);
+       
+       if (delta > 63)
+         ch->mid_futures = 0;
+       else
+         ch->mid_futures >>= delta;
+       ch->mid_recv.mid = htonl (1 + ntohl (msg->mid.mid));
+      }
+      send_channel_data_ack (ch);
+      return;
+    }
   }
 
   if (GNUNET_YES == ch->reliable)
@@ -1374,6 +1405,57 @@ GCCH_handle_channel_plaintext_data (struct CadetChannel *ch,
   }
   else /* ! ch->reliable */
   {
+    struct CadetOutOfOrderMessage *next_msg;
+
+    /**
+     * We always send if possible in this case.
+     * It is guaranteed that the queued MID < received MID
+     **/
+    if ((NULL != ccc->head_recv) &&
+        (GNUNET_YES == ccc->client_ready))
+    {
+      next_msg = ccc->head_recv;
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Giving queued MID %u from %s to client %s\n",
+           ntohl (next_msg->mid.mid),
+           GCCH_2s (ch),
+           GSC_2s (ccc->c));
+      ccc->client_ready = GNUNET_NO;
+      GSC_send_to_client (ccc->c,
+                          next_msg->env);
+      ch->mid_recv.mid = htonl (1 + ntohl (next_msg->mid.mid));
+      ch->mid_futures >>= 1;
+      send_channel_data_ack (ch);
+      GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
+                                   ccc->tail_recv,
+                                   next_msg);
+      ccc->num_recv--;
+      /* Do not process duplicate MID */
+      if (msg->mid.mid == next_msg->mid.mid) /* Duplicate */
+      {
+        /* Duplicate within the queue, drop */
+        LOG (GNUNET_ERROR_TYPE_DEBUG,
+             "Message on %s (mid %u) dropped, duplicate\n",
+             GCCH_2s (ch),
+             ntohl (msg->mid.mid));
+        GNUNET_free (next_msg);
+        GNUNET_MQ_discard (env);
+        return;
+      }
+      GNUNET_free (next_msg);
+    }
+
+    if (ntohl (msg->mid.mid) < ntohl (ch->mid_recv.mid)) /* Old */
+    {
+      /* Duplicate within the queue, drop */
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Message on %s (mid %u) dropped, old.\n",
+           GCCH_2s (ch),
+           ntohl (msg->mid.mid));
+      GNUNET_MQ_discard (env);
+      return;
+    }
+
     /* Channel is unreliable, so we do not ACK. But we also cannot
        allow buffering everything, so check if we have space... */
     if (ccc->num_recv >= ch->max_pending_messages)
@@ -1528,9 +1610,8 @@ handle_matching_ack (struct CadetChannel *ch,
        (NULL != cti) )
   {
     GCC_ack_observed (cti);
-    if (0 == memcmp (cti,
-                     &crm->connection_taken,
-                     sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier)))
+    if (0 == GNUNET_memcmp (cti,
+                     &crm->connection_taken))
     {
       GCC_latency_observed (cti,
                             GNUNET_TIME_absolute_get_duration (crm->first_transmission_time));
@@ -1579,7 +1660,7 @@ GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch,
   mid_mask = GNUNET_htonll (ack->futures);
   found = GNUNET_NO;
   for (crm = ch->head_sent;
-        NULL != crm;
+       NULL != crm;
        crm = crmn)
   {
     crmn = crm->next;
@@ -1822,7 +1903,7 @@ GCCH_handle_local_data (struct CadetChannel *ch,
 
   if (ch->pending_messages >= ch->max_pending_messages)
   {
-    GNUNET_break (0);
+    GNUNET_break (0); /* Fails: #5370 */
     return GNUNET_SYSERR;
   }
   if (GNUNET_YES == ch->destroy)