/** * Listen for incoming messages on this chat room. Also, support servers going * away/coming back (i.e. rejoin chat room to keep server state up to date). * * @param cls closure, pointer to the 'struct GNUNET_CHAT_Room' * @param msg message received, NULL on timeout or fatal error */ static void receive_results (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_CHAT_Room *chat_room = cls; #if DEBUG_CHAT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a message from the service\n"); #endif if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & GNUNET_SCHEDULER_get_reason ())) return; if (NULL == msg) { GNUNET_break (0); rejoin_room (chat_room); return; } process_result (chat_room, msg); if (NULL == chat_room->client) return; /* fatal error */ /* continue receiving */ GNUNET_CLIENT_receive (chat_room->client, &receive_results, chat_room, GNUNET_TIME_UNIT_FOREVER_REL); }
/** * Connection notifies us about failure or success of a transmission * request. Either pass it on to our user or, if possible, retry. * * @param cls our `struct GNUNET_CLIENT_TransmissionHandle` * @param size number of bytes available for transmission * @param buf where to write them * @return number of bytes written to @a buf */ static size_t client_notify (void *cls, size_t size, void *buf) { struct GNUNET_CLIENT_TransmitHandle *th = cls; struct GNUNET_CLIENT_Connection *client = th->client; size_t ret; struct GNUNET_TIME_Relative delay; LOG (GNUNET_ERROR_TYPE_DEBUG, "client_notify is running\n"); th->th = NULL; client->th = NULL; if (NULL == buf) { delay = GNUNET_TIME_absolute_get_remaining (th->timeout); delay.rel_value_us /= 2; if ( (GNUNET_YES != th->auto_retry) || (0 == --th->attempts_left) || (delay.rel_value_us < 1)|| (0 != (GNUNET_SCHEDULER_get_reason() & GNUNET_SCHEDULER_REASON_SHUTDOWN))) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmission failed %u times, giving up.\n", MAX_ATTEMPTS - th->attempts_left); GNUNET_break (0 == th->notify (th->notify_cls, 0, NULL)); GNUNET_free (th); return 0; } /* auto-retry */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect to `%s', automatically trying again.\n", client->service_name); if (GNUNET_YES == client->in_receive) { GNUNET_CONNECTION_receive_cancel (client->connection); client->in_receive = GNUNET_NO; } GNUNET_CONNECTION_destroy (client->connection); client->connection = NULL; delay = GNUNET_TIME_relative_min (delay, client->back_off); client->back_off = GNUNET_TIME_relative_min (GNUNET_TIME_relative_multiply (client->back_off, 2), GNUNET_TIME_UNIT_SECONDS); LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmission failed %u times, trying again in %s.\n", MAX_ATTEMPTS - th->attempts_left, GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES)); client->th = th; GNUNET_assert (NULL == th->reconnect_task); GNUNET_assert (NULL == th->th); th->reconnect_task = GNUNET_SCHEDULER_add_delayed (delay, &client_delayed_retry, th); return 0; } GNUNET_assert (size >= th->size); ret = th->notify (th->notify_cls, size, buf); GNUNET_free (th); if (sizeof (struct GNUNET_MessageHeader) <= ret) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting message of type %u and size %u to %s service.\n", ntohs (((struct GNUNET_MessageHeader *) buf)->type), ntohs (((struct GNUNET_MessageHeader *) buf)->size), client->service_name); } return ret; }