*/
GNUNET_SCHEDULER_TaskIdentifier write_task;
+ /**
+ * Destroy task (if already scheduled).
+ */
+ GNUNET_SCHEDULER_TaskIdentifier destroy_task;
+
/**
* Handle to a pending DNS lookup request.
*/
*/
uint16_t port;
+ /**
+ * When shutdown, do not ever actually close the socket, but
+ * free resources. Only should ever be set if using program
+ * termination as a signal (because only then will the leaked
+ * socket be freed!)
+ */
+ int persist;
+
};
+/**
+ * Set the persist option on this connection handle. Indicates
+ * that the underlying socket or fd should never really be closed.
+ * Used for indicating process death.
+ *
+ * @param sock the connection to set persistent
+ */
+void GNUNET_CONNECTION_persist_(struct GNUNET_CONNECTION_Handle *sock)
+{
+ sock->persist = GNUNET_YES;
+}
/**
* Create a socket handle by boxing an existing OS socket. The OS
struct GNUNET_CONNECTION_Handle *sock = cls;
GNUNET_CONNECTION_TransmitReadyNotify notify;
struct AddressProbe *pos;
-
+
+ sock->destroy_task = GNUNET_SCHEDULER_NO_TASK;
GNUNET_assert (sock->dns_active == NULL);
if (0 != (sock->ccs & COCO_TRANSMIT_READY))
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Destroy waits for write_task to be done (%p)\n", sock);
#endif
- GNUNET_SCHEDULER_add_after (sock->sched,
- sock->write_task,
- &destroy_continuation, sock);
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == sock->destroy_task);
+ sock->destroy_task
+ = GNUNET_SCHEDULER_add_after (sock->sched,
+ sock->write_task,
+ &destroy_continuation, sock);
return;
}
if (0 != (sock->ccs & COCO_RECEIVE_AGAIN))
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Shutting down socket (%p)\n", sock);
#endif
- GNUNET_NETWORK_socket_shutdown (sock->sock, SHUT_RDWR);
+ if (sock->persist != GNUNET_YES)
+ GNUNET_NETWORK_socket_shutdown (sock->sock, SHUT_RDWR);
}
if (sock->read_task != GNUNET_SCHEDULER_NO_TASK)
{
- GNUNET_SCHEDULER_add_after (sock->sched,
- sock->read_task,
- &destroy_continuation, sock);
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == sock->destroy_task);
+ sock->destroy_task
+ = GNUNET_SCHEDULER_add_after (sock->sched,
+ sock->read_task,
+ &destroy_continuation, sock);
return;
}
#if DEBUG_CONNECTION
sock->nth.notify_ready = NULL;
notify (sock->nth.notify_ready_cls, 0, NULL);
}
- if (sock->sock != NULL)
- GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock->sock));
+
+ if (sock->sock != NULL)
+ {
+ if (sock->persist != GNUNET_YES)
+ GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock->sock));
+ else
+ GNUNET_free (sock->sock); /* at least no memory leak (we deliberately
+ leak the socket in this special case) ... */
+ }
GNUNET_free_non_null (sock->addr);
GNUNET_free_non_null (sock->hostname);
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == sock->destroy_task);
#if DEBUG_CONNECTION
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Freeing memory of connection %p.\n", sock);
h);
#endif
h->ccs -= COCO_DESTROY_CONTINUATION;
- GNUNET_SCHEDULER_add_continuation (h->sched,
- &destroy_continuation,
- h, GNUNET_SCHEDULER_REASON_TIMEOUT);
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == h->destroy_task);
+ h->destroy_task
+ = GNUNET_SCHEDULER_add_now (h->sched,
+ &destroy_continuation,
+ h);
}
}
h);
#endif
h->ccs -= COCO_DESTROY_CONTINUATION;
- GNUNET_SCHEDULER_add_continuation (h->sched,
- &destroy_continuation,
- h,
- GNUNET_SCHEDULER_REASON_PREREQ_DONE);
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == h->destroy_task);
+ h->destroy_task
+ = GNUNET_SCHEDULER_add_now (h->sched,
+ &destroy_continuation,
+ h);
}
}
sock->dns_active = NULL;
}
GNUNET_assert (sock->sched != NULL);
- GNUNET_SCHEDULER_add_now (sock->sched,
- &destroy_continuation, sock);
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == sock->destroy_task);
+ sock->destroy_task
+ = GNUNET_SCHEDULER_add_now (sock->sched,
+ &destroy_continuation, sock);
}