/** * Release the session slot from the session table (ATS service is * also done using it). * * @param sh our handle * @param session_id identifies session that is no longer valid */ static void release_session (struct GNUNET_ATS_SchedulingHandle *sh, uint32_t session_id) { struct GNUNET_ATS_AddressRecord *ar; if (NOT_FOUND == session_id) return; if (session_id >= sh->session_array_size) { GNUNET_break (0); force_reconnect (sh); return; } /* this slot should have been removed from remove_session before */ ar = sh->session_array[session_id]; if (NULL != ar->session) { GNUNET_break (0); force_reconnect (sh); return; } GNUNET_HELLO_address_free (ar->address); GNUNET_free (ar); sh->session_array[session_id] = NULL; }
/** * We can now transmit a message to NAMESTORE. Do it. * * @param cls the 'struct GNUNET_NAMESTORE_Handle' * @param size number of bytes we can transmit * @param buf where to copy the messages * @return number of bytes copied into buf */ static size_t transmit_message_to_namestore (void *cls, size_t size, void *buf) { struct GNUNET_NAMESTORE_Handle *h = cls; struct PendingMessage *p; size_t ret; char *cbuf; h->th = NULL; if ((size == 0) || (buf == NULL)) { force_reconnect (h); return 0; } ret = 0; cbuf = buf; while ((NULL != (p = h->pending_head)) && (p->size <= size)) { memcpy (&cbuf[ret], &p[1], p->size); ret += p->size; size -= p->size; GNUNET_CONTAINER_DLL_remove (h->pending_head, h->pending_tail, p); if (GNUNET_YES == p->is_init) GNUNET_CLIENT_receive (h->client, &process_namestore_message, h, GNUNET_TIME_UNIT_FOREVER_REL); GNUNET_free (p); } do_transmit (h); return ret; }
/** * Generic error handler, called with the appropriate error code and * the same closure specified at the creation of the message queue. * Not every message queue implementation supports an error handler. * * @param cls closure with the `struct GNUNET_GNS_Handle *` * @param error error code */ static void mq_error_handler (void *cls, enum GNUNET_MQ_Error error) { struct GNUNET_GNS_Handle *handle = cls; LOG (GNUNET_ERROR_TYPE_WARNING, "Problem with message queue. error: %i\n", error); force_reconnect (handle); }
void wait_server_backoff(unsigned int timeout /* seconds */, jsonrpc_server_t* server, bool delay) { if(!server) { ERR("Trying to close/reconnect a NULL server\n"); return; } if(delay == false) { if (requests_using_server(server) <= 0) { if(server->status == JSONRPC_SERVER_RECONNECTING) { bev_connect(server); } else if(server->status == JSONRPC_SERVER_CLOSING) { close_server(server); } return; } } const struct timeval tv = {timeout, 0}; server_backoff_args_t* args = pkg_malloc(sizeof(server_backoff_args_t)); CHECK_MALLOC_VOID(args); memset(args, 0, sizeof(server_backoff_args_t)); args->ev = evtimer_new(global_ev_base, server_backoff_cb, (void*)args); CHECK_MALLOC_GOTO(args->ev, error); args->server = server; args->timeout = timeout; if(evtimer_add(args->ev, &tv)<0) { ERR("event_add failed while setting request timer (%s).", strerror(errno)); goto error; } return; error: ERR("schedule_server failed.\n"); if(args) { if(args->ev) { evtimer_del(args->ev); } pkg_free(args); } if (server->status == JSONRPC_SERVER_CLOSING) { ERR("Closing server now...\n"); close_server(server); } else if (server->status == JSONRPC_SERVER_RECONNECTING) { ERR("Reconnecting server now...\n"); force_reconnect(server); } }
/** * We encountered an error handling the MQ to the * ATS service. Reconnect. * * @param cls the `struct GNUNET_ATS_SchedulingHandle` * @param error details about the error */ static void error_handler (void *cls, enum GNUNET_MQ_Error error) { struct GNUNET_ATS_SchedulingHandle *sh = cls; LOG (GNUNET_ERROR_TYPE_ERROR, "ATS connection died (code %d), reconnecting\n", (int) error); force_reconnect (sh); }
/** * Process a given reply that might match the given * request. * * @param qe a queue entry * @param msg the shorten msg received */ static void process_shorten_reply (struct GNUNET_GNS_ShortenRequest *qe, const struct GNUNET_GNS_ClientShortenResultMessage *msg) { struct GNUNET_GNS_Handle *handle = qe->gns_handle; struct PendingMessage *p = (struct PendingMessage *)&qe[1]; const char *short_name; size_t mlen; if (GNUNET_YES != p->transmitted) { /* service send reply to query we never managed to send!? */ GNUNET_break (0); force_reconnect (handle); return; } mlen = ntohs (msg->header.size); if (ntohs (msg->header.size) == sizeof (struct GNUNET_GNS_ClientShortenResultMessage)) { /* service reports resolution failed */ short_name = NULL; } else { short_name = (const char *) &msg[1]; if ('\0' != short_name[mlen - sizeof (struct GNUNET_GNS_ClientShortenResultMessage) - 1]) { GNUNET_break (0); force_reconnect (handle); return; } } GNUNET_CONTAINER_DLL_remove (handle->shorten_head, handle->shorten_tail, qe); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received shortened reply `%s' from GNS service\n", short_name); qe->shorten_proc (qe->proc_cls, short_name); GNUNET_free (qe); }
/** * Process a given reply that might match the given * request. * * @param qe the handle to the request * @param msg the message to process */ static void process_get_auth_reply (struct GNUNET_GNS_GetAuthRequest *qe, const struct GNUNET_GNS_ClientGetAuthResultMessage *msg) { struct GNUNET_GNS_Handle *handle = qe->gns_handle; struct PendingMessage *p = (struct PendingMessage *)&qe[1]; const char *auth_name; size_t mlen; if (GNUNET_YES != p->transmitted) { /* service send reply to query we never managed to send!? */ GNUNET_break (0); force_reconnect (handle); return; } mlen = ntohs (msg->header.size); if (mlen == sizeof (struct GNUNET_GNS_ClientGetAuthResultMessage)) { auth_name = NULL; } else { auth_name = (const char*) &msg[1]; if ('\0' != auth_name[mlen - sizeof (struct GNUNET_GNS_ClientGetAuthResultMessage) - 1]) { GNUNET_break (0); force_reconnect (handle); return; } } GNUNET_CONTAINER_DLL_remove (handle->get_auth_head, handle->get_auth_tail, qe); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received GET_AUTH reply `%s' from GNS service\n", auth_name); qe->auth_proc (qe->proc_cls, auth_name); GNUNET_free (qe); }
void bev_read_cb(struct bufferevent* bev, void* arg) { jsonrpc_server_t* server = (jsonrpc_server_t*)arg; int retval = 0; while (retval == 0) { int retval = netstring_read_evbuffer(bev, &server->buffer); if (retval == NETSTRING_INCOMPLETE) { return; } else if (retval < 0) { char* msg = ""; switch(retval) { case NETSTRING_ERROR_TOO_LONG: msg = "too long"; break; case NETSTRING_ERROR_NO_COLON: msg = "no colon after length field"; break; case NETSTRING_ERROR_TOO_SHORT: msg = "too short"; break; case NETSTRING_ERROR_NO_COMMA: msg = "missing comma"; break; case NETSTRING_ERROR_LEADING_ZERO: msg = "length field has a leading zero"; break; case NETSTRING_ERROR_NO_LENGTH: msg = "missing length field"; break; case NETSTRING_INCOMPLETE: msg = "incomplete"; break; default: ERR("bad netstring: unknown error (%d)\n", retval); goto reconnect; } ERR("bad netstring: %s\n", msg); reconnect: force_reconnect(server); return; } handle_netstring(server); free_netstring(server->buffer); server->buffer = NULL; } }
/** * Re-establish the connection to the ATS service. * * @param sh handle to use to re-connect. */ static void reconnect (struct GNUNET_ATS_SchedulingHandle *sh) { static const struct GNUNET_MQ_MessageHandler handlers[] = { { &process_ats_session_release_message, GNUNET_MESSAGE_TYPE_ATS_SESSION_RELEASE, sizeof (struct GNUNET_ATS_SessionReleaseMessage) }, { &process_ats_address_suggestion_message, GNUNET_MESSAGE_TYPE_ATS_ADDRESS_SUGGESTION, sizeof (struct AddressSuggestionMessage) }, { NULL, 0, 0 } }; struct GNUNET_MQ_Envelope *ev; struct ClientStartMessage *init; unsigned int i; struct GNUNET_ATS_AddressRecord *ar; GNUNET_assert (NULL == sh->client); sh->client = GNUNET_CLIENT_connect ("ats", sh->cfg); if (NULL == sh->client) { GNUNET_break (0); force_reconnect (sh); return; } sh->mq = GNUNET_MQ_queue_for_connection_client (sh->client, handlers, &error_handler, sh); ev = GNUNET_MQ_msg (init, GNUNET_MESSAGE_TYPE_ATS_START); init->start_flag = htonl (START_FLAG_SCHEDULING); GNUNET_MQ_send (sh->mq, ev); if (NULL == sh->mq) return; for (i=0;i<sh->session_array_size;i++) { ar = sh->session_array[i]; if (NULL == ar) continue; send_add_address_message (sh, ar); if (NULL == sh->mq) return; } }
/** * Transmit the next pending message, called by notify_transmit_ready * * @param cls the closure * @param size size of pending data * @param buf buffer with pending data * @return size data transmitted */ static size_t transmit_pending (void *cls, size_t size, void *buf) { struct GNUNET_GNS_Handle *handle = cls; char *cbuf = buf; struct PendingMessage *p; size_t tsize; handle->th = NULL; if ((0 == size) || (NULL == buf)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission to GNS service failed!\n"); force_reconnect (handle); return 0; } if (NULL == (p = handle->pending_head)) return 0; tsize = 0; while ((NULL != (p = handle->pending_head)) && (p->size <= size)) { memcpy (&cbuf[tsize], &p[1], p->size); tsize += p->size; size -= p->size; p->transmitted = GNUNET_YES; GNUNET_CONTAINER_DLL_remove (handle->pending_head, handle->pending_tail, p); if (GNUNET_YES != handle->in_receive) { GNUNET_CLIENT_receive (handle->client, &process_message, handle, GNUNET_TIME_UNIT_FOREVER_REL); handle->in_receive = GNUNET_YES; } } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending %u bytes\n", (unsigned int) tsize); process_pending_messages (handle); return tsize; }
/** * Process a given reply to the lookup request * * @param qe a queue entry * @param msg the lookup message received */ static void process_lookup_reply (struct GNUNET_GNS_LookupRequest *qe, const struct GNUNET_GNS_ClientLookupResultMessage *msg) { struct GNUNET_GNS_Handle *handle = qe->gns_handle; struct PendingMessage *p = (struct PendingMessage *) &qe[1]; uint32_t rd_count = ntohl (msg->rd_count); struct GNUNET_NAMESTORE_RecordData rd[rd_count]; size_t mlen; if (GNUNET_YES != p->transmitted) { /* service send reply to query we never managed to send!? */ GNUNET_break (0); force_reconnect (handle); return; } mlen = ntohs (msg->header.size); mlen -= sizeof (struct GNUNET_GNS_ClientLookupResultMessage); if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (mlen, (const char*) &msg[1], rd_count, rd)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to serialize lookup reply from GNS service!\n")); qe->lookup_proc (qe->proc_cls, 0, NULL); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received lookup reply from GNS service (%u records)\n", (unsigned int) rd_count); qe->lookup_proc (qe->proc_cls, rd_count, rd); } GNUNET_CONTAINER_DLL_remove (handle->lookup_head, handle->lookup_tail, qe); GNUNET_free (qe); }
/** * Type of a function to call when we receive a message * from the service. * * @param cls the 'struct GNUNET_NAMESTORE_SchedulingHandle' * @param msg message received, NULL on timeout or fatal error */ static void process_namestore_message (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_NAMESTORE_Handle *h = cls; struct GNUNET_NAMESTORE_Header * gm; struct GNUNET_NAMESTORE_QueueEntry *qe; struct GNUNET_NAMESTORE_ZoneIterator *ze; uint16_t size; uint16_t type; uint32_t r_id = UINT32_MAX; if (NULL == msg) { force_reconnect (h); return; } size = ntohs (msg->size); type = ntohs (msg->type); if (size < sizeof (struct GNUNET_NAMESTORE_Header)) { GNUNET_break_op (0); GNUNET_CLIENT_receive (h->client, &process_namestore_message, h, GNUNET_TIME_UNIT_FOREVER_REL); return; } gm = (struct GNUNET_NAMESTORE_Header *) msg; r_id = ntohl (gm->r_id); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received message type %i size %i op %u\n", type, size, r_id); /* Find matching operation */ if (r_id > h->op_id) { /* No matching pending operation found */ GNUNET_break_op (0); GNUNET_CLIENT_receive (h->client, &process_namestore_message, h, GNUNET_TIME_UNIT_FOREVER_REL); return; } /* Is it a record related operation ? */ for (qe = h->op_head; qe != NULL; qe = qe->next) { if (qe->op_id == r_id) break; } if (qe != NULL) { manage_record_operations (qe, msg, type, size); } /* Is it a zone iteration operation ? */ for (ze = h->z_head; ze != NULL; ze = ze->next) { if (ze->op_id == r_id) break; } if (ze != NULL) { manage_zone_operations (ze, msg, type, size); } GNUNET_CLIENT_receive (h->client, &process_namestore_message, h, GNUNET_TIME_UNIT_FOREVER_REL); if (GNUNET_YES == h->reconnect) force_reconnect (h); }
/** * Handler for messages received from the GNS service * * @param cls the 'struct GNUNET_GNS_Handle' * @param msg the incoming message */ static void process_message (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_GNS_Handle *handle = cls; struct GNUNET_GNS_LookupRequest *lr; struct GNUNET_GNS_ShortenRequest *sr; struct GNUNET_GNS_GetAuthRequest *gar; const struct GNUNET_GNS_ClientLookupResultMessage *lookup_msg; const struct GNUNET_GNS_ClientShortenResultMessage *shorten_msg; const struct GNUNET_GNS_ClientGetAuthResultMessage *get_auth_msg; uint32_t r_id; if (NULL == msg) { force_reconnect (handle); return; } switch (ntohs (msg->type)) { case GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got LOOKUP_RESULT msg\n"); if (ntohs (msg->size) < sizeof (struct GNUNET_GNS_ClientLookupResultMessage)) { GNUNET_break (0); force_reconnect (handle); return; } lookup_msg = (const struct GNUNET_GNS_ClientLookupResultMessage *) msg; r_id = ntohl (lookup_msg->id); for (lr = handle->lookup_head; NULL != lr; lr = lr->next) if (lr->r_id == r_id) { process_lookup_reply(lr, lookup_msg); break; } break; case GNUNET_MESSAGE_TYPE_GNS_SHORTEN_RESULT: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got SHORTEN_RESULT msg\n"); if (ntohs (msg->size) < sizeof (struct GNUNET_GNS_ClientShortenResultMessage)) { GNUNET_break (0); force_reconnect (handle); return; } shorten_msg = (const struct GNUNET_GNS_ClientShortenResultMessage *) msg; r_id = ntohl (shorten_msg->id); for (sr = handle->shorten_head; NULL != sr; sr = sr->next) if (sr->r_id == r_id) { process_shorten_reply (sr, shorten_msg); break; } break; case GNUNET_MESSAGE_TYPE_GNS_GET_AUTH_RESULT: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got GET_AUTH_RESULT msg\n"); if (ntohs (msg->size) < sizeof (struct GNUNET_GNS_ClientGetAuthResultMessage)) { GNUNET_break (0); force_reconnect (handle); return; } get_auth_msg = (const struct GNUNET_GNS_ClientGetAuthResultMessage *) msg; r_id = ntohl (get_auth_msg->id); for (gar = handle->get_auth_head; NULL != gar; gar = gar->next) if (gar->r_id == r_id) { process_get_auth_reply (gar, get_auth_msg); break; } break; default: GNUNET_break (0); force_reconnect (handle); return; } GNUNET_CLIENT_receive (handle->client, &process_message, handle, GNUNET_TIME_UNIT_FOREVER_REL); }
/** * Type of a function to call when we receive a address suggestion * message from the service. * * @param cls the `struct GNUNET_ATS_SchedulingHandle` * @param msg message received, NULL on timeout or fatal error */ static void process_ats_address_suggestion_message (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_ATS_SchedulingHandle *sh = cls; const struct AddressSuggestionMessage *m; struct GNUNET_ATS_AddressRecord *ar; uint32_t session_id; m = (const struct AddressSuggestionMessage *) msg; session_id = ntohl (m->session_id); if (0 == session_id) { GNUNET_break (0); force_reconnect (sh); return; } ar = find_session (sh, session_id, &m->peer); if (NULL == ar) { GNUNET_break (0); force_reconnect (sh); return; } if (NULL == sh->suggest_cb) return; if (GNUNET_YES == ar->in_destroy) { /* ignore suggestion, as this address is dying, unless BW is 0, in that case signal 'disconnect' via BW 0 */ if ( (0 == ntohl (m->bandwidth_out.value__)) && (0 == ntohl (m->bandwidth_in.value__)) ) { LOG (GNUNET_ERROR_TYPE_DEBUG, "ATS suggests disconnect from peer `%s' with BW %u/%u\n", GNUNET_i2s (&ar->address->peer), (unsigned int) ntohl (m->bandwidth_out.value__), (unsigned int) ntohl (m->bandwidth_in.value__)); sh->suggest_cb (sh->suggest_cb_cls, &m->peer, NULL, NULL, m->bandwidth_out, m->bandwidth_in); } return; } if ( (NULL == ar->session) && (GNUNET_HELLO_address_check_option (ar->address, GNUNET_HELLO_ADDRESS_INFO_INBOUND)) ) { GNUNET_break (0); return; } sh->backoff = GNUNET_TIME_UNIT_ZERO; LOG (GNUNET_ERROR_TYPE_DEBUG, "ATS suggests address slot %u for peer `%s' using plugin %s\n", ar->slot, GNUNET_i2s (&ar->address->peer), ar->address->transport_name); sh->suggest_cb (sh->suggest_cb_cls, &m->peer, ar->address, ar->session, m->bandwidth_out, m->bandwidth_in); }