fix crash if this end closed connection and other still sends data
[oweals/gnunet.git] / src / cadet / gnunet-service-cadet-new_channel.c
index 98cfa83839eaf40983d17b7f592cf27fb6b5fd5e..cc59ced522fe7bb670c334604aa841303b33a7ec 100644 (file)
@@ -126,9 +126,8 @@ struct CadetReliableMessage
   /**
    * Data message we are trying to send.
    */
-  struct GNUNET_CADET_ChannelAppDataMessage data_message;
+  struct GNUNET_CADET_ChannelAppDataMessage *data_message;
 
-  /* followed by variable-size payload */
 };
 
 
@@ -420,6 +419,7 @@ channel_destroy (struct CadetChannel *ch)
     GNUNET_CONTAINER_DLL_remove (ch->head_sent,
                                  ch->tail_sent,
                                  crm);
+    GNUNET_free (crm->data_message);
     GNUNET_free (crm);
   }
   if (NULL != ch->owner)
@@ -578,6 +578,7 @@ GCCH_channel_local_new (struct CadetClient *owner,
   ccco->client_ready = GNUNET_YES;
 
   ch = GNUNET_new (struct CadetChannel);
+  ch->mid_recv.mid = htonl (1); /* The OPEN_ACK counts as message 0! */
   ch->nobuffer = (0 != (options & GNUNET_CADET_OPTION_NOBUFFER));
   ch->reliable = (0 != (options & GNUNET_CADET_OPTION_RELIABLE));
   ch->out_of_order = (0 != (options & GNUNET_CADET_OPTION_OUT_OF_ORDER));
@@ -898,7 +899,7 @@ GCCH_bind (struct CadetChannel *ch,
                         options);
   GNUNET_assert (ntohl (cccd->ccn.channel_of_client) <
                  GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
-  ch->mid_recv.mid = htonl (1); /* The CONNECT counts as message 0! */
+  ch->mid_recv.mid = htonl (1); /* The OPEN counts as message 0! */
   if (GNUNET_YES == ch->is_loopback)
   {
     ch->state = CADET_CHANNEL_OPEN_SENT;
@@ -1086,6 +1087,20 @@ GCCH_handle_channel_plaintext_data (struct CadetChannel *ch,
   size_t payload_size;
 
   GNUNET_assert (GNUNET_NO == ch->is_loopback);
+  if ( (GNUNET_YES == ch->destroy) &&
+       (NULL == ch->owner) &&
+       (NULL == ch->dest) )
+  {
+    /* This client is gone, but we still have messages to send to
+       the other end (which is why @a ch is not yet dead).  However,
+       we cannot pass messages to our client anymore. */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Dropping incoming payload on %s as this end is already closed\n",
+         GCCH_2s (ch));
+    /* FIXME: send back ACK/NACK/Closed notification
+       to stop retransmissions! */
+    return;
+  }
   payload_size = ntohs (msg->header.size) - sizeof (*msg);
   env = GNUNET_MQ_msg_extra (ld,
                              payload_size,
@@ -1188,7 +1203,7 @@ GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch,
   for (crm = ch->head_sent;
         NULL != crm;
        crm = crm->next)
-    if (ack->mid.mid == crm->data_message.mid.mid)
+    if (ack->mid.mid == crm->data_message->mid.mid)
       break;
   if (NULL == crm)
   {
@@ -1206,12 +1221,13 @@ GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch,
   GNUNET_CONTAINER_DLL_remove (ch->head_sent,
                                ch->tail_sent,
                                crm);
+  GNUNET_free (crm->data_message);
+  GNUNET_free (crm);
   ch->pending_messages--;
   send_ack_to_client (ch,
                       (NULL == ch->owner)
                       ? GNUNET_NO
                       : GNUNET_YES);
-  GNUNET_free (crm);
   GNUNET_assert (ch->pending_messages < ch->max_pending_messages);
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Received DATA_ACK on %s for message %u (%u ACKs pending)\n",
@@ -1290,7 +1306,7 @@ retry_transmission (void *cls)
   ch->retry_data_task = NULL;
   GNUNET_assert (NULL == crm->qe);
   crm->qe = GCT_send (ch->t,
-                      &crm->data_message.header,
+                      &crm->data_message->header,
                       &data_sent_cb,
                       crm);
 }
@@ -1432,14 +1448,16 @@ GCCH_handle_local_data (struct CadetChannel *ch,
   }
 
   /* Everything is correct, send the message. */
-  crm = GNUNET_malloc (sizeof (*crm) + buf_len);
+  crm = GNUNET_malloc (sizeof (*crm));
   crm->ch = ch;
-  crm->data_message.header.size = htons (sizeof (struct GNUNET_CADET_ChannelAppDataMessage) + buf_len);
-  crm->data_message.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA);
+  crm->data_message = GNUNET_malloc (sizeof (struct GNUNET_CADET_ChannelAppDataMessage)
+                                     + buf_len);
+  crm->data_message->header.size = htons (sizeof (struct GNUNET_CADET_ChannelAppDataMessage) + buf_len);
+  crm->data_message->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA);
   ch->mid_send.mid = htonl (ntohl (ch->mid_send.mid) + 1);
-  crm->data_message.mid = ch->mid_send;
-  crm->data_message.ctn = ch->ctn;
-  GNUNET_memcpy (&crm[1],
+  crm->data_message->mid = ch->mid_send;
+  crm->data_message->ctn = ch->ctn;
+  GNUNET_memcpy (&crm->data_message[1],
                  buf,
                  buf_len);
   GNUNET_CONTAINER_DLL_insert (ch->head_sent,
@@ -1450,7 +1468,7 @@ GCCH_handle_local_data (struct CadetChannel *ch,
        buf_len,
        GCCH_2s (ch));
   crm->qe = GCT_send (ch->t,
-                      &crm->data_message.header,
+                      &crm->data_message->header,
                       &data_sent_cb,
                       crm);
   return GNUNET_OK;