X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Ftransport%2Fgnunet-service-transport.c;h=fe8b5043edac0f921a182254b9e926167f7ba8a3;hb=87487477c67697355c79d2fe079d23a5b31c7ab6;hp=da6ee9df8c38a3cc601d602f55ce62add07a9116;hpb=f1696b714e33c293f4243be27ccfa6fd2f305518;p=oweals%2Fgnunet.git diff --git a/src/transport/gnunet-service-transport.c b/src/transport/gnunet-service-transport.c index da6ee9df8..fe8b5043e 100644 --- a/src/transport/gnunet-service-transport.c +++ b/src/transport/gnunet-service-transport.c @@ -29,6 +29,7 @@ */ #include "platform.h" #include "gnunet_client_lib.h" +#include "gnunet_constants.h" #include "gnunet_getopt_lib.h" #include "gnunet_hello_lib.h" #include "gnunet_os_lib.h" @@ -66,8 +67,20 @@ /** * How long until a HELLO verification attempt should time out? + * Must be rather small, otherwise a partially successful HELLO + * validation (some addresses working) might not be available + * before a client's request for a connection fails for good. + * Besides, if a single request to an address takes a long time, + * then the peer is unlikely worthwhile anyway. */ -#define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_UNIT_MINUTES +#define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3) + +/** + * How long will we allow sending of a ping to be delayed? + */ +#define TRANSPORT_DEFAULT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15) + +#define TRANSPORT_DEFAULT_PRIORITY 4 /* Tired of remembering arbitrary priority names */ /** * How often do we re-add (cheaper) plugins to our list of plugins @@ -82,12 +95,6 @@ */ #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12) -/** - * After how long do we consider a connection to a peer dead - * if we don't receive messages from the peer? - */ -#define IDLE_CONNECTION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5) - /** * Entry in linked list of network addresses. @@ -173,11 +180,11 @@ struct TransportPlugin int rebuild; }; -struct NeighbourList; +struct NeighborList; /** - * For each neighbour we keep a list of messages - * that we still want to transmit to the neighbour. + * For each neighbor we keep a list of messages + * that we still want to transmit to the neighbor. */ struct MessageQueue { @@ -200,9 +207,9 @@ struct MessageQueue struct TransportClient *client; /** - * Neighbour this entry belongs to. + * Neighbor this entry belongs to. */ - struct NeighbourList *neighbour; + struct NeighborList *neighbor; /** * Plugin that we used for the transmission. @@ -219,11 +226,16 @@ struct MessageQueue */ int internal_msg; + /** + * How important is the message? + */ + unsigned int priority; + }; /** - * For a given Neighbour, which plugins are available + * For a given Neighbor, which plugins are available * to talk to this peer and what are their costs? */ struct ReadyList @@ -241,15 +253,9 @@ struct ReadyList struct TransportPlugin *plugin; /** - * Neighbour this entry belongs to. - */ - struct NeighbourList *neighbour; - - /** - * Opaque handle (specific to the plugin) for the - * connection to our target; can be NULL. + * Neighbor this entry belongs to. */ - void *plugin_handle; + struct NeighborList *neighbor; /** * What was the last latency observed for this plugin @@ -258,12 +264,11 @@ struct ReadyList struct GNUNET_TIME_Relative latency; /** - * If we did not successfully transmit a message to the - * given peer via this connection during the specified - * time, we should consider the connection to be dead. - * This is used in the case that a TCP transport simply - * stalls writing to the stream but does not formerly - * get a signal that the other peer died. + * If we did not successfully transmit a message to the given peer + * via this connection during the specified time, we should consider + * the connection to be dead. This is used in the case that a TCP + * transport simply stalls writing to the stream but does not + * formerly get a signal that the other peer died. */ struct GNUNET_TIME_Absolute timeout; @@ -287,10 +292,10 @@ struct ReadyList unsigned int connect_attempts; /** - * Is this plugin ready to transmit to the specific - * target? GNUNET_NO if not. Initially, all plugins - * are marked ready. If a transmission is in progress, - * "transmit_ready" is set to GNUNET_NO. + * Is this plugin ready to transmit to the specific target? + * GNUNET_NO if not. Initially, all plugins are marked ready. If a + * transmission is in progress, "transmit_ready" is set to + * GNUNET_NO. */ int transmit_ready; @@ -298,15 +303,15 @@ struct ReadyList /** - * Entry in linked list of all of our current neighbours. + * Entry in linked list of all of our current neighbors. */ -struct NeighbourList +struct NeighborList { /** * This is a linked list. */ - struct NeighbourList *next; + struct NeighborList *next; /** * Which of our transports is connected to this peer @@ -321,10 +326,20 @@ struct NeighbourList struct MessageQueue *messages; /** - * Identity of this neighbour. + * Identity of this neighbor. */ struct GNUNET_PeerIdentity id; + /* + * Opaque addr of this peer, only known to the plugin + */ + char *addr; + + /* + * Size of addr + */ + size_t addr_len; + /** * ID of task scheduled to run when this peer is about to * time out (will free resources associated with the peer). @@ -356,16 +371,10 @@ struct NeighbourList uint64_t last_received; /** - * Global quota for outbound traffic for the neighbour in bytes/ms. + * Global quota for inbound traffic for the neighbor in bytes/ms. */ uint32_t quota_in; - /** - * What is the latest version of our HELLO that we have - * sent to this neighbour? - */ - unsigned int hello_version_sent; - /** * How often has the other peer (recently) violated the * inbound traffic limit? Incremented by 10 per violation, @@ -375,133 +384,150 @@ struct NeighbourList unsigned int quota_violation_count; /** - * Have we seen an ACK from this neighbour in the past? + * Have we seen an ACK from this neighbor in the past? * (used to make up a fake ACK for clients connecting after - * the neighbour connected to us). + * the neighbor connected to us). */ int saw_ack; -}; + /* The latency we have seen for this particular address for + * this particular peer. This latency may have been calculated + * over multiple transports. This value reflects how long it took + * us to receive a response when SENDING via this particular + * transport/neighbor/address combination! + */ + struct GNUNET_TIME_RelativeNBO latency; +}; /** - * Linked list of messages to be transmitted to - * the client. Each entry is followed by the - * actual message. + * Message used to ask a peer to validate receipt (to check an address + * from a HELLO). Followed by the address used. Note that the + * recipients response does not affirm that he has this address, + * only that he got the challenge message. */ -struct ClientMessageQueueEntry +struct TransportPingMessage { + /** - * This is a linked list. + * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING */ - struct ClientMessageQueueEntry *next; + struct GNUNET_MessageHeader header; + + /** + * Random challenge number (in network byte order). + */ + uint32_t challenge GNUNET_PACKED; + + /** + * Who is the intended recipient? + */ + struct GNUNET_PeerIdentity target; + }; /** - * Client connected to the transport service. + * Message used to validate a HELLO. The challenge is included in the + * confirmation to make matching of replies to requests possible. The + * signature signs the original challenge number, our public key, the + * sender's address (so that the sender can check that the address we + * saw is plausible for him and possibly detect a MiM attack) and a + * timestamp (to limit replay).
+ * + * This message is followed by the address of the + * client that we are observing (which is part of what + * is being signed). */ -struct TransportClient +struct TransportPongMessage { /** - * This is a linked list. + * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG */ - struct TransportClient *next; + struct GNUNET_MessageHeader header; /** - * Handle to the client. + * For padding, always zero. */ - struct GNUNET_SERVER_Client *client; + uint32_t reserved GNUNET_PACKED; /** - * Linked list of messages yet to be transmitted to - * the client. + * Signature. */ - struct ClientMessageQueueEntry *message_queue_head; + struct GNUNET_CRYPTO_RsaSignature signature; /** - * Tail of linked list of messages yet to be transmitted to the - * client. + * What are we signing and why? */ - struct ClientMessageQueueEntry *message_queue_tail; + struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; /** - * Is a call to "transmit_send_continuation" pending? If so, we - * must not free this struct (even if the corresponding client - * disconnects) and instead only remove it from the linked list and - * set the "client" field to NULL. + * Random challenge number (in network byte order). */ - int tcs_pending; + uint32_t challenge GNUNET_PACKED; /** - * Length of the list of messages pending for this client. + * Who signed this message? */ - unsigned int message_count; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded signer; }; - /** - * Message used to ask a peer to validate receipt (to check an address - * from a HELLO). Followed by the address used. Note that the - * recipients response does not affirm that he has this address, - * only that he got the challenge message. + * Linked list of messages to be transmitted to + * the client. Each entry is followed by the + * actual message. */ -struct ValidationChallengeMessage +struct ClientMessageQueueEntry { - /** - * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING + * This is a linked list. */ - struct GNUNET_MessageHeader header; + struct ClientMessageQueueEntry *next; +}; - /** - * What are we signing and why? - */ - struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; + +/** + * Client connected to the transport service. + */ +struct TransportClient +{ /** - * Random challenge number (in network byte order). + * This is a linked list. */ - uint32_t challenge GNUNET_PACKED; + struct TransportClient *next; /** - * Who is the intended recipient? + * Handle to the client. */ - struct GNUNET_PeerIdentity target; -}; - - -/** - * Message used to validate a HELLO. If this was - * the right recipient, the response is a signature - * of the original validation request. The - * challenge is included in the confirmation to make - * matching of replies to requests possible. - */ -struct ValidationChallengeResponse -{ + struct GNUNET_SERVER_Client *client; /** - * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG + * Linked list of messages yet to be transmitted to + * the client. */ - struct GNUNET_MessageHeader header; + struct ClientMessageQueueEntry *message_queue_head; /** - * Random challenge number (in network byte order). + * Tail of linked list of messages yet to be transmitted to the + * client. */ - uint32_t challenge GNUNET_PACKED; + struct ClientMessageQueueEntry *message_queue_tail; /** - * Who signed this message? + * Is a call to "transmit_send_continuation" pending? If so, we + * must not free this struct (even if the corresponding client + * disconnects) and instead only remove it from the linked list and + * set the "client" field to NULL. */ - struct GNUNET_PeerIdentity sender; + int tcs_pending; /** - * Signature. + * Length of the list of messages pending for this client. */ - struct GNUNET_CRYPTO_RsaSignature signature; + unsigned int message_count; }; @@ -517,12 +543,6 @@ struct ValidationAddress */ struct ValidationAddress *next; - /** - * Our challenge message. Points to after this - * struct, so this field should not be freed. - */ - struct ValidationChallengeMessage *msg; - /** * Name of the transport. */ @@ -538,6 +558,11 @@ struct ValidationAddress */ size_t addr_len; + /** + * Challenge number we used. + */ + uint32_t challenge; + /** * Set to GNUNET_YES if the challenge was met, * GNUNET_SYSERR if we know it failed, GNUNET_NO @@ -590,7 +615,7 @@ static struct GNUNET_HELLO_Message *our_hello; /** * "version" of "our_hello". Used to see if a given - * neighbour has already been sent the latest version + * neighbor has already been sent the latest version * of our HELLO message. */ static unsigned int our_hello_version; @@ -618,7 +643,7 @@ struct GNUNET_SCHEDULER_Handle *sched; /** * Our configuration. */ -struct GNUNET_CONFIGURATION_Handle *cfg; +const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Linked list of all clients to this service. @@ -636,38 +661,43 @@ static struct TransportPlugin *plugins; static struct GNUNET_SERVER_Handle *server; /** - * All known neighbours and their HELLOs. - */ -static struct NeighbourList *neighbours; - -/** - * Default bandwidth quota for receiving for new peers in bytes/ms. - */ -static uint32_t default_quota_in; - -/** - * Default bandwidth quota for sending for new peers in bytes/ms. + * All known neighbors and their HELLOs. */ -static uint32_t default_quota_out; +static struct NeighborList *neighbors; /** - * Number of neighbours we'd like to have. + * Number of neighbors we'd like to have. */ static uint32_t max_connect_per_transport; /** - * Find an entry in the neighbour list for a particular peer. + * Find an entry in the neighbor list for a particular peer. + * if sender_address is not specified (NULL) then return the + * first matching entry. If sender_address is specified, then + * make sure that the address and address_len also matches. * * @return NULL if not found. */ -static struct NeighbourList * -find_neighbour (const struct GNUNET_PeerIdentity *key) +static struct NeighborList * +find_neighbor (const struct GNUNET_PeerIdentity *key, const char *sender_address, + size_t sender_address_len) { - struct NeighbourList *head = neighbours; - while ((head != NULL) && - (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity)))) - head = head->next; + struct NeighborList *head = neighbors; + if (sender_address == NULL) + { + while ((head != NULL) && + (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity)))) + head = head->next; + } + else + { + while ((head != NULL) && + (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))) && + (sender_address_len != head->addr_len) && + (0 != memcmp (sender_address, &head->addr, head->addr_len))) + head = head->next; + } return head; } @@ -688,10 +718,10 @@ find_transport (const char *short_name) /** - * Update the quota values for the given neighbour now. + * Update the quota values for the given neighbor now. */ static void -update_quota (struct NeighbourList *n) +update_quota (struct NeighborList *n) { struct GNUNET_TIME_Relative delta; uint64_t allowed; @@ -748,13 +778,13 @@ transmit_to_client_callback (void *cls, size_t size, void *buf) uint16_t msize; size_t tsize; const struct GNUNET_MessageHeader *msg; - struct GNUNET_NETWORK_TransmitHandle *th; + struct GNUNET_CONNECTION_TransmitHandle *th; char *cbuf; if (buf == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Transmission to client failed, closing connection.\n"); + "Transmission to client failed, closing connection.\n"); /* fatal error with client, free message queue! */ while (NULL != (q = client->message_queue_head)) { @@ -773,6 +803,11 @@ transmit_to_client_callback (void *cls, size_t size, void *buf) msize = ntohs (msg->size); if (msize + tsize > size) break; +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Transmitting message of type %u to client.\n", + ntohs (msg->type)); +#endif client->message_queue_head = q->next; if (q->next == NULL) client->message_queue_tail = NULL; @@ -781,9 +816,9 @@ transmit_to_client_callback (void *cls, size_t size, void *buf) GNUNET_free (q); client->message_count--; } - GNUNET_assert (tsize > 0); if (NULL != q) { + GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader)); th = GNUNET_SERVER_notify_transmit_ready (client->client, msize, GNUNET_TIME_UNIT_FOREVER_REL, @@ -811,7 +846,7 @@ transmit_to_client (struct TransportClient *client, { struct ClientMessageQueueEntry *q; uint16_t msize; - struct GNUNET_NETWORK_TransmitHandle *th; + struct GNUNET_CONNECTION_TransmitHandle *th; if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop)) { @@ -824,6 +859,7 @@ transmit_to_client (struct TransportClient *client, } client->message_count++; msize = ntohs (msg->size); + GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader)); q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize); memcpy (&q[1], msg, msize); /* append to message queue */ @@ -852,22 +888,22 @@ transmit_to_client (struct TransportClient *client, /** * Find alternative plugins for communication. * - * @param neighbour for which neighbour should we try to find + * @param neighbor for which neighbor should we try to find * more plugins? */ static void -try_alternative_plugins (struct NeighbourList *neighbour) +try_alternative_plugins (struct NeighborList *neighbor) { struct ReadyList *rl; - if ((neighbour->plugins != NULL) && - (neighbour->retry_plugins_time.value > + if ((neighbor->plugins != NULL) && + (neighbor->retry_plugins_time.value > GNUNET_TIME_absolute_get ().value)) return; /* don't try right now */ - neighbour->retry_plugins_time + neighbor->retry_plugins_time = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY); - rl = neighbour->plugins; + rl = neighbor->plugins; while (rl != NULL) { if (rl->connect_attempts > 0) @@ -879,13 +915,29 @@ try_alternative_plugins (struct NeighbourList *neighbour) /** - * Check the ready list for the given neighbour and + * The peer specified by the given neighbor has timed-out or a plugin + * has disconnected. We may either need to do nothing (other plugins + * still up), or trigger a full disconnect and clean up. This + * function updates our state and do the necessary notifications. + * Also notifies our clients that the neighbor is now officially + * gone. + * + * @param n the neighbor list entry for the peer + * @param check should we just check if all plugins + * disconnected or must we ask all plugins to + * disconnect? + */ +static void disconnect_neighbor (struct NeighborList *n, int check); + + +/** + * Check the ready list for the given neighbor and * if a plugin is ready for transmission (and if we * have a message), do so! * - * @param neighbour target peer for which to check the plugins + * @param neighbor target peer for which to check the plugins */ -static void try_transmission_to_peer (struct NeighbourList *neighbour); +static void try_transmission_to_peer (struct NeighborList *neighbor); /** @@ -897,9 +949,6 @@ static void try_transmission_to_peer (struct NeighbourList *neighbour); * @param cls closure, identifies the entry on the * message queue that was transmitted and the * client responsible for queueing the message - * @param rl identifies plugin used for the transmission for - * this neighbour; needs to be re-enabled for - * future transmissions * @param target the peer receiving the message * @param result GNUNET_OK on success, if the transmission * failed, we should not tell the client to transmit @@ -907,41 +956,44 @@ static void try_transmission_to_peer (struct NeighbourList *neighbour); */ static void transmit_send_continuation (void *cls, - struct ReadyList *rl, const struct GNUNET_PeerIdentity *target, int result) { struct MessageQueue *mq = cls; + struct ReadyList *rl; struct SendOkMessage send_ok_msg; - struct NeighbourList *n; + struct NeighborList *n; GNUNET_assert (mq != NULL); - n = mq->neighbour; + n = mq->neighbor; GNUNET_assert (n != NULL); GNUNET_assert (0 == memcmp (&n->id, target, sizeof (struct GNUNET_PeerIdentity))); - if (rl == NULL) - { - rl = n->plugins; - while ((rl != NULL) && (rl->plugin != mq->plugin)) - rl = rl->next; - GNUNET_assert (rl != NULL); - } + rl = n->plugins; + while ((rl != NULL) && (rl->plugin != mq->plugin)) + rl = rl->next; + GNUNET_assert (rl != NULL); if (result == GNUNET_OK) { - rl->timeout = GNUNET_TIME_relative_to_absolute (IDLE_CONNECTION_TIMEOUT); + rl->timeout = + GNUNET_TIME_relative_to_absolute + (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Transmission failed, marking connection as down.\n"); + "Transmission to peer `%s' failed, marking connection as down.\n", + GNUNET_i2s (target)); rl->connected = GNUNET_NO; } if (!mq->internal_msg) rl->transmit_ready = GNUNET_YES; if (mq->client != NULL) { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Notifying client %p about failed transission to peer `%4s'.\n", + mq->client, GNUNET_i2s (target)); send_ok_msg.header.size = htons (sizeof (send_ok_msg)); send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK); send_ok_msg.success = htonl (result); @@ -952,125 +1004,20 @@ transmit_send_continuation (void *cls, GNUNET_free (mq); /* one plugin just became ready again, try transmitting another message (if available) */ - try_transmission_to_peer (n); -} - - - - -/** - * We could not use an existing (or validated) connection to - * talk to a peer. Try addresses that have not yet been - * validated. - * - * @param n neighbour we want to communicate with - * @return plugin ready to talk, or NULL if none is available - */ -static struct ReadyList * -try_unvalidated_addresses (struct NeighbourList *n) -{ - struct ValidationList *vl; - struct ValidationAddress *va; - struct GNUNET_PeerIdentity id; - struct GNUNET_TIME_Absolute now; - unsigned int total; - unsigned int cnt; - struct ReadyList *rl; - struct TransportPlugin *plugin; - -#if DEBUG_TRANSPORT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Trying to connect to `%4s' using unvalidated addresses\n", - GNUNET_i2s (&n->id)); -#endif - /* NOTE: this function needs to not only identify the - plugin but also setup "plugin_handle", binding it to the - right address using the plugin's "send_to" API */ - now = GNUNET_TIME_absolute_get (); - vl = pending_validations; - while (vl != NULL) - { - GNUNET_CRYPTO_hash (&vl->publicKey, - sizeof (struct - GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - &id.hashPubKey); - if (0 == memcmp (&id, &n->id, sizeof (struct GNUNET_PeerIdentity))) - break; - vl = vl->next; - } - if (vl == NULL) - { -#if DEBUG_TRANSPORT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "No unvalidated address found for peer `%4s'\n", - GNUNET_i2s (&n->id)); -#endif - return NULL; - } - total = 0; - cnt = 0; - va = vl->addresses; - while (va != NULL) - { - cnt++; - if (va->expiration.value > now.value) - total++; - va = va->next; - } - if (total == 0) - { -#if DEBUG_TRANSPORT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "All %u unvalidated addresses for peer have expired\n", - cnt); -#endif - return NULL; - } - total = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, total); - for (va = vl->addresses; va != NULL; va = va->next) - { - if (va->expiration.value <= now.value) - continue; - if (total > 0) - { - total--; - continue; - } -#if DEBUG_TRANSPORT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, - "Trying unvalidated address of `%s' transport\n", - va->transport_name); -#endif - plugin = find_transport (va->transport_name); - if (plugin == NULL) - { - GNUNET_break (0); - break; - } - rl = GNUNET_malloc (sizeof (struct ReadyList)); - rl->next = n->plugins; - n->plugins = rl; - rl->plugin = plugin; - rl->plugin_handle = plugin->api->send_to (plugin->api->cls, - &n->id, - NULL, - NULL, - GNUNET_TIME_UNIT_ZERO, - &va->msg[1], va->addr_len); - rl->transmit_ready = GNUNET_YES; - return rl; - } - return NULL; + if (result == GNUNET_OK) + try_transmission_to_peer (n); + else + disconnect_neighbor (n, GNUNET_YES); } /** - * Check the ready list for the given neighbour and + * Check the ready list for the given neighbor and * if a plugin is ready for transmission (and if we * have a message), do so! */ static void -try_transmission_to_peer (struct NeighbourList *neighbour) +try_transmission_to_peer (struct NeighborList *neighbor) { struct ReadyList *pos; struct GNUNET_TIME_Relative min_latency; @@ -1078,14 +1025,14 @@ try_transmission_to_peer (struct NeighbourList *neighbour) struct MessageQueue *mq; struct GNUNET_TIME_Absolute now; - if (neighbour->messages == NULL) + if (neighbor->messages == NULL) return; /* nothing to do */ - try_alternative_plugins (neighbour); + try_alternative_plugins (neighbor); min_latency = GNUNET_TIME_UNIT_FOREVER_REL; rl = NULL; - mq = neighbour->messages; + mq = neighbor->messages; now = GNUNET_TIME_absolute_get (); - pos = neighbour->plugins; + pos = neighbor->plugins; while (pos != NULL) { /* set plugins that are inactive for a long time back to disconnected */ @@ -1094,7 +1041,7 @@ try_transmission_to_peer (struct NeighbourList *neighbour) #if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Marking long-time inactive connection to `%4s' as down.\n", - GNUNET_i2s (&neighbour->id)); + GNUNET_i2s (&neighbor->id)); #endif pos->connected = GNUNET_NO; } @@ -1108,8 +1055,6 @@ try_transmission_to_peer (struct NeighbourList *neighbour) } pos = pos->next; } - if (rl == NULL) - rl = try_unvalidated_addresses (neighbour); if (rl == NULL) { #if DEBUG_TRANSPORT @@ -1122,8 +1067,13 @@ try_transmission_to_peer (struct NeighbourList *neighbour) { rl->connect_attempts++; rl->connected = GNUNET_YES; +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Establishing fresh connection with `%4s' via plugin `%s'\n", + GNUNET_i2s (&neighbor->id), rl->plugin->short_name); +#endif } - neighbour->messages = mq->next; + neighbor->messages = mq->next; mq->plugin = rl->plugin; if (!mq->internal_msg) rl->transmit_ready = GNUNET_NO; @@ -1131,16 +1081,18 @@ try_transmission_to_peer (struct NeighbourList *neighbour) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Giving message of type `%u' for `%4s' to plugin `%s'\n", ntohs (mq->message->type), - GNUNET_i2s (&neighbour->id), rl->plugin->short_name); + GNUNET_i2s (&neighbor->id), rl->plugin->short_name); #endif - rl->plugin_handle - = rl->plugin->api->send (rl->plugin->api->cls, - rl->plugin_handle, - rl, - &neighbour->id, - mq->message, - IDLE_CONNECTION_TIMEOUT, - &transmit_send_continuation, mq); + + rl->plugin->api->send (rl->plugin->api->cls, + &neighbor->id, + mq->message, + mq->priority, + GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, + rl->neighbor->addr, + rl->neighbor->addr_len, + GNUNET_NO, + &transmit_send_continuation, mq); } @@ -1148,14 +1100,16 @@ try_transmission_to_peer (struct NeighbourList *neighbour) * Send the specified message to the specified peer. * * @param client source of the transmission request (can be NULL) + * @param priority how important is the message * @param msg message to send * @param is_internal is this an internal message - * @param neighbour handle to the neighbour for transmission + * @param neighbor handle to the neighbor for transmission */ static void transmit_to_peer (struct TransportClient *client, + unsigned int priority, const struct GNUNET_MessageHeader *msg, - int is_internal, struct NeighbourList *neighbour) + int is_internal, struct NeighborList *neighbor) { struct MessageQueue *mq; struct MessageQueue *mqe; @@ -1164,12 +1118,12 @@ transmit_to_peer (struct TransportClient *client, #if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Sending message of type %u to peer `%4s'\n"), - ntohs (msg->type), GNUNET_i2s (&neighbour->id)); + ntohs (msg->type), GNUNET_i2s (&neighbor->id)); #endif if (client != NULL) { /* check for duplicate submission */ - mq = neighbour->messages; + mq = neighbor->messages; while (NULL != mq) { if (mq->client == client) @@ -1187,19 +1141,20 @@ transmit_to_peer (struct TransportClient *client, m = GNUNET_malloc (ntohs (msg->size)); memcpy (m, msg, ntohs (msg->size)); mq->message = m; - mq->neighbour = neighbour; + mq->neighbor = neighbor; mq->internal_msg = is_internal; + mq->priority = priority; /* find tail */ - mqe = neighbour->messages; + mqe = neighbor->messages; if (mqe != NULL) while (mqe->next != NULL) mqe = mqe->next; if (mqe == NULL) { /* new head */ - neighbour->messages = mq; - try_transmission_to_peer (neighbour); + neighbor->messages = mq; + try_transmission_to_peer (neighbor); } else { @@ -1209,6 +1164,9 @@ transmit_to_peer (struct TransportClient *client, } +/** + * FIXME: document. + */ struct GeneratorContext { struct TransportPlugin *plug_pos; @@ -1217,6 +1175,9 @@ struct GeneratorContext }; +/** + * FIXME: document. + */ static size_t address_generator (void *cls, size_t max, void *buf) { @@ -1248,12 +1209,12 @@ refresh_hello () { struct GNUNET_HELLO_Message *hello; struct TransportClient *cpos; - struct NeighbourList *npos; + struct NeighborList *npos; struct GeneratorContext gc; #if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, - "Refreshing my HELLO\n"); + "Refreshing my `%s'\n", "HELLO"); #endif gc.plug_pos = plugins; gc.addr_pos = plugins != NULL ? plugins->addresses : NULL; @@ -1271,10 +1232,16 @@ refresh_hello () GNUNET_free_non_null (our_hello); our_hello = hello; our_hello_version++; - npos = neighbours; + GNUNET_PEERINFO_add_peer (cfg, sched, &my_identity, our_hello); + npos = neighbors; while (npos != NULL) { - transmit_to_peer (NULL, +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, + "Transmitting updated `%s' to neighbor `%4s'\n", + "HELLO", GNUNET_i2s (&npos->id)); +#endif + transmit_to_peer (NULL, 0, (const struct GNUNET_MessageHeader *) our_hello, GNUNET_YES, npos); npos = npos->next; @@ -1313,9 +1280,9 @@ update_addresses (struct TransportPlugin *plugin, int fresh) struct AddressList *next; int expired; - if (plugin->address_update_task != GNUNET_SCHEDULER_NO_PREREQUISITE_TASK) + if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (plugin->env.sched, plugin->address_update_task); - plugin->address_update_task = GNUNET_SCHEDULER_NO_PREREQUISITE_TASK; + plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK; now = GNUNET_TIME_absolute_get (); min_remaining = GNUNET_TIME_UNIT_FOREVER_REL; expired = GNUNET_NO; @@ -1348,9 +1315,6 @@ update_addresses (struct TransportPlugin *plugin, int fresh) if (min_remaining.value < GNUNET_TIME_UNIT_FOREVER_REL.value) plugin->address_update_task = GNUNET_SCHEDULER_add_delayed (plugin->env.sched, - GNUNET_NO, - GNUNET_SCHEDULER_PRIORITY_IDLE, - GNUNET_SCHEDULER_NO_PREREQUISITE_TASK, min_remaining, &expire_address_task, plugin); @@ -1367,7 +1331,7 @@ static void expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct TransportPlugin *plugin = cls; - plugin->address_update_task = GNUNET_SCHEDULER_NO_PREREQUISITE_TASK; + plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK; update_addresses (plugin, GNUNET_NO); } @@ -1395,11 +1359,6 @@ plugin_env_notify_address (void *cls, struct AddressList *al; struct GNUNET_TIME_Absolute abex; -#if DEBUG_TRANSPORT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Plugin `%s' informs us about a new address `%s'\n", name, - GNUNET_a2s(addr, addrlen)); -#endif abex = GNUNET_TIME_relative_to_absolute (expires); GNUNET_assert (p == find_transport (name)); @@ -1414,6 +1373,11 @@ plugin_env_notify_address (void *cls, } al = al->next; } +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Plugin `%s' informs us about a new address `%s'\n", name, + GNUNET_a2s (addr, addrlen)); +#endif al = GNUNET_malloc (sizeof (struct AddressList) + addrlen); al->addr = &al[1]; al->next = p->addresses; @@ -1425,83 +1389,15 @@ plugin_env_notify_address (void *cls, } -struct LookupHelloContext -{ - GNUNET_TRANSPORT_AddressCallback iterator; - - void *iterator_cls; -}; - - -static int -lookup_address_callback (void *cls, - const char *tname, - struct GNUNET_TIME_Absolute expiration, - const void *addr, size_t addrlen) +/** + * Notify all of our clients about a peer connecting. + */ +static void +notify_clients_connect (const struct GNUNET_PeerIdentity *peer, + struct GNUNET_TIME_Relative latency) { - struct LookupHelloContext *lhc = cls; - lhc->iterator (lhc->iterator_cls, tname, addr, addrlen); - return GNUNET_OK; -} - - -static void -lookup_hello_callback (void *cls, - const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_HELLO_Message *h, uint32_t trust) -{ - struct LookupHelloContext *lhc = cls; - - if (peer == NULL) - { - lhc->iterator (lhc->iterator_cls, NULL, NULL, 0); - GNUNET_free (lhc); - return; - } - if (h == NULL) - return; - GNUNET_HELLO_iterate_addresses (h, - GNUNET_NO, &lookup_address_callback, lhc); -} - - -/** - * Function that allows a transport to query the known - * network addresses for a given peer. - * - * @param cls closure - * @param timeout after how long should we time out? - * @param target which peer are we looking for? - * @param iter function to call for each known address - * @param iter_cls closure for iter - */ -static void -plugin_env_lookup_address (void *cls, - struct GNUNET_TIME_Relative timeout, - const struct GNUNET_PeerIdentity *target, - GNUNET_TRANSPORT_AddressCallback iter, - void *iter_cls) -{ - struct LookupHelloContext *lhc; - - lhc = GNUNET_malloc (sizeof (struct LookupHelloContext)); - lhc->iterator = iter; - lhc->iterator_cls = iter_cls; - GNUNET_PEERINFO_for_all (cfg, - sched, - target, 0, timeout, &lookup_hello_callback, &lhc); -} - - -/** - * Notify all of our clients about a peer connecting. - */ -static void -notify_clients_connect (const struct GNUNET_PeerIdentity *peer, - struct GNUNET_TIME_Relative latency) -{ - struct ConnectInfoMessage cim; - struct TransportClient *cpos; + struct ConnectInfoMessage cim; + struct TransportClient *cpos; #if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, @@ -1510,7 +1406,7 @@ notify_clients_connect (const struct GNUNET_PeerIdentity *peer, #endif cim.header.size = htons (sizeof (struct ConnectInfoMessage)); cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT); - cim.quota_out = htonl (default_quota_out); + cim.quota_out = htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000)); cim.latency = GNUNET_TIME_relative_hton (latency); memcpy (&cim.id, peer, sizeof (struct GNUNET_PeerIdentity)); cpos = clients; @@ -1567,7 +1463,7 @@ list_validated_addresses (void *cls, size_t max, void *buf) return 0; ret = GNUNET_HELLO_add_address ((*va)->transport_name, (*va)->expiration, - &(*va)->msg[1], (*va)->addr_len, buf, max); + &(*va)[1], (*va)->addr_len, buf, max); *va = (*va)->next; return ret; } @@ -1583,8 +1479,10 @@ cleanup_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) struct ValidationList *pos; struct ValidationList *prev; struct GNUNET_TIME_Absolute now; + struct GNUNET_TIME_Absolute first; struct GNUNET_HELLO_Message *hello; struct GNUNET_PeerIdentity pid; + struct NeighborList *n; #if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, @@ -1614,6 +1512,9 @@ cleanup_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) "HELLO", GNUNET_i2s (&pid)); #endif GNUNET_PEERINFO_add_peer (cfg, sched, &pid, hello); + n = find_neighbor (&pid, NULL, 0); + if (NULL != n) + try_transmission_to_peer (n); GNUNET_free (hello); while (NULL != (va = pos->addresses)) { @@ -1627,23 +1528,148 @@ cleanup_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) else pos = prev->next; continue; - } + } prev = pos; pos = pos->next; } /* finally, reschedule cleanup if needed; list is ordered by timeout, so we need the last element... */ + if (NULL != pending_validations) + { + first = pending_validations->timeout; + pos = pending_validations; + while (pos != NULL) + { + first = GNUNET_TIME_absolute_min (first, pos->timeout); + pos = pos->next; + } + GNUNET_SCHEDULER_add_delayed (sched, + GNUNET_TIME_absolute_get_remaining + (first), &cleanup_validation, NULL); + } +} + + +static struct GNUNET_MessageHeader * +createPingMessage (struct GNUNET_PeerIdentity * target, struct ValidationAddress *va) +{ + + struct TransportPingMessage *ping; + ping = GNUNET_malloc(sizeof(struct TransportPingMessage)); + + ping->challenge = htonl(va->challenge); + ping->header.size = sizeof(struct TransportPingMessage); + ping->header.type = GNUNET_MESSAGE_TYPE_TRANSPORT_PING; + memcpy(&ping->target, target, sizeof(struct GNUNET_PeerIdentity)); + + return &ping->header; +} + +/** + * Function that will be called if we receive a validation + * of an address challenge that we transmitted to another + * peer. Note that the validation should only be considered + * acceptable if the challenge matches AND if the sender + * address is at least a plausible address for this peer + * (otherwise we may be seeing a MiM attack). + * + * @param cls closure + * @param name name of the transport that generated the address + * @param peer who responded to our challenge + * @param challenge the challenge number we presumably used + * @param sender_addr string describing our sender address (as observed + * by the other peer in human-readable format) + */ +static void +handle_pong (void *cls, const struct GNUNET_MessageHeader *message, + const struct GNUNET_PeerIdentity *peer, + const char *sender_address, + size_t sender_address_len) +{ + unsigned int not_done; + int matched; + struct ValidationList *pos; + struct ValidationAddress *va; + struct GNUNET_PeerIdentity id; + struct TransportPongMessage *pong = (struct TransportPongMessage *)message; + + unsigned int challenge = ntohl(pong->challenge); pos = pending_validations; - while ((pos != NULL) && (pos->next != NULL)) - pos = pos->next; - if (NULL != pos) - GNUNET_SCHEDULER_add_delayed (sched, - GNUNET_NO, - GNUNET_SCHEDULER_PRIORITY_IDLE, - GNUNET_SCHEDULER_NO_PREREQUISITE_TASK, - GNUNET_TIME_absolute_get_remaining - (pos->timeout), &cleanup_validation, NULL); + while (pos != NULL) + { + GNUNET_CRYPTO_hash (&pos->publicKey, + sizeof (struct + GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &id.hashPubKey); + if (0 == memcmp (peer, &id, sizeof (struct GNUNET_PeerIdentity))) + break; + pos = pos->next; + } + if (pos == NULL) + { + /* TODO: call statistics (unmatched PONG) */ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _ + ("Received validation response but have no record of any validation request for `%4s'. Ignoring.\n"), + GNUNET_i2s (peer)); + return; + } + not_done = 0; + matched = GNUNET_NO; + va = pos->addresses; + while (va != NULL) + { + if (va->challenge == challenge) + { +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Confirmed validity of address, peer `%4s' has address `%s'.\n", + GNUNET_i2s (peer), + GNUNET_a2s ((const struct sockaddr *) &va[1], + va->addr_len)); +#endif + GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK, + _ + ("Another peer saw us using the address `%s' via `FIXME'. If this is not plausible, this address should be listed in the configuration as implausible to avoid MiM attacks.\n"), + sender_address); + va->ok = GNUNET_YES; + va->expiration = + GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION); + matched = GNUNET_YES; + } + if (va->ok != GNUNET_YES) + not_done++; + va = va->next; + } + if (GNUNET_NO == matched) + { + /* TODO: call statistics (unmatched PONG) */ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _ + ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"), + "PONG", "PING"); + } + if (0 == not_done) + { +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All addresses validated, will now construct `%s' for `%4s'.\n", + "HELLO", GNUNET_i2s (peer)); +#endif + pos->timeout.value = 0; + GNUNET_SCHEDULER_add_with_priority (sched, + GNUNET_SCHEDULER_PRIORITY_IDLE, + &cleanup_validation, NULL); + } + else + { +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Still waiting for %u additional `%s' messages before constructing `%s' for `%4s'.\n", + not_done, "PONG", "HELLO", GNUNET_i2s (peer)); +#endif + } } @@ -1664,6 +1690,12 @@ struct CheckHelloValidatedContext */ struct ValidationList *e; + /** + * Context for peerinfo iteration. + * NULL after we are done processing peerinfo's information. + */ + struct GNUNET_PEERINFO_IteratorContext *piter; + }; @@ -1680,9 +1712,8 @@ run_validation (void *cls, struct ValidationList *e = cls; struct TransportPlugin *tp; struct ValidationAddress *va; - struct ValidationChallengeMessage *vcm; struct GNUNET_PeerIdentity id; - + struct GNUNET_MessageHeader *pingMessage; tp = find_transport (tname); if (tp == NULL) { @@ -1694,37 +1725,58 @@ run_validation (void *cls, return GNUNET_OK; } GNUNET_CRYPTO_hash (&e->publicKey, - sizeof (struct - GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - &id.hashPubKey); + sizeof (struct + GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &id.hashPubKey); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Scheduling validation of address `%s' via `%s' for `%4s'\n", - GNUNET_a2s(addr, addrlen), - tname, - GNUNET_i2s(&id)); + "Scheduling validation of address `%s' via `%s' for `%4s'\n", + GNUNET_a2s (addr, addrlen), tname, GNUNET_i2s (&id)); - va = GNUNET_malloc (sizeof (struct ValidationAddress) + - sizeof (struct ValidationChallengeMessage) + addrlen); + va = GNUNET_malloc (sizeof (struct ValidationAddress) + addrlen); va->next = e->addresses; e->addresses = va; - vcm = (struct ValidationChallengeMessage *) &va[1]; - va->msg = vcm; va->transport_name = GNUNET_strdup (tname); va->addr_len = addrlen; - vcm->header.size = - htons (sizeof (struct ValidationChallengeMessage) + addrlen); - vcm->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PING); - vcm->purpose.size = - htonl (sizeof (struct ValidationChallengeMessage) + addrlen - - sizeof (struct GNUNET_MessageHeader)); - vcm->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO); - vcm->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, - (unsigned int) -1); - vcm->target = id; - memcpy (&vcm[1], addr, addrlen); + va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, + (unsigned int) -1); + memcpy (&va[1], addr, addrlen); + + pingMessage = createPingMessage(&id, va); + + tp->api->send(tp->api->cls, &id, pingMessage, GNUNET_SCHEDULER_PRIORITY_DEFAULT, + TRANSPORT_DEFAULT_TIMEOUT, addr, addrlen, GNUNET_YES, NULL, NULL); + + GNUNET_free(pingMessage); + return GNUNET_OK; } +/* + * @param cls handle to the plugin (for sending) + * @param target the peer identity of the peer we are sending to + * @param challenge the challenge number + * @param timeout how long to await validation? + * @param addr the address to validate + * @param addrlen the length of the address + * + * Perform address validation, which means sending a PING PONG to + * the address via the transport plugin. If not validated, then + * do not count this as a good peer/address... + * + */ +static void +validate_address (void *cls, struct ValidationAddress *va, + const struct GNUNET_PeerIdentity *target, + struct GNUNET_TIME_Relative timeout, + const void *addr, size_t addrlen) +{ + /* struct Plugin *plugin = cls; + int challenge = va->challenge; */ + + + return; +} + /** * Check if addresses in validated hello "h" overlap with @@ -1740,10 +1792,12 @@ check_hello_validated (void *cls, struct ValidationAddress *va; struct TransportPlugin *tp; int first_call; + struct GNUNET_PeerIdentity apeer; first_call = GNUNET_NO; if (chvc->e == NULL) { + chvc->piter = NULL; first_call = GNUNET_YES; chvc->e = GNUNET_malloc (sizeof (struct ValidationList)); GNUNET_assert (GNUNET_OK == @@ -1770,35 +1824,36 @@ check_hello_validated (void *cls, if (h != NULL) return; /* wait for next call */ /* finally, transmit validation attempts */ + GNUNET_assert (GNUNET_OK == GNUNET_HELLO_get_id (chvc->hello, &apeer)); +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Ready to validate addresses from `%s' message for peer `%4s'\n", + "HELLO", GNUNET_i2s (&apeer)); +#endif va = chvc->e->addresses; while (va != NULL) { #if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Establishing `%s' connection to validate `%s' of `%4s' (sending our `%s')\n", + "Establishing `%s' connection to validate `%s' address `%s' of `%4s'\n", va->transport_name, - "HELLO", GNUNET_i2s (&va->msg->target), "HELLO"); + "HELLO", + GNUNET_a2s ((const struct sockaddr *) &va[1], + va->addr_len), GNUNET_i2s (&apeer)); #endif tp = find_transport (va->transport_name); GNUNET_assert (tp != NULL); - if (NULL == - tp->api->send_to (tp->api->cls, - &va->msg->target, - (const struct GNUNET_MessageHeader *) our_hello, - &va->msg->header, - HELLO_VERIFICATION_TIMEOUT, - &va->msg[1], va->addr_len)) - va->ok = GNUNET_SYSERR; + /* This validation should happen inside the transport, not from the plugin! */ + validate_address (tp->api->cls, va, &apeer, + HELLO_VERIFICATION_TIMEOUT, + &va[1], va->addr_len); + /* va->ok = GNUNET_SYSERR; will be set by validate_address! */ va = va->next; } - if (chvc->e->next == NULL) - GNUNET_SCHEDULER_add_delayed (sched, - GNUNET_NO, - GNUNET_SCHEDULER_PRIORITY_IDLE, - GNUNET_SCHEDULER_NO_PREREQUISITE_TASK, - GNUNET_TIME_absolute_get_remaining - (chvc->e->timeout), &cleanup_validation, - NULL); + GNUNET_SCHEDULER_add_delayed (sched, + GNUNET_TIME_absolute_get_remaining (chvc-> + e->timeout), + &cleanup_validation, NULL); GNUNET_free (chvc); } @@ -1859,10 +1914,10 @@ process_hello (struct TransportPlugin *plugin, { /* TODO: call to stats? */ #if DEBUG_TRANSPORT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "`%s' message for peer `%4s' is already pending; ignoring new message\n", - "HELLO", GNUNET_i2s (&target)); -#endif + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "`%s' message for peer `%4s' is already pending; ignoring new message\n", + "HELLO", GNUNET_i2s (&target)); +#endif return GNUNET_OK; } e = e->next; @@ -1873,219 +1928,55 @@ process_hello (struct TransportPlugin *plugin, memcpy (chvc->hello, hello, hsize); /* finally, check if HELLO was previously validated (continuation will then schedule actual validation) */ - GNUNET_PEERINFO_for_all (cfg, - sched, - &target, - 0, - HELLO_VERIFICATION_TIMEOUT, - &check_hello_validated, chvc); + chvc->piter = GNUNET_PEERINFO_iterate (cfg, + sched, + &target, + 0, + HELLO_VERIFICATION_TIMEOUT, + &check_hello_validated, chvc); return GNUNET_OK; } /** - * Handle PING-message. If the plugin that gave us the message is - * able to queue the PONG immediately, we only queue one PONG. - * Otherwise we send at most TWO PONG messages, one via an unconfirmed - * transport and one via a confirmed transport. Both addresses are - * selected randomly among those available. + * The peer specified by the given neighbor has timed-out or a plugin + * has disconnected. We may either need to do nothing (other plugins + * still up), or trigger a full disconnect and clean up. This + * function updates our state and do the necessary notifications. + * Also notifies our clients that the neighbor is now officially + * gone. * - * @param plugin plugin that gave us the message - * @param sender claimed sender of the PING - * @param plugin_context context that might be used to send response - * @param message the actual message + * @param n the neighbor list entry for the peer + * @param check should we just check if all plugins + * disconnected or must we ask all plugins to + * disconnect? */ static void -process_ping (struct TransportPlugin *plugin, - const struct GNUNET_PeerIdentity *sender, - void *plugin_context, - const struct GNUNET_MessageHeader *message) +disconnect_neighbor (struct NeighborList *n, int check) { - const struct ValidationChallengeMessage *vcm; - struct ValidationChallengeResponse vcr; - uint16_t msize; - struct NeighbourList *n; - -#if DEBUG_TRANSPORT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, - "Processing PING\n"); -#endif - msize = ntohs (message->size); - if (msize < sizeof (struct ValidationChallengeMessage)) - { - GNUNET_break_op (0); - return; - } - vcm = (const struct ValidationChallengeMessage *) message; - if (0 != memcmp (&vcm->target, - &my_identity, sizeof (struct GNUNET_PeerIdentity))) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("Received `%s' message not destined for me!\n"), "PING"); - /* TODO: call statistics */ - return; - } - if ((ntohl (vcm->purpose.size) != - msize - sizeof (struct GNUNET_MessageHeader)) - || (ntohl (vcm->purpose.purpose) != - GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO)) - { - GNUNET_break_op (0); - return; - } - msize -= sizeof (struct ValidationChallengeMessage); - if (GNUNET_OK != - plugin->api->address_suggested (plugin->api->cls, &vcm[1], msize)) - { - GNUNET_break_op (0); - return; - } - vcr.header.size = htons (sizeof (struct ValidationChallengeResponse)); - vcr.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG); - vcr.challenge = vcm->challenge; - vcr.sender = my_identity; - GNUNET_assert (GNUNET_OK == - GNUNET_CRYPTO_rsa_sign (my_private_key, - &vcm->purpose, &vcr.signature)); -#if EXTRA_CHECKS - GNUNET_assert (GNUNET_OK == - GNUNET_CRYPTO_rsa_verify - (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO, &vcm->purpose, - &vcr.signature, &my_public_key)); -#endif -#if DEBUG_TRANSPORT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, - "Trying to transmit PONG using inbound connection\n"); -#endif - n = find_neighbour (sender); - if (n == NULL) - { - GNUNET_break (0); - return; - } - transmit_to_peer (NULL, &vcr.header, GNUNET_YES, n); -} - - -/** - * Handle PONG-message. - * - * @param message the actual message - */ -static void -process_pong (struct TransportPlugin *plugin, - const struct GNUNET_MessageHeader *message) -{ - const struct ValidationChallengeResponse *vcr; - struct ValidationList *pos; - struct GNUNET_PeerIdentity peer; - struct ValidationAddress *va; - int all_done; - int matched; + struct ReadyList *rpos; + struct NeighborList *npos; + struct NeighborList *nprev; + struct MessageQueue *mq; -#if DEBUG_TRANSPORT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, - "Processing PONG\n"); -#endif - vcr = (const struct ValidationChallengeResponse *) message; - pos = pending_validations; - while (pos != NULL) - { - GNUNET_CRYPTO_hash (&pos->publicKey, - sizeof (struct - GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - &peer.hashPubKey); - if (0 == - memcmp (&peer, &vcr->sender, sizeof (struct GNUNET_PeerIdentity))) - break; - pos = pos->next; - } - if (pos == NULL) - { - /* TODO: call statistics (unmatched PONG) */ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _ - ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"), - "PONG", "PING"); - return; - } - all_done = GNUNET_YES; - matched = GNUNET_NO; - va = pos->addresses; - while (va != NULL) + if (GNUNET_YES == check) { - if (va->msg->challenge == vcr->challenge) + rpos = n->plugins; + while (NULL != rpos) { - if (GNUNET_OK != - GNUNET_CRYPTO_rsa_verify - (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO, &va->msg->purpose, - &vcr->signature, &pos->publicKey)) - { - /* this could rarely happen if we used the same - challenge number for the peer for two different - transports / addresses, but the likelihood is - very small... */ - GNUNET_break_op (0); - } - else - { -#if DEBUG_TRANSPORT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Confirmed validity of peer address.\n"); -#endif - va->ok = GNUNET_YES; - va->expiration = - GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION); - matched = GNUNET_YES; - } + if (GNUNET_YES == rpos->connected) + return; /* still connected */ + rpos = rpos->next; } - if (va->ok != GNUNET_YES) - all_done = GNUNET_NO; - va = va->next; - } - if (GNUNET_NO == matched) - { - /* TODO: call statistics (unmatched PONG) */ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _ - ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"), - "PONG", "PING"); } - if (GNUNET_YES == all_done) - { - pos->timeout.value = 0; - GNUNET_SCHEDULER_add_delayed (sched, - GNUNET_NO, - GNUNET_SCHEDULER_PRIORITY_IDLE, - GNUNET_SCHEDULER_NO_PREREQUISITE_TASK, - GNUNET_TIME_UNIT_ZERO, - &cleanup_validation, NULL); - } -} - - -/** - * The peer specified by the given neighbour has timed-out. Update - * our state and do the necessary notifications. Also notifies - * our clients that the neighbour is now officially gone. - * - * @param n the neighbour list entry for the peer - */ -static void -disconnect_neighbour (struct NeighbourList *n) -{ - struct ReadyList *rpos; - struct NeighbourList *npos; - struct NeighbourList *nprev; - struct MessageQueue *mq; #if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, - "Disconnecting from neighbour\n"); + "Disconnecting from `%4s'\n", GNUNET_i2s (&n->id)); #endif - /* remove n from neighbours list */ + /* remove n from neighbors list */ nprev = NULL; - npos = neighbours; + npos = neighbors; while ((npos != NULL) && (npos != n)) { nprev = npos; @@ -2093,20 +1984,20 @@ disconnect_neighbour (struct NeighbourList *n) } GNUNET_assert (npos != NULL); if (nprev == NULL) - neighbours = n->next; + neighbors = n->next; else nprev->next = n->next; /* notify all clients about disconnect */ notify_clients_disconnect (&n->id); - /* clean up all plugins, cancel connections & pending transmissions */ + /* clean up all plugins, cancel connections and pending transmissions */ while (NULL != (rpos = n->plugins)) { n->plugins = rpos->next; - GNUNET_assert (rpos->neighbour == n); - rpos->plugin->api->cancel (rpos->plugin->api->cls, - rpos->plugin_handle, rpos, &n->id); + GNUNET_assert (rpos->neighbor == n); + if (GNUNET_YES == rpos->connected) + rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id); GNUNET_free (rpos); } @@ -2114,10 +2005,11 @@ disconnect_neighbour (struct NeighbourList *n) while (NULL != (mq = n->messages)) { n->messages = mq->next; - GNUNET_assert (mq->neighbour == n); + GNUNET_assert (mq->neighbor == n); GNUNET_free (mq); } - + if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (sched, n->timeout_task); /* finally, free n itself */ GNUNET_free (n); } @@ -2126,17 +2018,17 @@ disconnect_neighbour (struct NeighbourList *n) /** * Add an entry for each of our transport plugins * (that are able to send) to the list of plugins - * for this neighbour. + * for this neighbor. * - * @param neighbour to initialize + * @param neighbor to initialize */ static void -add_plugins (struct NeighbourList *neighbour) +add_plugins (struct NeighborList *neighbor) { struct TransportPlugin *tp; struct ReadyList *rl; - neighbour->retry_plugins_time + neighbor->retry_plugins_time = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY); tp = plugins; while (tp != NULL) @@ -2144,10 +2036,10 @@ add_plugins (struct NeighbourList *neighbour) if (tp->api->send != NULL) { rl = GNUNET_malloc (sizeof (struct ReadyList)); - rl->next = neighbour->plugins; - neighbour->plugins = rl; + rl->next = neighbor->plugins; + neighbor->plugins = rl; rl->plugin = tp; - rl->neighbour = neighbour; + rl->neighbor = neighbor; rl->transmit_ready = GNUNET_YES; } tp = tp->next; @@ -2156,63 +2048,138 @@ add_plugins (struct NeighbourList *neighbour) static void -neighbour_timeout_task (void *cls, +neighbor_timeout_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { - struct NeighbourList *n = cls; + struct NeighborList *n = cls; #if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, - "Neighbour has timed out!\n"); + "Neighbor `%4s' has timed out!\n", GNUNET_i2s (&n->id)); #endif - n->timeout_task = GNUNET_SCHEDULER_NO_PREREQUISITE_TASK; - disconnect_neighbour (n); + n->timeout_task = GNUNET_SCHEDULER_NO_TASK; + disconnect_neighbor (n, GNUNET_NO); } - /** - * Create a fresh entry in our neighbour list for the given peer. - * Will try to transmit our current HELLO to the new neighbour. Also + * Create a fresh entry in our neighbor list for the given peer. + * Will try to transmit our current HELLO to the new neighbor. Also * notifies our clients about the new "connection". * * @param peer the peer for which we create the entry - * @return the new neighbour list entry + * @return the new neighbor list entry */ -static struct NeighbourList * -setup_new_neighbour (const struct GNUNET_PeerIdentity *peer) +static struct NeighborList * +setup_new_neighbor (const struct GNUNET_PeerIdentity *peer, const char *addr, size_t sender_address_len) { - struct NeighbourList *n; + struct NeighborList *n; #if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, - "Setting up new neighbour `%4s', sending our HELLO to introduce ourselves\n", + "Setting up new neighbor `%4s', sending our HELLO to introduce ourselves\n", GNUNET_i2s (peer)); #endif GNUNET_assert (our_hello != NULL); - n = GNUNET_malloc (sizeof (struct NeighbourList)); - n->next = neighbours; - neighbours = n; + n = GNUNET_malloc (sizeof (struct NeighborList)); + n->next = neighbors; + neighbors = n; n->id = *peer; n->last_quota_update = GNUNET_TIME_absolute_get (); n->peer_timeout = - GNUNET_TIME_relative_to_absolute (IDLE_CONNECTION_TIMEOUT); - n->quota_in = default_quota_in; + GNUNET_TIME_relative_to_absolute + (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); + n->quota_in = (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000); add_plugins (n); - n->hello_version_sent = our_hello_version; n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched, - GNUNET_NO, - GNUNET_SCHEDULER_PRIORITY_IDLE, - GNUNET_SCHEDULER_NO_PREREQUISITE_TASK, - IDLE_CONNECTION_TIMEOUT, - &neighbour_timeout_task, n); - transmit_to_peer (NULL, + GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, + &neighbor_timeout_task, n); + transmit_to_peer (NULL, 0, (const struct GNUNET_MessageHeader *) our_hello, GNUNET_YES, n); notify_clients_connect (peer, GNUNET_TIME_UNIT_FOREVER_REL); return n; } +/* + * We have received a PING message from someone. Need to send a PONG message + * in response to the peer by any means necessary. Of course, with something + * like TCP where a connection exists, we may want to send it that way. But + * we may not be able to make that distinction... + */ +static int handle_ping(void *cls, const struct GNUNET_MessageHeader *message, + const struct GNUNET_PeerIdentity *peer, + const char *sender_address, + size_t sender_address_len) +{ + struct TransportPlugin *plugin = cls; + struct TransportPingMessage *ping; + struct TransportPongMessage *pong; + uint16_t msize; + + pong = GNUNET_malloc(sizeof(struct TransportPongMessage)); + +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, + "Processing `%s' from `%s'\n", + "PING", GNUNET_a2s ((const struct sockaddr *)sender_address, sender_address_len)); +#endif + + msize = ntohs (message->size); + if (msize < sizeof (struct TransportPingMessage)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + ping = (struct TransportPingMessage *) message; + if (0 != memcmp (&ping->target, + plugin->env.my_identity, + sizeof (struct GNUNET_PeerIdentity))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Received `%s' message not destined for me!\n"), "PING"); + return GNUNET_SYSERR; + } + + msize -= sizeof (struct TransportPingMessage); +/* + * if (GNUNET_OK != tcp_plugin_address_suggested (plugin, &vcm[1], msize)) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + + if (GNUNET_OK != GNUNET_SERVER_client_get_address (client, &addr, &addrlen)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } +*/ + pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len); + pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len); + pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG); + pong->purpose.size = + htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + + sizeof (uint32_t) + + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sender_address_len); + pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_TCP_PING); + pong->challenge = ping->challenge; + + memcpy(&pong->signer, &my_public_key, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + memcpy (&pong[1], sender_address, sender_address_len); + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_rsa_sign (my_private_key, + &pong->purpose, &pong->signature)); + + transmit_to_peer(NULL, TRANSPORT_DEFAULT_PRIORITY, &pong->header, GNUNET_NO, find_neighbor(peer, NULL, 0)); + /* plugin->api->send(); */ /* We can't directly send back along received address, because + the port we saw for the peer (for TCP especially) will not + likely be the open port on the other side! */ + GNUNET_free(pong); + return GNUNET_OK; +} /** * Function called by the plugin for each received message. @@ -2220,68 +2187,58 @@ setup_new_neighbour (const struct GNUNET_PeerIdentity *peer) * reducing the rate at which they read from the socket * and generally forward to our receive callback. * - * @param plugin_context value to pass to this plugin - * to respond to the given peer (use is optional, - * but may speed up processing) - * @param service_context value passed to the transport-service - * to identify the neighbour; will be NULL on the first - * call for a given peer - * @param latency estimated latency for communicating with the - * given peer - * @param peer (claimed) identity of the other peer + * @param cls the "struct TransportPlugin *" we gave to the plugin * @param message the message, NULL if peer was disconnected + * @param distance the transport cost to this peer (not latency!) + * @param sender_address the address that the sender reported + * (opaque to transport service) + * @param sender_address_len the length of the sender address + * @param peer (claimed) identity of the other peer * @return the new service_context that the plugin should use * for future receive calls for messages from this * particular peer + * */ -static struct ReadyList * -plugin_env_receive (void *cls, - void *plugin_context, - struct ReadyList *service_context, - struct GNUNET_TIME_Relative latency, - const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_MessageHeader *message) +static void +plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + unsigned int distance, const char *sender_address, + size_t sender_address_len) { const struct GNUNET_MessageHeader ack = { htons (sizeof (struct GNUNET_MessageHeader)), htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK) }; + struct ReadyList *service_context; struct TransportPlugin *plugin = cls; struct TransportClient *cpos; struct InboundMessage *im; uint16_t msize; - struct NeighbourList *n; + struct NeighborList *n; - if (service_context != NULL) + n = find_neighbor (peer, sender_address, sender_address_len); + if (n == NULL) { - n = service_context->neighbour; - GNUNET_assert (n != NULL); - } - else - { - n = find_neighbour (peer); - if (n == NULL) - { - if (message == NULL) - return NULL; /* disconnect of peer already marked down */ - n = setup_new_neighbour (peer); - } - service_context = n->plugins; - while ((service_context != NULL) && (plugin != service_context->plugin)) - service_context = service_context->next; - GNUNET_assert ((plugin->api->send == NULL) || - (service_context != NULL)); + if (message == NULL) + return; /* disconnect of peer already marked down */ + n = setup_new_neighbor (peer, sender_address, sender_address_len); } + service_context = n->plugins; + while ((service_context != NULL) && (plugin != service_context->plugin)) + service_context = service_context->next; + GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL)); if (message == NULL) { - if ((service_context != NULL) && - (service_context->plugin_handle == plugin_context)) - { - service_context->connected = GNUNET_NO; - service_context->plugin_handle = NULL; - } +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, + "Receive failed from `%4s', triggering disconnect\n", + GNUNET_i2s (&n->id)); +#endif /* TODO: call stats */ - return NULL; + if (service_context != NULL) + service_context->connected = GNUNET_NO; + disconnect_neighbor (n, GNUNET_YES); + return; } #if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, @@ -2297,22 +2254,22 @@ plugin_env_receive (void *cls, service_context->connect_attempts++; } service_context->timeout - = GNUNET_TIME_relative_to_absolute (IDLE_CONNECTION_TIMEOUT); - service_context->plugin_handle = plugin_context; - service_context->latency = latency; + = + GNUNET_TIME_relative_to_absolute + (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); + /* service_context->latency = latency; */ /* This value should be set by us! */ } /* update traffic received amount ... */ msize = ntohs (message->size); n->last_received += msize; GNUNET_SCHEDULER_cancel (sched, n->timeout_task); n->peer_timeout = - GNUNET_TIME_relative_to_absolute (IDLE_CONNECTION_TIMEOUT); + GNUNET_TIME_relative_to_absolute + (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); n->timeout_task = - GNUNET_SCHEDULER_add_delayed (sched, GNUNET_NO, - GNUNET_SCHEDULER_PRIORITY_IDLE, - GNUNET_SCHEDULER_NO_PREREQUISITE_TASK, - IDLE_CONNECTION_TIMEOUT, - &neighbour_timeout_task, n); + GNUNET_SCHEDULER_add_delayed (sched, + GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, + &neighbor_timeout_task, n); update_quota (n); if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD) { @@ -2322,43 +2279,45 @@ plugin_env_receive (void *cls, _ ("Dropping incoming message due to repeated bandwidth quota violations.\n")); /* TODO: call stats */ - GNUNET_assert (NULL != service_context->neighbour); - return service_context; + GNUNET_assert ((service_context == NULL) || + (NULL != service_context->neighbor)); + return; } switch (ntohs (message->type)) { case GNUNET_MESSAGE_TYPE_HELLO: #if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Receiving `%s' message from other peer.\n", "HELLO"); + "Receiving `%s' message from `%4s'.\n", "HELLO", + GNUNET_i2s (peer)); #endif process_hello (plugin, message); #if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Sending `%s' message to connecting peer.\n", "ACK"); + "Sending `%s' message to connecting peer `%4s'.\n", "ACK", + GNUNET_i2s (peer)); #endif - transmit_to_peer (NULL, &ack, GNUNET_YES, n); + transmit_to_peer (NULL, 0, &ack, GNUNET_YES, n); break; case GNUNET_MESSAGE_TYPE_TRANSPORT_PING: - process_ping (plugin, peer, plugin_context, message); - break; + handle_ping(plugin, message, peer, sender_address, sender_address_len); case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG: - process_pong (plugin, message); - break; + handle_pong(plugin, message, peer, sender_address, sender_address_len); + //plugin_env_notify_validation(); case GNUNET_MESSAGE_TYPE_TRANSPORT_ACK: n->saw_ack = GNUNET_YES; /* intentional fall-through! */ default: #if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received message of type %u from other peer, sending to all clients.\n", - ntohs (message->type)); + "Received message of type %u from `%4s', sending to all clients.\n", + ntohs (message->type), GNUNET_i2s (peer)); #endif /* transmit message to all clients */ im = GNUNET_malloc (sizeof (struct InboundMessage) + msize); im->header.size = htons (sizeof (struct InboundMessage) + msize); im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV); - im->latency = GNUNET_TIME_relative_hton (latency); + im->latency = n->latency; im->peer = *peer; memcpy (&im[1], message, msize); @@ -2370,8 +2329,8 @@ plugin_env_receive (void *cls, } GNUNET_free (im); } - GNUNET_assert (NULL != service_context->neighbour); - return service_context; + GNUNET_assert ((service_context == NULL) || + (NULL != service_context->neighbor)); } @@ -2390,7 +2349,7 @@ handle_start (void *cls, { struct TransportClient *c; struct ConnectInfoMessage cim; - struct NeighbourList *n; + struct NeighborList *n; struct InboundMessage *im; struct GNUNET_MessageHeader *ack; @@ -2418,7 +2377,7 @@ handle_start (void *cls, { #if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Sending our own HELLO to new client\n"); + "Sending our own `%s' to new client\n", "HELLO"); #endif transmit_to_client (c, (const struct GNUNET_MessageHeader *) our_hello, @@ -2426,7 +2385,8 @@ handle_start (void *cls, /* tell new client about all existing connections */ cim.header.size = htons (sizeof (struct ConnectInfoMessage)); cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT); - cim.quota_out = htonl (default_quota_out); + cim.quota_out = + htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000)); cim.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO); /* FIXME? */ im = GNUNET_malloc (sizeof (struct InboundMessage) + sizeof (struct GNUNET_MessageHeader)); @@ -2437,7 +2397,7 @@ handle_start (void *cls, ack = (struct GNUNET_MessageHeader *) &im[1]; ack->size = htons (sizeof (struct GNUNET_MessageHeader)); ack->type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK); - for (n = neighbours; n != NULL; n = n->next) + for (n = neighbors; n != NULL; n = n->next) { cim.id = n->id; transmit_to_client (c, &cim.header, GNUNET_NO); @@ -2489,7 +2449,7 @@ handle_send (void *cls, const struct GNUNET_MessageHeader *message) { struct TransportClient *tc; - struct NeighbourList *n; + struct NeighborList *n; const struct OutboundMessage *obm; const struct GNUNET_MessageHeader *obmm; uint16_t size; @@ -2517,9 +2477,9 @@ handle_send (void *cls, GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } - n = find_neighbour (&obm->peer); + n = find_neighbor (&obm->peer, NULL, 0); if (n == NULL) - n = setup_new_neighbour (&obm->peer); + n = setup_new_neighbor (&obm->peer, NULL, 0); tc = clients; while ((tc != NULL) && (tc->client != client)) tc = tc->next; @@ -2530,7 +2490,7 @@ handle_send (void *cls, ntohs (obmm->size), ntohs (obmm->type), GNUNET_i2s (&obm->peer)); #endif - transmit_to_peer (tc, obmm, GNUNET_NO, n); + transmit_to_peer (tc, ntohl (obm->priority), obmm, GNUNET_NO, n); GNUNET_SERVER_receive_done (client, GNUNET_OK); } @@ -2549,7 +2509,7 @@ handle_set_quota (void *cls, { const struct QuotaSetMessage *qsm = (const struct QuotaSetMessage *) message; - struct NeighbourList *n; + struct NeighborList *n; struct TransportPlugin *p; struct ReadyList *rl; @@ -2558,7 +2518,7 @@ handle_set_quota (void *cls, "Received `%s' request from client for peer `%4s'\n", "SET_QUOTA", GNUNET_i2s (&qsm->peer)); #endif - n = find_neighbour (&qsm->peer); + n = find_neighbor (&qsm->peer, NULL, 0); if (n == NULL) { GNUNET_SERVER_receive_done (client, GNUNET_OK); @@ -2597,14 +2557,104 @@ handle_try_connect (void *cls, tcm = (const struct TryConnectMessage *) message; #if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received `%s' request from client asking to connect to `%4s'\n", - "TRY_CONNECT", GNUNET_i2s (&tcm->peer)); + "Received `%s' request from client %p asking to connect to `%4s'\n", + "TRY_CONNECT", client, GNUNET_i2s (&tcm->peer)); +#endif + if (NULL == find_neighbor (&tcm->peer, NULL, 0)) + setup_new_neighbor (&tcm->peer, NULL, 0); /* Can we set up a truly _new_ neighbor without + knowing its address? Should we ask the plugin + for more information about this peer? I don't + think we can... Or set up new peer should only + happen when transport notifies us of an address, + and this setup should check for an address in + the existing list only */ +#if DEBUG_TRANSPORT + else + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Client asked to connect to `%4s', but connection already exists\n", + "TRY_CONNECT", GNUNET_i2s (&tcm->peer)); #endif - if (NULL == find_neighbour (&tcm->peer)) - setup_new_neighbour (&tcm->peer); GNUNET_SERVER_receive_done (client, GNUNET_OK); } +static void +transmit_address_to_client (void *cls, const char *address) +{ + struct GNUNET_SERVER_TransmitContext *tc = cls; + size_t slen; + + if (NULL == address) + slen = 0; + else + slen = strlen (address) + 1; + GNUNET_SERVER_transmit_context_append (tc, address, slen, + GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY); + if (NULL == address) + GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL); +} + +/** + * Handle AddressLookup-message. + * + * @param cls closure (always NULL) + * @param client identification of the client + * @param message the actual message + */ +static void +handle_address_lookup (void *cls, + struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct AddressLookupMessage *alum; + struct TransportPlugin *lsPlugin; + const char *nameTransport; + const char *address; + uint16_t size; + struct GNUNET_SERVER_TransmitContext *tc; + + size = ntohs (message->size); + if (size < sizeof (struct AddressLookupMessage)) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + alum = (const struct AddressLookupMessage *) message; + uint32_t addressLen = ntohl (alum->addrlen); + if (size <= sizeof (struct AddressLookupMessage) + addressLen) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + address = (const char *) &alum[1]; + nameTransport = (const char *) &address[addressLen]; + if (nameTransport + [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0') + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + struct GNUNET_TIME_Absolute timeout = + GNUNET_TIME_absolute_ntoh (alum->timeout); + struct GNUNET_TIME_Relative rtimeout = + GNUNET_TIME_absolute_get_remaining (timeout); + lsPlugin = find_transport (nameTransport); + if (NULL == lsPlugin) + { + tc = GNUNET_SERVER_transmit_context_create (client); + GNUNET_SERVER_transmit_context_append (tc, NULL, 0, + GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY); + GNUNET_SERVER_transmit_context_run (tc, rtimeout); + return; + } + tc = GNUNET_SERVER_transmit_context_create (client); + lsPlugin->api->address_pretty_printer (cls, nameTransport, + address, addressLen, GNUNET_YES, + rtimeout, + &transmit_address_to_client, tc); +} /** * List of handlers for the messages understood by this @@ -2622,6 +2672,9 @@ static struct GNUNET_SERVER_MessageHandler handlers[] = { {&handle_try_connect, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_TRY_CONNECT, sizeof (struct TryConnectMessage)}, + {&handle_address_lookup, NULL, + GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP, + 0}, {NULL, NULL, 0, 0} }; @@ -2634,12 +2687,12 @@ create_environment (struct TransportPlugin *plug) { plug->env.cfg = cfg; plug->env.sched = sched; - plug->env.my_public_key = &my_public_key; + plug->env.my_identity = &my_identity; plug->env.cls = plug; plug->env.receive = &plugin_env_receive; - plug->env.lookup = &plugin_env_lookup_address; plug->env.notify_address = &plugin_env_notify_address; - plug->env.default_quota_in = default_quota_in; + plug->env.default_quota_in = + (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000); plug->env.max_connections = max_connect_per_transport; } @@ -2690,6 +2743,8 @@ client_disconnect_notification (void *cls, struct TransportClient *prev; struct ClientMessageQueueEntry *mqe; + if (client == NULL) + return; #if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, "Client disconnected, cleaning up.\n"); @@ -2722,6 +2777,41 @@ client_disconnect_notification (void *cls, } +/** + * Function called when the service shuts down. Unloads our plugins. + * + * @param cls closure, unused + * @param tc task context (unused) + */ +static void +unload_plugins (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct TransportPlugin *plug; + struct AddressList *al; + +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Transport service is unloading plugins...\n"); +#endif + while (NULL != (plug = plugins)) + { + plugins = plug->next; + GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api)); + GNUNET_free (plug->lib_name); + GNUNET_free (plug->short_name); + while (NULL != (al = plug->addresses)) + { + plug->addresses = al->next; + GNUNET_free (al); + } + GNUNET_free (plug); + } + if (my_private_key != NULL) + GNUNET_CRYPTO_rsa_key_free (my_private_key); + GNUNET_free_non_null (our_hello); +} + + /** * Initiate transport service. * @@ -2733,13 +2823,12 @@ client_disconnect_notification (void *cls, static void run (void *cls, struct GNUNET_SCHEDULER_Handle *s, - struct GNUNET_SERVER_Handle *serv, struct GNUNET_CONFIGURATION_Handle *c) + struct GNUNET_SERVER_Handle *serv, + const struct GNUNET_CONFIGURATION_Handle *c) { char *plugs; char *pos; int no_transports; - unsigned long long qin; - unsigned long long qout; unsigned long long tneigh; char *keyfile; @@ -2747,16 +2836,6 @@ run (void *cls, cfg = c; /* parse configuration */ if ((GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (c, - "TRANSPORT", - "DEFAULT_QUOTA_IN", - &qin)) || - (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (c, - "TRANSPORT", - "DEFAULT_QUOTA_OUT", - &qout)) || - (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (c, "TRANSPORT", "NEIGHBOUR_LIMIT", @@ -2773,8 +2852,6 @@ run (void *cls, return; } max_connect_per_transport = (uint32_t) tneigh; - default_quota_in = (uint32_t) qin; - default_quota_out = (uint32_t) qout; my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); GNUNET_free (keyfile); if (my_private_key == NULL) @@ -2809,52 +2886,19 @@ run (void *cls, } GNUNET_free (plugs); } + GNUNET_SCHEDULER_add_delayed (sched, + GNUNET_TIME_UNIT_FOREVER_REL, + &unload_plugins, NULL); if (no_transports) refresh_hello (); #if DEBUG_TRANSPORT - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("Transport service ready.\n")); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n")); #endif /* process client requests */ GNUNET_SERVER_add_handlers (server, handlers); } -/** - * Function called when the service shuts - * down. Unloads our plugins. - * - * @param cls closure - * @param cfg configuration to use - */ -static void -unload_plugins (void *cls, struct GNUNET_CONFIGURATION_Handle *cfg) -{ - struct TransportPlugin *plug; - struct AddressList *al; - -#if DEBUG_TRANSPORT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Transport service is unloading plugins...\n"); -#endif - while (NULL != (plug = plugins)) - { - plugins = plug->next; - GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api)); - GNUNET_free (plug->lib_name); - GNUNET_free (plug->short_name); - while (NULL != (al = plug->addresses)) - { - plug->addresses = al->next; - GNUNET_free (al); - } - GNUNET_free (plug); - } - if (my_private_key != NULL) - GNUNET_CRYPTO_rsa_key_free (my_private_key); -} - - /** * The main function for the transport service. * @@ -2869,7 +2913,8 @@ main (int argc, char *const *argv) GNUNET_SERVICE_run (argc, argv, "transport", - &run, NULL, &unload_plugins, NULL)) ? 0 : 1; + GNUNET_SERVICE_OPTION_NONE, + &run, NULL)) ? 0 : 1; } /* end of gnunet-service-transport.c */