/**
* Call "transmit_ready".
*/
- COCO_TRANSMIT_READY = 2,
+ COCO_TRANSMIT_READY = 2
- /**
- * Call "destroy_continuation".
- */
- COCO_DESTROY_CONTINUATION = 4
};
*/
GNUNET_SCHEDULER_TaskIdentifier write_task;
- /**
- * Destroy task (if already scheduled).
- */
- GNUNET_SCHEDULER_TaskIdentifier destroy_task;
-
/**
* Handle to a pending DNS lookup request.
*/
receive_again (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
-/**
- * Scheduler let us know that the connect task is finished (or was
- * cancelled due to shutdown). Now really clean up.
- *
- * @param cls our "struct GNUNET_CONNECTION_Handle *"
- * @param tc unused
- */
-static void
-destroy_continuation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct GNUNET_CONNECTION_Handle *connection = cls;
- GNUNET_CONNECTION_TransmitReadyNotify notify;
- struct AddressProbe *pos;
-
- connection->destroy_task = GNUNET_SCHEDULER_NO_TASK;
- GNUNET_assert (connection->dns_active == NULL);
- if (0 != (connection->ccs & COCO_TRANSMIT_READY))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Destroy waits for CCS-TR to be done (%p)\n",
- connection);
- connection->ccs |= COCO_DESTROY_CONTINUATION;
- return;
- }
- if (connection->write_task != GNUNET_SCHEDULER_NO_TASK)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Destroy waits for write_task to be done (%p)\n", connection);
- GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->destroy_task);
- connection->destroy_task =
- GNUNET_SCHEDULER_add_after (connection->write_task, &destroy_continuation,
- connection);
- return;
- }
- if (0 != (connection->ccs & COCO_RECEIVE_AGAIN))
- {
- connection->ccs |= COCO_DESTROY_CONTINUATION;
- return;
- }
- if (connection->sock != NULL)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down connection (%p)\n", connection);
- if (connection->persist != GNUNET_YES)
- {
- if ((GNUNET_YES != GNUNET_NETWORK_socket_shutdown (connection->sock, SHUT_RDWR))
- && (errno != ENOTCONN) && (errno != ECONNRESET))
- LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "shutdown");
- }
- }
- if (connection->read_task != GNUNET_SCHEDULER_NO_TASK)
- {
- GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->destroy_task);
- connection->destroy_task =
- GNUNET_SCHEDULER_add_after (connection->read_task, &destroy_continuation,
- connection);
- return;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Destroy actually runs (%p)!\n", connection);
- while (NULL != (pos = connection->ap_head))
- {
- GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pos->sock));
- GNUNET_SCHEDULER_cancel (pos->task);
- GNUNET_CONTAINER_DLL_remove (connection->ap_head, connection->ap_tail, pos);
- GNUNET_free (pos);
- }
- GNUNET_assert (connection->nth.timeout_task == GNUNET_SCHEDULER_NO_TASK);
- GNUNET_assert (connection->ccs == COCO_NONE);
- if (NULL != (notify = connection->nth.notify_ready))
- {
- connection->nth.notify_ready = NULL;
- notify (connection->nth.notify_ready_cls, 0, NULL);
- }
-
- if (connection->sock != NULL)
- {
- if (connection->persist != GNUNET_YES)
- GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (connection->sock));
- else
- GNUNET_free (connection->sock); /* at least no memory leak (we deliberately
- * leak the socket in this special case) ... */
- }
- GNUNET_free_non_null (connection->addr);
- GNUNET_free_non_null (connection->hostname);
- GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->destroy_task);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Freeing memory of connection %p.\n", connection);
- GNUNET_free (connection->write_buffer);
- GNUNET_free (connection);
-}
-
-
-
/**
* See if we are now connected. If not, wait longer for
* connect to succeed. If connected, we should be able
GNUNET_assert (h->write_task == GNUNET_SCHEDULER_NO_TASK);
h->write_task = GNUNET_SCHEDULER_add_now (&transmit_ready, h);
}
- if (0 != (h->ccs & COCO_DESTROY_CONTINUATION))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "connect_fail_continuation runs destroy_continuation (%p)\n", h);
- h->ccs -= COCO_DESTROY_CONTINUATION;
- GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == h->destroy_task);
- h->destroy_task = GNUNET_SCHEDULER_add_now (&destroy_continuation, h);
- }
}
(connection->nth.transmit_timeout), connection->sock,
&transmit_ready, connection);
}
- if (0 != (connection->ccs & COCO_DESTROY_CONTINUATION))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "connect_success_continuation runs destroy_continuation (%p)\n", connection);
- connection->ccs -= COCO_DESTROY_CONTINUATION;
- GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->destroy_task);
- connection->destroy_task = GNUNET_SCHEDULER_add_now (&destroy_continuation, connection);
- }
}
/**
- * Close the connection and free associated resources. A pending
- * request for transmission is automatically cancelled (we might
- * want to change this in the future). We require that there
- * are no active pending requests for reading from the connection.
+ * Close the connection and free associated resources. There must
+ * not be any pending requests for reading or writing to the
+ * connection at this time.
*
* @param connection connection to destroy
*/
void
GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection)
{
+ struct AddressProbe *pos;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down connection (%p)\n", connection);
+ GNUNET_assert (NULL == connection->nth.notify_ready);
GNUNET_assert (NULL == connection->receiver);
GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->read_task);
if (connection->write_task != GNUNET_SCHEDULER_NO_TASK)
connection->write_task = GNUNET_SCHEDULER_NO_TASK;
connection->write_buffer_off = 0;
}
+ if (connection->read_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (connection->read_task);
+ connection->read_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ if (connection->nth.timeout_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (connection->nth.timeout_task);
+ connection->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ }
connection->nth.notify_ready = NULL;
- if (connection->dns_active != NULL)
+ if (NULL != connection->dns_active)
{
GNUNET_RESOLVER_request_cancel (connection->dns_active);
connection->dns_active = NULL;
}
- GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->destroy_task);
- connection->destroy_task = GNUNET_SCHEDULER_add_now (&destroy_continuation, connection);
+ while (NULL != (pos = connection->ap_head))
+ {
+ GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pos->sock));
+ GNUNET_SCHEDULER_cancel (pos->task);
+ GNUNET_CONTAINER_DLL_remove (connection->ap_head, connection->ap_tail, pos);
+ GNUNET_free (pos);
+ }
+ if ( (NULL != connection->sock) &&
+ (connection->persist != GNUNET_YES) )
+ {
+ if ((GNUNET_YES != GNUNET_NETWORK_socket_shutdown (connection->sock, SHUT_RDWR)) &&
+ (errno != ENOTCONN) &&
+ (errno != ECONNRESET) )
+ LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "shutdown");
+ }
+ if (connection->sock != NULL)
+ {
+ if (connection->persist != GNUNET_YES)
+ GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (connection->sock));
+ else
+ GNUNET_free (connection->sock); /* at least no memory leak (we deliberately
+ * leak the socket in this special case) ... */
+ }
+ GNUNET_free_non_null (connection->addr);
+ GNUNET_free_non_null (connection->hostname);
+ GNUNET_free (connection->write_buffer);
+ GNUNET_free (connection);
}
* Tell the receiver callback that a timeout was reached.
*/
static void
-signal_timeout (struct GNUNET_CONNECTION_Handle *sh)
+signal_timeout (struct GNUNET_CONNECTION_Handle *connection)
{
GNUNET_CONNECTION_Receiver receiver;
LOG (GNUNET_ERROR_TYPE_DEBUG, "Network signals time out to receiver (%p)!\n",
- sh);
- GNUNET_assert (NULL != (receiver = sh->receiver));
- sh->receiver = NULL;
- receiver (sh->receiver_cls, NULL, 0, NULL, 0, 0);
+ connection);
+ GNUNET_assert (NULL != (receiver = connection->receiver));
+ connection->receiver = NULL;
+ receiver (connection->receiver_cls, NULL, 0, NULL, 0, 0);
}
* Tell the receiver callback that we had an IO error.
*/
static void
-signal_error (struct GNUNET_CONNECTION_Handle *sh, int errcode)
+signal_error (struct GNUNET_CONNECTION_Handle *connection, int errcode)
{
GNUNET_CONNECTION_Receiver receiver;
- GNUNET_assert (NULL != (receiver = sh->receiver));
- sh->receiver = NULL;
- receiver (sh->receiver_cls, NULL, 0, sh->addr, sh->addrlen, errcode);
+ GNUNET_assert (NULL != (receiver = connection->receiver));
+ connection->receiver = NULL;
+ receiver (connection->receiver_cls, NULL, 0, connection->addr, connection->addrlen, errcode);
}
*/
int clients_ignore_shutdown;
+ /**
+ * Alternative function to create a MST instance.
+ */
GNUNET_SERVER_MstCreateCallback mst_create;
+
+ /**
+ * Alternative function to destroy a MST instance.
+ */
GNUNET_SERVER_MstDestroyCallback mst_destroy;
+
+ /**
+ * Alternative function to give data to a MST instance.
+ */
GNUNET_SERVER_MstReceiveCallback mst_receive;
+
+ /**
+ * Closure for 'mst_'-callbacks.
+ */
void *mst_cls;
};
+/**
+ * Handle server returns for aborting transmission to a client.
+ */
+struct GNUNET_SERVER_TransmitHandle
+{
+ /**
+ * Function to call to get the message.
+ */
+ GNUNET_CONNECTION_TransmitReadyNotify callback;
+
+ /**
+ * Closure for 'callback'
+ */
+ void *callback_cls;
+
+ /**
+ * Active connection transmission handle.
+ */
+ struct GNUNET_CONNECTION_TransmitHandle *cth;
+
+};
+
+
/**
* @brief handle for a client of the server
*/
struct GNUNET_TIME_Absolute last_activity;
/**
- *
+ * Transmission handle we return for this client from
+ * GNUNET_SERVER_notify_transmit_ready.
*/
- GNUNET_CONNECTION_TransmitReadyNotify callback;
-
- /**
- * callback
- */
- void *callback_cls;
+ struct GNUNET_SERVER_TransmitHandle th;
/**
* After how long should an idle connection time
client->next = server->clients;
client->idle_timeout = server->idle_timeout;
server->clients = client;
- client->callback = NULL;
- client->callback_cls = NULL;
- if (server->mst_create != NULL)
+ if (NULL != server->mst_create)
client->mst =
server->mst_create (server->mst_cls, client);
else
transmit_ready_callback_wrapper (void *cls, size_t size, void *buf)
{
struct GNUNET_SERVER_Client *client = cls;
+ GNUNET_CONNECTION_TransmitReadyNotify callback;
size_t ret;
- ret = client->callback (client->callback_cls, size, buf);
+ client->th.cth = NULL;
+ callback = client->th.callback;
+ client->th.callback = NULL;
+ ret = callback (client->th.callback_cls, size, buf);
if (ret > 0)
client->last_activity = GNUNET_TIME_absolute_get ();
return ret;
* @param callback_cls closure for callback
* @return non-NULL if the notify callback was queued; can be used
* to cancel the request using
- * GNUNET_CONNECTION_notify_transmit_ready_cancel.
+ * GNUNET_SERVER_notify_transmit_ready_cancel.
* NULL if we are already going to notify someone else (busy)
*/
-struct GNUNET_CONNECTION_TransmitHandle *
+struct GNUNET_SERVER_TransmitHandle *
GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
size_t size,
struct GNUNET_TIME_Relative timeout,
GNUNET_CONNECTION_TransmitReadyNotify
callback, void *callback_cls)
{
- client->callback_cls = callback_cls;
- client->callback = callback;
- return GNUNET_CONNECTION_notify_transmit_ready (client->connection, size,
- timeout,
- &transmit_ready_callback_wrapper,
- client);
+ if (NULL != client->th.callback)
+ return NULL;
+ client->th.callback_cls = callback_cls;
+ client->th.callback = callback;
+ client->th.cth = GNUNET_CONNECTION_notify_transmit_ready (client->connection, size,
+ timeout,
+ &transmit_ready_callback_wrapper,
+ client);
+ return &client->th;
+}
+
+
+/**
+ * Abort transmission request.
+ *
+ * @param th request to abort
+ */
+void
+GNUNET_SERVER_notify_transmit_ready_cancel (struct GNUNET_SERVER_TransmitHandle *th)
+{
+ GNUNET_CONNECTION_notify_transmit_ready_cancel (th->cth);
+ th->cth = NULL;
+ th->callback = NULL;
}
static int ok = 1;
+static struct GNUNET_CLIENT_Connection *client;
+
static size_t
build_msg (void *cls, size_t size, void *buf)
{
- struct GNUNET_CLIENT_Connection *client = cls;
struct GNUNET_MessageHeader *msg = buf;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client connected, transmitting\n");
GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader));
msg->type = htons (MY_TYPE);
msg->size = htons (sizeof (struct GNUNET_MessageHeader));
- GNUNET_CLIENT_disconnect (client);
return sizeof (struct GNUNET_MessageHeader);
}
GNUNET_CLIENT_notify_transmit_ready (client,
sizeof (struct GNUNET_MessageHeader),
GNUNET_TIME_UNIT_SECONDS, GNUNET_NO,
- &build_msg, client);
+ &build_msg, NULL);
}
static void
do_stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
+ GNUNET_CLIENT_disconnect (client);
GNUNET_SERVICE_stop (sctx);
}
static void
-recv_cb (void *cls, struct GNUNET_SERVER_Client *client,
+recv_cb (void *cls, struct GNUNET_SERVER_Client *sc,
const struct GNUNET_MessageHeader *message)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving client message...\n");
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ GNUNET_SERVER_receive_done (sc, GNUNET_OK);
if (sctx != NULL)
GNUNET_SCHEDULER_add_now (&do_stop, NULL);
else
ready6 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
- struct GNUNET_CLIENT_Connection *client;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "V6 ready\n");
GNUNET_assert (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE));
GNUNET_CLIENT_notify_transmit_ready (client,
sizeof (struct GNUNET_MessageHeader),
GNUNET_TIME_UNIT_SECONDS, GNUNET_NO,
- &build_msg, client);
+ &build_msg, NULL);
}
static void