+/**
+ * Handler for port close requests. Marks this port as closed
+ * (unless of course we have another client with the same port
+ * open). Note that existing channels accepted on the port are
+ * not affected.
+ *
+ * @param cls Identification of the client.
+ * @param pmsg The actual message.
+ */
+static void
+handle_port_close (void *cls,
+ const struct GNUNET_CADET_PortMessage *pmsg)
+{
+ struct CadetClient *c = cls;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Closing port %s as requested by %s\n",
+ GNUNET_h2s (&pmsg->port),
+ GSC_2s (c));
+ if (GNUNET_YES !=
+ GNUNET_CONTAINER_multihashmap_remove (c->ports,
+ &pmsg->port,
+ c))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVICE_client_drop (c->client);
+ return;
+ }
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (open_ports,
+ &pmsg->port,
+ c));
+ GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Handler for requests for us creating a new channel to another peer and port.
+ *
+ * @param cls Identification of the client.
+ * @param tcm The actual message.
+ */
+static void
+handle_channel_create (void *cls,
+ const struct GNUNET_CADET_LocalChannelCreateMessage *tcm)
+{
+ struct CadetClient *c = cls;
+ struct CadetChannel *ch;
+
+ if (ntohl (tcm->ccn.channel_of_client) < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
+ {
+ /* Channel ID not in allowed range. */
+ GNUNET_break (0);
+ GNUNET_SERVICE_client_drop (c->client);
+ return;
+ }
+ ch = lookup_channel (c,
+ tcm->ccn);
+ if (NULL != ch)
+ {
+ /* Channel ID already in use. Not allowed. */
+ GNUNET_break (0);
+ GNUNET_SERVICE_client_drop (c->client);
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "New channel to %s at port %s requested by %s\n",
+ GNUNET_i2s (&tcm->peer),
+ GNUNET_h2s (&tcm->port),
+ GSC_2s (c));
+
+ /* Create channel */
+ ch = GCCH_channel_local_new (c,
+ tcm->ccn,
+ GCP_get (&tcm->peer,
+ GNUNET_YES),
+ &tcm->port,
+ ntohl (tcm->opt));
+ if (NULL == ch)
+ {
+ GNUNET_break (0);
+ GNUNET_SERVICE_client_drop (c->client);
+ return;
+ }
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap32_put (c->channels,
+ ntohl (tcm->ccn.channel_of_client),
+ ch,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+
+ GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Handler for requests of destroying an existing channel.
+ *
+ * @param cls client identification of the client
+ * @param msg the actual message
+ */
+static void
+handle_channel_destroy (void *cls,
+ const struct GNUNET_CADET_LocalChannelDestroyMessage *msg)
+{
+ struct CadetClient *c = cls;
+ struct CadetChannel *ch;
+
+ ch = lookup_channel (c,
+ msg->ccn);
+ if (NULL == ch)
+ {
+ /* Client attempted to destroy unknown channel.
+ Can happen if the other side went down at the same time.*/
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "%s tried to destroy unknown channel %X\n",
+ GSC_2s(c),
+ (uint32_t) ntohl (msg->ccn.channel_of_client));
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "%s is destroying %s\n",
+ GSC_2s(c),
+ GCCH_2s (ch));
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap32_remove (c->channels,
+ ntohl (msg->ccn.channel_of_client),
+ ch));
+ GCCH_channel_local_destroy (ch,
+ c,
+ msg->ccn);
+ GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Check for client traffic data message is well-formed.
+ *
+ * @param cls identification of the client
+ * @param msg the actual message
+ * @return #GNUNET_OK if @a msg is OK, #GNUNET_SYSERR if not
+ */
+static int
+check_local_data (void *cls,
+ const struct GNUNET_CADET_LocalData *msg)
+{
+ size_t payload_size;
+ size_t payload_claimed_size;
+ const char *buf;
+ struct GNUNET_MessageHeader pa;
+
+ /* FIXME: what is the format we shall allow for @a msg?
+ ONE payload item or multiple? Seems current cadet_api
+ at least in theory allows more than one. Next-gen
+ cadet_api will likely no more, so we could then
+ simplify this mess again. */
+ /* Sanity check for message size */
+ payload_size = ntohs (msg->header.size) - sizeof (*msg);
+ buf = (const char *) &msg[1];
+ while (payload_size >= sizeof (struct GNUNET_MessageHeader))
+ {
+ /* need to memcpy() for alignment */
+ GNUNET_memcpy (&pa,
+ buf,
+ sizeof (pa));
+ payload_claimed_size = ntohs (pa.size);
+ if ( (payload_size < payload_claimed_size) ||
+ (payload_claimed_size < sizeof (struct GNUNET_MessageHeader)) ||
+ (GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE < payload_claimed_size) )
+ {
+ GNUNET_break (0);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Local data of %u total size had sub-message %u at %u with %u bytes\n",
+ ntohs (msg->header.size),
+ ntohs (pa.type),
+ (unsigned int) (buf - (const char *) &msg[1]),
+ (unsigned int) payload_claimed_size);
+ return GNUNET_SYSERR;
+ }
+ payload_size -= payload_claimed_size;
+ buf += payload_claimed_size;
+ }
+ if (0 != payload_size)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Handler for client payload traffic to be send on a channel to
+ * another peer.
+ *
+ * @param cls identification of the client
+ * @param msg the actual message
+ */
+static void
+handle_local_data (void *cls,
+ const struct GNUNET_CADET_LocalData *msg)
+{
+ struct CadetClient *c = cls;
+ struct CadetChannel *ch;
+ size_t payload_size;
+ const char *buf;
+
+ ch = lookup_channel (c,
+ msg->ccn);
+ if (NULL == ch)
+ {
+ /* Channel does not exist (anymore) */
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Dropping payload for channel %u from client (channel unknown, other endpoint may have disconnected)\n",
+ (unsigned int) ntohl (msg->ccn.channel_of_client));
+ GNUNET_SERVICE_client_continue (c->client);
+ return;
+ }
+ payload_size = ntohs (msg->header.size) - sizeof (*msg);
+ GNUNET_STATISTICS_update (stats,
+ "# payload received from clients",
+ payload_size,
+ GNUNET_NO);
+ buf = (const char *) &msg[1];
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Received %u bytes payload from %s for %s\n",
+ (unsigned int) payload_size,
+ GSC_2s (c),
+ GCCH_2s (ch));
+ if (GNUNET_OK !=
+ GCCH_handle_local_data (ch,
+ msg->ccn,
+ buf,
+ payload_size))
+ {
+ GNUNET_SERVICE_client_drop (c->client);
+ return;
+ }
+ GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Handler for client's ACKs for payload traffic.
+ *
+ * @param cls identification of the client.
+ * @param msg The actual message.
+ */
+static void
+handle_local_ack (void *cls,
+ const struct GNUNET_CADET_LocalAck *msg)
+{
+ struct CadetClient *c = cls;
+ struct CadetChannel *ch;
+
+ ch = lookup_channel (c,
+ msg->ccn);
+ if (NULL == ch)
+ {
+ /* Channel does not exist (anymore) */
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Ignoring local ACK for channel %u from client (channel unknown, other endpoint may have disconnected)\n",
+ (unsigned int) ntohl (msg->ccn.channel_of_client));
+ GNUNET_SERVICE_client_continue (c->client);
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Got a local ACK from %s for %s\n",
+ GSC_2s(c),
+ GCCH_2s (ch));
+ GCCH_handle_local_ack (ch,
+ msg->ccn);
+ GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Iterator over all peers to send a monitoring client info about each peer.
+ *
+ * @param cls Closure ().
+ * @param peer Peer ID (tunnel remote peer).
+ * @param value Peer info.
+ * @return #GNUNET_YES, to keep iterating.
+ */
+static int
+get_all_peers_iterator (void *cls,
+ const struct GNUNET_PeerIdentity *peer,
+ void *value)
+{
+ struct CadetClient *c = cls;
+ struct CadetPeer *p = value;
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_CADET_LocalInfoPeer *msg;
+
+ env = GNUNET_MQ_msg (msg,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
+ msg->destination = *peer;
+ msg->paths = htons (GCP_count_paths (p));
+ msg->tunnel = htons (NULL != GCP_get_tunnel (p,
+ GNUNET_NO));
+ GNUNET_MQ_send (c->mq,
+ env);
+ return GNUNET_YES;
+}
+
+
+/**
+ * Handler for client's INFO PEERS request.
+ *
+ * @param cls Identification of the client.
+ * @param message The actual message.
+ */
+static void
+handle_get_peers (void *cls,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct CadetClient *c = cls;
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_MessageHeader *reply;
+
+ GCP_iterate_all (&get_all_peers_iterator,
+ c);
+ env = GNUNET_MQ_msg (reply,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
+ GNUNET_MQ_send (c->mq,
+ env);
+ GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Iterator over all paths of a peer to build an InfoPeer message.
+ * Message contains blocks of peers, first not included.
+ *
+ * @param cls message queue for transmission
+ * @param path Path itself
+ * @param off offset of the peer on @a path
+ * @return #GNUNET_YES if should keep iterating.
+ * #GNUNET_NO otherwise.
+ */
+static int
+path_info_iterator (void *cls,
+ struct CadetPeerPath *path,
+ unsigned int off)
+{
+ struct GNUNET_MQ_Handle *mq = cls;
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_MessageHeader *resp;
+ struct GNUNET_PeerIdentity *id;
+ uint16_t path_size;
+ unsigned int i;
+ unsigned int path_length;
+
+ path_length = GCPP_get_length (path);
+ path_size = sizeof (struct GNUNET_PeerIdentity) * (path_length - 1);
+ if (sizeof (*resp) + path_size > UINT16_MAX)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Path of %u entries is too long for info message\n",
+ path_length);
+ return GNUNET_YES;
+ }
+ env = GNUNET_MQ_msg_extra (resp,
+ path_size,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER);
+ id = (struct GNUNET_PeerIdentity *) &resp[1];
+
+ /* Don't copy first peer. First peer is always the local one. Last
+ * peer is always the destination (leave as 0, EOL).
+ */
+ for (i = 0; i < off; i++)
+ id[i] = *GCP_get_id (GCPP_get_peer_at_offset (path,
+ i + 1));
+ GNUNET_MQ_send (mq,
+ env);
+ return GNUNET_YES;
+}
+
+
+/**
+ * Handler for client's SHOW_PEER request.
+ *
+ * @param cls Identification of the client.
+ * @param msg The actual message.
+ */
+static void
+handle_show_peer (void *cls,
+ const struct GNUNET_CADET_LocalInfo *msg)
+{
+ struct CadetClient *c = cls;
+ struct CadetPeer *p;
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_MessageHeader *resp;
+
+ p = GCP_get (&msg->peer,
+ GNUNET_NO);
+ if (NULL != p)
+ GCP_iterate_paths (p,
+ &path_info_iterator,
+ c->mq);
+ /* Send message with 0/0 to indicate the end */
+ env = GNUNET_MQ_msg (resp,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER_END);
+ GNUNET_MQ_send (c->mq,
+ env);
+ GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Iterator over all tunnels to send a monitoring client info about each tunnel.
+ *
+ * @param cls Closure ().
+ * @param peer Peer ID (tunnel remote peer).
+ * @param value a `struct CadetPeer`
+ * @return #GNUNET_YES, to keep iterating.
+ */
+static int
+get_all_tunnels_iterator (void *cls,
+ const struct GNUNET_PeerIdentity *peer,
+ void *value)
+{
+ struct CadetClient *c = cls;
+ struct CadetPeer *p = value;
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_CADET_LocalInfoTunnel *msg;
+ struct CadetTunnel *t;
+
+ t = GCP_get_tunnel (p,
+ GNUNET_NO);
+ if (NULL == t)
+ return GNUNET_YES;
+ env = GNUNET_MQ_msg (msg,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
+ msg->destination = *peer;
+ msg->channels = htonl (GCT_count_channels (t));
+ msg->connections = htonl (GCT_count_any_connections (t));
+ msg->cstate = htons (0);
+ msg->estate = htons ((uint16_t) GCT_get_estate (t));
+ GNUNET_MQ_send (c->mq,
+ env);
+ return GNUNET_YES;
+}
+
+
+/**
+ * Handler for client's #GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS request.
+ *
+ * @param cls client Identification of the client.
+ * @param message The actual message.
+ */
+static void
+handle_info_tunnels (void *cls,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct CadetClient *c = cls;
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_MessageHeader *reply;
+
+ GCP_iterate_all (&get_all_tunnels_iterator,
+ c);
+ env = GNUNET_MQ_msg (reply,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
+ GNUNET_MQ_send (c->mq,
+ env);
+ GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Update the message with information about the connection.
+ *
+ * @param cls a `struct GNUNET_CADET_LocalInfoTunnel` message to update
+ * @param ct a connection about which we should store information in @a cls
+ */
+static void
+iter_connection (void *cls,
+ struct CadetTConnection *ct)
+{
+ struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
+ struct CadetConnection *cc = ct->cc;
+ struct GNUNET_CADET_ConnectionTunnelIdentifier *h;
+
+ h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1];
+ h[msg->connections++] = *(GCC_get_id (cc));
+}
+