/** * 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); if (GNUNET_SCHEDULER_NO_TASK != connection->write_task) { GNUNET_SCHEDULER_cancel (connection->write_task); connection->write_task = GNUNET_SCHEDULER_NO_TASK; connection->write_buffer_off = 0; } if (GNUNET_SCHEDULER_NO_TASK != connection->read_task) { GNUNET_SCHEDULER_cancel (connection->read_task); connection->read_task = GNUNET_SCHEDULER_NO_TASK; } if (GNUNET_SCHEDULER_NO_TASK != connection->nth.timeout_task) { GNUNET_SCHEDULER_cancel (connection->nth.timeout_task); connection->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK; } connection->nth.notify_ready = NULL; if (NULL != connection->dns_active) { GNUNET_RESOLVER_request_cancel (connection->dns_active); connection->dns_active = NULL; } 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) && (GNUNET_YES != connection->persist) ) { if ((GNUNET_YES != GNUNET_NETWORK_socket_shutdown (connection->sock, SHUT_RDWR)) && (ENOTCONN != errno) && (ECONNRESET != errno) ) LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "shutdown"); } if (NULL != connection->sock) { if (GNUNET_YES != connection->persist) 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); }
/** * A DNS resolution timed out. Notify the application. * * @param cls the `struct GNUNET_RESOLVER_RequestHandle *` * @param tc scheduler context */ static void handle_lookup_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_RESOLVER_RequestHandle *rh = cls; rh->task = NULL; rh->addr_callback (rh->cls, NULL, 0); GNUNET_RESOLVER_request_cancel (rh); }
/** * Process response with a hostname for a DNS lookup. * * @param cls our `struct GNUNET_RESOLVER_RequestHandle *` context * @param msg message with the hostname, NULL on error */ static void handle_response (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_RESOLVER_RequestHandle *rh = cls; uint16_t size; char *nret; LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving response from DNS service\n"); if (NULL == msg) { char buf[INET6_ADDRSTRLEN]; if (NULL != rh->name_callback) LOG (GNUNET_ERROR_TYPE_INFO, _("Timeout trying to resolve IP address `%s'.\n"), inet_ntop (rh->af, (const void *) &rh[1], buf, sizeof(buf))); else LOG (GNUNET_ERROR_TYPE_INFO, _("Timeout trying to resolve hostname `%s'.\n"), (const char *) &rh[1]); /* check if request was canceled */ if (GNUNET_SYSERR != rh->was_transmitted) { if (NULL != rh->name_callback) { /* no reverse lookup was successful, return IP as string */ if (GNUNET_NO == rh->received_response) { nret = no_resolve (rh->af, &rh[1], rh->data_len); rh->name_callback (rh->cls, nret); GNUNET_free (nret); } /* finally, make termination call */ rh->name_callback (rh->cls, NULL); } if (NULL != rh->addr_callback) rh->addr_callback (rh->cls, NULL, 0); } rh->was_transmitted = GNUNET_NO; GNUNET_RESOLVER_request_cancel (rh); GNUNET_CLIENT_disconnect (client); client = NULL; reconnect (); return; } if (GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE != ntohs (msg->type)) { GNUNET_break (0); GNUNET_CLIENT_disconnect (client); client = NULL; reconnect (); return; } size = ntohs (msg->size); if (size == sizeof (struct GNUNET_MessageHeader)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Received empty response from DNS service\n"); /* message contains not data, just header; end of replies */ /* check if request was canceled */ if (GNUNET_SYSERR != rh->was_transmitted) { /* no reverse lookup was successful, return IP as string */ if (NULL != rh->name_callback) { if (GNUNET_NO == rh->received_response) { nret = no_resolve (rh->af, &rh[1], rh->data_len); rh->name_callback (rh->cls, nret); GNUNET_free (nret); } /* finally, make termination call */ rh->name_callback (rh->cls, NULL); } if (NULL != rh->addr_callback) rh->addr_callback (rh->cls, NULL, 0); } rh->was_transmitted = GNUNET_NO; GNUNET_RESOLVER_request_cancel (rh); process_requests (); return; } /* return reverse lookup results to caller */ if (NULL != rh->name_callback) { const char *hostname; hostname = (const char *) &msg[1]; if (hostname[size - sizeof (struct GNUNET_MessageHeader) - 1] != '\0') { GNUNET_break (0); if (GNUNET_SYSERR != rh->was_transmitted) rh->name_callback (rh->cls, NULL); rh->was_transmitted = GNUNET_NO; GNUNET_RESOLVER_request_cancel (rh); GNUNET_CLIENT_disconnect (client); client = NULL; reconnect (); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Resolver returns `%s' for IP `%s'.\n", hostname, GNUNET_a2s ((const void *) &rh[1], rh->data_len)); if (rh->was_transmitted != GNUNET_SYSERR) rh->name_callback (rh->cls, hostname); rh->received_response = GNUNET_YES; } /* return lookup results to caller */ if (NULL != rh->addr_callback) { struct sockaddr_in v4; struct sockaddr_in6 v6; const struct sockaddr *sa; socklen_t salen; const void *ip; size_t ip_len; ip = &msg[1]; ip_len = size - sizeof (struct GNUNET_MessageHeader); if (ip_len == sizeof (struct in_addr)) { memset (&v4, 0, sizeof (v4)); v4.sin_family = AF_INET; v4.sin_addr = *(struct in_addr*) ip; #if HAVE_SOCKADDR_IN_SIN_LEN v4.sin_len = sizeof (v4); #endif salen = sizeof (v4); sa = (const struct sockaddr *) &v4; } else if (ip_len == sizeof (struct in6_addr)) { memset (&v6, 0, sizeof (v6)); v6.sin6_family = AF_INET6; v6.sin6_addr = *(struct in6_addr*) ip; #if HAVE_SOCKADDR_IN_SIN_LEN v6.sin6_len = sizeof (v6); #endif salen = sizeof (v6); sa = (const struct sockaddr *) &v6; } else { GNUNET_break (0); if (GNUNET_SYSERR != rh->was_transmitted) rh->addr_callback (rh->cls, NULL, 0); rh->was_transmitted = GNUNET_NO; GNUNET_RESOLVER_request_cancel (rh); GNUNET_CLIENT_disconnect (client); client = NULL; reconnect (); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Received IP from DNS service\n"); if (GNUNET_SYSERR != rh->was_transmitted) rh->addr_callback (rh->cls, sa, salen); } GNUNET_CLIENT_receive (client, &handle_response, rh, GNUNET_TIME_absolute_get_remaining (rh->timeout)); }