GNUnet 0.28.1-dev.5-1-gae1c02d74
 
Loading...
Searching...
No Matches
gnunet-service-transport.c File Reference

main for gnunet-service-transport More...

Include dependency graph for gnunet-service-transport.c:

Go to the source code of this file.

Data Structures

struct  MessageUUIDP
 Unique identifier we attach to a message. More...
 
struct  AcknowledgementUUIDP
 Unique identifier to map an acknowledgement to a transmission. More...
 
struct  TransportBackchannelEncapsulationMessage
 Outer layer of an encapsulated backchannel message. More...
 
struct  EphemeralConfirmationPS
 Body by which a peer confirms that it is using an ephemeral key. More...
 
struct  TransportDVBoxPayloadP
 Plaintext of the variable-size payload that is encrypted within a struct TransportBackchannelEncapsulationMessage More...
 
struct  TransportReliabilityBoxMessage
 Outer layer of an encapsulated unfragmented application message sent over an unreliable channel. More...
 
struct  TransportCummulativeAckPayloadP
 Acknowledgement payload. More...
 
struct  TransportReliabilityAckMessage
 Confirmation that the receiver got a GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX. More...
 
struct  TransportFragmentBoxMessage
 Outer layer of an encapsulated fragmented application message. More...
 
struct  DvInitPS
 Content signed by the initiator during DV learning. More...
 
struct  DvHopPS
 Content signed by each peer during DV learning. More...
 
struct  DVPathEntryP
 An entry describing a peer on a path in a struct TransportDVLearnMessage message. More...
 
struct  TransportDVLearnMessage
 Internal message used by transport for distance vector learning. More...
 
struct  TransportDVBoxMessage
 Outer layer of an encapsulated message send over multiple hops. More...
 
struct  TransportValidationChallengeMessage
 Message send to another peer to validate that it can indeed receive messages at a particular address. More...
 
struct  TransportValidationPS
 Message signed by a peer to confirm that it can indeed receive messages at a particular address. More...
 
struct  TransportValidationResponseMessage
 Message send to a peer to respond to a #GNUNET_MESSAGE_TYPE_ADDRESS_VALIDATION_CHALLENGE. More...
 
struct  TransportGlobalNattedAddress
 
struct  TransportFlowControlMessage
 Message for Transport-to-Transport Flow control. More...
 
struct  LearnLaunchEntry
 When did we launch this DV learning activity? More...
 
struct  TransmissionHistoryEntry
 Information we keep per GOODPUT_AGING_SLOTS about historic (or current) transmission performance. More...
 
struct  PerformanceData
 Performance data for a transmission possibility. More...
 
struct  CommunicatorMessageContext
 Context from handle_incoming_msg(). More...
 
struct  RingBufferEntry
 Entry for the ring buffer caching messages send to core, when virtual link is available. More...
 
struct  CoreSentContext
 Closure for core_env_sent_cb. More...
 
struct  ReassemblyContext
 Information we keep for a message that we are reassembling. More...
 
struct  VirtualLink
 A virtual link is another reachable peer that is known to CORE. More...
 
struct  PendingAcknowledgement
 Data structure kept when we are waiting for an acknowledgement. More...
 
struct  DistanceVectorHop
 One possible hop towards a DV target. More...
 
struct  DistanceVector
 Entry in our dv_routes table, representing a (set of) distance vector routes to a particular peer. More...
 
struct  QueueEntry
 Entry identifying transmission in one of our struct Queue which still awaits an ACK. More...
 
struct  Queue
 Handle for a queue. More...
 
struct  Neighbour
 A neighbour that at least one communicator is connected to. More...
 
struct  IncomingRequest
 Another peer attempted to talk to us, we should try to establish a connection in the other direction. More...
 
struct  PeerRequest
 Information per peer and request. More...
 
struct  PendingMessage
 List containing all messages that are yet to be send. More...
 
struct  TransportCummulativeAckPayload
 Acknowledgement payload. More...
 
struct  AcknowledgementCummulator
 Data structure in which we track acknowledgements still to be sent to the. More...
 
struct  AddressListEntry
 One of the addresses of this peer. More...
 
struct  TransportClient
 Client connected to the transport service. More...
 
struct  ValidationState
 State we keep for validation activities. More...
 
struct  Backtalker
 A Backtalker is a peer sending us backchannel messages. More...
 
struct  PilsRequest
 DLL. More...
 
struct  MonitorEvent
 Details about what to notify monitors about. More...
 
struct  AddGlobalAddressesContext
 
struct  PilsAddressSignContext
 Helper context struct for HELLO update. More...
 
struct  SignedAddress
 Binary block we sign when we sign an address. More...
 
struct  FindByMessageUuidContext
 Closure for find_by_message_uuid. More...
 
struct  NeighbourSelectionContext
 Closure for dv_neighbour_selection and dv_neighbour_transmission. More...
 
struct  CheckKnownAddressContext
 Closure for check_known_address. More...
 
struct  CheckKnownChallengeContext
 Closure for check_known_challenge. More...
 
struct  PendingMessageScoreContext
 Context for select_best_pending_from_link(). More...
 
struct  LinkListContext
 Closure for report_link(). More...
 
struct  QueueQualityContext
 Closure for check_connection_quality. More...
 
struct  TransportGlobalNattedAddressClosure
 
struct  UpdateHelloFromPidCtx
 

Macros

#define RING_BUFFER_SIZE   16
 Size of ring buffer to cache CORE and forwarded DVBox messages.
 
#define MAX_FC_RETRANSMIT_COUNT   1000
 Maximum number of FC retransmissions for a running retransmission task.
 
#define MIN_FC_RETRANSMIT_DELAY    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100)
 Lower bound on the delay between two flow control transmissions on the same virtual link.
 
#define UNCONFIRMED_LINK_TIMEOUT    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
 How long do we keep a virtual link that only exists because some peer sent us a FLOW_CONTROL message, without it ever becoming confirmed?
 
#define MAX_CUMMULATIVE_ACKS   64
 Maximum number of messages we acknowledge together in one cumulative ACK.
 
#define FC_NO_CHANGE_REPLY_PROBABILITY   8
 What is the 1:n chance that we send a Flow control response when receiving a flow control message that did not change anything for us? Basically, this is used in the case where both peers are stuck on flow control (no window changes), but one might continue sending flow control messages to the other peer as the first FC message when things stalled got lost, and then subsequently the other peer does usually not respond as nothing changed.
 
#define IN_PACKET_SIZE_WITHOUT_MTU   128
 What is the size we assume for a read operation in the absence of an MTU for the purpose of flow control?
 
#define GOODPUT_AGING_SLOTS   4
 Number of slots we keep of historic data for computation of goodput / message loss ratio.
 
#define DEFAULT_WINDOW_SIZE   (128 * 1024)
 How big is the flow control window size by default; limits per-neighbour RAM utilization.
 
#define MAX_INCOMING_REQUEST   16
 For how many incoming connections do we try to create a virtual link for (at the same time!).
 
#define MAX_DV_DISCOVERY_SELECTION   16
 Maximum number of peers we select for forwarding DVInit messages at the same time (excluding initiator).
 
#define RECV_WINDOW_SIZE   4
 Window size.
 
#define CORE_FC_STALL_TIMEOUT    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2)
 How long do we wait for CORE to return the flow control credit for the messages we handed it before we give up on them?
 
#define MAX_STALLED_CMCS   (4 * RECV_WINDOW_SIZE)
 How many messages may wait on VirtualLink::core_recv_window before we stop deferring their flow control ACKs?
 
#define MIN_DV_PATH_LENGTH_FOR_INITIATOR   3
 Minimum number of hops we should forward DV learn messages even if they are NOT useful for us in hope of looping back to the initiator?
 
#define MAX_DV_HOPS_ALLOWED   16
 Maximum DV distance allowed ever.
 
#define MAX_DV_LEARN_PENDING   64
 Maximum number of DV learning activities we may have pending at the same time.
 
#define MAX_DV_PATHS_TO_TARGET   3
 Maximum number of DV paths we keep simultaneously to the same target.
 
#define PILS_FEED_ADDRESSES_DELAY    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3)
 Delay between added/removed addresses and PILS feed call.
 
#define DELAY_WARN_THRESHOLD    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
 If a queue delays the next message by more than this number of seconds we log a warning.
 
#define DV_FORWARD_TIMEOUT    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
 If a DVBox could not be forwarded after this number of seconds we drop it.
 
#define DEFAULT_ACK_WAIT_DURATION    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
 Default value for how long we wait for reliability ack.
 
#define MIN_ACK_WAIT_DURATION    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 10)
 Lower bound on the RTT estimate we are willing to derive a retransmission deadline from.
 
#define DV_QUALITY_RTT_THRESHOLD    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
 We only consider queues as "quality" connections when suppressing the generation of DV initiation messages if the latency of the queue is below this threshold.
 
#define DV_PATH_VALIDITY_TIMEOUT    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
 How long do we consider a DV path valid if we see no further updates on it? Note: the value chosen here might be too low!
 
#define BACKCHANNEL_INACTIVITY_TIMEOUT    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
 How long do we cache backchannel (struct Backtalker) information after a backchannel goes inactive?
 
#define DV_PATH_DISCOVERY_FREQUENCY    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
 How long before paths expire would we like to (re)discover DV paths? Should be below DV_PATH_VALIDITY_TIMEOUT.
 
#define EPHEMERAL_VALIDITY    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
 How long are ephemeral keys valid?
 
#define REASSEMBLY_EXPIRATION    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
 How long do we keep partially reassembled messages around before giving up?
 
#define MAX_REASSEMBLY_CONTEXTS   32
 Maximum number of messages we are willing to reassemble in parallel for a single virtual link.
 
#define FAST_VALIDATION_CHALLENGE_FREQ    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
 What is the fastest rate at which we send challenges if we keep learning an address (gossip, DHT, etc.)?
 
#define MAX_VALIDATION_CHALLENGE_FREQ    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_DAYS, 1)
 What is the slowest rate at which we send challenges?
 
#define WANTED_VALIDATION_CHALLENGE_FREQ    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
 What is the slowest rate at which we send challenges to a peer that an application client explicitly asked for and that we have no confirmed link to? Somebody is waiting for this one, so a day is not an option.
 
#define SUGGEST_RETRY_MIN    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
 How soon after an application asked us for a peer do we retry bringing the link up for the first time?
 
#define SUGGEST_RETRY_MAX    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
 What is the slowest rate at which we retry bringing up a link that an application client explicitly asked for? Unlike a peer we merely heard about, somebody is waiting for this one, so this is far below MAX_VALIDATION_CHALLENGE_FREQ.
 
#define ACK_CUMMULATOR_TIMEOUT    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
 How long until we forget about historic accumulators and thus reset the ACK counter? Should exceed the maximum time an active connection experiences without an ACK.
 
#define DV_LEARN_BASE_FREQUENCY   GNUNET_TIME_UNIT_MINUTES
 What is the non-randomized base frequency at which we would initiate DV learn messages?
 
#define DV_LEARN_QUALITY_THRESHOLD   100
 How many good connections (confirmed, bi-directional, not DV) do we need to have to suppress initiating DV learn messages?
 
#define MAX_ADDRESS_VALID_UNTIL    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MONTHS, 1)
 When do we forget an invalid address for sure?
 
#define ADDRESS_VALIDATION_LIFETIME    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
 How long do we consider an address valid if we just checked?
 
#define NEIGHBOUR_LIVENESS_TIMEOUT    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
 How long may a direct neighbour stay completely silent before we stop believing that its queues work, regardless of what the communicator that owns them tells us?
 
#define FC_KEEPALIVE_INTERVAL
 How long may a confirmed virtual link go without us sending anything on it before we transmit an otherwise unnecessary FLOW_CONTROL message, purely so that the peer at the other end keeps seeing traffic from us?
 
#define MIN_ADDRESS_REFRESH_INTERVAL    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
 How often are we willing to re-sign and re-store one of our own addresses in PEERSTORE, no matter how short a lifetime the communicator that owns it claims? See peerstore_store_own_cb().
 
#define MIN_DELAY_ADDRESS_VALIDATION   GNUNET_TIME_UNIT_MILLISECONDS
 What is the maximum frequency at which we do address validation? A random value between 0 and this value is added when scheduling the validation_task (both to ensure we do not validate too often, and to randomize a bit).
 
#define VALIDATION_RTT_BUFFER_FACTOR   3
 How many network RTTs before an address validation expires should we begin trying to revalidate? (Note that the RTT used here is the one that we experienced during the last validation, not necessarily the latest RTT observed).
 
#define COMMUNICATOR_TOTAL_QUEUE_LIMIT   512
 How many messages can we have pending for a given communicator process before we start to throttle that communicator?
 
#define QUEUE_LENGTH_LIMIT   32
 How many messages can we have pending for a given queue (queue to a particular peer via a communicator) process before we start to throttle that queue?
 
#define QUEUE_ENTRY_TIMEOUT    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
 
#define RTT_DIFF    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
 Difference of the average RTT for the DistanceVector calculate by us and the target we are willing to accept for starting the burst.
 
#define SHUTDOWN_CLIENT_GRACE_PERIOD    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
 How long do we wait during shutdown for our clients to disconnect on their own before we drop them? We run with GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN, so nobody drops them for us and a single wedged client would otherwise keep us alive forever.
 

Typedefs

typedef void(* DVMessageHandler) (void *cls, struct Neighbour *next_hop, const struct GNUNET_MessageHeader *hdr, enum RouteMessageOptions options)
 Function to call to further operate on the now DV encapsulated message hdr, forwarding it via next_hop under respect of options.
 

Enumerations

enum  ClientType {
  CT_NONE = 0 , CT_CORE = 1 , CT_MONITOR = 2 , CT_COMMUNICATOR = 3 ,
  CT_APPLICATION = 4
}
 What type of client is the struct TransportClient about? More...
 
enum  RouteMessageOptions {
  RMO_NONE = 0 , RMO_DV_ALLOWED = 1 , RMO_UNCONFIRMED_ALLOWED = 2 , RMO_ANYTHING_GOES = (RMO_DV_ALLOWED | RMO_UNCONFIRMED_ALLOWED) ,
  RMO_REDUNDANT = 4
}
 Which transmission options are allowable for transmission? Interpreted bit-wise! More...
 
enum  PendingMessageType { PMT_CORE = 0 , PMT_FRAGMENT_BOX = 1 , PMT_RELIABILITY_BOX = 2 , PMT_DV_BOX = 3 }
 Types of different pending messages. More...
 

Functions

GNUNET_NETWORK_STRUCT_END GNUNET_static_assert (sizeof(struct TransportGlobalNattedAddress)==4)
 
 GNUNET_static_assert (sizeof(struct TransportFlowControlMessage)==60)
 
 GNUNET_static_assert (sizeof(struct TransportDVBoxMessage)==86)
 
 GNUNET_static_assert (sizeof(struct TransportDVLearnMessage)==152)
 
 GNUNET_static_assert (sizeof(struct TransportFragmentBoxMessage)==32)
 
 GNUNET_static_assert (sizeof(struct TransportReliabilityBoxMessage)==24)
 
 GNUNET_static_assert (sizeof(struct TransportReliabilityAckMessage)==8)
 
 GNUNET_static_assert (sizeof(struct TransportValidationChallengeMessage)==48)
 
 GNUNET_static_assert (sizeof(struct TransportValidationResponseMessage)==120)
 
static enum GNUNET_GenericReturnValue sign_by_my_identity (const struct GNUNET_CRYPTO_SignaturePurpose *purpose, struct GNUNET_CRYPTO_EddsaSignature *sig)
 Sign purpose with the private key of our current peer identity.
 
static unsigned int get_age ()
 Get an offset into the transmission history buffer for struct PerformanceData.
 
static void free_incoming_request (struct IncomingRequest *ir)
 Release ir data structure.
 
static void free_pending_acknowledgement (struct PendingAcknowledgement *pa)
 Release pa data structure.
 
static void free_fragment_tree (struct PendingMessage *root)
 Free fragment tree below root, excluding root itself.
 
static void free_pending_message (struct PendingMessage *pm)
 Release memory associated with pm and remove pm from associated data structures.
 
static void free_reassembly_context (struct ReassemblyContext *rc)
 Free rc.
 
static void reassembly_cleanup_task (void *cls)
 Task run to clean up reassembly context of a neighbour that have expired.
 
static int free_reassembly_cb (void *cls, uint32_t key, void *value)
 function called to free_reassembly_context().
 
static void finish_cmc_handling_with_continue (struct CommunicatorMessageContext *cmc, unsigned int free_cmc)
 Send ACK to communicator (if requested) and free cmc.
 
static void release_stalled_cmc (struct VirtualLink *vl, struct CommunicatorMessageContext *cmc)
 Take cmc off the list of messages waiting on vl's CORE receive window, release the flow control credit we were withholding and free it.
 
static void free_burst_cls (struct GNUNET_StartBurstCls *sb_cls)
 Release a burst closure, detaching it from its virtual link and from the scheduled burst_task (if that is the task the closure belongs to).
 
static void send_ok_to_client (struct TransportClient *tc, const struct GNUNET_PeerIdentity *pid)
 Return one unit of send window credit for pid to tc.
 
static void credit_client (struct PendingMessage *pm)
 Return the send window credit that pm's client is owed, at most once for pm.
 
static void free_virtual_link (struct VirtualLink *vl)
 Free virtual link.
 
static void free_validation_state (struct ValidationState *vs)
 Free validation state.
 
static struct Neighbourlookup_neighbour (const struct GNUNET_PeerIdentity *pid)
 Lookup neighbour for peer pid.
 
static struct VirtualLinklookup_virtual_link (const struct GNUNET_PeerIdentity *pid)
 Lookup virtual link for peer pid.
 
static void free_distance_vector_hop (struct DistanceVectorHop *dvh)
 Free a dvh.
 
static void check_link_down (void *cls)
 Task run to check whether the hops of the cls still are validated, or if we need to core about disconnection.
 
static void cores_send_disconnect_info (const struct GNUNET_PeerIdentity *pid)
 Send message to CORE clients that we lost a connection.
 
static void try_to_bring_link_up (const struct GNUNET_PeerIdentity *pid)
 Ask for everything that could give us a confirmed virtual link to pid: revalidate the addresses we already track, then those of the queues we still have, and failing both look for one in PEERSTORE.
 
static void disconnect_and_free_virtual_link (struct VirtualLink *vl)
 Tell CORE clients the link to vl is gone, then release it.
 
static void free_dv_route (struct DistanceVector *dv)
 Free entry in dv_routes.
 
static void notify_monitor (struct TransportClient *tc, const struct GNUNET_PeerIdentity *peer, const char *address, enum GNUNET_NetworkType nt, const struct MonitorEvent *me)
 Notify monitor tc about an event.
 
static void notify_monitors (const struct GNUNET_PeerIdentity *peer, const char *address, enum GNUNET_NetworkType nt, const struct MonitorEvent *me)
 Send information in me about a peer's status with respect to some address to all monitors that care.
 
static void * client_connect_cb (void *cls, struct GNUNET_SERVICE_Client *client, struct GNUNET_MQ_Handle *mq)
 Called whenever a client connects.
 
static enum GNUNET_GenericReturnValue remove_global_addresses (void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
 
static void free_neighbour (struct Neighbour *neighbour, enum GNUNET_GenericReturnValue drop_link)
 Release memory used by neighbour.
 
static void core_send_connect_info (struct TransportClient *tc, const struct GNUNET_PeerIdentity *pid)
 Send message to CORE clients that we lost a connection.
 
static void cores_send_connect_info (const struct GNUNET_PeerIdentity *pid)
 Send message to CORE clients that we gained a connection.
 
static void transmit_on_queue (void *cls)
 We believe we are ready to transmit a message on a queue.
 
static unsigned int check_for_queue_with_higher_prio (struct Queue *queue, struct Queue *queue_head)
 Check if there is another queue to the same neighbour, over a different communicator, that has a higher priority and is ready for sending.
 
static void arm_free_queue_entry_task (struct TransportClient *tc)
 Make sure free_timedout_queue_entry() will run for tc, so that `struct QueueEntry's the communicator never acknowledged are reclaimed.
 
static void schedule_transmit_on_queue (struct GNUNET_TIME_Relative delay, struct Queue *queue, enum GNUNET_SCHEDULER_Priority p)
 Called whenever something changed that might effect when we try to do the next transmission on queue using transmit_on_queue().
 
static void start_address_validation (const struct GNUNET_PeerIdentity *pid, const char *address)
 Start address validation.
 
static void free_queue (struct Queue *queue)
 Free queue.
 
static void cancel_address_store (struct AddressListEntry *ale)
 Abort the asynchronous sign-and-store chain (if any) that is currently running for ale and release its context.
 
static void free_address_list_entry (struct AddressListEntry *ale)
 Free ale.
 
static int stop_peer_request (void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
 Stop the peer request in value.
 
static void do_shutdown (void *cls)
 Function called when the service shuts down.
 
static enum GNUNET_GenericReturnValue detach_cmcs_from_link (void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
 Detach the `struct CommunicatorMessageContext's parked on value from the client in cls.
 
static enum GNUNET_GenericReturnValue detach_cmc_from_backtalker (void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
 Detach the ‘struct CommunicatorMessageContext’ parked on value from the client in cls.
 
static void detach_cmcs_from_client (const struct TransportClient *tc)
 A communicator client is going away.
 
static void client_disconnect_cb (void *cls, struct GNUNET_SERVICE_Client *client, void *app_ctx)
 Called whenever a client is disconnected.
 
static int notify_client_connect_info (void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
 Iterator telling new CORE client about all existing connections to peers.
 
static enum GNUNET_GenericReturnValue resume_communicators (void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
 
static void handle_client_start (void *cls, const struct StartMessage *start)
 Initialize a "CORE" client.
 
static int check_client_send (void *cls, const struct OutboundMessage *obm)
 Client asked for transmission to a peer.
 
static void client_send_response (struct PendingMessage *pm)
 Send a response to the pm that we have processed a "send" request.
 
static unsigned int pick_random_dv_hops (const struct DistanceVector *dv, enum RouteMessageOptions options, struct DistanceVectorHop **hops_array, unsigned int hops_array_length)
 Pick hops_array_length random DV paths satisfying options.
 
static int check_communicator_available (void *cls, const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
 Communicator started.
 
static void send_cmc_ack (struct CommunicatorMessageContext *cmc)
 Release the CORE flow control credit for cmc by acknowledging the message to the communicator that delivered it.
 
static void resume_cmc_client (struct CommunicatorMessageContext *cmc)
 Let the communicator that delivered cmc give us its next message.
 
static void finish_cmc_handling (struct CommunicatorMessageContext *cmc)
 
static void handle_client_recv_ok (void *cls, const struct RecvOkMessage *rom)
 Client confirms that it is done handling message(s) to a particular peer.
 
static void handle_communicator_available (void *cls, const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
 Communicator started.
 
static int check_communicator_backchannel (void *cls, const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
 Communicator requests backchannel transmission.
 
static enum GNUNET_GenericReturnValue sign_ephemeral (struct DistanceVector *dv)
 Sign the ephemeral key in dv, and mark it current.
 
static void free_queue_entry (struct QueueEntry *qe, struct TransportClient *tc)
 
static void free_timedout_queue_entry (void *cls)
 
static void queue_send_msg (struct Queue *queue, struct PendingMessage *pm, const void *payload, size_t payload_size)
 Send the message payload on queue.
 
static struct GNUNET_TIME_Relative route_via_neighbour (const struct Neighbour *n, const struct GNUNET_MessageHeader *hdr, enum RouteMessageOptions options)
 Pick a queue of n under constraints options and schedule transmission of hdr.
 
static struct GNUNET_TIME_Relative encapsulate_for_dv (struct DistanceVector *dv, unsigned int num_dvhs, struct DistanceVectorHop **dvhs, const struct GNUNET_MessageHeader *hdr, DVMessageHandler use, void *use_cls, enum RouteMessageOptions options, enum GNUNET_GenericReturnValue without_fc)
 Pick a path of dv under constraints options and schedule transmission of hdr.
 
static void send_dv_to_neighbour (void *cls, struct Neighbour *next_hop, const struct GNUNET_MessageHeader *hdr, enum RouteMessageOptions options)
 Wrapper around route_via_neighbour() that matches the DVMessageHandler structure.
 
static struct GNUNET_TIME_Relative route_control_message_without_fc (struct VirtualLink *vl, const struct GNUNET_MessageHeader *hdr, enum RouteMessageOptions options)
 We need to transmit hdr to target.
 
static void consider_sending_fc (void *cls)
 Something changed on the virtual link with respect to flow control.
 
static void task_consider_sending_fc (void *cls)
 Something changed on the virtual link with respect to flow control.
 
static char * get_address_without_port (const char *address)
 Get the IP address without the communicator prefix and the port number.
 
static enum GNUNET_GenericReturnValue add_global_addresses (void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
 
static struct GNUNET_TIME_Relative calculate_rtt (struct DistanceVector *dv)
 
static void check_vl_transmission (struct VirtualLink *vl)
 There is a message at the head of the pending messages for vl which may be ready for transmission.
 
static void handle_client_send (void *cls, const struct OutboundMessage *obm)
 Client asked for transmission to a peer.
 
static void handle_communicator_backchannel (void *cls, const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
 Communicator requests backchannel transmission.
 
static int check_add_address (void *cls, const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
 Address of our peer added.
 
static void store_pi (void *cls)
 Ask peerstore to store our address.
 
static void shc_cont (void *cls, int success)
 
static void pils_sign_hello_cb (void *cls, const struct GNUNET_PeerIdentity *pid, const struct GNUNET_CRYPTO_EddsaSignature *sig)
 Get HELLO signature and create message to store in PEERSTORE.
 
static void peerstore_store_own_cb (void *cls, int success)
 Function called when peerstore is done storing our address.
 
static void store_signed_address (struct PilsAddressSignContext *pc, const struct GNUNET_PeerIdentity *pid, const struct GNUNET_CRYPTO_EddsaSignature *sig)
 Turn the signed address into a HELLO URI and hand it to PEERSTORE.
 
void pils_sign_address (struct AddressListEntry *ale, struct GNUNET_TIME_Absolute mono_time)
 Build address record by signing raw information with private key of the peer identity.
 
static struct AddressListEntrycreate_address_entry (struct TransportClient *tc, struct GNUNET_TIME_Relative expiration, enum GNUNET_NetworkType nt, const char *address, uint32_t aid, size_t slen)
 
static void feed_addresses_to_pils (void *cls)
 
static void handle_add_address (void *cls, const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
 Address of our peer added.
 
static void handle_del_address (void *cls, const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
 Address of our peer deleted.
 
static void demultiplex_with_cmc (struct CommunicatorMessageContext *cmc)
 Given an inbound message msg from a communicator cmc, demultiplex it based on the type calling the right handler.
 
static void core_env_sent_cb (void *cls)
 Function called when we are done giving a message of a certain size to CORE and should thus decrement the number of bytes of RAM reserved for that peer's MQ.
 
static void core_fc_stalled (void *cls)
 CORE never returned the flow control credit for the messages we handed it for cls, so the communicators that delivered them are still waiting on us.
 
static void finish_handling_raw_message (struct VirtualLink *vl, const struct GNUNET_MessageHeader *mh, struct CommunicatorMessageContext *cmc, unsigned int free_cmc)
 
static void handle_raw_message (void *cls, const struct GNUNET_MessageHeader *mh)
 Communicator gave us an unencapsulated message to pass as-is to CORE.
 
static int check_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
 Communicator gave us a fragment box.
 
static void destroy_ack_cummulator (void *cls)
 Clean up an idle cumulative acknowledgement data structure.
 
static void transmit_cummulative_ack_cb (void *cls)
 Do the transmission of a cumulative acknowledgement now.
 
static void cummulative_ack (const struct GNUNET_PeerIdentity *pid, const struct AcknowledgementUUIDP *ack_uuid, struct GNUNET_TIME_Absolute max_delay)
 Transmit an acknowledgement for ack_uuid to pid delaying transmission by at most ack_delay.
 
static int find_by_message_uuid (void *cls, uint32_t key, void *value)
 Iterator called to find a reassembly context by the message UUID in the multihashmap32.
 
static void handle_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
 Communicator gave us a fragment.
 
static int check_reliability_box (void *cls, const struct TransportReliabilityBoxMessage *rb)
 Communicator gave us a reliability box.
 
static void handle_reliability_box (void *cls, const struct TransportReliabilityBoxMessage *rb)
 Communicator gave us a reliability box.
 
static void update_pd_age (struct PerformanceData *pd, unsigned int age)
 Check if we have advanced to another age since the last time.
 
static void update_performance_data (struct PerformanceData *pd, struct GNUNET_TIME_Relative rtt, uint16_t bytes_transmitted_ok)
 Update pd based on the latest rtt and the number of bytes that were confirmed to be successfully transmitted.
 
static void update_queue_performance (struct Queue *q, struct GNUNET_TIME_Relative rtt, uint16_t bytes_transmitted_ok)
 We have successfully transmitted data via q, update metrics.
 
static void update_dvh_performance (struct DistanceVectorHop *dvh, struct GNUNET_TIME_Relative rtt, uint16_t bytes_transmitted_ok)
 We have successfully transmitted data via dvh, update metrics.
 
static void completed_pending_message (struct PendingMessage *pm)
 We have completed transmission of pm, remove it from the transmission queues (and if it is a fragment, continue up the tree as necessary).
 
static void handle_acknowledged (struct PendingAcknowledgement *pa, struct GNUNET_TIME_Relative ack_delay)
 The pa was acknowledged, process the acknowledgement.
 
static int check_reliability_ack (void *cls, const struct TransportReliabilityAckMessage *ra)
 Communicator gave us a reliability ack.
 
static void handle_reliability_ack (void *cls, const struct TransportReliabilityAckMessage *ra)
 Communicator gave us a reliability ack.
 
static int check_backchannel_encapsulation (void *cls, const struct TransportBackchannelEncapsulationMessage *be)
 Communicator gave us a backchannel encapsulation.
 
static void handle_backchannel_encapsulation (void *cls, const struct TransportBackchannelEncapsulationMessage *be)
 Communicator gave us a backchannel encapsulation.
 
static void path_cleanup_cb (void *cls)
 Task called when we should check if any of the DV paths we have learned to a target are due for garbage collection.
 
static void send_msg_from_cache (struct VirtualLink *vl)
 
static void activate_core_visible_dv_path (struct DistanceVectorHop *hop)
 The hop is a validated path to the respective target peer and we should tell core about it – and schedule a job to revoke the state.
 
static int learn_dv_path (const struct GNUNET_PeerIdentity *path, unsigned int path_len, struct GNUNET_TIME_Relative network_latency, struct GNUNET_TIME_Absolute path_valid_until)
 We have learned a path through the network to some other peer, add it to our DV data structure (returning GNUNET_YES on success).
 
static int check_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
 Communicator gave us a DV learn message.
 
static void forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop, const struct TransportDVLearnMessage *msg, uint16_t bi_history, uint16_t nhops, const struct DVPathEntryP *hops, struct GNUNET_TIME_Absolute in_time)
 Build and forward a DV learn message to next_hop.
 
static int validate_dv_initiator_signature (struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time, const struct GNUNET_PeerIdentity *init, const struct GNUNET_CRYPTO_ChallengeNonceP *challenge, const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
 Check signature of type GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR.
 
static int dv_neighbour_selection (void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
 Function called for each neighbour during handle_dv_learn.
 
static int dv_neighbour_transmission (void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
 Function called for each neighbour during handle_dv_learn.
 
static unsigned int calculate_fork_degree (unsigned int hops_taken, unsigned int neighbour_count, unsigned int eligible_count)
 Computes the number of neighbours we should forward a DVInit message to given that it has so far taken hops_taken hops though the network and that the number of neighbours we have in total is neighbour_count, out of which eligible_count are not yet on the path.
 
static void neighbour_store_dvmono_cb (void *cls, int success)
 Function called when peerstore is done storing a DV monotonic time.
 
static struct GNUNET_TIME_Relative get_network_latency (const struct TransportDVLearnMessage *dvl)
 
static void handle_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
 Communicator gave us a DV learn message.
 
static int check_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
 Communicator gave us a DV box.
 
static void forward_dv_box (struct Neighbour *next_hop, struct TransportDVBoxMessage *hdr, uint16_t total_hops, uint16_t num_hops, const struct GNUNET_PeerIdentity *hops, const void *enc_payload, uint16_t enc_payload_size)
 Create a DV Box message and queue it for transmission to next_hop.
 
static void free_backtalker (struct Backtalker *b)
 Free data structures associated with b.
 
static int free_backtalker_cb (void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
 Callback to free backtalker records.
 
static void backtalker_timeout_cb (void *cls)
 Function called when it is time to clean up a backtalker.
 
static void backtalker_monotime_cb (void *cls, const struct GNUNET_PEERSTORE_Record *record, const char *emsg)
 Function called with the monotonic time of a backtalker by PEERSTORE.
 
static void backtalker_monotime_store_cb (void *cls, int success)
 Function called by PEERSTORE when the store operation of a backtalker's monotonic time is complete.
 
static void update_backtalker_monotime (struct Backtalker *b)
 The backtalker b monotonic time changed.
 
static void decaps_dv_box_cont (struct CommunicatorMessageContext *cmc, const struct TransportDVBoxMessage *dvb, const struct GNUNET_ShortHashCode *km)
 Open the DV box dvb addressed to us, using the key material km decapsulated from its ephemeral key.
 
static void handle_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
 Communicator gave us a DV box.
 
static int check_incoming_msg (void *cls, const struct GNUNET_TRANSPORT_IncomingMessage *im)
 Client notified us about transmission from a peer.
 
static int check_known_address (void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
 Test if the validation state in value matches the address from cls.
 
static void validation_start_cb (void *cls)
 Task run periodically to validate some address based on validation_heap.
 
static void update_next_challenge_time (struct ValidationState *vs, struct GNUNET_TIME_Absolute new_time)
 Set the time for next_challenge of vs to new_time.
 
static enum GNUNET_GenericReturnValue revalidate_now_cb (void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
 Pull value's next challenge forward: the link to that peer is not up.
 
static struct Queuefind_queue (const struct GNUNET_PeerIdentity *pid, const char *address)
 Find the queue matching pid and address.
 
static void suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address)
 Signature of a function called with a communicator address of a peer pid that an application wants us to connect to.
 
static void hello_for_incoming_cb (void *cls, const struct GNUNET_PeerIdentity *pid, const char *uri)
 
static const struct GNUNET_MessageHeaderhello_from_record (const struct GNUNET_PEERSTORE_Record *record)
 Obtain the HELLO message stored in record, if record actually carries one.
 
static void handle_hello_for_incoming (void *cls, const struct GNUNET_PEERSTORE_Record *record, const char *emsg)
 Function called by PEERSTORE for each matching record.
 
static void hello_for_incoming_error_cb (void *cls)
 
static void hello_for_incoming_sync_cb (void *cls)
 
static void send_t_validation_response (struct CommunicatorMessageContext *cmc, struct TransportValidationResponseMessage tvr)
 Route the signed validation response tvr back to the challenger and release cmc.
 
static void handle_validation_challenge (void *cls, const struct TransportValidationChallengeMessage *tvc)
 Communicator gave us a transport address validation challenge.
 
static int check_known_challenge (void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
 Test if the validation state in value matches the challenge from cls.
 
static void peerstore_store_validation_cb (void *cls, int success)
 Function called when peerstore is done storing a validated address.
 
static struct Queuefind_queue_by_ip (const struct GNUNET_PeerIdentity *pid, const char *address)
 Find a queue to pid whose address has the same IP as address, but possibly a different port.
 
static void validation_transmit_on_queue (struct Queue *q, struct ValidationState *vs)
 The queue q (which matches the peer and address in vs) is ready for queueing.
 
static void revalidation_start_cb (void *cls)
 
static enum GNUNET_GenericReturnValue revalidate_map_it (void *cls, const struct GNUNET_HashCode *key, void *value)
 
static void handle_validation_response (void *cls, const struct TransportValidationResponseMessage *tvr)
 Communicator gave us a transport address validation response.
 
static void handle_incoming_msg (void *cls, const struct GNUNET_TRANSPORT_IncomingMessage *im)
 Incoming message.
 
static int check_flow_control (void *cls, const struct TransportFlowControlMessage *fc)
 Communicator gave us a transport address validation response.
 
static void iterate_address_start_burst (void *cls, const struct GNUNET_PeerIdentity *pid, const char *uri)
 
static void check_for_burst_address (void *cls, const struct GNUNET_PEERSTORE_Record *record, const char *emsg)
 
static void burst_timeout (void *cls)
 
static void start_burst (void *cls)
 
static void queue_burst (void *cls)
 
static void unconfirmed_link_timeout (void *cls)
 Discard a virtual link that only ever existed because some peer sent us a FLOW_CONTROL message and that never became confirmed.
 
static void handle_flow_control (void *cls, const struct TransportFlowControlMessage *fc)
 Communicator gave us a transport address validation response.
 
static int check_add_queue_message (void *cls, const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
 New queue became available.
 
static void set_pending_message_uuid (struct PendingMessage *pm)
 If necessary, generates the UUID for a pm.
 
static struct PendingAcknowledgementprepare_pending_acknowledgement (struct Queue *queue, struct DistanceVectorHop *dvh, struct PendingMessage *pm)
 Setup data structure waiting for acknowledgements.
 
static struct PendingMessagefragment_message (struct Queue *queue, struct DistanceVectorHop *dvh, struct PendingMessage *pm)
 Fragment the given pm to the given mtu.
 
static struct PendingMessagereliability_box_message (struct Queue *queue, struct DistanceVectorHop *dvh, struct PendingMessage *pm)
 Reliability-box the given pm.
 
static void reorder_root_pm (struct PendingMessage *pm, struct GNUNET_TIME_Absolute next_attempt)
 
static unsigned int check_next_attempt_tree (struct PendingMessage *pm, struct PendingMessage *root)
 
static void harmonize_flight_round (struct PendingMessage *pm)
 
static void update_pm_next_attempt (struct PendingMessage *pm, struct GNUNET_TIME_Absolute next_attempt)
 Change the value of the next_attempt field of pm to next_attempt and re-order pm in the transmission list as required by the new timestamp.
 
static void select_best_pending_from_link (struct PendingMessageScoreContext *sc, struct Queue *queue, struct VirtualLink *vl, struct DistanceVectorHop *dvh, size_t overhead)
 Select the best pending message from vl for transmission via queue.
 
static void extract_box_cb (void *cls, struct Neighbour *next_hop, const struct GNUNET_MessageHeader *hdr, enum RouteMessageOptions options)
 Function to call to further operate on the now DV encapsulated message hdr, forwarding it via next_hop under respect of options.
 
static void handle_del_queue_message (void *cls, const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
 Queue to a peer went down.
 
static void handle_send_message_ack (void *cls, const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
 Message was transmitted.
 
static void handle_burst_finished (void *cls, const struct GNUNET_TRANSPORT_BurstFinished *bf)
 The burst finished.
 
static int notify_client_queues (void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
 Iterator telling new MONITOR client about all existing queues to peers.
 
static void handle_monitor_start (void *cls, const struct GNUNET_TRANSPORT_MonitorStart *start)
 Initialize a monitor client.
 
static char * communicator_list (struct Neighbour *n, unsigned int *num_queues)
 Build the 0-terminated, comma-separated list of address prefixes of the communicators that own the queues of n, without repeats.
 
static enum GNUNET_GenericReturnValue report_link (void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
 Send the state of the virtual link value to the requesting client.
 
static void handle_link_list_request (void *cls, const struct GNUNET_TRANSPORT_LinkListRequest *lr)
 A client asks for the virtual links we currently have.
 
static struct TransportClientlookup_communicator (const char *prefix)
 Find transport client providing communication service for the protocol prefix.
 
static struct GNUNET_TIME_Relative validation_challenge_freq (const struct GNUNET_PeerIdentity *pid)
 How slow are we allowed to get with challenges for pid?
 
static int check_connection_quality (void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
 Check whether any queue to the given neighbour is of a good "quality" and if so, increment the counter.
 
static void start_dv_learn (void *cls)
 Task run when we CONSIDER initiating a DV learn process.
 
static void transmit_dv_init (struct TransportDVLearnMessage dvl, struct LearnLaunchEntry *lle, struct QueueQualityContext qqc)
 Finish and transmit the DV learn message dvl we initiated.
 
static int check_validation_request_pending (void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
 A new queue has been created, check if any address validation requests have been waiting for it.
 
static void neighbour_dv_monotime_cb (void *cls, const struct GNUNET_PEERSTORE_Record *record, const char *emsg)
 Function called with the monotonic time of a DV initiator by PEERSTORE.
 
static void iterate_address_and_compare_cb (void *cls, const struct GNUNET_PeerIdentity *pid, const char *uri)
 
static enum GNUNET_GenericReturnValue contains_address (void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
 
static void check_for_global_natted_error_cb (void *cls)
 
static void check_for_global_natted_sync_cb (void *cls)
 
static void check_for_global_natted (void *cls, const struct GNUNET_PEERSTORE_Record *record, const char *emsg)
 
static void handle_add_queue_message (void *cls, const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
 New queue became available.
 
static void handle_update_queue_message (void *cls, const struct GNUNET_TRANSPORT_UpdateQueueMessage *msg)
 Handle updates to queues.
 
static void handle_queue_create_ok (void *cls, const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
 Communicator tells us that our request to create a queue "worked", that is setting up the queue is now in process.
 
static void handle_queue_create_fail (void *cls, const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
 Communicator tells us that our request to create a queue failed.
 
static void handle_suggest_cancel (void *cls, const struct ExpressPreferenceMessage *msg)
 An application client no longer wants us to connect to a peer it asked for earlier.
 
static void hello_for_client_cb (void *cls, const struct GNUNET_PeerIdentity *pid, const char *uri)
 
static void handle_hello_for_client (void *cls, const struct GNUNET_PEERSTORE_Record *record, const char *emsg)
 Function called by PEERSTORE for each matching record.
 
static void hello_for_client_error_cb (void *cls)
 
static void hello_for_client_sync_cb (void *cls)
 
static void start_peer_request_monitor (struct PeerRequest *pr)
 (Re)start the PEERSTORE HELLO monitor of pr.
 
static void suggest_retry_cb (void *cls)
 Task run for as long as an application client wants a link to pid that we do not have.
 
static void handle_suggest (void *cls, const struct ExpressPreferenceMessage *msg)
 We have received a struct ExpressPreferenceMessage from an application client.
 
static int check_request_hello_validation (void *cls, const struct RequestHelloValidationMessage *m)
 Check GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION messages.
 
static void handle_request_hello_validation (void *cls, const struct RequestHelloValidationMessage *m)
 A client encountered an address of another peer.
 
static int free_neighbour_cb (void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
 Free neighbour entry.
 
static int free_virtual_link_cb (void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
 Free virtual link entry.
 
static int free_dv_routes_cb (void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
 Free DV route entry.
 
static int free_validation_state_cb (void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
 Free validation state.
 
static int free_pending_ack_cb (void *cls, const struct GNUNET_Uuid *key, void *value)
 Free pending acknowledgement.
 
static int free_ack_cummulator_cb (void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
 Free acknowledgement cummulator.
 
static const char * get_client_type_name (enum ClientType type)
 
static void drop_remaining_clients (void *cls)
 The grace period we gave our clients to disconnect on their own expired.
 
static void shutdown_task (void *cls)
 
static void update_hello_from_pid_change_cb (void *cls, int success)
 
void print_address_list (void *cls, const struct GNUNET_PeerIdentity *pid, const char *uri)
 
static void pils_pid_change_cb (void *cls, const struct GNUNET_HELLO_Parser *parser, const struct GNUNET_HashCode *hash)
 Callback called when pils service updates us with our new peer identity.
 
static void run (void *cls, const struct GNUNET_CONFIGURATION_Handle *c, struct GNUNET_SERVICE_Handle *service)
 Initiate transport service.
 
 GNUNET_SERVICE_MAIN (GNUNET_OS_project_data_gnunet(), "transport", GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN, &run, &client_connect_cb, &client_disconnect_cb, NULL, GNUNET_MQ_hd_fixed_size(suggest, GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST, struct ExpressPreferenceMessage, NULL), GNUNET_MQ_hd_fixed_size(suggest_cancel, GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL, struct ExpressPreferenceMessage, NULL), GNUNET_MQ_hd_var_size(request_hello_validation, GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION, struct RequestHelloValidationMessage, NULL), GNUNET_MQ_hd_fixed_size(client_start, GNUNET_MESSAGE_TYPE_TRANSPORT_START, struct StartMessage, NULL), GNUNET_MQ_hd_var_size(client_send, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, struct OutboundMessage, NULL), GNUNET_MQ_hd_fixed_size(client_recv_ok, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK, struct RecvOkMessage, NULL), GNUNET_MQ_hd_var_size(communicator_available, GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR, struct GNUNET_TRANSPORT_CommunicatorAvailableMessage, NULL), GNUNET_MQ_hd_var_size(communicator_backchannel, GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL, struct GNUNET_TRANSPORT_CommunicatorBackchannel, NULL), GNUNET_MQ_hd_var_size(add_address, GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS, struct GNUNET_TRANSPORT_AddAddressMessage, NULL), GNUNET_MQ_hd_fixed_size(del_address, GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS, struct GNUNET_TRANSPORT_DelAddressMessage, NULL), GNUNET_MQ_hd_var_size(incoming_msg, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG, struct GNUNET_TRANSPORT_IncomingMessage, NULL), GNUNET_MQ_hd_fixed_size(queue_create_ok, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK, struct GNUNET_TRANSPORT_CreateQueueResponse, NULL), GNUNET_MQ_hd_fixed_size(queue_create_fail, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL, struct GNUNET_TRANSPORT_CreateQueueResponse, NULL), GNUNET_MQ_hd_var_size(add_queue_message, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP, struct GNUNET_TRANSPORT_AddQueueMessage, NULL), GNUNET_MQ_hd_fixed_size(update_queue_message, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_UPDATE, struct GNUNET_TRANSPORT_UpdateQueueMessage, NULL), GNUNET_MQ_hd_fixed_size(del_queue_message, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN, struct GNUNET_TRANSPORT_DelQueueMessage, NULL), GNUNET_MQ_hd_fixed_size(send_message_ack, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK, struct GNUNET_TRANSPORT_SendMessageToAck, NULL), GNUNET_MQ_hd_fixed_size(burst_finished, GNUNET_MESSAGE_TYPE_TRANSPORT_BURST_FINISHED, struct GNUNET_TRANSPORT_BurstFinished, NULL), GNUNET_MQ_hd_fixed_size(monitor_start, GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START, struct GNUNET_TRANSPORT_MonitorStart, NULL), GNUNET_MQ_hd_fixed_size(link_list_request, GNUNET_MESSAGE_TYPE_TRANSPORT_LINK_LIST_REQUEST, struct GNUNET_TRANSPORT_LinkListRequest, NULL), GNUNET_MQ_handler_end())
 Define "main" method using service macro.
 

Variables

static struct RingBufferEntryring_buffer [RING_BUFFER_SIZE]
 Ring buffer for a CORE message we did not deliver to CORE, because of missing virtual link to sender.
 
static unsigned int ring_buffer_head
 Head of the ring buffer.
 
static unsigned int is_ring_buffer_full
 Is the ring buffer filled up to RING_BUFFER_SIZE.
 
static struct PendingMessagering_buffer_dv [RING_BUFFER_SIZE]
 Ring buffer for a forwarded DVBox message we did not deliver to the next hop, because of missing virtual link that hop.
 
static unsigned int ring_buffer_dv_head
 Head of the ring buffer.
 
static unsigned int is_ring_buffer_dv_full
 Is the ring buffer filled up to RING_BUFFER_SIZE.
 
static struct TransportClientclients_head
 Head of linked list of all clients to this service.
 
static struct TransportClientclients_tail
 Tail of linked list of all clients to this service.
 
static struct GNUNET_STATISTICS_HandleGST_stats
 Statistics handle.
 
static const struct GNUNET_CONFIGURATION_HandleGST_cfg
 Configuration handle.
 
static struct GNUNET_SERVICE_HandleGST_service
 Our service handle; needed to force-disconnect clients that did not go away within SHUTDOWN_CLIENT_GRACE_PERIOD, as we use GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN.
 
static struct GNUNET_SCHEDULER_Taskclient_grace_task
 Task run when SHUTDOWN_CLIENT_GRACE_PERIOD expired and clients are still connected, or NULL.
 
struct GNUNET_HELLO_BuilderGST_my_hello
 Our HELLO.
 
static struct GNUNET_CONTAINER_MultiPeerMapneighbours
 Map from PIDs to struct Neighbour entries.
 
static struct GNUNET_CONTAINER_MultiPeerMapbacktalkers
 Map from PIDs to struct Backtalker entries.
 
static struct GNUNET_CONTAINER_MultiPeerMapack_cummulators
 Map from PIDs to struct AcknowledgementCummulators.
 
static struct GNUNET_CONTAINER_MultiUuidmappending_acks
 Map of pending acknowledgements, mapping struct AcknowledgementUUID to a struct PendingAcknowledgement.
 
static struct GNUNET_CONTAINER_MultiPeerMapdv_routes
 Map from PIDs to struct DistanceVector entries describing known paths to the peer.
 
static struct GNUNET_CONTAINER_MultiPeerMapvalidation_map
 Map from PIDs to struct ValidationState entries describing addresses we are aware of and their validity state.
 
static struct GNUNET_CONTAINER_MultiHashMaprevalidation_map
 Map from addresses to struct ValidationState entries describing addresses we are aware of and their validity state.
 
static struct GNUNET_CONTAINER_MultiPeerMaplinks
 Map from PIDs to struct VirtualLink entries describing links CORE knows to exist.
 
static struct GNUNET_CONTAINER_MultiShortmapdvlearn_map
 Map from challenges to struct LearnLaunchEntry values.
 
static struct LearnLaunchEntrylle_head = NULL
 Head of a DLL sorted by launch time.
 
static struct LearnLaunchEntrylle_tail = NULL
 Tail of a DLL sorted by launch time.
 
static struct GNUNET_CONTAINER_Heapvalidation_heap
 MIN Heap sorted by "next_challenge" to struct ValidationState entries sorting addresses we are aware of by when we should next try to (re)validate (or expire) them.
 
struct GNUNET_NAT_Handlenh
 Handle for connect to the NAT service.
 
static struct GNUNET_PEERSTORE_Handlepeerstore
 Database for peer's HELLOs.
 
static struct GNUNET_PILS_Handlepils
 Service that manages our peer id.
 
static struct PilsRequestpils_requests_head
 PILS Operation DLL.
 
static struct PilsRequestpils_requests_tail
 PILS Operation DLL.
 
static struct GNUNET_SCHEDULER_Taskdvlearn_task
 Task run to initiate DV learning.
 
static struct GNUNET_TIME_Relative dvlearn_pils_backoff
 Backoff for start_dv_learn() while PILS still owes us an identity.
 
static struct GNUNET_SCHEDULER_Taskvalidation_task
 Task to run address validation.
 
static struct GNUNET_SCHEDULER_Taskpils_feed_task
 Task to feed addresses to PILS.
 
static struct IncomingRequestir_head
 List of incoming connections where we are trying to get a connection back established.
 
static struct IncomingRequestir_tail
 Tail of DLL starting at ir_head.
 
static unsigned int ir_total
 Length of the DLL starting at ir_head.
 
static unsigned long long logging_uuid_gen
 Generator of logging_uuid in struct PendingMessage.
 
static enum GNUNET_GenericReturnValue burst_running
 Is there a burst running?
 
static struct GNUNET_TIME_Absolute hello_mono_time
 Monotonic time we use for HELLOs generated at this time.
 
static int in_shutdown
 Indication if we have received a shutdown signal and are in the process of cleaning up.
 
static struct GNUNET_SCHEDULER_Taskburst_task
 The task to start the burst.
 
static struct GNUNET_StartBurstClsburst_task_cls
 Closure of the currently scheduled burst_task, or NULL.
 
struct GNUNET_SCHEDULER_Taskburst_timeout_task
 
enum GNUNET_GenericReturnValue use_burst
 

Detailed Description

main for gnunet-service-transport

Author
Christian Grothoff

TODO: Implement next:

  • review retransmission logic, right now there is no smartness there! => congestion control, etc [PERFORMANCE-BASICS]

Optimizations-Statistics:

  • Track ACK losses based on ACK-counter [ROUTING]
  • Need to track total bandwidth per VirtualLink and adjust how frequently we send FC messages based on bandwidth-delay-product (and relation to the window size!). See OPTIMIZE-FC-BDP.
  • Consider more statistics in check_connection_quality() [FIXME-CONQ-STATISTICS]
  • Adapt available_fc_window_size, using larger values for high-bandwidth and high-latency links if we have the RAM [GOODPUT / utilization / stalls]
  • Set last_window_consum_limit promise properly based on latency and bandwidth of the respective connection [GOODPUT / utilization / stalls]

Optimizations-DV:

  • When forwarding DV learn messages, if a peer is reached that has a bidirectional link to the origin beyond 1st hop, do NOT forward it to peers other than the origin, as there is clearly a better path directly from the origin to whatever else we could reach.
  • When we passively learned DV (with unconfirmed freshness), we right now add the path to our list but with a zero path_valid_until time and only use it for unconfirmed routes. However, we could consider triggering an explicit validation mechanism ourselves, specifically routing a challenge-response message over the path [ROUTING] = if available, try to confirm unconfirmed DV paths when trying to establish virtual link for a struct IncomingRequest. (i.e. if DVH is unconfirmed, incoming requests cause us to try to validate a passively learned path (requires new message type!))

Optimizations-Fragmentation:

  • Fragments send over a reliable channel could do without the AcknowledgementUUIDP altogether, as they won't be acked! [BANDWIDTH] (-> have 2nd type of acknowledgment message; low priority, as we do not have an MTU-limited reliable communicator) [FIXME-FRAG-REL-UUID]
  • if messages are below MTU, consider adding ACKs and other stuff to the same transmission to avoid tiny messages (requires planning at receiver, and additional MST-style demultiplex at receiver!) [PACKET COUNT]

Optimizations-internals:

  • queue_send_msg by API design has to make a copy of the payload, and route_message on top of that requires a malloc/free. Change design to approximate "zero" copy better... [CPU]
  • could avoid copying body of message into each fragment and keep fragments as just pointers into the original message and only fully build fragments just before transmission (optimization, should reduce CPU and memory use) [CPU, MEMORY]

Definition in file gnunet-service-transport.c.

Macro Definition Documentation

◆ RING_BUFFER_SIZE

#define RING_BUFFER_SIZE   16

Size of ring buffer to cache CORE and forwarded DVBox messages.

Definition at line 90 of file gnunet-service-transport.c.

◆ MAX_FC_RETRANSMIT_COUNT

#define MAX_FC_RETRANSMIT_COUNT   1000

Maximum number of FC retransmissions for a running retransmission task.

Definition at line 95 of file gnunet-service-transport.c.

◆ MIN_FC_RETRANSMIT_DELAY

#define MIN_FC_RETRANSMIT_DELAY    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100)

Lower bound on the delay between two flow control transmissions on the same virtual link.

Without this an RTT estimate of zero turns consider_sending_fc() into a tight loop.

Definition at line 102 of file gnunet-service-transport.c.

515{
520 uint64_t uuid GNUNET_PACKED;
521};
522
523
528{
532 struct GNUNET_Uuid value;
533};
534
539{
544
545 /* Followed by *another* message header which is the message to
546 the communicator */
547
548 /* Followed by a 0-terminated name of the communicator */
549};
550
551
556{
561
577
582
588};
589
590
596{
601
607
619
620 /* Followed by a `struct GNUNET_MessageHeader` with a message
621 for the target peer */
622};
623
624
630{
635
643
650};
651
652
657{
665
670};
671
672
681{
686
691 uint32_t ack_counter GNUNET_PACKED;
692
693 /* followed by any number of `struct TransportCummulativeAckPayloadP`
694 messages providing ACKs */
695};
696
697
702{
707
711 uint16_t frag_off GNUNET_PACKED;
712
716 uint16_t msg_size GNUNET_PACKED;
717
726
731 struct MessageUUIDP msg_uuid;
732};
733
734
752struct DvInitPS
753{
758
772
777};
778
779
796struct DvHopPS
797{
802
807
812
817};
818
819
824struct DVPathEntryP
825{
830
836};
837
838
853{
858
863 uint16_t num_hops GNUNET_PACKED;
864
874
881
895
901
906
911
912 /* Followed by @e num_hops `struct DVPathEntryP` values,
913 excluding the initiator of the DV trace; the last entry is the
914 current sender; the current peer must not be included. */
915};
916
917
941{
946
950 uint32_t without_fc GNUNET_PACKED;
951
958 uint16_t total_hops GNUNET_PACKED;
959
965 uint16_t num_hops GNUNET_PACKED;
966
972
979
986
992 uint16_t orig_size GNUNET_PACKED;
993
994 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values;
995 excluding the @e origin and the current peer, the last must be
996 the ultimate target; if @e num_hops is zero, the receiver of this
997 message is the ultimate target. */
998
999 /* Followed by encrypted, variable-size payload, which
1000 must begin with a `struct TransportDVBoxPayloadP` */
1001
1002 /* Followed by the actual message, which itself must not be a
1003 a DV_LEARN or DV_BOX message! */
1004};
1005
1006
1012{
1017
1021 uint32_t reserved GNUNET_PACKED;
1022
1027
1033};
1034
1035
1041{
1046
1052
1057};
1058
1059
1065{
1070
1074 uint32_t reserved GNUNET_PACKED;
1075
1081
1086
1091 struct GNUNET_TIME_AbsoluteNBO origin_time;
1092
1097 struct GNUNET_TIME_RelativeNBO validity_duration;
1098};
1099
1101{
1106
1107 /* Followed by @e address_length bytes of the address. */
1108};
1109
1119{
1124
1132 uint32_t seq GNUNET_PACKED;
1133
1139
1146
1156
1166
1171
1175 uint32_t sync_ready GNUNET_PACKED;
1176
1181
1187
1188 /* Followed by @e number_of_addresses struct TransportGlobalNattedAddress. */
1189};
1190
1192
1193/* GNUNET_NETWORK_STRUCT_BEGIN/_END expand to nothing; only the per-member
1194 GNUNET_PACKED keeps these layouts free of compiler padding. Pin the sizes
1195 so that adding an unpacked or non-fixed-width member cannot silently put
1196 padding bytes -- i.e. uninitialised stack -- on the wire again. */
1198
1200GNUNET_static_assert (sizeof(struct TransportDVBoxMessage) == 86);
1201GNUNET_static_assert (sizeof(struct TransportDVLearnMessage) == 152);
1207
1208
1212enum ClientType
1213{
1217 CT_NONE = 0,
1218
1222 CT_CORE = 1,
1223
1227 CT_MONITOR = 2,
1228
1232 CT_COMMUNICATOR = 3,
1233
1237 CT_APPLICATION = 4
1238};
1239
1240
1246{
1250 RMO_NONE = 0,
1251
1255 RMO_DV_ALLOWED = 1,
1256
1261
1266
1272 RMO_REDUNDANT = 4
1273};
1274
1275
1279struct LearnLaunchEntry
1280{
1284 struct LearnLaunchEntry *prev;
1285
1289 struct LearnLaunchEntry *next;
1290
1295
1301};
1302
1303
1309{
1313 uint64_t bytes_sent;
1314
1319 uint64_t bytes_received;
1320};
1321
1322
1326struct PerformanceData
1327{
1332
1338
1343 unsigned int last_age;
1344};
1345
1346
1350struct TransportClient;
1351
1355struct Neighbour;
1356
1361struct DistanceVector;
1362
1367struct Queue;
1368
1372struct PendingMessage;
1373
1377struct DistanceVectorHop;
1378
1387struct VirtualLink;
1388
1389
1395{
1401
1407
1413 struct TransportClient *tc;
1414
1419
1423 const struct GNUNET_MessageHeader *mh;
1424
1429 uint16_t total_hops;
1430
1436 unsigned int ack_sent;
1437
1444 unsigned int client_resumed;
1445};
1446
1447
1451struct RingBufferEntry
1452{
1457
1461 struct GNUNET_MessageHeader *mh;
1462};
1463
1464
1468struct CoreSentContext
1469{
1473 struct CoreSentContext *next;
1474
1478 struct CoreSentContext *prev;
1479
1483 struct VirtualLink *vl;
1484
1488 uint16_t size;
1489
1496 uint16_t isize;
1497};
1498
1499
1503struct ReassemblyContext
1504{
1509 struct MessageUUIDP msg_uuid;
1510
1514 struct VirtualLink *virtual_link;
1515
1520
1528 uint8_t *bitfield;
1529
1534
1540
1544 uint16_t msg_size;
1545
1550 uint16_t msg_missing;
1551
1552 /* Followed by @e msg_size bytes of the (partially) defragmented original
1553 * message */
1554
1555 /* Followed by @e bitfield data */
1556};
1557
1558
1567struct VirtualLink
1568{
1573
1580
1587
1592
1598
1604
1609 unsigned int cmc_count;
1610
1617
1622
1627
1631 struct CoreSentContext *csc_tail;
1632
1636 struct CoreSentContext *csc_head;
1637
1645
1651
1657
1662
1666 char *burst_addr;
1667
1671 unsigned int fc_retransmit_count;
1672
1677 unsigned int confirmed;
1678
1682 struct Neighbour *n;
1683
1687 struct DistanceVector *dv;
1688
1695
1702
1711
1717
1723
1728
1733 uint64_t message_uuid_ctr;
1734
1742 uint64_t available_fc_window_size;
1743
1751
1757 uint64_t incoming_fc_window_size;
1758
1767
1780
1785 uint64_t outbound_fc_window_size;
1786
1793
1804
1809 uint32_t fc_seq_gen;
1810
1816 uint32_t last_fc_seq;
1817
1829 int core_recv_window;
1830
1835};
1836
1837
1842{
1848
1854
1861
1868
1875
1882
1887
1892 struct PendingMessage *pm;
1893
1898 struct DistanceVectorHop *dvh;
1899
1904 struct Queue *queue;
1905
1910
1914 uint16_t message_size;
1915
1919 unsigned int num_send;
1920};
1921
1922
1926struct DistanceVectorHop
1927{
1931 struct DistanceVectorHop *next_dv;
1932
1936 struct DistanceVectorHop *prev_dv;
1937
1942
1947
1952
1957
1961 struct Neighbour *next_hop;
1962
1966 struct DistanceVector *dv;
1967
1973 const struct GNUNET_PeerIdentity *path;
1974
1980
1989
1993 struct PerformanceData pd;
1994
2000 unsigned int distance;
2001};
2002
2003
2008struct DistanceVector
2009{
2014
2018 struct DistanceVectorHop *dv_head;
2019
2023 struct DistanceVectorHop *dv_tail;
2024
2029
2034 struct VirtualLink *vl;
2035
2041
2046
2051
2056
2060 struct GNUNET_ShortHashCode *km;
2061};
2062
2063
2073struct QueueEntry
2074{
2078 struct QueueEntry *next;
2079
2083 struct QueueEntry *prev;
2084
2088 struct Queue *queue;
2089
2093 struct PendingMessage *pm;
2094
2098 uint64_t mid;
2099
2104};
2105
2106
2111struct Queue
2112{
2116 struct Queue *next_neighbour;
2117
2121 struct Queue *prev_neighbour;
2122
2126 struct Queue *prev_client;
2127
2131 struct Queue *next_client;
2132
2137
2142
2146 struct QueueEntry *queue_head;
2147
2151 struct QueueEntry *queue_tail;
2152
2156 struct Neighbour *neighbour;
2157
2161 struct TransportClient *tc;
2162
2166 const char *address;
2167
2171 unsigned int unlimited_length;
2172
2178
2187
2191 struct PerformanceData pd;
2192
2198
2203 uint64_t mid_gen;
2204
2208 uint32_t qid;
2209
2213 uint32_t mtu;
2214
2218 uint32_t num_msg_pending;
2219
2223 uint32_t num_bytes_pending;
2224
2228 unsigned int queue_length;
2229
2233 uint64_t q_capacity;
2234
2238 uint32_t priority;
2239
2244
2249
2254 int idle;
2255
2260};
2261
2262
2266struct Neighbour
2267{
2271 struct GNUNET_PeerIdentity pid;
2272
2277 struct DistanceVectorHop *dv_head;
2278
2283 struct DistanceVectorHop *dv_tail;
2284
2292
2296 struct Queue *queue_head;
2297
2301 struct Queue *queue_tail;
2302
2308
2314
2319 struct VirtualLink *vl;
2320
2326
2332
2337
2341 unsigned int number_of_addresses;
2342
2347
2352};
2353
2354
2359struct IncomingRequest
2360{
2364 struct IncomingRequest *next;
2365
2369 struct IncomingRequest *prev;
2370
2375
2379 struct GNUNET_PeerIdentity pid;
2380};
2381
2382
2386struct PeerRequest
2387{
2391 struct GNUNET_PeerIdentity pid;
2392
2396 struct TransportClient *tc;
2397
2402
2408
2414
2421
2426};
2427
2428
2433{
2437 PMT_CORE = 0,
2438
2442 PMT_FRAGMENT_BOX = 1,
2443
2448
2452 PMT_DV_BOX = 3
2453};
2454
2455
2482struct PendingMessage
2483{
2487 struct PendingMessage *next_vl;
2488
2492 struct PendingMessage *prev_vl;
2493
2498
2503
2508 struct PendingMessage *next_frag;
2509
2514 struct PendingMessage *prev_frag;
2515
2520
2525
2530 struct PendingMessage *bpm;
2531
2536 struct VirtualLink *vl;
2537
2542
2551 struct QueueEntry *qe;
2552
2556 struct TransportClient *client;
2557
2561 struct PendingMessage *head_frag;
2562
2566 struct PendingMessage *tail_frag;
2567
2572
2577
2582
2587 struct MessageUUIDP msg_uuid;
2588
2593 uint64_t logging_uuid;
2594
2599
2605
2610
2614 uint16_t bytes_msg;
2615
2619 uint16_t frag_off;
2620
2624 uint32_t frags_in_flight;
2625
2629 uint32_t frags_in_flight_round;
2630
2634 uint16_t frag_count;
2635
2639 int16_t msg_uuid_set;
2640
2648 int16_t client_credited;
2649
2650 /* Followed by @e bytes_msg to transmit */
2651};
2652
2653
2658{
2664
2669};
2670
2671
2677{
2682
2687
2694
2699
2705 uint32_t ack_counter;
2706
2710 unsigned int num_acks;
2711};
2712
2713
2719
2720
2724struct AddressListEntry
2725{
2729 struct AddressListEntry *next;
2730
2734 struct AddressListEntry *prev;
2735
2739 struct TransportClient *tc;
2740
2745
2752 struct PilsAddressSignContext *pc;
2753
2757 const char *address;
2758
2762 void *signed_address;
2763
2767 size_t signed_address_len;
2768
2773
2777 struct GNUNET_SCHEDULER_Task *st;
2778
2784
2789
2793 uint32_t aid;
2794
2799};
2800
2801
2805struct TransportClient
2806{
2810 struct TransportClient *next;
2811
2815 struct TransportClient *prev;
2816
2821
2825 struct GNUNET_MQ_Handle *mq;
2826
2830 enum ClientType type;
2831
2832 union
2833 {
2837 struct
2838 {
2844
2849 } core;
2850
2854 struct
2855 {
2862
2866 int one_shot;
2867 } monitor;
2868
2869
2873 struct
2874 {
2879 char *address_prefix;
2880
2884 struct Queue *queue_head;
2885
2889 struct Queue *queue_tail;
2890
2896
2902
2908 unsigned int total_queue_length;
2909
2914
2919
2924
2925 } communicator;
2926
2930 struct
2931 {
2937 } application;
2938 } details;
2939};
2940
2941
2946struct ValidationState
2947{
2952 struct GNUNET_PeerIdentity pid;
2953
2961
2967
2974 struct GNUNET_TIME_Absolute first_challenge_use;
2975
2982 struct GNUNET_TIME_Absolute last_challenge_use;
2983
2991 struct GNUNET_TIME_Absolute next_challenge;
2992
3001 struct GNUNET_TIME_Relative challenge_backoff;
3002
3007 struct GNUNET_TIME_Relative validation_rtt;
3008
3016 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
3017
3021 struct GNUNET_HashCode hc;
3022
3026 struct GNUNET_SCHEDULER_Task *revalidation_task;
3027
3031 char *address;
3032
3038 struct GNUNET_CONTAINER_HeapNode *hn;
3039
3045
3051 uint32_t last_window_consum_limit;
3052
3057 int awaiting_queue;
3058};
3059
3060
3067struct Backtalker
3068{
3072 struct GNUNET_PeerIdentity pid;
3073
3078
3083
3088
3094
3099
3105
3111
3116 size_t body_size;
3117};
3118
3123
3127static unsigned int ring_buffer_head;
3128
3132static unsigned int is_ring_buffer_full;
3133
3138
3142static unsigned int ring_buffer_dv_head;
3143
3147static unsigned int is_ring_buffer_dv_full;
3148
3152static struct TransportClient *clients_head;
3153
3157static struct TransportClient *clients_tail;
3158
3162static struct GNUNET_STATISTICS_Handle *GST_stats;
3163
3167static const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
3168
3174static struct GNUNET_SERVICE_Handle *GST_service;
3175
3181
3186
3192
3198
3204
3210
3216
3222
3228
3234
3239
3243static struct LearnLaunchEntry *lle_head = NULL;
3244
3248static struct LearnLaunchEntry *lle_tail = NULL;
3249
3256
3260struct GNUNET_NAT_Handle *nh;
3261
3265static struct GNUNET_PEERSTORE_Handle *peerstore;
3266
3270static struct GNUNET_PILS_Handle *pils;
3271
3275struct PilsRequest
3276{
3280 struct PilsRequest *prev;
3281
3285 struct PilsRequest *next;
3286
3290 struct GNUNET_PILS_Operation *op;
3291};
3292
3296static struct PilsRequest *pils_requests_head;
3297
3301static struct PilsRequest *pils_requests_tail;
3302
3327static enum GNUNET_GenericReturnValue
3329 struct GNUNET_CRYPTO_EddsaSignature *sig)
3330{
3332
3334 if (NULL == my_private_key)
3335 {
3336 /* #run() enables local key access, so this means the key on disk does
3337 not match the identity PILS announced, or no identity is known yet. */
3339 "No private key for our peer identity, cannot sign\n");
3341 "# signatures failed (no private key)",
3342 1,
3343 GNUNET_NO);
3344 return GNUNET_SYSERR;
3345 }
3346 return GNUNET_CRYPTO_eddsa_sign_ (my_private_key, purpose, sig);
3347}
3348
3349
3353static struct GNUNET_SCHEDULER_Task *dvlearn_task;
3354
3359
3364
3369
3375static struct IncomingRequest *ir_head;
3376
3380static struct IncomingRequest *ir_tail;
3381
3385static unsigned int ir_total;
3386
3390static unsigned long long logging_uuid_gen;
3391
3396
3406
3411static int in_shutdown;
3412
3416static struct GNUNET_SCHEDULER_Task *burst_task;
3417
3424
3426
3428
3439static unsigned int
3440get_age ()
3441{
3442 struct GNUNET_TIME_Absolute now;
3443
3444 now = GNUNET_TIME_absolute_get ();
3445 return now.abs_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us / 15;
3446}
3447
3448
3454static void
3456{
3458 GNUNET_assert (ir_total > 0);
3459 ir_total--;
3460 if (NULL != ir->nc)
3462 ir->nc = NULL;
3463 GNUNET_free (ir);
3464}
3465
3466
3472static void
3474{
3475 struct Queue *q = pa->queue;
3476 struct PendingMessage *pm = pa->pm;
3477 struct DistanceVectorHop *dvh = pa->dvh;
3478
3480 "free_pending_acknowledgement\n");
3481 if (NULL != q)
3482 {
3483 GNUNET_CONTAINER_MDLL_remove (queue, q->pa_head, q->pa_tail, pa);
3484 pa->queue = NULL;
3485 }
3486 if (NULL != pm)
3487 {
3489 "remove pa from message\n");
3491 "remove pa from message %" PRIu64 "\n",
3492 pm->logging_uuid);
3494 "remove pa from message %u\n",
3495 pm->pmt);
3497 "remove pa from message %s\n",
3499 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
3500 pa->pm = NULL;
3501 }
3502 if (NULL != dvh)
3503 {
3504 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
3505 pa->dvh = NULL;
3506 }
3509 &pa->ack_uuid.value,
3510 pa));
3511 GNUNET_free (pa);
3512}
3513
3514
3523static void
3525{
3526 struct PendingMessage *frag;
3527
3528 while (NULL != (frag = root->head_frag))
3529 {
3530 struct PendingAcknowledgement *pa;
3531
3532 free_fragment_tree (frag);
3533 /* Release them: a `struct PendingAcknowledgement' whose @e pm is gone
3534 can never do anything useful again -- handle_acknowledged() would
3535 just free it -- but it stays in #pending_acks, and only an ACK that
3536 may never come takes it out. Merely detaching it here leaked one
3537 entry per fragment that was not acknowledged before its message went
3538 away, which on a lossy link is unbounded growth. */
3539 while (NULL != (pa = frag->pa_head))
3541 GNUNET_CONTAINER_MDLL_remove (frag, root->head_frag, root->tail_frag, frag);
3542 if (NULL != frag->qe)
3543 {
3544 GNUNET_assert (frag == frag->qe->pm);
3545 frag->qe->pm = NULL;
3546 }
3548 "Free frag %p\n",
3549 frag);
3550 GNUNET_free (frag);
3551 }
3552}
3553
3554
3562static void
3564{
3565 struct TransportClient *tc = pm->client;
3566 struct VirtualLink *vl = pm->vl;
3567 struct PendingAcknowledgement *pa;
3568
3570 "Freeing pm %p\n",
3571 pm);
3572 if (NULL != tc)
3573 {
3575 tc->details.core.pending_msg_head,
3576 tc->details.core.pending_msg_tail,
3577 pm);
3578 }
3579 if ((NULL != vl) && (NULL == pm->frag_parent))
3580 {
3582 "Removing pm %" PRIu64 "\n",
3583 pm->logging_uuid);
3585 vl->pending_msg_head,
3586 vl->pending_msg_tail,
3587 pm);
3588 }
3589 else if (NULL != pm->frag_parent && PMT_DV_BOX != pm->pmt)
3590 {
3591 struct PendingMessage *root = pm->frag_parent;
3592
3593 while (NULL != root->frag_parent && PMT_DV_BOX != root->pmt)
3594 root = root->frag_parent;
3595
3596 root->frag_count--;
3597 }
3598 /* Same as in #free_fragment_tree(): the message these acknowledgements
3599 belong to is going away, so they are garbage rather than orphans. */
3600 while (NULL != (pa = pm->pa_head))
3602
3603 free_fragment_tree (pm);
3604 if (NULL != pm->qe)
3605 {
3606 GNUNET_assert (pm == pm->qe->pm);
3607 pm->qe->pm = NULL;
3608 }
3609 if (NULL != pm->bpm)
3610 {
3611 free_fragment_tree (pm->bpm);
3612 /* @e bpm is released with GNUNET_free() rather than through
3613 #free_pending_message(), so nothing here ever unlinked the
3614 acknowledgements attached to the box itself -- only those of its
3615 fragments, via the call above. They kept @e pm pointing into the
3616 block we are about to release, and #handle_acknowledged() follows
3617 that pointer when the ACK finally arrives. */
3618 while (NULL != (pa = pm->bpm->pa_head))
3620 if (NULL != pm->bpm->qe)
3621 {
3622 struct QueueEntry *qe = pm->bpm->qe;
3623
3624 qe->pm = NULL;
3625 }
3626 GNUNET_free (pm->bpm);
3627 }
3628
3629 GNUNET_free (pm);
3631 "Freeing pm done\n");
3632}
3633
3634
3640static void
3642{
3643 struct VirtualLink *vl = rc->virtual_link;
3644
3648 rc->msg_uuid.uuid,
3649 rc));
3650 GNUNET_free (rc);
3651}
3652
3653
3659static void
3660reassembly_cleanup_task (void *cls)
3661{
3662 struct VirtualLink *vl = cls;
3663 struct ReassemblyContext *rc;
3664
3665 vl->reassembly_timeout_task = NULL;
3666 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (vl->reassembly_heap)))
3667 {
3669 .rel_value_us)
3670 {
3672 continue;
3673 }
3678 vl);
3679 return;
3680 }
3681}
3682
3683
3692static int
3693free_reassembly_cb (void *cls, uint32_t key, void *value)
3694{
3695 struct ReassemblyContext *rc = value;
3696
3697 (void) cls;
3698 (void) key;
3700 return GNUNET_OK;
3701}
3702
3703
3710static void
3712 unsigned int free_cmc);
3713
3714
3722static void
3724 struct CommunicatorMessageContext *cmc);
3725
3726
3733static void
3734free_burst_cls (struct GNUNET_StartBurstCls *sb_cls);
3735
3736
3754static void
3756 const struct GNUNET_PeerIdentity *pid)
3757{
3758 struct GNUNET_MQ_Envelope *env;
3759 struct SendOkMessage *so_msg;
3760
3761 if (NULL == tc)
3762 return;
3764 so_msg->peer = *pid;
3765 GNUNET_MQ_send (tc->mq, env);
3766}
3767
3768
3781static void
3782credit_client (struct PendingMessage *pm)
3783{
3784 if ((NULL == pm->client) || (GNUNET_YES == pm->client_credited))
3785 return;
3787 send_ok_to_client (pm->client, &pm->vl->target);
3788}
3789
3790
3796static void
3797free_virtual_link (struct VirtualLink *vl)
3798{
3799 struct PendingMessage *pm;
3800 struct CoreSentContext *csc;
3801 struct CommunicatorMessageContext *cmc;
3802
3804 "free virtual link %p\n",
3805 vl);
3806
3807 /* Communicators that are blocked on CORE flow control for this link MUST
3808 be resumed here. Otherwise their `struct CommunicatorMessageContext's
3809 leak and -- worse -- those clients never get their
3810 GNUNET_SERVICE_client_continue() and stall forever. */
3811 while (NULL != (cmc = vl->cmc_head))
3812 release_stalled_cmc (vl, cmc);
3813 if (NULL != vl->core_fc_stall_task)
3814 {
3816 vl->core_fc_stall_task = NULL;
3817 }
3818
3819 if (NULL != vl->reassembly_map)
3820 {
3823 NULL);
3825 vl->reassembly_map = NULL;
3827 vl->reassembly_heap = NULL;
3828 }
3829 if (NULL != vl->reassembly_timeout_task)
3830 {
3832 vl->reassembly_timeout_task = NULL;
3833 }
3834 while (NULL != (pm = vl->pending_msg_head))
3835 {
3836 /* These never got transmitted, so #completed_pending_message() will not
3837 run for them and nobody else answers their SEND either. Return the
3838 window credit anyway: CORE keeps its `struct Neighbour' -- and thus
3839 the window -- until it sees our DISCONNECT, and #handle_client_send()
3840 deliberately tolerates a SEND for a link that is already gone, so a
3841 client can easily still be sending while we free this. */
3842 credit_client (pm);
3844 }
3847 if (NULL != vl->visibility_task)
3848 {
3850 vl->visibility_task = NULL;
3851 }
3852 if (NULL != vl->fc_retransmit_task)
3853 {
3855 vl->fc_retransmit_task = NULL;
3856 }
3857 while (NULL != (csc = vl->csc_head))
3858 {
3860 GNUNET_assert (vl == csc->vl);
3861 csc->vl = NULL;
3862 }
3863 if (NULL != vl->unconfirmed_timeout_task)
3864 {
3866 vl->unconfirmed_timeout_task = NULL;
3867 }
3868 if (NULL != vl->ic)
3869 {
3870 /* the closure of this iteration is @e sb_cls, released just below */
3872 vl->ic = NULL;
3873 }
3874 if (NULL != vl->sb_cls)
3875 {
3876 /* Cancels #burst_task if that task's closure is ours: it would
3877 otherwise run on this (freed) link. */
3878 free_burst_cls (vl->sb_cls);
3879 GNUNET_assert (NULL == vl->sb_cls);
3880 }
3881 GNUNET_free (vl->burst_addr);
3882 GNUNET_break (NULL == vl->n);
3883 GNUNET_break (NULL == vl->dv);
3884 GNUNET_free (vl);
3885}
3886
3887
3893static void
3895{
3896 if (NULL != vs->revalidation_task)
3897 {
3898 GNUNET_SCHEDULER_cancel (vs->revalidation_task);
3899 vs->revalidation_task = NULL;
3900 }
3901 /*memcpy (&hkey,
3902 &hc,
3903 sizeof (hkey));*/
3905 "Remove key %s for address %s map size %u contains %u during freeing state\n",
3906 GNUNET_h2s (&vs->hc),
3907 vs->address,
3910 &vs->hc));
3913 GNUNET_YES ==
3916 vs->hn = NULL;
3917 if (NULL != vs->sc)
3918 {
3920 "store cancel\n");
3922 vs->sc = NULL;
3923 }
3924 GNUNET_free (vs->address);
3925 GNUNET_free (vs);
3926}
3927
3928
3935static struct Neighbour *
3937{
3939}
3940
3941
3948static struct VirtualLink *
3949lookup_virtual_link (const struct GNUNET_PeerIdentity *pid)
3950{
3952}
3953
3954
3958struct MonitorEvent
3959{
3966
3971
3976
3980 uint32_t num_msg_pending;
3981
3985 uint32_t num_bytes_pending;
3986};
3987
3988
3997static void
3999{
4000 struct Neighbour *n = dvh->next_hop;
4001 struct DistanceVector *dv = dvh->dv;
4002 struct PendingAcknowledgement *pa;
4003
4004 while (NULL != (pa = dvh->pa_head))
4005 {
4007 pa->dvh = NULL;
4008 }
4009 GNUNET_CONTAINER_MDLL_remove (neighbour, n->dv_head, n->dv_tail, dvh);
4011 GNUNET_free (dvh);
4012}
4013
4014
4021static void
4022check_link_down (void *cls);
4023
4024
4030static void
4032{
4034 "Informing CORE clients about disconnect from %s\n",
4035 GNUNET_i2s (pid));
4036 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
4037 {
4038 struct GNUNET_MQ_Envelope *env;
4039 struct DisconnectInfoMessage *dim;
4040
4041 if (CT_CORE != tc->type)
4042 continue;
4044 dim->peer = *pid;
4045 GNUNET_MQ_send (tc->mq, env);
4046 }
4047}
4048
4049
4050static void
4051try_to_bring_link_up (const struct GNUNET_PeerIdentity *pid);
4052
4053
4076static void
4078{
4079 struct GNUNET_PeerIdentity target = vl->target;
4080
4081 for (struct PendingMessage *pm = vl->pending_msg_head;
4082 NULL != pm;
4083 pm = pm->next_vl)
4084 credit_client (pm);
4086 free_virtual_link (vl);
4087 /* Start getting it back now. Only #handle_validation_response() can
4088 rebuild it, and a successful validation parks @e revalidation_task just
4089 short of #ADDRESS_VALIDATION_LIFETIME -- four hours away. */
4090 try_to_bring_link_up (&target);
4091}
4092
4093
4100static void
4101free_dv_route (struct DistanceVector *dv)
4102{
4103 struct DistanceVectorHop *dvh;
4104 struct VirtualLink *vl;
4105
4106 while (NULL != (dvh = dv->dv_head))
4108
4110 GNUNET_YES ==
4112 if (NULL != (vl = dv->vl))
4113 {
4114 GNUNET_assert (dv == vl->dv);
4115 vl->dv = NULL;
4116 if (NULL == vl->n)
4117 {
4119 }
4120 else
4121 {
4122 /* @e visibility_task is NULL while #check_link_down() itself runs, and
4123 #GNUNET_SCHEDULER_cancel() dereferences its argument. */
4124 if (NULL != vl->visibility_task)
4127 }
4128 dv->vl = NULL;
4129 }
4130
4131 if (NULL != dv->timeout_task)
4132 {
4134 dv->timeout_task = NULL;
4135 }
4136 GNUNET_free (dv->km);
4137 GNUNET_free (dv);
4138}
4139
4140
4154static void
4156 const struct GNUNET_PeerIdentity *peer,
4157 const char *address,
4159 const struct MonitorEvent *me)
4160{
4161 struct GNUNET_MQ_Envelope *env;
4163 size_t addr_len = strlen (address) + 1;
4164
4166 addr_len,
4168 md->nt = htonl ((uint32_t) nt);
4169 md->peer = *peer;
4170 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
4171 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
4172 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
4173 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
4174 md->cs = htonl ((uint32_t) me->cs);
4175 md->num_msg_pending = htonl (me->num_msg_pending);
4176 md->num_bytes_pending = htonl (me->num_bytes_pending);
4177 memcpy (&md[1], address, addr_len);
4178 GNUNET_MQ_send (tc->mq, env);
4179}
4180
4181
4191static void
4193 const char *address,
4195 const struct MonitorEvent *me)
4196{
4197 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
4198 {
4199 if (CT_MONITOR != tc->type)
4200 continue;
4201 if (tc->details.monitor.one_shot)
4202 continue;
4203 if ((GNUNET_NO == GNUNET_is_zero (&tc->details.monitor.peer)) &&
4204 (0 != GNUNET_memcmp (&tc->details.monitor.peer, peer)))
4205 continue;
4207 }
4208}
4209
4210
4220static void *
4221client_connect_cb (void *cls,
4222 struct GNUNET_SERVICE_Client *client,
4223 struct GNUNET_MQ_Handle *mq)
4224{
4225 struct TransportClient *tc;
4226
4227 (void) cls;
4228 tc = GNUNET_new (struct TransportClient);
4229 tc->client = client;
4230 tc->mq = mq;
4233 "Client %p of type %u connected\n",
4234 tc,
4235 tc->type);
4236 return tc;
4237}
4238
4239
4240static enum GNUNET_GenericReturnValue
4241remove_global_addresses (void *cls,
4242 const struct GNUNET_PeerIdentity *pid,
4243 void *value)
4244{
4245 struct TransportGlobalNattedAddress *tgna = value;
4246 (void) cls;
4247
4248 GNUNET_free (tgna);
4249
4250 return GNUNET_OK;
4251}
4252
4253
4260static void
4261free_neighbour (struct Neighbour *neighbour,
4262 enum GNUNET_GenericReturnValue drop_link)
4263{
4264 struct DistanceVectorHop *dvh;
4265 struct VirtualLink *vl;
4266
4267 GNUNET_assert (NULL == neighbour->queue_head);
4270 &neighbour->pid,
4271 neighbour));
4273 "Freeing neighbour\n");
4276 NULL);
4278 while (NULL != (dvh = neighbour->dv_head))
4279 {
4280 struct DistanceVector *dv = dvh->dv;
4281
4283 if (NULL == dv->dv_head)
4284 free_dv_route (dv);
4285 }
4286 if (NULL != neighbour->get)
4287 {
4289 neighbour->get = NULL;
4290 }
4291 if (NULL != neighbour->sc)
4292 {
4294 "store cancel\n");
4295 GNUNET_PEERSTORE_store_cancel (neighbour->sc);
4296 neighbour->sc = NULL;
4297 }
4298 if (NULL != (vl = neighbour->vl))
4299 {
4300 GNUNET_assert (neighbour == vl->n);
4301 vl->n = NULL;
4302 if ((GNUNET_YES == drop_link) || (NULL == vl->dv))
4303 {
4305 }
4306 else
4307 {
4308 /* See #free_dv_route(): may be NULL under #check_link_down(). */
4309 if (NULL != vl->visibility_task)
4312 }
4313 neighbour->vl = NULL;
4314 }
4315 GNUNET_free (neighbour);
4316}
4317
4318
4325static void
4327 const struct GNUNET_PeerIdentity *pid)
4328{
4329 struct GNUNET_MQ_Envelope *env;
4330 struct ConnectInfoMessage *cim;
4331
4332 GNUNET_assert (CT_CORE == tc->type);
4334 cim->id = *pid;
4335 GNUNET_MQ_send (tc->mq, env);
4336}
4337
4338
4344static void
4346{
4348 "Informing CORE clients about connection to %s\n",
4349 GNUNET_i2s (pid));
4350 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
4351 {
4352 if (CT_CORE != tc->type)
4353 continue;
4355 }
4356}
4357
4358
4366static void
4367transmit_on_queue (void *cls);
4368
4369
4378static unsigned int
4380{
4381 for (struct Queue *s = queue_head; NULL != s;
4382 s = s->next_neighbour)
4383 {
4384 if (s == queue)
4385 continue;
4386 if (s->tc->details.communicator.address_prefix !=
4387 queue->tc->details.communicator.address_prefix)
4388 {
4390 "queue address %s qid %u compare with queue: address %s qid %u\n",
4391 queue->address,
4392 queue->qid,
4393 s->address,
4394 s->qid);
4395 if ((s->priority > queue->priority) && (0 < s->q_capacity) &&
4396 (QUEUE_LENGTH_LIMIT > s->queue_length) )
4397 return GNUNET_YES;
4399 "Lower prio\n");
4400 }
4401 }
4402 return GNUNET_NO;
4403}
4404
4405
4412static void
4414
4415
4423static void
4425 struct Queue *queue,
4427{
4429
4430 if (queue->validated_until.abs_value_us < now.abs_value_us)
4431 return;
4433 queue->neighbour->queue_head))
4434 return;
4435
4436 if (queue->tc->details.communicator.total_queue_length >=
4438 {
4440 "Transmission on queue %s (QID %u) throttled due to communicator queue limit\n",
4441 queue->address,
4442 queue->qid);
4444 GST_stats,
4445 "# Transmission throttled due to communicator queue limit",
4446 1,
4447 GNUNET_NO);
4448 queue->idle = GNUNET_NO;
4449 /* @e total_queue_length is shared by every peer this communicator serves,
4450 so at the limit we can send to none of them, and the only things that
4451 lower it again are an ACK from the communicator, #free_queue() and
4452 #free_timedout_queue_entry(). If we got here because a peer stopped
4453 acknowledging, no ACK is coming; and we just declined to arm
4454 @e transmit_task, so #queue_send_msg() -- the *only* place that arms
4455 the sweeper -- will not run either. That leaves nothing at all to
4456 recover the count, and the communicator stays mute towards every peer
4457 until some unrelated queue happens to go down. Keep the sweeper
4458 going. */
4460 return;
4461 }
4462 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
4463 {
4465 "Transmission on queue %s (QID %u) throttled due to communicator queue length limit\n",
4466 queue->address,
4467 queue->qid);
4469 "# Transmission throttled due to queue queue limit",
4470 1,
4471 GNUNET_NO);
4472 queue->idle = GNUNET_NO;
4473 /* Same reasoning as above, for the per-queue limit. */
4475 return;
4476 }
4477 if (0 == queue->q_capacity)
4478 {
4480 "Transmission on queue %s (QID %u) throttled due to communicator message has capacity %"
4481 PRIu64 ".\n",
4482 queue->address,
4483 queue->qid,
4484 queue->q_capacity);
4486 "# Transmission throttled due to message queue capacity",
4487 1,
4488 GNUNET_NO);
4489 queue->idle = GNUNET_NO;
4490 return;
4491 }
4492 /* queue might indeed be ready, schedule it */
4493 if (NULL != queue->transmit_task)
4494 GNUNET_SCHEDULER_cancel (queue->transmit_task);
4495 queue->transmit_task =
4497 queue);
4499 "Considering transmission on queue `%s' QID %llu to %s\n",
4500 queue->address,
4501 (unsigned long long) queue->qid,
4502 GNUNET_i2s (&queue->neighbour->pid));
4503}
4504
4505
4506static void
4508 const char *address);
4509
4510
4517static void
4518check_link_down (void *cls)
4519{
4520 struct VirtualLink *vl = cls;
4521 struct DistanceVector *dv = vl->dv;
4522 struct Neighbour *n = vl->n;
4523 struct GNUNET_TIME_Absolute dvh_timeout;
4524 struct GNUNET_TIME_Absolute q_timeout;
4525
4527 "Checking if link is down\n");
4528 vl->visibility_task = NULL;
4529 dvh_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
4530 if (NULL != dv)
4531 {
4532 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4533 pos = pos->next_dv)
4534 dvh_timeout = GNUNET_TIME_absolute_max (dvh_timeout,
4535 pos->path_valid_until);
4536 if (0 == GNUNET_TIME_absolute_get_remaining (dvh_timeout).rel_value_us)
4537 {
4538 vl->dv->vl = NULL;
4539 vl->dv = NULL;
4540 }
4541 }
4542 q_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
4543 /* NOTE: @e n may be NULL here: #free_neighbour() clears vl->n and then
4544 schedules us when the link still has a DV route. */
4545 if (NULL != n)
4546 {
4547 struct GNUNET_TIME_Absolute liveness_deadline;
4548
4549 /* A successful validation is good for #ADDRESS_VALIDATION_LIFETIME (four
4550 hours). Do not take a communicator's word for that long: cap what the
4551 queues are worth by how recently this neighbour actually said anything
4552 to us. Otherwise a communicator that stops working without sending a
4553 QUEUE_TEARDOWN keeps this link -- and CORE's idea of the connection --
4554 alive until the validation expires. */
4555 liveness_deadline = GNUNET_TIME_absolute_add (n->last_inbound,
4557 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
4558 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
4559 if (GNUNET_TIME_absolute_cmp (liveness_deadline, <, q_timeout))
4560 {
4561 if (0 ==
4563 {
4564 /* Only reachable if a communicator failed to tear its queue down. */
4566 "Neighbour %s was silent for %s while its communicator "
4567 "kept claiming the queue works; treating link as down\n",
4568 GNUNET_i2s (&vl->target),
4571 GNUNET_YES));
4573 "# links dropped (neighbour silent)",
4574 1,
4575 GNUNET_NO);
4576 }
4577 q_timeout = liveness_deadline;
4578 }
4579 if (0 == GNUNET_TIME_absolute_get_remaining (q_timeout).rel_value_us)
4580 {
4581 vl->n->vl = NULL;
4582 vl->n = NULL;
4583 }
4584 }
4585 if ((NULL == vl->n) && (NULL == vl->dv))
4586 {
4588 /* @e n (if any) outlives the link, and so do its queues: the liveness cap
4589 above drops a link whose addresses are still well inside
4590 #ADDRESS_VALIDATION_LIFETIME. In that state nothing would ever ask for
4591 a fresh challenge -- @e revalidation_task does not fire until the four
4592 hour validity is nearly over, and the HELLO path reaches
4593 #start_address_validation() only to find an address that still counts
4594 as valid. Since #handle_validation_response() is the only thing that
4595 can rebuild this link and tell CORE about the peer again, ask for that
4596 validation now, or CORE never hears about this peer again. */
4597 if (NULL != n)
4598 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
4599 start_address_validation (&n->pid, q->address);
4600 return;
4601 }
4602 vl->visibility_task =
4603 GNUNET_SCHEDULER_add_at (GNUNET_TIME_absolute_max (q_timeout, dvh_timeout),
4605 vl);
4606}
4607
4608
4614static void
4615free_queue (struct Queue *queue)
4616{
4617 struct Neighbour *neighbour = queue->neighbour;
4618 struct TransportClient *tc = queue->tc;
4619 struct MonitorEvent me = { .cs = GNUNET_TRANSPORT_CS_DOWN,
4621 struct QueueEntry *qe;
4622 int maxxed;
4623 struct PendingAcknowledgement *pa;
4624 struct VirtualLink *vl;
4625
4627 "Cleaning up queue %u\n", queue->qid);
4628 if (NULL != queue->mo)
4629 {
4631 queue->mo = NULL;
4632 }
4633 if (NULL != queue->transmit_task)
4634 {
4635 GNUNET_SCHEDULER_cancel (queue->transmit_task);
4636 queue->transmit_task = NULL;
4637 }
4638 while (NULL != (pa = queue->pa_head))
4639 {
4640 GNUNET_CONTAINER_MDLL_remove (queue, queue->pa_head, queue->pa_tail, pa);
4641 pa->queue = NULL;
4642 }
4643
4645 neighbour->queue_head,
4646 neighbour->queue_tail,
4647 queue);
4649 tc->details.communicator.queue_head,
4650 tc->details.communicator.queue_tail,
4651 queue);
4653 tc->details.communicator.total_queue_length);
4655 "Cleaning up queue with length %u\n",
4656 queue->queue_length);
4657 while (NULL != (qe = queue->queue_head))
4658 {
4659 GNUNET_CONTAINER_DLL_remove (queue->queue_head, queue->queue_tail, qe);
4660 queue->queue_length--;
4661 tc->details.communicator.total_queue_length--;
4662 if (NULL != qe->pm)
4663 {
4664 GNUNET_assert (qe == qe->pm->qe);
4665 qe->pm->qe = NULL;
4666 }
4667 GNUNET_free (qe);
4668 }
4669 GNUNET_assert (0 == queue->queue_length);
4670 if ((maxxed) && (COMMUNICATOR_TOTAL_QUEUE_LIMIT >
4671 tc->details.communicator.total_queue_length))
4672 {
4673 /* Communicator dropped below threshold, resume all _other_ queues */
4675 GST_stats,
4676 "# Transmission throttled due to communicator queue limit",
4677 -1,
4678 GNUNET_NO);
4679 for (struct Queue *s = tc->details.communicator.queue_head; NULL != s;
4680 s = s->next_client)
4682 s,
4684 }
4685 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
4687
4688 vl = lookup_virtual_link (&neighbour->pid);
4689 if ((NULL != vl) && (neighbour == vl->n))
4690 {
4691 /* See #free_dv_route(): may be NULL under #check_link_down(), which is
4692 also what clears it -- so the call below needs no re-arm here. */
4693 if (NULL != vl->visibility_task)
4695 vl->visibility_task = NULL;
4696 check_link_down (vl);
4697 }
4698 if (NULL == neighbour->queue_head)
4699 {
4700 free_neighbour (neighbour, GNUNET_NO);
4701 }
4702}
4703
4704
4712static void
4714
4715
4721static void
4723{
4724 struct TransportClient *tc = ale->tc;
4725
4726 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
4727 tc->details.communicator.addr_tail,
4728 ale);
4729 /* Cancels @e sc, @e shc and the pending PILS signature request, all of
4730 which would otherwise run their callbacks on this freed entry. */
4732 if (NULL != ale->sc)
4733 {
4735 "store cancel\n");
4737 ale->sc = NULL;
4738 }
4739 if (NULL != ale->shc)
4740 {
4742 ale->shc = NULL;
4743 }
4744 if (NULL != ale->st)
4745 {
4747 ale->st = NULL;
4748 }
4749 if (NULL != ale->signed_address)
4751 GNUNET_free (ale);
4752}
4753
4754
4763static int
4764stop_peer_request (void *cls,
4765 const struct GNUNET_PeerIdentity *pid,
4766 void *value)
4767{
4768 struct TransportClient *tc = cls;
4769 struct PeerRequest *pr = value;
4770
4771 if (NULL != pr->retry_task)
4772 {
4773 GNUNET_SCHEDULER_cancel (pr->retry_task);
4774 pr->retry_task = NULL;
4775 }
4776 if (NULL != pr->nc)
4778 pr->nc = NULL;
4780 GNUNET_YES ==
4781 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
4782 pid,
4783 pr));
4784 GNUNET_free (pr);
4785
4786 return GNUNET_OK;
4787}
4788
4789
4790static void
4791do_shutdown (void *cls);
4792
4793
4803static enum GNUNET_GenericReturnValue
4804detach_cmcs_from_link (void *cls,
4805 const struct GNUNET_PeerIdentity *pid,
4806 void *value)
4807{
4808 const struct TransportClient *tc = cls;
4809 struct VirtualLink *vl = value;
4810
4811 (void) pid;
4812 for (struct CommunicatorMessageContext *cmc = vl->cmc_head;
4813 NULL != cmc;
4814 cmc = cmc->next)
4815 if (tc == cmc->tc)
4816 cmc->tc = NULL;
4817 return GNUNET_OK;
4818}
4819
4820
4830static enum GNUNET_GenericReturnValue
4832 const struct GNUNET_PeerIdentity *pid,
4833 void *value)
4834{
4835 const struct TransportClient *tc = cls;
4836 struct Backtalker *b = value;
4837
4838 (void) pid;
4839 if ((NULL != b->cmc) && (tc == b->cmc->tc))
4840 b->cmc->tc = NULL;
4841 return GNUNET_OK;
4842}
4843
4844
4863static void
4865{
4868 (void *) tc);
4871 (void *) tc);
4872 for (unsigned int i = 0; i < RING_BUFFER_SIZE; i++)
4873 if ((NULL != ring_buffer[i]) &&
4874 (tc == ring_buffer[i]->cmc->tc))
4875 ring_buffer[i]->cmc->tc = NULL;
4876}
4877
4878
4887static void
4888client_disconnect_cb (void *cls,
4889 struct GNUNET_SERVICE_Client *client,
4890 void *app_ctx)
4891{
4892 struct TransportClient *tc = app_ctx;
4893
4894 (void) cls;
4895 (void) client;
4897 switch (tc->type)
4898 {
4899 case CT_NONE:
4901 "Unknown Client %p disconnected, cleaning up.\n",
4902 tc);
4903 break;
4904
4905 case CT_CORE: {
4906 struct PendingMessage *pm;
4908 "CORE Client %p disconnected, cleaning up.\n",
4909 tc);
4910
4911
4912 while (NULL != (pm = tc->details.core.pending_msg_head))
4913 {
4915 tc->details.core.pending_msg_head,
4916 tc->details.core.pending_msg_tail,
4917 pm);
4918 pm->client = NULL;
4919 }
4920 }
4921 break;
4922
4923 case CT_MONITOR:
4925 "MONITOR Client %p disconnected, cleaning up.\n",
4926 tc);
4927
4928 break;
4929
4930 case CT_COMMUNICATOR: {
4931 struct Queue *q;
4932 struct AddressListEntry *ale;
4933
4935 "COMMUNICATOR Client %p disconnected, cleaning up.\n",
4936 tc);
4937
4938 /* MUST come first: freeing the queues below can tear a virtual link
4939 down, and #free_virtual_link() releases the cmcs parked on it. */
4941 if (NULL != tc->details.communicator.free_queue_entry_task)
4943 tc->details.communicator.free_queue_entry_task);
4944 while (NULL != (q = tc->details.communicator.queue_head))
4945 free_queue (q);
4946 while (NULL != (ale = tc->details.communicator.addr_head))
4948 GNUNET_free (tc->details.communicator.address_prefix);
4949 }
4950 break;
4951
4952 case CT_APPLICATION:
4954 "APPLICATION Client %p disconnected, cleaning up.\n",
4955 tc);
4956
4957 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
4959 tc);
4960 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
4961 break;
4962 }
4963 GNUNET_free (tc);
4964 if ((GNUNET_YES == in_shutdown) && (NULL == clients_head))
4965 {
4967 "Our last client disconnected\n");
4968 do_shutdown (cls);
4969 }
4970}
4971
4972
4982static int
4984 const struct GNUNET_PeerIdentity *pid,
4985 void *value)
4986{
4987 struct TransportClient *tc = cls;
4988 struct VirtualLink *vl = value;
4989
4990 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
4991 return GNUNET_OK;
4992
4994 "Telling new CORE client about existing connection to %s\n",
4995 GNUNET_i2s (pid));
4997 return GNUNET_OK;
4998}
4999
5000
5006static void
5008 unsigned
5009 int free_cmc);
5010
5011static enum GNUNET_GenericReturnValue
5012resume_communicators (void *cls,
5013 const struct GNUNET_PeerIdentity *pid,
5014 void *value)
5015{
5016 struct VirtualLink *vl = value;
5017 struct CommunicatorMessageContext *cmc;
5018
5019 /* resume communicators */
5020 while (NULL != (cmc = vl->cmc_tail))
5021 release_stalled_cmc (vl, cmc);
5022 if (NULL != vl->core_fc_stall_task)
5023 {
5025 vl->core_fc_stall_task = NULL;
5026 }
5027 /* A CORE client that just attached has nothing outstanding, so give it a
5028 full window. The RECV_OKs that would have returned the credit spent by
5029 its predecessor died with that client, and #handle_client_recv_ok() is
5030 the only thing that ever raises this counter -- so without the reset
5031 every message on this link takes the "CORE ran out of window" path from
5032 here on, and only #core_fc_stalled() (after CORE_FC_STALL_TIMEOUT, and
5033 once per round) ever lets any through. */
5035 return GNUNET_OK;
5036}
5037
5038
5047static void
5048handle_client_start (void *cls, const struct StartMessage *start)
5049{
5050 // const struct GNUNET_PeerIdentity *my_identity;
5051 struct TransportClient *tc = cls;
5052 // uint32_t options;
5053 //
5054 // my_identity = GNUNET_PILS_get_identity (pils);
5055 // GNUNET_assert (my_identity);
5056 //
5057 // FIXME ignore the check of the peer ids for now.
5058 // (also deprecate the old way of obtaining our own peer ID)
5059 // options = ntohl (start->options);
5060 // if ((0 != (1 & options)) &&
5061 // (0 != GNUNET_memcmp (&start->self, my_identity)))
5062 // {
5063 // /* client thinks this is a different peer, reject */
5064 // GNUNET_break (0);
5065 // GNUNET_SERVICE_client_drop (tc->client);
5066 // return;
5067 // }
5068 if (CT_NONE != tc->type)
5069 {
5070 GNUNET_break (0);
5072 return;
5073 }
5074 tc->type = CT_CORE;
5076 "New CORE client with PID %s registered\n",
5077 GNUNET_i2s (&start->self));
5080 tc);
5083 NULL);
5085}
5086
5087
5094static int
5095check_client_send (void *cls, const struct OutboundMessage *obm)
5096{
5097 struct TransportClient *tc = cls;
5098 uint16_t size;
5099 const struct GNUNET_MessageHeader *obmm;
5100
5101 if (CT_CORE != tc->type)
5102 {
5103 GNUNET_break (0);
5104 return GNUNET_SYSERR;
5105 }
5106 size = ntohs (obm->header.size) - sizeof(struct OutboundMessage);
5107 if (size < sizeof(struct GNUNET_MessageHeader))
5108 {
5109 GNUNET_break (0);
5110 return GNUNET_SYSERR;
5111 }
5112 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5113 if (size != ntohs (obmm->size))
5114 {
5115 GNUNET_break (0);
5116 return GNUNET_SYSERR;
5117 }
5118 return GNUNET_OK;
5119}
5120
5121
5129static void
5131{
5132 struct TransportClient *tc = pm->client;
5133 struct VirtualLink *vl = pm->vl;
5134
5136 "client send response\n");
5137 if (NULL != tc)
5138 {
5140 "Confirming transmission of <%" PRIu64 "> to %s\n",
5141 pm->logging_uuid,
5142 GNUNET_i2s (&vl->target));
5143 credit_client (pm);
5144 }
5146}
5147
5148
5158static unsigned int
5161 struct DistanceVectorHop **hops_array,
5162 unsigned int hops_array_length)
5163{
5164 uint64_t choices[hops_array_length];
5165 uint64_t num_dv;
5166 unsigned int dv_count;
5167
5168 /* Pick random vectors, but weighted by distance, giving more weight
5169 to shorter vectors */
5170 num_dv = 0;
5171 dv_count = 0;
5172 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5173 pos = pos->next_dv)
5174 {
5175 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
5176 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
5177 .rel_value_us == 0))
5178 continue; /* pos unconfirmed and confirmed required */
5179 num_dv += MAX_DV_HOPS_ALLOWED - pos->distance;
5180 dv_count++;
5181 }
5182 if (0 == dv_count)
5183 return 0;
5184 if (dv_count <= hops_array_length)
5185 {
5186 dv_count = 0;
5187 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5188 pos = pos->next_dv)
5189 hops_array[dv_count++] = pos;
5190 return dv_count;
5191 }
5192 for (unsigned int i = 0; i < hops_array_length; i++)
5193 {
5194 int ok = GNUNET_NO;
5195 while (GNUNET_NO == ok)
5196 {
5197 choices[i] =
5198 GNUNET_CRYPTO_random_u64 (num_dv);
5199 ok = GNUNET_YES;
5200 for (unsigned int j = 0; j < i; j++)
5201 if (choices[i] == choices[j])
5202 {
5203 ok = GNUNET_NO;
5204 break;
5205 }
5206 }
5207 }
5208 dv_count = 0;
5209 num_dv = 0;
5210 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5211 pos = pos->next_dv)
5212 {
5213 uint32_t delta = MAX_DV_HOPS_ALLOWED - pos->distance;
5214
5215 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
5216 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
5217 .rel_value_us == 0))
5218 continue; /* pos unconfirmed and confirmed required */
5219 for (unsigned int i = 0; i < hops_array_length; i++)
5220 if ((num_dv <= choices[i]) && (num_dv + delta > choices[i]))
5221 hops_array[dv_count++] = pos;
5222 num_dv += delta;
5223 }
5224 return dv_count;
5225}
5226
5227
5234static int
5236 void *cls,
5238{
5239 struct TransportClient *tc = cls;
5240 uint16_t size;
5241
5242 if (CT_NONE != tc->type)
5243 {
5244 GNUNET_break (0);
5245 return GNUNET_SYSERR;
5246 }
5247 tc->type = CT_COMMUNICATOR;
5248 size = ntohs (cam->header.size) - sizeof(*cam);
5249 if (0 == size)
5250 return GNUNET_OK; /* receive-only communicator */
5252 return GNUNET_OK;
5253}
5254
5255
5267static void
5269{
5270 struct GNUNET_MQ_Envelope *env;
5272
5273 if (GNUNET_YES == cmc->ack_sent)
5274 return;
5275 cmc->ack_sent = GNUNET_YES;
5276 if (NULL == cmc->tc)
5277 return; /* communicator is gone, see #detach_cmcs_from_client() */
5278 if (0 == ntohl (cmc->im.fc_on))
5279 return; /* communicator did not ask for flow control */
5281 "Acknowledge message with flow control id %" PRIu64 "\n",
5282 cmc->im.fc_id);
5284 ack->reserved = htonl (0);
5285 ack->fc_id = cmc->im.fc_id;
5286 ack->sender = cmc->im.neighbour_sender;
5287 GNUNET_MQ_send (cmc->tc->mq, env);
5288}
5289
5290
5301static void
5303{
5304 if (GNUNET_YES == cmc->client_resumed)
5305 return;
5307 if (NULL == cmc->tc)
5308 return; /* communicator is gone, see #detach_cmcs_from_client() */
5310}
5311
5312
5321static void
5323 unsigned
5324 int free_cmc)
5325{
5326 send_cmc_ack (cmc);
5327 resume_cmc_client (cmc);
5328 if (GNUNET_YES == free_cmc)
5329 {
5330 GNUNET_free (cmc);
5331 }
5332}
5333
5334
5335static void
5337 struct CommunicatorMessageContext *cmc)
5338{
5340 GNUNET_assert (0 < vl->cmc_count);
5341 vl->cmc_count--;
5343}
5344
5345
5346static void
5348{
5350}
5351
5352
5362static void
5363handle_client_recv_ok (void *cls, const struct RecvOkMessage *rom)
5364{
5365 struct TransportClient *tc = cls;
5366 struct VirtualLink *vl;
5367 uint32_t delta;
5368 struct CommunicatorMessageContext *cmc;
5369
5370 if (CT_CORE != tc->type)
5371 {
5372 GNUNET_break (0);
5374 return;
5375 }
5376 vl = lookup_virtual_link (&rom->peer);
5377 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
5378 {
5380 "# RECV_OK dropped: virtual link unknown",
5381 1,
5382 GNUNET_NO);
5384 return;
5385 }
5386 delta = ntohl (rom->increase_window_delta);
5387 vl->core_recv_window += delta;
5389 "CORE ack receiving message, increased CORE recv window to %d\n",
5390 vl->core_recv_window);
5392 if (vl->core_recv_window <= 0)
5393 return;
5394 /* release the flow control credit we withheld from the communicators */
5395 while (NULL != (cmc = vl->cmc_tail))
5396 release_stalled_cmc (vl, cmc);
5397 if (NULL != vl->core_fc_stall_task)
5398 {
5400 vl->core_fc_stall_task = NULL;
5401 }
5402}
5403
5404
5411static void
5413 void *cls,
5415{
5416 const struct GNUNET_PeerIdentity *my_identity;
5417 struct TransportClient *tc = cls;
5418 uint16_t size;
5419
5420 size = ntohs (cam->header.size) - sizeof(*cam);
5421 if (0 == size)
5422 {
5424 "Receive-only communicator connected\n");
5425 /* Receive-only communicator: it has no address prefix, but we still
5426 MUST resume the client or we will never read from it again. Use an
5427 empty prefix so that the various strcmp()s do not see NULL. */
5428 tc->details.communicator.address_prefix = GNUNET_strdup ("");
5430 return;
5431 }
5432 tc->details.communicator.address_prefix =
5433 GNUNET_strdup ((const char *) &cam[1]);
5434 tc->details.communicator.cc = ntohl (cam->cc);
5435 tc->details.communicator.can_burst = ntohl (cam->can_burst);
5437 if (NULL != my_identity)
5438 {
5440 "Communicator for peer %s with prefix '%s' connected %s\n",
5442 tc->details.communicator.address_prefix,
5443 tc->details.communicator.can_burst ? "can burst" :
5444 "can not burst");
5445 }
5446 else
5447 {
5449 "Communicator for local peer with prefix '%s' connected %s\n",
5450 tc->details.communicator.address_prefix,
5451 tc->details.communicator.can_burst ? "can burst" :
5452 "can not burst");
5453 }
5455}
5456
5457
5465static int
5467 void *cls,
5469{
5470 const struct GNUNET_MessageHeader *inbox;
5471 const char *is;
5472 uint16_t msize;
5473 uint16_t isize;
5474
5475 (void) cls;
5476 msize = ntohs (cb->header.size) - sizeof(*cb);
5477 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
5478 /* MUST bound the buffer before dereferencing @a inbox. */
5479 if (msize <= sizeof(struct GNUNET_MessageHeader))
5480 {
5481 GNUNET_break (0);
5482 return GNUNET_SYSERR;
5483 }
5484 isize = ntohs (inbox->size);
5485 if (isize >= msize)
5486 {
5487 GNUNET_break (0);
5488 return GNUNET_SYSERR;
5489 }
5490 is = (const char *) inbox;
5491 is += isize;
5492 msize -= isize;
5493 GNUNET_assert (0 < msize);
5494 if ('\0' != is[msize - 1])
5495 {
5496 GNUNET_break (0);
5497 return GNUNET_SYSERR;
5498 }
5499 return GNUNET_OK;
5500}
5501
5502
5517static enum GNUNET_GenericReturnValue
5518sign_ephemeral (struct DistanceVector *dv)
5519{
5520 struct EphemeralConfirmationPS ec;
5521
5523 dv->ephemeral_validity =
5525 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
5526 ec.target = dv->target;
5527 ec.ephemeral_key = dv->ephemeral_key;
5528 ec.sender_monotonic_time = GNUNET_TIME_absolute_hton (dv->monotime);
5529 ec.purpose.size = htonl (sizeof(ec));
5530 return sign_by_my_identity (&ec.purpose, &dv->sender_sig);
5531}
5532
5533
5534static void
5536 struct TransportClient *tc);
5537
5538
5539static void
5540free_timedout_queue_entry (void *cls)
5541{
5542 struct TransportClient *tc = cls;
5544
5546 "freeing timedout queue entries\n");
5547
5548 tc->details.communicator.free_queue_entry_task = NULL;
5549 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
5550 queue = queue->next_client)
5551 {
5552 struct QueueEntry *qep = queue->queue_head;
5553
5555 "checking QID %u for timedout queue entries\n",
5556 queue->qid);
5557 while (NULL != qep)
5558 {
5559 struct QueueEntry *pos = qep;
5561 pos->creation_timestamp, now);
5562 qep = qep->next;
5563
5565 "diff to now %s \n",
5568 {
5570 "Freeing timed out QueueEntry with MID %" PRIu64
5571 " and QID %u\n",
5572 pos->mid,
5573 queue->qid);
5575 "# QueueEntries timed out",
5576 1,
5577 GNUNET_NO);
5578 free_queue_entry (pos, tc);
5579 }
5580 }
5581 }
5582 /* Entries younger than #QUEUE_ENTRY_TIMEOUT are still to be reclaimed, and
5583 this task used to be a one-shot armed only by #queue_send_msg(). So the
5584 sweep that was supposed to bound how long an unacknowledged entry holds
5585 its slot only ever ran while *new* messages were being queued -- exactly
5586 not the case once the throttles in #schedule_transmit_on_queue() have
5587 stopped transmission. Keep going as long as anything is outstanding. */
5589}
5590
5591
5592static void
5594{
5595 if (NULL != tc->details.communicator.free_queue_entry_task)
5596 return;
5597 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
5598 queue = queue->next_client)
5599 {
5600 if (NULL == queue->queue_head)
5601 continue;
5602 tc->details.communicator.free_queue_entry_task =
5605 tc);
5606 return;
5607 }
5608}
5609
5610
5620static void
5621queue_send_msg (struct Queue *queue,
5622 struct PendingMessage *pm,
5623 const void *payload,
5624 size_t payload_size)
5625{
5626 struct Neighbour *n = queue->neighbour;
5628 struct GNUNET_MQ_Envelope *env;
5629 struct PendingAcknowledgement *pa;
5630
5631 GNUNET_log (
5633 "Queueing %u bytes of payload for transmission <%" PRIu64
5634 "> on queue %llu to %s\n",
5635 (unsigned int) payload_size,
5636 (NULL == pm) ? 0 : pm->logging_uuid,
5637 (unsigned long long) queue->qid,
5638 GNUNET_i2s (&queue->neighbour->pid));
5639 env = GNUNET_MQ_msg_extra (smt,
5640 payload_size,
5642 smt->qid = htonl (queue->qid);
5643 smt->mid = GNUNET_htonll (queue->mid_gen);
5644 smt->receiver = n->pid;
5645 memcpy (&smt[1], payload, payload_size);
5646 {
5647 /* Pass the env to the communicator of queue for transmission. */
5648 struct QueueEntry *qe;
5649
5650 qe = GNUNET_new (struct QueueEntry);
5651 qe->creation_timestamp = GNUNET_TIME_absolute_get ();
5652 qe->mid = queue->mid_gen;
5654 "Create QueueEntry with MID %" PRIu64
5655 " and QID %u and prefix %s\n",
5656 qe->mid,
5657 queue->qid,
5658 queue->tc->details.communicator.address_prefix);
5659 queue->mid_gen++;
5660 qe->queue = queue;
5661 if (NULL != pm)
5662 {
5663 qe->pm = pm;
5664 // TODO Why do we have a retransmission. When we know, make decision if we still want this.
5665 // GNUNET_assert (NULL == pm->qe);
5666 if (NULL != pm->qe)
5667 {
5669 "Retransmitting message <%" PRIu64
5670 "> remove pm from qe with MID: %llu \n",
5672 (unsigned long long) pm->qe->mid);
5673 pm->qe->pm = NULL;
5674 }
5675 pm->qe = qe;
5676 }
5677 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
5678 if (0 == queue->q_capacity)
5679 {
5680 // Messages without FC or fragments can get here.
5681 if (NULL != pm)
5682 {
5684 "Message %" PRIu64
5685 " (pm type %u) was not send because queue has no capacity.\n",
5687 pm->pmt);
5688 pm->qe = NULL;
5689 }
5690 GNUNET_free (env);
5691 GNUNET_free (qe);
5692 return;
5693 }
5694 GNUNET_CONTAINER_DLL_insert (queue->queue_head, queue->queue_tail, qe);
5695 queue->queue_length++;
5696 queue->tc->details.communicator.total_queue_length++;
5697 if (GNUNET_NO == queue->unlimited_length)
5698 queue->q_capacity--;
5700 "Queue %s with qid %u has capacity %" PRIu64 "\n",
5701 queue->address,
5702 queue->qid,
5703 queue->q_capacity);
5705 queue->tc->details.communicator.total_queue_length)
5706 queue->idle = GNUNET_NO;
5707 if (QUEUE_LENGTH_LIMIT == queue->queue_length)
5708 queue->idle = GNUNET_NO;
5709 if (0 == queue->q_capacity)
5710 queue->idle = GNUNET_NO;
5711
5712 if (GNUNET_NO == queue->idle)
5714 if (NULL != pm)
5715 {
5716 /* NOTE: @e next_pa was never the link of this list -- nothing ever
5717 assigned it, so it was NULL on every entry. The MDLL that
5718 #prepare_pending_acknowledgement() inserts into is keyed `pm', and
5719 thus threaded through @e next_pm. Walking @e next_pa dereferenced
5720 NULL the moment the head was not the entry we wanted. */
5721 for (pa = pm->pa_head; NULL != pa; pa = pa->next_pm)
5722 if (pm == pa->pm)
5723 {
5724 pa->num_send++;
5725 break;
5726 }
5727 }
5728 // GNUNET_CONTAINER_multiuuidmap_get (pending_acks, &ack[i].ack_uuid.value);
5730 "Sending message MID %" PRIu64
5731 " of type %u (%u) and size %lu with MQ %p queue %s (QID %u) pending %"
5732 PRIu64 "\n",
5733 GNUNET_ntohll (smt->mid),
5734 ntohs (((const struct GNUNET_MessageHeader *) payload)->type),
5735 ntohs (smt->header.size),
5736 (unsigned long) payload_size,
5737 queue->tc->mq,
5738 queue->address,
5739 queue->qid,
5740 (NULL == pm) ? 0 : pm->logging_uuid);
5741 GNUNET_MQ_send (queue->tc->mq, env);
5742 }
5743}
5744
5745
5756static struct GNUNET_TIME_Relative
5757route_via_neighbour (const struct Neighbour *n,
5758 const struct GNUNET_MessageHeader *hdr,
5760{
5761 struct GNUNET_TIME_Absolute now;
5762 unsigned int candidates;
5763 unsigned int sel1;
5764 unsigned int sel2;
5765 struct GNUNET_TIME_Relative rtt;
5766
5767 /* Pick one or two 'random' queues from n (under constraints of options) */
5768 now = GNUNET_TIME_absolute_get ();
5769 /* FIXME-OPTIMIZE: give queues 'weights' and pick proportional to
5770 weight in the future; weight could be assigned by observed
5771 bandwidth (note: not sure if we should do this for this type
5772 of control traffic though). */
5773 candidates = 0;
5774 for (struct Queue *pos = n->queue_head; NULL != pos;
5775 pos = pos->next_neighbour)
5776 {
5777 if ((0 != (options & RMO_UNCONFIRMED_ALLOWED)) ||
5778 (pos->validated_until.abs_value_us > now.abs_value_us))
5779 candidates++;
5780 }
5781 if (0 == candidates)
5782 {
5783 /* This can happen rarely if the last confirmed queue timed
5784 out just as we were beginning to process this message. */
5786 "Could not route message of type %u to %s: no valid queue\n",
5787 ntohs (hdr->type),
5788 GNUNET_i2s (&n->pid));
5790 "# route selection failed (all no valid queue)",
5791 1,
5792 GNUNET_NO);
5794 }
5795
5797 sel1 = GNUNET_CRYPTO_random_u32 (candidates);
5798 if (0 == (options & RMO_REDUNDANT))
5799 sel2 = candidates; /* picks none! */
5800 else
5801 sel2 = GNUNET_CRYPTO_random_u32 (candidates);
5802 candidates = 0;
5803 for (struct Queue *pos = n->queue_head; NULL != pos;
5804 pos = pos->next_neighbour)
5805 {
5806 if ((0 != (options & RMO_UNCONFIRMED_ALLOWED)) ||
5807 (pos->validated_until.abs_value_us > now.abs_value_us))
5808 {
5809 if ((sel1 == candidates) || (sel2 == candidates))
5810 {
5812 "Routing message of type %u to %s using %s (#%u)\n",
5813 ntohs (hdr->type),
5814 GNUNET_i2s (&n->pid),
5815 pos->address,
5816 (sel1 == candidates) ? 1 : 2);
5817 rtt = GNUNET_TIME_relative_min (rtt, pos->pd.aged_rtt);
5818 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
5819 }
5820 candidates++;
5821 }
5822 }
5823 return rtt;
5824}
5825
5826
5837typedef void (*DVMessageHandler) (void *cls,
5838 struct Neighbour *next_hop,
5839 const struct GNUNET_MessageHeader *hdr,
5841
5856static struct GNUNET_TIME_Relative
5858 unsigned int num_dvhs,
5859 struct DistanceVectorHop **dvhs,
5860 const struct GNUNET_MessageHeader *hdr,
5861 DVMessageHandler use,
5862 void *use_cls,
5864 enum GNUNET_GenericReturnValue without_fc)
5865{
5866 const struct GNUNET_PeerIdentity *my_identity;
5867 struct TransportDVBoxMessage box_hdr;
5868 struct TransportDVBoxPayloadP *payload_hdr;
5869 uint16_t body_len_hbo = ntohs (hdr->size);
5870 unsigned char pt[sizeof(struct TransportDVBoxPayloadP) + body_len_hbo]
5872 unsigned char ct[sizeof(struct TransportDVBoxPayloadP) + body_len_hbo]
5874 struct GNUNET_TIME_Relative rtt;
5876
5877 payload_hdr = (struct TransportDVBoxPayloadP*) pt;
5880
5881 /* Encrypt payload */
5882 memset (&box_hdr, 0, sizeof (box_hdr));
5883 box_hdr.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
5884 box_hdr.total_hops = htons (0);
5885 box_hdr.without_fc = htonl (without_fc);
5886 // update_ephemeral (dv);
5887 if ((0 ==
5888 GNUNET_TIME_absolute_get_remaining (dv->ephemeral_validity).rel_value_us)
5889 || (NULL == dv->km))
5890 {
5891 GNUNET_CRYPTO_eddsa_kem_encaps (&dv->target.public_key,
5892 &dv->ephemeral_key,
5893 (struct GNUNET_ShortHashCode*) &km);
5894 GNUNET_free (dv->km); /* do not leak the previous key material */
5895 dv->km = GNUNET_new (struct GNUNET_ShortHashCode);
5896 GNUNET_memcpy (dv->km, &km, sizeof(struct GNUNET_ShortHashCode));
5897 if (GNUNET_OK != sign_ephemeral (dv))
5898 {
5899 /* Without a matching signature the box is undecryptable noise to the
5900 receiver; do not spend the bandwidth. Expire the ephemeral so the
5901 next attempt re-derives and re-signs rather than reusing it. */
5902 dv->ephemeral_validity = GNUNET_TIME_UNIT_ZERO_ABS;
5904 }
5905 }
5906 else
5907 {
5908 /* The ephemeral key is still valid, so reuse the cached key material.
5909 Without this @a km stayed UNINITIALISED stack memory and the
5910 receiver could not decrypt the box. */
5911 GNUNET_memcpy (&km, dv->km, sizeof(struct GNUNET_ShortHashCode));
5912 }
5913 box_hdr.ephemeral_key = dv->ephemeral_key;
5914 payload_hdr->sender_sig = dv->sender_sig;
5915 memcpy (&payload_hdr[1], hdr, body_len_hbo);
5916 GNUNET_CRYPTO_random_block (&box_hdr.iv,
5917 sizeof(box_hdr.iv));
5918 payload_hdr->sender = *my_identity;
5919 payload_hdr->monotonic_time = GNUNET_TIME_absolute_hton (dv->monotime);
5920 GNUNET_CRYPTO_aead_encrypt (sizeof pt,
5921 pt,
5922 0,
5923 NULL,
5924 &km,
5925 &box_hdr.iv,
5926 ct,
5927 &box_hdr.mac);
5929 /* For each selected path, take the pre-computed header and body
5930 and add the path in the middle of the message; then send it. */
5931 for (unsigned int i = 0; i < num_dvhs; i++)
5932 {
5933 struct DistanceVectorHop *dvh = dvhs[i];
5934 unsigned int num_hops = dvh->distance + 1;
5935 char buf[sizeof(struct TransportDVBoxMessage)
5936 + sizeof(struct GNUNET_PeerIdentity) * num_hops
5937 + sizeof(struct TransportDVBoxPayloadP)
5938 + body_len_hbo] GNUNET_ALIGN;
5939 struct GNUNET_PeerIdentity *dhops;
5940
5941 box_hdr.header.size = htons (sizeof(buf));
5942 box_hdr.orig_size = htons (sizeof(buf));
5943 box_hdr.num_hops = htons (num_hops);
5944 memcpy (buf, &box_hdr, sizeof(box_hdr));
5945 dhops = (struct GNUNET_PeerIdentity *) &buf[sizeof(box_hdr)];
5946 memcpy (dhops,
5947 dvh->path,
5948 dvh->distance * sizeof(struct GNUNET_PeerIdentity));
5949 dhops[dvh->distance] = dv->target;
5950 if (GNUNET_EXTRA_LOGGING > 0)
5951 {
5952 char *path;
5953
5955 for (unsigned int j = 0; j < num_hops; j++)
5956 {
5957 char *tmp;
5958
5959 GNUNET_asprintf (&tmp, "%s-%s", path, GNUNET_i2s (&dhops[j]));
5960 GNUNET_free (path);
5961 path = tmp;
5962 }
5964 "Routing message of type %u to %s using DV (#%u/%u) via %s\n",
5965 ntohs (hdr->type),
5966 GNUNET_i2s (&dv->target),
5967 i + 1,
5968 num_dvhs,
5969 path);
5970 GNUNET_free (path);
5971 }
5972 rtt = GNUNET_TIME_relative_min (rtt, dvh->pd.aged_rtt);
5973 memcpy (&dhops[num_hops], ct, sizeof(ct));
5974 use (use_cls,
5975 dvh->next_hop,
5976 (const struct GNUNET_MessageHeader *) buf,
5977 options);
5978 }
5979 return rtt;
5980}
5981
5982
5992static void
5993send_dv_to_neighbour (void *cls,
5994 struct Neighbour *next_hop,
5995 const struct GNUNET_MessageHeader *hdr,
5997{
5998 (void) cls;
5999 (void) route_via_neighbour (next_hop, hdr, RMO_UNCONFIRMED_ALLOWED);
6000}
6001
6002
6014static struct GNUNET_TIME_Relative
6016// route_control_message_without_fc (const struct GNUNET_PeerIdentity *target,
6017 const struct GNUNET_MessageHeader *hdr,
6019{
6020 // struct VirtualLink *vl;
6021 struct Neighbour *n;
6022 struct DistanceVector *dv;
6023 struct GNUNET_TIME_Relative rtt1;
6024 struct GNUNET_TIME_Relative rtt2;
6025 const struct GNUNET_PeerIdentity *target = &vl->target;
6026
6028 "Trying to route message of type %u to %s without fc\n",
6029 ntohs (hdr->type),
6030 GNUNET_i2s (target));
6031
6032 // TODO Do this elsewhere. vl should be given as parameter to method.
6033 // vl = lookup_virtual_link (target);
6034 /* An unconfirmed link is allowed here: it has no @e n and no @e dv of its
6035 own, so the "confirmed required" branch below resolves the route from
6036 #neighbours / #dv_routes. Refusing to route at all is what deadlocks a
6037 pair of peers, see #consider_sending_fc(). */
6038 GNUNET_assert (NULL != vl);
6039 n = vl->n;
6040 dv = (0 != (options & RMO_DV_ALLOWED)) ? vl->dv : NULL;
6041 /* An unconfirmed link has neither @e n nor @e dv of its own, so resolve
6042 the route from #neighbours / #dv_routes. This used to be done only
6043 while #RMO_UNCONFIRMED_ALLOWED was *not* set -- exactly backwards: with
6044 the flag set (the caller that needs it most) we would find no route at
6045 all and drop the message. Whether an unvalidated queue or an
6046 unvalidated path may then be used is still decided by @a options, in
6047 #route_via_neighbour() and #pick_random_dv_hops(). */
6048 if (NULL == n)
6049 n = lookup_neighbour (target);
6050 if ((NULL == dv) && (0 != (options & RMO_DV_ALLOWED)))
6052 if ((NULL == n) && (NULL == dv))
6053 {
6055 "Cannot route message of type %u to %s: no route\n",
6056 ntohs (hdr->type),
6057 GNUNET_i2s (target));
6059 "# Messages dropped in routing: no acceptable method",
6060 1,
6061 GNUNET_NO);
6063 }
6065 "Routing message of type %u to %s with options %X\n",
6066 ntohs (hdr->type),
6067 GNUNET_i2s (target),
6068 (unsigned int) options);
6069 /* If both dv and n are possible and we must choose:
6070 flip a coin for the choice between the two; for now 50/50 */
6071 if ((NULL != n) && (NULL != dv) && (0 == (options & RMO_REDUNDANT)))
6072 {
6073 if (0 == GNUNET_CRYPTO_random_u32 (2))
6074 n = NULL;
6075 else
6076 dv = NULL;
6077 }
6078 if ((NULL != n) && (NULL != dv))
6079 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
6080 enough for redundancy, so clear the flag. */
6083 if (NULL != n)
6084 {
6086 "Try to route message of type %u to %s without fc via neighbour\n",
6087 ntohs (hdr->type),
6088 GNUNET_i2s (target));
6089 rtt1 = route_via_neighbour (n, hdr, options);
6090 }
6091 if (NULL != dv)
6092 {
6093 struct DistanceVectorHop *hops[2];
6094 unsigned int res;
6095
6097 options,
6098 hops,
6099 (0 == (options & RMO_REDUNDANT)) ? 1 : 2);
6100 if (0 == res)
6101 {
6103 "Failed to route message, could not determine DV path\n");
6104 return rtt1;
6105 }
6107 "encapsulate_for_dv 1\n");
6108 rtt2 = encapsulate_for_dv (dv,
6109 res,
6110 hops,
6111 hdr,
6113 NULL,
6115 GNUNET_YES);
6116 }
6117 return GNUNET_TIME_relative_min (rtt1, rtt2);
6118}
6119
6120
6121static void
6122consider_sending_fc (void *cls);
6123
6130static void
6131task_consider_sending_fc (void *cls)
6132{
6133 struct VirtualLink *vl = cls;
6134 vl->fc_retransmit_task = NULL;
6135 consider_sending_fc (cls);
6136}
6137
6138
6139static char *
6140get_address_without_port (const char *address);
6141
6142
6144{
6145 size_t off;
6146
6152 size_t size;
6153
6154 char *tgnas;
6155};
6156
6157
6158static enum GNUNET_GenericReturnValue
6159add_global_addresses (void *cls,
6160 const struct GNUNET_PeerIdentity *pid,
6161 void *value)
6162{
6163 struct AddGlobalAddressesContext *ctx = cls;
6164 struct TransportGlobalNattedAddress *tgna = value;
6165 char *addr = (char *) &tgna[1];
6166 size_t alen = ntohl (tgna->address_length);
6167 size_t need = sizeof (struct TransportGlobalNattedAddress) + alen;
6168
6169 /* NOTE: the address is NOT 0-terminated, it must be printed with an
6170 explicit precision. */
6172 "sending address %.*s length %lu\n",
6173 (int) alen,
6174 addr,
6175 (unsigned long) alen);
6176 if (ctx->off + need > ctx->size)
6177 {
6178 GNUNET_break (0);
6179 return GNUNET_NO;
6180 }
6181 GNUNET_memcpy (&(ctx->tgnas[ctx->off]), tgna, need);
6182 ctx->off += need;
6183
6184 return GNUNET_OK;
6185}
6186
6187
6188static struct GNUNET_TIME_Relative
6189calculate_rtt (struct DistanceVector *dv);
6190
6191
6198static void
6199consider_sending_fc (void *cls)
6200{
6201 struct VirtualLink *vl = cls;
6202 struct GNUNET_TIME_Absolute monotime;
6203 struct TransportFlowControlMessage *fc;
6205 struct GNUNET_TIME_Relative rtt;
6206 struct GNUNET_TIME_Relative rtt_average;
6207 struct Neighbour *n = vl->n;
6208 size_t addresses_size;
6209
6210 /* Most of our callers are not the retransmit task but inbound events:
6211 handle_flow_control() ends in check_vl_transmission(), which calls us
6212 once per flow-control-stalled message, and the peer's answer to what we
6213 send here arrives as another handle_flow_control(). On a link whose
6214 head message does not fit the window that is a ping-pong with nothing
6215 to damp it -- the backoff and the MIN_FC_RETRANSMIT_DELAY floor at the
6216 bottom of this function only ever governed @e fc_retransmit_task, which
6217 these callers bypass. If the chain is armed and we just sent one, let
6218 the task do it. */
6219 if ((NULL != vl->fc_retransmit_task) &&
6221 < MIN_FC_RETRANSMIT_DELAY.rel_value_us))
6222 {
6224 "Not sending FC to %s: one went out less than %s ago\n",
6225 GNUNET_i2s (&vl->target),
6228 GNUNET_YES));
6229 return;
6230 }
6231 if ((GNUNET_YES != vl->confirmed) &&
6232 (NULL == lookup_neighbour (&vl->target)) &&
6234 {
6235 /* Unconfirmed AND no way to reach the peer at all -- nothing to send on.
6236 An unconfirmed link that *does* have a route must still answer,
6237 see below.
6238
6239 Do NOT just return: #task_consider_sending_fc() cleared
6240 @e fc_retransmit_task before calling us, and the only other place that
6241 arms it is #handle_flow_control() -- which only does so when it is
6242 already non-NULL. Leaving without re-arming therefore ends the
6243 keepalive chain for this link permanently, and #check_link_down()
6244 tears it down #NEIGHBOUR_LIVENESS_TIMEOUT later. */
6246 "Not sending FC to %s: link unconfirmed and no route\n",
6247 GNUNET_i2s (&vl->target));
6248 if (NULL == vl->fc_retransmit_task)
6252 vl);
6253 return;
6254 }
6255 addresses_size = 0;
6256 if (NULL != n && 0 < n->number_of_addresses)
6257 {
6258 addresses_size =
6259 n->number_of_addresses * sizeof (struct TransportGlobalNattedAddress) + n
6260 ->size_of_global_addresses;
6261 if (addresses_size >
6262 UINT16_MAX - sizeof (struct TransportFlowControlMessage))
6263 {
6264 /* htons() below would silently truncate `header.size', leaving a
6265 message whose declared length does not match its contents. */
6266 GNUNET_break (0);
6267 addresses_size = 0;
6268 }
6269 }
6270 if (0 != addresses_size)
6271 {
6272 char *tgnas = GNUNET_malloc (addresses_size);
6274 ctx.off = 0;
6275 ctx.size = addresses_size;
6276 ctx.tgnas = tgnas;
6277
6279 + addresses_size);
6280 fc->header.size = htons (sizeof(struct TransportFlowControlMessage)
6281 + addresses_size);
6282 fc->size_of_addresses = htonl ((uint32_t) n->size_of_global_addresses);
6283 fc->number_of_addresses = htonl (n->number_of_addresses);
6286 &ctx);
6289 }
6290 else
6291 {
6292 fc = GNUNET_malloc (sizeof (struct TransportFlowControlMessage));
6293 fc->header.size = htons (sizeof(struct TransportFlowControlMessage));
6294 }
6295
6297 /* OPTIMIZE-FC-BDP: decide sane criteria on when to do this, instead of doing
6298 it always! */
6299 /* For example, we should probably ONLY do this if a bit more than
6300 an RTT has passed, or if the window changed "significantly" since
6301 then. See vl->last_fc_rtt! NOTE: to do this properly, we also
6302 need an estimate for the bandwidth-delay-product for the entire
6303 VL, as that determines "significantly". We have the delay, but
6304 the bandwidth statistics need to be added for the VL!*/(void) duration;
6305
6306 if (NULL != vl->dv)
6307 rtt_average = calculate_rtt (vl->dv);
6308 else
6309 rtt_average = GNUNET_TIME_UNIT_FOREVER_REL;
6310 fc->rtt = GNUNET_TIME_relative_hton (rtt_average);
6312 "Sending FC seq %u to %s with new window %llu %lu %u\n",
6313 (unsigned int) vl->fc_seq_gen,
6314 GNUNET_i2s (&vl->target),
6315 (unsigned long long) vl->incoming_fc_window_size,
6316 (unsigned long) rtt_average.rel_value_us,
6317 vl->sync_ready);
6319 vl->last_fc_transmission = monotime;
6320 fc->sync_ready = htonl ((uint32_t) vl->sync_ready);
6322 fc->seq = htonl (vl->fc_seq_gen++);
6323 fc->inbound_window_size = GNUNET_htonll (vl->incoming_fc_window_size
6326 fc->outbound_sent = GNUNET_htonll (vl->outbound_fc_window_size_used);
6327 fc->outbound_window_size = GNUNET_htonll (vl->outbound_fc_window_size);
6328 fc->sender_time = GNUNET_TIME_absolute_hton (monotime);
6329 /* On an unconfirmed link the only queues and paths we have are, by
6330 definition, unvalidated ones -- that is what "unconfirmed" means.
6331 Requiring a validated route here is what deadlocks the pair: the peer
6332 has a confirmed link to us and flow-controls us, we cannot answer, so
6333 its @e outbound_fc_window_size stays at zero and it cannot send us a
6334 single byte -- not its CORE handshake, not DHT traffic -- while its
6335 `gnunet-transport' shows an established link with messages pending
6336 forever. It reached us over that queue, so answering on it is sound. */
6338 &fc->header,
6339 (GNUNET_YES == vl->confirmed)
6342 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == rtt.rel_value_us)
6343 {
6346 "FC retransmission to %s failed, will retry in %s\n",
6347 GNUNET_i2s (&vl->target),
6350 }
6351 else
6352 {
6353 /* OPTIMIZE-FC-BDP: rtt is not ideal, we can do better! */
6354 vl->last_fc_rtt = rtt;
6355 }
6356 if (NULL != vl->fc_retransmit_task)
6358 /* Never re-arm with (near) zero delay: @a rtt is zero whenever we have no
6359 RTT sample yet, which turned this into a tight send loop. */
6361 {
6362 /* Back off while the peer stays silent. Retransmitting at the plain RTT
6363 for #MAX_FC_RETRANSMIT_COUNT rounds is a flood on a link that is not
6364 being answered -- and a peer that cannot answer keeps *every* one of
6365 its links in exactly that state, which is enough traffic to make
6366 transport fall behind its communicators. */
6368
6369 for (unsigned int i = 0;
6370 (i < vl->fc_retransmit_count) && (rtt.rel_value_us < cap.rel_value_us);
6371 i++)
6372 rtt = GNUNET_TIME_relative_multiply (rtt, 2);
6373 rtt = GNUNET_TIME_relative_min (rtt, cap);
6374 }
6375 vl->fc_retransmit_task =
6378 vl->fc_retransmit_count++;
6379 GNUNET_free (fc);
6380}
6381
6382
6399static void
6401{
6402 struct Neighbour *n = vl->n;
6403 struct DistanceVector *dv = vl->dv;
6404 struct GNUNET_TIME_Absolute now;
6405 struct VirtualLink *vl_next_hop;
6406 int elig;
6407
6409 "check_vl_transmission to target %s\n",
6410 GNUNET_i2s (&vl->target));
6411 /* Check that we have an eligible pending message!
6412 (cheaper than having #transmit_on_queue() find out!) */
6413 elig = GNUNET_NO;
6414 for (struct PendingMessage *pm = vl->pending_msg_head; NULL != pm;
6415 pm = pm->next_vl)
6416 {
6418 "check_vl_transmission loop\n");
6419 if (NULL != pm->qe)
6420 continue; /* not eligible, is in a queue! */
6423 {
6425 "Stalled message %" PRIu64
6426 " transmission on VL %s due to flow control: %llu < %llu\n",
6427 pm->logging_uuid,
6428 GNUNET_i2s (&vl->target),
6429 (unsigned long long) vl->outbound_fc_window_size,
6430 (unsigned long long) (pm->bytes_msg
6433 return; /* We have a message, but flow control says "nope" */
6434 }
6436 "Target window on VL %s not stalled. Scheduling transmission on queue\n",
6437 GNUNET_i2s (&vl->target));
6438 /* Notify queues at direct neighbours that we are interested */
6439 now = GNUNET_TIME_absolute_get ();
6440 if (NULL != n)
6441 {
6442 for (struct Queue *queue = n->queue_head; NULL != queue;
6443 queue = queue->next_neighbour)
6444 {
6445 if ((GNUNET_YES == queue->idle) &&
6446 (queue->validated_until.abs_value_us > now.abs_value_us))
6447 {
6449 "Direct neighbour %s not stalled\n",
6450 GNUNET_i2s (&n->pid));
6452 queue,
6454 elig = GNUNET_YES;
6455 }
6456 else
6458 "Neighbour Queue QID: %u (%u) busy or invalid\n",
6459 queue->qid,
6460 queue->idle);
6461 }
6462 }
6463 /* Notify queues via DV that we are interested */
6464 if (NULL != dv)
6465 {
6466 /* Do DV with lower scheduler priority, which effectively means that
6467 IF a neighbour exists and is available, we prefer it. */
6468 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
6469 pos = pos->next_dv)
6470 {
6471 struct Neighbour *nh_iter = pos->next_hop;
6472
6473
6474 if (pos->path_valid_until.abs_value_us <= now.abs_value_us)
6475 continue; /* skip this one: path not validated */
6476 else
6477 {
6478 /* The next hop is a neighbour we have queues to; it need not have
6479 a virtual link of its own, and then there is no window of it to
6480 respect either. */
6481 vl_next_hop = lookup_virtual_link (&nh_iter->pid);
6482 if ((NULL != vl_next_hop) &&
6483 (pm->bytes_msg + vl_next_hop->outbound_fc_window_size_used >
6484 vl_next_hop->outbound_fc_window_size))
6485 {
6487 "Stalled message %" PRIu64
6488 " transmission on next hop %s due to flow control: %llu < %llu\n",
6489 pm->logging_uuid,
6490 GNUNET_i2s (&vl_next_hop->target),
6491 (unsigned long
6492 long) vl_next_hop->outbound_fc_window_size,
6493 (unsigned long long) (pm->bytes_msg
6494 + vl_next_hop->
6495 outbound_fc_window_size_used));
6496 consider_sending_fc (vl_next_hop);
6497 continue; /* We have a message, but flow control says "nope" for the first hop of this path */
6498 }
6499 for (struct Queue *queue = nh_iter->queue_head; NULL != queue;
6500 queue = queue->next_neighbour)
6501 if ((GNUNET_YES == queue->idle) &&
6502 (queue->validated_until.abs_value_us > now.abs_value_us))
6503 {
6505 "Next hop neighbour %s not stalled\n",
6506 GNUNET_i2s (&nh_iter->pid));
6508 queue,
6510 elig = GNUNET_YES;
6511 }
6512 else
6514 "DV Queue QID: %u (%u) busy or invalid\n",
6515 queue->qid,
6516 queue->idle);
6517 }
6518 }
6519 }
6520 if (GNUNET_YES == elig)
6522 "Eligible message %" PRIu64 " of size %u to %s: %llu/%llu\n",
6523 pm->logging_uuid,
6524 pm->bytes_msg,
6525 GNUNET_i2s (&vl->target),
6526 (unsigned long long) vl->outbound_fc_window_size,
6527 (unsigned long long) (pm->bytes_msg
6529 break;
6530 }
6531}
6532
6533
6540static void
6541handle_client_send (void *cls, const struct OutboundMessage *obm)
6542{
6543 struct TransportClient *tc = cls;
6544 struct PendingMessage *pm;
6545 const struct GNUNET_MessageHeader *obmm;
6546 uint32_t bytes_msg;
6547 struct VirtualLink *vl;
6549
6550 GNUNET_assert (CT_CORE == tc->type);
6551 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
6552 bytes_msg = ntohs (obmm->size);
6553 pp = ntohl (obm->priority);
6554 vl = lookup_virtual_link (&obm->peer);
6555 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
6556 {
6558 "Don't have %s as a neighbour (anymore).\n",
6559 GNUNET_i2s (&obm->peer));
6560 /* Failure: don't have this peer as a neighbour (anymore).
6561 Might have gone down asynchronously, so this is NOT
6562 a protocol violation by CORE. Still count the event,
6563 as this should be rare. */
6564 /* Precisely because this is not a protocol violation we leave the
6565 client's `struct Neighbour' -- and its send window -- in place, so we
6566 owe it the SEND_OK for the message we are dropping here. Without it
6567 the window shrinks by one every time this happens and never grows
6568 back; after #SEND_WINDOW_SIZE such drops #mq_send_impl() parks every
6569 further message for this peer forever ("Flow control delays
6570 transmission to CORE until we see SEND_OK") and CORE goes mute
6571 towards a peer it still believes it is connected to -- while
6572 continuing to receive from it, so its own idle timeout is what
6573 eventually reports the peer down. */
6574 send_ok_to_client (tc, &obm->peer);
6577 "# messages dropped (neighbour unknown)",
6578 1,
6579 GNUNET_NO);
6580 return;
6581 }
6582
6583 pm = GNUNET_malloc (sizeof(struct PendingMessage) + bytes_msg);
6585 "1 created pm %p storing vl %p\n",
6586 pm,
6587 vl);
6589 pm->prefs = pp;
6590 pm->client = tc;
6591 pm->vl = vl;
6592 pm->bytes_msg = bytes_msg;
6593 memcpy (&pm[1], obmm, bytes_msg);
6595 "Sending message of type %u with %u bytes as <%" PRIu64
6596 "> to %s\n",
6597 ntohs (obmm->type),
6598 bytes_msg,
6599 pm->logging_uuid,
6600 GNUNET_i2s (&obm->peer));
6602 tc->details.core.pending_msg_head,
6603 tc->details.core.pending_msg_tail,
6604 pm);
6606 vl->pending_msg_head,
6607 vl->pending_msg_tail,
6608 pm);
6611}
6612
6613
6623static void
6625 void *cls,
6627{
6628 struct Neighbour *n;
6629 struct VirtualLink *vl;
6630 struct TransportClient *tc = cls;
6631 const struct GNUNET_MessageHeader *inbox =
6632 (const struct GNUNET_MessageHeader *) &cb[1];
6633 uint16_t isize = ntohs (inbox->size);
6634 const char *is = ((const char *) &cb[1]) + isize;
6635 size_t slen = strlen (is) + 1;
6636 char
6637 mbuf[slen + isize
6638 + sizeof(struct
6642
6643 /* 0-termination of 'is' was checked already in
6644 #check_communicator_backchannel() */
6646 "Preparing backchannel transmission to %s:%s of type %u and size %u\n",
6647 GNUNET_i2s (&cb->pid),
6648 is,
6649 ntohs (inbox->type),
6650 ntohs (inbox->size));
6651 /* encapsulate and encrypt message */
6652 be->header.type =
6654 be->header.size = htons (sizeof(mbuf));
6655 memcpy (&be[1], inbox, isize);
6656 memcpy (&mbuf[sizeof(struct TransportBackchannelEncapsulationMessage)
6657 + isize],
6658 is,
6659 strlen (is) + 1);
6660 // route_control_message_without_fc (&cb->pid, &be->header, RMO_DV_ALLOWED);
6661 vl = lookup_virtual_link (&cb->pid);
6662 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
6663 {
6665 }
6666 else
6667 {
6668 /* Use route via neighbour */
6669 n = lookup_neighbour (&cb->pid);
6670 if (NULL != n)
6672 n,
6673 &be->header,
6674 RMO_NONE);
6675 }
6677}
6678
6679
6687static int
6688check_add_address (void *cls,
6689 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
6690{
6691 struct TransportClient *tc = cls;
6692
6693 if (CT_COMMUNICATOR != tc->type)
6694 {
6695 GNUNET_break (0);
6696 return GNUNET_SYSERR;
6697 }
6699 return GNUNET_OK;
6700}
6701
6702
6708static void
6709store_pi (void *cls);
6710
6711
6716{
6717
6721 struct AddressListEntry *ale;
6722
6726 struct PilsRequest *req;
6727
6728
6732 struct GNUNET_TIME_Absolute et;
6733};
6734
6735
6742static void
6744{
6745 struct PilsAddressSignContext *pc = ale->pc;
6746
6747 if (NULL == pc)
6748 return;
6749 ale->pc = NULL;
6750 /* Each stage of the chain passes @a pc as its closure, so every handle
6751 that could still deliver one has to go before @a pc is released. */
6752 if (NULL != ale->sc)
6753 {
6755 ale->sc = NULL;
6756 }
6757 if (NULL != ale->shc)
6758 {
6760 ale->shc = NULL;
6761 }
6762 if (NULL != pc->req)
6763 {
6764 if (NULL != pc->req->op)
6765 GNUNET_PILS_cancel (pc->req->op);
6768 pc->req);
6769 GNUNET_free (pc->req);
6770 pc->req = NULL;
6771 }
6772 GNUNET_free (pc);
6773}
6774
6775
6776static void
6777shc_cont (void *cls, int success)
6778{
6779 struct PilsAddressSignContext *pc = cls;
6780
6781 GNUNET_assert (NULL == pc->req);
6782 /* The store completed; the handle is dead and must not be cancelled
6783 later by #free_address_list_entry(). */
6784 pc->ale->shc = NULL;
6785 pc->ale->pc = NULL;
6786 if (GNUNET_OK != success)
6787 {
6789 "Failed to store our address `%s' with peerstore\n",
6790 pc->ale->address);
6791 if (NULL == pc->ale->st)
6792 {
6794 &store_pi,
6795 pc->ale);
6796 }
6797 }
6798 GNUNET_free (pc);
6799}
6800
6801
6805static void
6806pils_sign_hello_cb (void *cls,
6807 const struct GNUNET_PeerIdentity *pid,
6808 const struct GNUNET_CRYPTO_EddsaSignature *sig)
6809{
6810 struct PilsAddressSignContext *pc = cls;
6811 struct GNUNET_MQ_Envelope *env;
6812 const struct GNUNET_MessageHeader *msg;
6813
6814 pc->req->op = NULL;
6817 pc->req);
6818 GNUNET_free (pc->req);
6819 pc->req = NULL;
6822 pid,
6823 sig,
6824 pc->et);
6827 "store_pi 1\n");
6829 msg,
6830 shc_cont,
6831 pc);
6832 GNUNET_free (env);
6833}
6834
6835
6842static void
6843peerstore_store_own_cb (void *cls, int success)
6844{
6845 struct PilsAddressSignContext *pc = cls;
6846
6847 pc->ale->sc = NULL;
6848 if (GNUNET_YES != success)
6850 "Failed to store our own address `%s' in peerstore!\n",
6851 pc->ale->address);
6852 else
6854 "Successfully stored our own address `%s' in peerstore!\n",
6855 pc->ale->address);
6856 /* refresh period is 1/4 of expiration time, that should be plenty
6857 without being excessive. */
6858 if (NULL == pc->ale->st)
6859 {
6860 /* @e expiration comes straight off the wire in ADD_ADDRESS and is not
6861 validated anywhere, so a communicator reporting a very short (or
6862 zero) lifetime would have us re-sign the HELLO and store it again on
6863 the next scheduler pass, forever. That is an EdDSA signature and a
6864 PEERSTORE round trip per iteration. */
6865 pc->ale->st =
6869 GNUNET_TIME_relative_divide (pc->ale->expiration,
6870 4ULL)),
6871 &store_pi,
6872 pc->ale);
6873 }
6874
6875 /* Now we have to update our HELLO! */
6877 pc->req = GNUNET_new (struct PilsRequest);
6880 pc->req);
6881 pc->req->op = GNUNET_PILS_sign_hello (pils,
6883 pc->et,
6885 pc);
6886}
6887
6888
6896static void
6898 const struct GNUNET_PeerIdentity *pid,
6899 const struct GNUNET_CRYPTO_EddsaSignature *sig)
6900{
6901 char *sig_str;
6902 void *result;
6903 size_t result_size;
6904
6905 sig_str = NULL;
6906 (void) GNUNET_STRINGS_base64_encode (sig, sizeof(*sig), &sig_str);
6907 result_size =
6908 1 + GNUNET_asprintf (
6909 (char **) &result,
6910 "%s;%llu;%u;%s",
6911 sig_str,
6912 (unsigned long long) pc->et.abs_value_us,
6913 (unsigned int) pc->ale->nt,
6914 pc->ale->address);
6915 GNUNET_free (sig_str);
6916
6918 "Build our HELLO URI `%s'\n",
6919 (char*) result);
6920
6921 GNUNET_free (pc->ale->signed_address);
6922 pc->ale->signed_address = result;
6923 pc->ale->signed_address_len = result_size;
6925
6926 expiration = GNUNET_TIME_relative_to_absolute (pc->ale->expiration);
6928 "transport",
6929 pid,
6931 result,
6932 result_size,
6933 expiration,
6936 pc);
6937}
6938
6939
6943struct SignedAddress
6944{
6949
6954
6958 struct GNUNET_HashCode addr_hash GNUNET_PACKED;
6959};
6960
6961
6975void
6977 struct AddressListEntry *ale,
6978 struct GNUNET_TIME_Absolute mono_time)
6979{
6980 struct SignedAddress sa;
6981 struct PilsAddressSignContext *pc;
6983 const struct GNUNET_PeerIdentity *my_identity;
6984
6985 sa.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_ADDRESS);
6986 sa.purpose.size = htonl (sizeof(sa));
6987 sa.mono_time = GNUNET_TIME_absolute_hton (mono_time);
6988 GNUNET_CRYPTO_hash (ale->address, strlen (ale->address), &sa.addr_hash);
6989 /* Only ever one chain per entry: the previous one (if any) still holds a
6990 pointer to @a ale and must be torn down first. */
6993 if ((NULL == my_identity) ||
6994 (GNUNET_OK != sign_by_my_identity (&sa.purpose, &sig)))
6995 {
6996 /* Nothing else re-arms @e st: #store_pi() cleared it before calling us,
6997 and the only other thing that sets it is #peerstore_store_own_cb(),
6998 which is on the far side of the store we just failed to start. So a
6999 single failure to sign used to end the refresh cycle for this address
7000 for the rest of the process' life. */
7001 if (NULL == ale->st)
7002 {
7005 &store_pi,
7006 ale);
7007 }
7008 return;
7009 }
7011 pc->ale = ale;
7012 pc->et = mono_time;
7013 ale->pc = pc;
7015}
7016
7017
7023static void
7024store_pi (void *cls)
7025{
7026 struct AddressListEntry *ale = cls;
7027 const char *dash;
7028 char *address_uri;
7029 char *prefix;
7030 unsigned int add_success;
7031
7032 if ((GNUNET_YES == in_shutdown) || (NULL == pils))
7033 {
7034 ale->st = NULL;
7035 return;
7036 }
7037 if (NULL == GNUNET_PILS_get_identity (pils))
7038 {
7039 /* Do NOT poll at 1kHz: that burns CPU and keeps the scheduler task
7040 list non-empty, which prevents the service from ever exiting. */
7043 &store_pi,
7044 ale);
7045 return;
7046 }
7049 dash = strchr (ale->address, '-');
7050 GNUNET_assert (NULL != dash);
7051 dash++;
7052 GNUNET_asprintf (&address_uri,
7053 "%s://%s",
7054 prefix,
7055 dash);
7057 ale->st = NULL;
7059 "Storing our address `%s' in peerstore until %s!\n",
7060 ale->address,
7063 address_uri);
7064 /* NOTE: #GNUNET_HELLO_builder_add_address() answers GNUNET_NO for an
7065 address that is already in the builder, and on every call after the
7066 first one for a given address that is exactly what happens: nothing
7067 ever removes an address from @a GST_my_hello except
7068 #handle_del_address(). This function is the *refresh* cycle --
7069 #peerstore_store_own_cb() re-arms it at a quarter of the address'
7070 expiration -- so bailing out on GNUNET_NO here stopped the refresh
7071 after precisely one round. Our own HELLO then expired
7072 (#GNUNET_HELLO_ADDRESS_EXPIRATION, twelve hours) and was never
7073 renewed: peers can no longer learn how to reach us, and a link that
7074 drops after that never comes back. Only GNUNET_SYSERR -- a malformed
7075 URI, which retrying cannot fix -- is a reason not to store. */
7076 if (GNUNET_SYSERR == add_success)
7077 {
7079 "Not storing our address `%s': not a valid HELLO URI\n",
7080 address_uri);
7081 GNUNET_free (address_uri);
7082 return;
7083 }
7084 GNUNET_log ((GNUNET_NO == add_success) ?
7086 "%s our address `%s' in PEERSTORE\n",
7087 (GNUNET_NO == add_success) ? "Refreshing" : "Storing",
7088 address_uri);
7089 // FIXME hello_mono_time used here?? What about expiration in ale?
7090 pils_sign_address (ale,
7092 // TODO keep track of op and potentially cancel/clean
7093 GNUNET_free (address_uri);
7094}
7095
7096
7097static struct AddressListEntry *
7101 const char *address,
7102 uint32_t aid,
7103 size_t slen)
7104{
7105 struct AddressListEntry *ale;
7106 char *address_without_port;
7107
7108 ale = GNUNET_malloc (sizeof(struct AddressListEntry) + slen);
7109 ale->tc = tc;
7110 ale->address = (const char *) &ale[1];
7111 ale->expiration = expiration;
7112 ale->aid = aid;
7113 ale->nt = nt;
7114 memcpy (&ale[1], address, slen);
7115 address_without_port = get_address_without_port (ale->address);
7117 "Is this %s a local address (%s)\n",
7118 (NULL == address_without_port) ? "<unparsable>"
7119 : address_without_port,
7120 ale->address);
7121 if ((NULL == address_without_port) ||
7122 (0 != strcmp ("127.0.0.1", address_without_port)))
7123 {
7124 if (NULL != ale->st)
7125 {
7127 }
7128 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
7129 }
7130 GNUNET_free (address_without_port);
7131
7132 return ale;
7133}
7134
7135
7136static void
7137feed_addresses_to_pils (void *cls)
7138{
7139
7141 "Feeding addresses to PILS\n");
7142 pils_feed_task = NULL;
7143
7145 GST_my_hello);
7146}
7147
7148
7155static void
7156handle_add_address (void *cls,
7157 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
7158{
7159 struct TransportClient *tc = cls;
7160 struct AddressListEntry *ale;
7161 size_t slen;
7162 char *address;
7163
7164 /* 0-termination of &aam[1] was checked in #check_add_address */
7166 "Communicator added address `%s'!\n",
7167 (const char *) &aam[1]);
7168 slen = ntohs (aam->header.size) - sizeof(*aam);
7169 address = GNUNET_malloc (slen);
7170 memcpy (address, &aam[1], slen);
7171 ale = create_address_entry (tc,
7173 ntohl (aam->nt),
7174 address,
7175 aam->aid,
7176 slen);
7177 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
7178 tc->details.communicator.addr_tail,
7179 ale);
7180 {
7181 for (struct AddressListEntry *iter = tc->details.communicator.addr_head;
7182 NULL != iter;
7183 iter = iter->next)
7184 {
7185 char *address_uri;
7186 const char *dash = strchr (iter->address, '-');
7187 char *prefix = GNUNET_HELLO_address_to_prefix (iter->address);
7188 GNUNET_assert (NULL != dash);
7189 dash++;
7190 GNUNET_asprintf (&address_uri,
7191 "%s://%s",
7192 prefix,
7193 dash);
7196 GNUNET_free (address_uri);
7197 }
7198 if (NULL != pils_feed_task)
7202 NULL);
7203 }
7206}
7207
7208
7215static void
7216handle_del_address (void *cls,
7217 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
7218{
7219 struct TransportClient *tc = cls;
7220 struct AddressListEntry *alen;
7221
7222 if (CT_COMMUNICATOR != tc->type)
7223 {
7224 GNUNET_break (0);
7226 return;
7227 }
7228 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
7229 NULL != ale;
7230 ale = alen)
7231 {
7232 alen = ale->next;
7233 if (dam->aid != ale->aid)
7234 continue;
7235 GNUNET_assert (ale->tc == tc);
7237 "Communicator deleted address `%s'!\n",
7238 ale->address);
7240 ale->address);
7241 if (NULL != pils_feed_task)
7245 NULL);
7248 return;
7249 }
7251 "Communicator removed address we did not even have.\n");
7253 // GNUNET_SERVICE_client_drop (tc->client);
7254}
7255
7256
7264static void
7266
7267
7275static void
7276core_env_sent_cb (void *cls)
7277{
7278 struct CoreSentContext *ctx = cls;
7279 struct VirtualLink *vl = ctx->vl;
7280
7281 if (NULL == vl)
7282 {
7283 /* lost the link in the meantime, ignore */
7284 GNUNET_free (ctx);
7285 return;
7286 }
7289 vl->incoming_fc_window_size_ram -= ctx->size;
7290 vl->incoming_fc_window_size_used += ctx->isize;
7292 GNUNET_free (ctx);
7293}
7294
7295
7317static void
7318core_fc_stalled (void *cls)
7319{
7320 struct VirtualLink *vl = cls;
7321 struct CommunicatorMessageContext *cmc;
7322
7323 vl->core_fc_stall_task = NULL;
7325 "CORE did not acknowledge messages from %s within %s; "
7326 "releasing the flow control credit anyway\n",
7327 GNUNET_i2s (&vl->target),
7329 GNUNET_YES));
7331 "# CORE flow control stalls",
7332 1,
7333 GNUNET_NO);
7334 while (NULL != (cmc = vl->cmc_tail))
7335 release_stalled_cmc (vl, cmc);
7338}
7339
7340
7341static void
7343 const struct GNUNET_MessageHeader *mh,
7344 struct CommunicatorMessageContext *cmc,
7345 unsigned int free_cmc)
7346{
7347 uint16_t size = ntohs (mh->size);
7348 int have_core;
7349
7350 if (vl->incoming_fc_window_size_ram > UINT_MAX - size)
7351 {
7353 "# CORE messages dropped (FC arithmetic overflow)",
7354 1,
7355 GNUNET_NO);
7357 "CORE messages of type %u with %u bytes dropped (FC arithmetic overflow)\n",
7358 (unsigned int) ntohs (mh->type),
7359 (unsigned int) ntohs (mh->size));
7360 if (GNUNET_YES == free_cmc)
7362 return;
7363 }
7365 {
7367 "# CORE messages dropped (FC window overflow)",
7368 1,
7369 GNUNET_NO);
7371 "CORE messages of type %u with %u bytes dropped (FC window overflow)\n",
7372 (unsigned int) ntohs (mh->type),
7373 (unsigned int) ntohs (mh->size));
7374 if (GNUNET_YES == free_cmc)
7376 return;
7377 }
7378
7379 /* Forward to all CORE clients */
7380 have_core = GNUNET_NO;
7381 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
7382 {
7383 struct GNUNET_MQ_Envelope *env;
7384 struct InboundMessage *im;
7385 struct CoreSentContext *ctx;
7386
7387 if (CT_CORE != tc->type)
7388 continue;
7391 ctx = GNUNET_new (struct CoreSentContext);
7392 ctx->vl = vl;
7393 ctx->size = size;
7394 ctx->isize = (GNUNET_NO == have_core) ? size : 0;
7395 have_core = GNUNET_YES;
7398 im->peer = cmc->im.sender;
7399 memcpy (&im[1], mh, size);
7400 GNUNET_MQ_send (tc->mq, env);
7402 }
7403 if (GNUNET_NO == have_core)
7404 {
7406 "Dropped message to CORE: no CORE client connected!\n");
7407 /* Nevertheless, count window as used, as it is from the
7408 perspective of the other peer! */
7410 /* TODO-M1 */
7412 "Dropped message of type %u with %u bytes to CORE: no CORE client connected!\n",
7413 (unsigned int) ntohs (mh->type),
7414 (unsigned int) ntohs (mh->size));
7415 if (GNUNET_YES == free_cmc)
7417 return;
7418 }
7420 "Delivered message from %s of type %u to CORE recv window %d\n",
7421 GNUNET_i2s (&cmc->im.sender),
7422 ntohs (mh->type),
7424 if (vl->core_recv_window > 0)
7425 {
7426 if (GNUNET_YES == free_cmc)
7428 return;
7429 }
7430 /* CORE ran out of receive window for *this* link. Withhold the
7431 per-message ACK -- that is what expresses the backpressure -- but
7432 resume the client immediately. The client is the communicator
7433 *process*, which carries every peer we reach through it, and a
7434 communicator we stop reading from does not stop receiving: it starts
7435 discarding, see "transport is too slow" in
7436 #GNUNET_TRANSPORT_communicator_receive(). Discarding is precisely
7437 what we cannot afford here, because among the messages dropped are
7438 the ones CORE needs in order to reopen the window it is waiting on. */
7439 if (GNUNET_YES == free_cmc)
7440 {
7441 resume_cmc_client (cmc);
7443 vl->cmc_count++;
7444 /* Nothing stalls the producer any more, so bound the list ourselves. */
7445 while (MAX_STALLED_CMCS < vl->cmc_count)
7447 /* ... and do not withhold the ACKs forever: see #core_fc_stalled(). */
7448 if (NULL == vl->core_fc_stall_task)
7452 vl);
7453 }
7454}
7455
7456
7465static void
7466handle_raw_message (void *cls, const struct GNUNET_MessageHeader *mh)
7467{
7468 struct CommunicatorMessageContext *cmc = cls;
7469 // struct CommunicatorMessageContext *cmc_copy =
7470 // GNUNET_new (struct CommunicatorMessageContext);
7471 struct GNUNET_MessageHeader *mh_copy;
7472 struct RingBufferEntry *rbe;
7473 struct VirtualLink *vl;
7474 uint16_t size = ntohs (mh->size);
7475
7477 "Handling raw message of type %u with %u bytes\n",
7478 (unsigned int) ntohs (mh->type),
7479 (unsigned int) ntohs (mh->size));
7480
7481 if ((size > UINT16_MAX - sizeof(struct InboundMessage)) ||
7482 (size < sizeof(struct GNUNET_MessageHeader)))
7483 {
7484 /* @a mh was unwrapped from what a *remote peer* sent us, so a bad size
7485 is that peer's protocol violation and says nothing about the
7486 communicator that carried it. Dropping the client here disconnects
7487 the communicator process and with it every neighbour reachable
7488 through it -- see the rationale in #demultiplex_with_cmc(). */
7489 GNUNET_break_op (0);
7491 "# CORE messages dropped (bad size)",
7492 1,
7493 GNUNET_NO);
7494 finish_cmc_handling (cmc);
7495 return;
7496 }
7497 vl = lookup_virtual_link (&cmc->im.sender);
7498 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
7499 {
7500 /* FIXME: sender is giving us messages for CORE but we don't have
7501 the link up yet! I *suspect* this can happen right now (i.e.
7502 sender has verified us, but we didn't verify sender), but if
7503 we pass this on, CORE would be confused (link down, messages
7504 arrive). We should investigate more if this happens often,
7505 or in a persistent manner, and possibly do "something" about
7506 it. Thus logging as error for now. */
7507
7508 mh_copy = GNUNET_malloc (size);
7509 rbe = GNUNET_new (struct RingBufferEntry);
7510 rbe->cmc = cmc;
7511 /*cmc_copy->tc = cmc->tc;
7512 cmc_copy->im = cmc->im;*/
7513 GNUNET_memcpy (mh_copy, mh, size);
7514
7515 rbe->mh = mh_copy;
7516
7518 {
7519 struct RingBufferEntry *rbe_old = ring_buffer[ring_buffer_head];
7520 GNUNET_free (rbe_old->cmc);
7521 GNUNET_free (rbe_old->mh);
7522 GNUNET_free (rbe_old);
7523 }
7524 ring_buffer[ring_buffer_head] = rbe;// cmc_copy;
7525 // cmc_copy->mh = (const struct GNUNET_MessageHeader *) mh_copy;
7526 cmc->mh = (const struct GNUNET_MessageHeader *) mh_copy;
7528 "Storing message for %s and type %u (%u) in ring buffer head %u is full %u\n",
7529 GNUNET_i2s (&cmc->im.sender),
7530 (unsigned int) ntohs (mh->type),
7531 (unsigned int) ntohs (mh_copy->type),
7535 {
7536 ring_buffer_head = 0;
7538 }
7539 else
7541
7543 "%u items stored in ring buffer\n",
7546
7547 /*GNUNET_break_op (0);
7548 GNUNET_STATISTICS_update (GST_stats,
7549 "# CORE messages dropped (virtual link still down)",
7550 1,
7551 GNUNET_NO);
7552
7553 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7554 "CORE messages of type %u with %u bytes dropped (virtual link still down)\n",
7555 (unsigned int) ntohs (mh->type),
7556 (unsigned int) ntohs (mh->size));
7557 finish_cmc_handling (cmc);*/
7558 /* @a cmc lives on in the ring buffer; #send_cmc_ack() and
7559 #resume_cmc_client() have recorded that they ran, so replaying it
7560 from #send_msg_from_cache() cannot ACK or continue a second time. */
7562 return;
7563 }
7565}
7566
7567
7575static int
7576check_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
7577{
7578 uint16_t size = ntohs (fb->header.size);
7579 uint16_t bsize = size - sizeof(*fb);
7580
7581 (void) cls;
7582 if (0 == bsize)
7583 {
7584 GNUNET_break_op (0);
7585 return GNUNET_SYSERR;
7586 }
7587 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
7588 {
7589 GNUNET_break_op (0);
7590 return GNUNET_SYSERR;
7591 }
7592 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
7593 {
7594 GNUNET_break_op (0);
7595 return GNUNET_SYSERR;
7596 }
7597 return GNUNET_YES;
7598}
7599
7600
7606static void
7607destroy_ack_cummulator (void *cls)
7608{
7609 struct AcknowledgementCummulator *ac = cls;
7610
7611 ac->task = NULL;
7612 GNUNET_assert (0 == ac->num_acks);
7614 GNUNET_YES ==
7616 GNUNET_free (ac);
7617}
7618
7619
7625static void
7627{
7628 struct Neighbour *n;
7629 struct VirtualLink *vl;
7630 struct AcknowledgementCummulator *ac = cls;
7631 char buf[sizeof(struct TransportReliabilityAckMessage)
7632 + ac->num_acks
7634 struct TransportReliabilityAckMessage *ack =
7635 (struct TransportReliabilityAckMessage *) buf;
7637
7638 ac->task = NULL;
7640 "Sending ACK with %u components to %s\n",
7641 ac->num_acks,
7642 GNUNET_i2s (&ac->target));
7643 GNUNET_assert (0 < ac->num_acks);
7645 ack->header.size =
7646 htons (sizeof(*ack)
7647 + ac->num_acks * sizeof(struct TransportCummulativeAckPayloadP));
7648 ack->ack_counter = htonl (ac->ack_counter += ac->num_acks);
7649 ap = (struct TransportCummulativeAckPayloadP *) &ack[1];
7650 for (unsigned int i = 0; i < ac->num_acks; i++)
7651 {
7652 ap[i].ack_uuid = ac->ack_uuids[i].ack_uuid;
7655 }
7656 /*route_control_message_without_fc (
7657 &ac->target,
7658 &ack->header,
7659 RMO_DV_ALLOWED);*/
7660 vl = lookup_virtual_link (&ac->target);
7661 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
7662 {
7664 vl,
7665 &ack->header,
7667 }
7668 else
7669 {
7670 /* Use route via neighbour */
7671 n = lookup_neighbour (&ac->target);
7672 if (NULL != n)
7674 n,
7675 &ack->header,
7676 RMO_NONE);
7677 }
7678 ac->num_acks = 0;
7679 /* The deadline belonged to the batch we just sent. #cummulative_ack()
7680 only ever lowers it (GNUNET_TIME_absolute_min), so leaving it behind
7681 means every later ACK is armed with GNUNET_SCHEDULER_add_at() on a time
7682 that has already passed: the task fires on the next scheduler pass and
7683 the batching this whole structure exists for is gone for good -- one
7684 ACK message per received message, for the rest of the process' life. */
7688 ac);
7689}
7690
7691
7700static void
7701cummulative_ack (const struct GNUNET_PeerIdentity *pid,
7702 const struct AcknowledgementUUIDP *ack_uuid,
7703 struct GNUNET_TIME_Absolute max_delay)
7704{
7705 struct AcknowledgementCummulator *ac;
7706
7708 "Scheduling ACK %s for transmission to %s\n",
7709 GNUNET_uuid2s (&ack_uuid->value),
7710 GNUNET_i2s (pid));
7712 if (NULL == ac)
7713 {
7715 ac->target = *pid;
7716 ac->min_transmission_time = max_delay;
7720 &ac->target,
7721 ac,
7723 }
7724 else
7725 {
7726 if (MAX_CUMMULATIVE_ACKS == ac->num_acks)
7727 {
7728 /* Must run immediately, ack buffer full. Cancel the pending task
7729 FIRST: #transmit_cummulative_ack_cb() clears @e task without
7730 cancelling it, which would leave the old task armed with its
7731 handle lost. */
7733 ac->task = NULL;
7735 }
7739 }
7742 ac->ack_uuids[ac->num_acks].ack_uuid = *ack_uuid;
7743 ac->num_acks++;
7746 ac);
7747}
7748
7749
7754{
7759
7763 struct ReassemblyContext *rc;
7764};
7765
7766
7776static int
7777find_by_message_uuid (void *cls, uint32_t key, void *value)
7778{
7779 struct FindByMessageUuidContext *fc = cls;
7780 struct ReassemblyContext *rc = value;
7781
7782 (void) key;
7783 if (0 == GNUNET_memcmp (&fc->message_uuid, &rc->msg_uuid))
7784 {
7785 fc->rc = rc;
7786 return GNUNET_NO;
7787 }
7788 return GNUNET_YES;
7789}
7790
7791
7799static void
7800handle_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
7801{
7802 struct CommunicatorMessageContext *cmc = cls;
7803 struct VirtualLink *vl;
7804 struct ReassemblyContext *rc;
7805 const struct GNUNET_MessageHeader *msg;
7806 uint16_t msize;
7807 uint16_t fsize;
7808 uint16_t frag_off;
7809 char *target;
7810 struct GNUNET_TIME_Relative cdelay;
7811 struct FindByMessageUuidContext fc;
7812
7813 vl = lookup_virtual_link (&cmc->im.sender);
7814 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
7815 {
7816 /* Entirely normal: fragments of a message that was already in flight
7817 keep arriving for a while after a link goes down, and a peer that has
7818 validated us may start sending before we have validated it. This used
7819 to call #GNUNET_SERVICE_client_drop(), which disconnects the
7820 communicator *process* -- every queue it owns, hence every neighbour
7821 reachable through it, hence every CORE session. On a peer with many
7822 neighbours a single ill-timed fragment therefore dropped all
7823 connections at once, and since the fragment comes from the network,
7824 any peer could cause it at will. Drop the fragment, keep the
7825 communicator; see #demultiplex_with_cmc() for the same reasoning. */
7827 "No virtual link for %s to handle fragment\n",
7828 GNUNET_i2s (&cmc->im.sender));
7830 "# fragments dropped (virtual link down)",
7831 1,
7832 GNUNET_NO);
7833 finish_cmc_handling (cmc);
7834 return;
7835 }
7836 if (NULL == vl->reassembly_map)
7837 {
7839 vl->reassembly_heap =
7844 vl);
7845 }
7846 msize = ntohs (fb->msg_size);
7847 fc.message_uuid = fb->msg_uuid;
7848 fc.rc = NULL;
7850 fb->msg_uuid.uuid,
7852 &fc);
7853 fsize = ntohs (fb->header.size) - sizeof(*fb);
7854 if (NULL == (rc = fc.rc))
7855 {
7856 /* Bound the RAM a single sender can pin here: @e msg_size is chosen by
7857 the peer, not by us. */
7860 {
7861 struct ReassemblyContext *drop;
7862
7864 GNUNET_assert (NULL != drop);
7866 "# Reassembly contexts dropped (limit reached)",
7867 1,
7868 GNUNET_NO);
7870 }
7871 rc = GNUNET_malloc (sizeof(*rc) + msize /* reassembly payload buffer */
7872 + (msize + 7) / 8 * sizeof(uint8_t) /* bitfield */);
7873 rc->msg_uuid = fb->msg_uuid;
7874 rc->virtual_link = vl;
7875 rc->msg_size = msize;
7876 rc->reassembly_timeout =
7880 rc,
7884 vl->reassembly_map,
7885 rc->msg_uuid.uuid,
7886 rc,
7888 target = (char *) &rc[1];
7889 rc->bitfield = (uint8_t *) (target + rc->msg_size);
7890 /* The bitfield loop below decrements @e msg_missing once per newly
7891 received byte, so this must always start at the full message size:
7892 initialising it to 0 for a single-fragment message made it
7893 underflow, and the message was then never delivered. */
7894 rc->msg_missing = rc->msg_size;
7896 "Received fragment with size %u at offset %u/%u %u bytes missing from %s for NEW message %"
7897 PRIu64 "\n",
7898 fsize,
7899 ntohs (fb->frag_off),
7900 msize,
7901 rc->msg_missing,
7902 GNUNET_i2s (&cmc->im.sender),
7903 fb->msg_uuid.uuid);
7904 }
7905 else
7906 {
7907 target = (char *) &rc[1];
7909 "Received fragment at offset %u/%u from %s for message %u\n",
7910 ntohs (fb->frag_off),
7911 msize,
7912 GNUNET_i2s (&cmc->im.sender),
7913 (unsigned int) fb->msg_uuid.uuid);
7914 }
7915 if (msize != rc->msg_size)
7916 {
7917 GNUNET_break (0);
7918 finish_cmc_handling (cmc);
7919 return;
7920 }
7921
7922 /* reassemble */
7923 if (0 == fsize)
7924 {
7925 GNUNET_break (0);
7926 finish_cmc_handling (cmc);
7927 return;
7928 }
7929 frag_off = ntohs (fb->frag_off);
7930 if (frag_off + fsize > msize)
7931 {
7932 /* Fragment (plus fragment size) exceeds message size! */
7933 GNUNET_break_op (0);
7934 finish_cmc_handling (cmc);
7935 return;
7936 }
7937 memcpy (&target[frag_off], &fb[1], fsize);
7938 /* update bitfield and msg_missing */
7939 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
7940 {
7941 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
7942 {
7943 rc->bitfield[i / 8] |= (1 << (i % 8));
7944 rc->msg_missing--;
7945 }
7946 }
7947
7948 /* Compute cumulative ACK */
7950 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->msg_missing / fsize);
7951 if (0 == rc->msg_missing)
7952 cdelay = GNUNET_TIME_UNIT_ZERO;
7953 cummulative_ack (&cmc->im.sender,
7954 &fb->ack_uuid,
7957 /* is reassembly complete? */
7958 if (0 != rc->msg_missing)
7959 {
7960 finish_cmc_handling (cmc);
7961 return;
7962 }
7963 /* reassembly is complete, verify result */
7964 msg = (const struct GNUNET_MessageHeader *) &rc[1];
7965 if (ntohs (msg->size) != rc->msg_size)
7966 {
7967 GNUNET_break (0);
7969 finish_cmc_handling (cmc);
7970 return;
7971 }
7972 /* successful reassembly */
7974 "Fragment reassembly complete for message %u\n",
7975 (unsigned int) fb->msg_uuid.uuid);
7976 /* FIXME: check that the resulting msg is NOT a
7977 DV Box or Reliability Box, as that is NOT allowed! */
7978 {
7979 uint16_t rsize = rc->msg_size;
7980 char rbuf[rsize] GNUNET_ALIGN;
7981
7982 /* Copy the reassembled message out and release `rc' BEFORE
7983 demultiplexing: the inner message may tear down the virtual link,
7984 which frees every reassembly context of that link -- the old code
7985 then used and freed `rc' a second time afterwards. */
7986 memcpy (rbuf, msg, rsize);
7988 cmc->mh = (const struct GNUNET_MessageHeader *) rbuf;
7990 }
7991}
7992
7993
8001static int
8002check_reliability_box (void *cls,
8003 const struct TransportReliabilityBoxMessage *rb)
8004{
8005 const struct GNUNET_MessageHeader *box = (const struct
8006 GNUNET_MessageHeader *) &rb[1];
8007 (void) cls;
8008
8010 "check_send_msg with size %u: inner msg type %u and size %u (%lu %lu)\n",
8011 ntohs (rb->header.size),
8012 ntohs (box->type),
8013 ntohs (box->size),
8014 sizeof (struct TransportReliabilityBoxMessage),
8015 sizeof (struct GNUNET_MessageHeader));
8017 return GNUNET_YES;
8018}
8019
8020
8028static void
8029handle_reliability_box (void *cls,
8030 const struct TransportReliabilityBoxMessage *rb)
8031{
8032 struct CommunicatorMessageContext *cmc = cls;
8033 const struct GNUNET_MessageHeader *inbox =
8034 (const struct GNUNET_MessageHeader *) &rb[1];
8035 struct GNUNET_TIME_Relative rtt;
8036
8038 "Received reliability box from %s with UUID %s of type %u\n",
8039 GNUNET_i2s (&cmc->im.sender),
8041 (unsigned int) ntohs (inbox->type));
8042 rtt = GNUNET_TIME_UNIT_SECONDS; /* FIXME: should base this on "RTT", but we
8043 do not really have an RTT for the
8044 * incoming* queue (should we have
8045 the sender add it to the rb message?) */
8047 &cmc->im.sender,
8048 &rb->ack_uuid,
8049 (0 == ntohl (rb->ack_countdown))
8052 GNUNET_TIME_relative_divide (rtt, 8 /* FIXME: magic constant */)));
8053 /* continue with inner message */
8054 /* FIXME: check that inbox is NOT a DV Box, fragment or another
8055 reliability box (not allowed!) */
8056 cmc->mh = inbox;
8058}
8059
8060
8069static void
8070update_pd_age (struct PerformanceData *pd, unsigned int age)
8071{
8072 unsigned int sage;
8073
8074 if (age == pd->last_age)
8075 return; /* nothing to do */
8076 sage = GNUNET_MAX (pd->last_age, age - 2 * GOODPUT_AGING_SLOTS);
8077 for (unsigned int i = sage; i <= age - GOODPUT_AGING_SLOTS; i++)
8078 {
8079 struct TransmissionHistoryEntry *the = &pd->the[i % GOODPUT_AGING_SLOTS];
8080
8081 the->bytes_sent = 0;
8082 the->bytes_received = 0;
8083 }
8084 pd->last_age = age;
8085}
8086
8087
8096static void
8098 struct GNUNET_TIME_Relative rtt,
8099 uint16_t bytes_transmitted_ok)
8100{
8101 uint64_t nval = rtt.rel_value_us;
8102 uint64_t oval = pd->aged_rtt.rel_value_us;
8103 unsigned int age = get_age ();
8104 struct TransmissionHistoryEntry *the = &pd->the[age % GOODPUT_AGING_SLOTS];
8105
8106 if (oval == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
8107 pd->aged_rtt = rtt;
8108 else
8109 pd->aged_rtt.rel_value_us = (nval + 7 * oval) / 8;
8110 update_pd_age (pd, age);
8111 the->bytes_received += bytes_transmitted_ok;
8112}
8113
8114
8122static void
8124 struct GNUNET_TIME_Relative rtt,
8125 uint16_t bytes_transmitted_ok)
8126{
8127 update_performance_data (&q->pd, rtt, bytes_transmitted_ok);
8128}
8129
8130
8138static void
8140 struct GNUNET_TIME_Relative rtt,
8141 uint16_t bytes_transmitted_ok)
8142{
8143 update_performance_data (&dvh->pd, rtt, bytes_transmitted_ok);
8144}
8145
8146
8154static void
8156{
8157 struct PendingMessage *pos;
8158
8160 "Complete transmission of message %" PRIu64 " %u\n",
8161 pm->logging_uuid,
8162 pm->pmt);
8163 switch (pm->pmt)
8164 {
8165 case PMT_CORE:
8167 /* Full message sent, we are done */
8169 return;
8170
8171 case PMT_FRAGMENT_BOX:
8172 /* Fragment sent over reliable channel */
8173 pos = pm->frag_parent;
8174 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
8177 "pos frag_off %lu pos bytes_msg %lu pmt %u parent %u\n",
8178 (unsigned long) pos->frag_off,
8179 (unsigned long) pos->bytes_msg,
8180 pos->pmt,
8181 NULL == pos->frag_parent ? 1 : 0);
8182 /* check if subtree is done */
8183 while ((NULL == pos->head_frag) && (pos->frag_off == (pos->bytes_msg
8184 - sizeof(struct
8186 &&
8187 (NULL != pos->frag_parent))
8188 {
8189 pm = pos;
8190 pos = pm->frag_parent;
8191 if ((NULL == pos) && (PMT_DV_BOX == pm->pmt))
8192 {
8194 return;
8195 }
8196 else if (PMT_DV_BOX == pm->pmt)
8197 {
8199 return;
8200 }
8201 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
8203 }
8204
8205 /* Was this the last applicable fragment?
8206
8207 NOTE: @a pos may be a DV box here, and then it is NOT the message the
8208 client is waiting for -- its @e frag_parent is, and that parent's
8209 @e bpm points at @a pos. Answering the client directly (and thereby
8210 releasing @a pos through #free_pending_message()) left @e bpm of a
8211 message that is still queued pointing at freed memory, which
8212 #transmit_on_queue() reads and may free a second time. Hand it to
8213 ourselves instead: the #PMT_DV_BOX case below clears @e bpm and
8214 answers for the parent, and for every other @e pmt it does exactly
8215 what the direct call did. */
8216 if ((NULL == pos->head_frag) && (NULL == pos->frag_parent || PMT_DV_BOX ==
8217 pos->pmt) &&
8218 (pos->frag_off == pos->bytes_msg))
8220 return;
8221
8222 case PMT_DV_BOX:
8224 "Completed transmission of message %" PRIu64 " (DV Box)\n",
8225 pm->logging_uuid);
8226 if (NULL != pm->frag_parent)
8227 {
8228 pos = pm->frag_parent;
8230 pos->bpm = NULL;
8232 }
8233 else
8235 return;
8236 }
8237}
8238
8239
8247static void
8249 struct GNUNET_TIME_Relative ack_delay)
8250{
8251 struct GNUNET_TIME_Relative delay;
8252 struct PendingMessage *pm = pa->pm;
8253
8255 delay = GNUNET_TIME_relative_subtract (delay, ack_delay);
8256 if (NULL != pa->queue && 1 == pa->num_send)
8258 if (NULL != pa->dvh && 1 == pa->num_send)
8259 update_dvh_performance (pa->dvh, delay, pa->message_size);
8260 /* Retire @a pa BEFORE handing its message on. completed_pending_message()
8261 ends in free_pending_message() for anything it finishes, and that now
8262 releases every acknowledgement still attached to the message -- this one
8263 included. Freeing it afterwards is a double free, and it aborts on the
8264 GNUNET_assert() over multiuuidmap_remove() in
8265 free_pending_acknowledgement(), the map entry having gone with the first
8266 release. Nothing below needs @a pa, only its message. */
8268 if (NULL != pm)
8270}
8271
8272
8280static int
8281check_reliability_ack (void *cls,
8282 const struct TransportReliabilityAckMessage *ra)
8283{
8284 unsigned int n_acks;
8285
8286 (void) cls;
8287 n_acks = (ntohs (ra->header.size) - sizeof(*ra))
8288 / sizeof(struct TransportCummulativeAckPayloadP);
8289 if (0 == n_acks)
8290 {
8291 GNUNET_break_op (0);
8292 return GNUNET_SYSERR;
8293 }
8294 if ((ntohs (ra->header.size) - sizeof(*ra)) !=
8295 n_acks * sizeof(struct TransportCummulativeAckPayloadP))
8296 {
8297 GNUNET_break_op (0);
8298 return GNUNET_SYSERR;
8299 }
8300 return GNUNET_OK;
8301}
8302
8303
8311static void
8312handle_reliability_ack (void *cls,
8313 const struct TransportReliabilityAckMessage *ra)
8314{
8315 struct CommunicatorMessageContext *cmc = cls;
8316 const struct TransportCummulativeAckPayloadP *ack;
8317 unsigned int n_acks;
8318 uint32_t ack_counter;
8319
8320 n_acks = (ntohs (ra->header.size) - sizeof(*ra))
8321 / sizeof(struct TransportCummulativeAckPayloadP);
8322 ack = (const struct TransportCummulativeAckPayloadP *) &ra[1];
8323 for (unsigned int i = 0; i < n_acks; i++)
8324 {
8325 struct PendingAcknowledgement *pa =
8327 if (NULL == pa)
8328 {
8330 "Received ACK from %s with UUID %s which is unknown to us!\n",
8331 GNUNET_i2s (&cmc->im.sender),
8332 GNUNET_uuid2s (&ack[i].ack_uuid.value));
8334 GST_stats,
8335 "# FRAGMENT_ACKS dropped, no matching pending message",
8336 1,
8337 GNUNET_NO);
8338 continue;
8339 }
8341 "Received ACK from %s with UUID %s\n",
8342 GNUNET_i2s (&cmc->im.sender),
8343 GNUNET_uuid2s (&ack[i].ack_uuid.value));
8344 handle_acknowledged (pa, GNUNET_TIME_relative_ntoh (ack[i].ack_delay));
8345 }
8346
8347 ack_counter = ntohl (ra->ack_counter);
8348 (void) ack_counter; /* silence compiler warning for now */
8349 // FIXME-OPTIMIZE: track ACK losses based on ack_counter somewhere!
8350 // (DV and/or Neighbour?)
8351 finish_cmc_handling (cmc);
8352}
8353
8354
8362static int
8364 void *cls,
8366{
8367 uint16_t size = ntohs (be->header.size) - sizeof(*be);
8368 const struct GNUNET_MessageHeader *inbox =
8369 (const struct GNUNET_MessageHeader *) &be[1];
8370 const char *is;
8371 uint16_t isize;
8372
8373 (void) cls;
8374 /* MUST bound the buffer before reading @a inbox: the size check below
8375 dereferences it, and a message consisting of nothing but the header
8376 leaves no bytes to read. */
8377 if (size <= sizeof(struct GNUNET_MessageHeader))
8378 {
8379 GNUNET_break_op (0);
8380 return GNUNET_SYSERR;
8381 }
8382 if (ntohs (inbox->size) >= size)
8383 {
8384 GNUNET_break_op (0);
8385 return GNUNET_SYSERR;
8386 }
8387 isize = ntohs (inbox->size);
8388 is = ((const char *) inbox) + isize;
8389 size -= isize;
8390 if ('\0' != is[size - 1])
8391 {
8392 GNUNET_break_op (0);
8393 return GNUNET_SYSERR;
8394 }
8395 return GNUNET_YES;
8396}
8397
8398
8407static void
8409 void *cls,
8411{
8412 const struct GNUNET_PeerIdentity *my_identity;
8413 struct CommunicatorMessageContext *cmc = cls;
8415 struct GNUNET_MQ_Envelope *env;
8416 struct TransportClient *tc;
8417 const struct GNUNET_MessageHeader *inbox =
8418 (const struct GNUNET_MessageHeader *) &be[1];
8419 uint16_t isize = ntohs (inbox->size);
8420 const char *target_communicator = ((const char *) inbox) + isize;
8421 char *sender;
8422 char *self;
8423
8426
8427 GNUNET_asprintf (&sender,
8428 "%s",
8429 GNUNET_i2s (&cmc->im.sender));
8430 GNUNET_asprintf (&self,
8431 "%s",
8433
8434 /* Find client providing this communicator */
8435 for (tc = clients_head; NULL != tc; tc = tc->next)
8436 if ((CT_COMMUNICATOR == tc->type) &&
8437 (NULL != tc->details.communicator.address_prefix) &&
8438 (0 ==
8439 strcmp (tc->details.communicator.address_prefix, target_communicator)))
8440 break;
8441 if (NULL == tc)
8442 {
8443 char *stastr;
8444
8446 &stastr,
8447 "# Backchannel message dropped: target communicator `%s' unknown",
8448 target_communicator);
8450 GNUNET_free (stastr);
8451 GNUNET_free (sender);
8452 GNUNET_free (self);
8453 finish_cmc_handling (cmc);
8454 return;
8455 }
8456 /* Finally, deliver backchannel message to communicator */
8458 "Delivering backchannel message from %s to %s of type %u to %s\n",
8459 sender,
8460 self,
8461 ntohs (inbox->type),
8462 target_communicator);
8464 cbi,
8465 isize,
8467 cbi->pid = cmc->im.sender;
8468 memcpy (&cbi[1], inbox, isize);
8469 GNUNET_MQ_send (tc->mq, env);
8470 GNUNET_free (sender);
8471 GNUNET_free (self);
8472 finish_cmc_handling (cmc);
8473}
8474
8475
8485static void
8486path_cleanup_cb (void *cls)
8487{
8488 struct DistanceVector *dv = cls;
8489 struct DistanceVectorHop *pos;
8490 struct GNUNET_TIME_Absolute next;
8491
8492 dv->timeout_task = NULL;
8493 /* @e dv_head is NOT sorted by @e timeout: learn_dv_path() inserts a new
8494 hop at the head, and moves a rediscovered one back to the head, so the
8495 list runs newest (i.e. latest deadline) first. Stopping at the first
8496 live entry therefore inspected exactly the youngest hop and re-armed
8497 for *its* deadline, which is the last one of the whole set: expired
8498 hops behind it were never collected, and check_vl_transmission() kept
8499 skipping them one by one for as long as the route lived. Sweep all of
8500 them and come back for the earliest survivor. */
8502 pos = dv->dv_head;
8503 while (NULL != pos)
8504 {
8505 struct DistanceVectorHop *next_pos = pos->next_dv;
8506
8507 GNUNET_assert (dv == pos->dv);
8510 else
8511 next = GNUNET_TIME_absolute_min (next, pos->timeout);
8512 pos = next_pos;
8513 }
8514 if (NULL == dv->dv_head)
8515 {
8516 free_dv_route (dv);
8517 return;
8518 }
8519 dv->timeout_task =
8521}
8522
8523
8524static void
8526{
8527
8528 const struct GNUNET_PeerIdentity target = vl->target;
8529
8530
8532 {
8533 struct RingBufferEntry *ring_buffer_copy[RING_BUFFER_SIZE];
8534 unsigned int tail = GNUNET_YES == is_ring_buffer_full ? ring_buffer_head :
8535 0;
8536 unsigned int head = GNUNET_YES == is_ring_buffer_full ? RING_BUFFER_SIZE :
8539 struct CommunicatorMessageContext *cmc;
8540 struct RingBufferEntry *rbe;
8541 struct GNUNET_MessageHeader *mh;
8542
8544 "Sending from ring buffer, which has %u items\n",
8545 head);
8546
8547 ring_buffer_head = 0;
8548 for (unsigned int i = 0; i < head; i++)
8549 {
8550 rbe = ring_buffer[(i + tail) % RING_BUFFER_SIZE];
8551 cmc = rbe->cmc;
8552 mh = rbe->mh;
8553
8554 im = cmc->im;
8555 // mh = cmc->mh;
8557 "Sending message of type %u to ring buffer target %s using vl target %s index %u\n",
8558 mh->type,
8559 GNUNET_i2s (&im.sender),
8560 GNUNET_i2s2 (&target),
8561 (i + tail) % RING_BUFFER_SIZE);
8562 if (0 == GNUNET_memcmp (&target, &im.sender))
8563 {
8565 "Finish handling message of type %u and size %u\n",
8566 (unsigned int) ntohs (mh->type),
8567 (unsigned int) ntohs (mh->size));
8569 GNUNET_free (mh);
8570 GNUNET_free (rbe->cmc);
8571 GNUNET_free (rbe);
8572 }
8573 else
8574 {
8575 ring_buffer_copy[ring_buffer_head] = rbe;
8577 }
8578 }
8579
8582 {
8584 }
8585
8586 for (unsigned int i = 0; i < ring_buffer_head; i++)
8587 {
8588 ring_buffer[i] = ring_buffer_copy[i];
8590 "ring_buffer[i]->mh->type for i %u %u\n",
8591 i,
8592 ring_buffer[i]->mh->type);
8593 }
8594 /* MUST clear the consumed slots, we freed those entries above */
8595 for (unsigned int i = ring_buffer_head; i < RING_BUFFER_SIZE; i++)
8596 ring_buffer[i] = NULL;
8597
8599 "%u items still in ring buffer\n",
8601 /* If we consumed nothing, compaction rewrote the buffer in place and
8602 left the write index one past the end. #handle_raw_message() would
8603 then read ring_buffer[RING_BUFFER_SIZE] and free whatever that is.
8604 The buffer is still full, and compaction moved the oldest entry to
8605 slot 0, so that is where the next write belongs. */
8607 ring_buffer_head = 0;
8608 }
8609
8611 {
8612 struct PendingMessage *ring_buffer_dv_copy[RING_BUFFER_SIZE];
8613 struct PendingMessage *pm;
8614 unsigned int tail = GNUNET_YES == is_ring_buffer_dv_full ?
8616 0;
8617 unsigned int head = GNUNET_YES == is_ring_buffer_dv_full ?
8620
8622 "Sending from ring buffer dv, which has %u items\n",
8623 head);
8624
8626 for (unsigned int i = 0; i < head; i++)
8627 {
8628 pm = ring_buffer_dv[(i + tail) % RING_BUFFER_SIZE];
8629
8631 "Sending to ring buffer target %s using vl target %s\n",
8632 GNUNET_i2s (&pm->target),
8633 GNUNET_i2s2 (&target));
8634 if (0 == GNUNET_memcmp (&target, &pm->target))
8635 {
8637 "Adding PendingMessage to vl, checking transmission.\n");
8638 pm->vl = vl;
8642 pm);
8643
8645 }
8646 else
8647 {
8648 ring_buffer_dv_copy[ring_buffer_dv_head] = pm;
8650 }
8651 }
8652
8654 {
8656 }
8657
8658 for (unsigned int i = 0; i < ring_buffer_dv_head; i++)
8659 ring_buffer_dv[i] = ring_buffer_dv_copy[i];
8660 /* MUST clear the consumed slots: entries we handed to a VirtualLink are
8661 now owned by that link, and #forward_dv_box() would GNUNET_free() them
8662 again once the ring buffer wraps around. */
8663 for (unsigned int i = ring_buffer_dv_head; i < RING_BUFFER_SIZE; i++)
8664 ring_buffer_dv[i] = NULL;
8665
8667 "%u items still in ring buffer dv.\n",
8669 /* Same one-past-the-end hazard as above: #forward_dv_box() reads
8670 ring_buffer_dv[ring_buffer_dv_head] and GNUNET_free()s it. */
8673 }
8674}
8675
8676
8684static void
8686{
8687 struct DistanceVector *dv = hop->dv;
8688 struct VirtualLink *vl;
8689
8690 vl = lookup_virtual_link (&dv->target);
8691 if (NULL == vl)
8692 {
8693
8694 vl = GNUNET_new (struct VirtualLink);
8696 "Creating new virtual link %p to %s using DV!\n",
8697 vl,
8698 GNUNET_i2s (&dv->target));
8699 vl->burst_addr = NULL;
8700 vl->confirmed = GNUNET_YES;
8701 vl->message_uuid_ctr =
8702 GNUNET_CRYPTO_random_u64 (UINT64_MAX);
8703 vl->target = dv->target;
8707 /* What the peer will grant us in its very first FLOW_CONTROL anyway
8708 (@e incoming_fc_window_size plus what we have sent, i.e. nothing).
8709 Starting at zero instead means a link that is up, validated and
8710 working carries nothing at all until an FC round trip completes --
8711 and if the peer cannot answer, not ever. */
8715 links,
8716 &vl->target,
8717 vl,
8719 vl->dv = dv;
8720 dv->vl = vl;
8721 vl->visibility_task =
8724 /* We lacked a confirmed connection to the target
8725 before, so tell CORE about it (finally!) */
8728 }
8729 else
8730 {
8731 /* Link was already up, remember dv is also now available and we are done */
8732 vl->dv = dv;
8733 dv->vl = vl;
8734 if (GNUNET_NO == vl->confirmed)
8735 {
8736 vl->confirmed = GNUNET_YES;
8737 vl->visibility_task =
8740 /* We lacked a confirmed connection to the target
8741 before, so tell CORE about it (finally!) */
8744 }
8745 else
8747 "Virtual link to %s could now also use DV!\n",
8748 GNUNET_i2s (&dv->target));
8749 }
8750}
8751
8752
8778static int
8779learn_dv_path (const struct GNUNET_PeerIdentity *path,
8780 unsigned int path_len,
8781 struct GNUNET_TIME_Relative network_latency,
8782 struct GNUNET_TIME_Absolute path_valid_until)
8783{
8784 const struct GNUNET_PeerIdentity *my_identity;
8785 struct DistanceVectorHop *hop;
8786 struct DistanceVector *dv;
8787 struct Neighbour *next_hop;
8788 unsigned int shorter_distance;
8789
8790 if (path_len < 3)
8791 {
8792 /* what a boring path! not allowed! */
8793 GNUNET_break (0);
8794 return GNUNET_SYSERR;
8795 }
8796
8799
8800 GNUNET_assert (0 == GNUNET_memcmp (my_identity, &path[0]));
8801 next_hop = lookup_neighbour (&path[1]);
8802 if (NULL == next_hop)
8803 {
8804 /* next hop must be a neighbour, otherwise this whole thing is useless! */
8805 GNUNET_break (0);
8806 return GNUNET_SYSERR;
8807 }
8808 for (unsigned int i = 2; i < path_len; i++)
8809 {
8810 struct Neighbour *n = lookup_neighbour (&path[i]);
8811 struct GNUNET_TIME_Absolute q_timeout;
8812
8813 if (NULL != n)
8814 {
8815 q_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
8816 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
8817 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
8819 "remaining %lu to %s\n",
8820 (unsigned long) GNUNET_TIME_absolute_get_remaining (q_timeout)
8821 .rel_value_us,
8822 GNUNET_i2s (&n->pid));
8823 if (0 != GNUNET_TIME_absolute_get_remaining (q_timeout).rel_value_us)
8824 {
8825 /* Useless path: we have a direct active connection to some hop
8826 in the middle of the path, so this one is not even
8827 terribly useful for redundancy */
8829 "Path of %u hops useless: directly link to hop %u (%s)\n",
8830 path_len,
8831 i,
8832 GNUNET_i2s (&path[i]));
8834 "# Useless DV path ignored: hop is neighbour",
8835 1,
8836 GNUNET_NO);
8837 return GNUNET_SYSERR;
8838 }
8839 }
8840 }
8841 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
8842 if (NULL == dv)
8843 {
8844 dv = GNUNET_new (struct DistanceVector);
8845 dv->target = path[path_len - 1];
8848 dv);
8851 dv_routes,
8852 &dv->target,
8853 dv,
8855 }
8856 /* Check if we have this path already! */
8857 shorter_distance = 0;
8858 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
8859 pos = pos->next_dv)
8860 {
8861 if (pos->distance < path_len - 3)
8862 shorter_distance++;
8863 /* Note that the distances in 'pos' excludes us (path[0]),
8864 the next_hop (path[1]) and the target so we need to subtract three
8865 and check next_hop explicitly */
8866 if ((pos->distance == path_len - 3) && (pos->next_hop == next_hop))
8867 {
8868 int match = GNUNET_YES;
8869
8870 for (unsigned int i = 0; i < pos->distance; i++)
8871 {
8872 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
8873 {
8874 match = GNUNET_NO;
8875 break;
8876 }
8877 }
8878 if (GNUNET_YES == match)
8879 {
8880 struct GNUNET_TIME_Relative last_timeout;
8881
8882 /* Re-discovered known path, update timeout */
8884 "# Known DV path refreshed",
8885 1,
8886 GNUNET_NO);
8887 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
8888 pos->timeout =
8890 pos->path_valid_until =
8891 GNUNET_TIME_absolute_max (pos->path_valid_until, path_valid_until);
8892 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
8893 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
8894 if (0 <
8897 if (last_timeout.rel_value_us <
8900 .rel_value_us)
8901 {
8902 /* Some peer send DV learn messages too often, we are learning
8903 the same path faster than it would be useful; do not forward! */
8905 "Rediscovered path too quickly, not forwarding further\n")
8906 ;
8907 return GNUNET_NO;
8908 }
8910 "Refreshed known path to %s valid until %s, forwarding further\n",
8911 GNUNET_i2s (&dv->target),
8913 pos->path_valid_until));
8914 return GNUNET_YES;
8915 }
8916 }
8917 }
8918 /* Count how many shorter paths we have (incl. direct
8919 neighbours) before simply giving up on this one! */
8920 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
8921 {
8922 /* We have a shorter path already! */
8924 "Have many shorter DV paths %s, not forwarding further\n",
8925 GNUNET_i2s (&dv->target));
8926 return GNUNET_NO;
8927 }
8928 /* create new DV path entry */
8930 "Discovered new DV path to %s valid until %s\n",
8931 GNUNET_i2s (&dv->target),
8932 GNUNET_STRINGS_absolute_time_to_string (path_valid_until));
8933 hop = GNUNET_malloc (sizeof(struct DistanceVectorHop)
8934 + sizeof(struct GNUNET_PeerIdentity) * (path_len - 3));
8935 hop->next_hop = next_hop;
8936 hop->dv = dv;
8937 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
8938 memcpy (&hop[1],
8939 &path[2],
8940 sizeof(struct GNUNET_PeerIdentity) * (path_len - 3));
8942 hop->path_valid_until = path_valid_until;
8943 hop->distance = path_len - 3;
8944 hop->pd.aged_rtt = network_latency;
8945 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
8947 next_hop->dv_head,
8948 next_hop->dv_tail,
8949 hop);
8950 if (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
8952 return GNUNET_YES;
8953}
8954
8955
8963static int
8964check_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
8965{
8966 const struct GNUNET_PeerIdentity *my_identity;
8967 uint16_t size = ntohs (dvl->header.size);
8968 uint16_t num_hops = ntohs (dvl->num_hops);
8969 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
8970
8971 (void) cls;
8972 if (size != sizeof(*dvl) + num_hops * sizeof(struct DVPathEntryP))
8973 {
8974 GNUNET_break_op (0);
8975 return GNUNET_SYSERR;
8976 }
8977 if (num_hops > MAX_DV_HOPS_ALLOWED)
8978 {
8979 GNUNET_break_op (0);
8980 return GNUNET_SYSERR;
8981 }
8982
8985
8986 for (unsigned int i = 0; i < num_hops; i++)
8987 {
8988 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
8989 {
8990 GNUNET_break_op (0);
8991 return GNUNET_SYSERR;
8992 }
8993 if (0 == GNUNET_memcmp (my_identity, &hops[i].hop))
8994 {
8995 GNUNET_break_op (0);
8996 return GNUNET_SYSERR;
8997 }
8998 }
8999 return GNUNET_YES;
9000}
9001
9002
9014static void
9015forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
9016 const struct TransportDVLearnMessage *msg,
9017 uint16_t bi_history,
9018 uint16_t nhops,
9019 const struct DVPathEntryP *hops,
9020 struct GNUNET_TIME_Absolute in_time)
9021{
9022 struct DVPathEntryP *dhops;
9023 size_t fwd_size = sizeof(struct TransportDVLearnMessage)
9024 + (nhops + 1) * sizeof(struct DVPathEntryP);
9025 /* Signing is synchronous and the routing calls below copy the message,
9026 so this never outlives the frame. Keeping it on the stack matters:
9027 a hub forwards a DV learn to every eligible neighbour, so this is one
9028 of the hottest allocation sites in the service. Size it by the hop
9029 limit rather than by @a nhops -- @a nhops is only asserted to be below
9030 that limit further down, and a VLA is sized before we get there. */
9031 char fwd_buf[sizeof(struct TransportDVLearnMessage)
9032 + (MAX_DV_HOPS_ALLOWED + 1)
9033 * sizeof(struct DVPathEntryP)] GNUNET_ALIGN;
9034 struct TransportDVLearnMessage *fwd
9035 = (struct TransportDVLearnMessage *) fwd_buf;
9036 struct GNUNET_TIME_Relative nnd;
9037 const struct GNUNET_PeerIdentity *my_identity;
9038 struct VirtualLink *vl;
9039 struct Neighbour *n;
9040
9042 memset (fwd_buf, 0, fwd_size);
9043
9044 /* compute message for forwarding */
9046 "Forwarding DV learn message originating from %s to %s\n",
9047 GNUNET_i2s (&msg->initiator),
9048 GNUNET_i2s2 (next_hop));
9051 fwd->header.size = htons (sizeof(struct TransportDVLearnMessage)
9052 + (nhops + 1) * sizeof(struct DVPathEntryP));
9053 fwd->num_hops = htons (nhops + 1);
9054 fwd->bidirectional = htons (bi_history);
9057 msg->non_network_delay));
9059 fwd->init_sig = msg->init_sig;
9060 fwd->initiator = msg->initiator;
9061 fwd->challenge = msg->challenge;
9062 fwd->monotonic_time = msg->monotonic_time;
9063
9066
9067 dhops = (struct DVPathEntryP *) &fwd[1];
9068 GNUNET_memcpy (dhops, hops, sizeof(struct DVPathEntryP) * nhops);
9069 dhops[nhops].hop = *my_identity;
9070 {
9071 struct DvHopPS dhp = {
9073 .purpose.size = htonl (sizeof(dhp)),
9074 .pred = (0 == nhops) ? msg->initiator : dhops[nhops - 1].hop,
9075 .succ = *next_hop,
9077 };
9078
9080 &dhops[nhops].hop_sig))
9081 return; /* nobody would accept the path without our hop signature */
9082 }
9083 vl = lookup_virtual_link (next_hop);
9084 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
9085 {
9087 &fwd->header,
9089 return;
9090 }
9091 /* Use route via neighbour */
9092 n = lookup_neighbour (next_hop);
9093 if (NULL != n)
9095 &fwd->header,
9097}
9098
9099
9109static int
9111 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time,
9112 const struct GNUNET_PeerIdentity *init,
9114 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
9115{
9116 struct DvInitPS ip = { .purpose.purpose = htonl (
9118 .purpose.size = htonl (sizeof(ip)),
9119 .monotonic_time = sender_monotonic_time,
9120 .challenge = *challenge };
9121
9122 if (
9123 GNUNET_OK !=
9125 &ip,
9126 init_sig,
9127 &init->public_key))
9128 {
9129 GNUNET_break_op (0);
9130 return GNUNET_SYSERR;
9131 }
9132 return GNUNET_OK;
9133}
9134
9135
9140{
9144 const struct TransportDVLearnMessage *dvl;
9145
9149 const struct DVPathEntryP *hops;
9150
9155
9160
9164 unsigned int num_eligible;
9165
9169 unsigned int num_selections;
9170
9174 uint16_t nhops;
9175
9179 uint16_t bi_history;
9180};
9181
9182
9191static int
9192dv_neighbour_selection (void *cls,
9193 const struct GNUNET_PeerIdentity *pid,
9194 void *value)
9195{
9196 struct NeighbourSelectionContext *nsc = cls;
9197
9198 (void) value;
9199 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
9200 return GNUNET_YES; /* skip initiator */
9201 for (unsigned int i = 0; i < nsc->nhops; i++)
9202 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
9203 return GNUNET_YES;
9204 /* skip peers on path */
9205 nsc->num_eligible++;
9206 return GNUNET_YES;
9207}
9208
9209
9220static int
9221dv_neighbour_transmission (void *cls,
9222 const struct GNUNET_PeerIdentity *pid,
9223 void *value)
9224{
9225 struct NeighbourSelectionContext *nsc = cls;
9226
9228 "transmission %s\n",
9229 GNUNET_i2s (pid));
9230 (void) value;
9231 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
9232 return GNUNET_YES; /* skip initiator */
9233 for (unsigned int i = 0; i < nsc->nhops; i++)
9234 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
9235 return GNUNET_YES;
9236 /* skip peers on path */
9237 for (unsigned int i = 0; i < nsc->num_selections; i++)
9238 {
9239 if (nsc->selections[i] == nsc->num_eligible)
9240 {
9241 forward_dv_learn (pid,
9242 nsc->dvl,
9243 nsc->bi_history,
9244 nsc->nhops,
9245 nsc->hops,
9246 nsc->in_time);
9247 break;
9248 }
9249 }
9250 nsc->num_eligible++;
9251 return GNUNET_YES;
9252}
9253
9254
9298static unsigned int
9299calculate_fork_degree (unsigned int hops_taken,
9300 unsigned int neighbour_count,
9301 unsigned int eligible_count)
9302{
9303 double target_total = 50.0; /* FIXME: use LOG(NSE)? */
9304 double eligible_ratio =
9305 ((double) eligible_count) / ((double) neighbour_count);
9306 double boost_factor = eligible_ratio * eligible_ratio;
9307 unsigned int rnd;
9308 double left;
9309
9310 if (hops_taken >= 64)
9311 {
9312 GNUNET_break (0);
9313 return 0; /* precaution given bitshift below */
9314 }
9315 for (unsigned int i = 1; i < hops_taken; i++)
9316 {
9317 /* For each hop, subtract the expected number of targets
9318 reached at distance d (so what remains divided by 2^d) */
9319 target_total -= (target_total * boost_factor / (1LLU << i));
9320 }
9321 {
9322 double degree = target_total * boost_factor / (1LLU << hops_taken);
9323
9324 rnd = (unsigned int) floor (degree);
9325 /* round up or down probabilistically depending on how close we were
9326 when floor()ing to rnd. NOTE: this must be the fractional part of
9327 @e degree; using `target_total - rnd' here made the condition below
9328 true essentially always, so we always rounded up. */
9329 left = degree - (double) rnd;
9330 }
9331 if (UINT32_MAX * left >
9332 GNUNET_CRYPTO_random_u64 (UINT32_MAX))
9333 rnd++; /* round up */
9335 "Forwarding DV learn message of %u hops %u(/%u/%u) times\n",
9336 hops_taken,
9337 rnd,
9338 eligible_count,
9339 neighbour_count);
9340 return rnd;
9341}
9342
9343
9350static void
9351neighbour_store_dvmono_cb (void *cls, int success)
9352{
9353 struct Neighbour *n = cls;
9354
9355 n->sc = NULL;
9356 if (GNUNET_YES != success)
9358 "Failed to store other peer's monotonic time in peerstore!\n");
9359}
9360
9361
9362static struct GNUNET_TIME_Relative
9364{
9365 struct GNUNET_TIME_Relative host_latency_sum;
9366 struct GNUNET_TIME_Relative latency;
9367 struct GNUNET_TIME_Relative network_latency;
9368 uint16_t nhops = ntohs (dvl->num_hops);;
9369
9370 /* We initiated this, learn the forward path! */
9371 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
9372
9373 // Need also something to lookup initiation time
9374 // to compute RTT! -> add RTT argument here?
9376 dvl->monotonic_time));
9377 /* @e non_network_delay is fully attacker-controlled, and our clock may
9378 simply be behind the initiator's: never assert on this. */
9379 if (latency.rel_value_us < host_latency_sum.rel_value_us)
9380 {
9382 "# DV learn with implausible non-network delay",
9383 1,
9384 GNUNET_NO);
9386 }
9387 // latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
9388 // (based on dvl->challenge, we can identify time of origin!)
9389
9390 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
9391 /* assumption: latency on all links is the same */
9392 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
9393
9394 return network_latency;
9395}
9396
9397
9405static void
9406handle_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
9407{
9408 struct CommunicatorMessageContext *cmc = cls;
9410 int bi_hop;
9411 uint16_t nhops;
9412 uint16_t bi_history;
9413 const struct DVPathEntryP *hops;
9414 int do_fwd;
9415 int did_initiator;
9416 struct GNUNET_TIME_Absolute in_time;
9417 struct Neighbour *n;
9418 const struct GNUNET_PeerIdentity *my_identity;
9419
9420 nhops = ntohs (dvl->num_hops); /* 0 = sender is initiator */
9421 bi_history = ntohs (dvl->bidirectional);
9422 hops = (const struct DVPathEntryP *) &dvl[1];
9423 if (0 == nhops)
9424 {
9425 /* sanity check */
9426 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
9427 {
9428 GNUNET_break (0);
9429 finish_cmc_handling (cmc);
9430 return;
9431 }
9432 /* A zero-hop message we supposedly initiated ourselves would make the
9433 "we are the initiator" branch below read hops[0] and write past the
9434 end of its `path[nhops + 1]' array. */
9436 {
9437 GNUNET_break_op (0);
9438 finish_cmc_handling (cmc);
9439 return;
9440 }
9441 }
9442 else
9443 {
9445 "handle dv learn message last hop %s\n",
9446 GNUNET_i2s (&hops[nhops - 1].hop));
9447 /* sanity check */
9448 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
9449 {
9450 GNUNET_break (0);
9451 finish_cmc_handling (cmc);
9452 return;
9453 }
9454 }
9455
9457 cc = cmc->tc->details.communicator.cc;
9458 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
9459 cc); // FIXME: add bi-directional flag to cc?
9460 in_time = GNUNET_TIME_absolute_get ();
9461
9462 /* continue communicator here, everything else can happen asynchronous! */
9463 finish_cmc_handling (cmc);
9464
9465 n = lookup_neighbour (&dvl->initiator);
9466 if (NULL != n)
9467 {
9468 if ((n->dv_monotime_available == GNUNET_YES) &&
9471 {
9473 "DV learn from %s discarded due to time travel",
9474 GNUNET_i2s (&dvl->initiator));
9476 "# DV learn discarded due to time travel",
9477 1,
9478 GNUNET_NO);
9479 return;
9480 }
9482 &dvl->initiator,
9483 &dvl->challenge,
9484 &dvl->init_sig))
9485 {
9487 "DV learn signature from %s invalid\n",
9488 GNUNET_i2s (&dvl->initiator));
9489 GNUNET_break_op (0);
9490 return;
9491 }
9494 {
9495 if (NULL != n->sc)
9496 {
9498 "store cancel\n");
9500 }
9501 n->sc =
9503 "transport",
9504 &dvl->initiator,
9506 &dvl->monotonic_time,
9507 sizeof(dvl->monotonic_time),
9511 n);
9512 }
9513 }
9514
9517
9518 /* OPTIMIZE-FIXME: asynchronously (!) verify signatures!,
9519 If signature verification load too high, implement random drop strategy */
9520 for (unsigned int i = 0; i < nhops; i++)
9521 {
9522 struct DvHopPS dhp = { .purpose.purpose =
9524 .purpose.size = htonl (sizeof(dhp)),
9525 .pred = (0 == i) ? dvl->initiator : hops[i - 1].hop,
9526 .succ = (nhops == i + 1) ? *my_identity
9527 : hops[i + 1].hop,
9528 .challenge = dvl->challenge };
9529
9530 if (GNUNET_OK !=
9532 &dhp,
9533 &hops[i].hop_sig,
9534 &hops[i].hop.public_key))
9535 {
9537 "DV learn from %s signature of hop %u invalid\n",
9538 GNUNET_i2s (&dvl->initiator),
9539 i);
9541 "signature of hop %s invalid\n",
9542 GNUNET_i2s (&hops[i].hop));
9544 "pred %s\n",
9545 GNUNET_i2s (&dhp.pred));
9547 "succ %s\n",
9548 GNUNET_i2s (&dhp.succ));
9550 "hash %s\n",
9551 GNUNET_sh2s (&dhp.challenge.value));
9552 GNUNET_break_op (0);
9553 return;
9554 }
9555 }
9556 if (GNUNET_EXTRA_LOGGING > 0)
9557 {
9558 char *path;
9559
9560 path = GNUNET_strdup (GNUNET_i2s (&dvl->initiator));
9561 for (unsigned int i = 0; i < nhops; i++)
9562 {
9563 char *tmp;
9564
9565 GNUNET_asprintf (&tmp,
9566 "%s%s%s",
9567 path,
9568 (bi_history & (1 << (nhops - i))) ? "<->" : "-->",
9569 GNUNET_i2s (&hops[i].hop));
9570 GNUNET_free (path);
9571 path = tmp;
9572 }
9574 "Received DVInit via %s%s%s\n",
9575 path,
9576 bi_hop ? "<->" : "-->",
9578 GNUNET_free (path);
9579 }
9580 do_fwd = GNUNET_YES;
9581 if (0 == GNUNET_memcmp (my_identity, &dvl->initiator))
9582 {
9583 struct GNUNET_PeerIdentity path[nhops + 1];
9584 struct GNUNET_TIME_Relative network_latency;
9585
9586 /* We initiated this, learn the forward path! */
9587 path[0] = *my_identity;
9588 path[1] = hops[0].hop;
9589
9590 network_latency = get_network_latency (dvl);
9591
9592 for (unsigned int i = 2; i <= nhops; i++)
9593 {
9594 struct GNUNET_TIME_Relative ilat;
9595
9596 /* assumption: linear latency increase per hop */
9597 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
9598 path[i] = hops[i - 1].hop;
9600 "Learned path with %u hops to %s with latency %s\n",
9601 i,
9602 GNUNET_i2s (&path[i]),
9604 learn_dv_path (path,
9605 i + 1,
9606 ilat,
9609 }
9610 /* as we initiated, do not forward again (would be circular!) */
9611 do_fwd = GNUNET_NO;
9612 return;
9613 }
9614 if (bi_hop)
9615 {
9616 /* last hop was bi-directional, we could learn something here! */
9617 struct GNUNET_PeerIdentity path[nhops + 2];
9618 struct GNUNET_TIME_Relative ilat;
9619 struct GNUNET_TIME_Relative network_latency;
9620
9621 path[0] = *my_identity;
9622 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
9623 for (unsigned int i = 0; i < nhops; i++)
9624 {
9625 int iret;
9626
9627 if (0 == (bi_history & (1 << i)))
9628 break; /* i-th hop not bi-directional, stop learning! */
9629 if (i == nhops - 1)
9630 {
9631 path[i + 2] = dvl->initiator;
9632 }
9633 else
9634 {
9635 path[i + 2] = hops[nhops - i - 2].hop;
9636 }
9637
9639 "Learned inverse path with %u hops to %s\n",
9640 i + 2,
9641 GNUNET_i2s (&path[i + 2]));
9642 network_latency = get_network_latency (dvl);
9643 ilat = GNUNET_TIME_relative_multiply (network_latency, i + 2);
9644 iret = learn_dv_path (path,
9645 i + 3,
9646 ilat,
9649 if (GNUNET_SYSERR == iret)
9650 {
9651 /* path invalid or too long to be interesting for US, thus should also
9652 not be interesting to our neighbours, cut path when forwarding to
9653 'i' hops, except of course for the one that goes back to the
9654 initiator */
9656 "# DV learn not forwarded due invalidity of path",
9657 1,
9658 GNUNET_NO);
9659 do_fwd = GNUNET_NO;
9660 break;
9661 }
9662 if ((GNUNET_NO == iret) && (nhops == i + 1))
9663 {
9664 /* we have better paths, and this is the longest target,
9665 so there cannot be anything interesting later */
9667 "# DV learn not forwarded, got better paths",
9668 1,
9669 GNUNET_NO);
9670 do_fwd = GNUNET_NO;
9671 break;
9672 }
9673 }
9674 }
9675 if (MAX_DV_HOPS_ALLOWED == nhops)
9676 {
9677 /* At limit, we're out of here! */
9678 return;
9679 }
9680
9681 /* Forward to initiator, if path non-trivial and possible */
9682 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
9683 did_initiator = GNUNET_NO;
9684 if ((1 <= nhops) &&
9685 (GNUNET_YES ==
9687 {
9688 /* send back to origin! */
9690 "Sending DVL back to initiator %s\n",
9691 GNUNET_i2s (&dvl->initiator));
9692 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
9693 did_initiator = GNUNET_YES;
9694 }
9695 /* We forward under two conditions: either we still learned something
9696 ourselves (do_fwd), or the path was darn short and thus the initiator is
9697 likely to still be very interested in this (and we did NOT already
9698 send it back to the initiator) */
9699 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
9700 (GNUNET_NO == did_initiator)))
9701 {
9702 /* Pick random neighbours that are not yet on the path */
9703 struct NeighbourSelectionContext nsc;
9704 unsigned int n_cnt;
9705 unsigned int n_eligible;
9706
9708 nsc.nhops = nhops;
9709 nsc.dvl = dvl;
9710 nsc.bi_history = bi_history;
9711 nsc.hops = hops;
9712 nsc.in_time = in_time;
9713 nsc.num_eligible = 0;
9716 &nsc);
9717 if (0 == nsc.num_eligible)
9718 return; /* done here, cannot forward to anyone else */
9719 n_eligible = nsc.num_eligible;
9720 nsc.num_selections = calculate_fork_degree (nhops, n_cnt, n_eligible);
9721 nsc.num_selections =
9724 "Forwarding DVL to %u other peers\n",
9725 nsc.num_selections);
9726 /* #dv_neighbour_transmission() counts ELIGIBLE peers only, so the
9727 offsets must be drawn from that range -- drawing from the total
9728 number of neighbours made us silently forward to fewer peers than
9729 #calculate_fork_degree() asked for. */
9730 for (unsigned int i = 0; i < nsc.num_selections; i++)
9731 nsc.selections[i] =
9732 (nsc.num_selections == n_eligible)
9733 ? i /* all were selected, avoid collisions by chance */
9734 : GNUNET_CRYPTO_random_u32 (n_eligible);
9735 nsc.num_eligible = 0;
9738 &nsc);
9739 }
9740}
9741
9742
9750static int
9751check_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
9752{
9753 uint16_t size = ntohs (dvb->header.size);
9754 uint16_t num_hops = ntohs (dvb->num_hops);
9755 uint16_t total_hops = ntohs (dvb->total_hops);
9756 uint16_t orig_size = ntohs (dvb->orig_size);
9757 const struct GNUNET_PeerIdentity *hops =
9758 (const struct GNUNET_PeerIdentity *) &dvb[1];
9759 const struct GNUNET_PeerIdentity *my_identity;
9760
9761 (void) cls;
9762 if (size < sizeof(*dvb) + num_hops * sizeof(struct GNUNET_PeerIdentity)
9763 + sizeof(struct GNUNET_MessageHeader))
9764 {
9765 GNUNET_break_op (0);
9766 return GNUNET_SYSERR;
9767 }
9768 if ((num_hops > MAX_DV_HOPS_ALLOWED) ||
9769 (total_hops > MAX_DV_HOPS_ALLOWED))
9770 {
9771 GNUNET_break_op (0);
9772 return GNUNET_SYSERR;
9773 }
9774 /* #decaps_dv_box_cb() derives a VLA size from
9775 orig_size - sizeof(*dvb) - total_hops * sizeof (struct
9776 GNUNET_PeerIdentity); make sure that cannot underflow and that the
9777 remainder can plausibly hold a payload header plus a message. */
9778 if ((orig_size < size) ||
9779 (orig_size < sizeof(*dvb)
9780 + total_hops * sizeof(struct GNUNET_PeerIdentity)
9781 + sizeof(struct TransportDVBoxPayloadP)
9782 + sizeof(struct GNUNET_MessageHeader)))
9783 {
9784 GNUNET_break_op (0);
9785 return GNUNET_SYSERR;
9786 }
9787
9790
9791 /* This peer must not be on the path */
9792 for (unsigned int i = 0; i < num_hops; i++)
9793 if (0 == GNUNET_memcmp (&hops[i], my_identity))
9794 {
9795 GNUNET_break_op (0);
9796 return GNUNET_SYSERR;
9797 }
9798 return GNUNET_YES;
9799}
9800
9801
9814static void
9815forward_dv_box (struct Neighbour *next_hop,
9816 struct TransportDVBoxMessage *hdr,
9817 uint16_t total_hops,
9818 uint16_t num_hops,
9819 const struct GNUNET_PeerIdentity *hops,
9820 const void *enc_payload,
9821 uint16_t enc_payload_size)
9822{
9823 struct VirtualLink *vl = next_hop->vl;
9824 struct PendingMessage *pm;
9825 size_t msg_size = sizeof(struct TransportDVBoxMessage)
9826 + num_hops * sizeof(struct GNUNET_PeerIdentity)
9827 + enc_payload_size;
9828 char *buf;
9829 char msg_buf[msg_size] GNUNET_ALIGN;
9830 struct GNUNET_PeerIdentity *dhops;
9831
9832 hdr->num_hops = htons (num_hops);
9833 hdr->total_hops = htons (total_hops);
9834 hdr->header.size = htons (msg_size);
9835 memcpy (msg_buf, hdr, sizeof(*hdr));
9836 dhops = (struct GNUNET_PeerIdentity *) &msg_buf[sizeof(struct
9838 ;
9839 memcpy (dhops, hops, num_hops * sizeof(struct GNUNET_PeerIdentity));
9840 memcpy (&dhops[num_hops], enc_payload, enc_payload_size);
9841
9842 if (GNUNET_YES == ntohl (hdr->without_fc))
9843 {
9845 "Forwarding control message (payload size %u) in DV Box to next hop %s (%u/%u) \n",
9846 enc_payload_size,
9847 GNUNET_i2s (&next_hop->pid),
9848 (unsigned int) num_hops,
9849 (unsigned int) total_hops);
9850 route_via_neighbour (next_hop, (const struct
9851 GNUNET_MessageHeader *) msg_buf,
9853 }
9854 else
9855 {
9856 pm = GNUNET_malloc (sizeof(struct PendingMessage) + msg_size);
9858 "2 created pm %p storing vl %p \n",
9859 pm,
9860 vl);
9861 pm->pmt = PMT_DV_BOX;
9862 pm->vl = vl;
9863 pm->target = next_hop->pid;
9867 pm->bytes_msg = msg_size;
9868 buf = (char *) &pm[1];
9869 memcpy (buf, msg_buf, msg_size);
9870
9872 "Created pending message %" PRIu64
9873 " for DV Box with next hop %s (%u/%u)\n",
9874 pm->logging_uuid,
9875 GNUNET_i2s (&next_hop->pid),
9876 (unsigned int) num_hops,
9877 (unsigned int) total_hops);
9878
9879 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
9880 {
9882 vl->pending_msg_head,
9883 vl->pending_msg_tail,
9884 pm);
9885
9887 }
9888 else
9889 {
9891 "The virtual link is not ready for forwarding a DV Box with payload, storing PendingMessage in ring buffer.\n");
9892
9894 {
9896
9897 GNUNET_free (pm_old);
9898 }
9901 {
9904 }
9905 else
9907
9909 "%u items stored in DV ring buffer\n",
9912 }
9913 }
9914}
9915
9916
9922static void
9923free_backtalker (struct Backtalker *b)
9924{
9925 if (NULL != b->get)
9926 {
9928 b->get = NULL;
9929 GNUNET_assert (NULL != b->cmc);
9931 b->cmc = NULL;
9932 }
9933 if (NULL != b->task)
9934 {
9936 b->task = NULL;
9937 }
9938 if (NULL != b->sc)
9939 {
9941 "store cancel\n");
9943 b->sc = NULL;
9944 }
9946 "Removing backtalker for %s\n",
9947 GNUNET_i2s (&b->pid));
9949 GNUNET_YES ==
9951 GNUNET_free (b);
9952}
9953
9954
9963static int
9964free_backtalker_cb (void *cls,
9965 const struct GNUNET_PeerIdentity *pid,
9966 void *value)
9967{
9968 struct Backtalker *b = value;
9969
9970 (void) cls;
9971 (void) pid;
9972 free_backtalker (b);
9973 return GNUNET_OK;
9974}
9975
9976
9982static void
9983backtalker_timeout_cb (void *cls)
9984{
9985 struct Backtalker *b = cls;
9986
9988 "backtalker timeout.\n");
9989 b->task = NULL;
9991 {
9993 return;
9994 }
9995 /* A monotime store may well still be in flight -- @e timeout is about how
9996 long the *peer* has been quiet, and says nothing about PEERSTORE. This
9997 used to `GNUNET_assert (NULL == b->sc)', which aborted the service in
9998 exactly that case. #free_backtalker() cancels the store. */
9999 free_backtalker (b);
10000}
10001
10002
10011static void
10012backtalker_monotime_cb (void *cls,
10013 const struct GNUNET_PEERSTORE_Record *record,
10014 const char *emsg)
10015{
10016 struct Backtalker *b = cls;
10017 struct GNUNET_TIME_AbsoluteNBO *mtbe;
10018 struct GNUNET_TIME_Absolute mt;
10019
10020 (void) emsg;
10021 if (NULL == record)
10022 {
10023 struct CommunicatorMessageContext *cmc;
10024
10025 /* we're done with #backtalker_monotime_cb() invocations,
10026 continue normal processing */
10027 b->get = NULL;
10028 GNUNET_assert (NULL != b->cmc);
10029 /* Take @e cmc out of @a b *before* dispatching: the dispatch runs
10030 arbitrary message handling, and writing `b->cmc = NULL' afterwards
10031 is a write to freed memory should anything on that path have
10032 released @a b. #free_backtalker() keys its "must finish the parked
10033 cmc" decision off @e get, which is already NULL here, so clearing
10034 @e cmc early cannot lose the message either. */
10035 cmc = b->cmc;
10036 b->cmc = NULL;
10037 cmc->mh = (const struct GNUNET_MessageHeader *) &b[1];
10038 if (0 != b->body_size)
10040 else
10041 finish_cmc_handling (cmc);
10042 return;
10043 }
10044 if (sizeof(*mtbe) != record->value_size)
10045 {
10047 GNUNET_break (0);
10048 return;
10049 }
10050 mtbe = record->value;
10051 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
10052 if (mt.abs_value_us > b->monotonic_time.abs_value_us)
10053 {
10055 "Backtalker message from %s dropped, monotime in the past\n",
10056 GNUNET_i2s (&b->pid));
10058 GST_stats,
10059 "# Backchannel messages dropped: monotonic time not increasing",
10060 1,
10061 GNUNET_NO);
10062 b->monotonic_time = mt;
10063 /* Setting body_size to 0 prevents call to #forward_backchannel_payload()
10064 */
10065 b->body_size = 0;
10066 }
10068}
10069
10070
10078static void
10079backtalker_monotime_store_cb (void *cls, int success)
10080{
10081 struct Backtalker *b = cls;
10082
10083 if (GNUNET_OK != success)
10084 {
10086 "Failed to store backtalker's monotonic time in PEERSTORE!\n");
10087 }
10088 b->sc = NULL;
10089 /* @e task is armed for the whole life of @a b -- #backtalker_timeout_cb()
10090 re-arms itself whenever @e timeout has moved forward -- so there is
10091 nothing to do here beyond releasing the store. It used to cancel and
10092 re-add the task, which is what made the task's existence depend on this
10093 callback ever running. */
10094 GNUNET_assert (NULL != b->task);
10095}
10096
10097
10103static void
10105{
10106 struct GNUNET_TIME_AbsoluteNBO mtbe;
10107
10108 /* At most one store may be outstanding. The value we are about to write
10109 supersedes whatever the previous one carried, and leaving the old
10110 context alive means its completion clears @e sc while the newer store
10111 is still in flight -- after which the next update sees a NULL @e sc and
10112 starts a third one. Cancelling is also what keeps @e sc from being
10113 silently overwritten and leaked.
10114
10115 Note what this must NOT do: touch @e task. That task is the only thing
10116 that ever releases a `struct CommunicatorMessageContext' parked in
10117 @e cmc, and cancelling it here left its re-arming up to
10118 #backtalker_monotime_store_cb() -- i.e. up to PEERSTORE answering. A
10119 lost store completion then stalled the parked communicator client for
10120 the life of the process. #backtalker_timeout_cb() already re-arms
10121 itself against the current @e timeout, so the task needs no help. */
10122 if (NULL != b->sc)
10123 {
10125 "Superseding in-flight backtalker monotime store %p\n",
10126 b->sc);
10128 b->sc = NULL;
10129 }
10131 b->sc =
10133 "transport",
10134 &b->pid,
10136 &mtbe,
10137 sizeof(mtbe),
10141 b);
10142}
10143
10144
10153static void
10155 const struct TransportDVBoxMessage *dvb,
10156 const struct GNUNET_ShortHashCode *km)
10157{
10158 const unsigned char *hdr;
10159 size_t hdr_len;
10161
10162 key = (struct GNUNET_CRYPTO_AeadSecretKey*) km;
10163 /* We are the ultimate target, so #handle_dv_box() has established that no
10164 hop entries are left: the ciphertext directly follows the header, and
10165 its length is what we actually received. Deriving it from orig_size
10166 and total_hops instead would only be equivalent if every forwarder
10167 accounted its skipped hops exactly. */
10168 hdr = (const unsigned char *) &dvb[1];
10169 {
10170 uint16_t size = ntohs (dvb->header.size);
10171
10172 if (size < sizeof(*dvb)
10173 + sizeof(struct TransportDVBoxPayloadP)
10174 + sizeof(struct GNUNET_MessageHeader))
10175 {
10176 GNUNET_break_op (0);
10177 finish_cmc_handling (cmc);
10178 return;
10179 }
10180 hdr_len = size - sizeof(*dvb);
10181 }
10182
10183 /* begin actual decryption */
10184 {
10185 struct Backtalker *b;
10186 struct GNUNET_TIME_Absolute monotime;
10187 struct TransportDVBoxPayloadP *ppay;
10188 unsigned char pt[hdr_len + sizeof *ppay] GNUNET_ALIGN;
10189 unsigned char *body;
10190 const struct GNUNET_MessageHeader *mh;
10191
10192 ppay = (struct TransportDVBoxPayloadP *) pt;
10193 body = &pt[sizeof *ppay];
10194 GNUNET_assert (hdr_len >=
10195 sizeof(*ppay) + sizeof(struct GNUNET_MessageHeader));
10196 if (GNUNET_OK != GNUNET_CRYPTO_aead_decrypt (hdr_len,
10197 hdr,
10198 0,
10199 NULL,
10200 key,
10201 &dvb->iv,
10202 &dvb->mac,
10203 pt))
10204 {
10206 "Error decrypting DV payload header\n");
10207 GNUNET_break_op (0);
10208 finish_cmc_handling (cmc);
10209 return;
10210 }
10211 mh = (const struct GNUNET_MessageHeader *) body;
10212 /* NOTE: this used to compare against `sizeof (body)', i.e. the size of
10213 a pointer, which meant only 8-byte payloads were ever accepted. */
10214 if (ntohs (mh->size) != hdr_len - sizeof(*ppay))
10215 {
10216 GNUNET_break_op (0);
10217 finish_cmc_handling (cmc);
10218 return;
10219 }
10220 /* need to prevent box-in-a-box (and DV_LEARN) so check inbox type! */
10221 switch (ntohs (mh->type))
10222 {
10224 GNUNET_break_op (0);
10225 finish_cmc_handling (cmc);
10226 return;
10227
10229 GNUNET_break_op (0);
10230 finish_cmc_handling (cmc);
10231 return;
10232
10233 default:
10234 /* permitted, continue */
10235 break;
10236 }
10237 monotime = GNUNET_TIME_absolute_ntoh (ppay->monotonic_time);
10239 "Decrypted backtalk from %s\n",
10240 GNUNET_i2s (&ppay->sender));
10242 &ppay->sender);
10243 if ((NULL != b) && (monotime.abs_value_us < b->monotonic_time.abs_value_us))
10244 {
10246 GST_stats,
10247 "# Backchannel messages dropped: monotonic time not increasing",
10248 1,
10249 GNUNET_NO);
10250 finish_cmc_handling (cmc);
10251 return;
10252 }
10253 if ((NULL == b) ||
10254 (0 != GNUNET_memcmp (&b->last_ephemeral, &dvb->ephemeral_key)))
10255 {
10256 /* Check signature */
10257 const struct GNUNET_PeerIdentity *my_identity;
10258 struct EphemeralConfirmationPS ec;
10259
10262
10263 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
10264 ec.target = *my_identity;
10265 ec.ephemeral_key = dvb->ephemeral_key;
10266 ec.purpose.size = htonl (sizeof(ec));
10267 ec.sender_monotonic_time = ppay->monotonic_time;
10268 if (
10269 GNUNET_OK !=
10272 &ec,
10273 &ppay->sender_sig,
10274 &ppay->sender.public_key))
10275 {
10276 /* Signature invalid, discard! */
10277 GNUNET_break_op (0);
10278 finish_cmc_handling (cmc);
10279 return;
10280 }
10281 }
10282 /* Update sender, we now know the real origin! */
10284 "DVBox received for me from %s via %s\n",
10285 GNUNET_i2s2 (&ppay->sender),
10286 GNUNET_i2s (&cmc->im.sender));
10287 cmc->im.sender = ppay->sender;
10288
10289 if (NULL != b)
10290 {
10291 /* update key cache and mono time */
10292 b->last_ephemeral = dvb->ephemeral_key;
10293 b->monotonic_time = monotime;
10295 b->timeout =
10297 cmc->mh = mh;
10299 return;
10300 }
10301 /* setup data structure to cache signature AND check
10302 monotonic time with PEERSTORE before forwarding backchannel payload */
10303 b = GNUNET_malloc (sizeof(struct Backtalker) + (hdr_len - sizeof(*ppay)));
10304 b->pid = ppay->sender;
10305 b->body_size = hdr_len - sizeof(*ppay);
10306 memcpy (&b[1], body, hdr_len - sizeof(*ppay));
10310 &b->pid,
10311 b,
10313 b->monotonic_time = monotime; /* NOTE: to be checked still! */
10314 b->cmc = cmc;
10315 b->timeout =
10318 b->get =
10320 "transport",
10321 &b->pid,
10324 b);
10325 } /* end actual decryption */
10326}
10327
10328
10336static void
10337handle_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
10338{
10339 struct CommunicatorMessageContext *cmc = cls;
10340 uint16_t size = ntohs (dvb->header.size) - sizeof(*dvb);
10341 uint16_t num_hops = ntohs (dvb->num_hops);
10342 const struct GNUNET_PeerIdentity *hops =
10343 (const struct GNUNET_PeerIdentity *) &dvb[1];
10344 const char *enc_payload = (const char *) &hops[num_hops];
10345 uint16_t enc_payload_size =
10346 size - (num_hops * sizeof(struct GNUNET_PeerIdentity));
10347 const struct GNUNET_PeerIdentity *my_identity;
10348
10351
10352 if (GNUNET_EXTRA_LOGGING > 0)
10353 {
10354 char *path;
10355
10357 for (unsigned int i = 0; i < num_hops; i++)
10358 {
10359 char *tmp;
10360
10361 GNUNET_asprintf (&tmp, "%s->%s", path, GNUNET_i2s (&hops[i]));
10362 GNUNET_free (path);
10363 path = tmp;
10364 }
10366 "Received DVBox with remaining path %s\n",
10367 path);
10368 GNUNET_free (path);
10369 }
10370
10371 if (num_hops > 0)
10372 {
10373 /* We're trying from the end of the hops array, as we may be
10374 able to find a shortcut unknown to the origin that way */
10375 for (int i = num_hops - 1; i >= 0; i--)
10376 {
10377 struct Neighbour *n;
10378
10379 if (0 == GNUNET_memcmp (&hops[i], my_identity))
10380 {
10381 GNUNET_break_op (0);
10382 finish_cmc_handling (cmc);
10383 return;
10384 }
10385 n = lookup_neighbour (&hops[i]);
10386 if (NULL == n)
10387 continue;
10389 "Skipping %u/%u hops ahead while routing DV Box\n",
10390 i,
10391 num_hops);
10392
10393 forward_dv_box (n,
10394 (struct TransportDVBoxMessage *) dvb,
10395 /* we strip i+1 entries, and the receiver reconstructs
10396 the ciphertext offset from total_hops */
10397 ntohs (dvb->total_hops) + i + 1,
10398 num_hops - i - 1, /* number of hops left */
10399 &hops[i + 1], /* remaining hops */
10400 enc_payload,
10401 enc_payload_size);
10403 "# DV hops skipped routing boxes",
10404 i,
10405 GNUNET_NO);
10407 "# DV boxes routed (total)",
10408 1,
10409 GNUNET_NO);
10410 finish_cmc_handling (cmc);
10411 return;
10412 }
10413 /* Woopsie, next hop not in neighbours, drop! */
10415 "# DV Boxes dropped: next hop unknown",
10416 1,
10417 GNUNET_NO);
10418 finish_cmc_handling (cmc);
10419 return;
10420 }
10421 /* We are the target. Unbox and handle message. */
10423 "# DV boxes opened (ultimate target)",
10424 1,
10425 GNUNET_NO);
10426 cmc->total_hops = ntohs (dvb->total_hops);
10427
10428 {
10429 // DH key derivation with received DV, could be garbage.
10431 struct GNUNET_ShortHashCode km;
10432
10434 if ( (NULL == my_private_key) ||
10435 (GNUNET_OK !=
10437 &dvb->ephemeral_key,
10438 &km)) )
10439 {
10440 GNUNET_break_op (0);
10441 finish_cmc_handling (cmc);
10442 return;
10443 }
10444 decaps_dv_box_cont (cmc,
10445 dvb,
10446 &km);
10447 }
10448}
10449
10450
10458static int
10459check_incoming_msg (void *cls,
10460 const struct GNUNET_TRANSPORT_IncomingMessage *im)
10461{
10462 struct TransportClient *tc = cls;
10463
10464 if (CT_COMMUNICATOR != tc->type)
10465 {
10466 GNUNET_break (0);
10467 return GNUNET_SYSERR;
10468 }
10470 return GNUNET_OK;
10471}
10472
10473
10478{
10482 const char *address;
10483
10487 struct ValidationState *vs;
10488};
10489
10490
10500static int
10501check_known_address (void *cls,
10502 const struct GNUNET_PeerIdentity *pid,
10503 void *value)
10504{
10505 struct CheckKnownAddressContext *ckac = cls;
10506 struct ValidationState *vs = value;
10507
10508 (void) pid;
10509 if (0 != strcmp (vs->address, ckac->address))
10510 return GNUNET_OK;
10511 ckac->vs = vs;
10512 return GNUNET_NO;
10513}
10514
10515
10521static void
10522validation_start_cb (void *cls);
10523
10524
10532static void
10534 struct GNUNET_TIME_Absolute new_time)
10535{
10537 struct ValidationState *next;
10538
10539 /* NOTE: "be lazy" must not apply while #validation_task is unset. Our
10540 only caller that can leave it unset is #validation_start_cb(), which
10541 NULLs it on entry and relies on us to arm it again -- and nothing else
10542 ever does. Returning early there stops address (re)validation and the
10543 #suggest_to_connect() retries that go with it for *every* peer, for
10544 good. */
10545 if ((new_time.abs_value_us == vs->next_challenge.abs_value_us) &&
10546 (NULL != validation_task) &&
10547 (NULL != vs->hn))
10548 return; /* be lazy */
10549 vs->next_challenge = new_time;
10550 if (NULL == vs->hn)
10551 vs->hn =
10553 else
10556 (NULL != validation_task))
10557 return;
10558 if (NULL != validation_task)
10560 /* Arm for the earliest entry in the heap, which need NOT be @a vs:
10561 #validation_start_cb() calls us with @e validation_task unset and with
10562 @a vs already pushed out to its new @e challenge_backoff, which doubles
10563 up to #MAX_VALIDATION_CHALLENGE_FREQ (one day) while an address stays
10564 unanswered. Arming for @a vs there parks the single global validation
10565 task for that long, no matter how many other addresses are due right
10566 now -- and every address of a peer we cannot reach (NAT) is such an
10567 address. Everything that needs a validation then stops with it:
10568 bringing a lost link back up, and confirming the link to a peer that
10569 contacted us. */
10571 if (NULL == next)
10572 return;
10573 /* randomize a bit */
10578 delta),
10580 NULL);
10581}
10582
10583
10594static enum GNUNET_GenericReturnValue
10595revalidate_now_cb (void *cls,
10596 const struct GNUNET_PeerIdentity *pid,
10597 void *value)
10598{
10599 struct ValidationState *vs = value;
10600 const struct GNUNET_TIME_Absolute now =
10602
10603 (void) cls;
10604 (void) pid;
10605 /* What #start_address_validation() does for an address it hears about
10606 again, but without needing the address string. */
10607 vs->challenge_backoff =
10610 vs->challenge_backoff,
10611 2));
10612 if (GNUNET_TIME_absolute_cmp (vs->first_challenge_use, >, now))
10613 vs->first_challenge_use = now;
10616 vs->challenge_backoff));
10617 return GNUNET_OK;
10618}
10619
10620
10627static void
10629 const char *address)
10630{
10631 struct GNUNET_TIME_Absolute now;
10632 struct ValidationState *vs;
10633 struct CheckKnownAddressContext ckac = { .address = address, .vs = NULL };
10634
10636 pid,
10638 &ckac);
10640 if (NULL != (vs = ckac.vs))
10641 {
10642 const struct VirtualLink *vl = lookup_virtual_link (pid);
10643
10644 /* Speed up retrying the validation if 'vs' is not currently valid, or if
10645 * we have no confirmed virtual link to @a pid. In the latter case the
10646 * address may still be well inside its validity window -- but the link is
10647 * down, and #handle_validation_response() is the only thing that can
10648 * rebuild it and tell CORE about the peer again. Without this we would
10649 * wait for @e revalidation_task, which does not fire until
10650 * #ADDRESS_VALIDATION_LIFETIME is nearly over. */
10651 if ((vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us) ||
10652 (NULL == vl) ||
10653 (GNUNET_NO == vl->confirmed))
10654 {
10655 /* reduce backoff as we got a fresh advertisement */
10656 vs->challenge_backoff =
10659 vs->challenge_backoff,
10660 2));
10661 /* A successful validation parks @e first_challenge_use just before
10662 @e validated_until, so that the *next* challenge is not used before
10663 the current validation is about to expire. #validation_start_cb()
10664 refuses to run while that time is still in the future, so pulling
10665 @e next_challenge in without this would only make it reschedule
10666 itself four hours out. The challenge has not been used yet, so
10667 moving the start of its window to now stays truthful -- it is what
10668 the fresh-@a vs path below does as well. */
10669 if (GNUNET_TIME_absolute_cmp (vs->first_challenge_use, >, now))
10670 vs->first_challenge_use = now;
10673 vs->challenge_backoff));
10674 }
10675 return;
10676 }
10677 vs = GNUNET_new (struct ValidationState);
10678 vs->pid = *pid;
10679 vs->valid_until =
10681 vs->first_challenge_use = now;
10682 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
10683 GNUNET_CRYPTO_random_block (&vs->challenge,
10684 sizeof(vs->challenge));
10685 vs->address = GNUNET_strdup (address);
10686 {
10687 /* The peer identity MUST be part of @e hc: two peers behind the same NAT
10688 advertise the very same address string (`PROTO-IP:0'), and with an
10689 address-only key the second one's #revalidation_map entry would be
10690 rejected as a duplicate of the first one's. */
10691 struct GNUNET_HashContext *hsh;
10692
10694 GNUNET_CRYPTO_hash_context_read (hsh, vs->address, strlen (vs->address));
10695 GNUNET_CRYPTO_hash_context_read (hsh, &vs->pid, sizeof(vs->pid));
10696 GNUNET_CRYPTO_hash_context_finish (hsh, &vs->hc);
10697 }
10699 "Starting address validation `%s' of peer %s using challenge %s\n",
10700 address,
10701 GNUNET_i2s (pid),
10702 GNUNET_sh2s (&vs->challenge.value));
10706 &vs->pid,
10707 vs,
10710}
10711
10712
10713static struct Queue *
10714find_queue (const struct GNUNET_PeerIdentity *pid, const char *address);
10715
10716
10717static void
10718suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address);
10719
10720
10721static void
10722hello_for_incoming_cb (void *cls,
10723 const struct GNUNET_PeerIdentity *pid,
10724 const char *uri)
10725{
10726 struct Queue *q;
10727 int pfx_len;
10728 const char *eou;
10729 char *address;
10730 (void) cls;
10731
10732 eou = strstr (uri,
10733 "://");
10734 if ((NULL == eou) || (eou == uri))
10735 {
10736 /* @a uri comes from a HELLO some remote peer published. */
10737 GNUNET_break_op (0);
10738 return;
10739 }
10740 pfx_len = eou - uri;
10741 eou += 3;
10743 "%.*s-%s",
10744 pfx_len,
10745 uri,
10746 eou);
10747
10749 "helo for client %s\n",
10750 address);
10751 q = find_queue (pid, address);
10752 if (NULL == q)
10753 {
10755 }
10756 else
10759}
10760
10761
10784static const struct GNUNET_MessageHeader *
10786{
10787 const struct GNUNET_MessageHeader *hello;
10788
10789 if ((NULL == record) ||
10790 (NULL == record->value) ||
10791 (record->value_size < sizeof(*hello)))
10792 {
10793 GNUNET_break_op (0);
10794 return NULL;
10795 }
10796 hello = record->value;
10797 if (ntohs (hello->size) > record->value_size)
10798 {
10799 GNUNET_break_op (0);
10800 return NULL;
10801 }
10802 return hello;
10803}
10804
10805
10813static void
10814handle_hello_for_incoming (void *cls,
10815 const struct GNUNET_PEERSTORE_Record *record,
10816 const char *emsg)
10817{
10818 struct IncomingRequest *ir = cls;
10820 const struct GNUNET_MessageHeader *hello;
10821 const struct GNUNET_PeerIdentity *my_identity;
10822
10823 if (NULL != emsg)
10824 {
10826 "Got failure from PEERSTORE: %s\n",
10827 emsg);
10829 return;
10830 }
10831 if (NULL == record)
10832 {
10833 GNUNET_break (0);
10835 return;
10836 }
10837 hello = hello_from_record (record);
10838 if (NULL == hello)
10839 {
10840 /* MUST still ask for the next record: a bad one is not a reason to
10841 stall this monitor forever. */
10843 return;
10844 }
10846 if (NULL == my_identity)
10847 {
10849 return;
10850 }
10851 if (0 == GNUNET_memcmp (&record->peer, my_identity))
10852 {
10854 return;
10855 }
10856 if (0 != GNUNET_memcmp (&record->peer, &ir->pid))
10857 {
10858 /* Not the peer this request is about. */
10860 return;
10861 }
10862 parser = GNUNET_HELLO_parser_from_msg (hello, &record->peer);
10863 if (NULL != parser)
10864 {
10867 NULL);
10868 GNUNET_HELLO_parser_free (parser);
10869 }
10870 /* MUST ask for the next record, or this monitor stalls after one HELLO */
10872}
10873
10874
10875static void
10877{
10879 "Error in PEERSTORE monitoring\n");
10880}
10881
10882
10883static void
10885{
10887 "Done with initial PEERSTORE iteration during monitoring\n");
10888}
10889
10890
10899static void
10900try_to_bring_link_up (const struct GNUNET_PeerIdentity *pid)
10901{
10902 struct Neighbour *n;
10903 struct IncomingRequest *ir;
10904
10905 if (GNUNET_YES == in_shutdown)
10906 return;
10907 /* (1) Addresses we already track. These outlive the queues, which is the
10908 point: once a link is down the queue that carried it is usually gone,
10909 so there is no address string left for #start_address_validation(). */
10911 pid,
10913 NULL);
10914 /* (2) Queues we still have; may cover an address with no validation state
10915 yet. After (1), because it may insert into #validation_map. */
10916 n = lookup_neighbour (pid);
10917 if (NULL != n)
10918 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
10919 start_address_validation (pid, q->address);
10920 /* (3) Failing that, look for an address in PEERSTORE. */
10921 for (ir = ir_head; NULL != ir; ir = ir->next)
10922 {
10923 if (0 == GNUNET_memcmp (&ir->pid, pid))
10924 return; /* we are already trying */
10925 }
10926 ir = GNUNET_new (struct IncomingRequest);
10927 ir->pid = *pid;
10929 /* Monitor only @a pid: with NULL every request sees every HELLO in
10930 PEERSTORE, so each of the up to #MAX_INCOMING_REQUEST requests started
10931 a connection attempt and an address validation for peers it was not
10932 created for. */
10934 GNUNET_YES,
10935 "peerstore",
10936 &ir->pid,
10939 NULL,
10941 NULL,
10943 ir);
10944 ir_total++;
10945 /* Bound attempts we do in parallel here, might otherwise get excessive.
10946 Drop the OLDEST request: #ir_head is the one we just inserted, so
10947 freeing that would immediately undo the work above. */
10950}
10951
10952
10960static void
10963{
10964 struct VirtualLink *vl;
10965 struct Neighbour *n;
10966 struct GNUNET_PeerIdentity sender;
10967
10968 sender = cmc->im.sender;
10969 vl = lookup_virtual_link (&sender);
10970 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
10971 {
10972 // route_control_message_without_fc (&cmc->im.sender,
10974 &tvr.header,
10976 }
10977 else
10978 {
10979 /* Use route via neighbour */
10980 n = lookup_neighbour (&sender);
10981 if (NULL != n)
10982 route_via_neighbour (n, &tvr.header,
10985 }
10986
10987 finish_cmc_handling (cmc);
10988 /* An *unconfirmed* link is not a link -- it carries nothing, and CORE has
10989 never been told about the peer. Bailing out on one merely because it
10990 exists is what deadlocks a pair of peers into permanent one-way state:
10991 the challenger validated us, so it believes the connection is up and
10992 starts sending us FLOW_CONTROL; #handle_flow_control() answers an
10993 unknown sender by allocating exactly such an unconfirmed link; and from
10994 then on every challenge it retransmits lands here, gets a response --
10995 which keeps *its* side confirmed and its RTT healthy -- and returns
10996 without ever validating an address of its own. The unconfirmed link
10997 reaps itself after #UNCONFIRMED_LINK_TIMEOUT, but the next FLOW_CONTROL
10998 recreates it, and the peer keeps sending those precisely because it
10999 thinks it is connected. Nothing ever breaks the tie, so CORE on this
11000 side never hears about the peer and never answers its handshake.
11001 Only a confirmed link means there is nothing left to do. */
11002 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
11003 return;
11004
11005 /* For us, the link is still down, but we need bi-directional
11006 connections (for flow-control and for this to be useful for
11007 CORE), so we must try to bring the link up! */
11008 try_to_bring_link_up (&sender);
11009}
11010
11011
11020static void
11022 void *cls,
11023 const struct TransportValidationChallengeMessage *tvc)
11024{
11025 struct CommunicatorMessageContext *cmc = cls;
11026 struct TransportValidationResponseMessage tvr = { 0 };
11027 struct GNUNET_TIME_RelativeNBO validity_duration;
11028
11029 /* DV-routed messages are not allowed for validation challenges */
11030 if (cmc->total_hops > 0)
11031 {
11032 GNUNET_break_op (0);
11033 finish_cmc_handling (cmc);
11034 return;
11035 }
11036 validity_duration = cmc->im.expected_address_validity;
11038 "Received address validation challenge %s\n",
11039 GNUNET_sh2s (&tvc->challenge.value));
11040 /* If we have a virtual link, we use this mechanism to signal the
11041 size of the flow control window, and to allow the sender
11042 to ask for increases. If for us the virtual link is still down,
11043 we will always give a window size of zero. */
11044 tvr.header.type =
11046 tvr.header.size = htons (sizeof(tvr));
11047 tvr.reserved = htonl (0);
11048 tvr.challenge = tvc->challenge;
11049 tvr.origin_time = tvc->sender_time;
11050 tvr.validity_duration = validity_duration;
11051 {
11052 /* create signature */
11053 struct TransportValidationPS tvp = {
11055 .purpose.size = htonl (sizeof(tvp)),
11056 .validity_duration = validity_duration,
11057 .challenge = tvc->challenge
11058 };
11059 if (GNUNET_OK != sign_by_my_identity (&tvp.purpose, &tvr.signature))
11060 {
11061 /* Not answering costs us this address validation; leaving @a cmc
11062 behind would cost us the communicator. */
11063 finish_cmc_handling (cmc);
11064 return;
11065 }
11066 }
11067 send_t_validation_response (cmc, tvr);
11068}
11069
11070
11075{
11080
11084 struct ValidationState *vs;
11085};
11086
11087
11097static int
11098check_known_challenge (void *cls,
11099 const struct GNUNET_PeerIdentity *pid,
11100 void *value)
11101{
11102 struct CheckKnownChallengeContext *ckac = cls;
11103 struct ValidationState *vs = value;
11104
11105 (void) pid;
11106 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
11107 return GNUNET_OK;
11108 ckac->vs = vs;
11109 return GNUNET_NO;
11110}
11111
11112
11120static void
11121peerstore_store_validation_cb (void *cls, int success)
11122{
11123 struct ValidationState *vs = cls;
11124
11125 vs->sc = NULL;
11126 if (GNUNET_YES == success)
11127 return;
11129 "# Peerstore failed to store foreign address",
11130 1,
11131 GNUNET_NO);
11132}
11133
11134
11142static struct Queue *
11143find_queue (const struct GNUNET_PeerIdentity *pid, const char *address)
11144{
11145 struct Neighbour *n;
11146
11147 n = lookup_neighbour (pid);
11148 if (NULL == n)
11149 return NULL;
11150 for (struct Queue *pos = n->queue_head; NULL != pos;
11151 pos = pos->next_neighbour)
11152 {
11153 if (0 == strcmp (pos->address, address))
11154 return pos;
11155 }
11156 return NULL;
11157}
11158
11159
11175static struct Queue *
11176find_queue_by_ip (const struct GNUNET_PeerIdentity *pid, const char *address)
11177{
11178 struct Neighbour *n;
11179 struct Queue *ret = NULL;
11180 char *prefix;
11181 char *ip;
11182
11183 n = lookup_neighbour (pid);
11184 if (NULL == n)
11185 return NULL;
11188 if ((NULL == prefix) || (NULL == ip))
11189 {
11191 GNUNET_free (ip);
11192 return NULL;
11193 }
11194 for (struct Queue *pos = n->queue_head; NULL != pos;
11195 pos = pos->next_neighbour)
11196 {
11197 char *q_prefix = GNUNET_HELLO_address_to_prefix (pos->address);
11198 char *q_ip = get_address_without_port (pos->address);
11199
11200 /* Same communicator and same host -- only the port may differ. */
11201 if ((NULL != q_prefix) && (NULL != q_ip) &&
11202 (0 == strcmp (q_prefix, prefix)) &&
11203 (0 == strcmp (q_ip, ip)))
11204 ret = pos;
11205 GNUNET_free (q_prefix);
11206 GNUNET_free (q_ip);
11207 if (NULL != ret)
11208 break;
11209 }
11211 GNUNET_free (ip);
11212 return ret;
11213}
11214
11215
11216static void
11218
11219static void
11220revalidation_start_cb (void *cls)
11221{
11222 struct ValidationState *vs = cls;
11223 struct Queue *q;
11224 struct GNUNET_TIME_Absolute now;
11225
11226 vs->revalidation_task = NULL;
11227 q = find_queue (&vs->pid, vs->address);
11228 if (NULL == q)
11229 {
11230 now = GNUNET_TIME_absolute_get ();
11231 vs->awaiting_queue = GNUNET_YES;
11232 suggest_to_connect (&vs->pid, vs->address);
11234 }
11235 else
11237}
11238
11239
11240static enum GNUNET_GenericReturnValue
11242 void *cls,
11243 const struct GNUNET_HashCode *key,
11244 void *value)
11245{
11246 (void) cls;
11248 "Key in revalidate map %s \n",
11249 GNUNET_h2s (key));
11250 return GNUNET_YES;
11251}
11252
11253
11262static void
11264 void *cls,
11265 const struct TransportValidationResponseMessage *tvr)
11266{
11267 struct CommunicatorMessageContext *cmc = cls;
11268 struct ValidationState *vs;
11269 struct CheckKnownChallengeContext ckac = { .challenge = &tvr->challenge,
11270 .vs = NULL};
11271 struct GNUNET_TIME_Absolute origin_time;
11272 struct Queue *q;
11273 struct Neighbour *n;
11274 struct VirtualLink *vl;
11276 GST_cfg);
11277
11278 /* check this is one of our challenges */
11280 &cmc->im.sender,
11282 &ckac);
11283 if (NULL == (vs = ckac.vs))
11284 {
11285 /* This can happen simply if we 'forgot' the challenge by now,
11286 i.e. because we received the validation response twice */
11288 "# Validations dropped, challenge unknown",
11289 1,
11290 GNUNET_NO);
11292 "Validation response %s dropped, challenge unknown\n",
11293 GNUNET_sh2s (&tvr->challenge.value));
11294 finish_cmc_handling (cmc);
11295 return;
11296 }
11297
11298 /* sanity check on origin time */
11299 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
11300 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
11301 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
11302 {
11304 "Diff first use %" PRIu64 " and last use %" PRIu64 "\n",
11305 vs->first_challenge_use.abs_value_us - origin_time.abs_value_us,
11306 origin_time.abs_value_us - vs->last_challenge_use.abs_value_us);
11307 GNUNET_break_op (0);
11308 finish_cmc_handling (cmc);
11309 return;
11310 }
11311
11312 {
11313 /* check signature */
11314 struct TransportValidationPS tvp = {
11316 .purpose.size = htonl (sizeof(tvp)),
11317 .validity_duration = tvr->validity_duration,
11318 .challenge = tvr->challenge
11319 };
11320
11321 if (
11322 GNUNET_OK !=
11324 &tvp,
11325 &tvr->signature,
11326 &cmc->im.sender.public_key))
11327 {
11328 GNUNET_break_op (0);
11329 finish_cmc_handling (cmc);
11330 return;
11331 }
11332 }
11333
11334 /* validity is capped by our willingness to keep track of the
11335 validation entry and the maximum the other peer allows */
11338 tvr->validity_duration),
11340 vs->validated_until =
11344 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
11345 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
11346 GNUNET_CRYPTO_random_block (&vs->challenge,
11347 sizeof(vs->challenge));
11348 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
11349 vs->validated_until,
11350 GNUNET_TIME_relative_multiply (vs->validation_rtt,
11352 if (GNUNET_TIME_absolute_cmp (vs->first_challenge_use, <, now))
11353 {
11355 "First challenge use is now %" PRIu64 " %s \n",
11356 vs->first_challenge_use.abs_value_us,
11357 GNUNET_sh2s (&vs->challenge.value));
11358 vs->first_challenge_use = now;
11359 }
11360 else
11362 "First challenge use is later %" PRIu64 " %s \n",
11363 vs->first_challenge_use.abs_value_us,
11364 GNUNET_sh2s (&vs->challenge.value));
11365 vs->last_challenge_use =
11366 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
11367 update_next_challenge_time (vs, vs->first_challenge_use);
11369 "Validation response %s from %s accepted, address valid until %s\n",
11370 GNUNET_sh2s (&tvr->challenge.value),
11371 GNUNET_i2s (&cmc->im.sender),
11373 /*memcpy (&hkey,
11374 &hc,
11375 sizeof (hkey));*/
11377 "Key %s for address %s map size %u contains %u\n",
11378 GNUNET_h2s (&vs->hc),
11379 vs->address,
11382 &vs->hc));
11383 /* NOTE: @e hc hashes the address only, so two `struct ValidationState's
11384 for different peers can collide here. That must not abort us. */
11385 if (GNUNET_YES !=
11388 &vs->hc,
11389 vs,
11392 "Address `%s' already tracked for revalidation\n",
11393 vs->address);
11396 NULL);
11397 vs->revalidation_task =
11402 "transport",
11403 &cmc->im.sender,
11405 vs->address,
11406 strlen (vs->address) + 1,
11407 vs->valid_until,
11410 vs);
11411 finish_cmc_handling (cmc);
11412
11413 /* Finally, we now possibly have a confirmed (!) working queue,
11414 update queue status (if queue still is around) */
11415 q = find_queue (&vs->pid, vs->address);
11416 if (NULL == q)
11417 {
11418 /* The challenge may have gone out on a queue whose address is not
11419 literally @e address: #check_validation_request_pending() matches on
11420 the IP alone, precisely so that a validation waiting for the NAT
11421 address `PROTO-IP:0' can be answered over the queue that the peer
11422 actually established from `PROTO-IP:port'. Insisting on an exact
11423 match here would silently discard that (successful!) validation and
11424 never bring the virtual link up. */
11425 q = find_queue_by_ip (&vs->pid, vs->address);
11426 }
11427 if (NULL == q)
11428 {
11430 "# Queues lost at time of successful validation",
11431 1,
11432 GNUNET_NO);
11433 return;
11434 }
11435 q->validated_until = vs->validated_until;
11436 q->pd.aged_rtt = vs->validation_rtt;
11437 n = q->neighbour;
11438 vl = lookup_virtual_link (&vs->pid);
11439 if (NULL == vl)
11440 {
11441 vl = GNUNET_new (struct VirtualLink);
11443 "Creating new virtual link %p to %s using direct neighbour!\n",
11444 vl,
11445 GNUNET_i2s (&vs->pid));
11446 vl->burst_addr = NULL;
11447 vl->confirmed = GNUNET_YES;
11448 vl->message_uuid_ctr =
11449 GNUNET_CRYPTO_random_u64 (UINT64_MAX);
11450 vl->target = n->pid;
11454 /* What the peer will grant us in its very first FLOW_CONTROL anyway
11455 (@e incoming_fc_window_size plus what we have sent, i.e. nothing).
11456 Starting at zero instead means a link that is up, validated and
11457 working carries nothing at all until an FC round trip completes --
11458 and if the peer cannot answer, not ever. */
11462 links,
11463 &vl->target,
11464 vl,
11466 vl->n = n;
11467 n->vl = vl;
11468 q->idle = GNUNET_YES;
11469 vl->visibility_task =
11470 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
11472 /* We lacked a confirmed connection to the target
11473 before, so tell CORE about it (finally!) */
11476 }
11477 else
11478 {
11479 /* Link was already up, remember n is also now available and we are done */
11480 if (NULL == vl->n)
11481 {
11482 vl->n = n;
11483 n->vl = vl;
11484 if (GNUNET_YES == vl->confirmed)
11486 "Virtual link to %s could now also use direct neighbour!\n",
11487 GNUNET_i2s (&vs->pid));
11488 }
11489 else
11490 {
11491 GNUNET_assert (n == vl->n);
11492 }
11493 if (GNUNET_NO == vl->confirmed)
11494 {
11495 vl->confirmed = GNUNET_YES;
11496 q->idle = GNUNET_YES;
11497 vl->visibility_task =
11498 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
11500 /* We lacked a confirmed connection to the target
11501 before, so tell CORE about it (finally!) */
11504 }
11505 }
11506}
11507
11508
11514static void
11515handle_incoming_msg (void *cls,
11516 const struct GNUNET_TRANSPORT_IncomingMessage *im)
11517{
11518 struct TransportClient *tc = cls;
11519 struct Neighbour *n;
11520 struct CommunicatorMessageContext *cmc =
11522
11523 cmc->tc = tc;
11524 cmc->im = *im;
11526 "Received message with size %u and flow control id %" PRIu64
11527 " via communicator from peer %s\n",
11528 ntohs (im->header.size),
11529 im->fc_id,
11530 GNUNET_i2s (&im->sender));
11531 cmc->im.neighbour_sender = cmc->im.sender;
11532 /* A communicator got this straight from @a im->sender, so the queues to
11533 that neighbour demonstrably still work. This is what #check_link_down()
11534 uses to bound how long a communicator that stopped working (without
11535 telling us) can keep a virtual link -- and CORE -- fooled. */
11536 if (NULL != (n = lookup_neighbour (&im->sender)))
11538 cmc->mh = (const struct GNUNET_MessageHeader *) &im[1];
11540}
11541
11542
11551static int
11552check_flow_control (void *cls, const struct TransportFlowControlMessage *fc)
11553{
11554 unsigned int number_of_addresses = ntohl (fc->number_of_addresses);
11555 uint16_t msize = ntohs (fc->header.size);
11556 const char *tgnas;
11557 size_t avail;
11558 size_t off;
11559
11560 (void) cls;
11562 "Flow control header size %u size of addresses %u number of addresses %u size of message struct %lu second struct %lu\n",
11563 ntohs (fc->header.size),
11564 ntohl (fc->size_of_addresses),
11565 ntohl (fc->number_of_addresses),
11566 sizeof(struct TransportFlowControlMessage),
11567 sizeof (struct TransportGlobalNattedAddress));
11568 if (0 == number_of_addresses)
11569 return GNUNET_OK;
11570 if (msize < sizeof(struct TransportFlowControlMessage))
11571 {
11572 GNUNET_break_op (0);
11573 return GNUNET_SYSERR;
11574 }
11575 avail = msize - sizeof(struct TransportFlowControlMessage);
11576 tgnas = (const char *) &fc[1];
11577 off = 0;
11578 /* Validate EVERY entry: checking only the aggregate size lets a single
11579 entry claim a bogus address_length and send #handle_flow_control()
11580 out of bounds. */
11581 for (unsigned int i = 0; i < number_of_addresses; i++)
11582 {
11583 const struct TransportGlobalNattedAddress *tgna;
11584 size_t alen;
11585
11586 if (avail - off < sizeof(struct TransportGlobalNattedAddress))
11587 {
11588 GNUNET_break_op (0);
11589 return GNUNET_SYSERR;
11590 }
11591 tgna = (const struct TransportGlobalNattedAddress *) &tgnas[off];
11592 off += sizeof(struct TransportGlobalNattedAddress);
11593 alen = ntohl (tgna->address_length);
11594 if (avail - off < alen)
11595 {
11596 GNUNET_break_op (0);
11597 return GNUNET_SYSERR;
11598 }
11599 off += alen;
11600 }
11601 return GNUNET_OK;
11602}
11603
11604
11605static struct GNUNET_TIME_Relative
11606calculate_rtt (struct DistanceVector *dv)
11607{
11609 unsigned int n_hops = 0;
11610
11612 "calculate_rtt\n");
11613 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
11614 pos = pos->next_dv)
11615 {
11617 "calculate_rtt %lu\n",
11618 (unsigned long) pos->pd.aged_rtt.rel_value_us);
11619 n_hops++;
11621 aged_rtt, pos
11622 ->distance
11623 + 2), ret);
11624 }
11625
11626 if (0 == n_hops)
11628 return ret;
11629}
11630
11631
11632static void
11634 const struct GNUNET_PeerIdentity *pid,
11635 const char *uri)
11636{
11637 struct VirtualLink *vl = cls;
11638 const char *slash;
11639 char *address_uri;
11640 char *prefix;
11641 char *uri_without_port;
11642
11643 slash = strrchr (uri, '/');
11644 if ((NULL == slash) || (slash - uri < 2))
11645 {
11646 GNUNET_break_op (0); /* @a uri comes from a remote HELLO */
11647 return;
11648 }
11649 prefix = GNUNET_strndup (uri, (slash - uri) - 2);
11650 slash++;
11651 GNUNET_asprintf (&address_uri,
11652 "%s-%s",
11653 prefix,
11654 slash);
11655
11656 uri_without_port = get_address_without_port (address_uri);
11658 "iterate_address_start_burst %s %s %s %s\n",
11659 (NULL == uri_without_port) ? "<unparsable>" : uri_without_port,
11660 uri,
11661 address_uri,
11662 slash);
11663 GNUNET_free (vl->burst_addr);
11664 if ((NULL != uri_without_port) &&
11665 (0 == strcmp (uri_without_port, slash)))
11666 vl->burst_addr = GNUNET_strdup (uri_without_port);
11667
11669 GNUNET_free (address_uri);
11670 GNUNET_free (uri_without_port);
11671}
11672
11673
11674static void
11675check_for_burst_address (void *cls,
11676 const struct GNUNET_PEERSTORE_Record *record,
11677 const char *emsg)
11678{
11679 struct GNUNET_StartBurstCls *sb_cls = cls;
11680 struct VirtualLink *vl = sb_cls->vl;
11681 const struct GNUNET_MessageHeader *hello;
11683
11684 if (NULL != emsg)
11685 {
11687 "Got failure from PEERSTORE: %s\n",
11688 emsg);
11689 /* @a emsg comes with a NULL record, which means the iteration is over
11690 and PEERSTORE is releasing the context itself -- stopping it here as
11691 well would free it twice. Just drop our handle. */
11692 vl->ic = NULL;
11693 free_burst_cls (sb_cls);
11694 return;
11695 }
11696 if (NULL == record)
11697 {
11699 "Hello iteration end for %s\n",
11700 GNUNET_i2s (&vl->target));
11701 /* PEERSTORE destroys the context itself once it signals the end. */
11702 vl->ic = NULL;
11703 free_burst_cls (sb_cls);
11704 return;
11705 }
11706
11708 "check_for_burst_address\n");
11709 /* @a hello was published by a remote peer, it may well be malformed. */
11710 hello = hello_from_record (record);
11711 if (NULL != hello)
11712 {
11713 parser = GNUNET_HELLO_parser_from_msg (hello, &record->peer);
11714 if (NULL != parser)
11715 {
11718 vl);
11719 GNUNET_HELLO_parser_free (parser);
11720 }
11721 }
11722
11723 /* MUST clear @e ic: #GNUNET_PEERSTORE_iteration_stop() frees it, and
11724 #free_virtual_link() would otherwise stop it a second time. */
11725 if (NULL != vl->ic)
11726 {
11728 vl->ic = NULL;
11729 }
11730 free_burst_cls (sb_cls);
11731}
11732
11733
11734static void
11735burst_timeout (void *cls)
11736{
11738}
11739
11740
11741static void
11742start_burst (void *cls)
11743{
11744 struct GNUNET_StartBurstCls *sb_cls = cls;
11745 struct VirtualLink *vl = sb_cls->vl;
11746 struct GNUNET_TRANSPORT_StartBurst *sb;
11747 struct GNUNET_MQ_Envelope *env;
11748 char *uri_without_port = vl->burst_addr;
11749
11750 burst_task = NULL;
11751 burst_task_cls = NULL;
11752 if (NULL == uri_without_port)
11753 {
11754 /* Lost the address in the meantime, nothing to burst to. */
11755 free_burst_cls (sb_cls);
11756 return;
11757 }
11758 /*char buf[strlen (uri_without_port) + 1];
11759
11760 GNUNET_memcpy (buf, uri_without_port, strlen (uri_without_port));
11761 buf[strlen (uri_without_port)] = '\0';*/
11762 env =
11764 strlen (uri_without_port) + 1,
11766 sb->rtt = GNUNET_TIME_relative_hton (sb_cls->rtt);
11767 sb->pid = vl->target;
11768 memcpy (&sb[1], uri_without_port, strlen (uri_without_port) + 1);
11769 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
11770 {
11771 if (CT_COMMUNICATOR != tc->type)
11772 continue; /* MUST come first: the log below reads the union! */
11774 "iterate_address_start_burst client tc prefix %s\n",
11775 tc->details.communicator.address_prefix);
11776 if (GNUNET_YES == tc->details.communicator.can_burst)
11777 {
11779 "iterate_address_start_burst %s call %lu %u rtt %lu\n",
11780 uri_without_port,
11781 strlen (uri_without_port),
11782 ntohs (sb->header.size),
11783 (unsigned long) sb_cls->rtt.rel_value_us);
11784 GNUNET_MQ_send (tc->mq, env);
11785 env = NULL; /* MQ took ownership */
11789 60),
11791 NULL);
11792 // TODO We need some algo to choose from available communicators. Can we run two bursts at once? Atm we only implemented udp burst.
11793 break;
11794 }
11795 }
11796 if (NULL != env)
11798 free_burst_cls (sb_cls);
11799}
11800
11801
11808static void
11809free_burst_cls (struct GNUNET_StartBurstCls *sb_cls)
11810{
11811 struct VirtualLink *vl = sb_cls->vl;
11812
11813 if (burst_task_cls == sb_cls)
11814 {
11815 if (NULL != burst_task)
11816 {
11818 burst_task = NULL;
11819 }
11820 burst_task_cls = NULL;
11821 }
11822 if ((NULL != vl) && (vl->sb_cls == sb_cls))
11823 vl->sb_cls = NULL;
11825}
11826
11827
11828static void
11829queue_burst (void *cls)
11830{
11831 struct GNUNET_StartBurstCls *sb_cls = cls;
11832 struct VirtualLink *vl = sb_cls->vl;
11833
11834 if (GNUNET_YES != use_burst)
11835 {
11836 /* MUST release: nobody else owns @a sb_cls, and #handle_flow_control()
11837 allocates one for every FLOW_CONTROL message we receive. */
11839 return;
11840 }
11842 "burst_task %p ready %s burst addr %s (%p)\n",
11843 burst_task,
11844 sb_cls->sync_ready ? "yes" : "no",
11845 vl->burst_addr,
11846 vl->burst_addr);
11847 if (NULL != burst_task && GNUNET_NO == sb_cls->sync_ready)
11848 {
11849 /* Cancel the pending burst. Both closures (the scheduled task's and
11850 ours) are ours to release. */
11852
11854 burst_task = NULL;
11855 burst_task_cls = NULL;
11856 if ((NULL != pending) && (pending != sb_cls))
11858 free_burst_cls (sb_cls);
11859 return;
11860 }
11861 if (GNUNET_NO == burst_running && NULL != vl->burst_addr && NULL == burst_task
11862 )
11863 {
11865 &start_burst,
11866 sb_cls);
11867 burst_task_cls = sb_cls;
11868 }
11869 else if (NULL == vl->burst_addr)
11870 {
11871 if (NULL != vl->ic)
11872 {
11873 /* An address lookup is already running for this link; starting a
11874 second one would leak the first. */
11875 free_burst_cls (sb_cls);
11876 return;
11877 }
11879 "peerstore",
11880 &vl->target,
11883 sb_cls);
11884 }
11885 else
11886 {
11887 /* A burst is already running or already scheduled; we have no use for
11888 this closure. */
11889 free_burst_cls (sb_cls);
11890 }
11891}
11892
11893
11900static void
11901unconfirmed_link_timeout (void *cls)
11902{
11903 struct VirtualLink *vl = cls;
11904
11905 vl->unconfirmed_timeout_task = NULL;
11906 if ((GNUNET_YES == vl->confirmed) ||
11907 (NULL != vl->n) ||
11908 (NULL != vl->dv))
11909 return; /* got promoted in the meantime, its owner will clean up */
11911 "Discarding unconfirmed virtual link to %s\n",
11912 GNUNET_i2s (&vl->target));
11914 "# Unconfirmed virtual links timed out",
11915 1,
11916 GNUNET_NO);
11917 free_virtual_link (vl);
11918}
11919
11920
11929static void
11930handle_flow_control (void *cls, const struct TransportFlowControlMessage *fc)
11931{
11932 struct CommunicatorMessageContext *cmc = cls;
11933 struct VirtualLink *vl;
11935 uint32_t seq;
11936 struct GNUNET_TIME_Absolute st;
11937 uint64_t os;
11938 uint64_t wnd;
11939 uint32_t random;
11940
11942 "Received FC from %s\n", GNUNET_i2s (&cmc->im.sender));
11943 vl = lookup_virtual_link (&cmc->im.sender);
11944 if (NULL == vl)
11945 {
11946 vl = GNUNET_new (struct VirtualLink);
11948 "No virtual link for %p FC creating new unconfirmed virtual link to %s!\n",
11949 vl,
11950 GNUNET_i2s (&cmc->im.sender));
11951 vl->burst_addr = NULL;
11952 vl->confirmed = GNUNET_NO;
11953 vl->message_uuid_ctr =
11954 GNUNET_CRYPTO_random_u64 (UINT64_MAX);
11955 vl->target = cmc->im.sender;
11959 /* What the peer will grant us in its very first FLOW_CONTROL anyway
11960 (@e incoming_fc_window_size plus what we have sent, i.e. nothing).
11961 Starting at zero instead means a link that is up, validated and
11962 working carries nothing at all until an FC round trip completes --
11963 and if the peer cannot answer, not ever. */
11967 links,
11968 &vl->target,
11969 vl,
11971 /* Nothing else owns this link yet, so it must reap itself if it never
11972 becomes confirmed -- otherwise any peer can make us allocate
11973 VirtualLinks without bound. */
11977 vl);
11978 }
11979 if (GNUNET_YES != vl->confirmed)
11980 {
11981 /* The peer flow-controls us, so it has a confirmed link to us -- but an
11982 unconfirmed link carries nothing and is never reported to CORE. Only
11983 #handle_validation_response() breaks that tie, and nothing here used
11984 to ask for one, so the pair could sit one-way until the peer's own
11985 four hour revalidation came round. */
11987 }
11988 if (NULL != vl->n)
11989 {
11990 for (struct Queue *q = vl->n->queue_head; NULL != q; q = q->next_neighbour)
11991 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
11992 }
11993
11995 "remaining %lu timeout for neighbour %p\n",
11996 (unsigned long) GNUNET_TIME_absolute_get_remaining (q_timeout).
11997 rel_value_us,
11998 vl->n);
11999 if (NULL == vl->n ||
12000 0 == GNUNET_TIME_absolute_get_remaining (q_timeout).rel_value_us)
12001 {
12002 struct GNUNET_TIME_Relative rtt;
12003 struct GNUNET_BurstSync burst_sync;
12004 struct GNUNET_StartBurstCls *bcls;
12005
12006 if (NULL != vl->sb_cls)
12007 {
12008 /* A burst attempt for this link is already in flight. Allocating a
12009 second closure would orphan the first one: @e sb_cls is how
12010 #free_virtual_link() finds (and cancels) the pending #burst_task,
12011 and a peer that just keeps sending us FLOW_CONTROL messages would
12012 otherwise make us leak one closure per message. */
12014 "Burst attempt to %s already pending\n",
12015 GNUNET_i2s (&vl->target));
12016 }
12017 else
12018 {
12019 bcls = GNUNET_new (struct GNUNET_StartBurstCls);
12020 bcls->vl = vl;
12021 vl->sb_cls = bcls;
12022 if (NULL != vl->dv)
12023 rtt = calculate_rtt (vl->dv);
12024 else
12026 burst_sync.rtt_average = fc->rtt;
12027 bcls->rtt = GNUNET_TIME_relative_ntoh (burst_sync.rtt_average);
12028 /* @e sync_ready of `struct GNUNET_BurstSync' is a host-order enum. */
12029 burst_sync.sync_ready =
12030 (enum GNUNET_GenericReturnValue) ntohl (fc->sync_ready);
12031
12032 /* NOTE: #GNUNET_is_burst_ready() does NOT invoke the task unless both
12033 RTT estimates are known and close; #queue_burst() is thus not
12034 guaranteed to run, which is why @e sb_cls stays owned by @a vl. */
12036 &burst_sync,
12037 &queue_burst,
12038 bcls);
12039 }
12040 }
12041 if (0 != ntohl (fc->number_of_addresses))
12042 {
12043 unsigned int number_of_addresses = ntohl (fc->number_of_addresses);
12044 const char *tgnas;
12045 unsigned int off = 0;
12046
12047 tgnas = (const char *) &fc[1];
12048
12049 for (unsigned int i = 0; i < number_of_addresses; i++)
12050 {
12051 struct TransportGlobalNattedAddress *tgna;
12052 char *addr;
12053 uint32_t address_length;
12054
12055 tgna = (struct TransportGlobalNattedAddress*) &tgnas[off];
12056 addr = (char *) &tgna[1];
12057 address_length = ntohl (tgna->address_length);
12058 off += sizeof(struct TransportGlobalNattedAddress) + address_length;
12059
12060 /* NOTE: the address is NOT 0-terminated (it comes straight off the
12061 wire), it must be printed with an explicit precision. */
12063 "received address %.*s length %u\n",
12064 (int) address_length,
12065 addr,
12067
12068 if (NULL != nh)
12069 GNUNET_NAT_add_global_address (nh, addr, ntohl (tgna->address_length));
12070 }
12071 }
12073 if (st.abs_value_us < vl->last_fc_timestamp.abs_value_us)
12074 {
12076 "FC dropped: Message out of order\n");
12077 /* out of order, drop */
12079 "# FC dropped: message out of order",
12080 1,
12081 GNUNET_NO);
12082 finish_cmc_handling (cmc);
12083 return;
12084 }
12085 seq = ntohl (fc->seq);
12086 if (seq < vl->last_fc_seq)
12087 {
12088 /* Wrap-around/reset of other peer; start all counters from zero */
12090 }
12091 vl->last_fc_seq = seq;
12092 vl->last_fc_timestamp = st;
12093 /* The peer is answering, so the backoff in #consider_sending_fc() starts
12094 over: @e fc_retransmit_count counts *unanswered* rounds. */
12095 vl->fc_retransmit_count = 0;
12097 os = GNUNET_ntohll (fc->outbound_sent);
12099 (int64_t) (os - vl->incoming_fc_window_size_used);
12101 "Received FC from %s, seq %u, new window %llu (loss at %lld)\n",
12102 GNUNET_i2s (&vl->target),
12103 (unsigned int) seq,
12104 (unsigned long long) vl->outbound_fc_window_size,
12105 (long long) vl->incoming_fc_window_size_loss);
12107 random = GNUNET_CRYPTO_random_u32 (UINT32_MAX);
12108 /* NOTE: this must NOT be restricted to a confirmed link. @e
12109 outbound_fc_window_size starts at zero and is raised *only* here, from
12110 the peer's FC. So a peer whose link to us is confirmed while ours to it
12111 is not cannot send us a single byte until we answer -- and it is exactly
12112 that peer that keeps asking. Staying quiet deadlocks the pair: it shows
12113 an established virtual link with messages pending forever, we show none,
12114 and CORE never completes its handshake in either direction. */
12115 if ((wnd < vl->incoming_fc_window_size
12119 (0 == random % FC_NO_CHANGE_REPLY_PROBABILITY))
12120 {
12122 "Consider re-sending our FC message, as clearly the other peer's idea of the window is not up-to-date (%llu vs %llu) or %llu last received differs, or random reply %u\n",
12123 (unsigned long long) wnd,
12124 (unsigned long long) vl->incoming_fc_window_size,
12125 (unsigned long long) vl->last_outbound_window_size_received,
12128 }
12129 if ((wnd == vl->incoming_fc_window_size
12133 {
12135 "Slowing FC transmission to %s to keepalive rate: peer is current at window %llu\n",
12136 GNUNET_i2s (&vl->target),
12137 (unsigned long long) wnd);
12138 /* NOTE: this used to also require @e fc_retransmit_task to be non-NULL
12139 and did nothing at all otherwise -- so a link whose chain had ended
12140 (see #consider_sending_fc()) could never pick the keepalive back up,
12141 even though the peer was demonstrably still talking to us. */
12142 if (NULL != vl->fc_retransmit_task)
12144 vl->fc_retransmit_count = 0;
12145 /* Drop to the keepalive rate rather than stopping outright. There is
12146 nothing left to retransmit -- but if we go completely quiet, and the
12147 peer does the same for the same reason, then neither end sees any
12148 traffic and #check_link_down() tears down a perfectly healthy link
12149 after #NEIGHBOUR_LIVENESS_TIMEOUT. One tiny FC message every
12150 #FC_KEEPALIVE_INTERVAL is what keeps @e last_inbound moving on the
12151 other side (and, via their reply, on ours). */
12152 vl->fc_retransmit_task =
12155 vl);
12156 }
12158 /* FC window likely increased, check transmission possibilities! */
12160 finish_cmc_handling (cmc);
12161}
12162
12163
12171static void
12173{
12175 { GNUNET_MQ_hd_var_size (fragment_box,
12178 cmc),
12179 GNUNET_MQ_hd_var_size (reliability_box,
12182 cmc),
12183 GNUNET_MQ_hd_var_size (reliability_ack,
12186 cmc),
12187 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
12190 cmc),
12191 GNUNET_MQ_hd_var_size (dv_learn,
12194 cmc),
12195 GNUNET_MQ_hd_var_size (dv_box,
12197 struct TransportDVBoxMessage,
12198 cmc),
12199 GNUNET_MQ_hd_var_size (flow_control,
12202 cmc),
12204 validation_challenge,
12207 cmc),
12209 validation_response,
12212 cmc),
12214 int ret;
12215 const struct GNUNET_MessageHeader *msg = cmc->mh;
12216
12218 "Handling message of type %u with %u bytes\n",
12219 (unsigned int) ntohs (msg->type),
12220 (unsigned int) ntohs (msg->size));
12221 /* @a handlers only covers the encapsulations *we* add; anything else is a
12222 payload for CORE and leaves through #handle_raw_message() below. So
12223 #GNUNET_NO is the common case here -- one per delivered CORE message --
12224 and not something to log about, which is why this is the "try" variant. */
12226 if (GNUNET_SYSERR == ret)
12227 {
12228 /* @a msg is the message a *remote peer* sent us: #handle_incoming_msg()
12229 points @e mh into the payload of the
12230 #GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG the communicator
12231 delivered, and every other caller unwraps it from remote traffic as
12232 well. So failing a check here is that peer's protocol violation, and
12233 it says nothing at all about the communicator that carried it.
12234
12235 Dropping the client therefore punishes the wrong party, and it
12236 punishes it hard: #GNUNET_SERVICE_client_drop() disconnects the
12237 communicator *process*, which takes down every queue it owns and thus
12238 every neighbour reachable through it. One malformed DV box on a
12239 shared UDP communicator disconnects every peer we have on it, CORE
12240 tears the sessions down, and the key exchanges that would rebuild
12241 them have to wait for the communicator to come back and revalidate.
12242 Since the offending bytes arrive from the network, any peer can do
12243 this to us at will, repeatedly.
12244
12245 Drop the message and keep the communicator: resume it exactly as the
12246 success path does, so it still gets its flow-control ACK and its
12247 GNUNET_SERVICE_client_continue(). */
12248 GNUNET_break_op (0);
12250 "# malformed messages discarded",
12251 1,
12252 GNUNET_NO);
12254 return;
12255 }
12256 if (GNUNET_NO == ret)
12257 {
12258 /* unencapsulated 'raw' message */
12259 handle_raw_message (cmc, msg);
12260 }
12261}
12262
12263
12270static int
12271check_add_queue_message (void *cls,
12272 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
12273{
12274 struct TransportClient *tc = cls;
12275
12276 if (CT_COMMUNICATOR != tc->type)
12277 {
12278 GNUNET_break (0);
12279 return GNUNET_SYSERR;
12280 }
12282 return GNUNET_OK;
12283}
12284
12285
12291static void
12293{
12294 if (pm->msg_uuid_set)
12295 return;
12296 pm->msg_uuid.uuid = pm->vl->message_uuid_ctr++;
12298}
12299
12300
12309static struct PendingAcknowledgement *
12311 struct DistanceVectorHop *dvh,
12312 struct PendingMessage *pm)
12313{
12314 struct PendingAcknowledgement *pa;
12315
12316 pa = GNUNET_new (struct PendingAcknowledgement);
12317 pa->queue = queue;
12318 pa->dvh = dvh;
12319 pa->pm = pm;
12320 do
12321 {
12323 sizeof(pa->ack_uuid));
12324 }
12327 &pa->ack_uuid.value,
12328 pa,
12330 GNUNET_CONTAINER_MDLL_insert (queue, queue->pa_head, queue->pa_tail, pa);
12332 if (NULL != dvh)
12335 pa->message_size = pm->bytes_msg;
12337 "Waiting for ACKnowledgment `%s' for <%" PRIu64 ">\n",
12339 pm->logging_uuid);
12340 return pa;
12341}
12342
12343
12355static struct PendingMessage *
12357 struct DistanceVectorHop *dvh,
12358 struct PendingMessage *pm)
12359{
12360 struct PendingAcknowledgement *pa;
12361 struct PendingMessage *ff;
12362 uint16_t mtu;
12363 uint16_t msize;
12364
12365 mtu = (UINT16_MAX == queue->mtu)
12366 ? UINT16_MAX - sizeof(struct GNUNET_TRANSPORT_SendMessageTo)
12367 : queue->mtu;
12369 "Fragmenting message <%" PRIu64
12370 "> with size %u to %s for MTU %u\n",
12371 pm->logging_uuid,
12372 pm->bytes_msg,
12373 GNUNET_i2s (&pm->vl->target),
12374 (unsigned int) mtu);
12377 "Fragmenting message %" PRIu64 " <%" PRIu64
12378 "> with size %u to %s for MTU %u\n",
12379 pm->msg_uuid.uuid,
12380 pm->logging_uuid,
12381 pm->bytes_msg,
12382 GNUNET_i2s (&pm->vl->target),
12383 (unsigned int) mtu);
12384
12385 /* This invariant is established in #handle_add_queue_message() */
12386 GNUNET_assert (mtu > sizeof(struct TransportFragmentBoxMessage));
12387
12388 /* select fragment for transmission, descending the tree if it has
12389 been expanded until we are at a leaf or at a fragment that is small
12390 enough
12391 */
12392 ff = pm;
12393 msize = ff->bytes_msg;
12394
12395 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
12396 (ff->frag_off == msize) && (NULL != ff->head_frag))
12397 {
12398 ff = ff->head_frag; /* descent into fragmented fragments */
12399 msize = ff->bytes_msg - sizeof(struct TransportFragmentBoxMessage);
12400 }
12401
12402 if (((ff->bytes_msg > mtu) || (pm == ff)) && (ff->frag_off < msize))
12403 {
12404 /* Did not yet calculate all fragments, calculate next fragment */
12405 struct PendingMessage *frag;
12406 struct TransportFragmentBoxMessage tfb;
12407 const char *orig;
12408 char *msg;
12409 uint16_t fragmax;
12410 uint16_t fragsize;
12411 uint16_t msize_ff;
12412 uint16_t xoff = 0;
12413 pm->frag_count++;
12414
12415 orig = (const char *) &ff[1];
12416 msize_ff = ff->bytes_msg;
12417 if (pm != ff)
12418 {
12419 const struct TransportFragmentBoxMessage *tfbo;
12420
12421 tfbo = (const struct TransportFragmentBoxMessage *) orig;
12422 orig += sizeof(struct TransportFragmentBoxMessage);
12423 msize_ff -= sizeof(struct TransportFragmentBoxMessage);
12424 xoff = ntohs (tfbo->frag_off);
12425 }
12426 fragmax = mtu - sizeof(struct TransportFragmentBoxMessage);
12427 fragsize = GNUNET_MIN (msize_ff - ff->frag_off, fragmax);
12428 frag =
12429 GNUNET_malloc (sizeof(struct PendingMessage)
12430 + sizeof(struct TransportFragmentBoxMessage) + fragsize);
12432 "3 created pm %p from pm %p storing vl %p from pm %p\n",
12433 frag,
12434 ff,
12435 pm->vl,
12436 pm);
12438 frag->vl = pm->vl;
12439 frag->frag_parent = ff;
12440 frag->timeout = pm->timeout;
12441 frag->bytes_msg = sizeof(struct TransportFragmentBoxMessage) + fragsize;
12442 frag->pmt = PMT_FRAGMENT_BOX;
12443 msg = (char *) &frag[1];
12444 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
12445 tfb.header.size =
12446 htons (sizeof(struct TransportFragmentBoxMessage) + fragsize);
12447 pa = prepare_pending_acknowledgement (queue, dvh, frag);
12448 tfb.ack_uuid = pa->ack_uuid;
12449 tfb.msg_uuid = pm->msg_uuid;
12450 tfb.frag_off = htons (ff->frag_off + xoff);
12451 tfb.msg_size = htons (pm->bytes_msg);
12452 memcpy (msg, &tfb, sizeof(tfb));
12453 memcpy (&msg[sizeof(tfb)], &orig[ff->frag_off], fragsize);
12455 ff->tail_frag, frag);
12456 ff->frag_off += fragsize;
12457 ff = frag;
12458 }
12459
12460 if (pm == ff)
12461 {
12462 /* Neither the descent nor the branch above moved us off @a pm, so there
12463 is no fragment to send: @e head_frag is empty *and* @e frag_off says
12464 everything was already cut. completed_pending_message() leaves
12465 exactly that state behind when the last outstanding fragment is
12466 acknowledged but its condition for finishing the root does not hold
12467 (@e frag_off having been advanced past the boxed payload size, or the
12468 root being a reliability box). The rotate below then dereferences
12469 @e frag_parent, which is NULL for the message on @e pending_msg_head.
12470
12471 Report "nothing to fragment" instead; the caller reschedules. */
12472 GNUNET_break (0);
12473 return NULL;
12474 }
12475 /* Move head to the tail and return it */
12479 ff);
12483 ff);
12484
12485 return ff;
12486}
12487
12488
12501static struct PendingMessage *
12503 struct DistanceVectorHop *dvh,
12504 struct PendingMessage *pm)
12505{
12507 struct PendingAcknowledgement *pa;
12508 struct PendingMessage *bpm;
12509 char *msg;
12510
12511 if ((PMT_CORE != pm->pmt) && (PMT_DV_BOX != pm->pmt))
12512 return pm; /* already fragmented or reliability boxed, or control message:
12513 do nothing */
12514 if (NULL != pm->bpm)
12515 return pm->bpm; /* already computed earlier: do nothing */
12516 // TODO I guess we do not need this assertion. We might have a DLL with
12517 // fragments, because the MTU changed, and we do not need to fragment anymore.
12518 // But we should keep the fragments until message was completed, because
12519 // the MTU might change again.
12520 // GNUNET_assert (NULL == pm->head_frag);
12521 if (pm->bytes_msg + sizeof(rbox) > UINT16_MAX)
12522 {
12523 /* failed hard */
12524 GNUNET_break (0);
12526 return NULL;
12527 }
12528
12529 pa = prepare_pending_acknowledgement (queue, dvh, pm);
12530
12531 bpm = GNUNET_malloc (sizeof(struct PendingMessage) + sizeof(rbox)
12532 + pm->bytes_msg);
12534 "4 created pm %p storing vl %p from pm %p\n",
12535 bpm,
12536 pm->vl,
12537 pm);
12539 bpm->vl = pm->vl;
12540 bpm->frag_parent = pm;
12541 // Why was this needed?
12542 // GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
12543 bpm->timeout = pm->timeout;
12545 bpm->bytes_msg = pm->bytes_msg + sizeof(rbox);
12547 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
12548 rbox.header.size = htons (sizeof(rbox) + pm->bytes_msg);
12549 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
12550
12551 rbox.ack_uuid = pa->ack_uuid;
12552 msg = (char *) &bpm[1];
12553 memcpy (msg, &rbox, sizeof(rbox));
12554 memcpy (&msg[sizeof(rbox)], &pm[1], pm->bytes_msg);
12555 pm->bpm = bpm;
12557 "Preparing reliability box for message <%" PRIu64
12558 "> of size %d (%d) to %s on queue %s\n",
12559 pm->logging_uuid,
12560 pm->bytes_msg,
12561 ntohs (((const struct GNUNET_MessageHeader *) &pm[1])->size),
12562 GNUNET_i2s (&pm->vl->target),
12563 queue->address);
12564 return bpm;
12565}
12566
12567
12568static void
12571{
12572 struct VirtualLink *vl = pm->vl;
12573 struct PendingMessage *pos;
12574
12575 /* Only a message without a parent is on vl->pending_msg_head; anything
12576 else is not ours to reorder and MDLL_remove() would abort on it. */
12577 if ((NULL == vl) ||
12578 (NULL != pm->frag_parent) ||
12579 ((NULL == pm->prev_vl) && (vl->pending_msg_head != pm)))
12580 {
12581 GNUNET_break (0);
12582 return;
12583 }
12584 /* re-insert sort in neighbour list */
12588 pm);
12589 pos = vl->pending_msg_tail;
12590 while ((NULL != pos) &&
12592 pos = pos->prev_vl;
12596 pos,
12597 pm);
12598}
12599
12600
12601static unsigned int
12602check_next_attempt_tree (struct PendingMessage *pm, struct PendingMessage *root)
12603{
12604 struct PendingMessage *pos;
12605 /* MUST be initialised: for a leaf the loop below never runs */
12607
12608 pos = pm->head_frag;
12609 while (NULL != pos)
12610 {
12612 GNUNET_NO == check_next_attempt_tree (pos, root))
12614 else
12615 {
12617 break;
12618 }
12619 pos = pos->next_frag;
12620 }
12621
12622 return frags_in_flight;
12623}
12624
12625
12626static void
12628{
12629 struct PendingMessage *pos;
12630
12631 pos = pm->head_frag;
12632 while (NULL != pos)
12633 {
12636 pos = pos->next_frag;
12637 }
12638}
12639
12640
12649static void
12652{
12653 if (NULL == pm->frag_parent)
12654 {
12657 "Next attempt for message <%" PRIu64 "> set to %" PRIu64 "\n",
12658 pm->logging_uuid,
12661 }
12662 else if ((PMT_RELIABILITY_BOX == pm->pmt) || (PMT_DV_BOX == pm->pmt))// || (PMT_FRAGMENT_BOX == pm->pmt))
12663 {
12664 struct PendingMessage *root = pm->frag_parent;
12665
12666 while (NULL != root->frag_parent)
12667 root = root->frag_parent;
12669 "Next attempt for root message <%" PRIu64 "> set to %s\n",
12670 root->logging_uuid,
12672 root->next_attempt = next_attempt;
12674 }
12675 else
12676 {
12677 struct PendingMessage *root = pm->frag_parent;
12678
12679 while (NULL != root->frag_parent && PMT_DV_BOX != root->pmt)
12680 root = root->frag_parent;
12681
12683 "frag_count next attempt %u\n",
12684 root->frag_count);
12685
12686 if (GNUNET_NO == root->frags_in_flight)
12687 {
12688 root->next_attempt = next_attempt;
12690 root->frags_in_flight_round++;
12692 "Next attempt for fragmented message <%" PRIu64 "> (<%" PRIu64
12693 ">)set to %" PRIu64 "\n",
12694 pm->logging_uuid,
12695 root->logging_uuid,
12697 }
12698
12699 pm->next_attempt = root->next_attempt;
12702
12703 if (root->bytes_msg == root->frag_off)
12704 root->frags_in_flight = check_next_attempt_tree (root, root);
12705 else
12707
12708 if (GNUNET_NO == root->frags_in_flight)
12709 {
12710 /* `root' deliberately stops at a DV box, which is itself a child of
12711 the message on vl->pending_msg_head. Walk the rest of the way for
12712 the reorder: only the parentless message is on that list. */
12713 struct PendingMessage *vl_root = root;
12714
12715 while (NULL != vl_root->frag_parent)
12716 vl_root = vl_root->frag_parent;
12717 vl_root->next_attempt = root->next_attempt;
12719 "We have no fragments in flight for message %" PRIu64
12720 ", reorder root %" PRIu64 "! Next attempt is %" PRIu64 "\n",
12721 root->logging_uuid,
12722 vl_root->logging_uuid,
12723 vl_root->next_attempt.abs_value_us);
12724 reorder_root_pm (vl_root, vl_root->next_attempt);
12725 }
12726 else
12727 {
12728 double factor = ((double) root->frag_count - 1)
12729 / (double) root->frag_count;
12730 struct GNUNET_TIME_Relative s1;
12731 struct GNUNET_TIME_Relative s2;
12732 struct GNUNET_TIME_Relative plus_mean =
12735 next_attempt);
12736
12738 "frag_count %u after factor\n",
12739 root->frag_count);
12741 factor);
12742 s2 = GNUNET_TIME_relative_divide (plus,
12743 root->frag_count);
12744 plus_mean = GNUNET_TIME_relative_add (s1, s2);
12747 "We have fragments in flight for message %" PRIu64
12748 ", do not reorder root! Actual next attempt %" PRIu64 "\n",
12749 root->logging_uuid,
12751 }
12752 }
12753}
12754
12755
12760{
12764 struct PendingMessage *best;
12765
12769 struct DistanceVectorHop *dvh;
12770
12774 size_t real_overhead;
12775
12779 unsigned int consideration_counter;
12780
12784 int frag;
12785
12789 int relb;
12790
12794 int to_early;
12795
12799 unsigned int frags_in_flight;
12800
12805};
12806
12807
12819static void
12821 struct Queue *queue,
12822 struct VirtualLink *vl,
12823 struct DistanceVectorHop *dvh,
12824 size_t overhead)
12825{
12826 struct GNUNET_TIME_Absolute now;
12827
12828 now = GNUNET_TIME_absolute_get ();
12829 /* NOTE: @a sc accumulates across calls -- #transmit_on_queue() zeroes it
12830 once and then runs us for the direct link and for every DV hop in turn.
12831 Clearing the verdict here made each call discard what the previous ones
12832 found, so a message that was too early on the direct link was forgotten
12833 as soon as one DV hop had nothing to offer, and nothing rescheduled the
12834 queue at all. */
12835 for (struct PendingMessage *pos = vl->pending_msg_head; NULL != pos;
12836 pos = pos->next_vl)
12837 {
12838 size_t real_overhead = overhead;
12839 int frag;
12840 int relb;
12841
12842 if ((NULL != dvh) && (PMT_DV_BOX == pos->pmt))
12843 {
12845 "DV messages must not be DV-routed to next hop!\n");
12846 continue; /* DV messages must not be DV-routed to next hop! */
12847 }
12848 if (pos->next_attempt.abs_value_us > now.abs_value_us)
12849 {
12850 if (GNUNET_YES == pos->frags_in_flight)
12851 {
12852 sc->frags_in_flight = GNUNET_YES;
12854 "Fragments in flight for message %" PRIu64 "\n",
12855 pos->logging_uuid);
12856 }
12857 else
12858 {
12860 "Maybe too early, because message are sorted by next_attempt, if there are no fragments in flight.Checked message %"
12861 PRIu64 "\n",
12862 pos->logging_uuid);
12863 /* The *earliest* deadline is the one to come back for: @e
12864 pending_msg_head is sorted by @e next_attempt, so overwriting
12865 this on every iteration left the largest delay of the whole
12866 list -- the queue then slept past every message but the last
12867 one. Across the calls for the direct link and each DV hop the
12868 same argument applies, hence the min() rather than an
12869 assignment. */
12870 sc->to_early_retry_delay =
12871 (GNUNET_YES == sc->to_early)
12872 ? GNUNET_TIME_relative_min (sc->to_early_retry_delay,
12874 pos->next_attempt))
12875 : GNUNET_TIME_absolute_get_remaining (pos->next_attempt);
12876 sc->to_early = GNUNET_YES;
12877 continue;
12878 }
12879 // break; /* too early for all messages, they are sorted by next_attempt */
12880 }
12881 if (NULL != pos->qe)
12882 {
12884 "not eligible\n");
12885 continue; /* not eligible */
12886 }
12887 sc->consideration_counter++;
12888 /* determine if we have to fragment, if so add fragmentation
12889 overhead! */
12891 "check %" PRIu64 " for sc->best\n",
12892 pos->logging_uuid);
12893 frag = GNUNET_NO;
12894 if (((0 != queue->mtu) &&
12895 (pos->bytes_msg + real_overhead > queue->mtu)) ||
12896 (pos->bytes_msg > UINT16_MAX - sizeof(struct
12898 ||
12899 (NULL != pos->head_frag /* fragments already exist, should
12900 respect that even if MTU is UINT16_MAX for
12901 this queue */))
12902 {
12904 "fragment msg with size %u, realoverhead is %lu\n",
12905 pos->bytes_msg,
12906 real_overhead);
12907 frag = GNUNET_YES;
12908 if (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc)
12909 {
12910 /* FIXME-FRAG-REL-UUID: we could use an optimized, shorter fragmentation
12911 header without the ACK UUID when using a *reliable* channel! */
12912 }
12913 real_overhead = overhead + sizeof(struct TransportFragmentBoxMessage);
12914 }
12915 /* determine if we have to reliability-box, if so add reliability box
12916 overhead */
12917 relb = GNUNET_NO;
12918 if ((GNUNET_NO == frag) &&
12919 (0 == (pos->prefs & GNUNET_MQ_PREF_UNRELIABLE)) &&
12920 (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc))
12921 {
12922 real_overhead += sizeof(struct TransportReliabilityBoxMessage);
12923
12924 if ((0 != queue->mtu) && (pos->bytes_msg + real_overhead > queue->mtu))
12925 {
12926 frag = GNUNET_YES;
12927 real_overhead = overhead + sizeof(struct TransportFragmentBoxMessage);
12928 }
12929 else
12930 {
12931 relb = GNUNET_YES;
12932 }
12934 "Create reliability box of msg with size %u, realoverhead is %lu %u %u %u\n",
12935 pos->bytes_msg,
12936 real_overhead,
12937 queue->mtu,
12938 frag,
12939 relb);
12940 }
12941
12942 /* Finally, compare to existing 'best' in sc to see if this 'pos' pending
12943 message would beat it! */
12944 if (GNUNET_NO == sc->frags_in_flight && NULL != sc->best)
12945 {
12946 /* CHECK if pos fits queue BETTER (=smaller) than pm, if not: continue;
12947 OPTIMIZE-ME: This is a heuristic, which so far has NOT been
12948 experimentally validated. There may be some huge potential for
12949 improvement here. Also, we right now only compare how well the
12950 given message fits _this_ queue, and do not consider how well other
12951 queues might suit the message. Taking other queues into consideration
12952 may further improve the result, but could also be expensive
12953 in terms of CPU time. */
12954 long long sc_score = sc->frag * 40 + sc->relb * 20 + sc->real_overhead;
12955 long long pm_score = frag * 40 + relb * 20 + real_overhead;
12956 long long time_delta =
12957 (sc->best->next_attempt.abs_value_us - pos->next_attempt.abs_value_us)
12958 / 1000LL;
12959
12960 /* "time_delta" considers which message has been 'ready' for transmission
12961 for longer, if a message has a preference for low latency, increase
12962 the weight of the time_delta by 10x if it is favorable for that message */
12963 if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
12964 (0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)))
12965 time_delta *= 10; /* increase weight (always, both are low latency) */
12966 else if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
12967 (time_delta > 0))
12968 time_delta *= 10; /* increase weight, favors 'pos', which is low latency */
12969 else if ((0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
12970 (time_delta < 0))
12971 time_delta *= 10; /* increase weight, favors 'sc->best', which is low latency */
12972 if (0 != queue->mtu)
12973 {
12974 /* Grant bonus if we are below MTU, larger bonus the closer we will
12975 be to the MTU */
12976 if (queue->mtu > sc->real_overhead + sc->best->bytes_msg)
12977 sc_score -= queue->mtu - (sc->real_overhead + sc->best->bytes_msg);
12978 if (queue->mtu > real_overhead + pos->bytes_msg)
12979 pm_score -= queue->mtu - (real_overhead + pos->bytes_msg);
12980 }
12981 if (sc_score + time_delta > pm_score)
12982 {
12984 "sc_score of %" PRIu64 " larger, keep sc->best %" PRIu64
12985 "\n",
12986 pos->logging_uuid,
12987 sc->best->logging_uuid);
12988 continue; /* sc_score larger, keep sc->best */
12989 }
12990 }
12991 sc->best = pos;
12992 sc->dvh = dvh;
12993 sc->frag = frag;
12994 sc->relb = relb;
12995 sc->real_overhead = real_overhead;
12996 }
12997}
12998
12999
13010static void
13011extract_box_cb (void *cls,
13012 struct Neighbour *next_hop,
13013 const struct GNUNET_MessageHeader *hdr,
13015{
13016 struct PendingMessageScoreContext *sc = cls;
13017 struct PendingMessage *pm = sc->best;
13018 struct PendingMessage *bpm;
13019 uint16_t bsize = ntohs (hdr->size);
13020
13021 GNUNET_assert (NULL == pm->bpm);
13022 bpm = GNUNET_malloc (sizeof(struct PendingMessage) + bsize);
13024 "5 created pm %p storing vl %p from pm %p\n",
13025 bpm,
13026 pm->vl,
13027 pm);
13029 bpm->pmt = PMT_DV_BOX;
13030 bpm->vl = pm->vl;
13031 bpm->timeout = pm->timeout;
13032 bpm->bytes_msg = bsize;
13033 bpm->frag_parent = pm;
13036 "Creating DV Box %" PRIu64 " for original message %" PRIu64
13037 " (next hop is %s)\n",
13039 pm->logging_uuid,
13040 GNUNET_i2s (&next_hop->pid));
13041 memcpy (&bpm[1], hdr, bsize);
13042 pm->bpm = bpm;
13043}
13044
13045
13061static void
13062transmit_on_queue (void *cls)
13063{
13064 struct Queue *queue = cls;
13065 struct Neighbour *n = queue->neighbour;
13067 struct PendingMessage *pm;
13068
13069 queue->transmit_task = NULL;
13070 if ((NULL == n->vl) && (NULL == n->dv_head))
13071 {
13073 "Virtual link `%s' is down, cannot have PM for queue `%s'\n",
13074 GNUNET_i2s (&n->pid),
13075 queue->address);
13076 queue->idle = GNUNET_YES;
13077 return;
13078 }
13079 memset (&sc, 0, sizeof(sc));
13080 /* @e n need not have a link of its own: it may serve only as the first
13081 hop of DV paths, and the traffic queued for those still has to go out. */
13082 if (NULL != n->vl)
13083 select_best_pending_from_link (&sc, queue, n->vl, NULL, 0);
13084 if (NULL == sc.best)
13085 {
13086 /* Also look at DVH that have the n as first hop! */
13087 for (struct DistanceVectorHop *dvh = n->dv_head; NULL != dvh;
13088 dvh = dvh->next_neighbour)
13089 {
13090 if (NULL == dvh->dv->vl)
13091 continue; /* route not (yet) visible to CORE, no messages for it */
13093 queue,
13094 dvh->dv->vl,
13095 dvh,
13096 sizeof(struct GNUNET_PeerIdentity)
13097 * (1 + dvh->distance)
13098 + sizeof(struct TransportDVBoxMessage)
13099 + sizeof(struct TransportDVBoxPayloadP));
13100 }
13101 }
13102 if (NULL == sc.best)
13103 {
13104 /* no message pending, nothing to do here! */
13106 "No pending messages, queue `%s' to %s now idle\n",
13107 queue->address,
13108 GNUNET_i2s (&n->pid));
13109 if (GNUNET_YES == sc.to_early)
13110 schedule_transmit_on_queue (sc.to_early_retry_delay,
13111 queue,
13113 queue->idle = GNUNET_YES;
13114 return;
13115 }
13116 /* There is a message pending, we are certainly not idle */
13117 queue->idle = GNUNET_NO;
13118
13119 /* Given selection in `sc`, do transmission */
13120 pm = sc.best;
13122 "Selected message <%" PRIu64 ">\n",
13123 pm->logging_uuid);
13124 if (NULL != sc.dvh)
13125 {
13127 "Is this %u a DV box?\n",
13128 pm->pmt);
13129 GNUNET_assert (PMT_DV_BOX != pm->pmt);
13130 if ((NULL != sc.best->bpm) && (sc.best->bpm->used_dvh != sc.dvh))
13131 {
13133 "Discard old box, because we have a new DV path.\n");
13134 free_pending_message (sc.best->bpm);
13135 sc.best->bpm = NULL;
13136 }
13137
13138 if (NULL == sc.best->bpm)
13139 {
13141 "encapsulate_for_dv 2\n");
13142 encapsulate_for_dv (sc.dvh->dv,
13143 1,
13144 &sc.dvh,
13145 (const struct GNUNET_MessageHeader *) &sc.best[1],
13147 &sc,
13148 RMO_NONE,
13149 GNUNET_NO);
13150 GNUNET_assert (NULL != sc.best->bpm);
13152 "%lu %lu %lu %lu %u\n",
13153 sizeof(struct GNUNET_PeerIdentity),
13154 sizeof(struct TransportDVBoxMessage),
13155 sizeof(struct TransportDVBoxPayloadP),
13156 sizeof(struct TransportFragmentBoxMessage),
13157 ((const struct GNUNET_MessageHeader *) &sc.best[1])->size);
13158 sc.best->bpm->used_dvh = sc.dvh;
13159 }
13160 pm = sc.best->bpm;
13161 }
13162 if (GNUNET_YES == sc.frag)
13163 {
13164 pm = fragment_message (queue, sc.dvh, pm);
13165 if (NULL == pm)
13166 {
13168 "Fragmentation failed queue %s to %s for <%" PRIu64
13169 ">, trying again\n",
13170 queue->address,
13171 GNUNET_i2s (&n->pid),
13172 sc.best->logging_uuid);
13173 /* NOT with a zero delay: nothing about @a queue or about the message
13174 changed between here and the next pass, so "trying again" at once
13175 is a busy loop that reproduces the failure at scheduler speed. */
13177 queue,
13179 return;
13180 }
13181 }
13182 else if (GNUNET_YES == sc.relb)
13183 {
13184 pm = reliability_box_message (queue, sc.dvh, pm);
13185 if (NULL == pm)
13186 {
13187 /* Reliability boxing failed, try next message... */
13188 GNUNET_log (
13190 "Reliability boxing failed queue %s to %s for <%" PRIu64
13191 ">, trying again\n",
13192 queue->address,
13193 GNUNET_i2s (&n->pid),
13194 sc.best->logging_uuid);
13195 /* Same reasoning as for the fragmentation failure above. */
13197 queue,
13199 return;
13200 }
13201 }
13202
13203 /* Pass 'pm' for transission to the communicator */
13204 GNUNET_log (
13206 "Passing message <%" PRIu64
13207 "> to queue %s for peer %s (considered %u others)\n",
13208 pm->logging_uuid,
13209 queue->address,
13210 GNUNET_i2s (&n->pid),
13211 sc.consideration_counter);
13212
13213 /* Flow control: increment amount of traffic sent; if we are routing
13214 via DV (and thus the ultimate target of the pending message is for
13215 a different virtual link than the one of the queue), then we need
13216 to use up not only the window of the direct link but also the
13217 flow control window for the DV link! */
13219
13220 if (pm->vl != queue->neighbour->vl)
13221 {
13222 /* If the virtual link of the queue differs, this better be distance
13223 vector routing! */
13224 GNUNET_assert (NULL != sc.dvh);
13225 /* If we do distance vector routing, we better not do this for a
13226 message that was itself DV-routed */
13227 GNUNET_assert (PMT_DV_BOX != sc.best->pmt);
13228 /* We use the size of the unboxed message here, to avoid counting
13229 the DV-Box header which is eaten up on the way by intermediaries.
13230 The next hop need not have a link of its own, in which case there is
13231 no window of it to charge. */
13232 if (NULL != queue->neighbour->vl)
13233 queue->neighbour->vl->outbound_fc_window_size_used += sc.best->bytes_msg;
13234 }
13235 else
13236 {
13237 GNUNET_assert (NULL == sc.dvh);
13238 }
13239
13240 queue_send_msg (queue, pm, &pm[1], pm->bytes_msg);
13241
13242 /* The message is with the communicator now, so return the CORE send
13243 window credit for it -- see #credit_client().
13244
13245 It used to be returned here only for an unboxed message or a reliable
13246 communicator, and otherwise not until the *peer* acknowledged the
13247 message below. That makes a window into a delivery confirmation: over
13248 an unreliable communicator every reliability-boxed or fragmented
13249 message holds one of the client's #SEND_WINDOW_SIZE slots for as long
13250 as its ACK takes, and a lost ACK holds it for the whole retransmission
13251 chain. Four of those and CORE cannot send to that peer at all -- not
13252 payload, but also not its HEARTBEATs and not one message of its key
13253 exchange. So the session times out for want of a heartbeat that is
13254 sitting in a queue, and the handshake that would rebuild it cannot go
13255 out either; CORE only recovers when a reconnect resets the window
13256 wholesale. Acknowledgements still drive retransmission below, they
13257 just no longer gate the client. */
13258 credit_client (sc.best);
13259
13260 /* Check if this transmission somehow conclusively finished handing 'pm'
13261 even without any explicit ACKs */
13262 if ((PMT_CORE == pm->pmt) ||
13263 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc))
13264 {
13266 }
13267 else
13268 {
13269 struct GNUNET_TIME_Relative wait_duration;
13270 unsigned int wait_multiplier;
13271
13272 if (PMT_FRAGMENT_BOX == pm->pmt)
13273 {
13274 struct PendingMessage *root;
13275
13276 root = pm->frag_parent;
13277 while (NULL != root->frag_parent && PMT_DV_BOX != root->pmt)
13278 root = root->frag_parent;
13279
13280 if ((0 == root->frag_off) || (0 == root->frag_count))
13281 {
13282 wait_multiplier = 4;
13283 }
13284 else
13285 {
13286 double wm = ceil ((double) root->bytes_msg
13287 / ((double) root->frag_off
13288 / (double) root->frag_count)) * 4.0;
13289
13290 if ((! (wm >= 1.0)) || (wm > 1024.0))
13291 wm = 4.0; /* NaN, infinity or absurd: fall back to the default */
13292 wait_multiplier = (unsigned int) wm;
13293 }
13294 }
13295 else
13296 {
13297 // No fragments, we use 4 RTT before retransmitting.
13298 wait_multiplier = 4;
13299 }
13300
13301 // Depending on how much pending message the VirtualLink is queueing, we wait longer.
13302 // wait_multiplier = wait_multiplier * pm->vl->pending_msg_num;
13303
13305 "Wait multiplier %u\n",
13306 wait_multiplier);
13307
13308 /* Message not finished, waiting for acknowledgement.
13309 Update time by which we might retransmit 's' based on queue
13310 characteristics (i.e. RTT); it takes one RTT for the message to
13311 arrive and the ACK to come back in the best case; but the other
13312 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
13313 retransmitting.
13314
13315 OPTIMIZE: Note that in the future this heuristic should likely
13316 be improved further (measure RTT stability, consider message
13317 urgency and size when delaying ACKs, etc.) */
13318
13319 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us !=
13320 queue->pd.aged_rtt.rel_value_us)
13321 wait_duration = GNUNET_TIME_relative_max (queue->pd.aged_rtt,
13323 else
13324 {
13325 wait_duration = DEFAULT_ACK_WAIT_DURATION;
13326 wait_multiplier = 4;
13327 }
13328 {
13331 wait_duration, wait_multiplier));
13333 wait_duration, wait_multiplier);
13335 "Waiting %s for ACK until %s\n",
13340 GNUNET_TIME_relative_multiply (wait_duration,
13341 wait_multiplier))
13342 );
13343 }
13344 }
13345 /* finally, re-schedule queue transmission task itself */
13347 queue,
13349}
13350
13351
13358static void
13359handle_del_queue_message (void *cls,
13360 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
13361{
13362 struct TransportClient *tc = cls;
13363
13364 if (CT_COMMUNICATOR != tc->type)
13365 {
13366 GNUNET_break (0);
13368 return;
13369 }
13370 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
13371 queue = queue->next_client)
13372 {
13373 struct Neighbour *neighbour = queue->neighbour;
13374
13375 if ((ntohl (dqm->qid) != queue->qid) ||
13376 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
13377 continue;
13379 "Dropped queue %s to peer %s\n",
13380 queue->address,
13381 GNUNET_i2s (&neighbour->pid));
13382 free_queue (queue);
13384 return;
13385 }
13386 /* Not finding the queue is a race, not a protocol violation: we may have
13387 freed it ourselves already, or the communicator may be tearing down a
13388 queue we never fully learned about. Do NOT drop the client over it --
13389 that runs #client_disconnect_cb(), which frees *every* queue this
13390 communicator owns, so one stale QUEUE_TEARDOWN would disconnect us from
13391 every peer it serves at once. Compare #handle_send_message_ack(), which
13392 tolerates the same lookup miss. */
13394 "QUEUE_TEARDOWN for unknown queue QID %u to peer %s ignored\n",
13395 ntohl (dqm->qid),
13396 GNUNET_i2s (&dqm->receiver));
13398 "# QUEUE_TEARDOWN dropped: queue unknown",
13399 1,
13400 GNUNET_NO);
13402}
13403
13404
13405static void
13407 struct TransportClient *tc)
13408{
13409 struct PendingMessage *pm;
13410
13411 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
13412 qe->queue->queue_tail,
13413 qe);
13414 qe->queue->queue_length--;
13415 tc->details.communicator.total_queue_length--;
13417 "Received ACK on queue %s (QID %u) to peer %s (new length: %u/%u)\n",
13418 qe->queue->address,
13419 qe->queue->qid,
13420 GNUNET_i2s (&qe->queue->neighbour->pid),
13421 qe->queue->queue_length,
13422 tc->details.communicator.total_queue_length);
13423
13424 /* if applicable, resume transmissions that waited on ACK */
13426 tc->details.communicator.total_queue_length)
13427 {
13428 /* Communicator dropped below threshold, resume all queues
13429 incident with this client! */
13431 GST_stats,
13432 "# Transmission throttled due to communicator queue limit",
13433 -1,
13434 GNUNET_NO);
13435 for (struct Queue *queue = tc->details.communicator.queue_head;
13436 NULL != queue;
13437 queue = queue->next_client)
13438 {
13440 queue,
13442 }
13443 }
13444 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
13445 {
13446 /* queue dropped below threshold; only resume this one queue */
13448 "# Transmission throttled due to queue queue limit",
13449 -1,
13450 GNUNET_NO);
13452 qe->queue,
13454 }
13455 else if (1 == qe->queue->q_capacity)
13456 {
13457 // TODO I guess this will never happen, because the communicator triggers this by updating its queue length itself.
13459 "Transmission rescheduled due to communicator message queue with qid %u has capacity %"
13460 PRIu64 ".\n",
13461 qe->queue->qid,
13462 qe->queue->q_capacity);
13463 /* message queue has capacity; only resume this one queue */
13464 /* queue dropped below threshold; only resume this one queue */
13466 "# Transmission throttled due to message queue capacity",
13467 -1,
13468 GNUNET_NO);
13470 qe->queue,
13472 }
13473
13474 if (NULL != (pm = qe->pm))
13475 {
13476 struct VirtualLink *vl;
13477
13478 // GNUNET_assert (qe == pm->qe);
13479 pm->qe = NULL;
13480 /* If waiting for this communicator may have blocked transmission
13481 of pm on other queues for this neighbour, force schedule
13482 transmit on queue for queues of the neighbour */
13483 if (NULL == pm->frag_parent)
13484 {
13485 vl = pm->vl;
13486 if ((NULL != vl) &&
13487 (NULL != vl->pending_msg_head) &&
13488 (vl->pending_msg_head == pm))
13490 }
13491 }
13492 GNUNET_free (qe);
13493}
13494
13495
13502static void
13503handle_send_message_ack (void *cls,
13504 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
13505{
13506 struct TransportClient *tc = cls;
13507 struct QueueEntry *qe;
13508 struct Queue *failed_queue = NULL;
13509
13510 if (CT_COMMUNICATOR != tc->type)
13511 {
13512 GNUNET_break (0);
13514 return;
13515 }
13516
13517 /* find our queue entry matching the ACK */
13518 qe = NULL;
13520 "Looking for queue for PID %s\n",
13521 GNUNET_i2s (&sma->receiver));
13522 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
13523 queue = queue->next_client)
13524 {
13525 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
13526 continue;
13528 "Found PID %s\n",
13529 GNUNET_i2s (&queue->neighbour->pid));
13530
13531
13532 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
13533 qep = qep->next)
13534 {
13535 if (qep->mid != GNUNET_ntohll (sma->mid) || queue->qid != ntohl (
13536 sma->qid))
13537 continue;
13539 "QueueEntry MID: %" PRIu64 " on queue QID: %u, Ack MID: %"
13540 PRIu64 " Ack QID %u\n",
13541 qep->mid,
13542 queue->qid,
13543 GNUNET_ntohll (sma->mid),
13544 ntohl (sma->qid));
13545 qe = qep;
13546 if ((NULL != qe->pm) && (qe->pm->qe != qe))
13548 "For pending message %" PRIu64 " we had retransmissions.\n",
13549 qe->pm->logging_uuid);
13550 break;
13551 }
13552 }
13553 if (GNUNET_OK != (int) ntohl (sma->status))
13554 {
13555 /* The communicator could not hand the message to the peer. The only
13556 thing that produces this today is #handle_send_msg()'s "queue no
13557 longer exists" branch in `transport_api_communication.c', i.e. the
13558 communicator has already torn the queue down on its side and the
13559 QUEUE_TEARDOWN is merely still in flight (or was lost).
13560
13561 Ignoring the status, as we used to, makes this self-sustaining:
13562 #free_queue_entry() releases the pending message and immediately
13563 reschedules transmission, #transmit_on_queue() picks the very same
13564 queue again -- transport still has it -- and we get another failure.
13565 Every round adds an envelope to the client MQ that is already
13566 congested, which is what shows up at the other end as
13567
13568 communicator INFO Transmission failed, queue no longer exists.
13569
13570 repeating at scheduler speed, and (because the service is busy
13571 servicing that loop) as
13572
13573 communicator WARNING Dropping message: transport is too slow,
13574 queue length N exceeded
13575
13576 on every *other* communicator. Treat the failure as the queue
13577 teardown it is and stop selecting this queue. */
13579 "Communicator could not send MID %" PRIu64
13580 " on QID %u to %s; dropping that queue\n",
13581 GNUNET_ntohll (sma->mid),
13582 ntohl (sma->qid),
13583 GNUNET_i2s (&sma->receiver));
13585 "# queues dropped (communicator send failed)",
13586 1,
13587 GNUNET_NO);
13588 if (NULL != qe)
13589 failed_queue = qe->queue;
13590 else
13591 for (struct Queue *queue = tc->details.communicator.queue_head;
13592 NULL != queue;
13593 queue = queue->next_client)
13594 if ((ntohl (sma->qid) == queue->qid) &&
13595 (0 == GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver)))
13596 {
13597 failed_queue = queue;
13598 break;
13599 }
13600 if (NULL != failed_queue)
13601 {
13602 /* #free_queue() releases every `struct QueueEntry' still on it --
13603 including @a qe -- and detaches their pending messages, so they are
13604 retried on whatever other queue this neighbour has. */
13605 free_queue (failed_queue);
13607 return;
13608 }
13609 }
13610 if (NULL == qe)
13611 {
13613 "No QueueEntry found for Ack MID %" PRIu64 " QID: %u\n",
13614 GNUNET_ntohll (sma->mid),
13615 ntohl (sma->qid));
13616 // TODO I guess this can happen, if the Ack from the peer comes before the Ack from the queue.
13617 // Update: Maybe QueueEntry was accidentally freed during freeing PendingMessage.
13618 /* this should never happen */
13619 // GNUNET_break (0);
13620 // GNUNET_SERVICE_client_drop (tc->client);
13622 return;
13623 }
13626}
13627
13628
13634static void
13635handle_burst_finished (void *cls,
13636 const struct GNUNET_TRANSPORT_BurstFinished *bf)
13637{
13638 struct TransportClient *tc = cls;
13639
13640 (void) bf;
13643}
13644
13645
13655static int
13656notify_client_queues (void *cls,
13657 const struct GNUNET_PeerIdentity *pid,
13658 void *value)
13659{
13660 struct TransportClient *tc = cls;
13661 struct Neighbour *neighbour = value;
13662
13663 GNUNET_assert (CT_MONITOR == tc->type);
13664 for (struct Queue *q = neighbour->queue_head; NULL != q;
13665 q = q->next_neighbour)
13666 {
13667 struct MonitorEvent me = { .rtt = q->pd.aged_rtt,
13668 .cs = q->cs,
13669 .num_msg_pending = q->num_msg_pending,
13670 .num_bytes_pending = q->num_bytes_pending };
13671
13672 notify_monitor (tc, pid, q->address, q->nt, &me);
13673 }
13674 return GNUNET_OK;
13675}
13676
13677
13684static void
13685handle_monitor_start (void *cls,
13687{
13688 struct TransportClient *tc = cls;
13689
13690 if (CT_NONE != tc->type)
13691 {
13692 GNUNET_break (0);
13694 return;
13695 }
13696 tc->type = CT_MONITOR;
13697 tc->details.monitor.peer = start->peer;
13698 tc->details.monitor.one_shot = ntohl (start->one_shot);
13702}
13703
13704
13708struct LinkListContext
13709{
13713 struct TransportClient *tc;
13714
13719};
13720
13721
13730static char *
13731communicator_list (struct Neighbour *n,
13732 unsigned int *num_queues)
13733{
13734 char *ret = GNUNET_strdup ("");
13735
13736 *num_queues = 0;
13737 if (NULL == n)
13738 return ret;
13739 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
13740 {
13741 const char *prefix = q->tc->details.communicator.address_prefix;
13742 size_t plen = strlen (prefix);
13743 const char *pos;
13744 char *tmp;
13745
13746 (*num_queues)++;
13747 if (0 == plen)
13748 continue;
13749 /* Several queues to one neighbour routinely share a communicator;
13750 name each one once. */
13751 for (pos = strstr (ret, prefix);
13752 NULL != pos;
13753 pos = strstr (pos + 1, prefix))
13754 if (((pos == ret) || (',' == pos[-1])) &&
13755 (('\0' == pos[plen]) || (',' == pos[plen])))
13756 break;
13757 if (NULL != pos)
13758 continue;
13759 GNUNET_asprintf (&tmp, "%s%s%s", ret, ('\0' == ret[0]) ? "" : ",", prefix);
13760 GNUNET_free (ret);
13761 ret = tmp;
13762 }
13763 return ret;
13764}
13765
13766
13775static enum GNUNET_GenericReturnValue
13776report_link (void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
13777{
13778 struct LinkListContext *llc = cls;
13779 struct VirtualLink *vl = value;
13781 struct GNUNET_MQ_Envelope *env;
13782 unsigned int pending = 0;
13783 unsigned int num_queues = 0;
13784 unsigned int distance = 0;
13785 struct Neighbour *hop;
13786 char *ccs;
13787 size_t clen;
13788
13789 if ((GNUNET_YES != llc->include_unconfirmed) &&
13790 (GNUNET_YES != vl->confirmed))
13791 return GNUNET_OK;
13792 for (struct PendingMessage *pm = vl->pending_msg_head;
13793 NULL != pm;
13794 pm = pm->next_vl)
13795 pending++;
13796 if (NULL != vl->n)
13797 {
13798 hop = vl->n;
13799 }
13800 else
13801 {
13802 /* Report the best (shortest) of the paths we currently know, and the
13803 communicators that carry its first hop. */
13804 struct DistanceVectorHop *best = NULL;
13805
13806 distance = UINT_MAX;
13807 if (NULL != vl->dv)
13808 for (struct DistanceVectorHop *pos = vl->dv->dv_head;
13809 NULL != pos;
13810 pos = pos->next_dv)
13811 if (pos->distance < distance)
13812 {
13813 distance = pos->distance;
13814 best = pos;
13815 }
13816 if (NULL == best)
13817 distance = 0; /* no paths left; report the link as adjacent */
13818 hop = (NULL != best) ? best->next_hop : NULL;
13819 }
13820 ccs = communicator_list (hop, &num_queues);
13821 clen = strlen (ccs) + 1;
13822 env = GNUNET_MQ_msg_extra (resp,
13823 clen,
13825 memcpy (&resp[1], ccs, clen);
13826 GNUNET_free (ccs);
13827 resp->target = *pid;
13828 resp->confirmed = htonl ((uint32_t) vl->confirmed);
13829 resp->route = htonl ((uint32_t) ((NULL != vl->n)
13832 resp->distance = htonl ((uint32_t) distance);
13833 resp->num_queues = htonl ((uint32_t) num_queues);
13834 resp->core_recv_window = htonl ((int32_t) vl->core_recv_window);
13835 resp->stalled = htonl ((uint32_t) vl->cmc_count);
13836 resp->pending = htonl (pending);
13837 resp->fc_retransmit_count = htonl ((uint32_t) vl->fc_retransmit_count);
13856 GNUNET_MQ_send (llc->tc->mq, env);
13857 return GNUNET_OK;
13858}
13859
13860
13869static void
13871 void *cls,
13873{
13874 struct TransportClient *tc = cls;
13875 struct LinkListContext llc = {
13876 .tc = tc,
13877 .include_unconfirmed = (int) ntohl (lr->include_unconfirmed)
13878 };
13879 struct GNUNET_MQ_Envelope *env;
13880 struct GNUNET_MessageHeader *end;
13881
13882 if (CT_NONE != tc->type)
13883 {
13884 GNUNET_break (0);
13886 return;
13887 }
13888 if (GNUNET_YES == GNUNET_is_zero (&lr->peer))
13889 {
13891 }
13892 else
13893 {
13894 struct VirtualLink *vl = lookup_virtual_link (&lr->peer);
13895
13896 if (NULL != vl)
13897 report_link (&llc, &lr->peer, vl);
13898 }
13901 GNUNET_MQ_send (tc->mq, env);
13903}
13904
13905
13913static struct TransportClient *
13914lookup_communicator (const char *prefix)
13915{
13916 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
13917 {
13918 if (CT_COMMUNICATOR != tc->type)
13919 continue;
13920 if (NULL == tc->details.communicator.address_prefix)
13921 continue; /* receive-only communicator */
13922 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
13923 return tc;
13924 }
13925 GNUNET_log (
13927 "Someone suggested use of communicator for `%s', but we do not have such a communicator!\n",
13928 prefix);
13929 return NULL;
13930}
13931
13932
13940static void
13941suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address)
13942{
13943 static uint32_t idgen = 0;
13944 struct TransportClient *tc;
13945 char *prefix;
13946 struct GNUNET_TRANSPORT_CreateQueue *cqm;
13947 struct GNUNET_MQ_Envelope *env;
13948 size_t alen;
13949
13951 if (NULL == prefix)
13952 {
13953 GNUNET_break (0); /* We got an invalid address!? */
13954 return;
13955 }
13957 if (NULL == tc)
13958 {
13960 "# Suggestions ignored due to missing communicator",
13961 1,
13962 GNUNET_NO);
13964 "Cannot connect to %s at `%s', no matching communicator present\n",
13965 GNUNET_i2s (pid),
13966 address);
13968 return;
13969 }
13970 /* forward suggestion for queue creation to communicator */
13972 "Request #%u for `%s' communicator to create queue to `%s' at `%s'\n",
13973 (unsigned int) idgen,
13974 prefix,
13975 GNUNET_i2s (pid),
13976 address);
13978 alen = strlen (address) + 1;
13979 env =
13981 cqm->request_id = htonl (idgen++);
13982 cqm->receiver = *pid;
13983 memcpy (&cqm[1], address, alen);
13984 GNUNET_MQ_send (tc->mq, env);
13985}
13986
13987
13995static void
13997{
13999 struct GNUNET_TIME_Absolute monotonic_time;
14000
14001 if (NULL != vs->revalidation_task)
14002 {
14003 GNUNET_SCHEDULER_cancel (vs->revalidation_task);
14004 vs->revalidation_task = NULL;
14005 }
14006 /*memcpy (&hkey,
14007 &hc,
14008 sizeof (hkey));*/
14010 "Remove key %s for address %s map size %u contains %u\n",
14011 GNUNET_h2s (&vs->hc),
14012 vs->address,
14015 &vs->hc));
14017
14019 if (GNUNET_TIME_UNIT_ZERO_ABS.abs_value_us ==
14020 vs->last_challenge_use.abs_value_us)
14021 {
14022 vs->first_challenge_use = monotonic_time;
14023 }
14024 vs->last_challenge_use = monotonic_time;
14025 tvc.header.type =
14027 tvc.header.size = htons (sizeof(tvc));
14028 tvc.reserved = htonl (0);
14029 tvc.challenge = vs->challenge;
14030 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
14032 "Sending address validation challenge %s to %s\n",
14034 GNUNET_i2s (&q->neighbour->pid));
14035 queue_send_msg (q, NULL, &tvc, sizeof(tvc));
14036}
14037
14038
14050static struct GNUNET_TIME_Relative
14052{
14053 const struct VirtualLink *vl = lookup_virtual_link (pid);
14054
14055 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
14056 return MAX_VALIDATION_CHALLENGE_FREQ; /* we have what we want */
14057 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
14058 {
14059 if (CT_APPLICATION != tc->type)
14060 continue;
14062 tc->details.application.requests,
14063 pid))
14065 }
14067}
14068
14069
14075static void
14076validation_start_cb (void *cls)
14077{
14078 struct ValidationState *vs;
14079 struct Queue *q;
14081 GST_cfg);
14082
14083 (void) cls;
14084 validation_task = NULL;
14086 /* drop validations past their expiration */
14087 while (
14088 (NULL != vs) &&
14090 {
14092 "Validation response %s cleaned up\n",
14093 GNUNET_sh2s (&vs->challenge.value));
14096 }
14097 if (NULL == vs)
14098 {
14100 "Address validation task not scheduled anymore, nothing to do\n");
14101 return; /* woopsie, no more addresses known, should only
14102 happen if we're really a lonely peer */
14103 }
14104 q = find_queue (&vs->pid, vs->address);
14105 if (GNUNET_TIME_absolute_cmp (vs->first_challenge_use, >, now))
14106 {
14108 "To early to start next address validation for challenge %s\n",
14109 GNUNET_sh2s (&vs->challenge.value));
14110 /* Do NOT just return: @e validation_task was set to NULL above and
14111 nothing re-arms it by itself. #update_next_challenge_time() only
14112 schedules us again when it is called with a *changed* time for some
14113 validation state, so bailing out here leaves a non-empty
14114 #validation_heap with no task attached: address (re)validation and
14115 the #suggest_to_connect() retries that go with it stop for *every*
14116 peer until some unrelated event happens to come along. A peer that
14117 just lost its only connection has no such events left. */
14120 now,
14121 vs->first_challenge_use),
14123 NULL);
14124 return;
14125 }
14126 if (NULL == q)
14127 {
14128 vs->awaiting_queue = GNUNET_YES;
14129 suggest_to_connect (&vs->pid, vs->address);
14130 }
14131 else
14133 /* Finally, reschedule next attempt */
14134 vs->challenge_backoff =
14135 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
14138 "Address validation task will run again in %s\n",
14139 GNUNET_STRINGS_relative_time_to_string (vs->challenge_backoff,
14140 GNUNET_YES));
14143 vs->challenge_backoff));
14144}
14145
14146
14151{
14155 struct Queue *q;
14156
14160 unsigned int quality_count;
14161
14165 unsigned int num_queues;
14166
14171 unsigned int k;
14172};
14173
14174
14186static int
14187check_connection_quality (void *cls,
14188 const struct GNUNET_PeerIdentity *pid,
14189 void *value)
14190{
14191 struct QueueQualityContext *ctx = cls;
14192 struct Neighbour *n = value;
14193 int do_inc;
14194
14195 (void) pid;
14196 do_inc = GNUNET_NO;
14197 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
14198 {
14199 ctx->num_queues++;
14200 if (0 == ctx->k--)
14201 ctx->q = q;
14202 /* FIXME-CONQ-STATISTICS: in the future, add reliability / goodput
14203 statistics and consider those as well here? */
14204 if (q->pd.aged_rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
14205 do_inc = GNUNET_YES;
14206 }
14207 if (GNUNET_YES == do_inc)
14208 ctx->quality_count++;
14209 return GNUNET_OK;
14210}
14211
14212
14224static void
14225start_dv_learn (void *cls);
14226
14227
14235static void
14237 struct LearnLaunchEntry *lle,
14238 struct QueueQualityContext qqc)
14239{
14240 if (0 == qqc.num_queues)
14241 {
14243 "# DV learn aborted: no queue left",
14244 1,
14245 GNUNET_NO);
14246 return;
14247 }
14248 qqc.quality_count = 0;
14250 qqc.num_queues = 0;
14251 qqc.q = NULL;
14254 &qqc);
14255 if (NULL == qqc.q)
14256 {
14258 "# DV learn aborted: no queue left",
14259 1,
14260 GNUNET_NO);
14261 return;
14262 }
14263
14264 /* Do this as close to transmission time as possible! */
14266
14267 queue_send_msg (qqc.q, NULL, &dvl, sizeof(dvl));
14268 /* reschedule this job, randomizing the time it runs (but no
14269 actual backoff!) */
14270 if (NULL != dvlearn_task)
14275 NULL);
14276}
14277
14278
14290static void
14291start_dv_learn (void *cls)
14292{
14293 struct LearnLaunchEntry *lle;
14294 struct QueueQualityContext qqc;
14295 struct TransportDVLearnMessage dvl;
14296 const struct GNUNET_PeerIdentity *my_identity;
14297
14298 (void) cls;
14299 dvlearn_task = NULL;
14300 if ((GNUNET_YES == in_shutdown) || (NULL == pils))
14301 return;
14303 return; /* lost all connectivity, cannot do learning */
14305 if (NULL == my_identity)
14306 {
14307 /* PILS has not handed us an identity yet. The first queue arriving
14308 schedules us with add_now(), which routinely wins that race; retry
14309 instead of taking the service down. */
14313 NULL);
14314 return;
14315 }
14317 qqc.quality_count = 0;
14318 qqc.num_queues = 0;
14322 &qqc);
14324 {
14325 struct GNUNET_TIME_Relative delay;
14326 unsigned int factor;
14327
14328 /* scale our retries by how far we are above the threshold */
14332 "At connection quality %u, will launch DV learn in %s\n",
14333 qqc.quality_count,
14336 return;
14337 }
14338 /* remove old entries in #dvlearn_map if it has grown too big */
14339 while (MAX_DV_LEARN_PENDING <=
14341 {
14342 lle = lle_tail;
14345 &lle->challenge.value,
14346 lle));
14348 GNUNET_free (lle);
14349 }
14350 /* setup data structure for learning */
14351 lle = GNUNET_new (struct LearnLaunchEntry);
14353 sizeof(lle->challenge));
14355 "Starting launch DV learn with challenge %s\n",
14356 GNUNET_sh2s (&lle->challenge.value));
14361 &lle->challenge.value,
14362 lle,
14365 dvl.header.size = htons (sizeof(dvl));
14366 dvl.num_hops = htons (0);
14367 dvl.bidirectional = htons (0);
14369 dvl.monotonic_time =
14371 // We will set the below again later
14372 memset (&dvl.init_sig, 0, sizeof dvl.init_sig);
14373 dvl.challenge = lle->challenge;
14374 dvl.initiator = *my_identity;
14375 {
14376 struct DvInitPS dvip = {
14377 .purpose.purpose = htonl (
14379 .purpose.size = htonl (sizeof(dvip)),
14380 .monotonic_time = dvl.monotonic_time,
14381 .challenge = lle->challenge
14382 };
14383
14384 if (GNUNET_OK != sign_by_my_identity (&dvip.purpose, &dvl.init_sig))
14385 return;
14386 }
14387 transmit_dv_init (dvl, lle, qqc);
14388}
14389
14390
14400static char *
14402{
14403 const char *dash;
14404 const char *colon;
14405
14406 if (NULL == address)
14407 return NULL;
14408 dash = strchr (address, '-');
14409 if (NULL == dash)
14410 return NULL;
14411 colon = strchr (dash, ':');
14412 if (NULL == colon)
14413 return NULL;
14414 return GNUNET_strndup (dash + 1,
14415 colon - (dash + 1));
14416}
14417
14418
14428static int
14430 const struct GNUNET_PeerIdentity *pid,
14431 void *value)
14432{
14433 struct Queue *q = cls;
14434 struct ValidationState *vs = value;
14435 char *address_without_port_vs;
14436 char *address_without_port_q;
14437 char *prefix_vs;
14438 char *prefix_q;
14439 int success = GNUNET_YES;
14440
14441 // TODO Check if this is really necessary.
14442 address_without_port_vs = get_address_without_port (vs->address);
14443 address_without_port_q = get_address_without_port (q->address);
14444 prefix_vs = GNUNET_HELLO_address_to_prefix (vs->address);
14445 prefix_q = GNUNET_HELLO_address_to_prefix (q->address);
14446
14448 "Check validation request pending for `%s' at `%s'/`%s' (vs)/(q)\n",
14449 GNUNET_i2s (pid),
14450 (NULL == address_without_port_vs) ? "<unparsable>"
14451 : address_without_port_vs,
14452 (NULL == address_without_port_q) ? "<unparsable>"
14453 : address_without_port_q);
14454 (void) pid;
14455 /* Only the port may differ: the address we asked to connect to is
14456 `PROTO-IP:0' for a NATed peer, while the queue that then materializes
14457 sits at `PROTO-IP:port'. The communicator must match all the same --
14458 a challenge for a `tcp-' address is not answered by a `udp-' queue. */
14459 if ((GNUNET_YES == vs->awaiting_queue) &&
14460 (NULL != address_without_port_vs) &&
14461 (NULL != address_without_port_q) &&
14462 (NULL != prefix_vs) &&
14463 (NULL != prefix_q) &&
14464 (0 == strcmp (prefix_vs, prefix_q)) &&
14465 (0 == strcmp (address_without_port_vs, address_without_port_q)))
14466 {
14467
14468 vs->awaiting_queue = GNUNET_NO;
14470 success = GNUNET_NO;
14471 }
14472
14473 GNUNET_free (address_without_port_vs);
14474 GNUNET_free (address_without_port_q);
14475 GNUNET_free (prefix_vs);
14476 GNUNET_free (prefix_q);
14477 return success;
14478}
14479
14480
14489static void
14490neighbour_dv_monotime_cb (void *cls,
14491 const struct GNUNET_PEERSTORE_Record *record,
14492 const char *emsg)
14493{
14494 struct Neighbour *n = cls;
14495 struct GNUNET_TIME_AbsoluteNBO *mtbe;
14496
14497 (void) emsg;
14498 if (NULL == record)
14499 {
14500 /* we're done with #neighbour_dv_monotime_cb() invocations,
14501 continue normal processing */
14502 n->get = NULL;
14504 return;
14505 }
14506 if (0 == record->value_size)
14507 {
14509 GNUNET_break (0);
14510 return;
14511 }
14512 mtbe = record->value;
14517}
14518
14519
14520static void
14522 const struct GNUNET_PeerIdentity *pid,
14523 const char *uri)
14524{
14525 struct Queue *queue = cls;
14526 struct sockaddr_in v4;
14527 const char *slash;
14528 char *address_uri;
14529 char *prefix;
14530 char *uri_without_port;
14531 char *address_uri_without_port;
14532
14533 slash = strrchr (uri, '/');
14534 if ((NULL == slash) || (slash - uri < 2))
14535 {
14536 GNUNET_break_op (0); /* @a uri comes from a remote HELLO */
14537 return;
14538 }
14539 prefix = GNUNET_strndup (uri, (slash - uri) - 2);
14540 slash++;
14541 GNUNET_asprintf (&address_uri,
14542 "%s-%s",
14543 prefix,
14544 slash);
14545
14547 "1 not global natted_address %u %s %s %s\n",
14548 queue->is_global_natted,
14549 uri,
14550 queue->address,
14551 slash);
14552
14553 uri_without_port = get_address_without_port (address_uri);
14554 if ((NULL == uri_without_port) ||
14555 (1 != inet_pton (AF_INET, uri_without_port, &v4.sin_addr)))
14556 {
14558 GNUNET_free (address_uri);
14559 GNUNET_free (uri_without_port);
14560 return;
14561 }
14562
14564 "2 not global natted_address %u %s %s\n",
14565 queue->is_global_natted,
14566 uri,
14567 queue->address);
14568
14569 if (GNUNET_NO == queue->is_global_natted)
14570 {
14572 GNUNET_free (address_uri);
14573 GNUNET_free (uri_without_port);
14574 return;
14575 }
14576
14578 "3 not global natted_address %u %s %s\n",
14579 queue->is_global_natted,
14580 uri,
14581 queue->address);
14582
14583 if (0 == strcmp (uri_without_port, address_uri))
14584 {
14586 GNUNET_free (address_uri);
14587 GNUNET_free (uri_without_port);
14588 return;
14589 }
14590
14592 "4 not global natted_address %u %s %s\n",
14593 queue->is_global_natted,
14594 uri,
14595 queue->address);
14596
14597 address_uri_without_port = get_address_without_port (queue->address);
14598 if ((NULL != address_uri_without_port) &&
14599 (0 == strcmp (uri_without_port, address_uri_without_port)))
14600 {
14601 queue->is_global_natted = GNUNET_NO;
14602 }
14603
14605 "not global natted_address %u %s %s %s %s %s %u\n",
14606 queue->is_global_natted,
14607 uri,
14608 queue->address,
14609 uri_without_port,
14610 address_uri_without_port,
14611 prefix,
14612 GNUNET_NO);
14614 GNUNET_free (address_uri);
14615 GNUNET_free (address_uri_without_port);
14616 GNUNET_free (uri_without_port);
14617}
14618
14619
14621{
14625 char *addr;
14626
14631};
14632
14633
14634static enum GNUNET_GenericReturnValue
14635contains_address (void *cls,
14636 const struct GNUNET_PeerIdentity *pid,
14637 void *value)
14638{
14639 struct TransportGlobalNattedAddressClosure *tgna_cls = cls;
14640 struct TransportGlobalNattedAddress *tgna = value;
14641 char *addr = (char *) &tgna[1];
14642
14643 /* NOTE: @a addr is NOT 0-terminated. */
14645 "Checking tgna %p with addr %.*s and length %u compare length %lu\n",
14646 tgna,
14647 (int) ntohl (tgna->address_length),
14648 addr,
14649 ntohl (tgna->address_length),
14650 strlen (tgna_cls->addr));
14651 if (strlen (tgna_cls->addr) == ntohl (tgna->address_length)
14652 && 0 == strncmp (addr, tgna_cls->addr, ntohl (tgna->address_length)))
14653 {
14654 tgna_cls->tgna = tgna;
14655 return GNUNET_NO;
14656 }
14657 return GNUNET_YES;
14658}
14659
14660
14661static void
14663{
14665 "Error in PEERSTORE monitoring for checking global natted\n");
14666}
14667
14668
14669static void
14671{
14673 "Done with initial PEERSTORE iteration during monitoring for checking global natted\n");
14674}
14675
14676
14677static void
14678check_for_global_natted (void *cls,
14679 const struct GNUNET_PEERSTORE_Record *record,
14680 const char *emsg)
14681{
14682 struct Queue *queue = cls;
14683 struct Neighbour *neighbour = queue->neighbour;
14685 const struct GNUNET_MessageHeader *hello;
14687 size_t address_len_without_port;
14688
14689 if (NULL != emsg)
14690 {
14692 "Got failure from PEERSTORE: %s\n",
14693 emsg);
14695 return;
14696 }
14697 if (NULL == record)
14698 {
14699 GNUNET_break (0);
14701 return;
14702 }
14703 /* @a hello was published by a remote peer and may be malformed. */
14704 hello = hello_from_record (record);
14705 if (NULL == hello)
14706 {
14708 return;
14709 }
14710 queue->is_global_natted = GNUNET_YES;
14711 parser = GNUNET_HELLO_parser_from_msg (hello, &record->peer);
14712 if (NULL == parser)
14713 {
14715 "HELLO cannot be parsed!\n");
14717 return;
14718 }
14720 "before not global natted %u\n",
14721 queue->is_global_natted);
14724 queue);
14726 "after not global natted %u\n",
14727 queue->is_global_natted);
14728 GNUNET_HELLO_parser_free (parser);
14729
14730 tgna_cls.addr = get_address_without_port (queue->address);
14731 if (NULL == tgna_cls.addr)
14732 {
14733 GNUNET_break (0);
14735 return;
14736 }
14737 address_len_without_port = strlen (tgna_cls.addr);
14738 /*{
14739 char buf[address_len_without_port + 1];
14740
14741 GNUNET_memcpy (&buf, addr, address_len_without_port);
14742 buf[address_len_without_port] = '\0';
14743 GNUNET_free (addr);
14744 GNUNET_memcpy (tgna_cls.addr, buf, address_len_without_port + 1);
14745 }*/
14746 tgna_cls.tgna = NULL;
14748 &neighbour->pid,
14750 &tgna_cls);
14751 if (NULL != tgna_cls.tgna)
14753 " tgna_cls.tgna tgna %p %lu %u %u\n",
14754 tgna_cls.tgna,
14755 neighbour->size_of_global_addresses,
14756 ntohl (tgna_cls.tgna->address_length),
14757 neighbour->number_of_addresses);
14758 if (NULL == tgna_cls.tgna && GNUNET_YES == queue->is_global_natted)
14759 {
14760 struct TransportGlobalNattedAddress *tgna;
14761
14762 tgna = GNUNET_malloc (sizeof (struct TransportGlobalNattedAddress)
14763 + address_len_without_port);
14764 tgna->address_length = htonl (address_len_without_port);
14765 GNUNET_memcpy (&tgna[1], tgna_cls.addr, address_len_without_port);
14767 &neighbour->pid,
14768 tgna,
14770 neighbour->number_of_addresses++;
14771 /* MUST match what is subtracted on removal (and what
14772 #add_global_addresses() actually copies), or the accounting drifts. */
14773 neighbour->size_of_global_addresses += address_len_without_port;
14775 "Created tgna %p with address %s and length %lu\n",
14776 tgna,
14777 tgna_cls.addr,
14778 address_len_without_port + 1);
14779 }
14780 else if (NULL != tgna_cls.tgna && GNUNET_NO == queue->is_global_natted)
14781 {
14783 &neighbour->pid,
14784 tgna_cls.tgna);
14785 GNUNET_assert (neighbour->size_of_global_addresses >= ntohl (tgna_cls.tgna->
14787 );
14788 neighbour->size_of_global_addresses -= ntohl (tgna_cls.tgna->address_length)
14789 ;
14790 GNUNET_assert (0 < neighbour->number_of_addresses);
14791 neighbour->number_of_addresses--;
14793 "removed tgna %p\n",
14794 tgna_cls.tgna);
14795 GNUNET_free (tgna_cls.tgna);
14796 }
14798 GNUNET_free (tgna_cls.addr);
14799}
14800
14801
14808static void
14809handle_add_queue_message (void *cls,
14810 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
14811{
14812 struct TransportClient *tc = cls;
14813 struct Queue *queue;
14814 struct Neighbour *neighbour;
14815 const char *addr;
14816 uint16_t addr_len;
14817
14818 if (ntohl (aqm->mtu) <= sizeof(struct TransportFragmentBoxMessage))
14819 {
14820 /* MTU so small as to be useless for transmissions,
14821 required for #fragment_message()! */
14822 GNUNET_break_op (0);
14824 return;
14825 }
14826 /* This may simply be a queue update. Match on the peer as well as the
14827 QID: the communicator's key for a queue is the pair, and
14828 #handle_send_msg() on its side looks both of them up. Matching on the
14829 QID alone let an ADD_QUEUE for a *different* peer be folded into an
14830 existing queue, leaving @e neighbour pointing at the old peer -- after
14831 which every SEND_MSG we put on it carries a receiver the communicator
14832 cannot match, and comes straight back as "queue no longer exists". */
14833 for (queue = tc->details.communicator.queue_head;
14834 NULL != queue;
14835 queue = queue->next_client)
14836 {
14837 if (queue->qid != ntohl (aqm->qid))
14838 continue;
14839 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &aqm->receiver))
14840 continue;
14841 break;
14842 }
14843
14844 if (NULL != queue)
14845 {
14846 neighbour = queue->neighbour;
14847 }
14848 else
14849 {
14850 struct GNUNET_TIME_Absolute validated_until = GNUNET_TIME_UNIT_ZERO_ABS;
14851
14852 neighbour = lookup_neighbour (&aqm->receiver);
14853 if (NULL == neighbour)
14854 {
14855 neighbour = GNUNET_new (struct Neighbour);
14857 GNUNET_YES);
14858 neighbour->pid = aqm->receiver;
14859 /* Give a fresh neighbour a full window to say something. */
14860 neighbour->last_inbound = GNUNET_TIME_absolute_get ();
14863 neighbours,
14864 &neighbour->pid,
14865 neighbour,
14867 neighbour->get =
14869 "transport",
14870 &neighbour->pid,
14873 neighbour);
14874 }
14875 addr_len = ntohs (aqm->header.size) - sizeof(*aqm);
14876 addr = (const char *) &aqm[1];
14878 "New queue %s to %s available with QID %u and q_len %" PRIu64
14879 " and mtu %u\n",
14880 addr,
14881 GNUNET_i2s (&aqm->receiver),
14882 ntohl (aqm->qid),
14883 GNUNET_ntohll (aqm->q_len),
14884 ntohl (aqm->mtu));
14885 queue = GNUNET_malloc (sizeof(struct Queue) + addr_len);
14886 queue->tc = tc;
14887 for (struct Queue *q = neighbour->queue_head; NULL != q; q = q->
14888 next_neighbour)
14889 validated_until = GNUNET_TIME_absolute_max (validated_until, q->
14890 validated_until);
14891 /* Inherit the validity of the sibling queues, but only while it is
14892 still in the future -- copying an already expired timestamp is
14893 pointless (and the condition used to be inverted). */
14894 if (0 != GNUNET_TIME_absolute_get_remaining (validated_until).rel_value_us)
14895 {
14897 "New queue with QID %u inherit validated until\n",
14898 ntohl (aqm->qid));
14899 queue->validated_until = validated_until;
14900 }
14901 queue->address = (const char *) &queue[1];
14902 queue->pd.aged_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
14903 queue->qid = ntohl (aqm->qid);
14904 queue->neighbour = neighbour;
14906 queue->unlimited_length = GNUNET_YES;
14907 queue->q_capacity = GNUNET_ntohll (aqm->q_len);
14908 memcpy (&queue[1], addr, addr_len);
14909 /* notify monitors about new queue */
14910 {
14911 struct MonitorEvent me = { .rtt = queue->pd.aged_rtt, .cs = queue->cs };
14912
14913 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
14914 }
14916 neighbour->queue_head,
14917 neighbour->queue_tail,
14918 queue);
14920 tc->details.communicator.queue_head,
14921 tc->details.communicator.queue_tail,
14922 queue);
14923
14924 }
14925 queue->mtu = ntohl (aqm->mtu);
14926 queue->nt = ntohl (aqm->nt);
14927 queue->cs = ntohl (aqm->cs);
14928 queue->idle = GNUNET_YES;
14929
14930 if (NULL == queue->mo)
14931 {
14932 /* Only for a NEW queue: on a queue update this used to start a second
14933 monitor and leak the first one. */
14934 struct sockaddr_in v4;
14935 char *addr_without = get_address_without_port (queue->address);
14936 if ((NULL != addr_without) &&
14937 (1 == inet_pton (AF_INET, addr_without, &v4.sin_addr)))
14938 {
14940 "start not global natted\n");
14942 GNUNET_YES,
14943 "peerstore",
14944 &neighbour->pid,
14946 &
14948 NULL,
14949 &
14951 NULL,
14953 queue);
14954 }
14955 GNUNET_free (addr_without);
14956 }
14957 /* check if valdiations are waiting for the queue */
14959 &aqm->receiver))
14962 &aqm->receiver,
14964 queue);
14965 /* Always (also) validate the address of the queue itself. A pending
14966 validation served above may well be for a *different* address string:
14967 #check_validation_request_pending() matches on the IP only, so a
14968 validation state waiting for the NAT address `PROTO-IP:0' is happily
14969 satisfied by a queue at `PROTO-IP:12345'. If we stopped here,
14970 #handle_validation_response() would later look for a queue at
14971 `PROTO-IP:0' -- which never exists -- and drop the successful
14972 validation on the floor without ever creating the virtual link. That
14973 is exactly what happens to the second of two peers behind the same
14974 NAT, as both of them advertise the very same `PROTO-IP:0'. */
14975 start_address_validation (&aqm->receiver, queue->address);
14976 /* look for traffic for this queue */
14977 // TODO Check whether this makes any sense at all.
14978 /*schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
14979 queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);*/
14980 /* might be our first queue, try launching DV learning */
14981 if (NULL == dvlearn_task)
14984}
14985
14986
14993static void
14995 const struct
14997{
14998 struct TransportClient *tc = cls;
14999 struct Queue *target_queue = NULL;
15000
15001 if (CT_COMMUNICATOR != tc->type)
15002 {
15003 /* Without this we walk `details.communicator.queue_head' for a client
15004 whose union holds something else entirely. */
15005 GNUNET_break (0);
15007 return;
15008 }
15010 "Received queue update message for %u with q_len %llu and mtu %u\n",
15011 ntohl (msg->qid),
15012 (unsigned long long) GNUNET_ntohll (msg->q_len),
15013 ntohl (msg->mtu));
15014 for (target_queue = tc->details.communicator.queue_head;
15015 NULL != target_queue;
15016 target_queue = target_queue->next_client)
15017 {
15018 if (ntohl (msg->qid) == target_queue->qid)
15019 break;
15020 }
15021 if (NULL == target_queue)
15022 {
15024 "Queue to update no longer exists! Discarding update.\n");
15026 return;
15027 }
15028
15029 target_queue->nt = ntohl (msg->nt);
15030 target_queue->mtu = ntohl (msg->mtu);
15031 target_queue->cs = ntohl (msg->cs);
15032 target_queue->priority = ntohl (msg->priority);
15033 /* The update message indicates how many messages
15034 * the queue should be able to handle.
15035 */
15037 target_queue->unlimited_length = GNUNET_YES;
15038 else
15039 target_queue->unlimited_length = GNUNET_NO;
15040 target_queue->q_capacity += GNUNET_ntohll (msg->q_len);
15041 if (0 < target_queue->q_capacity)
15043 target_queue,
15046}
15047
15048
15056static void
15057handle_queue_create_ok (void *cls,
15058 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
15059{
15060 struct TransportClient *tc = cls;
15061
15062 if (CT_COMMUNICATOR != tc->type)
15063 {
15064 GNUNET_break (0);
15066 return;
15067 }
15069 "# Suggestions succeeded at communicator",
15070 1,
15071 GNUNET_NO);
15073 "Request #%u for communicator to create queue succeeded\n",
15074 (unsigned int) ntohs (cqr->request_id));
15076}
15077
15078
15087static void
15089 void *cls,
15090 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
15091{
15092 struct TransportClient *tc = cls;
15093
15094 if (CT_COMMUNICATOR != tc->type)
15095 {
15096 GNUNET_break (0);
15098 return;
15099 }
15101 "Request #%u for communicator to create queue failed\n",
15102 (unsigned int) ntohl (cqr->request_id));
15104 "# Suggestions failed in queue creation at communicator",
15105 1,
15106 GNUNET_NO);
15108}
15109
15110
15118static void
15119handle_suggest_cancel (void *cls, const struct ExpressPreferenceMessage *msg)
15120{
15121 struct TransportClient *tc = cls;
15122 struct PeerRequest *pr;
15123
15124 if (CT_APPLICATION != tc->type)
15125 {
15126 GNUNET_break (0);
15128 return;
15129 }
15130 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
15131 &msg->peer);
15132 if (NULL == pr)
15133 {
15134 GNUNET_break (0);
15136 return;
15137 }
15138 (void) stop_peer_request (tc, &pr->pid, pr);
15140}
15141
15142
15143static void
15144hello_for_client_cb (void *cls,
15145 const struct GNUNET_PeerIdentity *pid,
15146 const char *uri)
15147{
15148 struct Queue *q;
15149 int pfx_len;
15150 const char *eou;
15151 char *address;
15152 (void) cls;
15153
15154 eou = strstr (uri,
15155 "://");
15156 if ((NULL == eou) || (eou == uri))
15157 {
15158 /* @a uri comes from a HELLO some remote peer published. */
15159 GNUNET_break_op (0);
15160 return;
15161 }
15162 pfx_len = eou - uri;
15163 eou += 3;
15165 "%.*s-%s",
15166 pfx_len,
15167 uri,
15168 eou);
15169
15171 "hello for client %s\n",
15172 address);
15173
15174 q = find_queue (pid, address);
15175 if (NULL == q)
15176 {
15178 }
15179 else
15182}
15183
15184
15192static void
15193handle_hello_for_client (void *cls,
15194 const struct GNUNET_PEERSTORE_Record *record,
15195 const char *emsg)
15196{
15197 const struct GNUNET_PeerIdentity *my_identity;
15198 struct PeerRequest *pr = cls;
15200 const struct GNUNET_MessageHeader *hello;
15201
15202 if (NULL != emsg)
15203 {
15205 "Got failure from PEERSTORE: %s\n",
15206 emsg);
15208 return;
15209 }
15210 if (NULL == record)
15211 {
15212 GNUNET_break (0);
15214 return;
15215 }
15217 if (NULL == my_identity)
15218 {
15220 "No identity given yet!\n");
15222 return;
15223 }
15224 hello = hello_from_record (record);
15225 if (NULL == hello)
15226 {
15227 /* MUST still ask for the next record: a bad one is not a reason to
15228 stall this monitor forever. */
15230 return;
15231 }
15232 if (0 == GNUNET_memcmp (&record->peer, my_identity))
15233 {
15235 return;
15236 }
15237 parser = GNUNET_HELLO_parser_from_msg (hello, &record->peer);
15238 if (NULL == parser)
15239 {
15241 "HELLO cannot be parsed!\n");
15243 return;
15244 }
15246 "HELLO for `%s' could be parsed, iterating addresses...!\n",
15250 NULL);
15251 GNUNET_HELLO_parser_free (parser);
15252 /* MUST ask for the next record, or this monitor stalls after one HELLO */
15254}
15255
15256
15257static void
15258hello_for_client_error_cb (void *cls)
15259{
15261 "Error in PEERSTORE monitoring\n");
15262}
15263
15264
15265static void
15266hello_for_client_sync_cb (void *cls)
15267{
15269 "Done with initial PEERSTORE iteration during monitoring\n");
15270}
15271
15272
15284static void
15286{
15287 if (NULL != pr->nc)
15289 /* Monitor only @e pid. With NULL every application request sees every
15290 HELLO in PEERSTORE, so a client asking for one peer made us suggest a
15291 connection to -- and start an address validation for -- every peer we
15292 have ever heard of, once per request. #try_to_bring_link_up() had the
15293 same bug and was already fixed the same way. */
15294 pr->nc =
15296 GNUNET_YES,
15297 "peerstore",
15298 &pr->pid,
15301 NULL,
15303 NULL,
15305 pr);
15306}
15307
15308
15318static void
15319suggest_retry_cb (void *cls)
15320{
15321 struct PeerRequest *pr = cls;
15322 struct VirtualLink *vl;
15323
15324 pr->retry_task = NULL;
15325 vl = lookup_virtual_link (&pr->pid);
15326 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
15327 {
15328 /* The client has what it asked for. Keep watching cheaply, and start
15329 over from the short interval when the link goes away again. */
15333 pr);
15334 return;
15335 }
15337 "Retrying to connect to %s, an application client wants it\n",
15338 GNUNET_i2s (&pr->pid));
15340 "# link setup retries for application clients",
15341 1,
15342 GNUNET_NO);
15343 /* Addresses we already track, queues we still have, and a fresh look in
15344 PEERSTORE. */
15346 /* ... plus a replay of what PEERSTORE has for this peer, which is the
15347 only way back once the validation state expired and the queues are
15348 gone. */
15354 pr);
15355}
15356
15357
15365static void
15366handle_suggest (void *cls, const struct ExpressPreferenceMessage *msg)
15367{
15368 struct TransportClient *tc = cls;
15369 const struct GNUNET_PeerIdentity *my_identity;
15370 struct PeerRequest *pr;
15371
15372 if (CT_NONE == tc->type)
15373 {
15374 tc->type = CT_APPLICATION;
15375 tc->details.application.requests =
15377 }
15378 if (CT_APPLICATION != tc->type)
15379 {
15380 GNUNET_break (0);
15382 return;
15383 }
15385 if (NULL == my_identity)
15386 {
15388 "Still waiting for own identity!\n");
15390 return;
15391 }
15393 "Client suggested we talk to %s with preference %d at rate %u\n",
15394 GNUNET_i2s (&msg->peer),
15395 (int) ntohl (msg->pk),
15396 (int) ntohl (msg->bw.value__));
15397 if (0 == GNUNET_memcmp (my_identity, &msg->peer))
15398 {
15400 "Client suggested connection to ourselves, ignoring...\n");
15402 return;
15403 }
15404 pr = GNUNET_new (struct PeerRequest);
15405 pr->tc = tc;
15406 pr->pid = msg->peer;
15407 pr->bw = msg->bw;
15408 pr->pk = ntohl (msg->pk);
15410 tc->details.application.requests,
15411 &pr->pid,
15412 pr,
15414 {
15415 GNUNET_break (0);
15416 GNUNET_free (pr);
15418 return;
15419 }
15421 /* The monitor alone only ever fires again if the HELLO *changes*. Keep
15422 asking for the link ourselves for as long as the client wants it. */
15423 pr->retry_backoff = SUGGEST_RETRY_MIN;
15424 pr->retry_task = GNUNET_SCHEDULER_add_delayed (pr->retry_backoff,
15426 pr);
15428}
15429
15430
15439static int
15441 const struct RequestHelloValidationMessage *m)
15442{
15443 (void) cls;
15445 return GNUNET_OK;
15446}
15447
15448
15456static void
15458 const struct RequestHelloValidationMessage *m)
15459{
15460 struct TransportClient *tc = cls;
15461 struct Queue *q;
15462
15463 q = find_queue (&m->peer, (const char *) &m[1]);
15464 if (NULL == q)
15465 {
15466 suggest_to_connect (&m->peer, (const char *) &m[1]);
15467 }
15468 else
15469 start_address_validation (&m->peer, (const char *) &m[1]);
15471}
15472
15473
15482static int
15483free_neighbour_cb (void *cls,
15484 const struct GNUNET_PeerIdentity *pid,
15485 void *value)
15486{
15487 struct Neighbour *neighbour = value;
15488
15489 (void) cls;
15490 (void) pid;
15491 GNUNET_break (0); // should this ever happen?
15492 free_neighbour (neighbour, GNUNET_YES);
15493
15494 return GNUNET_OK;
15495}
15496
15497
15512static int
15513free_virtual_link_cb (void *cls,
15514 const struct GNUNET_PeerIdentity *pid,
15515 void *value)
15516{
15517 struct VirtualLink *vl = value;
15518
15519 (void) cls;
15520 (void) pid;
15521 free_virtual_link (vl);
15522
15523 return GNUNET_OK;
15524}
15525
15526
15535static int
15536free_dv_routes_cb (void *cls,
15537 const struct GNUNET_PeerIdentity *pid,
15538 void *value)
15539{
15540 struct DistanceVector *dv = value;
15541
15542 (void) cls;
15543 (void) pid;
15544 free_dv_route (dv);
15545
15546 return GNUNET_OK;
15547}
15548
15549
15558static int
15559free_validation_state_cb (void *cls,
15560 const struct GNUNET_PeerIdentity *pid,
15561 void *value)
15562{
15563 struct ValidationState *vs = value;
15564
15565 (void) cls;
15566 (void) pid;
15568 return GNUNET_OK;
15569}
15570
15571
15580static int
15581free_pending_ack_cb (void *cls, const struct GNUNET_Uuid *key, void *value)
15582{
15583 struct PendingAcknowledgement *pa = value;
15584
15585 (void) cls;
15586 (void) key;
15588 return GNUNET_OK;
15589}
15590
15591
15600static int
15601free_ack_cummulator_cb (void *cls,
15602 const struct GNUNET_PeerIdentity *pid,
15603 void *value)
15604{
15605 struct AcknowledgementCummulator *ac = value;
15606
15607 (void) cls;
15608 (void) pid;
15609 /* @e task is armed for the whole life of @a ac -- but
15610 #transmit_cummulative_ack_cb() clears it before re-arming, and it
15611 routes a message while it is clear. #GNUNET_SCHEDULER_cancel()
15612 dereferences its argument unconditionally. */
15613 if (NULL != ac->task)
15614 {
15616 ac->task = NULL;
15617 }
15618 GNUNET_free (ac);
15619 return GNUNET_OK;
15620}
15621
15622
15629static void
15630do_shutdown (void *cls)
15631{
15632 static int shutdown_done;
15633 struct LearnLaunchEntry *lle;
15634 struct PilsRequest *pr;
15635 (void) cls;
15636
15638 "shutdown logic\n");
15639 if (GNUNET_YES == shutdown_done)
15640 return; /* reachable both from #shutdown_task() and #client_disconnect_cb() */
15641 shutdown_done = GNUNET_YES;
15642 if (NULL != client_grace_task)
15643 {
15645 client_grace_task = NULL;
15646 }
15647 if (NULL != nh)
15648 {
15650 nh = NULL;
15651 }
15653 &free_neighbour_cb, NULL);
15654 /* Freeing a neighbour takes its virtual link with it, so whatever is
15655 left here is ownerless: a link we created from an inbound FLOW_CONTROL
15656 message that never got confirmed, kept alive only by its @e
15657 unconfirmed_timeout_task. #GNUNET_SCHEDULER_shutdown() does not run
15658 that task, so leaving the link in place left the task armed against a
15659 map we destroy further down -- it fired afterwards and
15660 #free_virtual_link() called GNUNET_CONTAINER_multipeermap_remove() on
15661 NULL. Drop them here, while every structure they touch is still
15662 alive. */
15665 NULL);
15666 if (NULL != validation_task)
15667 {
15669 validation_task = NULL;
15670 }
15671 if (NULL != dvlearn_task)
15672 {
15674 dvlearn_task = NULL;
15675 }
15676 if (NULL != burst_task)
15677 {
15679 burst_task = NULL;
15680 }
15681 if (NULL != burst_timeout_task)
15682 {
15684 burst_timeout_task = NULL;
15685 }
15688 dvlearn_map = NULL;
15691 dv_routes = NULL;
15692 if (NULL != GST_stats)
15693 {
15695 GST_stats = NULL;
15696 }
15697 if (NULL != GST_my_hello)
15698 {
15700 GST_my_hello = NULL;
15701 }
15704 NULL);
15706 ack_cummulators = NULL;
15709 NULL);
15711 pending_acks = NULL;
15714 neighbours = NULL;
15717 links = NULL;
15720 NULL);
15722 backtalkers = NULL;
15725 NULL);
15727 validation_map = NULL;
15729 validation_heap = NULL;
15731 revalidation_map = NULL;
15732 while (NULL != ir_head)
15734 GNUNET_assert (0 == ir_total);
15735 while (NULL != (lle = lle_head))
15736 {
15738 GNUNET_free (lle);
15739 }
15740 while (NULL != (pr = pils_requests_head))
15741 {
15744 pr);
15745 if (NULL != pr->op)
15746 GNUNET_PILS_cancel (pr->op);
15747 GNUNET_free (pr);
15748 }
15749 if (NULL != pils_feed_task)
15750 {
15752 pils_feed_task = NULL;
15753 }
15754 if (NULL != pils)
15755 {
15757 pils = NULL;
15758 }
15759 if (NULL != peerstore)
15760 {
15762 "Disconnecting from PEERSTORE service\n");
15764 peerstore = NULL;
15765 }
15767}
15768
15769
15770static const char*
15772{
15773 switch (type)
15774 {
15775 case CT_CORE:
15776 return "CORE";
15777 case CT_MONITOR:
15778 return "MONITOR";
15779 case CT_COMMUNICATOR:
15780 return "COMMUNICATOR";
15781 case CT_APPLICATION:
15782 return "APPLICATION";
15783 default:
15784 return "UNKNOWN";
15785 }
15786}
15787
15788
15796static void
15797drop_remaining_clients (void *cls)
15798{
15799 client_grace_task = NULL;
15800 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
15801 {
15803 "Client did not disconnect within the shutdown grace period, "
15804 "dropping it: %s\n",
15805 get_client_type_name (tc->type));
15806 }
15807 /* We use #GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN, so the service will NOT
15808 drop clients for us. Without this we would wait forever for them to
15809 leave on their own and never reach #do_shutdown(). */
15811 /* Dropping the clients ran #client_disconnect_cb() for each of them, so
15812 #do_shutdown() has normally run by now; it is idempotent, and this
15813 covers the case where there was nothing left to drop. */
15814 do_shutdown (cls);
15815}
15816
15817
15818static void
15819shutdown_task (void *cls)
15820{
15822
15824 "Shutdown task executed\n");
15825 if (NULL != clients_head)
15826 {
15827 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
15828 {
15830 "Waiting for client to disconnect: %s\n",
15831 get_client_type_name (tc->type));
15832 }
15833 /* Give them a chance to shut down cleanly; #client_disconnect_cb() calls
15834 #do_shutdown() once the last one is gone, and #do_shutdown() cancels
15835 this task. */
15839 cls);
15840 return;
15841 }
15842 do_shutdown (cls);
15843}
15844
15845
15847{
15849};
15850
15851static void
15852update_hello_from_pid_change_cb (void *cls, int success)
15853{
15854 struct UpdateHelloFromPidCtx *pc = cls;
15855
15856 /* NOTE: @a success is GNUNET_OK even when #hello_add_iter() decided not to
15857 store anything because PEERSTORE already holds a HELLO that expires
15858 later; the API reports the desired state, not whether it wrote. So this
15859 says "we have a current HELLO on record", not "we just wrote one". */
15860 if (GNUNET_OK != success)
15862 "Failed to store our new hello with peerstore\n");
15863 else
15865 "Our hello is current in peerstore\n");
15866 GNUNET_free (pc);
15867}
15868
15869
15870void
15871print_address_list (void *cls,
15872 const struct GNUNET_PeerIdentity *pid,
15873 const char *uri)
15874{
15876 "%s\n", uri);
15877}
15878
15879
15889static void
15890pils_pid_change_cb (void *cls,
15891 const struct GNUNET_HELLO_Parser *parser,
15892 const struct GNUNET_HashCode *hash)
15893{
15894 const struct GNUNET_PeerIdentity *my_identity;
15895 struct GNUNET_MQ_Envelope *env;
15896 const struct GNUNET_MessageHeader *msg;
15897 struct UpdateHelloFromPidCtx *sc;
15898 struct GNUNET_HELLO_Builder *nbuilder;
15899 struct GNUNET_PeerIdentity npid;
15900
15903
15904 if (NULL == GST_my_hello)
15907 "My current identity is `%s'\n",
15919 nbuilder = GNUNET_HELLO_builder_from_parser (parser,
15920 &npid);
15921 if (GNUNET_NO ==
15923 {
15925 "New PID from PILS is derived from address list inconsistent with ours. Ignoring...\n");
15927 "Proposed address list:\n");
15930 "Current address list:\n");
15932 GNUNET_HELLO_builder_free (nbuilder);
15933 return;
15934 }
15936 GST_my_hello = nbuilder;
15938 "My new identity is `%s'\n",
15944 msg,
15946 sc);
15947 GNUNET_free (env);
15948}
15949
15950
15958static void
15959run (void *cls,
15960 const struct GNUNET_CONFIGURATION_Handle *c,
15962{
15963 (void) cls;
15964 /* setup globals */
15968 GST_cfg = c;
15976 GNUNET_YES);
15981 // TODO check for all uses of GST_my_hello that it is not used uninitialized
15983 "transport",
15984 "USE_BURST_NAT");
15985 if (GNUNET_SYSERR == use_burst)
15987 "Could not configure burst nat use. Default to no.\n");
15993 "transport",
15994 0,
15995 0,
15996 NULL,
15997 0,
15998 NULL,
15999 NULL,
16000 NULL);
16001 if (NULL == peerstore)
16002 {
16003 GNUNET_break (0);
16005 return;
16006 }
16009 NULL); // FIXME we need to wait for
16010 // our first peer id before
16011 // we can start the service
16012 // completely - PILS in turn
16013 // waits for the first
16014 // addresses from the
16015 // communicators in order to
16016 // be able to generate a
16017 // peer id
16018 if (NULL == pils)
16019 {
16020 GNUNET_break (0);
16022 return;
16023 }
16024 /* Decapsulate DV box ephemeral keys ourselves. #handle_dv_box() needs
16025 the key material while it still has the box, which points into the
16026 communicator's inbound message and is gone the moment the handler
16027 returns -- so the asynchronous answer arrived to a dangling @a dvb. */
16028 if (GNUNET_OK !=
16031 _ ("Failed to load our private key, "
16032 "cannot open DV boxes addressed to us\n"));
16033}
16034
16035
16041 "transport",
16043 &run,
16046 NULL,
16047 /* communication with applications */
16048 GNUNET_MQ_hd_fixed_size (suggest,
16051 NULL),
16052 GNUNET_MQ_hd_fixed_size (suggest_cancel,
16055 NULL),
16056 GNUNET_MQ_hd_var_size (request_hello_validation,
16059 NULL),
16060 /* communication with core */
16061 GNUNET_MQ_hd_fixed_size (client_start,
16063 struct StartMessage,
16064 NULL),
16065 GNUNET_MQ_hd_var_size (client_send,
16067 struct OutboundMessage,
16068 NULL),
16069 GNUNET_MQ_hd_fixed_size (client_recv_ok,
16071 struct RecvOkMessage,
16072 NULL),
16073 /* communication with communicators */
16074 GNUNET_MQ_hd_var_size (communicator_available,
16077 NULL),
16078 GNUNET_MQ_hd_var_size (communicator_backchannel,
16081 NULL),
16082 GNUNET_MQ_hd_var_size (add_address,
16085 NULL),
16086 GNUNET_MQ_hd_fixed_size (del_address,
16089 NULL),
16090 GNUNET_MQ_hd_var_size (incoming_msg,
16093 NULL),
16094 GNUNET_MQ_hd_fixed_size (queue_create_ok,
16097 NULL),
16098 GNUNET_MQ_hd_fixed_size (queue_create_fail,
16101 NULL),
16102 GNUNET_MQ_hd_var_size (add_queue_message,
16105 NULL),
16106 GNUNET_MQ_hd_fixed_size (update_queue_message,
16109 NULL),
16110 GNUNET_MQ_hd_fixed_size (del_queue_message,
16113 NULL),
16114 GNUNET_MQ_hd_fixed_size (send_message_ack,
16117 NULL),
16118 GNUNET_MQ_hd_fixed_size (burst_finished,
16121 NULL),
16122 /* communication with monitors */
16123 GNUNET_MQ_hd_fixed_size (monitor_start,
16126 NULL),
16127 GNUNET_MQ_hd_fixed_size (link_list_request,
16130 NULL),
16132
16133
16134/* end of file gnunet-service-transport.c */
struct GNUNET_GETOPT_CommandLineOption options[]
Definition 002.c:5
struct GNUNET_MQ_MessageHandlers handlers[]
Definition 003.c:1
struct GNUNET_MessageHeader * msg
Definition 005.c:2
struct GNUNET_MQ_Envelope * env
Definition 005.c:1
static struct GNUNET_ARM_MonitorHandle * m
Monitor connection with ARM.
Definition gnunet-arm.c:103
static int start
Set if we are to start default services (including ARM).
Definition gnunet-arm.c:38
static int ret
Final status code.
Definition gnunet-arm.c:93
static char * init
Set to the name of a service to start.
Definition gnunet-arm.c:73
static int end
Set if we are to shutdown all services (including ARM).
Definition gnunet-arm.c:33
static int do_shutdown
Set to GNUNET_YES if we are shutting down.
static struct GNUNET_CADET_Handle * mh
Cadet handle.
static struct GNUNET_TESTING_Interpreter * is
static struct Queue * queue_head
Head of queue of messages to transmit.
static int prefix
If printing the value of PREFIX has been requested.
static struct GNUNET_SCHEDULER_Task * st
The shutdown task.
static void record(void *cls, size_t data_size, const void *data)
Process recorded audio data.
static char * address
GNS address for this phone.
static GNUNET_NETWORK_STRUCT_END struct GNUNET_PeerIdentity me
Our own peer identity.
static struct GNUNET_DATASTORE_QueueEntry * qe
Current operation.
struct GNUNET_HashCode key
The key used in the DHT.
static struct GNUNET_TIME_Relative expiration
User supplied expiration value.
static struct GNUNET_FS_Handle * ctx
static struct GNUNET_GNS_LookupWithTldRequest * lr
Handle to lookup request.
Definition gnunet-gns.c:98
struct GNUNET_SCHEDULER_Task * shutdown_task
static unsigned int pending
The number of DNS queries that are outstanding.
static void queue(const char *label, uint32_t rd_count, struct GNUNET_GNSRECORD_Data *rd, const struct Zone *zone)
Add hostname to the list of requests to be made.
static char * res
Currently read line or NULL on EOF.
static char * value
Value of the record to add/remove.
static uint32_t type
Type string converted to DNS type value.
static struct GNUNET_NAT_AUTO_Test * nt
Handle to a NAT test operation.
static struct GNUNET_FS_Uri * uri
Value of URI provided on command-line (when not publishing a file but just creating UBlocks to refer ...
static struct GNUNET_FS_PublishContext * pc
Handle to FS-publishing operation.
static int result
Global testing status.
static struct GNUNET_REVOCATION_Query * q
Handle for revocation query.
static struct GNUNET_FS_SearchContext * sc
static struct GNUNET_SERVICE_Handle * service
Handle to our service instance.
static struct GNUNET_PeerIdentity my_identity
Identity of this peer.
static unsigned long long payload
How much data are we currently storing in the database?
struct GNUNET_CRYPTO_EddsaPrivateKey my_private_key
The current private key.
static unsigned int ring_buffer_dv_head
Head of the ring buffer.
static void peerstore_store_validation_cb(void *cls, int success)
Function called when peerstore is done storing a validated address.
static void handle_dv_box(void *cls, const struct TransportDVBoxMessage *dvb)
Communicator gave us a DV box.
#define DV_PATH_DISCOVERY_FREQUENCY
How long before paths expire would we like to (re)discover DV paths? Should be below DV_PATH_VALIDITY...
static struct GNUNET_SERVICE_Handle * GST_service
Our service handle; needed to force-disconnect clients that did not go away within SHUTDOWN_CLIENT_GR...
static struct PendingMessage * ring_buffer_dv[RING_BUFFER_SIZE]
Ring buffer for a forwarded DVBox message we did not deliver to the next hop, because of missing virt...
static int dv_neighbour_transmission(void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
Function called for each neighbour during handle_dv_learn.
static void reassembly_cleanup_task(void *cls)
Task run to clean up reassembly context of a neighbour that have expired.
static enum GNUNET_GenericReturnValue remove_global_addresses(void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
static void backtalker_timeout_cb(void *cls)
Function called when it is time to clean up a backtalker.
static void handle_add_address(void *cls, const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
Address of our peer added.
static void send_cmc_ack(struct CommunicatorMessageContext *cmc)
Release the CORE flow control credit for cmc by acknowledging the message to the communicator that de...
static unsigned int calculate_fork_degree(unsigned int hops_taken, unsigned int neighbour_count, unsigned int eligible_count)
Computes the number of neighbours we should forward a DVInit message to given that it has so far take...
static enum GNUNET_GenericReturnValue detach_cmc_from_backtalker(void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
Detach the ‘struct CommunicatorMessageContext’ parked on value from the client in cls.
static struct GNUNET_SCHEDULER_Task * dvlearn_task
Task run to initiate DV learning.
static int check_reliability_box(void *cls, const struct TransportReliabilityBoxMessage *rb)
Communicator gave us a reliability box.
static void handle_communicator_available(void *cls, const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
Communicator started.
#define SUGGEST_RETRY_MAX
What is the slowest rate at which we retry bringing up a link that an application client explicitly a...
static int check_fragment_box(void *cls, const struct TransportFragmentBoxMessage *fb)
Communicator gave us a fragment box.
static unsigned int get_age()
Get an offset into the transmission history buffer for struct PerformanceData.
static void free_validation_state(struct ValidationState *vs)
Free validation state.
static struct PendingAcknowledgement * prepare_pending_acknowledgement(struct Queue *queue, struct DistanceVectorHop *dvh, struct PendingMessage *pm)
Setup data structure waiting for acknowledgements.
static int check_request_hello_validation(void *cls, const struct RequestHelloValidationMessage *m)
Check GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION messages.
static void hello_for_incoming_cb(void *cls, const struct GNUNET_PeerIdentity *pid, const char *uri)
#define MAX_DV_DISCOVERY_SELECTION
Maximum number of peers we select for forwarding DVInit messages at the same time (excluding initiato...
#define QUEUE_ENTRY_TIMEOUT
static struct LearnLaunchEntry * lle_tail
Tail of a DLL sorted by launch time.
static struct GNUNET_CONTAINER_Heap * validation_heap
MIN Heap sorted by "next_challenge" to struct ValidationState entries sorting addresses we are aware ...
static void core_send_connect_info(struct TransportClient *tc, const struct GNUNET_PeerIdentity *pid)
Send message to CORE clients that we lost a connection.
static void send_dv_to_neighbour(void *cls, struct Neighbour *next_hop, const struct GNUNET_MessageHeader *hdr, enum RouteMessageOptions options)
Wrapper around route_via_neighbour() that matches the DVMessageHandler structure.
static void harmonize_flight_round(struct PendingMessage *pm)
#define ACK_CUMMULATOR_TIMEOUT
How long until we forget about historic accumulators and thus reset the ACK counter?...
void pils_sign_address(struct AddressListEntry *ale, struct GNUNET_TIME_Absolute mono_time)
Build address record by signing raw information with private key of the peer identity.
static struct GNUNET_SCHEDULER_Task * client_grace_task
Task run when SHUTDOWN_CLIENT_GRACE_PERIOD expired and clients are still connected,...
static void free_queue(struct Queue *queue)
Free queue.
static void handle_del_address(void *cls, const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
Address of our peer deleted.
static struct LearnLaunchEntry * lle_head
Head of a DLL sorted by launch time.
#define EPHEMERAL_VALIDITY
How long are ephemeral keys valid?
static void free_fragment_tree(struct PendingMessage *root)
Free fragment tree below root, excluding root itself.
static unsigned int is_ring_buffer_full
Is the ring buffer filled up to RING_BUFFER_SIZE.
static struct IncomingRequest * ir_tail
Tail of DLL starting at ir_head.
static void pils_pid_change_cb(void *cls, const struct GNUNET_HELLO_Parser *parser, const struct GNUNET_HashCode *hash)
Callback called when pils service updates us with our new peer identity.
static int free_pending_ack_cb(void *cls, const struct GNUNET_Uuid *key, void *value)
Free pending acknowledgement.
static void credit_client(struct PendingMessage *pm)
Return the send window credit that pm's client is owed, at most once for pm.
static int check_dv_box(void *cls, const struct TransportDVBoxMessage *dvb)
Communicator gave us a DV box.
static void completed_pending_message(struct PendingMessage *pm)
We have completed transmission of pm, remove it from the transmission queues (and if it is a fragment...
static void update_dvh_performance(struct DistanceVectorHop *dvh, struct GNUNET_TIME_Relative rtt, uint16_t bytes_transmitted_ok)
We have successfully transmitted data via dvh, update metrics.
struct GNUNET_NAT_Handle * nh
Handle for connect to the NAT service.
static int check_add_queue_message(void *cls, const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
New queue became available.
static struct GNUNET_SCHEDULER_Task * pils_feed_task
Task to feed addresses to PILS.
static void client_send_response(struct PendingMessage *pm)
Send a response to the pm that we have processed a "send" request.
static void start_dv_learn(void *cls)
Task run when we CONSIDER initiating a DV learn process.
static int dv_neighbour_selection(void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
Function called for each neighbour during handle_dv_learn.
static enum GNUNET_GenericReturnValue revalidate_now_cb(void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
Pull value's next challenge forward: the link to that peer is not up.
static void start_address_validation(const struct GNUNET_PeerIdentity *pid, const char *address)
Start address validation.
static void handle_del_queue_message(void *cls, const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
Queue to a peer went down.
static void drop_remaining_clients(void *cls)
The grace period we gave our clients to disconnect on their own expired.
#define QUEUE_LENGTH_LIMIT
How many messages can we have pending for a given queue (queue to a particular peer via a communicato...
static void update_backtalker_monotime(struct Backtalker *b)
The backtalker b monotonic time changed.
#define MAX_CUMMULATIVE_ACKS
Maximum number of messages we acknowledge together in one cumulative ACK.
#define MAX_DV_HOPS_ALLOWED
Maximum DV distance allowed ever.
static const char * get_client_type_name(enum ClientType type)
static void burst_timeout(void *cls)
#define BACKCHANNEL_INACTIVITY_TIMEOUT
How long do we cache backchannel (struct Backtalker) information after a backchannel goes inactive?
#define WANTED_VALIDATION_CHALLENGE_FREQ
What is the slowest rate at which we send challenges to a peer that an application client explicitly ...
static struct GNUNET_TIME_Relative get_network_latency(const struct TransportDVLearnMessage *dvl)
static void hello_for_client_error_cb(void *cls)
static void check_for_global_natted(void *cls, const struct GNUNET_PEERSTORE_Record *record, const char *emsg)
#define ADDRESS_VALIDATION_LIFETIME
How long do we consider an address valid if we just checked?
static void free_distance_vector_hop(struct DistanceVectorHop *dvh)
Free a dvh.
#define MAX_FC_RETRANSMIT_COUNT
Maximum number of FC retransmissions for a running retransmission task.
#define MIN_ACK_WAIT_DURATION
Lower bound on the RTT estimate we are willing to derive a retransmission deadline from.
static void handle_fragment_box(void *cls, const struct TransportFragmentBoxMessage *fb)
Communicator gave us a fragment.
static enum GNUNET_GenericReturnValue report_link(void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
Send the state of the virtual link value to the requesting client.
static struct PendingMessage * fragment_message(struct Queue *queue, struct DistanceVectorHop *dvh, struct PendingMessage *pm)
Fragment the given pm to the given mtu.
static void update_hello_from_pid_change_cb(void *cls, int success)
static struct GNUNET_SCHEDULER_Task * validation_task
Task to run address validation.
static void handle_suggest(void *cls, const struct ExpressPreferenceMessage *msg)
We have received a struct ExpressPreferenceMessage from an application client.
static void handle_link_list_request(void *cls, const struct GNUNET_TRANSPORT_LinkListRequest *lr)
A client asks for the virtual links we currently have.
static void cores_send_connect_info(const struct GNUNET_PeerIdentity *pid)
Send message to CORE clients that we gained a connection.
#define SUGGEST_RETRY_MIN
How soon after an application asked us for a peer do we retry bringing the link up for the first time...
static void cummulative_ack(const struct GNUNET_PeerIdentity *pid, const struct AcknowledgementUUIDP *ack_uuid, struct GNUNET_TIME_Absolute max_delay)
Transmit an acknowledgement for ack_uuid to pid delaying transmission by at most ack_delay.
static void task_consider_sending_fc(void *cls)
Something changed on the virtual link with respect to flow control.
#define DV_LEARN_QUALITY_THRESHOLD
How many good connections (confirmed, bi-directional, not DV) do we need to have to suppress initiati...
static void free_neighbour(struct Neighbour *neighbour, enum GNUNET_GenericReturnValue drop_link)
Release memory used by neighbour.
PendingMessageType
Types of different pending messages.
@ PMT_FRAGMENT_BOX
Fragment box.
@ PMT_DV_BOX
Pending message created during forward_dv_box().
@ PMT_CORE
Ordinary message received from the CORE service.
@ PMT_RELIABILITY_BOX
Reliability box.
static struct GNUNET_TIME_Relative calculate_rtt(struct DistanceVector *dv)
static void arm_free_queue_entry_task(struct TransportClient *tc)
Make sure free_timedout_queue_entry() will run for tc, so that `struct QueueEntry's the communicator ...
static int check_flow_control(void *cls, const struct TransportFlowControlMessage *fc)
Communicator gave us a transport address validation response.
static int stop_peer_request(void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
Stop the peer request in value.
static void handle_update_queue_message(void *cls, const struct GNUNET_TRANSPORT_UpdateQueueMessage *msg)
Handle updates to queues.
static void cores_send_disconnect_info(const struct GNUNET_PeerIdentity *pid)
Send message to CORE clients that we lost a connection.
static void handle_client_start(void *cls, const struct StartMessage *start)
Initialize a "CORE" client.
#define MAX_DV_PATHS_TO_TARGET
Maximum number of DV paths we keep simultaneously to the same target.
static void free_virtual_link(struct VirtualLink *vl)
Free virtual link.
static enum GNUNET_GenericReturnValue detach_cmcs_from_link(void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
Detach the `struct CommunicatorMessageContext's parked on value from the client in cls.
RouteMessageOptions
Which transmission options are allowable for transmission? Interpreted bit-wise!
@ RMO_UNCONFIRMED_ALLOWED
We are allowed to use unconfirmed queues or DV routes for this message.
@ RMO_DV_ALLOWED
We are allowed to use DV routing for this hdr.
@ RMO_REDUNDANT
If we have multiple choices, it is OK to send this message over multiple channels at the same time to...
@ RMO_NONE
Only confirmed, non-DV direct neighbours.
@ RMO_ANYTHING_GOES
Reliable and unreliable, DV and non-DV are all acceptable.
static int notify_client_queues(void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
Iterator telling new MONITOR client about all existing queues to peers.
static struct AddressListEntry * create_address_entry(struct TransportClient *tc, struct GNUNET_TIME_Relative expiration, enum GNUNET_NetworkType nt, const char *address, uint32_t aid, size_t slen)
static void extract_box_cb(void *cls, struct Neighbour *next_hop, const struct GNUNET_MessageHeader *hdr, enum RouteMessageOptions options)
Function to call to further operate on the now DV encapsulated message hdr, forwarding it via next_ho...
static void backtalker_monotime_cb(void *cls, const struct GNUNET_PEERSTORE_Record *record, const char *emsg)
Function called with the monotonic time of a backtalker by PEERSTORE.
static void queue_burst(void *cls)
static void handle_monitor_start(void *cls, const struct GNUNET_TRANSPORT_MonitorStart *start)
Initialize a monitor client.
static struct GNUNET_PEERSTORE_Handle * peerstore
Database for peer's HELLOs.
static void finish_cmc_handling(struct CommunicatorMessageContext *cmc)
static int learn_dv_path(const struct GNUNET_PeerIdentity *path, unsigned int path_len, struct GNUNET_TIME_Relative network_latency, struct GNUNET_TIME_Absolute path_valid_until)
We have learned a path through the network to some other peer, add it to our DV data structure (retur...
static void store_pi(void *cls)
Ask peerstore to store our address.
#define FC_NO_CHANGE_REPLY_PROBABILITY
What is the 1:n chance that we send a Flow control response when receiving a flow control message tha...
static void notify_monitors(const struct GNUNET_PeerIdentity *peer, const char *address, enum GNUNET_NetworkType nt, const struct MonitorEvent *me)
Send information in me about a peer's status with respect to some address to all monitors that care.
static struct GNUNET_TIME_Relative route_via_neighbour(const struct Neighbour *n, const struct GNUNET_MessageHeader *hdr, enum RouteMessageOptions options)
Pick a queue of n under constraints options and schedule transmission of hdr.
#define RECV_WINDOW_SIZE
Window size.
static int check_known_challenge(void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
Test if the validation state in value matches the challenge from cls.
static void store_signed_address(struct PilsAddressSignContext *pc, const struct GNUNET_PeerIdentity *pid, const struct GNUNET_CRYPTO_EddsaSignature *sig)
Turn the signed address into a HELLO URI and hand it to PEERSTORE.
static unsigned int check_for_queue_with_higher_prio(struct Queue *queue, struct Queue *queue_head)
Check if there is another queue to the same neighbour, over a different communicator,...
#define GOODPUT_AGING_SLOTS
Number of slots we keep of historic data for computation of goodput / message loss ratio.
static int free_validation_state_cb(void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
Free validation state.
static int free_neighbour_cb(void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
Free neighbour entry.
static void handle_client_send(void *cls, const struct OutboundMessage *obm)
Client asked for transmission to a peer.
static void decaps_dv_box_cont(struct CommunicatorMessageContext *cmc, const struct TransportDVBoxMessage *dvb, const struct GNUNET_ShortHashCode *km)
Open the DV box dvb addressed to us, using the key material km decapsulated from its ephemeral key.
static enum GNUNET_GenericReturnValue burst_running
Is there a burst running?
struct GNUNET_HELLO_Builder * GST_my_hello
Our HELLO.
static void start_burst(void *cls)
#define DV_QUALITY_RTT_THRESHOLD
We only consider queues as "quality" connections when suppressing the generation of DV initiation mes...
static struct TransportClient * clients_head
Head of linked list of all clients to this service.
static void handle_validation_challenge(void *cls, const struct TransportValidationChallengeMessage *tvc)
Communicator gave us a transport address validation challenge.
static struct PilsRequest * pils_requests_head
PILS Operation DLL.
#define COMMUNICATOR_TOTAL_QUEUE_LIMIT
How many messages can we have pending for a given communicator process before we start to throttle th...
static void free_reassembly_context(struct ReassemblyContext *rc)
Free rc.
static struct VirtualLink * lookup_virtual_link(const struct GNUNET_PeerIdentity *pid)
Lookup virtual link for peer pid.
static int check_connection_quality(void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
Check whether any queue to the given neighbour is of a good "quality" and if so, increment the counte...
static void reorder_root_pm(struct PendingMessage *pm, struct GNUNET_TIME_Absolute next_attempt)
static void core_env_sent_cb(void *cls)
Function called when we are done giving a message of a certain size to CORE and should thus decrement...
static unsigned int ir_total
Length of the DLL starting at ir_head.
static int in_shutdown
Indication if we have received a shutdown signal and are in the process of cleaning up.
static struct GNUNET_TIME_Relative validation_challenge_freq(const struct GNUNET_PeerIdentity *pid)
How slow are we allowed to get with challenges for pid?
static void select_best_pending_from_link(struct PendingMessageScoreContext *sc, struct Queue *queue, struct VirtualLink *vl, struct DistanceVectorHop *dvh, size_t overhead)
Select the best pending message from vl for transmission via queue.
static void suggest_to_connect(const struct GNUNET_PeerIdentity *pid, const char *address)
Signature of a function called with a communicator address of a peer pid that an application wants us...
static void free_timedout_queue_entry(void *cls)
static void handle_send_message_ack(void *cls, const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
Message was transmitted.
static void update_pd_age(struct PerformanceData *pd, unsigned int age)
Check if we have advanced to another age since the last time.
#define DV_LEARN_BASE_FREQUENCY
What is the non-randomized base frequency at which we would initiate DV learn messages?
struct GNUNET_SCHEDULER_Task * burst_timeout_task
static void free_pending_acknowledgement(struct PendingAcknowledgement *pa)
Release pa data structure.
static struct GNUNET_CONTAINER_MultiUuidmap * pending_acks
Map of pending acknowledgements, mapping struct AcknowledgementUUID to a struct PendingAcknowledgemen...
static struct GNUNET_CONTAINER_MultiShortmap * dvlearn_map
Map from challenges to struct LearnLaunchEntry values.
#define DV_FORWARD_TIMEOUT
If a DVBox could not be forwarded after this number of seconds we drop it.
static void finish_handling_raw_message(struct VirtualLink *vl, const struct GNUNET_MessageHeader *mh, struct CommunicatorMessageContext *cmc, unsigned int free_cmc)
static void handle_add_queue_message(void *cls, const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
New queue became available.
static void update_queue_performance(struct Queue *q, struct GNUNET_TIME_Relative rtt, uint16_t bytes_transmitted_ok)
We have successfully transmitted data via q, update metrics.
static void schedule_transmit_on_queue(struct GNUNET_TIME_Relative delay, struct Queue *queue, enum GNUNET_SCHEDULER_Priority p)
Called whenever something changed that might effect when we try to do the next transmission on queue ...
static void set_pending_message_uuid(struct PendingMessage *pm)
If necessary, generates the UUID for a pm.
static void free_pending_message(struct PendingMessage *pm)
Release memory associated with pm and remove pm from associated data structures.
static void revalidation_start_cb(void *cls)
static void backtalker_monotime_store_cb(void *cls, int success)
Function called by PEERSTORE when the store operation of a backtalker's monotonic time is complete.
static int free_reassembly_cb(void *cls, uint32_t key, void *value)
function called to free_reassembly_context().
static void * client_connect_cb(void *cls, struct GNUNET_SERVICE_Client *client, struct GNUNET_MQ_Handle *mq)
Called whenever a client connects.
#define DV_PATH_VALIDITY_TIMEOUT
How long do we consider a DV path valid if we see no further updates on it? Note: the value chosen he...
static enum GNUNET_GenericReturnValue sign_ephemeral(struct DistanceVector *dv)
Sign the ephemeral key in dv, and mark it current.
#define RING_BUFFER_SIZE
Size of ring buffer to cache CORE and forwarded DVBox messages.
static void check_vl_transmission(struct VirtualLink *vl)
There is a message at the head of the pending messages for vl which may be ready for transmission.
static int find_by_message_uuid(void *cls, uint32_t key, void *value)
Iterator called to find a reassembly context by the message UUID in the multihashmap32.
static struct TransportClient * lookup_communicator(const char *prefix)
Find transport client providing communication service for the protocol prefix.
static unsigned int ring_buffer_head
Head of the ring buffer.
#define MAX_ADDRESS_VALID_UNTIL
When do we forget an invalid address for sure?
static void handle_hello_for_client(void *cls, const struct GNUNET_PEERSTORE_Record *record, const char *emsg)
Function called by PEERSTORE for each matching record.
#define SHUTDOWN_CLIENT_GRACE_PERIOD
How long do we wait during shutdown for our clients to disconnect on their own before we drop them?...
static void transmit_dv_init(struct TransportDVLearnMessage dvl, struct LearnLaunchEntry *lle, struct QueueQualityContext qqc)
Finish and transmit the DV learn message dvl we initiated.
static void handle_suggest_cancel(void *cls, const struct ExpressPreferenceMessage *msg)
An application client no longer wants us to connect to a peer it asked for earlier.
static void update_performance_data(struct PerformanceData *pd, struct GNUNET_TIME_Relative rtt, uint16_t bytes_transmitted_ok)
Update pd based on the latest rtt and the number of bytes that were confirmed to be successfully tran...
static void forward_dv_box(struct Neighbour *next_hop, struct TransportDVBoxMessage *hdr, uint16_t total_hops, uint16_t num_hops, const struct GNUNET_PeerIdentity *hops, const void *enc_payload, uint16_t enc_payload_size)
Create a DV Box message and queue it for transmission to next_hop.
static void handle_validation_response(void *cls, const struct TransportValidationResponseMessage *tvr)
Communicator gave us a transport address validation response.
static void handle_reliability_ack(void *cls, const struct TransportReliabilityAckMessage *ra)
Communicator gave us a reliability ack.
static int free_virtual_link_cb(void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
Free virtual link entry.
static void send_msg_from_cache(struct VirtualLink *vl)
static void free_address_list_entry(struct AddressListEntry *ale)
Free ale.
static void free_burst_cls(struct GNUNET_StartBurstCls *sb_cls)
Release a burst closure, detaching it from its virtual link and from the scheduled burst_task (if tha...
static unsigned int pick_random_dv_hops(const struct DistanceVector *dv, enum RouteMessageOptions options, struct DistanceVectorHop **hops_array, unsigned int hops_array_length)
Pick hops_array_length random DV paths satisfying options.
static void handle_burst_finished(void *cls, const struct GNUNET_TRANSPORT_BurstFinished *bf)
The burst finished.
static void hello_for_incoming_sync_cb(void *cls)
static enum GNUNET_GenericReturnValue resume_communicators(void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
#define FC_KEEPALIVE_INTERVAL
How long may a confirmed virtual link go without us sending anything on it before we transmit an othe...
static struct PilsRequest * pils_requests_tail
PILS Operation DLL.
static struct GNUNET_CONTAINER_MultiPeerMap * neighbours
Map from PIDs to struct Neighbour entries.
static void release_stalled_cmc(struct VirtualLink *vl, struct CommunicatorMessageContext *cmc)
Take cmc off the list of messages waiting on vl's CORE receive window, release the flow control credi...
static void transmit_on_queue(void *cls)
We believe we are ready to transmit a message on a queue.
static void handle_dv_learn(void *cls, const struct TransportDVLearnMessage *dvl)
Communicator gave us a DV learn message.
static void iterate_address_start_burst(void *cls, const struct GNUNET_PeerIdentity *pid, const char *uri)
static void disconnect_and_free_virtual_link(struct VirtualLink *vl)
Tell CORE clients the link to vl is gone, then release it.
static struct Queue * find_queue(const struct GNUNET_PeerIdentity *pid, const char *address)
Find the queue matching pid and address.
static void activate_core_visible_dv_path(struct DistanceVectorHop *hop)
The hop is a validated path to the respective target peer and we should tell core about it – and sche...
static void free_dv_route(struct DistanceVector *dv)
Free entry in dv_routes.
static unsigned int is_ring_buffer_dv_full
Is the ring buffer filled up to RING_BUFFER_SIZE.
static int check_communicator_backchannel(void *cls, const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
Communicator requests backchannel transmission.
#define DEFAULT_WINDOW_SIZE
How big is the flow control window size by default; limits per-neighbour RAM utilization.
static void run(void *cls, const struct GNUNET_CONFIGURATION_Handle *c, struct GNUNET_SERVICE_Handle *service)
Initiate transport service.
#define MAX_VALIDATION_CHALLENGE_FREQ
What is the slowest rate at which we send challenges?
static void cancel_address_store(struct AddressListEntry *ale)
Abort the asynchronous sign-and-store chain (if any) that is currently running for ale and release it...
static void handle_queue_create_ok(void *cls, const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
Communicator tells us that our request to create a queue "worked", that is setting up the queue is no...
static enum GNUNET_GenericReturnValue sign_by_my_identity(const struct GNUNET_CRYPTO_SignaturePurpose *purpose, struct GNUNET_CRYPTO_EddsaSignature *sig)
Sign purpose with the private key of our current peer identity.
static int notify_client_connect_info(void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
Iterator telling new CORE client about all existing connections to peers.
static void core_fc_stalled(void *cls)
CORE never returned the flow control credit for the messages we handed it for cls,...
static void shc_cont(void *cls, int success)
static void handle_raw_message(void *cls, const struct GNUNET_MessageHeader *mh)
Communicator gave us an unencapsulated message to pass as-is to CORE.
static void handle_communicator_backchannel(void *cls, const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
Communicator requests backchannel transmission.
static struct Queue * find_queue_by_ip(const struct GNUNET_PeerIdentity *pid, const char *address)
Find a queue to pid whose address has the same IP as address, but possibly a different port.
static unsigned long long logging_uuid_gen
Generator of logging_uuid in struct PendingMessage.
static int check_incoming_msg(void *cls, const struct GNUNET_TRANSPORT_IncomingMessage *im)
Client notified us about transmission from a peer.
#define REASSEMBLY_EXPIRATION
How long do we keep partially reassembled messages around before giving up?
static void update_next_challenge_time(struct ValidationState *vs, struct GNUNET_TIME_Absolute new_time)
Set the time for next_challenge of vs to new_time.
static struct Neighbour * lookup_neighbour(const struct GNUNET_PeerIdentity *pid)
Lookup neighbour for peer pid.
static void peerstore_store_own_cb(void *cls, int success)
Function called when peerstore is done storing our address.
static struct RingBufferEntry * ring_buffer[RING_BUFFER_SIZE]
Ring buffer for a CORE message we did not deliver to CORE, because of missing virtual link to sender.
#define MIN_DELAY_ADDRESS_VALIDATION
What is the maximum frequency at which we do address validation? A random value between 0 and this va...
static void handle_acknowledged(struct PendingAcknowledgement *pa, struct GNUNET_TIME_Relative ack_delay)
The pa was acknowledged, process the acknowledgement.
static struct GNUNET_CONTAINER_MultiPeerMap * backtalkers
Map from PIDs to struct Backtalker entries.
static struct GNUNET_TIME_Absolute hello_mono_time
Monotonic time we use for HELLOs generated at this time.
static int check_communicator_available(void *cls, const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
Communicator started.
static char * communicator_list(struct Neighbour *n, unsigned int *num_queues)
Build the 0-terminated, comma-separated list of address prefixes of the communicators that own the qu...
static void handle_backchannel_encapsulation(void *cls, const struct TransportBackchannelEncapsulationMessage *be)
Communicator gave us a backchannel encapsulation.
static struct GNUNET_CONTAINER_MultiHashMap * revalidation_map
Map from addresses to struct ValidationState entries describing addresses we are aware of and their v...
static const struct GNUNET_CONFIGURATION_Handle * GST_cfg
Configuration handle.
static enum GNUNET_GenericReturnValue revalidate_map_it(void *cls, const struct GNUNET_HashCode *key, void *value)
#define DEFAULT_ACK_WAIT_DURATION
Default value for how long we wait for reliability ack.
static struct PendingMessage * reliability_box_message(struct Queue *queue, struct DistanceVectorHop *dvh, struct PendingMessage *pm)
Reliability-box the given pm.
static int free_backtalker_cb(void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
Callback to free backtalker records.
static enum GNUNET_GenericReturnValue contains_address(void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
static void path_cleanup_cb(void *cls)
Task called when we should check if any of the DV paths we have learned to a target are due for garba...
#define FAST_VALIDATION_CHALLENGE_FREQ
What is the fastest rate at which we send challenges if we keep learning an address (gossip,...
static int check_add_address(void *cls, const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
Address of our peer added.
static void demultiplex_with_cmc(struct CommunicatorMessageContext *cmc)
Given an inbound message msg from a communicator cmc, demultiplex it based on the type calling the ri...
#define MAX_DV_LEARN_PENDING
Maximum number of DV learning activities we may have pending at the same time.
static void hello_for_client_cb(void *cls, const struct GNUNET_PeerIdentity *pid, const char *uri)
static void validation_start_cb(void *cls)
Task run periodically to validate some address based on validation_heap.
#define VALIDATION_RTT_BUFFER_FACTOR
How many network RTTs before an address validation expires should we begin trying to revalidate?...
static void handle_client_recv_ok(void *cls, const struct RecvOkMessage *rom)
Client confirms that it is done handling message(s) to a particular peer.
static void feed_addresses_to_pils(void *cls)
static struct GNUNET_CONTAINER_MultiPeerMap * links
Map from PIDs to struct VirtualLink entries describing links CORE knows to exist.
static int check_client_send(void *cls, const struct OutboundMessage *obm)
Client asked for transmission to a peer.
static int check_backchannel_encapsulation(void *cls, const struct TransportBackchannelEncapsulationMessage *be)
Communicator gave us a backchannel encapsulation.
static struct TransportClient * clients_tail
Tail of linked list of all clients to this service.
static struct GNUNET_CONTAINER_MultiPeerMap * ack_cummulators
Map from PIDs to struct AcknowledgementCummulators.
static void transmit_cummulative_ack_cb(void *cls)
Do the transmission of a cumulative acknowledgement now.
static int check_validation_request_pending(void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
A new queue has been created, check if any address validation requests have been waiting for it.
static void resume_cmc_client(struct CommunicatorMessageContext *cmc)
Let the communicator that delivered cmc give us its next message.
static struct GNUNET_STATISTICS_Handle * GST_stats
Statistics handle.
static const struct GNUNET_MessageHeader * hello_from_record(const struct GNUNET_PEERSTORE_Record *record)
Obtain the HELLO message stored in record, if record actually carries one.
static struct GNUNET_SCHEDULER_Task * burst_task
The task to start the burst.
static void send_t_validation_response(struct CommunicatorMessageContext *cmc, struct TransportValidationResponseMessage tvr)
Route the signed validation response tvr back to the challenger and release cmc.
void print_address_list(void *cls, const struct GNUNET_PeerIdentity *pid, const char *uri)
static struct GNUNET_TIME_Relative encapsulate_for_dv(struct DistanceVector *dv, unsigned int num_dvhs, struct DistanceVectorHop **dvhs, const struct GNUNET_MessageHeader *hdr, DVMessageHandler use, void *use_cls, enum RouteMessageOptions options, enum GNUNET_GenericReturnValue without_fc)
Pick a path of dv under constraints options and schedule transmission of hdr.
static void suggest_retry_cb(void *cls)
Task run for as long as an application client wants a link to pid that we do not have.
static void neighbour_store_dvmono_cb(void *cls, int success)
Function called when peerstore is done storing a DV monotonic time.
static void handle_request_hello_validation(void *cls, const struct RequestHelloValidationMessage *m)
A client encountered an address of another peer.
static void free_queue_entry(struct QueueEntry *qe, struct TransportClient *tc)
static void pils_sign_hello_cb(void *cls, const struct GNUNET_PeerIdentity *pid, const struct GNUNET_CRYPTO_EddsaSignature *sig)
Get HELLO signature and create message to store in PEERSTORE.
static void check_for_global_natted_sync_cb(void *cls)
#define UNCONFIRMED_LINK_TIMEOUT
How long do we keep a virtual link that only exists because some peer sent us a FLOW_CONTROL message,...
static void handle_reliability_box(void *cls, const struct TransportReliabilityBoxMessage *rb)
Communicator gave us a reliability box.
static void notify_monitor(struct TransportClient *tc, const struct GNUNET_PeerIdentity *peer, const char *address, enum GNUNET_NetworkType nt, const struct MonitorEvent *me)
Notify monitor tc about an event.
static void check_for_burst_address(void *cls, const struct GNUNET_PEERSTORE_Record *record, const char *emsg)
static unsigned int check_next_attempt_tree(struct PendingMessage *pm, struct PendingMessage *root)
static void hello_for_incoming_error_cb(void *cls)
static struct GNUNET_StartBurstCls * burst_task_cls
Closure of the currently scheduled burst_task, or NULL.
static void send_ok_to_client(struct TransportClient *tc, const struct GNUNET_PeerIdentity *pid)
Return one unit of send window credit for pid to tc.
static void queue_send_msg(struct Queue *queue, struct PendingMessage *pm, const void *payload, size_t payload_size)
Send the message payload on queue.
static void handle_flow_control(void *cls, const struct TransportFlowControlMessage *fc)
Communicator gave us a transport address validation response.
#define MIN_ADDRESS_REFRESH_INTERVAL
How often are we willing to re-sign and re-store one of our own addresses in PEERSTORE,...
static int check_dv_learn(void *cls, const struct TransportDVLearnMessage *dvl)
Communicator gave us a DV learn message.
static void handle_hello_for_incoming(void *cls, const struct GNUNET_PEERSTORE_Record *record, const char *emsg)
Function called by PEERSTORE for each matching record.
static void try_to_bring_link_up(const struct GNUNET_PeerIdentity *pid)
Ask for everything that could give us a confirmed virtual link to pid: revalidate the addresses we al...
static void client_disconnect_cb(void *cls, struct GNUNET_SERVICE_Client *client, void *app_ctx)
Called whenever a client is disconnected.
static int check_reliability_ack(void *cls, const struct TransportReliabilityAckMessage *ra)
Communicator gave us a reliability ack.
static void iterate_address_and_compare_cb(void *cls, const struct GNUNET_PeerIdentity *pid, const char *uri)
static struct GNUNET_CONTAINER_MultiPeerMap * validation_map
Map from PIDs to struct ValidationState entries describing addresses we are aware of and their validi...
static struct GNUNET_TIME_Relative dvlearn_pils_backoff
Backoff for start_dv_learn() while PILS still owes us an identity.
#define MIN_FC_RETRANSMIT_DELAY
Lower bound on the delay between two flow control transmissions on the same virtual link.
static int free_dv_routes_cb(void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
Free DV route entry.
static enum GNUNET_GenericReturnValue add_global_addresses(void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
#define MIN_DV_PATH_LENGTH_FOR_INITIATOR
Minimum number of hops we should forward DV learn messages even if they are NOT useful for us in hope...
static void handle_queue_create_fail(void *cls, const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
Communicator tells us that our request to create a queue failed.
static void check_link_down(void *cls)
Task run to check whether the hops of the cls still are validated, or if we need to core about discon...
static void check_for_global_natted_error_cb(void *cls)
static void finish_cmc_handling_with_continue(struct CommunicatorMessageContext *cmc, unsigned int free_cmc)
Send ACK to communicator (if requested) and free cmc.
static void forward_dv_learn(const struct GNUNET_PeerIdentity *next_hop, const struct TransportDVLearnMessage *msg, uint16_t bi_history, uint16_t nhops, const struct DVPathEntryP *hops, struct GNUNET_TIME_Absolute in_time)
Build and forward a DV learn message to next_hop.
static void handle_incoming_msg(void *cls, const struct GNUNET_TRANSPORT_IncomingMessage *im)
Incoming message.
static void validation_transmit_on_queue(struct Queue *q, struct ValidationState *vs)
The queue q (which matches the peer and address in vs) is ready for queueing.
static int free_ack_cummulator_cb(void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
Free acknowledgement cummulator.
static void update_pm_next_attempt(struct PendingMessage *pm, struct GNUNET_TIME_Absolute next_attempt)
Change the value of the next_attempt field of pm to next_attempt and re-order pm in the transmission ...
#define PILS_FEED_ADDRESSES_DELAY
Delay between added/removed addresses and PILS feed call.
static int check_known_address(void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
Test if the validation state in value matches the address from cls.
enum GNUNET_GenericReturnValue use_burst
static struct GNUNET_CONTAINER_MultiPeerMap * dv_routes
Map from PIDs to struct DistanceVector entries describing known paths to the peer.
static void detach_cmcs_from_client(const struct TransportClient *tc)
A communicator client is going away.
static struct GNUNET_TIME_Relative route_control_message_without_fc(struct VirtualLink *vl, const struct GNUNET_MessageHeader *hdr, enum RouteMessageOptions options)
We need to transmit hdr to target.
static void free_incoming_request(struct IncomingRequest *ir)
Release ir data structure.
#define MAX_INCOMING_REQUEST
For how many incoming connections do we try to create a virtual link for (at the same time!...
static void neighbour_dv_monotime_cb(void *cls, const struct GNUNET_PEERSTORE_Record *record, const char *emsg)
Function called with the monotonic time of a DV initiator by PEERSTORE.
static struct GNUNET_PILS_Handle * pils
Service that manages our peer id.
static void start_peer_request_monitor(struct PeerRequest *pr)
(Re)start the PEERSTORE HELLO monitor of pr.
void(* DVMessageHandler)(void *cls, struct Neighbour *next_hop, const struct GNUNET_MessageHeader *hdr, enum RouteMessageOptions options)
Function to call to further operate on the now DV encapsulated message hdr, forwarding it via next_ho...
static char * get_address_without_port(const char *address)
Get the IP address without the communicator prefix and the port number.
ClientType
What type of client is the struct TransportClient about?
@ CT_APPLICATION
"Application" telling us where to connect (i.e.
@ CT_MONITOR
It is a monitor, forward monitor data.
@ CT_NONE
We do not know yet (client is fresh).
@ CT_CORE
Is the CORE service, we need to forward traffic to it.
@ CT_COMMUNICATOR
It is a communicator, use for communication.
#define NEIGHBOUR_LIVENESS_TIMEOUT
How long may a direct neighbour stay completely silent before we stop believing that its queues work,...
static int validate_dv_initiator_signature(struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time, const struct GNUNET_PeerIdentity *init, const struct GNUNET_CRYPTO_ChallengeNonceP *challenge, const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
Check signature of type GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR.
#define MAX_REASSEMBLY_CONTEXTS
Maximum number of messages we are willing to reassemble in parallel for a single virtual link.
static void unconfirmed_link_timeout(void *cls)
Discard a virtual link that only ever existed because some peer sent us a FLOW_CONTROL message and th...
static struct IncomingRequest * ir_head
List of incoming connections where we are trying to get a connection back established.
static void free_backtalker(struct Backtalker *b)
Free data structures associated with b.
static void hello_for_client_sync_cb(void *cls)
static void destroy_ack_cummulator(void *cls)
Clean up an idle cumulative acknowledgement data structure.
static void consider_sending_fc(void *cls)
Something changed on the virtual link with respect to flow control.
#define CORE_FC_STALL_TIMEOUT
How long do we wait for CORE to return the flow control credit for the messages we handed it before w...
static unsigned int bsize
static struct GNUNET_TRANSPORT_LinkListContext * llc
Handle to the running listing, NULL once it completed.
static struct GNUNET_Process * p
Helper process we started.
Definition gnunet-uri.c:38
static struct GNUNET_TIME_Relative duration
Option '-d': duration of the mapping.
Definition gnunet-vpn.c:90
enum GNUNET_GenericReturnValue GNUNET_PILS_enable_private_key(struct GNUNET_PILS_Handle *handle)
Enable local access to the private key of the current peer identity.
Definition pils_api.c:896
struct GNUNET_PILS_Handle * GNUNET_PILS_connect(const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_PILS_PidChangeCallback pid_change_cb, void *cls)
Connect to the PILS service.
Definition pils_api.c:624
void GNUNET_PILS_disconnect(struct GNUNET_PILS_Handle *handle)
Disconnect from the PILS service.
Definition pils_api.c:647
struct GNUNET_PILS_Operation * GNUNET_PILS_sign_hello(struct GNUNET_PILS_Handle *handle, const struct GNUNET_HELLO_Builder *builder, struct GNUNET_TIME_Absolute et, GNUNET_PILS_SignResultCallback cb, void *cb_cls)
Create HELLO signature.
Definition pils_api.c:851
const struct GNUNET_CRYPTO_EddsaPrivateKey * GNUNET_PILS_get_private_key(const struct GNUNET_PILS_Handle *handle)
Return the private key of the current peer identity.
Definition pils_api.c:943
void GNUNET_PILS_cancel(struct GNUNET_PILS_Operation *op)
Cancel request.
Definition pils_api.c:776
const struct GNUNET_PeerIdentity * GNUNET_PILS_get_identity(const struct GNUNET_PILS_Handle *handle)
Return the current peer identity of a given handle.
Definition pils_api.c:875
void GNUNET_PILS_feed_addresses(struct GNUNET_PILS_Handle *handle, const struct GNUNET_HELLO_Builder *addresses_builder)
Feed a set of addresses to pils so that it will generate a new peer id based on the given set of addr...
Definition pils_api.c:817
uint32_t dim
#define GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE
Signature by a peer affirming that it received a challenge (and stating how long it expects the addre...
#define GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
Signature by a peer affirming that the given ephemeral key is currently in use by that peer's transpo...
#define GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
Signature by a peer affirming that it originated the DV path.
#define GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
Signature by a peer affirming that it is on a DV path.
#define GNUNET_SIGNATURE_PURPOSE_TRANSPORT_ADDRESS
Signature by a peer affirming that this is one of its addresses for the given time period.
#define GNUNET_TRANSPORT_QUEUE_LENGTH_UNLIMITED
Queue length.
GNUNET_TRANSPORT_CommunicatorCharacteristics
What characteristics does this communicator have?
GNUNET_TRANSPORT_ConnectionStatus
Possible states of a connection.
@ GNUNET_TRANSPORT_CC_RELIABLE
Transmission is reliabile (with ACKs), e.g.
@ GNUNET_TRANSPORT_LINK_ROUTE_DV
Over a distance vector path.
@ GNUNET_TRANSPORT_LINK_ROUTE_DIRECT
Over one or more queues to a directly connected neighbour.
@ GNUNET_TRANSPORT_CS_DOWN
Connection is down.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_yesno(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option)
Get a configuration value that should be in a set of "YES" or "NO".
enum GNUNET_GenericReturnValue GNUNET_CRYPTO_eddsa_kem_decaps(const struct GNUNET_CRYPTO_EddsaPrivateKey *priv, const struct GNUNET_CRYPTO_HpkeEncapsulation *c, struct GNUNET_ShortHashCode *prk)
Decapsulate a key for a private EdDSA key.
uint64_t GNUNET_CRYPTO_random_u64(uint64_t max)
Generate a random unsigned 64-bit value.
enum GNUNET_GenericReturnValue GNUNET_CRYPTO_aead_decrypt(size_t ct_len, const unsigned char ct[ct_len], size_t aad_len, const unsigned char aad[aad_len], const struct GNUNET_CRYPTO_AeadSecretKey *key, const struct GNUNET_CRYPTO_AeadNonce *nonce, const struct GNUNET_CRYPTO_AeadMac *mac, void *pt)
Decrypt the given data using XChaCha20-Poly1305.
enum GNUNET_GenericReturnValue GNUNET_CRYPTO_eddsa_sign_(const struct GNUNET_CRYPTO_EddsaPrivateKey *priv, const struct GNUNET_CRYPTO_SignaturePurpose *purpose, struct GNUNET_CRYPTO_EddsaSignature *sig)
EdDSA sign a given block.
Definition crypto_ecc.c:646
enum GNUNET_GenericReturnValue GNUNET_CRYPTO_aead_encrypt(size_t pt_len, const unsigned char pt[pt_len], size_t aad_len, const unsigned char aad[aad_len], const struct GNUNET_CRYPTO_AeadSecretKey *key, const struct GNUNET_CRYPTO_AeadNonce *nonce, void *ct, struct GNUNET_CRYPTO_AeadMac *mac)
Encrypt the given data using XChaCha20-Poly1305.
void GNUNET_CRYPTO_random_block(void *buffer, size_t length)
Fill block with a random values.
enum GNUNET_GenericReturnValue GNUNET_CRYPTO_eddsa_kem_encaps(const struct GNUNET_CRYPTO_EddsaPublicKey *pub, struct GNUNET_CRYPTO_HpkeEncapsulation *c, struct GNUNET_ShortHashCode *prk)
Encapsulate key material for a EdDSA public key.
#define GNUNET_CRYPTO_eddsa_verify(purp, ps, sig, pub)
Verify EdDSA signature.
uint32_t GNUNET_CRYPTO_random_u32(uint32_t i)
Produce a random value.
#define GNUNET_CONTAINER_MDLL_remove(mdll, head, tail, element)
Remove an element from a MDLL.
#define GNUNET_CONTAINER_MDLL_insert_tail(mdll, head, tail, element)
Insert an element at the tail of a MDLL.
#define GNUNET_CONTAINER_MDLL_insert_after(mdll, head, tail, other, element)
Insert an element into a MDLL after the given other element.
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_MDLL_insert(mdll, head, tail, element)
Insert an element at the head of a MDLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
void GNUNET_CRYPTO_hash(const void *block, size_t size, struct GNUNET_HashCode *ret)
Compute hash of a given block.
Definition crypto_hash.c:40
struct GNUNET_CONTAINER_MultiUuidmap * GNUNET_CONTAINER_multiuuidmap_create(unsigned int len, int do_not_copy_keys)
Create a multi peer map (hash map for public keys of peers).
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_multihashmap_contains(const struct GNUNET_CONTAINER_MultiHashMap *map, const struct GNUNET_HashCode *key)
Check if the map contains any value under the given key (including values that are NULL).
void * GNUNET_CONTAINER_multipeermap_get(const struct GNUNET_CONTAINER_MultiPeerMap *map, const struct GNUNET_PeerIdentity *key)
Given a key find a value in the map matching the key.
int GNUNET_CONTAINER_multihashmap32_get_multiple(struct GNUNET_CONTAINER_MultiHashMap32 *map, uint32_t key, GNUNET_CONTAINER_MultiHashMapIterator32Callback it, void *it_cls)
Iterate over all entries in the map that match a particular key.
int GNUNET_CONTAINER_multihashmap_iterate(struct GNUNET_CONTAINER_MultiHashMap *map, GNUNET_CONTAINER_MultiHashMapIteratorCallback it, void *it_cls)
Iterate over all entries in the map.
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_multihashmap32_put(struct GNUNET_CONTAINER_MultiHashMap32 *map, uint32_t key, void *value, enum GNUNET_CONTAINER_MultiHashMapOption opt)
Store a key-value pair in the map.
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_multipeermap_contains(const struct GNUNET_CONTAINER_MultiPeerMap *map, const struct GNUNET_PeerIdentity *key)
Check if the map contains any value under the given key (including values that are NULL).
void GNUNET_CONTAINER_multipeermap_destroy(struct GNUNET_CONTAINER_MultiPeerMap *map)
Destroy a hash map.
struct GNUNET_CONTAINER_MultiHashMap32 * GNUNET_CONTAINER_multihashmap32_create(unsigned int len)
Create a 32-bit key multi hash map.
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_multihashmap32_remove(struct GNUNET_CONTAINER_MultiHashMap32 *map, uint32_t key, const void *value)
Remove the given key-value pair from the map.
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_multihashmap_remove(struct GNUNET_CONTAINER_MultiHashMap *map, const struct GNUNET_HashCode *key, const void *value)
Remove the given key-value pair from the map.
int GNUNET_CONTAINER_multipeermap_iterate(struct GNUNET_CONTAINER_MultiPeerMap *map, GNUNET_CONTAINER_PeerMapIterator it, void *it_cls)
Iterate over all entries in the map.
unsigned int GNUNET_CONTAINER_multihashmap32_size(const struct GNUNET_CONTAINER_MultiHashMap32 *map)
Get the number of key-value pairs in the map.
struct GNUNET_CONTAINER_MultiShortmap * GNUNET_CONTAINER_multishortmap_create(unsigned int len, int do_not_copy_keys)
Create a multi peer map (hash map for public keys of peers).
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_multishortmap_put(struct GNUNET_CONTAINER_MultiShortmap *map, const struct GNUNET_ShortHashCode *key, void *value, enum GNUNET_CONTAINER_MultiHashMapOption opt)
Store a key-value pair in the map.
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_multihashmap_put(struct GNUNET_CONTAINER_MultiHashMap *map, const struct GNUNET_HashCode *key, void *value, enum GNUNET_CONTAINER_MultiHashMapOption opt)
Store a key-value pair in the map.
unsigned int GNUNET_CONTAINER_multihashmap_size(const struct GNUNET_CONTAINER_MultiHashMap *map)
Get the number of key-value pairs in the map.
void GNUNET_CONTAINER_multihashmap_destroy(struct GNUNET_CONTAINER_MultiHashMap *map)
Destroy a hash map.
struct GNUNET_CONTAINER_MultiHashMap * GNUNET_CONTAINER_multihashmap_create(unsigned int len, int do_not_copy_keys)
Create a multi hash map.
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_multiuuidmap_remove(struct GNUNET_CONTAINER_MultiUuidmap *map, const struct GNUNET_Uuid *key, const void *value)
Remove the given key-value pair from the map.
void GNUNET_CONTAINER_multiuuidmap_destroy(struct GNUNET_CONTAINER_MultiUuidmap *map)
Destroy a hash map.
struct GNUNET_CONTAINER_MultiPeerMap * GNUNET_CONTAINER_multipeermap_create(unsigned int len, int do_not_copy_keys)
Create a multi peer map (hash map for public keys of peers).
void GNUNET_CONTAINER_multishortmap_destroy(struct GNUNET_CONTAINER_MultiShortmap *map)
Destroy a hash map.
void GNUNET_CONTAINER_multihashmap32_destroy(struct GNUNET_CONTAINER_MultiHashMap32 *map)
Destroy a 32-bit key hash map.
int GNUNET_CONTAINER_multipeermap_get_multiple(struct GNUNET_CONTAINER_MultiPeerMap *map, const struct GNUNET_PeerIdentity *key, GNUNET_CONTAINER_PeerMapIterator it, void *it_cls)
Iterate over all entries in the map that match a particular key.
unsigned int GNUNET_CONTAINER_multishortmap_size(const struct GNUNET_CONTAINER_MultiShortmap *map)
Get the number of key-value pairs in the map.
unsigned int GNUNET_CONTAINER_multipeermap_size(const struct GNUNET_CONTAINER_MultiPeerMap *map)
Get the number of key-value pairs in the map.
int GNUNET_CONTAINER_multipeermap_put(struct GNUNET_CONTAINER_MultiPeerMap *map, const struct GNUNET_PeerIdentity *key, void *value, enum GNUNET_CONTAINER_MultiHashMapOption opt)
Store a key-value pair in the map.
int GNUNET_CONTAINER_multihashmap32_iterate(struct GNUNET_CONTAINER_MultiHashMap32 *map, GNUNET_CONTAINER_MultiHashMapIterator32Callback it, void *it_cls)
Iterate over all entries in the map.
int GNUNET_CONTAINER_multishortmap_remove(struct GNUNET_CONTAINER_MultiShortmap *map, const struct GNUNET_ShortHashCode *key, const void *value)
Remove the given key-value pair from the map.
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_multiuuidmap_iterate(struct GNUNET_CONTAINER_MultiUuidmap *map, GNUNET_CONTAINER_MultiUuidmapIteratorCallback it, void *it_cls)
Iterate over all entries in the map.
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_multiuuidmap_put(struct GNUNET_CONTAINER_MultiUuidmap *map, const struct GNUNET_Uuid *key, void *value, enum GNUNET_CONTAINER_MultiHashMapOption opt)
Store a key-value pair in the map.
void * GNUNET_CONTAINER_multiuuidmap_get(const struct GNUNET_CONTAINER_MultiUuidmap *map, const struct GNUNET_Uuid *key)
Given a key find a value in the map matching the key.
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_multipeermap_remove(struct GNUNET_CONTAINER_MultiPeerMap *map, const struct GNUNET_PeerIdentity *key, const void *value)
Remove the given key-value pair from the map.
@ GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE
Allow multiple values with the same key.
@ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY
There must only be one value per key; storing a value should fail if a value under the same key alrea...
void * GNUNET_CONTAINER_heap_remove_node(struct GNUNET_CONTAINER_HeapNode *node)
Removes a node from the heap.
void * GNUNET_CONTAINER_heap_peek(const struct GNUNET_CONTAINER_Heap *heap)
Get element stored at the root of heap.
void GNUNET_CONTAINER_heap_update_cost(struct GNUNET_CONTAINER_HeapNode *node, GNUNET_CONTAINER_HeapCostType new_cost)
Updates the cost of any node in the tree.
struct GNUNET_CONTAINER_HeapNode * GNUNET_CONTAINER_heap_insert(struct GNUNET_CONTAINER_Heap *heap, void *element, GNUNET_CONTAINER_HeapCostType cost)
Inserts a new element into the heap.
struct GNUNET_CONTAINER_Heap * GNUNET_CONTAINER_heap_create(enum GNUNET_CONTAINER_HeapOrder order)
Create a new heap.
void GNUNET_CONTAINER_heap_destroy(struct GNUNET_CONTAINER_Heap *heap)
Destroys the heap.
@ GNUNET_CONTAINER_HEAP_ORDER_MIN
Heap with the minimum cost at the root.
void GNUNET_HELLO_parser_free(struct GNUNET_HELLO_Parser *parser)
Release resources of a builder.
Definition hello-uri.c:380
void GNUNET_HELLO_builder_free(struct GNUNET_HELLO_Builder *builder)
Release resources of a builder.
Definition hello-uri.c:398
struct GNUNET_HELLO_Builder * GNUNET_HELLO_builder_new()
Allocate builder.
Definition hello-uri.c:344
void GNUNET_HELLO_builder_iterate(const struct GNUNET_HELLO_Builder *builder, GNUNET_HELLO_UriCallback uc, void *uc_cls)
Iterate over URIs in a builder.
Definition hello-uri.c:1033
struct GNUNET_HELLO_Builder * GNUNET_HELLO_builder_from_parser(const struct GNUNET_HELLO_Parser *parser, struct GNUNET_PeerIdentity *pid)
Allocate builder from parser.
Definition hello-uri.c:361
const struct GNUNET_PeerIdentity * GNUNET_HELLO_parser_iterate(const struct GNUNET_HELLO_Parser *parser, GNUNET_HELLO_UriCallback uc, void *uc_cls)
Iterate over URIs in a parser.
Definition hello-uri.c:1052
struct GNUNET_MQ_Envelope * GNUNET_HELLO_parser_to_env(const struct GNUNET_HELLO_Parser *parser)
Generate envelope with GNUnet HELLO message (including peer ID) from a parser.
Definition hello-uri.c:980
enum GNUNET_GenericReturnValue GNUNET_HELLO_builder_address_list_cmp(const struct GNUNET_HELLO_Builder *abuilder, const struct GNUNET_HELLO_Builder *bbuilder)
Compare address lists of two builders.
Definition hello-uri.c:1408
enum GNUNET_GenericReturnValue GNUNET_HELLO_builder_del_address(struct GNUNET_HELLO_Builder *builder, const char *address)
Remove individual address from the builder.
Definition hello-uri.c:1009
const struct GNUNET_PeerIdentity * GNUNET_HELLO_parser_get_id(const struct GNUNET_HELLO_Parser *parser)
Get the PeerIdentity for this builder.
Definition hello-uri.c:354
#define GNUNET_HELLO_ADDRESS_EXPIRATION
For how long are HELLO signatures valid?
struct GNUNET_HELLO_Parser * GNUNET_HELLO_parser_from_msg(const struct GNUNET_MessageHeader *msg, const struct GNUNET_PeerIdentity *pid)
Parse msg.
Definition hello-uri.c:416
enum GNUNET_GenericReturnValue GNUNET_HELLO_builder_add_address(struct GNUNET_HELLO_Builder *builder, const char *address)
Add individual address to the builder.
Definition hello-uri.c:701
char * GNUNET_HELLO_address_to_prefix(const char *address)
Given an address as a string, extract the prefix that identifies the communicator offering transmissi...
Definition hello-uri.c:1139
struct GNUNET_MQ_Envelope * GNUNET_HELLO_builder_to_env(const struct GNUNET_HELLO_Builder *builder, const struct GNUNET_PeerIdentity *pid, const struct GNUNET_CRYPTO_EddsaSignature *sig, struct GNUNET_TIME_Absolute expiration_time)
Generate envelope with GNUnet HELLO message (including peer ID) from a builder.
Definition hello-uri.c:1219
#define GNUNET_is_zero(a)
Check that memory in a is all zeros.
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
#define GNUNET_log(kind,...)
#define GNUNET_MAX(a, b)
void GNUNET_CRYPTO_hash_context_read(struct GNUNET_HashContext *hc, const void *buf, size_t size)
Add data to be hashed.
uint64_t GNUNET_ntohll(uint64_t n)
Convert unsigned 64-bit integer to host byte order.
GNUNET_SCHEDULER_Priority
Valid task priorities.
#define GNUNET_NETWORK_STRUCT_END
Define as empty, GNUNET_PACKED should suffice, but this won't work on W32;.
#define GNUNET_memcmp(a, b)
Compare memory in a and b, where both must be of the same pointer type.
uint64_t GNUNET_htonll(uint64_t n)
Convert unsigned 64-bit integer to network byte order.
void GNUNET_CRYPTO_hash_context_finish(struct GNUNET_HashContext *hc, struct GNUNET_HashCode *r_hash)
Finish the hash computation.
#define GNUNET_ALIGN
gcc-ism to force alignment; we use this to align char-arrays that may then be cast to 'struct's.
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
GNUNET_GenericReturnValue
Named constants for return values.
#define GNUNET_MIN(a, b)
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format.
struct GNUNET_HashContext * GNUNET_CRYPTO_hash_context_start(void)
Start incremental hashing operation.
#define GNUNET_static_assert(cond)
#define GNUNET_PACKED
gcc-ism to get packed structs.
@ GNUNET_SCHEDULER_PRIORITY_BACKGROUND
Run as background job (higher than idle, lower than default).
@ GNUNET_SCHEDULER_PRIORITY_DEFAULT
Run with the default priority (normal P2P operations).
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
const char * GNUNET_uuid2s(const struct GNUNET_Uuid *uuid)
Convert a UUID to a string (for printing debug messages).
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
const char * GNUNET_i2s(const struct GNUNET_PeerIdentity *pid)
Convert a peer identity to a string (for printing debug messages).
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
const char * GNUNET_sh2s(const struct GNUNET_ShortHashCode *shc)
Convert a short hash value to a string (for printing debug messages).
const char * GNUNET_i2s_full(const struct GNUNET_PeerIdentity *pid)
Convert a peer identity to a string (for printing debug messages).
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
const char * GNUNET_h2s(const struct GNUNET_HashCode *hc)
Convert a hash value to a string (for printing debug messages).
const char * GNUNET_i2s2(const struct GNUNET_PeerIdentity *pid)
Convert a peer identity to a string (for printing debug messages).
#define GNUNET_EXTRA_LOGGING
define GNUNET_EXTRA_LOGGING if using this header outside the GNUnet source tree where gnunet_config....
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
@ GNUNET_ERROR_TYPE_INFO
int int GNUNET_asprintf(char **buf, const char *format,...) __attribute__((format(printf
Like asprintf, just portable.
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_strndup(a, length)
Wrapper around GNUNET_xstrndup_.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_free(ptr)
Wrapper around free.
void GNUNET_MQ_send(struct GNUNET_MQ_Handle *mq, struct GNUNET_MQ_Envelope *ev)
Send a message with the given message queue.
Definition mq.c:337
#define GNUNET_MQ_handler_end()
End-marker for the handlers array.
#define GNUNET_MQ_check_zero_termination(m)
Insert code for a "check_" function that verifies that a given variable-length message received over ...
void GNUNET_MQ_discard(struct GNUNET_MQ_Envelope *mqm)
Discard the message queue message, free all allocated resources.
Definition mq.c:317
#define GNUNET_MQ_msg_extra(mvar, esize, type)
Allocate an envelope, with extra space allocated after the space needed by the message struct.
#define GNUNET_MQ_check_boxed_message(m)
Insert code for a "check_" function that verifies that a given variable-length message received over ...
#define GNUNET_MQ_msg(mvar, type)
Allocate a GNUNET_MQ_Envelope.
GNUNET_MQ_PriorityPreferences
Per envelope preferences and priorities.
#define GNUNET_MQ_hd_var_size(name, code, str, ctx)
void GNUNET_MQ_notify_sent(struct GNUNET_MQ_Envelope *ev, GNUNET_SCHEDULER_TaskCallback cb, void *cb_cls)
Call a callback once the envelope has been sent, that is, sending it can not be canceled anymore.
Definition mq.c:687
const struct GNUNET_MessageHeader * GNUNET_MQ_env_get_msg(const struct GNUNET_MQ_Envelope *env)
Obtain message contained in envelope.
Definition mq.c:928
#define GNUNET_MQ_hd_fixed_size(name, code, str, ctx)
enum GNUNET_GenericReturnValue GNUNET_MQ_try_handle_message(const struct GNUNET_MQ_MessageHandler *handlers, const struct GNUNET_MessageHeader *mh)
Same as GNUNET_MQ_handle_message(), except that a message for which no handler is registered is not l...
Definition mq.c:291
@ GNUNET_MQ_PRIO_BACKGROUND
Lowest priority, i.e.
@ GNUNET_MQ_PREF_UNRELIABLE
Flag to indicate that unreliable delivery is acceptable.
@ GNUNET_MQ_PREF_LOW_LATENCY
Flag to indicate that low latency is important.
void GNUNET_is_burst_ready(struct GNUNET_TIME_Relative rtt_average, struct GNUNET_BurstSync *burst_sync, GNUNET_SCHEDULER_TaskCallback task, struct GNUNET_StartBurstCls *task_cls)
Checks if we are ready and starts burst when we and the other peer is ready.
Definition nat.c:89
struct GNUNET_NAT_Handle * GNUNET_NAT_register(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *config_section, uint8_t proto, unsigned int num_addrs, const struct sockaddr **addrs, const socklen_t *addrlens, GNUNET_NAT_AddressCallback address_callback, GNUNET_NAT_ReversalCallback reversal_callback, void *callback_cls)
Attempt to enable port redirection and detect public IP address contacting UPnP or NAT-PMP routers on...
Definition nat_api.c:366
void GNUNET_NAT_unregister(struct GNUNET_NAT_Handle *nh)
Stop port redirection and public IP address detection for the given handle.
Definition nat_api.c:703
void GNUNET_NAT_add_global_address(struct GNUNET_NAT_Handle *nh, char *addr, unsigned int address_length)
Add global address to the list of addresses and notify clients.
Definition nat_api.c:460
GNUNET_NetworkType
Types of networks (with separate quotas) we support.
const struct GNUNET_OS_ProjectData * GNUNET_OS_project_data_gnunet(void)
Return default project data used by 'libgnunetutil' for GNUnet.
void GNUNET_PEERSTORE_monitor_stop(struct GNUNET_PEERSTORE_Monitor *zm)
Stop monitoring.
struct GNUNET_PEERSTORE_IterateContext * GNUNET_PEERSTORE_iteration_start(struct GNUNET_PEERSTORE_Handle *h, const char *sub_system, const struct GNUNET_PeerIdentity *peer, const char *key, GNUNET_PEERSTORE_Processor callback, void *callback_cls)
Iterate over peerstore entries.
void GNUNET_PEERSTORE_iteration_next(struct GNUNET_PEERSTORE_IterateContext *ic, uint64_t limit)
Continue an iteration.
void GNUNET_PEERSTORE_store_cancel(struct GNUNET_PEERSTORE_StoreContext *sc)
Cancel a store request.
#define GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME
Key used to store sender's monotonic time from backchannel messages.
void GNUNET_PEERSTORE_disconnect(struct GNUNET_PEERSTORE_Handle *h)
Disconnect from the PEERSTORE service.
#define GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY
Key used for storing addresses in URL format in the peerstore.
struct GNUNET_PEERSTORE_Monitor * GNUNET_PEERSTORE_monitor_start(const struct GNUNET_CONFIGURATION_Handle *cfg, int iterate_first, const char *sub_system, const struct GNUNET_PeerIdentity *peer, const char *key, GNUNET_SCHEDULER_TaskCallback error_cb, void *error_cb_cls, GNUNET_SCHEDULER_TaskCallback sync_cb, void *sync_cb_cls, GNUNET_PEERSTORE_Processor callback, void *callback_cls)
Request watching a given key The monitoring can be filtered to contain only records matching peer and...
#define GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME
Key used to store sender's monotonic time from DV learn messages.
struct GNUNET_PEERSTORE_Handle * GNUNET_PEERSTORE_connect(const struct GNUNET_CONFIGURATION_Handle *cfg)
Connect to the PEERSTORE service.
void GNUNET_PEERSTORE_monitor_next(struct GNUNET_PEERSTORE_Monitor *zm, uint64_t limit)
Calls the monitor processor specified in GNUNET_PEERSTORE_monitor_start for the next record(s).
void GNUNET_PEERSTORE_hello_add_cancel(struct GNUNET_PEERSTORE_StoreHelloContext *huc)
Cancel the request to add a hello.
struct GNUNET_PEERSTORE_StoreContext * GNUNET_PEERSTORE_store(struct GNUNET_PEERSTORE_Handle *h, const char *sub_system, const struct GNUNET_PeerIdentity *peer, const char *key, const void *value, size_t size, struct GNUNET_TIME_Absolute expiry, enum GNUNET_PEERSTORE_StoreOption options, GNUNET_PEERSTORE_Continuation cont, void *cont_cls)
Store a new entry in the PEERSTORE.
#define GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY
Key used for storing HELLOs in the peerstore.
void GNUNET_PEERSTORE_iteration_stop(struct GNUNET_PEERSTORE_IterateContext *ic)
Cancel an iteration.
#define GNUNET_PEERSTORE_HELLO_KEY
Key used for storing HELLO in the peerstore.
struct GNUNET_PEERSTORE_StoreHelloContext * GNUNET_PEERSTORE_hello_add(struct GNUNET_PEERSTORE_Handle *h, const struct GNUNET_MessageHeader *msg, GNUNET_PEERSTORE_Continuation cont, void *cont_cls)
Add hello to peerstore.
@ GNUNET_PEERSTORE_STOREOPTION_MULTIPLE
Possibly store multiple values under given key.
@ GNUNET_PEERSTORE_STOREOPTION_REPLACE
Delete any previous values for the given key before storing the given value.
#define GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE
P2P message: transport requests confirmation that an address works.
#define GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK
transport acknowledges processing an incoming message
#define GNUNET_MESSAGE_TYPE_TRANSPORT_LINK_LIST_RESPONSE
Information about a single virtual link, in response to a GNUNET_MESSAGE_TYPE_TRANSPORT_LINK_LIST_REQ...
#define GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT
Message from TRANSPORT notifying about a client that connected to us.
#define GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN
inform transport that a queue was torn down
#define GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION
Type of the 'struct RequestHelloValidationMessage' send by clients to TRANSPORT to trigger validation...
#define GNUNET_MESSAGE_TYPE_TRANSPORT_START
Message from the core saying that the transport server should start giving it messages.
#define GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA
Message sent to indicate to a monitor about events.
#define GNUNET_MESSAGE_TYPE_TRANSPORT_LINK_LIST_REQUEST
Request a one-shot listing of the virtual links transport currently has, with their flow control stat...
#define GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR
Message sent to indicate to the transport which address prefix is supported by a communicator.
#define GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK
Message telling transport to limit its receive rate.
#define GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT
Type of a fragment of a CORE message created by transport to adjust message length to a queue's MTU.
#define GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL
Response from communicator: address bogus, will not try to create queue.
#define GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX
Source-routed transport message based DV information gathered.
#define GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX
Wrapper around non-fragmented CORE message used to measure RTT and ensure reliability.
#define GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL
Type of the 'struct ExpressPreferenceMessage' send by clients to TRANSPORT to abandon bandwidth prefe...
#define GNUNET_MESSAGE_TYPE_TRANSPORT_RECV
Message from TRANSPORT notifying about a message that was received.
#define GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION
Message type used between transport services when they internally forward communicator backchannel me...
#define GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE
transport tells communicator it wants a queue
#define GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN
Message sent for topology discovery at transport level.
#define GNUNET_MESSAGE_TYPE_TRANSPORT_BURST_FINISHED
Burst message we send to another peer for hole punching.
#define GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL
Tell transport that it should assist with exchanging a message between communicators.
#define GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT
Message from TRANSPORT notifying about a client that disconnected from us.
#define GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG
inform transport about an incoming message
#define GNUNET_MESSAGE_TYPE_TRANSPORT_START_BURST
Burst message we send to another peer for hole punching.
#define GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK
Response from communicator: will try to create queue.
#define GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING
Transport signalling incoming backchannel message to a communicator.
#define GNUNET_MESSAGE_TYPE_TRANSPORT_LINK_LIST_RESPONSE_END
End of the responses to a GNUNET_MESSAGE_TYPE_TRANSPORT_LINK_LIST_REQUEST.
#define GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK
communicator tells transports that message was sent
#define GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS
inform transport to add an address of this peer
#define GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START
Message sent to indicate to the transport that a monitor wants to observe certain events.
#define GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS
inform transport to delete an address of this peer
#define GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE
P2P message: transport proves that an address worked.
#define GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL
Transport signalling incoming backchannel message to a communicator.
#define GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG
transport tells communicator it wants to transmit
#define GNUNET_MESSAGE_TYPE_TRANSPORT_SEND
Request to TRANSPORT to transmit a message.
#define GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK
Confirmation from TRANSPORT that message for transmission has been queued (and that the next message ...
#define GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK
Confirmation for a GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX.
#define GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP
inform transport that a queue was setup to talk to some peer
#define GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST
Type of the 'struct ExpressPreferenceMessage' send by clients to TRANSPORT to establish bandwidth pre...
#define GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_UPDATE
inform transport that a queue was updated
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition scheduler.c:572
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_at(struct GNUNET_TIME_Absolute at, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run at the specified time.
Definition scheduler.c:1260
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_shutdown(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run on shutdown, that is when a CTRL-C signal is received,...
Definition scheduler.c:1345
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition scheduler.c:986
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_now(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run as soon as possible.
Definition scheduler.c:1310
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed(struct GNUNET_TIME_Relative delay, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition scheduler.c:1283
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed_with_priority(struct GNUNET_TIME_Relative delay, enum GNUNET_SCHEDULER_Priority priority, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition scheduler.c:1213
#define GNUNET_SERVICE_MAIN(pd, service_name, service_options, init_cb, connect_cb, disconnect_cb, cls,...)
Creates the "main" function for a GNUnet service.
void GNUNET_SERVICE_shutdown(struct GNUNET_SERVICE_Handle *sh)
Explicitly stops the service.
Definition service.c:2512
void GNUNET_SERVICE_client_mark_monitor(struct GNUNET_SERVICE_Client *c)
Set the 'monitor' flag on this client.
Definition service.c:2528
void GNUNET_SERVICE_client_drop(struct GNUNET_SERVICE_Client *c)
Ask the server to disconnect from the given client.
Definition service.c:2463
void GNUNET_SERVICE_client_continue(struct GNUNET_SERVICE_Client *c)
Continue receiving further messages from the given client.
Definition service.c:2434
@ GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN
Trigger a SOFT server shutdown on signals, allowing active non-monitor clients to complete their tran...
struct GNUNET_STATISTICS_Handle * GNUNET_STATISTICS_create(const char *subsystem, const struct GNUNET_CONFIGURATION_Handle *cfg)
Get handle for the statistics service.
void GNUNET_STATISTICS_update(struct GNUNET_STATISTICS_Handle *handle, const char *name, int64_t delta, int make_persistent)
Set statistic value for the peer.
void GNUNET_STATISTICS_destroy(struct GNUNET_STATISTICS_Handle *h, int sync_first)
Destroy a handle (free all state associated with it).
size_t GNUNET_STRINGS_base64_encode(const void *in, size_t len, char **output)
Encode into Base64.
Definition strings.c:1629
struct GNUNET_TIME_Relative GNUNET_TIME_relative_min(struct GNUNET_TIME_Relative t1, struct GNUNET_TIME_Relative t2)
Return the minimum of two relative time values.
Definition time.c:344
const char * GNUNET_TIME_relative2s(struct GNUNET_TIME_Relative delta, bool do_round)
Give relative time in human-readable fancy format.
Definition time.c:264
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
struct GNUNET_TIME_Relative GNUNET_TIME_relative_ntoh(struct GNUNET_TIME_RelativeNBO a)
Convert relative time from network byte order.
Definition time.c:626
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_duration(struct GNUNET_TIME_Absolute whence)
Get the duration of an operation as the difference of the current time and the given start time "henc...
Definition time.c:438
struct GNUNET_TIME_Relative GNUNET_TIME_relative_max(struct GNUNET_TIME_Relative t1, struct GNUNET_TIME_Relative t2)
Return the maximum of two relative time values.
Definition time.c:352
#define GNUNET_TIME_relative_cmp(t1, op, t2)
Compare two relative times.
#define GNUNET_TIME_UNIT_SECONDS
One second.
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_remaining(struct GNUNET_TIME_Absolute future)
Given a timestamp in the future, how much time remains until then?
Definition time.c:406
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_max(struct GNUNET_TIME_Absolute t1, struct GNUNET_TIME_Absolute t2)
Return the maximum of two absolute time values.
Definition time.c:368
const char * GNUNET_STRINGS_relative_time_to_string(struct GNUNET_TIME_Relative delta, int do_round)
Give relative time in human-readable fancy format.
Definition strings.c:610
struct GNUNET_TIME_Relative GNUNET_TIME_randomized_backoff(struct GNUNET_TIME_Relative rt, struct GNUNET_TIME_Relative threshold)
Randomized exponential back-off, starting at 1 ms and going up by a factor of 2+r,...
Definition time.c:830
struct GNUNET_TIME_Relative GNUNET_TIME_relative_subtract(struct GNUNET_TIME_Relative a1, struct GNUNET_TIME_Relative a2)
Subtract relative timestamp from the other.
Definition time.c:601
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition time.c:111
#define GNUNET_TIME_UNIT_MINUTES
One minute.
struct GNUNET_TIME_Relative GNUNET_TIME_relative_multiply_double(struct GNUNET_TIME_Relative rel, double factor)
Multiply relative time by a given factor.
Definition time.c:506
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_ntoh(struct GNUNET_TIME_AbsoluteNBO a)
Convert absolute time from network byte order.
Definition time.c:737
struct GNUNET_TIME_Relative GNUNET_TIME_relative_add(struct GNUNET_TIME_Relative a1, struct GNUNET_TIME_Relative a2)
Add relative times together.
Definition time.c:583
struct GNUNET_TIME_Relative GNUNET_TIME_randomize(struct GNUNET_TIME_Relative r)
Return a random time value between 0.5*r and 1.5*r.
Definition time.c:851
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_subtract(struct GNUNET_TIME_Absolute start, struct GNUNET_TIME_Relative duration)
Subtract a given relative duration from the given start time.
Definition time.c:471
struct GNUNET_TIME_Absolute GNUNET_TIME_relative_to_absolute(struct GNUNET_TIME_Relative rel)
Convert relative time to an absolute time in the future.
Definition time.c:316
struct GNUNET_TIME_Relative GNUNET_TIME_relative_multiply(struct GNUNET_TIME_Relative rel, unsigned long long factor)
Multiply relative time by a given factor.
Definition time.c:486
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_min(struct GNUNET_TIME_Absolute t1, struct GNUNET_TIME_Absolute t2)
Return the minimum of two absolute time values.
Definition time.c:360
#define GNUNET_TIME_UNIT_ZERO
Relative time zero.
struct GNUNET_TIME_RelativeNBO GNUNET_TIME_relative_hton(struct GNUNET_TIME_Relative a)
Convert relative time to network byte order.
Definition time.c:616
#define GNUNET_TIME_absolute_cmp(t1, op, t2)
Compare two absolute times.
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_add(struct GNUNET_TIME_Absolute start, struct GNUNET_TIME_Relative duration)
Add a given relative duration to the given start time.
Definition time.c:452
#define GNUNET_TIME_UNIT_ZERO_ABS
Absolute time zero.
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get_monotonic(const struct GNUNET_CONFIGURATION_Handle *cfg)
Obtain the current time and make sure it is monotonically increasing.
Definition time.c:860
struct GNUNET_TIME_Relative GNUNET_TIME_relative_divide(struct GNUNET_TIME_Relative rel, unsigned long long factor)
Divide relative time by a given factor.
Definition time.c:548
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_difference(struct GNUNET_TIME_Absolute start, struct GNUNET_TIME_Absolute end)
Compute the time difference between the given start and end times.
Definition time.c:423
struct GNUNET_TIME_AbsoluteNBO GNUNET_TIME_absolute_hton(struct GNUNET_TIME_Absolute a)
Convert absolute time to network byte order.
Definition time.c:636
const char * GNUNET_STRINGS_absolute_time_to_string(struct GNUNET_TIME_Absolute t)
Like asctime, except for GNUnet time.
Definition strings.c:671
#define GNUNET_TIME_UNIT_FOREVER_ABS
Constant used to specify "forever".
#define GNUNET_TIME_STD_BACKOFF(r)
Perform our standard exponential back-off calculation, starting at 1 ms and then going by a factor of...
static unsigned int size
Size of the "table".
Definition peer.c:68
#define _(String)
GNU gettext support macro.
Definition platform.h:179
static struct GNUNET_MQ_Handle * mq
Our connection to the resolver service, created on-demand, but then persists until error or shutdown.
static struct GNUNET_SCHEDULER_TaskContext tc
Task context of the current task.
Definition scheduler.c:436
static struct GNUNET_TIME_Relative delta
Definition speedup.c:36
Data structure in which we track acknowledgements still to be sent to the.
struct GNUNET_SCHEDULER_Task * task
Task scheduled either to transmit the cumulative ACK message, or to clean up this data structure afte...
struct GNUNET_TIME_Absolute min_transmission_time
When is task run (only used if num_acks is non-zero)?
struct TransportCummulativeAckPayload ack_uuids[64]
ACK data being accumulated.
struct GNUNET_PeerIdentity target
Target peer for which we are accumulating ACKs here.
unsigned int num_acks
Number of entries used in ack_uuids.
uint32_t ack_counter
Counter to produce the ack_counter in the struct TransportReliabilityAckMessage.
Unique identifier to map an acknowledgement to a transmission.
struct GNUNET_Uuid value
The UUID value.
size_t size
Capacity of tgnas, so that a drift between the cached ‘number_of_addresses’ / ‘size_of_global_address...
One of the addresses of this peer.
struct GNUNET_TIME_Relative expiration
What is a typical lifetime the communicator expects this address to have? (Always from now....
uint32_t aid
Address identifier used by the communicator.
struct GNUNET_TIME_Relative pils_backoff
Backoff used while waiting for PILS to hand us our peer identity.
size_t signed_address_len
Signed address length.
enum GNUNET_NetworkType nt
Network type offered by this address.
struct AddressListEntry * prev
Kept in a DLL.
struct TransportClient * tc
Which communicator provides this address?
struct AddressListEntry * next
Kept in a DLL.
struct GNUNET_PEERSTORE_StoreHelloContext * shc
Store hello handle.
void * signed_address
Signed address.
struct PilsAddressSignContext * pc
Context of the sign-and-store chain currently running for this entry, or NULL.
const char * address
The actual address.
struct GNUNET_SCHEDULER_Task * st
Task to periodically do st operation.
struct GNUNET_PEERSTORE_StoreContext * sc
Current context for storing this address in the peerstore.
A Backtalker is a peer sending us backchannel messages.
struct GNUNET_TIME_Absolute timeout
When will this entry time out?
struct CommunicatorMessageContext * cmc
Communicator context waiting on this backchannel's get, or NULL.
struct GNUNET_CRYPTO_HpkeEncapsulation last_ephemeral
Last (valid) ephemeral key received from this sender.
struct GNUNET_PEERSTORE_StoreContext * sc
Handle to a PEERSTORE store operation for this pid's monotonic_time.
struct GNUNET_SCHEDULER_Task * task
Task associated with this backtalker.
size_t body_size
Number of bytes of the original message body that follows after this struct.
struct GNUNET_TIME_Absolute monotonic_time
Last (valid) monotonic time received from this sender.
struct GNUNET_PEERSTORE_IterateContext * get
Handle for an operation to fetch monotonic_time information from the PEERSTORE, or NULL.
struct GNUNET_PeerIdentity pid
Peer this is about.
Closure for check_known_address.
struct ValidationState * vs
Set to a matching validation state, if one was found.
const char * address
Set to the address we are looking for.
Closure for check_known_challenge.
struct ValidationState * vs
Set to a matching validation state, if one was found.
const struct GNUNET_CRYPTO_ChallengeNonceP * challenge
Set to the challenge we are looking for.
Context from handle_incoming_msg().
unsigned int client_resumed
Did we already call GNUNET_SERVICE_client_continue()? That call is per client, not per message,...
struct CommunicatorMessageContext * next
Kept in a DLL of struct VirtualLink if waiting for CORE flow control to unchoke.
uint16_t total_hops
Number of hops the message has travelled (if DV-routed).
struct GNUNET_TRANSPORT_IncomingMessage im
Additional information for flow control and about the sender.
const struct GNUNET_MessageHeader * mh
The message to demultiplex.
unsigned int ack_sent
Did we already send the flow control ACK to the communicator? The ACK is per-message and expresses CO...
struct CommunicatorMessageContext * prev
Kept in a DLL of struct VirtualLink if waiting for CORE flow control to unchoke.
struct TransportClient * tc
Which communicator provided us with the message.
Message from the transport service to the library informing about neighbors.
Definition transport.h:90
struct GNUNET_PeerIdentity id
Identity of the new neighbour.
Definition transport.h:113
Closure for core_env_sent_cb.
uint16_t isize
By how much should we increment vl's incoming_fc_window_size_used once we are done sending to CORE?...
struct CoreSentContext * next
Kept in a DLL to clear vl in case vl is lost.
struct VirtualLink * vl
Virtual link this is about.
struct CoreSentContext * prev
Kept in a DLL to clear vl in case vl is lost.
uint16_t size
How big was the message.
An entry describing a peer on a path in a struct TransportDVLearnMessage message.
struct GNUNET_CRYPTO_EddsaSignature hop_sig
Signature of this hop over the path, of purpose GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP.
struct GNUNET_PeerIdentity hop
Identity of a peer on the path.
Message from the transport service to the library informing about disconnects.
Definition transport.h:122
One possible hop towards a DV target.
struct PerformanceData pd
Performance data for this transmission possibility.
struct PendingAcknowledgement * pa_head
Head of DLL of PAs that used our path.
unsigned int distance
Number of hops in total to the target (excluding next_hop and target itself).
struct DistanceVectorHop * next_neighbour
Kept in a MDLL.
struct Neighbour * next_hop
What would be the next hop to target?
struct GNUNET_TIME_Absolute timeout
At what time do we forget about this path unless we see it again while learning?
struct DistanceVector * dv
Distance vector entry this hop belongs with.
const struct GNUNET_PeerIdentity * path
Array of distance hops to the target, excluding next_hop.
struct DistanceVectorHop * next_dv
Kept in a MDLL, sorted by timeout.
struct GNUNET_TIME_Absolute path_valid_until
For how long is the validation of this path considered valid? Set to ZERO if the path is learned by s...
struct DistanceVectorHop * prev_dv
Kept in a MDLL, sorted by timeout.
struct DistanceVectorHop * prev_neighbour
Kept in a MDLL.
struct PendingAcknowledgement * pa_tail
Tail of DLL of PAs that used our path.
Entry in our dv_routes table, representing a (set of) distance vector routes to a particular peer.
struct DistanceVectorHop * dv_head
Known paths to target.
struct VirtualLink * vl
Do we have a confirmed working queue and are thus visible to CORE? If so, this is the virtual link,...
struct GNUNET_TIME_Absolute monotime
What time was sender_sig created.
struct GNUNET_CRYPTO_EddsaSignature sender_sig
Signature affirming ephemeral_key of type GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL.
struct DistanceVectorHop * dv_tail
Known paths to target.
struct GNUNET_CRYPTO_HpkeEncapsulation ephemeral_key
Our ephemeral key.
struct GNUNET_ShortHashCode * km
Master secret for the setup of the Key material for the backchannel.
struct GNUNET_PeerIdentity target
To which peer is this a route?
struct GNUNET_TIME_Absolute ephemeral_validity
How long is sender_sig valid.
struct GNUNET_SCHEDULER_Task * timeout_task
Task scheduled to purge expired paths from dv_head MDLL.
Content signed by each peer during DV learning.
struct GNUNET_PeerIdentity pred
Identity of the previous peer on the path.
struct GNUNET_CRYPTO_SignaturePurpose purpose
Purpose is GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP.
struct GNUNET_CRYPTO_ChallengeNonceP challenge
Challenge value used by the initiator to re-identify the path.
struct GNUNET_PeerIdentity succ
Identity of the next peer on the path.
Content signed by the initiator during DV learning.
struct GNUNET_CRYPTO_SignaturePurpose purpose
Purpose is GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR.
struct GNUNET_TIME_AbsoluteNBO monotonic_time
Time at the initiator when generating the signature.
struct GNUNET_CRYPTO_ChallengeNonceP challenge
Challenge value used by the initiator to re-identify the path.
Body by which a peer confirms that it is using an ephemeral key.
struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time
How long is this signature over the ephemeral key valid?
struct GNUNET_CRYPTO_SignaturePurpose purpose
Purpose is GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL.
struct GNUNET_PeerIdentity target
Target's peer identity.
struct GNUNET_CRYPTO_HpkeEncapsulation ephemeral_key
Ephemeral key setup by the sender for target, used to encrypt the payload.
Application client to TRANSPORT service: we would like to have address suggestions for this peer.
Definition transport.h:948
Closure for find_by_message_uuid.
struct ReassemblyContext * rc
Set to the reassembly context if found.
struct MessageUUIDP message_uuid
UUID to look for.
32-bit bandwidth used for network exchange by GNUnet, in bytes per second.
Wrapper struct with the average RTT of message to some peer and if this peer und us is ready to sync.
Handle to a node in a heap.
Internal representation of the hash map.
Internal representation of the hash map.
Internal representation of the hash map.
Internal representation of the hash map.
Internal representation of the hash map.
type for session keys
type for session keys
Type of a nonce used for challenges.
struct GNUNET_ShortHashCode value
The value of the nonce.
Private ECC key encoded for transmission.
an ECC signature using EdDSA.
HPKE DHKEM encapsulation (X25519) See RFC 9180.
header of what an ECC signature signs this must be followed by "size - 8" bytes of the actual signed ...
uint32_t purpose
What does this signature vouch for? This must contain a GNUNET_SIGNATURE_PURPOSE_XXX constant (from g...
Context for building (or parsing) HELLO URIs.
Definition hello-uri.c:185
Context for parsing HELLOs.
Definition hello-uri.c:233
A 512-bit hashcode.
Handle to a message queue.
Definition mq.c:87
Message handler for a specific message type.
Header for all communications.
Handle for active NAT registrations.
Definition nat_api.c:72
Handle to the PEERSTORE service.
Context for a iterate request.
Context for a store request.
Context for a add hello uri request.
A handle for the PILS service.
Definition pils_api.c:86
The identity of the host (wraps the signing key of the peer).
struct GNUNET_CRYPTO_EddsaPublicKey public_key
Entry in list of pending tasks.
Definition scheduler.c:141
Handle to a client that is connected to a service.
Definition service.c:249
Handle to a service.
Definition service.c:116
Handle for the service.
A 256-bit hashcode.
Struct wrapping information we use for starting the burst.
struct VirtualLink * vl
The VirtualLink of the peer to which we like to burst with.
struct GNUNET_TIME_Relative delay
The delay - calculate from the RTT and which peer was ready to sync first, after we will start the bu...
unsigned int sync_ready
We are ready to start the burst.
struct GNUNET_TIME_Relative rtt
The average RTT between the peers.
Time for absolute time used by GNUnet, in microseconds and in network byte order.
Time for absolute times used by GNUnet, in microseconds.
uint64_t abs_value_us
The actual value.
Time for relative time used by GNUnet, in microseconds and in network byte order.
Time for relative time used by GNUnet, in microseconds.
uint64_t rel_value_us
The actual value.
Add address to the list.
Definition transport.h:289
struct GNUNET_MessageHeader header
Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS.
Definition transport.h:293
struct GNUNET_TIME_RelativeNBO expiration
When does the address expire?
Definition transport.h:303
uint32_t nt
An enum GNUNET_NetworkType in NBO.
Definition transport.h:308
uint32_t aid
Address identifier (used during deletion).
Definition transport.h:298
Add queue to the transport.
Definition transport.h:403
uint32_t nt
An enum GNUNET_NetworkType in NBO.
Definition transport.h:422
uint32_t mtu
Maximum transmission unit, in NBO.
Definition transport.h:427
uint64_t q_len
Queue length, in NBO.
Definition transport.h:433
uint32_t qid
Queue identifier (used to identify the queue).
Definition transport.h:412
struct GNUNET_PeerIdentity receiver
Receiver that can be addressed via the queue.
Definition transport.h:417
struct GNUNET_MessageHeader header
Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP.
Definition transport.h:407
uint32_t cs
An enum GNUNET_TRANSPORT_ConnectionStatus in NBO.
Definition transport.h:443
struct GNUNET_MessageHeader header
Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR.
Definition transport.h:269
uint32_t cc
NBO encoding of enum GNUNET_TRANSPORT_CommunicatorCharacteristics
Definition transport.h:274
uint32_t can_burst
The communicator can do burst msgs.
Definition transport.h:279
Message from transport to communicator passing along a backchannel message from the given peer pid.
Definition transport.h:657
struct GNUNET_PeerIdentity pid
Origin peer.
Definition transport.h:672
Message from communicator to transport service asking for transmission of a backchannel message with ...
Definition transport.h:628
struct GNUNET_MessageHeader header
Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL.
Definition transport.h:632
struct GNUNET_PeerIdentity pid
Target peer.
Definition transport.h:642
Communicator tells transport how queue creation went down.
Definition transport.h:547
uint32_t request_id
Unique ID for the request.
Definition transport.h:557
Transport tells communicator that it wants a new queue.
Definition transport.h:523
uint32_t request_id
Unique ID for the request.
Definition transport.h:532
struct GNUNET_PeerIdentity receiver
Receiver that can be addressed via the queue.
Definition transport.h:537
Remove address from the list.
Definition transport.h:318
uint32_t aid
Address identifier.
Definition transport.h:327
Remove queue, it is no longer available.
Definition transport.h:501
struct GNUNET_PeerIdentity receiver
Receiver that can be addressed via the queue.
Definition transport.h:515
uint32_t qid
Address identifier.
Definition transport.h:510
Transport informs us about being done with an incoming message.
Definition transport.h:376
struct GNUNET_PeerIdentity sender
Sender identifier of the original message.
Definition transport.h:395
uint64_t fc_id
Which message is being ACKed?
Definition transport.h:390
uint32_t reserved
Reserved (0)
Definition transport.h:385
Inform transport about an incoming message.
Definition transport.h:335
struct GNUNET_PeerIdentity neighbour_sender
Direct neighbour sender identifier.
Definition transport.h:365
struct GNUNET_TIME_RelativeNBO expected_address_validity
How long does the communicator believe the address on which the message was received to remain valid?
Definition transport.h:355
struct GNUNET_PeerIdentity sender
Sender identifier.
Definition transport.h:360
struct GNUNET_MessageHeader header
Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG.
Definition transport.h:339
uint32_t fc_on
Do we use flow control or not?
Definition transport.h:344
uint64_t fc_id
64-bit number to identify the matching ACK.
Definition transport.h:349
struct GNUNET_MQ_Handle * mq
Queue to talk to the transport service.
Request a one-shot listing of our virtual links.
Definition transport.h:783
State of one virtual link.
Definition transport.h:805
uint32_t stalled
Number of messages whose flow control ACK we are withholding because core_recv_window is exhausted.
Definition transport.h:849
struct GNUNET_TIME_AbsoluteNBO last_fc_transmission
When did we last send a flow control message?
Definition transport.h:910
uint32_t fc_retransmit_count
Number of flow control retransmissions of the running task.
Definition transport.h:859
uint32_t num_queues
Number of queues to the neighbour, 0 if route is GNUNET_TRANSPORT_LINK_ROUTE_DV.
Definition transport.h:836
uint64_t incoming_fc_window_size_ram
RAM currently held for this link.
Definition transport.h:869
uint64_t incoming_fc_window_size_used
How much of incoming_fc_window_size the other peer used.
Definition transport.h:879
uint32_t pending
Number of messages queued for transmission to target.
Definition transport.h:854
int64_t incoming_fc_window_size_loss
Current estimate of the message loss rate for the sender.
Definition transport.h:885
struct GNUNET_TIME_RelativeNBO other_rtt
RTT over all DV paths, as calculated by the target.
Definition transport.h:905
uint64_t outbound_fc_window_size
Window the other peer granted us.
Definition transport.h:890
uint64_t outbound_fc_window_size_used
How much of outbound_fc_window_size we used.
Definition transport.h:895
uint64_t incoming_fc_window_size
Window we last granted the other peer.
Definition transport.h:874
uint32_t route
An ‘enum GNUNET_TRANSPORT_LinkRoute’ in NBO.
Definition transport.h:824
uint32_t distance
Distance of the DV path, 0 if route is GNUNET_TRANSPORT_LINK_ROUTE_DIRECT.
Definition transport.h:830
struct GNUNET_PeerIdentity target
Peer at the other end of the link.
Definition transport.h:814
struct GNUNET_TIME_RelativeNBO last_fc_rtt
RTT of the last flow control exchange.
Definition transport.h:900
uint32_t confirmed
GNUNET_YES if the link is confirmed, i.e.
Definition transport.h:819
int32_t core_recv_window
How many more messages we may hand to CORE before it must acknowledge them.
Definition transport.h:843
uint64_t available_fc_window_size
RAM we are willing to spend on this link.
Definition transport.h:864
uint32_t num_msg_pending
Messages pending (in NBO).
Definition transport.h:768
struct GNUNET_PeerIdentity peer
Target identifier.
Definition transport.h:746
struct GNUNET_TIME_AbsoluteNBO valid_until
Definition transport.h:752
struct GNUNET_TIME_AbsoluteNBO last_validation
Definition transport.h:751
uint32_t num_bytes_pending
Bytes pending (in NBO).
Definition transport.h:773
struct GNUNET_TIME_AbsoluteNBO next_validation
Definition transport.h:753
uint32_t nt
Network type (an enum GNUNET_NetworkType in NBO).
Definition transport.h:741
struct GNUNET_TIME_RelativeNBO rtt
Current round-trip time estimate.
Definition transport.h:758
uint32_t cs
Connection status (in NBO).
Definition transport.h:763
Request to start monitoring.
Definition transport.h:710
Inform transport that message was sent.
Definition transport.h:594
uint32_t status
Success (GNUNET_OK), failure (GNUNET_SYSERR).
Definition transport.h:603
uint64_t mid
Message ID of the original message.
Definition transport.h:608
uint32_t qid
Queue ID for the queue which was used to send the message.
Definition transport.h:613
struct GNUNET_PeerIdentity receiver
Receiver identifier.
Definition transport.h:618
Inform communicator about transport's desire to send a message.
Definition transport.h:565
uint32_t qid
Which queue should we use?
Definition transport.h:574
uint64_t mid
Message ID, used for flow control.
Definition transport.h:579
struct GNUNET_MessageHeader header
Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG.
Definition transport.h:569
struct GNUNET_PeerIdentity receiver
Receiver identifier.
Definition transport.h:584
Message from transport to communicator to start a burst.
Definition transport.h:682
struct GNUNET_MessageHeader header
Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_START_BURST.
Definition transport.h:686
struct GNUNET_TIME_RelativeNBO rtt
Definition transport.h:693
struct GNUNET_PeerIdentity pid
Target peer.
Definition transport.h:691
A UUID, a 128 bit "random" value.
Message used to notify the transport API about a message received from the network.
Definition transport.h:145
struct GNUNET_PeerIdentity peer
Which peer sent the message?
Definition transport.h:154
Another peer attempted to talk to us, we should try to establish a connection in the other direction.
struct IncomingRequest * next
Kept in a DLL.
struct IncomingRequest * prev
Kept in a DLL.
struct GNUNET_PEERSTORE_Monitor * nc
Notify context for new HELLOs.
struct GNUNET_PeerIdentity pid
Which peer is this about?
When did we launch this DV learning activity?
struct LearnLaunchEntry * next
Kept (also) in a DLL sorted by launch time.
struct GNUNET_CRYPTO_ChallengeNonceP challenge
Challenge that uniquely identifies this activity.
struct LearnLaunchEntry * prev
Kept (also) in a DLL sorted by launch time.
struct GNUNET_TIME_Absolute launch_time
When did we transmit the DV learn message (used to calculate RTT) and determine freshness of paths le...
Closure for report_link().
int include_unconfirmed
Also report links that are not confirmed?
struct TransportClient * tc
Client asking for the listing.
Unique identifier we attach to a message.
uint64_t uuid
Unique value, generated by incrementing the message_uuid_ctr of struct Neighbour.
Details about what to notify monitors about.
enum GNUNET_TRANSPORT_ConnectionStatus cs
Connection status.
struct GNUNET_TIME_Absolute last_validation
struct GNUNET_TIME_Absolute next_validation
struct GNUNET_TIME_Absolute valid_until
struct GNUNET_TIME_Relative rtt
Current round-trip time estimate.
uint32_t num_msg_pending
Messages pending.
uint32_t num_bytes_pending
Bytes pending.
Closure for dv_neighbour_selection and dv_neighbour_transmission.
const struct TransportDVLearnMessage * dvl
Original message we received.
struct GNUNET_TIME_Absolute in_time
Time we received the message.
const struct DVPathEntryP * hops
The hops taken.
uint16_t bi_history
Bitmap of bidirectional connections encountered.
unsigned int num_eligible
Number of peers eligible for selection.
unsigned int num_selections
Number of peers that were selected for forwarding.
uint32_t selections[MAX_DV_DISCOVERY_SELECTION]
Offsets of the selected peers.
uint16_t nhops
Number of hops in hops.
A neighbour that at least one communicator is connected to.
size_t size_of_global_addresses
Size of all global natted addresses for this neighbour.
struct DistanceVectorHop * dv_tail
Tail of MDLL of DV hops that have this neighbour as next hop.
struct GNUNET_CONTAINER_MultiPeerMap * natted_addresses
Map of struct TransportGlobalNattedAddress for this neighbour.
struct GNUNET_TIME_Absolute last_dv_learn_monotime
Latest DVLearn monotonic time seen from this peer.
int dv_monotime_available
Do we have the latest value for last_dv_learn_monotime from PEERSTORE yet, or are we still waiting fo...
unsigned int number_of_addresses
Number of global natted addresses for this neighbour.
struct Queue * queue_tail
Tail of DLL of queues to this peer.
struct GNUNET_PEERSTORE_StoreContext * sc
Handle to a PEERSTORE store operation to store this pid's last_dv_learn_monotime.
struct DistanceVectorHop * dv_head
Head of MDLL of DV hops that have this neighbour as next hop.
struct VirtualLink * vl
Do we have a confirmed working queue and are thus visible to CORE? If so, this is the virtual link,...
struct Queue * queue_head
Head of DLL of queues to this peer.
struct GNUNET_TIME_Absolute last_inbound
When did a communicator last hand us a message that this peer sent us directly (i....
struct GNUNET_PeerIdentity pid
Which peer is this about?
enum GNUNET_GenericReturnValue is_global_natted
A queue of this neighbour has a global natted address.
struct GNUNET_PEERSTORE_IterateContext * get
Handle for an operation to fetch last_dv_learn_monotime information from the PEERSTORE,...
Message used to notify the transport service about a message to be transmitted to another peer.
Definition transport.h:231
uint32_t priority
An enum GNUNET_MQ_PriorityPreferences in NBO.
Definition transport.h:240
struct GNUNET_MessageHeader header
Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_SEND.
Definition transport.h:235
struct GNUNET_PeerIdentity peer
Which peer should receive the message?
Definition transport.h:254
Information per peer and request.
struct GNUNET_BANDWIDTH_Value32NBO bw
How much bandwidth would this tc like to see?
struct TransportClient * tc
Client responsible for the request.
struct GNUNET_SCHEDULER_Task * retry_task
Task that keeps trying to bring the link to pid up for as long as this request exists.
enum GNUNET_MQ_PriorityPreferences pk
What kind of performance preference does this tc have?
struct GSF_PendingRequest * pr
Handle to generic request (generic: from peer or local client).
struct GNUNET_TIME_Relative retry_backoff
Current delay between two runs of retry_task, growing from SUGGEST_RETRY_MIN to SUGGEST_RETRY_MAX.
struct GNUNET_PEERSTORE_Monitor * nc
Notify context for new HELLOs.
struct GNUNET_PeerIdentity pid
Which peer is this about?
Data structure kept when we are waiting for an acknowledgement.
struct AcknowledgementUUIDP ack_uuid
Unique identifier for this transmission operation.
unsigned int num_send
How often the PendingMessage was send via the Queue of this PendingAcknowledgement.
struct PendingAcknowledgement * next_pm
If pm is non-NULL, this is the DLL in which this acknowledgement is kept in relation to its pending m...
struct PendingMessage * pm
Message that was transmitted, may be NULL if the message was ACKed via another channel.
struct PendingAcknowledgement * next_dvh
If dvh is non-NULL, this is the DLL in which this acknowledgement is kept in relation to the DVH that...
struct PendingAcknowledgement * next_queue
If queue is non-NULL, this is the DLL in which this acknowledgement is kept in relation to the queue ...
struct GNUNET_TIME_Absolute transmission_time
Time of the transmission, for RTT calculation.
struct Queue * queue
Queue used for transmission, NULL if the queue has been destroyed (which may happen before we get an ...
struct DistanceVectorHop * dvh
Distance vector path chosen for this transmission, NULL if transmission was to a direct neighbour OR ...
uint16_t message_size
Number of bytes of the original message (to calculate bandwidth).
struct PendingAcknowledgement * prev_queue
If queue is non-NULL, this is the DLL in which this acknowledgement is kept in relation to the queue ...
struct PendingAcknowledgement * prev_pm
If pm is non-NULL, this is the DLL in which this acknowledgement is kept in relation to its pending m...
struct PendingAcknowledgement * prev_dvh
If dvh is non-NULL, this is the DLL in which this acknowledgement is kept in relation to the DVH that...
Context for select_best_pending_from_link().
struct GNUNET_TIME_Relative to_early_retry_delay
When will we try to transmit the message again for which it was to early to retry.
struct PendingMessage * best
Set to the best message that was found, NULL for none.
int to_early
There are pending messages, but it was to early to send one of them.
unsigned int consideration_counter
Number of pending messages we seriously considered this time.
struct DistanceVectorHop * dvh
DVH that best should take, or NULL for direct transmission.
size_t real_overhead
What is the estimated total overhead for this message?
unsigned int frags_in_flight
There is a pending messages we are sending fragments at the moment.
int frag
Did we have to fragment?
int relb
Did we have to reliability box?
List containing all messages that are yet to be send.
struct PendingMessage * tail_frag
Tail of a MDLL of fragments created for this core message.
struct PendingMessage * frag_parent
Our parent in the fragmentation tree.
enum GNUNET_MQ_PriorityPreferences prefs
Preferences for this message.
struct TransportClient * client
Client that issued the transmission request, if pmt is PMT_CORE.
struct QueueEntry * qe
Set to non-NULL value if this message is currently being given to a communicator and we are awaiting ...
struct MessageUUIDP msg_uuid
UUID to use for this message (used for reassembly of fragments, only initialized if msg_uuid_set is G...
struct PendingMessage * head_frag
Head of a MDLL of fragments created for this core message.
uint16_t bytes_msg
Size of the original message.
enum PendingMessageType pmt
Type of the pending message.
struct PendingMessage * prev_client
Kept in a MDLL of messages from this client (if pmt is PMT_CORE)
struct PendingMessage * prev_vl
Kept in a MDLL of messages for this vl.
struct PendingAcknowledgement * pa_tail
Tail of DLL of PAs for this pending message.
struct PendingMessage * next_vl
Kept in a MDLL of messages for this vl.
struct VirtualLink * vl
Target of the request (always the ultimate destination!).
struct PendingAcknowledgement * pa_head
Head of DLL of PAs for this pending message.
struct DistanceVectorHop * used_dvh
If pmt is of type PMT_DV_BOX we store the used path here.
int16_t msg_uuid_set
GNUNET_YES once msg_uuid was initialized
uint32_t frags_in_flight_round
The round we are (re)-sending fragments.
struct PendingMessage * next_client
Kept in a MDLL of messages from this client (if pmt is PMT_CORE)
uint32_t frags_in_flight
Are we sending fragments at the moment?
uint16_t frag_off
Offset at which we should generate the next fragment.
struct PendingMessage * next_frag
Kept in a MDLL of messages from this cpm (if pmt is #PMT_FRAGMENT_BOx)
uint64_t logging_uuid
UUID we use to identify this message in our logs.
uint16_t frag_count
How many fragments do we have?
struct PendingMessage * prev_frag
Kept in a MDLL of messages from this cpm (if pmt is PMT_FRAGMENT_BOX)
struct PendingMessage * bpm
This message, reliability or DV-boxed.
int16_t client_credited
GNUNET_YES once the CORE send window credit for this message has been returned to client.
struct GNUNET_TIME_Absolute next_attempt
What is the earliest time for us to retry transmission of this message?
struct GNUNET_TIME_Absolute timeout
At what time should we give up on the transmission (and no longer retry)?
struct GNUNET_PeerIdentity target
In case of a not validated neighbour, we store the target peer.
Performance data for a transmission possibility.
struct GNUNET_TIME_Relative aged_rtt
Weighted average for the RTT.
struct TransmissionHistoryEntry the[4]
Historic performance data, using a ring buffer of::GOODPUT_AGING_SLOTS entries.
unsigned int last_age
What was the last age when we wrote to the? Used to clear old entries when the age advances.
Helper context struct for HELLO update.
struct GNUNET_TIME_Absolute et
Signature expiration.
struct AddressListEntry * ale
The ale to update.
struct PilsRequest * req
Any pending PILS requests.
struct GNUNET_PILS_Operation * op
The pils operation.
struct PilsRequest * next
DLL.
struct PilsRequest * prev
DLL.
Entry identifying transmission in one of our struct Queue which still awaits an ACK.
struct QueueEntry * next
Kept as a DLL.
struct QueueEntry * prev
Kept as a DLL.
struct GNUNET_TIME_Absolute creation_timestamp
Timestamp this QueueEntry was created.
uint64_t mid
Message ID used for this message with the queue used for transmission.
struct PendingMessage * pm
Pending message this entry is for, or NULL for none.
struct Queue * queue
Queue this entry is queued with.
Closure for check_connection_quality.
unsigned int k
Decremented for each queue, for selection of the k-th queue in q.
struct Queue * q
Set to the k'th queue encountered.
unsigned int num_queues
Set to the total number of queues encountered.
unsigned int quality_count
Set to the number of quality queues encountered.
Handle for a queue.
uint32_t qid
Unique identifier of this queue with the communicator.
struct QueueEntry * queue_tail
End of DLL of unacked transmission requests.
struct Queue * prev_client
Kept in a MDLL.
unsigned int queue_length
Length of the DLL starting at queue_head.
uint32_t num_msg_pending
Messages pending.
struct GNUNET_PEERSTORE_Monitor * mo
Handle for an operation to iterate through all hellos to compare the hello addresses with address whi...
uint64_t q_capacity
Capacity of the queue.
struct Queue * next_neighbour
Kept in a MDLL.
uint32_t num_bytes_pending
Bytes pending.
uint32_t priority
Queue priority.
struct Neighbour * neighbour
Which neighbour is this queue for?
int idle
Set to GNUNET_YES if this queue is idle waiting for some virtual link to give it a pending message.
struct Queue * prev_neighbour
Kept in a MDLL.
struct PerformanceData pd
Performance data for this queue.
enum GNUNET_NetworkType nt
Which network type does this queue use?
struct GNUNET_SCHEDULER_Task * transmit_task
Task scheduled for the time when this queue can (likely) transmit the next message.
struct QueueEntry * queue_head
Head of DLL of unacked transmission requests.
struct PendingAcknowledgement * pa_tail
Tail of DLL of PAs that used this queue.
struct TransportClient * tc
Which communicator offers this queue?
struct Queue * next_client
Kept in a MDLL.
enum GNUNET_GenericReturnValue is_global_natted
Set to GNUNET_YES, if this queues address is a global natted one.
struct GNUNET_TIME_Absolute validated_until
How long do we consider this address to be valid? In the past or zero if we have not yet validated it...
uint32_t mtu
Maximum transmission unit supported by this queue.
unsigned int unlimited_length
Is this queue of unlimited length.
enum GNUNET_TRANSPORT_ConnectionStatus cs
The connection status of this queue.
uint64_t mid_gen
Message ID generator for transmissions on this queue to the communicator.
struct PendingAcknowledgement * pa_head
Head of DLL of PAs that used this queue.
struct sockaddr * address
Address of the other peer.
Information we keep for a message that we are reassembling.
struct GNUNET_CONTAINER_HeapNode * hn
Entry in the reassembly heap (sorted by expiration).
struct GNUNET_TIME_Absolute last_frag
Time we received the last fragment.
struct MessageUUIDP msg_uuid
Original message ID for of the message that all the fragments belong to.
struct VirtualLink * virtual_link
Which neighbour is this context for?
uint8_t * bitfield
Bitfield with msg_size bits representing the positions where we have received fragments.
uint16_t msg_size
How big is the message we are reassembling in total?
struct GNUNET_TIME_Absolute reassembly_timeout
At what time will we give up reassembly of this message?
uint16_t msg_missing
How many bytes of the message are still missing? Defragmentation is complete when msg_missing == 0.
Message used to notify the transport API that it can send another message to the transport service.
Definition transport.h:207
struct GNUNET_PeerIdentity peer
Which peer can CORE handle more from now?
Definition transport.h:222
uint32_t increase_window_delta
Number of messages by which to increase the window, greater or equal to one.
Definition transport.h:217
We got an address of another peer, TRANSPORT service should validate it.
Definition transport.h:979
Entry for the ring buffer caching messages send to core, when virtual link is available.
struct CommunicatorMessageContext * cmc
Communicator context for this ring buffer entry.
struct GNUNET_MessageHeader * mh
The message in this entry.
Message used to notify the transport API that it can send another message to the transport service.
Definition transport.h:163
struct GNUNET_PeerIdentity peer
Which peer can send more now?
Definition transport.h:197
Binary block we sign when we sign an address.
struct GNUNET_TIME_AbsoluteNBO mono_time
When was the address generated.
struct GNUNET_HashCode addr_hash GNUNET_PACKED
Hash of the address.
struct GNUNET_CRYPTO_SignaturePurpose purpose
Purpose must be GNUNET_SIGNATURE_PURPOSE_TRANSPORT_ADDRESS.
Message from the transport service to the library asking to check if both processes agree about this ...
Definition transport.h:63
Information we keep per GOODPUT_AGING_SLOTS about historic (or current) transmission performance.
uint64_t bytes_received
Number of bytes received and acknowledged by the other peer in the interval.
uint64_t bytes_sent
Number of bytes actually sent in the interval.
Outer layer of an encapsulated backchannel message.
struct GNUNET_MessageHeader header
Type is GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION.
Client connected to the transport service.
enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc
Characteristics of this communicator.
struct PendingMessage * pending_msg_head
Head of list of messages pending for this client, sorted by transmission time ("next_attempt" + possi...
enum ClientType type
What type of client is this?
struct AddressListEntry * addr_tail
Tail of list of the addresses of this peer offered by this communicator.
union TransportClient::@68 details
struct TransportClient * next
Kept in a DLL.
struct GNUNET_MQ_Handle * mq
Message queue to the client.
struct GNUNET_SCHEDULER_Task * free_queue_entry_task
Task to check for timed out QueueEntry.
struct PendingMessage * pending_msg_tail
Tail of list of messages pending for this client.
struct TransportClient::@68::@72 application
Information for type CT_APPLICATION.
struct TransportClient::@68::@70 monitor
Information for type CT_MONITOR.
struct Queue * queue_head
Head of DLL of queues offered by this communicator.
struct AddressListEntry * addr_head
Head of list of the addresses of this peer offered by this communicator.
struct TransportClient::@68::@69 core
Information for type CT_CORE.
struct GNUNET_CONTAINER_MultiPeerMap * requests
Map of requests for peers the given client application would like to see connections for.
struct GNUNET_SERVICE_Client * client
Handle to the client.
struct TransportClient * prev
Kept in a DLL.
struct TransportClient::@68::@71 communicator
Information for type CT_COMMUNICATOR.
char * address_prefix
If type is CT_COMMUNICATOR, this communicator supports communicating using these addresses.
struct Queue * queue_tail
Tail of DLL of queues offered by this communicator.
unsigned int total_queue_length
Number of queue entries in all queues to this communicator.
int one_shot
Is this a one-shot monitor?
struct GNUNET_PeerIdentity peer
Peer identity to monitor the addresses of.
enum GNUNET_GenericReturnValue can_burst
Can be used for burst messages.
struct GNUNET_TIME_RelativeNBO ack_delay
How long was the ACK delayed for generating cumulative ACKs? Used to calculate the correct network RT...
struct AcknowledgementUUIDP ack_uuid
UUID of a message being acknowledged.
struct GNUNET_TIME_Absolute receive_time
When did we receive the message we are ACKing? Used to calculate the delay we introduced by cummulati...
struct AcknowledgementUUIDP ack_uuid
UUID of a message being acknowledged.
Outer layer of an encapsulated message send over multiple hops.
struct GNUNET_CRYPTO_AeadNonce iv
We use an IV here as the ephemeral_key is reused for EPHEMERAL_VALIDITY time to avoid re-signing it a...
struct GNUNET_MessageHeader header
Type is GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX.
uint16_t num_hops
Number of hops this messages includes.
uint16_t orig_size
Size this msg had initially.
struct GNUNET_CRYPTO_HpkeEncapsulation ephemeral_key
Ephemeral key setup by the sender for target, used to encrypt the payload.
struct GNUNET_CRYPTO_AeadMac mac
HMAC over the ciphertext of the encrypted, variable-size body that follows.
uint16_t total_hops
Number of total hops this messages travelled.
uint32_t without_fc
Flag if the payload is a control message.
Plaintext of the variable-size payload that is encrypted within a struct TransportBackchannelEncapsul...
struct GNUNET_CRYPTO_EddsaSignature sender_sig
Signature of the sender over an GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL.
struct GNUNET_TIME_AbsoluteNBO monotonic_time
Current monotonic time of the sending transport service.
struct GNUNET_PeerIdentity sender
Sender's peer identity.
Internal message used by transport for distance vector learning.
struct GNUNET_PeerIdentity initiator
Identity of the peer that started this learning activity.
struct GNUNET_CRYPTO_ChallengeNonceP challenge
Challenge value used by the initiator to re-identify the path.
struct GNUNET_MessageHeader header
Type is GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN.
struct GNUNET_TIME_RelativeNBO non_network_delay
Peers receiving this message and delaying forwarding to other peers for any reason should increment t...
struct GNUNET_TIME_AbsoluteNBO monotonic_time
Time at the initiator when generating the signature.
struct GNUNET_CRYPTO_EddsaSignature init_sig
Signature of this hop over the path, of purpose GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR.
uint16_t num_hops
Number of hops this messages has travelled, in NBO.
uint16_t bidirectional
Bitmask of the last 16 hops indicating whether they are confirmed available (without DV) in both dire...
Message for Transport-to-Transport Flow control.
uint64_t outbound_window_size
Latest flow control window size we learned from the other peer, in bytes, in NBO.
uint32_t number_of_addresses
Number of TransportGlobalNattedAddress following the struct.
uint64_t inbound_window_size
Flow control window size in bytes, in NBO.
struct GNUNET_TIME_AbsoluteNBO sender_time
Timestamp of the sender.
uint32_t seq
Sequence number of the flow control message.
uint32_t size_of_addresses
Size of all the addresses attached to all TransportGlobalNattedAddress.
uint64_t outbound_sent
How many bytes has the sender sent that count for flow control at this time.
struct GNUNET_TIME_RelativeNBO rtt
Average RTT for the DistanceVector of the VirtualLink we tell the target.
struct GNUNET_MessageHeader header
Type is GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL.
uint32_t sync_ready
We tell the target, if we are ready to start the burst.
Outer layer of an encapsulated fragmented application message.
uint16_t frag_off
Offset of this fragment in the overall message.
struct MessageUUIDP msg_uuid
Original message ID for of the message that all the fragments belong to.
struct AcknowledgementUUIDP ack_uuid
Unique ID of this fragment (and fragment transmission!).
struct GNUNET_MessageHeader header
Type is GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT.
uint16_t msg_size
Total size of the message that is being fragmented.
struct TransportGlobalNattedAddress * tgna
The struct TransportGlobalNattedAddress to set.
uint32_t address_length
Length of the address following the struct in NBO.
Confirmation that the receiver got a GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX.
uint32_t ack_counter
Counter of ACKs transmitted by the sender to us.
struct GNUNET_MessageHeader header
Type is GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK.
Outer layer of an encapsulated unfragmented application message sent over an unreliable channel.
uint32_t ack_countdown
Number of messages still to be sent before a commulative ACK is requested.
struct GNUNET_MessageHeader header
Type is GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX.
struct AcknowledgementUUIDP ack_uuid
Unique ID of the message used for signalling receipt of messages sent over possibly unreliable channe...
Message send to another peer to validate that it can indeed receive messages at a particular address.
struct GNUNET_MessageHeader header
Type is GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE.
struct GNUNET_CRYPTO_ChallengeNonceP challenge
Challenge to be signed by the receiving peer.
struct GNUNET_TIME_AbsoluteNBO sender_time
Timestamp of the sender, to be copied into the reply to allow sender to calculate RTT.
Message signed by a peer to confirm that it can indeed receive messages at a particular address.
struct GNUNET_TIME_RelativeNBO validity_duration
How long does the sender believe the address on which the challenge was received to remain valid?
struct GNUNET_CRYPTO_SignaturePurpose purpose
Purpose is GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE.
struct GNUNET_CRYPTO_ChallengeNonceP challenge
Challenge signed by the receiving peer.
Message send to a peer to respond to a #GNUNET_MESSAGE_TYPE_ADDRESS_VALIDATION_CHALLENGE.
struct GNUNET_MessageHeader header
Type is GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE.
struct GNUNET_CRYPTO_ChallengeNonceP challenge
The challenge that was signed by the receiving peer.
struct GNUNET_CRYPTO_EddsaSignature signature
The peer's signature matching the GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE purpose.
struct GNUNET_PEERSTORE_StoreHelloContext * sc
State we keep for validation activities.
struct GNUNET_TIME_Absolute valid_until
How long did the peer claim this address to be valid? Capped at minimum of MAX_ADDRESS_VALID_UNTIL re...
struct GNUNET_PeerIdentity pid
For which peer is address to be validated (or possibly valid)? Serves as key in the validation_map.
struct GNUNET_TIME_Absolute validated_until
How long do we consider this address to be valid? In the past or zero if we have not yet validated it...

◆ UNCONFIRMED_LINK_TIMEOUT

#define UNCONFIRMED_LINK_TIMEOUT    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)

How long do we keep a virtual link that only exists because some peer sent us a FLOW_CONTROL message, without it ever becoming confirmed?

Definition at line 109 of file gnunet-service-transport.c.

◆ MAX_CUMMULATIVE_ACKS

#define MAX_CUMMULATIVE_ACKS   64

Maximum number of messages we acknowledge together in one cumulative ACK.

Larger values may save a bit of bandwidth.

Definition at line 116 of file gnunet-service-transport.c.

◆ FC_NO_CHANGE_REPLY_PROBABILITY

#define FC_NO_CHANGE_REPLY_PROBABILITY   8

What is the 1:n chance that we send a Flow control response when receiving a flow control message that did not change anything for us? Basically, this is used in the case where both peers are stuck on flow control (no window changes), but one might continue sending flow control messages to the other peer as the first FC message when things stalled got lost, and then subsequently the other peer does usually not respond as nothing changed.

So to ensure that eventually the FC messages stop, we do send with 1/8th probability an FC message even if nothing changed. That prevents one peer being stuck in sending (useless) FC messages "forever".

Definition at line 130 of file gnunet-service-transport.c.

◆ IN_PACKET_SIZE_WITHOUT_MTU

#define IN_PACKET_SIZE_WITHOUT_MTU   128

What is the size we assume for a read operation in the absence of an MTU for the purpose of flow control?

Definition at line 136 of file gnunet-service-transport.c.

◆ GOODPUT_AGING_SLOTS

#define GOODPUT_AGING_SLOTS   4

Number of slots we keep of historic data for computation of goodput / message loss ratio.

Definition at line 142 of file gnunet-service-transport.c.

◆ DEFAULT_WINDOW_SIZE

#define DEFAULT_WINDOW_SIZE   (128 * 1024)

How big is the flow control window size by default; limits per-neighbour RAM utilization.

Definition at line 148 of file gnunet-service-transport.c.

◆ MAX_INCOMING_REQUEST

#define MAX_INCOMING_REQUEST   16

For how many incoming connections do we try to create a virtual link for (at the same time!).

This does NOT limit the number of incoming connections, just the number for which we are actively trying to find working addresses in the absence (!) of our own applications wanting the link to go up.

Definition at line 158 of file gnunet-service-transport.c.

◆ MAX_DV_DISCOVERY_SELECTION

#define MAX_DV_DISCOVERY_SELECTION   16

Maximum number of peers we select for forwarding DVInit messages at the same time (excluding initiator).

Definition at line 164 of file gnunet-service-transport.c.

◆ RECV_WINDOW_SIZE

#define RECV_WINDOW_SIZE   4

Window size.

How many messages to the same target do we pass to CORE without a RECV_OK in between? Small values limit throughput, large values will increase latency.

FIXME-OPTIMIZE: find out what good values are experimentally, maybe set adaptively (i.e. to observed available bandwidth).

Definition at line 174 of file gnunet-service-transport.c.

◆ CORE_FC_STALL_TIMEOUT

#define CORE_FC_STALL_TIMEOUT    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2)

How long do we wait for CORE to return the flow control credit for the messages we handed it before we give up on them?

Only the per-message ACK to the communicator is delayed this long; the communicator itself keeps being read (see finish_handling_raw_message()), so overshooting no longer takes every other peer down with it. What is left to bound is a CORE that has gone silent throttling the flow-control-capable communicators indefinitely. A RECV_OK is a local IPC round trip against a CORE that processes our messages synchronously, so this is roughly three orders of magnitude of headroom over the healthy case while still being short enough that a wedged CORE does not cost a peer a minute of throughput.

Definition at line 190 of file gnunet-service-transport.c.

◆ MAX_STALLED_CMCS

#define MAX_STALLED_CMCS   (4 * RECV_WINDOW_SIZE)

How many messages may wait on VirtualLink::core_recv_window before we stop deferring their flow control ACKs?

The payload of a stalled message has already been handed to CORE; the ‘struct CommunicatorMessageContext’ left behind only carries the ACK we are withholding. Dropping the oldest one therefore costs nothing but the backpressure it expressed, which is a far better trade than letting the list grow without bound now that the client is no longer stalled along with it.

Definition at line 204 of file gnunet-service-transport.c.

◆ MIN_DV_PATH_LENGTH_FOR_INITIATOR

#define MIN_DV_PATH_LENGTH_FOR_INITIATOR   3

Minimum number of hops we should forward DV learn messages even if they are NOT useful for us in hope of looping back to the initiator?

FIXME: allow initiator some control here instead?

Definition at line 213 of file gnunet-service-transport.c.

◆ MAX_DV_HOPS_ALLOWED

#define MAX_DV_HOPS_ALLOWED   16

Maximum DV distance allowed ever.

Definition at line 218 of file gnunet-service-transport.c.

◆ MAX_DV_LEARN_PENDING

#define MAX_DV_LEARN_PENDING   64

Maximum number of DV learning activities we may have pending at the same time.

Definition at line 224 of file gnunet-service-transport.c.

◆ MAX_DV_PATHS_TO_TARGET

#define MAX_DV_PATHS_TO_TARGET   3

Maximum number of DV paths we keep simultaneously to the same target.

Definition at line 229 of file gnunet-service-transport.c.

◆ PILS_FEED_ADDRESSES_DELAY

#define PILS_FEED_ADDRESSES_DELAY    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3)

Delay between added/removed addresses and PILS feed call.

Introduced to handle cases with high address churn across communicators (startup, location change etc)

Definition at line 237 of file gnunet-service-transport.c.

◆ DELAY_WARN_THRESHOLD

#define DELAY_WARN_THRESHOLD    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)

If a queue delays the next message by more than this number of seconds we log a warning.

Note: this is for testing, the value chosen here might be too aggressively low!

Definition at line 245 of file gnunet-service-transport.c.

◆ DV_FORWARD_TIMEOUT

#define DV_FORWARD_TIMEOUT    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)

If a DVBox could not be forwarded after this number of seconds we drop it.

Definition at line 252 of file gnunet-service-transport.c.

◆ DEFAULT_ACK_WAIT_DURATION

#define DEFAULT_ACK_WAIT_DURATION    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)

Default value for how long we wait for reliability ack.

Definition at line 258 of file gnunet-service-transport.c.

◆ MIN_ACK_WAIT_DURATION

#define MIN_ACK_WAIT_DURATION    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 10)

Lower bound on the RTT estimate we are willing to derive a retransmission deadline from.

‘struct PerformanceData::aged_rtt’ is an exponential average over observed round trip times with no floor of its own, and over a UNIX domain socket or a loopback queue the observed RTT is a few microseconds. transmit_on_queue() turns that straight into ‘next_attempt’, so the message it just sent is eligible again on the very next pass – and it arms that pass itself, unconditionally, with GNUNET_TIME_UNIT_ZERO. The result is a tight retransmission loop that saturates a core and drowns the communicator ("Dropping message: transport is too slow").

Compare MIN_FC_RETRANSMIT_DELAY, which exists for exactly the same reason on the flow control path.

Definition at line 277 of file gnunet-service-transport.c.

◆ DV_QUALITY_RTT_THRESHOLD

#define DV_QUALITY_RTT_THRESHOLD    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)

We only consider queues as "quality" connections when suppressing the generation of DV initiation messages if the latency of the queue is below this threshold.

Definition at line 285 of file gnunet-service-transport.c.

◆ DV_PATH_VALIDITY_TIMEOUT

#define DV_PATH_VALIDITY_TIMEOUT    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)

How long do we consider a DV path valid if we see no further updates on it? Note: the value chosen here might be too low!

Definition at line 292 of file gnunet-service-transport.c.

◆ BACKCHANNEL_INACTIVITY_TIMEOUT

#define BACKCHANNEL_INACTIVITY_TIMEOUT    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)

How long do we cache backchannel (struct Backtalker) information after a backchannel goes inactive?

Definition at line 299 of file gnunet-service-transport.c.

◆ DV_PATH_DISCOVERY_FREQUENCY

#define DV_PATH_DISCOVERY_FREQUENCY    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)

How long before paths expire would we like to (re)discover DV paths? Should be below DV_PATH_VALIDITY_TIMEOUT.

Definition at line 306 of file gnunet-service-transport.c.

◆ EPHEMERAL_VALIDITY

#define EPHEMERAL_VALIDITY    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)

How long are ephemeral keys valid?

Definition at line 312 of file gnunet-service-transport.c.

◆ REASSEMBLY_EXPIRATION

#define REASSEMBLY_EXPIRATION    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)

How long do we keep partially reassembled messages around before giving up?

Definition at line 318 of file gnunet-service-transport.c.

◆ MAX_REASSEMBLY_CONTEXTS

#define MAX_REASSEMBLY_CONTEXTS   32

Maximum number of messages we are willing to reassemble in parallel for a single virtual link.

Each context is sized from the sender's ‘msg_size’ field (up to 64k) and lives for REASSEMBLY_EXPIRATION, so this must be bounded.

Definition at line 327 of file gnunet-service-transport.c.

◆ FAST_VALIDATION_CHALLENGE_FREQ

#define FAST_VALIDATION_CHALLENGE_FREQ    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)

What is the fastest rate at which we send challenges if we keep learning an address (gossip, DHT, etc.)?

Definition at line 333 of file gnunet-service-transport.c.

◆ MAX_VALIDATION_CHALLENGE_FREQ

#define MAX_VALIDATION_CHALLENGE_FREQ    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_DAYS, 1)

What is the slowest rate at which we send challenges?

Definition at line 339 of file gnunet-service-transport.c.

◆ WANTED_VALIDATION_CHALLENGE_FREQ

#define WANTED_VALIDATION_CHALLENGE_FREQ    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)

What is the slowest rate at which we send challenges to a peer that an application client explicitly asked for and that we have no confirmed link to? Somebody is waiting for this one, so a day is not an option.

Definition at line 347 of file gnunet-service-transport.c.

◆ SUGGEST_RETRY_MIN

#define SUGGEST_RETRY_MIN    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)

How soon after an application asked us for a peer do we retry bringing the link up for the first time?

Definition at line 354 of file gnunet-service-transport.c.

◆ SUGGEST_RETRY_MAX

#define SUGGEST_RETRY_MAX    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)

What is the slowest rate at which we retry bringing up a link that an application client explicitly asked for? Unlike a peer we merely heard about, somebody is waiting for this one, so this is far below MAX_VALIDATION_CHALLENGE_FREQ.

Definition at line 363 of file gnunet-service-transport.c.

◆ ACK_CUMMULATOR_TIMEOUT

#define ACK_CUMMULATOR_TIMEOUT    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)

How long until we forget about historic accumulators and thus reset the ACK counter? Should exceed the maximum time an active connection experiences without an ACK.

Definition at line 371 of file gnunet-service-transport.c.

◆ DV_LEARN_BASE_FREQUENCY

#define DV_LEARN_BASE_FREQUENCY   GNUNET_TIME_UNIT_MINUTES

What is the non-randomized base frequency at which we would initiate DV learn messages?

Definition at line 378 of file gnunet-service-transport.c.

◆ DV_LEARN_QUALITY_THRESHOLD

#define DV_LEARN_QUALITY_THRESHOLD   100

How many good connections (confirmed, bi-directional, not DV) do we need to have to suppress initiating DV learn messages?

Definition at line 384 of file gnunet-service-transport.c.

◆ MAX_ADDRESS_VALID_UNTIL

#define MAX_ADDRESS_VALID_UNTIL    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MONTHS, 1)

When do we forget an invalid address for sure?

Definition at line 389 of file gnunet-service-transport.c.

◆ ADDRESS_VALIDATION_LIFETIME

#define ADDRESS_VALIDATION_LIFETIME    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)

How long do we consider an address valid if we just checked?

Definition at line 395 of file gnunet-service-transport.c.

◆ NEIGHBOUR_LIVENESS_TIMEOUT

#define NEIGHBOUR_LIVENESS_TIMEOUT    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)

How long may a direct neighbour stay completely silent before we stop believing that its queues work, regardless of what the communicator that owns them tells us?

We normally learn that a queue died because the communicator sends us a GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN. If it does not (because it is buggy or wedged), the only other bound is the expiry of the last successful address validation – i.e. ADDRESS_VALIDATION_LIFETIME, four hours – during all of which CORE would keep believing it is connected.

This is a backstop, not the primary detector: it is deliberately several times GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, which is what the communicators themselves use, so that under normal operation it never fires first. When it does fire, a communicator misbehaved.

Definition at line 414 of file gnunet-service-transport.c.

◆ FC_KEEPALIVE_INTERVAL

#define FC_KEEPALIVE_INTERVAL
Value:
2)
#define GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT
After how long do we consider a connection to a peer dead if we don't receive messages from the peer?

How long may a confirmed virtual link go without us sending anything on it before we transmit an otherwise unnecessary FLOW_CONTROL message, purely so that the peer at the other end keeps seeing traffic from us?

check_link_down() drops a neighbour that has said nothing for NEIGHBOUR_LIVENESS_TIMEOUT, which silently assumes that something generates traffic on a healthy link. Nothing in this service did: FC is event-driven and handle_flow_control() deliberately stops retransmitting once both ends agree on the window, which on an idle link is immediately. A link with no application traffic therefore fell completely silent and then tore itself down on the very timer meant to catch broken ones.

MUST stay comfortably below NEIGHBOUR_LIVENESS_TIMEOUT so that a couple of lost keepalives are not enough to trip it.

It MUST also stay comfortably below GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, which is what the communicators use to decide that a connection went idle (‘Queue p was idle for s, disconnecting’ in the TCP communicator). This used to be NEIGHBOUR_LIVENESS_TIMEOUT / 3, which is exactly that timeout, and the race went the wrong way every time: the queue's idle deadline is refreshed when the peer's FC arrives, ours is armed a moment later when handle_flow_control() has finished processing it, so the communicator's five minutes were always up first. On a link with no CORE session to keep it busy that tore down a working TCP connection every five minutes. Deriving it from the timeout it has to beat keeps the two from drifting into each other again.

Definition at line 445 of file gnunet-service-transport.c.

◆ MIN_ADDRESS_REFRESH_INTERVAL

#define MIN_ADDRESS_REFRESH_INTERVAL    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)

How often are we willing to re-sign and re-store one of our own addresses in PEERSTORE, no matter how short a lifetime the communicator that owns it claims? See peerstore_store_own_cb().

Definition at line 454 of file gnunet-service-transport.c.

◆ MIN_DELAY_ADDRESS_VALIDATION

#define MIN_DELAY_ADDRESS_VALIDATION   GNUNET_TIME_UNIT_MILLISECONDS

What is the maximum frequency at which we do address validation? A random value between 0 and this value is added when scheduling the validation_task (both to ensure we do not validate too often, and to randomize a bit).

Definition at line 463 of file gnunet-service-transport.c.

◆ VALIDATION_RTT_BUFFER_FACTOR

#define VALIDATION_RTT_BUFFER_FACTOR   3

How many network RTTs before an address validation expires should we begin trying to revalidate? (Note that the RTT used here is the one that we experienced during the last validation, not necessarily the latest RTT observed).

Definition at line 471 of file gnunet-service-transport.c.

◆ COMMUNICATOR_TOTAL_QUEUE_LIMIT

#define COMMUNICATOR_TOTAL_QUEUE_LIMIT   512

How many messages can we have pending for a given communicator process before we start to throttle that communicator?

Used if a communicator might be CPU-bound and cannot handle the traffic.

Definition at line 479 of file gnunet-service-transport.c.

◆ QUEUE_LENGTH_LIMIT

#define QUEUE_LENGTH_LIMIT   32

How many messages can we have pending for a given queue (queue to a particular peer via a communicator) process before we start to throttle that queue?

Definition at line 486 of file gnunet-service-transport.c.

◆ QUEUE_ENTRY_TIMEOUT

#define QUEUE_ENTRY_TIMEOUT    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)

Definition at line 491 of file gnunet-service-transport.c.

◆ RTT_DIFF

Difference of the average RTT for the DistanceVector calculate by us and the target we are willing to accept for starting the burst.

Definition at line 498 of file gnunet-service-transport.c.

◆ SHUTDOWN_CLIENT_GRACE_PERIOD

#define SHUTDOWN_CLIENT_GRACE_PERIOD    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)

How long do we wait during shutdown for our clients to disconnect on their own before we drop them? We run with GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN, so nobody drops them for us and a single wedged client would otherwise keep us alive forever.

Definition at line 507 of file gnunet-service-transport.c.

Typedef Documentation

◆ DVMessageHandler

typedef void(* DVMessageHandler) (void *cls, struct Neighbour *next_hop, const struct GNUNET_MessageHeader *hdr, enum RouteMessageOptions options)

Function to call to further operate on the now DV encapsulated message hdr, forwarding it via next_hop under respect of options.

Parameters
clsclosure
next_hopnext hop of the DV path
hdrencapsulated message, technically a struct TransportDFBoxMessage
optionsoptions of the original message

Definition at line 5838 of file gnunet-service-transport.c.

Enumeration Type Documentation

◆ ClientType

enum ClientType

What type of client is the struct TransportClient about?

Enumerator
CT_NONE 

We do not know yet (client is fresh).

CT_CORE 

Is the CORE service, we need to forward traffic to it.

CT_MONITOR 

It is a monitor, forward monitor data.

CT_COMMUNICATOR 

It is a communicator, use for communication.

CT_APPLICATION 

"Application" telling us where to connect (i.e.

TOPOLOGY, DHT or CADET).

Definition at line 1213 of file gnunet-service-transport.c.

1214{
1218 CT_NONE = 0,
1219
1223 CT_CORE = 1,
1224
1228 CT_MONITOR = 2,
1229
1233 CT_COMMUNICATOR = 3,
1234
1238 CT_APPLICATION = 4
1239};

◆ RouteMessageOptions

Which transmission options are allowable for transmission? Interpreted bit-wise!

Enumerator
RMO_NONE 

Only confirmed, non-DV direct neighbours.

RMO_DV_ALLOWED 

We are allowed to use DV routing for this hdr.

RMO_UNCONFIRMED_ALLOWED 

We are allowed to use unconfirmed queues or DV routes for this message.

RMO_ANYTHING_GOES 

Reliable and unreliable, DV and non-DV are all acceptable.

RMO_REDUNDANT 

If we have multiple choices, it is OK to send this message over multiple channels at the same time to improve loss tolerance.

(We do at most 2 transmissions.)

Definition at line 1246 of file gnunet-service-transport.c.

1247{
1251 RMO_NONE = 0,
1252
1256 RMO_DV_ALLOWED = 1,
1257
1262
1267
1273 RMO_REDUNDANT = 4
1274};

◆ PendingMessageType

Types of different pending messages.

Enumerator
PMT_CORE 

Ordinary message received from the CORE service.

PMT_FRAGMENT_BOX 

Fragment box.

PMT_RELIABILITY_BOX 

Reliability box.

PMT_DV_BOX 

Pending message created during forward_dv_box().

Definition at line 2433 of file gnunet-service-transport.c.

2434{
2438 PMT_CORE = 0,
2439
2443 PMT_FRAGMENT_BOX = 1,
2444
2449
2453 PMT_DV_BOX = 3
2454};

Function Documentation

◆ GNUNET_static_assert() [1/9]

GNUNET_NETWORK_STRUCT_END GNUNET_static_assert ( sizeof(struct TransportGlobalNattedAddress = =4)

◆ GNUNET_static_assert() [2/9]

GNUNET_static_assert ( sizeof(struct TransportFlowControlMessage = =60)

◆ GNUNET_static_assert() [3/9]

GNUNET_static_assert ( sizeof(struct TransportDVBoxMessage = =86)

◆ GNUNET_static_assert() [4/9]

GNUNET_static_assert ( sizeof(struct TransportDVLearnMessage = =152)

◆ GNUNET_static_assert() [5/9]

GNUNET_static_assert ( sizeof(struct TransportFragmentBoxMessage = =32)

◆ GNUNET_static_assert() [6/9]

GNUNET_static_assert ( sizeof(struct TransportReliabilityBoxMessage = =24)

◆ GNUNET_static_assert() [7/9]

GNUNET_static_assert ( sizeof(struct TransportReliabilityAckMessage = =8)

◆ GNUNET_static_assert() [8/9]

GNUNET_static_assert ( sizeof(struct TransportValidationChallengeMessage = =48)

◆ GNUNET_static_assert() [9/9]

GNUNET_static_assert ( sizeof(struct TransportValidationResponseMessage = =120)

◆ sign_by_my_identity()

static enum GNUNET_GenericReturnValue sign_by_my_identity ( const struct GNUNET_CRYPTO_SignaturePurpose purpose,
struct GNUNET_CRYPTO_EddsaSignature sig 
)
static

Sign purpose with the private key of our current peer identity.

This is the synchronous counterpart of GNUNET_PILS_sign_by_peer_identity(): GNUNET_PILS_enable_private_key() gave us the key itself, so the signature is available before we return instead of after a round-trip through the PILS service.

Prefer it everywhere. Signing asynchronously means suspending whatever the signature was needed for until the scheduler comes back, and the state that has to survive until then is state we do not control: a struct CommunicatorMessageContext keeps its communicator client blocked until finish_cmc_handling() runs, and a communicator we stop reading from does not stop receiving – it starts discarding ("transport is too slow", see GNUNET_TRANSPORT_communicator_receive()). So one signature that PILS is slow to answer, or never answers because the connection broke, does not delay one message: it silently drops every peer that communicator carries.

Parameters
purposewhat to sign (size, purpose and data)
[out]sigwhere to write the signature
Returns
GNUNET_OK on success, GNUNET_SYSERR if we have no usable private key for our current peer identity

Definition at line 3329 of file gnunet-service-transport.c.

3331{
3333
3335 if (NULL == my_private_key)
3336 {
3337 /* #run() enables local key access, so this means the key on disk does
3338 not match the identity PILS announced, or no identity is known yet. */
3340 "No private key for our peer identity, cannot sign\n");
3342 "# signatures failed (no private key)",
3343 1,
3344 GNUNET_NO);
3345 return GNUNET_SYSERR;
3346 }
3347 return GNUNET_CRYPTO_eddsa_sign_ (my_private_key, purpose, sig);
3348}

References GNUNET_CRYPTO_eddsa_sign_(), GNUNET_ERROR_TYPE_WARNING, GNUNET_log, GNUNET_NO, GNUNET_PILS_get_private_key(), GNUNET_STATISTICS_update(), GNUNET_SYSERR, GST_stats, my_private_key, and pils.

Referenced by forward_dv_learn(), handle_validation_challenge(), pils_sign_address(), sign_ephemeral(), and start_dv_learn().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_age()

static unsigned int get_age ( )
static

Get an offset into the transmission history buffer for struct PerformanceData.

Note that the caller must perform the required modulo GOODPUT_AGING_SLOTS operation before indexing into the array!

An 'age' lasts 15 minute slots.

Returns
current age of the world

Definition at line 3441 of file gnunet-service-transport.c.

3442{
3443 struct GNUNET_TIME_Absolute now;
3444
3445 now = GNUNET_TIME_absolute_get ();
3446 return now.abs_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us / 15;
3447}

References GNUNET_TIME_Absolute::abs_value_us, GNUNET_TIME_absolute_get(), and GNUNET_TIME_UNIT_MINUTES.

Referenced by update_performance_data().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ free_incoming_request()

static void free_incoming_request ( struct IncomingRequest ir)
static

Release ir data structure.

Parameters
irdata structure to release

Definition at line 3456 of file gnunet-service-transport.c.

3457{
3459 GNUNET_assert (ir_total > 0);
3460 ir_total--;
3461 if (NULL != ir->nc)
3463 ir->nc = NULL;
3464 GNUNET_free (ir);
3465}

References GNUNET_assert, GNUNET_CONTAINER_DLL_remove, GNUNET_free, GNUNET_PEERSTORE_monitor_stop(), ir_head, ir_tail, ir_total, and IncomingRequest::nc.

Referenced by do_shutdown(), and try_to_bring_link_up().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ free_pending_acknowledgement()

static void free_pending_acknowledgement ( struct PendingAcknowledgement pa)
static

Release pa data structure.

Parameters
padata structure to release

Definition at line 3474 of file gnunet-service-transport.c.

3475{
3476 struct Queue *q = pa->queue;
3477 struct PendingMessage *pm = pa->pm;
3478 struct DistanceVectorHop *dvh = pa->dvh;
3479
3481 "free_pending_acknowledgement\n");
3482 if (NULL != q)
3483 {
3484 GNUNET_CONTAINER_MDLL_remove (queue, q->pa_head, q->pa_tail, pa);
3485 pa->queue = NULL;
3486 }
3487 if (NULL != pm)
3488 {
3490 "remove pa from message\n");
3492 "remove pa from message %" PRIu64 "\n",
3493 pm->logging_uuid);
3495 "remove pa from message %u\n",
3496 pm->pmt);
3498 "remove pa from message %s\n",
3500 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
3501 pa->pm = NULL;
3502 }
3503 if (NULL != dvh)
3504 {
3505 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
3506 pa->dvh = NULL;
3507 }
3510 &pa->ack_uuid.value,
3511 pa));
3512 GNUNET_free (pa);
3513}

References PendingAcknowledgement::ack_uuid, PendingAcknowledgement::dvh, GNUNET_assert, GNUNET_CONTAINER_MDLL_remove, GNUNET_CONTAINER_multiuuidmap_remove(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_log, GNUNET_uuid2s(), GNUNET_YES, PendingMessage::logging_uuid, DistanceVectorHop::pa_head, PendingMessage::pa_head, DistanceVectorHop::pa_tail, PendingMessage::pa_tail, pending_acks, PendingAcknowledgement::pm, PendingMessage::pmt, q, queue(), PendingAcknowledgement::queue, and AcknowledgementUUIDP::value.

Referenced by free_fragment_tree(), free_pending_ack_cb(), free_pending_message(), and handle_acknowledged().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ free_fragment_tree()

static void free_fragment_tree ( struct PendingMessage root)
static

Free fragment tree below root, excluding root itself.

FIXME: this does NOT seem to have the intended semantics based on how this is called. Seems we generally DO expect root to be free'ed itself as well!

Parameters
rootroot of the tree to free

Definition at line 3525 of file gnunet-service-transport.c.

3526{
3527 struct PendingMessage *frag;
3528
3529 while (NULL != (frag = root->head_frag))
3530 {
3531 struct PendingAcknowledgement *pa;
3532
3533 free_fragment_tree (frag);
3534 /* Release them: a `struct PendingAcknowledgement' whose @e pm is gone
3535 can never do anything useful again -- handle_acknowledged() would
3536 just free it -- but it stays in #pending_acks, and only an ACK that
3537 may never come takes it out. Merely detaching it here leaked one
3538 entry per fragment that was not acknowledged before its message went
3539 away, which on a lossy link is unbounded growth. */
3540 while (NULL != (pa = frag->pa_head))
3542 GNUNET_CONTAINER_MDLL_remove (frag, root->head_frag, root->tail_frag, frag);
3543 if (NULL != frag->qe)
3544 {
3545 GNUNET_assert (frag == frag->qe->pm);
3546 frag->qe->pm = NULL;
3547 }
3549 "Free frag %p\n",
3550 frag);
3551 GNUNET_free (frag);
3552 }
3553}

References free_fragment_tree(), free_pending_acknowledgement(), GNUNET_assert, GNUNET_CONTAINER_MDLL_remove, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_log, PendingMessage::head_frag, PendingMessage::pa_head, QueueEntry::pm, PendingMessage::qe, and PendingMessage::tail_frag.

Referenced by free_fragment_tree(), and free_pending_message().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ free_pending_message()

static void free_pending_message ( struct PendingMessage pm)
static

Release memory associated with pm and remove pm from associated data structures.

pm must be a top-level pending message and not a fragment in the tree. The entire tree is freed (if applicable).

Parameters
pmthe pending message to free

Definition at line 3564 of file gnunet-service-transport.c.

3565{
3566 struct TransportClient *tc = pm->client;
3567 struct VirtualLink *vl = pm->vl;
3568 struct PendingAcknowledgement *pa;
3569
3571 "Freeing pm %p\n",
3572 pm);
3573 if (NULL != tc)
3574 {
3576 tc->details.core.pending_msg_head,
3577 tc->details.core.pending_msg_tail,
3578 pm);
3579 }
3580 if ((NULL != vl) && (NULL == pm->frag_parent))
3581 {
3583 "Removing pm %" PRIu64 "\n",
3584 pm->logging_uuid);
3586 vl->pending_msg_head,
3587 vl->pending_msg_tail,
3588 pm);
3589 }
3590 else if (NULL != pm->frag_parent && PMT_DV_BOX != pm->pmt)
3591 {
3592 struct PendingMessage *root = pm->frag_parent;
3593
3594 while (NULL != root->frag_parent && PMT_DV_BOX != root->pmt)
3595 root = root->frag_parent;
3596
3597 root->frag_count--;
3598 }
3599 /* Same as in #free_fragment_tree(): the message these acknowledgements
3600 belong to is going away, so they are garbage rather than orphans. */
3601 while (NULL != (pa = pm->pa_head))
3603
3604 free_fragment_tree (pm);
3605 if (NULL != pm->qe)
3606 {
3607 GNUNET_assert (pm == pm->qe->pm);
3608 pm->qe->pm = NULL;
3609 }
3610 if (NULL != pm->bpm)
3611 {
3612 free_fragment_tree (pm->bpm);
3613 /* @e bpm is released with GNUNET_free() rather than through
3614 #free_pending_message(), so nothing here ever unlinked the
3615 acknowledgements attached to the box itself -- only those of its
3616 fragments, via the call above. They kept @e pm pointing into the
3617 block we are about to release, and #handle_acknowledged() follows
3618 that pointer when the ACK finally arrives. */
3619 while (NULL != (pa = pm->bpm->pa_head))
3621 if (NULL != pm->bpm->qe)
3622 {
3623 struct QueueEntry *qe = pm->bpm->qe;
3624
3625 qe->pm = NULL;
3626 }
3627 GNUNET_free (pm->bpm);
3628 }
3629
3630 GNUNET_free (pm);
3632 "Freeing pm done\n");
3633}

References PendingMessage::bpm, PendingMessage::client, PendingMessage::frag_count, PendingMessage::frag_parent, free_fragment_tree(), free_pending_acknowledgement(), GNUNET_assert, GNUNET_CONTAINER_MDLL_remove, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_log, PendingMessage::logging_uuid, PendingMessage::pa_head, VirtualLink::pending_msg_head, VirtualLink::pending_msg_tail, PendingAcknowledgement::pm, QueueEntry::pm, PendingMessage::pmt, PMT_DV_BOX, qe, PendingMessage::qe, tc, and PendingMessage::vl.

Referenced by client_send_response(), completed_pending_message(), free_virtual_link(), and transmit_on_queue().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ free_reassembly_context()

static void free_reassembly_context ( struct ReassemblyContext rc)
static

Free rc.

Parameters
rcdata structure to free

Definition at line 3642 of file gnunet-service-transport.c.

3643{
3644 struct VirtualLink *vl = rc->virtual_link;
3645
3649 rc->msg_uuid.uuid,
3650 rc));
3651 GNUNET_free (rc);
3652}

References GNUNET_assert, GNUNET_CONTAINER_heap_remove_node(), GNUNET_CONTAINER_multihashmap32_remove(), GNUNET_free, GNUNET_OK, ReassemblyContext::hn, ReassemblyContext::msg_uuid, VirtualLink::reassembly_map, MessageUUIDP::uuid, and ReassemblyContext::virtual_link.

Referenced by free_reassembly_cb(), handle_fragment_box(), and reassembly_cleanup_task().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ reassembly_cleanup_task()

static void reassembly_cleanup_task ( void *  cls)
static

Task run to clean up reassembly context of a neighbour that have expired.

Parameters
clsa struct Neighbour

Definition at line 3661 of file gnunet-service-transport.c.

3662{
3663 struct VirtualLink *vl = cls;
3664 struct ReassemblyContext *rc;
3665
3666 vl->reassembly_timeout_task = NULL;
3667 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (vl->reassembly_heap)))
3668 {
3670 .rel_value_us)
3671 {
3673 continue;
3674 }
3679 vl);
3680 return;
3681 }
3682}

References free_reassembly_context(), GNUNET_assert, GNUNET_CONTAINER_heap_peek(), GNUNET_SCHEDULER_add_at(), GNUNET_TIME_absolute_get_remaining(), reassembly_cleanup_task(), VirtualLink::reassembly_heap, ReassemblyContext::reassembly_timeout, VirtualLink::reassembly_timeout_task, and GNUNET_TIME_Relative::rel_value_us.

Referenced by handle_fragment_box(), and reassembly_cleanup_task().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ free_reassembly_cb()

static int free_reassembly_cb ( void *  cls,
uint32_t  key,
void *  value 
)
static

function called to free_reassembly_context().

Parameters
clsNULL
keyunused
valuea struct ReassemblyContext to free
Returns
GNUNET_OK (continue iteration)

Definition at line 3694 of file gnunet-service-transport.c.

3695{
3696 struct ReassemblyContext *rc = value;
3697
3698 (void) cls;
3699 (void) key;
3701 return GNUNET_OK;
3702}

References free_reassembly_context(), GNUNET_OK, key, and value.

Referenced by free_virtual_link().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ finish_cmc_handling_with_continue()

static void finish_cmc_handling_with_continue ( struct CommunicatorMessageContext cmc,
unsigned int  free_cmc 
)
static

Send ACK to communicator (if requested) and free cmc.

Send ACK to communicator (if requested), resume its client and free cmc.

Parameters
cmccontext for which we are done handling the message
free_cmcshould cmc be released?
cmccontext for which we are done handling the message
cmccontext for which we are done handling the message
free_cmcGNUNET_YES to release cmc, GNUNET_NO if the caller still owns it

Definition at line 5323 of file gnunet-service-transport.c.

5326{
5327 send_cmc_ack (cmc);
5328 resume_cmc_client (cmc);
5329 if (GNUNET_YES == free_cmc)
5330 {
5331 GNUNET_free (cmc);
5332 }
5333}

References GNUNET_free, GNUNET_YES, resume_cmc_client(), and send_cmc_ack().

Referenced by demultiplex_with_cmc(), finish_cmc_handling(), finish_handling_raw_message(), handle_raw_message(), and release_stalled_cmc().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ release_stalled_cmc()

static void release_stalled_cmc ( struct VirtualLink vl,
struct CommunicatorMessageContext cmc 
)
static

Take cmc off the list of messages waiting on vl's CORE receive window, release the flow control credit we were withholding and free it.

Parameters
vlvirtual link cmc is queued on
cmccontext to release

Definition at line 5337 of file gnunet-service-transport.c.

5339{
5341 GNUNET_assert (0 < vl->cmc_count);
5342 vl->cmc_count--;
5344}

References VirtualLink::cmc_count, VirtualLink::cmc_head, VirtualLink::cmc_tail, finish_cmc_handling_with_continue(), GNUNET_assert, GNUNET_CONTAINER_DLL_remove, and GNUNET_YES.

Referenced by core_fc_stalled(), finish_handling_raw_message(), free_virtual_link(), handle_client_recv_ok(), and resume_communicators().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ free_burst_cls()

static void free_burst_cls ( struct GNUNET_StartBurstCls sb_cls)
static

Release a burst closure, detaching it from its virtual link and from the scheduled burst_task (if that is the task the closure belongs to).

Parameters
sb_clsclosure to release

Definition at line 11810 of file gnunet-service-transport.c.

11811{
11812 struct VirtualLink *vl = sb_cls->vl;
11813
11814 if (burst_task_cls == sb_cls)
11815 {
11816 if (NULL != burst_task)
11817 {
11819 burst_task = NULL;
11820 }
11821 burst_task_cls = NULL;
11822 }
11823 if ((NULL != vl) && (vl->sb_cls == sb_cls))
11824 vl->sb_cls = NULL;
11826}

References burst_task, burst_task_cls, GNUNET_free, GNUNET_SCHEDULER_cancel(), VirtualLink::sb_cls, and GNUNET_StartBurstCls::vl.

Referenced by check_for_burst_address(), free_virtual_link(), queue_burst(), and start_burst().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ send_ok_to_client()

static void send_ok_to_client ( struct TransportClient tc,
const struct GNUNET_PeerIdentity pid 
)
static

Return one unit of send window credit for pid to tc.

GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK is the only way a CORE client ever learns that it may hand us another message for a peer: the client side (SEND_WINDOW_SIZE in transport_api_core.c) decrements a per-peer window on every send and only handle_send_ok() ever raises it again. So every SEND we accept has to be answered exactly once, whatever became of the message – it is a window, not a delivery confirmation ("in either case, it is now OK for this client to send us another message for the given peer", see ‘struct SendOkMessage’). Swallow one and the client loses that slot for good; swallow SEND_WINDOW_SIZE of them and it can never send to that peer again, with nothing to tell it why.

Parameters
tcclient to credit, may be NULL (message was not from a client)
pidpeer the credit is for

Definition at line 3756 of file gnunet-service-transport.c.

3758{
3759 struct GNUNET_MQ_Envelope *env;
3760 struct SendOkMessage *so_msg;
3761
3762 if (NULL == tc)
3763 return;
3765 so_msg->peer = *pid;
3766 GNUNET_MQ_send (tc->mq, env);
3767}

References env, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK, GNUNET_MQ_msg, GNUNET_MQ_send(), SendOkMessage::peer, and tc.

Referenced by credit_client(), and handle_client_send().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ credit_client()

static void credit_client ( struct PendingMessage pm)
static

Return the send window credit that pm's client is owed, at most once for pm.

A top-level message can reach more than one place that owes the credit – it is credited when it is handed to a queue, and its completion path may run afterwards, it may be picked up again for retransmission, and its link may be freed underneath it. The window would grow past SEND_WINDOW_SIZE if any two of those paid out for the same message.

Parameters
pmtop-level pending message whose credit to return

Definition at line 3783 of file gnunet-service-transport.c.

3784{
3785 if ((NULL == pm->client) || (GNUNET_YES == pm->client_credited))
3786 return;
3788 send_ok_to_client (pm->client, &pm->vl->target);
3789}

References PendingMessage::client, PendingMessage::client_credited, GNUNET_YES, send_ok_to_client(), VirtualLink::target, and PendingMessage::vl.

Referenced by client_send_response(), disconnect_and_free_virtual_link(), free_virtual_link(), and transmit_on_queue().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ free_virtual_link()

static void free_virtual_link ( struct VirtualLink vl)
static

Free virtual link.

Parameters
vllink data to free

Definition at line 3798 of file gnunet-service-transport.c.

3799{
3800 struct PendingMessage *pm;
3801 struct CoreSentContext *csc;
3802 struct CommunicatorMessageContext *cmc;
3803
3805 "free virtual link %p\n",
3806 vl);
3807
3808 /* Communicators that are blocked on CORE flow control for this link MUST
3809 be resumed here. Otherwise their `struct CommunicatorMessageContext's
3810 leak and -- worse -- those clients never get their
3811 GNUNET_SERVICE_client_continue() and stall forever. */
3812 while (NULL != (cmc = vl->cmc_head))
3813 release_stalled_cmc (vl, cmc);
3814 if (NULL != vl->core_fc_stall_task)
3815 {
3817 vl->core_fc_stall_task = NULL;
3818 }
3819
3820 if (NULL != vl->reassembly_map)
3821 {
3824 NULL);
3826 vl->reassembly_map = NULL;
3828 vl->reassembly_heap = NULL;
3829 }
3830 if (NULL != vl->reassembly_timeout_task)
3831 {
3833 vl->reassembly_timeout_task = NULL;
3834 }
3835 while (NULL != (pm = vl->pending_msg_head))
3836 {
3837 /* These never got transmitted, so #completed_pending_message() will not
3838 run for them and nobody else answers their SEND either. Return the
3839 window credit anyway: CORE keeps its `struct Neighbour' -- and thus
3840 the window -- until it sees our DISCONNECT, and #handle_client_send()
3841 deliberately tolerates a SEND for a link that is already gone, so a
3842 client can easily still be sending while we free this. */
3843 credit_client (pm);
3845 }
3848 if (NULL != vl->visibility_task)
3849 {
3851 vl->visibility_task = NULL;
3852 }
3853 if (NULL != vl->fc_retransmit_task)
3854 {
3856 vl->fc_retransmit_task = NULL;
3857 }
3858 while (NULL != (csc = vl->csc_head))
3859 {
3861 GNUNET_assert (vl == csc->vl);
3862 csc->vl = NULL;
3863 }
3864 if (NULL != vl->unconfirmed_timeout_task)
3865 {
3867 vl->unconfirmed_timeout_task = NULL;
3868 }
3869 if (NULL != vl->ic)
3870 {
3871 /* the closure of this iteration is @e sb_cls, released just below */
3873 vl->ic = NULL;
3874 }
3875 if (NULL != vl->sb_cls)
3876 {
3877 /* Cancels #burst_task if that task's closure is ours: it would
3878 otherwise run on this (freed) link. */
3879 free_burst_cls (vl->sb_cls);
3880 GNUNET_assert (NULL == vl->sb_cls);
3881 }
3882 GNUNET_free (vl->burst_addr);
3883 GNUNET_break (NULL == vl->n);
3884 GNUNET_break (NULL == vl->dv);
3885 GNUNET_free (vl);
3886}

References VirtualLink::burst_addr, VirtualLink::cmc_head, VirtualLink::core_fc_stall_task, credit_client(), VirtualLink::csc_head, VirtualLink::csc_tail, VirtualLink::dv, VirtualLink::fc_retransmit_task, free_burst_cls(), free_pending_message(), free_reassembly_cb(), GNUNET_assert, GNUNET_break, GNUNET_CONTAINER_DLL_remove, GNUNET_CONTAINER_heap_destroy(), GNUNET_CONTAINER_multihashmap32_destroy(), GNUNET_CONTAINER_multihashmap32_iterate(), GNUNET_CONTAINER_multipeermap_remove(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_log, GNUNET_PEERSTORE_iteration_stop(), GNUNET_SCHEDULER_cancel(), GNUNET_YES, VirtualLink::ic, links, VirtualLink::n, VirtualLink::pending_msg_head, VirtualLink::reassembly_heap, VirtualLink::reassembly_map, VirtualLink::reassembly_timeout_task, release_stalled_cmc(), VirtualLink::sb_cls, VirtualLink::target, VirtualLink::unconfirmed_timeout_task, VirtualLink::visibility_task, and CoreSentContext::vl.

Referenced by disconnect_and_free_virtual_link(), free_virtual_link_cb(), and unconfirmed_link_timeout().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ free_validation_state()

static void free_validation_state ( struct ValidationState vs)
static

Free validation state.

Parameters
vsvalidation state to free

Definition at line 3895 of file gnunet-service-transport.c.

3896{
3897 if (NULL != vs->revalidation_task)
3898 {
3899 GNUNET_SCHEDULER_cancel (vs->revalidation_task);
3900 vs->revalidation_task = NULL;
3901 }
3902 /*memcpy (&hkey,
3903 &hc,
3904 sizeof (hkey));*/
3906 "Remove key %s for address %s map size %u contains %u during freeing state\n",
3907 GNUNET_h2s (&vs->hc),
3908 vs->address,
3911 &vs->hc));
3914 GNUNET_YES ==
3917 vs->hn = NULL;
3918 if (NULL != vs->sc)
3919 {
3921 "store cancel\n");
3923 vs->sc = NULL;
3924 }
3925 GNUNET_free (vs->address);
3926 GNUNET_free (vs);
3927}

References GNUNET_assert, GNUNET_CONTAINER_heap_remove_node(), GNUNET_CONTAINER_multihashmap_contains(), GNUNET_CONTAINER_multihashmap_remove(), GNUNET_CONTAINER_multihashmap_size(), GNUNET_CONTAINER_multipeermap_remove(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_h2s(), GNUNET_log, GNUNET_PEERSTORE_store_cancel(), GNUNET_SCHEDULER_cancel(), GNUNET_YES, ValidationState::pid, revalidation_map, and validation_map.

Referenced by free_validation_state_cb(), and validation_start_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ lookup_neighbour()

static struct Neighbour * lookup_neighbour ( const struct GNUNET_PeerIdentity pid)
static

Lookup neighbour for peer pid.

Parameters
pidneighbour to look for
Returns
NULL if we do not have this peer as a neighbour

Definition at line 3937 of file gnunet-service-transport.c.

3938{
3940}

References GNUNET_CONTAINER_multipeermap_get(), neighbours, and Neighbour::pid.

Referenced by consider_sending_fc(), find_queue(), find_queue_by_ip(), forward_dv_learn(), handle_add_queue_message(), handle_communicator_backchannel(), handle_dv_box(), handle_dv_learn(), handle_incoming_msg(), learn_dv_path(), route_control_message_without_fc(), send_t_validation_response(), transmit_cummulative_ack_cb(), and try_to_bring_link_up().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ lookup_virtual_link()

static struct VirtualLink * lookup_virtual_link ( const struct GNUNET_PeerIdentity pid)
static

Lookup virtual link for peer pid.

Parameters
pidvirtual link to look for
Returns
NULL if we do not have this peer as a virtual link

Definition at line 3950 of file gnunet-service-transport.c.

3951{
3953}

References GNUNET_CONTAINER_multipeermap_get(), and links.

Referenced by activate_core_visible_dv_path(), check_vl_transmission(), forward_dv_learn(), free_queue(), handle_client_recv_ok(), handle_client_send(), handle_communicator_backchannel(), handle_flow_control(), handle_fragment_box(), handle_link_list_request(), handle_raw_message(), handle_validation_response(), send_t_validation_response(), start_address_validation(), suggest_retry_cb(), transmit_cummulative_ack_cb(), and validation_challenge_freq().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ free_distance_vector_hop()

static void free_distance_vector_hop ( struct DistanceVectorHop dvh)
static

Free a dvh.

Callers MAY want to check if this was the last path to the target, and if so call free_dv_route to also free the associated DV entry in dv_routes (if not, the associated scheduler job should eventually take care of it).

Parameters
dvhhop to free

Definition at line 3999 of file gnunet-service-transport.c.

4000{
4001 struct Neighbour *n = dvh->next_hop;
4002 struct DistanceVector *dv = dvh->dv;
4003 struct PendingAcknowledgement *pa;
4004
4005 while (NULL != (pa = dvh->pa_head))
4006 {
4008 pa->dvh = NULL;
4009 }
4010 GNUNET_CONTAINER_MDLL_remove (neighbour, n->dv_head, n->dv_tail, dvh);
4012 GNUNET_free (dvh);
4013}

References DistanceVectorHop::dv, DistanceVector::dv_head, Neighbour::dv_head, DistanceVector::dv_tail, Neighbour::dv_tail, PendingAcknowledgement::dvh, GNUNET_CONTAINER_MDLL_remove, GNUNET_free, DistanceVectorHop::next_hop, DistanceVectorHop::pa_head, and DistanceVectorHop::pa_tail.

Referenced by free_dv_route(), free_neighbour(), and path_cleanup_cb().

Here is the caller graph for this function:

◆ check_link_down()

static void check_link_down ( void *  cls)
static

Task run to check whether the hops of the cls still are validated, or if we need to core about disconnection.

Parameters
clsa struct VirtualLink

Definition at line 4519 of file gnunet-service-transport.c.

4520{
4521 struct VirtualLink *vl = cls;
4522 struct DistanceVector *dv = vl->dv;
4523 struct Neighbour *n = vl->n;
4524 struct GNUNET_TIME_Absolute dvh_timeout;
4525 struct GNUNET_TIME_Absolute q_timeout;
4526
4528 "Checking if link is down\n");
4529 vl->visibility_task = NULL;
4530 dvh_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
4531 if (NULL != dv)
4532 {
4533 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4534 pos = pos->next_dv)
4535 dvh_timeout = GNUNET_TIME_absolute_max (dvh_timeout,
4536 pos->path_valid_until);
4537 if (0 == GNUNET_TIME_absolute_get_remaining (dvh_timeout).rel_value_us)
4538 {
4539 vl->dv->vl = NULL;
4540 vl->dv = NULL;
4541 }
4542 }
4543 q_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
4544 /* NOTE: @e n may be NULL here: #free_neighbour() clears vl->n and then
4545 schedules us when the link still has a DV route. */
4546 if (NULL != n)
4547 {
4548 struct GNUNET_TIME_Absolute liveness_deadline;
4549
4550 /* A successful validation is good for #ADDRESS_VALIDATION_LIFETIME (four
4551 hours). Do not take a communicator's word for that long: cap what the
4552 queues are worth by how recently this neighbour actually said anything
4553 to us. Otherwise a communicator that stops working without sending a
4554 QUEUE_TEARDOWN keeps this link -- and CORE's idea of the connection --
4555 alive until the validation expires. */
4556 liveness_deadline = GNUNET_TIME_absolute_add (n->last_inbound,
4558 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
4559 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
4560 if (GNUNET_TIME_absolute_cmp (liveness_deadline, <, q_timeout))
4561 {
4562 if (0 ==
4564 {
4565 /* Only reachable if a communicator failed to tear its queue down. */
4567 "Neighbour %s was silent for %s while its communicator "
4568 "kept claiming the queue works; treating link as down\n",
4569 GNUNET_i2s (&vl->target),
4572 GNUNET_YES));
4574 "# links dropped (neighbour silent)",
4575 1,
4576 GNUNET_NO);
4577 }
4578 q_timeout = liveness_deadline;
4579 }
4580 if (0 == GNUNET_TIME_absolute_get_remaining (q_timeout).rel_value_us)
4581 {
4582 vl->n->vl = NULL;
4583 vl->n = NULL;
4584 }
4585 }
4586 if ((NULL == vl->n) && (NULL == vl->dv))
4587 {
4589 /* @e n (if any) outlives the link, and so do its queues: the liveness cap
4590 above drops a link whose addresses are still well inside
4591 #ADDRESS_VALIDATION_LIFETIME. In that state nothing would ever ask for
4592 a fresh challenge -- @e revalidation_task does not fire until the four
4593 hour validity is nearly over, and the HELLO path reaches
4594 #start_address_validation() only to find an address that still counts
4595 as valid. Since #handle_validation_response() is the only thing that
4596 can rebuild this link and tell CORE about the peer again, ask for that
4597 validation now, or CORE never hears about this peer again. */
4598 if (NULL != n)
4599 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
4600 start_address_validation (&n->pid, q->address);
4601 return;
4602 }
4603 vl->visibility_task =
4604 GNUNET_SCHEDULER_add_at (GNUNET_TIME_absolute_max (q_timeout, dvh_timeout),
4606 vl);
4607}

References check_link_down(), disconnect_and_free_virtual_link(), VirtualLink::dv, DistanceVector::dv_head, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_WARNING, GNUNET_i2s(), GNUNET_log, GNUNET_NO, GNUNET_SCHEDULER_add_at(), GNUNET_STATISTICS_update(), GNUNET_STRINGS_relative_time_to_string(), GNUNET_TIME_absolute_add(), GNUNET_TIME_absolute_cmp, GNUNET_TIME_absolute_get_remaining(), GNUNET_TIME_absolute_max(), GNUNET_TIME_UNIT_ZERO_ABS, GNUNET_YES, GST_stats, Neighbour::last_inbound, VirtualLink::n, NEIGHBOUR_LIVENESS_TIMEOUT, Neighbour::pid, q, Neighbour::queue_head, GNUNET_TIME_Relative::rel_value_us, start_address_validation(), VirtualLink::target, VirtualLink::visibility_task, DistanceVector::vl, and Neighbour::vl.

Referenced by activate_core_visible_dv_path(), check_link_down(), free_dv_route(), free_neighbour(), free_queue(), and handle_validation_response().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cores_send_disconnect_info()

static void cores_send_disconnect_info ( const struct GNUNET_PeerIdentity pid)
static

Send message to CORE clients that we lost a connection.

Parameters
pidpeer the connection was for

Definition at line 4032 of file gnunet-service-transport.c.

4033{
4035 "Informing CORE clients about disconnect from %s\n",
4036 GNUNET_i2s (pid));
4037 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
4038 {
4039 struct GNUNET_MQ_Envelope *env;
4040 struct DisconnectInfoMessage *dim;
4041
4042 if (CT_CORE != tc->type)
4043 continue;
4045 dim->peer = *pid;
4046 GNUNET_MQ_send (tc->mq, env);
4047 }
4048}

References clients_head, CT_CORE, dim, env, GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT, GNUNET_MQ_msg, GNUNET_MQ_send(), and tc.

Referenced by disconnect_and_free_virtual_link().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ try_to_bring_link_up()

static void try_to_bring_link_up ( const struct GNUNET_PeerIdentity pid)
static

Ask for everything that could give us a confirmed virtual link to pid: revalidate the addresses we already track, then those of the queues we still have, and failing both look for one in PEERSTORE.

Rate limited internally, so it is cheap to call often.

Parameters
pidpeer we want a link to

Definition at line 10901 of file gnunet-service-transport.c.

10902{
10903 struct Neighbour *n;
10904 struct IncomingRequest *ir;
10905
10906 if (GNUNET_YES == in_shutdown)
10907 return;
10908 /* (1) Addresses we already track. These outlive the queues, which is the
10909 point: once a link is down the queue that carried it is usually gone,
10910 so there is no address string left for #start_address_validation(). */
10912 pid,
10914 NULL);
10915 /* (2) Queues we still have; may cover an address with no validation state
10916 yet. After (1), because it may insert into #validation_map. */
10917 n = lookup_neighbour (pid);
10918 if (NULL != n)
10919 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
10920 start_address_validation (pid, q->address);
10921 /* (3) Failing that, look for an address in PEERSTORE. */
10922 for (ir = ir_head; NULL != ir; ir = ir->next)
10923 {
10924 if (0 == GNUNET_memcmp (&ir->pid, pid))
10925 return; /* we are already trying */
10926 }
10927 ir = GNUNET_new (struct IncomingRequest);
10928 ir->pid = *pid;
10930 /* Monitor only @a pid: with NULL every request sees every HELLO in
10931 PEERSTORE, so each of the up to #MAX_INCOMING_REQUEST requests started
10932 a connection attempt and an address validation for peers it was not
10933 created for. */
10935 GNUNET_YES,
10936 "peerstore",
10937 &ir->pid,
10940 NULL,
10942 NULL,
10944 ir);
10945 ir_total++;
10946 /* Bound attempts we do in parallel here, might otherwise get excessive.
10947 Drop the OLDEST request: #ir_head is the one we just inserted, so
10948 freeing that would immediately undo the work above. */
10951}

References free_incoming_request(), GNUNET_CONTAINER_DLL_insert, GNUNET_CONTAINER_multipeermap_get_multiple(), GNUNET_memcmp, GNUNET_new, GNUNET_PEERSTORE_HELLO_KEY, GNUNET_PEERSTORE_monitor_start(), GNUNET_YES, GST_cfg, handle_hello_for_incoming(), hello_for_incoming_error_cb(), hello_for_incoming_sync_cb(), in_shutdown, ir_head, ir_tail, ir_total, lookup_neighbour(), MAX_INCOMING_REQUEST, IncomingRequest::nc, IncomingRequest::next, IncomingRequest::pid, q, Neighbour::queue_head, revalidate_now_cb(), start_address_validation(), and validation_map.

Referenced by disconnect_and_free_virtual_link(), handle_flow_control(), send_t_validation_response(), and suggest_retry_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ disconnect_and_free_virtual_link()

static void disconnect_and_free_virtual_link ( struct VirtualLink vl)
static

Tell CORE clients the link to vl is gone, then release it.

Order matters. free_virtual_link() returns the send window credit for every message that never made it out, and that credit and the DISCONNECT travel the same client MQ in the order we queue them. A CORE client drops its ‘struct Neighbour’ – window and all – the instant it sees the DISCONNECT, so a SEND_OK queued behind it arrives for a peer the client no longer knows. That path is handle_send_ok()'s "we should never get a SEND_OK for a peer that we are not connected to" (transport_api_core.c), and it does not merely complain: it calls disconnect_and_schedule_reconnect(), which drops every neighbour the client has and forces a fresh key exchange with all of them. One link going down with a message still pending thus costs the peer all of its CORE sessions.

So pay out the credits first, while the client still has the neighbour to book them against. credit_client() is idempotent, so the calls free_virtual_link() makes afterwards are no-ops.

Parameters
vllink that is going away

Definition at line 4078 of file gnunet-service-transport.c.

4079{
4080 struct GNUNET_PeerIdentity target = vl->target;
4081
4082 for (struct PendingMessage *pm = vl->pending_msg_head;
4083 NULL != pm;
4084 pm = pm->next_vl)
4085 credit_client (pm);
4087 free_virtual_link (vl);
4088 /* Start getting it back now. Only #handle_validation_response() can
4089 rebuild it, and a successful validation parks @e revalidation_task just
4090 short of #ADDRESS_VALIDATION_LIFETIME -- four hours away. */
4091 try_to_bring_link_up (&target);
4092}

References cores_send_disconnect_info(), credit_client(), free_virtual_link(), VirtualLink::pending_msg_head, VirtualLink::target, and try_to_bring_link_up().

Referenced by check_link_down(), free_dv_route(), and free_neighbour().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ free_dv_route()

static void free_dv_route ( struct DistanceVector dv)
static

Free entry in dv_routes.

First frees all hops to the target, and if there are no entries left, frees dv as well.

Parameters
dvroute to free

Definition at line 4102 of file gnunet-service-transport.c.

4103{
4104 struct DistanceVectorHop *dvh;
4105 struct VirtualLink *vl;
4106
4107 while (NULL != (dvh = dv->dv_head))
4109
4111 GNUNET_YES ==
4113 if (NULL != (vl = dv->vl))
4114 {
4115 GNUNET_assert (dv == vl->dv);
4116 vl->dv = NULL;
4117 if (NULL == vl->n)
4118 {
4120 }
4121 else
4122 {
4123 /* @e visibility_task is NULL while #check_link_down() itself runs, and
4124 #GNUNET_SCHEDULER_cancel() dereferences its argument. */
4125 if (NULL != vl->visibility_task)
4128 }
4129 dv->vl = NULL;
4130 }
4131
4132 if (NULL != dv->timeout_task)
4133 {
4135 dv->timeout_task = NULL;
4136 }
4137 GNUNET_free (dv->km);
4138 GNUNET_free (dv);
4139}

References check_link_down(), disconnect_and_free_virtual_link(), VirtualLink::dv, DistanceVector::dv_head, dv_routes, free_distance_vector_hop(), GNUNET_assert, GNUNET_CONTAINER_multipeermap_remove(), GNUNET_free, GNUNET_SCHEDULER_add_now(), GNUNET_SCHEDULER_cancel(), GNUNET_YES, DistanceVector::km, VirtualLink::n, DistanceVector::target, DistanceVector::timeout_task, VirtualLink::visibility_task, and DistanceVector::vl.

Referenced by free_dv_routes_cb(), free_neighbour(), and path_cleanup_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ notify_monitor()

static void notify_monitor ( struct TransportClient tc,
const struct GNUNET_PeerIdentity peer,
const char *  address,
enum GNUNET_NetworkType  nt,
const struct MonitorEvent me 
)
static

Notify monitor tc about an event.

That tc cares about the event has already been checked.

Send tc information in me about a peer's status with respect to some address to all monitors that care.

Parameters
tcmonitor to inform
peerpeer the information is about
addressaddress the information is about
ntnetwork type associated with address
medetailed information to transmit

Definition at line 4156 of file gnunet-service-transport.c.

4161{
4162 struct GNUNET_MQ_Envelope *env;
4164 size_t addr_len = strlen (address) + 1;
4165
4167 addr_len,
4169 md->nt = htonl ((uint32_t) nt);
4170 md->peer = *peer;
4171 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
4172 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
4173 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
4174 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
4175 md->cs = htonl ((uint32_t) me->cs);
4176 md->num_msg_pending = htonl (me->num_msg_pending);
4177 md->num_bytes_pending = htonl (me->num_bytes_pending);
4178 memcpy (&md[1], address, addr_len);
4179 GNUNET_MQ_send (tc->mq, env);
4180}

References address, GNUNET_TRANSPORT_MonitorData::cs, env, GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA, GNUNET_MQ_msg_extra, GNUNET_MQ_send(), GNUNET_TIME_absolute_hton(), GNUNET_TIME_relative_hton(), GNUNET_TRANSPORT_MonitorData::last_validation, me, GNUNET_TRANSPORT_MonitorData::next_validation, nt, GNUNET_TRANSPORT_MonitorData::nt, GNUNET_TRANSPORT_MonitorData::num_bytes_pending, GNUNET_TRANSPORT_MonitorData::num_msg_pending, GNUNET_TRANSPORT_MonitorData::peer, GNUNET_TRANSPORT_MonitorData::rtt, tc, and GNUNET_TRANSPORT_MonitorData::valid_until.

Referenced by notify_client_queues(), and notify_monitors().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ notify_monitors()

static void notify_monitors ( const struct GNUNET_PeerIdentity peer,
const char *  address,
enum GNUNET_NetworkType  nt,
const struct MonitorEvent me 
)
static

Send information in me about a peer's status with respect to some address to all monitors that care.

Parameters
peerpeer the information is about
addressaddress the information is about
ntnetwork type associated with address
medetailed information to transmit

Definition at line 4193 of file gnunet-service-transport.c.

4197{
4198 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
4199 {
4200 if (CT_MONITOR != tc->type)
4201 continue;
4202 if (tc->details.monitor.one_shot)
4203 continue;
4204 if ((GNUNET_NO == GNUNET_is_zero (&tc->details.monitor.peer)) &&
4205 (0 != GNUNET_memcmp (&tc->details.monitor.peer, peer)))
4206 continue;
4207 notify_monitor (tc, peer, address, nt, me);
4208 }
4209}

References address, clients_head, CT_MONITOR, GNUNET_is_zero, GNUNET_memcmp, GNUNET_NO, me, notify_monitor(), nt, GNUNET_TRANSPORT_MonitorData::peer, and tc.

Referenced by free_queue(), and handle_add_queue_message().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ client_connect_cb()

static void * client_connect_cb ( void *  cls,
struct GNUNET_SERVICE_Client client,
struct GNUNET_MQ_Handle mq 
)
static

Called whenever a client connects.

Allocates our data structures associated with that client.

Parameters
clsclosure, NULL
clientidentification of the client
mqmessage queue for the client
Returns
our struct TransportClient

Definition at line 4222 of file gnunet-service-transport.c.

4225{
4226 struct TransportClient *tc;
4227
4228 (void) cls;
4229 tc = GNUNET_new (struct TransportClient);
4230 tc->client = client;
4231 tc->mq = mq;
4234 "Client %p of type %u connected\n",
4235 tc,
4236 tc->type);
4237 return tc;
4238}

References TransportClient::client, clients_head, clients_tail, GNUNET_CONTAINER_DLL_insert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_new, mq, and tc.

◆ remove_global_addresses()

static enum GNUNET_GenericReturnValue remove_global_addresses ( void *  cls,
const struct GNUNET_PeerIdentity pid,
void *  value 
)
static

Definition at line 4242 of file gnunet-service-transport.c.

4245{
4246 struct TransportGlobalNattedAddress *tgna = value;
4247 (void) cls;
4248
4249 GNUNET_free (tgna);
4250
4251 return GNUNET_OK;
4252}

References GNUNET_free, GNUNET_OK, and value.

Referenced by free_neighbour().

Here is the caller graph for this function:

◆ free_neighbour()

static void free_neighbour ( struct Neighbour neighbour,
enum GNUNET_GenericReturnValue  drop_link 
)
static

Release memory used by neighbour.

Parameters
neighbourneighbour entry to free
drop_linkflag to decide whether to drop its virtual link

Definition at line 4262 of file gnunet-service-transport.c.

4264{
4265 struct DistanceVectorHop *dvh;
4266 struct VirtualLink *vl;
4267
4268 GNUNET_assert (NULL == neighbour->queue_head);
4271 &neighbour->pid,
4272 neighbour));
4274 "Freeing neighbour\n");
4277 NULL);
4279 while (NULL != (dvh = neighbour->dv_head))
4280 {
4281 struct DistanceVector *dv = dvh->dv;
4282
4284 if (NULL == dv->dv_head)
4285 free_dv_route (dv);
4286 }
4287 if (NULL != neighbour->get)
4288 {
4290 neighbour->get = NULL;
4291 }
4292 if (NULL != neighbour->sc)
4293 {
4295 "store cancel\n");
4296 GNUNET_PEERSTORE_store_cancel (neighbour->sc);
4297 neighbour->sc = NULL;
4298 }
4299 if (NULL != (vl = neighbour->vl))
4300 {
4301 GNUNET_assert (neighbour == vl->n);
4302 vl->n = NULL;
4303 if ((GNUNET_YES == drop_link) || (NULL == vl->dv))
4304 {
4306 }
4307 else
4308 {
4309 /* See #free_dv_route(): may be NULL under #check_link_down(). */
4310 if (NULL != vl->visibility_task)
4313 }
4314 neighbour->vl = NULL;
4315 }
4316 GNUNET_free (neighbour);
4317}

References check_link_down(), disconnect_and_free_virtual_link(), VirtualLink::dv, DistanceVectorHop::dv, DistanceVector::dv_head, Neighbour::dv_head, free_distance_vector_hop(), free_dv_route(), Neighbour::get, GNUNET_assert, GNUNET_CONTAINER_multipeermap_destroy(), GNUNET_CONTAINER_multipeermap_iterate(), GNUNET_CONTAINER_multipeermap_remove(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_log, GNUNET_PEERSTORE_iteration_stop(), GNUNET_PEERSTORE_store_cancel(), GNUNET_SCHEDULER_add_now(), GNUNET_SCHEDULER_cancel(), GNUNET_YES, VirtualLink::n, Neighbour::natted_addresses, neighbours, Neighbour::pid, Neighbour::queue_head, remove_global_addresses(), Neighbour::sc, VirtualLink::visibility_task, DistanceVector::vl, and Neighbour::vl.

Referenced by free_neighbour_cb(), and free_queue().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ core_send_connect_info()

static void core_send_connect_info ( struct TransportClient tc,
const struct GNUNET_PeerIdentity pid 
)
static

Send message to CORE clients that we lost a connection.

Parameters
tcclient to inform (must be CORE client)
pidpeer the connection is for

Definition at line 4327 of file gnunet-service-transport.c.

4329{
4330 struct GNUNET_MQ_Envelope *env;
4331 struct ConnectInfoMessage *cim;
4332
4333 GNUNET_assert (CT_CORE == tc->type);
4335 cim->id = *pid;
4336 GNUNET_MQ_send (tc->mq, env);
4337}

References CT_CORE, env, GNUNET_assert, GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT, GNUNET_MQ_msg, GNUNET_MQ_send(), ConnectInfoMessage::id, and tc.

Referenced by cores_send_connect_info(), and notify_client_connect_info().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cores_send_connect_info()

static void cores_send_connect_info ( const struct GNUNET_PeerIdentity pid)
static

Send message to CORE clients that we gained a connection.

Parameters
pidpeer the queue was for

Definition at line 4346 of file gnunet-service-transport.c.

4347{
4349 "Informing CORE clients about connection to %s\n",
4350 GNUNET_i2s (pid));
4351 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
4352 {
4353 if (CT_CORE != tc->type)
4354 continue;
4356 }
4357}

References clients_head, core_send_connect_info(), CT_CORE, GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, and tc.

Referenced by activate_core_visible_dv_path(), and handle_validation_response().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ transmit_on_queue()

static void transmit_on_queue ( void *  cls)
static

We believe we are ready to transmit a message on a queue.

We believe we are ready to transmit a struct PendingMessage on a queue, the big question is which one! We need to see if there is one pending that is allowed by flow control and congestion control and (ideally) matches our queue's performance profile.

Gives the message to the communicator for transmission (updating the tracker, and re-scheduling itself if applicable).

Parameters
clsthe struct Queue to process transmissions for

If such a message is found, we give the message to the communicator for transmission (updating the tracker, and re-scheduling ourselves if applicable).

If no such message is found, the queue's idle field must be set to GNUNET_YES.

Parameters
clsthe struct Queue to process transmissions for

Definition at line 13063 of file gnunet-service-transport.c.

13064{
13065 struct Queue *queue = cls;
13066 struct Neighbour *n = queue->neighbour;
13068 struct PendingMessage *pm;
13069
13070 queue->transmit_task = NULL;
13071 if ((NULL == n->vl) && (NULL == n->dv_head))
13072 {
13074 "Virtual link `%s' is down, cannot have PM for queue `%s'\n",
13075 GNUNET_i2s (&n->pid),
13076 queue->address);
13077 queue->idle = GNUNET_YES;
13078 return;
13079 }
13080 memset (&sc, 0, sizeof(sc));
13081 /* @e n need not have a link of its own: it may serve only as the first
13082 hop of DV paths, and the traffic queued for those still has to go out. */
13083 if (NULL != n->vl)
13084 select_best_pending_from_link (&sc, queue, n->vl, NULL, 0);
13085 if (NULL == sc.best)
13086 {
13087 /* Also look at DVH that have the n as first hop! */
13088 for (struct DistanceVectorHop *dvh = n->dv_head; NULL != dvh;
13089 dvh = dvh->next_neighbour)
13090 {
13091 if (NULL == dvh->dv->vl)
13092 continue; /* route not (yet) visible to CORE, no messages for it */
13094 queue,
13095 dvh->dv->vl,
13096 dvh,
13097 sizeof(struct GNUNET_PeerIdentity)
13098 * (1 + dvh->distance)
13099 + sizeof(struct TransportDVBoxMessage)
13100 + sizeof(struct TransportDVBoxPayloadP));
13101 }
13102 }
13103 if (NULL == sc.best)
13104 {
13105 /* no message pending, nothing to do here! */
13107 "No pending messages, queue `%s' to %s now idle\n",
13108 queue->address,
13109 GNUNET_i2s (&n->pid));
13110 if (GNUNET_YES == sc.to_early)
13111 schedule_transmit_on_queue (sc.to_early_retry_delay,
13112 queue,
13114 queue->idle = GNUNET_YES;
13115 return;
13116 }
13117 /* There is a message pending, we are certainly not idle */
13118 queue->idle = GNUNET_NO;
13119
13120 /* Given selection in `sc`, do transmission */
13121 pm = sc.best;
13123 "Selected message <%" PRIu64 ">\n",
13124 pm->logging_uuid);
13125 if (NULL != sc.dvh)
13126 {
13128 "Is this %u a DV box?\n",
13129 pm->pmt);
13130 GNUNET_assert (PMT_DV_BOX != pm->pmt);
13131 if ((NULL != sc.best->bpm) && (sc.best->bpm->used_dvh != sc.dvh))
13132 {
13134 "Discard old box, because we have a new DV path.\n");
13135 free_pending_message (sc.best->bpm);
13136 sc.best->bpm = NULL;
13137 }
13138
13139 if (NULL == sc.best->bpm)
13140 {
13142 "encapsulate_for_dv 2\n");
13143 encapsulate_for_dv (sc.dvh->dv,
13144 1,
13145 &sc.dvh,
13146 (const struct GNUNET_MessageHeader *) &sc.best[1],
13148 &sc,
13149 RMO_NONE,
13150 GNUNET_NO);
13151 GNUNET_assert (NULL != sc.best->bpm);
13153 "%lu %lu %lu %lu %u\n",
13154 sizeof(struct GNUNET_PeerIdentity),
13155 sizeof(struct TransportDVBoxMessage),
13156 sizeof(struct TransportDVBoxPayloadP),
13157 sizeof(struct TransportFragmentBoxMessage),
13158 ((const struct GNUNET_MessageHeader *) &sc.best[1])->size);
13159 sc.best->bpm->used_dvh = sc.dvh;
13160 }
13161 pm = sc.best->bpm;
13162 }
13163 if (GNUNET_YES == sc.frag)
13164 {
13165 pm = fragment_message (queue, sc.dvh, pm);
13166 if (NULL == pm)
13167 {
13169 "Fragmentation failed queue %s to %s for <%" PRIu64
13170 ">, trying again\n",
13171 queue->address,
13172 GNUNET_i2s (&n->pid),
13173 sc.best->logging_uuid);
13174 /* NOT with a zero delay: nothing about @a queue or about the message
13175 changed between here and the next pass, so "trying again" at once
13176 is a busy loop that reproduces the failure at scheduler speed. */
13178 queue,
13180 return;
13181 }
13182 }
13183 else if (GNUNET_YES == sc.relb)
13184 {
13185 pm = reliability_box_message (queue, sc.dvh, pm);
13186 if (NULL == pm)
13187 {
13188 /* Reliability boxing failed, try next message... */
13189 GNUNET_log (
13191 "Reliability boxing failed queue %s to %s for <%" PRIu64
13192 ">, trying again\n",
13193 queue->address,
13194 GNUNET_i2s (&n->pid),
13195 sc.best->logging_uuid);
13196 /* Same reasoning as for the fragmentation failure above. */
13198 queue,
13200 return;
13201 }
13202 }
13203
13204 /* Pass 'pm' for transission to the communicator */
13205 GNUNET_log (
13207 "Passing message <%" PRIu64
13208 "> to queue %s for peer %s (considered %u others)\n",
13209 pm->logging_uuid,
13210 queue->address,
13211 GNUNET_i2s (&n->pid),
13212 sc.consideration_counter);
13213
13214 /* Flow control: increment amount of traffic sent; if we are routing
13215 via DV (and thus the ultimate target of the pending message is for
13216 a different virtual link than the one of the queue), then we need
13217 to use up not only the window of the direct link but also the
13218 flow control window for the DV link! */
13220
13221 if (pm->vl != queue->neighbour->vl)
13222 {
13223 /* If the virtual link of the queue differs, this better be distance
13224 vector routing! */
13225 GNUNET_assert (NULL != sc.dvh);
13226 /* If we do distance vector routing, we better not do this for a
13227 message that was itself DV-routed */
13228 GNUNET_assert (PMT_DV_BOX != sc.best->pmt);
13229 /* We use the size of the unboxed message here, to avoid counting
13230 the DV-Box header which is eaten up on the way by intermediaries.
13231 The next hop need not have a link of its own, in which case there is
13232 no window of it to charge. */
13233 if (NULL != queue->neighbour->vl)
13234 queue->neighbour->vl->outbound_fc_window_size_used += sc.best->bytes_msg;
13235 }
13236 else
13237 {
13238 GNUNET_assert (NULL == sc.dvh);
13239 }
13240
13241 queue_send_msg (queue, pm, &pm[1], pm->bytes_msg);
13242
13243 /* The message is with the communicator now, so return the CORE send
13244 window credit for it -- see #credit_client().
13245
13246 It used to be returned here only for an unboxed message or a reliable
13247 communicator, and otherwise not until the *peer* acknowledged the
13248 message below. That makes a window into a delivery confirmation: over
13249 an unreliable communicator every reliability-boxed or fragmented
13250 message holds one of the client's #SEND_WINDOW_SIZE slots for as long
13251 as its ACK takes, and a lost ACK holds it for the whole retransmission
13252 chain. Four of those and CORE cannot send to that peer at all -- not
13253 payload, but also not its HEARTBEATs and not one message of its key
13254 exchange. So the session times out for want of a heartbeat that is
13255 sitting in a queue, and the handshake that would rebuild it cannot go
13256 out either; CORE only recovers when a reconnect resets the window
13257 wholesale. Acknowledgements still drive retransmission below, they
13258 just no longer gate the client. */
13259 credit_client (sc.best);
13260
13261 /* Check if this transmission somehow conclusively finished handing 'pm'
13262 even without any explicit ACKs */
13263 if ((PMT_CORE == pm->pmt) ||
13264 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc))
13265 {
13267 }
13268 else
13269 {
13270 struct GNUNET_TIME_Relative wait_duration;
13271 unsigned int wait_multiplier;
13272
13273 if (PMT_FRAGMENT_BOX == pm->pmt)
13274 {
13275 struct PendingMessage *root;
13276
13277 root = pm->frag_parent;
13278 while (NULL != root->frag_parent && PMT_DV_BOX != root->pmt)
13279 root = root->frag_parent;
13280
13281 if ((0 == root->frag_off) || (0 == root->frag_count))
13282 {
13283 wait_multiplier = 4;
13284 }
13285 else
13286 {
13287 double wm = ceil ((double) root->bytes_msg
13288 / ((double) root->frag_off
13289 / (double) root->frag_count)) * 4.0;
13290
13291 if ((! (wm >= 1.0)) || (wm > 1024.0))
13292 wm = 4.0; /* NaN, infinity or absurd: fall back to the default */
13293 wait_multiplier = (unsigned int) wm;
13294 }
13295 }
13296 else
13297 {
13298 // No fragments, we use 4 RTT before retransmitting.
13299 wait_multiplier = 4;
13300 }
13301
13302 // Depending on how much pending message the VirtualLink is queueing, we wait longer.
13303 // wait_multiplier = wait_multiplier * pm->vl->pending_msg_num;
13304
13306 "Wait multiplier %u\n",
13307 wait_multiplier);
13308
13309 /* Message not finished, waiting for acknowledgement.
13310 Update time by which we might retransmit 's' based on queue
13311 characteristics (i.e. RTT); it takes one RTT for the message to
13312 arrive and the ACK to come back in the best case; but the other
13313 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
13314 retransmitting.
13315
13316 OPTIMIZE: Note that in the future this heuristic should likely
13317 be improved further (measure RTT stability, consider message
13318 urgency and size when delaying ACKs, etc.) */
13319
13320 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us !=
13321 queue->pd.aged_rtt.rel_value_us)
13322 wait_duration = GNUNET_TIME_relative_max (queue->pd.aged_rtt,
13324 else
13325 {
13326 wait_duration = DEFAULT_ACK_WAIT_DURATION;
13327 wait_multiplier = 4;
13328 }
13329 {
13332 wait_duration, wait_multiplier));
13334 wait_duration, wait_multiplier);
13336 "Waiting %s for ACK until %s\n",
13341 GNUNET_TIME_relative_multiply (wait_duration,
13342 wait_multiplier))
13343 );
13344 }
13345 }
13346 /* finally, re-schedule queue transmission task itself */
13348 queue,
13350}

References PendingMessage::bytes_msg, completed_pending_message(), credit_client(), DEFAULT_ACK_WAIT_DURATION, Neighbour::dv_head, encapsulate_for_dv(), extract_box_cb(), PendingMessage::frag_count, PendingMessage::frag_off, PendingMessage::frag_parent, fragment_message(), free_pending_message(), GNUNET_assert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, GNUNET_NO, GNUNET_SCHEDULER_PRIORITY_DEFAULT, GNUNET_STRINGS_absolute_time_to_string(), GNUNET_STRINGS_relative_time_to_string(), GNUNET_TIME_relative_max(), GNUNET_TIME_relative_multiply(), GNUNET_TIME_relative_to_absolute(), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_TIME_UNIT_ZERO, GNUNET_TRANSPORT_CC_RELIABLE, GNUNET_YES, PendingMessage::logging_uuid, MIN_ACK_WAIT_DURATION, VirtualLink::outbound_fc_window_size_used, Neighbour::pid, PendingMessage::pmt, PMT_CORE, PMT_DV_BOX, PMT_FRAGMENT_BOX, queue(), queue_send_msg(), reliability_box_message(), RMO_NONE, sc, schedule_transmit_on_queue(), select_best_pending_from_link(), update_pm_next_attempt(), Neighbour::vl, and PendingMessage::vl.

Referenced by schedule_transmit_on_queue().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_for_queue_with_higher_prio()

static unsigned int check_for_queue_with_higher_prio ( struct Queue queue,
struct Queue queue_head 
)
static

Check if there is another queue to the same neighbour, over a different communicator, that has a higher priority and is ready for sending.

Parameters
queuequeue we are considering transmission on
queue_headfirst queue to the neighbour of queue
Returns
GNUNET_YES if a better queue exists and should be preferred

Definition at line 4380 of file gnunet-service-transport.c.

4381{
4382 for (struct Queue *s = queue_head; NULL != s;
4383 s = s->next_neighbour)
4384 {
4385 if (s == queue)
4386 continue;
4387 if (s->tc->details.communicator.address_prefix !=
4388 queue->tc->details.communicator.address_prefix)
4389 {
4391 "queue address %s qid %u compare with queue: address %s qid %u\n",
4392 queue->address,
4393 queue->qid,
4394 s->address,
4395 s->qid);
4396 if ((s->priority > queue->priority) && (0 < s->q_capacity) &&
4397 (QUEUE_LENGTH_LIMIT > s->queue_length) )
4398 return GNUNET_YES;
4400 "Lower prio\n");
4401 }
4402 }
4403 return GNUNET_NO;
4404}

References GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_NO, GNUNET_YES, Queue::next_neighbour, queue(), queue_head, and QUEUE_LENGTH_LIMIT.

Referenced by schedule_transmit_on_queue().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ arm_free_queue_entry_task()

static void arm_free_queue_entry_task ( struct TransportClient tc)
static

Make sure free_timedout_queue_entry() will run for tc, so that `struct QueueEntry's the communicator never acknowledged are reclaimed.

Parameters
tccommunicator whose queue entries need sweeping

Definition at line 5594 of file gnunet-service-transport.c.

5595{
5596 if (NULL != tc->details.communicator.free_queue_entry_task)
5597 return;
5598 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
5599 queue = queue->next_client)
5600 {
5601 if (NULL == queue->queue_head)
5602 continue;
5603 tc->details.communicator.free_queue_entry_task =
5606 tc);
5607 return;
5608 }
5609}

References free_timedout_queue_entry(), GNUNET_SCHEDULER_add_delayed(), GNUNET_TIME_UNIT_SECONDS, queue(), and tc.

Referenced by free_timedout_queue_entry(), queue_send_msg(), and schedule_transmit_on_queue().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ schedule_transmit_on_queue()

static void schedule_transmit_on_queue ( struct GNUNET_TIME_Relative  delay,
struct Queue queue,
enum GNUNET_SCHEDULER_Priority  p 
)
static

Called whenever something changed that might effect when we try to do the next transmission on queue using transmit_on_queue().

Parameters
queuethe queue to do scheduling for
ptask priority to use, if queue is scheduled

Definition at line 4425 of file gnunet-service-transport.c.

4428{
4430
4431 if (queue->validated_until.abs_value_us < now.abs_value_us)
4432 return;
4434 queue->neighbour->queue_head))
4435 return;
4436
4437 if (queue->tc->details.communicator.total_queue_length >=
4439 {
4441 "Transmission on queue %s (QID %u) throttled due to communicator queue limit\n",
4442 queue->address,
4443 queue->qid);
4445 GST_stats,
4446 "# Transmission throttled due to communicator queue limit",
4447 1,
4448 GNUNET_NO);
4449 queue->idle = GNUNET_NO;
4450 /* @e total_queue_length is shared by every peer this communicator serves,
4451 so at the limit we can send to none of them, and the only things that
4452 lower it again are an ACK from the communicator, #free_queue() and
4453 #free_timedout_queue_entry(). If we got here because a peer stopped
4454 acknowledging, no ACK is coming; and we just declined to arm
4455 @e transmit_task, so #queue_send_msg() -- the *only* place that arms
4456 the sweeper -- will not run either. That leaves nothing at all to
4457 recover the count, and the communicator stays mute towards every peer
4458 until some unrelated queue happens to go down. Keep the sweeper
4459 going. */
4461 return;
4462 }
4463 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
4464 {
4466 "Transmission on queue %s (QID %u) throttled due to communicator queue length limit\n",
4467 queue->address,
4468 queue->qid);
4470 "# Transmission throttled due to queue queue limit",
4471 1,
4472 GNUNET_NO);
4473 queue->idle = GNUNET_NO;
4474 /* Same reasoning as above, for the per-queue limit. */
4476 return;
4477 }
4478 if (0 == queue->q_capacity)
4479 {
4481 "Transmission on queue %s (QID %u) throttled due to communicator message has capacity %"
4482 PRIu64 ".\n",
4483 queue->address,
4484 queue->qid,
4485 queue->q_capacity);
4487 "# Transmission throttled due to message queue capacity",
4488 1,
4489 GNUNET_NO);
4490 queue->idle = GNUNET_NO;
4491 return;
4492 }
4493 /* queue might indeed be ready, schedule it */
4494 if (NULL != queue->transmit_task)
4495 GNUNET_SCHEDULER_cancel (queue->transmit_task);
4496 queue->transmit_task =
4498 queue);
4500 "Considering transmission on queue `%s' QID %llu to %s\n",
4501 queue->address,
4502 (unsigned long long) queue->qid,
4503 GNUNET_i2s (&queue->neighbour->pid));
4504}

References GNUNET_TIME_Absolute::abs_value_us, arm_free_queue_entry_task(), check_for_queue_with_higher_prio(), COMMUNICATOR_TOTAL_QUEUE_LIMIT, GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, GNUNET_NO, GNUNET_SCHEDULER_add_delayed_with_priority(), GNUNET_SCHEDULER_cancel(), GNUNET_STATISTICS_update(), GNUNET_TIME_absolute_get(), GST_stats, p, queue(), QUEUE_LENGTH_LIMIT, and transmit_on_queue().

Referenced by check_vl_transmission(), free_queue(), free_queue_entry(), handle_update_queue_message(), and transmit_on_queue().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ start_address_validation()

static void start_address_validation ( const struct GNUNET_PeerIdentity pid,
const char *  address 
)
static

Start address validation.

Parameters
pidpeer the address is for
addressan address to reach pid (presumably)

Definition at line 10629 of file gnunet-service-transport.c.

10631{
10632 struct GNUNET_TIME_Absolute now;
10633 struct ValidationState *vs;
10634 struct CheckKnownAddressContext ckac = { .address = address, .vs = NULL };
10635
10637 pid,
10639 &ckac);
10641 if (NULL != (vs = ckac.vs))
10642 {
10643 const struct VirtualLink *vl = lookup_virtual_link (pid);
10644
10645 /* Speed up retrying the validation if 'vs' is not currently valid, or if
10646 * we have no confirmed virtual link to @a pid. In the latter case the
10647 * address may still be well inside its validity window -- but the link is
10648 * down, and #handle_validation_response() is the only thing that can
10649 * rebuild it and tell CORE about the peer again. Without this we would
10650 * wait for @e revalidation_task, which does not fire until
10651 * #ADDRESS_VALIDATION_LIFETIME is nearly over. */
10652 if ((vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us) ||
10653 (NULL == vl) ||
10654 (GNUNET_NO == vl->confirmed))
10655 {
10656 /* reduce backoff as we got a fresh advertisement */
10657 vs->challenge_backoff =
10660 vs->challenge_backoff,
10661 2));
10662 /* A successful validation parks @e first_challenge_use just before
10663 @e validated_until, so that the *next* challenge is not used before
10664 the current validation is about to expire. #validation_start_cb()
10665 refuses to run while that time is still in the future, so pulling
10666 @e next_challenge in without this would only make it reschedule
10667 itself four hours out. The challenge has not been used yet, so
10668 moving the start of its window to now stays truthful -- it is what
10669 the fresh-@a vs path below does as well. */
10670 if (GNUNET_TIME_absolute_cmp (vs->first_challenge_use, >, now))
10671 vs->first_challenge_use = now;
10674 vs->challenge_backoff));
10675 }
10676 return;
10677 }
10678 vs = GNUNET_new (struct ValidationState);
10679 vs->pid = *pid;
10680 vs->valid_until =
10682 vs->first_challenge_use = now;
10683 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
10684 GNUNET_CRYPTO_random_block (&vs->challenge,
10685 sizeof(vs->challenge));
10686 vs->address = GNUNET_strdup (address);
10687 {
10688 /* The peer identity MUST be part of @e hc: two peers behind the same NAT
10689 advertise the very same address string (`PROTO-IP:0'), and with an
10690 address-only key the second one's #revalidation_map entry would be
10691 rejected as a duplicate of the first one's. */
10692 struct GNUNET_HashContext *hsh;
10693
10695 GNUNET_CRYPTO_hash_context_read (hsh, vs->address, strlen (vs->address));
10696 GNUNET_CRYPTO_hash_context_read (hsh, &vs->pid, sizeof(vs->pid));
10697 GNUNET_CRYPTO_hash_context_finish (hsh, &vs->hc);
10698 }
10700 "Starting address validation `%s' of peer %s using challenge %s\n",
10701 address,
10702 GNUNET_i2s (pid),
10703 GNUNET_sh2s (&vs->challenge.value));
10707 &vs->pid,
10708 vs,
10711}

References GNUNET_TIME_Absolute::abs_value_us, address, CheckKnownAddressContext::address, ADDRESS_VALIDATION_LIFETIME, check_known_address(), VirtualLink::confirmed, FAST_VALIDATION_CHALLENGE_FREQ, GNUNET_assert, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE, GNUNET_CONTAINER_multipeermap_get_multiple(), GNUNET_CONTAINER_multipeermap_put(), GNUNET_CRYPTO_hash_context_finish(), GNUNET_CRYPTO_hash_context_read(), GNUNET_CRYPTO_hash_context_start(), GNUNET_CRYPTO_random_block(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, GNUNET_new, GNUNET_NO, GNUNET_sh2s(), GNUNET_strdup, GNUNET_TIME_absolute_cmp, GNUNET_TIME_absolute_get_monotonic(), GNUNET_TIME_relative_divide(), GNUNET_TIME_relative_min(), GNUNET_TIME_relative_to_absolute(), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, GST_cfg, lookup_virtual_link(), ValidationState::pid, update_next_challenge_time(), ValidationState::valid_until, ValidationState::validated_until, validation_map, and CheckKnownAddressContext::vs.

Referenced by check_link_down(), handle_add_queue_message(), handle_request_hello_validation(), hello_for_client_cb(), hello_for_incoming_cb(), and try_to_bring_link_up().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ free_queue()

static void free_queue ( struct Queue queue)
static

Free queue.

Parameters
queuethe queue to free

Definition at line 4616 of file gnunet-service-transport.c.

4617{
4618 struct Neighbour *neighbour = queue->neighbour;
4619 struct TransportClient *tc = queue->tc;
4620 struct MonitorEvent me = { .cs = GNUNET_TRANSPORT_CS_DOWN,
4622 struct QueueEntry *qe;
4623 int maxxed;
4624 struct PendingAcknowledgement *pa;
4625 struct VirtualLink *vl;
4626
4628 "Cleaning up queue %u\n", queue->qid);
4629 if (NULL != queue->mo)
4630 {
4632 queue->mo = NULL;
4633 }
4634 if (NULL != queue->transmit_task)
4635 {
4636 GNUNET_SCHEDULER_cancel (queue->transmit_task);
4637 queue->transmit_task = NULL;
4638 }
4639 while (NULL != (pa = queue->pa_head))
4640 {
4641 GNUNET_CONTAINER_MDLL_remove (queue, queue->pa_head, queue->pa_tail, pa);
4642 pa->queue = NULL;
4643 }
4644
4646 neighbour->queue_head,
4647 neighbour->queue_tail,
4648 queue);
4650 tc->details.communicator.queue_head,
4651 tc->details.communicator.queue_tail,
4652 queue);
4654 tc->details.communicator.total_queue_length);
4656 "Cleaning up queue with length %u\n",
4657 queue->queue_length);
4658 while (NULL != (qe = queue->queue_head))
4659 {
4660 GNUNET_CONTAINER_DLL_remove (queue->queue_head, queue->queue_tail, qe);
4661 queue->queue_length--;
4662 tc->details.communicator.total_queue_length--;
4663 if (NULL != qe->pm)
4664 {
4665 GNUNET_assert (qe == qe->pm->qe);
4666 qe->pm->qe = NULL;
4667 }
4668 GNUNET_free (qe);
4669 }
4670 GNUNET_assert (0 == queue->queue_length);
4671 if ((maxxed) && (COMMUNICATOR_TOTAL_QUEUE_LIMIT >
4672 tc->details.communicator.total_queue_length))
4673 {
4674 /* Communicator dropped below threshold, resume all _other_ queues */
4676 GST_stats,
4677 "# Transmission throttled due to communicator queue limit",
4678 -1,
4679 GNUNET_NO);
4680 for (struct Queue *s = tc->details.communicator.queue_head; NULL != s;
4681 s = s->next_client)
4683 s,
4685 }
4686 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
4688
4689 vl = lookup_virtual_link (&neighbour->pid);
4690 if ((NULL != vl) && (neighbour == vl->n))
4691 {
4692 /* See #free_dv_route(): may be NULL under #check_link_down(), which is
4693 also what clears it -- so the call below needs no re-arm here. */
4694 if (NULL != vl->visibility_task)
4696 vl->visibility_task = NULL;
4697 check_link_down (vl);
4698 }
4699 if (NULL == neighbour->queue_head)
4700 {
4701 free_neighbour (neighbour, GNUNET_NO);
4702 }
4703}

References check_link_down(), COMMUNICATOR_TOTAL_QUEUE_LIMIT, free_neighbour(), GNUNET_assert, GNUNET_CONTAINER_DLL_remove, GNUNET_CONTAINER_MDLL_remove, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_log, GNUNET_NO, GNUNET_PEERSTORE_monitor_stop(), GNUNET_SCHEDULER_cancel(), GNUNET_SCHEDULER_PRIORITY_DEFAULT, GNUNET_STATISTICS_update(), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_TIME_UNIT_ZERO, GNUNET_TRANSPORT_CS_DOWN, GST_stats, lookup_virtual_link(), me, VirtualLink::n, notify_monitors(), Neighbour::pid, qe, queue(), PendingAcknowledgement::queue, Neighbour::queue_head, Neighbour::queue_tail, schedule_transmit_on_queue(), tc, and VirtualLink::visibility_task.

Referenced by client_disconnect_cb(), handle_del_queue_message(), and handle_send_message_ack().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cancel_address_store()

static void cancel_address_store ( struct AddressListEntry ale)
static

Abort the asynchronous sign-and-store chain (if any) that is currently running for ale and release its context.

Without this, PILS and PEERSTORE callbacks keep a pointer to ale and run after it was freed.

Parameters
aleaddress list entry to cancel operations for
aleaddress list entry to cancel operations for

Definition at line 6744 of file gnunet-service-transport.c.

6745{
6746 struct PilsAddressSignContext *pc = ale->pc;
6747
6748 if (NULL == pc)
6749 return;
6750 ale->pc = NULL;
6751 /* Each stage of the chain passes @a pc as its closure, so every handle
6752 that could still deliver one has to go before @a pc is released. */
6753 if (NULL != ale->sc)
6754 {
6756 ale->sc = NULL;
6757 }
6758 if (NULL != ale->shc)
6759 {
6761 ale->shc = NULL;
6762 }
6763 if (NULL != pc->req)
6764 {
6765 if (NULL != pc->req->op)
6766 GNUNET_PILS_cancel (pc->req->op);
6769 pc->req);
6770 GNUNET_free (pc->req);
6771 pc->req = NULL;
6772 }
6773 GNUNET_free (pc);
6774}

References PilsAddressSignContext::ale, GNUNET_CONTAINER_DLL_remove, GNUNET_free, GNUNET_PEERSTORE_hello_add_cancel(), GNUNET_PEERSTORE_store_cancel(), GNUNET_PILS_cancel(), pc, AddressListEntry::pc, pils_requests_head, pils_requests_tail, AddressListEntry::sc, and AddressListEntry::shc.

Referenced by free_address_list_entry(), and pils_sign_address().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ free_address_list_entry()

static void free_address_list_entry ( struct AddressListEntry ale)
static

Free ale.

Parameters
aleaddress list entry to free

Definition at line 4723 of file gnunet-service-transport.c.

4724{
4725 struct TransportClient *tc = ale->tc;
4726
4727 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
4728 tc->details.communicator.addr_tail,
4729 ale);
4730 /* Cancels @e sc, @e shc and the pending PILS signature request, all of
4731 which would otherwise run their callbacks on this freed entry. */
4733 if (NULL != ale->sc)
4734 {
4736 "store cancel\n");
4738 ale->sc = NULL;
4739 }
4740 if (NULL != ale->shc)
4741 {
4743 ale->shc = NULL;
4744 }
4745 if (NULL != ale->st)
4746 {
4748 ale->st = NULL;
4749 }
4750 if (NULL != ale->signed_address)
4752 GNUNET_free (ale);
4753}

References cancel_address_store(), GNUNET_CONTAINER_DLL_remove, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_log, GNUNET_PEERSTORE_hello_add_cancel(), GNUNET_PEERSTORE_store_cancel(), GNUNET_SCHEDULER_cancel(), AddressListEntry::sc, AddressListEntry::shc, AddressListEntry::signed_address, AddressListEntry::st, tc, and AddressListEntry::tc.

Referenced by client_disconnect_cb(), and handle_del_address().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ stop_peer_request()

static int stop_peer_request ( void *  cls,
const struct GNUNET_PeerIdentity pid,
void *  value 
)
static

Stop the peer request in value.

Parameters
clsa struct TransportClient that no longer makes the request
pidthe peer's identity
valuea struct PeerRequest
Returns
GNUNET_YES (always)

Definition at line 4765 of file gnunet-service-transport.c.

4768{
4769 struct TransportClient *tc = cls;
4770 struct PeerRequest *pr = value;
4771
4772 if (NULL != pr->retry_task)
4773 {
4774 GNUNET_SCHEDULER_cancel (pr->retry_task);
4775 pr->retry_task = NULL;
4776 }
4777 if (NULL != pr->nc)
4779 pr->nc = NULL;
4781 GNUNET_YES ==
4782 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
4783 pid,
4784 pr));
4785 GNUNET_free (pr);
4786
4787 return GNUNET_OK;
4788}

References GNUNET_assert, GNUNET_CONTAINER_multipeermap_remove(), GNUNET_free, GNUNET_OK, GNUNET_PEERSTORE_monitor_stop(), GNUNET_SCHEDULER_cancel(), GNUNET_YES, PeerRequest::pid, PeerRequest::pr, tc, and value.

Referenced by client_disconnect_cb(), and handle_suggest_cancel().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ do_shutdown()

static void do_shutdown ( void *  cls)
static

Function called when the service shuts down.

Unloads our plugins and cancels pending validations.

Parameters
clsclosure, unused

Definition at line 15631 of file gnunet-service-transport.c.

15632{
15633 static int shutdown_done;
15634 struct LearnLaunchEntry *lle;
15635 struct PilsRequest *pr;
15636 (void) cls;
15637
15639 "shutdown logic\n");
15640 if (GNUNET_YES == shutdown_done)
15641 return; /* reachable both from #shutdown_task() and #client_disconnect_cb() */
15642 shutdown_done = GNUNET_YES;
15643 if (NULL != client_grace_task)
15644 {
15646 client_grace_task = NULL;
15647 }
15648 if (NULL != nh)
15649 {
15651 nh = NULL;
15652 }
15654 &free_neighbour_cb, NULL);
15655 /* Freeing a neighbour takes its virtual link with it, so whatever is
15656 left here is ownerless: a link we created from an inbound FLOW_CONTROL
15657 message that never got confirmed, kept alive only by its @e
15658 unconfirmed_timeout_task. #GNUNET_SCHEDULER_shutdown() does not run
15659 that task, so leaving the link in place left the task armed against a
15660 map we destroy further down -- it fired afterwards and
15661 #free_virtual_link() called GNUNET_CONTAINER_multipeermap_remove() on
15662 NULL. Drop them here, while every structure they touch is still
15663 alive. */
15666 NULL);
15667 if (NULL != validation_task)
15668 {
15670 validation_task = NULL;
15671 }
15672 if (NULL != dvlearn_task)
15673 {
15675 dvlearn_task = NULL;
15676 }
15677 if (NULL != burst_task)
15678 {
15680 burst_task = NULL;
15681 }
15682 if (NULL != burst_timeout_task)
15683 {
15685 burst_timeout_task = NULL;
15686 }
15689 dvlearn_map = NULL;
15692 dv_routes = NULL;
15693 if (NULL != GST_stats)
15694 {
15696 GST_stats = NULL;
15697 }
15698 if (NULL != GST_my_hello)
15699 {
15701 GST_my_hello = NULL;
15702 }
15705 NULL);
15707 ack_cummulators = NULL;
15710 NULL);
15712 pending_acks = NULL;
15715 neighbours = NULL;
15718 links = NULL;
15721 NULL);
15723 backtalkers = NULL;
15726 NULL);
15728 validation_map = NULL;
15730 validation_heap = NULL;
15732 revalidation_map = NULL;
15733 while (NULL != ir_head)
15735 GNUNET_assert (0 == ir_total);
15736 while (NULL != (lle = lle_head))
15737 {
15739 GNUNET_free (lle);
15740 }
15741 while (NULL != (pr = pils_requests_head))
15742 {
15745 pr);
15746 if (NULL != pr->op)
15747 GNUNET_PILS_cancel (pr->op);
15748 GNUNET_free (pr);
15749 }
15750 if (NULL != pils_feed_task)
15751 {
15753 pils_feed_task = NULL;
15754 }
15755 if (NULL != pils)
15756 {
15758 pils = NULL;
15759 }
15760 if (NULL != peerstore)
15761 {
15763 "Disconnecting from PEERSTORE service\n");
15765 peerstore = NULL;
15766 }
15768}

References ack_cummulators, backtalkers, burst_running, burst_task, burst_timeout_task, client_grace_task, dv_routes, dvlearn_map, dvlearn_task, free_ack_cummulator_cb(), free_backtalker_cb(), free_dv_routes_cb(), free_incoming_request(), free_neighbour_cb(), free_pending_ack_cb(), free_validation_state_cb(), free_virtual_link_cb(), GNUNET_assert, GNUNET_break, GNUNET_CONTAINER_DLL_remove, GNUNET_CONTAINER_heap_destroy(), GNUNET_CONTAINER_multihashmap_destroy(), GNUNET_CONTAINER_multipeermap_destroy(), GNUNET_CONTAINER_multipeermap_iterate(), GNUNET_CONTAINER_multipeermap_size(), GNUNET_CONTAINER_multishortmap_destroy(), GNUNET_CONTAINER_multiuuidmap_destroy(), GNUNET_CONTAINER_multiuuidmap_iterate(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_HELLO_builder_free(), GNUNET_log, GNUNET_NAT_unregister(), GNUNET_NO, GNUNET_PEERSTORE_disconnect(), GNUNET_PILS_cancel(), GNUNET_PILS_disconnect(), GNUNET_SCHEDULER_cancel(), GNUNET_SCHEDULER_shutdown(), GNUNET_STATISTICS_destroy(), GNUNET_YES, GST_my_hello, GST_stats, ir_head, ir_total, links, lle_head, lle_tail, neighbours, nh, PilsRequest::op, peerstore, pending_acks, pils, pils_feed_task, pils_requests_head, pils_requests_tail, revalidation_map, validation_heap, validation_map, and validation_task.

Here is the call graph for this function:

◆ detach_cmcs_from_link()

static enum GNUNET_GenericReturnValue detach_cmcs_from_link ( void *  cls,
const struct GNUNET_PeerIdentity pid,
void *  value 
)
static

Detach the `struct CommunicatorMessageContext's parked on value from the client in cls.

Parameters
clsthe struct TransportClient that is going away
pidunused
valuea struct VirtualLink
Returns
GNUNET_OK (continue to iterate)

Definition at line 4805 of file gnunet-service-transport.c.

4808{
4809 const struct TransportClient *tc = cls;
4810 struct VirtualLink *vl = value;
4811
4812 (void) pid;
4813 for (struct CommunicatorMessageContext *cmc = vl->cmc_head;
4814 NULL != cmc;
4815 cmc = cmc->next)
4816 if (tc == cmc->tc)
4817 cmc->tc = NULL;
4818 return GNUNET_OK;
4819}

References VirtualLink::cmc_head, GNUNET_OK, tc, and value.

Referenced by detach_cmcs_from_client().

Here is the caller graph for this function:

◆ detach_cmc_from_backtalker()

static enum GNUNET_GenericReturnValue detach_cmc_from_backtalker ( void *  cls,
const struct GNUNET_PeerIdentity pid,
void *  value 
)
static

Detach the ‘struct CommunicatorMessageContext’ parked on value from the client in cls.

Parameters
clsthe struct TransportClient that is going away
pidunused
valuea struct Backtalker
Returns
GNUNET_OK (continue to iterate)

Definition at line 4832 of file gnunet-service-transport.c.

4835{
4836 const struct TransportClient *tc = cls;
4837 struct Backtalker *b = value;
4838
4839 (void) pid;
4840 if ((NULL != b->cmc) && (tc == b->cmc->tc))
4841 b->cmc->tc = NULL;
4842 return GNUNET_OK;
4843}

References Backtalker::cmc, GNUNET_OK, Backtalker::pid, tc, CommunicatorMessageContext::tc, and value.

Referenced by detach_cmcs_from_client().

Here is the caller graph for this function:

◆ detach_cmcs_from_client()

static void detach_cmcs_from_client ( const struct TransportClient tc)
static

A communicator client is going away.

Detach every ‘struct CommunicatorMessageContext’ that still points at it.

A cmc does not end with the handler that created it: it is parked on cmc_head of a ‘struct VirtualLink’ while CORE's receive window for that link is exhausted (see finish_handling_raw_message()), on a ‘struct Backtalker’ across a PEERSTORE round trip (see decaps_dv_box_cont()), or in ring_buffer while the link is still coming up (see handle_raw_message()). Each of those is released later by a path that runs send_cmc_ack() and resume_cmc_client() on tc – which client_disconnect_cb() is about to free. Whether that later path runs during this disconnect (free_virtual_link() releases the parked cmcs of a link it tears down) or long after it (a RECV_OK, the CORE stall timeout, a PEERSTORE reply), the client is no longer ours to touch.

Parameters
tcclient that is being disconnected

Definition at line 4865 of file gnunet-service-transport.c.

4866{
4869 (void *) tc);
4872 (void *) tc);
4873 for (unsigned int i = 0; i < RING_BUFFER_SIZE; i++)
4874 if ((NULL != ring_buffer[i]) &&
4875 (tc == ring_buffer[i]->cmc->tc))
4876 ring_buffer[i]->cmc->tc = NULL;
4877}

References backtalkers, RingBufferEntry::cmc, Backtalker::cmc, detach_cmc_from_backtalker(), detach_cmcs_from_link(), GNUNET_CONTAINER_multipeermap_iterate(), links, ring_buffer, RING_BUFFER_SIZE, tc, and CommunicatorMessageContext::tc.

Referenced by client_disconnect_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ client_disconnect_cb()

static void client_disconnect_cb ( void *  cls,
struct GNUNET_SERVICE_Client client,
void *  app_ctx 
)
static

Called whenever a client is disconnected.

Frees our resources associated with that client.

Parameters
clsclosure, NULL
clientidentification of the client
app_ctxour struct TransportClient

Definition at line 4889 of file gnunet-service-transport.c.

4892{
4893 struct TransportClient *tc = app_ctx;
4894
4895 (void) cls;
4896 (void) client;
4898 switch (tc->type)
4899 {
4900 case CT_NONE:
4902 "Unknown Client %p disconnected, cleaning up.\n",
4903 tc);
4904 break;
4905
4906 case CT_CORE: {
4907 struct PendingMessage *pm;
4909 "CORE Client %p disconnected, cleaning up.\n",
4910 tc);
4911
4912
4913 while (NULL != (pm = tc->details.core.pending_msg_head))
4914 {
4916 tc->details.core.pending_msg_head,
4917 tc->details.core.pending_msg_tail,
4918 pm);
4919 pm->client = NULL;
4920 }
4921 }
4922 break;
4923
4924 case CT_MONITOR:
4926 "MONITOR Client %p disconnected, cleaning up.\n",
4927 tc);
4928
4929 break;
4930
4931 case CT_COMMUNICATOR: {
4932 struct Queue *q;
4933 struct AddressListEntry *ale;
4934
4936 "COMMUNICATOR Client %p disconnected, cleaning up.\n",
4937 tc);
4938
4939 /* MUST come first: freeing the queues below can tear a virtual link
4940 down, and #free_virtual_link() releases the cmcs parked on it. */
4942 if (NULL != tc->details.communicator.free_queue_entry_task)
4944 tc->details.communicator.free_queue_entry_task);
4945 while (NULL != (q = tc->details.communicator.queue_head))
4946 free_queue (q);
4947 while (NULL != (ale = tc->details.communicator.addr_head))
4949 GNUNET_free (tc->details.communicator.address_prefix);
4950 }
4951 break;
4952
4953 case CT_APPLICATION:
4955 "APPLICATION Client %p disconnected, cleaning up.\n",
4956 tc);
4957
4958 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
4960 tc);
4961 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
4962 break;
4963 }
4964 GNUNET_free (tc);
4965 if ((GNUNET_YES == in_shutdown) && (NULL == clients_head))
4966 {
4968 "Our last client disconnected\n");
4969 do_shutdown (cls);
4970 }
4971}

References PendingMessage::client, TransportClient::client, clients_head, clients_tail, CT_APPLICATION, CT_COMMUNICATOR, CT_CORE, CT_MONITOR, CT_NONE, detach_cmcs_from_client(), do_shutdown, free_address_list_entry(), free_queue(), GNUNET_CONTAINER_DLL_remove, GNUNET_CONTAINER_MDLL_remove, GNUNET_CONTAINER_multipeermap_destroy(), GNUNET_CONTAINER_multipeermap_iterate(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_INFO, GNUNET_free, GNUNET_log, GNUNET_SCHEDULER_cancel(), GNUNET_YES, in_shutdown, q, stop_peer_request(), and tc.

Here is the call graph for this function:

◆ notify_client_connect_info()

static int notify_client_connect_info ( void *  cls,
const struct GNUNET_PeerIdentity pid,
void *  value 
)
static

Iterator telling new CORE client about all existing connections to peers.

Parameters
clsthe new struct TransportClient
pida connected peer
valuethe struct Neighbour with more information
Returns
GNUNET_OK (continue to iterate)

Definition at line 4984 of file gnunet-service-transport.c.

4987{
4988 struct TransportClient *tc = cls;
4989 struct VirtualLink *vl = value;
4990
4991 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
4992 return GNUNET_OK;
4993
4995 "Telling new CORE client about existing connection to %s\n",
4996 GNUNET_i2s (pid));
4998 return GNUNET_OK;
4999}

References VirtualLink::confirmed, core_send_connect_info(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, GNUNET_NO, GNUNET_OK, tc, and value.

Referenced by handle_client_start().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ resume_communicators()

static enum GNUNET_GenericReturnValue resume_communicators ( void *  cls,
const struct GNUNET_PeerIdentity pid,
void *  value 
)
static

Definition at line 5013 of file gnunet-service-transport.c.

5016{
5017 struct VirtualLink *vl = value;
5018 struct CommunicatorMessageContext *cmc;
5019
5020 /* resume communicators */
5021 while (NULL != (cmc = vl->cmc_tail))
5022 release_stalled_cmc (vl, cmc);
5023 if (NULL != vl->core_fc_stall_task)
5024 {
5026 vl->core_fc_stall_task = NULL;
5027 }
5028 /* A CORE client that just attached has nothing outstanding, so give it a
5029 full window. The RECV_OKs that would have returned the credit spent by
5030 its predecessor died with that client, and #handle_client_recv_ok() is
5031 the only thing that ever raises this counter -- so without the reset
5032 every message on this link takes the "CORE ran out of window" path from
5033 here on, and only #core_fc_stalled() (after CORE_FC_STALL_TIMEOUT, and
5034 once per round) ever lets any through. */
5036 return GNUNET_OK;
5037}

References VirtualLink::cmc_tail, VirtualLink::core_fc_stall_task, VirtualLink::core_recv_window, GNUNET_OK, GNUNET_SCHEDULER_cancel(), RECV_WINDOW_SIZE, release_stalled_cmc(), and value.

Referenced by handle_client_start().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_client_start()

static void handle_client_start ( void *  cls,
const struct StartMessage start 
)
static

Initialize a "CORE" client.

We got a start message from this client, so add it to the list of clients for broadcasting of inbound messages.

Parameters
clsthe client
startthe start message that was sent

Definition at line 5049 of file gnunet-service-transport.c.

5050{
5051 // const struct GNUNET_PeerIdentity *my_identity;
5052 struct TransportClient *tc = cls;
5053 // uint32_t options;
5054 //
5055 // my_identity = GNUNET_PILS_get_identity (pils);
5056 // GNUNET_assert (my_identity);
5057 //
5058 // FIXME ignore the check of the peer ids for now.
5059 // (also deprecate the old way of obtaining our own peer ID)
5060 // options = ntohl (start->options);
5061 // if ((0 != (1 & options)) &&
5062 // (0 != GNUNET_memcmp (&start->self, my_identity)))
5063 // {
5064 // /* client thinks this is a different peer, reject */
5065 // GNUNET_break (0);
5066 // GNUNET_SERVICE_client_drop (tc->client);
5067 // return;
5068 // }
5069 if (CT_NONE != tc->type)
5070 {
5071 GNUNET_break (0);
5073 return;
5074 }
5075 tc->type = CT_CORE;
5077 "New CORE client with PID %s registered\n",
5078 GNUNET_i2s (&start->self));
5081 tc);
5084 NULL);
5086}

References CT_CORE, CT_NONE, GNUNET_break, GNUNET_CONTAINER_multipeermap_iterate(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, GNUNET_SERVICE_client_continue(), GNUNET_SERVICE_client_drop(), links, notify_client_connect_info(), resume_communicators(), start, and tc.

Here is the call graph for this function:

◆ check_client_send()

static int check_client_send ( void *  cls,
const struct OutboundMessage obm 
)
static

Client asked for transmission to a peer.

Process the request.

Parameters
clsthe client
obmthe send message that was sent

Definition at line 5096 of file gnunet-service-transport.c.

5097{
5098 struct TransportClient *tc = cls;
5099 uint16_t size;
5100 const struct GNUNET_MessageHeader *obmm;
5101
5102 if (CT_CORE != tc->type)
5103 {
5104 GNUNET_break (0);
5105 return GNUNET_SYSERR;
5106 }
5107 size = ntohs (obm->header.size) - sizeof(struct OutboundMessage);
5108 if (size < sizeof(struct GNUNET_MessageHeader))
5109 {
5110 GNUNET_break (0);
5111 return GNUNET_SYSERR;
5112 }
5113 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5114 if (size != ntohs (obmm->size))
5115 {
5116 GNUNET_break (0);
5117 return GNUNET_SYSERR;
5118 }
5119 return GNUNET_OK;
5120}

References CT_CORE, GNUNET_break, GNUNET_OK, GNUNET_SYSERR, OutboundMessage::header, GNUNET_MessageHeader::size, size, and tc.

◆ client_send_response()

static void client_send_response ( struct PendingMessage pm)
static

Send a response to the pm that we have processed a "send" request.

Sends a confirmation to the "core" client responsible for the original request and free's pm.

Parameters
pmhandle to the original pending message

Definition at line 5131 of file gnunet-service-transport.c.

5132{
5133 struct TransportClient *tc = pm->client;
5134 struct VirtualLink *vl = pm->vl;
5135
5137 "client send response\n");
5138 if (NULL != tc)
5139 {
5141 "Confirming transmission of <%" PRIu64 "> to %s\n",
5142 pm->logging_uuid,
5143 GNUNET_i2s (&vl->target));
5144 credit_client (pm);
5145 }
5147}

References PendingMessage::client, credit_client(), free_pending_message(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, PendingMessage::logging_uuid, VirtualLink::target, tc, and PendingMessage::vl.

Referenced by completed_pending_message(), and reliability_box_message().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pick_random_dv_hops()

static unsigned int pick_random_dv_hops ( const struct DistanceVector dv,
enum RouteMessageOptions  options,
struct DistanceVectorHop **  hops_array,
unsigned int  hops_array_length 
)
static

Pick hops_array_length random DV paths satisfying options.

Parameters
dvdata structure to pick paths from
optionsconstraints to satisfy
[out]hops_arrayset to the result
hops_array_lengthlength of the hops_array
Returns
number of entries set in hops_array

Definition at line 5160 of file gnunet-service-transport.c.

5164{
5165 uint64_t choices[hops_array_length];
5166 uint64_t num_dv;
5167 unsigned int dv_count;
5168
5169 /* Pick random vectors, but weighted by distance, giving more weight
5170 to shorter vectors */
5171 num_dv = 0;
5172 dv_count = 0;
5173 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5174 pos = pos->next_dv)
5175 {
5176 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
5177 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
5178 .rel_value_us == 0))
5179 continue; /* pos unconfirmed and confirmed required */
5180 num_dv += MAX_DV_HOPS_ALLOWED - pos->distance;
5181 dv_count++;
5182 }
5183 if (0 == dv_count)
5184 return 0;
5185 if (dv_count <= hops_array_length)
5186 {
5187 dv_count = 0;
5188 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5189 pos = pos->next_dv)
5190 hops_array[dv_count++] = pos;
5191 return dv_count;
5192 }
5193 for (unsigned int i = 0; i < hops_array_length; i++)
5194 {
5195 int ok = GNUNET_NO;
5196 while (GNUNET_NO == ok)
5197 {
5198 choices[i] =
5199 GNUNET_CRYPTO_random_u64 (num_dv);
5200 ok = GNUNET_YES;
5201 for (unsigned int j = 0; j < i; j++)
5202 if (choices[i] == choices[j])
5203 {
5204 ok = GNUNET_NO;
5205 break;
5206 }
5207 }
5208 }
5209 dv_count = 0;
5210 num_dv = 0;
5211 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5212 pos = pos->next_dv)
5213 {
5214 uint32_t delta = MAX_DV_HOPS_ALLOWED - pos->distance;
5215
5216 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
5217 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
5218 .rel_value_us == 0))
5219 continue; /* pos unconfirmed and confirmed required */
5220 for (unsigned int i = 0; i < hops_array_length; i++)
5221 if ((num_dv <= choices[i]) && (num_dv + delta > choices[i]))
5222 hops_array[dv_count++] = pos;
5223 num_dv += delta;
5224 }
5225 return dv_count;
5226}

References delta, VirtualLink::dv, DistanceVector::dv_head, GNUNET_CRYPTO_random_u64(), GNUNET_NO, GNUNET_TIME_absolute_get_remaining(), GNUNET_YES, MAX_DV_HOPS_ALLOWED, options, GNUNET_TIME_Relative::rel_value_us, and RMO_UNCONFIRMED_ALLOWED.

Referenced by route_control_message_without_fc().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_communicator_available()

static int check_communicator_available ( void *  cls,
const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage cam 
)
static

Communicator started.

Test message is well-formed.

Parameters
clsthe client
camthe send message that was sent

Definition at line 5236 of file gnunet-service-transport.c.

5239{
5240 struct TransportClient *tc = cls;
5241 uint16_t size;
5242
5243 if (CT_NONE != tc->type)
5244 {
5245 GNUNET_break (0);
5246 return GNUNET_SYSERR;
5247 }
5248 tc->type = CT_COMMUNICATOR;
5249 size = ntohs (cam->header.size) - sizeof(*cam);
5250 if (0 == size)
5251 return GNUNET_OK; /* receive-only communicator */
5253 return GNUNET_OK;
5254}

References CT_COMMUNICATOR, CT_NONE, GNUNET_break, GNUNET_MQ_check_zero_termination, GNUNET_OK, GNUNET_SYSERR, GNUNET_TRANSPORT_CommunicatorAvailableMessage::header, GNUNET_MessageHeader::size, size, and tc.

◆ send_cmc_ack()

static void send_cmc_ack ( struct CommunicatorMessageContext cmc)
static

Release the CORE flow control credit for cmc by acknowledging the message to the communicator that delivered it.

Idempotent: the ACK carries a flow control id the communicator retires on receipt, so a second one would match nothing, and GNUNET_TRANSPORT_communicator_receive()'s caller reacts to that by dropping its whole transport connection.

Parameters
cmccontext for which we are done handling the message

Definition at line 5269 of file gnunet-service-transport.c.

5270{
5271 struct GNUNET_MQ_Envelope *env;
5273
5274 if (GNUNET_YES == cmc->ack_sent)
5275 return;
5276 cmc->ack_sent = GNUNET_YES;
5277 if (NULL == cmc->tc)
5278 return; /* communicator is gone, see #detach_cmcs_from_client() */
5279 if (0 == ntohl (cmc->im.fc_on))
5280 return; /* communicator did not ask for flow control */
5282 "Acknowledge message with flow control id %" PRIu64 "\n",
5283 cmc->im.fc_id);
5285 ack->reserved = htonl (0);
5286 ack->fc_id = cmc->im.fc_id;
5287 ack->sender = cmc->im.neighbour_sender;
5288 GNUNET_MQ_send (cmc->tc->mq, env);
5289}

References CommunicatorMessageContext::ack_sent, env, GNUNET_TRANSPORT_IncomingMessage::fc_id, GNUNET_TRANSPORT_IncomingMessageAck::fc_id, GNUNET_TRANSPORT_IncomingMessage::fc_on, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK, GNUNET_MQ_msg, GNUNET_MQ_send(), GNUNET_YES, CommunicatorMessageContext::im, TransportClient::mq, GNUNET_TRANSPORT_IncomingMessage::neighbour_sender, GNUNET_TRANSPORT_IncomingMessageAck::reserved, GNUNET_TRANSPORT_IncomingMessageAck::sender, and CommunicatorMessageContext::tc.

Referenced by finish_cmc_handling_with_continue().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ resume_cmc_client()

static void resume_cmc_client ( struct CommunicatorMessageContext cmc)
static

Let the communicator that delivered cmc give us its next message.

This is per client, and one client serves every peer reachable over that communicator, so it must not be held back for anything that concerns a single virtual link. Idempotent, as the service API expects exactly one continue per message received.

Parameters
cmccontext whose client to resume

Definition at line 5303 of file gnunet-service-transport.c.

5304{
5305 if (GNUNET_YES == cmc->client_resumed)
5306 return;
5308 if (NULL == cmc->tc)
5309 return; /* communicator is gone, see #detach_cmcs_from_client() */
5311}

References TransportClient::client, CommunicatorMessageContext::client_resumed, GNUNET_SERVICE_client_continue(), GNUNET_YES, and CommunicatorMessageContext::tc.

Referenced by finish_cmc_handling_with_continue(), and finish_handling_raw_message().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ finish_cmc_handling()

static void finish_cmc_handling ( struct CommunicatorMessageContext cmc)
static

Definition at line 5348 of file gnunet-service-transport.c.

References finish_cmc_handling_with_continue(), and GNUNET_YES.

Referenced by backtalker_monotime_cb(), decaps_dv_box_cont(), free_backtalker(), handle_backchannel_encapsulation(), handle_dv_box(), handle_dv_learn(), handle_flow_control(), handle_fragment_box(), handle_raw_message(), handle_reliability_ack(), handle_validation_challenge(), handle_validation_response(), and send_t_validation_response().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_client_recv_ok()

static void handle_client_recv_ok ( void *  cls,
const struct RecvOkMessage rom 
)
static

Client confirms that it is done handling message(s) to a particular peer.

We may now provide more messages to CORE for this peer.

Notifies the respective queues that more messages can now be received.

Parameters
clsthe client
romthe message that was sent

Definition at line 5364 of file gnunet-service-transport.c.

5365{
5366 struct TransportClient *tc = cls;
5367 struct VirtualLink *vl;
5368 uint32_t delta;
5369 struct CommunicatorMessageContext *cmc;
5370
5371 if (CT_CORE != tc->type)
5372 {
5373 GNUNET_break (0);
5375 return;
5376 }
5377 vl = lookup_virtual_link (&rom->peer);
5378 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
5379 {
5381 "# RECV_OK dropped: virtual link unknown",
5382 1,
5383 GNUNET_NO);
5385 return;
5386 }
5387 delta = ntohl (rom->increase_window_delta);
5388 vl->core_recv_window += delta;
5390 "CORE ack receiving message, increased CORE recv window to %d\n",
5391 vl->core_recv_window);
5393 if (vl->core_recv_window <= 0)
5394 return;
5395 /* release the flow control credit we withheld from the communicators */
5396 while (NULL != (cmc = vl->cmc_tail))
5397 release_stalled_cmc (vl, cmc);
5398 if (NULL != vl->core_fc_stall_task)
5399 {
5401 vl->core_fc_stall_task = NULL;
5402 }
5403}

References VirtualLink::cmc_tail, VirtualLink::confirmed, VirtualLink::core_fc_stall_task, VirtualLink::core_recv_window, CT_CORE, delta, GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_NO, GNUNET_SCHEDULER_cancel(), GNUNET_SERVICE_client_continue(), GNUNET_SERVICE_client_drop(), GNUNET_STATISTICS_update(), GST_stats, RecvOkMessage::increase_window_delta, lookup_virtual_link(), RecvOkMessage::peer, release_stalled_cmc(), and tc.

Here is the call graph for this function:

◆ handle_communicator_available()

static void handle_communicator_available ( void *  cls,
const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage cam 
)
static

Communicator started.

Process the request.

Parameters
clsthe client
camthe send message that was sent

Definition at line 5413 of file gnunet-service-transport.c.

5416{
5417 const struct GNUNET_PeerIdentity *my_identity;
5418 struct TransportClient *tc = cls;
5419 uint16_t size;
5420
5421 size = ntohs (cam->header.size) - sizeof(*cam);
5422 if (0 == size)
5423 {
5425 "Receive-only communicator connected\n");
5426 /* Receive-only communicator: it has no address prefix, but we still
5427 MUST resume the client or we will never read from it again. Use an
5428 empty prefix so that the various strcmp()s do not see NULL. */
5429 tc->details.communicator.address_prefix = GNUNET_strdup ("");
5431 return;
5432 }
5433 tc->details.communicator.address_prefix =
5434 GNUNET_strdup ((const char *) &cam[1]);
5435 tc->details.communicator.cc = ntohl (cam->cc);
5436 tc->details.communicator.can_burst = ntohl (cam->can_burst);
5438 if (NULL != my_identity)
5439 {
5441 "Communicator for peer %s with prefix '%s' connected %s\n",
5443 tc->details.communicator.address_prefix,
5444 tc->details.communicator.can_burst ? "can burst" :
5445 "can not burst");
5446 }
5447 else
5448 {
5450 "Communicator for local peer with prefix '%s' connected %s\n",
5451 tc->details.communicator.address_prefix,
5452 tc->details.communicator.can_burst ? "can burst" :
5453 "can not burst");
5454 }
5456}

References GNUNET_TRANSPORT_CommunicatorAvailableMessage::can_burst, GNUNET_TRANSPORT_CommunicatorAvailableMessage::cc, GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, GNUNET_PILS_get_identity(), GNUNET_SERVICE_client_continue(), GNUNET_strdup, GNUNET_TRANSPORT_CommunicatorAvailableMessage::header, my_identity, pils, GNUNET_MessageHeader::size, size, and tc.

Here is the call graph for this function:

◆ check_communicator_backchannel()

static int check_communicator_backchannel ( void *  cls,
const struct GNUNET_TRANSPORT_CommunicatorBackchannel cb 
)
static

Communicator requests backchannel transmission.

Check the request.

Parameters
clsthe client
cbthe send message that was sent
Returns
GNUNET_OK if message is well-formed

Definition at line 5467 of file gnunet-service-transport.c.

5470{
5471 const struct GNUNET_MessageHeader *inbox;
5472 const char *is;
5473 uint16_t msize;
5474 uint16_t isize;
5475
5476 (void) cls;
5477 msize = ntohs (cb->header.size) - sizeof(*cb);
5478 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
5479 /* MUST bound the buffer before dereferencing @a inbox. */
5480 if (msize <= sizeof(struct GNUNET_MessageHeader))
5481 {
5482 GNUNET_break (0);
5483 return GNUNET_SYSERR;
5484 }
5485 isize = ntohs (inbox->size);
5486 if (isize >= msize)
5487 {
5488 GNUNET_break (0);
5489 return GNUNET_SYSERR;
5490 }
5491 is = (const char *) inbox;
5492 is += isize;
5493 msize -= isize;
5494 GNUNET_assert (0 < msize);
5495 if ('\0' != is[msize - 1])
5496 {
5497 GNUNET_break (0);
5498 return GNUNET_SYSERR;
5499 }
5500 return GNUNET_OK;
5501}

References GNUNET_assert, GNUNET_break, GNUNET_OK, GNUNET_SYSERR, GNUNET_TRANSPORT_CommunicatorBackchannel::header, is, and GNUNET_MessageHeader::size.

◆ sign_ephemeral()

static enum GNUNET_GenericReturnValue sign_ephemeral ( struct DistanceVector dv)
static

Sign the ephemeral key in dv, and mark it current.

MUST be synchronous. encapsulate_for_dv() copies sender_sig into the box it is about to encrypt on the very next line, so a signature that only arrives once PILS answers is a signature the receiver never sees. Worse, ephemeral_key and monotime are updated here and go out immediately: every box sent between the call and the answer carries the new ephemeral under the previous signature, which the receiver cannot verify, and it drops all of them.

Parameters
[in,out]dvdistance vector to update the ephemeral for
Returns
GNUNET_OK if sender_sig now covers ephemeral_key

Definition at line 5519 of file gnunet-service-transport.c.

5520{
5521 struct EphemeralConfirmationPS ec;
5522
5524 dv->ephemeral_validity =
5526 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
5527 ec.target = dv->target;
5528 ec.ephemeral_key = dv->ephemeral_key;
5529 ec.sender_monotonic_time = GNUNET_TIME_absolute_hton (dv->monotime);
5530 ec.purpose.size = htonl (sizeof(ec));
5531 return sign_by_my_identity (&ec.purpose, &dv->sender_sig);
5532}

References EphemeralConfirmationPS::ephemeral_key, DistanceVector::ephemeral_key, EPHEMERAL_VALIDITY, DistanceVector::ephemeral_validity, GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL, GNUNET_TIME_absolute_add(), GNUNET_TIME_absolute_get_monotonic(), GNUNET_TIME_absolute_hton(), GST_cfg, DistanceVector::monotime, GNUNET_CRYPTO_SignaturePurpose::purpose, EphemeralConfirmationPS::purpose, EphemeralConfirmationPS::sender_monotonic_time, DistanceVector::sender_sig, sign_by_my_identity(), GNUNET_CRYPTO_SignaturePurpose::size, EphemeralConfirmationPS::target, and DistanceVector::target.

Referenced by encapsulate_for_dv().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ free_queue_entry()

static void free_queue_entry ( struct QueueEntry qe,
struct TransportClient tc 
)
static

Definition at line 13407 of file gnunet-service-transport.c.

13409{
13410 struct PendingMessage *pm;
13411
13412 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
13413 qe->queue->queue_tail,
13414 qe);
13415 qe->queue->queue_length--;
13416 tc->details.communicator.total_queue_length--;
13418 "Received ACK on queue %s (QID %u) to peer %s (new length: %u/%u)\n",
13419 qe->queue->address,
13420 qe->queue->qid,
13421 GNUNET_i2s (&qe->queue->neighbour->pid),
13422 qe->queue->queue_length,
13423 tc->details.communicator.total_queue_length);
13424
13425 /* if applicable, resume transmissions that waited on ACK */
13427 tc->details.communicator.total_queue_length)
13428 {
13429 /* Communicator dropped below threshold, resume all queues
13430 incident with this client! */
13432 GST_stats,
13433 "# Transmission throttled due to communicator queue limit",
13434 -1,
13435 GNUNET_NO);
13436 for (struct Queue *queue = tc->details.communicator.queue_head;
13437 NULL != queue;
13438 queue = queue->next_client)
13439 {
13441 queue,
13443 }
13444 }
13445 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
13446 {
13447 /* queue dropped below threshold; only resume this one queue */
13449 "# Transmission throttled due to queue queue limit",
13450 -1,
13451 GNUNET_NO);
13453 qe->queue,
13455 }
13456 else if (1 == qe->queue->q_capacity)
13457 {
13458 // TODO I guess this will never happen, because the communicator triggers this by updating its queue length itself.
13460 "Transmission rescheduled due to communicator message queue with qid %u has capacity %"
13461 PRIu64 ".\n",
13462 qe->queue->qid,
13463 qe->queue->q_capacity);
13464 /* message queue has capacity; only resume this one queue */
13465 /* queue dropped below threshold; only resume this one queue */
13467 "# Transmission throttled due to message queue capacity",
13468 -1,
13469 GNUNET_NO);
13471 qe->queue,
13473 }
13474
13475 if (NULL != (pm = qe->pm))
13476 {
13477 struct VirtualLink *vl;
13478
13479 // GNUNET_assert (qe == pm->qe);
13480 pm->qe = NULL;
13481 /* If waiting for this communicator may have blocked transmission
13482 of pm on other queues for this neighbour, force schedule
13483 transmit on queue for queues of the neighbour */
13484 if (NULL == pm->frag_parent)
13485 {
13486 vl = pm->vl;
13487 if ((NULL != vl) &&
13488 (NULL != vl->pending_msg_head) &&
13489 (vl->pending_msg_head == pm))
13491 }
13492 }
13493 GNUNET_free (qe);
13494}

References check_vl_transmission(), COMMUNICATOR_TOTAL_QUEUE_LIMIT, PendingMessage::frag_parent, GNUNET_CONTAINER_DLL_remove, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_i2s(), GNUNET_log, GNUNET_NO, GNUNET_SCHEDULER_PRIORITY_DEFAULT, GNUNET_STATISTICS_update(), GNUNET_TIME_UNIT_ZERO, GST_stats, VirtualLink::pending_msg_head, qe, PendingMessage::qe, queue(), QUEUE_LENGTH_LIMIT, schedule_transmit_on_queue(), tc, and PendingMessage::vl.

Referenced by free_timedout_queue_entry(), and handle_send_message_ack().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ free_timedout_queue_entry()

static void free_timedout_queue_entry ( void *  cls)
static

Definition at line 5541 of file gnunet-service-transport.c.

5542{
5543 struct TransportClient *tc = cls;
5545
5547 "freeing timedout queue entries\n");
5548
5549 tc->details.communicator.free_queue_entry_task = NULL;
5550 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
5551 queue = queue->next_client)
5552 {
5553 struct QueueEntry *qep = queue->queue_head;
5554
5556 "checking QID %u for timedout queue entries\n",
5557 queue->qid);
5558 while (NULL != qep)
5559 {
5560 struct QueueEntry *pos = qep;
5562 pos->creation_timestamp, now);
5563 qep = qep->next;
5564
5566 "diff to now %s \n",
5569 {
5571 "Freeing timed out QueueEntry with MID %" PRIu64
5572 " and QID %u\n",
5573 pos->mid,
5574 queue->qid);
5576 "# QueueEntries timed out",
5577 1,
5578 GNUNET_NO);
5579 free_queue_entry (pos, tc);
5580 }
5581 }
5582 }
5583 /* Entries younger than #QUEUE_ENTRY_TIMEOUT are still to be reclaimed, and
5584 this task used to be a one-shot armed only by #queue_send_msg(). So the
5585 sweep that was supposed to bound how long an unacknowledged entry holds
5586 its slot only ever ran while *new* messages were being queued -- exactly
5587 not the case once the throttles in #schedule_transmit_on_queue() have
5588 stopped transmission. Keep going as long as anything is outstanding. */
5590}

References arm_free_queue_entry_task(), QueueEntry::creation_timestamp, free_queue_entry(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_NO, GNUNET_STATISTICS_update(), GNUNET_TIME_absolute_get(), GNUNET_TIME_absolute_get_difference(), GNUNET_TIME_relative2s(), GNUNET_TIME_relative_cmp, GST_stats, QueueEntry::mid, QueueEntry::next, queue(), QUEUE_ENTRY_TIMEOUT, and tc.

Referenced by arm_free_queue_entry_task().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ queue_send_msg()

static void queue_send_msg ( struct Queue queue,
struct PendingMessage pm,
const void *  payload,
size_t  payload_size 
)
static

Send the message payload on queue.

Parameters
queuethe queue to use for transmission
pmpending message to update once transmission is done, may be NULL!
payloadthe payload to send (encapsulated in a GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG).
payload_sizenumber of bytes in payload

Definition at line 5622 of file gnunet-service-transport.c.

5626{
5627 struct Neighbour *n = queue->neighbour;
5629 struct GNUNET_MQ_Envelope *env;
5630 struct PendingAcknowledgement *pa;
5631
5632 GNUNET_log (
5634 "Queueing %u bytes of payload for transmission <%" PRIu64
5635 "> on queue %llu to %s\n",
5636 (unsigned int) payload_size,
5637 (NULL == pm) ? 0 : pm->logging_uuid,
5638 (unsigned long long) queue->qid,
5639 GNUNET_i2s (&queue->neighbour->pid));
5640 env = GNUNET_MQ_msg_extra (smt,
5641 payload_size,
5643 smt->qid = htonl (queue->qid);
5644 smt->mid = GNUNET_htonll (queue->mid_gen);
5645 smt->receiver = n->pid;
5646 memcpy (&smt[1], payload, payload_size);
5647 {
5648 /* Pass the env to the communicator of queue for transmission. */
5649 struct QueueEntry *qe;
5650
5651 qe = GNUNET_new (struct QueueEntry);
5652 qe->creation_timestamp = GNUNET_TIME_absolute_get ();
5653 qe->mid = queue->mid_gen;
5655 "Create QueueEntry with MID %" PRIu64
5656 " and QID %u and prefix %s\n",
5657 qe->mid,
5658 queue->qid,
5659 queue->tc->details.communicator.address_prefix);
5660 queue->mid_gen++;
5661 qe->queue = queue;
5662 if (NULL != pm)
5663 {
5664 qe->pm = pm;
5665 // TODO Why do we have a retransmission. When we know, make decision if we still want this.
5666 // GNUNET_assert (NULL == pm->qe);
5667 if (NULL != pm->qe)
5668 {
5670 "Retransmitting message <%" PRIu64
5671 "> remove pm from qe with MID: %llu \n",
5673 (unsigned long long) pm->qe->mid);
5674 pm->qe->pm = NULL;
5675 }
5676 pm->qe = qe;
5677 }
5678 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
5679 if (0 == queue->q_capacity)
5680 {
5681 // Messages without FC or fragments can get here.
5682 if (NULL != pm)
5683 {
5685 "Message %" PRIu64
5686 " (pm type %u) was not send because queue has no capacity.\n",
5688 pm->pmt);
5689 pm->qe = NULL;
5690 }
5691 GNUNET_free (env);
5692 GNUNET_free (qe);
5693 return;
5694 }
5695 GNUNET_CONTAINER_DLL_insert (queue->queue_head, queue->queue_tail, qe);
5696 queue->queue_length++;
5697 queue->tc->details.communicator.total_queue_length++;
5698 if (GNUNET_NO == queue->unlimited_length)
5699 queue->q_capacity--;
5701 "Queue %s with qid %u has capacity %" PRIu64 "\n",
5702 queue->address,
5703 queue->qid,
5704 queue->q_capacity);
5706 queue->tc->details.communicator.total_queue_length)
5707 queue->idle = GNUNET_NO;
5708 if (QUEUE_LENGTH_LIMIT == queue->queue_length)
5709 queue->idle = GNUNET_NO;
5710 if (0 == queue->q_capacity)
5711 queue->idle = GNUNET_NO;
5712
5713 if (GNUNET_NO == queue->idle)
5715 if (NULL != pm)
5716 {
5717 /* NOTE: @e next_pa was never the link of this list -- nothing ever
5718 assigned it, so it was NULL on every entry. The MDLL that
5719 #prepare_pending_acknowledgement() inserts into is keyed `pm', and
5720 thus threaded through @e next_pm. Walking @e next_pa dereferenced
5721 NULL the moment the head was not the entry we wanted. */
5722 for (pa = pm->pa_head; NULL != pa; pa = pa->next_pm)
5723 if (pm == pa->pm)
5724 {
5725 pa->num_send++;
5726 break;
5727 }
5728 }
5729 // GNUNET_CONTAINER_multiuuidmap_get (pending_acks, &ack[i].ack_uuid.value);
5731 "Sending message MID %" PRIu64
5732 " of type %u (%u) and size %lu with MQ %p queue %s (QID %u) pending %"
5733 PRIu64 "\n",
5734 GNUNET_ntohll (smt->mid),
5735 ntohs (((const struct GNUNET_MessageHeader *) payload)->type),
5736 ntohs (smt->header.size),
5737 (unsigned long) payload_size,
5738 queue->tc->mq,
5739 queue->address,
5740 queue->qid,
5741 (NULL == pm) ? 0 : pm->logging_uuid);
5742 GNUNET_MQ_send (queue->tc->mq, env);
5743 }
5744}

References arm_free_queue_entry_task(), COMMUNICATOR_TOTAL_QUEUE_LIMIT, CT_COMMUNICATOR, env, GNUNET_assert, GNUNET_CONTAINER_DLL_insert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_htonll(), GNUNET_i2s(), GNUNET_log, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG, GNUNET_MQ_msg_extra, GNUNET_MQ_send(), GNUNET_new, GNUNET_NO, GNUNET_ntohll(), GNUNET_TIME_absolute_get(), GNUNET_TRANSPORT_SendMessageTo::header, PendingMessage::logging_uuid, QueueEntry::mid, GNUNET_TRANSPORT_SendMessageTo::mid, PendingAcknowledgement::next_pm, PendingAcknowledgement::num_send, PendingMessage::pa_head, payload, Neighbour::pid, PendingAcknowledgement::pm, QueueEntry::pm, PendingMessage::pmt, qe, PendingMessage::qe, GNUNET_TRANSPORT_SendMessageTo::qid, queue(), QUEUE_LENGTH_LIMIT, GNUNET_TRANSPORT_SendMessageTo::receiver, GNUNET_MessageHeader::size, and type.

Referenced by route_via_neighbour(), transmit_dv_init(), transmit_on_queue(), and validation_transmit_on_queue().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ route_via_neighbour()

static struct GNUNET_TIME_Relative route_via_neighbour ( const struct Neighbour n,
const struct GNUNET_MessageHeader hdr,
enum RouteMessageOptions  options 
)
static

Pick a queue of n under constraints options and schedule transmission of hdr.

Parameters
nneighbour to send to
hdrmessage to send as payload
optionswhether queues must be confirmed or not, and whether we may pick multiple (2) queues
Returns
expected RTT for transmission, GNUNET_TIME_UNIT_FOREVER_REL if sending failed

Definition at line 5758 of file gnunet-service-transport.c.

5761{
5762 struct GNUNET_TIME_Absolute now;
5763 unsigned int candidates;
5764 unsigned int sel1;
5765 unsigned int sel2;
5766 struct GNUNET_TIME_Relative rtt;
5767
5768 /* Pick one or two 'random' queues from n (under constraints of options) */
5769 now = GNUNET_TIME_absolute_get ();
5770 /* FIXME-OPTIMIZE: give queues 'weights' and pick proportional to
5771 weight in the future; weight could be assigned by observed
5772 bandwidth (note: not sure if we should do this for this type
5773 of control traffic though). */
5774 candidates = 0;
5775 for (struct Queue *pos = n->queue_head; NULL != pos;
5776 pos = pos->next_neighbour)
5777 {
5778 if ((0 != (options & RMO_UNCONFIRMED_ALLOWED)) ||
5779 (pos->validated_until.abs_value_us > now.abs_value_us))
5780 candidates++;
5781 }
5782 if (0 == candidates)
5783 {
5784 /* This can happen rarely if the last confirmed queue timed
5785 out just as we were beginning to process this message. */
5787 "Could not route message of type %u to %s: no valid queue\n",
5788 ntohs (hdr->type),
5789 GNUNET_i2s (&n->pid));
5791 "# route selection failed (all no valid queue)",
5792 1,
5793 GNUNET_NO);
5795 }
5796
5798 sel1 = GNUNET_CRYPTO_random_u32 (candidates);
5799 if (0 == (options & RMO_REDUNDANT))
5800 sel2 = candidates; /* picks none! */
5801 else
5802 sel2 = GNUNET_CRYPTO_random_u32 (candidates);
5803 candidates = 0;
5804 for (struct Queue *pos = n->queue_head; NULL != pos;
5805 pos = pos->next_neighbour)
5806 {
5807 if ((0 != (options & RMO_UNCONFIRMED_ALLOWED)) ||
5808 (pos->validated_until.abs_value_us > now.abs_value_us))
5809 {
5810 if ((sel1 == candidates) || (sel2 == candidates))
5811 {
5813 "Routing message of type %u to %s using %s (#%u)\n",
5814 ntohs (hdr->type),
5815 GNUNET_i2s (&n->pid),
5816 pos->address,
5817 (sel1 == candidates) ? 1 : 2);
5818 rtt = GNUNET_TIME_relative_min (rtt, pos->pd.aged_rtt);
5819 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
5820 }
5821 candidates++;
5822 }
5823 }
5824 return rtt;
5825}

References GNUNET_TIME_Absolute::abs_value_us, GNUNET_CRYPTO_random_u32(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_INFO, GNUNET_i2s(), GNUNET_log, GNUNET_NO, GNUNET_STATISTICS_update(), GNUNET_TIME_absolute_get(), GNUNET_TIME_relative_min(), GNUNET_TIME_UNIT_FOREVER_REL, GST_stats, options, queue_send_msg(), RMO_REDUNDANT, RMO_UNCONFIRMED_ALLOWED, GNUNET_MessageHeader::size, and GNUNET_MessageHeader::type.

Referenced by forward_dv_box(), forward_dv_learn(), handle_communicator_backchannel(), route_control_message_without_fc(), send_dv_to_neighbour(), send_t_validation_response(), and transmit_cummulative_ack_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ encapsulate_for_dv()

static struct GNUNET_TIME_Relative encapsulate_for_dv ( struct DistanceVector dv,
unsigned int  num_dvhs,
struct DistanceVectorHop **  dvhs,
const struct GNUNET_MessageHeader hdr,
DVMessageHandler  use,
void *  use_cls,
enum RouteMessageOptions  options,
enum GNUNET_GenericReturnValue  without_fc 
)
static

Pick a path of dv under constraints options and schedule transmission of hdr.

Parameters
targetneighbour to ultimately send to
num_dvhslength of the dvhs array
dvhsarray of hops to send the message to
hdrmessage to send as payload
usefunction to call with the encapsulated message
use_clsclosure for use
optionswhether path must be confirmed or not, to be passed to use
without_fcshall this TransportDVBoxMessage be forwarded without flow control.
Returns
expected RTT for transmission, GNUNET_TIME_UNIT_FOREVER_REL if sending failed

Definition at line 5858 of file gnunet-service-transport.c.

5866{
5867 const struct GNUNET_PeerIdentity *my_identity;
5868 struct TransportDVBoxMessage box_hdr;
5869 struct TransportDVBoxPayloadP *payload_hdr;
5870 uint16_t body_len_hbo = ntohs (hdr->size);
5871 unsigned char pt[sizeof(struct TransportDVBoxPayloadP) + body_len_hbo]
5873 unsigned char ct[sizeof(struct TransportDVBoxPayloadP) + body_len_hbo]
5875 struct GNUNET_TIME_Relative rtt;
5877
5878 payload_hdr = (struct TransportDVBoxPayloadP*) pt;
5881
5882 /* Encrypt payload */
5883 memset (&box_hdr, 0, sizeof (box_hdr));
5884 box_hdr.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
5885 box_hdr.total_hops = htons (0);
5886 box_hdr.without_fc = htonl (without_fc);
5887 // update_ephemeral (dv);
5888 if ((0 ==
5890 || (NULL == dv->km))
5891 {
5893 &dv->ephemeral_key,
5894 (struct GNUNET_ShortHashCode*) &km);
5895 GNUNET_free (dv->km); /* do not leak the previous key material */
5896 dv->km = GNUNET_new (struct GNUNET_ShortHashCode);
5897 GNUNET_memcpy (dv->km, &km, sizeof(struct GNUNET_ShortHashCode));
5898 if (GNUNET_OK != sign_ephemeral (dv))
5899 {
5900 /* Without a matching signature the box is undecryptable noise to the
5901 receiver; do not spend the bandwidth. Expire the ephemeral so the
5902 next attempt re-derives and re-signs rather than reusing it. */
5905 }
5906 }
5907 else
5908 {
5909 /* The ephemeral key is still valid, so reuse the cached key material.
5910 Without this @a km stayed UNINITIALISED stack memory and the
5911 receiver could not decrypt the box. */
5912 GNUNET_memcpy (&km, dv->km, sizeof(struct GNUNET_ShortHashCode));
5913 }
5914 box_hdr.ephemeral_key = dv->ephemeral_key;
5915 payload_hdr->sender_sig = dv->sender_sig;
5916 memcpy (&payload_hdr[1], hdr, body_len_hbo);
5917 GNUNET_CRYPTO_random_block (&box_hdr.iv,
5918 sizeof(box_hdr.iv));
5919 payload_hdr->sender = *my_identity;
5921 GNUNET_CRYPTO_aead_encrypt (sizeof pt,
5922 pt,
5923 0,
5924 NULL,
5925 &km,
5926 &box_hdr.iv,
5927 ct,
5928 &box_hdr.mac);
5930 /* For each selected path, take the pre-computed header and body
5931 and add the path in the middle of the message; then send it. */
5932 for (unsigned int i = 0; i < num_dvhs; i++)
5933 {
5934 struct DistanceVectorHop *dvh = dvhs[i];
5935 unsigned int num_hops = dvh->distance + 1;
5936 char buf[sizeof(struct TransportDVBoxMessage)
5937 + sizeof(struct GNUNET_PeerIdentity) * num_hops
5938 + sizeof(struct TransportDVBoxPayloadP)
5939 + body_len_hbo] GNUNET_ALIGN;
5940 struct GNUNET_PeerIdentity *dhops;
5941
5942 box_hdr.header.size = htons (sizeof(buf));
5943 box_hdr.orig_size = htons (sizeof(buf));
5944 box_hdr.num_hops = htons (num_hops);
5945 memcpy (buf, &box_hdr, sizeof(box_hdr));
5946 dhops = (struct GNUNET_PeerIdentity *) &buf[sizeof(box_hdr)];
5947 memcpy (dhops,
5948 dvh->path,
5949 dvh->distance * sizeof(struct GNUNET_PeerIdentity));
5950 dhops[dvh->distance] = dv->target;
5951 if (GNUNET_EXTRA_LOGGING > 0)
5952 {
5953 char *path;
5954
5956 for (unsigned int j = 0; j < num_hops; j++)
5957 {
5958 char *tmp;
5959
5960 GNUNET_asprintf (&tmp, "%s-%s", path, GNUNET_i2s (&dhops[j]));
5961 GNUNET_free (path);
5962 path = tmp;
5963 }
5965 "Routing message of type %u to %s using DV (#%u/%u) via %s\n",
5966 ntohs (hdr->type),
5967 GNUNET_i2s (&dv->target),
5968 i + 1,
5969 num_dvhs,
5970 path);
5971 GNUNET_free (path);
5972 }
5973 rtt = GNUNET_TIME_relative_min (rtt, dvh->pd.aged_rtt);
5974 memcpy (&dhops[num_hops], ct, sizeof(ct));
5975 use (use_cls,
5976 dvh->next_hop,
5977 (const struct GNUNET_MessageHeader *) buf,
5978 options);
5979 }
5980 return rtt;
5981}

References PerformanceData::aged_rtt, DistanceVectorHop::distance, TransportDVBoxMessage::ephemeral_key, GNUNET_ALIGN, GNUNET_asprintf(), GNUNET_assert, GNUNET_CRYPTO_aead_encrypt(), GNUNET_CRYPTO_eddsa_kem_encaps(), GNUNET_CRYPTO_random_block(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_EXTRA_LOGGING, GNUNET_free, GNUNET_i2s(), GNUNET_log, GNUNET_memcpy, GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX, GNUNET_new, GNUNET_OK, GNUNET_PILS_get_identity(), GNUNET_strdup, GNUNET_TIME_absolute_get_remaining(), GNUNET_TIME_absolute_hton(), GNUNET_TIME_relative_min(), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_TIME_UNIT_ZERO_ABS, TransportDVBoxMessage::header, TransportDVBoxMessage::iv, TransportDVBoxMessage::mac, TransportDVBoxPayloadP::monotonic_time, my_identity, DistanceVectorHop::next_hop, TransportDVBoxMessage::num_hops, options, TransportDVBoxMessage::orig_size, DistanceVectorHop::path, DistanceVectorHop::pd, pils, GNUNET_TIME_Relative::rel_value_us, TransportDVBoxPayloadP::sender, TransportDVBoxPayloadP::sender_sig, sign_ephemeral(), GNUNET_MessageHeader::size, TransportDVBoxMessage::total_hops, GNUNET_MessageHeader::type, and TransportDVBoxMessage::without_fc.

Referenced by route_control_message_without_fc(), and transmit_on_queue().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ send_dv_to_neighbour()

static void send_dv_to_neighbour ( void *  cls,
struct Neighbour next_hop,
const struct GNUNET_MessageHeader hdr,
enum RouteMessageOptions  options 
)
static

Wrapper around route_via_neighbour() that matches the DVMessageHandler structure.

Parameters
clsunused
next_hopwhere to send next
hdrheader of the message to send
optionsmessage options for queue selection

Definition at line 5994 of file gnunet-service-transport.c.

5998{
5999 (void) cls;
6000 (void) route_via_neighbour (next_hop, hdr, RMO_UNCONFIRMED_ALLOWED);
6001}

References RMO_UNCONFIRMED_ALLOWED, and route_via_neighbour().

Referenced by route_control_message_without_fc().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ route_control_message_without_fc()

static struct GNUNET_TIME_Relative route_control_message_without_fc ( struct VirtualLink vl,
const struct GNUNET_MessageHeader hdr,
enum RouteMessageOptions  options 
)
static

We need to transmit hdr to target.

If necessary, this may involve DV routing. This function routes without applying flow control or congestion control and should only be used for control traffic.

Parameters
targetpeer to receive hdr
hdrheader of the message to route and GNUNET_free()
optionswhich transmission channels are allowed
Returns
expected RTT for transmission, GNUNET_TIME_UNIT_FOREVER_REL if sending failed

Definition at line 6016 of file gnunet-service-transport.c.

6020{
6021 // struct VirtualLink *vl;
6022 struct Neighbour *n;
6023 struct DistanceVector *dv;
6024 struct GNUNET_TIME_Relative rtt1;
6025 struct GNUNET_TIME_Relative rtt2;
6026 const struct GNUNET_PeerIdentity *target = &vl->target;
6027
6029 "Trying to route message of type %u to %s without fc\n",
6030 ntohs (hdr->type),
6031 GNUNET_i2s (target));
6032
6033 // TODO Do this elsewhere. vl should be given as parameter to method.
6034 // vl = lookup_virtual_link (target);
6035 /* An unconfirmed link is allowed here: it has no @e n and no @e dv of its
6036 own, so the "confirmed required" branch below resolves the route from
6037 #neighbours / #dv_routes. Refusing to route at all is what deadlocks a
6038 pair of peers, see #consider_sending_fc(). */
6039 GNUNET_assert (NULL != vl);
6040 n = vl->n;
6041 dv = (0 != (options & RMO_DV_ALLOWED)) ? vl->dv : NULL;
6042 /* An unconfirmed link has neither @e n nor @e dv of its own, so resolve
6043 the route from #neighbours / #dv_routes. This used to be done only
6044 while #RMO_UNCONFIRMED_ALLOWED was *not* set -- exactly backwards: with
6045 the flag set (the caller that needs it most) we would find no route at
6046 all and drop the message. Whether an unvalidated queue or an
6047 unvalidated path may then be used is still decided by @a options, in
6048 #route_via_neighbour() and #pick_random_dv_hops(). */
6049 if (NULL == n)
6050 n = lookup_neighbour (target);
6051 if ((NULL == dv) && (0 != (options & RMO_DV_ALLOWED)))
6053 if ((NULL == n) && (NULL == dv))
6054 {
6056 "Cannot route message of type %u to %s: no route\n",
6057 ntohs (hdr->type),
6058 GNUNET_i2s (target));
6060 "# Messages dropped in routing: no acceptable method",
6061 1,
6062 GNUNET_NO);
6064 }
6066 "Routing message of type %u to %s with options %X\n",
6067 ntohs (hdr->type),
6068 GNUNET_i2s (target),
6069 (unsigned int) options);
6070 /* If both dv and n are possible and we must choose:
6071 flip a coin for the choice between the two; for now 50/50 */
6072 if ((NULL != n) && (NULL != dv) && (0 == (options & RMO_REDUNDANT)))
6073 {
6074 if (0 == GNUNET_CRYPTO_random_u32 (2))
6075 n = NULL;
6076 else
6077 dv = NULL;
6078 }
6079 if ((NULL != n) && (NULL != dv))
6080 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
6081 enough for redundancy, so clear the flag. */
6084 if (NULL != n)
6085 {
6087 "Try to route message of type %u to %s without fc via neighbour\n",
6088 ntohs (hdr->type),
6089 GNUNET_i2s (target));
6090 rtt1 = route_via_neighbour (n, hdr, options);
6091 }
6092 if (NULL != dv)
6093 {
6094 struct DistanceVectorHop *hops[2];
6095 unsigned int res;
6096
6098 options,
6099 hops,
6100 (0 == (options & RMO_REDUNDANT)) ? 1 : 2);
6101 if (0 == res)
6102 {
6104 "Failed to route message, could not determine DV path\n");
6105 return rtt1;
6106 }
6108 "encapsulate_for_dv 1\n");
6109 rtt2 = encapsulate_for_dv (dv,
6110 res,
6111 hops,
6112 hdr,
6114 NULL,
6116 GNUNET_YES);
6117 }
6118 return GNUNET_TIME_relative_min (rtt1, rtt2);
6119}

References DistanceVectorHop::dv, dv_routes, encapsulate_for_dv(), GNUNET_assert, GNUNET_CONTAINER_multipeermap_get(), GNUNET_CRYPTO_random_u32(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_INFO, GNUNET_i2s(), GNUNET_log, GNUNET_NO, GNUNET_STATISTICS_update(), GNUNET_TIME_relative_min(), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, GST_stats, lookup_neighbour(), options, pick_random_dv_hops(), res, RMO_DV_ALLOWED, RMO_REDUNDANT, route_via_neighbour(), send_dv_to_neighbour(), and GNUNET_MessageHeader::type.

Referenced by consider_sending_fc(), forward_dv_learn(), handle_communicator_backchannel(), send_t_validation_response(), and transmit_cummulative_ack_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ consider_sending_fc()

static void consider_sending_fc ( void *  cls)
static

Something changed on the virtual link with respect to flow control.

Consider retransmitting the FC window size.

Parameters
clsa struct VirtualLink to work with

Definition at line 6200 of file gnunet-service-transport.c.

6201{
6202 struct VirtualLink *vl = cls;
6203 struct GNUNET_TIME_Absolute monotime;
6204 struct TransportFlowControlMessage *fc;
6206 struct GNUNET_TIME_Relative rtt;
6207 struct GNUNET_TIME_Relative rtt_average;
6208 struct Neighbour *n = vl->n;
6209 size_t addresses_size;
6210
6211 /* Most of our callers are not the retransmit task but inbound events:
6212 handle_flow_control() ends in check_vl_transmission(), which calls us
6213 once per flow-control-stalled message, and the peer's answer to what we
6214 send here arrives as another handle_flow_control(). On a link whose
6215 head message does not fit the window that is a ping-pong with nothing
6216 to damp it -- the backoff and the MIN_FC_RETRANSMIT_DELAY floor at the
6217 bottom of this function only ever governed @e fc_retransmit_task, which
6218 these callers bypass. If the chain is armed and we just sent one, let
6219 the task do it. */
6220 if ((NULL != vl->fc_retransmit_task) &&
6222 < MIN_FC_RETRANSMIT_DELAY.rel_value_us))
6223 {
6225 "Not sending FC to %s: one went out less than %s ago\n",
6226 GNUNET_i2s (&vl->target),
6229 GNUNET_YES));
6230 return;
6231 }
6232 if ((GNUNET_YES != vl->confirmed) &&
6233 (NULL == lookup_neighbour (&vl->target)) &&
6235 {
6236 /* Unconfirmed AND no way to reach the peer at all -- nothing to send on.
6237 An unconfirmed link that *does* have a route must still answer,
6238 see below.
6239
6240 Do NOT just return: #task_consider_sending_fc() cleared
6241 @e fc_retransmit_task before calling us, and the only other place that
6242 arms it is #handle_flow_control() -- which only does so when it is
6243 already non-NULL. Leaving without re-arming therefore ends the
6244 keepalive chain for this link permanently, and #check_link_down()
6245 tears it down #NEIGHBOUR_LIVENESS_TIMEOUT later. */
6247 "Not sending FC to %s: link unconfirmed and no route\n",
6248 GNUNET_i2s (&vl->target));
6249 if (NULL == vl->fc_retransmit_task)
6253 vl);
6254 return;
6255 }
6256 addresses_size = 0;
6257 if (NULL != n && 0 < n->number_of_addresses)
6258 {
6259 addresses_size =
6260 n->number_of_addresses * sizeof (struct TransportGlobalNattedAddress) + n
6261 ->size_of_global_addresses;
6262 if (addresses_size >
6263 UINT16_MAX - sizeof (struct TransportFlowControlMessage))
6264 {
6265 /* htons() below would silently truncate `header.size', leaving a
6266 message whose declared length does not match its contents. */
6267 GNUNET_break (0);
6268 addresses_size = 0;
6269 }
6270 }
6271 if (0 != addresses_size)
6272 {
6273 char *tgnas = GNUNET_malloc (addresses_size);
6275 ctx.off = 0;
6276 ctx.size = addresses_size;
6277 ctx.tgnas = tgnas;
6278
6280 + addresses_size);
6281 fc->header.size = htons (sizeof(struct TransportFlowControlMessage)
6282 + addresses_size);
6283 fc->size_of_addresses = htonl ((uint32_t) n->size_of_global_addresses);
6284 fc->number_of_addresses = htonl (n->number_of_addresses);
6287 &ctx);
6290 }
6291 else
6292 {
6293 fc = GNUNET_malloc (sizeof (struct TransportFlowControlMessage));
6294 fc->header.size = htons (sizeof(struct TransportFlowControlMessage));
6295 }
6296
6298 /* OPTIMIZE-FC-BDP: decide sane criteria on when to do this, instead of doing
6299 it always! */
6300 /* For example, we should probably ONLY do this if a bit more than
6301 an RTT has passed, or if the window changed "significantly" since
6302 then. See vl->last_fc_rtt! NOTE: to do this properly, we also
6303 need an estimate for the bandwidth-delay-product for the entire
6304 VL, as that determines "significantly". We have the delay, but
6305 the bandwidth statistics need to be added for the VL!*/(void) duration;
6306
6307 if (NULL != vl->dv)
6308 rtt_average = calculate_rtt (vl->dv);
6309 else
6310 rtt_average = GNUNET_TIME_UNIT_FOREVER_REL;
6311 fc->rtt = GNUNET_TIME_relative_hton (rtt_average);
6313 "Sending FC seq %u to %s with new window %llu %lu %u\n",
6314 (unsigned int) vl->fc_seq_gen,
6315 GNUNET_i2s (&vl->target),
6316 (unsigned long long) vl->incoming_fc_window_size,
6317 (unsigned long) rtt_average.rel_value_us,
6318 vl->sync_ready);
6320 vl->last_fc_transmission = monotime;
6321 fc->sync_ready = htonl ((uint32_t) vl->sync_ready);
6323 fc->seq = htonl (vl->fc_seq_gen++);
6324 fc->inbound_window_size = GNUNET_htonll (vl->incoming_fc_window_size
6327 fc->outbound_sent = GNUNET_htonll (vl->outbound_fc_window_size_used);
6328 fc->outbound_window_size = GNUNET_htonll (vl->outbound_fc_window_size);
6329 fc->sender_time = GNUNET_TIME_absolute_hton (monotime);
6330 /* On an unconfirmed link the only queues and paths we have are, by
6331 definition, unvalidated ones -- that is what "unconfirmed" means.
6332 Requiring a validated route here is what deadlocks the pair: the peer
6333 has a confirmed link to us and flow-controls us, we cannot answer, so
6334 its @e outbound_fc_window_size stays at zero and it cannot send us a
6335 single byte -- not its CORE handshake, not DHT traffic -- while its
6336 `gnunet-transport' shows an established link with messages pending
6337 forever. It reached us over that queue, so answering on it is sound. */
6339 &fc->header,
6340 (GNUNET_YES == vl->confirmed)
6343 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == rtt.rel_value_us)
6344 {
6347 "FC retransmission to %s failed, will retry in %s\n",
6348 GNUNET_i2s (&vl->target),
6351 }
6352 else
6353 {
6354 /* OPTIMIZE-FC-BDP: rtt is not ideal, we can do better! */
6355 vl->last_fc_rtt = rtt;
6356 }
6357 if (NULL != vl->fc_retransmit_task)
6359 /* Never re-arm with (near) zero delay: @a rtt is zero whenever we have no
6360 RTT sample yet, which turned this into a tight send loop. */
6362 {
6363 /* Back off while the peer stays silent. Retransmitting at the plain RTT
6364 for #MAX_FC_RETRANSMIT_COUNT rounds is a flood on a link that is not
6365 being answered -- and a peer that cannot answer keeps *every* one of
6366 its links in exactly that state, which is enough traffic to make
6367 transport fall behind its communicators. */
6369
6370 for (unsigned int i = 0;
6371 (i < vl->fc_retransmit_count) && (rtt.rel_value_us < cap.rel_value_us);
6372 i++)
6373 rtt = GNUNET_TIME_relative_multiply (rtt, 2);
6374 rtt = GNUNET_TIME_relative_min (rtt, cap);
6375 }
6376 vl->fc_retransmit_task =
6379 vl->fc_retransmit_count++;
6380 GNUNET_free (fc);
6381}

References add_global_addresses(), calculate_rtt(), VirtualLink::confirmed, ctx, duration, VirtualLink::dv, dv_routes, FC_KEEPALIVE_INTERVAL, VirtualLink::fc_retransmit_count, VirtualLink::fc_retransmit_task, VirtualLink::fc_seq_gen, GNUNET_break, GNUNET_CONTAINER_multipeermap_get(), GNUNET_CONTAINER_multipeermap_iterate(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_htonll(), GNUNET_i2s(), GNUNET_log, GNUNET_malloc, GNUNET_memcpy, GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL, GNUNET_SCHEDULER_add_delayed(), GNUNET_SCHEDULER_cancel(), GNUNET_STRINGS_relative_time_to_string(), GNUNET_TIME_absolute_get_duration(), GNUNET_TIME_absolute_get_monotonic(), GNUNET_TIME_absolute_hton(), GNUNET_TIME_relative_hton(), GNUNET_TIME_relative_max(), GNUNET_TIME_relative_min(), GNUNET_TIME_relative_multiply(), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_TIME_UNIT_SECONDS, GNUNET_TIME_UNIT_ZERO, GNUNET_YES, GST_cfg, VirtualLink::incoming_fc_window_size, VirtualLink::incoming_fc_window_size_loss, VirtualLink::incoming_fc_window_size_used, VirtualLink::last_fc_rtt, VirtualLink::last_fc_transmission, lookup_neighbour(), MAX_FC_RETRANSMIT_COUNT, MIN_FC_RETRANSMIT_DELAY, VirtualLink::n, Neighbour::natted_addresses, Neighbour::number_of_addresses, AddGlobalAddressesContext::off, VirtualLink::outbound_fc_window_size, VirtualLink::outbound_fc_window_size_used, GNUNET_TIME_Relative::rel_value_us, RMO_ANYTHING_GOES, RMO_DV_ALLOWED, route_control_message_without_fc(), Neighbour::size_of_global_addresses, VirtualLink::sync_ready, VirtualLink::target, task_consider_sending_fc(), AddGlobalAddressesContext::tgnas, and Neighbour::vl.

Referenced by activate_core_visible_dv_path(), check_vl_transmission(), core_env_sent_cb(), core_fc_stalled(), handle_flow_control(), handle_validation_response(), and task_consider_sending_fc().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ task_consider_sending_fc()

static void task_consider_sending_fc ( void *  cls)
static

Something changed on the virtual link with respect to flow control.

Consider retransmitting the FC window size.

Parameters
clsa struct VirtualLink to work with

Definition at line 6132 of file gnunet-service-transport.c.

6133{
6134 struct VirtualLink *vl = cls;
6135 vl->fc_retransmit_task = NULL;
6136 consider_sending_fc (cls);
6137}

References consider_sending_fc(), and VirtualLink::fc_retransmit_task.

Referenced by consider_sending_fc(), and handle_flow_control().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_address_without_port()

static char * get_address_without_port ( const char *  address)
static

Get the IP address without the communicator prefix and the port number.

Parameters
addressstring of the form 'PREFIX-IP:PORT', for example 'tcp-92.68.150.1:55452'
Returns
string with the IP address only, or NULL if address is not of that form. Addresses reach us from remote HELLOs, so callers MUST handle NULL!

Definition at line 14402 of file gnunet-service-transport.c.

14403{
14404 const char *dash;
14405 const char *colon;
14406
14407 if (NULL == address)
14408 return NULL;
14409 dash = strchr (address, '-');
14410 if (NULL == dash)
14411 return NULL;
14412 colon = strchr (dash, ':');
14413 if (NULL == colon)
14414 return NULL;
14415 return GNUNET_strndup (dash + 1,
14416 colon - (dash + 1));
14417}

References address, and GNUNET_strndup.

Referenced by check_for_global_natted(), check_validation_request_pending(), create_address_entry(), find_queue_by_ip(), handle_add_queue_message(), iterate_address_and_compare_cb(), and iterate_address_start_burst().

Here is the caller graph for this function:

◆ add_global_addresses()

static enum GNUNET_GenericReturnValue add_global_addresses ( void *  cls,
const struct GNUNET_PeerIdentity pid,
void *  value 
)
static

Definition at line 6160 of file gnunet-service-transport.c.

6163{
6164 struct AddGlobalAddressesContext *ctx = cls;
6165 struct TransportGlobalNattedAddress *tgna = value;
6166 char *addr = (char *) &tgna[1];
6167 size_t alen = ntohl (tgna->address_length);
6168 size_t need = sizeof (struct TransportGlobalNattedAddress) + alen;
6169
6170 /* NOTE: the address is NOT 0-terminated, it must be printed with an
6171 explicit precision. */
6173 "sending address %.*s length %lu\n",
6174 (int) alen,
6175 addr,
6176 (unsigned long) alen);
6177 if (ctx->off + need > ctx->size)
6178 {
6179 GNUNET_break (0);
6180 return GNUNET_NO;
6181 }
6182 GNUNET_memcpy (&(ctx->tgnas[ctx->off]), tgna, need);
6183 ctx->off += need;
6184
6185 return GNUNET_OK;
6186}

References TransportGlobalNattedAddress::address_length, ctx, GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_memcpy, GNUNET_NO, GNUNET_OK, and value.

Referenced by consider_sending_fc().

Here is the caller graph for this function:

◆ calculate_rtt()

static struct GNUNET_TIME_Relative calculate_rtt ( struct DistanceVector dv)
static

Definition at line 11607 of file gnunet-service-transport.c.

11608{
11610 unsigned int n_hops = 0;
11611
11613 "calculate_rtt\n");
11614 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
11615 pos = pos->next_dv)
11616 {
11618 "calculate_rtt %lu\n",
11619 (unsigned long) pos->pd.aged_rtt.rel_value_us);
11620 n_hops++;
11622 aged_rtt, pos
11623 ->distance
11624 + 2), ret);
11625 }
11626
11627 if (0 == n_hops)
11629 return ret;
11630}

References GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_TIME_relative_add(), GNUNET_TIME_relative_multiply(), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_TIME_UNIT_ZERO, and ret.

Referenced by consider_sending_fc(), and handle_flow_control().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_vl_transmission()

static void check_vl_transmission ( struct VirtualLink vl)
static

There is a message at the head of the pending messages for vl which may be ready for transmission.

Check if a queue is ready to take it.

This function must (1) check for flow control to ensure that we can right now send to vl, (2) check that the pending message in the queue is actually eligible, (3) determine if any applicable queue (direct neighbour or DVH path) is ready to accept messages, and (4) prioritize based on the preferences associated with the pending message.

So yeah, easy.

Parameters
vlvirtual link where we should check for transmission

Definition at line 6401 of file gnunet-service-transport.c.

6402{
6403 struct Neighbour *n = vl->n;
6404 struct DistanceVector *dv = vl->dv;
6405 struct GNUNET_TIME_Absolute now;
6406 struct VirtualLink *vl_next_hop;
6407 int elig;
6408
6410 "check_vl_transmission to target %s\n",
6411 GNUNET_i2s (&vl->target));
6412 /* Check that we have an eligible pending message!
6413 (cheaper than having #transmit_on_queue() find out!) */
6414 elig = GNUNET_NO;
6415 for (struct PendingMessage *pm = vl->pending_msg_head; NULL != pm;
6416 pm = pm->next_vl)
6417 {
6419 "check_vl_transmission loop\n");
6420 if (NULL != pm->qe)
6421 continue; /* not eligible, is in a queue! */
6422 if (pm->bytes_msg + vl->outbound_fc_window_size_used >
6424 {
6426 "Stalled message %" PRIu64
6427 " transmission on VL %s due to flow control: %llu < %llu\n",
6428 pm->logging_uuid,
6429 GNUNET_i2s (&vl->target),
6430 (unsigned long long) vl->outbound_fc_window_size,
6431 (unsigned long long) (pm->bytes_msg
6434 return; /* We have a message, but flow control says "nope" */
6435 }
6437 "Target window on VL %s not stalled. Scheduling transmission on queue\n",
6438 GNUNET_i2s (&vl->target));
6439 /* Notify queues at direct neighbours that we are interested */
6440 now = GNUNET_TIME_absolute_get ();
6441 if (NULL != n)
6442 {
6443 for (struct Queue *queue = n->queue_head; NULL != queue;
6444 queue = queue->next_neighbour)
6445 {
6446 if ((GNUNET_YES == queue->idle) &&
6447 (queue->validated_until.abs_value_us > now.abs_value_us))
6448 {
6450 "Direct neighbour %s not stalled\n",
6451 GNUNET_i2s (&n->pid));
6453 queue,
6455 elig = GNUNET_YES;
6456 }
6457 else
6459 "Neighbour Queue QID: %u (%u) busy or invalid\n",
6460 queue->qid,
6461 queue->idle);
6462 }
6463 }
6464 /* Notify queues via DV that we are interested */
6465 if (NULL != dv)
6466 {
6467 /* Do DV with lower scheduler priority, which effectively means that
6468 IF a neighbour exists and is available, we prefer it. */
6469 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
6470 pos = pos->next_dv)
6471 {
6472 struct Neighbour *nh_iter = pos->next_hop;
6473
6474
6475 if (pos->path_valid_until.abs_value_us <= now.abs_value_us)
6476 continue; /* skip this one: path not validated */
6477 else
6478 {
6479 /* The next hop is a neighbour we have queues to; it need not have
6480 a virtual link of its own, and then there is no window of it to
6481 respect either. */
6482 vl_next_hop = lookup_virtual_link (&nh_iter->pid);
6483 if ((NULL != vl_next_hop) &&
6484 (pm->bytes_msg + vl_next_hop->outbound_fc_window_size_used >
6485 vl_next_hop->outbound_fc_window_size))
6486 {
6488 "Stalled message %" PRIu64
6489 " transmission on next hop %s due to flow control: %llu < %llu\n",
6490 pm->logging_uuid,
6491 GNUNET_i2s (&vl_next_hop->target),
6492 (unsigned long
6493 long) vl_next_hop->outbound_fc_window_size,
6494 (unsigned long long) (pm->bytes_msg
6495 + vl_next_hop->
6496 outbound_fc_window_size_used));
6497 consider_sending_fc (vl_next_hop);
6498 continue; /* We have a message, but flow control says "nope" for the first hop of this path */
6499 }
6500 for (struct Queue *queue = nh_iter->queue_head; NULL != queue;
6501 queue = queue->next_neighbour)
6502 if ((GNUNET_YES == queue->idle) &&
6503 (queue->validated_until.abs_value_us > now.abs_value_us))
6504 {
6506 "Next hop neighbour %s not stalled\n",
6507 GNUNET_i2s (&nh_iter->pid));
6509 queue,
6511 elig = GNUNET_YES;
6512 }
6513 else
6515 "DV Queue QID: %u (%u) busy or invalid\n",
6516 queue->qid,
6517 queue->idle);
6518 }
6519 }
6520 }
6521 if (GNUNET_YES == elig)
6523 "Eligible message %" PRIu64 " of size %u to %s: %llu/%llu\n",
6524 pm->logging_uuid,
6525 pm->bytes_msg,
6526 GNUNET_i2s (&vl->target),
6527 (unsigned long long) vl->outbound_fc_window_size,
6528 (unsigned long long) (pm->bytes_msg
6530 break;
6531 }
6532}

References GNUNET_TIME_Absolute::abs_value_us, consider_sending_fc(), VirtualLink::dv, DistanceVector::dv_head, GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, GNUNET_NO, GNUNET_SCHEDULER_PRIORITY_BACKGROUND, GNUNET_SCHEDULER_PRIORITY_DEFAULT, GNUNET_TIME_absolute_get(), GNUNET_TIME_UNIT_ZERO, GNUNET_YES, lookup_virtual_link(), VirtualLink::n, VirtualLink::outbound_fc_window_size, VirtualLink::outbound_fc_window_size_used, VirtualLink::pending_msg_head, Neighbour::pid, queue(), Neighbour::queue_head, schedule_transmit_on_queue(), VirtualLink::target, DistanceVector::vl, and Neighbour::vl.

Referenced by forward_dv_box(), free_queue_entry(), handle_client_send(), handle_flow_control(), and send_msg_from_cache().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_client_send()

static void handle_client_send ( void *  cls,
const struct OutboundMessage obm 
)
static

Client asked for transmission to a peer.

Process the request.

Parameters
clsthe client
obmthe send message that was sent

Definition at line 6542 of file gnunet-service-transport.c.

6543{
6544 struct TransportClient *tc = cls;
6545 struct PendingMessage *pm;
6546 const struct GNUNET_MessageHeader *obmm;
6547 uint32_t bytes_msg;
6548 struct VirtualLink *vl;
6550
6551 GNUNET_assert (CT_CORE == tc->type);
6552 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
6553 bytes_msg = ntohs (obmm->size);
6554 pp = ntohl (obm->priority);
6555 vl = lookup_virtual_link (&obm->peer);
6556 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
6557 {
6559 "Don't have %s as a neighbour (anymore).\n",
6560 GNUNET_i2s (&obm->peer));
6561 /* Failure: don't have this peer as a neighbour (anymore).
6562 Might have gone down asynchronously, so this is NOT
6563 a protocol violation by CORE. Still count the event,
6564 as this should be rare. */
6565 /* Precisely because this is not a protocol violation we leave the
6566 client's `struct Neighbour' -- and its send window -- in place, so we
6567 owe it the SEND_OK for the message we are dropping here. Without it
6568 the window shrinks by one every time this happens and never grows
6569 back; after #SEND_WINDOW_SIZE such drops #mq_send_impl() parks every
6570 further message for this peer forever ("Flow control delays
6571 transmission to CORE until we see SEND_OK") and CORE goes mute
6572 towards a peer it still believes it is connected to -- while
6573 continuing to receive from it, so its own idle timeout is what
6574 eventually reports the peer down. */
6575 send_ok_to_client (tc, &obm->peer);
6578 "# messages dropped (neighbour unknown)",
6579 1,
6580 GNUNET_NO);
6581 return;
6582 }
6583
6584 pm = GNUNET_malloc (sizeof(struct PendingMessage) + bytes_msg);
6586 "1 created pm %p storing vl %p\n",
6587 pm,
6588 vl);
6590 pm->prefs = pp;
6591 pm->client = tc;
6592 pm->vl = vl;
6593 pm->bytes_msg = bytes_msg;
6594 memcpy (&pm[1], obmm, bytes_msg);
6596 "Sending message of type %u with %u bytes as <%" PRIu64
6597 "> to %s\n",
6598 ntohs (obmm->type),
6599 bytes_msg,
6600 pm->logging_uuid,
6601 GNUNET_i2s (&obm->peer));
6603 tc->details.core.pending_msg_head,
6604 tc->details.core.pending_msg_tail,
6605 pm);
6607 vl->pending_msg_head,
6608 vl->pending_msg_tail,
6609 pm);
6612}

References PendingMessage::bytes_msg, check_vl_transmission(), PendingMessage::client, VirtualLink::confirmed, CT_CORE, GNUNET_assert, GNUNET_CONTAINER_MDLL_insert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, GNUNET_malloc, GNUNET_NO, GNUNET_SERVICE_client_continue(), GNUNET_STATISTICS_update(), GST_stats, PendingMessage::logging_uuid, logging_uuid_gen, lookup_virtual_link(), OutboundMessage::peer, VirtualLink::pending_msg_head, VirtualLink::pending_msg_tail, PendingMessage::prefs, OutboundMessage::priority, send_ok_to_client(), GNUNET_MessageHeader::size, tc, GNUNET_MessageHeader::type, and PendingMessage::vl.

Here is the call graph for this function:

◆ handle_communicator_backchannel()

static void handle_communicator_backchannel ( void *  cls,
const struct GNUNET_TRANSPORT_CommunicatorBackchannel cb 
)
static

Communicator requests backchannel transmission.

Process the request. Just repacks it into our struct TransportBackchannelEncapsulationMessage * (which for now has exactly the same format, only a different message type) and passes it on for routing.

Parameters
clsthe client
cbthe send message that was sent

Definition at line 6625 of file gnunet-service-transport.c.

6628{
6629 struct Neighbour *n;
6630 struct VirtualLink *vl;
6631 struct TransportClient *tc = cls;
6632 const struct GNUNET_MessageHeader *inbox =
6633 (const struct GNUNET_MessageHeader *) &cb[1];
6634 uint16_t isize = ntohs (inbox->size);
6635 const char *is = ((const char *) &cb[1]) + isize;
6636 size_t slen = strlen (is) + 1;
6637 char
6638 mbuf[slen + isize
6639 + sizeof(struct
6643
6644 /* 0-termination of 'is' was checked already in
6645 #check_communicator_backchannel() */
6647 "Preparing backchannel transmission to %s:%s of type %u and size %u\n",
6648 GNUNET_i2s (&cb->pid),
6649 is,
6650 ntohs (inbox->type),
6651 ntohs (inbox->size));
6652 /* encapsulate and encrypt message */
6653 be->header.type =
6655 be->header.size = htons (sizeof(mbuf));
6656 memcpy (&be[1], inbox, isize);
6657 memcpy (&mbuf[sizeof(struct TransportBackchannelEncapsulationMessage)
6658 + isize],
6659 is,
6660 strlen (is) + 1);
6661 // route_control_message_without_fc (&cb->pid, &be->header, RMO_DV_ALLOWED);
6662 vl = lookup_virtual_link (&cb->pid);
6663 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
6664 {
6666 }
6667 else
6668 {
6669 /* Use route via neighbour */
6670 n = lookup_neighbour (&cb->pid);
6671 if (NULL != n)
6673 n,
6674 &be->header,
6675 RMO_NONE);
6676 }
6678}

References VirtualLink::confirmed, GNUNET_ALIGN, GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION, GNUNET_SERVICE_client_continue(), GNUNET_YES, TransportBackchannelEncapsulationMessage::header, is, lookup_neighbour(), lookup_virtual_link(), GNUNET_TRANSPORT_CommunicatorBackchannel::pid, RMO_DV_ALLOWED, RMO_NONE, route_control_message_without_fc(), route_via_neighbour(), GNUNET_MessageHeader::size, tc, and GNUNET_MessageHeader::type.

Here is the call graph for this function:

◆ check_add_address()

static int check_add_address ( void *  cls,
const struct GNUNET_TRANSPORT_AddAddressMessage aam 
)
static

Address of our peer added.

Test message is well-formed.

Parameters
clsthe client
aamthe send message that was sent
Returns
GNUNET_OK if message is well-formed

Definition at line 6689 of file gnunet-service-transport.c.

6691{
6692 struct TransportClient *tc = cls;
6693
6694 if (CT_COMMUNICATOR != tc->type)
6695 {
6696 GNUNET_break (0);
6697 return GNUNET_SYSERR;
6698 }
6700 return GNUNET_OK;
6701}

References CT_COMMUNICATOR, GNUNET_break, GNUNET_MQ_check_zero_termination, GNUNET_OK, GNUNET_SYSERR, and tc.

◆ store_pi()

static void store_pi ( void *  cls)
static

Ask peerstore to store our address.

Parameters
clsan struct AddressListEntry *

Definition at line 7025 of file gnunet-service-transport.c.

7026{
7027 struct AddressListEntry *ale = cls;
7028 const char *dash;
7029 char *address_uri;
7030 char *prefix;
7031 unsigned int add_success;
7032
7033 if ((GNUNET_YES == in_shutdown) || (NULL == pils))
7034 {
7035 ale->st = NULL;
7036 return;
7037 }
7038 if (NULL == GNUNET_PILS_get_identity (pils))
7039 {
7040 /* Do NOT poll at 1kHz: that burns CPU and keeps the scheduler task
7041 list non-empty, which prevents the service from ever exiting. */
7044 &store_pi,
7045 ale);
7046 return;
7047 }
7050 dash = strchr (ale->address, '-');
7051 GNUNET_assert (NULL != dash);
7052 dash++;
7053 GNUNET_asprintf (&address_uri,
7054 "%s://%s",
7055 prefix,
7056 dash);
7058 ale->st = NULL;
7060 "Storing our address `%s' in peerstore until %s!\n",
7061 ale->address,
7064 address_uri);
7065 /* NOTE: #GNUNET_HELLO_builder_add_address() answers GNUNET_NO for an
7066 address that is already in the builder, and on every call after the
7067 first one for a given address that is exactly what happens: nothing
7068 ever removes an address from @a GST_my_hello except
7069 #handle_del_address(). This function is the *refresh* cycle --
7070 #peerstore_store_own_cb() re-arms it at a quarter of the address'
7071 expiration -- so bailing out on GNUNET_NO here stopped the refresh
7072 after precisely one round. Our own HELLO then expired
7073 (#GNUNET_HELLO_ADDRESS_EXPIRATION, twelve hours) and was never
7074 renewed: peers can no longer learn how to reach us, and a link that
7075 drops after that never comes back. Only GNUNET_SYSERR -- a malformed
7076 URI, which retrying cannot fix -- is a reason not to store. */
7077 if (GNUNET_SYSERR == add_success)
7078 {
7080 "Not storing our address `%s': not a valid HELLO URI\n",
7081 address_uri);
7082 GNUNET_free (address_uri);
7083 return;
7084 }
7085 GNUNET_log ((GNUNET_NO == add_success) ?
7087 "%s our address `%s' in PEERSTORE\n",
7088 (GNUNET_NO == add_success) ? "Refreshing" : "Storing",
7089 address_uri);
7090 // FIXME hello_mono_time used here?? What about expiration in ale?
7091 pils_sign_address (ale,
7093 // TODO keep track of op and potentially cancel/clean
7094 GNUNET_free (address_uri);
7095}

References AddressListEntry::address, GNUNET_asprintf(), GNUNET_assert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_INFO, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_HELLO_address_to_prefix(), GNUNET_HELLO_builder_add_address(), GNUNET_log, GNUNET_NO, GNUNET_PILS_get_identity(), GNUNET_SCHEDULER_add_delayed(), GNUNET_STRINGS_absolute_time_to_string(), GNUNET_SYSERR, GNUNET_TIME_STD_BACKOFF, GNUNET_TIME_UNIT_ZERO, GNUNET_YES, GST_my_hello, hello_mono_time, in_shutdown, pils, AddressListEntry::pils_backoff, pils_sign_address(), prefix, AddressListEntry::st, and store_pi().

Referenced by create_address_entry(), peerstore_store_own_cb(), pils_sign_address(), shc_cont(), and store_pi().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ shc_cont()

static void shc_cont ( void *  cls,
int  success 
)
static

Definition at line 6778 of file gnunet-service-transport.c.

6779{
6780 struct PilsAddressSignContext *pc = cls;
6781
6782 GNUNET_assert (NULL == pc->req);
6783 /* The store completed; the handle is dead and must not be cancelled
6784 later by #free_address_list_entry(). */
6785 pc->ale->shc = NULL;
6786 pc->ale->pc = NULL;
6787 if (GNUNET_OK != success)
6788 {
6790 "Failed to store our address `%s' with peerstore\n",
6791 pc->ale->address);
6792 if (NULL == pc->ale->st)
6793 {
6795 &store_pi,
6796 pc->ale);
6797 }
6798 }
6799 GNUNET_free (pc);
6800}

References GNUNET_assert, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_log, GNUNET_OK, GNUNET_SCHEDULER_add_delayed(), GNUNET_TIME_UNIT_SECONDS, pc, and store_pi().

Referenced by pils_sign_hello_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pils_sign_hello_cb()

static void pils_sign_hello_cb ( void *  cls,
const struct GNUNET_PeerIdentity pid,
const struct GNUNET_CRYPTO_EddsaSignature sig 
)
static

Get HELLO signature and create message to store in PEERSTORE.

Definition at line 6807 of file gnunet-service-transport.c.

6810{
6811 struct PilsAddressSignContext *pc = cls;
6812 struct GNUNET_MQ_Envelope *env;
6813 const struct GNUNET_MessageHeader *msg;
6814
6815 pc->req->op = NULL;
6818 pc->req);
6819 GNUNET_free (pc->req);
6820 pc->req = NULL;
6823 pid,
6824 sig,
6825 pc->et);
6828 "store_pi 1\n");
6830 msg,
6831 shc_cont,
6832 pc);
6833 GNUNET_free (env);
6834}

References env, GNUNET_CONTAINER_DLL_remove, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_HELLO_builder_to_env(), GNUNET_log, GNUNET_MQ_env_get_msg(), GNUNET_PEERSTORE_hello_add(), GST_my_hello, msg, pc, peerstore, pils_requests_head, pils_requests_tail, and shc_cont().

Referenced by peerstore_store_own_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ peerstore_store_own_cb()

static void peerstore_store_own_cb ( void *  cls,
int  success 
)
static

Function called when peerstore is done storing our address.

Parameters
clsa struct AddressListEntry
successGNUNET_YES if peerstore was successful

Definition at line 6844 of file gnunet-service-transport.c.

6845{
6846 struct PilsAddressSignContext *pc = cls;
6847
6848 pc->ale->sc = NULL;
6849 if (GNUNET_YES != success)
6851 "Failed to store our own address `%s' in peerstore!\n",
6852 pc->ale->address);
6853 else
6855 "Successfully stored our own address `%s' in peerstore!\n",
6856 pc->ale->address);
6857 /* refresh period is 1/4 of expiration time, that should be plenty
6858 without being excessive. */
6859 if (NULL == pc->ale->st)
6860 {
6861 /* @e expiration comes straight off the wire in ADD_ADDRESS and is not
6862 validated anywhere, so a communicator reporting a very short (or
6863 zero) lifetime would have us re-sign the HELLO and store it again on
6864 the next scheduler pass, forever. That is an EdDSA signature and a
6865 PEERSTORE round trip per iteration. */
6866 pc->ale->st =
6870 GNUNET_TIME_relative_divide (pc->ale->expiration,
6871 4ULL)),
6872 &store_pi,
6873 pc->ale);
6874 }
6875
6876 /* Now we have to update our HELLO! */
6878 pc->req = GNUNET_new (struct PilsRequest);
6881 pc->req);
6882 pc->req->op = GNUNET_PILS_sign_hello (pils,
6884 pc->et,
6886 pc);
6887}

References GNUNET_CONTAINER_DLL_insert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_HELLO_ADDRESS_EXPIRATION, GNUNET_log, GNUNET_new, GNUNET_PILS_sign_hello(), GNUNET_SCHEDULER_add_delayed(), GNUNET_TIME_relative_divide(), GNUNET_TIME_relative_max(), GNUNET_TIME_relative_to_absolute(), GNUNET_YES, GST_my_hello, MIN_ADDRESS_REFRESH_INTERVAL, pc, pils, pils_requests_head, pils_requests_tail, pils_sign_hello_cb(), and store_pi().

Referenced by store_signed_address().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ store_signed_address()

static void store_signed_address ( struct PilsAddressSignContext pc,
const struct GNUNET_PeerIdentity pid,
const struct GNUNET_CRYPTO_EddsaSignature sig 
)
static

Turn the signed address into a HELLO URI and hand it to PEERSTORE.

Parameters
pcthe sign-and-store chain this belongs to
pidour peer identity
sigsignature over the address

Definition at line 6898 of file gnunet-service-transport.c.

6901{
6902 char *sig_str;
6903 void *result;
6904 size_t result_size;
6905
6906 sig_str = NULL;
6907 (void) GNUNET_STRINGS_base64_encode (sig, sizeof(*sig), &sig_str);
6908 result_size =
6909 1 + GNUNET_asprintf (
6910 (char **) &result,
6911 "%s;%llu;%u;%s",
6912 sig_str,
6913 (unsigned long long) pc->et.abs_value_us,
6914 (unsigned int) pc->ale->nt,
6915 pc->ale->address);
6916 GNUNET_free (sig_str);
6917
6919 "Build our HELLO URI `%s'\n",
6920 (char*) result);
6921
6922 GNUNET_free (pc->ale->signed_address);
6923 pc->ale->signed_address = result;
6924 pc->ale->signed_address_len = result_size;
6926
6927 expiration = GNUNET_TIME_relative_to_absolute (pc->ale->expiration);
6929 "transport",
6930 pid,
6932 result,
6933 result_size,
6934 expiration,
6937 pc);
6938}

References expiration, GNUNET_asprintf(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_log, GNUNET_PEERSTORE_store(), GNUNET_PEERSTORE_STOREOPTION_MULTIPLE, GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY, GNUNET_STRINGS_base64_encode(), GNUNET_TIME_relative_to_absolute(), pc, peerstore, peerstore_store_own_cb(), and result.

Referenced by pils_sign_address().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pils_sign_address()

void pils_sign_address ( struct AddressListEntry ale,
struct GNUNET_TIME_Absolute  mono_time 
)

Build address record by signing raw information with private key of the peer identity.

Parameters
handlehandle to the PILS service
addresstext address at communicator to sign
ntnetwork type of address
mono_timemonotonic time at which address was valid
cbcallback called once the signature is ready
cb_clsclosure to the cb callback
Returns
handle to the operation, NULL on error

Definition at line 6977 of file gnunet-service-transport.c.

6980{
6981 struct SignedAddress sa;
6982 struct PilsAddressSignContext *pc;
6984 const struct GNUNET_PeerIdentity *my_identity;
6985
6986 sa.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_ADDRESS);
6987 sa.purpose.size = htonl (sizeof(sa));
6988 sa.mono_time = GNUNET_TIME_absolute_hton (mono_time);
6989 GNUNET_CRYPTO_hash (ale->address, strlen (ale->address), &sa.addr_hash);
6990 /* Only ever one chain per entry: the previous one (if any) still holds a
6991 pointer to @a ale and must be torn down first. */
6994 if ((NULL == my_identity) ||
6995 (GNUNET_OK != sign_by_my_identity (&sa.purpose, &sig)))
6996 {
6997 /* Nothing else re-arms @e st: #store_pi() cleared it before calling us,
6998 and the only other thing that sets it is #peerstore_store_own_cb(),
6999 which is on the far side of the store we just failed to start. So a
7000 single failure to sign used to end the refresh cycle for this address
7001 for the rest of the process' life. */
7002 if (NULL == ale->st)
7003 {
7006 &store_pi,
7007 ale);
7008 }
7009 return;
7010 }
7012 pc->ale = ale;
7013 pc->et = mono_time;
7014 ale->pc = pc;
7016}

References AddressListEntry::address, cancel_address_store(), GNUNET_CRYPTO_hash(), GNUNET_new, GNUNET_OK, GNUNET_PILS_get_identity(), GNUNET_SCHEDULER_add_delayed(), GNUNET_SIGNATURE_PURPOSE_TRANSPORT_ADDRESS, GNUNET_TIME_absolute_hton(), GNUNET_TIME_STD_BACKOFF, SignedAddress::mono_time, my_identity, pc, AddressListEntry::pc, pils, AddressListEntry::pils_backoff, GNUNET_CRYPTO_SignaturePurpose::purpose, SignedAddress::purpose, sign_by_my_identity(), GNUNET_CRYPTO_SignaturePurpose::size, AddressListEntry::st, store_pi(), and store_signed_address().

Referenced by store_pi().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ create_address_entry()

static struct AddressListEntry * create_address_entry ( struct TransportClient tc,
struct GNUNET_TIME_Relative  expiration,
enum GNUNET_NetworkType  nt,
const char *  address,
uint32_t  aid,
size_t  slen 
)
static

Definition at line 7099 of file gnunet-service-transport.c.

7105{
7106 struct AddressListEntry *ale;
7107 char *address_without_port;
7108
7109 ale = GNUNET_malloc (sizeof(struct AddressListEntry) + slen);
7110 ale->tc = tc;
7111 ale->address = (const char *) &ale[1];
7112 ale->expiration = expiration;
7113 ale->aid = aid;
7114 ale->nt = nt;
7115 memcpy (&ale[1], address, slen);
7116 address_without_port = get_address_without_port (ale->address);
7118 "Is this %s a local address (%s)\n",
7119 (NULL == address_without_port) ? "<unparsable>"
7120 : address_without_port,
7121 ale->address);
7122 if ((NULL == address_without_port) ||
7123 (0 != strcmp ("127.0.0.1", address_without_port)))
7124 {
7125 if (NULL != ale->st)
7126 {
7128 }
7129 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
7130 }
7131 GNUNET_free (address_without_port);
7132
7133 return ale;
7134}

References address, AddressListEntry::address, AddressListEntry::aid, expiration, AddressListEntry::expiration, get_address_without_port(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_log, GNUNET_malloc, GNUNET_SCHEDULER_add_now(), GNUNET_SCHEDULER_cancel(), nt, AddressListEntry::nt, AddressListEntry::st, store_pi(), tc, and AddressListEntry::tc.

Referenced by handle_add_address().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ feed_addresses_to_pils()

static void feed_addresses_to_pils ( void *  cls)
static

Definition at line 7138 of file gnunet-service-transport.c.

7139{
7140
7142 "Feeding addresses to PILS\n");
7143 pils_feed_task = NULL;
7144
7146 GST_my_hello);
7147}

References GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_PILS_feed_addresses(), GST_my_hello, pils, and pils_feed_task.

Referenced by handle_add_address(), and handle_del_address().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_add_address()

static void handle_add_address ( void *  cls,
const struct GNUNET_TRANSPORT_AddAddressMessage aam 
)
static

Address of our peer added.

Process the request.

Parameters
clsthe client
aamthe send message that was sent

Definition at line 7157 of file gnunet-service-transport.c.

7159{
7160 struct TransportClient *tc = cls;
7161 struct AddressListEntry *ale;
7162 size_t slen;
7163 char *address;
7164
7165 /* 0-termination of &aam[1] was checked in #check_add_address */
7167 "Communicator added address `%s'!\n",
7168 (const char *) &aam[1]);
7169 slen = ntohs (aam->header.size) - sizeof(*aam);
7170 address = GNUNET_malloc (slen);
7171 memcpy (address, &aam[1], slen);
7172 ale = create_address_entry (tc,
7174 ntohl (aam->nt),
7175 address,
7176 aam->aid,
7177 slen);
7178 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
7179 tc->details.communicator.addr_tail,
7180 ale);
7181 {
7182 for (struct AddressListEntry *iter = tc->details.communicator.addr_head;
7183 NULL != iter;
7184 iter = iter->next)
7185 {
7186 char *address_uri;
7187 const char *dash = strchr (iter->address, '-');
7188 char *prefix = GNUNET_HELLO_address_to_prefix (iter->address);
7189 GNUNET_assert (NULL != dash);
7190 dash++;
7191 GNUNET_asprintf (&address_uri,
7192 "%s://%s",
7193 prefix,
7194 dash);
7197 GNUNET_free (address_uri);
7198 }
7199 if (NULL != pils_feed_task)
7203 NULL);
7204 }
7207}

References address, GNUNET_TRANSPORT_AddAddressMessage::aid, create_address_entry(), GNUNET_TRANSPORT_AddAddressMessage::expiration, feed_addresses_to_pils(), GNUNET_asprintf(), GNUNET_assert, GNUNET_CONTAINER_DLL_insert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_HELLO_address_to_prefix(), GNUNET_HELLO_builder_add_address(), GNUNET_log, GNUNET_malloc, GNUNET_SCHEDULER_add_delayed(), GNUNET_SCHEDULER_cancel(), GNUNET_SERVICE_client_continue(), GNUNET_TIME_relative_ntoh(), GST_my_hello, GNUNET_TRANSPORT_AddAddressMessage::header, GNUNET_TRANSPORT_AddAddressMessage::nt, PILS_FEED_ADDRESSES_DELAY, pils_feed_task, prefix, GNUNET_MessageHeader::size, and tc.

Here is the call graph for this function:

◆ handle_del_address()

static void handle_del_address ( void *  cls,
const struct GNUNET_TRANSPORT_DelAddressMessage dam 
)
static

Address of our peer deleted.

Process the request.

Parameters
clsthe client
damthe send message that was sent

Definition at line 7217 of file gnunet-service-transport.c.

7219{
7220 struct TransportClient *tc = cls;
7221 struct AddressListEntry *alen;
7222
7223 if (CT_COMMUNICATOR != tc->type)
7224 {
7225 GNUNET_break (0);
7227 return;
7228 }
7229 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
7230 NULL != ale;
7231 ale = alen)
7232 {
7233 alen = ale->next;
7234 if (dam->aid != ale->aid)
7235 continue;
7236 GNUNET_assert (ale->tc == tc);
7238 "Communicator deleted address `%s'!\n",
7239 ale->address);
7241 ale->address);
7242 if (NULL != pils_feed_task)
7246 NULL);
7249 return;
7250 }
7252 "Communicator removed address we did not even have.\n");
7254 // GNUNET_SERVICE_client_drop (tc->client);
7255}

References GNUNET_TRANSPORT_DelAddressMessage::aid, CT_COMMUNICATOR, feed_addresses_to_pils(), free_address_list_entry(), GNUNET_assert, GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_WARNING, GNUNET_HELLO_builder_del_address(), GNUNET_log, GNUNET_SCHEDULER_add_delayed(), GNUNET_SCHEDULER_cancel(), GNUNET_SERVICE_client_continue(), GNUNET_SERVICE_client_drop(), GST_my_hello, AddressListEntry::next, PILS_FEED_ADDRESSES_DELAY, pils_feed_task, and tc.

Here is the call graph for this function:

◆ demultiplex_with_cmc()

static void demultiplex_with_cmc ( struct CommunicatorMessageContext cmc)
static

Given an inbound message msg from a communicator cmc, demultiplex it based on the type calling the right handler.

Parameters
cmccontext for demultiplexing
msgmessage to demultiplex

Definition at line 12173 of file gnunet-service-transport.c.

12174{
12176 { GNUNET_MQ_hd_var_size (fragment_box,
12179 cmc),
12180 GNUNET_MQ_hd_var_size (reliability_box,
12183 cmc),
12184 GNUNET_MQ_hd_var_size (reliability_ack,
12187 cmc),
12188 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
12191 cmc),
12192 GNUNET_MQ_hd_var_size (dv_learn,
12195 cmc),
12196 GNUNET_MQ_hd_var_size (dv_box,
12198 struct TransportDVBoxMessage,
12199 cmc),
12200 GNUNET_MQ_hd_var_size (flow_control,
12203 cmc),
12205 validation_challenge,
12208 cmc),
12210 validation_response,
12213 cmc),
12215 int ret;
12216 const struct GNUNET_MessageHeader *msg = cmc->mh;
12217
12219 "Handling message of type %u with %u bytes\n",
12220 (unsigned int) ntohs (msg->type),
12221 (unsigned int) ntohs (msg->size));
12222 /* @a handlers only covers the encapsulations *we* add; anything else is a
12223 payload for CORE and leaves through #handle_raw_message() below. So
12224 #GNUNET_NO is the common case here -- one per delivered CORE message --
12225 and not something to log about, which is why this is the "try" variant. */
12227 if (GNUNET_SYSERR == ret)
12228 {
12229 /* @a msg is the message a *remote peer* sent us: #handle_incoming_msg()
12230 points @e mh into the payload of the
12231 #GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG the communicator
12232 delivered, and every other caller unwraps it from remote traffic as
12233 well. So failing a check here is that peer's protocol violation, and
12234 it says nothing at all about the communicator that carried it.
12235
12236 Dropping the client therefore punishes the wrong party, and it
12237 punishes it hard: #GNUNET_SERVICE_client_drop() disconnects the
12238 communicator *process*, which takes down every queue it owns and thus
12239 every neighbour reachable through it. One malformed DV box on a
12240 shared UDP communicator disconnects every peer we have on it, CORE
12241 tears the sessions down, and the key exchanges that would rebuild
12242 them have to wait for the communicator to come back and revalidate.
12243 Since the offending bytes arrive from the network, any peer can do
12244 this to us at will, repeatedly.
12245
12246 Drop the message and keep the communicator: resume it exactly as the
12247 success path does, so it still gets its flow-control ACK and its
12248 GNUNET_SERVICE_client_continue(). */
12249 GNUNET_break_op (0);
12251 "# malformed messages discarded",
12252 1,
12253 GNUNET_NO);
12255 return;
12256 }
12257 if (GNUNET_NO == ret)
12258 {
12259 /* unencapsulated 'raw' message */
12260 handle_raw_message (cmc, msg);
12261 }
12262}

References finish_cmc_handling_with_continue(), GNUNET_break_op, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE, GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE, GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION, GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX, GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN, GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL, GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT, GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK, GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX, GNUNET_MQ_handler_end, GNUNET_MQ_hd_fixed_size, GNUNET_MQ_hd_var_size, GNUNET_MQ_try_handle_message(), GNUNET_NO, GNUNET_STATISTICS_update(), GNUNET_SYSERR, GNUNET_YES, GST_stats, handle_raw_message(), handlers, CommunicatorMessageContext::mh, msg, ret, GNUNET_MessageHeader::size, and GNUNET_MessageHeader::type.

Referenced by backtalker_monotime_cb(), decaps_dv_box_cont(), handle_fragment_box(), handle_incoming_msg(), and handle_reliability_box().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ core_env_sent_cb()

static void core_env_sent_cb ( void *  cls)
static

Function called when we are done giving a message of a certain size to CORE and should thus decrement the number of bytes of RAM reserved for that peer's MQ.

Parameters
clsa struct CoreSentContext

Definition at line 7277 of file gnunet-service-transport.c.

7278{
7279 struct CoreSentContext *ctx = cls;
7280 struct VirtualLink *vl = ctx->vl;
7281
7282 if (NULL == vl)
7283 {
7284 /* lost the link in the meantime, ignore */
7285 GNUNET_free (ctx);
7286 return;
7287 }
7290 vl->incoming_fc_window_size_ram -= ctx->size;
7291 vl->incoming_fc_window_size_used += ctx->isize;
7293 GNUNET_free (ctx);
7294}

References consider_sending_fc(), VirtualLink::csc_head, VirtualLink::csc_tail, ctx, GNUNET_assert, GNUNET_CONTAINER_DLL_remove, GNUNET_free, VirtualLink::incoming_fc_window_size_ram, and VirtualLink::incoming_fc_window_size_used.

Referenced by finish_handling_raw_message().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ core_fc_stalled()

static void core_fc_stalled ( void *  cls)
static

CORE never returned the flow control credit for the messages we handed it for cls, so the communicators that delivered them are still waiting on us.

A communicator is shared by every peer it talks to, so one stuck link would otherwise take all of them down with it – and nothing else ever unblocks this: handle_client_recv_ok() is the only thing that drains cmc_head, and it needs the RECV_OK that is not coming.

Give up on the parked messages and start the window over. Note that a late RECV_OK can then push core_recv_window above RECV_WINDOW_SIZE; that merely weakens flow control for a while, which is what the existing unconditional ‘+= delta’ does anyway.

The bytes we drop here need no accounting: the next FLOW_CONTROL exchange derives incoming_fc_window_size_loss from the difference between what the sender says it sent and what we counted as used, so the peer's window is corrected automatically.

Parameters
clsthe struct VirtualLink whose CORE window is stuck

Definition at line 7319 of file gnunet-service-transport.c.

7320{
7321 struct VirtualLink *vl = cls;
7322 struct CommunicatorMessageContext *cmc;
7323
7324 vl->core_fc_stall_task = NULL;
7326 "CORE did not acknowledge messages from %s within %s; "
7327 "releasing the flow control credit anyway\n",
7328 GNUNET_i2s (&vl->target),
7330 GNUNET_YES));
7332 "# CORE flow control stalls",
7333 1,
7334 GNUNET_NO);
7335 while (NULL != (cmc = vl->cmc_tail))
7336 release_stalled_cmc (vl, cmc);
7339}

References VirtualLink::cmc_tail, consider_sending_fc(), VirtualLink::core_fc_stall_task, CORE_FC_STALL_TIMEOUT, VirtualLink::core_recv_window, GNUNET_ERROR_TYPE_WARNING, GNUNET_i2s(), GNUNET_log, GNUNET_NO, GNUNET_STATISTICS_update(), GNUNET_STRINGS_relative_time_to_string(), GNUNET_YES, GST_stats, RECV_WINDOW_SIZE, release_stalled_cmc(), and VirtualLink::target.

Referenced by finish_handling_raw_message().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ finish_handling_raw_message()

static void finish_handling_raw_message ( struct VirtualLink vl,
const struct GNUNET_MessageHeader mh,
struct CommunicatorMessageContext cmc,
unsigned int  free_cmc 
)
static

Definition at line 7343 of file gnunet-service-transport.c.

7347{
7348 uint16_t size = ntohs (mh->size);
7349 int have_core;
7350
7351 if (vl->incoming_fc_window_size_ram > UINT_MAX - size)
7352 {
7354 "# CORE messages dropped (FC arithmetic overflow)",
7355 1,
7356 GNUNET_NO);
7358 "CORE messages of type %u with %u bytes dropped (FC arithmetic overflow)\n",
7359 (unsigned int) ntohs (mh->type),
7360 (unsigned int) ntohs (mh->size));
7361 if (GNUNET_YES == free_cmc)
7363 return;
7364 }
7366 {
7368 "# CORE messages dropped (FC window overflow)",
7369 1,
7370 GNUNET_NO);
7372 "CORE messages of type %u with %u bytes dropped (FC window overflow)\n",
7373 (unsigned int) ntohs (mh->type),
7374 (unsigned int) ntohs (mh->size));
7375 if (GNUNET_YES == free_cmc)
7377 return;
7378 }
7379
7380 /* Forward to all CORE clients */
7381 have_core = GNUNET_NO;
7382 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
7383 {
7384 struct GNUNET_MQ_Envelope *env;
7385 struct InboundMessage *im;
7386 struct CoreSentContext *ctx;
7387
7388 if (CT_CORE != tc->type)
7389 continue;
7392 ctx = GNUNET_new (struct CoreSentContext);
7393 ctx->vl = vl;
7394 ctx->size = size;
7395 ctx->isize = (GNUNET_NO == have_core) ? size : 0;
7396 have_core = GNUNET_YES;
7399 im->peer = cmc->im.sender;
7400 memcpy (&im[1], mh, size);
7401 GNUNET_MQ_send (tc->mq, env);
7403 }
7404 if (GNUNET_NO == have_core)
7405 {
7407 "Dropped message to CORE: no CORE client connected!\n");
7408 /* Nevertheless, count window as used, as it is from the
7409 perspective of the other peer! */
7411 /* TODO-M1 */
7413 "Dropped message of type %u with %u bytes to CORE: no CORE client connected!\n",
7414 (unsigned int) ntohs (mh->type),
7415 (unsigned int) ntohs (mh->size));
7416 if (GNUNET_YES == free_cmc)
7418 return;
7419 }
7421 "Delivered message from %s of type %u to CORE recv window %d\n",
7422 GNUNET_i2s (&cmc->im.sender),
7423 ntohs (mh->type),
7425 if (vl->core_recv_window > 0)
7426 {
7427 if (GNUNET_YES == free_cmc)
7429 return;
7430 }
7431 /* CORE ran out of receive window for *this* link. Withhold the
7432 per-message ACK -- that is what expresses the backpressure -- but
7433 resume the client immediately. The client is the communicator
7434 *process*, which carries every peer we reach through it, and a
7435 communicator we stop reading from does not stop receiving: it starts
7436 discarding, see "transport is too slow" in
7437 #GNUNET_TRANSPORT_communicator_receive(). Discarding is precisely
7438 what we cannot afford here, because among the messages dropped are
7439 the ones CORE needs in order to reopen the window it is waiting on. */
7440 if (GNUNET_YES == free_cmc)
7441 {
7442 resume_cmc_client (cmc);
7444 vl->cmc_count++;
7445 /* Nothing stalls the producer any more, so bound the list ourselves. */
7446 while (MAX_STALLED_CMCS < vl->cmc_count)
7448 /* ... and do not withhold the ACKs forever: see #core_fc_stalled(). */
7449 if (NULL == vl->core_fc_stall_task)
7453 vl);
7454 }
7455}

References VirtualLink::available_fc_window_size, clients_head, VirtualLink::cmc_count, VirtualLink::cmc_head, VirtualLink::cmc_tail, core_env_sent_cb(), VirtualLink::core_fc_stall_task, CORE_FC_STALL_TIMEOUT, core_fc_stalled(), VirtualLink::core_recv_window, VirtualLink::csc_head, VirtualLink::csc_tail, CT_CORE, ctx, env, finish_cmc_handling_with_continue(), GNUNET_CONTAINER_DLL_insert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_WARNING, GNUNET_i2s(), GNUNET_log, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV, GNUNET_MQ_msg_extra, GNUNET_MQ_notify_sent(), GNUNET_MQ_send(), GNUNET_new, GNUNET_NO, GNUNET_SCHEDULER_add_delayed(), GNUNET_STATISTICS_update(), GNUNET_YES, GST_stats, CommunicatorMessageContext::im, VirtualLink::incoming_fc_window_size_ram, VirtualLink::incoming_fc_window_size_used, mh, InboundMessage::peer, release_stalled_cmc(), resume_cmc_client(), GNUNET_TRANSPORT_IncomingMessage::sender, size, tc, and CoreSentContext::vl.

Referenced by handle_raw_message(), and send_msg_from_cache().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_raw_message()

static void handle_raw_message ( void *  cls,
const struct GNUNET_MessageHeader mh 
)
static

Communicator gave us an unencapsulated message to pass as-is to CORE.

Process the request.

Parameters
clsa struct CommunicatorMessageContext (must call finish_cmc_handling() when done)
mhthe message that was received

Definition at line 7467 of file gnunet-service-transport.c.

7468{
7469 struct CommunicatorMessageContext *cmc = cls;
7470 // struct CommunicatorMessageContext *cmc_copy =
7471 // GNUNET_new (struct CommunicatorMessageContext);
7472 struct GNUNET_MessageHeader *mh_copy;
7473 struct RingBufferEntry *rbe;
7474 struct VirtualLink *vl;
7475 uint16_t size = ntohs (mh->size);
7476
7478 "Handling raw message of type %u with %u bytes\n",
7479 (unsigned int) ntohs (mh->type),
7480 (unsigned int) ntohs (mh->size));
7481
7482 if ((size > UINT16_MAX - sizeof(struct InboundMessage)) ||
7483 (size < sizeof(struct GNUNET_MessageHeader)))
7484 {
7485 /* @a mh was unwrapped from what a *remote peer* sent us, so a bad size
7486 is that peer's protocol violation and says nothing about the
7487 communicator that carried it. Dropping the client here disconnects
7488 the communicator process and with it every neighbour reachable
7489 through it -- see the rationale in #demultiplex_with_cmc(). */
7490 GNUNET_break_op (0);
7492 "# CORE messages dropped (bad size)",
7493 1,
7494 GNUNET_NO);
7495 finish_cmc_handling (cmc);
7496 return;
7497 }
7498 vl = lookup_virtual_link (&cmc->im.sender);
7499 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
7500 {
7501 /* FIXME: sender is giving us messages for CORE but we don't have
7502 the link up yet! I *suspect* this can happen right now (i.e.
7503 sender has verified us, but we didn't verify sender), but if
7504 we pass this on, CORE would be confused (link down, messages
7505 arrive). We should investigate more if this happens often,
7506 or in a persistent manner, and possibly do "something" about
7507 it. Thus logging as error for now. */
7508
7509 mh_copy = GNUNET_malloc (size);
7510 rbe = GNUNET_new (struct RingBufferEntry);
7511 rbe->cmc = cmc;
7512 /*cmc_copy->tc = cmc->tc;
7513 cmc_copy->im = cmc->im;*/
7514 GNUNET_memcpy (mh_copy, mh, size);
7515
7516 rbe->mh = mh_copy;
7517
7519 {
7520 struct RingBufferEntry *rbe_old = ring_buffer[ring_buffer_head];
7521 GNUNET_free (rbe_old->cmc);
7522 GNUNET_free (rbe_old->mh);
7523 GNUNET_free (rbe_old);
7524 }
7525 ring_buffer[ring_buffer_head] = rbe;// cmc_copy;
7526 // cmc_copy->mh = (const struct GNUNET_MessageHeader *) mh_copy;
7527 cmc->mh = (const struct GNUNET_MessageHeader *) mh_copy;
7529 "Storing message for %s and type %u (%u) in ring buffer head %u is full %u\n",
7530 GNUNET_i2s (&cmc->im.sender),
7531 (unsigned int) ntohs (mh->type),
7532 (unsigned int) ntohs (mh_copy->type),
7536 {
7537 ring_buffer_head = 0;
7539 }
7540 else
7542
7544 "%u items stored in ring buffer\n",
7547
7548 /*GNUNET_break_op (0);
7549 GNUNET_STATISTICS_update (GST_stats,
7550 "# CORE messages dropped (virtual link still down)",
7551 1,
7552 GNUNET_NO);
7553
7554 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7555 "CORE messages of type %u with %u bytes dropped (virtual link still down)\n",
7556 (unsigned int) ntohs (mh->type),
7557 (unsigned int) ntohs (mh->size));
7558 finish_cmc_handling (cmc);*/
7559 /* @a cmc lives on in the ring buffer; #send_cmc_ack() and
7560 #resume_cmc_client() have recorded that they ran, so replaying it
7561 from #send_msg_from_cache() cannot ACK or continue a second time. */
7563 return;
7564 }
7566}

References RingBufferEntry::cmc, VirtualLink::confirmed, finish_cmc_handling(), finish_cmc_handling_with_continue(), finish_handling_raw_message(), GNUNET_break_op, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_i2s(), GNUNET_log, GNUNET_malloc, GNUNET_memcpy, GNUNET_new, GNUNET_NO, GNUNET_STATISTICS_update(), GNUNET_YES, GST_stats, CommunicatorMessageContext::im, is_ring_buffer_full, lookup_virtual_link(), mh, CommunicatorMessageContext::mh, RingBufferEntry::mh, ring_buffer, ring_buffer_head, RING_BUFFER_SIZE, GNUNET_TRANSPORT_IncomingMessage::sender, size, and GNUNET_MessageHeader::type.

Referenced by demultiplex_with_cmc().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_fragment_box()

static int check_fragment_box ( void *  cls,
const struct TransportFragmentBoxMessage fb 
)
static

Communicator gave us a fragment box.

Check the message.

Parameters
clsa struct CommunicatorMessageContext
fbthe send message that was sent
Returns
GNUNET_YES if message is well-formed

Definition at line 7577 of file gnunet-service-transport.c.

7578{
7579 uint16_t size = ntohs (fb->header.size);
7580 uint16_t bsize = size - sizeof(*fb);
7581
7582 (void) cls;
7583 if (0 == bsize)
7584 {
7585 GNUNET_break_op (0);
7586 return GNUNET_SYSERR;
7587 }
7588 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
7589 {
7590 GNUNET_break_op (0);
7591 return GNUNET_SYSERR;
7592 }
7593 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
7594 {
7595 GNUNET_break_op (0);
7596 return GNUNET_SYSERR;
7597 }
7598 return GNUNET_YES;
7599}

References bsize, TransportFragmentBoxMessage::frag_off, GNUNET_break_op, GNUNET_SYSERR, GNUNET_YES, TransportFragmentBoxMessage::header, TransportFragmentBoxMessage::msg_size, GNUNET_MessageHeader::size, and size.

◆ destroy_ack_cummulator()

static void destroy_ack_cummulator ( void *  cls)
static

Clean up an idle cumulative acknowledgement data structure.

Parameters
clsa struct AcknowledgementCummulator *

Definition at line 7608 of file gnunet-service-transport.c.

7609{
7610 struct AcknowledgementCummulator *ac = cls;
7611
7612 ac->task = NULL;
7613 GNUNET_assert (0 == ac->num_acks);
7615 GNUNET_YES ==
7617 GNUNET_free (ac);
7618}

References ack_cummulators, GNUNET_assert, GNUNET_CONTAINER_multipeermap_remove(), GNUNET_free, GNUNET_YES, AcknowledgementCummulator::num_acks, AcknowledgementCummulator::target, and AcknowledgementCummulator::task.

Referenced by transmit_cummulative_ack_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ transmit_cummulative_ack_cb()

static void transmit_cummulative_ack_cb ( void *  cls)
static

Do the transmission of a cumulative acknowledgement now.

Parameters
clsa struct AcknowledgementCummulator *

Definition at line 7627 of file gnunet-service-transport.c.

7628{
7629 struct Neighbour *n;
7630 struct VirtualLink *vl;
7631 struct AcknowledgementCummulator *ac = cls;
7632 char buf[sizeof(struct TransportReliabilityAckMessage)
7633 + ac->num_acks
7635 struct TransportReliabilityAckMessage *ack =
7636 (struct TransportReliabilityAckMessage *) buf;
7638
7639 ac->task = NULL;
7641 "Sending ACK with %u components to %s\n",
7642 ac->num_acks,
7643 GNUNET_i2s (&ac->target));
7644 GNUNET_assert (0 < ac->num_acks);
7646 ack->header.size =
7647 htons (sizeof(*ack)
7648 + ac->num_acks * sizeof(struct TransportCummulativeAckPayloadP));
7649 ack->ack_counter = htonl (ac->ack_counter += ac->num_acks);
7650 ap = (struct TransportCummulativeAckPayloadP *) &ack[1];
7651 for (unsigned int i = 0; i < ac->num_acks; i++)
7652 {
7653 ap[i].ack_uuid = ac->ack_uuids[i].ack_uuid;
7656 }
7657 /*route_control_message_without_fc (
7658 &ac->target,
7659 &ack->header,
7660 RMO_DV_ALLOWED);*/
7661 vl = lookup_virtual_link (&ac->target);
7662 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
7663 {
7665 vl,
7666 &ack->header,
7668 }
7669 else
7670 {
7671 /* Use route via neighbour */
7672 n = lookup_neighbour (&ac->target);
7673 if (NULL != n)
7675 n,
7676 &ack->header,
7677 RMO_NONE);
7678 }
7679 ac->num_acks = 0;
7680 /* The deadline belonged to the batch we just sent. #cummulative_ack()
7681 only ever lowers it (GNUNET_TIME_absolute_min), so leaving it behind
7682 means every later ACK is armed with GNUNET_SCHEDULER_add_at() on a time
7683 that has already passed: the task fires on the next scheduler pass and
7684 the batching this whole structure exists for is gone for good -- one
7685 ACK message per received message, for the rest of the process' life. */
7689 ac);
7690}

References TransportReliabilityAckMessage::ack_counter, AcknowledgementCummulator::ack_counter, ACK_CUMMULATOR_TIMEOUT, TransportCummulativeAckPayloadP::ack_delay, TransportCummulativeAckPayloadP::ack_uuid, TransportCummulativeAckPayload::ack_uuid, AcknowledgementCummulator::ack_uuids, VirtualLink::confirmed, destroy_ack_cummulator(), GNUNET_ALIGN, GNUNET_assert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK, GNUNET_SCHEDULER_add_delayed(), GNUNET_TIME_absolute_get_duration(), GNUNET_TIME_relative_hton(), GNUNET_TIME_UNIT_FOREVER_ABS, GNUNET_YES, TransportReliabilityAckMessage::header, lookup_neighbour(), lookup_virtual_link(), AcknowledgementCummulator::min_transmission_time, AcknowledgementCummulator::num_acks, TransportCummulativeAckPayload::receive_time, RMO_DV_ALLOWED, RMO_NONE, route_control_message_without_fc(), route_via_neighbour(), GNUNET_MessageHeader::size, AcknowledgementCummulator::target, AcknowledgementCummulator::task, and GNUNET_MessageHeader::type.

Referenced by cummulative_ack().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cummulative_ack()

static void cummulative_ack ( const struct GNUNET_PeerIdentity pid,
const struct AcknowledgementUUIDP ack_uuid,
struct GNUNET_TIME_Absolute  max_delay 
)
static

Transmit an acknowledgement for ack_uuid to pid delaying transmission by at most ack_delay.

Parameters
pidtarget peer
ack_uuidUUID to ack
max_delayhow long can the ACK wait

Definition at line 7702 of file gnunet-service-transport.c.

7705{
7706 struct AcknowledgementCummulator *ac;
7707
7709 "Scheduling ACK %s for transmission to %s\n",
7710 GNUNET_uuid2s (&ack_uuid->value),
7711 GNUNET_i2s (pid));
7713 if (NULL == ac)
7714 {
7716 ac->target = *pid;
7717 ac->min_transmission_time = max_delay;
7721 &ac->target,
7722 ac,
7724 }
7725 else
7726 {
7727 if (MAX_CUMMULATIVE_ACKS == ac->num_acks)
7728 {
7729 /* Must run immediately, ack buffer full. Cancel the pending task
7730 FIRST: #transmit_cummulative_ack_cb() clears @e task without
7731 cancelling it, which would leave the old task armed with its
7732 handle lost. */
7734 ac->task = NULL;
7736 }
7740 }
7743 ac->ack_uuids[ac->num_acks].ack_uuid = *ack_uuid;
7744 ac->num_acks++;
7747 ac);
7748}

References ack_cummulators, TransportCummulativeAckPayload::ack_uuid, AcknowledgementCummulator::ack_uuids, GNUNET_assert, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY, GNUNET_CONTAINER_multipeermap_get(), GNUNET_CONTAINER_multipeermap_put(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, GNUNET_new, GNUNET_SCHEDULER_add_at(), GNUNET_SCHEDULER_cancel(), GNUNET_TIME_absolute_get(), GNUNET_TIME_absolute_min(), GNUNET_uuid2s(), GNUNET_YES, MAX_CUMMULATIVE_ACKS, AcknowledgementCummulator::min_transmission_time, AcknowledgementCummulator::num_acks, TransportCummulativeAckPayload::receive_time, AcknowledgementCummulator::target, AcknowledgementCummulator::task, transmit_cummulative_ack_cb(), and AcknowledgementUUIDP::value.

Referenced by handle_fragment_box(), and handle_reliability_box().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ find_by_message_uuid()

static int find_by_message_uuid ( void *  cls,
uint32_t  key,
void *  value 
)
static

Iterator called to find a reassembly context by the message UUID in the multihashmap32.

Parameters
clsa struct FindByMessageUuidContext
keya key (unused)
valuea struct ReassemblyContext
Returns
GNUNET_YES if not found, GNUNET_NO if found

Definition at line 7778 of file gnunet-service-transport.c.

7779{
7780 struct FindByMessageUuidContext *fc = cls;
7781 struct ReassemblyContext *rc = value;
7782
7783 (void) key;
7784 if (0 == GNUNET_memcmp (&fc->message_uuid, &rc->msg_uuid))
7785 {
7786 fc->rc = rc;
7787 return GNUNET_NO;
7788 }
7789 return GNUNET_YES;
7790}

References GNUNET_memcmp, GNUNET_NO, GNUNET_YES, key, FindByMessageUuidContext::message_uuid, ReassemblyContext::msg_uuid, FindByMessageUuidContext::rc, and value.

Referenced by handle_fragment_box().

Here is the caller graph for this function:

◆ handle_fragment_box()

static void handle_fragment_box ( void *  cls,
const struct TransportFragmentBoxMessage fb 
)
static

Communicator gave us a fragment.

Process the request.

Parameters
clsa struct CommunicatorMessageContext (must call finish_cmc_handling() when done)
fbthe message that was received

Definition at line 7801 of file gnunet-service-transport.c.

7802{
7803 struct CommunicatorMessageContext *cmc = cls;
7804 struct VirtualLink *vl;
7805 struct ReassemblyContext *rc;
7806 const struct GNUNET_MessageHeader *msg;
7807 uint16_t msize;
7808 uint16_t fsize;
7809 uint16_t frag_off;
7810 char *target;
7811 struct GNUNET_TIME_Relative cdelay;
7812 struct FindByMessageUuidContext fc;
7813
7814 vl = lookup_virtual_link (&cmc->im.sender);
7815 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
7816 {
7817 /* Entirely normal: fragments of a message that was already in flight
7818 keep arriving for a while after a link goes down, and a peer that has
7819 validated us may start sending before we have validated it. This used
7820 to call #GNUNET_SERVICE_client_drop(), which disconnects the
7821 communicator *process* -- every queue it owns, hence every neighbour
7822 reachable through it, hence every CORE session. On a peer with many
7823 neighbours a single ill-timed fragment therefore dropped all
7824 connections at once, and since the fragment comes from the network,
7825 any peer could cause it at will. Drop the fragment, keep the
7826 communicator; see #demultiplex_with_cmc() for the same reasoning. */
7828 "No virtual link for %s to handle fragment\n",
7829 GNUNET_i2s (&cmc->im.sender));
7831 "# fragments dropped (virtual link down)",
7832 1,
7833 GNUNET_NO);
7834 finish_cmc_handling (cmc);
7835 return;
7836 }
7837 if (NULL == vl->reassembly_map)
7838 {
7840 vl->reassembly_heap =
7845 vl);
7846 }
7847 msize = ntohs (fb->msg_size);
7848 fc.message_uuid = fb->msg_uuid;
7849 fc.rc = NULL;
7851 fb->msg_uuid.uuid,
7853 &fc);
7854 fsize = ntohs (fb->header.size) - sizeof(*fb);
7855 if (NULL == (rc = fc.rc))
7856 {
7857 /* Bound the RAM a single sender can pin here: @e msg_size is chosen by
7858 the peer, not by us. */
7861 {
7862 struct ReassemblyContext *drop;
7863
7865 GNUNET_assert (NULL != drop);
7867 "# Reassembly contexts dropped (limit reached)",
7868 1,
7869 GNUNET_NO);
7871 }
7872 rc = GNUNET_malloc (sizeof(*rc) + msize /* reassembly payload buffer */
7873 + (msize + 7) / 8 * sizeof(uint8_t) /* bitfield */);
7874 rc->msg_uuid = fb->msg_uuid;
7875 rc->virtual_link = vl;
7876 rc->msg_size = msize;
7877 rc->reassembly_timeout =
7881 rc,
7885 vl->reassembly_map,
7886 rc->msg_uuid.uuid,
7887 rc,
7889 target = (char *) &rc[1];
7890 rc->bitfield = (uint8_t *) (target + rc->msg_size);
7891 /* The bitfield loop below decrements @e msg_missing once per newly
7892 received byte, so this must always start at the full message size:
7893 initialising it to 0 for a single-fragment message made it
7894 underflow, and the message was then never delivered. */
7895 rc->msg_missing = rc->msg_size;
7897 "Received fragment with size %u at offset %u/%u %u bytes missing from %s for NEW message %"
7898 PRIu64 "\n",
7899 fsize,
7900 ntohs (fb->frag_off),
7901 msize,
7902 rc->msg_missing,
7903 GNUNET_i2s (&cmc->im.sender),
7904 fb->msg_uuid.uuid);
7905 }
7906 else
7907 {
7908 target = (char *) &rc[1];
7910 "Received fragment at offset %u/%u from %s for message %u\n",
7911 ntohs (fb->frag_off),
7912 msize,
7913 GNUNET_i2s (&cmc->im.sender),
7914 (unsigned int) fb->msg_uuid.uuid);
7915 }
7916 if (msize != rc->msg_size)
7917 {
7918 GNUNET_break (0);
7919 finish_cmc_handling (cmc);
7920 return;
7921 }
7922
7923 /* reassemble */
7924 if (0 == fsize)
7925 {
7926 GNUNET_break (0);
7927 finish_cmc_handling (cmc);
7928 return;
7929 }
7930 frag_off = ntohs (fb->frag_off);
7931 if (frag_off + fsize > msize)
7932 {
7933 /* Fragment (plus fragment size) exceeds message size! */
7934 GNUNET_break_op (0);
7935 finish_cmc_handling (cmc);
7936 return;
7937 }
7938 memcpy (&target[frag_off], &fb[1], fsize);
7939 /* update bitfield and msg_missing */
7940 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
7941 {
7942 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
7943 {
7944 rc->bitfield[i / 8] |= (1 << (i % 8));
7945 rc->msg_missing--;
7946 }
7947 }
7948
7949 /* Compute cumulative ACK */
7951 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->msg_missing / fsize);
7952 if (0 == rc->msg_missing)
7953 cdelay = GNUNET_TIME_UNIT_ZERO;
7954 cummulative_ack (&cmc->im.sender,
7955 &fb->ack_uuid,
7958 /* is reassembly complete? */
7959 if (0 != rc->msg_missing)
7960 {
7961 finish_cmc_handling (cmc);
7962 return;
7963 }
7964 /* reassembly is complete, verify result */
7965 msg = (const struct GNUNET_MessageHeader *) &rc[1];
7966 if (ntohs (msg->size) != rc->msg_size)
7967 {
7968 GNUNET_break (0);
7970 finish_cmc_handling (cmc);
7971 return;
7972 }
7973 /* successful reassembly */
7975 "Fragment reassembly complete for message %u\n",
7976 (unsigned int) fb->msg_uuid.uuid);
7977 /* FIXME: check that the resulting msg is NOT a
7978 DV Box or Reliability Box, as that is NOT allowed! */
7979 {
7980 uint16_t rsize = rc->msg_size;
7981 char rbuf[rsize] GNUNET_ALIGN;
7982
7983 /* Copy the reassembled message out and release `rc' BEFORE
7984 demultiplexing: the inner message may tear down the virtual link,
7985 which frees every reassembly context of that link -- the old code
7986 then used and freed `rc' a second time afterwards. */
7987 memcpy (rbuf, msg, rsize);
7989 cmc->mh = (const struct GNUNET_MessageHeader *) rbuf;
7991 }
7992}

References GNUNET_TIME_Absolute::abs_value_us, TransportFragmentBoxMessage::ack_uuid, ReassemblyContext::bitfield, VirtualLink::confirmed, cummulative_ack(), demultiplex_with_cmc(), find_by_message_uuid(), finish_cmc_handling(), TransportFragmentBoxMessage::frag_off, free_reassembly_context(), GNUNET_ALIGN, GNUNET_assert, GNUNET_break, GNUNET_break_op, GNUNET_CONTAINER_heap_create(), GNUNET_CONTAINER_heap_insert(), GNUNET_CONTAINER_HEAP_ORDER_MIN, GNUNET_CONTAINER_heap_peek(), GNUNET_CONTAINER_multihashmap32_create(), GNUNET_CONTAINER_multihashmap32_get_multiple(), GNUNET_CONTAINER_multihashmap32_put(), GNUNET_CONTAINER_multihashmap32_size(), GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE, GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, GNUNET_malloc, GNUNET_NO, GNUNET_OK, GNUNET_SCHEDULER_add_delayed(), GNUNET_STATISTICS_update(), GNUNET_TIME_absolute_get(), GNUNET_TIME_absolute_get_duration(), GNUNET_TIME_relative_multiply(), GNUNET_TIME_relative_to_absolute(), GNUNET_TIME_UNIT_ZERO, GST_stats, TransportFragmentBoxMessage::header, ReassemblyContext::hn, CommunicatorMessageContext::im, ReassemblyContext::last_frag, lookup_virtual_link(), MAX_REASSEMBLY_CONTEXTS, FindByMessageUuidContext::message_uuid, CommunicatorMessageContext::mh, msg, ReassemblyContext::msg_missing, TransportFragmentBoxMessage::msg_size, ReassemblyContext::msg_size, TransportFragmentBoxMessage::msg_uuid, ReassemblyContext::msg_uuid, FindByMessageUuidContext::rc, reassembly_cleanup_task(), REASSEMBLY_EXPIRATION, VirtualLink::reassembly_heap, VirtualLink::reassembly_map, ReassemblyContext::reassembly_timeout, VirtualLink::reassembly_timeout_task, GNUNET_TRANSPORT_IncomingMessage::sender, GNUNET_MessageHeader::size, MessageUUIDP::uuid, and ReassemblyContext::virtual_link.

Here is the call graph for this function:

◆ check_reliability_box()

static int check_reliability_box ( void *  cls,
const struct TransportReliabilityBoxMessage rb 
)
static

Communicator gave us a reliability box.

Check the message.

Parameters
clsa struct CommunicatorMessageContext
rbthe send message that was sent
Returns
GNUNET_YES if message is well-formed

Definition at line 8003 of file gnunet-service-transport.c.

8005{
8006 const struct GNUNET_MessageHeader *box = (const struct
8007 GNUNET_MessageHeader *) &rb[1];
8008 (void) cls;
8009
8011 "check_send_msg with size %u: inner msg type %u and size %u (%lu %lu)\n",
8012 ntohs (rb->header.size),
8013 ntohs (box->type),
8014 ntohs (box->size),
8015 sizeof (struct TransportReliabilityBoxMessage),
8016 sizeof (struct GNUNET_MessageHeader));
8018 return GNUNET_YES;
8019}

References GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_MQ_check_boxed_message, GNUNET_YES, TransportReliabilityBoxMessage::header, GNUNET_MessageHeader::size, and GNUNET_MessageHeader::type.

◆ handle_reliability_box()

static void handle_reliability_box ( void *  cls,
const struct TransportReliabilityBoxMessage rb 
)
static

Communicator gave us a reliability box.

Process the request.

Parameters
clsa struct CommunicatorMessageContext (must call finish_cmc_handling() when done)
rbthe message that was received

Definition at line 8030 of file gnunet-service-transport.c.

8032{
8033 struct CommunicatorMessageContext *cmc = cls;
8034 const struct GNUNET_MessageHeader *inbox =
8035 (const struct GNUNET_MessageHeader *) &rb[1];
8036 struct GNUNET_TIME_Relative rtt;
8037
8039 "Received reliability box from %s with UUID %s of type %u\n",
8040 GNUNET_i2s (&cmc->im.sender),
8042 (unsigned int) ntohs (inbox->type));
8043 rtt = GNUNET_TIME_UNIT_SECONDS; /* FIXME: should base this on "RTT", but we
8044 do not really have an RTT for the
8045 * incoming* queue (should we have
8046 the sender add it to the rb message?) */
8048 &cmc->im.sender,
8049 &rb->ack_uuid,
8050 (0 == ntohl (rb->ack_countdown))
8053 GNUNET_TIME_relative_divide (rtt, 8 /* FIXME: magic constant */)));
8054 /* continue with inner message */
8055 /* FIXME: check that inbox is NOT a DV Box, fragment or another
8056 reliability box (not allowed!) */
8057 cmc->mh = inbox;
8059}

References TransportReliabilityBoxMessage::ack_countdown, TransportReliabilityBoxMessage::ack_uuid, cummulative_ack(), demultiplex_with_cmc(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, GNUNET_TIME_relative_divide(), GNUNET_TIME_relative_to_absolute(), GNUNET_TIME_UNIT_SECONDS, GNUNET_TIME_UNIT_ZERO_ABS, GNUNET_uuid2s(), CommunicatorMessageContext::im, CommunicatorMessageContext::mh, GNUNET_TRANSPORT_IncomingMessage::sender, GNUNET_MessageHeader::type, and AcknowledgementUUIDP::value.

Here is the call graph for this function:

◆ update_pd_age()

static void update_pd_age ( struct PerformanceData pd,
unsigned int  age 
)
static

Check if we have advanced to another age since the last time.

If so, purge ancient statistics (more than GOODPUT_AGING_SLOTS before the current age)

Parameters
[in,out]pddata to update
agecurrent age

Definition at line 8071 of file gnunet-service-transport.c.

8072{
8073 unsigned int sage;
8074
8075 if (age == pd->last_age)
8076 return; /* nothing to do */
8077 sage = GNUNET_MAX (pd->last_age, age - 2 * GOODPUT_AGING_SLOTS);
8078 for (unsigned int i = sage; i <= age - GOODPUT_AGING_SLOTS; i++)
8079 {
8080 struct TransmissionHistoryEntry *the = &pd->the[i % GOODPUT_AGING_SLOTS];
8081
8082 the->bytes_sent = 0;
8083 the->bytes_received = 0;
8084 }
8085 pd->last_age = age;
8086}

References TransmissionHistoryEntry::bytes_received, TransmissionHistoryEntry::bytes_sent, GNUNET_MAX, GOODPUT_AGING_SLOTS, PerformanceData::last_age, and PerformanceData::the.

Referenced by update_performance_data().

Here is the caller graph for this function:

◆ update_performance_data()

static void update_performance_data ( struct PerformanceData pd,
struct GNUNET_TIME_Relative  rtt,
uint16_t  bytes_transmitted_ok 
)
static

Update pd based on the latest rtt and the number of bytes that were confirmed to be successfully transmitted.

Parameters
[in,out]pddata to update
rttlatest round-trip time
bytes_transmitted_oknumber of bytes receiver confirmed as received

Definition at line 8098 of file gnunet-service-transport.c.

8101{
8102 uint64_t nval = rtt.rel_value_us;
8103 uint64_t oval = pd->aged_rtt.rel_value_us;
8104 unsigned int age = get_age ();
8105 struct TransmissionHistoryEntry *the = &pd->the[age % GOODPUT_AGING_SLOTS];
8106
8107 if (oval == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
8108 pd->aged_rtt = rtt;
8109 else
8110 pd->aged_rtt.rel_value_us = (nval + 7 * oval) / 8;
8111 update_pd_age (pd, age);
8112 the->bytes_received += bytes_transmitted_ok;
8113}

References PerformanceData::aged_rtt, TransmissionHistoryEntry::bytes_received, get_age(), GNUNET_TIME_UNIT_FOREVER_REL, GOODPUT_AGING_SLOTS, GNUNET_TIME_Relative::rel_value_us, PerformanceData::the, and update_pd_age().

Referenced by update_dvh_performance(), and update_queue_performance().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ update_queue_performance()

static void update_queue_performance ( struct Queue q,
struct GNUNET_TIME_Relative  rtt,
uint16_t  bytes_transmitted_ok 
)
static

We have successfully transmitted data via q, update metrics.

Parameters
qqueue to update
rttround trip time observed
bytes_transmitted_oknumber of bytes successfully transmitted

Definition at line 8124 of file gnunet-service-transport.c.

8127{
8128 update_performance_data (&q->pd, rtt, bytes_transmitted_ok);
8129}

References q, and update_performance_data().

Referenced by handle_acknowledged().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ update_dvh_performance()

static void update_dvh_performance ( struct DistanceVectorHop dvh,
struct GNUNET_TIME_Relative  rtt,
uint16_t  bytes_transmitted_ok 
)
static

We have successfully transmitted data via dvh, update metrics.

Parameters
dvhdistance vector path data to update
rttround trip time observed
bytes_transmitted_oknumber of bytes successfully transmitted

Definition at line 8140 of file gnunet-service-transport.c.

8143{
8144 update_performance_data (&dvh->pd, rtt, bytes_transmitted_ok);
8145}

References DistanceVectorHop::pd, and update_performance_data().

Referenced by handle_acknowledged().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ completed_pending_message()

static void completed_pending_message ( struct PendingMessage pm)
static

We have completed transmission of pm, remove it from the transmission queues (and if it is a fragment, continue up the tree as necessary).

Parameters
pmpending message that was transmitted

Definition at line 8156 of file gnunet-service-transport.c.

8157{
8158 struct PendingMessage *pos;
8159
8161 "Complete transmission of message %" PRIu64 " %u\n",
8162 pm->logging_uuid,
8163 pm->pmt);
8164 switch (pm->pmt)
8165 {
8166 case PMT_CORE:
8168 /* Full message sent, we are done */
8170 return;
8171
8172 case PMT_FRAGMENT_BOX:
8173 /* Fragment sent over reliable channel */
8174 pos = pm->frag_parent;
8175 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
8178 "pos frag_off %lu pos bytes_msg %lu pmt %u parent %u\n",
8179 (unsigned long) pos->frag_off,
8180 (unsigned long) pos->bytes_msg,
8181 pos->pmt,
8182 NULL == pos->frag_parent ? 1 : 0);
8183 /* check if subtree is done */
8184 while ((NULL == pos->head_frag) && (pos->frag_off == (pos->bytes_msg
8185 - sizeof(struct
8187 &&
8188 (NULL != pos->frag_parent))
8189 {
8190 pm = pos;
8191 pos = pm->frag_parent;
8192 if ((NULL == pos) && (PMT_DV_BOX == pm->pmt))
8193 {
8195 return;
8196 }
8197 else if (PMT_DV_BOX == pm->pmt)
8198 {
8200 return;
8201 }
8202 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
8204 }
8205
8206 /* Was this the last applicable fragment?
8207
8208 NOTE: @a pos may be a DV box here, and then it is NOT the message the
8209 client is waiting for -- its @e frag_parent is, and that parent's
8210 @e bpm points at @a pos. Answering the client directly (and thereby
8211 releasing @a pos through #free_pending_message()) left @e bpm of a
8212 message that is still queued pointing at freed memory, which
8213 #transmit_on_queue() reads and may free a second time. Hand it to
8214 ourselves instead: the #PMT_DV_BOX case below clears @e bpm and
8215 answers for the parent, and for every other @e pmt it does exactly
8216 what the direct call did. */
8217 if ((NULL == pos->head_frag) && (NULL == pos->frag_parent || PMT_DV_BOX ==
8218 pos->pmt) &&
8219 (pos->frag_off == pos->bytes_msg))
8221 return;
8222
8223 case PMT_DV_BOX:
8225 "Completed transmission of message %" PRIu64 " (DV Box)\n",
8226 pm->logging_uuid);
8227 if (NULL != pm->frag_parent)
8228 {
8229 pos = pm->frag_parent;
8231 pos->bpm = NULL;
8233 }
8234 else
8236 return;
8237 }
8238}

References PendingMessage::bpm, PendingMessage::bytes_msg, client_send_response(), completed_pending_message(), PendingMessage::frag_off, PendingMessage::frag_parent, free_pending_message(), GNUNET_CONTAINER_MDLL_remove, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, PendingMessage::head_frag, PendingMessage::logging_uuid, PendingMessage::pmt, PMT_CORE, PMT_DV_BOX, PMT_FRAGMENT_BOX, PMT_RELIABILITY_BOX, and PendingMessage::tail_frag.

Referenced by completed_pending_message(), handle_acknowledged(), and transmit_on_queue().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_acknowledged()

static void handle_acknowledged ( struct PendingAcknowledgement pa,
struct GNUNET_TIME_Relative  ack_delay 
)
static

The pa was acknowledged, process the acknowledgement.

Parameters
pathe pending acknowledgement that was satisfied
ack_delayartificial delay from cumulative acks created by the other peer

Definition at line 8249 of file gnunet-service-transport.c.

8251{
8252 struct GNUNET_TIME_Relative delay;
8253 struct PendingMessage *pm = pa->pm;
8254
8256 delay = GNUNET_TIME_relative_subtract (delay, ack_delay);
8257 if (NULL != pa->queue && 1 == pa->num_send)
8259 if (NULL != pa->dvh && 1 == pa->num_send)
8260 update_dvh_performance (pa->dvh, delay, pa->message_size);
8261 /* Retire @a pa BEFORE handing its message on. completed_pending_message()
8262 ends in free_pending_message() for anything it finishes, and that now
8263 releases every acknowledgement still attached to the message -- this one
8264 included. Freeing it afterwards is a double free, and it aborts on the
8265 GNUNET_assert() over multiuuidmap_remove() in
8266 free_pending_acknowledgement(), the map entry having gone with the first
8267 release. Nothing below needs @a pa, only its message. */
8269 if (NULL != pm)
8271}

References completed_pending_message(), PendingAcknowledgement::dvh, free_pending_acknowledgement(), GNUNET_TIME_absolute_get_duration(), GNUNET_TIME_relative_subtract(), PendingAcknowledgement::message_size, PendingAcknowledgement::num_send, PendingAcknowledgement::pm, PendingAcknowledgement::queue, PendingAcknowledgement::transmission_time, update_dvh_performance(), and update_queue_performance().

Referenced by handle_reliability_ack().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_reliability_ack()

static int check_reliability_ack ( void *  cls,
const struct TransportReliabilityAckMessage ra 
)
static

Communicator gave us a reliability ack.

Check it is well-formed.

Parameters
clsa struct CommunicatorMessageContext (unused)
rathe message that was received
Returns
#GNUNET_Ok if ra is well-formed

Definition at line 8282 of file gnunet-service-transport.c.

8284{
8285 unsigned int n_acks;
8286
8287 (void) cls;
8288 n_acks = (ntohs (ra->header.size) - sizeof(*ra))
8289 / sizeof(struct TransportCummulativeAckPayloadP);
8290 if (0 == n_acks)
8291 {
8292 GNUNET_break_op (0);
8293 return GNUNET_SYSERR;
8294 }
8295 if ((ntohs (ra->header.size) - sizeof(*ra)) !=
8296 n_acks * sizeof(struct TransportCummulativeAckPayloadP))
8297 {
8298 GNUNET_break_op (0);
8299 return GNUNET_SYSERR;
8300 }
8301 return GNUNET_OK;
8302}

References GNUNET_break_op, GNUNET_OK, GNUNET_SYSERR, TransportReliabilityAckMessage::header, and GNUNET_MessageHeader::size.

◆ handle_reliability_ack()

static void handle_reliability_ack ( void *  cls,
const struct TransportReliabilityAckMessage ra 
)
static

Communicator gave us a reliability ack.

Process the request.

Parameters
clsa struct CommunicatorMessageContext (must call finish_cmc_handling() when done)
rathe message that was received

Definition at line 8313 of file gnunet-service-transport.c.

8315{
8316 struct CommunicatorMessageContext *cmc = cls;
8317 const struct TransportCummulativeAckPayloadP *ack;
8318 unsigned int n_acks;
8319 uint32_t ack_counter;
8320
8321 n_acks = (ntohs (ra->header.size) - sizeof(*ra))
8322 / sizeof(struct TransportCummulativeAckPayloadP);
8323 ack = (const struct TransportCummulativeAckPayloadP *) &ra[1];
8324 for (unsigned int i = 0; i < n_acks; i++)
8325 {
8326 struct PendingAcknowledgement *pa =
8328 if (NULL == pa)
8329 {
8331 "Received ACK from %s with UUID %s which is unknown to us!\n",
8332 GNUNET_i2s (&cmc->im.sender),
8333 GNUNET_uuid2s (&ack[i].ack_uuid.value));
8335 GST_stats,
8336 "# FRAGMENT_ACKS dropped, no matching pending message",
8337 1,
8338 GNUNET_NO);
8339 continue;
8340 }
8342 "Received ACK from %s with UUID %s\n",
8343 GNUNET_i2s (&cmc->im.sender),
8344 GNUNET_uuid2s (&ack[i].ack_uuid.value));
8345 handle_acknowledged (pa, GNUNET_TIME_relative_ntoh (ack[i].ack_delay));
8346 }
8347
8348 ack_counter = ntohl (ra->ack_counter);
8349 (void) ack_counter; /* silence compiler warning for now */
8350 // FIXME-OPTIMIZE: track ACK losses based on ack_counter somewhere!
8351 // (DV and/or Neighbour?)
8352 finish_cmc_handling (cmc);
8353}

References TransportReliabilityAckMessage::ack_counter, PendingAcknowledgement::ack_uuid, finish_cmc_handling(), GNUNET_CONTAINER_multiuuidmap_get(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_INFO, GNUNET_i2s(), GNUNET_log, GNUNET_NO, GNUNET_STATISTICS_update(), GNUNET_TIME_relative_ntoh(), GNUNET_uuid2s(), GST_stats, handle_acknowledged(), TransportReliabilityAckMessage::header, CommunicatorMessageContext::im, pending_acks, GNUNET_TRANSPORT_IncomingMessage::sender, GNUNET_MessageHeader::size, and AcknowledgementUUIDP::value.

Here is the call graph for this function:

◆ check_backchannel_encapsulation()

static int check_backchannel_encapsulation ( void *  cls,
const struct TransportBackchannelEncapsulationMessage be 
)
static

Communicator gave us a backchannel encapsulation.

Check the message.

Parameters
clsa struct CommunicatorMessageContext
bethe send message that was sent
Returns
GNUNET_YES if message is well-formed

Definition at line 8364 of file gnunet-service-transport.c.

8367{
8368 uint16_t size = ntohs (be->header.size) - sizeof(*be);
8369 const struct GNUNET_MessageHeader *inbox =
8370 (const struct GNUNET_MessageHeader *) &be[1];
8371 const char *is;
8372 uint16_t isize;
8373
8374 (void) cls;
8375 /* MUST bound the buffer before reading @a inbox: the size check below
8376 dereferences it, and a message consisting of nothing but the header
8377 leaves no bytes to read. */
8378 if (size <= sizeof(struct GNUNET_MessageHeader))
8379 {
8380 GNUNET_break_op (0);
8381 return GNUNET_SYSERR;
8382 }
8383 if (ntohs (inbox->size) >= size)
8384 {
8385 GNUNET_break_op (0);
8386 return GNUNET_SYSERR;
8387 }
8388 isize = ntohs (inbox->size);
8389 is = ((const char *) inbox) + isize;
8390 size -= isize;
8391 if ('\0' != is[size - 1])
8392 {
8393 GNUNET_break_op (0);
8394 return GNUNET_SYSERR;
8395 }
8396 return GNUNET_YES;
8397}

References GNUNET_break_op, GNUNET_SYSERR, GNUNET_YES, TransportBackchannelEncapsulationMessage::header, is, GNUNET_MessageHeader::size, and size.

◆ handle_backchannel_encapsulation()

static void handle_backchannel_encapsulation ( void *  cls,
const struct TransportBackchannelEncapsulationMessage be 
)
static

Communicator gave us a backchannel encapsulation.

Process the request. (We are the destination of the backchannel here.)

Parameters
clsa struct CommunicatorMessageContext (must call finish_cmc_handling() when done)
bethe message that was received

Definition at line 8409 of file gnunet-service-transport.c.

8412{
8413 const struct GNUNET_PeerIdentity *my_identity;
8414 struct CommunicatorMessageContext *cmc = cls;
8416 struct GNUNET_MQ_Envelope *env;
8417 struct TransportClient *tc;
8418 const struct GNUNET_MessageHeader *inbox =
8419 (const struct GNUNET_MessageHeader *) &be[1];
8420 uint16_t isize = ntohs (inbox->size);
8421 const char *target_communicator = ((const char *) inbox) + isize;
8422 char *sender;
8423 char *self;
8424
8427
8428 GNUNET_asprintf (&sender,
8429 "%s",
8430 GNUNET_i2s (&cmc->im.sender));
8431 GNUNET_asprintf (&self,
8432 "%s",
8434
8435 /* Find client providing this communicator */
8436 for (tc = clients_head; NULL != tc; tc = tc->next)
8437 if ((CT_COMMUNICATOR == tc->type) &&
8438 (NULL != tc->details.communicator.address_prefix) &&
8439 (0 ==
8440 strcmp (tc->details.communicator.address_prefix, target_communicator)))
8441 break;
8442 if (NULL == tc)
8443 {
8444 char *stastr;
8445
8447 &stastr,
8448 "# Backchannel message dropped: target communicator `%s' unknown",
8449 target_communicator);
8451 GNUNET_free (stastr);
8452 GNUNET_free (sender);
8453 GNUNET_free (self);
8454 finish_cmc_handling (cmc);
8455 return;
8456 }
8457 /* Finally, deliver backchannel message to communicator */
8459 "Delivering backchannel message from %s to %s of type %u to %s\n",
8460 sender,
8461 self,
8462 ntohs (inbox->type),
8463 target_communicator);
8465 cbi,
8466 isize,
8468 cbi->pid = cmc->im.sender;
8469 memcpy (&cbi[1], inbox, isize);
8470 GNUNET_MQ_send (tc->mq, env);
8471 GNUNET_free (sender);
8472 GNUNET_free (self);
8473 finish_cmc_handling (cmc);
8474}

References clients_head, CT_COMMUNICATOR, env, finish_cmc_handling(), GNUNET_asprintf(), GNUNET_assert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_i2s(), GNUNET_log, GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING, GNUNET_MQ_msg_extra, GNUNET_MQ_send(), GNUNET_NO, GNUNET_PILS_get_identity(), GNUNET_STATISTICS_update(), GST_stats, CommunicatorMessageContext::im, my_identity, GNUNET_TRANSPORT_CommunicatorBackchannelIncoming::pid, pils, GNUNET_TRANSPORT_IncomingMessage::sender, GNUNET_MessageHeader::size, tc, and GNUNET_MessageHeader::type.

Here is the call graph for this function:

◆ path_cleanup_cb()

static void path_cleanup_cb ( void *  cls)
static

Task called when we should check if any of the DV paths we have learned to a target are due for garbage collection.

Collects stale paths, and possibly frees the entire DV entry if no paths are left. Otherwise re-schedules itself.

Parameters
clsa struct DistanceVector

Definition at line 8487 of file gnunet-service-transport.c.

8488{
8489 struct DistanceVector *dv = cls;
8490 struct DistanceVectorHop *pos;
8491 struct GNUNET_TIME_Absolute next;
8492
8493 dv->timeout_task = NULL;
8494 /* @e dv_head is NOT sorted by @e timeout: learn_dv_path() inserts a new
8495 hop at the head, and moves a rediscovered one back to the head, so the
8496 list runs newest (i.e. latest deadline) first. Stopping at the first
8497 live entry therefore inspected exactly the youngest hop and re-armed
8498 for *its* deadline, which is the last one of the whole set: expired
8499 hops behind it were never collected, and check_vl_transmission() kept
8500 skipping them one by one for as long as the route lived. Sweep all of
8501 them and come back for the earliest survivor. */
8503 pos = dv->dv_head;
8504 while (NULL != pos)
8505 {
8506 struct DistanceVectorHop *next_pos = pos->next_dv;
8507
8508 GNUNET_assert (dv == pos->dv);
8511 else
8512 next = GNUNET_TIME_absolute_min (next, pos->timeout);
8513 pos = next_pos;
8514 }
8515 if (NULL == dv->dv_head)
8516 {
8517 free_dv_route (dv);
8518 return;
8519 }
8520 dv->timeout_task =
8522}

References DistanceVectorHop::dv, DistanceVector::dv_head, free_distance_vector_hop(), free_dv_route(), GNUNET_assert, GNUNET_SCHEDULER_add_at(), GNUNET_TIME_absolute_get_remaining(), GNUNET_TIME_absolute_min(), GNUNET_TIME_UNIT_FOREVER_ABS, DistanceVectorHop::next_dv, path_cleanup_cb(), GNUNET_TIME_Relative::rel_value_us, DistanceVectorHop::timeout, and DistanceVector::timeout_task.

Referenced by learn_dv_path(), and path_cleanup_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ send_msg_from_cache()

static void send_msg_from_cache ( struct VirtualLink vl)
static

Definition at line 8526 of file gnunet-service-transport.c.

8527{
8528
8529 const struct GNUNET_PeerIdentity target = vl->target;
8530
8531
8533 {
8534 struct RingBufferEntry *ring_buffer_copy[RING_BUFFER_SIZE];
8535 unsigned int tail = GNUNET_YES == is_ring_buffer_full ? ring_buffer_head :
8536 0;
8537 unsigned int head = GNUNET_YES == is_ring_buffer_full ? RING_BUFFER_SIZE :
8540 struct CommunicatorMessageContext *cmc;
8541 struct RingBufferEntry *rbe;
8542 struct GNUNET_MessageHeader *mh;
8543
8545 "Sending from ring buffer, which has %u items\n",
8546 head);
8547
8548 ring_buffer_head = 0;
8549 for (unsigned int i = 0; i < head; i++)
8550 {
8551 rbe = ring_buffer[(i + tail) % RING_BUFFER_SIZE];
8552 cmc = rbe->cmc;
8553 mh = rbe->mh;
8554
8555 im = cmc->im;
8556 // mh = cmc->mh;
8558 "Sending message of type %u to ring buffer target %s using vl target %s index %u\n",
8559 mh->type,
8560 GNUNET_i2s (&im.sender),
8561 GNUNET_i2s2 (&target),
8562 (i + tail) % RING_BUFFER_SIZE);
8563 if (0 == GNUNET_memcmp (&target, &im.sender))
8564 {
8566 "Finish handling message of type %u and size %u\n",
8567 (unsigned int) ntohs (mh->type),
8568 (unsigned int) ntohs (mh->size));
8570 GNUNET_free (mh);
8571 GNUNET_free (rbe->cmc);
8572 GNUNET_free (rbe);
8573 }
8574 else
8575 {
8576 ring_buffer_copy[ring_buffer_head] = rbe;
8578 }
8579 }
8580
8583 {
8585 }
8586
8587 for (unsigned int i = 0; i < ring_buffer_head; i++)
8588 {
8589 ring_buffer[i] = ring_buffer_copy[i];
8591 "ring_buffer[i]->mh->type for i %u %u\n",
8592 i,
8593 ring_buffer[i]->mh->type);
8594 }
8595 /* MUST clear the consumed slots, we freed those entries above */
8596 for (unsigned int i = ring_buffer_head; i < RING_BUFFER_SIZE; i++)
8597 ring_buffer[i] = NULL;
8598
8600 "%u items still in ring buffer\n",
8602 /* If we consumed nothing, compaction rewrote the buffer in place and
8603 left the write index one past the end. #handle_raw_message() would
8604 then read ring_buffer[RING_BUFFER_SIZE] and free whatever that is.
8605 The buffer is still full, and compaction moved the oldest entry to
8606 slot 0, so that is where the next write belongs. */
8608 ring_buffer_head = 0;
8609 }
8610
8612 {
8613 struct PendingMessage *ring_buffer_dv_copy[RING_BUFFER_SIZE];
8614 struct PendingMessage *pm;
8615 unsigned int tail = GNUNET_YES == is_ring_buffer_dv_full ?
8617 0;
8618 unsigned int head = GNUNET_YES == is_ring_buffer_dv_full ?
8621
8623 "Sending from ring buffer dv, which has %u items\n",
8624 head);
8625
8627 for (unsigned int i = 0; i < head; i++)
8628 {
8629 pm = ring_buffer_dv[(i + tail) % RING_BUFFER_SIZE];
8630
8632 "Sending to ring buffer target %s using vl target %s\n",
8633 GNUNET_i2s (&pm->target),
8634 GNUNET_i2s2 (&target));
8635 if (0 == GNUNET_memcmp (&target, &pm->target))
8636 {
8638 "Adding PendingMessage to vl, checking transmission.\n");
8639 pm->vl = vl;
8643 pm);
8644
8646 }
8647 else
8648 {
8649 ring_buffer_dv_copy[ring_buffer_dv_head] = pm;
8651 }
8652 }
8653
8655 {
8657 }
8658
8659 for (unsigned int i = 0; i < ring_buffer_dv_head; i++)
8660 ring_buffer_dv[i] = ring_buffer_dv_copy[i];
8661 /* MUST clear the consumed slots: entries we handed to a VirtualLink are
8662 now owned by that link, and #forward_dv_box() would GNUNET_free() them
8663 again once the ring buffer wraps around. */
8664 for (unsigned int i = ring_buffer_dv_head; i < RING_BUFFER_SIZE; i++)
8665 ring_buffer_dv[i] = NULL;
8666
8668 "%u items still in ring buffer dv.\n",
8670 /* Same one-past-the-end hazard as above: #forward_dv_box() reads
8671 ring_buffer_dv[ring_buffer_dv_head] and GNUNET_free()s it. */
8674 }
8675}

References check_vl_transmission(), RingBufferEntry::cmc, finish_handling_raw_message(), GNUNET_CONTAINER_MDLL_insert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_i2s(), GNUNET_i2s2(), GNUNET_log, GNUNET_memcmp, GNUNET_NO, GNUNET_YES, is_ring_buffer_dv_full, is_ring_buffer_full, mh, RingBufferEntry::mh, VirtualLink::pending_msg_head, VirtualLink::pending_msg_tail, ring_buffer, ring_buffer_dv, ring_buffer_dv_head, ring_buffer_head, RING_BUFFER_SIZE, GNUNET_TRANSPORT_IncomingMessage::sender, VirtualLink::target, PendingMessage::target, and PendingMessage::vl.

Referenced by activate_core_visible_dv_path(), and handle_validation_response().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ activate_core_visible_dv_path()

static void activate_core_visible_dv_path ( struct DistanceVectorHop hop)
static

The hop is a validated path to the respective target peer and we should tell core about it – and schedule a job to revoke the state.

Parameters
hopa path to some peer that is the reason for activation

Definition at line 8686 of file gnunet-service-transport.c.

8687{
8688 struct DistanceVector *dv = hop->dv;
8689 struct VirtualLink *vl;
8690
8691 vl = lookup_virtual_link (&dv->target);
8692 if (NULL == vl)
8693 {
8694
8695 vl = GNUNET_new (struct VirtualLink);
8697 "Creating new virtual link %p to %s using DV!\n",
8698 vl,
8699 GNUNET_i2s (&dv->target));
8700 vl->burst_addr = NULL;
8701 vl->confirmed = GNUNET_YES;
8702 vl->message_uuid_ctr =
8703 GNUNET_CRYPTO_random_u64 (UINT64_MAX);
8704 vl->target = dv->target;
8708 /* What the peer will grant us in its very first FLOW_CONTROL anyway
8709 (@e incoming_fc_window_size plus what we have sent, i.e. nothing).
8710 Starting at zero instead means a link that is up, validated and
8711 working carries nothing at all until an FC round trip completes --
8712 and if the peer cannot answer, not ever. */
8716 links,
8717 &vl->target,
8718 vl,
8720 vl->dv = dv;
8721 dv->vl = vl;
8722 vl->visibility_task =
8725 /* We lacked a confirmed connection to the target
8726 before, so tell CORE about it (finally!) */
8729 }
8730 else
8731 {
8732 /* Link was already up, remember dv is also now available and we are done */
8733 vl->dv = dv;
8734 dv->vl = vl;
8735 if (GNUNET_NO == vl->confirmed)
8736 {
8737 vl->confirmed = GNUNET_YES;
8738 vl->visibility_task =
8741 /* We lacked a confirmed connection to the target
8742 before, so tell CORE about it (finally!) */
8745 }
8746 else
8748 "Virtual link to %s could now also use DV!\n",
8749 GNUNET_i2s (&dv->target));
8750 }
8751}

References VirtualLink::available_fc_window_size, VirtualLink::burst_addr, check_link_down(), VirtualLink::confirmed, consider_sending_fc(), VirtualLink::core_recv_window, cores_send_connect_info(), DEFAULT_WINDOW_SIZE, VirtualLink::dv, DistanceVectorHop::dv, GNUNET_break, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY, GNUNET_CONTAINER_multipeermap_put(), GNUNET_CRYPTO_random_u64(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, GNUNET_new, GNUNET_NO, GNUNET_SCHEDULER_add_at(), GNUNET_YES, VirtualLink::incoming_fc_window_size, links, lookup_virtual_link(), VirtualLink::message_uuid_ctr, VirtualLink::outbound_fc_window_size, DistanceVectorHop::path_valid_until, RECV_WINDOW_SIZE, send_msg_from_cache(), VirtualLink::target, DistanceVector::target, VirtualLink::visibility_task, and DistanceVector::vl.

Referenced by learn_dv_path().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ learn_dv_path()

static int learn_dv_path ( const struct GNUNET_PeerIdentity path,
unsigned int  path_len,
struct GNUNET_TIME_Relative  network_latency,
struct GNUNET_TIME_Absolute  path_valid_until 
)
static

We have learned a path through the network to some other peer, add it to our DV data structure (returning GNUNET_YES on success).

We do not add paths if we have a sufficient number of shorter paths to this target already (returning GNUNET_NO).

We also do not add problematic paths, like those where we lack the first hop in our neighbour list (i.e. due to a topology change) or where some non-first hop is in our neighbour list (returning GNUNET_SYSERR).

Parameters
paththe path we learned, path[0] should be us, and then path contains a valid path from us to path[path_len-1] path[1] should be a direct neighbour (we should check!)
path_lennumber of entries on the path, at least three!
network_latencyhow long does the message take from us to path[path_len-1]? set to "forever" if unknown
path_valid_untilhow long is this path considered validated? Maybe be zero.
Returns
GNUNET_YES on success, GNUNET_NO if we have better path(s) to the target GNUNET_SYSERR if the path is useless and/or invalid (i.e. path[1] not a direct neighbour or path[i+1] is a direct neighbour for i>0)

Definition at line 8780 of file gnunet-service-transport.c.

8784{
8785 const struct GNUNET_PeerIdentity *my_identity;
8786 struct DistanceVectorHop *hop;
8787 struct DistanceVector *dv;
8788 struct Neighbour *next_hop;
8789 unsigned int shorter_distance;
8790
8791 if (path_len < 3)
8792 {
8793 /* what a boring path! not allowed! */
8794 GNUNET_break (0);
8795 return GNUNET_SYSERR;
8796 }
8797
8800
8801 GNUNET_assert (0 == GNUNET_memcmp (my_identity, &path[0]));
8802 next_hop = lookup_neighbour (&path[1]);
8803 if (NULL == next_hop)
8804 {
8805 /* next hop must be a neighbour, otherwise this whole thing is useless! */
8806 GNUNET_break (0);
8807 return GNUNET_SYSERR;
8808 }
8809 for (unsigned int i = 2; i < path_len; i++)
8810 {
8811 struct Neighbour *n = lookup_neighbour (&path[i]);
8812 struct GNUNET_TIME_Absolute q_timeout;
8813
8814 if (NULL != n)
8815 {
8816 q_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
8817 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
8818 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
8820 "remaining %lu to %s\n",
8821 (unsigned long) GNUNET_TIME_absolute_get_remaining (q_timeout)
8822 .rel_value_us,
8823 GNUNET_i2s (&n->pid));
8824 if (0 != GNUNET_TIME_absolute_get_remaining (q_timeout).rel_value_us)
8825 {
8826 /* Useless path: we have a direct active connection to some hop
8827 in the middle of the path, so this one is not even
8828 terribly useful for redundancy */
8830 "Path of %u hops useless: directly link to hop %u (%s)\n",
8831 path_len,
8832 i,
8833 GNUNET_i2s (&path[i]));
8835 "# Useless DV path ignored: hop is neighbour",
8836 1,
8837 GNUNET_NO);
8838 return GNUNET_SYSERR;
8839 }
8840 }
8841 }
8842 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
8843 if (NULL == dv)
8844 {
8845 dv = GNUNET_new (struct DistanceVector);
8846 dv->target = path[path_len - 1];
8849 dv);
8852 dv_routes,
8853 &dv->target,
8854 dv,
8856 }
8857 /* Check if we have this path already! */
8858 shorter_distance = 0;
8859 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
8860 pos = pos->next_dv)
8861 {
8862 if (pos->distance < path_len - 3)
8863 shorter_distance++;
8864 /* Note that the distances in 'pos' excludes us (path[0]),
8865 the next_hop (path[1]) and the target so we need to subtract three
8866 and check next_hop explicitly */
8867 if ((pos->distance == path_len - 3) && (pos->next_hop == next_hop))
8868 {
8869 int match = GNUNET_YES;
8870
8871 for (unsigned int i = 0; i < pos->distance; i++)
8872 {
8873 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
8874 {
8875 match = GNUNET_NO;
8876 break;
8877 }
8878 }
8879 if (GNUNET_YES == match)
8880 {
8881 struct GNUNET_TIME_Relative last_timeout;
8882
8883 /* Re-discovered known path, update timeout */
8885 "# Known DV path refreshed",
8886 1,
8887 GNUNET_NO);
8888 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
8889 pos->timeout =
8891 pos->path_valid_until =
8892 GNUNET_TIME_absolute_max (pos->path_valid_until, path_valid_until);
8893 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
8894 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
8895 if (0 <
8898 if (last_timeout.rel_value_us <
8901 .rel_value_us)
8902 {
8903 /* Some peer send DV learn messages too often, we are learning
8904 the same path faster than it would be useful; do not forward! */
8906 "Rediscovered path too quickly, not forwarding further\n")
8907 ;
8908 return GNUNET_NO;
8909 }
8911 "Refreshed known path to %s valid until %s, forwarding further\n",
8912 GNUNET_i2s (&dv->target),
8914 pos->path_valid_until));
8915 return GNUNET_YES;
8916 }
8917 }
8918 }
8919 /* Count how many shorter paths we have (incl. direct
8920 neighbours) before simply giving up on this one! */
8921 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
8922 {
8923 /* We have a shorter path already! */
8925 "Have many shorter DV paths %s, not forwarding further\n",
8926 GNUNET_i2s (&dv->target));
8927 return GNUNET_NO;
8928 }
8929 /* create new DV path entry */
8931 "Discovered new DV path to %s valid until %s\n",
8932 GNUNET_i2s (&dv->target),
8933 GNUNET_STRINGS_absolute_time_to_string (path_valid_until));
8934 hop = GNUNET_malloc (sizeof(struct DistanceVectorHop)
8935 + sizeof(struct GNUNET_PeerIdentity) * (path_len - 3));
8936 hop->next_hop = next_hop;
8937 hop->dv = dv;
8938 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
8939 memcpy (&hop[1],
8940 &path[2],
8941 sizeof(struct GNUNET_PeerIdentity) * (path_len - 3));
8943 hop->path_valid_until = path_valid_until;
8944 hop->distance = path_len - 3;
8945 hop->pd.aged_rtt = network_latency;
8946 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
8948 next_hop->dv_head,
8949 next_hop->dv_tail,
8950 hop);
8951 if (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
8953 return GNUNET_YES;
8954}

References activate_core_visible_dv_path(), PerformanceData::aged_rtt, DistanceVectorHop::distance, DistanceVectorHop::dv, DistanceVector::dv_head, Neighbour::dv_head, DV_PATH_DISCOVERY_FREQUENCY, DV_PATH_VALIDITY_TIMEOUT, dv_routes, DistanceVector::dv_tail, Neighbour::dv_tail, GNUNET_assert, GNUNET_break, GNUNET_CONTAINER_MDLL_insert, GNUNET_CONTAINER_MDLL_remove, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY, GNUNET_CONTAINER_multipeermap_get(), GNUNET_CONTAINER_multipeermap_put(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_INFO, GNUNET_i2s(), GNUNET_log, GNUNET_malloc, GNUNET_memcmp, GNUNET_new, GNUNET_NO, GNUNET_OK, GNUNET_PILS_get_identity(), GNUNET_SCHEDULER_add_delayed(), GNUNET_STATISTICS_update(), GNUNET_STRINGS_absolute_time_to_string(), GNUNET_SYSERR, GNUNET_TIME_absolute_get_remaining(), GNUNET_TIME_absolute_max(), GNUNET_TIME_relative_subtract(), GNUNET_TIME_relative_to_absolute(), GNUNET_TIME_UNIT_ZERO_ABS, GNUNET_YES, GST_stats, lookup_neighbour(), MAX_DV_PATHS_TO_TARGET, my_identity, DistanceVectorHop::next_hop, DistanceVectorHop::path, path_cleanup_cb(), DistanceVectorHop::path_valid_until, DistanceVectorHop::pd, Neighbour::pid, pils, q, Neighbour::queue_head, GNUNET_TIME_Relative::rel_value_us, DistanceVector::target, DistanceVectorHop::timeout, and DistanceVector::timeout_task.

Referenced by handle_dv_learn().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_dv_learn()

static int check_dv_learn ( void *  cls,
const struct TransportDVLearnMessage dvl 
)
static

Communicator gave us a DV learn message.

Check the message.

Parameters
clsa struct CommunicatorMessageContext
dvlthe send message that was sent
Returns
GNUNET_YES if message is well-formed

Definition at line 8965 of file gnunet-service-transport.c.

8966{
8967 const struct GNUNET_PeerIdentity *my_identity;
8968 uint16_t size = ntohs (dvl->header.size);
8969 uint16_t num_hops = ntohs (dvl->num_hops);
8970 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
8971
8972 (void) cls;
8973 if (size != sizeof(*dvl) + num_hops * sizeof(struct DVPathEntryP))
8974 {
8975 GNUNET_break_op (0);
8976 return GNUNET_SYSERR;
8977 }
8978 if (num_hops > MAX_DV_HOPS_ALLOWED)
8979 {
8980 GNUNET_break_op (0);
8981 return GNUNET_SYSERR;
8982 }
8983
8986
8987 for (unsigned int i = 0; i < num_hops; i++)
8988 {
8989 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
8990 {
8991 GNUNET_break_op (0);
8992 return GNUNET_SYSERR;
8993 }
8994 if (0 == GNUNET_memcmp (my_identity, &hops[i].hop))
8995 {
8996 GNUNET_break_op (0);
8997 return GNUNET_SYSERR;
8998 }
8999 }
9000 return GNUNET_YES;
9001}

References GNUNET_assert, GNUNET_break_op, GNUNET_memcmp, GNUNET_PILS_get_identity(), GNUNET_SYSERR, GNUNET_YES, TransportDVLearnMessage::header, DVPathEntryP::hop, TransportDVLearnMessage::initiator, MAX_DV_HOPS_ALLOWED, my_identity, TransportDVLearnMessage::num_hops, pils, GNUNET_MessageHeader::size, and size.

Here is the call graph for this function:

◆ forward_dv_learn()

static void forward_dv_learn ( const struct GNUNET_PeerIdentity next_hop,
const struct TransportDVLearnMessage msg,
uint16_t  bi_history,
uint16_t  nhops,
const struct DVPathEntryP hops,
struct GNUNET_TIME_Absolute  in_time 
)
static

Build and forward a DV learn message to next_hop.

Parameters
next_hoppeer to send the message to
msgmessage received
bi_historybitmask specifying hops on path that were bidirectional
nhopslength of the hops array
hopspath the message traversed so far
in_timewhen did we receive the message, used to calculate network delay

Definition at line 9016 of file gnunet-service-transport.c.

9022{
9023 struct DVPathEntryP *dhops;
9024 size_t fwd_size = sizeof(struct TransportDVLearnMessage)
9025 + (nhops + 1) * sizeof(struct DVPathEntryP);
9026 /* Signing is synchronous and the routing calls below copy the message,
9027 so this never outlives the frame. Keeping it on the stack matters:
9028 a hub forwards a DV learn to every eligible neighbour, so this is one
9029 of the hottest allocation sites in the service. Size it by the hop
9030 limit rather than by @a nhops -- @a nhops is only asserted to be below
9031 that limit further down, and a VLA is sized before we get there. */
9032 char fwd_buf[sizeof(struct TransportDVLearnMessage)
9033 + (MAX_DV_HOPS_ALLOWED + 1)
9034 * sizeof(struct DVPathEntryP)] GNUNET_ALIGN;
9035 struct TransportDVLearnMessage *fwd
9036 = (struct TransportDVLearnMessage *) fwd_buf;
9037 struct GNUNET_TIME_Relative nnd;
9038 const struct GNUNET_PeerIdentity *my_identity;
9039 struct VirtualLink *vl;
9040 struct Neighbour *n;
9041
9043 memset (fwd_buf, 0, fwd_size);
9044
9045 /* compute message for forwarding */
9047 "Forwarding DV learn message originating from %s to %s\n",
9048 GNUNET_i2s (&msg->initiator),
9049 GNUNET_i2s2 (next_hop));
9052 fwd->header.size = htons (sizeof(struct TransportDVLearnMessage)
9053 + (nhops + 1) * sizeof(struct DVPathEntryP));
9054 fwd->num_hops = htons (nhops + 1);
9055 fwd->bidirectional = htons (bi_history);
9058 msg->non_network_delay));
9060 fwd->init_sig = msg->init_sig;
9061 fwd->initiator = msg->initiator;
9062 fwd->challenge = msg->challenge;
9063 fwd->monotonic_time = msg->monotonic_time;
9064
9067
9068 dhops = (struct DVPathEntryP *) &fwd[1];
9069 GNUNET_memcpy (dhops, hops, sizeof(struct DVPathEntryP) * nhops);
9070 dhops[nhops].hop = *my_identity;
9071 {
9072 struct DvHopPS dhp = {
9074 .purpose.size = htonl (sizeof(dhp)),
9075 .pred = (0 == nhops) ? msg->initiator : dhops[nhops - 1].hop,
9076 .succ = *next_hop,
9078 };
9079
9081 &dhops[nhops].hop_sig))
9082 return; /* nobody would accept the path without our hop signature */
9083 }
9084 vl = lookup_virtual_link (next_hop);
9085 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
9086 {
9088 &fwd->header,
9090 return;
9091 }
9092 /* Use route via neighbour */
9093 n = lookup_neighbour (next_hop);
9094 if (NULL != n)
9096 &fwd->header,
9098}

References TransportDVLearnMessage::bidirectional, TransportDVLearnMessage::challenge, VirtualLink::confirmed, GNUNET_ALIGN, GNUNET_assert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_i2s2(), GNUNET_log, GNUNET_memcpy, GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN, GNUNET_OK, GNUNET_PILS_get_identity(), GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP, GNUNET_TIME_absolute_get_duration(), GNUNET_TIME_relative_add(), GNUNET_TIME_relative_hton(), GNUNET_TIME_relative_ntoh(), GNUNET_YES, TransportDVLearnMessage::header, DVPathEntryP::hop, DVPathEntryP::hop_sig, TransportDVLearnMessage::init_sig, TransportDVLearnMessage::initiator, lookup_neighbour(), lookup_virtual_link(), MAX_DV_HOPS_ALLOWED, TransportDVLearnMessage::monotonic_time, msg, my_identity, TransportDVLearnMessage::non_network_delay, TransportDVLearnMessage::num_hops, pils, GNUNET_CRYPTO_SignaturePurpose::purpose, DvHopPS::purpose, RMO_UNCONFIRMED_ALLOWED, route_control_message_without_fc(), route_via_neighbour(), sign_by_my_identity(), GNUNET_MessageHeader::size, and GNUNET_MessageHeader::type.

Referenced by dv_neighbour_transmission(), and handle_dv_learn().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ validate_dv_initiator_signature()

static int validate_dv_initiator_signature ( struct GNUNET_TIME_AbsoluteNBO  sender_monotonic_time,
const struct GNUNET_PeerIdentity init,
const struct GNUNET_CRYPTO_ChallengeNonceP challenge,
const struct GNUNET_CRYPTO_EddsaSignature init_sig 
)
static

Check signature of type GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR.

Parameters
sender_monotonic_timemonotonic time of the initiator
initthe signer
challengethe challenge that was signed
init_sigsignature presumably by init
Returns
GNUNET_OK if the signature is valid

Definition at line 9111 of file gnunet-service-transport.c.

9116{
9117 struct DvInitPS ip = { .purpose.purpose = htonl (
9119 .purpose.size = htonl (sizeof(ip)),
9120 .monotonic_time = sender_monotonic_time,
9121 .challenge = *challenge };
9122
9123 if (
9124 GNUNET_OK !=
9126 &ip,
9127 init_sig,
9128 &init->public_key))
9129 {
9130 GNUNET_break_op (0);
9131 return GNUNET_SYSERR;
9132 }
9133 return GNUNET_OK;
9134}

References DvInitPS::challenge, GNUNET_break_op, GNUNET_CRYPTO_eddsa_verify, GNUNET_OK, GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR, GNUNET_SYSERR, init, GNUNET_CRYPTO_SignaturePurpose::purpose, and DvInitPS::purpose.

Referenced by handle_dv_learn().

Here is the caller graph for this function:

◆ dv_neighbour_selection()

static int dv_neighbour_selection ( void *  cls,
const struct GNUNET_PeerIdentity pid,
void *  value 
)
static

Function called for each neighbour during handle_dv_learn.

Parameters
clsa struct NeighbourSelectionContext *
pididentity of the peer
valuea struct Neighbour
Returns
GNUNET_YES (always)

Definition at line 9193 of file gnunet-service-transport.c.

9196{
9197 struct NeighbourSelectionContext *nsc = cls;
9198
9199 (void) value;
9200 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
9201 return GNUNET_YES; /* skip initiator */
9202 for (unsigned int i = 0; i < nsc->nhops; i++)
9203 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
9204 return GNUNET_YES;
9205 /* skip peers on path */
9206 nsc->num_eligible++;
9207 return GNUNET_YES;
9208}

References NeighbourSelectionContext::dvl, GNUNET_memcmp, GNUNET_YES, DVPathEntryP::hop, NeighbourSelectionContext::hops, TransportDVLearnMessage::initiator, NeighbourSelectionContext::nhops, NeighbourSelectionContext::num_eligible, and value.

Referenced by handle_dv_learn().

Here is the caller graph for this function:

◆ dv_neighbour_transmission()

static int dv_neighbour_transmission ( void *  cls,
const struct GNUNET_PeerIdentity pid,
void *  value 
)
static

Function called for each neighbour during handle_dv_learn.

We call forward_dv_learn() on the neighbour(s) selected during dv_neighbour_selection().

Parameters
clsa struct NeighbourSelectionContext *
pididentity of the peer
valuea struct Neighbour
Returns
GNUNET_YES (always)

Definition at line 9222 of file gnunet-service-transport.c.

9225{
9226 struct NeighbourSelectionContext *nsc = cls;
9227
9229 "transmission %s\n",
9230 GNUNET_i2s (pid));
9231 (void) value;
9232 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
9233 return GNUNET_YES; /* skip initiator */
9234 for (unsigned int i = 0; i < nsc->nhops; i++)
9235 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
9236 return GNUNET_YES;
9237 /* skip peers on path */
9238 for (unsigned int i = 0; i < nsc->num_selections; i++)
9239 {
9240 if (nsc->selections[i] == nsc->num_eligible)
9241 {
9242 forward_dv_learn (pid,
9243 nsc->dvl,
9244 nsc->bi_history,
9245 nsc->nhops,
9246 nsc->hops,
9247 nsc->in_time);
9248 break;
9249 }
9250 }
9251 nsc->num_eligible++;
9252 return GNUNET_YES;
9253}

References NeighbourSelectionContext::bi_history, NeighbourSelectionContext::dvl, forward_dv_learn(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, GNUNET_memcmp, GNUNET_YES, DVPathEntryP::hop, NeighbourSelectionContext::hops, NeighbourSelectionContext::in_time, TransportDVLearnMessage::initiator, NeighbourSelectionContext::nhops, NeighbourSelectionContext::num_eligible, NeighbourSelectionContext::num_selections, NeighbourSelectionContext::selections, and value.

Referenced by handle_dv_learn().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ calculate_fork_degree()

static unsigned int calculate_fork_degree ( unsigned int  hops_taken,
unsigned int  neighbour_count,
unsigned int  eligible_count 
)
static

Computes the number of neighbours we should forward a DVInit message to given that it has so far taken hops_taken hops though the network and that the number of neighbours we have in total is neighbour_count, out of which eligible_count are not yet on the path.

NOTE: technically we might want to include NSE in the formula to get a better grip on the overall network size. However, for now using NSE here would create a dependency issue in the build system. => Left for later, hardcoded to 50 for now.

The goal of the formula is that we want to reach a total of LOG(NSE) peers via DV (target_total). We want the reach to be spread out over various distances to the origin, with a bias towards shorter distances.

We make the strong assumption that the network topology looks "similar" at other hops, in particular the neighbour_count should be comparable at other hops.

If the local neighbourhood is densely connected, we expect that eligible_count is close to neighbour_count minus hops_taken as a lot of the path is already known. In that case, we should forward to few(er) peers to try to find a path out of the neighbourhood. OTOH, if eligible_count is close to neighbour_count, we should forward to many peers as we are either still close to the origin (i.e. hops_taken is small) or because we managed to get beyond a local cluster. We express this as the boost_factor using the square of the fraction of eligible neighbours (so if only 50% are eligible, we boost by 1/4, but if 99% are eligible, the 'boost' will be almost 1).

Second, the more hops we have taken, the larger the problem of an exponential traffic explosion gets. So we take the target_total, and compute our degree such that at each distance d 2^{-d} peers are selected (corrected by the boost_factor).

Parameters
hops_takennumber of hops DVInit has travelled so far
neighbour_countnumber of neighbours we have in total
eligible_countnumber of neighbours we could in theory forward to

Definition at line 9300 of file gnunet-service-transport.c.

9303{
9304 double target_total = 50.0; /* FIXME: use LOG(NSE)? */
9305 double eligible_ratio =
9306 ((double) eligible_count) / ((double) neighbour_count);
9307 double boost_factor = eligible_ratio * eligible_ratio;
9308 unsigned int rnd;
9309 double left;
9310
9311 if (hops_taken >= 64)
9312 {
9313 GNUNET_break (0);
9314 return 0; /* precaution given bitshift below */
9315 }
9316 for (unsigned int i = 1; i < hops_taken; i++)
9317 {
9318 /* For each hop, subtract the expected number of targets
9319 reached at distance d (so what remains divided by 2^d) */
9320 target_total -= (target_total * boost_factor / (1LLU << i));
9321 }
9322 {
9323 double degree = target_total * boost_factor / (1LLU << hops_taken);
9324
9325 rnd = (unsigned int) floor (degree);
9326 /* round up or down probabilistically depending on how close we were
9327 when floor()ing to rnd. NOTE: this must be the fractional part of
9328 @e degree; using `target_total - rnd' here made the condition below
9329 true essentially always, so we always rounded up. */
9330 left = degree - (double) rnd;
9331 }
9332 if (UINT32_MAX * left >
9333 GNUNET_CRYPTO_random_u64 (UINT32_MAX))
9334 rnd++; /* round up */
9336 "Forwarding DV learn message of %u hops %u(/%u/%u) times\n",
9337 hops_taken,
9338 rnd,
9339 eligible_count,
9340 neighbour_count);
9341 return rnd;
9342}

References GNUNET_break, GNUNET_CRYPTO_random_u64(), GNUNET_ERROR_TYPE_DEBUG, and GNUNET_log.

Referenced by handle_dv_learn().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ neighbour_store_dvmono_cb()

static void neighbour_store_dvmono_cb ( void *  cls,
int  success 
)
static

Function called when peerstore is done storing a DV monotonic time.

Parameters
clsa struct Neighbour
successGNUNET_YES if peerstore was successful

Definition at line 9352 of file gnunet-service-transport.c.

9353{
9354 struct Neighbour *n = cls;
9355
9356 n->sc = NULL;
9357 if (GNUNET_YES != success)
9359 "Failed to store other peer's monotonic time in peerstore!\n");
9360}

References GNUNET_ERROR_TYPE_ERROR, GNUNET_log, GNUNET_YES, and Neighbour::sc.

Referenced by handle_dv_learn().

Here is the caller graph for this function:

◆ get_network_latency()

static struct GNUNET_TIME_Relative get_network_latency ( const struct TransportDVLearnMessage dvl)
static

Definition at line 9364 of file gnunet-service-transport.c.

9365{
9366 struct GNUNET_TIME_Relative host_latency_sum;
9367 struct GNUNET_TIME_Relative latency;
9368 struct GNUNET_TIME_Relative network_latency;
9369 uint16_t nhops = ntohs (dvl->num_hops);;
9370
9371 /* We initiated this, learn the forward path! */
9372 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
9373
9374 // Need also something to lookup initiation time
9375 // to compute RTT! -> add RTT argument here?
9377 dvl->monotonic_time));
9378 /* @e non_network_delay is fully attacker-controlled, and our clock may
9379 simply be behind the initiator's: never assert on this. */
9380 if (latency.rel_value_us < host_latency_sum.rel_value_us)
9381 {
9383 "# DV learn with implausible non-network delay",
9384 1,
9385 GNUNET_NO);
9387 }
9388 // latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
9389 // (based on dvl->challenge, we can identify time of origin!)
9390
9391 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
9392 /* assumption: latency on all links is the same */
9393 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
9394
9395 return network_latency;
9396}

References GNUNET_NO, GNUNET_STATISTICS_update(), GNUNET_TIME_absolute_get_duration(), GNUNET_TIME_absolute_ntoh(), GNUNET_TIME_relative_divide(), GNUNET_TIME_relative_ntoh(), GNUNET_TIME_relative_subtract(), GNUNET_TIME_UNIT_FOREVER_REL, GST_stats, and GNUNET_TIME_Relative::rel_value_us.

Referenced by handle_dv_learn().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_dv_learn()

static void handle_dv_learn ( void *  cls,
const struct TransportDVLearnMessage dvl 
)
static

Communicator gave us a DV learn message.

Process the request.

Parameters
clsa struct CommunicatorMessageContext (must call finish_cmc_handling() when done)
dvlthe message that was received

Definition at line 9407 of file gnunet-service-transport.c.

9408{
9409 struct CommunicatorMessageContext *cmc = cls;
9411 int bi_hop;
9412 uint16_t nhops;
9413 uint16_t bi_history;
9414 const struct DVPathEntryP *hops;
9415 int do_fwd;
9416 int did_initiator;
9417 struct GNUNET_TIME_Absolute in_time;
9418 struct Neighbour *n;
9419 const struct GNUNET_PeerIdentity *my_identity;
9420
9421 nhops = ntohs (dvl->num_hops); /* 0 = sender is initiator */
9422 bi_history = ntohs (dvl->bidirectional);
9423 hops = (const struct DVPathEntryP *) &dvl[1];
9424 if (0 == nhops)
9425 {
9426 /* sanity check */
9427 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
9428 {
9429 GNUNET_break (0);
9430 finish_cmc_handling (cmc);
9431 return;
9432 }
9433 /* A zero-hop message we supposedly initiated ourselves would make the
9434 "we are the initiator" branch below read hops[0] and write past the
9435 end of its `path[nhops + 1]' array. */
9437 {
9438 GNUNET_break_op (0);
9439 finish_cmc_handling (cmc);
9440 return;
9441 }
9442 }
9443 else
9444 {
9446 "handle dv learn message last hop %s\n",
9447 GNUNET_i2s (&hops[nhops - 1].hop));
9448 /* sanity check */
9449 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
9450 {
9451 GNUNET_break (0);
9452 finish_cmc_handling (cmc);
9453 return;
9454 }
9455 }
9456
9458 cc = cmc->tc->details.communicator.cc;
9459 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
9460 cc); // FIXME: add bi-directional flag to cc?
9461 in_time = GNUNET_TIME_absolute_get ();
9462
9463 /* continue communicator here, everything else can happen asynchronous! */
9464 finish_cmc_handling (cmc);
9465
9466 n = lookup_neighbour (&dvl->initiator);
9467 if (NULL != n)
9468 {
9469 if ((n->dv_monotime_available == GNUNET_YES) &&
9472 {
9474 "DV learn from %s discarded due to time travel",
9475 GNUNET_i2s (&dvl->initiator));
9477 "# DV learn discarded due to time travel",
9478 1,
9479 GNUNET_NO);
9480 return;
9481 }
9483 &dvl->initiator,
9484 &dvl->challenge,
9485 &dvl->init_sig))
9486 {
9488 "DV learn signature from %s invalid\n",
9489 GNUNET_i2s (&dvl->initiator));
9490 GNUNET_break_op (0);
9491 return;
9492 }
9495 {
9496 if (NULL != n->sc)
9497 {
9499 "store cancel\n");
9501 }
9502 n->sc =
9504 "transport",
9505 &dvl->initiator,
9507 &dvl->monotonic_time,
9508 sizeof(dvl->monotonic_time),
9512 n);
9513 }
9514 }
9515
9518
9519 /* OPTIMIZE-FIXME: asynchronously (!) verify signatures!,
9520 If signature verification load too high, implement random drop strategy */
9521 for (unsigned int i = 0; i < nhops; i++)
9522 {
9523 struct DvHopPS dhp = { .purpose.purpose =
9525 .purpose.size = htonl (sizeof(dhp)),
9526 .pred = (0 == i) ? dvl->initiator : hops[i - 1].hop,
9527 .succ = (nhops == i + 1) ? *my_identity
9528 : hops[i + 1].hop,
9529 .challenge = dvl->challenge };
9530
9531 if (GNUNET_OK !=
9533 &dhp,
9534 &hops[i].hop_sig,
9535 &hops[i].hop.public_key))
9536 {
9538 "DV learn from %s signature of hop %u invalid\n",
9539 GNUNET_i2s (&dvl->initiator),
9540 i);
9542 "signature of hop %s invalid\n",
9543 GNUNET_i2s (&hops[i].hop));
9545 "pred %s\n",
9546 GNUNET_i2s (&dhp.pred));
9548 "succ %s\n",
9549 GNUNET_i2s (&dhp.succ));
9551 "hash %s\n",
9552 GNUNET_sh2s (&dhp.challenge.value));
9553 GNUNET_break_op (0);
9554 return;
9555 }
9556 }
9557 if (GNUNET_EXTRA_LOGGING > 0)
9558 {
9559 char *path;
9560
9561 path = GNUNET_strdup (GNUNET_i2s (&dvl->initiator));
9562 for (unsigned int i = 0; i < nhops; i++)
9563 {
9564 char *tmp;
9565
9566 GNUNET_asprintf (&tmp,
9567 "%s%s%s",
9568 path,
9569 (bi_history & (1 << (nhops - i))) ? "<->" : "-->",
9570 GNUNET_i2s (&hops[i].hop));
9571 GNUNET_free (path);
9572 path = tmp;
9573 }
9575 "Received DVInit via %s%s%s\n",
9576 path,
9577 bi_hop ? "<->" : "-->",
9579 GNUNET_free (path);
9580 }
9581 do_fwd = GNUNET_YES;
9582 if (0 == GNUNET_memcmp (my_identity, &dvl->initiator))
9583 {
9584 struct GNUNET_PeerIdentity path[nhops + 1];
9585 struct GNUNET_TIME_Relative network_latency;
9586
9587 /* We initiated this, learn the forward path! */
9588 path[0] = *my_identity;
9589 path[1] = hops[0].hop;
9590
9591 network_latency = get_network_latency (dvl);
9592
9593 for (unsigned int i = 2; i <= nhops; i++)
9594 {
9595 struct GNUNET_TIME_Relative ilat;
9596
9597 /* assumption: linear latency increase per hop */
9598 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
9599 path[i] = hops[i - 1].hop;
9601 "Learned path with %u hops to %s with latency %s\n",
9602 i,
9603 GNUNET_i2s (&path[i]),
9605 learn_dv_path (path,
9606 i + 1,
9607 ilat,
9610 }
9611 /* as we initiated, do not forward again (would be circular!) */
9612 do_fwd = GNUNET_NO;
9613 return;
9614 }
9615 if (bi_hop)
9616 {
9617 /* last hop was bi-directional, we could learn something here! */
9618 struct GNUNET_PeerIdentity path[nhops + 2];
9619 struct GNUNET_TIME_Relative ilat;
9620 struct GNUNET_TIME_Relative network_latency;
9621
9622 path[0] = *my_identity;
9623 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
9624 for (unsigned int i = 0; i < nhops; i++)
9625 {
9626 int iret;
9627
9628 if (0 == (bi_history & (1 << i)))
9629 break; /* i-th hop not bi-directional, stop learning! */
9630 if (i == nhops - 1)
9631 {
9632 path[i + 2] = dvl->initiator;
9633 }
9634 else
9635 {
9636 path[i + 2] = hops[nhops - i - 2].hop;
9637 }
9638
9640 "Learned inverse path with %u hops to %s\n",
9641 i + 2,
9642 GNUNET_i2s (&path[i + 2]));
9643 network_latency = get_network_latency (dvl);
9644 ilat = GNUNET_TIME_relative_multiply (network_latency, i + 2);
9645 iret = learn_dv_path (path,
9646 i + 3,
9647 ilat,
9650 if (GNUNET_SYSERR == iret)
9651 {
9652 /* path invalid or too long to be interesting for US, thus should also
9653 not be interesting to our neighbours, cut path when forwarding to
9654 'i' hops, except of course for the one that goes back to the
9655 initiator */
9657 "# DV learn not forwarded due invalidity of path",
9658 1,
9659 GNUNET_NO);
9660 do_fwd = GNUNET_NO;
9661 break;
9662 }
9663 if ((GNUNET_NO == iret) && (nhops == i + 1))
9664 {
9665 /* we have better paths, and this is the longest target,
9666 so there cannot be anything interesting later */
9668 "# DV learn not forwarded, got better paths",
9669 1,
9670 GNUNET_NO);
9671 do_fwd = GNUNET_NO;
9672 break;
9673 }
9674 }
9675 }
9676 if (MAX_DV_HOPS_ALLOWED == nhops)
9677 {
9678 /* At limit, we're out of here! */
9679 return;
9680 }
9681
9682 /* Forward to initiator, if path non-trivial and possible */
9683 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
9684 did_initiator = GNUNET_NO;
9685 if ((1 <= nhops) &&
9686 (GNUNET_YES ==
9688 {
9689 /* send back to origin! */
9691 "Sending DVL back to initiator %s\n",
9692 GNUNET_i2s (&dvl->initiator));
9693 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
9694 did_initiator = GNUNET_YES;
9695 }
9696 /* We forward under two conditions: either we still learned something
9697 ourselves (do_fwd), or the path was darn short and thus the initiator is
9698 likely to still be very interested in this (and we did NOT already
9699 send it back to the initiator) */
9700 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
9701 (GNUNET_NO == did_initiator)))
9702 {
9703 /* Pick random neighbours that are not yet on the path */
9704 struct NeighbourSelectionContext nsc;
9705 unsigned int n_cnt;
9706 unsigned int n_eligible;
9707
9709 nsc.nhops = nhops;
9710 nsc.dvl = dvl;
9711 nsc.bi_history = bi_history;
9712 nsc.hops = hops;
9713 nsc.in_time = in_time;
9714 nsc.num_eligible = 0;
9717 &nsc);
9718 if (0 == nsc.num_eligible)
9719 return; /* done here, cannot forward to anyone else */
9720 n_eligible = nsc.num_eligible;
9721 nsc.num_selections = calculate_fork_degree (nhops, n_cnt, n_eligible);
9722 nsc.num_selections =
9723 GNUNET_MIN (MAX_DV_DISCOVERY_SELECTION, nsc.num_selections);
9725 "Forwarding DVL to %u other peers\n",
9726 nsc.num_selections);
9727 /* #dv_neighbour_transmission() counts ELIGIBLE peers only, so the
9728 offsets must be drawn from that range -- drawing from the total
9729 number of neighbours made us silently forward to fewer peers than
9730 #calculate_fork_degree() asked for. */
9731 for (unsigned int i = 0; i < nsc.num_selections; i++)
9732 nsc.selections[i] =
9733 (nsc.num_selections == n_eligible)
9734 ? i /* all were selected, avoid collisions by chance */
9735 : GNUNET_CRYPTO_random_u32 (n_eligible);
9736 nsc.num_eligible = 0;
9739 &nsc);
9740 }
9741}

References GNUNET_TIME_Absolute::abs_value_us, ADDRESS_VALIDATION_LIFETIME, NeighbourSelectionContext::bi_history, TransportDVLearnMessage::bidirectional, calculate_fork_degree(), TransportClient::cc, DvHopPS::challenge, TransportDVLearnMessage::challenge, TransportClient::communicator, CT_COMMUNICATOR, TransportClient::details, Neighbour::dv_monotime_available, dv_neighbour_selection(), dv_neighbour_transmission(), NeighbourSelectionContext::dvl, finish_cmc_handling(), forward_dv_learn(), get_network_latency(), GNUNET_asprintf(), GNUNET_assert, GNUNET_break, GNUNET_break_op, GNUNET_CONTAINER_multipeermap_contains(), GNUNET_CONTAINER_multipeermap_iterate(), GNUNET_CONTAINER_multipeermap_size(), GNUNET_CRYPTO_eddsa_verify, GNUNET_CRYPTO_random_u32(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_EXTRA_LOGGING, GNUNET_free, GNUNET_i2s(), GNUNET_log, GNUNET_memcmp, GNUNET_MIN, GNUNET_NO, GNUNET_OK, GNUNET_PEERSTORE_store(), GNUNET_PEERSTORE_store_cancel(), GNUNET_PEERSTORE_STOREOPTION_REPLACE, GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME, GNUNET_PILS_get_identity(), GNUNET_sh2s(), GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP, GNUNET_STATISTICS_update(), GNUNET_strdup, GNUNET_STRINGS_relative_time_to_string(), GNUNET_SYSERR, GNUNET_TIME_absolute_get(), GNUNET_TIME_absolute_ntoh(), GNUNET_TIME_relative_multiply(), GNUNET_TIME_relative_to_absolute(), GNUNET_TIME_UNIT_FOREVER_ABS, GNUNET_TRANSPORT_CC_RELIABLE, GNUNET_YES, GST_stats, DVPathEntryP::hop, NeighbourSelectionContext::hops, CommunicatorMessageContext::im, NeighbourSelectionContext::in_time, TransportDVLearnMessage::init_sig, TransportDVLearnMessage::initiator, Neighbour::last_dv_learn_monotime, learn_dv_path(), lookup_neighbour(), MAX_DV_DISCOVERY_SELECTION, MAX_DV_HOPS_ALLOWED, MIN_DV_PATH_LENGTH_FOR_INITIATOR, TransportDVLearnMessage::monotonic_time, my_identity, neighbour_store_dvmono_cb(), neighbours, NeighbourSelectionContext::nhops, NeighbourSelectionContext::num_eligible, TransportDVLearnMessage::num_hops, NeighbourSelectionContext::num_selections, peerstore, pils, DvHopPS::pred, GNUNET_CRYPTO_SignaturePurpose::purpose, DvHopPS::purpose, Neighbour::sc, NeighbourSelectionContext::selections, GNUNET_TRANSPORT_IncomingMessage::sender, DvHopPS::succ, CommunicatorMessageContext::tc, TransportClient::type, validate_dv_initiator_signature(), and GNUNET_CRYPTO_ChallengeNonceP::value.

Here is the call graph for this function:

◆ check_dv_box()

static int check_dv_box ( void *  cls,
const struct TransportDVBoxMessage dvb 
)
static

Communicator gave us a DV box.

Check the message.

Parameters
clsa struct CommunicatorMessageContext
dvbthe send message that was sent
Returns
GNUNET_YES if message is well-formed

Definition at line 9752 of file gnunet-service-transport.c.

9753{
9754 uint16_t size = ntohs (dvb->header.size);
9755 uint16_t num_hops = ntohs (dvb->num_hops);
9756 uint16_t total_hops = ntohs (dvb->total_hops);
9757 uint16_t orig_size = ntohs (dvb->orig_size);
9758 const struct GNUNET_PeerIdentity *hops =
9759 (const struct GNUNET_PeerIdentity *) &dvb[1];
9760 const struct GNUNET_PeerIdentity *my_identity;
9761
9762 (void) cls;
9763 if (size < sizeof(*dvb) + num_hops * sizeof(struct GNUNET_PeerIdentity)
9764 + sizeof(struct GNUNET_MessageHeader))
9765 {
9766 GNUNET_break_op (0);
9767 return GNUNET_SYSERR;
9768 }
9769 if ((num_hops > MAX_DV_HOPS_ALLOWED) ||
9770 (total_hops > MAX_DV_HOPS_ALLOWED))
9771 {
9772 GNUNET_break_op (0);
9773 return GNUNET_SYSERR;
9774 }
9775 /* #decaps_dv_box_cb() derives a VLA size from
9776 orig_size - sizeof(*dvb) - total_hops * sizeof (struct
9777 GNUNET_PeerIdentity); make sure that cannot underflow and that the
9778 remainder can plausibly hold a payload header plus a message. */
9779 if ((orig_size < size) ||
9780 (orig_size < sizeof(*dvb)
9781 + total_hops * sizeof(struct GNUNET_PeerIdentity)
9782 + sizeof(struct TransportDVBoxPayloadP)
9783 + sizeof(struct GNUNET_MessageHeader)))
9784 {
9785 GNUNET_break_op (0);
9786 return GNUNET_SYSERR;
9787 }
9788
9791
9792 /* This peer must not be on the path */
9793 for (unsigned int i = 0; i < num_hops; i++)
9794 if (0 == GNUNET_memcmp (&hops[i], my_identity))
9795 {
9796 GNUNET_break_op (0);
9797 return GNUNET_SYSERR;
9798 }
9799 return GNUNET_YES;
9800}

References GNUNET_assert, GNUNET_break_op, GNUNET_memcmp, GNUNET_PILS_get_identity(), GNUNET_SYSERR, GNUNET_YES, TransportDVBoxMessage::header, MAX_DV_HOPS_ALLOWED, my_identity, TransportDVBoxMessage::num_hops, TransportDVBoxMessage::orig_size, pils, GNUNET_MessageHeader::size, size, and TransportDVBoxMessage::total_hops.

Here is the call graph for this function:

◆ forward_dv_box()

static void forward_dv_box ( struct Neighbour next_hop,
struct TransportDVBoxMessage hdr,
uint16_t  total_hops,
uint16_t  num_hops,
const struct GNUNET_PeerIdentity hops,
const void *  enc_payload,
uint16_t  enc_payload_size 
)
static

Create a DV Box message and queue it for transmission to next_hop.

Parameters
next_hoppeer to receive the message next
total_hopshow many hops did the message take so far
num_hopslength of the hops array
originorigin of the message
hopsnext peer(s) to the destination, including destination
payloadpayload of the box
payload_sizenumber of bytes in payload

Definition at line 9816 of file gnunet-service-transport.c.

9823{
9824 struct VirtualLink *vl = next_hop->vl;
9825 struct PendingMessage *pm;
9826 size_t msg_size = sizeof(struct TransportDVBoxMessage)
9827 + num_hops * sizeof(struct GNUNET_PeerIdentity)
9828 + enc_payload_size;
9829 char *buf;
9830 char msg_buf[msg_size] GNUNET_ALIGN;
9831 struct GNUNET_PeerIdentity *dhops;
9832
9833 hdr->num_hops = htons (num_hops);
9834 hdr->total_hops = htons (total_hops);
9835 hdr->header.size = htons (msg_size);
9836 memcpy (msg_buf, hdr, sizeof(*hdr));
9837 dhops = (struct GNUNET_PeerIdentity *) &msg_buf[sizeof(struct
9839 ;
9840 memcpy (dhops, hops, num_hops * sizeof(struct GNUNET_PeerIdentity));
9841 memcpy (&dhops[num_hops], enc_payload, enc_payload_size);
9842
9843 if (GNUNET_YES == ntohl (hdr->without_fc))
9844 {
9846 "Forwarding control message (payload size %u) in DV Box to next hop %s (%u/%u) \n",
9847 enc_payload_size,
9848 GNUNET_i2s (&next_hop->pid),
9849 (unsigned int) num_hops,
9850 (unsigned int) total_hops);
9851 route_via_neighbour (next_hop, (const struct
9852 GNUNET_MessageHeader *) msg_buf,
9854 }
9855 else
9856 {
9857 pm = GNUNET_malloc (sizeof(struct PendingMessage) + msg_size);
9859 "2 created pm %p storing vl %p \n",
9860 pm,
9861 vl);
9862 pm->pmt = PMT_DV_BOX;
9863 pm->vl = vl;
9864 pm->target = next_hop->pid;
9868 pm->bytes_msg = msg_size;
9869 buf = (char *) &pm[1];
9870 memcpy (buf, msg_buf, msg_size);
9871
9873 "Created pending message %" PRIu64
9874 " for DV Box with next hop %s (%u/%u)\n",
9875 pm->logging_uuid,
9876 GNUNET_i2s (&next_hop->pid),
9877 (unsigned int) num_hops,
9878 (unsigned int) total_hops);
9879
9880 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
9881 {
9883 vl->pending_msg_head,
9884 vl->pending_msg_tail,
9885 pm);
9886
9888 }
9889 else
9890 {
9892 "The virtual link is not ready for forwarding a DV Box with payload, storing PendingMessage in ring buffer.\n");
9893
9895 {
9897
9898 GNUNET_free (pm_old);
9899 }
9902 {
9905 }
9906 else
9908
9910 "%u items stored in DV ring buffer\n",
9913 }
9914 }
9915}

References PendingMessage::bytes_msg, check_vl_transmission(), VirtualLink::confirmed, DV_FORWARD_TIMEOUT, GNUNET_ALIGN, GNUNET_CONTAINER_MDLL_insert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_i2s(), GNUNET_log, GNUNET_malloc, GNUNET_MQ_PRIO_BACKGROUND, GNUNET_TIME_relative_to_absolute(), GNUNET_YES, TransportDVBoxMessage::header, is_ring_buffer_dv_full, PendingMessage::logging_uuid, logging_uuid_gen, TransportDVBoxMessage::num_hops, VirtualLink::pending_msg_head, VirtualLink::pending_msg_tail, Neighbour::pid, PendingMessage::pmt, PMT_DV_BOX, PendingMessage::prefs, ring_buffer_dv, ring_buffer_dv_head, RING_BUFFER_SIZE, RMO_ANYTHING_GOES, route_via_neighbour(), GNUNET_MessageHeader::size, PendingMessage::target, PendingMessage::timeout, TransportDVBoxMessage::total_hops, Neighbour::vl, PendingMessage::vl, and TransportDVBoxMessage::without_fc.

Referenced by handle_dv_box().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ free_backtalker()

static void free_backtalker ( struct Backtalker b)
static

Free data structures associated with b.

Parameters
bdata structure to release

Definition at line 9924 of file gnunet-service-transport.c.

9925{
9926 if (NULL != b->get)
9927 {
9929 b->get = NULL;
9930 GNUNET_assert (NULL != b->cmc);
9932 b->cmc = NULL;
9933 }
9934 if (NULL != b->task)
9935 {
9937 b->task = NULL;
9938 }
9939 if (NULL != b->sc)
9940 {
9942 "store cancel\n");
9944 b->sc = NULL;
9945 }
9947 "Removing backtalker for %s\n",
9948 GNUNET_i2s (&b->pid));
9950 GNUNET_YES ==
9952 GNUNET_free (b);
9953}

References backtalkers, Backtalker::cmc, finish_cmc_handling(), Backtalker::get, GNUNET_assert, GNUNET_CONTAINER_multipeermap_remove(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_i2s(), GNUNET_log, GNUNET_PEERSTORE_iteration_stop(), GNUNET_PEERSTORE_store_cancel(), GNUNET_SCHEDULER_cancel(), GNUNET_YES, Backtalker::pid, Backtalker::sc, and Backtalker::task.

Referenced by backtalker_timeout_cb(), and free_backtalker_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ free_backtalker_cb()

static int free_backtalker_cb ( void *  cls,
const struct GNUNET_PeerIdentity pid,
void *  value 
)
static

Callback to free backtalker records.

Parameters
clsNULL
pidunused
valuea struct Backtalker
Returns
GNUNET_OK (always)

Definition at line 9965 of file gnunet-service-transport.c.

9968{
9969 struct Backtalker *b = value;
9970
9971 (void) cls;
9972 (void) pid;
9973 free_backtalker (b);
9974 return GNUNET_OK;
9975}

References free_backtalker(), GNUNET_OK, Backtalker::pid, and value.

Referenced by do_shutdown().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ backtalker_timeout_cb()

static void backtalker_timeout_cb ( void *  cls)
static

Function called when it is time to clean up a backtalker.

Parameters
clsa struct Backtalker

Definition at line 9984 of file gnunet-service-transport.c.

9985{
9986 struct Backtalker *b = cls;
9987
9989 "backtalker timeout.\n");
9990 b->task = NULL;
9992 {
9994 return;
9995 }
9996 /* A monotime store may well still be in flight -- @e timeout is about how
9997 long the *peer* has been quiet, and says nothing about PEERSTORE. This
9998 used to `GNUNET_assert (NULL == b->sc)', which aborted the service in
9999 exactly that case. #free_backtalker() cancels the store. */
10000 free_backtalker (b);
10001}

References backtalker_timeout_cb(), free_backtalker(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_SCHEDULER_add_at(), GNUNET_TIME_absolute_get_remaining(), GNUNET_TIME_Relative::rel_value_us, Backtalker::task, and Backtalker::timeout.

Referenced by backtalker_timeout_cb(), and decaps_dv_box_cont().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ backtalker_monotime_cb()

static void backtalker_monotime_cb ( void *  cls,
const struct GNUNET_PEERSTORE_Record record,
const char *  emsg 
)
static

Function called with the monotonic time of a backtalker by PEERSTORE.

Updates the time and continues processing.

Parameters
clsa struct Backtalker
recordthe information found, NULL for the last call
emsgerror message

Definition at line 10013 of file gnunet-service-transport.c.

10016{
10017 struct Backtalker *b = cls;
10018 struct GNUNET_TIME_AbsoluteNBO *mtbe;
10019 struct GNUNET_TIME_Absolute mt;
10020
10021 (void) emsg;
10022 if (NULL == record)
10023 {
10024 struct CommunicatorMessageContext *cmc;
10025
10026 /* we're done with #backtalker_monotime_cb() invocations,
10027 continue normal processing */
10028 b->get = NULL;
10029 GNUNET_assert (NULL != b->cmc);
10030 /* Take @e cmc out of @a b *before* dispatching: the dispatch runs
10031 arbitrary message handling, and writing `b->cmc = NULL' afterwards
10032 is a write to freed memory should anything on that path have
10033 released @a b. #free_backtalker() keys its "must finish the parked
10034 cmc" decision off @e get, which is already NULL here, so clearing
10035 @e cmc early cannot lose the message either. */
10036 cmc = b->cmc;
10037 b->cmc = NULL;
10038 cmc->mh = (const struct GNUNET_MessageHeader *) &b[1];
10039 if (0 != b->body_size)
10041 else
10042 finish_cmc_handling (cmc);
10043 return;
10044 }
10045 if (sizeof(*mtbe) != record->value_size)
10046 {
10048 GNUNET_break (0);
10049 return;
10050 }
10051 mtbe = record->value;
10052 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
10053 if (mt.abs_value_us > b->monotonic_time.abs_value_us)
10054 {
10056 "Backtalker message from %s dropped, monotime in the past\n",
10057 GNUNET_i2s (&b->pid));
10059 GST_stats,
10060 "# Backchannel messages dropped: monotonic time not increasing",
10061 1,
10062 GNUNET_NO);
10063 b->monotonic_time = mt;
10064 /* Setting body_size to 0 prevents call to #forward_backchannel_payload()
10065 */
10066 b->body_size = 0;
10067 }
10069}

References GNUNET_TIME_Absolute::abs_value_us, Backtalker::body_size, Backtalker::cmc, demultiplex_with_cmc(), finish_cmc_handling(), Backtalker::get, GNUNET_assert, GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, GNUNET_NO, GNUNET_PEERSTORE_iteration_next(), GNUNET_STATISTICS_update(), GNUNET_TIME_absolute_ntoh(), GST_stats, CommunicatorMessageContext::mh, Backtalker::monotonic_time, Backtalker::pid, and record().

Referenced by decaps_dv_box_cont().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ backtalker_monotime_store_cb()

static void backtalker_monotime_store_cb ( void *  cls,
int  success 
)
static

Function called by PEERSTORE when the store operation of a backtalker's monotonic time is complete.

Parameters
clsthe struct Backtalker
successGNUNET_OK on success

Definition at line 10080 of file gnunet-service-transport.c.

10081{
10082 struct Backtalker *b = cls;
10083
10084 if (GNUNET_OK != success)
10085 {
10087 "Failed to store backtalker's monotonic time in PEERSTORE!\n");
10088 }
10089 b->sc = NULL;
10090 /* @e task is armed for the whole life of @a b -- #backtalker_timeout_cb()
10091 re-arms itself whenever @e timeout has moved forward -- so there is
10092 nothing to do here beyond releasing the store. It used to cancel and
10093 re-add the task, which is what made the task's existence depend on this
10094 callback ever running. */
10095 GNUNET_assert (NULL != b->task);
10096}

References GNUNET_assert, GNUNET_ERROR_TYPE_ERROR, GNUNET_log, GNUNET_OK, Backtalker::sc, and Backtalker::task.

Referenced by update_backtalker_monotime().

Here is the caller graph for this function:

◆ update_backtalker_monotime()

static void update_backtalker_monotime ( struct Backtalker b)
static

The backtalker b monotonic time changed.

Update PEERSTORE.

Parameters
ba backtalker with updated monotonic time

Definition at line 10105 of file gnunet-service-transport.c.

10106{
10107 struct GNUNET_TIME_AbsoluteNBO mtbe;
10108
10109 /* At most one store may be outstanding. The value we are about to write
10110 supersedes whatever the previous one carried, and leaving the old
10111 context alive means its completion clears @e sc while the newer store
10112 is still in flight -- after which the next update sees a NULL @e sc and
10113 starts a third one. Cancelling is also what keeps @e sc from being
10114 silently overwritten and leaked.
10115
10116 Note what this must NOT do: touch @e task. That task is the only thing
10117 that ever releases a `struct CommunicatorMessageContext' parked in
10118 @e cmc, and cancelling it here left its re-arming up to
10119 #backtalker_monotime_store_cb() -- i.e. up to PEERSTORE answering. A
10120 lost store completion then stalled the parked communicator client for
10121 the life of the process. #backtalker_timeout_cb() already re-arms
10122 itself against the current @e timeout, so the task needs no help. */
10123 if (NULL != b->sc)
10124 {
10126 "Superseding in-flight backtalker monotime store %p\n",
10127 b->sc);
10129 b->sc = NULL;
10130 }
10132 b->sc =
10134 "transport",
10135 &b->pid,
10137 &mtbe,
10138 sizeof(mtbe),
10142 b);
10143}

References backtalker_monotime_store_cb(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_PEERSTORE_store(), GNUNET_PEERSTORE_store_cancel(), GNUNET_PEERSTORE_STOREOPTION_REPLACE, GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME, GNUNET_TIME_absolute_hton(), GNUNET_TIME_UNIT_FOREVER_ABS, Backtalker::monotonic_time, peerstore, Backtalker::pid, and Backtalker::sc.

Referenced by decaps_dv_box_cont().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ decaps_dv_box_cont()

static void decaps_dv_box_cont ( struct CommunicatorMessageContext cmc,
const struct TransportDVBoxMessage dvb,
const struct GNUNET_ShortHashCode km 
)
static

Open the DV box dvb addressed to us, using the key material km decapsulated from its ephemeral key.

Parameters
cmccontext of the message being handled
dvbthe box, valid for the duration of this call
kmdecapsulation of dvb's ephemeral_key

Definition at line 10155 of file gnunet-service-transport.c.

10158{
10159 const unsigned char *hdr;
10160 size_t hdr_len;
10162
10163 key = (struct GNUNET_CRYPTO_AeadSecretKey*) km;
10164 /* We are the ultimate target, so #handle_dv_box() has established that no
10165 hop entries are left: the ciphertext directly follows the header, and
10166 its length is what we actually received. Deriving it from orig_size
10167 and total_hops instead would only be equivalent if every forwarder
10168 accounted its skipped hops exactly. */
10169 hdr = (const unsigned char *) &dvb[1];
10170 {
10171 uint16_t size = ntohs (dvb->header.size);
10172
10173 if (size < sizeof(*dvb)
10174 + sizeof(struct TransportDVBoxPayloadP)
10175 + sizeof(struct GNUNET_MessageHeader))
10176 {
10177 GNUNET_break_op (0);
10178 finish_cmc_handling (cmc);
10179 return;
10180 }
10181 hdr_len = size - sizeof(*dvb);
10182 }
10183
10184 /* begin actual decryption */
10185 {
10186 struct Backtalker *b;
10187 struct GNUNET_TIME_Absolute monotime;
10188 struct TransportDVBoxPayloadP *ppay;
10189 unsigned char pt[hdr_len + sizeof *ppay] GNUNET_ALIGN;
10190 unsigned char *body;
10191 const struct GNUNET_MessageHeader *mh;
10192
10193 ppay = (struct TransportDVBoxPayloadP *) pt;
10194 body = &pt[sizeof *ppay];
10195 GNUNET_assert (hdr_len >=
10196 sizeof(*ppay) + sizeof(struct GNUNET_MessageHeader));
10197 if (GNUNET_OK != GNUNET_CRYPTO_aead_decrypt (hdr_len,
10198 hdr,
10199 0,
10200 NULL,
10201 key,
10202 &dvb->iv,
10203 &dvb->mac,
10204 pt))
10205 {
10207 "Error decrypting DV payload header\n");
10208 GNUNET_break_op (0);
10209 finish_cmc_handling (cmc);
10210 return;
10211 }
10212 mh = (const struct GNUNET_MessageHeader *) body;
10213 /* NOTE: this used to compare against `sizeof (body)', i.e. the size of
10214 a pointer, which meant only 8-byte payloads were ever accepted. */
10215 if (ntohs (mh->size) != hdr_len - sizeof(*ppay))
10216 {
10217 GNUNET_break_op (0);
10218 finish_cmc_handling (cmc);
10219 return;
10220 }
10221 /* need to prevent box-in-a-box (and DV_LEARN) so check inbox type! */
10222 switch (ntohs (mh->type))
10223 {
10225 GNUNET_break_op (0);
10226 finish_cmc_handling (cmc);
10227 return;
10228
10230 GNUNET_break_op (0);
10231 finish_cmc_handling (cmc);
10232 return;
10233
10234 default:
10235 /* permitted, continue */
10236 break;
10237 }
10238 monotime = GNUNET_TIME_absolute_ntoh (ppay->monotonic_time);
10240 "Decrypted backtalk from %s\n",
10241 GNUNET_i2s (&ppay->sender));
10243 &ppay->sender);
10244 if ((NULL != b) && (monotime.abs_value_us < b->monotonic_time.abs_value_us))
10245 {
10247 GST_stats,
10248 "# Backchannel messages dropped: monotonic time not increasing",
10249 1,
10250 GNUNET_NO);
10251 finish_cmc_handling (cmc);
10252 return;
10253 }
10254 if ((NULL == b) ||
10255 (0 != GNUNET_memcmp (&b->last_ephemeral, &dvb->ephemeral_key)))
10256 {
10257 /* Check signature */
10258 const struct GNUNET_PeerIdentity *my_identity;
10259 struct EphemeralConfirmationPS ec;
10260
10263
10264 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
10265 ec.target = *my_identity;
10266 ec.ephemeral_key = dvb->ephemeral_key;
10267 ec.purpose.size = htonl (sizeof(ec));
10268 ec.sender_monotonic_time = ppay->monotonic_time;
10269 if (
10270 GNUNET_OK !=
10273 &ec,
10274 &ppay->sender_sig,
10275 &ppay->sender.public_key))
10276 {
10277 /* Signature invalid, discard! */
10278 GNUNET_break_op (0);
10279 finish_cmc_handling (cmc);
10280 return;
10281 }
10282 }
10283 /* Update sender, we now know the real origin! */
10285 "DVBox received for me from %s via %s\n",
10286 GNUNET_i2s2 (&ppay->sender),
10287 GNUNET_i2s (&cmc->im.sender));
10288 cmc->im.sender = ppay->sender;
10289
10290 if (NULL != b)
10291 {
10292 /* update key cache and mono time */
10293 b->last_ephemeral = dvb->ephemeral_key;
10294 b->monotonic_time = monotime;
10296 b->timeout =
10298 cmc->mh = mh;
10300 return;
10301 }
10302 /* setup data structure to cache signature AND check
10303 monotonic time with PEERSTORE before forwarding backchannel payload */
10304 b = GNUNET_malloc (sizeof(struct Backtalker) + (hdr_len - sizeof(*ppay)));
10305 b->pid = ppay->sender;
10306 b->body_size = hdr_len - sizeof(*ppay);
10307 memcpy (&b[1], body, hdr_len - sizeof(*ppay));
10311 &b->pid,
10312 b,
10314 b->monotonic_time = monotime; /* NOTE: to be checked still! */
10315 b->cmc = cmc;
10316 b->timeout =
10319 b->get =
10321 "transport",
10322 &b->pid,
10325 b);
10326 } /* end actual decryption */
10327}

References GNUNET_TIME_Absolute::abs_value_us, BACKCHANNEL_INACTIVITY_TIMEOUT, backtalker_monotime_cb(), backtalker_timeout_cb(), backtalkers, Backtalker::body_size, Backtalker::cmc, demultiplex_with_cmc(), EphemeralConfirmationPS::ephemeral_key, TransportDVBoxMessage::ephemeral_key, finish_cmc_handling(), Backtalker::get, GNUNET_ALIGN, GNUNET_assert, GNUNET_break_op, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY, GNUNET_CONTAINER_multipeermap_get(), GNUNET_CONTAINER_multipeermap_put(), GNUNET_CRYPTO_aead_decrypt(), GNUNET_CRYPTO_eddsa_verify, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_i2s(), GNUNET_i2s2(), GNUNET_log, GNUNET_malloc, GNUNET_memcmp, GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX, GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN, GNUNET_NO, GNUNET_OK, GNUNET_PEERSTORE_iteration_start(), GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME, GNUNET_PILS_get_identity(), GNUNET_SCHEDULER_add_at(), GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL, GNUNET_STATISTICS_update(), GNUNET_TIME_absolute_ntoh(), GNUNET_TIME_relative_to_absolute(), GNUNET_YES, GST_stats, TransportDVBoxMessage::header, CommunicatorMessageContext::im, TransportDVBoxMessage::iv, key, Backtalker::last_ephemeral, TransportDVBoxMessage::mac, mh, CommunicatorMessageContext::mh, TransportDVBoxPayloadP::monotonic_time, Backtalker::monotonic_time, my_identity, peerstore, Backtalker::pid, pils, GNUNET_PeerIdentity::public_key, GNUNET_CRYPTO_SignaturePurpose::purpose, EphemeralConfirmationPS::purpose, TransportDVBoxPayloadP::sender, GNUNET_TRANSPORT_IncomingMessage::sender, EphemeralConfirmationPS::sender_monotonic_time, TransportDVBoxPayloadP::sender_sig, GNUNET_MessageHeader::size, GNUNET_CRYPTO_SignaturePurpose::size, size, EphemeralConfirmationPS::target, Backtalker::task, Backtalker::timeout, and update_backtalker_monotime().

Referenced by handle_dv_box().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_dv_box()

static void handle_dv_box ( void *  cls,
const struct TransportDVBoxMessage dvb 
)
static

Communicator gave us a DV box.

Process the request.

Parameters
clsa struct CommunicatorMessageContext (must call finish_cmc_handling() when done)
dvbthe message that was received

Definition at line 10338 of file gnunet-service-transport.c.

10339{
10340 struct CommunicatorMessageContext *cmc = cls;
10341 uint16_t size = ntohs (dvb->header.size) - sizeof(*dvb);
10342 uint16_t num_hops = ntohs (dvb->num_hops);
10343 const struct GNUNET_PeerIdentity *hops =
10344 (const struct GNUNET_PeerIdentity *) &dvb[1];
10345 const char *enc_payload = (const char *) &hops[num_hops];
10346 uint16_t enc_payload_size =
10347 size - (num_hops * sizeof(struct GNUNET_PeerIdentity));
10348 const struct GNUNET_PeerIdentity *my_identity;
10349
10352
10353 if (GNUNET_EXTRA_LOGGING > 0)
10354 {
10355 char *path;
10356
10358 for (unsigned int i = 0; i < num_hops; i++)
10359 {
10360 char *tmp;
10361
10362 GNUNET_asprintf (&tmp, "%s->%s", path, GNUNET_i2s (&hops[i]));
10363 GNUNET_free (path);
10364 path = tmp;
10365 }
10367 "Received DVBox with remaining path %s\n",
10368 path);
10369 GNUNET_free (path);
10370 }
10371
10372 if (num_hops > 0)
10373 {
10374 /* We're trying from the end of the hops array, as we may be
10375 able to find a shortcut unknown to the origin that way */
10376 for (int i = num_hops - 1; i >= 0; i--)
10377 {
10378 struct Neighbour *n;
10379
10380 if (0 == GNUNET_memcmp (&hops[i], my_identity))
10381 {
10382 GNUNET_break_op (0);
10383 finish_cmc_handling (cmc);
10384 return;
10385 }
10386 n = lookup_neighbour (&hops[i]);
10387 if (NULL == n)
10388 continue;
10390 "Skipping %u/%u hops ahead while routing DV Box\n",
10391 i,
10392 num_hops);
10393
10394 forward_dv_box (n,
10395 (struct TransportDVBoxMessage *) dvb,
10396 /* we strip i+1 entries, and the receiver reconstructs
10397 the ciphertext offset from total_hops */
10398 ntohs (dvb->total_hops) + i + 1,
10399 num_hops - i - 1, /* number of hops left */
10400 &hops[i + 1], /* remaining hops */
10401 enc_payload,
10402 enc_payload_size);
10404 "# DV hops skipped routing boxes",
10405 i,
10406 GNUNET_NO);
10408 "# DV boxes routed (total)",
10409 1,
10410 GNUNET_NO);
10411 finish_cmc_handling (cmc);
10412 return;
10413 }
10414 /* Woopsie, next hop not in neighbours, drop! */
10416 "# DV Boxes dropped: next hop unknown",
10417 1,
10418 GNUNET_NO);
10419 finish_cmc_handling (cmc);
10420 return;
10421 }
10422 /* We are the target. Unbox and handle message. */
10424 "# DV boxes opened (ultimate target)",
10425 1,
10426 GNUNET_NO);
10427 cmc->total_hops = ntohs (dvb->total_hops);
10428
10429 {
10430 // DH key derivation with received DV, could be garbage.
10432 struct GNUNET_ShortHashCode km;
10433
10435 if ( (NULL == my_private_key) ||
10436 (GNUNET_OK !=
10438 &dvb->ephemeral_key,
10439 &km)) )
10440 {
10441 GNUNET_break_op (0);
10442 finish_cmc_handling (cmc);
10443 return;
10444 }
10445 decaps_dv_box_cont (cmc,
10446 dvb,
10447 &km);
10448 }
10449}

References decaps_dv_box_cont(), TransportDVBoxMessage::ephemeral_key, finish_cmc_handling(), forward_dv_box(), GNUNET_asprintf(), GNUNET_assert, GNUNET_break_op, GNUNET_CRYPTO_eddsa_kem_decaps(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_EXTRA_LOGGING, GNUNET_free, GNUNET_i2s(), GNUNET_log, GNUNET_memcmp, GNUNET_NO, GNUNET_OK, GNUNET_PILS_get_identity(), GNUNET_PILS_get_private_key(), GNUNET_STATISTICS_update(), GNUNET_strdup, GST_stats, TransportDVBoxMessage::header, lookup_neighbour(), my_identity, my_private_key, TransportDVBoxMessage::num_hops, pils, GNUNET_MessageHeader::size, size, TransportDVBoxMessage::total_hops, and CommunicatorMessageContext::total_hops.

Here is the call graph for this function:

◆ check_incoming_msg()

static int check_incoming_msg ( void *  cls,
const struct GNUNET_TRANSPORT_IncomingMessage im 
)
static

Client notified us about transmission from a peer.

Process the request.

Parameters
clsa struct TransportClient which sent us the message
imthe send message that was sent
Returns
GNUNET_YES if message is well-formed

Definition at line 10460 of file gnunet-service-transport.c.

10462{
10463 struct TransportClient *tc = cls;
10464
10465 if (CT_COMMUNICATOR != tc->type)
10466 {
10467 GNUNET_break (0);
10468 return GNUNET_SYSERR;
10469 }
10471 return GNUNET_OK;
10472}

References CT_COMMUNICATOR, GNUNET_break, GNUNET_MQ_check_boxed_message, GNUNET_OK, GNUNET_SYSERR, and tc.

◆ check_known_address()

static int check_known_address ( void *  cls,
const struct GNUNET_PeerIdentity pid,
void *  value 
)
static

Test if the validation state in value matches the address from cls.

Parameters
clsa struct CheckKnownAddressContext
pidunused (must match though)
valuea struct ValidationState
Returns
GNUNET_OK if not matching, GNUNET_NO if match found

Definition at line 10502 of file gnunet-service-transport.c.

10505{
10506 struct CheckKnownAddressContext *ckac = cls;
10507 struct ValidationState *vs = value;
10508
10509 (void) pid;
10510 if (0 != strcmp (vs->address, ckac->address))
10511 return GNUNET_OK;
10512 ckac->vs = vs;
10513 return GNUNET_NO;
10514}

References CheckKnownAddressContext::address, GNUNET_NO, GNUNET_OK, ValidationState::pid, value, and CheckKnownAddressContext::vs.

Referenced by start_address_validation().

Here is the caller graph for this function:

◆ validation_start_cb()

static void validation_start_cb ( void *  cls)
static

Task run periodically to validate some address based on validation_heap.

Parameters
clsNULL

Definition at line 14077 of file gnunet-service-transport.c.

14078{
14079 struct ValidationState *vs;
14080 struct Queue *q;
14082 GST_cfg);
14083
14084 (void) cls;
14085 validation_task = NULL;
14087 /* drop validations past their expiration */
14088 while (
14089 (NULL != vs) &&
14091 {
14093 "Validation response %s cleaned up\n",
14094 GNUNET_sh2s (&vs->challenge.value));
14097 }
14098 if (NULL == vs)
14099 {
14101 "Address validation task not scheduled anymore, nothing to do\n");
14102 return; /* woopsie, no more addresses known, should only
14103 happen if we're really a lonely peer */
14104 }
14105 q = find_queue (&vs->pid, vs->address);
14106 if (GNUNET_TIME_absolute_cmp (vs->first_challenge_use, >, now))
14107 {
14109 "To early to start next address validation for challenge %s\n",
14110 GNUNET_sh2s (&vs->challenge.value));
14111 /* Do NOT just return: @e validation_task was set to NULL above and
14112 nothing re-arms it by itself. #update_next_challenge_time() only
14113 schedules us again when it is called with a *changed* time for some
14114 validation state, so bailing out here leaves a non-empty
14115 #validation_heap with no task attached: address (re)validation and
14116 the #suggest_to_connect() retries that go with it stop for *every*
14117 peer until some unrelated event happens to come along. A peer that
14118 just lost its only connection has no such events left. */
14121 now,
14122 vs->first_challenge_use),
14124 NULL);
14125 return;
14126 }
14127 if (NULL == q)
14128 {
14129 vs->awaiting_queue = GNUNET_YES;
14130 suggest_to_connect (&vs->pid, vs->address);
14131 }
14132 else
14134 /* Finally, reschedule next attempt */
14135 vs->challenge_backoff =
14136 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
14139 "Address validation task will run again in %s\n",
14140 GNUNET_STRINGS_relative_time_to_string (vs->challenge_backoff,
14141 GNUNET_YES));
14144 vs->challenge_backoff));
14145}

References find_queue(), free_validation_state(), GNUNET_CONTAINER_heap_peek(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_INFO, GNUNET_log, GNUNET_SCHEDULER_add_delayed(), GNUNET_sh2s(), GNUNET_STRINGS_relative_time_to_string(), GNUNET_TIME_absolute_cmp, GNUNET_TIME_absolute_get_difference(), GNUNET_TIME_absolute_get_monotonic(), GNUNET_TIME_absolute_get_remaining(), GNUNET_TIME_randomized_backoff(), GNUNET_TIME_relative_to_absolute(), GNUNET_YES, GST_cfg, ValidationState::pid, q, GNUNET_TIME_Relative::rel_value_us, suggest_to_connect(), update_next_challenge_time(), ValidationState::valid_until, validation_challenge_freq(), validation_heap, validation_start_cb(), validation_task, and validation_transmit_on_queue().

Referenced by update_next_challenge_time(), and validation_start_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ update_next_challenge_time()

static void update_next_challenge_time ( struct ValidationState vs,
struct GNUNET_TIME_Absolute  new_time 
)
static

Set the time for next_challenge of vs to new_time.

Updates the heap and if necessary reschedules the job.

Parameters
vsvalidation state to update
new_timenew time for revalidation

Definition at line 10534 of file gnunet-service-transport.c.

10536{
10538 struct ValidationState *next;
10539
10540 /* NOTE: "be lazy" must not apply while #validation_task is unset. Our
10541 only caller that can leave it unset is #validation_start_cb(), which
10542 NULLs it on entry and relies on us to arm it again -- and nothing else
10543 ever does. Returning early there stops address (re)validation and the
10544 #suggest_to_connect() retries that go with it for *every* peer, for
10545 good. */
10546 if ((new_time.abs_value_us == vs->next_challenge.abs_value_us) &&
10547 (NULL != validation_task) &&
10548 (NULL != vs->hn))
10549 return; /* be lazy */
10550 vs->next_challenge = new_time;
10551 if (NULL == vs->hn)
10552 vs->hn =
10554 else
10557 (NULL != validation_task))
10558 return;
10559 if (NULL != validation_task)
10561 /* Arm for the earliest entry in the heap, which need NOT be @a vs:
10562 #validation_start_cb() calls us with @e validation_task unset and with
10563 @a vs already pushed out to its new @e challenge_backoff, which doubles
10564 up to #MAX_VALIDATION_CHALLENGE_FREQ (one day) while an address stays
10565 unanswered. Arming for @a vs there parks the single global validation
10566 task for that long, no matter how many other addresses are due right
10567 now -- and every address of a peer we cannot reach (NAT) is such an
10568 address. Everything that needs a validation then stops with it:
10569 bringing a lost link back up, and confirming the link to a peer that
10570 contacted us. */
10572 if (NULL == next)
10573 return;
10574 /* randomize a bit */
10579 delta),
10581 NULL);
10582}

References GNUNET_TIME_Absolute::abs_value_us, delta, GNUNET_CONTAINER_heap_insert(), GNUNET_CONTAINER_heap_peek(), GNUNET_CONTAINER_heap_update_cost(), GNUNET_CRYPTO_random_u64(), GNUNET_SCHEDULER_add_at(), GNUNET_SCHEDULER_cancel(), GNUNET_TIME_absolute_add(), MIN_DELAY_ADDRESS_VALIDATION, GNUNET_TIME_Relative::rel_value_us, validation_heap, validation_start_cb(), and validation_task.

Referenced by handle_validation_response(), revalidate_now_cb(), revalidation_start_cb(), start_address_validation(), and validation_start_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ revalidate_now_cb()

static enum GNUNET_GenericReturnValue revalidate_now_cb ( void *  cls,
const struct GNUNET_PeerIdentity pid,
void *  value 
)
static

Pull value's next challenge forward: the link to that peer is not up.

Touches only validation_heap, so it is safe to run while iterating validation_map.

Parameters
clsNULL
pidpeer the validation state belongs to
valuea struct ValidationState
Returns
GNUNET_OK (continue to iterate)

Definition at line 10596 of file gnunet-service-transport.c.

10599{
10600 struct ValidationState *vs = value;
10601 const struct GNUNET_TIME_Absolute now =
10603
10604 (void) cls;
10605 (void) pid;
10606 /* What #start_address_validation() does for an address it hears about
10607 again, but without needing the address string. */
10608 vs->challenge_backoff =
10611 vs->challenge_backoff,
10612 2));
10613 if (GNUNET_TIME_absolute_cmp (vs->first_challenge_use, >, now))
10614 vs->first_challenge_use = now;
10617 vs->challenge_backoff));
10618 return GNUNET_OK;
10619}

References FAST_VALIDATION_CHALLENGE_FREQ, GNUNET_OK, GNUNET_TIME_absolute_cmp, GNUNET_TIME_absolute_get_monotonic(), GNUNET_TIME_relative_divide(), GNUNET_TIME_relative_min(), GNUNET_TIME_relative_to_absolute(), GST_cfg, update_next_challenge_time(), and value.

Referenced by try_to_bring_link_up().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ find_queue()

static struct Queue * find_queue ( const struct GNUNET_PeerIdentity pid,
const char *  address 
)
static

Find the queue matching pid and address.

Parameters
pidpeer the queue must go to
addressaddress the queue must use
Returns
NULL if no such queue exists

Definition at line 11144 of file gnunet-service-transport.c.

11145{
11146 struct Neighbour *n;
11147
11148 n = lookup_neighbour (pid);
11149 if (NULL == n)
11150 return NULL;
11151 for (struct Queue *pos = n->queue_head; NULL != pos;
11152 pos = pos->next_neighbour)
11153 {
11154 if (0 == strcmp (pos->address, address))
11155 return pos;
11156 }
11157 return NULL;
11158}

References address, lookup_neighbour(), Neighbour::pid, and Neighbour::queue_head.

Referenced by handle_request_hello_validation(), handle_validation_response(), hello_for_client_cb(), hello_for_incoming_cb(), revalidation_start_cb(), and validation_start_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ suggest_to_connect()

static void suggest_to_connect ( const struct GNUNET_PeerIdentity pid,
const char *  address 
)
static

Signature of a function called with a communicator address of a peer pid that an application wants us to connect to.

Parameters
pidtarget peer
addressthe address to try

Definition at line 13942 of file gnunet-service-transport.c.

13943{
13944 static uint32_t idgen = 0;
13945 struct TransportClient *tc;
13946 char *prefix;
13947 struct GNUNET_TRANSPORT_CreateQueue *cqm;
13948 struct GNUNET_MQ_Envelope *env;
13949 size_t alen;
13950
13952 if (NULL == prefix)
13953 {
13954 GNUNET_break (0); /* We got an invalid address!? */
13955 return;
13956 }
13958 if (NULL == tc)
13959 {
13961 "# Suggestions ignored due to missing communicator",
13962 1,
13963 GNUNET_NO);
13965 "Cannot connect to %s at `%s', no matching communicator present\n",
13966 GNUNET_i2s (pid),
13967 address);
13969 return;
13970 }
13971 /* forward suggestion for queue creation to communicator */
13973 "Request #%u for `%s' communicator to create queue to `%s' at `%s'\n",
13974 (unsigned int) idgen,
13975 prefix,
13976 GNUNET_i2s (pid),
13977 address);
13979 alen = strlen (address) + 1;
13980 env =
13982 cqm->request_id = htonl (idgen++);
13983 cqm->receiver = *pid;
13984 memcpy (&cqm[1], address, alen);
13985 GNUNET_MQ_send (tc->mq, env);
13986}

References address, env, GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_INFO, GNUNET_free, GNUNET_HELLO_address_to_prefix(), GNUNET_i2s(), GNUNET_log, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE, GNUNET_MQ_msg_extra, GNUNET_MQ_send(), GNUNET_NO, GNUNET_STATISTICS_update(), GST_stats, lookup_communicator(), prefix, GNUNET_TRANSPORT_CreateQueue::receiver, GNUNET_TRANSPORT_CreateQueue::request_id, and tc.

Referenced by handle_request_hello_validation(), hello_for_client_cb(), hello_for_incoming_cb(), revalidation_start_cb(), and validation_start_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hello_for_incoming_cb()

static void hello_for_incoming_cb ( void *  cls,
const struct GNUNET_PeerIdentity pid,
const char *  uri 
)
static

Definition at line 10723 of file gnunet-service-transport.c.

10726{
10727 struct Queue *q;
10728 int pfx_len;
10729 const char *eou;
10730 char *address;
10731 (void) cls;
10732
10733 eou = strstr (uri,
10734 "://");
10735 if ((NULL == eou) || (eou == uri))
10736 {
10737 /* @a uri comes from a HELLO some remote peer published. */
10738 GNUNET_break_op (0);
10739 return;
10740 }
10741 pfx_len = eou - uri;
10742 eou += 3;
10744 "%.*s-%s",
10745 pfx_len,
10746 uri,
10747 eou);
10748
10750 "helo for client %s\n",
10751 address);
10752 q = find_queue (pid, address);
10753 if (NULL == q)
10754 {
10756 }
10757 else
10760}

References address, find_queue(), GNUNET_asprintf(), GNUNET_break_op, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_log, q, start_address_validation(), suggest_to_connect(), and uri.

Referenced by handle_hello_for_incoming().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hello_from_record()

static const struct GNUNET_MessageHeader * hello_from_record ( const struct GNUNET_PEERSTORE_Record record)
static

Obtain the HELLO message stored in record, if record actually carries one.

PEERSTORE values are opaque blobs: handle_store() of the PEERSTORE service performs no validation whatsoever, and the records under GNUNET_PEERSTORE_HELLO_KEY originate from other peers (via the DHT, the hostlist daemon and topology gossip). So the length of the value and the length the embedded message claims to have are two independent numbers, and neither may be trusted:

  • a zero-length value leaves value at NULL (see PEERSTORE_parse_record_message()), and GNUNET_HELLO_parser_from_msg() dereferences its argument unconditionally – that is a NULL dereference;
  • a value shorter than a message header, or one whose size field exceeds value_size, makes the parser read past the end of the heap block the record was parsed into.
Parameters
recordrecord to inspect, may be NULL
Returns
the HELLO, or NULL if record does not hold a well-formed one

Definition at line 10786 of file gnunet-service-transport.c.

10787{
10788 const struct GNUNET_MessageHeader *hello;
10789
10790 if ((NULL == record) ||
10791 (NULL == record->value) ||
10792 (record->value_size < sizeof(*hello)))
10793 {
10794 GNUNET_break_op (0);
10795 return NULL;
10796 }
10797 hello = record->value;
10798 if (ntohs (hello->size) > record->value_size)
10799 {
10800 GNUNET_break_op (0);
10801 return NULL;
10802 }
10803 return hello;
10804}

References GNUNET_break_op, record(), and GNUNET_MessageHeader::size.

Referenced by check_for_burst_address(), check_for_global_natted(), handle_hello_for_client(), and handle_hello_for_incoming().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_hello_for_incoming()

static void handle_hello_for_incoming ( void *  cls,
const struct GNUNET_PEERSTORE_Record record,
const char *  emsg 
)
static

Function called by PEERSTORE for each matching record.

Parameters
clsclosure, a struct IncomingRequest
recordpeerstore record information
emsgerror message, or NULL if no errors

Definition at line 10815 of file gnunet-service-transport.c.

10818{
10819 struct IncomingRequest *ir = cls;
10821 const struct GNUNET_MessageHeader *hello;
10822 const struct GNUNET_PeerIdentity *my_identity;
10823
10824 if (NULL != emsg)
10825 {
10827 "Got failure from PEERSTORE: %s\n",
10828 emsg);
10830 return;
10831 }
10832 if (NULL == record)
10833 {
10834 GNUNET_break (0);
10836 return;
10837 }
10838 hello = hello_from_record (record);
10839 if (NULL == hello)
10840 {
10841 /* MUST still ask for the next record: a bad one is not a reason to
10842 stall this monitor forever. */
10844 return;
10845 }
10847 if (NULL == my_identity)
10848 {
10850 return;
10851 }
10852 if (0 == GNUNET_memcmp (&record->peer, my_identity))
10853 {
10855 return;
10856 }
10857 if (0 != GNUNET_memcmp (&record->peer, &ir->pid))
10858 {
10859 /* Not the peer this request is about. */
10861 return;
10862 }
10863 parser = GNUNET_HELLO_parser_from_msg (hello, &record->peer);
10864 if (NULL != parser)
10865 {
10868 NULL);
10869 GNUNET_HELLO_parser_free (parser);
10870 }
10871 /* MUST ask for the next record, or this monitor stalls after one HELLO */
10873}

References GNUNET_break, GNUNET_ERROR_TYPE_WARNING, GNUNET_HELLO_parser_free(), GNUNET_HELLO_parser_from_msg(), GNUNET_HELLO_parser_iterate(), GNUNET_log, GNUNET_memcmp, GNUNET_PEERSTORE_monitor_next(), GNUNET_PILS_get_identity(), hello_for_incoming_cb(), hello_from_record(), my_identity, IncomingRequest::nc, IncomingRequest::pid, pils, and record().

Referenced by try_to_bring_link_up().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hello_for_incoming_error_cb()

static void hello_for_incoming_error_cb ( void *  cls)
static

Definition at line 10877 of file gnunet-service-transport.c.

10878{
10880 "Error in PEERSTORE monitoring\n");
10881}

References GNUNET_ERROR_TYPE_WARNING, and GNUNET_log.

Referenced by try_to_bring_link_up().

Here is the caller graph for this function:

◆ hello_for_incoming_sync_cb()

static void hello_for_incoming_sync_cb ( void *  cls)
static

Definition at line 10885 of file gnunet-service-transport.c.

10886{
10888 "Done with initial PEERSTORE iteration during monitoring\n");
10889}

References GNUNET_ERROR_TYPE_DEBUG, and GNUNET_log.

Referenced by try_to_bring_link_up().

Here is the caller graph for this function:

◆ send_t_validation_response()

static void send_t_validation_response ( struct CommunicatorMessageContext cmc,
struct TransportValidationResponseMessage  tvr 
)
static

Route the signed validation response tvr back to the challenger and release cmc.

Parameters
cmccontext of the challenge we are answering
tvrthe response, signature already filled in

Definition at line 10962 of file gnunet-service-transport.c.

10964{
10965 struct VirtualLink *vl;
10966 struct Neighbour *n;
10967 struct GNUNET_PeerIdentity sender;
10968
10969 sender = cmc->im.sender;
10970 vl = lookup_virtual_link (&sender);
10971 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
10972 {
10973 // route_control_message_without_fc (&cmc->im.sender,
10975 &tvr.header,
10977 }
10978 else
10979 {
10980 /* Use route via neighbour */
10981 n = lookup_neighbour (&sender);
10982 if (NULL != n)
10983 route_via_neighbour (n, &tvr.header,
10986 }
10987
10988 finish_cmc_handling (cmc);
10989 /* An *unconfirmed* link is not a link -- it carries nothing, and CORE has
10990 never been told about the peer. Bailing out on one merely because it
10991 exists is what deadlocks a pair of peers into permanent one-way state:
10992 the challenger validated us, so it believes the connection is up and
10993 starts sending us FLOW_CONTROL; #handle_flow_control() answers an
10994 unknown sender by allocating exactly such an unconfirmed link; and from
10995 then on every challenge it retransmits lands here, gets a response --
10996 which keeps *its* side confirmed and its RTT healthy -- and returns
10997 without ever validating an address of its own. The unconfirmed link
10998 reaps itself after #UNCONFIRMED_LINK_TIMEOUT, but the next FLOW_CONTROL
10999 recreates it, and the peer keeps sending those precisely because it
11000 thinks it is connected. Nothing ever breaks the tie, so CORE on this
11001 side never hears about the peer and never answers its handshake.
11002 Only a confirmed link means there is nothing left to do. */
11003 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
11004 return;
11005
11006 /* For us, the link is still down, but we need bi-directional
11007 connections (for flow-control and for this to be useful for
11008 CORE), so we must try to bring the link up! */
11009 try_to_bring_link_up (&sender);
11010}

References VirtualLink::confirmed, finish_cmc_handling(), GNUNET_YES, TransportValidationResponseMessage::header, CommunicatorMessageContext::im, lookup_neighbour(), lookup_virtual_link(), RMO_ANYTHING_GOES, RMO_REDUNDANT, RMO_UNCONFIRMED_ALLOWED, route_control_message_without_fc(), route_via_neighbour(), GNUNET_TRANSPORT_IncomingMessage::sender, and try_to_bring_link_up().

Referenced by handle_validation_challenge().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_validation_challenge()

static void handle_validation_challenge ( void *  cls,
const struct TransportValidationChallengeMessage tvc 
)
static

Communicator gave us a transport address validation challenge.

Process the request.

Parameters
clsa struct CommunicatorMessageContext (must call finish_cmc_handling() when done)
tvcthe message that was received

Definition at line 11022 of file gnunet-service-transport.c.

11025{
11026 struct CommunicatorMessageContext *cmc = cls;
11027 struct TransportValidationResponseMessage tvr = { 0 };
11028 struct GNUNET_TIME_RelativeNBO validity_duration;
11029
11030 /* DV-routed messages are not allowed for validation challenges */
11031 if (cmc->total_hops > 0)
11032 {
11033 GNUNET_break_op (0);
11034 finish_cmc_handling (cmc);
11035 return;
11036 }
11037 validity_duration = cmc->im.expected_address_validity;
11039 "Received address validation challenge %s\n",
11040 GNUNET_sh2s (&tvc->challenge.value));
11041 /* If we have a virtual link, we use this mechanism to signal the
11042 size of the flow control window, and to allow the sender
11043 to ask for increases. If for us the virtual link is still down,
11044 we will always give a window size of zero. */
11045 tvr.header.type =
11047 tvr.header.size = htons (sizeof(tvr));
11048 tvr.reserved = htonl (0);
11049 tvr.challenge = tvc->challenge;
11050 tvr.origin_time = tvc->sender_time;
11051 tvr.validity_duration = validity_duration;
11052 {
11053 /* create signature */
11054 struct TransportValidationPS tvp = {
11056 .purpose.size = htonl (sizeof(tvp)),
11057 .validity_duration = validity_duration,
11058 .challenge = tvc->challenge
11059 };
11060 if (GNUNET_OK != sign_by_my_identity (&tvp.purpose, &tvr.signature))
11061 {
11062 /* Not answering costs us this address validation; leaving @a cmc
11063 behind would cost us the communicator. */
11064 finish_cmc_handling (cmc);
11065 return;
11066 }
11067 }
11068 send_t_validation_response (cmc, tvr);
11069}

References TransportValidationChallengeMessage::challenge, TransportValidationResponseMessage::challenge, GNUNET_TRANSPORT_IncomingMessage::expected_address_validity, finish_cmc_handling(), GNUNET_break_op, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE, GNUNET_OK, GNUNET_sh2s(), GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE, TransportValidationResponseMessage::header, CommunicatorMessageContext::im, GNUNET_CRYPTO_SignaturePurpose::purpose, TransportValidationPS::purpose, TransportValidationResponseMessage::reserved, send_t_validation_response(), TransportValidationChallengeMessage::sender_time, sign_by_my_identity(), TransportValidationResponseMessage::signature, GNUNET_MessageHeader::size, CommunicatorMessageContext::total_hops, GNUNET_MessageHeader::type, TransportValidationPS::validity_duration, and GNUNET_CRYPTO_ChallengeNonceP::value.

Here is the call graph for this function:

◆ check_known_challenge()

static int check_known_challenge ( void *  cls,
const struct GNUNET_PeerIdentity pid,
void *  value 
)
static

Test if the validation state in value matches the challenge from cls.

Parameters
clsa struct CheckKnownChallengeContext
pidunused (must match though)
valuea struct ValidationState
Returns
GNUNET_OK if not matching, GNUNET_NO if match found

Definition at line 11099 of file gnunet-service-transport.c.

11102{
11103 struct CheckKnownChallengeContext *ckac = cls;
11104 struct ValidationState *vs = value;
11105
11106 (void) pid;
11107 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
11108 return GNUNET_OK;
11109 ckac->vs = vs;
11110 return GNUNET_NO;
11111}

References CheckKnownChallengeContext::challenge, GNUNET_memcmp, GNUNET_NO, GNUNET_OK, ValidationState::pid, value, and CheckKnownChallengeContext::vs.

Referenced by handle_validation_response().

Here is the caller graph for this function:

◆ peerstore_store_validation_cb()

static void peerstore_store_validation_cb ( void *  cls,
int  success 
)
static

Function called when peerstore is done storing a validated address.

Parameters
clsa struct ValidationState
successGNUNET_YES on success

Definition at line 11122 of file gnunet-service-transport.c.

11123{
11124 struct ValidationState *vs = cls;
11125
11126 vs->sc = NULL;
11127 if (GNUNET_YES == success)
11128 return;
11130 "# Peerstore failed to store foreign address",
11131 1,
11132 GNUNET_NO);
11133}

References GNUNET_NO, GNUNET_STATISTICS_update(), GNUNET_YES, and GST_stats.

Referenced by handle_validation_response().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ find_queue_by_ip()

static struct Queue * find_queue_by_ip ( const struct GNUNET_PeerIdentity pid,
const char *  address 
)
static

Find a queue to pid whose address has the same IP as address, but possibly a different port.

This mirrors the (deliberately) loose matching done by check_validation_request_pending(): a validation may legitimately be transmitted on a queue whose address is not literally address, because for a NATed peer the address we asked to connect to (‘PROTO-IP:0’) and the address the resulting queue ends up with (‘PROTO-IP:port’) differ. When the validation then succeeds we must be able to find that queue again.

Parameters
pidpeer the queue must go to
addressaddress whose IP the queue must use
Returns
NULL if no such queue exists

Definition at line 11177 of file gnunet-service-transport.c.

11178{
11179 struct Neighbour *n;
11180 struct Queue *ret = NULL;
11181 char *prefix;
11182 char *ip;
11183
11184 n = lookup_neighbour (pid);
11185 if (NULL == n)
11186 return NULL;
11189 if ((NULL == prefix) || (NULL == ip))
11190 {
11192 GNUNET_free (ip);
11193 return NULL;
11194 }
11195 for (struct Queue *pos = n->queue_head; NULL != pos;
11196 pos = pos->next_neighbour)
11197 {
11198 char *q_prefix = GNUNET_HELLO_address_to_prefix (pos->address);
11199 char *q_ip = get_address_without_port (pos->address);
11200
11201 /* Same communicator and same host -- only the port may differ. */
11202 if ((NULL != q_prefix) && (NULL != q_ip) &&
11203 (0 == strcmp (q_prefix, prefix)) &&
11204 (0 == strcmp (q_ip, ip)))
11205 ret = pos;
11206 GNUNET_free (q_prefix);
11207 GNUNET_free (q_ip);
11208 if (NULL != ret)
11209 break;
11210 }
11212 GNUNET_free (ip);
11213 return ret;
11214}

References address, get_address_without_port(), GNUNET_free, GNUNET_HELLO_address_to_prefix(), lookup_neighbour(), prefix, Neighbour::queue_head, and ret.

Referenced by handle_validation_response().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ validation_transmit_on_queue()

static void validation_transmit_on_queue ( struct Queue q,
struct ValidationState vs 
)
static

The queue q (which matches the peer and address in vs) is ready for queueing.

We should now queue the validation request.

Parameters
qqueue to send on
vsstate to derive validation challenge from

Definition at line 13997 of file gnunet-service-transport.c.

13998{
14000 struct GNUNET_TIME_Absolute monotonic_time;
14001
14002 if (NULL != vs->revalidation_task)
14003 {
14004 GNUNET_SCHEDULER_cancel (vs->revalidation_task);
14005 vs->revalidation_task = NULL;
14006 }
14007 /*memcpy (&hkey,
14008 &hc,
14009 sizeof (hkey));*/
14011 "Remove key %s for address %s map size %u contains %u\n",
14012 GNUNET_h2s (&vs->hc),
14013 vs->address,
14016 &vs->hc));
14018
14020 if (GNUNET_TIME_UNIT_ZERO_ABS.abs_value_us ==
14021 vs->last_challenge_use.abs_value_us)
14022 {
14023 vs->first_challenge_use = monotonic_time;
14024 }
14025 vs->last_challenge_use = monotonic_time;
14026 tvc.header.type =
14028 tvc.header.size = htons (sizeof(tvc));
14029 tvc.reserved = htonl (0);
14030 tvc.challenge = vs->challenge;
14031 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
14033 "Sending address validation challenge %s to %s\n",
14034 GNUNET_sh2s (&tvc.challenge.value),
14035 GNUNET_i2s (&q->neighbour->pid));
14036 queue_send_msg (q, NULL, &tvc, sizeof(tvc));
14037}

References TransportValidationChallengeMessage::challenge, GNUNET_CONTAINER_multihashmap_contains(), GNUNET_CONTAINER_multihashmap_remove(), GNUNET_CONTAINER_multihashmap_size(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_INFO, GNUNET_h2s(), GNUNET_i2s(), GNUNET_log, GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE, GNUNET_SCHEDULER_cancel(), GNUNET_sh2s(), GNUNET_TIME_absolute_get_monotonic(), GNUNET_TIME_absolute_hton(), GNUNET_TIME_UNIT_ZERO_ABS, GST_cfg, TransportValidationChallengeMessage::header, q, queue_send_msg(), TransportValidationChallengeMessage::reserved, revalidation_map, TransportValidationChallengeMessage::sender_time, GNUNET_MessageHeader::size, GNUNET_MessageHeader::type, and GNUNET_CRYPTO_ChallengeNonceP::value.

Referenced by check_validation_request_pending(), revalidation_start_cb(), and validation_start_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ revalidation_start_cb()

static void revalidation_start_cb ( void *  cls)
static

Definition at line 11221 of file gnunet-service-transport.c.

11222{
11223 struct ValidationState *vs = cls;
11224 struct Queue *q;
11225 struct GNUNET_TIME_Absolute now;
11226
11227 vs->revalidation_task = NULL;
11228 q = find_queue (&vs->pid, vs->address);
11229 if (NULL == q)
11230 {
11231 now = GNUNET_TIME_absolute_get ();
11232 vs->awaiting_queue = GNUNET_YES;
11233 suggest_to_connect (&vs->pid, vs->address);
11235 }
11236 else
11238}

References find_queue(), GNUNET_TIME_absolute_get(), GNUNET_YES, ValidationState::pid, q, suggest_to_connect(), update_next_challenge_time(), and validation_transmit_on_queue().

Referenced by handle_validation_response().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ revalidate_map_it()

static enum GNUNET_GenericReturnValue revalidate_map_it ( void *  cls,
const struct GNUNET_HashCode key,
void *  value 
)
static

Definition at line 11242 of file gnunet-service-transport.c.

11246{
11247 (void) cls;
11249 "Key in revalidate map %s \n",
11250 GNUNET_h2s (key));
11251 return GNUNET_YES;
11252}

References GNUNET_ERROR_TYPE_DEBUG, GNUNET_h2s(), GNUNET_log, GNUNET_YES, and key.

Referenced by handle_validation_response().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_validation_response()

static void handle_validation_response ( void *  cls,
const struct TransportValidationResponseMessage tvr 
)
static

Communicator gave us a transport address validation response.

Process the request.

Parameters
clsa struct CommunicatorMessageContext (must call finish_cmc_handling() when done)
tvrthe message that was received

Definition at line 11264 of file gnunet-service-transport.c.

11267{
11268 struct CommunicatorMessageContext *cmc = cls;
11269 struct ValidationState *vs;
11270 struct CheckKnownChallengeContext ckac = { .challenge = &tvr->challenge,
11271 .vs = NULL};
11272 struct GNUNET_TIME_Absolute origin_time;
11273 struct Queue *q;
11274 struct Neighbour *n;
11275 struct VirtualLink *vl;
11277 GST_cfg);
11278
11279 /* check this is one of our challenges */
11281 &cmc->im.sender,
11283 &ckac);
11284 if (NULL == (vs = ckac.vs))
11285 {
11286 /* This can happen simply if we 'forgot' the challenge by now,
11287 i.e. because we received the validation response twice */
11289 "# Validations dropped, challenge unknown",
11290 1,
11291 GNUNET_NO);
11293 "Validation response %s dropped, challenge unknown\n",
11294 GNUNET_sh2s (&tvr->challenge.value));
11295 finish_cmc_handling (cmc);
11296 return;
11297 }
11298
11299 /* sanity check on origin time */
11300 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
11301 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
11302 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
11303 {
11305 "Diff first use %" PRIu64 " and last use %" PRIu64 "\n",
11306 vs->first_challenge_use.abs_value_us - origin_time.abs_value_us,
11307 origin_time.abs_value_us - vs->last_challenge_use.abs_value_us);
11308 GNUNET_break_op (0);
11309 finish_cmc_handling (cmc);
11310 return;
11311 }
11312
11313 {
11314 /* check signature */
11315 struct TransportValidationPS tvp = {
11317 .purpose.size = htonl (sizeof(tvp)),
11318 .validity_duration = tvr->validity_duration,
11319 .challenge = tvr->challenge
11320 };
11321
11322 if (
11323 GNUNET_OK !=
11325 &tvp,
11326 &tvr->signature,
11327 &cmc->im.sender.public_key))
11328 {
11329 GNUNET_break_op (0);
11330 finish_cmc_handling (cmc);
11331 return;
11332 }
11333 }
11334
11335 /* validity is capped by our willingness to keep track of the
11336 validation entry and the maximum the other peer allows */
11339 tvr->validity_duration),
11341 vs->validated_until =
11345 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
11346 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
11347 GNUNET_CRYPTO_random_block (&vs->challenge,
11348 sizeof(vs->challenge));
11349 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
11350 vs->validated_until,
11351 GNUNET_TIME_relative_multiply (vs->validation_rtt,
11353 if (GNUNET_TIME_absolute_cmp (vs->first_challenge_use, <, now))
11354 {
11356 "First challenge use is now %" PRIu64 " %s \n",
11357 vs->first_challenge_use.abs_value_us,
11358 GNUNET_sh2s (&vs->challenge.value));
11359 vs->first_challenge_use = now;
11360 }
11361 else
11363 "First challenge use is later %" PRIu64 " %s \n",
11364 vs->first_challenge_use.abs_value_us,
11365 GNUNET_sh2s (&vs->challenge.value));
11366 vs->last_challenge_use =
11367 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
11368 update_next_challenge_time (vs, vs->first_challenge_use);
11370 "Validation response %s from %s accepted, address valid until %s\n",
11371 GNUNET_sh2s (&tvr->challenge.value),
11372 GNUNET_i2s (&cmc->im.sender),
11374 /*memcpy (&hkey,
11375 &hc,
11376 sizeof (hkey));*/
11378 "Key %s for address %s map size %u contains %u\n",
11379 GNUNET_h2s (&vs->hc),
11380 vs->address,
11383 &vs->hc));
11384 /* NOTE: @e hc hashes the address only, so two `struct ValidationState's
11385 for different peers can collide here. That must not abort us. */
11386 if (GNUNET_YES !=
11389 &vs->hc,
11390 vs,
11393 "Address `%s' already tracked for revalidation\n",
11394 vs->address);
11397 NULL);
11398 vs->revalidation_task =
11403 "transport",
11404 &cmc->im.sender,
11406 vs->address,
11407 strlen (vs->address) + 1,
11408 vs->valid_until,
11411 vs);
11412 finish_cmc_handling (cmc);
11413
11414 /* Finally, we now possibly have a confirmed (!) working queue,
11415 update queue status (if queue still is around) */
11416 q = find_queue (&vs->pid, vs->address);
11417 if (NULL == q)
11418 {
11419 /* The challenge may have gone out on a queue whose address is not
11420 literally @e address: #check_validation_request_pending() matches on
11421 the IP alone, precisely so that a validation waiting for the NAT
11422 address `PROTO-IP:0' can be answered over the queue that the peer
11423 actually established from `PROTO-IP:port'. Insisting on an exact
11424 match here would silently discard that (successful!) validation and
11425 never bring the virtual link up. */
11426 q = find_queue_by_ip (&vs->pid, vs->address);
11427 }
11428 if (NULL == q)
11429 {
11431 "# Queues lost at time of successful validation",
11432 1,
11433 GNUNET_NO);
11434 return;
11435 }
11436 q->validated_until = vs->validated_until;
11437 q->pd.aged_rtt = vs->validation_rtt;
11438 n = q->neighbour;
11439 vl = lookup_virtual_link (&vs->pid);
11440 if (NULL == vl)
11441 {
11442 vl = GNUNET_new (struct VirtualLink);
11444 "Creating new virtual link %p to %s using direct neighbour!\n",
11445 vl,
11446 GNUNET_i2s (&vs->pid));
11447 vl->burst_addr = NULL;
11448 vl->confirmed = GNUNET_YES;
11449 vl->message_uuid_ctr =
11450 GNUNET_CRYPTO_random_u64 (UINT64_MAX);
11451 vl->target = n->pid;
11455 /* What the peer will grant us in its very first FLOW_CONTROL anyway
11456 (@e incoming_fc_window_size plus what we have sent, i.e. nothing).
11457 Starting at zero instead means a link that is up, validated and
11458 working carries nothing at all until an FC round trip completes --
11459 and if the peer cannot answer, not ever. */
11463 links,
11464 &vl->target,
11465 vl,
11467 vl->n = n;
11468 n->vl = vl;
11469 q->idle = GNUNET_YES;
11470 vl->visibility_task =
11471 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
11473 /* We lacked a confirmed connection to the target
11474 before, so tell CORE about it (finally!) */
11477 }
11478 else
11479 {
11480 /* Link was already up, remember n is also now available and we are done */
11481 if (NULL == vl->n)
11482 {
11483 vl->n = n;
11484 n->vl = vl;
11485 if (GNUNET_YES == vl->confirmed)
11487 "Virtual link to %s could now also use direct neighbour!\n",
11488 GNUNET_i2s (&vs->pid));
11489 }
11490 else
11491 {
11492 GNUNET_assert (n == vl->n);
11493 }
11494 if (GNUNET_NO == vl->confirmed)
11495 {
11496 vl->confirmed = GNUNET_YES;
11497 q->idle = GNUNET_YES;
11498 vl->visibility_task =
11499 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
11501 /* We lacked a confirmed connection to the target
11502 before, so tell CORE about it (finally!) */
11505 }
11506 }
11507}

References GNUNET_TIME_Absolute::abs_value_us, ADDRESS_VALIDATION_LIFETIME, VirtualLink::available_fc_window_size, VirtualLink::burst_addr, TransportValidationResponseMessage::challenge, CheckKnownChallengeContext::challenge, check_known_challenge(), check_link_down(), VirtualLink::confirmed, consider_sending_fc(), VirtualLink::core_recv_window, cores_send_connect_info(), DEFAULT_WINDOW_SIZE, find_queue(), find_queue_by_ip(), finish_cmc_handling(), GNUNET_assert, GNUNET_break, GNUNET_break_op, GNUNET_CONTAINER_multihashmap_contains(), GNUNET_CONTAINER_multihashmap_iterate(), GNUNET_CONTAINER_multihashmap_put(), GNUNET_CONTAINER_multihashmap_size(), GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY, GNUNET_CONTAINER_multipeermap_get_multiple(), GNUNET_CONTAINER_multipeermap_put(), GNUNET_CRYPTO_eddsa_verify, GNUNET_CRYPTO_random_block(), GNUNET_CRYPTO_random_u64(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_h2s(), GNUNET_i2s(), GNUNET_log, GNUNET_new, GNUNET_NO, GNUNET_OK, GNUNET_PEERSTORE_store(), GNUNET_PEERSTORE_STOREOPTION_MULTIPLE, GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY, GNUNET_SCHEDULER_add_at(), GNUNET_sh2s(), GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE, GNUNET_STATISTICS_update(), GNUNET_STRINGS_absolute_time_to_string(), GNUNET_TIME_absolute_cmp, GNUNET_TIME_absolute_get_duration(), GNUNET_TIME_absolute_get_monotonic(), GNUNET_TIME_absolute_min(), GNUNET_TIME_absolute_ntoh(), GNUNET_TIME_absolute_subtract(), GNUNET_TIME_relative_min(), GNUNET_TIME_relative_multiply(), GNUNET_TIME_relative_ntoh(), GNUNET_TIME_relative_to_absolute(), GNUNET_TIME_UNIT_MINUTES, GNUNET_TIME_UNIT_ZERO, GNUNET_TIME_UNIT_ZERO_ABS, GNUNET_YES, GST_cfg, GST_stats, CommunicatorMessageContext::im, VirtualLink::incoming_fc_window_size, links, lookup_virtual_link(), MAX_ADDRESS_VALID_UNTIL, VirtualLink::message_uuid_ctr, VirtualLink::n, VirtualLink::outbound_fc_window_size, peerstore, peerstore_store_validation_cb(), Neighbour::pid, ValidationState::pid, GNUNET_PeerIdentity::public_key, GNUNET_CRYPTO_SignaturePurpose::purpose, TransportValidationPS::purpose, q, RECV_WINDOW_SIZE, revalidate_map_it(), revalidation_map, revalidation_start_cb(), send_msg_from_cache(), GNUNET_TRANSPORT_IncomingMessage::sender, TransportValidationResponseMessage::signature, VirtualLink::target, update_next_challenge_time(), ValidationState::valid_until, ValidationState::validated_until, validation_map, VALIDATION_RTT_BUFFER_FACTOR, GNUNET_CRYPTO_ChallengeNonceP::value, VirtualLink::visibility_task, Neighbour::vl, and CheckKnownChallengeContext::vs.

Here is the call graph for this function:

◆ handle_incoming_msg()

static void handle_incoming_msg ( void *  cls,
const struct GNUNET_TRANSPORT_IncomingMessage im 
)
static

Incoming message.

Process the request.

Parameters
imthe send message that was received

Definition at line 11516 of file gnunet-service-transport.c.

11518{
11519 struct TransportClient *tc = cls;
11520 struct Neighbour *n;
11521 struct CommunicatorMessageContext *cmc =
11523
11524 cmc->tc = tc;
11525 cmc->im = *im;
11527 "Received message with size %u and flow control id %" PRIu64
11528 " via communicator from peer %s\n",
11529 ntohs (im->header.size),
11530 im->fc_id,
11531 GNUNET_i2s (&im->sender));
11532 cmc->im.neighbour_sender = cmc->im.sender;
11533 /* A communicator got this straight from @a im->sender, so the queues to
11534 that neighbour demonstrably still work. This is what #check_link_down()
11535 uses to bound how long a communicator that stopped working (without
11536 telling us) can keep a virtual link -- and CORE -- fooled. */
11537 if (NULL != (n = lookup_neighbour (&im->sender)))
11539 cmc->mh = (const struct GNUNET_MessageHeader *) &im[1];
11541}

References demultiplex_with_cmc(), GNUNET_TRANSPORT_IncomingMessage::fc_id, GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, GNUNET_new, GNUNET_TIME_absolute_get(), GNUNET_TRANSPORT_IncomingMessage::header, CommunicatorMessageContext::im, Neighbour::last_inbound, lookup_neighbour(), CommunicatorMessageContext::mh, GNUNET_TRANSPORT_IncomingMessage::neighbour_sender, GNUNET_TRANSPORT_IncomingMessage::sender, GNUNET_MessageHeader::size, tc, and CommunicatorMessageContext::tc.

Here is the call graph for this function:

◆ check_flow_control()

static int check_flow_control ( void *  cls,
const struct TransportFlowControlMessage fc 
)
static

Communicator gave us a transport address validation response.

Check the request.

Parameters
clsa struct CommunicatorMessageContext
fcthe message that was received
Returns
GNUNET_YES if message is well-formed

Definition at line 11553 of file gnunet-service-transport.c.

11554{
11555 unsigned int number_of_addresses = ntohl (fc->number_of_addresses);
11556 uint16_t msize = ntohs (fc->header.size);
11557 const char *tgnas;
11558 size_t avail;
11559 size_t off;
11560
11561 (void) cls;
11563 "Flow control header size %u size of addresses %u number of addresses %u size of message struct %lu second struct %lu\n",
11564 ntohs (fc->header.size),
11565 ntohl (fc->size_of_addresses),
11566 ntohl (fc->number_of_addresses),
11567 sizeof(struct TransportFlowControlMessage),
11568 sizeof (struct TransportGlobalNattedAddress));
11569 if (0 == number_of_addresses)
11570 return GNUNET_OK;
11571 if (msize < sizeof(struct TransportFlowControlMessage))
11572 {
11573 GNUNET_break_op (0);
11574 return GNUNET_SYSERR;
11575 }
11576 avail = msize - sizeof(struct TransportFlowControlMessage);
11577 tgnas = (const char *) &fc[1];
11578 off = 0;
11579 /* Validate EVERY entry: checking only the aggregate size lets a single
11580 entry claim a bogus address_length and send #handle_flow_control()
11581 out of bounds. */
11582 for (unsigned int i = 0; i < number_of_addresses; i++)
11583 {
11584 const struct TransportGlobalNattedAddress *tgna;
11585 size_t alen;
11586
11587 if (avail - off < sizeof(struct TransportGlobalNattedAddress))
11588 {
11589 GNUNET_break_op (0);
11590 return GNUNET_SYSERR;
11591 }
11592 tgna = (const struct TransportGlobalNattedAddress *) &tgnas[off];
11593 off += sizeof(struct TransportGlobalNattedAddress);
11594 alen = ntohl (tgna->address_length);
11595 if (avail - off < alen)
11596 {
11597 GNUNET_break_op (0);
11598 return GNUNET_SYSERR;
11599 }
11600 off += alen;
11601 }
11602 return GNUNET_OK;
11603}

References TransportGlobalNattedAddress::address_length, GNUNET_break_op, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_OK, GNUNET_SYSERR, TransportFlowControlMessage::header, TransportFlowControlMessage::number_of_addresses, GNUNET_MessageHeader::size, and TransportFlowControlMessage::size_of_addresses.

◆ iterate_address_start_burst()

static void iterate_address_start_burst ( void *  cls,
const struct GNUNET_PeerIdentity pid,
const char *  uri 
)
static

Definition at line 11634 of file gnunet-service-transport.c.

11637{
11638 struct VirtualLink *vl = cls;
11639 const char *slash;
11640 char *address_uri;
11641 char *prefix;
11642 char *uri_without_port;
11643
11644 slash = strrchr (uri, '/');
11645 if ((NULL == slash) || (slash - uri < 2))
11646 {
11647 GNUNET_break_op (0); /* @a uri comes from a remote HELLO */
11648 return;
11649 }
11650 prefix = GNUNET_strndup (uri, (slash - uri) - 2);
11651 slash++;
11652 GNUNET_asprintf (&address_uri,
11653 "%s-%s",
11654 prefix,
11655 slash);
11656
11657 uri_without_port = get_address_without_port (address_uri);
11659 "iterate_address_start_burst %s %s %s %s\n",
11660 (NULL == uri_without_port) ? "<unparsable>" : uri_without_port,
11661 uri,
11662 address_uri,
11663 slash);
11664 GNUNET_free (vl->burst_addr);
11665 if ((NULL != uri_without_port) &&
11666 (0 == strcmp (uri_without_port, slash)))
11667 vl->burst_addr = GNUNET_strdup (uri_without_port);
11668
11670 GNUNET_free (address_uri);
11671 GNUNET_free (uri_without_port);
11672}

References VirtualLink::burst_addr, get_address_without_port(), GNUNET_asprintf(), GNUNET_break_op, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_log, GNUNET_strdup, GNUNET_strndup, prefix, and uri.

Referenced by check_for_burst_address().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_for_burst_address()

static void check_for_burst_address ( void *  cls,
const struct GNUNET_PEERSTORE_Record record,
const char *  emsg 
)
static

Definition at line 11676 of file gnunet-service-transport.c.

11679{
11680 struct GNUNET_StartBurstCls *sb_cls = cls;
11681 struct VirtualLink *vl = sb_cls->vl;
11682 const struct GNUNET_MessageHeader *hello;
11684
11685 if (NULL != emsg)
11686 {
11688 "Got failure from PEERSTORE: %s\n",
11689 emsg);
11690 /* @a emsg comes with a NULL record, which means the iteration is over
11691 and PEERSTORE is releasing the context itself -- stopping it here as
11692 well would free it twice. Just drop our handle. */
11693 vl->ic = NULL;
11694 free_burst_cls (sb_cls);
11695 return;
11696 }
11697 if (NULL == record)
11698 {
11700 "Hello iteration end for %s\n",
11701 GNUNET_i2s (&vl->target));
11702 /* PEERSTORE destroys the context itself once it signals the end. */
11703 vl->ic = NULL;
11704 free_burst_cls (sb_cls);
11705 return;
11706 }
11707
11709 "check_for_burst_address\n");
11710 /* @a hello was published by a remote peer, it may well be malformed. */
11711 hello = hello_from_record (record);
11712 if (NULL != hello)
11713 {
11714 parser = GNUNET_HELLO_parser_from_msg (hello, &record->peer);
11715 if (NULL != parser)
11716 {
11719 vl);
11720 GNUNET_HELLO_parser_free (parser);
11721 }
11722 }
11723
11724 /* MUST clear @e ic: #GNUNET_PEERSTORE_iteration_stop() frees it, and
11725 #free_virtual_link() would otherwise stop it a second time. */
11726 if (NULL != vl->ic)
11727 {
11729 vl->ic = NULL;
11730 }
11731 free_burst_cls (sb_cls);
11732}

References free_burst_cls(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_WARNING, GNUNET_HELLO_parser_free(), GNUNET_HELLO_parser_from_msg(), GNUNET_HELLO_parser_iterate(), GNUNET_i2s(), GNUNET_log, GNUNET_PEERSTORE_iteration_stop(), hello_from_record(), VirtualLink::ic, iterate_address_start_burst(), record(), VirtualLink::sb_cls, VirtualLink::target, and GNUNET_StartBurstCls::vl.

Referenced by queue_burst().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ burst_timeout()

static void burst_timeout ( void *  cls)
static

Definition at line 11736 of file gnunet-service-transport.c.

11737{
11739}

References burst_running, and GNUNET_NO.

Referenced by start_burst().

Here is the caller graph for this function:

◆ start_burst()

static void start_burst ( void *  cls)
static

Definition at line 11743 of file gnunet-service-transport.c.

11744{
11745 struct GNUNET_StartBurstCls *sb_cls = cls;
11746 struct VirtualLink *vl = sb_cls->vl;
11747 struct GNUNET_TRANSPORT_StartBurst *sb;
11748 struct GNUNET_MQ_Envelope *env;
11749 char *uri_without_port = vl->burst_addr;
11750
11751 burst_task = NULL;
11752 burst_task_cls = NULL;
11753 if (NULL == uri_without_port)
11754 {
11755 /* Lost the address in the meantime, nothing to burst to. */
11756 free_burst_cls (sb_cls);
11757 return;
11758 }
11759 /*char buf[strlen (uri_without_port) + 1];
11760
11761 GNUNET_memcpy (buf, uri_without_port, strlen (uri_without_port));
11762 buf[strlen (uri_without_port)] = '\0';*/
11763 env =
11765 strlen (uri_without_port) + 1,
11767 sb->rtt = GNUNET_TIME_relative_hton (sb_cls->rtt);
11768 sb->pid = vl->target;
11769 memcpy (&sb[1], uri_without_port, strlen (uri_without_port) + 1);
11770 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
11771 {
11772 if (CT_COMMUNICATOR != tc->type)
11773 continue; /* MUST come first: the log below reads the union! */
11775 "iterate_address_start_burst client tc prefix %s\n",
11776 tc->details.communicator.address_prefix);
11777 if (GNUNET_YES == tc->details.communicator.can_burst)
11778 {
11780 "iterate_address_start_burst %s call %lu %u rtt %lu\n",
11781 uri_without_port,
11782 strlen (uri_without_port),
11783 ntohs (sb->header.size),
11784 (unsigned long) sb_cls->rtt.rel_value_us);
11785 GNUNET_MQ_send (tc->mq, env);
11786 env = NULL; /* MQ took ownership */
11790 60),
11792 NULL);
11793 // TODO We need some algo to choose from available communicators. Can we run two bursts at once? Atm we only implemented udp burst.
11794 break;
11795 }
11796 }
11797 if (NULL != env)
11799 free_burst_cls (sb_cls);
11800}

References VirtualLink::burst_addr, burst_running, burst_task, burst_task_cls, burst_timeout(), burst_timeout_task, clients_head, CT_COMMUNICATOR, env, free_burst_cls(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_MESSAGE_TYPE_TRANSPORT_START_BURST, GNUNET_MQ_discard(), GNUNET_MQ_msg_extra, GNUNET_MQ_send(), GNUNET_SCHEDULER_add_delayed(), GNUNET_TIME_relative_hton(), GNUNET_TIME_relative_multiply(), GNUNET_TIME_UNIT_SECONDS, GNUNET_YES, GNUNET_TRANSPORT_StartBurst::header, GNUNET_TRANSPORT_StartBurst::pid, GNUNET_TIME_Relative::rel_value_us, GNUNET_StartBurstCls::rtt, GNUNET_TRANSPORT_StartBurst::rtt, VirtualLink::sb_cls, GNUNET_MessageHeader::size, VirtualLink::target, tc, and GNUNET_StartBurstCls::vl.

Referenced by queue_burst().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ queue_burst()

static void queue_burst ( void *  cls)
static

Definition at line 11830 of file gnunet-service-transport.c.

11831{
11832 struct GNUNET_StartBurstCls *sb_cls = cls;
11833 struct VirtualLink *vl = sb_cls->vl;
11834
11835 if (GNUNET_YES != use_burst)
11836 {
11837 /* MUST release: nobody else owns @a sb_cls, and #handle_flow_control()
11838 allocates one for every FLOW_CONTROL message we receive. */
11840 return;
11841 }
11843 "burst_task %p ready %s burst addr %s (%p)\n",
11844 burst_task,
11845 sb_cls->sync_ready ? "yes" : "no",
11846 vl->burst_addr,
11847 vl->burst_addr);
11848 if (NULL != burst_task && GNUNET_NO == sb_cls->sync_ready)
11849 {
11850 /* Cancel the pending burst. Both closures (the scheduled task's and
11851 ours) are ours to release. */
11853
11855 burst_task = NULL;
11856 burst_task_cls = NULL;
11857 if ((NULL != pending) && (pending != sb_cls))
11859 free_burst_cls (sb_cls);
11860 return;
11861 }
11862 if (GNUNET_NO == burst_running && NULL != vl->burst_addr && NULL == burst_task
11863 )
11864 {
11866 &start_burst,
11867 sb_cls);
11868 burst_task_cls = sb_cls;
11869 }
11870 else if (NULL == vl->burst_addr)
11871 {
11872 if (NULL != vl->ic)
11873 {
11874 /* An address lookup is already running for this link; starting a
11875 second one would leak the first. */
11876 free_burst_cls (sb_cls);
11877 return;
11878 }
11880 "peerstore",
11881 &vl->target,
11884 sb_cls);
11885 }
11886 else
11887 {
11888 /* A burst is already running or already scheduled; we have no use for
11889 this closure. */
11890 free_burst_cls (sb_cls);
11891 }
11892}

References VirtualLink::burst_addr, burst_running, burst_task, burst_task_cls, check_for_burst_address(), GNUNET_StartBurstCls::delay, free_burst_cls(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_NO, GNUNET_PEERSTORE_HELLO_KEY, GNUNET_PEERSTORE_iteration_start(), GNUNET_SCHEDULER_add_delayed(), GNUNET_SCHEDULER_cancel(), GNUNET_YES, VirtualLink::ic, peerstore, pending, VirtualLink::sb_cls, start_burst(), GNUNET_StartBurstCls::sync_ready, VirtualLink::target, use_burst, and GNUNET_StartBurstCls::vl.

Referenced by handle_flow_control().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ unconfirmed_link_timeout()

static void unconfirmed_link_timeout ( void *  cls)
static

Discard a virtual link that only ever existed because some peer sent us a FLOW_CONTROL message and that never became confirmed.

Parameters
clsthe struct VirtualLink

Definition at line 11902 of file gnunet-service-transport.c.

11903{
11904 struct VirtualLink *vl = cls;
11905
11906 vl->unconfirmed_timeout_task = NULL;
11907 if ((GNUNET_YES == vl->confirmed) ||
11908 (NULL != vl->n) ||
11909 (NULL != vl->dv))
11910 return; /* got promoted in the meantime, its owner will clean up */
11912 "Discarding unconfirmed virtual link to %s\n",
11913 GNUNET_i2s (&vl->target));
11915 "# Unconfirmed virtual links timed out",
11916 1,
11917 GNUNET_NO);
11918 free_virtual_link (vl);
11919}

References VirtualLink::confirmed, VirtualLink::dv, free_virtual_link(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, GNUNET_NO, GNUNET_STATISTICS_update(), GNUNET_YES, GST_stats, VirtualLink::n, VirtualLink::target, and VirtualLink::unconfirmed_timeout_task.

Referenced by handle_flow_control().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_flow_control()

static void handle_flow_control ( void *  cls,
const struct TransportFlowControlMessage fc 
)
static

Communicator gave us a transport address validation response.

Process the request.

Parameters
clsa struct CommunicatorMessageContext (must call finish_cmc_handling() when done)
fcthe message that was received

Definition at line 11931 of file gnunet-service-transport.c.

11932{
11933 struct CommunicatorMessageContext *cmc = cls;
11934 struct VirtualLink *vl;
11936 uint32_t seq;
11937 struct GNUNET_TIME_Absolute st;
11938 uint64_t os;
11939 uint64_t wnd;
11940 uint32_t random;
11941
11943 "Received FC from %s\n", GNUNET_i2s (&cmc->im.sender));
11944 vl = lookup_virtual_link (&cmc->im.sender);
11945 if (NULL == vl)
11946 {
11947 vl = GNUNET_new (struct VirtualLink);
11949 "No virtual link for %p FC creating new unconfirmed virtual link to %s!\n",
11950 vl,
11951 GNUNET_i2s (&cmc->im.sender));
11952 vl->burst_addr = NULL;
11953 vl->confirmed = GNUNET_NO;
11954 vl->message_uuid_ctr =
11955 GNUNET_CRYPTO_random_u64 (UINT64_MAX);
11956 vl->target = cmc->im.sender;
11960 /* What the peer will grant us in its very first FLOW_CONTROL anyway
11961 (@e incoming_fc_window_size plus what we have sent, i.e. nothing).
11962 Starting at zero instead means a link that is up, validated and
11963 working carries nothing at all until an FC round trip completes --
11964 and if the peer cannot answer, not ever. */
11968 links,
11969 &vl->target,
11970 vl,
11972 /* Nothing else owns this link yet, so it must reap itself if it never
11973 becomes confirmed -- otherwise any peer can make us allocate
11974 VirtualLinks without bound. */
11978 vl);
11979 }
11980 if (GNUNET_YES != vl->confirmed)
11981 {
11982 /* The peer flow-controls us, so it has a confirmed link to us -- but an
11983 unconfirmed link carries nothing and is never reported to CORE. Only
11984 #handle_validation_response() breaks that tie, and nothing here used
11985 to ask for one, so the pair could sit one-way until the peer's own
11986 four hour revalidation came round. */
11988 }
11989 if (NULL != vl->n)
11990 {
11991 for (struct Queue *q = vl->n->queue_head; NULL != q; q = q->next_neighbour)
11992 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
11993 }
11994
11996 "remaining %lu timeout for neighbour %p\n",
11997 (unsigned long) GNUNET_TIME_absolute_get_remaining (q_timeout).
11998 rel_value_us,
11999 vl->n);
12000 if (NULL == vl->n ||
12001 0 == GNUNET_TIME_absolute_get_remaining (q_timeout).rel_value_us)
12002 {
12003 struct GNUNET_TIME_Relative rtt;
12004 struct GNUNET_BurstSync burst_sync;
12005 struct GNUNET_StartBurstCls *bcls;
12006
12007 if (NULL != vl->sb_cls)
12008 {
12009 /* A burst attempt for this link is already in flight. Allocating a
12010 second closure would orphan the first one: @e sb_cls is how
12011 #free_virtual_link() finds (and cancels) the pending #burst_task,
12012 and a peer that just keeps sending us FLOW_CONTROL messages would
12013 otherwise make us leak one closure per message. */
12015 "Burst attempt to %s already pending\n",
12016 GNUNET_i2s (&vl->target));
12017 }
12018 else
12019 {
12020 bcls = GNUNET_new (struct GNUNET_StartBurstCls);
12021 bcls->vl = vl;
12022 vl->sb_cls = bcls;
12023 if (NULL != vl->dv)
12024 rtt = calculate_rtt (vl->dv);
12025 else
12027 burst_sync.rtt_average = fc->rtt;
12028 bcls->rtt = GNUNET_TIME_relative_ntoh (burst_sync.rtt_average);
12029 /* @e sync_ready of `struct GNUNET_BurstSync' is a host-order enum. */
12030 burst_sync.sync_ready =
12031 (enum GNUNET_GenericReturnValue) ntohl (fc->sync_ready);
12032
12033 /* NOTE: #GNUNET_is_burst_ready() does NOT invoke the task unless both
12034 RTT estimates are known and close; #queue_burst() is thus not
12035 guaranteed to run, which is why @e sb_cls stays owned by @a vl. */
12037 &burst_sync,
12038 &queue_burst,
12039 bcls);
12040 }
12041 }
12042 if (0 != ntohl (fc->number_of_addresses))
12043 {
12044 unsigned int number_of_addresses = ntohl (fc->number_of_addresses);
12045 const char *tgnas;
12046 unsigned int off = 0;
12047
12048 tgnas = (const char *) &fc[1];
12049
12050 for (unsigned int i = 0; i < number_of_addresses; i++)
12051 {
12052 struct TransportGlobalNattedAddress *tgna;
12053 char *addr;
12054 uint32_t address_length;
12055
12056 tgna = (struct TransportGlobalNattedAddress*) &tgnas[off];
12057 addr = (char *) &tgna[1];
12058 address_length = ntohl (tgna->address_length);
12059 off += sizeof(struct TransportGlobalNattedAddress) + address_length;
12060
12061 /* NOTE: the address is NOT 0-terminated (it comes straight off the
12062 wire), it must be printed with an explicit precision. */
12064 "received address %.*s length %u\n",
12065 (int) address_length,
12066 addr,
12068
12069 if (NULL != nh)
12070 GNUNET_NAT_add_global_address (nh, addr, ntohl (tgna->address_length));
12071 }
12072 }
12074 if (st.abs_value_us < vl->last_fc_timestamp.abs_value_us)
12075 {
12077 "FC dropped: Message out of order\n");
12078 /* out of order, drop */
12080 "# FC dropped: message out of order",
12081 1,
12082 GNUNET_NO);
12083 finish_cmc_handling (cmc);
12084 return;
12085 }
12086 seq = ntohl (fc->seq);
12087 if (seq < vl->last_fc_seq)
12088 {
12089 /* Wrap-around/reset of other peer; start all counters from zero */
12091 }
12092 vl->last_fc_seq = seq;
12093 vl->last_fc_timestamp = st;
12094 /* The peer is answering, so the backoff in #consider_sending_fc() starts
12095 over: @e fc_retransmit_count counts *unanswered* rounds. */
12096 vl->fc_retransmit_count = 0;
12098 os = GNUNET_ntohll (fc->outbound_sent);
12100 (int64_t) (os - vl->incoming_fc_window_size_used);
12102 "Received FC from %s, seq %u, new window %llu (loss at %lld)\n",
12103 GNUNET_i2s (&vl->target),
12104 (unsigned int) seq,
12105 (unsigned long long) vl->outbound_fc_window_size,
12106 (long long) vl->incoming_fc_window_size_loss);
12108 random = GNUNET_CRYPTO_random_u32 (UINT32_MAX);
12109 /* NOTE: this must NOT be restricted to a confirmed link. @e
12110 outbound_fc_window_size starts at zero and is raised *only* here, from
12111 the peer's FC. So a peer whose link to us is confirmed while ours to it
12112 is not cannot send us a single byte until we answer -- and it is exactly
12113 that peer that keeps asking. Staying quiet deadlocks the pair: it shows
12114 an established virtual link with messages pending forever, we show none,
12115 and CORE never completes its handshake in either direction. */
12116 if ((wnd < vl->incoming_fc_window_size
12120 (0 == random % FC_NO_CHANGE_REPLY_PROBABILITY))
12121 {
12123 "Consider re-sending our FC message, as clearly the other peer's idea of the window is not up-to-date (%llu vs %llu) or %llu last received differs, or random reply %u\n",
12124 (unsigned long long) wnd,
12125 (unsigned long long) vl->incoming_fc_window_size,
12126 (unsigned long long) vl->last_outbound_window_size_received,
12129 }
12130 if ((wnd == vl->incoming_fc_window_size
12134 {
12136 "Slowing FC transmission to %s to keepalive rate: peer is current at window %llu\n",
12137 GNUNET_i2s (&vl->target),
12138 (unsigned long long) wnd);
12139 /* NOTE: this used to also require @e fc_retransmit_task to be non-NULL
12140 and did nothing at all otherwise -- so a link whose chain had ended
12141 (see #consider_sending_fc()) could never pick the keepalive back up,
12142 even though the peer was demonstrably still talking to us. */
12143 if (NULL != vl->fc_retransmit_task)
12145 vl->fc_retransmit_count = 0;
12146 /* Drop to the keepalive rate rather than stopping outright. There is
12147 nothing left to retransmit -- but if we go completely quiet, and the
12148 peer does the same for the same reason, then neither end sees any
12149 traffic and #check_link_down() tears down a perfectly healthy link
12150 after #NEIGHBOUR_LIVENESS_TIMEOUT. One tiny FC message every
12151 #FC_KEEPALIVE_INTERVAL is what keeps @e last_inbound moving on the
12152 other side (and, via their reply, on ours). */
12153 vl->fc_retransmit_task =
12156 vl);
12157 }
12159 /* FC window likely increased, check transmission possibilities! */
12161 finish_cmc_handling (cmc);
12162}

References GNUNET_TIME_Absolute::abs_value_us, TransportGlobalNattedAddress::address_length, VirtualLink::available_fc_window_size, VirtualLink::burst_addr, calculate_rtt(), check_vl_transmission(), VirtualLink::confirmed, consider_sending_fc(), VirtualLink::core_recv_window, DEFAULT_WINDOW_SIZE, VirtualLink::dv, FC_KEEPALIVE_INTERVAL, FC_NO_CHANGE_REPLY_PROBABILITY, VirtualLink::fc_retransmit_count, VirtualLink::fc_retransmit_task, finish_cmc_handling(), GNUNET_break, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY, GNUNET_CONTAINER_multipeermap_put(), GNUNET_CRYPTO_random_u32(), GNUNET_CRYPTO_random_u64(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_is_burst_ready(), GNUNET_log, GNUNET_NAT_add_global_address(), GNUNET_new, GNUNET_NO, GNUNET_ntohll(), GNUNET_SCHEDULER_add_delayed(), GNUNET_SCHEDULER_cancel(), GNUNET_STATISTICS_update(), GNUNET_TIME_absolute_get_remaining(), GNUNET_TIME_absolute_max(), GNUNET_TIME_absolute_ntoh(), GNUNET_TIME_relative_ntoh(), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_TIME_UNIT_ZERO_ABS, GNUNET_YES, GST_stats, CommunicatorMessageContext::im, TransportFlowControlMessage::inbound_window_size, VirtualLink::incoming_fc_window_size, VirtualLink::incoming_fc_window_size_loss, VirtualLink::incoming_fc_window_size_used, VirtualLink::last_fc_seq, VirtualLink::last_fc_timestamp, VirtualLink::last_outbound_window_size_received, links, lookup_virtual_link(), VirtualLink::message_uuid_ctr, VirtualLink::n, nh, TransportFlowControlMessage::number_of_addresses, VirtualLink::outbound_fc_window_size, VirtualLink::outbound_fc_window_size_used, TransportFlowControlMessage::outbound_sent, TransportFlowControlMessage::outbound_window_size, q, queue_burst(), Neighbour::queue_head, RECV_WINDOW_SIZE, GNUNET_StartBurstCls::rtt, TransportFlowControlMessage::rtt, GNUNET_BurstSync::rtt_average, VirtualLink::sb_cls, GNUNET_TRANSPORT_IncomingMessage::sender, TransportFlowControlMessage::sender_time, TransportFlowControlMessage::seq, st, GNUNET_BurstSync::sync_ready, TransportFlowControlMessage::sync_ready, VirtualLink::target, task_consider_sending_fc(), try_to_bring_link_up(), UNCONFIRMED_LINK_TIMEOUT, unconfirmed_link_timeout(), VirtualLink::unconfirmed_timeout_task, and GNUNET_StartBurstCls::vl.

Here is the call graph for this function:

◆ check_add_queue_message()

static int check_add_queue_message ( void *  cls,
const struct GNUNET_TRANSPORT_AddQueueMessage aqm 
)
static

New queue became available.

Check message.

Parameters
clsthe client
aqmthe send message that was sent

Definition at line 12272 of file gnunet-service-transport.c.

12274{
12275 struct TransportClient *tc = cls;
12276
12277 if (CT_COMMUNICATOR != tc->type)
12278 {
12279 GNUNET_break (0);
12280 return GNUNET_SYSERR;
12281 }
12283 return GNUNET_OK;
12284}

References CT_COMMUNICATOR, GNUNET_break, GNUNET_MQ_check_zero_termination, GNUNET_OK, GNUNET_SYSERR, and tc.

◆ set_pending_message_uuid()

static void set_pending_message_uuid ( struct PendingMessage pm)
static

If necessary, generates the UUID for a pm.

Parameters
pmpending message to generate UUID for.

Definition at line 12293 of file gnunet-service-transport.c.

12294{
12295 if (pm->msg_uuid_set)
12296 return;
12297 pm->msg_uuid.uuid = pm->vl->message_uuid_ctr++;
12299}

References GNUNET_YES, VirtualLink::message_uuid_ctr, PendingMessage::msg_uuid, PendingMessage::msg_uuid_set, MessageUUIDP::uuid, and PendingMessage::vl.

Referenced by extract_box_cb(), fragment_message(), and reliability_box_message().

Here is the caller graph for this function:

◆ prepare_pending_acknowledgement()

static struct PendingAcknowledgement * prepare_pending_acknowledgement ( struct Queue queue,
struct DistanceVectorHop dvh,
struct PendingMessage pm 
)
static

Setup data structure waiting for acknowledgements.

Parameters
queuequeue the pm will be sent over
dvhpath the message will take, may be NULL
pmthe pending message for transmission
Returns
corresponding fresh pending acknowledgement

Definition at line 12311 of file gnunet-service-transport.c.

12314{
12315 struct PendingAcknowledgement *pa;
12316
12317 pa = GNUNET_new (struct PendingAcknowledgement);
12318 pa->queue = queue;
12319 pa->dvh = dvh;
12320 pa->pm = pm;
12321 do
12322 {
12324 sizeof(pa->ack_uuid));
12325 }
12328 &pa->ack_uuid.value,
12329 pa,
12331 GNUNET_CONTAINER_MDLL_insert (queue, queue->pa_head, queue->pa_tail, pa);
12333 if (NULL != dvh)
12336 pa->message_size = pm->bytes_msg;
12338 "Waiting for ACKnowledgment `%s' for <%" PRIu64 ">\n",
12340 pm->logging_uuid);
12341 return pa;
12342}

References PendingAcknowledgement::ack_uuid, PendingMessage::bytes_msg, PendingAcknowledgement::dvh, GNUNET_CONTAINER_MDLL_insert, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY, GNUNET_CONTAINER_multiuuidmap_put(), GNUNET_CRYPTO_random_block(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_new, GNUNET_TIME_absolute_get(), GNUNET_uuid2s(), GNUNET_YES, PendingMessage::logging_uuid, PendingAcknowledgement::message_size, DistanceVectorHop::pa_head, PendingMessage::pa_head, DistanceVectorHop::pa_tail, PendingMessage::pa_tail, pending_acks, PendingAcknowledgement::pm, queue(), PendingAcknowledgement::queue, PendingAcknowledgement::transmission_time, and AcknowledgementUUIDP::value.

Referenced by fragment_message(), and reliability_box_message().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ fragment_message()

static struct PendingMessage * fragment_message ( struct Queue queue,
struct DistanceVectorHop dvh,
struct PendingMessage pm 
)
static

Fragment the given pm to the given mtu.

Adds additional fragments to the neighbour as well. If the mtu is too small, generates and error for the pm and returns NULL.

Parameters
queuewhich queue to fragment for
dvhpath the message will take, or NULL
pmpending message to fragment for transmission
Returns
new message to transmit

Definition at line 12357 of file gnunet-service-transport.c.

12360{
12361 struct PendingAcknowledgement *pa;
12362 struct PendingMessage *ff;
12363 uint16_t mtu;
12364 uint16_t msize;
12365
12366 mtu = (UINT16_MAX == queue->mtu)
12367 ? UINT16_MAX - sizeof(struct GNUNET_TRANSPORT_SendMessageTo)
12368 : queue->mtu;
12370 "Fragmenting message <%" PRIu64
12371 "> with size %u to %s for MTU %u\n",
12372 pm->logging_uuid,
12373 pm->bytes_msg,
12374 GNUNET_i2s (&pm->vl->target),
12375 (unsigned int) mtu);
12378 "Fragmenting message %" PRIu64 " <%" PRIu64
12379 "> with size %u to %s for MTU %u\n",
12380 pm->msg_uuid.uuid,
12381 pm->logging_uuid,
12382 pm->bytes_msg,
12383 GNUNET_i2s (&pm->vl->target),
12384 (unsigned int) mtu);
12385
12386 /* This invariant is established in #handle_add_queue_message() */
12387 GNUNET_assert (mtu > sizeof(struct TransportFragmentBoxMessage));
12388
12389 /* select fragment for transmission, descending the tree if it has
12390 been expanded until we are at a leaf or at a fragment that is small
12391 enough
12392 */
12393 ff = pm;
12394 msize = ff->bytes_msg;
12395
12396 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
12397 (ff->frag_off == msize) && (NULL != ff->head_frag))
12398 {
12399 ff = ff->head_frag; /* descent into fragmented fragments */
12400 msize = ff->bytes_msg - sizeof(struct TransportFragmentBoxMessage);
12401 }
12402
12403 if (((ff->bytes_msg > mtu) || (pm == ff)) && (ff->frag_off < msize))
12404 {
12405 /* Did not yet calculate all fragments, calculate next fragment */
12406 struct PendingMessage *frag;
12407 struct TransportFragmentBoxMessage tfb;
12408 const char *orig;
12409 char *msg;
12410 uint16_t fragmax;
12411 uint16_t fragsize;
12412 uint16_t msize_ff;
12413 uint16_t xoff = 0;
12414 pm->frag_count++;
12415
12416 orig = (const char *) &ff[1];
12417 msize_ff = ff->bytes_msg;
12418 if (pm != ff)
12419 {
12420 const struct TransportFragmentBoxMessage *tfbo;
12421
12422 tfbo = (const struct TransportFragmentBoxMessage *) orig;
12423 orig += sizeof(struct TransportFragmentBoxMessage);
12424 msize_ff -= sizeof(struct TransportFragmentBoxMessage);
12425 xoff = ntohs (tfbo->frag_off);
12426 }
12427 fragmax = mtu - sizeof(struct TransportFragmentBoxMessage);
12428 fragsize = GNUNET_MIN (msize_ff - ff->frag_off, fragmax);
12429 frag =
12430 GNUNET_malloc (sizeof(struct PendingMessage)
12431 + sizeof(struct TransportFragmentBoxMessage) + fragsize);
12433 "3 created pm %p from pm %p storing vl %p from pm %p\n",
12434 frag,
12435 ff,
12436 pm->vl,
12437 pm);
12439 frag->vl = pm->vl;
12440 frag->frag_parent = ff;
12441 frag->timeout = pm->timeout;
12442 frag->bytes_msg = sizeof(struct TransportFragmentBoxMessage) + fragsize;
12443 frag->pmt = PMT_FRAGMENT_BOX;
12444 msg = (char *) &frag[1];
12445 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
12446 tfb.header.size =
12447 htons (sizeof(struct TransportFragmentBoxMessage) + fragsize);
12448 pa = prepare_pending_acknowledgement (queue, dvh, frag);
12449 tfb.ack_uuid = pa->ack_uuid;
12450 tfb.msg_uuid = pm->msg_uuid;
12451 tfb.frag_off = htons (ff->frag_off + xoff);
12452 tfb.msg_size = htons (pm->bytes_msg);
12453 memcpy (msg, &tfb, sizeof(tfb));
12454 memcpy (&msg[sizeof(tfb)], &orig[ff->frag_off], fragsize);
12456 ff->tail_frag, frag);
12457 ff->frag_off += fragsize;
12458 ff = frag;
12459 }
12460
12461 if (pm == ff)
12462 {
12463 /* Neither the descent nor the branch above moved us off @a pm, so there
12464 is no fragment to send: @e head_frag is empty *and* @e frag_off says
12465 everything was already cut. completed_pending_message() leaves
12466 exactly that state behind when the last outstanding fragment is
12467 acknowledged but its condition for finishing the root does not hold
12468 (@e frag_off having been advanced past the boxed payload size, or the
12469 root being a reliability box). The rotate below then dereferences
12470 @e frag_parent, which is NULL for the message on @e pending_msg_head.
12471
12472 Report "nothing to fragment" instead; the caller reschedules. */
12473 GNUNET_break (0);
12474 return NULL;
12475 }
12476 /* Move head to the tail and return it */
12480 ff);
12484 ff);
12485
12486 return ff;
12487}

References TransportFragmentBoxMessage::ack_uuid, PendingAcknowledgement::ack_uuid, PendingMessage::bytes_msg, PendingMessage::frag_count, TransportFragmentBoxMessage::frag_off, PendingMessage::frag_off, PendingMessage::frag_parent, GNUNET_assert, GNUNET_break, GNUNET_CONTAINER_MDLL_insert, GNUNET_CONTAINER_MDLL_insert_tail, GNUNET_CONTAINER_MDLL_remove, GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, GNUNET_malloc, GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT, GNUNET_MIN, PendingMessage::head_frag, TransportFragmentBoxMessage::header, PendingMessage::logging_uuid, logging_uuid_gen, msg, TransportFragmentBoxMessage::msg_size, TransportFragmentBoxMessage::msg_uuid, PendingMessage::msg_uuid, PendingMessage::pmt, PMT_FRAGMENT_BOX, prepare_pending_acknowledgement(), queue(), set_pending_message_uuid(), GNUNET_MessageHeader::size, PendingMessage::tail_frag, VirtualLink::target, PendingMessage::timeout, GNUNET_MessageHeader::type, MessageUUIDP::uuid, and PendingMessage::vl.

Referenced by transmit_on_queue().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ reliability_box_message()

static struct PendingMessage * reliability_box_message ( struct Queue queue,
struct DistanceVectorHop dvh,
struct PendingMessage pm 
)
static

Reliability-box the given pm.

On error (can there be any), NULL may be returned, otherwise the "replacement" for pm (which should then be added to the respective neighbour's queue instead of pm). If the pm is already fragmented or reliability boxed, or itself an ACK, this function simply returns pm.

Parameters
queuewhich queue to prepare transmission for
dvhpath the message will take, or NULL
pmpending message to box for transmission over unreliabile queue
Returns
new message to transmit

Definition at line 12503 of file gnunet-service-transport.c.

12506{
12508 struct PendingAcknowledgement *pa;
12509 struct PendingMessage *bpm;
12510 char *msg;
12511
12512 if ((PMT_CORE != pm->pmt) && (PMT_DV_BOX != pm->pmt))
12513 return pm; /* already fragmented or reliability boxed, or control message:
12514 do nothing */
12515 if (NULL != pm->bpm)
12516 return pm->bpm; /* already computed earlier: do nothing */
12517 // TODO I guess we do not need this assertion. We might have a DLL with
12518 // fragments, because the MTU changed, and we do not need to fragment anymore.
12519 // But we should keep the fragments until message was completed, because
12520 // the MTU might change again.
12521 // GNUNET_assert (NULL == pm->head_frag);
12522 if (pm->bytes_msg + sizeof(rbox) > UINT16_MAX)
12523 {
12524 /* failed hard */
12525 GNUNET_break (0);
12527 return NULL;
12528 }
12529
12530 pa = prepare_pending_acknowledgement (queue, dvh, pm);
12531
12532 bpm = GNUNET_malloc (sizeof(struct PendingMessage) + sizeof(rbox)
12533 + pm->bytes_msg);
12535 "4 created pm %p storing vl %p from pm %p\n",
12536 bpm,
12537 pm->vl,
12538 pm);
12540 bpm->vl = pm->vl;
12541 bpm->frag_parent = pm;
12542 // Why was this needed?
12543 // GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
12544 bpm->timeout = pm->timeout;
12546 bpm->bytes_msg = pm->bytes_msg + sizeof(rbox);
12548 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
12549 rbox.header.size = htons (sizeof(rbox) + pm->bytes_msg);
12550 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
12551
12552 rbox.ack_uuid = pa->ack_uuid;
12553 msg = (char *) &bpm[1];
12554 memcpy (msg, &rbox, sizeof(rbox));
12555 memcpy (&msg[sizeof(rbox)], &pm[1], pm->bytes_msg);
12556 pm->bpm = bpm;
12558 "Preparing reliability box for message <%" PRIu64
12559 "> of size %d (%d) to %s on queue %s\n",
12560 pm->logging_uuid,
12561 pm->bytes_msg,
12562 ntohs (((const struct GNUNET_MessageHeader *) &pm[1])->size),
12563 GNUNET_i2s (&pm->vl->target),
12564 queue->address);
12565 return bpm;
12566}

References TransportReliabilityBoxMessage::ack_countdown, TransportReliabilityBoxMessage::ack_uuid, PendingAcknowledgement::ack_uuid, PendingMessage::bpm, PendingMessage::bytes_msg, client_send_response(), PendingMessage::frag_parent, GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, GNUNET_malloc, GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX, TransportReliabilityBoxMessage::header, PendingMessage::logging_uuid, logging_uuid_gen, msg, PendingMessage::pmt, PMT_CORE, PMT_DV_BOX, PMT_RELIABILITY_BOX, prepare_pending_acknowledgement(), queue(), set_pending_message_uuid(), GNUNET_MessageHeader::size, size, VirtualLink::target, PendingMessage::timeout, GNUNET_MessageHeader::type, and PendingMessage::vl.

Referenced by transmit_on_queue().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ reorder_root_pm()

static void reorder_root_pm ( struct PendingMessage pm,
struct GNUNET_TIME_Absolute  next_attempt 
)
static

Definition at line 12570 of file gnunet-service-transport.c.

12572{
12573 struct VirtualLink *vl = pm->vl;
12574 struct PendingMessage *pos;
12575
12576 /* Only a message without a parent is on vl->pending_msg_head; anything
12577 else is not ours to reorder and MDLL_remove() would abort on it. */
12578 if ((NULL == vl) ||
12579 (NULL != pm->frag_parent) ||
12580 ((NULL == pm->prev_vl) && (vl->pending_msg_head != pm)))
12581 {
12582 GNUNET_break (0);
12583 return;
12584 }
12585 /* re-insert sort in neighbour list */
12589 pm);
12590 pos = vl->pending_msg_tail;
12591 while ((NULL != pos) &&
12593 pos = pos->prev_vl;
12597 pos,
12598 pm);
12599}

References GNUNET_TIME_Absolute::abs_value_us, PendingMessage::frag_parent, GNUNET_break, GNUNET_CONTAINER_MDLL_insert_after, GNUNET_CONTAINER_MDLL_remove, PendingMessage::next_attempt, VirtualLink::pending_msg_head, VirtualLink::pending_msg_tail, PendingMessage::prev_vl, and PendingMessage::vl.

Referenced by update_pm_next_attempt().

Here is the caller graph for this function:

◆ check_next_attempt_tree()

static unsigned int check_next_attempt_tree ( struct PendingMessage pm,
struct PendingMessage root 
)
static

Definition at line 12603 of file gnunet-service-transport.c.

12604{
12605 struct PendingMessage *pos;
12606 /* MUST be initialised: for a leaf the loop below never runs */
12608
12609 pos = pm->head_frag;
12610 while (NULL != pos)
12611 {
12613 GNUNET_NO == check_next_attempt_tree (pos, root))
12615 else
12616 {
12618 break;
12619 }
12620 pos = pos->next_frag;
12621 }
12622
12623 return frags_in_flight;
12624}

References check_next_attempt_tree(), PendingMessage::frags_in_flight, PendingMessage::frags_in_flight_round, GNUNET_NO, GNUNET_YES, PendingMessage::head_frag, and PendingMessage::next_frag.

Referenced by check_next_attempt_tree(), and update_pm_next_attempt().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ harmonize_flight_round()

static void harmonize_flight_round ( struct PendingMessage pm)
static

Definition at line 12628 of file gnunet-service-transport.c.

12629{
12630 struct PendingMessage *pos;
12631
12632 pos = pm->head_frag;
12633 while (NULL != pos)
12634 {
12637 pos = pos->next_frag;
12638 }
12639}

References PendingMessage::frags_in_flight_round, harmonize_flight_round(), PendingMessage::head_frag, and PendingMessage::next_frag.

Referenced by harmonize_flight_round(), and update_pm_next_attempt().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ update_pm_next_attempt()

static void update_pm_next_attempt ( struct PendingMessage pm,
struct GNUNET_TIME_Absolute  next_attempt 
)
static

Change the value of the next_attempt field of pm to next_attempt and re-order pm in the transmission list as required by the new timestamp.

Parameters
pma pending message to update
next_attempttimestamp to use

Definition at line 12651 of file gnunet-service-transport.c.

12653{
12654 if (NULL == pm->frag_parent)
12655 {
12656 pm->next_attempt = next_attempt;
12658 "Next attempt for message <%" PRIu64 "> set to %" PRIu64 "\n",
12659 pm->logging_uuid,
12660 next_attempt.abs_value_us);
12661 reorder_root_pm (pm, next_attempt);
12662 }
12663 else if ((PMT_RELIABILITY_BOX == pm->pmt) || (PMT_DV_BOX == pm->pmt))// || (PMT_FRAGMENT_BOX == pm->pmt))
12664 {
12665 struct PendingMessage *root = pm->frag_parent;
12666
12667 while (NULL != root->frag_parent)
12668 root = root->frag_parent;
12670 "Next attempt for root message <%" PRIu64 "> set to %s\n",
12671 root->logging_uuid,
12673 root->next_attempt = next_attempt;
12675 }
12676 else
12677 {
12678 struct PendingMessage *root = pm->frag_parent;
12679
12680 while (NULL != root->frag_parent && PMT_DV_BOX != root->pmt)
12681 root = root->frag_parent;
12682
12684 "frag_count next attempt %u\n",
12685 root->frag_count);
12686
12687 if (GNUNET_NO == root->frags_in_flight)
12688 {
12689 root->next_attempt = next_attempt;
12691 root->frags_in_flight_round++;
12693 "Next attempt for fragmented message <%" PRIu64 "> (<%" PRIu64
12694 ">)set to %" PRIu64 "\n",
12695 pm->logging_uuid,
12696 root->logging_uuid,
12698 }
12699
12700 pm->next_attempt = root->next_attempt;
12703
12704 if (root->bytes_msg == root->frag_off)
12705 root->frags_in_flight = check_next_attempt_tree (root, root);
12706 else
12708
12709 if (GNUNET_NO == root->frags_in_flight)
12710 {
12711 /* `root' deliberately stops at a DV box, which is itself a child of
12712 the message on vl->pending_msg_head. Walk the rest of the way for
12713 the reorder: only the parentless message is on that list. */
12714 struct PendingMessage *vl_root = root;
12715
12716 while (NULL != vl_root->frag_parent)
12717 vl_root = vl_root->frag_parent;
12718 vl_root->next_attempt = root->next_attempt;
12720 "We have no fragments in flight for message %" PRIu64
12721 ", reorder root %" PRIu64 "! Next attempt is %" PRIu64 "\n",
12722 root->logging_uuid,
12723 vl_root->logging_uuid,
12724 vl_root->next_attempt.abs_value_us);
12725 reorder_root_pm (vl_root, vl_root->next_attempt);
12726 }
12727 else
12728 {
12729 double factor = ((double) root->frag_count - 1)
12730 / (double) root->frag_count;
12731 struct GNUNET_TIME_Relative s1;
12732 struct GNUNET_TIME_Relative s2;
12733 struct GNUNET_TIME_Relative plus_mean =
12736 next_attempt);
12737
12739 "frag_count %u after factor\n",
12740 root->frag_count);
12742 factor);
12743 s2 = GNUNET_TIME_relative_divide (plus,
12744 root->frag_count);
12745 plus_mean = GNUNET_TIME_relative_add (s1, s2);
12748 "We have fragments in flight for message %" PRIu64
12749 ", do not reorder root! Actual next attempt %" PRIu64 "\n",
12750 root->logging_uuid,
12752 }
12753 }
12754}

References GNUNET_TIME_Absolute::abs_value_us, PendingMessage::bytes_msg, check_next_attempt_tree(), PendingMessage::frag_count, PendingMessage::frag_off, PendingMessage::frag_parent, PendingMessage::frags_in_flight, PendingMessage::frags_in_flight_round, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_NO, GNUNET_STRINGS_absolute_time_to_string(), GNUNET_TIME_absolute_get_remaining(), GNUNET_TIME_relative_add(), GNUNET_TIME_relative_divide(), GNUNET_TIME_relative_multiply_double(), GNUNET_TIME_relative_to_absolute(), GNUNET_YES, harmonize_flight_round(), PendingMessage::logging_uuid, PendingMessage::next_attempt, PendingMessage::pmt, PMT_DV_BOX, PMT_RELIABILITY_BOX, and reorder_root_pm().

Referenced by transmit_on_queue().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ select_best_pending_from_link()

static void select_best_pending_from_link ( struct PendingMessageScoreContext sc,
struct Queue queue,
struct VirtualLink vl,
struct DistanceVectorHop dvh,
size_t  overhead 
)
static

Select the best pending message from vl for transmission via queue.

Parameters
[in,out]scbest message so far (NULL for none), plus scoring data
queuethe queue that will be used for transmission
vlthe virtual link providing the messages
dvhpath we are currently considering, or NULL for none
overheadnumber of bytes of overhead to be expected from DV encapsulation (0 for without DV)

Definition at line 12821 of file gnunet-service-transport.c.

12826{
12827 struct GNUNET_TIME_Absolute now;
12828
12829 now = GNUNET_TIME_absolute_get ();
12830 /* NOTE: @a sc accumulates across calls -- #transmit_on_queue() zeroes it
12831 once and then runs us for the direct link and for every DV hop in turn.
12832 Clearing the verdict here made each call discard what the previous ones
12833 found, so a message that was too early on the direct link was forgotten
12834 as soon as one DV hop had nothing to offer, and nothing rescheduled the
12835 queue at all. */
12836 for (struct PendingMessage *pos = vl->pending_msg_head; NULL != pos;
12837 pos = pos->next_vl)
12838 {
12839 size_t real_overhead = overhead;
12840 int frag;
12841 int relb;
12842
12843 if ((NULL != dvh) && (PMT_DV_BOX == pos->pmt))
12844 {
12846 "DV messages must not be DV-routed to next hop!\n");
12847 continue; /* DV messages must not be DV-routed to next hop! */
12848 }
12849 if (pos->next_attempt.abs_value_us > now.abs_value_us)
12850 {
12851 if (GNUNET_YES == pos->frags_in_flight)
12852 {
12853 sc->frags_in_flight = GNUNET_YES;
12855 "Fragments in flight for message %" PRIu64 "\n",
12856 pos->logging_uuid);
12857 }
12858 else
12859 {
12861 "Maybe too early, because message are sorted by next_attempt, if there are no fragments in flight.Checked message %"
12862 PRIu64 "\n",
12863 pos->logging_uuid);
12864 /* The *earliest* deadline is the one to come back for: @e
12865 pending_msg_head is sorted by @e next_attempt, so overwriting
12866 this on every iteration left the largest delay of the whole
12867 list -- the queue then slept past every message but the last
12868 one. Across the calls for the direct link and each DV hop the
12869 same argument applies, hence the min() rather than an
12870 assignment. */
12871 sc->to_early_retry_delay =
12872 (GNUNET_YES == sc->to_early)
12873 ? GNUNET_TIME_relative_min (sc->to_early_retry_delay,
12875 pos->next_attempt))
12876 : GNUNET_TIME_absolute_get_remaining (pos->next_attempt);
12877 sc->to_early = GNUNET_YES;
12878 continue;
12879 }
12880 // break; /* too early for all messages, they are sorted by next_attempt */
12881 }
12882 if (NULL != pos->qe)
12883 {
12885 "not eligible\n");
12886 continue; /* not eligible */
12887 }
12888 sc->consideration_counter++;
12889 /* determine if we have to fragment, if so add fragmentation
12890 overhead! */
12892 "check %" PRIu64 " for sc->best\n",
12893 pos->logging_uuid);
12894 frag = GNUNET_NO;
12895 if (((0 != queue->mtu) &&
12896 (pos->bytes_msg + real_overhead > queue->mtu)) ||
12897 (pos->bytes_msg > UINT16_MAX - sizeof(struct
12899 ||
12900 (NULL != pos->head_frag /* fragments already exist, should
12901 respect that even if MTU is UINT16_MAX for
12902 this queue */))
12903 {
12905 "fragment msg with size %u, realoverhead is %lu\n",
12906 pos->bytes_msg,
12907 real_overhead);
12908 frag = GNUNET_YES;
12909 if (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc)
12910 {
12911 /* FIXME-FRAG-REL-UUID: we could use an optimized, shorter fragmentation
12912 header without the ACK UUID when using a *reliable* channel! */
12913 }
12914 real_overhead = overhead + sizeof(struct TransportFragmentBoxMessage);
12915 }
12916 /* determine if we have to reliability-box, if so add reliability box
12917 overhead */
12918 relb = GNUNET_NO;
12919 if ((GNUNET_NO == frag) &&
12920 (0 == (pos->prefs & GNUNET_MQ_PREF_UNRELIABLE)) &&
12921 (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc))
12922 {
12923 real_overhead += sizeof(struct TransportReliabilityBoxMessage);
12924
12925 if ((0 != queue->mtu) && (pos->bytes_msg + real_overhead > queue->mtu))
12926 {
12927 frag = GNUNET_YES;
12928 real_overhead = overhead + sizeof(struct TransportFragmentBoxMessage);
12929 }
12930 else
12931 {
12932 relb = GNUNET_YES;
12933 }
12935 "Create reliability box of msg with size %u, realoverhead is %lu %u %u %u\n",
12936 pos->bytes_msg,
12937 real_overhead,
12938 queue->mtu,
12939 frag,
12940 relb);
12941 }
12942
12943 /* Finally, compare to existing 'best' in sc to see if this 'pos' pending
12944 message would beat it! */
12945 if (GNUNET_NO == sc->frags_in_flight && NULL != sc->best)
12946 {
12947 /* CHECK if pos fits queue BETTER (=smaller) than pm, if not: continue;
12948 OPTIMIZE-ME: This is a heuristic, which so far has NOT been
12949 experimentally validated. There may be some huge potential for
12950 improvement here. Also, we right now only compare how well the
12951 given message fits _this_ queue, and do not consider how well other
12952 queues might suit the message. Taking other queues into consideration
12953 may further improve the result, but could also be expensive
12954 in terms of CPU time. */
12955 long long sc_score = sc->frag * 40 + sc->relb * 20 + sc->real_overhead;
12956 long long pm_score = frag * 40 + relb * 20 + real_overhead;
12957 long long time_delta =
12958 (sc->best->next_attempt.abs_value_us - pos->next_attempt.abs_value_us)
12959 / 1000LL;
12960
12961 /* "time_delta" considers which message has been 'ready' for transmission
12962 for longer, if a message has a preference for low latency, increase
12963 the weight of the time_delta by 10x if it is favorable for that message */
12964 if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
12965 (0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)))
12966 time_delta *= 10; /* increase weight (always, both are low latency) */
12967 else if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
12968 (time_delta > 0))
12969 time_delta *= 10; /* increase weight, favors 'pos', which is low latency */
12970 else if ((0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
12971 (time_delta < 0))
12972 time_delta *= 10; /* increase weight, favors 'sc->best', which is low latency */
12973 if (0 != queue->mtu)
12974 {
12975 /* Grant bonus if we are below MTU, larger bonus the closer we will
12976 be to the MTU */
12977 if (queue->mtu > sc->real_overhead + sc->best->bytes_msg)
12978 sc_score -= queue->mtu - (sc->real_overhead + sc->best->bytes_msg);
12979 if (queue->mtu > real_overhead + pos->bytes_msg)
12980 pm_score -= queue->mtu - (real_overhead + pos->bytes_msg);
12981 }
12982 if (sc_score + time_delta > pm_score)
12983 {
12985 "sc_score of %" PRIu64 " larger, keep sc->best %" PRIu64
12986 "\n",
12987 pos->logging_uuid,
12988 sc->best->logging_uuid);
12989 continue; /* sc_score larger, keep sc->best */
12990 }
12991 }
12992 sc->best = pos;
12993 sc->dvh = dvh;
12994 sc->frag = frag;
12995 sc->relb = relb;
12996 sc->real_overhead = real_overhead;
12997 }
12998}

References GNUNET_TIME_Absolute::abs_value_us, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_MQ_PREF_LOW_LATENCY, GNUNET_MQ_PREF_UNRELIABLE, GNUNET_NO, GNUNET_TIME_absolute_get(), GNUNET_TIME_absolute_get_remaining(), GNUNET_TIME_relative_min(), GNUNET_TRANSPORT_CC_RELIABLE, GNUNET_YES, VirtualLink::pending_msg_head, PMT_DV_BOX, queue(), and sc.

Referenced by transmit_on_queue().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ extract_box_cb()

static void extract_box_cb ( void *  cls,
struct Neighbour next_hop,
const struct GNUNET_MessageHeader hdr,
enum RouteMessageOptions  options 
)
static

Function to call to further operate on the now DV encapsulated message hdr, forwarding it via next_hop under respect of options.

Parameters
clsa struct PendingMessageScoreContext
next_hopnext hop of the DV path
hdrencapsulated message, technically a struct TransportDVBoxMessage
optionsoptions of the original message

Definition at line 13012 of file gnunet-service-transport.c.

13016{
13017 struct PendingMessageScoreContext *sc = cls;
13018 struct PendingMessage *pm = sc->best;
13019 struct PendingMessage *bpm;
13020 uint16_t bsize = ntohs (hdr->size);
13021
13022 GNUNET_assert (NULL == pm->bpm);
13023 bpm = GNUNET_malloc (sizeof(struct PendingMessage) + bsize);
13025 "5 created pm %p storing vl %p from pm %p\n",
13026 bpm,
13027 pm->vl,
13028 pm);
13030 bpm->pmt = PMT_DV_BOX;
13031 bpm->vl = pm->vl;
13032 bpm->timeout = pm->timeout;
13033 bpm->bytes_msg = bsize;
13034 bpm->frag_parent = pm;
13037 "Creating DV Box %" PRIu64 " for original message %" PRIu64
13038 " (next hop is %s)\n",
13040 pm->logging_uuid,
13041 GNUNET_i2s (&next_hop->pid));
13042 memcpy (&bpm[1], hdr, bsize);
13043 pm->bpm = bpm;
13044}

References PendingMessage::bpm, bsize, PendingMessage::bytes_msg, PendingMessage::frag_parent, GNUNET_assert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, GNUNET_malloc, PendingMessage::logging_uuid, logging_uuid_gen, Neighbour::pid, PendingMessage::pmt, PMT_DV_BOX, sc, set_pending_message_uuid(), GNUNET_MessageHeader::size, PendingMessage::timeout, and PendingMessage::vl.

Referenced by transmit_on_queue().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_del_queue_message()

static void handle_del_queue_message ( void *  cls,
const struct GNUNET_TRANSPORT_DelQueueMessage dqm 
)
static

Queue to a peer went down.

Process the request.

Parameters
clsthe client
dqmthe send message that was sent

Definition at line 13360 of file gnunet-service-transport.c.

13362{
13363 struct TransportClient *tc = cls;
13364
13365 if (CT_COMMUNICATOR != tc->type)
13366 {
13367 GNUNET_break (0);
13369 return;
13370 }
13371 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
13372 queue = queue->next_client)
13373 {
13374 struct Neighbour *neighbour = queue->neighbour;
13375
13376 if ((ntohl (dqm->qid) != queue->qid) ||
13377 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
13378 continue;
13380 "Dropped queue %s to peer %s\n",
13381 queue->address,
13382 GNUNET_i2s (&neighbour->pid));
13383 free_queue (queue);
13385 return;
13386 }
13387 /* Not finding the queue is a race, not a protocol violation: we may have
13388 freed it ourselves already, or the communicator may be tearing down a
13389 queue we never fully learned about. Do NOT drop the client over it --
13390 that runs #client_disconnect_cb(), which frees *every* queue this
13391 communicator owns, so one stale QUEUE_TEARDOWN would disconnect us from
13392 every peer it serves at once. Compare #handle_send_message_ack(), which
13393 tolerates the same lookup miss. */
13395 "QUEUE_TEARDOWN for unknown queue QID %u to peer %s ignored\n",
13396 ntohl (dqm->qid),
13397 GNUNET_i2s (&dqm->receiver));
13399 "# QUEUE_TEARDOWN dropped: queue unknown",
13400 1,
13401 GNUNET_NO);
13403}

References CT_COMMUNICATOR, free_queue(), GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_WARNING, GNUNET_i2s(), GNUNET_log, GNUNET_memcmp, GNUNET_NO, GNUNET_SERVICE_client_continue(), GNUNET_SERVICE_client_drop(), GNUNET_STATISTICS_update(), GST_stats, Neighbour::pid, GNUNET_TRANSPORT_DelQueueMessage::qid, queue(), GNUNET_TRANSPORT_DelQueueMessage::receiver, and tc.

Here is the call graph for this function:

◆ handle_send_message_ack()

static void handle_send_message_ack ( void *  cls,
const struct GNUNET_TRANSPORT_SendMessageToAck sma 
)
static

Message was transmitted.

Process the request.

Parameters
clsthe client
smathe send message that was sent

Definition at line 13504 of file gnunet-service-transport.c.

13506{
13507 struct TransportClient *tc = cls;
13508 struct QueueEntry *qe;
13509 struct Queue *failed_queue = NULL;
13510
13511 if (CT_COMMUNICATOR != tc->type)
13512 {
13513 GNUNET_break (0);
13515 return;
13516 }
13517
13518 /* find our queue entry matching the ACK */
13519 qe = NULL;
13521 "Looking for queue for PID %s\n",
13522 GNUNET_i2s (&sma->receiver));
13523 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
13524 queue = queue->next_client)
13525 {
13526 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
13527 continue;
13529 "Found PID %s\n",
13530 GNUNET_i2s (&queue->neighbour->pid));
13531
13532
13533 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
13534 qep = qep->next)
13535 {
13536 if (qep->mid != GNUNET_ntohll (sma->mid) || queue->qid != ntohl (
13537 sma->qid))
13538 continue;
13540 "QueueEntry MID: %" PRIu64 " on queue QID: %u, Ack MID: %"
13541 PRIu64 " Ack QID %u\n",
13542 qep->mid,
13543 queue->qid,
13544 GNUNET_ntohll (sma->mid),
13545 ntohl (sma->qid));
13546 qe = qep;
13547 if ((NULL != qe->pm) && (qe->pm->qe != qe))
13549 "For pending message %" PRIu64 " we had retransmissions.\n",
13550 qe->pm->logging_uuid);
13551 break;
13552 }
13553 }
13554 if (GNUNET_OK != (int) ntohl (sma->status))
13555 {
13556 /* The communicator could not hand the message to the peer. The only
13557 thing that produces this today is #handle_send_msg()'s "queue no
13558 longer exists" branch in `transport_api_communication.c', i.e. the
13559 communicator has already torn the queue down on its side and the
13560 QUEUE_TEARDOWN is merely still in flight (or was lost).
13561
13562 Ignoring the status, as we used to, makes this self-sustaining:
13563 #free_queue_entry() releases the pending message and immediately
13564 reschedules transmission, #transmit_on_queue() picks the very same
13565 queue again -- transport still has it -- and we get another failure.
13566 Every round adds an envelope to the client MQ that is already
13567 congested, which is what shows up at the other end as
13568
13569 communicator INFO Transmission failed, queue no longer exists.
13570
13571 repeating at scheduler speed, and (because the service is busy
13572 servicing that loop) as
13573
13574 communicator WARNING Dropping message: transport is too slow,
13575 queue length N exceeded
13576
13577 on every *other* communicator. Treat the failure as the queue
13578 teardown it is and stop selecting this queue. */
13580 "Communicator could not send MID %" PRIu64
13581 " on QID %u to %s; dropping that queue\n",
13582 GNUNET_ntohll (sma->mid),
13583 ntohl (sma->qid),
13584 GNUNET_i2s (&sma->receiver));
13586 "# queues dropped (communicator send failed)",
13587 1,
13588 GNUNET_NO);
13589 if (NULL != qe)
13590 failed_queue = qe->queue;
13591 else
13592 for (struct Queue *queue = tc->details.communicator.queue_head;
13593 NULL != queue;
13594 queue = queue->next_client)
13595 if ((ntohl (sma->qid) == queue->qid) &&
13596 (0 == GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver)))
13597 {
13598 failed_queue = queue;
13599 break;
13600 }
13601 if (NULL != failed_queue)
13602 {
13603 /* #free_queue() releases every `struct QueueEntry' still on it --
13604 including @a qe -- and detaches their pending messages, so they are
13605 retried on whatever other queue this neighbour has. */
13606 free_queue (failed_queue);
13608 return;
13609 }
13610 }
13611 if (NULL == qe)
13612 {
13614 "No QueueEntry found for Ack MID %" PRIu64 " QID: %u\n",
13615 GNUNET_ntohll (sma->mid),
13616 ntohl (sma->qid));
13617 // TODO I guess this can happen, if the Ack from the peer comes before the Ack from the queue.
13618 // Update: Maybe QueueEntry was accidentally freed during freeing PendingMessage.
13619 /* this should never happen */
13620 // GNUNET_break (0);
13621 // GNUNET_SERVICE_client_drop (tc->client);
13623 return;
13624 }
13627}

References CT_COMMUNICATOR, free_queue(), free_queue_entry(), GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_INFO, GNUNET_i2s(), GNUNET_log, GNUNET_memcmp, GNUNET_NO, GNUNET_ntohll(), GNUNET_OK, GNUNET_SERVICE_client_continue(), GNUNET_SERVICE_client_drop(), GNUNET_STATISTICS_update(), GST_stats, GNUNET_TRANSPORT_SendMessageToAck::mid, qe, GNUNET_TRANSPORT_SendMessageToAck::qid, queue(), GNUNET_TRANSPORT_SendMessageToAck::receiver, GNUNET_TRANSPORT_SendMessageToAck::status, and tc.

Here is the call graph for this function:

◆ handle_burst_finished()

static void handle_burst_finished ( void *  cls,
const struct GNUNET_TRANSPORT_BurstFinished bf 
)
static

The burst finished.

Parameters
clsthe client

Definition at line 13636 of file gnunet-service-transport.c.

13638{
13639 struct TransportClient *tc = cls;
13640
13641 (void) bf;
13644}

References burst_running, GNUNET_NO, GNUNET_SERVICE_client_continue(), and tc.

Here is the call graph for this function:

◆ notify_client_queues()

static int notify_client_queues ( void *  cls,
const struct GNUNET_PeerIdentity pid,
void *  value 
)
static

Iterator telling new MONITOR client about all existing queues to peers.

Parameters
clsthe new struct TransportClient
pida connected peer
valuethe struct Neighbour with more information
Returns
GNUNET_OK (continue to iterate)

Definition at line 13657 of file gnunet-service-transport.c.

13660{
13661 struct TransportClient *tc = cls;
13662 struct Neighbour *neighbour = value;
13663
13664 GNUNET_assert (CT_MONITOR == tc->type);
13665 for (struct Queue *q = neighbour->queue_head; NULL != q;
13666 q = q->next_neighbour)
13667 {
13668 struct MonitorEvent me = { .rtt = q->pd.aged_rtt,
13669 .cs = q->cs,
13670 .num_msg_pending = q->num_msg_pending,
13671 .num_bytes_pending = q->num_bytes_pending };
13672
13673 notify_monitor (tc, pid, q->address, q->nt, &me);
13674 }
13675 return GNUNET_OK;
13676}

References CT_MONITOR, GNUNET_assert, GNUNET_OK, me, notify_monitor(), q, Neighbour::queue_head, tc, and value.

Referenced by handle_monitor_start().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_monitor_start()

static void handle_monitor_start ( void *  cls,
const struct GNUNET_TRANSPORT_MonitorStart start 
)
static

Initialize a monitor client.

Parameters
clsthe client
startthe start message that was sent

Definition at line 13686 of file gnunet-service-transport.c.

13688{
13689 struct TransportClient *tc = cls;
13690
13691 if (CT_NONE != tc->type)
13692 {
13693 GNUNET_break (0);
13695 return;
13696 }
13697 tc->type = CT_MONITOR;
13698 tc->details.monitor.peer = start->peer;
13699 tc->details.monitor.one_shot = ntohl (start->one_shot);
13703}

References CT_MONITOR, CT_NONE, GNUNET_break, GNUNET_CONTAINER_multipeermap_iterate(), GNUNET_SERVICE_client_continue(), GNUNET_SERVICE_client_drop(), GNUNET_SERVICE_client_mark_monitor(), neighbours, notify_client_queues(), start, and tc.

Here is the call graph for this function:

◆ communicator_list()

static char * communicator_list ( struct Neighbour n,
unsigned int *  num_queues 
)
static

Build the 0-terminated, comma-separated list of address prefixes of the communicators that own the queues of n, without repeats.

Parameters
nneighbour to inspect, may be NULL
[out]num_queuesset to the number of queues considered
Returns
list to be released with GNUNET_free()

Definition at line 13732 of file gnunet-service-transport.c.

13734{
13735 char *ret = GNUNET_strdup ("");
13736
13737 *num_queues = 0;
13738 if (NULL == n)
13739 return ret;
13740 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
13741 {
13742 const char *prefix = q->tc->details.communicator.address_prefix;
13743 size_t plen = strlen (prefix);
13744 const char *pos;
13745 char *tmp;
13746
13747 (*num_queues)++;
13748 if (0 == plen)
13749 continue;
13750 /* Several queues to one neighbour routinely share a communicator;
13751 name each one once. */
13752 for (pos = strstr (ret, prefix);
13753 NULL != pos;
13754 pos = strstr (pos + 1, prefix))
13755 if (((pos == ret) || (',' == pos[-1])) &&
13756 (('\0' == pos[plen]) || (',' == pos[plen])))
13757 break;
13758 if (NULL != pos)
13759 continue;
13760 GNUNET_asprintf (&tmp, "%s%s%s", ret, ('\0' == ret[0]) ? "" : ",", prefix);
13761 GNUNET_free (ret);
13762 ret = tmp;
13763 }
13764 return ret;
13765}

References GNUNET_asprintf(), GNUNET_free, GNUNET_strdup, prefix, q, Neighbour::queue_head, and ret.

Referenced by report_link().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ report_link()

static enum GNUNET_GenericReturnValue report_link ( void *  cls,
const struct GNUNET_PeerIdentity pid,
void *  value 
)
static

Send the state of the virtual link value to the requesting client.

Parameters
clsa struct LinkListContext *
pidpeer at the other end of the link
valuethe struct VirtualLink * to report on
Returns
GNUNET_OK (continue to iterate)

Definition at line 13777 of file gnunet-service-transport.c.

13778{
13779 struct LinkListContext *llc = cls;
13780 struct VirtualLink *vl = value;
13782 struct GNUNET_MQ_Envelope *env;
13783 unsigned int pending = 0;
13784 unsigned int num_queues = 0;
13785 unsigned int distance = 0;
13786 struct Neighbour *hop;
13787 char *ccs;
13788 size_t clen;
13789
13790 if ((GNUNET_YES != llc->include_unconfirmed) &&
13791 (GNUNET_YES != vl->confirmed))
13792 return GNUNET_OK;
13793 for (struct PendingMessage *pm = vl->pending_msg_head;
13794 NULL != pm;
13795 pm = pm->next_vl)
13796 pending++;
13797 if (NULL != vl->n)
13798 {
13799 hop = vl->n;
13800 }
13801 else
13802 {
13803 /* Report the best (shortest) of the paths we currently know, and the
13804 communicators that carry its first hop. */
13805 struct DistanceVectorHop *best = NULL;
13806
13807 distance = UINT_MAX;
13808 if (NULL != vl->dv)
13809 for (struct DistanceVectorHop *pos = vl->dv->dv_head;
13810 NULL != pos;
13811 pos = pos->next_dv)
13812 if (pos->distance < distance)
13813 {
13814 distance = pos->distance;
13815 best = pos;
13816 }
13817 if (NULL == best)
13818 distance = 0; /* no paths left; report the link as adjacent */
13819 hop = (NULL != best) ? best->next_hop : NULL;
13820 }
13821 ccs = communicator_list (hop, &num_queues);
13822 clen = strlen (ccs) + 1;
13823 env = GNUNET_MQ_msg_extra (resp,
13824 clen,
13826 memcpy (&resp[1], ccs, clen);
13827 GNUNET_free (ccs);
13828 resp->target = *pid;
13829 resp->confirmed = htonl ((uint32_t) vl->confirmed);
13830 resp->route = htonl ((uint32_t) ((NULL != vl->n)
13833 resp->distance = htonl ((uint32_t) distance);
13834 resp->num_queues = htonl ((uint32_t) num_queues);
13835 resp->core_recv_window = htonl ((int32_t) vl->core_recv_window);
13836 resp->stalled = htonl ((uint32_t) vl->cmc_count);
13837 resp->pending = htonl (pending);
13838 resp->fc_retransmit_count = htonl ((uint32_t) vl->fc_retransmit_count);
13857 GNUNET_MQ_send (llc->tc->mq, env);
13858 return GNUNET_OK;
13859}

References VirtualLink::available_fc_window_size, GNUNET_TRANSPORT_LinkListResponse::available_fc_window_size, VirtualLink::cmc_count, communicator_list(), VirtualLink::confirmed, GNUNET_TRANSPORT_LinkListResponse::confirmed, VirtualLink::core_recv_window, GNUNET_TRANSPORT_LinkListResponse::core_recv_window, DistanceVectorHop::distance, GNUNET_TRANSPORT_LinkListResponse::distance, VirtualLink::dv, DistanceVector::dv_head, env, VirtualLink::fc_retransmit_count, GNUNET_TRANSPORT_LinkListResponse::fc_retransmit_count, GNUNET_free, GNUNET_htonll(), GNUNET_MESSAGE_TYPE_TRANSPORT_LINK_LIST_RESPONSE, GNUNET_MQ_msg_extra, GNUNET_MQ_send(), GNUNET_OK, GNUNET_TIME_absolute_hton(), GNUNET_TIME_relative_hton(), GNUNET_TRANSPORT_LINK_ROUTE_DIRECT, GNUNET_TRANSPORT_LINK_ROUTE_DV, GNUNET_YES, VirtualLink::incoming_fc_window_size, GNUNET_TRANSPORT_LinkListResponse::incoming_fc_window_size, VirtualLink::incoming_fc_window_size_loss, GNUNET_TRANSPORT_LinkListResponse::incoming_fc_window_size_loss, VirtualLink::incoming_fc_window_size_ram, GNUNET_TRANSPORT_LinkListResponse::incoming_fc_window_size_ram, VirtualLink::incoming_fc_window_size_used, GNUNET_TRANSPORT_LinkListResponse::incoming_fc_window_size_used, VirtualLink::last_fc_rtt, GNUNET_TRANSPORT_LinkListResponse::last_fc_rtt, VirtualLink::last_fc_transmission, GNUNET_TRANSPORT_LinkListResponse::last_fc_transmission, llc, GNUNET_TRANSPORT_LinkListContext::mq, VirtualLink::n, DistanceVectorHop::next_hop, GNUNET_TRANSPORT_LinkListResponse::num_queues, VirtualLink::other_rtt, GNUNET_TRANSPORT_LinkListResponse::other_rtt, VirtualLink::outbound_fc_window_size, GNUNET_TRANSPORT_LinkListResponse::outbound_fc_window_size, VirtualLink::outbound_fc_window_size_used, GNUNET_TRANSPORT_LinkListResponse::outbound_fc_window_size_used, pending, GNUNET_TRANSPORT_LinkListResponse::pending, VirtualLink::pending_msg_head, GNUNET_TRANSPORT_LinkListResponse::route, GNUNET_TRANSPORT_LinkListResponse::stalled, GNUNET_TRANSPORT_LinkListResponse::target, value, and Neighbour::vl.

Referenced by handle_link_list_request().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_link_list_request()

static void handle_link_list_request ( void *  cls,
const struct GNUNET_TRANSPORT_LinkListRequest lr 
)
static

A client asks for the virtual links we currently have.

Answer with one GNUNET_MESSAGE_TYPE_TRANSPORT_LINK_LIST_RESPONSE per link, then a GNUNET_MESSAGE_TYPE_TRANSPORT_LINK_LIST_RESPONSE_END.

Parameters
clsthe client
lrthe request

Definition at line 13871 of file gnunet-service-transport.c.

13874{
13875 struct TransportClient *tc = cls;
13876 struct LinkListContext llc = {
13877 .tc = tc,
13878 .include_unconfirmed = (int) ntohl (lr->include_unconfirmed)
13879 };
13880 struct GNUNET_MQ_Envelope *env;
13881 struct GNUNET_MessageHeader *end;
13882
13883 if (CT_NONE != tc->type)
13884 {
13885 GNUNET_break (0);
13887 return;
13888 }
13889 if (GNUNET_YES == GNUNET_is_zero (&lr->peer))
13890 {
13892 }
13893 else
13894 {
13895 struct VirtualLink *vl = lookup_virtual_link (&lr->peer);
13896
13897 if (NULL != vl)
13898 report_link (&llc, &lr->peer, vl);
13899 }
13902 GNUNET_MQ_send (tc->mq, env);
13904}

References CT_NONE, end, env, GNUNET_break, GNUNET_CONTAINER_multipeermap_iterate(), GNUNET_is_zero, GNUNET_MESSAGE_TYPE_TRANSPORT_LINK_LIST_RESPONSE_END, GNUNET_MQ_msg, GNUNET_MQ_send(), GNUNET_SERVICE_client_continue(), GNUNET_SERVICE_client_drop(), GNUNET_YES, links, llc, lookup_virtual_link(), lr, report_link(), and tc.

Here is the call graph for this function:

◆ lookup_communicator()

static struct TransportClient * lookup_communicator ( const char *  prefix)
static

Find transport client providing communication service for the protocol prefix.

Parameters
prefixcommunicator name
Returns
NULL if no such transport client is available

Definition at line 13915 of file gnunet-service-transport.c.

13916{
13917 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
13918 {
13919 if (CT_COMMUNICATOR != tc->type)
13920 continue;
13921 if (NULL == tc->details.communicator.address_prefix)
13922 continue; /* receive-only communicator */
13923 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
13924 return tc;
13925 }
13926 GNUNET_log (
13928 "Someone suggested use of communicator for `%s', but we do not have such a communicator!\n",
13929 prefix);
13930 return NULL;
13931}

References clients_head, CT_COMMUNICATOR, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, prefix, and tc.

Referenced by suggest_to_connect().

Here is the caller graph for this function:

◆ validation_challenge_freq()

static struct GNUNET_TIME_Relative validation_challenge_freq ( const struct GNUNET_PeerIdentity pid)
static

How slow are we allowed to get with challenges for pid?

An address of a peer nobody is waiting for may back off all the way to MAX_VALIDATION_CHALLENGE_FREQ. A peer an application client asked for and that we have no confirmed link to may not: at a day between challenges the client would be told about the peer some time next week.

Parameters
pidpeer whose address we are about to challenge
Returns
the cap for GNUNET_TIME_randomized_backoff()

Definition at line 14052 of file gnunet-service-transport.c.

14053{
14054 const struct VirtualLink *vl = lookup_virtual_link (pid);
14055
14056 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
14057 return MAX_VALIDATION_CHALLENGE_FREQ; /* we have what we want */
14058 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
14059 {
14060 if (CT_APPLICATION != tc->type)
14061 continue;
14063 tc->details.application.requests,
14064 pid))
14066 }
14068}

References clients_head, VirtualLink::confirmed, CT_APPLICATION, GNUNET_CONTAINER_multipeermap_get(), GNUNET_YES, lookup_virtual_link(), MAX_VALIDATION_CHALLENGE_FREQ, tc, and WANTED_VALIDATION_CHALLENGE_FREQ.

Referenced by validation_start_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_connection_quality()

static int check_connection_quality ( void *  cls,
const struct GNUNET_PeerIdentity pid,
void *  value 
)
static

Check whether any queue to the given neighbour is of a good "quality" and if so, increment the counter.

Also counts the total number of queues, and returns the k-th queue found.

Parameters
clsa struct QueueQualityContext * with counters
pidpeer this is about
valuea struct Neighbour
Returns
GNUNET_OK (continue to iterate)

Definition at line 14188 of file gnunet-service-transport.c.

14191{
14192 struct QueueQualityContext *ctx = cls;
14193 struct Neighbour *n = value;
14194 int do_inc;
14195
14196 (void) pid;
14197 do_inc = GNUNET_NO;
14198 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
14199 {
14200 ctx->num_queues++;
14201 if (0 == ctx->k--)
14202 ctx->q = q;
14203 /* FIXME-CONQ-STATISTICS: in the future, add reliability / goodput
14204 statistics and consider those as well here? */
14205 if (q->pd.aged_rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
14206 do_inc = GNUNET_YES;
14207 }
14208 if (GNUNET_YES == do_inc)
14209 ctx->quality_count++;
14210 return GNUNET_OK;
14211}

References ctx, DV_QUALITY_RTT_THRESHOLD, GNUNET_NO, GNUNET_OK, GNUNET_YES, Neighbour::pid, q, Neighbour::queue_head, and value.

Referenced by start_dv_learn(), and transmit_dv_init().

Here is the caller graph for this function:

◆ start_dv_learn()

static void start_dv_learn ( void *  cls)
static

Task run when we CONSIDER initiating a DV learn process.

We first check that sending out a message is even possible (queues exist), then that it is desirable (if not, reschedule the task for later), and finally we may then begin the job. If there are too many entries in the dvlearn_map, we purge the oldest entry using lle_tail.

Parameters
clsNULL

Definition at line 14292 of file gnunet-service-transport.c.

14293{
14294 struct LearnLaunchEntry *lle;
14295 struct QueueQualityContext qqc;
14296 struct TransportDVLearnMessage dvl;
14297 const struct GNUNET_PeerIdentity *my_identity;
14298
14299 (void) cls;
14300 dvlearn_task = NULL;
14301 if ((GNUNET_YES == in_shutdown) || (NULL == pils))
14302 return;
14304 return; /* lost all connectivity, cannot do learning */
14306 if (NULL == my_identity)
14307 {
14308 /* PILS has not handed us an identity yet. The first queue arriving
14309 schedules us with add_now(), which routinely wins that race; retry
14310 instead of taking the service down. */
14314 NULL);
14315 return;
14316 }
14318 qqc.quality_count = 0;
14319 qqc.num_queues = 0;
14323 &qqc);
14324 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
14325 {
14326 struct GNUNET_TIME_Relative delay;
14327 unsigned int factor;
14328
14329 /* scale our retries by how far we are above the threshold */
14330 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
14333 "At connection quality %u, will launch DV learn in %s\n",
14334 qqc.quality_count,
14337 return;
14338 }
14339 /* remove old entries in #dvlearn_map if it has grown too big */
14340 while (MAX_DV_LEARN_PENDING <=
14342 {
14343 lle = lle_tail;
14346 &lle->challenge.value,
14347 lle));
14349 GNUNET_free (lle);
14350 }
14351 /* setup data structure for learning */
14352 lle = GNUNET_new (struct LearnLaunchEntry);
14354 sizeof(lle->challenge));
14356 "Starting launch DV learn with challenge %s\n",
14357 GNUNET_sh2s (&lle->challenge.value));
14362 &lle->challenge.value,
14363 lle,
14365 dvl.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
14366 dvl.header.size = htons (sizeof(dvl));
14367 dvl.num_hops = htons (0);
14368 dvl.bidirectional = htons (0);
14369 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
14370 dvl.monotonic_time =
14372 // We will set the below again later
14373 memset (&dvl.init_sig, 0, sizeof dvl.init_sig);
14374 dvl.challenge = lle->challenge;
14375 dvl.initiator = *my_identity;
14376 {
14377 struct DvInitPS dvip = {
14378 .purpose.purpose = htonl (
14380 .purpose.size = htonl (sizeof(dvip)),
14381 .monotonic_time = dvl.monotonic_time,
14382 .challenge = lle->challenge
14383 };
14384
14385 if (GNUNET_OK != sign_by_my_identity (&dvip.purpose, &dvl.init_sig))
14386 return;
14387 }
14388 transmit_dv_init (dvl, lle, qqc);
14389}

References TransportDVLearnMessage::bidirectional, TransportDVLearnMessage::challenge, LearnLaunchEntry::challenge, check_connection_quality(), DV_LEARN_BASE_FREQUENCY, DV_LEARN_QUALITY_THRESHOLD, dvlearn_map, dvlearn_pils_backoff, dvlearn_task, GNUNET_assert, GNUNET_break, GNUNET_CONTAINER_DLL_insert, GNUNET_CONTAINER_DLL_remove, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY, GNUNET_CONTAINER_multipeermap_iterate(), GNUNET_CONTAINER_multipeermap_size(), GNUNET_CONTAINER_multishortmap_put(), GNUNET_CONTAINER_multishortmap_remove(), GNUNET_CONTAINER_multishortmap_size(), GNUNET_CRYPTO_random_block(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_log, GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN, GNUNET_new, GNUNET_OK, GNUNET_PILS_get_identity(), GNUNET_SCHEDULER_add_delayed(), GNUNET_sh2s(), GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR, GNUNET_STRINGS_relative_time_to_string(), GNUNET_TIME_absolute_get_monotonic(), GNUNET_TIME_absolute_hton(), GNUNET_TIME_relative_hton(), GNUNET_TIME_relative_multiply(), GNUNET_TIME_STD_BACKOFF, GNUNET_TIME_UNIT_ZERO, GNUNET_YES, GST_cfg, TransportDVLearnMessage::header, in_shutdown, TransportDVLearnMessage::init_sig, TransportDVLearnMessage::initiator, QueueQualityContext::k, lle_head, lle_tail, MAX_DV_LEARN_PENDING, TransportDVLearnMessage::monotonic_time, my_identity, neighbours, TransportDVLearnMessage::non_network_delay, TransportDVLearnMessage::num_hops, QueueQualityContext::num_queues, pils, GNUNET_CRYPTO_SignaturePurpose::purpose, DvInitPS::purpose, QueueQualityContext::quality_count, sign_by_my_identity(), GNUNET_MessageHeader::size, start_dv_learn(), transmit_dv_init(), GNUNET_MessageHeader::type, and GNUNET_CRYPTO_ChallengeNonceP::value.

Referenced by handle_add_queue_message(), start_dv_learn(), and transmit_dv_init().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ transmit_dv_init()

static void transmit_dv_init ( struct TransportDVLearnMessage  dvl,
struct LearnLaunchEntry lle,
struct QueueQualityContext  qqc 
)
static

Finish and transmit the DV learn message dvl we initiated.

Parameters
dvlthe message, signature already filled in
lleour launch entry for this challenge
qqcqueue quality context to pick the transmitting queue from

Definition at line 14237 of file gnunet-service-transport.c.

14240{
14241 if (0 == qqc.num_queues)
14242 {
14244 "# DV learn aborted: no queue left",
14245 1,
14246 GNUNET_NO);
14247 return;
14248 }
14249 qqc.quality_count = 0;
14251 qqc.num_queues = 0;
14252 qqc.q = NULL;
14255 &qqc);
14256 if (NULL == qqc.q)
14257 {
14259 "# DV learn aborted: no queue left",
14260 1,
14261 GNUNET_NO);
14262 return;
14263 }
14264
14265 /* Do this as close to transmission time as possible! */
14267
14268 queue_send_msg (qqc.q, NULL, &dvl, sizeof(dvl));
14269 /* reschedule this job, randomizing the time it runs (but no
14270 actual backoff!) */
14271 if (NULL != dvlearn_task)
14276 NULL);
14277}

References check_connection_quality(), DV_LEARN_BASE_FREQUENCY, dvlearn_task, GNUNET_CONTAINER_multipeermap_iterate(), GNUNET_CRYPTO_random_u32(), GNUNET_NO, GNUNET_SCHEDULER_add_delayed(), GNUNET_SCHEDULER_cancel(), GNUNET_STATISTICS_update(), GNUNET_TIME_absolute_get(), GNUNET_TIME_randomize(), GST_stats, QueueQualityContext::k, LearnLaunchEntry::launch_time, neighbours, QueueQualityContext::num_queues, QueueQualityContext::q, QueueQualityContext::quality_count, queue_send_msg(), and start_dv_learn().

Referenced by start_dv_learn().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_validation_request_pending()

static int check_validation_request_pending ( void *  cls,
const struct GNUNET_PeerIdentity pid,
void *  value 
)
static

A new queue has been created, check if any address validation requests have been waiting for it.

Parameters
clsa struct Queue
pidpeer concerned (unused)
valuea struct ValidationState
Returns
GNUNET_NO if a match was found and we can stop looking

Definition at line 14430 of file gnunet-service-transport.c.

14433{
14434 struct Queue *q = cls;
14435 struct ValidationState *vs = value;
14436 char *address_without_port_vs;
14437 char *address_without_port_q;
14438 char *prefix_vs;
14439 char *prefix_q;
14440 int success = GNUNET_YES;
14441
14442 // TODO Check if this is really necessary.
14443 address_without_port_vs = get_address_without_port (vs->address);
14444 address_without_port_q = get_address_without_port (q->address);
14445 prefix_vs = GNUNET_HELLO_address_to_prefix (vs->address);
14446 prefix_q = GNUNET_HELLO_address_to_prefix (q->address);
14447
14449 "Check validation request pending for `%s' at `%s'/`%s' (vs)/(q)\n",
14450 GNUNET_i2s (pid),
14451 (NULL == address_without_port_vs) ? "<unparsable>"
14452 : address_without_port_vs,
14453 (NULL == address_without_port_q) ? "<unparsable>"
14454 : address_without_port_q);
14455 (void) pid;
14456 /* Only the port may differ: the address we asked to connect to is
14457 `PROTO-IP:0' for a NATed peer, while the queue that then materializes
14458 sits at `PROTO-IP:port'. The communicator must match all the same --
14459 a challenge for a `tcp-' address is not answered by a `udp-' queue. */
14460 if ((GNUNET_YES == vs->awaiting_queue) &&
14461 (NULL != address_without_port_vs) &&
14462 (NULL != address_without_port_q) &&
14463 (NULL != prefix_vs) &&
14464 (NULL != prefix_q) &&
14465 (0 == strcmp (prefix_vs, prefix_q)) &&
14466 (0 == strcmp (address_without_port_vs, address_without_port_q)))
14467 {
14468
14469 vs->awaiting_queue = GNUNET_NO;
14471 success = GNUNET_NO;
14472 }
14473
14474 GNUNET_free (address_without_port_vs);
14475 GNUNET_free (address_without_port_q);
14476 GNUNET_free (prefix_vs);
14477 GNUNET_free (prefix_q);
14478 return success;
14479}

References get_address_without_port(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_HELLO_address_to_prefix(), GNUNET_i2s(), GNUNET_log, GNUNET_NO, GNUNET_YES, ValidationState::pid, q, validation_transmit_on_queue(), and value.

Referenced by handle_add_queue_message().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ neighbour_dv_monotime_cb()

static void neighbour_dv_monotime_cb ( void *  cls,
const struct GNUNET_PEERSTORE_Record record,
const char *  emsg 
)
static

Function called with the monotonic time of a DV initiator by PEERSTORE.

Updates the time.

Parameters
clsa struct Neighbour
recordthe information found, NULL for the last call
emsgerror message

Definition at line 14491 of file gnunet-service-transport.c.

14494{
14495 struct Neighbour *n = cls;
14496 struct GNUNET_TIME_AbsoluteNBO *mtbe;
14497
14498 (void) emsg;
14499 if (NULL == record)
14500 {
14501 /* we're done with #neighbour_dv_monotime_cb() invocations,
14502 continue normal processing */
14503 n->get = NULL;
14505 return;
14506 }
14507 if (0 == record->value_size)
14508 {
14510 GNUNET_break (0);
14511 return;
14512 }
14513 mtbe = record->value;
14518}

References Neighbour::dv_monotime_available, Neighbour::get, GNUNET_break, GNUNET_PEERSTORE_iteration_next(), GNUNET_TIME_absolute_max(), GNUNET_TIME_absolute_ntoh(), GNUNET_YES, Neighbour::last_dv_learn_monotime, and record().

Referenced by handle_add_queue_message().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ iterate_address_and_compare_cb()

static void iterate_address_and_compare_cb ( void *  cls,
const struct GNUNET_PeerIdentity pid,
const char *  uri 
)
static

Definition at line 14522 of file gnunet-service-transport.c.

14525{
14526 struct Queue *queue = cls;
14527 struct sockaddr_in v4;
14528 const char *slash;
14529 char *address_uri;
14530 char *prefix;
14531 char *uri_without_port;
14532 char *address_uri_without_port;
14533
14534 slash = strrchr (uri, '/');
14535 if ((NULL == slash) || (slash - uri < 2))
14536 {
14537 GNUNET_break_op (0); /* @a uri comes from a remote HELLO */
14538 return;
14539 }
14540 prefix = GNUNET_strndup (uri, (slash - uri) - 2);
14541 slash++;
14542 GNUNET_asprintf (&address_uri,
14543 "%s-%s",
14544 prefix,
14545 slash);
14546
14548 "1 not global natted_address %u %s %s %s\n",
14549 queue->is_global_natted,
14550 uri,
14551 queue->address,
14552 slash);
14553
14554 uri_without_port = get_address_without_port (address_uri);
14555 if ((NULL == uri_without_port) ||
14556 (1 != inet_pton (AF_INET, uri_without_port, &v4.sin_addr)))
14557 {
14559 GNUNET_free (address_uri);
14560 GNUNET_free (uri_without_port);
14561 return;
14562 }
14563
14565 "2 not global natted_address %u %s %s\n",
14566 queue->is_global_natted,
14567 uri,
14568 queue->address);
14569
14570 if (GNUNET_NO == queue->is_global_natted)
14571 {
14573 GNUNET_free (address_uri);
14574 GNUNET_free (uri_without_port);
14575 return;
14576 }
14577
14579 "3 not global natted_address %u %s %s\n",
14580 queue->is_global_natted,
14581 uri,
14582 queue->address);
14583
14584 if (0 == strcmp (uri_without_port, address_uri))
14585 {
14587 GNUNET_free (address_uri);
14588 GNUNET_free (uri_without_port);
14589 return;
14590 }
14591
14593 "4 not global natted_address %u %s %s\n",
14594 queue->is_global_natted,
14595 uri,
14596 queue->address);
14597
14598 address_uri_without_port = get_address_without_port (queue->address);
14599 if ((NULL != address_uri_without_port) &&
14600 (0 == strcmp (uri_without_port, address_uri_without_port)))
14601 {
14602 queue->is_global_natted = GNUNET_NO;
14603 }
14604
14606 "not global natted_address %u %s %s %s %s %s %u\n",
14607 queue->is_global_natted,
14608 uri,
14609 queue->address,
14610 uri_without_port,
14611 address_uri_without_port,
14612 prefix,
14613 GNUNET_NO);
14615 GNUNET_free (address_uri);
14616 GNUNET_free (address_uri_without_port);
14617 GNUNET_free (uri_without_port);
14618}

References get_address_without_port(), GNUNET_asprintf(), GNUNET_break_op, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_log, GNUNET_NO, GNUNET_strndup, prefix, queue(), and uri.

Referenced by check_for_global_natted().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ contains_address()

static enum GNUNET_GenericReturnValue contains_address ( void *  cls,
const struct GNUNET_PeerIdentity pid,
void *  value 
)
static

Definition at line 14636 of file gnunet-service-transport.c.

14639{
14640 struct TransportGlobalNattedAddressClosure *tgna_cls = cls;
14641 struct TransportGlobalNattedAddress *tgna = value;
14642 char *addr = (char *) &tgna[1];
14643
14644 /* NOTE: @a addr is NOT 0-terminated. */
14646 "Checking tgna %p with addr %.*s and length %u compare length %lu\n",
14647 tgna,
14648 (int) ntohl (tgna->address_length),
14649 addr,
14650 ntohl (tgna->address_length),
14651 strlen (tgna_cls->addr));
14652 if (strlen (tgna_cls->addr) == ntohl (tgna->address_length)
14653 && 0 == strncmp (addr, tgna_cls->addr, ntohl (tgna->address_length)))
14654 {
14655 tgna_cls->tgna = tgna;
14656 return GNUNET_NO;
14657 }
14658 return GNUNET_YES;
14659}

References TransportGlobalNattedAddressClosure::addr, TransportGlobalNattedAddress::address_length, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_NO, GNUNET_YES, TransportGlobalNattedAddressClosure::tgna, and value.

Referenced by check_for_global_natted().

Here is the caller graph for this function:

◆ check_for_global_natted_error_cb()

static void check_for_global_natted_error_cb ( void *  cls)
static

Definition at line 14663 of file gnunet-service-transport.c.

14664{
14666 "Error in PEERSTORE monitoring for checking global natted\n");
14667}

References GNUNET_ERROR_TYPE_WARNING, and GNUNET_log.

Referenced by handle_add_queue_message().

Here is the caller graph for this function:

◆ check_for_global_natted_sync_cb()

static void check_for_global_natted_sync_cb ( void *  cls)
static

Definition at line 14671 of file gnunet-service-transport.c.

14672{
14674 "Done with initial PEERSTORE iteration during monitoring for checking global natted\n");
14675}

References GNUNET_ERROR_TYPE_DEBUG, and GNUNET_log.

Referenced by handle_add_queue_message().

Here is the caller graph for this function:

◆ check_for_global_natted()

static void check_for_global_natted ( void *  cls,
const struct GNUNET_PEERSTORE_Record record,
const char *  emsg 
)
static

Definition at line 14679 of file gnunet-service-transport.c.

14682{
14683 struct Queue *queue = cls;
14684 struct Neighbour *neighbour = queue->neighbour;
14686 const struct GNUNET_MessageHeader *hello;
14688 size_t address_len_without_port;
14689
14690 if (NULL != emsg)
14691 {
14693 "Got failure from PEERSTORE: %s\n",
14694 emsg);
14696 return;
14697 }
14698 if (NULL == record)
14699 {
14700 GNUNET_break (0);
14702 return;
14703 }
14704 /* @a hello was published by a remote peer and may be malformed. */
14705 hello = hello_from_record (record);
14706 if (NULL == hello)
14707 {
14709 return;
14710 }
14711 queue->is_global_natted = GNUNET_YES;
14712 parser = GNUNET_HELLO_parser_from_msg (hello, &record->peer);
14713 if (NULL == parser)
14714 {
14716 "HELLO cannot be parsed!\n");
14718 return;
14719 }
14721 "before not global natted %u\n",
14722 queue->is_global_natted);
14725 queue);
14727 "after not global natted %u\n",
14728 queue->is_global_natted);
14729 GNUNET_HELLO_parser_free (parser);
14730
14731 tgna_cls.addr = get_address_without_port (queue->address);
14732 if (NULL == tgna_cls.addr)
14733 {
14734 GNUNET_break (0);
14736 return;
14737 }
14738 address_len_without_port = strlen (tgna_cls.addr);
14739 /*{
14740 char buf[address_len_without_port + 1];
14741
14742 GNUNET_memcpy (&buf, addr, address_len_without_port);
14743 buf[address_len_without_port] = '\0';
14744 GNUNET_free (addr);
14745 GNUNET_memcpy (tgna_cls.addr, buf, address_len_without_port + 1);
14746 }*/
14747 tgna_cls.tgna = NULL;
14749 &neighbour->pid,
14751 &tgna_cls);
14752 if (NULL != tgna_cls.tgna)
14754 " tgna_cls.tgna tgna %p %lu %u %u\n",
14755 tgna_cls.tgna,
14756 neighbour->size_of_global_addresses,
14757 ntohl (tgna_cls.tgna->address_length),
14758 neighbour->number_of_addresses);
14759 if (NULL == tgna_cls.tgna && GNUNET_YES == queue->is_global_natted)
14760 {
14761 struct TransportGlobalNattedAddress *tgna;
14762
14763 tgna = GNUNET_malloc (sizeof (struct TransportGlobalNattedAddress)
14764 + address_len_without_port);
14765 tgna->address_length = htonl (address_len_without_port);
14766 GNUNET_memcpy (&tgna[1], tgna_cls.addr, address_len_without_port);
14768 &neighbour->pid,
14769 tgna,
14771 neighbour->number_of_addresses++;
14772 /* MUST match what is subtracted on removal (and what
14773 #add_global_addresses() actually copies), or the accounting drifts. */
14774 neighbour->size_of_global_addresses += address_len_without_port;
14776 "Created tgna %p with address %s and length %lu\n",
14777 tgna,
14778 tgna_cls.addr,
14779 address_len_without_port + 1);
14780 }
14781 else if (NULL != tgna_cls.tgna && GNUNET_NO == queue->is_global_natted)
14782 {
14784 &neighbour->pid,
14785 tgna_cls.tgna);
14786 GNUNET_assert (neighbour->size_of_global_addresses >= ntohl (tgna_cls.tgna->
14788 );
14789 neighbour->size_of_global_addresses -= ntohl (tgna_cls.tgna->address_length)
14790 ;
14791 GNUNET_assert (0 < neighbour->number_of_addresses);
14792 neighbour->number_of_addresses--;
14794 "removed tgna %p\n",
14795 tgna_cls.tgna);
14796 GNUNET_free (tgna_cls.tgna);
14797 }
14799 GNUNET_free (tgna_cls.addr);
14800}

References TransportGlobalNattedAddressClosure::addr, TransportGlobalNattedAddress::address_length, contains_address(), get_address_without_port(), GNUNET_assert, GNUNET_break, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE, GNUNET_CONTAINER_multipeermap_get_multiple(), GNUNET_CONTAINER_multipeermap_put(), GNUNET_CONTAINER_multipeermap_remove(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_HELLO_parser_free(), GNUNET_HELLO_parser_from_msg(), GNUNET_HELLO_parser_iterate(), GNUNET_log, GNUNET_malloc, GNUNET_memcpy, GNUNET_NO, GNUNET_PEERSTORE_monitor_next(), GNUNET_YES, hello_from_record(), iterate_address_and_compare_cb(), Neighbour::natted_addresses, Neighbour::number_of_addresses, Neighbour::pid, queue(), record(), Neighbour::size_of_global_addresses, and TransportGlobalNattedAddressClosure::tgna.

Referenced by handle_add_queue_message().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_add_queue_message()

static void handle_add_queue_message ( void *  cls,
const struct GNUNET_TRANSPORT_AddQueueMessage aqm 
)
static

New queue became available.

Process the request.

Parameters
clsthe client
aqmthe send message that was sent

Definition at line 14810 of file gnunet-service-transport.c.

14812{
14813 struct TransportClient *tc = cls;
14814 struct Queue *queue;
14815 struct Neighbour *neighbour;
14816 const char *addr;
14817 uint16_t addr_len;
14818
14819 if (ntohl (aqm->mtu) <= sizeof(struct TransportFragmentBoxMessage))
14820 {
14821 /* MTU so small as to be useless for transmissions,
14822 required for #fragment_message()! */
14823 GNUNET_break_op (0);
14825 return;
14826 }
14827 /* This may simply be a queue update. Match on the peer as well as the
14828 QID: the communicator's key for a queue is the pair, and
14829 #handle_send_msg() on its side looks both of them up. Matching on the
14830 QID alone let an ADD_QUEUE for a *different* peer be folded into an
14831 existing queue, leaving @e neighbour pointing at the old peer -- after
14832 which every SEND_MSG we put on it carries a receiver the communicator
14833 cannot match, and comes straight back as "queue no longer exists". */
14834 for (queue = tc->details.communicator.queue_head;
14835 NULL != queue;
14836 queue = queue->next_client)
14837 {
14838 if (queue->qid != ntohl (aqm->qid))
14839 continue;
14840 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &aqm->receiver))
14841 continue;
14842 break;
14843 }
14844
14845 if (NULL != queue)
14846 {
14847 neighbour = queue->neighbour;
14848 }
14849 else
14850 {
14851 struct GNUNET_TIME_Absolute validated_until = GNUNET_TIME_UNIT_ZERO_ABS;
14852
14853 neighbour = lookup_neighbour (&aqm->receiver);
14854 if (NULL == neighbour)
14855 {
14856 neighbour = GNUNET_new (struct Neighbour);
14858 GNUNET_YES);
14859 neighbour->pid = aqm->receiver;
14860 /* Give a fresh neighbour a full window to say something. */
14861 neighbour->last_inbound = GNUNET_TIME_absolute_get ();
14864 neighbours,
14865 &neighbour->pid,
14866 neighbour,
14868 neighbour->get =
14870 "transport",
14871 &neighbour->pid,
14874 neighbour);
14875 }
14876 addr_len = ntohs (aqm->header.size) - sizeof(*aqm);
14877 addr = (const char *) &aqm[1];
14879 "New queue %s to %s available with QID %u and q_len %" PRIu64
14880 " and mtu %u\n",
14881 addr,
14882 GNUNET_i2s (&aqm->receiver),
14883 ntohl (aqm->qid),
14884 GNUNET_ntohll (aqm->q_len),
14885 ntohl (aqm->mtu));
14886 queue = GNUNET_malloc (sizeof(struct Queue) + addr_len);
14887 queue->tc = tc;
14888 for (struct Queue *q = neighbour->queue_head; NULL != q; q = q->
14889 next_neighbour)
14890 validated_until = GNUNET_TIME_absolute_max (validated_until, q->
14891 validated_until);
14892 /* Inherit the validity of the sibling queues, but only while it is
14893 still in the future -- copying an already expired timestamp is
14894 pointless (and the condition used to be inverted). */
14895 if (0 != GNUNET_TIME_absolute_get_remaining (validated_until).rel_value_us)
14896 {
14898 "New queue with QID %u inherit validated until\n",
14899 ntohl (aqm->qid));
14900 queue->validated_until = validated_until;
14901 }
14902 queue->address = (const char *) &queue[1];
14903 queue->pd.aged_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
14904 queue->qid = ntohl (aqm->qid);
14905 queue->neighbour = neighbour;
14907 queue->unlimited_length = GNUNET_YES;
14908 queue->q_capacity = GNUNET_ntohll (aqm->q_len);
14909 memcpy (&queue[1], addr, addr_len);
14910 /* notify monitors about new queue */
14911 {
14912 struct MonitorEvent me = { .rtt = queue->pd.aged_rtt, .cs = queue->cs };
14913
14914 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
14915 }
14917 neighbour->queue_head,
14918 neighbour->queue_tail,
14919 queue);
14921 tc->details.communicator.queue_head,
14922 tc->details.communicator.queue_tail,
14923 queue);
14924
14925 }
14926 queue->mtu = ntohl (aqm->mtu);
14927 queue->nt = ntohl (aqm->nt);
14928 queue->cs = ntohl (aqm->cs);
14929 queue->idle = GNUNET_YES;
14930
14931 if (NULL == queue->mo)
14932 {
14933 /* Only for a NEW queue: on a queue update this used to start a second
14934 monitor and leak the first one. */
14935 struct sockaddr_in v4;
14936 char *addr_without = get_address_without_port (queue->address);
14937 if ((NULL != addr_without) &&
14938 (1 == inet_pton (AF_INET, addr_without, &v4.sin_addr)))
14939 {
14941 "start not global natted\n");
14943 GNUNET_YES,
14944 "peerstore",
14945 &neighbour->pid,
14947 &
14949 NULL,
14950 &
14952 NULL,
14954 queue);
14955 }
14956 GNUNET_free (addr_without);
14957 }
14958 /* check if valdiations are waiting for the queue */
14960 &aqm->receiver))
14963 &aqm->receiver,
14965 queue);
14966 /* Always (also) validate the address of the queue itself. A pending
14967 validation served above may well be for a *different* address string:
14968 #check_validation_request_pending() matches on the IP only, so a
14969 validation state waiting for the NAT address `PROTO-IP:0' is happily
14970 satisfied by a queue at `PROTO-IP:12345'. If we stopped here,
14971 #handle_validation_response() would later look for a queue at
14972 `PROTO-IP:0' -- which never exists -- and drop the successful
14973 validation on the floor without ever creating the virtual link. That
14974 is exactly what happens to the second of two peers behind the same
14975 NAT, as both of them advertise the very same `PROTO-IP:0'. */
14976 start_address_validation (&aqm->receiver, queue->address);
14977 /* look for traffic for this queue */
14978 // TODO Check whether this makes any sense at all.
14979 /*schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
14980 queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);*/
14981 /* might be our first queue, try launching DV learning */
14982 if (NULL == dvlearn_task)
14985}

References check_for_global_natted(), check_for_global_natted_error_cb(), check_for_global_natted_sync_cb(), check_validation_request_pending(), GNUNET_TRANSPORT_AddQueueMessage::cs, dvlearn_task, Neighbour::get, get_address_without_port(), GNUNET_assert, GNUNET_break_op, GNUNET_CONTAINER_MDLL_insert, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY, GNUNET_CONTAINER_multipeermap_contains(), GNUNET_CONTAINER_multipeermap_create(), GNUNET_CONTAINER_multipeermap_get_multiple(), GNUNET_CONTAINER_multipeermap_put(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_i2s(), GNUNET_log, GNUNET_malloc, GNUNET_memcmp, GNUNET_new, GNUNET_ntohll(), GNUNET_OK, GNUNET_PEERSTORE_HELLO_KEY, GNUNET_PEERSTORE_iteration_start(), GNUNET_PEERSTORE_monitor_start(), GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME, GNUNET_SCHEDULER_add_now(), GNUNET_SERVICE_client_continue(), GNUNET_SERVICE_client_drop(), GNUNET_TIME_absolute_get(), GNUNET_TIME_absolute_get_remaining(), GNUNET_TIME_absolute_max(), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_TIME_UNIT_ZERO_ABS, GNUNET_TRANSPORT_QUEUE_LENGTH_UNLIMITED, GNUNET_YES, GST_cfg, GNUNET_TRANSPORT_AddQueueMessage::header, Neighbour::last_inbound, lookup_neighbour(), me, GNUNET_TRANSPORT_AddQueueMessage::mtu, Neighbour::natted_addresses, neighbour_dv_monotime_cb(), neighbours, notify_monitors(), GNUNET_TRANSPORT_AddQueueMessage::nt, peerstore, Neighbour::pid, q, GNUNET_TRANSPORT_AddQueueMessage::q_len, GNUNET_TRANSPORT_AddQueueMessage::qid, queue(), Neighbour::queue_head, Neighbour::queue_tail, GNUNET_TRANSPORT_AddQueueMessage::receiver, GNUNET_TIME_Relative::rel_value_us, GNUNET_MessageHeader::size, start_address_validation(), start_dv_learn(), tc, and validation_map.

Here is the call graph for this function:

◆ handle_update_queue_message()

static void handle_update_queue_message ( void *  cls,
const struct GNUNET_TRANSPORT_UpdateQueueMessage msg 
)
static

Handle updates to queues.

Parameters
clsthe transport client.
msgMessage struct.

Definition at line 14995 of file gnunet-service-transport.c.

14998{
14999 struct TransportClient *tc = cls;
15000 struct Queue *target_queue = NULL;
15001
15002 if (CT_COMMUNICATOR != tc->type)
15003 {
15004 /* Without this we walk `details.communicator.queue_head' for a client
15005 whose union holds something else entirely. */
15006 GNUNET_break (0);
15008 return;
15009 }
15011 "Received queue update message for %u with q_len %llu and mtu %u\n",
15012 ntohl (msg->qid),
15013 (unsigned long long) GNUNET_ntohll (msg->q_len),
15014 ntohl (msg->mtu));
15015 for (target_queue = tc->details.communicator.queue_head;
15016 NULL != target_queue;
15017 target_queue = target_queue->next_client)
15018 {
15019 if (ntohl (msg->qid) == target_queue->qid)
15020 break;
15021 }
15022 if (NULL == target_queue)
15023 {
15025 "Queue to update no longer exists! Discarding update.\n");
15027 return;
15028 }
15029
15030 target_queue->nt = ntohl (msg->nt);
15031 target_queue->mtu = ntohl (msg->mtu);
15032 target_queue->cs = ntohl (msg->cs);
15033 target_queue->priority = ntohl (msg->priority);
15034 /* The update message indicates how many messages
15035 * the queue should be able to handle.
15036 */
15038 target_queue->unlimited_length = GNUNET_YES;
15039 else
15040 target_queue->unlimited_length = GNUNET_NO;
15041 target_queue->q_capacity += GNUNET_ntohll (msg->q_len);
15042 if (0 < target_queue->q_capacity)
15044 target_queue,
15047}

References Queue::cs, CT_COMMUNICATOR, GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_WARNING, GNUNET_log, GNUNET_NO, GNUNET_ntohll(), GNUNET_SCHEDULER_PRIORITY_DEFAULT, GNUNET_SERVICE_client_continue(), GNUNET_SERVICE_client_drop(), GNUNET_TIME_UNIT_ZERO, GNUNET_TRANSPORT_QUEUE_LENGTH_UNLIMITED, GNUNET_YES, msg, Queue::mtu, Queue::next_client, Queue::nt, Queue::priority, Queue::q_capacity, Queue::qid, schedule_transmit_on_queue(), tc, and Queue::unlimited_length.

Here is the call graph for this function:

◆ handle_queue_create_ok()

static void handle_queue_create_ok ( void *  cls,
const struct GNUNET_TRANSPORT_CreateQueueResponse cqr 
)
static

Communicator tells us that our request to create a queue "worked", that is setting up the queue is now in process.

Parameters
clsthe struct TransportClient
cqrconfirmation message

Definition at line 15058 of file gnunet-service-transport.c.

15060{
15061 struct TransportClient *tc = cls;
15062
15063 if (CT_COMMUNICATOR != tc->type)
15064 {
15065 GNUNET_break (0);
15067 return;
15068 }
15070 "# Suggestions succeeded at communicator",
15071 1,
15072 GNUNET_NO);
15074 "Request #%u for communicator to create queue succeeded\n",
15075 (unsigned int) ntohs (cqr->request_id));
15077}

References CT_COMMUNICATOR, GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_NO, GNUNET_SERVICE_client_continue(), GNUNET_SERVICE_client_drop(), GNUNET_STATISTICS_update(), GST_stats, GNUNET_TRANSPORT_CreateQueueResponse::request_id, and tc.

Here is the call graph for this function:

◆ handle_queue_create_fail()

static void handle_queue_create_fail ( void *  cls,
const struct GNUNET_TRANSPORT_CreateQueueResponse cqr 
)
static

Communicator tells us that our request to create a queue failed.

This usually indicates that the provided address is simply invalid or that the communicator's resources are exhausted.

Parameters
clsthe struct TransportClient
cqrfailure message

Definition at line 15089 of file gnunet-service-transport.c.

15092{
15093 struct TransportClient *tc = cls;
15094
15095 if (CT_COMMUNICATOR != tc->type)
15096 {
15097 GNUNET_break (0);
15099 return;
15100 }
15102 "Request #%u for communicator to create queue failed\n",
15103 (unsigned int) ntohl (cqr->request_id));
15105 "# Suggestions failed in queue creation at communicator",
15106 1,
15107 GNUNET_NO);
15109}

References CT_COMMUNICATOR, GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_NO, GNUNET_SERVICE_client_continue(), GNUNET_SERVICE_client_drop(), GNUNET_STATISTICS_update(), GST_stats, GNUNET_TRANSPORT_CreateQueueResponse::request_id, and tc.

Here is the call graph for this function:

◆ handle_suggest_cancel()

static void handle_suggest_cancel ( void *  cls,
const struct ExpressPreferenceMessage msg 
)
static

An application client no longer wants us to connect to a peer it asked for earlier.

Parameters
clshandle to the client
msgthe request to cancel

Definition at line 15120 of file gnunet-service-transport.c.

15121{
15122 struct TransportClient *tc = cls;
15123 struct PeerRequest *pr;
15124
15125 if (CT_APPLICATION != tc->type)
15126 {
15127 GNUNET_break (0);
15129 return;
15130 }
15131 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
15132 &msg->peer);
15133 if (NULL == pr)
15134 {
15135 GNUNET_break (0);
15137 return;
15138 }
15139 (void) stop_peer_request (tc, &pr->pid, pr);
15141}

References CT_APPLICATION, GNUNET_break, GNUNET_CONTAINER_multipeermap_get(), GNUNET_SERVICE_client_continue(), GNUNET_SERVICE_client_drop(), msg, PeerRequest::pr, stop_peer_request(), and tc.

Here is the call graph for this function:

◆ hello_for_client_cb()

static void hello_for_client_cb ( void *  cls,
const struct GNUNET_PeerIdentity pid,
const char *  uri 
)
static

Definition at line 15145 of file gnunet-service-transport.c.

15148{
15149 struct Queue *q;
15150 int pfx_len;
15151 const char *eou;
15152 char *address;
15153 (void) cls;
15154
15155 eou = strstr (uri,
15156 "://");
15157 if ((NULL == eou) || (eou == uri))
15158 {
15159 /* @a uri comes from a HELLO some remote peer published. */
15160 GNUNET_break_op (0);
15161 return;
15162 }
15163 pfx_len = eou - uri;
15164 eou += 3;
15166 "%.*s-%s",
15167 pfx_len,
15168 uri,
15169 eou);
15170
15172 "hello for client %s\n",
15173 address);
15174
15175 q = find_queue (pid, address);
15176 if (NULL == q)
15177 {
15179 }
15180 else
15183}

References address, find_queue(), GNUNET_asprintf(), GNUNET_break_op, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_log, q, start_address_validation(), suggest_to_connect(), and uri.

Referenced by handle_hello_for_client().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_hello_for_client()

static void handle_hello_for_client ( void *  cls,
const struct GNUNET_PEERSTORE_Record record,
const char *  emsg 
)
static

Function called by PEERSTORE for each matching record.

Parameters
clsclosure, a struct PeerRequest
recordpeerstore record information
emsgerror message, or NULL if no errors

Definition at line 15194 of file gnunet-service-transport.c.

15197{
15198 const struct GNUNET_PeerIdentity *my_identity;
15199 struct PeerRequest *pr = cls;
15201 const struct GNUNET_MessageHeader *hello;
15202
15203 if (NULL != emsg)
15204 {
15206 "Got failure from PEERSTORE: %s\n",
15207 emsg);
15209 return;
15210 }
15211 if (NULL == record)
15212 {
15213 GNUNET_break (0);
15215 return;
15216 }
15218 if (NULL == my_identity)
15219 {
15221 "No identity given yet!\n");
15223 return;
15224 }
15225 hello = hello_from_record (record);
15226 if (NULL == hello)
15227 {
15228 /* MUST still ask for the next record: a bad one is not a reason to
15229 stall this monitor forever. */
15231 return;
15232 }
15233 if (0 == GNUNET_memcmp (&record->peer, my_identity))
15234 {
15236 return;
15237 }
15238 parser = GNUNET_HELLO_parser_from_msg (hello, &record->peer);
15239 if (NULL == parser)
15240 {
15242 "HELLO cannot be parsed!\n");
15244 return;
15245 }
15247 "HELLO for `%s' could be parsed, iterating addresses...!\n",
15251 NULL);
15252 GNUNET_HELLO_parser_free (parser);
15253 /* MUST ask for the next record, or this monitor stalls after one HELLO */
15255}

References GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_WARNING, GNUNET_HELLO_parser_free(), GNUNET_HELLO_parser_from_msg(), GNUNET_HELLO_parser_get_id(), GNUNET_HELLO_parser_iterate(), GNUNET_i2s(), GNUNET_log, GNUNET_memcmp, GNUNET_PEERSTORE_monitor_next(), GNUNET_PILS_get_identity(), hello_for_client_cb(), hello_from_record(), my_identity, PeerRequest::nc, pils, PeerRequest::pr, and record().

Referenced by start_peer_request_monitor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hello_for_client_error_cb()

static void hello_for_client_error_cb ( void *  cls)
static

Definition at line 15259 of file gnunet-service-transport.c.

15260{
15262 "Error in PEERSTORE monitoring\n");
15263}

References GNUNET_ERROR_TYPE_WARNING, and GNUNET_log.

Referenced by start_peer_request_monitor().

Here is the caller graph for this function:

◆ hello_for_client_sync_cb()

static void hello_for_client_sync_cb ( void *  cls)
static

Definition at line 15267 of file gnunet-service-transport.c.

15268{
15270 "Done with initial PEERSTORE iteration during monitoring\n");
15271}

References GNUNET_ERROR_TYPE_DEBUG, and GNUNET_log.

Referenced by start_peer_request_monitor().

Here is the caller graph for this function:

◆ start_peer_request_monitor()

static void start_peer_request_monitor ( struct PeerRequest pr)
static

(Re)start the PEERSTORE HELLO monitor of pr.

Starting the monitor with iterate_first also replays what PEERSTORE already knows about pid, which is what makes this useful as a retry: after the initial replay the monitor only reports changes, and a peer whose HELLO does not change is one we would otherwise never look at again.

Parameters
prrequest to (re)start the monitor for

Definition at line 15286 of file gnunet-service-transport.c.

15287{
15288 if (NULL != pr->nc)
15290 /* Monitor only @e pid. With NULL every application request sees every
15291 HELLO in PEERSTORE, so a client asking for one peer made us suggest a
15292 connection to -- and start an address validation for -- every peer we
15293 have ever heard of, once per request. #try_to_bring_link_up() had the
15294 same bug and was already fixed the same way. */
15295 pr->nc =
15297 GNUNET_YES,
15298 "peerstore",
15299 &pr->pid,
15302 NULL,
15304 NULL,
15306 pr);
15307}

References GNUNET_PEERSTORE_HELLO_KEY, GNUNET_PEERSTORE_monitor_start(), GNUNET_PEERSTORE_monitor_stop(), GNUNET_YES, GST_cfg, handle_hello_for_client(), hello_for_client_error_cb(), hello_for_client_sync_cb(), PeerRequest::nc, and PeerRequest::pid.

Referenced by handle_suggest(), and suggest_retry_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ suggest_retry_cb()

static void suggest_retry_cb ( void *  cls)
static

Task run for as long as an application client wants a link to pid that we do not have.

Nothing else retries: the validation heap backs off to MAX_VALIDATION_CHALLENGE_FREQ (a day) and drops the validation state entirely once it expires, and the HELLO monitor only fires when the HELLO actually changes – which, for a peer we cannot reach, it does not.

Parameters
clsthe struct PeerRequest

Definition at line 15320 of file gnunet-service-transport.c.

15321{
15322 struct PeerRequest *pr = cls;
15323 struct VirtualLink *vl;
15324
15325 pr->retry_task = NULL;
15326 vl = lookup_virtual_link (&pr->pid);
15327 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
15328 {
15329 /* The client has what it asked for. Keep watching cheaply, and start
15330 over from the short interval when the link goes away again. */
15334 pr);
15335 return;
15336 }
15338 "Retrying to connect to %s, an application client wants it\n",
15339 GNUNET_i2s (&pr->pid));
15341 "# link setup retries for application clients",
15342 1,
15343 GNUNET_NO);
15344 /* Addresses we already track, queues we still have, and a fresh look in
15345 PEERSTORE. */
15347 /* ... plus a replay of what PEERSTORE has for this peer, which is the
15348 only way back once the validation state expired and the queues are
15349 gone. */
15355 pr);
15356}

References VirtualLink::confirmed, GNUNET_ERROR_TYPE_DEBUG, GNUNET_i2s(), GNUNET_log, GNUNET_NO, GNUNET_SCHEDULER_add_delayed(), GNUNET_STATISTICS_update(), GNUNET_TIME_randomized_backoff(), GNUNET_YES, GST_stats, lookup_virtual_link(), PeerRequest::pid, PeerRequest::pr, PeerRequest::retry_backoff, PeerRequest::retry_task, start_peer_request_monitor(), suggest_retry_cb(), SUGGEST_RETRY_MAX, SUGGEST_RETRY_MIN, and try_to_bring_link_up().

Referenced by handle_suggest(), and suggest_retry_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_suggest()

static void handle_suggest ( void *  cls,
const struct ExpressPreferenceMessage msg 
)
static

We have received a struct ExpressPreferenceMessage from an application client.

Parameters
clshandle to the client
msgthe start message

Definition at line 15367 of file gnunet-service-transport.c.

15368{
15369 struct TransportClient *tc = cls;
15370 const struct GNUNET_PeerIdentity *my_identity;
15371 struct PeerRequest *pr;
15372
15373 if (CT_NONE == tc->type)
15374 {
15375 tc->type = CT_APPLICATION;
15376 tc->details.application.requests =
15378 }
15379 if (CT_APPLICATION != tc->type)
15380 {
15381 GNUNET_break (0);
15383 return;
15384 }
15386 if (NULL == my_identity)
15387 {
15389 "Still waiting for own identity!\n");
15391 return;
15392 }
15394 "Client suggested we talk to %s with preference %d at rate %u\n",
15395 GNUNET_i2s (&msg->peer),
15396 (int) ntohl (msg->pk),
15397 (int) ntohl (msg->bw.value__));
15398 if (0 == GNUNET_memcmp (my_identity, &msg->peer))
15399 {
15401 "Client suggested connection to ourselves, ignoring...\n");
15403 return;
15404 }
15405 pr = GNUNET_new (struct PeerRequest);
15406 pr->tc = tc;
15407 pr->pid = msg->peer;
15408 pr->bw = msg->bw;
15409 pr->pk = ntohl (msg->pk);
15411 tc->details.application.requests,
15412 &pr->pid,
15413 pr,
15415 {
15416 GNUNET_break (0);
15417 GNUNET_free (pr);
15419 return;
15420 }
15422 /* The monitor alone only ever fires again if the HELLO *changes*. Keep
15423 asking for the link ourselves for as long as the client wants it. */
15424 pr->retry_backoff = SUGGEST_RETRY_MIN;
15425 pr->retry_task = GNUNET_SCHEDULER_add_delayed (pr->retry_backoff,
15427 pr);
15429}

References CT_APPLICATION, CT_NONE, GNUNET_break, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY, GNUNET_CONTAINER_multipeermap_create(), GNUNET_CONTAINER_multipeermap_put(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_i2s(), GNUNET_log, GNUNET_memcmp, GNUNET_new, GNUNET_PILS_get_identity(), GNUNET_SCHEDULER_add_delayed(), GNUNET_SERVICE_client_continue(), GNUNET_SERVICE_client_drop(), GNUNET_YES, msg, my_identity, pils, PeerRequest::pr, start_peer_request_monitor(), suggest_retry_cb(), SUGGEST_RETRY_MIN, and tc.

Here is the call graph for this function:

◆ check_request_hello_validation()

static int check_request_hello_validation ( void *  cls,
const struct RequestHelloValidationMessage m 
)
static

Check GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION messages.

Parameters
clsa struct TransportClient *
mmessage to verify
Returns
GNUNET_OK on success

Definition at line 15441 of file gnunet-service-transport.c.

15443{
15444 (void) cls;
15446 return GNUNET_OK;
15447}

References GNUNET_MQ_check_zero_termination, GNUNET_OK, and m.

◆ handle_request_hello_validation()

static void handle_request_hello_validation ( void *  cls,
const struct RequestHelloValidationMessage m 
)
static

A client encountered an address of another peer.

Consider validating it, and if validation succeeds, persist it to PEERSTORE.

Parameters
clsa struct TransportClient *
mmessage to verify

Definition at line 15458 of file gnunet-service-transport.c.

15460{
15461 struct TransportClient *tc = cls;
15462 struct Queue *q;
15463
15464 q = find_queue (&m->peer, (const char *) &m[1]);
15465 if (NULL == q)
15466 {
15467 suggest_to_connect (&m->peer, (const char *) &m[1]);
15468 }
15469 else
15470 start_address_validation (&m->peer, (const char *) &m[1]);
15472}

References find_queue(), GNUNET_SERVICE_client_continue(), m, q, start_address_validation(), suggest_to_connect(), and tc.

Here is the call graph for this function:

◆ free_neighbour_cb()

static int free_neighbour_cb ( void *  cls,
const struct GNUNET_PeerIdentity pid,
void *  value 
)
static

Free neighbour entry.

Parameters
clsNULL
pidunused
valuea struct Neighbour
Returns
GNUNET_OK (always)

Definition at line 15484 of file gnunet-service-transport.c.

15487{
15488 struct Neighbour *neighbour = value;
15489
15490 (void) cls;
15491 (void) pid;
15492 GNUNET_break (0); // should this ever happen?
15493 free_neighbour (neighbour, GNUNET_YES);
15494
15495 return GNUNET_OK;
15496}

References free_neighbour(), GNUNET_break, GNUNET_OK, GNUNET_YES, Neighbour::pid, and value.

Referenced by do_shutdown().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ free_virtual_link_cb()

static int free_virtual_link_cb ( void *  cls,
const struct GNUNET_PeerIdentity pid,
void *  value 
)
static

Free virtual link entry.

A link with neither a ‘struct Neighbour’ nor a ‘struct DistanceVector’ – one we created from an inbound FLOW_CONTROL message and that never got confirmed – is owned by nothing but its unconfirmed_timeout_task, so unlike neighbours it routinely survives to here. Not a bug, no GNUNET_break().

Parameters
clsNULL
pidunused
valuea ‘struct VirtualLink
Returns
GNUNET_OK (always)

Definition at line 15514 of file gnunet-service-transport.c.

15517{
15518 struct VirtualLink *vl = value;
15519
15520 (void) cls;
15521 (void) pid;
15522 free_virtual_link (vl);
15523
15524 return GNUNET_OK;
15525}

References free_virtual_link(), GNUNET_OK, and value.

Referenced by do_shutdown().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ free_dv_routes_cb()

static int free_dv_routes_cb ( void *  cls,
const struct GNUNET_PeerIdentity pid,
void *  value 
)
static

Free DV route entry.

Parameters
clsNULL
pidunused
valuea struct DistanceVector
Returns
GNUNET_OK (always)

Definition at line 15537 of file gnunet-service-transport.c.

15540{
15541 struct DistanceVector *dv = value;
15542
15543 (void) cls;
15544 (void) pid;
15545 free_dv_route (dv);
15546
15547 return GNUNET_OK;
15548}

References free_dv_route(), GNUNET_OK, and value.

Referenced by do_shutdown().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ free_validation_state_cb()

static int free_validation_state_cb ( void *  cls,
const struct GNUNET_PeerIdentity pid,
void *  value 
)
static

Free validation state.

Parameters
clsNULL
pidunused
valuea struct ValidationState
Returns
GNUNET_OK (always)

Definition at line 15560 of file gnunet-service-transport.c.

15563{
15564 struct ValidationState *vs = value;
15565
15566 (void) cls;
15567 (void) pid;
15569 return GNUNET_OK;
15570}

References free_validation_state(), GNUNET_OK, ValidationState::pid, and value.

Referenced by do_shutdown().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ free_pending_ack_cb()

static int free_pending_ack_cb ( void *  cls,
const struct GNUNET_Uuid key,
void *  value 
)
static

Free pending acknowledgement.

Parameters
clsNULL
keyunused
valuea struct PendingAcknowledgement
Returns
GNUNET_OK (always)

Definition at line 15582 of file gnunet-service-transport.c.

15583{
15584 struct PendingAcknowledgement *pa = value;
15585
15586 (void) cls;
15587 (void) key;
15589 return GNUNET_OK;
15590}

References free_pending_acknowledgement(), GNUNET_OK, key, and value.

Referenced by do_shutdown().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ free_ack_cummulator_cb()

static int free_ack_cummulator_cb ( void *  cls,
const struct GNUNET_PeerIdentity pid,
void *  value 
)
static

Free acknowledgement cummulator.

Parameters
clsNULL
pidunused
valuea struct AcknowledgementCummulator
Returns
GNUNET_OK (always)

Definition at line 15602 of file gnunet-service-transport.c.

15605{
15606 struct AcknowledgementCummulator *ac = value;
15607
15608 (void) cls;
15609 (void) pid;
15610 /* @e task is armed for the whole life of @a ac -- but
15611 #transmit_cummulative_ack_cb() clears it before re-arming, and it
15612 routes a message while it is clear. #GNUNET_SCHEDULER_cancel()
15613 dereferences its argument unconditionally. */
15614 if (NULL != ac->task)
15615 {
15617 ac->task = NULL;
15618 }
15619 GNUNET_free (ac);
15620 return GNUNET_OK;
15621}

References GNUNET_free, GNUNET_OK, GNUNET_SCHEDULER_cancel(), AcknowledgementCummulator::task, and value.

Referenced by do_shutdown().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_client_type_name()

static const char * get_client_type_name ( enum ClientType  type)
static

Definition at line 15772 of file gnunet-service-transport.c.

15773{
15774 switch (type)
15775 {
15776 case CT_CORE:
15777 return "CORE";
15778 case CT_MONITOR:
15779 return "MONITOR";
15780 case CT_COMMUNICATOR:
15781 return "COMMUNICATOR";
15782 case CT_APPLICATION:
15783 return "APPLICATION";
15784 default:
15785 return "UNKNOWN";
15786 }
15787}

References CT_APPLICATION, CT_COMMUNICATOR, CT_CORE, CT_MONITOR, and type.

Referenced by drop_remaining_clients(), and shutdown_task().

Here is the caller graph for this function:

◆ drop_remaining_clients()

static void drop_remaining_clients ( void *  cls)
static

The grace period we gave our clients to disconnect on their own expired.

Drop whoever is left, which gets us to do_shutdown() via client_disconnect_cb().

Parameters
clsclosure, unused

Definition at line 15798 of file gnunet-service-transport.c.

15799{
15800 client_grace_task = NULL;
15801 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
15802 {
15804 "Client did not disconnect within the shutdown grace period, "
15805 "dropping it: %s\n",
15806 get_client_type_name (tc->type));
15807 }
15808 /* We use #GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN, so the service will NOT
15809 drop clients for us. Without this we would wait forever for them to
15810 leave on their own and never reach #do_shutdown(). */
15812 /* Dropping the clients ran #client_disconnect_cb() for each of them, so
15813 #do_shutdown() has normally run by now; it is idempotent, and this
15814 covers the case where there was nothing left to drop. */
15815 do_shutdown (cls);
15816}

References client_grace_task, clients_head, do_shutdown, get_client_type_name(), GNUNET_ERROR_TYPE_WARNING, GNUNET_log, GNUNET_SERVICE_shutdown(), GST_service, and tc.

Referenced by shutdown_task().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ shutdown_task()

static void shutdown_task ( void *  cls)
static

Definition at line 15820 of file gnunet-service-transport.c.

15821{
15823
15825 "Shutdown task executed\n");
15826 if (NULL != clients_head)
15827 {
15828 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
15829 {
15831 "Waiting for client to disconnect: %s\n",
15832 get_client_type_name (tc->type));
15833 }
15834 /* Give them a chance to shut down cleanly; #client_disconnect_cb() calls
15835 #do_shutdown() once the last one is gone, and #do_shutdown() cancels
15836 this task. */
15840 cls);
15841 return;
15842 }
15843 do_shutdown (cls);
15844}

References client_grace_task, clients_head, do_shutdown, drop_remaining_clients(), get_client_type_name(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_INFO, GNUNET_log, GNUNET_SCHEDULER_add_delayed(), GNUNET_YES, in_shutdown, SHUTDOWN_CLIENT_GRACE_PERIOD, and tc.

Here is the call graph for this function:

◆ update_hello_from_pid_change_cb()

static void update_hello_from_pid_change_cb ( void *  cls,
int  success 
)
static

Definition at line 15853 of file gnunet-service-transport.c.

15854{
15855 struct UpdateHelloFromPidCtx *pc = cls;
15856
15857 /* NOTE: @a success is GNUNET_OK even when #hello_add_iter() decided not to
15858 store anything because PEERSTORE already holds a HELLO that expires
15859 later; the API reports the desired state, not whether it wrote. So this
15860 says "we have a current HELLO on record", not "we just wrote one". */
15861 if (GNUNET_OK != success)
15863 "Failed to store our new hello with peerstore\n");
15864 else
15866 "Our hello is current in peerstore\n");
15867 GNUNET_free (pc);
15868}

References GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_log, GNUNET_OK, and pc.

Referenced by pils_pid_change_cb().

Here is the caller graph for this function:

◆ print_address_list()

void print_address_list ( void *  cls,
const struct GNUNET_PeerIdentity pid,
const char *  uri 
)

Definition at line 15872 of file gnunet-service-transport.c.

15875{
15877 "%s\n", uri);
15878}

References GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, and uri.

Referenced by pils_pid_change_cb().

Here is the caller graph for this function:

◆ pils_pid_change_cb()

static void pils_pid_change_cb ( void *  cls,
const struct GNUNET_HELLO_Parser parser,
const struct GNUNET_HashCode hash 
)
static

Callback called when pils service updates us with our new peer identity.

Parameters
clsclosure given to GNUNET_PILS_connect
parserthe new HELLO from which the PID can be extracted
hashThe hash of addresses the peer id is based on. This hash is also returned by #GNUNET_PILS_feed_address.

FIXME we may want to have a sanity check here that verifies that our address list in the builder is the same as the one in the parser (and hence derived from the correct set). If it is NOT, then it is very likely that PILS is behind and will send another update shortly. In this case, we may want to hold off and not generate the new HELLO.

Definition at line 15891 of file gnunet-service-transport.c.

15894{
15895 const struct GNUNET_PeerIdentity *my_identity;
15896 struct GNUNET_MQ_Envelope *env;
15897 const struct GNUNET_MessageHeader *msg;
15898 struct UpdateHelloFromPidCtx *sc;
15899 struct GNUNET_HELLO_Builder *nbuilder;
15900 struct GNUNET_PeerIdentity npid;
15901
15904
15905 if (NULL == GST_my_hello)
15908 "My current identity is `%s'\n",
15920 nbuilder = GNUNET_HELLO_builder_from_parser (parser,
15921 &npid);
15922 if (GNUNET_NO ==
15924 {
15926 "New PID from PILS is derived from address list inconsistent with ours. Ignoring...\n");
15928 "Proposed address list:\n");
15931 "Current address list:\n");
15933 GNUNET_HELLO_builder_free (nbuilder);
15934 return;
15935 }
15937 GST_my_hello = nbuilder;
15939 "My new identity is `%s'\n",
15945 msg,
15947 sc);
15948 GNUNET_free (env);
15949}

References env, GNUNET_assert, GNUNET_ERROR_TYPE_INFO, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_HELLO_builder_address_list_cmp(), GNUNET_HELLO_builder_free(), GNUNET_HELLO_builder_from_parser(), GNUNET_HELLO_builder_iterate(), GNUNET_HELLO_builder_new(), GNUNET_HELLO_parser_to_env(), GNUNET_i2s_full(), GNUNET_log, GNUNET_MQ_env_get_msg(), GNUNET_new, GNUNET_NO, GNUNET_PEERSTORE_hello_add(), GNUNET_PILS_get_identity(), GST_my_hello, msg, my_identity, peerstore, pils, print_address_list(), sc, and update_hello_from_pid_change_cb().

Referenced by run().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ run()

static void run ( void *  cls,
const struct GNUNET_CONFIGURATION_Handle c,
struct GNUNET_SERVICE_Handle service 
)
static

Initiate transport service.

Parameters
clsclosure
cconfiguration to use
servicethe initialized service

Definition at line 15960 of file gnunet-service-transport.c.

15963{
15964 (void) cls;
15965 /* setup globals */
15969 GST_cfg = c;
15977 GNUNET_YES);
15982 // TODO check for all uses of GST_my_hello that it is not used uninitialized
15984 "transport",
15985 "USE_BURST_NAT");
15986 if (GNUNET_SYSERR == use_burst)
15988 "Could not configure burst nat use. Default to no.\n");
15994 "transport",
15995 0,
15996 0,
15997 NULL,
15998 0,
15999 NULL,
16000 NULL,
16001 NULL);
16002 if (NULL == peerstore)
16003 {
16004 GNUNET_break (0);
16006 return;
16007 }
16010 NULL); // FIXME we need to wait for
16011 // our first peer id before
16012 // we can start the service
16013 // completely - PILS in turn
16014 // waits for the first
16015 // addresses from the
16016 // communicators in order to
16017 // be able to generate a
16018 // peer id
16019 if (NULL == pils)
16020 {
16021 GNUNET_break (0);
16023 return;
16024 }
16025 /* Decapsulate DV box ephemeral keys ourselves. #handle_dv_box() needs
16026 the key material while it still has the box, which points into the
16027 communicator's inbound message and is gone the moment the handler
16028 returns -- so the asynchronous answer arrived to a dangling @a dvb. */
16029 if (GNUNET_OK !=
16032 _ ("Failed to load our private key, "
16033 "cannot open DV boxes addressed to us\n"));
16034}

References _, ack_cummulators, backtalkers, dv_routes, dvlearn_map, GNUNET_break, GNUNET_CONFIGURATION_get_value_yesno(), GNUNET_CONTAINER_heap_create(), GNUNET_CONTAINER_HEAP_ORDER_MIN, GNUNET_CONTAINER_multihashmap_create(), GNUNET_CONTAINER_multipeermap_create(), GNUNET_CONTAINER_multishortmap_create(), GNUNET_CONTAINER_multiuuidmap_create(), GNUNET_ERROR_TYPE_WARNING, GNUNET_HELLO_builder_new(), GNUNET_log, GNUNET_NAT_register(), GNUNET_NO, GNUNET_OK, GNUNET_PEERSTORE_connect(), GNUNET_PILS_connect(), GNUNET_PILS_enable_private_key(), GNUNET_SCHEDULER_add_shutdown(), GNUNET_SCHEDULER_shutdown(), GNUNET_STATISTICS_create(), GNUNET_SYSERR, GNUNET_TIME_absolute_get_monotonic(), GNUNET_YES, GST_cfg, GST_my_hello, GST_service, GST_stats, hello_mono_time, in_shutdown, links, MAX_DV_LEARN_PENDING, neighbours, nh, peerstore, pending_acks, pils, pils_pid_change_cb(), revalidation_map, service, shutdown_task, use_burst, validation_heap, and validation_map.

Here is the call graph for this function:

◆ GNUNET_SERVICE_MAIN()

GNUNET_SERVICE_MAIN ( GNUNET_OS_project_data_gnunet()  ,
"transport"  ,
GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN  ,
run,
client_connect_cb,
client_disconnect_cb,
NULL  ,
GNUNET_MQ_hd_fixed_size(suggest, GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST, struct ExpressPreferenceMessage, NULL)  ,
GNUNET_MQ_hd_fixed_size(suggest_cancel, GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL, struct ExpressPreferenceMessage, NULL)  ,
GNUNET_MQ_hd_var_size(request_hello_validation, GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION, struct RequestHelloValidationMessage, NULL)  ,
GNUNET_MQ_hd_fixed_size(client_start, GNUNET_MESSAGE_TYPE_TRANSPORT_START, struct StartMessage, NULL)  ,
GNUNET_MQ_hd_var_size(client_send, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, struct OutboundMessage, NULL)  ,
GNUNET_MQ_hd_fixed_size(client_recv_ok, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK, struct RecvOkMessage, NULL)  ,
GNUNET_MQ_hd_var_size(communicator_available, GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR, struct GNUNET_TRANSPORT_CommunicatorAvailableMessage, NULL)  ,
GNUNET_MQ_hd_var_size(communicator_backchannel, GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL, struct GNUNET_TRANSPORT_CommunicatorBackchannel, NULL)  ,
GNUNET_MQ_hd_var_size(add_address, GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS, struct GNUNET_TRANSPORT_AddAddressMessage, NULL)  ,
GNUNET_MQ_hd_fixed_size(del_address, GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS, struct GNUNET_TRANSPORT_DelAddressMessage, NULL)  ,
GNUNET_MQ_hd_var_size(incoming_msg, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG, struct GNUNET_TRANSPORT_IncomingMessage, NULL)  ,
GNUNET_MQ_hd_fixed_size(queue_create_ok, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK, struct GNUNET_TRANSPORT_CreateQueueResponse, NULL)  ,
GNUNET_MQ_hd_fixed_size(queue_create_fail, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL, struct GNUNET_TRANSPORT_CreateQueueResponse, NULL)  ,
GNUNET_MQ_hd_var_size(add_queue_message, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP, struct GNUNET_TRANSPORT_AddQueueMessage, NULL)  ,
GNUNET_MQ_hd_fixed_size(update_queue_message, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_UPDATE, struct GNUNET_TRANSPORT_UpdateQueueMessage, NULL)  ,
GNUNET_MQ_hd_fixed_size(del_queue_message, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN, struct GNUNET_TRANSPORT_DelQueueMessage, NULL)  ,
GNUNET_MQ_hd_fixed_size(send_message_ack, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK, struct GNUNET_TRANSPORT_SendMessageToAck, NULL)  ,
GNUNET_MQ_hd_fixed_size(burst_finished, GNUNET_MESSAGE_TYPE_TRANSPORT_BURST_FINISHED, struct GNUNET_TRANSPORT_BurstFinished, NULL)  ,
GNUNET_MQ_hd_fixed_size(monitor_start, GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START, struct GNUNET_TRANSPORT_MonitorStart, NULL)  ,
GNUNET_MQ_hd_fixed_size(link_list_request, GNUNET_MESSAGE_TYPE_TRANSPORT_LINK_LIST_REQUEST, struct GNUNET_TRANSPORT_LinkListRequest, NULL)  ,
GNUNET_MQ_handler_end()   
)

Define "main" method using service macro.

Variable Documentation

◆ ring_buffer

struct RingBufferEntry* ring_buffer[RING_BUFFER_SIZE]
static

Ring buffer for a CORE message we did not deliver to CORE, because of missing virtual link to sender.

Definition at line 3123 of file gnunet-service-transport.c.

Referenced by detach_cmcs_from_client(), handle_raw_message(), and send_msg_from_cache().

◆ ring_buffer_head

unsigned int ring_buffer_head
static

Head of the ring buffer.

Definition at line 3128 of file gnunet-service-transport.c.

Referenced by handle_raw_message(), and send_msg_from_cache().

◆ is_ring_buffer_full

unsigned int is_ring_buffer_full
static

Is the ring buffer filled up to RING_BUFFER_SIZE.

Definition at line 3133 of file gnunet-service-transport.c.

Referenced by handle_raw_message(), and send_msg_from_cache().

◆ ring_buffer_dv

struct PendingMessage* ring_buffer_dv[RING_BUFFER_SIZE]
static

Ring buffer for a forwarded DVBox message we did not deliver to the next hop, because of missing virtual link that hop.

Definition at line 3138 of file gnunet-service-transport.c.

Referenced by forward_dv_box(), and send_msg_from_cache().

◆ ring_buffer_dv_head

unsigned int ring_buffer_dv_head
static

Head of the ring buffer.

Definition at line 3143 of file gnunet-service-transport.c.

Referenced by forward_dv_box(), and send_msg_from_cache().

◆ is_ring_buffer_dv_full

unsigned int is_ring_buffer_dv_full
static

Is the ring buffer filled up to RING_BUFFER_SIZE.

Definition at line 3148 of file gnunet-service-transport.c.

Referenced by forward_dv_box(), and send_msg_from_cache().

◆ clients_head

◆ clients_tail

struct TransportClient* clients_tail
static

Tail of linked list of all clients to this service.

Definition at line 3158 of file gnunet-service-transport.c.

Referenced by client_connect_cb(), and client_disconnect_cb().

◆ GST_stats

◆ GST_cfg

◆ GST_service

struct GNUNET_SERVICE_Handle* GST_service
static

Our service handle; needed to force-disconnect clients that did not go away within SHUTDOWN_CLIENT_GRACE_PERIOD, as we use GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN.

Definition at line 3175 of file gnunet-service-transport.c.

Referenced by drop_remaining_clients(), and run().

◆ client_grace_task

struct GNUNET_SCHEDULER_Task* client_grace_task
static

Task run when SHUTDOWN_CLIENT_GRACE_PERIOD expired and clients are still connected, or NULL.

Definition at line 3181 of file gnunet-service-transport.c.

Referenced by do_shutdown(), drop_remaining_clients(), and shutdown_task().

◆ GST_my_hello

◆ neighbours

struct GNUNET_CONTAINER_MultiPeerMap* neighbours
static

Map from PIDs to struct Neighbour entries.

A peer is a neighbour if we have an MQ to it from some communicator.

Definition at line 3192 of file gnunet-service-transport.c.

Referenced by do_shutdown(), free_neighbour(), handle_add_queue_message(), handle_dv_learn(), handle_monitor_start(), lookup_neighbour(), run(), start_dv_learn(), and transmit_dv_init().

◆ backtalkers

struct GNUNET_CONTAINER_MultiPeerMap* backtalkers
static

Map from PIDs to struct Backtalker entries.

A peer is a backtalker if it recently send us backchannel messages.

Definition at line 3198 of file gnunet-service-transport.c.

Referenced by decaps_dv_box_cont(), detach_cmcs_from_client(), do_shutdown(), free_backtalker(), and run().

◆ ack_cummulators

struct GNUNET_CONTAINER_MultiPeerMap* ack_cummulators
static

Map from PIDs to struct AcknowledgementCummulators.

Here we track the cumulative ACKs for transmission.

Definition at line 3204 of file gnunet-service-transport.c.

Referenced by cummulative_ack(), destroy_ack_cummulator(), do_shutdown(), and run().

◆ pending_acks

struct GNUNET_CONTAINER_MultiUuidmap* pending_acks
static

Map of pending acknowledgements, mapping struct AcknowledgementUUID to a struct PendingAcknowledgement.

Definition at line 3210 of file gnunet-service-transport.c.

Referenced by do_shutdown(), free_pending_acknowledgement(), handle_reliability_ack(), prepare_pending_acknowledgement(), and run().

◆ dv_routes

struct GNUNET_CONTAINER_MultiPeerMap* dv_routes
static

Map from PIDs to struct DistanceVector entries describing known paths to the peer.

Definition at line 3216 of file gnunet-service-transport.c.

Referenced by consider_sending_fc(), do_shutdown(), free_dv_route(), learn_dv_path(), route_control_message_without_fc(), and run().

◆ validation_map

struct GNUNET_CONTAINER_MultiPeerMap* validation_map
static

Map from PIDs to struct ValidationState entries describing addresses we are aware of and their validity state.

Definition at line 3222 of file gnunet-service-transport.c.

Referenced by do_shutdown(), free_validation_state(), handle_add_queue_message(), handle_validation_response(), run(), start_address_validation(), and try_to_bring_link_up().

◆ revalidation_map

struct GNUNET_CONTAINER_MultiHashMap* revalidation_map
static

Map from addresses to struct ValidationState entries describing addresses we are aware of and their validity state.

Definition at line 3228 of file gnunet-service-transport.c.

Referenced by do_shutdown(), free_validation_state(), handle_validation_response(), run(), and validation_transmit_on_queue().

◆ links

◆ dvlearn_map

struct GNUNET_CONTAINER_MultiShortmap* dvlearn_map
static

Map from challenges to struct LearnLaunchEntry values.

Definition at line 3239 of file gnunet-service-transport.c.

Referenced by do_shutdown(), run(), and start_dv_learn().

◆ lle_head

struct LearnLaunchEntry* lle_head = NULL
static

Head of a DLL sorted by launch time.

Definition at line 3244 of file gnunet-service-transport.c.

Referenced by do_shutdown(), and start_dv_learn().

◆ lle_tail

struct LearnLaunchEntry* lle_tail = NULL
static

Tail of a DLL sorted by launch time.

Definition at line 3249 of file gnunet-service-transport.c.

Referenced by do_shutdown(), and start_dv_learn().

◆ validation_heap

struct GNUNET_CONTAINER_Heap* validation_heap
static

MIN Heap sorted by "next_challenge" to struct ValidationState entries sorting addresses we are aware of by when we should next try to (re)validate (or expire) them.

Definition at line 3256 of file gnunet-service-transport.c.

Referenced by do_shutdown(), run(), update_next_challenge_time(), and validation_start_cb().

◆ nh

struct GNUNET_NAT_Handle* nh

Handle for connect to the NAT service.

Definition at line 3261 of file gnunet-service-transport.c.

Referenced by do_shutdown(), handle_flow_control(), and run().

◆ peerstore

◆ pils

◆ pils_requests_head

struct PilsRequest* pils_requests_head
static

◆ pils_requests_tail

struct PilsRequest* pils_requests_tail
static

◆ dvlearn_task

struct GNUNET_SCHEDULER_Task* dvlearn_task
static

Task run to initiate DV learning.

Definition at line 3354 of file gnunet-service-transport.c.

Referenced by do_shutdown(), handle_add_queue_message(), start_dv_learn(), and transmit_dv_init().

◆ dvlearn_pils_backoff

struct GNUNET_TIME_Relative dvlearn_pils_backoff
static

Backoff for start_dv_learn() while PILS still owes us an identity.

Definition at line 3359 of file gnunet-service-transport.c.

Referenced by start_dv_learn().

◆ validation_task

struct GNUNET_SCHEDULER_Task* validation_task
static

Task to run address validation.

Definition at line 3364 of file gnunet-service-transport.c.

Referenced by do_shutdown(), update_next_challenge_time(), and validation_start_cb().

◆ pils_feed_task

struct GNUNET_SCHEDULER_Task* pils_feed_task
static

Task to feed addresses to PILS.

Definition at line 3369 of file gnunet-service-transport.c.

Referenced by do_shutdown(), feed_addresses_to_pils(), handle_add_address(), and handle_del_address().

◆ ir_head

struct IncomingRequest* ir_head
static

List of incoming connections where we are trying to get a connection back established.

Length kept in ir_total.

Definition at line 3376 of file gnunet-service-transport.c.

Referenced by do_shutdown(), free_incoming_request(), and try_to_bring_link_up().

◆ ir_tail

struct IncomingRequest* ir_tail
static

Tail of DLL starting at ir_head.

Definition at line 3381 of file gnunet-service-transport.c.

Referenced by free_incoming_request(), and try_to_bring_link_up().

◆ ir_total

unsigned int ir_total
static

Length of the DLL starting at ir_head.

Definition at line 3386 of file gnunet-service-transport.c.

Referenced by do_shutdown(), free_incoming_request(), and try_to_bring_link_up().

◆ logging_uuid_gen

unsigned long long logging_uuid_gen
static

Generator of logging_uuid in struct PendingMessage.

Definition at line 3391 of file gnunet-service-transport.c.

Referenced by extract_box_cb(), forward_dv_box(), fragment_message(), handle_client_send(), and reliability_box_message().

◆ burst_running

enum GNUNET_GenericReturnValue burst_running
static

Is there a burst running?

Definition at line 3396 of file gnunet-service-transport.c.

Referenced by burst_timeout(), do_shutdown(), handle_burst_finished(), queue_burst(), and start_burst().

◆ hello_mono_time

struct GNUNET_TIME_Absolute hello_mono_time
static

Monotonic time we use for HELLOs generated at this time.

TODO: we should increase this value from time to time (i.e. whenever a struct AddressListEntry actually expires), but IF we do this, we must also update all (remaining) addresses in the PEERSTORE at that time! (So for now only increased when the peer is restarted, which hopefully roughly matches whenever our addresses change.)

Definition at line 3406 of file gnunet-service-transport.c.

Referenced by run(), and store_pi().

◆ in_shutdown

int in_shutdown
static

Indication if we have received a shutdown signal and are in the process of cleaning up.

Definition at line 3412 of file gnunet-service-transport.c.

Referenced by client_disconnect_cb(), run(), shutdown_task(), start_dv_learn(), store_pi(), and try_to_bring_link_up().

◆ burst_task

struct GNUNET_SCHEDULER_Task* burst_task
static

The task to start the burst.

Definition at line 3417 of file gnunet-service-transport.c.

Referenced by do_shutdown(), free_burst_cls(), queue_burst(), and start_burst().

◆ burst_task_cls

struct GNUNET_StartBurstCls* burst_task_cls
static

Closure of the currently scheduled burst_task, or NULL.

Needed so that we can release it (and only it) when the task is cancelled or when the struct VirtualLink it refers to goes away.

Definition at line 3424 of file gnunet-service-transport.c.

Referenced by free_burst_cls(), queue_burst(), and start_burst().

◆ burst_timeout_task

struct GNUNET_SCHEDULER_Task* burst_timeout_task

Definition at line 3426 of file gnunet-service-transport.c.

Referenced by do_shutdown(), and start_burst().

◆ use_burst

enum GNUNET_GenericReturnValue use_burst

Definition at line 3428 of file gnunet-service-transport.c.

Referenced by queue_burst(), and run().