+/**
+ * Functions with this signature are called whenever we need
+ * to close a session due to a disconnect or failure to
+ * establish a connection.
+ *
+ * @param cls the `struct Plugin`
+ * @param session session to close down
+ * @return #GNUNET_OK on success
+ */
+static int
+tcp_disconnect_session (void *cls,
+ struct Session *session)
+{
+ struct Plugin *plugin = cls;
+ struct PendingMessage *pm;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Disconnecting session of peer `%s' address `%s'\n",
+ GNUNET_i2s (&session->target),
+ tcp_address_to_string (NULL, session->addr, session->addrlen));
+
+ if (GNUNET_SCHEDULER_NO_TASK != session->timeout_task)
+ {
+ GNUNET_SCHEDULER_cancel (session->timeout_task);
+ session->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ if (GNUNET_YES ==
+ GNUNET_CONTAINER_multipeermap_remove (plugin->sessionmap,
+ &session->target,
+ session))
+ {
+ GNUNET_STATISTICS_update (session->plugin->env->stats,
+ gettext_noop ("# TCP sessions active"), -1,
+ GNUNET_NO);
+ }
+ else
+ {
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multipeermap_remove (plugin->nat_wait_conns,
+ &session->target,
+ session));
+ }
+ GNUNET_SERVER_client_set_user_context (session->client,
+ (void *) NULL);
+
+ /* clean up state */
+ if (NULL != session->transmit_handle)
+ {
+ GNUNET_SERVER_notify_transmit_ready_cancel (session->transmit_handle);
+ session->transmit_handle = NULL;
+ }
+ session->plugin->env->session_end (session->plugin->env->cls,
+ &session->target, session);
+
+ if (GNUNET_SCHEDULER_NO_TASK != session->nat_connection_timeout)
+ {
+ GNUNET_SCHEDULER_cancel (session->nat_connection_timeout);
+ session->nat_connection_timeout = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ while (NULL != (pm = session->pending_messages_head))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ pm->transmit_cont !=
+ NULL ? "Could not deliver message to `%4s'.\n" :
+ "Could not deliver message to `%4s', notifying.\n",
+ GNUNET_i2s (&session->target));
+ GNUNET_STATISTICS_update (session->plugin->env->stats,
+ gettext_noop ("# bytes currently in TCP buffers"),
+ -(int64_t) pm->message_size, GNUNET_NO);
+ GNUNET_STATISTICS_update (session->plugin->env->stats,
+ gettext_noop
+ ("# bytes discarded by TCP (disconnect)"),
+ pm->message_size, GNUNET_NO);
+ GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
+ session->pending_messages_tail, pm);
+ if (NULL != pm->transmit_cont)
+ pm->transmit_cont (pm->transmit_cont_cls, &session->target,
+ GNUNET_SYSERR, pm->message_size, 0);
+ GNUNET_free (pm);
+ }
+ if (session->receive_delay_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (session->receive_delay_task);
+ if (NULL != session->client)
+ GNUNET_SERVER_receive_done (session->client, GNUNET_SYSERR);
+ }
+ if (NULL != session->client)
+ {
+ GNUNET_SERVER_client_disconnect (session->client);
+ GNUNET_SERVER_client_drop (session->client);
+ session->client = NULL;
+ }
+ GNUNET_free_non_null (session->addr);
+ GNUNET_assert (NULL == session->transmit_handle);
+ GNUNET_free (session);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Session was idle, so disconnect it
+ *
+ * @param cls the `struct Session` of the idle session
+ * @param tc scheduler context
+ */
+static void
+session_timeout (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct Session *s = cls;
+
+ s->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Session %p was idle for %s, disconnecting\n",
+ s,
+ GNUNET_STRINGS_relative_time_to_string (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
+ GNUNET_YES));
+ /* call session destroy function */
+ tcp_disconnect_session (s->plugin, s);
+}
+
+
+/**
+ * Increment session timeout due to activity
+ *
+ * @param s session to increment timeout for
+ */
+static void
+reschedule_session_timeout (struct Session *s)
+{
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != s->timeout_task);
+ GNUNET_SCHEDULER_cancel (s->timeout_task);
+ s->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
+ &session_timeout,
+ s);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Timeout rescheduled for session %p set to %s\n",
+ s,
+ GNUNET_STRINGS_relative_time_to_string (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
+ GNUNET_YES));
+}
+
+