/** * We've failed for good to establish a connection (timeout or * no more addresses to try). * * @param connection the connection we tried to establish */ static void connect_fail_continuation (struct GNUNET_CONNECTION_Handle *connection) { LOG (GNUNET_ERROR_TYPE_INFO, _("Failed to establish TCP connection to `%s:%u', no further addresses to try.\n"), connection->hostname, connection->port); GNUNET_break (NULL == connection->ap_head); GNUNET_break (NULL == connection->ap_tail); GNUNET_break (GNUNET_NO == connection->dns_active); GNUNET_break (NULL == connection->sock); GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->write_task); /* signal errors for jobs that used to wait on the connection */ connection->destroy_later = 1; if (NULL != connection->receiver) signal_receive_error (connection, ECONNREFUSED); if (NULL != connection->nth.notify_ready) { GNUNET_assert (connection->nth.timeout_task != GNUNET_SCHEDULER_NO_TASK); GNUNET_SCHEDULER_cancel (connection->nth.timeout_task); connection->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK; signal_transmit_error (connection, ECONNREFUSED); } if (-1 == connection->destroy_later) { /* do it now */ connection->destroy_later = 0; GNUNET_CONNECTION_destroy (connection); return; } connection->destroy_later = 0; }
/** * We are ready to transmit (or got a timeout). * * @param cls our connection handle * @param tc task context describing why we are here */ static void transmit_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_CONNECTION_Handle *connection = cls; GNUNET_CONNECTION_TransmitReadyNotify notify; ssize_t ret; size_t have; LOG (GNUNET_ERROR_TYPE_DEBUG, "transmit_ready running (%p).\n", connection); GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != connection->write_task); connection->write_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->nth.timeout_task); if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) { if (NULL != connection->sock) goto SCHEDULE_WRITE; /* ignore shutdown, go again immediately */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmit to `%s' fails, shutdown happened (%p).\n", GNUNET_a2s (connection->addr, connection->addrlen), connection); notify = connection->nth.notify_ready; if (NULL != notify) { connection->nth.notify_ready = NULL; notify (connection->nth.notify_ready_cls, 0, NULL); } return; } if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmit to `%s' fails, time out reached (%p).\n", GNUNET_a2s (connection->addr, connection->addrlen), connection); notify = connection->nth.notify_ready; GNUNET_assert (NULL != notify); connection->nth.notify_ready = NULL; notify (connection->nth.notify_ready_cls, 0, NULL); return; } GNUNET_assert (NULL != connection->sock); if (NULL == tc->write_ready) { /* special circumstances (in particular, PREREQ_DONE after * connect): not yet ready to write, but no "fatal" error either. * Hence retry. */ goto SCHEDULE_WRITE; } if (!GNUNET_NETWORK_fdset_isset (tc->write_ready, connection->sock)) { GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->write_task); /* special circumstances (in particular, shutdown): not yet ready * to write, but no "fatal" error either. Hence retry. */ goto SCHEDULE_WRITE; } GNUNET_assert (connection->write_buffer_off >= connection->write_buffer_pos); if ((NULL != connection->nth.notify_ready) && (connection->write_buffer_size < connection->nth.notify_size)) { connection->write_buffer = GNUNET_realloc (connection->write_buffer, connection->nth.notify_size); connection->write_buffer_size = connection->nth.notify_size; } process_notify (connection); have = connection->write_buffer_off - connection->write_buffer_pos; if (0 == have) { /* no data ready for writing, terminate write loop */ return; } GNUNET_assert (have <= connection->write_buffer_size); GNUNET_assert (have + connection->write_buffer_pos <= connection->write_buffer_size); GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_size); RETRY: ret = GNUNET_NETWORK_socket_send (connection->sock, &connection->write_buffer[connection->write_buffer_pos], have); if (-1 == ret) { if (EINTR == errno) goto RETRY; if (GNUNET_SCHEDULER_NO_TASK != connection->write_task) { GNUNET_SCHEDULER_cancel (connection->write_task); connection->write_task = GNUNET_SCHEDULER_NO_TASK; } signal_transmit_error (connection, errno); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection transmitted %u/%u bytes to `%s' (%p)\n", (unsigned int) ret, have, GNUNET_a2s (connection->addr, connection->addrlen), connection); connection->write_buffer_pos += ret; if (connection->write_buffer_pos == connection->write_buffer_off) { /* transmitted all pending data */ connection->write_buffer_pos = 0; connection->write_buffer_off = 0; } if ((0 == connection->write_buffer_off) && (NULL == connection->nth.notify_ready)) return; /* all data sent! */ /* not done writing, schedule more */ SCHEDULE_WRITE: LOG (GNUNET_ERROR_TYPE_DEBUG, "Re-scheduling transmit_ready (more to do) (%p).\n", connection); have = connection->write_buffer_off - connection->write_buffer_pos; GNUNET_assert ((NULL != connection->nth.notify_ready) || (have > 0)); if (GNUNET_SCHEDULER_NO_TASK == connection->write_task) connection->write_task = GNUNET_SCHEDULER_add_write_net ((connection->nth.notify_ready == NULL) ? GNUNET_TIME_UNIT_FOREVER_REL : GNUNET_TIME_absolute_get_remaining (connection->nth.transmit_timeout), connection->sock, &transmit_ready, connection); }