}
else
{
- ch->dest = GNUNET_new (struct CadetChannelClient);
- ch->dest->c = c;
- ch->dest->client_ready = GNUNET_YES;
GCCH_bind (ch,
- ch->dest->c);
+ c);
}
}
else
port,
ch,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+ GNUNET_assert (NULL == ch->retry_control_task);
ch->retry_control_task
= GNUNET_SCHEDULER_add_delayed (TIMEOUT_CLOSED_PORT,
&timeout_closed_cb,
struct CadetChannel *ch = cls;
struct GNUNET_CADET_ChannelManageMessage msg;
+ ch->retry_control_task = NULL;
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Sending CHANNEL_OPEN_ACK on %s\n",
GCCH_2s (ch));
- ch->retry_control_task = NULL;
msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK);
msg.header.size = htons (sizeof (msg));
msg.reserved = htonl (0);
if (ch->out_of_order)
options |= GNUNET_CADET_OPTION_OUT_OF_ORDER;
cccd = GNUNET_new (struct CadetChannelClient);
+ GNUNET_assert (NULL == ch->dest);
ch->dest = cccd;
cccd->c = c;
cccd->client_ready = GNUNET_YES;
}
+/**
+ * One of our clients has disconnected, tell the other one that we
+ * are finished. Done asynchronously to avoid concurrent modification
+ * issues if this is the same client.
+ *
+ * @param cls the `struct CadetChannel` where one of the ends is now dead
+ */
+static void
+signal_remote_destroy_cb (void *cls)
+{
+ struct CadetChannel *ch = cls;
+ struct CadetChannelClient *ccc;
+
+ /* Find which end is left... */
+ ch->retry_control_task = NULL;
+ ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
+ GSC_handle_remote_channel_destroy (ccc->c,
+ ccc->ccn,
+ ch);
+ channel_destroy (ch);
+}
+
+
/**
* Destroy locally created channel. Called by the local client, so no
* need to tell the client.
channel_destroy (ch);
return;
}
- if ( (NULL != ch->head_sent) ||
- (NULL != ch->owner) ||
- (NULL != ch->dest) )
+ if ( (NULL != ch->head_sent) &&
+ ( (NULL != ch->owner) ||
+ (NULL != ch->dest) ) )
{
/* Wait for other end to destroy us as well,
and otherwise allow send queue to be transmitted first */
ch->destroy = GNUNET_YES;
return;
}
- /* If the we ever sent the CHANNEL_CREATE, we need to send a destroy message. */
- switch (ch->state)
+ if ( (GNUNET_YES == ch->is_loopback) &&
+ ( (NULL != ch->owner) ||
+ (NULL != ch->dest) ) )
{
- case CADET_CHANNEL_NEW:
- GNUNET_break (0);
- break;
- case CADET_CHANNEL_LOOSE:
- GSC_drop_loose_channel (&ch->port,
- ch);
- break;
- default:
- GCT_send_channel_destroy (ch->t,
- ch->ctn);
+ if (NULL != ch->retry_control_task)
+ GNUNET_SCHEDULER_cancel (ch->retry_control_task);
+ ch->retry_control_task
+ = GNUNET_SCHEDULER_add_now (&signal_remote_destroy_cb,
+ ch);
+ return;
+ }
+ if (GNUNET_NO == ch->is_loopback)
+ {
+ /* If the we ever sent the CHANNEL_CREATE, we need to send a destroy message. */
+ switch (ch->state)
+ {
+ case CADET_CHANNEL_NEW:
+ /* We gave up on a channel that we created as a client to a remote
+ target, but that never went anywhere. Nothing to do here. */
+ break;
+ case CADET_CHANNEL_LOOSE:
+ GSC_drop_loose_channel (&ch->port,
+ ch);
+ break;
+ default:
+ GCT_send_channel_destroy (ch->t,
+ ch->ctn);
+ }
}
/* Nothing left to do, just finish destruction */
channel_destroy (ch);
return;
}
ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
- if (NULL != ccc->head_recv)
+ if ( (NULL != ccc) &&
+ (NULL != ccc->head_recv) )
{
LOG (GNUNET_ERROR_TYPE_WARNING,
"Lost end of transmission due to remote shutdown on %s\n",
/* FIXME: change API to notify client about truncated transmission! */
}
ch->destroy = GNUNET_YES;
- GSC_handle_remote_channel_destroy (ccc->c,
- ccc->ccn,
- ch);
+ if (NULL != ccc)
+ GSC_handle_remote_channel_destroy (ccc->c,
+ ccc->ccn,
+ ch);
channel_destroy (ch);
}
struct CadetChannelClient *receiver;
struct GNUNET_MQ_Envelope *env;
struct GNUNET_CADET_LocalData *ld;
- int to_owner;
+ int ack_to_owner;
env = GNUNET_MQ_msg_extra (ld,
buf_len,
ch->owner->ccn.channel_of_client) )
{
receiver = ch->dest;
- to_owner = GNUNET_NO;
+ ack_to_owner = GNUNET_YES;
}
else if ( (NULL != ch->dest) &&
(sender_ccn.channel_of_client ==
ch->dest->ccn.channel_of_client) )
{
receiver = ch->owner;
- to_owner = GNUNET_YES;
+ ack_to_owner = GNUNET_NO;
}
else
{
buf_len);
if (GNUNET_YES == receiver->client_ready)
{
+ ch->pending_messages--;
GSC_send_to_client (receiver->c,
env);
send_ack_to_client (ch,
- to_owner);
+ ack_to_owner);
}
else
{