GNUnet 0.29.1-2-g89ecb1bfd
 
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_PICK_TRIES   1000
 How often pick_random_dv_hops() may redraw before settling for the paths it has.
 
#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 Neighbour * lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
 Lookup neighbour for peer pid.
 
static struct VirtualLink * lookup_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 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 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 void speed_up_challenge (struct ValidationState *vs)
 Speed the next challenge for vs up because we heard something about that address again – but never faster than FAST_VALIDATION_CHALLENGE_FREQ.
 
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 Queue * find_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_MessageHeader * hello_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 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 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 PendingAcknowledgement * prepare_pending_acknowledgement (struct Queue *queue, struct DistanceVectorHop *dvh, struct PendingMessage *pm)
 Setup data structure waiting for acknowledgements.
 
static struct PendingMessage * fragment_message (struct Queue *queue, struct DistanceVectorHop *dvh, struct PendingMessage *pm)
 Fragment the given pm to the given mtu.
 
static struct PendingMessage * reliability_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 TransportClient * lookup_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 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.
 
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 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 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 TransportClient * clients_head
 Head of linked list of all clients to this service.
 
static struct TransportClient * clients_tail
 Tail of linked list of all clients to this service.
 
static struct GNUNET_STATISTICS_Handle * GST_stats
 Statistics handle.
 
static const struct GNUNET_CONFIGURATION_Handle * GST_cfg
 Configuration handle.
 
static struct GNUNET_SERVICE_Handle * GST_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_Task * client_grace_task
 Task run when SHUTDOWN_CLIENT_GRACE_PERIOD expired and clients are still connected, or NULL.
 
struct GNUNET_HELLO_Builder * GST_my_hello
 Our HELLO.
 
static struct GNUNET_CONTAINER_MultiPeerMap * neighbours
 Map from PIDs to struct Neighbour entries.
 
static struct GNUNET_CONTAINER_MultiPeerMap * backtalkers
 Map from PIDs to struct Backtalker entries.
 
static struct GNUNET_CONTAINER_MultiPeerMap * ack_cummulators
 Map from PIDs to struct AcknowledgementCummulators.
 
static struct GNUNET_CONTAINER_MultiUuidmap * pending_acks
 Map of pending acknowledgements, mapping struct AcknowledgementUUID to a struct PendingAcknowledgement.
 
static struct GNUNET_CONTAINER_MultiPeerMap * dv_routes
 Map from PIDs to struct DistanceVector entries describing known paths to the peer.
 
static struct GNUNET_CONTAINER_MultiPeerMap * validation_map
 Map from PIDs to struct ValidationState entries describing addresses we are aware of and their validity state.
 
static struct GNUNET_CONTAINER_MultiHashMap * revalidation_map
 Map from addresses to struct ValidationState entries describing addresses we are aware of and their validity state.
 
static struct GNUNET_CONTAINER_MultiPeerMap * links
 Map from PIDs to struct VirtualLink entries describing links CORE knows to exist.
 
static struct GNUNET_CONTAINER_MultiShortmap * dvlearn_map
 Map from challenges to struct LearnLaunchEntry values.
 
static struct LearnLaunchEntry * lle_head = NULL
 Head of a DLL sorted by launch time.
 
static struct LearnLaunchEntry * lle_tail = NULL
 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 of by when we should next try to (re)validate (or expire) them.
 
struct GNUNET_NAT_Handle * nh
 Handle for connect to the NAT service.
 
static struct GNUNET_PEERSTORE_Handle * peerstore
 Database for peer's HELLOs.
 
static struct GNUNET_PILS_Handle * pils
 Service that manages our peer id.
 
static struct PilsRequest * pils_requests_head
 PILS Operation DLL.
 
static struct PilsRequest * pils_requests_tail
 PILS Operation DLL.
 
static struct GNUNET_SCHEDULER_Task * dvlearn_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_Task * validation_task
 Task to run address validation.
 
static struct GNUNET_SCHEDULER_Task * pils_feed_task
 Task to feed addresses to PILS.
 
static struct IncomingRequest * ir_head
 List of incoming connections where we are trying to get a connection back established.
 
static struct IncomingRequest * ir_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_Task * burst_task
 The task to start the burst.
 
static struct GNUNET_StartBurstCls * burst_task_cls
 Closure of the currently scheduled burst_task, or NULL.
 
struct GNUNET_SCHEDULER_Task * burst_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.

522{
527 uint64_t uuid GNUNET_PACKED;
528};
529
530
535{
539 struct GNUNET_Uuid value;
540};
541
546{
551
552 /* Followed by *another* message header which is the message to
553 the communicator */
554
555 /* Followed by a 0-terminated name of the communicator */
556};
557
558
563{
568
584
589
595};
596
597
603{
608
614
626
627 /* Followed by a `struct GNUNET_MessageHeader` with a message
628 for the target peer */
629};
630
631
637{
642
650
657};
658
659
664{
672
677};
678
679
688{
693
698 uint32_t ack_counter GNUNET_PACKED;
699
700 /* followed by any number of `struct TransportCummulativeAckPayloadP`
701 messages providing ACKs */
702};
703
704
709{
714
718 uint16_t frag_off GNUNET_PACKED;
719
723 uint16_t msg_size GNUNET_PACKED;
724
733
738 struct MessageUUIDP msg_uuid;
739};
740
741
759struct DvInitPS
760{
765
779
784};
785
786
803struct DvHopPS
804{
809
814
819
824};
825
826
831struct DVPathEntryP
832{
837
843};
844
845
860{
865
870 uint16_t num_hops GNUNET_PACKED;
871
881
888
902
908
913
918
919 /* Followed by @e num_hops `struct DVPathEntryP` values,
920 excluding the initiator of the DV trace; the last entry is the
921 current sender; the current peer must not be included. */
922};
923
924
948{
953
957 uint32_t without_fc GNUNET_PACKED;
958
965 uint16_t total_hops GNUNET_PACKED;
966
972 uint16_t num_hops GNUNET_PACKED;
973
979
986
993
999 uint16_t orig_size GNUNET_PACKED;
1000
1001 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values;
1002 excluding the @e origin and the current peer, the last must be
1003 the ultimate target; if @e num_hops is zero, the receiver of this
1004 message is the ultimate target. */
1005
1006 /* Followed by encrypted, variable-size payload, which
1007 must begin with a `struct TransportDVBoxPayloadP` */
1008
1009 /* Followed by the actual message, which itself must not be a
1010 a DV_LEARN or DV_BOX message! */
1011};
1012
1013
1019{
1024
1028 uint32_t reserved GNUNET_PACKED;
1029
1034
1040};
1041
1042
1048{
1053
1059
1064};
1065
1066
1072{
1077
1081 uint32_t reserved GNUNET_PACKED;
1082
1088
1093
1098 struct GNUNET_TIME_AbsoluteNBO origin_time;
1099
1104 struct GNUNET_TIME_RelativeNBO validity_duration;
1105};
1106
1108{
1113
1114 /* Followed by @e address_length bytes of the address. */
1115};
1116
1126{
1131
1139 uint32_t seq GNUNET_PACKED;
1140
1146
1153
1163
1173
1178
1182 uint32_t sync_ready GNUNET_PACKED;
1183
1188
1194
1195 /* Followed by @e number_of_addresses struct TransportGlobalNattedAddress. */
1196};
1197
1199
1200/* GNUNET_NETWORK_STRUCT_BEGIN/_END expand to nothing; only the per-member
1201 GNUNET_PACKED keeps these layouts free of compiler padding. Pin the sizes
1202 so that adding an unpacked or non-fixed-width member cannot silently put
1203 padding bytes -- i.e. uninitialised stack -- on the wire again. */
1205
1207GNUNET_static_assert (sizeof(struct TransportDVBoxMessage) == 86);
1208GNUNET_static_assert (sizeof(struct TransportDVLearnMessage) == 152);
1214
1215
1219enum ClientType
1220{
1224 CT_NONE = 0,
1225
1229 CT_CORE = 1,
1230
1234 CT_MONITOR = 2,
1235
1239 CT_COMMUNICATOR = 3,
1240
1244 CT_APPLICATION = 4
1245};
1246
1247
1253{
1257 RMO_NONE = 0,
1258
1262 RMO_DV_ALLOWED = 1,
1263
1268
1273
1279 RMO_REDUNDANT = 4
1280};
1281
1282
1286struct LearnLaunchEntry
1287{
1291 struct LearnLaunchEntry *prev;
1292
1296 struct LearnLaunchEntry *next;
1297
1302
1308};
1309
1310
1316{
1320 uint64_t bytes_sent;
1321
1326 uint64_t bytes_received;
1327};
1328
1329
1333struct PerformanceData
1334{
1339
1345
1350 unsigned int last_age;
1351};
1352
1353
1357struct TransportClient;
1358
1362struct Neighbour;
1363
1368struct DistanceVector;
1369
1374struct Queue;
1375
1379struct PendingMessage;
1380
1384struct DistanceVectorHop;
1385
1394struct VirtualLink;
1395
1396
1402{
1408
1414
1420 struct TransportClient *tc;
1421
1426
1430 const struct GNUNET_MessageHeader *mh;
1431
1436 uint16_t total_hops;
1437
1443 unsigned int ack_sent;
1444
1451 unsigned int client_resumed;
1452};
1453
1454
1458struct RingBufferEntry
1459{
1464
1468 struct GNUNET_MessageHeader *mh;
1469};
1470
1471
1475struct CoreSentContext
1476{
1480 struct CoreSentContext *next;
1481
1485 struct CoreSentContext *prev;
1486
1490 struct VirtualLink *vl;
1491
1495 uint16_t size;
1496
1503 uint16_t isize;
1504};
1505
1506
1510struct ReassemblyContext
1511{
1516 struct MessageUUIDP msg_uuid;
1517
1521 struct VirtualLink *virtual_link;
1522
1527
1535 uint8_t *bitfield;
1536
1541
1547
1551 uint16_t msg_size;
1552
1557 uint16_t msg_missing;
1558
1559 /* Followed by @e msg_size bytes of the (partially) defragmented original
1560 * message */
1561
1562 /* Followed by @e bitfield data */
1563};
1564
1565
1574struct VirtualLink
1575{
1580
1587
1594
1599
1605
1611
1616 unsigned int cmc_count;
1617
1624
1629
1634
1638 struct CoreSentContext *csc_tail;
1639
1643 struct CoreSentContext *csc_head;
1644
1652
1658
1664
1669
1673 char *burst_addr;
1674
1678 unsigned int fc_retransmit_count;
1679
1684 unsigned int confirmed;
1685
1689 struct Neighbour *n;
1690
1694 struct DistanceVector *dv;
1695
1702
1709
1718
1724
1730
1735
1740 uint64_t message_uuid_ctr;
1741
1749 uint64_t available_fc_window_size;
1750
1758
1764 uint64_t incoming_fc_window_size;
1765
1774
1787
1792 uint64_t outbound_fc_window_size;
1793
1800
1811
1816 uint32_t fc_seq_gen;
1817
1823 uint32_t last_fc_seq;
1824
1836 int core_recv_window;
1837
1842};
1843
1844
1849{
1855
1861
1868
1875
1882
1889
1894
1899 struct PendingMessage *pm;
1900
1905 struct DistanceVectorHop *dvh;
1906
1911 struct Queue *queue;
1912
1917
1921 uint16_t message_size;
1922
1926 unsigned int num_send;
1927};
1928
1929
1933struct DistanceVectorHop
1934{
1938 struct DistanceVectorHop *next_dv;
1939
1943 struct DistanceVectorHop *prev_dv;
1944
1949
1954
1959
1964
1968 struct Neighbour *next_hop;
1969
1973 struct DistanceVector *dv;
1974
1980 const struct GNUNET_PeerIdentity *path;
1981
1987
1996
2000 struct PerformanceData pd;
2001
2007 unsigned int distance;
2008};
2009
2010
2015struct DistanceVector
2016{
2021
2025 struct DistanceVectorHop *dv_head;
2026
2030 struct DistanceVectorHop *dv_tail;
2031
2036
2041 struct VirtualLink *vl;
2042
2048
2053
2058
2063
2067 struct GNUNET_ShortHashCode *km;
2068};
2069
2070
2080struct QueueEntry
2081{
2085 struct QueueEntry *next;
2086
2090 struct QueueEntry *prev;
2091
2095 struct Queue *queue;
2096
2100 struct PendingMessage *pm;
2101
2105 uint64_t mid;
2106
2111};
2112
2113
2118struct Queue
2119{
2123 struct Queue *next_neighbour;
2124
2128 struct Queue *prev_neighbour;
2129
2133 struct Queue *prev_client;
2134
2138 struct Queue *next_client;
2139
2144
2149
2153 struct QueueEntry *queue_head;
2154
2158 struct QueueEntry *queue_tail;
2159
2163 struct Neighbour *neighbour;
2164
2168 struct TransportClient *tc;
2169
2173 const char *address;
2174
2178 unsigned int unlimited_length;
2179
2185
2194
2198 struct PerformanceData pd;
2199
2205
2210 uint64_t mid_gen;
2211
2215 uint32_t qid;
2216
2220 uint32_t mtu;
2221
2225 uint32_t num_msg_pending;
2226
2230 uint32_t num_bytes_pending;
2231
2235 unsigned int queue_length;
2236
2240 uint64_t q_capacity;
2241
2245 uint32_t priority;
2246
2251
2256
2261 int idle;
2262
2267};
2268
2269
2273struct Neighbour
2274{
2278 struct GNUNET_PeerIdentity pid;
2279
2284 struct DistanceVectorHop *dv_head;
2285
2290 struct DistanceVectorHop *dv_tail;
2291
2299
2303 struct Queue *queue_head;
2304
2308 struct Queue *queue_tail;
2309
2315
2321
2326 struct VirtualLink *vl;
2327
2333
2339
2344
2348 unsigned int number_of_addresses;
2349
2354
2359};
2360
2361
2366struct IncomingRequest
2367{
2371 struct IncomingRequest *next;
2372
2376 struct IncomingRequest *prev;
2377
2382
2386 struct GNUNET_PeerIdentity pid;
2387};
2388
2389
2393struct PeerRequest
2394{
2398 struct GNUNET_PeerIdentity pid;
2399
2403 struct TransportClient *tc;
2404
2409
2415
2421
2428
2433};
2434
2435
2440{
2444 PMT_CORE = 0,
2445
2449 PMT_FRAGMENT_BOX = 1,
2450
2455
2459 PMT_DV_BOX = 3
2460};
2461
2462
2489struct PendingMessage
2490{
2494 struct PendingMessage *next_vl;
2495
2499 struct PendingMessage *prev_vl;
2500
2505
2510
2515 struct PendingMessage *next_frag;
2516
2521 struct PendingMessage *prev_frag;
2522
2527
2532
2537 struct PendingMessage *bpm;
2538
2543 struct VirtualLink *vl;
2544
2549
2558 struct QueueEntry *qe;
2559
2563 struct TransportClient *client;
2564
2568 struct PendingMessage *head_frag;
2569
2573 struct PendingMessage *tail_frag;
2574
2579
2584
2589
2594 struct MessageUUIDP msg_uuid;
2595
2600 uint64_t logging_uuid;
2601
2606
2612
2617
2621 uint16_t bytes_msg;
2622
2626 uint16_t frag_off;
2627
2631 uint32_t frags_in_flight;
2632
2636 uint32_t frags_in_flight_round;
2637
2641 uint16_t frag_count;
2642
2646 int16_t msg_uuid_set;
2647
2655 int16_t client_credited;
2656
2657 /* Followed by @e bytes_msg to transmit */
2658};
2659
2660
2665{
2671
2676};
2677
2678
2684{
2689
2694
2701
2706
2712 uint32_t ack_counter;
2713
2717 unsigned int num_acks;
2718};
2719
2720
2726
2727
2731struct AddressListEntry
2732{
2736 struct AddressListEntry *next;
2737
2741 struct AddressListEntry *prev;
2742
2746 struct TransportClient *tc;
2747
2752
2759 struct PilsAddressSignContext *pc;
2760
2764 const char *address;
2765
2769 void *signed_address;
2770
2774 size_t signed_address_len;
2775
2780
2784 struct GNUNET_SCHEDULER_Task *st;
2785
2791
2796
2800 uint32_t aid;
2801
2806};
2807
2808
2812struct TransportClient
2813{
2817 struct TransportClient *next;
2818
2822 struct TransportClient *prev;
2823
2828
2832 struct GNUNET_MQ_Handle *mq;
2833
2837 enum ClientType type;
2838
2839 union
2840 {
2844 struct
2845 {
2851
2856 } core;
2857
2861 struct
2862 {
2869
2873 int one_shot;
2874 } monitor;
2875
2876
2880 struct
2881 {
2886 char *address_prefix;
2887
2891 struct Queue *queue_head;
2892
2896 struct Queue *queue_tail;
2897
2903
2909
2915 unsigned int total_queue_length;
2916
2921
2926
2931
2932 } communicator;
2933
2937 struct
2938 {
2944 } application;
2945 } details;
2946};
2947
2948
2953struct ValidationState
2954{
2959 struct GNUNET_PeerIdentity pid;
2960
2968
2974
2981 struct GNUNET_TIME_Absolute first_challenge_use;
2982
2989 struct GNUNET_TIME_Absolute last_challenge_use;
2990
2998 struct GNUNET_TIME_Absolute next_challenge;
2999
3008 struct GNUNET_TIME_Relative challenge_backoff;
3009
3014 struct GNUNET_TIME_Relative validation_rtt;
3015
3023 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
3024
3028 struct GNUNET_HashCode hc;
3029
3033 struct GNUNET_SCHEDULER_Task *revalidation_task;
3034
3038 char *address;
3039
3045 struct GNUNET_CONTAINER_HeapNode *hn;
3046
3052
3058 uint32_t last_window_consum_limit;
3059
3064 int awaiting_queue;
3065};
3066
3067
3074struct Backtalker
3075{
3079 struct GNUNET_PeerIdentity pid;
3080
3085
3090
3095
3101
3106
3112
3118
3123 size_t body_size;
3124};
3125
3130
3134static unsigned int ring_buffer_head;
3135
3139static unsigned int is_ring_buffer_full;
3140
3145
3149static unsigned int ring_buffer_dv_head;
3150
3154static unsigned int is_ring_buffer_dv_full;
3155
3159static struct TransportClient *clients_head;
3160
3164static struct TransportClient *clients_tail;
3165
3169static struct GNUNET_STATISTICS_Handle *GST_stats;
3170
3174static const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
3175
3181static struct GNUNET_SERVICE_Handle *GST_service;
3182
3188
3193
3199
3205
3211
3217
3223
3229
3235
3241
3246
3250static struct LearnLaunchEntry *lle_head = NULL;
3251
3255static struct LearnLaunchEntry *lle_tail = NULL;
3256
3263
3267struct GNUNET_NAT_Handle *nh;
3268
3272static struct GNUNET_PEERSTORE_Handle *peerstore;
3273
3277static struct GNUNET_PILS_Handle *pils;
3278
3282struct PilsRequest
3283{
3287 struct PilsRequest *prev;
3288
3292 struct PilsRequest *next;
3293
3297 struct GNUNET_PILS_Operation *op;
3298};
3299
3303static struct PilsRequest *pils_requests_head;
3304
3308static struct PilsRequest *pils_requests_tail;
3309
3334static enum GNUNET_GenericReturnValue
3336 struct GNUNET_CRYPTO_EddsaSignature *sig)
3337{
3339
3341 if (NULL == my_private_key)
3342 {
3343 /* #run() enables local key access, so this means the key on disk does
3344 not match the identity PILS announced, or no identity is known yet. */
3346 "No private key for our peer identity, cannot sign\n");
3348 "# signatures failed (no private key)",
3349 1,
3350 GNUNET_NO);
3351 return GNUNET_SYSERR;
3352 }
3353 return GNUNET_CRYPTO_eddsa_sign_ (my_private_key, purpose, sig);
3354}
3355
3356
3360static struct GNUNET_SCHEDULER_Task *dvlearn_task;
3361
3366
3371
3376
3382static struct IncomingRequest *ir_head;
3383
3387static struct IncomingRequest *ir_tail;
3388
3392static unsigned int ir_total;
3393
3397static unsigned long long logging_uuid_gen;
3398
3403
3413
3418static int in_shutdown;
3419
3423static struct GNUNET_SCHEDULER_Task *burst_task;
3424
3431
3433
3435
3446static unsigned int
3447get_age ()
3448{
3449 struct GNUNET_TIME_Absolute now;
3450
3451 now = GNUNET_TIME_absolute_get ();
3452 return now.abs_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us / 15;
3453}
3454
3455
3461static void
3463{
3465 GNUNET_assert (ir_total > 0);
3466 ir_total--;
3467 if (NULL != ir->nc)
3469 ir->nc = NULL;
3470 GNUNET_free (ir);
3471}
3472
3473
3479static void
3481{
3482 struct Queue *q = pa->queue;
3483 struct PendingMessage *pm = pa->pm;
3484 struct DistanceVectorHop *dvh = pa->dvh;
3485
3487 "free_pending_acknowledgement\n");
3488 if (NULL != q)
3489 {
3490 GNUNET_CONTAINER_MDLL_remove (queue, q->pa_head, q->pa_tail, pa);
3491 pa->queue = NULL;
3492 }
3493 if (NULL != pm)
3494 {
3496 "remove pa from message\n");
3498 "remove pa from message %" PRIu64 "\n",
3499 pm->logging_uuid);
3501 "remove pa from message %u\n",
3502 pm->pmt);
3504 "remove pa from message %s\n",
3506 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
3507 pa->pm = NULL;
3508 }
3509 if (NULL != dvh)
3510 {
3511 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
3512 pa->dvh = NULL;
3513 }
3516 &pa->ack_uuid.value,
3517 pa));
3518 GNUNET_free (pa);
3519}
3520
3521
3530static void
3532{
3533 struct PendingMessage *frag;
3534
3535 while (NULL != (frag = root->head_frag))
3536 {
3537 struct PendingAcknowledgement *pa;
3538
3539 free_fragment_tree (frag);
3540 /* Release them: a `struct PendingAcknowledgement' whose @e pm is gone
3541 can never do anything useful again -- handle_acknowledged() would
3542 just free it -- but it stays in #pending_acks, and only an ACK that
3543 may never come takes it out. Merely detaching it here leaked one
3544 entry per fragment that was not acknowledged before its message went
3545 away, which on a lossy link is unbounded growth. */
3546 while (NULL != (pa = frag->pa_head))
3548 GNUNET_CONTAINER_MDLL_remove (frag, root->head_frag, root->tail_frag, frag);
3549 if (NULL != frag->qe)
3550 {
3551 GNUNET_assert (frag == frag->qe->pm);
3552 frag->qe->pm = NULL;
3553 }
3555 "Free frag %p\n",
3556 frag);
3557 GNUNET_free (frag);
3558 }
3559}
3560
3561
3569static void
3571{
3572 struct TransportClient *tc = pm->client;
3573 struct VirtualLink *vl = pm->vl;
3574 struct PendingAcknowledgement *pa;
3575
3577 "Freeing pm %p\n",
3578 pm);
3579 if (NULL != tc)
3580 {
3582 tc->details.core.pending_msg_head,
3583 tc->details.core.pending_msg_tail,
3584 pm);
3585 }
3586 if ((NULL != vl) && (NULL == pm->frag_parent))
3587 {
3589 "Removing pm %" PRIu64 "\n",
3590 pm->logging_uuid);
3592 vl->pending_msg_head,
3593 vl->pending_msg_tail,
3594 pm);
3595 }
3596 else if (NULL != pm->frag_parent && PMT_DV_BOX != pm->pmt)
3597 {
3598 struct PendingMessage *root = pm->frag_parent;
3599
3600 while (NULL != root->frag_parent && PMT_DV_BOX != root->pmt)
3601 root = root->frag_parent;
3602
3603 root->frag_count--;
3604 }
3605 /* Same as in #free_fragment_tree(): the message these acknowledgements
3606 belong to is going away, so they are garbage rather than orphans. */
3607 while (NULL != (pa = pm->pa_head))
3609
3610 free_fragment_tree (pm);
3611 if (NULL != pm->qe)
3612 {
3613 GNUNET_assert (pm == pm->qe->pm);
3614 pm->qe->pm = NULL;
3615 }
3616 if (NULL != pm->bpm)
3617 {
3618 free_fragment_tree (pm->bpm);
3619 /* @e bpm is released with GNUNET_free() rather than through
3620 #free_pending_message(), so nothing here ever unlinked the
3621 acknowledgements attached to the box itself -- only those of its
3622 fragments, via the call above. They kept @e pm pointing into the
3623 block we are about to release, and #handle_acknowledged() follows
3624 that pointer when the ACK finally arrives. */
3625 while (NULL != (pa = pm->bpm->pa_head))
3627 if (NULL != pm->bpm->qe)
3628 {
3629 struct QueueEntry *qe = pm->bpm->qe;
3630
3631 qe->pm = NULL;
3632 }
3633 GNUNET_free (pm->bpm);
3634 }
3635
3636 GNUNET_free (pm);
3638 "Freeing pm done\n");
3639}
3640
3641
3647static void
3649{
3650 struct VirtualLink *vl = rc->virtual_link;
3651
3655 rc->msg_uuid.uuid,
3656 rc));
3657 GNUNET_free (rc);
3658}
3659
3660
3666static void
3667reassembly_cleanup_task (void *cls)
3668{
3669 struct VirtualLink *vl = cls;
3670 struct ReassemblyContext *rc;
3671
3672 vl->reassembly_timeout_task = NULL;
3673 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (vl->reassembly_heap)))
3674 {
3676 .rel_value_us)
3677 {
3679 continue;
3680 }
3685 vl);
3686 return;
3687 }
3688}
3689
3690
3699static int
3700free_reassembly_cb (void *cls, uint32_t key, void *value)
3701{
3702 struct ReassemblyContext *rc = value;
3703
3704 (void) cls;
3705 (void) key;
3707 return GNUNET_OK;
3708}
3709
3710
3717static void
3719 unsigned int free_cmc);
3720
3721
3729static void
3731 struct CommunicatorMessageContext *cmc);
3732
3733
3740static void
3741free_burst_cls (struct GNUNET_StartBurstCls *sb_cls);
3742
3743
3761static void
3763 const struct GNUNET_PeerIdentity *pid)
3764{
3765 struct GNUNET_MQ_Envelope *env;
3766 struct SendOkMessage *so_msg;
3767
3768 if (NULL == tc)
3769 return;
3771 so_msg->peer = *pid;
3772 GNUNET_MQ_send (tc->mq, env);
3773}
3774
3775
3788static void
3789credit_client (struct PendingMessage *pm)
3790{
3791 if ((NULL == pm->client) || (GNUNET_YES == pm->client_credited))
3792 return;
3794 send_ok_to_client (pm->client, &pm->vl->target);
3795}
3796
3797
3803static void
3804free_virtual_link (struct VirtualLink *vl)
3805{
3806 struct PendingMessage *pm;
3807 struct CoreSentContext *csc;
3808 struct CommunicatorMessageContext *cmc;
3809
3811 "free virtual link %p\n",
3812 vl);
3813
3814 /* Communicators that are blocked on CORE flow control for this link MUST
3815 be resumed here. Otherwise their `struct CommunicatorMessageContext's
3816 leak and -- worse -- those clients never get their
3817 GNUNET_SERVICE_client_continue() and stall forever. */
3818 while (NULL != (cmc = vl->cmc_head))
3819 release_stalled_cmc (vl, cmc);
3820 if (NULL != vl->core_fc_stall_task)
3821 {
3823 vl->core_fc_stall_task = NULL;
3824 }
3825
3826 if (NULL != vl->reassembly_map)
3827 {
3830 NULL);
3832 vl->reassembly_map = NULL;
3834 vl->reassembly_heap = NULL;
3835 }
3836 if (NULL != vl->reassembly_timeout_task)
3837 {
3839 vl->reassembly_timeout_task = NULL;
3840 }
3841 while (NULL != (pm = vl->pending_msg_head))
3842 {
3843 /* These never got transmitted, so #completed_pending_message() will not
3844 run for them and nobody else answers their SEND either. Return the
3845 window credit anyway: CORE keeps its `struct Neighbour' -- and thus
3846 the window -- until it sees our DISCONNECT, and #handle_client_send()
3847 deliberately tolerates a SEND for a link that is already gone, so a
3848 client can easily still be sending while we free this. */
3849 credit_client (pm);
3851 }
3854 if (NULL != vl->visibility_task)
3855 {
3857 vl->visibility_task = NULL;
3858 }
3859 if (NULL != vl->fc_retransmit_task)
3860 {
3862 vl->fc_retransmit_task = NULL;
3863 }
3864 while (NULL != (csc = vl->csc_head))
3865 {
3867 GNUNET_assert (vl == csc->vl);
3868 csc->vl = NULL;
3869 }
3870 if (NULL != vl->unconfirmed_timeout_task)
3871 {
3873 vl->unconfirmed_timeout_task = NULL;
3874 }
3875 if (NULL != vl->ic)
3876 {
3877 /* the closure of this iteration is @e sb_cls, released just below */
3879 vl->ic = NULL;
3880 }
3881 if (NULL != vl->sb_cls)
3882 {
3883 /* Cancels #burst_task if that task's closure is ours: it would
3884 otherwise run on this (freed) link. */
3885 free_burst_cls (vl->sb_cls);
3886 GNUNET_assert (NULL == vl->sb_cls);
3887 }
3888 GNUNET_free (vl->burst_addr);
3889 GNUNET_break (NULL == vl->n);
3890 GNUNET_break (NULL == vl->dv);
3891 GNUNET_free (vl);
3892}
3893
3894
3900static void
3902{
3903 if (NULL != vs->revalidation_task)
3904 {
3905 GNUNET_SCHEDULER_cancel (vs->revalidation_task);
3906 vs->revalidation_task = NULL;
3907 }
3908 /*memcpy (&hkey,
3909 &hc,
3910 sizeof (hkey));*/
3912 "Remove key %s for address %s map size %u contains %u during freeing state\n",
3913 GNUNET_h2s (&vs->hc),
3914 vs->address,
3917 &vs->hc));
3920 GNUNET_YES ==
3923 vs->hn = NULL;
3924 if (NULL != vs->sc)
3925 {
3927 "store cancel\n");
3929 vs->sc = NULL;
3930 }
3931 GNUNET_free (vs->address);
3932 GNUNET_free (vs);
3933}
3934
3935
3942static struct Neighbour *
3944{
3946}
3947
3948
3955static struct VirtualLink *
3956lookup_virtual_link (const struct GNUNET_PeerIdentity *pid)
3957{
3959}
3960
3961
3965struct MonitorEvent
3966{
3973
3978
3983
3987 uint32_t num_msg_pending;
3988
3992 uint32_t num_bytes_pending;
3993};
3994
3995
4004static void
4006{
4007 struct Neighbour *n = dvh->next_hop;
4008 struct DistanceVector *dv = dvh->dv;
4009 struct PendingAcknowledgement *pa;
4010
4011 while (NULL != (pa = dvh->pa_head))
4012 {
4014 pa->dvh = NULL;
4015 }
4016 GNUNET_CONTAINER_MDLL_remove (neighbour, n->dv_head, n->dv_tail, dvh);
4018 GNUNET_free (dvh);
4019}
4020
4021
4028static void
4029check_link_down (void *cls);
4030
4031
4037static void
4039{
4041 "Informing CORE clients about disconnect from %s\n",
4042 GNUNET_i2s (pid));
4043 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
4044 {
4045 struct GNUNET_MQ_Envelope *env;
4046 struct DisconnectInfoMessage *dim;
4047
4048 if (CT_CORE != tc->type)
4049 continue;
4051 dim->peer = *pid;
4052 GNUNET_MQ_send (tc->mq, env);
4053 }
4054}
4055
4056
4057static void
4058try_to_bring_link_up (const struct GNUNET_PeerIdentity *pid);
4059
4060
4083static void
4085{
4086 struct GNUNET_PeerIdentity target = vl->target;
4087
4088 for (struct PendingMessage *pm = vl->pending_msg_head;
4089 NULL != pm;
4090 pm = pm->next_vl)
4091 credit_client (pm);
4093 free_virtual_link (vl);
4094 /* Start getting it back now. Only #handle_validation_response() can
4095 rebuild it, and a successful validation parks @e revalidation_task just
4096 short of #ADDRESS_VALIDATION_LIFETIME -- four hours away. */
4097 try_to_bring_link_up (&target);
4098}
4099
4100
4107static void
4108free_dv_route (struct DistanceVector *dv)
4109{
4110 struct DistanceVectorHop *dvh;
4111 struct VirtualLink *vl;
4112
4113 while (NULL != (dvh = dv->dv_head))
4115
4117 GNUNET_YES ==
4119 if (NULL != (vl = dv->vl))
4120 {
4121 GNUNET_assert (dv == vl->dv);
4122 vl->dv = NULL;
4123 if (NULL == vl->n)
4124 {
4126 }
4127 else
4128 {
4129 /* @e visibility_task is NULL while #check_link_down() itself runs, and
4130 #GNUNET_SCHEDULER_cancel() dereferences its argument. */
4131 if (NULL != vl->visibility_task)
4134 }
4135 dv->vl = NULL;
4136 }
4137
4138 if (NULL != dv->timeout_task)
4139 {
4141 dv->timeout_task = NULL;
4142 }
4143 GNUNET_free (dv->km);
4144 GNUNET_free (dv);
4145}
4146
4147
4161static void
4163 const struct GNUNET_PeerIdentity *peer,
4164 const char *address,
4166 const struct MonitorEvent *me)
4167{
4168 struct GNUNET_MQ_Envelope *env;
4170 size_t addr_len = strlen (address) + 1;
4171
4173 addr_len,
4175 md->nt = htonl ((uint32_t) nt);
4176 md->peer = *peer;
4177 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
4178 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
4179 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
4180 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
4181 md->cs = htonl ((uint32_t) me->cs);
4182 md->num_msg_pending = htonl (me->num_msg_pending);
4183 md->num_bytes_pending = htonl (me->num_bytes_pending);
4184 memcpy (&md[1], address, addr_len);
4185 GNUNET_MQ_send (tc->mq, env);
4186}
4187
4188
4198static void
4200 const char *address,
4202 const struct MonitorEvent *me)
4203{
4204 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
4205 {
4206 if (CT_MONITOR != tc->type)
4207 continue;
4208 if (tc->details.monitor.one_shot)
4209 continue;
4210 if ((GNUNET_NO == GNUNET_is_zero (&tc->details.monitor.peer)) &&
4211 (0 != GNUNET_memcmp (&tc->details.monitor.peer, peer)))
4212 continue;
4214 }
4215}
4216
4217
4227static void *
4228client_connect_cb (void *cls,
4229 struct GNUNET_SERVICE_Client *client,
4230 struct GNUNET_MQ_Handle *mq)
4231{
4232 struct TransportClient *tc;
4233
4234 (void) cls;
4235 tc = GNUNET_new (struct TransportClient);
4236 tc->client = client;
4237 tc->mq = mq;
4240 "Client %p of type %u connected\n",
4241 tc,
4242 tc->type);
4243 return tc;
4244}
4245
4246
4247static enum GNUNET_GenericReturnValue
4248remove_global_addresses (void *cls,
4249 const struct GNUNET_PeerIdentity *pid,
4250 void *value)
4251{
4252 struct TransportGlobalNattedAddress *tgna = value;
4253 (void) cls;
4254
4255 GNUNET_free (tgna);
4256
4257 return GNUNET_OK;
4258}
4259
4260
4267static void
4268free_neighbour (struct Neighbour *neighbour,
4269 enum GNUNET_GenericReturnValue drop_link)
4270{
4271 struct DistanceVectorHop *dvh;
4272 struct VirtualLink *vl;
4273
4274 GNUNET_assert (NULL == neighbour->queue_head);
4277 &neighbour->pid,
4278 neighbour));
4280 "Freeing neighbour\n");
4283 NULL);
4285 while (NULL != (dvh = neighbour->dv_head))
4286 {
4287 struct DistanceVector *dv = dvh->dv;
4288
4290 if (NULL == dv->dv_head)
4291 free_dv_route (dv);
4292 }
4293 if (NULL != neighbour->get)
4294 {
4296 neighbour->get = NULL;
4297 }
4298 if (NULL != neighbour->sc)
4299 {
4301 "store cancel\n");
4302 GNUNET_PEERSTORE_store_cancel (neighbour->sc);
4303 neighbour->sc = NULL;
4304 }
4305 if (NULL != (vl = neighbour->vl))
4306 {
4307 GNUNET_assert (neighbour == vl->n);
4308 vl->n = NULL;
4309 if ((GNUNET_YES == drop_link) || (NULL == vl->dv))
4310 {
4312 }
4313 else
4314 {
4315 /* See #free_dv_route(): may be NULL under #check_link_down(). */
4316 if (NULL != vl->visibility_task)
4319 }
4320 neighbour->vl = NULL;
4321 }
4322 GNUNET_free (neighbour);
4323}
4324
4325
4332static void
4334 const struct GNUNET_PeerIdentity *pid)
4335{
4336 struct GNUNET_MQ_Envelope *env;
4337 struct ConnectInfoMessage *cim;
4338
4339 GNUNET_assert (CT_CORE == tc->type);
4341 cim->id = *pid;
4342 GNUNET_MQ_send (tc->mq, env);
4343}
4344
4345
4351static void
4353{
4355 "Informing CORE clients about connection to %s\n",
4356 GNUNET_i2s (pid));
4357 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
4358 {
4359 if (CT_CORE != tc->type)
4360 continue;
4362 }
4363}
4364
4365
4373static void
4374transmit_on_queue (void *cls);
4375
4376
4385static unsigned int
4387{
4388 for (struct Queue *s = queue_head; NULL != s;
4389 s = s->next_neighbour)
4390 {
4391 if (s == queue)
4392 continue;
4393 if (s->tc->details.communicator.address_prefix !=
4394 queue->tc->details.communicator.address_prefix)
4395 {
4397 "queue address %s qid %u compare with queue: address %s qid %u\n",
4398 queue->address,
4399 queue->qid,
4400 s->address,
4401 s->qid);
4402 if ((s->priority > queue->priority) && (0 < s->q_capacity) &&
4403 (QUEUE_LENGTH_LIMIT > s->queue_length) )
4404 return GNUNET_YES;
4406 "Lower prio\n");
4407 }
4408 }
4409 return GNUNET_NO;
4410}
4411
4412
4419static void
4421
4422
4430static void
4432 struct Queue *queue,
4434{
4436
4437 if (queue->validated_until.abs_value_us < now.abs_value_us)
4438 return;
4440 queue->neighbour->queue_head))
4441 return;
4442
4443 if (queue->tc->details.communicator.total_queue_length >=
4445 {
4447 "Transmission on queue %s (QID %u) throttled due to communicator queue limit\n",
4448 queue->address,
4449 queue->qid);
4451 GST_stats,
4452 "# Transmission throttled due to communicator queue limit",
4453 1,
4454 GNUNET_NO);
4455 queue->idle = GNUNET_NO;
4456 /* @e total_queue_length is shared by every peer this communicator serves,
4457 so at the limit we can send to none of them, and the only things that
4458 lower it again are an ACK from the communicator, #free_queue() and
4459 #free_timedout_queue_entry(). If we got here because a peer stopped
4460 acknowledging, no ACK is coming; and we just declined to arm
4461 @e transmit_task, so #queue_send_msg() -- the *only* place that arms
4462 the sweeper -- will not run either. That leaves nothing at all to
4463 recover the count, and the communicator stays mute towards every peer
4464 until some unrelated queue happens to go down. Keep the sweeper
4465 going. */
4467 return;
4468 }
4469 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
4470 {
4472 "Transmission on queue %s (QID %u) throttled due to communicator queue length limit\n",
4473 queue->address,
4474 queue->qid);
4476 "# Transmission throttled due to queue queue limit",
4477 1,
4478 GNUNET_NO);
4479 queue->idle = GNUNET_NO;
4480 /* Same reasoning as above, for the per-queue limit. */
4482 return;
4483 }
4484 if (0 == queue->q_capacity)
4485 {
4487 "Transmission on queue %s (QID %u) throttled due to communicator message has capacity %"
4488 PRIu64 ".\n",
4489 queue->address,
4490 queue->qid,
4491 queue->q_capacity);
4493 "# Transmission throttled due to message queue capacity",
4494 1,
4495 GNUNET_NO);
4496 queue->idle = GNUNET_NO;
4497 return;
4498 }
4499 /* queue might indeed be ready, schedule it */
4500 if (NULL != queue->transmit_task)
4501 GNUNET_SCHEDULER_cancel (queue->transmit_task);
4502 queue->transmit_task =
4504 queue);
4506 "Considering transmission on queue `%s' QID %llu to %s\n",
4507 queue->address,
4508 (unsigned long long) queue->qid,
4509 GNUNET_i2s (&queue->neighbour->pid));
4510}
4511
4512
4513static void
4515 const char *address);
4516
4517
4524static void
4525check_link_down (void *cls)
4526{
4527 struct VirtualLink *vl = cls;
4528 struct DistanceVector *dv = vl->dv;
4529 struct Neighbour *n = vl->n;
4530 struct GNUNET_TIME_Absolute dvh_timeout;
4531 struct GNUNET_TIME_Absolute q_timeout;
4532
4534 "Checking if link is down\n");
4535 vl->visibility_task = NULL;
4536 dvh_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
4537 if (NULL != dv)
4538 {
4539 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4540 pos = pos->next_dv)
4541 dvh_timeout = GNUNET_TIME_absolute_max (dvh_timeout,
4542 pos->path_valid_until);
4543 if (0 == GNUNET_TIME_absolute_get_remaining (dvh_timeout).rel_value_us)
4544 {
4545 vl->dv->vl = NULL;
4546 vl->dv = NULL;
4547 }
4548 }
4549 q_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
4550 /* NOTE: @e n may be NULL here: #free_neighbour() clears vl->n and then
4551 schedules us when the link still has a DV route. */
4552 if (NULL != n)
4553 {
4554 struct GNUNET_TIME_Absolute liveness_deadline;
4555
4556 /* A successful validation is good for #ADDRESS_VALIDATION_LIFETIME (four
4557 hours). Do not take a communicator's word for that long: cap what the
4558 queues are worth by how recently this neighbour actually said anything
4559 to us. Otherwise a communicator that stops working without sending a
4560 QUEUE_TEARDOWN keeps this link -- and CORE's idea of the connection --
4561 alive until the validation expires. */
4562 liveness_deadline = GNUNET_TIME_absolute_add (n->last_inbound,
4564 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
4565 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
4566 if (GNUNET_TIME_absolute_cmp (liveness_deadline, <, q_timeout))
4567 {
4568 if (0 ==
4570 {
4571 /* Only reachable if a communicator failed to tear its queue down. */
4573 "Neighbour %s was silent for %s while its communicator "
4574 "kept claiming the queue works; treating link as down\n",
4575 GNUNET_i2s (&vl->target),
4578 GNUNET_YES));
4580 "# links dropped (neighbour silent)",
4581 1,
4582 GNUNET_NO);
4583 }
4584 q_timeout = liveness_deadline;
4585 }
4586 if (0 == GNUNET_TIME_absolute_get_remaining (q_timeout).rel_value_us)
4587 {
4588 vl->n->vl = NULL;
4589 vl->n = NULL;
4590 }
4591 }
4592 if ((NULL == vl->n) && (NULL == vl->dv))
4593 {
4595 /* @e n (if any) outlives the link, and so do its queues: the liveness cap
4596 above drops a link whose addresses are still well inside
4597 #ADDRESS_VALIDATION_LIFETIME. In that state nothing would ever ask for
4598 a fresh challenge -- @e revalidation_task does not fire until the four
4599 hour validity is nearly over, and the HELLO path reaches
4600 #start_address_validation() only to find an address that still counts
4601 as valid. Since #handle_validation_response() is the only thing that
4602 can rebuild this link and tell CORE about the peer again, ask for that
4603 validation now, or CORE never hears about this peer again. */
4604 if (NULL != n)
4605 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
4606 start_address_validation (&n->pid, q->address);
4607 return;
4608 }
4609 vl->visibility_task =
4610 GNUNET_SCHEDULER_add_at (GNUNET_TIME_absolute_max (q_timeout, dvh_timeout),
4612 vl);
4613}
4614
4615
4621static void
4622free_queue (struct Queue *queue)
4623{
4624 struct Neighbour *neighbour = queue->neighbour;
4625 struct TransportClient *tc = queue->tc;
4626 struct MonitorEvent me = { .cs = GNUNET_TRANSPORT_CS_DOWN,
4628 struct QueueEntry *qe;
4629 int maxxed;
4630 struct PendingAcknowledgement *pa;
4631 struct VirtualLink *vl;
4632
4634 "Cleaning up queue %u\n", queue->qid);
4635 if (NULL != queue->mo)
4636 {
4638 queue->mo = NULL;
4639 }
4640 if (NULL != queue->transmit_task)
4641 {
4642 GNUNET_SCHEDULER_cancel (queue->transmit_task);
4643 queue->transmit_task = NULL;
4644 }
4645 while (NULL != (pa = queue->pa_head))
4646 {
4647 GNUNET_CONTAINER_MDLL_remove (queue, queue->pa_head, queue->pa_tail, pa);
4648 pa->queue = NULL;
4649 }
4650
4652 neighbour->queue_head,
4653 neighbour->queue_tail,
4654 queue);
4656 tc->details.communicator.queue_head,
4657 tc->details.communicator.queue_tail,
4658 queue);
4660 tc->details.communicator.total_queue_length);
4662 "Cleaning up queue with length %u\n",
4663 queue->queue_length);
4664 while (NULL != (qe = queue->queue_head))
4665 {
4666 GNUNET_CONTAINER_DLL_remove (queue->queue_head, queue->queue_tail, qe);
4667 queue->queue_length--;
4668 tc->details.communicator.total_queue_length--;
4669 if (NULL != qe->pm)
4670 {
4671 GNUNET_assert (qe == qe->pm->qe);
4672 qe->pm->qe = NULL;
4673 }
4674 GNUNET_free (qe);
4675 }
4676 GNUNET_assert (0 == queue->queue_length);
4677 if ((maxxed) && (COMMUNICATOR_TOTAL_QUEUE_LIMIT >
4678 tc->details.communicator.total_queue_length))
4679 {
4680 /* Communicator dropped below threshold, resume all _other_ queues */
4682 GST_stats,
4683 "# Transmission throttled due to communicator queue limit",
4684 -1,
4685 GNUNET_NO);
4686 for (struct Queue *s = tc->details.communicator.queue_head; NULL != s;
4687 s = s->next_client)
4689 s,
4691 }
4692 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
4694
4695 vl = lookup_virtual_link (&neighbour->pid);
4696 if ((NULL != vl) && (neighbour == vl->n))
4697 {
4698 /* See #free_dv_route(): may be NULL under #check_link_down(), which is
4699 also what clears it -- so the call below needs no re-arm here. */
4700 if (NULL != vl->visibility_task)
4702 vl->visibility_task = NULL;
4703 check_link_down (vl);
4704 }
4705 if (NULL == neighbour->queue_head)
4706 {
4707 free_neighbour (neighbour, GNUNET_NO);
4708 }
4709}
4710
4711
4719static void
4721
4722
4728static void
4730{
4731 struct TransportClient *tc = ale->tc;
4732
4733 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
4734 tc->details.communicator.addr_tail,
4735 ale);
4736 /* Cancels @e sc, @e shc and the pending PILS signature request, all of
4737 which would otherwise run their callbacks on this freed entry. */
4739 if (NULL != ale->sc)
4740 {
4742 "store cancel\n");
4744 ale->sc = NULL;
4745 }
4746 if (NULL != ale->shc)
4747 {
4749 ale->shc = NULL;
4750 }
4751 if (NULL != ale->st)
4752 {
4754 ale->st = NULL;
4755 }
4756 if (NULL != ale->signed_address)
4758 GNUNET_free (ale);
4759}
4760
4761
4770static int
4771stop_peer_request (void *cls,
4772 const struct GNUNET_PeerIdentity *pid,
4773 void *value)
4774{
4775 struct TransportClient *tc = cls;
4776 struct PeerRequest *pr = value;
4777
4778 if (NULL != pr->retry_task)
4779 {
4780 GNUNET_SCHEDULER_cancel (pr->retry_task);
4781 pr->retry_task = NULL;
4782 }
4783 if (NULL != pr->nc)
4785 pr->nc = NULL;
4787 GNUNET_YES ==
4788 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
4789 pid,
4790 pr));
4791 GNUNET_free (pr);
4792
4793 return GNUNET_OK;
4794}
4795
4796
4797static void
4798do_shutdown (void *cls);
4799
4800
4810static enum GNUNET_GenericReturnValue
4811detach_cmcs_from_link (void *cls,
4812 const struct GNUNET_PeerIdentity *pid,
4813 void *value)
4814{
4815 const struct TransportClient *tc = cls;
4816 struct VirtualLink *vl = value;
4817
4818 (void) pid;
4819 for (struct CommunicatorMessageContext *cmc = vl->cmc_head;
4820 NULL != cmc;
4821 cmc = cmc->next)
4822 if (tc == cmc->tc)
4823 cmc->tc = NULL;
4824 return GNUNET_OK;
4825}
4826
4827
4837static enum GNUNET_GenericReturnValue
4839 const struct GNUNET_PeerIdentity *pid,
4840 void *value)
4841{
4842 const struct TransportClient *tc = cls;
4843 struct Backtalker *b = value;
4844
4845 (void) pid;
4846 if ((NULL != b->cmc) && (tc == b->cmc->tc))
4847 b->cmc->tc = NULL;
4848 return GNUNET_OK;
4849}
4850
4851
4870static void
4872{
4875 (void *) tc);
4878 (void *) tc);
4879 for (unsigned int i = 0; i < RING_BUFFER_SIZE; i++)
4880 if ((NULL != ring_buffer[i]) &&
4881 (tc == ring_buffer[i]->cmc->tc))
4882 ring_buffer[i]->cmc->tc = NULL;
4883}
4884
4885
4894static void
4895client_disconnect_cb (void *cls,
4896 struct GNUNET_SERVICE_Client *client,
4897 void *app_ctx)
4898{
4899 struct TransportClient *tc = app_ctx;
4900
4901 (void) cls;
4902 (void) client;
4904 switch (tc->type)
4905 {
4906 case CT_NONE:
4908 "Unknown Client %p disconnected, cleaning up.\n",
4909 tc);
4910 break;
4911
4912 case CT_CORE: {
4913 struct PendingMessage *pm;
4915 "CORE Client %p disconnected, cleaning up.\n",
4916 tc);
4917
4918
4919 while (NULL != (pm = tc->details.core.pending_msg_head))
4920 {
4922 tc->details.core.pending_msg_head,
4923 tc->details.core.pending_msg_tail,
4924 pm);
4925 pm->client = NULL;
4926 }
4927 }
4928 break;
4929
4930 case CT_MONITOR:
4932 "MONITOR Client %p disconnected, cleaning up.\n",
4933 tc);
4934
4935 break;
4936
4937 case CT_COMMUNICATOR: {
4938 struct Queue *q;
4939 struct AddressListEntry *ale;
4940
4942 "COMMUNICATOR Client %p disconnected, cleaning up.\n",
4943 tc);
4944
4945 /* MUST come first: freeing the queues below can tear a virtual link
4946 down, and #free_virtual_link() releases the cmcs parked on it. */
4948 if (NULL != tc->details.communicator.free_queue_entry_task)
4950 tc->details.communicator.free_queue_entry_task);
4951 while (NULL != (q = tc->details.communicator.queue_head))
4952 free_queue (q);
4953 while (NULL != (ale = tc->details.communicator.addr_head))
4955 GNUNET_free (tc->details.communicator.address_prefix);
4956 }
4957 break;
4958
4959 case CT_APPLICATION:
4961 "APPLICATION Client %p disconnected, cleaning up.\n",
4962 tc);
4963
4964 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
4966 tc);
4967 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
4968 break;
4969 }
4970 GNUNET_free (tc);
4971 if ((GNUNET_YES == in_shutdown) && (NULL == clients_head))
4972 {
4974 "Our last client disconnected\n");
4975 do_shutdown (cls);
4976 }
4977}
4978
4979
4989static int
4991 const struct GNUNET_PeerIdentity *pid,
4992 void *value)
4993{
4994 struct TransportClient *tc = cls;
4995 struct VirtualLink *vl = value;
4996
4997 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
4998 return GNUNET_OK;
4999
5001 "Telling new CORE client about existing connection to %s\n",
5002 GNUNET_i2s (pid));
5004 return GNUNET_OK;
5005}
5006
5007
5013static void
5015 unsigned
5016 int free_cmc);
5017
5018static enum GNUNET_GenericReturnValue
5019resume_communicators (void *cls,
5020 const struct GNUNET_PeerIdentity *pid,
5021 void *value)
5022{
5023 struct VirtualLink *vl = value;
5024 struct CommunicatorMessageContext *cmc;
5025
5026 /* resume communicators */
5027 while (NULL != (cmc = vl->cmc_tail))
5028 release_stalled_cmc (vl, cmc);
5029 if (NULL != vl->core_fc_stall_task)
5030 {
5032 vl->core_fc_stall_task = NULL;
5033 }
5034 /* A CORE client that just attached has nothing outstanding, so give it a
5035 full window. The RECV_OKs that would have returned the credit spent by
5036 its predecessor died with that client, and #handle_client_recv_ok() is
5037 the only thing that ever raises this counter -- so without the reset
5038 every message on this link takes the "CORE ran out of window" path from
5039 here on, and only #core_fc_stalled() (after CORE_FC_STALL_TIMEOUT, and
5040 once per round) ever lets any through. */
5042 return GNUNET_OK;
5043}
5044
5045
5054static void
5055handle_client_start (void *cls, const struct StartMessage *start)
5056{
5057 // const struct GNUNET_PeerIdentity *my_identity;
5058 struct TransportClient *tc = cls;
5059 // uint32_t options;
5060 //
5061 // my_identity = GNUNET_PILS_get_identity (pils);
5062 // GNUNET_assert (my_identity);
5063 //
5064 // FIXME ignore the check of the peer ids for now.
5065 // (also deprecate the old way of obtaining our own peer ID)
5066 // options = ntohl (start->options);
5067 // if ((0 != (1 & options)) &&
5068 // (0 != GNUNET_memcmp (&start->self, my_identity)))
5069 // {
5070 // /* client thinks this is a different peer, reject */
5071 // GNUNET_break (0);
5072 // GNUNET_SERVICE_client_drop (tc->client);
5073 // return;
5074 // }
5075 if (CT_NONE != tc->type)
5076 {
5077 GNUNET_break (0);
5079 return;
5080 }
5081 tc->type = CT_CORE;
5083 "New CORE client with PID %s registered\n",
5084 GNUNET_i2s (&start->self));
5087 tc);
5090 NULL);
5092}
5093
5094
5101static int
5102check_client_send (void *cls, const struct OutboundMessage *obm)
5103{
5104 struct TransportClient *tc = cls;
5105 uint16_t size;
5106 const struct GNUNET_MessageHeader *obmm;
5107
5108 if (CT_CORE != tc->type)
5109 {
5110 GNUNET_break (0);
5111 return GNUNET_SYSERR;
5112 }
5113 size = ntohs (obm->header.size) - sizeof(struct OutboundMessage);
5114 if (size < sizeof(struct GNUNET_MessageHeader))
5115 {
5116 GNUNET_break (0);
5117 return GNUNET_SYSERR;
5118 }
5119 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5120 if (size != ntohs (obmm->size))
5121 {
5122 GNUNET_break (0);
5123 return GNUNET_SYSERR;
5124 }
5125 return GNUNET_OK;
5126}
5127
5128
5136static void
5138{
5139 struct TransportClient *tc = pm->client;
5140 struct VirtualLink *vl = pm->vl;
5141
5143 "client send response\n");
5144 if (NULL != tc)
5145 {
5147 "Confirming transmission of <%" PRIu64 "> to %s\n",
5148 pm->logging_uuid,
5149 GNUNET_i2s (&vl->target));
5150 credit_client (pm);
5151 }
5153}
5154
5155
5165static unsigned int
5168 struct DistanceVectorHop **hops_array,
5169 unsigned int hops_array_length)
5170{
5171 uint64_t choices[hops_array_length];
5172 uint64_t num_dv;
5173 unsigned int dv_count;
5174
5175 /* Pick random vectors, but weighted by distance, giving more weight
5176 to shorter vectors */
5177 num_dv = 0;
5178 dv_count = 0;
5179 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5180 pos = pos->next_dv)
5181 {
5182 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
5183 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
5184 .rel_value_us == 0))
5185 continue; /* pos unconfirmed and confirmed required */
5186 /* A hop at (or past) the limit has weight zero -- past it, unsigned
5187 arithmetic makes the weight huge. Either way it can never be picked
5188 below, so it must not be counted: the sampling loop draws
5189 @a hops_array_length distinct values out of @e num_dv, and counting a
5190 hop that contributes nothing to @e num_dv can leave it with fewer
5191 values than draws, which never terminates. #learn_dv_path() caps
5192 @e distance well below the limit today, so this is defence in depth. */
5193 if (pos->distance >= MAX_DV_HOPS_ALLOWED)
5194 continue;
5195 num_dv += MAX_DV_HOPS_ALLOWED - pos->distance;
5196 dv_count++;
5197 }
5198 if (0 == dv_count)
5199 return 0;
5200 if (dv_count <= hops_array_length)
5201 {
5202 dv_count = 0;
5203 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5204 pos = pos->next_dv)
5205 hops_array[dv_count++] = pos;
5206 return dv_count;
5207 }
5208 for (unsigned int i = 0; i < hops_array_length; i++)
5209 {
5210 int ok = GNUNET_NO;
5211 unsigned int tries = 0;
5212
5213 while (GNUNET_NO == ok)
5214 {
5215 choices[i] =
5216 GNUNET_CRYPTO_random_u64 (num_dv);
5217 ok = GNUNET_YES;
5218 for (unsigned int j = 0; j < i; j++)
5219 if (choices[i] == choices[j])
5220 {
5221 ok = GNUNET_NO;
5222 break;
5223 }
5224 /* Give up rather than spin: with weight >= 2 per hop the expected
5225 number of draws per pick is below four, so this many failures is a
5226 set we cannot sample distinctly. Returning fewer paths is a routing
5227 nuisance, hanging here is a deaf service; and a duplicated choice
5228 would at worst repeat a path, so stopping is safe. */
5229 if (MAX_DV_PICK_TRIES < ++tries)
5230 break;
5231 }
5232 if (GNUNET_NO == ok)
5233 {
5234 hops_array_length = i;
5235 break;
5236 }
5237 }
5238 dv_count = 0;
5239 num_dv = 0;
5240 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5241 pos = pos->next_dv)
5242 {
5243 uint64_t delta;
5244
5245 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
5246 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
5247 .rel_value_us == 0))
5248 continue; /* pos unconfirmed and confirmed required */
5249 if (pos->distance >= MAX_DV_HOPS_ALLOWED)
5250 continue; /* zero weight: not counted in @e num_dv above either */
5251 delta = MAX_DV_HOPS_ALLOWED - pos->distance;
5252 for (unsigned int i = 0; i < hops_array_length; i++)
5253 if ((num_dv <= choices[i]) && (num_dv + delta > choices[i]))
5254 hops_array[dv_count++] = pos;
5255 num_dv += delta;
5256 }
5257 return dv_count;
5258}
5259
5260
5267static int
5269 void *cls,
5271{
5272 struct TransportClient *tc = cls;
5273 uint16_t size;
5274
5275 if (CT_NONE != tc->type)
5276 {
5277 GNUNET_break (0);
5278 return GNUNET_SYSERR;
5279 }
5280 tc->type = CT_COMMUNICATOR;
5281 size = ntohs (cam->header.size) - sizeof(*cam);
5282 if (0 == size)
5283 return GNUNET_OK; /* receive-only communicator */
5285 return GNUNET_OK;
5286}
5287
5288
5300static void
5302{
5303 struct GNUNET_MQ_Envelope *env;
5305
5306 if (GNUNET_YES == cmc->ack_sent)
5307 return;
5308 cmc->ack_sent = GNUNET_YES;
5309 if (NULL == cmc->tc)
5310 return; /* communicator is gone, see #detach_cmcs_from_client() */
5311 if (0 == ntohl (cmc->im.fc_on))
5312 return; /* communicator did not ask for flow control */
5314 "Acknowledge message with flow control id %" PRIu64 "\n",
5315 cmc->im.fc_id);
5317 ack->reserved = htonl (0);
5318 ack->fc_id = cmc->im.fc_id;
5319 ack->sender = cmc->im.neighbour_sender;
5320 GNUNET_MQ_send (cmc->tc->mq, env);
5321}
5322
5323
5334static void
5336{
5337 if (GNUNET_YES == cmc->client_resumed)
5338 return;
5340 if (NULL == cmc->tc)
5341 return; /* communicator is gone, see #detach_cmcs_from_client() */
5343}
5344
5345
5354static void
5356 unsigned
5357 int free_cmc)
5358{
5359 send_cmc_ack (cmc);
5360 resume_cmc_client (cmc);
5361 if (GNUNET_YES == free_cmc)
5362 {
5363 GNUNET_free (cmc);
5364 }
5365}
5366
5367
5368static void
5370 struct CommunicatorMessageContext *cmc)
5371{
5373 GNUNET_assert (0 < vl->cmc_count);
5374 vl->cmc_count--;
5376}
5377
5378
5379static void
5381{
5383}
5384
5385
5395static void
5396handle_client_recv_ok (void *cls, const struct RecvOkMessage *rom)
5397{
5398 struct TransportClient *tc = cls;
5399 struct VirtualLink *vl;
5400 uint32_t delta;
5401 struct CommunicatorMessageContext *cmc;
5402
5403 if (CT_CORE != tc->type)
5404 {
5405 GNUNET_break (0);
5407 return;
5408 }
5409 vl = lookup_virtual_link (&rom->peer);
5410 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
5411 {
5413 "# RECV_OK dropped: virtual link unknown",
5414 1,
5415 GNUNET_NO);
5417 return;
5418 }
5419 delta = ntohl (rom->increase_window_delta);
5420 vl->core_recv_window += delta;
5422 "CORE ack receiving message, increased CORE recv window to %d\n",
5423 vl->core_recv_window);
5425 if (vl->core_recv_window <= 0)
5426 return;
5427 /* release the flow control credit we withheld from the communicators */
5428 while (NULL != (cmc = vl->cmc_tail))
5429 release_stalled_cmc (vl, cmc);
5430 if (NULL != vl->core_fc_stall_task)
5431 {
5433 vl->core_fc_stall_task = NULL;
5434 }
5435}
5436
5437
5444static void
5446 void *cls,
5448{
5449 const struct GNUNET_PeerIdentity *my_identity;
5450 struct TransportClient *tc = cls;
5451 uint16_t size;
5452
5453 size = ntohs (cam->header.size) - sizeof(*cam);
5454 if (0 == size)
5455 {
5457 "Receive-only communicator connected\n");
5458 /* Receive-only communicator: it has no address prefix, but we still
5459 MUST resume the client or we will never read from it again. Use an
5460 empty prefix so that the various strcmp()s do not see NULL. */
5461 tc->details.communicator.address_prefix = GNUNET_strdup ("");
5463 return;
5464 }
5465 tc->details.communicator.address_prefix =
5466 GNUNET_strdup ((const char *) &cam[1]);
5467 tc->details.communicator.cc = ntohl (cam->cc);
5468 tc->details.communicator.can_burst = ntohl (cam->can_burst);
5470 if (NULL != my_identity)
5471 {
5473 "Communicator for peer %s with prefix '%s' connected %s\n",
5475 tc->details.communicator.address_prefix,
5476 tc->details.communicator.can_burst ? "can burst" :
5477 "can not burst");
5478 }
5479 else
5480 {
5482 "Communicator for local peer with prefix '%s' connected %s\n",
5483 tc->details.communicator.address_prefix,
5484 tc->details.communicator.can_burst ? "can burst" :
5485 "can not burst");
5486 }
5488}
5489
5490
5498static int
5500 void *cls,
5502{
5503 const struct GNUNET_MessageHeader *inbox;
5504 const char *is;
5505 uint16_t msize;
5506 uint16_t isize;
5507
5508 (void) cls;
5509 msize = ntohs (cb->header.size) - sizeof(*cb);
5510 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
5511 /* MUST bound the buffer before dereferencing @a inbox. */
5512 if (msize <= sizeof(struct GNUNET_MessageHeader))
5513 {
5514 GNUNET_break (0);
5515 return GNUNET_SYSERR;
5516 }
5517 isize = ntohs (inbox->size);
5518 if (isize >= msize)
5519 {
5520 GNUNET_break (0);
5521 return GNUNET_SYSERR;
5522 }
5523 is = (const char *) inbox;
5524 is += isize;
5525 msize -= isize;
5526 GNUNET_assert (0 < msize);
5527 if ('\0' != is[msize - 1])
5528 {
5529 GNUNET_break (0);
5530 return GNUNET_SYSERR;
5531 }
5532 return GNUNET_OK;
5533}
5534
5535
5550static enum GNUNET_GenericReturnValue
5551sign_ephemeral (struct DistanceVector *dv)
5552{
5553 struct EphemeralConfirmationPS ec;
5554
5556 dv->ephemeral_validity =
5558 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
5559 ec.target = dv->target;
5560 ec.ephemeral_key = dv->ephemeral_key;
5561 ec.sender_monotonic_time = GNUNET_TIME_absolute_hton (dv->monotime);
5562 ec.purpose.size = htonl (sizeof(ec));
5563 return sign_by_my_identity (&ec.purpose, &dv->sender_sig);
5564}
5565
5566
5567static void
5569 struct TransportClient *tc);
5570
5571
5572static void
5573free_timedout_queue_entry (void *cls)
5574{
5575 struct TransportClient *tc = cls;
5577
5579 "freeing timedout queue entries\n");
5580
5581 tc->details.communicator.free_queue_entry_task = NULL;
5582 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
5583 queue = queue->next_client)
5584 {
5585 struct QueueEntry *qep = queue->queue_head;
5586
5588 "checking QID %u for timedout queue entries\n",
5589 queue->qid);
5590 while (NULL != qep)
5591 {
5592 struct QueueEntry *pos = qep;
5594 pos->creation_timestamp, now);
5595 qep = qep->next;
5596
5598 "diff to now %s \n",
5601 {
5603 "Freeing timed out QueueEntry with MID %" PRIu64
5604 " and QID %u\n",
5605 pos->mid,
5606 queue->qid);
5608 "# QueueEntries timed out",
5609 1,
5610 GNUNET_NO);
5611 free_queue_entry (pos, tc);
5612 }
5613 }
5614 }
5615 /* Entries younger than #QUEUE_ENTRY_TIMEOUT are still to be reclaimed, and
5616 this task used to be a one-shot armed only by #queue_send_msg(). So the
5617 sweep that was supposed to bound how long an unacknowledged entry holds
5618 its slot only ever ran while *new* messages were being queued -- exactly
5619 not the case once the throttles in #schedule_transmit_on_queue() have
5620 stopped transmission. Keep going as long as anything is outstanding. */
5622}
5623
5624
5625static void
5627{
5628 if (NULL != tc->details.communicator.free_queue_entry_task)
5629 return;
5630 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
5631 queue = queue->next_client)
5632 {
5633 if (NULL == queue->queue_head)
5634 continue;
5635 tc->details.communicator.free_queue_entry_task =
5638 tc);
5639 return;
5640 }
5641}
5642
5643
5653static void
5654queue_send_msg (struct Queue *queue,
5655 struct PendingMessage *pm,
5656 const void *payload,
5657 size_t payload_size)
5658{
5659 struct Neighbour *n = queue->neighbour;
5661 struct GNUNET_MQ_Envelope *env;
5662 struct PendingAcknowledgement *pa;
5663
5664 GNUNET_log (
5666 "Queueing %u bytes of payload for transmission <%" PRIu64
5667 "> on queue %llu to %s\n",
5668 (unsigned int) payload_size,
5669 (NULL == pm) ? 0 : pm->logging_uuid,
5670 (unsigned long long) queue->qid,
5671 GNUNET_i2s (&queue->neighbour->pid));
5672 env = GNUNET_MQ_msg_extra (smt,
5673 payload_size,
5675 smt->qid = htonl (queue->qid);
5676 smt->mid = GNUNET_htonll (queue->mid_gen);
5677 smt->receiver = n->pid;
5678 memcpy (&smt[1], payload, payload_size);
5679 {
5680 /* Pass the env to the communicator of queue for transmission. */
5681 struct QueueEntry *qe;
5682
5683 qe = GNUNET_new (struct QueueEntry);
5684 qe->creation_timestamp = GNUNET_TIME_absolute_get ();
5685 qe->mid = queue->mid_gen;
5687 "Create QueueEntry with MID %" PRIu64
5688 " and QID %u and prefix %s\n",
5689 qe->mid,
5690 queue->qid,
5691 queue->tc->details.communicator.address_prefix);
5692 queue->mid_gen++;
5693 qe->queue = queue;
5694 if (NULL != pm)
5695 {
5696 qe->pm = pm;
5697 // TODO Why do we have a retransmission. When we know, make decision if we still want this.
5698 // GNUNET_assert (NULL == pm->qe);
5699 if (NULL != pm->qe)
5700 {
5702 "Retransmitting message <%" PRIu64
5703 "> remove pm from qe with MID: %llu \n",
5705 (unsigned long long) pm->qe->mid);
5706 pm->qe->pm = NULL;
5707 }
5708 pm->qe = qe;
5709 }
5710 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
5711 if (0 == queue->q_capacity)
5712 {
5713 // Messages without FC or fragments can get here.
5714 if (NULL != pm)
5715 {
5717 "Message %" PRIu64
5718 " (pm type %u) was not send because queue has no capacity.\n",
5720 pm->pmt);
5721 pm->qe = NULL;
5722 }
5723 GNUNET_free (env);
5724 GNUNET_free (qe);
5725 return;
5726 }
5727 GNUNET_CONTAINER_DLL_insert (queue->queue_head, queue->queue_tail, qe);
5728 queue->queue_length++;
5729 queue->tc->details.communicator.total_queue_length++;
5730 if (GNUNET_NO == queue->unlimited_length)
5731 queue->q_capacity--;
5733 "Queue %s with qid %u has capacity %" PRIu64 "\n",
5734 queue->address,
5735 queue->qid,
5736 queue->q_capacity);
5738 queue->tc->details.communicator.total_queue_length)
5739 queue->idle = GNUNET_NO;
5740 if (QUEUE_LENGTH_LIMIT == queue->queue_length)
5741 queue->idle = GNUNET_NO;
5742 if (0 == queue->q_capacity)
5743 queue->idle = GNUNET_NO;
5744
5745 if (GNUNET_NO == queue->idle)
5747 if (NULL != pm)
5748 {
5749 /* NOTE: @e next_pa was never the link of this list -- nothing ever
5750 assigned it, so it was NULL on every entry. The MDLL that
5751 #prepare_pending_acknowledgement() inserts into is keyed `pm', and
5752 thus threaded through @e next_pm. Walking @e next_pa dereferenced
5753 NULL the moment the head was not the entry we wanted. */
5754 for (pa = pm->pa_head; NULL != pa; pa = pa->next_pm)
5755 if (pm == pa->pm)
5756 {
5757 pa->num_send++;
5758 break;
5759 }
5760 }
5761 // GNUNET_CONTAINER_multiuuidmap_get (pending_acks, &ack[i].ack_uuid.value);
5763 "Sending message MID %" PRIu64
5764 " of type %u (%u) and size %lu with MQ %p queue %s (QID %u) pending %"
5765 PRIu64 "\n",
5766 GNUNET_ntohll (smt->mid),
5767 ntohs (((const struct GNUNET_MessageHeader *) payload)->type),
5768 ntohs (smt->header.size),
5769 (unsigned long) payload_size,
5770 queue->tc->mq,
5771 queue->address,
5772 queue->qid,
5773 (NULL == pm) ? 0 : pm->logging_uuid);
5774 GNUNET_MQ_send (queue->tc->mq, env);
5775 }
5776}
5777
5778
5789static struct GNUNET_TIME_Relative
5790route_via_neighbour (const struct Neighbour *n,
5791 const struct GNUNET_MessageHeader *hdr,
5793{
5794 struct GNUNET_TIME_Absolute now;
5795 unsigned int candidates;
5796 unsigned int sel1;
5797 unsigned int sel2;
5798 struct GNUNET_TIME_Relative rtt;
5799
5800 /* Pick one or two 'random' queues from n (under constraints of options) */
5801 now = GNUNET_TIME_absolute_get ();
5802 /* FIXME-OPTIMIZE: give queues 'weights' and pick proportional to
5803 weight in the future; weight could be assigned by observed
5804 bandwidth (note: not sure if we should do this for this type
5805 of control traffic though). */
5806 candidates = 0;
5807 for (struct Queue *pos = n->queue_head; NULL != pos;
5808 pos = pos->next_neighbour)
5809 {
5810 if ((0 != (options & RMO_UNCONFIRMED_ALLOWED)) ||
5811 (pos->validated_until.abs_value_us > now.abs_value_us))
5812 candidates++;
5813 }
5814 if (0 == candidates)
5815 {
5816 /* This can happen rarely if the last confirmed queue timed
5817 out just as we were beginning to process this message. */
5819 "Could not route message of type %u to %s: no valid queue\n",
5820 ntohs (hdr->type),
5821 GNUNET_i2s (&n->pid));
5823 "# route selection failed (all no valid queue)",
5824 1,
5825 GNUNET_NO);
5827 }
5828
5830 sel1 = GNUNET_CRYPTO_random_u32 (candidates);
5831 if (0 == (options & RMO_REDUNDANT))
5832 sel2 = candidates; /* picks none! */
5833 else
5834 sel2 = GNUNET_CRYPTO_random_u32 (candidates);
5835 candidates = 0;
5836 for (struct Queue *pos = n->queue_head; NULL != pos;
5837 pos = pos->next_neighbour)
5838 {
5839 if ((0 != (options & RMO_UNCONFIRMED_ALLOWED)) ||
5840 (pos->validated_until.abs_value_us > now.abs_value_us))
5841 {
5842 if ((sel1 == candidates) || (sel2 == candidates))
5843 {
5845 "Routing message of type %u to %s using %s (#%u)\n",
5846 ntohs (hdr->type),
5847 GNUNET_i2s (&n->pid),
5848 pos->address,
5849 (sel1 == candidates) ? 1 : 2);
5850 rtt = GNUNET_TIME_relative_min (rtt, pos->pd.aged_rtt);
5851 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
5852 }
5853 candidates++;
5854 }
5855 }
5856 return rtt;
5857}
5858
5859
5870typedef void (*DVMessageHandler) (void *cls,
5871 struct Neighbour *next_hop,
5872 const struct GNUNET_MessageHeader *hdr,
5874
5889static struct GNUNET_TIME_Relative
5891 unsigned int num_dvhs,
5892 struct DistanceVectorHop **dvhs,
5893 const struct GNUNET_MessageHeader *hdr,
5894 DVMessageHandler use,
5895 void *use_cls,
5897 enum GNUNET_GenericReturnValue without_fc)
5898{
5899 const struct GNUNET_PeerIdentity *my_identity;
5900 struct TransportDVBoxMessage box_hdr;
5901 struct TransportDVBoxPayloadP *payload_hdr;
5902 uint16_t body_len_hbo = ntohs (hdr->size);
5903 unsigned char pt[sizeof(struct TransportDVBoxPayloadP) + body_len_hbo]
5905 unsigned char ct[sizeof(struct TransportDVBoxPayloadP) + body_len_hbo]
5907 struct GNUNET_TIME_Relative rtt;
5909
5910 payload_hdr = (struct TransportDVBoxPayloadP*) pt;
5913
5914 /* Encrypt payload */
5915 memset (&box_hdr, 0, sizeof (box_hdr));
5916 box_hdr.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
5917 box_hdr.total_hops = htons (0);
5918 box_hdr.without_fc = htonl (without_fc);
5919 // update_ephemeral (dv);
5920 if ((0 ==
5921 GNUNET_TIME_absolute_get_remaining (dv->ephemeral_validity).rel_value_us)
5922 || (NULL == dv->km))
5923 {
5924 GNUNET_CRYPTO_eddsa_kem_encaps (&dv->target.public_key,
5925 &dv->ephemeral_key,
5926 (struct GNUNET_ShortHashCode*) &km);
5927 GNUNET_free (dv->km); /* do not leak the previous key material */
5928 dv->km = GNUNET_new (struct GNUNET_ShortHashCode);
5929 GNUNET_memcpy (dv->km, &km, sizeof(struct GNUNET_ShortHashCode));
5930 if (GNUNET_OK != sign_ephemeral (dv))
5931 {
5932 /* Without a matching signature the box is undecryptable noise to the
5933 receiver; do not spend the bandwidth. Expire the ephemeral so the
5934 next attempt re-derives and re-signs rather than reusing it. */
5935 dv->ephemeral_validity = GNUNET_TIME_UNIT_ZERO_ABS;
5937 }
5938 }
5939 else
5940 {
5941 /* The ephemeral key is still valid, so reuse the cached key material.
5942 Without this @a km stayed UNINITIALISED stack memory and the
5943 receiver could not decrypt the box. */
5944 GNUNET_memcpy (&km, dv->km, sizeof(struct GNUNET_ShortHashCode));
5945 }
5946 box_hdr.ephemeral_key = dv->ephemeral_key;
5947 payload_hdr->sender_sig = dv->sender_sig;
5948 memcpy (&payload_hdr[1], hdr, body_len_hbo);
5949 GNUNET_CRYPTO_random_block (&box_hdr.iv,
5950 sizeof(box_hdr.iv));
5951 payload_hdr->sender = *my_identity;
5952 payload_hdr->monotonic_time = GNUNET_TIME_absolute_hton (dv->monotime);
5953 GNUNET_CRYPTO_aead_encrypt (sizeof pt,
5954 pt,
5955 0,
5956 NULL,
5957 &km,
5958 &box_hdr.iv,
5959 ct,
5960 &box_hdr.mac);
5962 /* For each selected path, take the pre-computed header and body
5963 and add the path in the middle of the message; then send it. */
5964 for (unsigned int i = 0; i < num_dvhs; i++)
5965 {
5966 struct DistanceVectorHop *dvh = dvhs[i];
5967 unsigned int num_hops = dvh->distance + 1;
5968 char buf[sizeof(struct TransportDVBoxMessage)
5969 + sizeof(struct GNUNET_PeerIdentity) * num_hops
5970 + sizeof(struct TransportDVBoxPayloadP)
5971 + body_len_hbo] GNUNET_ALIGN;
5972 struct GNUNET_PeerIdentity *dhops;
5973
5974 box_hdr.header.size = htons (sizeof(buf));
5975 box_hdr.orig_size = htons (sizeof(buf));
5976 box_hdr.num_hops = htons (num_hops);
5977 memcpy (buf, &box_hdr, sizeof(box_hdr));
5978 dhops = (struct GNUNET_PeerIdentity *) &buf[sizeof(box_hdr)];
5979 memcpy (dhops,
5980 dvh->path,
5981 dvh->distance * sizeof(struct GNUNET_PeerIdentity));
5982 dhops[dvh->distance] = dv->target;
5983 if (GNUNET_EXTRA_LOGGING > 0)
5984 {
5985 char *path;
5986
5988 for (unsigned int j = 0; j < num_hops; j++)
5989 {
5990 char *tmp;
5991
5992 GNUNET_asprintf (&tmp, "%s-%s", path, GNUNET_i2s (&dhops[j]));
5993 GNUNET_free (path);
5994 path = tmp;
5995 }
5997 "Routing message of type %u to %s using DV (#%u/%u) via %s\n",
5998 ntohs (hdr->type),
5999 GNUNET_i2s (&dv->target),
6000 i + 1,
6001 num_dvhs,
6002 path);
6003 GNUNET_free (path);
6004 }
6005 rtt = GNUNET_TIME_relative_min (rtt, dvh->pd.aged_rtt);
6006 memcpy (&dhops[num_hops], ct, sizeof(ct));
6007 use (use_cls,
6008 dvh->next_hop,
6009 (const struct GNUNET_MessageHeader *) buf,
6010 options);
6011 }
6012 return rtt;
6013}
6014
6015
6025static void
6026send_dv_to_neighbour (void *cls,
6027 struct Neighbour *next_hop,
6028 const struct GNUNET_MessageHeader *hdr,
6030{
6031 (void) cls;
6032 (void) route_via_neighbour (next_hop, hdr, RMO_UNCONFIRMED_ALLOWED);
6033}
6034
6035
6047static struct GNUNET_TIME_Relative
6049// route_control_message_without_fc (const struct GNUNET_PeerIdentity *target,
6050 const struct GNUNET_MessageHeader *hdr,
6052{
6053 // struct VirtualLink *vl;
6054 struct Neighbour *n;
6055 struct DistanceVector *dv;
6056 struct GNUNET_TIME_Relative rtt1;
6057 struct GNUNET_TIME_Relative rtt2;
6058 const struct GNUNET_PeerIdentity *target = &vl->target;
6059
6061 "Trying to route message of type %u to %s without fc\n",
6062 ntohs (hdr->type),
6063 GNUNET_i2s (target));
6064
6065 // TODO Do this elsewhere. vl should be given as parameter to method.
6066 // vl = lookup_virtual_link (target);
6067 /* An unconfirmed link is allowed here: it has no @e n and no @e dv of its
6068 own, so the "confirmed required" branch below resolves the route from
6069 #neighbours / #dv_routes. Refusing to route at all is what deadlocks a
6070 pair of peers, see #consider_sending_fc(). */
6071 GNUNET_assert (NULL != vl);
6072 n = vl->n;
6073 dv = (0 != (options & RMO_DV_ALLOWED)) ? vl->dv : NULL;
6074 /* An unconfirmed link has neither @e n nor @e dv of its own, so resolve
6075 the route from #neighbours / #dv_routes. This used to be done only
6076 while #RMO_UNCONFIRMED_ALLOWED was *not* set -- exactly backwards: with
6077 the flag set (the caller that needs it most) we would find no route at
6078 all and drop the message. Whether an unvalidated queue or an
6079 unvalidated path may then be used is still decided by @a options, in
6080 #route_via_neighbour() and #pick_random_dv_hops(). */
6081 if (NULL == n)
6082 n = lookup_neighbour (target);
6083 if ((NULL == dv) && (0 != (options & RMO_DV_ALLOWED)))
6085 if ((NULL == n) && (NULL == dv))
6086 {
6088 "Cannot route message of type %u to %s: no route\n",
6089 ntohs (hdr->type),
6090 GNUNET_i2s (target));
6092 "# Messages dropped in routing: no acceptable method",
6093 1,
6094 GNUNET_NO);
6096 }
6098 "Routing message of type %u to %s with options %X\n",
6099 ntohs (hdr->type),
6100 GNUNET_i2s (target),
6101 (unsigned int) options);
6102 /* If both dv and n are possible and we must choose:
6103 flip a coin for the choice between the two; for now 50/50 */
6104 if ((NULL != n) && (NULL != dv) && (0 == (options & RMO_REDUNDANT)))
6105 {
6106 if (0 == GNUNET_CRYPTO_random_u32 (2))
6107 n = NULL;
6108 else
6109 dv = NULL;
6110 }
6111 if ((NULL != n) && (NULL != dv))
6112 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
6113 enough for redundancy, so clear the flag. */
6116 if (NULL != n)
6117 {
6119 "Try to route message of type %u to %s without fc via neighbour\n",
6120 ntohs (hdr->type),
6121 GNUNET_i2s (target));
6122 rtt1 = route_via_neighbour (n, hdr, options);
6123 }
6124 if (NULL != dv)
6125 {
6126 struct DistanceVectorHop *hops[2];
6127 unsigned int res;
6128
6130 options,
6131 hops,
6132 (0 == (options & RMO_REDUNDANT)) ? 1 : 2);
6133 if (0 == res)
6134 {
6136 "Failed to route message, could not determine DV path\n");
6137 return rtt1;
6138 }
6140 "encapsulate_for_dv 1\n");
6141 rtt2 = encapsulate_for_dv (dv,
6142 res,
6143 hops,
6144 hdr,
6146 NULL,
6148 GNUNET_YES);
6149 }
6150 return GNUNET_TIME_relative_min (rtt1, rtt2);
6151}
6152
6153
6154static void
6155consider_sending_fc (void *cls);
6156
6163static void
6164task_consider_sending_fc (void *cls)
6165{
6166 struct VirtualLink *vl = cls;
6167 vl->fc_retransmit_task = NULL;
6168 consider_sending_fc (cls);
6169}
6170
6171
6172static char *
6173get_address_without_port (const char *address);
6174
6175
6177{
6178 size_t off;
6179
6185 size_t size;
6186
6187 char *tgnas;
6188};
6189
6190
6191static enum GNUNET_GenericReturnValue
6192add_global_addresses (void *cls,
6193 const struct GNUNET_PeerIdentity *pid,
6194 void *value)
6195{
6196 struct AddGlobalAddressesContext *ctx = cls;
6197 struct TransportGlobalNattedAddress *tgna = value;
6198 char *addr = (char *) &tgna[1];
6199 size_t alen = ntohl (tgna->address_length);
6200 size_t need = sizeof (struct TransportGlobalNattedAddress) + alen;
6201
6202 /* NOTE: the address is NOT 0-terminated, it must be printed with an
6203 explicit precision. */
6205 "sending address %.*s length %lu\n",
6206 (int) alen,
6207 addr,
6208 (unsigned long) alen);
6209 if (ctx->off + need > ctx->size)
6210 {
6211 GNUNET_break (0);
6212 return GNUNET_NO;
6213 }
6214 GNUNET_memcpy (&(ctx->tgnas[ctx->off]), tgna, need);
6215 ctx->off += need;
6216
6217 return GNUNET_OK;
6218}
6219
6220
6221static struct GNUNET_TIME_Relative
6222calculate_rtt (struct DistanceVector *dv);
6223
6224
6231static void
6232consider_sending_fc (void *cls)
6233{
6234 struct VirtualLink *vl = cls;
6235 struct GNUNET_TIME_Absolute monotime;
6236 struct TransportFlowControlMessage *fc;
6238 struct GNUNET_TIME_Relative rtt;
6239 struct GNUNET_TIME_Relative rtt_average;
6240 struct Neighbour *n = vl->n;
6241 size_t addresses_size;
6242
6243 /* Most of our callers are not the retransmit task but inbound events:
6244 handle_flow_control() ends in check_vl_transmission(), which calls us
6245 once per flow-control-stalled message, and the peer's answer to what we
6246 send here arrives as another handle_flow_control(). On a link whose
6247 head message does not fit the window that is a ping-pong with nothing
6248 to damp it -- the backoff and the MIN_FC_RETRANSMIT_DELAY floor at the
6249 bottom of this function only ever governed @e fc_retransmit_task, which
6250 these callers bypass. If the chain is armed and we just sent one, let
6251 the task do it. */
6252 if ((NULL != vl->fc_retransmit_task) &&
6254 < MIN_FC_RETRANSMIT_DELAY.rel_value_us))
6255 {
6257 "Not sending FC to %s: one went out less than %s ago\n",
6258 GNUNET_i2s (&vl->target),
6261 GNUNET_YES));
6262 return;
6263 }
6264 if ((GNUNET_YES != vl->confirmed) &&
6265 (NULL == lookup_neighbour (&vl->target)) &&
6267 {
6268 /* Unconfirmed AND no way to reach the peer at all -- nothing to send on.
6269 An unconfirmed link that *does* have a route must still answer,
6270 see below.
6271
6272 Do NOT just return: #task_consider_sending_fc() cleared
6273 @e fc_retransmit_task before calling us, and the only other place that
6274 arms it is #handle_flow_control() -- which only does so when it is
6275 already non-NULL. Leaving without re-arming therefore ends the
6276 keepalive chain for this link permanently, and #check_link_down()
6277 tears it down #NEIGHBOUR_LIVENESS_TIMEOUT later. */
6279 "Not sending FC to %s: link unconfirmed and no route\n",
6280 GNUNET_i2s (&vl->target));
6281 if (NULL == vl->fc_retransmit_task)
6285 vl);
6286 return;
6287 }
6288 addresses_size = 0;
6289 if (NULL != n && 0 < n->number_of_addresses)
6290 {
6291 addresses_size =
6292 n->number_of_addresses * sizeof (struct TransportGlobalNattedAddress) + n
6293 ->size_of_global_addresses;
6294 if (addresses_size >
6295 UINT16_MAX - sizeof (struct TransportFlowControlMessage))
6296 {
6297 /* htons() below would silently truncate `header.size', leaving a
6298 message whose declared length does not match its contents. */
6299 GNUNET_break (0);
6300 addresses_size = 0;
6301 }
6302 }
6303 if (0 != addresses_size)
6304 {
6305 char *tgnas = GNUNET_malloc (addresses_size);
6307 ctx.off = 0;
6308 ctx.size = addresses_size;
6309 ctx.tgnas = tgnas;
6310
6312 + addresses_size);
6313 fc->header.size = htons (sizeof(struct TransportFlowControlMessage)
6314 + addresses_size);
6315 fc->size_of_addresses = htonl ((uint32_t) n->size_of_global_addresses);
6316 fc->number_of_addresses = htonl (n->number_of_addresses);
6319 &ctx);
6322 }
6323 else
6324 {
6325 fc = GNUNET_malloc (sizeof (struct TransportFlowControlMessage));
6326 fc->header.size = htons (sizeof(struct TransportFlowControlMessage));
6327 }
6328
6330 /* OPTIMIZE-FC-BDP: decide sane criteria on when to do this, instead of doing
6331 it always! */
6332 /* For example, we should probably ONLY do this if a bit more than
6333 an RTT has passed, or if the window changed "significantly" since
6334 then. See vl->last_fc_rtt! NOTE: to do this properly, we also
6335 need an estimate for the bandwidth-delay-product for the entire
6336 VL, as that determines "significantly". We have the delay, but
6337 the bandwidth statistics need to be added for the VL!*/(void) duration;
6338
6339 if (NULL != vl->dv)
6340 rtt_average = calculate_rtt (vl->dv);
6341 else
6342 rtt_average = GNUNET_TIME_UNIT_FOREVER_REL;
6343 fc->rtt = GNUNET_TIME_relative_hton (rtt_average);
6345 "Sending FC seq %u to %s with new window %llu %lu %u\n",
6346 (unsigned int) vl->fc_seq_gen,
6347 GNUNET_i2s (&vl->target),
6348 (unsigned long long) vl->incoming_fc_window_size,
6349 (unsigned long) rtt_average.rel_value_us,
6350 vl->sync_ready);
6352 vl->last_fc_transmission = monotime;
6353 fc->sync_ready = htonl ((uint32_t) vl->sync_ready);
6355 fc->seq = htonl (vl->fc_seq_gen++);
6356 fc->inbound_window_size = GNUNET_htonll (vl->incoming_fc_window_size
6359 fc->outbound_sent = GNUNET_htonll (vl->outbound_fc_window_size_used);
6360 fc->outbound_window_size = GNUNET_htonll (vl->outbound_fc_window_size);
6361 fc->sender_time = GNUNET_TIME_absolute_hton (monotime);
6362 /* On an unconfirmed link the only queues and paths we have are, by
6363 definition, unvalidated ones -- that is what "unconfirmed" means.
6364 Requiring a validated route here is what deadlocks the pair: the peer
6365 has a confirmed link to us and flow-controls us, we cannot answer, so
6366 its @e outbound_fc_window_size stays at zero and it cannot send us a
6367 single byte -- not its CORE handshake, not DHT traffic -- while its
6368 `gnunet-transport' shows an established link with messages pending
6369 forever. It reached us over that queue, so answering on it is sound. */
6371 &fc->header,
6372 (GNUNET_YES == vl->confirmed)
6375 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == rtt.rel_value_us)
6376 {
6379 "FC retransmission to %s failed, will retry in %s\n",
6380 GNUNET_i2s (&vl->target),
6383 }
6384 else
6385 {
6386 /* OPTIMIZE-FC-BDP: rtt is not ideal, we can do better! */
6387 vl->last_fc_rtt = rtt;
6388 }
6389 if (NULL != vl->fc_retransmit_task)
6391 /* Never re-arm with (near) zero delay: @a rtt is zero whenever we have no
6392 RTT sample yet, which turned this into a tight send loop. */
6394 {
6395 /* Back off while the peer stays silent. Retransmitting at the plain RTT
6396 for #MAX_FC_RETRANSMIT_COUNT rounds is a flood on a link that is not
6397 being answered -- and a peer that cannot answer keeps *every* one of
6398 its links in exactly that state, which is enough traffic to make
6399 transport fall behind its communicators. */
6401
6402 for (unsigned int i = 0;
6403 (i < vl->fc_retransmit_count) && (rtt.rel_value_us < cap.rel_value_us);
6404 i++)
6405 rtt = GNUNET_TIME_relative_multiply (rtt, 2);
6406 rtt = GNUNET_TIME_relative_min (rtt, cap);
6407 }
6408 vl->fc_retransmit_task =
6411 vl->fc_retransmit_count++;
6412 GNUNET_free (fc);
6413}
6414
6415
6432static void
6434{
6435 struct Neighbour *n = vl->n;
6436 struct DistanceVector *dv = vl->dv;
6437 struct GNUNET_TIME_Absolute now;
6438 struct VirtualLink *vl_next_hop;
6439 int elig;
6440
6442 "check_vl_transmission to target %s\n",
6443 GNUNET_i2s (&vl->target));
6444 /* Check that we have an eligible pending message!
6445 (cheaper than having #transmit_on_queue() find out!) */
6446 elig = GNUNET_NO;
6447 for (struct PendingMessage *pm = vl->pending_msg_head; NULL != pm;
6448 pm = pm->next_vl)
6449 {
6451 "check_vl_transmission loop\n");
6452 if (NULL != pm->qe)
6453 continue; /* not eligible, is in a queue! */
6456 {
6458 "Stalled message %" PRIu64
6459 " transmission on VL %s due to flow control: %llu < %llu\n",
6460 pm->logging_uuid,
6461 GNUNET_i2s (&vl->target),
6462 (unsigned long long) vl->outbound_fc_window_size,
6463 (unsigned long long) (pm->bytes_msg
6466 return; /* We have a message, but flow control says "nope" */
6467 }
6469 "Target window on VL %s not stalled. Scheduling transmission on queue\n",
6470 GNUNET_i2s (&vl->target));
6471 /* Notify queues at direct neighbours that we are interested */
6472 now = GNUNET_TIME_absolute_get ();
6473 if (NULL != n)
6474 {
6475 for (struct Queue *queue = n->queue_head; NULL != queue;
6476 queue = queue->next_neighbour)
6477 {
6478 if ((GNUNET_YES == queue->idle) &&
6479 (queue->validated_until.abs_value_us > now.abs_value_us))
6480 {
6482 "Direct neighbour %s not stalled\n",
6483 GNUNET_i2s (&n->pid));
6485 queue,
6487 elig = GNUNET_YES;
6488 }
6489 else
6491 "Neighbour Queue QID: %u (%u) busy or invalid\n",
6492 queue->qid,
6493 queue->idle);
6494 }
6495 }
6496 /* Notify queues via DV that we are interested */
6497 if (NULL != dv)
6498 {
6499 /* Do DV with lower scheduler priority, which effectively means that
6500 IF a neighbour exists and is available, we prefer it. */
6501 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
6502 pos = pos->next_dv)
6503 {
6504 struct Neighbour *nh_iter = pos->next_hop;
6505
6506
6507 if (pos->path_valid_until.abs_value_us <= now.abs_value_us)
6508 continue; /* skip this one: path not validated */
6509 else
6510 {
6511 /* The next hop is a neighbour we have queues to; it need not have
6512 a virtual link of its own, and then there is no window of it to
6513 respect either. */
6514 vl_next_hop = lookup_virtual_link (&nh_iter->pid);
6515 if ((NULL != vl_next_hop) &&
6516 (pm->bytes_msg + vl_next_hop->outbound_fc_window_size_used >
6517 vl_next_hop->outbound_fc_window_size))
6518 {
6520 "Stalled message %" PRIu64
6521 " transmission on next hop %s due to flow control: %llu < %llu\n",
6522 pm->logging_uuid,
6523 GNUNET_i2s (&vl_next_hop->target),
6524 (unsigned long
6525 long) vl_next_hop->outbound_fc_window_size,
6526 (unsigned long long) (pm->bytes_msg
6527 + vl_next_hop->
6528 outbound_fc_window_size_used));
6529 consider_sending_fc (vl_next_hop);
6530 continue; /* We have a message, but flow control says "nope" for the first hop of this path */
6531 }
6532 for (struct Queue *queue = nh_iter->queue_head; NULL != queue;
6533 queue = queue->next_neighbour)
6534 if ((GNUNET_YES == queue->idle) &&
6535 (queue->validated_until.abs_value_us > now.abs_value_us))
6536 {
6538 "Next hop neighbour %s not stalled\n",
6539 GNUNET_i2s (&nh_iter->pid));
6541 queue,
6543 elig = GNUNET_YES;
6544 }
6545 else
6547 "DV Queue QID: %u (%u) busy or invalid\n",
6548 queue->qid,
6549 queue->idle);
6550 }
6551 }
6552 }
6553 if (GNUNET_YES == elig)
6555 "Eligible message %" PRIu64 " of size %u to %s: %llu/%llu\n",
6556 pm->logging_uuid,
6557 pm->bytes_msg,
6558 GNUNET_i2s (&vl->target),
6559 (unsigned long long) vl->outbound_fc_window_size,
6560 (unsigned long long) (pm->bytes_msg
6562 break;
6563 }
6564}
6565
6566
6573static void
6574handle_client_send (void *cls, const struct OutboundMessage *obm)
6575{
6576 struct TransportClient *tc = cls;
6577 struct PendingMessage *pm;
6578 const struct GNUNET_MessageHeader *obmm;
6579 uint32_t bytes_msg;
6580 struct VirtualLink *vl;
6582
6583 GNUNET_assert (CT_CORE == tc->type);
6584 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
6585 bytes_msg = ntohs (obmm->size);
6586 pp = ntohl (obm->priority);
6587 vl = lookup_virtual_link (&obm->peer);
6588 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
6589 {
6591 "Don't have %s as a neighbour (anymore).\n",
6592 GNUNET_i2s (&obm->peer));
6593 /* Failure: don't have this peer as a neighbour (anymore).
6594 Might have gone down asynchronously, so this is NOT
6595 a protocol violation by CORE. Still count the event,
6596 as this should be rare. */
6597 /* Precisely because this is not a protocol violation we leave the
6598 client's `struct Neighbour' -- and its send window -- in place, so we
6599 owe it the SEND_OK for the message we are dropping here. Without it
6600 the window shrinks by one every time this happens and never grows
6601 back; after #SEND_WINDOW_SIZE such drops #mq_send_impl() parks every
6602 further message for this peer forever ("Flow control delays
6603 transmission to CORE until we see SEND_OK") and CORE goes mute
6604 towards a peer it still believes it is connected to -- while
6605 continuing to receive from it, so its own idle timeout is what
6606 eventually reports the peer down. */
6607 send_ok_to_client (tc, &obm->peer);
6610 "# messages dropped (neighbour unknown)",
6611 1,
6612 GNUNET_NO);
6613 return;
6614 }
6615
6616 pm = GNUNET_malloc (sizeof(struct PendingMessage) + bytes_msg);
6618 "1 created pm %p storing vl %p\n",
6619 pm,
6620 vl);
6622 pm->prefs = pp;
6623 pm->client = tc;
6624 pm->vl = vl;
6625 pm->bytes_msg = bytes_msg;
6626 memcpy (&pm[1], obmm, bytes_msg);
6628 "Sending message of type %u with %u bytes as <%" PRIu64
6629 "> to %s\n",
6630 ntohs (obmm->type),
6631 bytes_msg,
6632 pm->logging_uuid,
6633 GNUNET_i2s (&obm->peer));
6635 tc->details.core.pending_msg_head,
6636 tc->details.core.pending_msg_tail,
6637 pm);
6639 vl->pending_msg_head,
6640 vl->pending_msg_tail,
6641 pm);
6644}
6645
6646
6656static void
6658 void *cls,
6660{
6661 struct Neighbour *n;
6662 struct VirtualLink *vl;
6663 struct TransportClient *tc = cls;
6664 const struct GNUNET_MessageHeader *inbox =
6665 (const struct GNUNET_MessageHeader *) &cb[1];
6666 uint16_t isize = ntohs (inbox->size);
6667 const char *is = ((const char *) &cb[1]) + isize;
6668 size_t slen = strlen (is) + 1;
6669 char
6670 mbuf[slen + isize
6671 + sizeof(struct
6675
6676 /* 0-termination of 'is' was checked already in
6677 #check_communicator_backchannel() */
6679 "Preparing backchannel transmission to %s:%s of type %u and size %u\n",
6680 GNUNET_i2s (&cb->pid),
6681 is,
6682 ntohs (inbox->type),
6683 ntohs (inbox->size));
6684 /* encapsulate and encrypt message */
6685 be->header.type =
6687 be->header.size = htons (sizeof(mbuf));
6688 memcpy (&be[1], inbox, isize);
6689 memcpy (&mbuf[sizeof(struct TransportBackchannelEncapsulationMessage)
6690 + isize],
6691 is,
6692 strlen (is) + 1);
6693 // route_control_message_without_fc (&cb->pid, &be->header, RMO_DV_ALLOWED);
6694 vl = lookup_virtual_link (&cb->pid);
6695 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
6696 {
6698 }
6699 else
6700 {
6701 /* Use route via neighbour */
6702 n = lookup_neighbour (&cb->pid);
6703 if (NULL != n)
6705 n,
6706 &be->header,
6707 RMO_NONE);
6708 }
6710}
6711
6712
6720static int
6721check_add_address (void *cls,
6722 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
6723{
6724 struct TransportClient *tc = cls;
6725
6726 if (CT_COMMUNICATOR != tc->type)
6727 {
6728 GNUNET_break (0);
6729 return GNUNET_SYSERR;
6730 }
6732 return GNUNET_OK;
6733}
6734
6735
6741static void
6742store_pi (void *cls);
6743
6744
6749{
6750
6754 struct AddressListEntry *ale;
6755
6759 struct PilsRequest *req;
6760
6761
6765 struct GNUNET_TIME_Absolute et;
6766};
6767
6768
6775static void
6777{
6778 struct PilsAddressSignContext *pc = ale->pc;
6779
6780 if (NULL == pc)
6781 return;
6782 ale->pc = NULL;
6783 /* Each stage of the chain passes @a pc as its closure, so every handle
6784 that could still deliver one has to go before @a pc is released. */
6785 if (NULL != ale->sc)
6786 {
6788 ale->sc = NULL;
6789 }
6790 if (NULL != ale->shc)
6791 {
6793 ale->shc = NULL;
6794 }
6795 if (NULL != pc->req)
6796 {
6797 if (NULL != pc->req->op)
6798 GNUNET_PILS_cancel (pc->req->op);
6801 pc->req);
6802 GNUNET_free (pc->req);
6803 pc->req = NULL;
6804 }
6805 GNUNET_free (pc);
6806}
6807
6808
6809static void
6810shc_cont (void *cls, int success)
6811{
6812 struct PilsAddressSignContext *pc = cls;
6813
6814 GNUNET_assert (NULL == pc->req);
6815 /* The store completed; the handle is dead and must not be cancelled
6816 later by #free_address_list_entry(). */
6817 pc->ale->shc = NULL;
6818 pc->ale->pc = NULL;
6819 if (GNUNET_OK != success)
6820 {
6822 "Failed to store our address `%s' with peerstore\n",
6823 pc->ale->address);
6824 if (NULL == pc->ale->st)
6825 {
6827 &store_pi,
6828 pc->ale);
6829 }
6830 }
6831 GNUNET_free (pc);
6832}
6833
6834
6838static void
6839pils_sign_hello_cb (void *cls,
6840 const struct GNUNET_PeerIdentity *pid,
6841 const struct GNUNET_CRYPTO_EddsaSignature *sig)
6842{
6843 struct PilsAddressSignContext *pc = cls;
6844 struct GNUNET_MQ_Envelope *env;
6845 const struct GNUNET_MessageHeader *msg;
6846
6847 pc->req->op = NULL;
6850 pc->req);
6851 GNUNET_free (pc->req);
6852 pc->req = NULL;
6855 pid,
6856 sig,
6857 pc->et);
6860 "store_pi 1\n");
6862 msg,
6863 shc_cont,
6864 pc);
6865 GNUNET_free (env);
6866}
6867
6868
6875static void
6876peerstore_store_own_cb (void *cls, int success)
6877{
6878 struct PilsAddressSignContext *pc = cls;
6879
6880 pc->ale->sc = NULL;
6881 if (GNUNET_YES != success)
6883 "Failed to store our own address `%s' in peerstore!\n",
6884 pc->ale->address);
6885 else
6887 "Successfully stored our own address `%s' in peerstore!\n",
6888 pc->ale->address);
6889 /* refresh period is 1/4 of expiration time, that should be plenty
6890 without being excessive. */
6891 if (NULL == pc->ale->st)
6892 {
6893 /* @e expiration comes straight off the wire in ADD_ADDRESS and is not
6894 validated anywhere, so a communicator reporting a very short (or
6895 zero) lifetime would have us re-sign the HELLO and store it again on
6896 the next scheduler pass, forever. That is an EdDSA signature and a
6897 PEERSTORE round trip per iteration. */
6898 pc->ale->st =
6902 GNUNET_TIME_relative_divide (pc->ale->expiration,
6903 4ULL)),
6904 &store_pi,
6905 pc->ale);
6906 }
6907
6908 /* Now we have to update our HELLO! */
6910 pc->req = GNUNET_new (struct PilsRequest);
6913 pc->req);
6914 pc->req->op = GNUNET_PILS_sign_hello (pils,
6916 pc->et,
6918 pc);
6919}
6920
6921
6929static void
6931 const struct GNUNET_PeerIdentity *pid,
6932 const struct GNUNET_CRYPTO_EddsaSignature *sig)
6933{
6934 char *sig_str;
6935 void *result;
6936 size_t result_size;
6937
6938 sig_str = NULL;
6939 (void) GNUNET_STRINGS_base64_encode (sig, sizeof(*sig), &sig_str);
6940 result_size =
6941 1 + GNUNET_asprintf (
6942 (char **) &result,
6943 "%s;%llu;%u;%s",
6944 sig_str,
6945 (unsigned long long) pc->et.abs_value_us,
6946 (unsigned int) pc->ale->nt,
6947 pc->ale->address);
6948 GNUNET_free (sig_str);
6949
6951 "Build our HELLO URI `%s'\n",
6952 (char*) result);
6953
6954 GNUNET_free (pc->ale->signed_address);
6955 pc->ale->signed_address = result;
6956 pc->ale->signed_address_len = result_size;
6958
6959 expiration = GNUNET_TIME_relative_to_absolute (pc->ale->expiration);
6961 "transport",
6962 pid,
6964 result,
6965 result_size,
6966 expiration,
6969 pc);
6970}
6971
6972
6976struct SignedAddress
6977{
6982
6987
6991 struct GNUNET_HashCode addr_hash GNUNET_PACKED;
6992};
6993
6994
7008void
7010 struct AddressListEntry *ale,
7011 struct GNUNET_TIME_Absolute mono_time)
7012{
7013 struct SignedAddress sa;
7014 struct PilsAddressSignContext *pc;
7016 const struct GNUNET_PeerIdentity *my_identity;
7017
7018 sa.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_ADDRESS);
7019 sa.purpose.size = htonl (sizeof(sa));
7020 sa.mono_time = GNUNET_TIME_absolute_hton (mono_time);
7021 GNUNET_CRYPTO_hash (ale->address, strlen (ale->address), &sa.addr_hash);
7022 /* Only ever one chain per entry: the previous one (if any) still holds a
7023 pointer to @a ale and must be torn down first. */
7026 if ((NULL == my_identity) ||
7027 (GNUNET_OK != sign_by_my_identity (&sa.purpose, &sig)))
7028 {
7029 /* Nothing else re-arms @e st: #store_pi() cleared it before calling us,
7030 and the only other thing that sets it is #peerstore_store_own_cb(),
7031 which is on the far side of the store we just failed to start. So a
7032 single failure to sign used to end the refresh cycle for this address
7033 for the rest of the process' life. */
7034 if (NULL == ale->st)
7035 {
7038 &store_pi,
7039 ale);
7040 }
7041 return;
7042 }
7044 pc->ale = ale;
7045 pc->et = mono_time;
7046 ale->pc = pc;
7048}
7049
7050
7056static void
7057store_pi (void *cls)
7058{
7059 struct AddressListEntry *ale = cls;
7060 const char *dash;
7061 char *address_uri;
7062 char *prefix;
7063 unsigned int add_success;
7064
7065 if ((GNUNET_YES == in_shutdown) || (NULL == pils))
7066 {
7067 ale->st = NULL;
7068 return;
7069 }
7070 if (NULL == GNUNET_PILS_get_identity (pils))
7071 {
7072 /* Do NOT poll at 1kHz: that burns CPU and keeps the scheduler task
7073 list non-empty, which prevents the service from ever exiting. */
7076 &store_pi,
7077 ale);
7078 return;
7079 }
7082 dash = strchr (ale->address, '-');
7083 GNUNET_assert (NULL != dash);
7084 dash++;
7085 GNUNET_asprintf (&address_uri,
7086 "%s://%s",
7087 prefix,
7088 dash);
7090 ale->st = NULL;
7092 "Storing our address `%s' in peerstore until %s!\n",
7093 ale->address,
7096 address_uri);
7097 /* NOTE: #GNUNET_HELLO_builder_add_address() answers GNUNET_NO for an
7098 address that is already in the builder, and on every call after the
7099 first one for a given address that is exactly what happens: nothing
7100 ever removes an address from @a GST_my_hello except
7101 #handle_del_address(). This function is the *refresh* cycle --
7102 #peerstore_store_own_cb() re-arms it at a quarter of the address'
7103 expiration -- so bailing out on GNUNET_NO here stopped the refresh
7104 after precisely one round. Our own HELLO then expired
7105 (#GNUNET_HELLO_ADDRESS_EXPIRATION, twelve hours) and was never
7106 renewed: peers can no longer learn how to reach us, and a link that
7107 drops after that never comes back. Only GNUNET_SYSERR -- a malformed
7108 URI, which retrying cannot fix -- is a reason not to store. */
7109 if (GNUNET_SYSERR == add_success)
7110 {
7112 "Not storing our address `%s': not a valid HELLO URI\n",
7113 address_uri);
7114 GNUNET_free (address_uri);
7115 return;
7116 }
7117 GNUNET_log ((GNUNET_NO == add_success) ?
7119 "%s our address `%s' in PEERSTORE\n",
7120 (GNUNET_NO == add_success) ? "Refreshing" : "Storing",
7121 address_uri);
7122 // FIXME hello_mono_time used here?? What about expiration in ale?
7123 pils_sign_address (ale,
7125 // TODO keep track of op and potentially cancel/clean
7126 GNUNET_free (address_uri);
7127}
7128
7129
7130static struct AddressListEntry *
7134 const char *address,
7135 uint32_t aid,
7136 size_t slen)
7137{
7138 struct AddressListEntry *ale;
7139 char *address_without_port;
7140
7141 ale = GNUNET_malloc (sizeof(struct AddressListEntry) + slen);
7142 ale->tc = tc;
7143 ale->address = (const char *) &ale[1];
7144 ale->expiration = expiration;
7145 ale->aid = aid;
7146 ale->nt = nt;
7147 memcpy (&ale[1], address, slen);
7148 address_without_port = get_address_without_port (ale->address);
7150 "Is this %s a local address (%s)\n",
7151 (NULL == address_without_port) ? "<unparsable>"
7152 : address_without_port,
7153 ale->address);
7154 if ((NULL == address_without_port) ||
7155 (0 != strcmp ("127.0.0.1", address_without_port)))
7156 {
7157 if (NULL != ale->st)
7158 {
7160 }
7161 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
7162 }
7163 GNUNET_free (address_without_port);
7164
7165 return ale;
7166}
7167
7168
7169static void
7170feed_addresses_to_pils (void *cls)
7171{
7172
7174 "Feeding addresses to PILS\n");
7175 pils_feed_task = NULL;
7176
7178 GST_my_hello);
7179}
7180
7181
7188static void
7189handle_add_address (void *cls,
7190 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
7191{
7192 struct TransportClient *tc = cls;
7193 struct AddressListEntry *ale;
7194 size_t slen;
7195 char *address;
7196
7197 /* 0-termination of &aam[1] was checked in #check_add_address */
7199 "Communicator added address `%s'!\n",
7200 (const char *) &aam[1]);
7201 slen = ntohs (aam->header.size) - sizeof(*aam);
7202 address = GNUNET_malloc (slen);
7203 memcpy (address, &aam[1], slen);
7204 ale = create_address_entry (tc,
7206 ntohl (aam->nt),
7207 address,
7208 aam->aid,
7209 slen);
7210 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
7211 tc->details.communicator.addr_tail,
7212 ale);
7213 {
7214 for (struct AddressListEntry *iter = tc->details.communicator.addr_head;
7215 NULL != iter;
7216 iter = iter->next)
7217 {
7218 char *address_uri;
7219 const char *dash = strchr (iter->address, '-');
7220 char *prefix = GNUNET_HELLO_address_to_prefix (iter->address);
7221 GNUNET_assert (NULL != dash);
7222 dash++;
7223 GNUNET_asprintf (&address_uri,
7224 "%s://%s",
7225 prefix,
7226 dash);
7229 GNUNET_free (address_uri);
7230 }
7231 if (NULL != pils_feed_task)
7235 NULL);
7236 }
7239}
7240
7241
7248static void
7249handle_del_address (void *cls,
7250 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
7251{
7252 struct TransportClient *tc = cls;
7253 struct AddressListEntry *alen;
7254
7255 if (CT_COMMUNICATOR != tc->type)
7256 {
7257 GNUNET_break (0);
7259 return;
7260 }
7261 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
7262 NULL != ale;
7263 ale = alen)
7264 {
7265 alen = ale->next;
7266 if (dam->aid != ale->aid)
7267 continue;
7268 GNUNET_assert (ale->tc == tc);
7270 "Communicator deleted address `%s'!\n",
7271 ale->address);
7273 ale->address);
7274 if (NULL != pils_feed_task)
7278 NULL);
7281 return;
7282 }
7284 "Communicator removed address we did not even have.\n");
7286 // GNUNET_SERVICE_client_drop (tc->client);
7287}
7288
7289
7297static void
7299
7300
7308static void
7309core_env_sent_cb (void *cls)
7310{
7311 struct CoreSentContext *ctx = cls;
7312 struct VirtualLink *vl = ctx->vl;
7313
7314 if (NULL == vl)
7315 {
7316 /* lost the link in the meantime, ignore */
7317 GNUNET_free (ctx);
7318 return;
7319 }
7322 vl->incoming_fc_window_size_ram -= ctx->size;
7323 vl->incoming_fc_window_size_used += ctx->isize;
7325 GNUNET_free (ctx);
7326}
7327
7328
7350static void
7351core_fc_stalled (void *cls)
7352{
7353 struct VirtualLink *vl = cls;
7354 struct CommunicatorMessageContext *cmc;
7355
7356 vl->core_fc_stall_task = NULL;
7358 "CORE did not acknowledge messages from %s within %s; "
7359 "releasing the flow control credit anyway\n",
7360 GNUNET_i2s (&vl->target),
7362 GNUNET_YES));
7364 "# CORE flow control stalls",
7365 1,
7366 GNUNET_NO);
7367 while (NULL != (cmc = vl->cmc_tail))
7368 release_stalled_cmc (vl, cmc);
7371}
7372
7373
7374static void
7376 const struct GNUNET_MessageHeader *mh,
7377 struct CommunicatorMessageContext *cmc,
7378 unsigned int free_cmc)
7379{
7380 uint16_t size = ntohs (mh->size);
7381 int have_core;
7382
7383 if (vl->incoming_fc_window_size_ram > UINT_MAX - size)
7384 {
7386 "# CORE messages dropped (FC arithmetic overflow)",
7387 1,
7388 GNUNET_NO);
7390 "CORE messages of type %u with %u bytes dropped (FC arithmetic overflow)\n",
7391 (unsigned int) ntohs (mh->type),
7392 (unsigned int) ntohs (mh->size));
7393 if (GNUNET_YES == free_cmc)
7395 return;
7396 }
7398 {
7400 "# CORE messages dropped (FC window overflow)",
7401 1,
7402 GNUNET_NO);
7404 "CORE messages of type %u with %u bytes dropped (FC window overflow)\n",
7405 (unsigned int) ntohs (mh->type),
7406 (unsigned int) ntohs (mh->size));
7407 if (GNUNET_YES == free_cmc)
7409 return;
7410 }
7411
7412 /* Forward to all CORE clients */
7413 have_core = GNUNET_NO;
7414 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
7415 {
7416 struct GNUNET_MQ_Envelope *env;
7417 struct InboundMessage *im;
7418 struct CoreSentContext *ctx;
7419
7420 if (CT_CORE != tc->type)
7421 continue;
7424 ctx = GNUNET_new (struct CoreSentContext);
7425 ctx->vl = vl;
7426 ctx->size = size;
7427 ctx->isize = (GNUNET_NO == have_core) ? size : 0;
7428 have_core = GNUNET_YES;
7431 im->peer = cmc->im.sender;
7432 memcpy (&im[1], mh, size);
7433 GNUNET_MQ_send (tc->mq, env);
7435 }
7436 if (GNUNET_NO == have_core)
7437 {
7439 "Dropped message to CORE: no CORE client connected!\n");
7440 /* Nevertheless, count window as used, as it is from the
7441 perspective of the other peer! */
7443 /* TODO-M1 */
7445 "Dropped message of type %u with %u bytes to CORE: no CORE client connected!\n",
7446 (unsigned int) ntohs (mh->type),
7447 (unsigned int) ntohs (mh->size));
7448 if (GNUNET_YES == free_cmc)
7450 return;
7451 }
7453 "Delivered message from %s of type %u to CORE recv window %d\n",
7454 GNUNET_i2s (&cmc->im.sender),
7455 ntohs (mh->type),
7457 if (vl->core_recv_window > 0)
7458 {
7459 if (GNUNET_YES == free_cmc)
7461 return;
7462 }
7463 /* CORE ran out of receive window for *this* link. Withhold the
7464 per-message ACK -- that is what expresses the backpressure -- but
7465 resume the client immediately. The client is the communicator
7466 *process*, which carries every peer we reach through it, and a
7467 communicator we stop reading from does not stop receiving: it starts
7468 discarding, see "transport is too slow" in
7469 #GNUNET_TRANSPORT_communicator_receive(). Discarding is precisely
7470 what we cannot afford here, because among the messages dropped are
7471 the ones CORE needs in order to reopen the window it is waiting on. */
7472 if (GNUNET_YES == free_cmc)
7473 {
7474 resume_cmc_client (cmc);
7476 vl->cmc_count++;
7477 /* Nothing stalls the producer any more, so bound the list ourselves. */
7478 while (MAX_STALLED_CMCS < vl->cmc_count)
7480 /* ... and do not withhold the ACKs forever: see #core_fc_stalled(). */
7481 if (NULL == vl->core_fc_stall_task)
7485 vl);
7486 }
7487}
7488
7489
7498static void
7499handle_raw_message (void *cls, const struct GNUNET_MessageHeader *mh)
7500{
7501 struct CommunicatorMessageContext *cmc = cls;
7502 // struct CommunicatorMessageContext *cmc_copy =
7503 // GNUNET_new (struct CommunicatorMessageContext);
7504 struct GNUNET_MessageHeader *mh_copy;
7505 struct RingBufferEntry *rbe;
7506 struct VirtualLink *vl;
7507 uint16_t size = ntohs (mh->size);
7508
7510 "Handling raw message of type %u with %u bytes\n",
7511 (unsigned int) ntohs (mh->type),
7512 (unsigned int) ntohs (mh->size));
7513
7514 if ((size > UINT16_MAX - sizeof(struct InboundMessage)) ||
7515 (size < sizeof(struct GNUNET_MessageHeader)))
7516 {
7517 /* @a mh was unwrapped from what a *remote peer* sent us, so a bad size
7518 is that peer's protocol violation and says nothing about the
7519 communicator that carried it. Dropping the client here disconnects
7520 the communicator process and with it every neighbour reachable
7521 through it -- see the rationale in #demultiplex_with_cmc(). */
7522 GNUNET_break_op (0);
7524 "# CORE messages dropped (bad size)",
7525 1,
7526 GNUNET_NO);
7527 finish_cmc_handling (cmc);
7528 return;
7529 }
7530 vl = lookup_virtual_link (&cmc->im.sender);
7531 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
7532 {
7533 /* FIXME: sender is giving us messages for CORE but we don't have
7534 the link up yet! I *suspect* this can happen right now (i.e.
7535 sender has verified us, but we didn't verify sender), but if
7536 we pass this on, CORE would be confused (link down, messages
7537 arrive). We should investigate more if this happens often,
7538 or in a persistent manner, and possibly do "something" about
7539 it. Thus logging as error for now. */
7540
7541 mh_copy = GNUNET_malloc (size);
7542 rbe = GNUNET_new (struct RingBufferEntry);
7543 rbe->cmc = cmc;
7544 /*cmc_copy->tc = cmc->tc;
7545 cmc_copy->im = cmc->im;*/
7546 GNUNET_memcpy (mh_copy, mh, size);
7547
7548 rbe->mh = mh_copy;
7549
7551 {
7552 struct RingBufferEntry *rbe_old = ring_buffer[ring_buffer_head];
7553 GNUNET_free (rbe_old->cmc);
7554 GNUNET_free (rbe_old->mh);
7555 GNUNET_free (rbe_old);
7556 }
7557 ring_buffer[ring_buffer_head] = rbe;// cmc_copy;
7558 // cmc_copy->mh = (const struct GNUNET_MessageHeader *) mh_copy;
7559 cmc->mh = (const struct GNUNET_MessageHeader *) mh_copy;
7561 "Storing message for %s and type %u (%u) in ring buffer head %u is full %u\n",
7562 GNUNET_i2s (&cmc->im.sender),
7563 (unsigned int) ntohs (mh->type),
7564 (unsigned int) ntohs (mh_copy->type),
7568 {
7569 ring_buffer_head = 0;
7571 }
7572 else
7574
7576 "%u items stored in ring buffer\n",
7579
7580 /*GNUNET_break_op (0);
7581 GNUNET_STATISTICS_update (GST_stats,
7582 "# CORE messages dropped (virtual link still down)",
7583 1,
7584 GNUNET_NO);
7585
7586 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7587 "CORE messages of type %u with %u bytes dropped (virtual link still down)\n",
7588 (unsigned int) ntohs (mh->type),
7589 (unsigned int) ntohs (mh->size));
7590 finish_cmc_handling (cmc);*/
7591 /* @a cmc lives on in the ring buffer; #send_cmc_ack() and
7592 #resume_cmc_client() have recorded that they ran, so replaying it
7593 from #send_msg_from_cache() cannot ACK or continue a second time. */
7595 return;
7596 }
7598}
7599
7600
7608static int
7609check_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
7610{
7611 uint16_t size = ntohs (fb->header.size);
7612 uint16_t bsize = size - sizeof(*fb);
7613
7614 (void) cls;
7615 if (0 == bsize)
7616 {
7617 GNUNET_break_op (0);
7618 return GNUNET_SYSERR;
7619 }
7620 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
7621 {
7622 GNUNET_break_op (0);
7623 return GNUNET_SYSERR;
7624 }
7625 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
7626 {
7627 GNUNET_break_op (0);
7628 return GNUNET_SYSERR;
7629 }
7630 return GNUNET_YES;
7631}
7632
7633
7639static void
7640destroy_ack_cummulator (void *cls)
7641{
7642 struct AcknowledgementCummulator *ac = cls;
7643
7644 ac->task = NULL;
7645 GNUNET_assert (0 == ac->num_acks);
7647 GNUNET_YES ==
7649 GNUNET_free (ac);
7650}
7651
7652
7658static void
7660{
7661 struct Neighbour *n;
7662 struct VirtualLink *vl;
7663 struct AcknowledgementCummulator *ac = cls;
7664 char buf[sizeof(struct TransportReliabilityAckMessage)
7665 + ac->num_acks
7667 struct TransportReliabilityAckMessage *ack =
7668 (struct TransportReliabilityAckMessage *) buf;
7670
7671 ac->task = NULL;
7673 "Sending ACK with %u components to %s\n",
7674 ac->num_acks,
7675 GNUNET_i2s (&ac->target));
7676 GNUNET_assert (0 < ac->num_acks);
7678 ack->header.size =
7679 htons (sizeof(*ack)
7680 + ac->num_acks * sizeof(struct TransportCummulativeAckPayloadP));
7681 ack->ack_counter = htonl (ac->ack_counter += ac->num_acks);
7682 ap = (struct TransportCummulativeAckPayloadP *) &ack[1];
7683 for (unsigned int i = 0; i < ac->num_acks; i++)
7684 {
7685 ap[i].ack_uuid = ac->ack_uuids[i].ack_uuid;
7688 }
7689 /*route_control_message_without_fc (
7690 &ac->target,
7691 &ack->header,
7692 RMO_DV_ALLOWED);*/
7693 vl = lookup_virtual_link (&ac->target);
7694 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
7695 {
7697 vl,
7698 &ack->header,
7700 }
7701 else
7702 {
7703 /* Use route via neighbour */
7704 n = lookup_neighbour (&ac->target);
7705 if (NULL != n)
7707 n,
7708 &ack->header,
7709 RMO_NONE);
7710 }
7711 ac->num_acks = 0;
7712 /* The deadline belonged to the batch we just sent. #cummulative_ack()
7713 only ever lowers it (GNUNET_TIME_absolute_min), so leaving it behind
7714 means every later ACK is armed with GNUNET_SCHEDULER_add_at() on a time
7715 that has already passed: the task fires on the next scheduler pass and
7716 the batching this whole structure exists for is gone for good -- one
7717 ACK message per received message, for the rest of the process' life. */
7721 ac);
7722}
7723
7724
7733static void
7734cummulative_ack (const struct GNUNET_PeerIdentity *pid,
7735 const struct AcknowledgementUUIDP *ack_uuid,
7736 struct GNUNET_TIME_Absolute max_delay)
7737{
7738 struct AcknowledgementCummulator *ac;
7739
7741 "Scheduling ACK %s for transmission to %s\n",
7742 GNUNET_uuid2s (&ack_uuid->value),
7743 GNUNET_i2s (pid));
7745 if (NULL == ac)
7746 {
7748 ac->target = *pid;
7749 ac->min_transmission_time = max_delay;
7753 &ac->target,
7754 ac,
7756 }
7757 else
7758 {
7759 if (MAX_CUMMULATIVE_ACKS == ac->num_acks)
7760 {
7761 /* Must run immediately, ack buffer full. Cancel the pending task
7762 FIRST: #transmit_cummulative_ack_cb() clears @e task without
7763 cancelling it, which would leave the old task armed with its
7764 handle lost. */
7766 ac->task = NULL;
7768 }
7772 }
7775 ac->ack_uuids[ac->num_acks].ack_uuid = *ack_uuid;
7776 ac->num_acks++;
7779 ac);
7780}
7781
7782
7787{
7792
7796 struct ReassemblyContext *rc;
7797};
7798
7799
7809static int
7810find_by_message_uuid (void *cls, uint32_t key, void *value)
7811{
7812 struct FindByMessageUuidContext *fc = cls;
7813 struct ReassemblyContext *rc = value;
7814
7815 (void) key;
7816 if (0 == GNUNET_memcmp (&fc->message_uuid, &rc->msg_uuid))
7817 {
7818 fc->rc = rc;
7819 return GNUNET_NO;
7820 }
7821 return GNUNET_YES;
7822}
7823
7824
7832static void
7833handle_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
7834{
7835 struct CommunicatorMessageContext *cmc = cls;
7836 struct VirtualLink *vl;
7837 struct ReassemblyContext *rc;
7838 const struct GNUNET_MessageHeader *msg;
7839 uint16_t msize;
7840 uint16_t fsize;
7841 uint16_t frag_off;
7842 char *target;
7843 struct GNUNET_TIME_Relative cdelay;
7844 struct FindByMessageUuidContext fc;
7845
7846 vl = lookup_virtual_link (&cmc->im.sender);
7847 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
7848 {
7849 /* Entirely normal: fragments of a message that was already in flight
7850 keep arriving for a while after a link goes down, and a peer that has
7851 validated us may start sending before we have validated it. This used
7852 to call #GNUNET_SERVICE_client_drop(), which disconnects the
7853 communicator *process* -- every queue it owns, hence every neighbour
7854 reachable through it, hence every CORE session. On a peer with many
7855 neighbours a single ill-timed fragment therefore dropped all
7856 connections at once, and since the fragment comes from the network,
7857 any peer could cause it at will. Drop the fragment, keep the
7858 communicator; see #demultiplex_with_cmc() for the same reasoning. */
7860 "No virtual link for %s to handle fragment\n",
7861 GNUNET_i2s (&cmc->im.sender));
7863 "# fragments dropped (virtual link down)",
7864 1,
7865 GNUNET_NO);
7866 finish_cmc_handling (cmc);
7867 return;
7868 }
7869 if (NULL == vl->reassembly_map)
7870 {
7872 vl->reassembly_heap =
7877 vl);
7878 }
7879 msize = ntohs (fb->msg_size);
7880 fc.message_uuid = fb->msg_uuid;
7881 fc.rc = NULL;
7883 fb->msg_uuid.uuid,
7885 &fc);
7886 fsize = ntohs (fb->header.size) - sizeof(*fb);
7887 if (NULL == (rc = fc.rc))
7888 {
7889 /* Bound the RAM a single sender can pin here: @e msg_size is chosen by
7890 the peer, not by us. */
7893 {
7894 struct ReassemblyContext *drop;
7895
7897 GNUNET_assert (NULL != drop);
7899 "# Reassembly contexts dropped (limit reached)",
7900 1,
7901 GNUNET_NO);
7903 }
7904 rc = GNUNET_malloc (sizeof(*rc) + msize /* reassembly payload buffer */
7905 + (msize + 7) / 8 * sizeof(uint8_t) /* bitfield */);
7906 rc->msg_uuid = fb->msg_uuid;
7907 rc->virtual_link = vl;
7908 rc->msg_size = msize;
7909 rc->reassembly_timeout =
7913 rc,
7917 vl->reassembly_map,
7918 rc->msg_uuid.uuid,
7919 rc,
7921 target = (char *) &rc[1];
7922 rc->bitfield = (uint8_t *) (target + rc->msg_size);
7923 /* The bitfield loop below decrements @e msg_missing once per newly
7924 received byte, so this must always start at the full message size:
7925 initialising it to 0 for a single-fragment message made it
7926 underflow, and the message was then never delivered. */
7927 rc->msg_missing = rc->msg_size;
7929 "Received fragment with size %u at offset %u/%u %u bytes missing from %s for NEW message %"
7930 PRIu64 "\n",
7931 fsize,
7932 ntohs (fb->frag_off),
7933 msize,
7934 rc->msg_missing,
7935 GNUNET_i2s (&cmc->im.sender),
7936 fb->msg_uuid.uuid);
7937 }
7938 else
7939 {
7940 target = (char *) &rc[1];
7942 "Received fragment at offset %u/%u from %s for message %u\n",
7943 ntohs (fb->frag_off),
7944 msize,
7945 GNUNET_i2s (&cmc->im.sender),
7946 (unsigned int) fb->msg_uuid.uuid);
7947 }
7948 if (msize != rc->msg_size)
7949 {
7950 GNUNET_break (0);
7951 finish_cmc_handling (cmc);
7952 return;
7953 }
7954
7955 /* reassemble */
7956 if (0 == fsize)
7957 {
7958 GNUNET_break (0);
7959 finish_cmc_handling (cmc);
7960 return;
7961 }
7962 frag_off = ntohs (fb->frag_off);
7963 if (frag_off + fsize > msize)
7964 {
7965 /* Fragment (plus fragment size) exceeds message size! */
7966 GNUNET_break_op (0);
7967 finish_cmc_handling (cmc);
7968 return;
7969 }
7970 memcpy (&target[frag_off], &fb[1], fsize);
7971 /* update bitfield and msg_missing */
7972 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
7973 {
7974 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
7975 {
7976 rc->bitfield[i / 8] |= (1 << (i % 8));
7977 rc->msg_missing--;
7978 }
7979 }
7980
7981 /* Compute cumulative ACK */
7983 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->msg_missing / fsize);
7984 if (0 == rc->msg_missing)
7985 cdelay = GNUNET_TIME_UNIT_ZERO;
7986 cummulative_ack (&cmc->im.sender,
7987 &fb->ack_uuid,
7990 /* is reassembly complete? */
7991 if (0 != rc->msg_missing)
7992 {
7993 finish_cmc_handling (cmc);
7994 return;
7995 }
7996 /* reassembly is complete, verify result */
7997 msg = (const struct GNUNET_MessageHeader *) &rc[1];
7998 if (ntohs (msg->size) != rc->msg_size)
7999 {
8000 GNUNET_break (0);
8002 finish_cmc_handling (cmc);
8003 return;
8004 }
8005 /* successful reassembly */
8007 "Fragment reassembly complete for message %u\n",
8008 (unsigned int) fb->msg_uuid.uuid);
8009 /* FIXME: check that the resulting msg is NOT a
8010 DV Box or Reliability Box, as that is NOT allowed! */
8011 {
8012 uint16_t rsize = rc->msg_size;
8013 char rbuf[rsize] GNUNET_ALIGN;
8014
8015 /* Copy the reassembled message out and release `rc' BEFORE
8016 demultiplexing: the inner message may tear down the virtual link,
8017 which frees every reassembly context of that link -- the old code
8018 then used and freed `rc' a second time afterwards. */
8019 memcpy (rbuf, msg, rsize);
8021 cmc->mh = (const struct GNUNET_MessageHeader *) rbuf;
8023 }
8024}
8025
8026
8034static int
8035check_reliability_box (void *cls,
8036 const struct TransportReliabilityBoxMessage *rb)
8037{
8038 const struct GNUNET_MessageHeader *box = (const struct
8039 GNUNET_MessageHeader *) &rb[1];
8040 (void) cls;
8041
8043 "check_send_msg with size %u: inner msg type %u and size %u (%lu %lu)\n",
8044 ntohs (rb->header.size),
8045 ntohs (box->type),
8046 ntohs (box->size),
8047 sizeof (struct TransportReliabilityBoxMessage),
8048 sizeof (struct GNUNET_MessageHeader));
8050 return GNUNET_YES;
8051}
8052
8053
8061static void
8062handle_reliability_box (void *cls,
8063 const struct TransportReliabilityBoxMessage *rb)
8064{
8065 struct CommunicatorMessageContext *cmc = cls;
8066 const struct GNUNET_MessageHeader *inbox =
8067 (const struct GNUNET_MessageHeader *) &rb[1];
8068 struct GNUNET_TIME_Relative rtt;
8069
8071 "Received reliability box from %s with UUID %s of type %u\n",
8072 GNUNET_i2s (&cmc->im.sender),
8074 (unsigned int) ntohs (inbox->type));
8075 rtt = GNUNET_TIME_UNIT_SECONDS; /* FIXME: should base this on "RTT", but we
8076 do not really have an RTT for the
8077 * incoming* queue (should we have
8078 the sender add it to the rb message?) */
8080 &cmc->im.sender,
8081 &rb->ack_uuid,
8082 (0 == ntohl (rb->ack_countdown))
8085 GNUNET_TIME_relative_divide (rtt, 8 /* FIXME: magic constant */)));
8086 /* continue with inner message */
8087 /* FIXME: check that inbox is NOT a DV Box, fragment or another
8088 reliability box (not allowed!) */
8089 cmc->mh = inbox;
8091}
8092
8093
8102static void
8103update_pd_age (struct PerformanceData *pd, unsigned int age)
8104{
8105 unsigned int sage;
8106
8107 if (age == pd->last_age)
8108 return; /* nothing to do */
8109 sage = GNUNET_MAX (pd->last_age, age - 2 * GOODPUT_AGING_SLOTS);
8110 for (unsigned int i = sage; i <= age - GOODPUT_AGING_SLOTS; i++)
8111 {
8112 struct TransmissionHistoryEntry *the = &pd->the[i % GOODPUT_AGING_SLOTS];
8113
8114 the->bytes_sent = 0;
8115 the->bytes_received = 0;
8116 }
8117 pd->last_age = age;
8118}
8119
8120
8129static void
8131 struct GNUNET_TIME_Relative rtt,
8132 uint16_t bytes_transmitted_ok)
8133{
8134 uint64_t nval = rtt.rel_value_us;
8135 uint64_t oval = pd->aged_rtt.rel_value_us;
8136 unsigned int age = get_age ();
8137 struct TransmissionHistoryEntry *the = &pd->the[age % GOODPUT_AGING_SLOTS];
8138
8139 if (oval == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
8140 pd->aged_rtt = rtt;
8141 else
8142 pd->aged_rtt.rel_value_us = (nval + 7 * oval) / 8;
8143 update_pd_age (pd, age);
8144 the->bytes_received += bytes_transmitted_ok;
8145}
8146
8147
8155static void
8157 struct GNUNET_TIME_Relative rtt,
8158 uint16_t bytes_transmitted_ok)
8159{
8160 update_performance_data (&q->pd, rtt, bytes_transmitted_ok);
8161}
8162
8163
8171static void
8173 struct GNUNET_TIME_Relative rtt,
8174 uint16_t bytes_transmitted_ok)
8175{
8176 update_performance_data (&dvh->pd, rtt, bytes_transmitted_ok);
8177}
8178
8179
8187static void
8189{
8190 struct PendingMessage *pos;
8191
8193 "Complete transmission of message %" PRIu64 " %u\n",
8194 pm->logging_uuid,
8195 pm->pmt);
8196 switch (pm->pmt)
8197 {
8198 case PMT_CORE:
8200 /* Full message sent, we are done */
8202 return;
8203
8204 case PMT_FRAGMENT_BOX:
8205 /* Fragment sent over reliable channel */
8206 pos = pm->frag_parent;
8207 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
8210 "pos frag_off %lu pos bytes_msg %lu pmt %u parent %u\n",
8211 (unsigned long) pos->frag_off,
8212 (unsigned long) pos->bytes_msg,
8213 pos->pmt,
8214 NULL == pos->frag_parent ? 1 : 0);
8215 /* check if subtree is done */
8216 while ((NULL == pos->head_frag) && (pos->frag_off == (pos->bytes_msg
8217 - sizeof(struct
8219 &&
8220 (NULL != pos->frag_parent))
8221 {
8222 pm = pos;
8223 pos = pm->frag_parent;
8224 if ((NULL == pos) && (PMT_DV_BOX == pm->pmt))
8225 {
8227 return;
8228 }
8229 else if (PMT_DV_BOX == pm->pmt)
8230 {
8232 return;
8233 }
8234 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
8236 }
8237
8238 /* Was this the last applicable fragment?
8239
8240 NOTE: @a pos may be a DV box here, and then it is NOT the message the
8241 client is waiting for -- its @e frag_parent is, and that parent's
8242 @e bpm points at @a pos. Answering the client directly (and thereby
8243 releasing @a pos through #free_pending_message()) left @e bpm of a
8244 message that is still queued pointing at freed memory, which
8245 #transmit_on_queue() reads and may free a second time. Hand it to
8246 ourselves instead: the #PMT_DV_BOX case below clears @e bpm and
8247 answers for the parent, and for every other @e pmt it does exactly
8248 what the direct call did. */
8249 if ((NULL == pos->head_frag) && (NULL == pos->frag_parent || PMT_DV_BOX ==
8250 pos->pmt) &&
8251 (pos->frag_off == pos->bytes_msg))
8253 return;
8254
8255 case PMT_DV_BOX:
8257 "Completed transmission of message %" PRIu64 " (DV Box)\n",
8258 pm->logging_uuid);
8259 if (NULL != pm->frag_parent)
8260 {
8261 pos = pm->frag_parent;
8263 pos->bpm = NULL;
8265 }
8266 else
8268 return;
8269 }
8270}
8271
8272
8280static void
8282 struct GNUNET_TIME_Relative ack_delay)
8283{
8284 struct GNUNET_TIME_Relative delay;
8285 struct PendingMessage *pm = pa->pm;
8286
8288 delay = GNUNET_TIME_relative_subtract (delay, ack_delay);
8289 if (NULL != pa->queue && 1 == pa->num_send)
8291 if (NULL != pa->dvh && 1 == pa->num_send)
8292 update_dvh_performance (pa->dvh, delay, pa->message_size);
8293 /* Retire @a pa BEFORE handing its message on. completed_pending_message()
8294 ends in free_pending_message() for anything it finishes, and that now
8295 releases every acknowledgement still attached to the message -- this one
8296 included. Freeing it afterwards is a double free, and it aborts on the
8297 GNUNET_assert() over multiuuidmap_remove() in
8298 free_pending_acknowledgement(), the map entry having gone with the first
8299 release. Nothing below needs @a pa, only its message. */
8301 if (NULL != pm)
8303}
8304
8305
8313static int
8314check_reliability_ack (void *cls,
8315 const struct TransportReliabilityAckMessage *ra)
8316{
8317 unsigned int n_acks;
8318
8319 (void) cls;
8320 n_acks = (ntohs (ra->header.size) - sizeof(*ra))
8321 / sizeof(struct TransportCummulativeAckPayloadP);
8322 if (0 == n_acks)
8323 {
8324 GNUNET_break_op (0);
8325 return GNUNET_SYSERR;
8326 }
8327 if ((ntohs (ra->header.size) - sizeof(*ra)) !=
8328 n_acks * sizeof(struct TransportCummulativeAckPayloadP))
8329 {
8330 GNUNET_break_op (0);
8331 return GNUNET_SYSERR;
8332 }
8333 return GNUNET_OK;
8334}
8335
8336
8344static void
8345handle_reliability_ack (void *cls,
8346 const struct TransportReliabilityAckMessage *ra)
8347{
8348 struct CommunicatorMessageContext *cmc = cls;
8349 const struct TransportCummulativeAckPayloadP *ack;
8350 unsigned int n_acks;
8351 uint32_t ack_counter;
8352
8353 n_acks = (ntohs (ra->header.size) - sizeof(*ra))
8354 / sizeof(struct TransportCummulativeAckPayloadP);
8355 ack = (const struct TransportCummulativeAckPayloadP *) &ra[1];
8356 for (unsigned int i = 0; i < n_acks; i++)
8357 {
8358 struct PendingAcknowledgement *pa =
8360 if (NULL == pa)
8361 {
8363 "Received ACK from %s with UUID %s which is unknown to us!\n",
8364 GNUNET_i2s (&cmc->im.sender),
8365 GNUNET_uuid2s (&ack[i].ack_uuid.value));
8367 GST_stats,
8368 "# FRAGMENT_ACKS dropped, no matching pending message",
8369 1,
8370 GNUNET_NO);
8371 continue;
8372 }
8374 "Received ACK from %s with UUID %s\n",
8375 GNUNET_i2s (&cmc->im.sender),
8376 GNUNET_uuid2s (&ack[i].ack_uuid.value));
8377 handle_acknowledged (pa, GNUNET_TIME_relative_ntoh (ack[i].ack_delay));
8378 }
8379
8380 ack_counter = ntohl (ra->ack_counter);
8381 (void) ack_counter; /* silence compiler warning for now */
8382 // FIXME-OPTIMIZE: track ACK losses based on ack_counter somewhere!
8383 // (DV and/or Neighbour?)
8384 finish_cmc_handling (cmc);
8385}
8386
8387
8395static int
8397 void *cls,
8399{
8400 uint16_t size = ntohs (be->header.size) - sizeof(*be);
8401 const struct GNUNET_MessageHeader *inbox =
8402 (const struct GNUNET_MessageHeader *) &be[1];
8403 const char *is;
8404 uint16_t isize;
8405
8406 (void) cls;
8407 /* MUST bound the buffer before reading @a inbox: the size check below
8408 dereferences it, and a message consisting of nothing but the header
8409 leaves no bytes to read. */
8410 if (size <= sizeof(struct GNUNET_MessageHeader))
8411 {
8412 GNUNET_break_op (0);
8413 return GNUNET_SYSERR;
8414 }
8415 if (ntohs (inbox->size) >= size)
8416 {
8417 GNUNET_break_op (0);
8418 return GNUNET_SYSERR;
8419 }
8420 isize = ntohs (inbox->size);
8421 is = ((const char *) inbox) + isize;
8422 size -= isize;
8423 if ('\0' != is[size - 1])
8424 {
8425 GNUNET_break_op (0);
8426 return GNUNET_SYSERR;
8427 }
8428 return GNUNET_YES;
8429}
8430
8431
8440static void
8442 void *cls,
8444{
8445 const struct GNUNET_PeerIdentity *my_identity;
8446 struct CommunicatorMessageContext *cmc = cls;
8448 struct GNUNET_MQ_Envelope *env;
8449 struct TransportClient *tc;
8450 const struct GNUNET_MessageHeader *inbox =
8451 (const struct GNUNET_MessageHeader *) &be[1];
8452 uint16_t isize = ntohs (inbox->size);
8453 const char *target_communicator = ((const char *) inbox) + isize;
8454 char *sender;
8455 char *self;
8456
8459
8460 GNUNET_asprintf (&sender,
8461 "%s",
8462 GNUNET_i2s (&cmc->im.sender));
8463 GNUNET_asprintf (&self,
8464 "%s",
8466
8467 /* Find client providing this communicator */
8468 for (tc = clients_head; NULL != tc; tc = tc->next)
8469 if ((CT_COMMUNICATOR == tc->type) &&
8470 (NULL != tc->details.communicator.address_prefix) &&
8471 (0 ==
8472 strcmp (tc->details.communicator.address_prefix, target_communicator)))
8473 break;
8474 if (NULL == tc)
8475 {
8476 char *stastr;
8477
8479 &stastr,
8480 "# Backchannel message dropped: target communicator `%s' unknown",
8481 target_communicator);
8483 GNUNET_free (stastr);
8484 GNUNET_free (sender);
8485 GNUNET_free (self);
8486 finish_cmc_handling (cmc);
8487 return;
8488 }
8489 /* Finally, deliver backchannel message to communicator */
8491 "Delivering backchannel message from %s to %s of type %u to %s\n",
8492 sender,
8493 self,
8494 ntohs (inbox->type),
8495 target_communicator);
8497 cbi,
8498 isize,
8500 cbi->pid = cmc->im.sender;
8501 memcpy (&cbi[1], inbox, isize);
8502 GNUNET_MQ_send (tc->mq, env);
8503 GNUNET_free (sender);
8504 GNUNET_free (self);
8505 finish_cmc_handling (cmc);
8506}
8507
8508
8518static void
8519path_cleanup_cb (void *cls)
8520{
8521 struct DistanceVector *dv = cls;
8522 struct DistanceVectorHop *pos;
8523 struct GNUNET_TIME_Absolute next;
8524
8525 dv->timeout_task = NULL;
8526 /* @e dv_head is NOT sorted by @e timeout: learn_dv_path() inserts a new
8527 hop at the head, and moves a rediscovered one back to the head, so the
8528 list runs newest (i.e. latest deadline) first. Stopping at the first
8529 live entry therefore inspected exactly the youngest hop and re-armed
8530 for *its* deadline, which is the last one of the whole set: expired
8531 hops behind it were never collected, and check_vl_transmission() kept
8532 skipping them one by one for as long as the route lived. Sweep all of
8533 them and come back for the earliest survivor. */
8535 pos = dv->dv_head;
8536 while (NULL != pos)
8537 {
8538 struct DistanceVectorHop *next_pos = pos->next_dv;
8539
8540 GNUNET_assert (dv == pos->dv);
8543 else
8544 next = GNUNET_TIME_absolute_min (next, pos->timeout);
8545 pos = next_pos;
8546 }
8547 if (NULL == dv->dv_head)
8548 {
8549 free_dv_route (dv);
8550 return;
8551 }
8552 dv->timeout_task =
8554}
8555
8556
8557static void
8559{
8560
8561 const struct GNUNET_PeerIdentity target = vl->target;
8562
8563
8565 {
8566 struct RingBufferEntry *ring_buffer_copy[RING_BUFFER_SIZE];
8567 unsigned int tail = GNUNET_YES == is_ring_buffer_full ? ring_buffer_head :
8568 0;
8569 unsigned int head = GNUNET_YES == is_ring_buffer_full ? RING_BUFFER_SIZE :
8572 struct CommunicatorMessageContext *cmc;
8573 struct RingBufferEntry *rbe;
8574 struct GNUNET_MessageHeader *mh;
8575
8577 "Sending from ring buffer, which has %u items\n",
8578 head);
8579
8580 ring_buffer_head = 0;
8581 for (unsigned int i = 0; i < head; i++)
8582 {
8583 rbe = ring_buffer[(i + tail) % RING_BUFFER_SIZE];
8584 cmc = rbe->cmc;
8585 mh = rbe->mh;
8586
8587 im = cmc->im;
8588 // mh = cmc->mh;
8590 "Sending message of type %u to ring buffer target %s using vl target %s index %u\n",
8591 mh->type,
8592 GNUNET_i2s (&im.sender),
8593 GNUNET_i2s2 (&target),
8594 (i + tail) % RING_BUFFER_SIZE);
8595 if (0 == GNUNET_memcmp (&target, &im.sender))
8596 {
8598 "Finish handling message of type %u and size %u\n",
8599 (unsigned int) ntohs (mh->type),
8600 (unsigned int) ntohs (mh->size));
8602 GNUNET_free (mh);
8603 GNUNET_free (rbe->cmc);
8604 GNUNET_free (rbe);
8605 }
8606 else
8607 {
8608 ring_buffer_copy[ring_buffer_head] = rbe;
8610 }
8611 }
8612
8615 {
8617 }
8618
8619 for (unsigned int i = 0; i < ring_buffer_head; i++)
8620 {
8621 ring_buffer[i] = ring_buffer_copy[i];
8623 "ring_buffer[i]->mh->type for i %u %u\n",
8624 i,
8625 ring_buffer[i]->mh->type);
8626 }
8627 /* MUST clear the consumed slots, we freed those entries above */
8628 for (unsigned int i = ring_buffer_head; i < RING_BUFFER_SIZE; i++)
8629 ring_buffer[i] = NULL;
8630
8632 "%u items still in ring buffer\n",
8634 /* If we consumed nothing, compaction rewrote the buffer in place and
8635 left the write index one past the end. #handle_raw_message() would
8636 then read ring_buffer[RING_BUFFER_SIZE] and free whatever that is.
8637 The buffer is still full, and compaction moved the oldest entry to
8638 slot 0, so that is where the next write belongs. */
8640 ring_buffer_head = 0;
8641 }
8642
8644 {
8645 struct PendingMessage *ring_buffer_dv_copy[RING_BUFFER_SIZE];
8646 struct PendingMessage *pm;
8647 unsigned int tail = GNUNET_YES == is_ring_buffer_dv_full ?
8649 0;
8650 unsigned int head = GNUNET_YES == is_ring_buffer_dv_full ?
8653
8655 "Sending from ring buffer dv, which has %u items\n",
8656 head);
8657
8659 for (unsigned int i = 0; i < head; i++)
8660 {
8661 pm = ring_buffer_dv[(i + tail) % RING_BUFFER_SIZE];
8662
8664 "Sending to ring buffer target %s using vl target %s\n",
8665 GNUNET_i2s (&pm->target),
8666 GNUNET_i2s2 (&target));
8667 if (0 == GNUNET_memcmp (&target, &pm->target))
8668 {
8670 "Adding PendingMessage to vl, checking transmission.\n");
8671 pm->vl = vl;
8675 pm);
8676
8678 }
8679 else
8680 {
8681 ring_buffer_dv_copy[ring_buffer_dv_head] = pm;
8683 }
8684 }
8685
8687 {
8689 }
8690
8691 for (unsigned int i = 0; i < ring_buffer_dv_head; i++)
8692 ring_buffer_dv[i] = ring_buffer_dv_copy[i];
8693 /* MUST clear the consumed slots: entries we handed to a VirtualLink are
8694 now owned by that link, and #forward_dv_box() would GNUNET_free() them
8695 again once the ring buffer wraps around. */
8696 for (unsigned int i = ring_buffer_dv_head; i < RING_BUFFER_SIZE; i++)
8697 ring_buffer_dv[i] = NULL;
8698
8700 "%u items still in ring buffer dv.\n",
8702 /* Same one-past-the-end hazard as above: #forward_dv_box() reads
8703 ring_buffer_dv[ring_buffer_dv_head] and GNUNET_free()s it. */
8706 }
8707}
8708
8709
8717static void
8719{
8720 struct DistanceVector *dv = hop->dv;
8721 struct VirtualLink *vl;
8722
8723 vl = lookup_virtual_link (&dv->target);
8724 if (NULL == vl)
8725 {
8726
8727 vl = GNUNET_new (struct VirtualLink);
8729 "Creating new virtual link %p to %s using DV!\n",
8730 vl,
8731 GNUNET_i2s (&dv->target));
8732 vl->burst_addr = NULL;
8733 vl->confirmed = GNUNET_YES;
8734 vl->message_uuid_ctr =
8735 GNUNET_CRYPTO_random_u64 (UINT64_MAX);
8736 vl->target = dv->target;
8740 /* What the peer will grant us in its very first FLOW_CONTROL anyway
8741 (@e incoming_fc_window_size plus what we have sent, i.e. nothing).
8742 Starting at zero instead means a link that is up, validated and
8743 working carries nothing at all until an FC round trip completes --
8744 and if the peer cannot answer, not ever. */
8748 links,
8749 &vl->target,
8750 vl,
8752 vl->dv = dv;
8753 dv->vl = vl;
8754 vl->visibility_task =
8757 /* We lacked a confirmed connection to the target
8758 before, so tell CORE about it (finally!) */
8761 }
8762 else
8763 {
8764 /* Link was already up, remember dv is also now available and we are done */
8765 vl->dv = dv;
8766 dv->vl = vl;
8767 if (GNUNET_NO == vl->confirmed)
8768 {
8769 vl->confirmed = GNUNET_YES;
8770 vl->visibility_task =
8773 /* We lacked a confirmed connection to the target
8774 before, so tell CORE about it (finally!) */
8777 }
8778 else
8780 "Virtual link to %s could now also use DV!\n",
8781 GNUNET_i2s (&dv->target));
8782 }
8783}
8784
8785
8811static int
8812learn_dv_path (const struct GNUNET_PeerIdentity *path,
8813 unsigned int path_len,
8814 struct GNUNET_TIME_Relative network_latency,
8815 struct GNUNET_TIME_Absolute path_valid_until)
8816{
8817 const struct GNUNET_PeerIdentity *my_identity;
8818 struct DistanceVectorHop *hop;
8819 struct DistanceVector *dv;
8820 struct Neighbour *next_hop;
8821 unsigned int shorter_distance;
8822
8823 if (path_len < 3)
8824 {
8825 /* what a boring path! not allowed! */
8826 GNUNET_break (0);
8827 return GNUNET_SYSERR;
8828 }
8829
8832
8833 GNUNET_assert (0 == GNUNET_memcmp (my_identity, &path[0]));
8834 next_hop = lookup_neighbour (&path[1]);
8835 if (NULL == next_hop)
8836 {
8837 /* next hop must be a neighbour, otherwise this whole thing is useless! */
8838 GNUNET_break (0);
8839 return GNUNET_SYSERR;
8840 }
8841 for (unsigned int i = 2; i < path_len; i++)
8842 {
8843 struct Neighbour *n = lookup_neighbour (&path[i]);
8844 struct GNUNET_TIME_Absolute q_timeout;
8845
8846 if (NULL != n)
8847 {
8848 q_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
8849 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
8850 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
8852 "remaining %lu to %s\n",
8853 (unsigned long) GNUNET_TIME_absolute_get_remaining (q_timeout)
8854 .rel_value_us,
8855 GNUNET_i2s (&n->pid));
8856 if (0 != GNUNET_TIME_absolute_get_remaining (q_timeout).rel_value_us)
8857 {
8858 /* Useless path: we have a direct active connection to some hop
8859 in the middle of the path, so this one is not even
8860 terribly useful for redundancy */
8862 "Path of %u hops useless: directly link to hop %u (%s)\n",
8863 path_len,
8864 i,
8865 GNUNET_i2s (&path[i]));
8867 "# Useless DV path ignored: hop is neighbour",
8868 1,
8869 GNUNET_NO);
8870 return GNUNET_SYSERR;
8871 }
8872 }
8873 }
8874 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
8875 if (NULL == dv)
8876 {
8877 dv = GNUNET_new (struct DistanceVector);
8878 dv->target = path[path_len - 1];
8881 dv);
8884 dv_routes,
8885 &dv->target,
8886 dv,
8888 }
8889 /* Check if we have this path already! */
8890 shorter_distance = 0;
8891 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
8892 pos = pos->next_dv)
8893 {
8894 if (pos->distance < path_len - 3)
8895 shorter_distance++;
8896 /* Note that the distances in 'pos' excludes us (path[0]),
8897 the next_hop (path[1]) and the target so we need to subtract three
8898 and check next_hop explicitly */
8899 if ((pos->distance == path_len - 3) && (pos->next_hop == next_hop))
8900 {
8901 int match = GNUNET_YES;
8902
8903 for (unsigned int i = 0; i < pos->distance; i++)
8904 {
8905 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
8906 {
8907 match = GNUNET_NO;
8908 break;
8909 }
8910 }
8911 if (GNUNET_YES == match)
8912 {
8913 struct GNUNET_TIME_Relative last_timeout;
8914
8915 /* Re-discovered known path, update timeout */
8917 "# Known DV path refreshed",
8918 1,
8919 GNUNET_NO);
8920 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
8921 pos->timeout =
8923 pos->path_valid_until =
8924 GNUNET_TIME_absolute_max (pos->path_valid_until, path_valid_until);
8925 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
8926 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
8927 if (0 <
8930 if (last_timeout.rel_value_us <
8933 .rel_value_us)
8934 {
8935 /* Some peer send DV learn messages too often, we are learning
8936 the same path faster than it would be useful; do not forward! */
8938 "Rediscovered path too quickly, not forwarding further\n")
8939 ;
8940 return GNUNET_NO;
8941 }
8943 "Refreshed known path to %s valid until %s, forwarding further\n",
8944 GNUNET_i2s (&dv->target),
8946 pos->path_valid_until));
8947 return GNUNET_YES;
8948 }
8949 }
8950 }
8951 /* Count how many shorter paths we have (incl. direct
8952 neighbours) before simply giving up on this one! */
8953 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
8954 {
8955 /* We have a shorter path already! */
8957 "Have many shorter DV paths %s, not forwarding further\n",
8958 GNUNET_i2s (&dv->target));
8959 return GNUNET_NO;
8960 }
8961 /* create new DV path entry */
8963 "Discovered new DV path to %s valid until %s\n",
8964 GNUNET_i2s (&dv->target),
8965 GNUNET_STRINGS_absolute_time_to_string (path_valid_until));
8966 hop = GNUNET_malloc (sizeof(struct DistanceVectorHop)
8967 + sizeof(struct GNUNET_PeerIdentity) * (path_len - 3));
8968 hop->next_hop = next_hop;
8969 hop->dv = dv;
8970 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
8971 memcpy (&hop[1],
8972 &path[2],
8973 sizeof(struct GNUNET_PeerIdentity) * (path_len - 3));
8975 hop->path_valid_until = path_valid_until;
8976 hop->distance = path_len - 3;
8977 hop->pd.aged_rtt = network_latency;
8978 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
8980 next_hop->dv_head,
8981 next_hop->dv_tail,
8982 hop);
8983 if (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
8985 return GNUNET_YES;
8986}
8987
8988
8996static int
8997check_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
8998{
8999 const struct GNUNET_PeerIdentity *my_identity;
9000 uint16_t size = ntohs (dvl->header.size);
9001 uint16_t num_hops = ntohs (dvl->num_hops);
9002 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
9003
9004 (void) cls;
9005 if (size != sizeof(*dvl) + num_hops * sizeof(struct DVPathEntryP))
9006 {
9007 GNUNET_break_op (0);
9008 return GNUNET_SYSERR;
9009 }
9010 if (num_hops > MAX_DV_HOPS_ALLOWED)
9011 {
9012 GNUNET_break_op (0);
9013 return GNUNET_SYSERR;
9014 }
9015
9018
9019 for (unsigned int i = 0; i < num_hops; i++)
9020 {
9021 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
9022 {
9023 GNUNET_break_op (0);
9024 return GNUNET_SYSERR;
9025 }
9026 if (0 == GNUNET_memcmp (my_identity, &hops[i].hop))
9027 {
9028 GNUNET_break_op (0);
9029 return GNUNET_SYSERR;
9030 }
9031 }
9032 return GNUNET_YES;
9033}
9034
9035
9047static void
9048forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
9049 const struct TransportDVLearnMessage *msg,
9050 uint16_t bi_history,
9051 uint16_t nhops,
9052 const struct DVPathEntryP *hops,
9053 struct GNUNET_TIME_Absolute in_time)
9054{
9055 struct DVPathEntryP *dhops;
9056 size_t fwd_size = sizeof(struct TransportDVLearnMessage)
9057 + (nhops + 1) * sizeof(struct DVPathEntryP);
9058 /* Signing is synchronous and the routing calls below copy the message,
9059 so this never outlives the frame. Keeping it on the stack matters:
9060 a hub forwards a DV learn to every eligible neighbour, so this is one
9061 of the hottest allocation sites in the service. Size it by the hop
9062 limit rather than by @a nhops -- @a nhops is only asserted to be below
9063 that limit further down, and a VLA is sized before we get there. */
9064 char fwd_buf[sizeof(struct TransportDVLearnMessage)
9065 + (MAX_DV_HOPS_ALLOWED + 1)
9066 * sizeof(struct DVPathEntryP)] GNUNET_ALIGN;
9067 struct TransportDVLearnMessage *fwd
9068 = (struct TransportDVLearnMessage *) fwd_buf;
9069 struct GNUNET_TIME_Relative nnd;
9070 const struct GNUNET_PeerIdentity *my_identity;
9071 struct VirtualLink *vl;
9072 struct Neighbour *n;
9073
9075 memset (fwd_buf, 0, fwd_size);
9076
9077 /* compute message for forwarding */
9079 "Forwarding DV learn message originating from %s to %s\n",
9080 GNUNET_i2s (&msg->initiator),
9081 GNUNET_i2s2 (next_hop));
9084 fwd->header.size = htons (sizeof(struct TransportDVLearnMessage)
9085 + (nhops + 1) * sizeof(struct DVPathEntryP));
9086 fwd->num_hops = htons (nhops + 1);
9087 fwd->bidirectional = htons (bi_history);
9090 msg->non_network_delay));
9092 fwd->init_sig = msg->init_sig;
9093 fwd->initiator = msg->initiator;
9094 fwd->challenge = msg->challenge;
9095 fwd->monotonic_time = msg->monotonic_time;
9096
9099
9100 dhops = (struct DVPathEntryP *) &fwd[1];
9101 GNUNET_memcpy (dhops, hops, sizeof(struct DVPathEntryP) * nhops);
9102 dhops[nhops].hop = *my_identity;
9103 {
9104 struct DvHopPS dhp = {
9106 .purpose.size = htonl (sizeof(dhp)),
9107 .pred = (0 == nhops) ? msg->initiator : dhops[nhops - 1].hop,
9108 .succ = *next_hop,
9110 };
9111
9113 &dhops[nhops].hop_sig))
9114 return; /* nobody would accept the path without our hop signature */
9115 }
9116 vl = lookup_virtual_link (next_hop);
9117 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
9118 {
9120 &fwd->header,
9122 return;
9123 }
9124 /* Use route via neighbour */
9125 n = lookup_neighbour (next_hop);
9126 if (NULL != n)
9128 &fwd->header,
9130}
9131
9132
9142static int
9144 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time,
9145 const struct GNUNET_PeerIdentity *init,
9147 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
9148{
9149 struct DvInitPS ip = { .purpose.purpose = htonl (
9151 .purpose.size = htonl (sizeof(ip)),
9152 .monotonic_time = sender_monotonic_time,
9153 .challenge = *challenge };
9154
9155 if (
9156 GNUNET_OK !=
9158 &ip,
9159 init_sig,
9160 &init->public_key))
9161 {
9162 GNUNET_break_op (0);
9163 return GNUNET_SYSERR;
9164 }
9165 return GNUNET_OK;
9166}
9167
9168
9173{
9177 const struct TransportDVLearnMessage *dvl;
9178
9182 const struct DVPathEntryP *hops;
9183
9188
9193
9197 unsigned int num_eligible;
9198
9202 unsigned int num_selections;
9203
9207 uint16_t nhops;
9208
9212 uint16_t bi_history;
9213};
9214
9215
9224static int
9225dv_neighbour_selection (void *cls,
9226 const struct GNUNET_PeerIdentity *pid,
9227 void *value)
9228{
9229 struct NeighbourSelectionContext *nsc = cls;
9230
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 nsc->num_eligible++;
9239 return GNUNET_YES;
9240}
9241
9242
9253static int
9254dv_neighbour_transmission (void *cls,
9255 const struct GNUNET_PeerIdentity *pid,
9256 void *value)
9257{
9258 struct NeighbourSelectionContext *nsc = cls;
9259
9261 "transmission %s\n",
9262 GNUNET_i2s (pid));
9263 (void) value;
9264 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
9265 return GNUNET_YES; /* skip initiator */
9266 for (unsigned int i = 0; i < nsc->nhops; i++)
9267 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
9268 return GNUNET_YES;
9269 /* skip peers on path */
9270 for (unsigned int i = 0; i < nsc->num_selections; i++)
9271 {
9272 if (nsc->selections[i] == nsc->num_eligible)
9273 {
9274 forward_dv_learn (pid,
9275 nsc->dvl,
9276 nsc->bi_history,
9277 nsc->nhops,
9278 nsc->hops,
9279 nsc->in_time);
9280 break;
9281 }
9282 }
9283 nsc->num_eligible++;
9284 return GNUNET_YES;
9285}
9286
9287
9331static unsigned int
9332calculate_fork_degree (unsigned int hops_taken,
9333 unsigned int neighbour_count,
9334 unsigned int eligible_count)
9335{
9336 double target_total = 50.0; /* FIXME: use LOG(NSE)? */
9337 double eligible_ratio =
9338 ((double) eligible_count) / ((double) neighbour_count);
9339 double boost_factor = eligible_ratio * eligible_ratio;
9340 unsigned int rnd;
9341 double left;
9342
9343 if (hops_taken >= 64)
9344 {
9345 GNUNET_break (0);
9346 return 0; /* precaution given bitshift below */
9347 }
9348 for (unsigned int i = 1; i < hops_taken; i++)
9349 {
9350 /* For each hop, subtract the expected number of targets
9351 reached at distance d (so what remains divided by 2^d) */
9352 target_total -= (target_total * boost_factor / (1LLU << i));
9353 }
9354 {
9355 double degree = target_total * boost_factor / (1LLU << hops_taken);
9356
9357 rnd = (unsigned int) floor (degree);
9358 /* round up or down probabilistically depending on how close we were
9359 when floor()ing to rnd. NOTE: this must be the fractional part of
9360 @e degree; using `target_total - rnd' here made the condition below
9361 true essentially always, so we always rounded up. */
9362 left = degree - (double) rnd;
9363 }
9364 if (UINT32_MAX * left >
9365 GNUNET_CRYPTO_random_u64 (UINT32_MAX))
9366 rnd++; /* round up */
9368 "Forwarding DV learn message of %u hops %u(/%u/%u) times\n",
9369 hops_taken,
9370 rnd,
9371 eligible_count,
9372 neighbour_count);
9373 return rnd;
9374}
9375
9376
9383static void
9384neighbour_store_dvmono_cb (void *cls, int success)
9385{
9386 struct Neighbour *n = cls;
9387
9388 n->sc = NULL;
9389 if (GNUNET_YES != success)
9391 "Failed to store other peer's monotonic time in peerstore!\n");
9392}
9393
9394
9395static struct GNUNET_TIME_Relative
9397{
9398 struct GNUNET_TIME_Relative host_latency_sum;
9399 struct GNUNET_TIME_Relative latency;
9400 struct GNUNET_TIME_Relative network_latency;
9401 uint16_t nhops = ntohs (dvl->num_hops);;
9402
9403 /* We initiated this, learn the forward path! */
9404 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
9405
9406 // Need also something to lookup initiation time
9407 // to compute RTT! -> add RTT argument here?
9409 dvl->monotonic_time));
9410 /* @e non_network_delay is fully attacker-controlled, and our clock may
9411 simply be behind the initiator's: never assert on this. */
9412 if (latency.rel_value_us < host_latency_sum.rel_value_us)
9413 {
9415 "# DV learn with implausible non-network delay",
9416 1,
9417 GNUNET_NO);
9419 }
9420 // latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
9421 // (based on dvl->challenge, we can identify time of origin!)
9422
9423 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
9424 /* assumption: latency on all links is the same */
9425 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
9426
9427 return network_latency;
9428}
9429
9430
9438static void
9439handle_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
9440{
9441 struct CommunicatorMessageContext *cmc = cls;
9443 int bi_hop;
9444 uint16_t nhops;
9445 uint16_t bi_history;
9446 const struct DVPathEntryP *hops;
9447 int do_fwd;
9448 int did_initiator;
9449 struct GNUNET_TIME_Absolute in_time;
9450 struct Neighbour *n;
9451 const struct GNUNET_PeerIdentity *my_identity;
9452
9453 nhops = ntohs (dvl->num_hops); /* 0 = sender is initiator */
9454 bi_history = ntohs (dvl->bidirectional);
9455 hops = (const struct DVPathEntryP *) &dvl[1];
9456 if (0 == nhops)
9457 {
9458 /* sanity check */
9459 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
9460 {
9461 GNUNET_break (0);
9462 finish_cmc_handling (cmc);
9463 return;
9464 }
9465 /* A zero-hop message we supposedly initiated ourselves would make the
9466 "we are the initiator" branch below read hops[0] and write past the
9467 end of its `path[nhops + 1]' array. */
9469 {
9470 GNUNET_break_op (0);
9471 finish_cmc_handling (cmc);
9472 return;
9473 }
9474 }
9475 else
9476 {
9478 "handle dv learn message last hop %s\n",
9479 GNUNET_i2s (&hops[nhops - 1].hop));
9480 /* sanity check */
9481 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
9482 {
9483 GNUNET_break (0);
9484 finish_cmc_handling (cmc);
9485 return;
9486 }
9487 }
9488
9490 cc = cmc->tc->details.communicator.cc;
9491 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
9492 cc); // FIXME: add bi-directional flag to cc?
9493 in_time = GNUNET_TIME_absolute_get ();
9494
9495 /* continue communicator here, everything else can happen asynchronous! */
9496 finish_cmc_handling (cmc);
9497
9498 n = lookup_neighbour (&dvl->initiator);
9499 if (NULL != n)
9500 {
9501 if ((n->dv_monotime_available == GNUNET_YES) &&
9504 {
9506 "DV learn from %s discarded due to time travel",
9507 GNUNET_i2s (&dvl->initiator));
9509 "# DV learn discarded due to time travel",
9510 1,
9511 GNUNET_NO);
9512 return;
9513 }
9515 &dvl->initiator,
9516 &dvl->challenge,
9517 &dvl->init_sig))
9518 {
9520 "DV learn signature from %s invalid\n",
9521 GNUNET_i2s (&dvl->initiator));
9522 GNUNET_break_op (0);
9523 return;
9524 }
9527 {
9528 if (NULL != n->sc)
9529 {
9531 "store cancel\n");
9533 }
9534 n->sc =
9536 "transport",
9537 &dvl->initiator,
9539 &dvl->monotonic_time,
9540 sizeof(dvl->monotonic_time),
9544 n);
9545 }
9546 }
9547
9550
9551 /* OPTIMIZE-FIXME: asynchronously (!) verify signatures!,
9552 If signature verification load too high, implement random drop strategy */
9553 for (unsigned int i = 0; i < nhops; i++)
9554 {
9555 struct DvHopPS dhp = { .purpose.purpose =
9557 .purpose.size = htonl (sizeof(dhp)),
9558 .pred = (0 == i) ? dvl->initiator : hops[i - 1].hop,
9559 .succ = (nhops == i + 1) ? *my_identity
9560 : hops[i + 1].hop,
9561 .challenge = dvl->challenge };
9562
9563 if (GNUNET_OK !=
9565 &dhp,
9566 &hops[i].hop_sig,
9567 &hops[i].hop.public_key))
9568 {
9570 "DV learn from %s signature of hop %u invalid\n",
9571 GNUNET_i2s (&dvl->initiator),
9572 i);
9574 "signature of hop %s invalid\n",
9575 GNUNET_i2s (&hops[i].hop));
9577 "pred %s\n",
9578 GNUNET_i2s (&dhp.pred));
9580 "succ %s\n",
9581 GNUNET_i2s (&dhp.succ));
9583 "hash %s\n",
9584 GNUNET_sh2s (&dhp.challenge.value));
9585 GNUNET_break_op (0);
9586 return;
9587 }
9588 }
9589 if (GNUNET_EXTRA_LOGGING > 0)
9590 {
9591 char *path;
9592
9593 path = GNUNET_strdup (GNUNET_i2s (&dvl->initiator));
9594 for (unsigned int i = 0; i < nhops; i++)
9595 {
9596 char *tmp;
9597
9598 GNUNET_asprintf (&tmp,
9599 "%s%s%s",
9600 path,
9601 (bi_history & (1 << (nhops - i))) ? "<->" : "-->",
9602 GNUNET_i2s (&hops[i].hop));
9603 GNUNET_free (path);
9604 path = tmp;
9605 }
9607 "Received DVInit via %s%s%s\n",
9608 path,
9609 bi_hop ? "<->" : "-->",
9611 GNUNET_free (path);
9612 }
9613 do_fwd = GNUNET_YES;
9614 if (0 == GNUNET_memcmp (my_identity, &dvl->initiator))
9615 {
9616 struct GNUNET_PeerIdentity path[nhops + 1];
9617 struct GNUNET_TIME_Relative network_latency;
9618
9619 /* We initiated this, learn the forward path! */
9620 path[0] = *my_identity;
9621 path[1] = hops[0].hop;
9622
9623 network_latency = get_network_latency (dvl);
9624
9625 for (unsigned int i = 2; i <= nhops; i++)
9626 {
9627 struct GNUNET_TIME_Relative ilat;
9628
9629 /* assumption: linear latency increase per hop */
9630 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
9631 path[i] = hops[i - 1].hop;
9633 "Learned path with %u hops to %s with latency %s\n",
9634 i,
9635 GNUNET_i2s (&path[i]),
9637 learn_dv_path (path,
9638 i + 1,
9639 ilat,
9642 }
9643 /* as we initiated, do not forward again (would be circular!) */
9644 do_fwd = GNUNET_NO;
9645 return;
9646 }
9647 if (bi_hop)
9648 {
9649 /* last hop was bi-directional, we could learn something here! */
9650 struct GNUNET_PeerIdentity path[nhops + 2];
9651 struct GNUNET_TIME_Relative ilat;
9652 struct GNUNET_TIME_Relative network_latency;
9653
9654 path[0] = *my_identity;
9655 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
9656 for (unsigned int i = 0; i < nhops; i++)
9657 {
9658 int iret;
9659
9660 if (0 == (bi_history & (1 << i)))
9661 break; /* i-th hop not bi-directional, stop learning! */
9662 if (i == nhops - 1)
9663 {
9664 path[i + 2] = dvl->initiator;
9665 }
9666 else
9667 {
9668 path[i + 2] = hops[nhops - i - 2].hop;
9669 }
9670
9672 "Learned inverse path with %u hops to %s\n",
9673 i + 2,
9674 GNUNET_i2s (&path[i + 2]));
9675 network_latency = get_network_latency (dvl);
9676 ilat = GNUNET_TIME_relative_multiply (network_latency, i + 2);
9677 iret = learn_dv_path (path,
9678 i + 3,
9679 ilat,
9682 if (GNUNET_SYSERR == iret)
9683 {
9684 /* path invalid or too long to be interesting for US, thus should also
9685 not be interesting to our neighbours, cut path when forwarding to
9686 'i' hops, except of course for the one that goes back to the
9687 initiator */
9689 "# DV learn not forwarded due invalidity of path",
9690 1,
9691 GNUNET_NO);
9692 do_fwd = GNUNET_NO;
9693 break;
9694 }
9695 if ((GNUNET_NO == iret) && (nhops == i + 1))
9696 {
9697 /* we have better paths, and this is the longest target,
9698 so there cannot be anything interesting later */
9700 "# DV learn not forwarded, got better paths",
9701 1,
9702 GNUNET_NO);
9703 do_fwd = GNUNET_NO;
9704 break;
9705 }
9706 }
9707 }
9708 if (MAX_DV_HOPS_ALLOWED == nhops)
9709 {
9710 /* At limit, we're out of here! */
9711 return;
9712 }
9713
9714 /* Forward to initiator, if path non-trivial and possible */
9715 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
9716 did_initiator = GNUNET_NO;
9717 if ((1 <= nhops) &&
9718 (GNUNET_YES ==
9720 {
9721 /* send back to origin! */
9723 "Sending DVL back to initiator %s\n",
9724 GNUNET_i2s (&dvl->initiator));
9725 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
9726 did_initiator = GNUNET_YES;
9727 }
9728 /* We forward under two conditions: either we still learned something
9729 ourselves (do_fwd), or the path was darn short and thus the initiator is
9730 likely to still be very interested in this (and we did NOT already
9731 send it back to the initiator) */
9732 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
9733 (GNUNET_NO == did_initiator)))
9734 {
9735 /* Pick random neighbours that are not yet on the path */
9736 struct NeighbourSelectionContext nsc;
9737 unsigned int n_cnt;
9738 unsigned int n_eligible;
9739
9741 nsc.nhops = nhops;
9742 nsc.dvl = dvl;
9743 nsc.bi_history = bi_history;
9744 nsc.hops = hops;
9745 nsc.in_time = in_time;
9746 nsc.num_eligible = 0;
9749 &nsc);
9750 if (0 == nsc.num_eligible)
9751 return; /* done here, cannot forward to anyone else */
9752 n_eligible = nsc.num_eligible;
9753 nsc.num_selections = calculate_fork_degree (nhops, n_cnt, n_eligible);
9754 nsc.num_selections =
9757 "Forwarding DVL to %u other peers\n",
9758 nsc.num_selections);
9759 /* #dv_neighbour_transmission() counts ELIGIBLE peers only, so the
9760 offsets must be drawn from that range -- drawing from the total
9761 number of neighbours made us silently forward to fewer peers than
9762 #calculate_fork_degree() asked for. */
9763 for (unsigned int i = 0; i < nsc.num_selections; i++)
9764 nsc.selections[i] =
9765 (nsc.num_selections == n_eligible)
9766 ? i /* all were selected, avoid collisions by chance */
9767 : GNUNET_CRYPTO_random_u32 (n_eligible);
9768 nsc.num_eligible = 0;
9771 &nsc);
9772 }
9773}
9774
9775
9783static int
9784check_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
9785{
9786 uint16_t size = ntohs (dvb->header.size);
9787 uint16_t num_hops = ntohs (dvb->num_hops);
9788 uint16_t total_hops = ntohs (dvb->total_hops);
9789 uint16_t orig_size = ntohs (dvb->orig_size);
9790 const struct GNUNET_PeerIdentity *hops =
9791 (const struct GNUNET_PeerIdentity *) &dvb[1];
9792 const struct GNUNET_PeerIdentity *my_identity;
9793
9794 (void) cls;
9795 if (size < sizeof(*dvb) + num_hops * sizeof(struct GNUNET_PeerIdentity)
9796 + sizeof(struct GNUNET_MessageHeader))
9797 {
9798 GNUNET_break_op (0);
9799 return GNUNET_SYSERR;
9800 }
9801 if ((num_hops > MAX_DV_HOPS_ALLOWED) ||
9802 (total_hops > MAX_DV_HOPS_ALLOWED))
9803 {
9804 GNUNET_break_op (0);
9805 return GNUNET_SYSERR;
9806 }
9807 /* #decaps_dv_box_cb() derives a VLA size from
9808 orig_size - sizeof(*dvb) - total_hops * sizeof (struct
9809 GNUNET_PeerIdentity); make sure that cannot underflow and that the
9810 remainder can plausibly hold a payload header plus a message. */
9811 if ((orig_size < size) ||
9812 (orig_size < sizeof(*dvb)
9813 + total_hops * sizeof(struct GNUNET_PeerIdentity)
9814 + sizeof(struct TransportDVBoxPayloadP)
9815 + sizeof(struct GNUNET_MessageHeader)))
9816 {
9817 GNUNET_break_op (0);
9818 return GNUNET_SYSERR;
9819 }
9820
9823
9824 /* This peer must not be on the path */
9825 for (unsigned int i = 0; i < num_hops; i++)
9826 if (0 == GNUNET_memcmp (&hops[i], my_identity))
9827 {
9828 GNUNET_break_op (0);
9829 return GNUNET_SYSERR;
9830 }
9831 return GNUNET_YES;
9832}
9833
9834
9847static void
9848forward_dv_box (struct Neighbour *next_hop,
9849 struct TransportDVBoxMessage *hdr,
9850 uint16_t total_hops,
9851 uint16_t num_hops,
9852 const struct GNUNET_PeerIdentity *hops,
9853 const void *enc_payload,
9854 uint16_t enc_payload_size)
9855{
9856 struct VirtualLink *vl = next_hop->vl;
9857 struct PendingMessage *pm;
9858 size_t msg_size = sizeof(struct TransportDVBoxMessage)
9859 + num_hops * sizeof(struct GNUNET_PeerIdentity)
9860 + enc_payload_size;
9861 char *buf;
9862 char msg_buf[msg_size] GNUNET_ALIGN;
9863 struct GNUNET_PeerIdentity *dhops;
9864
9865 hdr->num_hops = htons (num_hops);
9866 hdr->total_hops = htons (total_hops);
9867 hdr->header.size = htons (msg_size);
9868 memcpy (msg_buf, hdr, sizeof(*hdr));
9869 dhops = (struct GNUNET_PeerIdentity *) &msg_buf[sizeof(struct
9871 ;
9872 memcpy (dhops, hops, num_hops * sizeof(struct GNUNET_PeerIdentity));
9873 memcpy (&dhops[num_hops], enc_payload, enc_payload_size);
9874
9875 if (GNUNET_YES == ntohl (hdr->without_fc))
9876 {
9878 "Forwarding control message (payload size %u) in DV Box to next hop %s (%u/%u) \n",
9879 enc_payload_size,
9880 GNUNET_i2s (&next_hop->pid),
9881 (unsigned int) num_hops,
9882 (unsigned int) total_hops);
9883 route_via_neighbour (next_hop, (const struct
9884 GNUNET_MessageHeader *) msg_buf,
9886 }
9887 else
9888 {
9889 pm = GNUNET_malloc (sizeof(struct PendingMessage) + msg_size);
9891 "2 created pm %p storing vl %p \n",
9892 pm,
9893 vl);
9894 pm->pmt = PMT_DV_BOX;
9895 pm->vl = vl;
9896 pm->target = next_hop->pid;
9900 pm->bytes_msg = msg_size;
9901 buf = (char *) &pm[1];
9902 memcpy (buf, msg_buf, msg_size);
9903
9905 "Created pending message %" PRIu64
9906 " for DV Box with next hop %s (%u/%u)\n",
9907 pm->logging_uuid,
9908 GNUNET_i2s (&next_hop->pid),
9909 (unsigned int) num_hops,
9910 (unsigned int) total_hops);
9911
9912 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
9913 {
9915 vl->pending_msg_head,
9916 vl->pending_msg_tail,
9917 pm);
9918
9920 }
9921 else
9922 {
9924 "The virtual link is not ready for forwarding a DV Box with payload, storing PendingMessage in ring buffer.\n");
9925
9927 {
9929
9930 GNUNET_free (pm_old);
9931 }
9934 {
9937 }
9938 else
9940
9942 "%u items stored in DV ring buffer\n",
9945 }
9946 }
9947}
9948
9949
9955static void
9956free_backtalker (struct Backtalker *b)
9957{
9958 if (NULL != b->get)
9959 {
9961 b->get = NULL;
9962 GNUNET_assert (NULL != b->cmc);
9964 b->cmc = NULL;
9965 }
9966 if (NULL != b->task)
9967 {
9969 b->task = NULL;
9970 }
9971 if (NULL != b->sc)
9972 {
9974 "store cancel\n");
9976 b->sc = NULL;
9977 }
9979 "Removing backtalker for %s\n",
9980 GNUNET_i2s (&b->pid));
9982 GNUNET_YES ==
9984 GNUNET_free (b);
9985}
9986
9987
9996static int
9997free_backtalker_cb (void *cls,
9998 const struct GNUNET_PeerIdentity *pid,
9999 void *value)
10000{
10001 struct Backtalker *b = value;
10002
10003 (void) cls;
10004 (void) pid;
10005 free_backtalker (b);
10006 return GNUNET_OK;
10007}
10008
10009
10015static void
10016backtalker_timeout_cb (void *cls)
10017{
10018 struct Backtalker *b = cls;
10019
10021 "backtalker timeout.\n");
10022 b->task = NULL;
10024 {
10026 return;
10027 }
10028 /* A monotime store may well still be in flight -- @e timeout is about how
10029 long the *peer* has been quiet, and says nothing about PEERSTORE. This
10030 used to `GNUNET_assert (NULL == b->sc)', which aborted the service in
10031 exactly that case. #free_backtalker() cancels the store. */
10032 free_backtalker (b);
10033}
10034
10035
10044static void
10045backtalker_monotime_cb (void *cls,
10046 const struct GNUNET_PEERSTORE_Record *record,
10047 const char *emsg)
10048{
10049 struct Backtalker *b = cls;
10050 struct GNUNET_TIME_AbsoluteNBO *mtbe;
10051 struct GNUNET_TIME_Absolute mt;
10052
10053 (void) emsg;
10054 if (NULL == record)
10055 {
10056 struct CommunicatorMessageContext *cmc;
10057
10058 /* we're done with #backtalker_monotime_cb() invocations,
10059 continue normal processing */
10060 b->get = NULL;
10061 GNUNET_assert (NULL != b->cmc);
10062 /* Take @e cmc out of @a b *before* dispatching: the dispatch runs
10063 arbitrary message handling, and writing `b->cmc = NULL' afterwards
10064 is a write to freed memory should anything on that path have
10065 released @a b. #free_backtalker() keys its "must finish the parked
10066 cmc" decision off @e get, which is already NULL here, so clearing
10067 @e cmc early cannot lose the message either. */
10068 cmc = b->cmc;
10069 b->cmc = NULL;
10070 cmc->mh = (const struct GNUNET_MessageHeader *) &b[1];
10071 if (0 != b->body_size)
10073 else
10074 finish_cmc_handling (cmc);
10075 return;
10076 }
10077 if (sizeof(*mtbe) != record->value_size)
10078 {
10080 GNUNET_break (0);
10081 return;
10082 }
10083 mtbe = record->value;
10084 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
10085 if (mt.abs_value_us > b->monotonic_time.abs_value_us)
10086 {
10088 "Backtalker message from %s dropped, monotime in the past\n",
10089 GNUNET_i2s (&b->pid));
10091 GST_stats,
10092 "# Backchannel messages dropped: monotonic time not increasing",
10093 1,
10094 GNUNET_NO);
10095 b->monotonic_time = mt;
10096 /* Setting body_size to 0 prevents call to #forward_backchannel_payload()
10097 */
10098 b->body_size = 0;
10099 }
10101}
10102
10103
10111static void
10112backtalker_monotime_store_cb (void *cls, int success)
10113{
10114 struct Backtalker *b = cls;
10115
10116 if (GNUNET_OK != success)
10117 {
10119 "Failed to store backtalker's monotonic time in PEERSTORE!\n");
10120 }
10121 b->sc = NULL;
10122 /* @e task is armed for the whole life of @a b -- #backtalker_timeout_cb()
10123 re-arms itself whenever @e timeout has moved forward -- so there is
10124 nothing to do here beyond releasing the store. It used to cancel and
10125 re-add the task, which is what made the task's existence depend on this
10126 callback ever running. */
10127 GNUNET_assert (NULL != b->task);
10128}
10129
10130
10136static void
10138{
10139 struct GNUNET_TIME_AbsoluteNBO mtbe;
10140
10141 /* At most one store may be outstanding. The value we are about to write
10142 supersedes whatever the previous one carried, and leaving the old
10143 context alive means its completion clears @e sc while the newer store
10144 is still in flight -- after which the next update sees a NULL @e sc and
10145 starts a third one. Cancelling is also what keeps @e sc from being
10146 silently overwritten and leaked.
10147
10148 Note what this must NOT do: touch @e task. That task is the only thing
10149 that ever releases a `struct CommunicatorMessageContext' parked in
10150 @e cmc, and cancelling it here left its re-arming up to
10151 #backtalker_monotime_store_cb() -- i.e. up to PEERSTORE answering. A
10152 lost store completion then stalled the parked communicator client for
10153 the life of the process. #backtalker_timeout_cb() already re-arms
10154 itself against the current @e timeout, so the task needs no help. */
10155 if (NULL != b->sc)
10156 {
10158 "Superseding in-flight backtalker monotime store %p\n",
10159 b->sc);
10161 b->sc = NULL;
10162 }
10164 b->sc =
10166 "transport",
10167 &b->pid,
10169 &mtbe,
10170 sizeof(mtbe),
10174 b);
10175}
10176
10177
10186static void
10188 const struct TransportDVBoxMessage *dvb,
10189 const struct GNUNET_ShortHashCode *km)
10190{
10191 const unsigned char *hdr;
10192 size_t hdr_len;
10194
10195 key = (struct GNUNET_CRYPTO_AeadSecretKey*) km;
10196 /* We are the ultimate target, so #handle_dv_box() has established that no
10197 hop entries are left: the ciphertext directly follows the header, and
10198 its length is what we actually received. Deriving it from orig_size
10199 and total_hops instead would only be equivalent if every forwarder
10200 accounted its skipped hops exactly. */
10201 hdr = (const unsigned char *) &dvb[1];
10202 {
10203 uint16_t size = ntohs (dvb->header.size);
10204
10205 if (size < sizeof(*dvb)
10206 + sizeof(struct TransportDVBoxPayloadP)
10207 + sizeof(struct GNUNET_MessageHeader))
10208 {
10209 GNUNET_break_op (0);
10210 finish_cmc_handling (cmc);
10211 return;
10212 }
10213 hdr_len = size - sizeof(*dvb);
10214 }
10215
10216 /* begin actual decryption */
10217 {
10218 struct Backtalker *b;
10219 struct GNUNET_TIME_Absolute monotime;
10220 struct TransportDVBoxPayloadP *ppay;
10221 unsigned char pt[hdr_len + sizeof *ppay] GNUNET_ALIGN;
10222 unsigned char *body;
10223 const struct GNUNET_MessageHeader *mh;
10224
10225 ppay = (struct TransportDVBoxPayloadP *) pt;
10226 body = &pt[sizeof *ppay];
10227 GNUNET_assert (hdr_len >=
10228 sizeof(*ppay) + sizeof(struct GNUNET_MessageHeader));
10229 if (GNUNET_OK != GNUNET_CRYPTO_aead_decrypt (hdr_len,
10230 hdr,
10231 0,
10232 NULL,
10233 key,
10234 &dvb->iv,
10235 &dvb->mac,
10236 pt))
10237 {
10239 "Error decrypting DV payload header\n");
10240 GNUNET_break_op (0);
10241 finish_cmc_handling (cmc);
10242 return;
10243 }
10244 mh = (const struct GNUNET_MessageHeader *) body;
10245 /* NOTE: this used to compare against `sizeof (body)', i.e. the size of
10246 a pointer, which meant only 8-byte payloads were ever accepted. */
10247 if (ntohs (mh->size) != hdr_len - sizeof(*ppay))
10248 {
10249 GNUNET_break_op (0);
10250 finish_cmc_handling (cmc);
10251 return;
10252 }
10253 /* need to prevent box-in-a-box (and DV_LEARN) so check inbox type! */
10254 switch (ntohs (mh->type))
10255 {
10257 GNUNET_break_op (0);
10258 finish_cmc_handling (cmc);
10259 return;
10260
10262 GNUNET_break_op (0);
10263 finish_cmc_handling (cmc);
10264 return;
10265
10266 default:
10267 /* permitted, continue */
10268 break;
10269 }
10270 monotime = GNUNET_TIME_absolute_ntoh (ppay->monotonic_time);
10272 "Decrypted backtalk from %s\n",
10273 GNUNET_i2s (&ppay->sender));
10275 &ppay->sender);
10276 if ((NULL != b) && (monotime.abs_value_us < b->monotonic_time.abs_value_us))
10277 {
10279 GST_stats,
10280 "# Backchannel messages dropped: monotonic time not increasing",
10281 1,
10282 GNUNET_NO);
10283 finish_cmc_handling (cmc);
10284 return;
10285 }
10286 if ((NULL == b) ||
10287 (0 != GNUNET_memcmp (&b->last_ephemeral, &dvb->ephemeral_key)))
10288 {
10289 /* Check signature */
10290 const struct GNUNET_PeerIdentity *my_identity;
10291 struct EphemeralConfirmationPS ec;
10292
10295
10296 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
10297 ec.target = *my_identity;
10298 ec.ephemeral_key = dvb->ephemeral_key;
10299 ec.purpose.size = htonl (sizeof(ec));
10300 ec.sender_monotonic_time = ppay->monotonic_time;
10301 if (
10302 GNUNET_OK !=
10305 &ec,
10306 &ppay->sender_sig,
10307 &ppay->sender.public_key))
10308 {
10309 /* Signature invalid, discard! */
10310 GNUNET_break_op (0);
10311 finish_cmc_handling (cmc);
10312 return;
10313 }
10314 }
10315 /* Update sender, we now know the real origin! */
10317 "DVBox received for me from %s via %s\n",
10318 GNUNET_i2s2 (&ppay->sender),
10319 GNUNET_i2s (&cmc->im.sender));
10320 cmc->im.sender = ppay->sender;
10321
10322 if (NULL != b)
10323 {
10324 /* update key cache and mono time */
10325 b->last_ephemeral = dvb->ephemeral_key;
10326 b->monotonic_time = monotime;
10328 b->timeout =
10330 cmc->mh = mh;
10332 return;
10333 }
10334 /* setup data structure to cache signature AND check
10335 monotonic time with PEERSTORE before forwarding backchannel payload */
10336 b = GNUNET_malloc (sizeof(struct Backtalker) + (hdr_len - sizeof(*ppay)));
10337 b->pid = ppay->sender;
10338 b->body_size = hdr_len - sizeof(*ppay);
10339 memcpy (&b[1], body, hdr_len - sizeof(*ppay));
10343 &b->pid,
10344 b,
10346 b->monotonic_time = monotime; /* NOTE: to be checked still! */
10347 b->cmc = cmc;
10348 b->timeout =
10351 b->get =
10353 "transport",
10354 &b->pid,
10357 b);
10358 } /* end actual decryption */
10359}
10360
10361
10369static void
10370handle_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
10371{
10372 struct CommunicatorMessageContext *cmc = cls;
10373 uint16_t size = ntohs (dvb->header.size) - sizeof(*dvb);
10374 uint16_t num_hops = ntohs (dvb->num_hops);
10375 const struct GNUNET_PeerIdentity *hops =
10376 (const struct GNUNET_PeerIdentity *) &dvb[1];
10377 const char *enc_payload = (const char *) &hops[num_hops];
10378 uint16_t enc_payload_size =
10379 size - (num_hops * sizeof(struct GNUNET_PeerIdentity));
10380 const struct GNUNET_PeerIdentity *my_identity;
10381
10384
10385 if (GNUNET_EXTRA_LOGGING > 0)
10386 {
10387 char *path;
10388
10390 for (unsigned int i = 0; i < num_hops; i++)
10391 {
10392 char *tmp;
10393
10394 GNUNET_asprintf (&tmp, "%s->%s", path, GNUNET_i2s (&hops[i]));
10395 GNUNET_free (path);
10396 path = tmp;
10397 }
10399 "Received DVBox with remaining path %s\n",
10400 path);
10401 GNUNET_free (path);
10402 }
10403
10404 if (num_hops > 0)
10405 {
10406 /* We're trying from the end of the hops array, as we may be
10407 able to find a shortcut unknown to the origin that way */
10408 for (int i = num_hops - 1; i >= 0; i--)
10409 {
10410 struct Neighbour *n;
10411
10412 if (0 == GNUNET_memcmp (&hops[i], my_identity))
10413 {
10414 GNUNET_break_op (0);
10415 finish_cmc_handling (cmc);
10416 return;
10417 }
10418 n = lookup_neighbour (&hops[i]);
10419 if (NULL == n)
10420 continue;
10422 "Skipping %u/%u hops ahead while routing DV Box\n",
10423 i,
10424 num_hops);
10425
10426 forward_dv_box (n,
10427 (struct TransportDVBoxMessage *) dvb,
10428 /* we strip i+1 entries, and the receiver reconstructs
10429 the ciphertext offset from total_hops */
10430 ntohs (dvb->total_hops) + i + 1,
10431 num_hops - i - 1, /* number of hops left */
10432 &hops[i + 1], /* remaining hops */
10433 enc_payload,
10434 enc_payload_size);
10436 "# DV hops skipped routing boxes",
10437 i,
10438 GNUNET_NO);
10440 "# DV boxes routed (total)",
10441 1,
10442 GNUNET_NO);
10443 finish_cmc_handling (cmc);
10444 return;
10445 }
10446 /* Woopsie, next hop not in neighbours, drop! */
10448 "# DV Boxes dropped: next hop unknown",
10449 1,
10450 GNUNET_NO);
10451 finish_cmc_handling (cmc);
10452 return;
10453 }
10454 /* We are the target. Unbox and handle message. */
10456 "# DV boxes opened (ultimate target)",
10457 1,
10458 GNUNET_NO);
10459 cmc->total_hops = ntohs (dvb->total_hops);
10460
10461 {
10462 // DH key derivation with received DV, could be garbage.
10464 struct GNUNET_ShortHashCode km;
10465
10467 if ( (NULL == my_private_key) ||
10468 (GNUNET_OK !=
10470 &dvb->ephemeral_key,
10471 &km)) )
10472 {
10473 GNUNET_break_op (0);
10474 finish_cmc_handling (cmc);
10475 return;
10476 }
10477 decaps_dv_box_cont (cmc,
10478 dvb,
10479 &km);
10480 }
10481}
10482
10483
10491static int
10492check_incoming_msg (void *cls,
10493 const struct GNUNET_TRANSPORT_IncomingMessage *im)
10494{
10495 struct TransportClient *tc = cls;
10496
10497 if (CT_COMMUNICATOR != tc->type)
10498 {
10499 GNUNET_break (0);
10500 return GNUNET_SYSERR;
10501 }
10503 return GNUNET_OK;
10504}
10505
10506
10511{
10515 const char *address;
10516
10520 struct ValidationState *vs;
10521};
10522
10523
10533static int
10534check_known_address (void *cls,
10535 const struct GNUNET_PeerIdentity *pid,
10536 void *value)
10537{
10538 struct CheckKnownAddressContext *ckac = cls;
10539 struct ValidationState *vs = value;
10540
10541 (void) pid;
10542 if (0 != strcmp (vs->address, ckac->address))
10543 return GNUNET_OK;
10544 ckac->vs = vs;
10545 return GNUNET_NO;
10546}
10547
10548
10554static void
10555validation_start_cb (void *cls);
10556
10557
10565static void
10567 struct GNUNET_TIME_Absolute new_time)
10568{
10570 struct ValidationState *next;
10571
10572 /* NOTE: "be lazy" must not apply while #validation_task is unset. Our
10573 only caller that can leave it unset is #validation_start_cb(), which
10574 NULLs it on entry and relies on us to arm it again -- and nothing else
10575 ever does. Returning early there stops address (re)validation and the
10576 #suggest_to_connect() retries that go with it for *every* peer, for
10577 good. */
10578 if ((new_time.abs_value_us == vs->next_challenge.abs_value_us) &&
10579 (NULL != validation_task) &&
10580 (NULL != vs->hn))
10581 return; /* be lazy */
10582 vs->next_challenge = new_time;
10583 if (NULL == vs->hn)
10584 vs->hn =
10586 else
10589 (NULL != validation_task))
10590 return;
10591 if (NULL != validation_task)
10593 /* Arm for the earliest entry in the heap, which need NOT be @a vs:
10594 #validation_start_cb() calls us with @e validation_task unset and with
10595 @a vs already pushed out to its new @e challenge_backoff, which doubles
10596 up to #MAX_VALIDATION_CHALLENGE_FREQ (one day) while an address stays
10597 unanswered. Arming for @a vs there parks the single global validation
10598 task for that long, no matter how many other addresses are due right
10599 now -- and every address of a peer we cannot reach (NAT) is such an
10600 address. Everything that needs a validation then stops with it:
10601 bringing a lost link back up, and confirming the link to a peer that
10602 contacted us. */
10604 if (NULL == next)
10605 return;
10606 /* randomize a bit */
10611 delta),
10613 NULL);
10614}
10615
10616
10635static void
10637{
10638 vs->challenge_backoff = FAST_VALIDATION_CHALLENGE_FREQ;
10639}
10640
10641
10652static enum GNUNET_GenericReturnValue
10653revalidate_now_cb (void *cls,
10654 const struct GNUNET_PeerIdentity *pid,
10655 void *value)
10656{
10657 struct ValidationState *vs = value;
10658 const struct GNUNET_TIME_Absolute now =
10660
10661 (void) cls;
10662 (void) pid;
10663 /* What #start_address_validation() does for an address it hears about
10664 again, but without needing the address string. */
10665 speed_up_challenge (vs);
10666 if (GNUNET_TIME_absolute_cmp (vs->first_challenge_use, >, now))
10667 vs->first_challenge_use = now;
10670 vs->challenge_backoff));
10671 return GNUNET_OK;
10672}
10673
10674
10681static void
10683 const char *address)
10684{
10685 struct GNUNET_TIME_Absolute now;
10686 struct ValidationState *vs;
10687 struct CheckKnownAddressContext ckac = { .address = address, .vs = NULL };
10688
10690 pid,
10692 &ckac);
10694 if (NULL != (vs = ckac.vs))
10695 {
10696 const struct VirtualLink *vl = lookup_virtual_link (pid);
10697
10698 /* Speed up retrying the validation if 'vs' is not currently valid, or if
10699 * we have no confirmed virtual link to @a pid. In the latter case the
10700 * address may still be well inside its validity window -- but the link is
10701 * down, and #handle_validation_response() is the only thing that can
10702 * rebuild it and tell CORE about the peer again. Without this we would
10703 * wait for @e revalidation_task, which does not fire until
10704 * #ADDRESS_VALIDATION_LIFETIME is nearly over. */
10705 if ((vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us) ||
10706 (NULL == vl) ||
10707 (GNUNET_NO == vl->confirmed))
10708 {
10709 /* reduce backoff as we got a fresh advertisement */
10710 speed_up_challenge (vs);
10711 /* A successful validation parks @e first_challenge_use just before
10712 @e validated_until, so that the *next* challenge is not used before
10713 the current validation is about to expire. #validation_start_cb()
10714 refuses to run while that time is still in the future, so pulling
10715 @e next_challenge in without this would only make it reschedule
10716 itself four hours out. The challenge has not been used yet, so
10717 moving the start of its window to now stays truthful -- it is what
10718 the fresh-@a vs path below does as well. */
10719 if (GNUNET_TIME_absolute_cmp (vs->first_challenge_use, >, now))
10720 vs->first_challenge_use = now;
10723 vs->challenge_backoff));
10724 }
10725 return;
10726 }
10727 vs = GNUNET_new (struct ValidationState);
10728 vs->pid = *pid;
10729 vs->valid_until =
10731 vs->first_challenge_use = now;
10732 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
10733 GNUNET_CRYPTO_random_block (&vs->challenge,
10734 sizeof(vs->challenge));
10735 vs->address = GNUNET_strdup (address);
10736 {
10737 /* The peer identity MUST be part of @e hc: two peers behind the same NAT
10738 advertise the very same address string (`PROTO-IP:0'), and with an
10739 address-only key the second one's #revalidation_map entry would be
10740 rejected as a duplicate of the first one's. */
10741 struct GNUNET_HashContext *hsh;
10742
10744 GNUNET_CRYPTO_hash_context_read (hsh, vs->address, strlen (vs->address));
10745 GNUNET_CRYPTO_hash_context_read (hsh, &vs->pid, sizeof(vs->pid));
10746 GNUNET_CRYPTO_hash_context_finish (hsh, &vs->hc);
10747 }
10749 "Starting address validation `%s' of peer %s using challenge %s\n",
10750 address,
10751 GNUNET_i2s (pid),
10752 GNUNET_sh2s (&vs->challenge.value));
10756 &vs->pid,
10757 vs,
10760}
10761
10762
10763static struct Queue *
10764find_queue (const struct GNUNET_PeerIdentity *pid, const char *address);
10765
10766
10767static void
10768suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address);
10769
10770
10771static void
10772hello_for_incoming_cb (void *cls,
10773 const struct GNUNET_PeerIdentity *pid,
10774 const char *uri)
10775{
10776 struct Queue *q;
10777 int pfx_len;
10778 const char *eou;
10779 char *address;
10780 (void) cls;
10781
10782 eou = strstr (uri,
10783 "://");
10784 if ((NULL == eou) || (eou == uri))
10785 {
10786 /* @a uri comes from a HELLO some remote peer published. */
10787 GNUNET_break_op (0);
10788 return;
10789 }
10790 pfx_len = eou - uri;
10791 eou += 3;
10793 "%.*s-%s",
10794 pfx_len,
10795 uri,
10796 eou);
10797
10799 "helo for client %s\n",
10800 address);
10801 q = find_queue (pid, address);
10802 if (NULL == q)
10803 {
10805 }
10806 else
10809}
10810
10811
10834static const struct GNUNET_MessageHeader *
10836{
10837 const struct GNUNET_MessageHeader *hello;
10838
10839 if ((NULL == record) ||
10840 (NULL == record->value) ||
10841 (record->value_size < sizeof(*hello)))
10842 {
10843 GNUNET_break_op (0);
10844 return NULL;
10845 }
10846 hello = record->value;
10847 if (ntohs (hello->size) > record->value_size)
10848 {
10849 GNUNET_break_op (0);
10850 return NULL;
10851 }
10852 return hello;
10853}
10854
10855
10863static void
10864handle_hello_for_incoming (void *cls,
10865 const struct GNUNET_PEERSTORE_Record *record,
10866 const char *emsg)
10867{
10868 struct IncomingRequest *ir = cls;
10870 const struct GNUNET_MessageHeader *hello;
10871 const struct GNUNET_PeerIdentity *my_identity;
10872
10873 if (NULL != emsg)
10874 {
10876 "Got failure from PEERSTORE: %s\n",
10877 emsg);
10879 return;
10880 }
10881 if (NULL == record)
10882 {
10883 GNUNET_break (0);
10885 return;
10886 }
10887 hello = hello_from_record (record);
10888 if (NULL == hello)
10889 {
10890 /* MUST still ask for the next record: a bad one is not a reason to
10891 stall this monitor forever. */
10893 return;
10894 }
10896 if (NULL == my_identity)
10897 {
10899 return;
10900 }
10901 if (0 == GNUNET_memcmp (&record->peer, my_identity))
10902 {
10904 return;
10905 }
10906 if (0 != GNUNET_memcmp (&record->peer, &ir->pid))
10907 {
10908 /* Not the peer this request is about. */
10910 return;
10911 }
10912 parser = GNUNET_HELLO_parser_from_msg (hello, &record->peer);
10913 if (NULL != parser)
10914 {
10917 NULL);
10918 GNUNET_HELLO_parser_free (parser);
10919 }
10920 /* MUST ask for the next record, or this monitor stalls after one HELLO */
10922}
10923
10924
10925static void
10927{
10929 "Error in PEERSTORE monitoring\n");
10930}
10931
10932
10933static void
10935{
10937 "Done with initial PEERSTORE iteration during monitoring\n");
10938}
10939
10940
10949static void
10950try_to_bring_link_up (const struct GNUNET_PeerIdentity *pid)
10951{
10952 struct Neighbour *n;
10953 struct IncomingRequest *ir;
10954
10955 if (GNUNET_YES == in_shutdown)
10956 return;
10957 /* (1) Addresses we already track. These outlive the queues, which is the
10958 point: once a link is down the queue that carried it is usually gone,
10959 so there is no address string left for #start_address_validation(). */
10961 pid,
10963 NULL);
10964 /* (2) Queues we still have; may cover an address with no validation state
10965 yet. After (1), because it may insert into #validation_map. */
10966 n = lookup_neighbour (pid);
10967 if (NULL != n)
10968 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
10969 start_address_validation (pid, q->address);
10970 /* (3) Failing that, look for an address in PEERSTORE. */
10971 for (ir = ir_head; NULL != ir; ir = ir->next)
10972 {
10973 if (0 == GNUNET_memcmp (&ir->pid, pid))
10974 return; /* we are already trying */
10975 }
10976 ir = GNUNET_new (struct IncomingRequest);
10977 ir->pid = *pid;
10979 /* Monitor only @a pid: with NULL every request sees every HELLO in
10980 PEERSTORE, so each of the up to #MAX_INCOMING_REQUEST requests started
10981 a connection attempt and an address validation for peers it was not
10982 created for. */
10984 GNUNET_YES,
10985 "peerstore",
10986 &ir->pid,
10989 NULL,
10991 NULL,
10993 ir);
10994 ir_total++;
10995 /* Bound attempts we do in parallel here, might otherwise get excessive.
10996 Drop the OLDEST request: #ir_head is the one we just inserted, so
10997 freeing that would immediately undo the work above. */
11000}
11001
11002
11010static void
11013{
11014 struct VirtualLink *vl;
11015 struct Neighbour *n;
11016 struct GNUNET_PeerIdentity sender;
11017
11018 sender = cmc->im.sender;
11019 vl = lookup_virtual_link (&sender);
11020 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
11021 {
11022 // route_control_message_without_fc (&cmc->im.sender,
11024 &tvr.header,
11026 }
11027 else
11028 {
11029 /* Use route via neighbour */
11030 n = lookup_neighbour (&sender);
11031 if (NULL != n)
11032 route_via_neighbour (n, &tvr.header,
11035 }
11036
11037 finish_cmc_handling (cmc);
11038 /* An *unconfirmed* link is not a link -- it carries nothing, and CORE has
11039 never been told about the peer. Bailing out on one merely because it
11040 exists is what deadlocks a pair of peers into permanent one-way state:
11041 the challenger validated us, so it believes the connection is up and
11042 starts sending us FLOW_CONTROL; #handle_flow_control() answers an
11043 unknown sender by allocating exactly such an unconfirmed link; and from
11044 then on every challenge it retransmits lands here, gets a response --
11045 which keeps *its* side confirmed and its RTT healthy -- and returns
11046 without ever validating an address of its own. The unconfirmed link
11047 reaps itself after #UNCONFIRMED_LINK_TIMEOUT, but the next FLOW_CONTROL
11048 recreates it, and the peer keeps sending those precisely because it
11049 thinks it is connected. Nothing ever breaks the tie, so CORE on this
11050 side never hears about the peer and never answers its handshake.
11051 Only a confirmed link means there is nothing left to do. */
11052 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
11053 return;
11054
11055 /* For us, the link is still down, but we need bi-directional
11056 connections (for flow-control and for this to be useful for
11057 CORE), so we must try to bring the link up! */
11058 try_to_bring_link_up (&sender);
11059}
11060
11061
11070static void
11072 void *cls,
11073 const struct TransportValidationChallengeMessage *tvc)
11074{
11075 struct CommunicatorMessageContext *cmc = cls;
11076 struct TransportValidationResponseMessage tvr = { 0 };
11077 struct GNUNET_TIME_RelativeNBO validity_duration;
11078
11079 /* DV-routed messages are not allowed for validation challenges */
11080 if (cmc->total_hops > 0)
11081 {
11082 GNUNET_break_op (0);
11083 finish_cmc_handling (cmc);
11084 return;
11085 }
11086 validity_duration = cmc->im.expected_address_validity;
11088 "Received address validation challenge %s\n",
11089 GNUNET_sh2s (&tvc->challenge.value));
11090 /* If we have a virtual link, we use this mechanism to signal the
11091 size of the flow control window, and to allow the sender
11092 to ask for increases. If for us the virtual link is still down,
11093 we will always give a window size of zero. */
11094 tvr.header.type =
11096 tvr.header.size = htons (sizeof(tvr));
11097 tvr.reserved = htonl (0);
11098 tvr.challenge = tvc->challenge;
11099 tvr.origin_time = tvc->sender_time;
11100 tvr.validity_duration = validity_duration;
11101 {
11102 /* create signature */
11103 struct TransportValidationPS tvp = {
11105 .purpose.size = htonl (sizeof(tvp)),
11106 .validity_duration = validity_duration,
11107 .challenge = tvc->challenge
11108 };
11109 if (GNUNET_OK != sign_by_my_identity (&tvp.purpose, &tvr.signature))
11110 {
11111 /* Not answering costs us this address validation; leaving @a cmc
11112 behind would cost us the communicator. */
11113 finish_cmc_handling (cmc);
11114 return;
11115 }
11116 }
11117 send_t_validation_response (cmc, tvr);
11118}
11119
11120
11125{
11130
11134 struct ValidationState *vs;
11135};
11136
11137
11147static int
11148check_known_challenge (void *cls,
11149 const struct GNUNET_PeerIdentity *pid,
11150 void *value)
11151{
11152 struct CheckKnownChallengeContext *ckac = cls;
11153 struct ValidationState *vs = value;
11154
11155 (void) pid;
11156 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
11157 return GNUNET_OK;
11158 ckac->vs = vs;
11159 return GNUNET_NO;
11160}
11161
11162
11170static void
11171peerstore_store_validation_cb (void *cls, int success)
11172{
11173 struct ValidationState *vs = cls;
11174
11175 vs->sc = NULL;
11176 if (GNUNET_YES == success)
11177 return;
11179 "# Peerstore failed to store foreign address",
11180 1,
11181 GNUNET_NO);
11182}
11183
11184
11192static struct Queue *
11193find_queue (const struct GNUNET_PeerIdentity *pid, const char *address)
11194{
11195 struct Neighbour *n;
11196
11197 n = lookup_neighbour (pid);
11198 if (NULL == n)
11199 return NULL;
11200 for (struct Queue *pos = n->queue_head; NULL != pos;
11201 pos = pos->next_neighbour)
11202 {
11203 if (0 == strcmp (pos->address, address))
11204 return pos;
11205 }
11206 return NULL;
11207}
11208
11209
11225static struct Queue *
11226find_queue_by_ip (const struct GNUNET_PeerIdentity *pid, const char *address)
11227{
11228 struct Neighbour *n;
11229 struct Queue *ret = NULL;
11230 char *prefix;
11231 char *ip;
11232
11233 n = lookup_neighbour (pid);
11234 if (NULL == n)
11235 return NULL;
11238 if ((NULL == prefix) || (NULL == ip))
11239 {
11241 GNUNET_free (ip);
11242 return NULL;
11243 }
11244 for (struct Queue *pos = n->queue_head; NULL != pos;
11245 pos = pos->next_neighbour)
11246 {
11247 char *q_prefix = GNUNET_HELLO_address_to_prefix (pos->address);
11248 char *q_ip = get_address_without_port (pos->address);
11249
11250 /* Same communicator and same host -- only the port may differ. */
11251 if ((NULL != q_prefix) && (NULL != q_ip) &&
11252 (0 == strcmp (q_prefix, prefix)) &&
11253 (0 == strcmp (q_ip, ip)))
11254 ret = pos;
11255 GNUNET_free (q_prefix);
11256 GNUNET_free (q_ip);
11257 if (NULL != ret)
11258 break;
11259 }
11261 GNUNET_free (ip);
11262 return ret;
11263}
11264
11265
11266static void
11268
11269static void
11270revalidation_start_cb (void *cls)
11271{
11272 struct ValidationState *vs = cls;
11273 struct Queue *q;
11274 struct GNUNET_TIME_Absolute now;
11275
11276 vs->revalidation_task = NULL;
11277 q = find_queue (&vs->pid, vs->address);
11278 if (NULL == q)
11279 {
11280 now = GNUNET_TIME_absolute_get ();
11281 vs->awaiting_queue = GNUNET_YES;
11282 suggest_to_connect (&vs->pid, vs->address);
11284 }
11285 else
11287}
11288
11289
11290static enum GNUNET_GenericReturnValue
11292 void *cls,
11293 const struct GNUNET_HashCode *key,
11294 void *value)
11295{
11296 (void) cls;
11298 "Key in revalidate map %s \n",
11299 GNUNET_h2s (key));
11300 return GNUNET_YES;
11301}
11302
11303
11312static void
11314 void *cls,
11315 const struct TransportValidationResponseMessage *tvr)
11316{
11317 struct CommunicatorMessageContext *cmc = cls;
11318 struct ValidationState *vs;
11319 struct CheckKnownChallengeContext ckac = { .challenge = &tvr->challenge,
11320 .vs = NULL};
11321 struct GNUNET_TIME_Absolute origin_time;
11322 struct Queue *q;
11323 struct Neighbour *n;
11324 struct VirtualLink *vl;
11326 GST_cfg);
11327
11328 /* check this is one of our challenges */
11330 &cmc->im.sender,
11332 &ckac);
11333 if (NULL == (vs = ckac.vs))
11334 {
11335 /* This can happen simply if we 'forgot' the challenge by now,
11336 i.e. because we received the validation response twice */
11338 "# Validations dropped, challenge unknown",
11339 1,
11340 GNUNET_NO);
11342 "Validation response %s dropped, challenge unknown\n",
11343 GNUNET_sh2s (&tvr->challenge.value));
11344 finish_cmc_handling (cmc);
11345 return;
11346 }
11347
11348 /* sanity check on origin time */
11349 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
11350 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
11351 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
11352 {
11354 "Diff first use %" PRIu64 " and last use %" PRIu64 "\n",
11355 vs->first_challenge_use.abs_value_us - origin_time.abs_value_us,
11356 origin_time.abs_value_us - vs->last_challenge_use.abs_value_us);
11357 GNUNET_break_op (0);
11358 finish_cmc_handling (cmc);
11359 return;
11360 }
11361
11362 {
11363 /* check signature */
11364 struct TransportValidationPS tvp = {
11366 .purpose.size = htonl (sizeof(tvp)),
11367 .validity_duration = tvr->validity_duration,
11368 .challenge = tvr->challenge
11369 };
11370
11371 if (
11372 GNUNET_OK !=
11374 &tvp,
11375 &tvr->signature,
11376 &cmc->im.sender.public_key))
11377 {
11378 GNUNET_break_op (0);
11379 finish_cmc_handling (cmc);
11380 return;
11381 }
11382 }
11383
11384 /* validity is capped by our willingness to keep track of the
11385 validation entry and the maximum the other peer allows */
11388 tvr->validity_duration),
11390 vs->validated_until =
11394 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
11395 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
11396 GNUNET_CRYPTO_random_block (&vs->challenge,
11397 sizeof(vs->challenge));
11398 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
11399 vs->validated_until,
11400 GNUNET_TIME_relative_multiply (vs->validation_rtt,
11402 if (GNUNET_TIME_absolute_cmp (vs->first_challenge_use, <, now))
11403 {
11405 "First challenge use is now %" PRIu64 " %s \n",
11406 vs->first_challenge_use.abs_value_us,
11407 GNUNET_sh2s (&vs->challenge.value));
11408 vs->first_challenge_use = now;
11409 }
11410 else
11412 "First challenge use is later %" PRIu64 " %s \n",
11413 vs->first_challenge_use.abs_value_us,
11414 GNUNET_sh2s (&vs->challenge.value));
11415 vs->last_challenge_use =
11416 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
11417 update_next_challenge_time (vs, vs->first_challenge_use);
11419 "Validation response %s from %s accepted, address valid until %s\n",
11420 GNUNET_sh2s (&tvr->challenge.value),
11421 GNUNET_i2s (&cmc->im.sender),
11423 /*memcpy (&hkey,
11424 &hc,
11425 sizeof (hkey));*/
11427 "Key %s for address %s map size %u contains %u\n",
11428 GNUNET_h2s (&vs->hc),
11429 vs->address,
11432 &vs->hc));
11433 /* NOTE: @e hc hashes the address only, so two `struct ValidationState's
11434 for different peers can collide here. That must not abort us. */
11435 if (GNUNET_YES !=
11438 &vs->hc,
11439 vs,
11442 "Address `%s' already tracked for revalidation\n",
11443 vs->address);
11446 NULL);
11447 vs->revalidation_task =
11452 "transport",
11453 &cmc->im.sender,
11455 vs->address,
11456 strlen (vs->address) + 1,
11457 vs->valid_until,
11460 vs);
11461 finish_cmc_handling (cmc);
11462
11463 /* Finally, we now possibly have a confirmed (!) working queue,
11464 update queue status (if queue still is around) */
11465 q = find_queue (&vs->pid, vs->address);
11466 if (NULL == q)
11467 {
11468 /* The challenge may have gone out on a queue whose address is not
11469 literally @e address: #check_validation_request_pending() matches on
11470 the IP alone, precisely so that a validation waiting for the NAT
11471 address `PROTO-IP:0' can be answered over the queue that the peer
11472 actually established from `PROTO-IP:port'. Insisting on an exact
11473 match here would silently discard that (successful!) validation and
11474 never bring the virtual link up. */
11475 q = find_queue_by_ip (&vs->pid, vs->address);
11476 }
11477 if (NULL == q)
11478 {
11480 "# Queues lost at time of successful validation",
11481 1,
11482 GNUNET_NO);
11483 return;
11484 }
11485 q->validated_until = vs->validated_until;
11486 q->pd.aged_rtt = vs->validation_rtt;
11487 n = q->neighbour;
11488 vl = lookup_virtual_link (&vs->pid);
11489 if (NULL == vl)
11490 {
11491 vl = GNUNET_new (struct VirtualLink);
11493 "Creating new virtual link %p to %s using direct neighbour!\n",
11494 vl,
11495 GNUNET_i2s (&vs->pid));
11496 vl->burst_addr = NULL;
11497 vl->confirmed = GNUNET_YES;
11498 vl->message_uuid_ctr =
11499 GNUNET_CRYPTO_random_u64 (UINT64_MAX);
11500 vl->target = n->pid;
11504 /* What the peer will grant us in its very first FLOW_CONTROL anyway
11505 (@e incoming_fc_window_size plus what we have sent, i.e. nothing).
11506 Starting at zero instead means a link that is up, validated and
11507 working carries nothing at all until an FC round trip completes --
11508 and if the peer cannot answer, not ever. */
11512 links,
11513 &vl->target,
11514 vl,
11516 vl->n = n;
11517 n->vl = vl;
11518 q->idle = GNUNET_YES;
11519 vl->visibility_task =
11520 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
11522 /* We lacked a confirmed connection to the target
11523 before, so tell CORE about it (finally!) */
11526 }
11527 else
11528 {
11529 /* Link was already up, remember n is also now available and we are done */
11530 if (NULL == vl->n)
11531 {
11532 vl->n = n;
11533 n->vl = vl;
11534 if (GNUNET_YES == vl->confirmed)
11536 "Virtual link to %s could now also use direct neighbour!\n",
11537 GNUNET_i2s (&vs->pid));
11538 }
11539 else
11540 {
11541 GNUNET_assert (n == vl->n);
11542 }
11543 if (GNUNET_NO == vl->confirmed)
11544 {
11545 vl->confirmed = GNUNET_YES;
11546 q->idle = GNUNET_YES;
11547 vl->visibility_task =
11548 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
11550 /* We lacked a confirmed connection to the target
11551 before, so tell CORE about it (finally!) */
11554 }
11555 }
11556}
11557
11558
11564static void
11565handle_incoming_msg (void *cls,
11566 const struct GNUNET_TRANSPORT_IncomingMessage *im)
11567{
11568 struct TransportClient *tc = cls;
11569 struct Neighbour *n;
11570 struct CommunicatorMessageContext *cmc =
11572
11573 cmc->tc = tc;
11574 cmc->im = *im;
11576 "Received message with size %u and flow control id %" PRIu64
11577 " via communicator from peer %s\n",
11578 ntohs (im->header.size),
11579 im->fc_id,
11580 GNUNET_i2s (&im->sender));
11581 cmc->im.neighbour_sender = cmc->im.sender;
11582 /* A communicator got this straight from @a im->sender, so the queues to
11583 that neighbour demonstrably still work. This is what #check_link_down()
11584 uses to bound how long a communicator that stopped working (without
11585 telling us) can keep a virtual link -- and CORE -- fooled. */
11586 if (NULL != (n = lookup_neighbour (&im->sender)))
11588 cmc->mh = (const struct GNUNET_MessageHeader *) &im[1];
11590}
11591
11592
11601static int
11602check_flow_control (void *cls, const struct TransportFlowControlMessage *fc)
11603{
11604 unsigned int number_of_addresses = ntohl (fc->number_of_addresses);
11605 uint16_t msize = ntohs (fc->header.size);
11606 const char *tgnas;
11607 size_t avail;
11608 size_t off;
11609
11610 (void) cls;
11612 "Flow control header size %u size of addresses %u number of addresses %u size of message struct %lu second struct %lu\n",
11613 ntohs (fc->header.size),
11614 ntohl (fc->size_of_addresses),
11615 ntohl (fc->number_of_addresses),
11616 sizeof(struct TransportFlowControlMessage),
11617 sizeof (struct TransportGlobalNattedAddress));
11618 if (0 == number_of_addresses)
11619 return GNUNET_OK;
11620 if (msize < sizeof(struct TransportFlowControlMessage))
11621 {
11622 GNUNET_break_op (0);
11623 return GNUNET_SYSERR;
11624 }
11625 avail = msize - sizeof(struct TransportFlowControlMessage);
11626 tgnas = (const char *) &fc[1];
11627 off = 0;
11628 /* Validate EVERY entry: checking only the aggregate size lets a single
11629 entry claim a bogus address_length and send #handle_flow_control()
11630 out of bounds. */
11631 for (unsigned int i = 0; i < number_of_addresses; i++)
11632 {
11633 const struct TransportGlobalNattedAddress *tgna;
11634 size_t alen;
11635
11636 if (avail - off < sizeof(struct TransportGlobalNattedAddress))
11637 {
11638 GNUNET_break_op (0);
11639 return GNUNET_SYSERR;
11640 }
11641 tgna = (const struct TransportGlobalNattedAddress *) &tgnas[off];
11642 off += sizeof(struct TransportGlobalNattedAddress);
11643 alen = ntohl (tgna->address_length);
11644 if (avail - off < alen)
11645 {
11646 GNUNET_break_op (0);
11647 return GNUNET_SYSERR;
11648 }
11649 off += alen;
11650 }
11651 return GNUNET_OK;
11652}
11653
11654
11655static struct GNUNET_TIME_Relative
11656calculate_rtt (struct DistanceVector *dv)
11657{
11659 unsigned int n_hops = 0;
11660
11662 "calculate_rtt\n");
11663 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
11664 pos = pos->next_dv)
11665 {
11667 "calculate_rtt %lu\n",
11668 (unsigned long) pos->pd.aged_rtt.rel_value_us);
11669 n_hops++;
11671 aged_rtt, pos
11672 ->distance
11673 + 2), ret);
11674 }
11675
11676 if (0 == n_hops)
11678 return ret;
11679}
11680
11681
11682static void
11684 const struct GNUNET_PeerIdentity *pid,
11685 const char *uri)
11686{
11687 struct VirtualLink *vl = cls;
11688 const char *slash;
11689 char *address_uri;
11690 char *prefix;
11691 char *uri_without_port;
11692
11693 slash = strrchr (uri, '/');
11694 if ((NULL == slash) || (slash - uri < 2))
11695 {
11696 GNUNET_break_op (0); /* @a uri comes from a remote HELLO */
11697 return;
11698 }
11699 prefix = GNUNET_strndup (uri, (slash - uri) - 2);
11700 slash++;
11701 GNUNET_asprintf (&address_uri,
11702 "%s-%s",
11703 prefix,
11704 slash);
11705
11706 uri_without_port = get_address_without_port (address_uri);
11708 "iterate_address_start_burst %s %s %s %s\n",
11709 (NULL == uri_without_port) ? "<unparsable>" : uri_without_port,
11710 uri,
11711 address_uri,
11712 slash);
11713 GNUNET_free (vl->burst_addr);
11714 if ((NULL != uri_without_port) &&
11715 (0 == strcmp (uri_without_port, slash)))
11716 vl->burst_addr = GNUNET_strdup (uri_without_port);
11717
11719 GNUNET_free (address_uri);
11720 GNUNET_free (uri_without_port);
11721}
11722
11723
11724static void
11725check_for_burst_address (void *cls,
11726 const struct GNUNET_PEERSTORE_Record *record,
11727 const char *emsg)
11728{
11729 struct GNUNET_StartBurstCls *sb_cls = cls;
11730 struct VirtualLink *vl = sb_cls->vl;
11731 const struct GNUNET_MessageHeader *hello;
11733
11734 if (NULL != emsg)
11735 {
11737 "Got failure from PEERSTORE: %s\n",
11738 emsg);
11739 /* @a emsg comes with a NULL record, which means the iteration is over
11740 and PEERSTORE is releasing the context itself -- stopping it here as
11741 well would free it twice. Just drop our handle. */
11742 vl->ic = NULL;
11743 free_burst_cls (sb_cls);
11744 return;
11745 }
11746 if (NULL == record)
11747 {
11749 "Hello iteration end for %s\n",
11750 GNUNET_i2s (&vl->target));
11751 /* PEERSTORE destroys the context itself once it signals the end. */
11752 vl->ic = NULL;
11753 free_burst_cls (sb_cls);
11754 return;
11755 }
11756
11758 "check_for_burst_address\n");
11759 /* @a hello was published by a remote peer, it may well be malformed. */
11760 hello = hello_from_record (record);
11761 if (NULL != hello)
11762 {
11763 parser = GNUNET_HELLO_parser_from_msg (hello, &record->peer);
11764 if (NULL != parser)
11765 {
11768 vl);
11769 GNUNET_HELLO_parser_free (parser);
11770 }
11771 }
11772
11773 /* MUST clear @e ic: #GNUNET_PEERSTORE_iteration_stop() frees it, and
11774 #free_virtual_link() would otherwise stop it a second time. */
11775 if (NULL != vl->ic)
11776 {
11778 vl->ic = NULL;
11779 }
11780 free_burst_cls (sb_cls);
11781}
11782
11783
11784static void
11785burst_timeout (void *cls)
11786{
11788}
11789
11790
11791static void
11792start_burst (void *cls)
11793{
11794 struct GNUNET_StartBurstCls *sb_cls = cls;
11795 struct VirtualLink *vl = sb_cls->vl;
11796 struct GNUNET_TRANSPORT_StartBurst *sb;
11797 struct GNUNET_MQ_Envelope *env;
11798 char *uri_without_port = vl->burst_addr;
11799
11800 burst_task = NULL;
11801 burst_task_cls = NULL;
11802 if (NULL == uri_without_port)
11803 {
11804 /* Lost the address in the meantime, nothing to burst to. */
11805 free_burst_cls (sb_cls);
11806 return;
11807 }
11808 /*char buf[strlen (uri_without_port) + 1];
11809
11810 GNUNET_memcpy (buf, uri_without_port, strlen (uri_without_port));
11811 buf[strlen (uri_without_port)] = '\0';*/
11812 env =
11814 strlen (uri_without_port) + 1,
11816 sb->rtt = GNUNET_TIME_relative_hton (sb_cls->rtt);
11817 sb->pid = vl->target;
11818 memcpy (&sb[1], uri_without_port, strlen (uri_without_port) + 1);
11819 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
11820 {
11821 if (CT_COMMUNICATOR != tc->type)
11822 continue; /* MUST come first: the log below reads the union! */
11824 "iterate_address_start_burst client tc prefix %s\n",
11825 tc->details.communicator.address_prefix);
11826 if (GNUNET_YES == tc->details.communicator.can_burst)
11827 {
11829 "iterate_address_start_burst %s call %lu %u rtt %lu\n",
11830 uri_without_port,
11831 strlen (uri_without_port),
11832 ntohs (sb->header.size),
11833 (unsigned long) sb_cls->rtt.rel_value_us);
11834 GNUNET_MQ_send (tc->mq, env);
11835 env = NULL; /* MQ took ownership */
11839 60),
11841 NULL);
11842 // TODO We need some algo to choose from available communicators. Can we run two bursts at once? Atm we only implemented udp burst.
11843 break;
11844 }
11845 }
11846 if (NULL != env)
11848 free_burst_cls (sb_cls);
11849}
11850
11851
11858static void
11859free_burst_cls (struct GNUNET_StartBurstCls *sb_cls)
11860{
11861 struct VirtualLink *vl = sb_cls->vl;
11862
11863 if (burst_task_cls == sb_cls)
11864 {
11865 if (NULL != burst_task)
11866 {
11868 burst_task = NULL;
11869 }
11870 burst_task_cls = NULL;
11871 }
11872 if ((NULL != vl) && (vl->sb_cls == sb_cls))
11873 vl->sb_cls = NULL;
11875}
11876
11877
11878static void
11879queue_burst (void *cls)
11880{
11881 struct GNUNET_StartBurstCls *sb_cls = cls;
11882 struct VirtualLink *vl = sb_cls->vl;
11883
11884 if (GNUNET_YES != use_burst)
11885 {
11886 /* MUST release: nobody else owns @a sb_cls, and #handle_flow_control()
11887 allocates one for every FLOW_CONTROL message we receive. */
11889 return;
11890 }
11892 "burst_task %p ready %s burst addr %s (%p)\n",
11893 burst_task,
11894 sb_cls->sync_ready ? "yes" : "no",
11895 vl->burst_addr,
11896 vl->burst_addr);
11897 if (NULL != burst_task && GNUNET_NO == sb_cls->sync_ready)
11898 {
11899 /* Cancel the pending burst. Both closures (the scheduled task's and
11900 ours) are ours to release. */
11902
11904 burst_task = NULL;
11905 burst_task_cls = NULL;
11906 if ((NULL != pending) && (pending != sb_cls))
11908 free_burst_cls (sb_cls);
11909 return;
11910 }
11911 if (GNUNET_NO == burst_running && NULL != vl->burst_addr && NULL == burst_task
11912 )
11913 {
11915 &start_burst,
11916 sb_cls);
11917 burst_task_cls = sb_cls;
11918 }
11919 else if (NULL == vl->burst_addr)
11920 {
11921 if (NULL != vl->ic)
11922 {
11923 /* An address lookup is already running for this link; starting a
11924 second one would leak the first. */
11925 free_burst_cls (sb_cls);
11926 return;
11927 }
11929 "peerstore",
11930 &vl->target,
11933 sb_cls);
11934 }
11935 else
11936 {
11937 /* A burst is already running or already scheduled; we have no use for
11938 this closure. */
11939 free_burst_cls (sb_cls);
11940 }
11941}
11942
11943
11950static void
11951unconfirmed_link_timeout (void *cls)
11952{
11953 struct VirtualLink *vl = cls;
11954
11955 vl->unconfirmed_timeout_task = NULL;
11956 if ((GNUNET_YES == vl->confirmed) ||
11957 (NULL != vl->n) ||
11958 (NULL != vl->dv))
11959 return; /* got promoted in the meantime, its owner will clean up */
11961 "Discarding unconfirmed virtual link to %s\n",
11962 GNUNET_i2s (&vl->target));
11964 "# Unconfirmed virtual links timed out",
11965 1,
11966 GNUNET_NO);
11967 free_virtual_link (vl);
11968}
11969
11970
11979static void
11980handle_flow_control (void *cls, const struct TransportFlowControlMessage *fc)
11981{
11982 struct CommunicatorMessageContext *cmc = cls;
11983 struct VirtualLink *vl;
11985 uint32_t seq;
11986 struct GNUNET_TIME_Absolute st;
11987 uint64_t os;
11988 uint64_t wnd;
11989 uint32_t random;
11990
11992 "Received FC from %s\n", GNUNET_i2s (&cmc->im.sender));
11993 vl = lookup_virtual_link (&cmc->im.sender);
11994 if (NULL == vl)
11995 {
11996 vl = GNUNET_new (struct VirtualLink);
11998 "No virtual link for %p FC creating new unconfirmed virtual link to %s!\n",
11999 vl,
12000 GNUNET_i2s (&cmc->im.sender));
12001 vl->burst_addr = NULL;
12002 vl->confirmed = GNUNET_NO;
12003 vl->message_uuid_ctr =
12004 GNUNET_CRYPTO_random_u64 (UINT64_MAX);
12005 vl->target = cmc->im.sender;
12009 /* What the peer will grant us in its very first FLOW_CONTROL anyway
12010 (@e incoming_fc_window_size plus what we have sent, i.e. nothing).
12011 Starting at zero instead means a link that is up, validated and
12012 working carries nothing at all until an FC round trip completes --
12013 and if the peer cannot answer, not ever. */
12017 links,
12018 &vl->target,
12019 vl,
12021 /* Nothing else owns this link yet, so it must reap itself if it never
12022 becomes confirmed -- otherwise any peer can make us allocate
12023 VirtualLinks without bound. */
12027 vl);
12028 }
12029 if (GNUNET_YES != vl->confirmed)
12030 {
12031 /* The peer flow-controls us, so it has a confirmed link to us -- but an
12032 unconfirmed link carries nothing and is never reported to CORE. Only
12033 #handle_validation_response() breaks that tie, and nothing here used
12034 to ask for one, so the pair could sit one-way until the peer's own
12035 four hour revalidation came round. */
12037 }
12038 if (NULL != vl->n)
12039 {
12040 for (struct Queue *q = vl->n->queue_head; NULL != q; q = q->next_neighbour)
12041 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
12042 }
12043
12045 "remaining %lu timeout for neighbour %p\n",
12046 (unsigned long) GNUNET_TIME_absolute_get_remaining (q_timeout).
12047 rel_value_us,
12048 vl->n);
12049 if (NULL == vl->n ||
12050 0 == GNUNET_TIME_absolute_get_remaining (q_timeout).rel_value_us)
12051 {
12052 struct GNUNET_TIME_Relative rtt;
12053 struct GNUNET_BurstSync burst_sync;
12054 struct GNUNET_StartBurstCls *bcls;
12055
12056 if (NULL != vl->sb_cls)
12057 {
12058 /* A burst attempt for this link is already in flight. Allocating a
12059 second closure would orphan the first one: @e sb_cls is how
12060 #free_virtual_link() finds (and cancels) the pending #burst_task,
12061 and a peer that just keeps sending us FLOW_CONTROL messages would
12062 otherwise make us leak one closure per message. */
12064 "Burst attempt to %s already pending\n",
12065 GNUNET_i2s (&vl->target));
12066 }
12067 else
12068 {
12069 bcls = GNUNET_new (struct GNUNET_StartBurstCls);
12070 bcls->vl = vl;
12071 vl->sb_cls = bcls;
12072 if (NULL != vl->dv)
12073 rtt = calculate_rtt (vl->dv);
12074 else
12076 burst_sync.rtt_average = fc->rtt;
12077 bcls->rtt = GNUNET_TIME_relative_ntoh (burst_sync.rtt_average);
12078 /* @e sync_ready of `struct GNUNET_BurstSync' is a host-order enum. */
12079 burst_sync.sync_ready =
12080 (enum GNUNET_GenericReturnValue) ntohl (fc->sync_ready);
12081
12082 /* NOTE: #GNUNET_is_burst_ready() does NOT invoke the task unless both
12083 RTT estimates are known and close; #queue_burst() is thus not
12084 guaranteed to run, which is why @e sb_cls stays owned by @a vl. */
12086 &burst_sync,
12087 &queue_burst,
12088 bcls);
12089 }
12090 }
12091 if (0 != ntohl (fc->number_of_addresses))
12092 {
12093 unsigned int number_of_addresses = ntohl (fc->number_of_addresses);
12094 const char *tgnas;
12095 unsigned int off = 0;
12096
12097 tgnas = (const char *) &fc[1];
12098
12099 for (unsigned int i = 0; i < number_of_addresses; i++)
12100 {
12101 struct TransportGlobalNattedAddress *tgna;
12102 char *addr;
12103 uint32_t address_length;
12104
12105 tgna = (struct TransportGlobalNattedAddress*) &tgnas[off];
12106 addr = (char *) &tgna[1];
12107 address_length = ntohl (tgna->address_length);
12108 off += sizeof(struct TransportGlobalNattedAddress) + address_length;
12109
12110 /* NOTE: the address is NOT 0-terminated (it comes straight off the
12111 wire), it must be printed with an explicit precision. */
12113 "received address %.*s length %u\n",
12114 (int) address_length,
12115 addr,
12117
12118 if (NULL != nh)
12119 GNUNET_NAT_add_global_address (nh, addr, ntohl (tgna->address_length));
12120 }
12121 }
12123 if (st.abs_value_us < vl->last_fc_timestamp.abs_value_us)
12124 {
12126 "FC dropped: Message out of order\n");
12127 /* out of order, drop */
12129 "# FC dropped: message out of order",
12130 1,
12131 GNUNET_NO);
12132 finish_cmc_handling (cmc);
12133 return;
12134 }
12135 seq = ntohl (fc->seq);
12136 if (seq < vl->last_fc_seq)
12137 {
12138 /* Wrap-around/reset of other peer; start all counters from zero */
12140 }
12141 vl->last_fc_seq = seq;
12142 vl->last_fc_timestamp = st;
12143 /* The peer is answering, so the backoff in #consider_sending_fc() starts
12144 over: @e fc_retransmit_count counts *unanswered* rounds. */
12145 vl->fc_retransmit_count = 0;
12147 os = GNUNET_ntohll (fc->outbound_sent);
12149 (int64_t) (os - vl->incoming_fc_window_size_used);
12151 "Received FC from %s, seq %u, new window %llu (loss at %lld)\n",
12152 GNUNET_i2s (&vl->target),
12153 (unsigned int) seq,
12154 (unsigned long long) vl->outbound_fc_window_size,
12155 (long long) vl->incoming_fc_window_size_loss);
12157 random = GNUNET_CRYPTO_random_u32 (UINT32_MAX);
12158 /* NOTE: this must NOT be restricted to a confirmed link. @e
12159 outbound_fc_window_size starts at zero and is raised *only* here, from
12160 the peer's FC. So a peer whose link to us is confirmed while ours to it
12161 is not cannot send us a single byte until we answer -- and it is exactly
12162 that peer that keeps asking. Staying quiet deadlocks the pair: it shows
12163 an established virtual link with messages pending forever, we show none,
12164 and CORE never completes its handshake in either direction. */
12165 if ((wnd < vl->incoming_fc_window_size
12169 (0 == random % FC_NO_CHANGE_REPLY_PROBABILITY))
12170 {
12172 "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",
12173 (unsigned long long) wnd,
12174 (unsigned long long) vl->incoming_fc_window_size,
12175 (unsigned long long) vl->last_outbound_window_size_received,
12178 }
12179 if ((wnd == vl->incoming_fc_window_size
12183 {
12185 "Slowing FC transmission to %s to keepalive rate: peer is current at window %llu\n",
12186 GNUNET_i2s (&vl->target),
12187 (unsigned long long) wnd);
12188 /* NOTE: this used to also require @e fc_retransmit_task to be non-NULL
12189 and did nothing at all otherwise -- so a link whose chain had ended
12190 (see #consider_sending_fc()) could never pick the keepalive back up,
12191 even though the peer was demonstrably still talking to us. */
12192 if (NULL != vl->fc_retransmit_task)
12194 vl->fc_retransmit_count = 0;
12195 /* Drop to the keepalive rate rather than stopping outright. There is
12196 nothing left to retransmit -- but if we go completely quiet, and the
12197 peer does the same for the same reason, then neither end sees any
12198 traffic and #check_link_down() tears down a perfectly healthy link
12199 after #NEIGHBOUR_LIVENESS_TIMEOUT. One tiny FC message every
12200 #FC_KEEPALIVE_INTERVAL is what keeps @e last_inbound moving on the
12201 other side (and, via their reply, on ours). */
12202 vl->fc_retransmit_task =
12205 vl);
12206 }
12208 /* FC window likely increased, check transmission possibilities! */
12210 finish_cmc_handling (cmc);
12211}
12212
12213
12221static void
12223{
12225 { GNUNET_MQ_hd_var_size (fragment_box,
12228 cmc),
12229 GNUNET_MQ_hd_var_size (reliability_box,
12232 cmc),
12233 GNUNET_MQ_hd_var_size (reliability_ack,
12236 cmc),
12237 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
12240 cmc),
12241 GNUNET_MQ_hd_var_size (dv_learn,
12244 cmc),
12245 GNUNET_MQ_hd_var_size (dv_box,
12247 struct TransportDVBoxMessage,
12248 cmc),
12249 GNUNET_MQ_hd_var_size (flow_control,
12252 cmc),
12254 validation_challenge,
12257 cmc),
12259 validation_response,
12262 cmc),
12264 int ret;
12265 const struct GNUNET_MessageHeader *msg = cmc->mh;
12266
12268 "Handling message of type %u with %u bytes\n",
12269 (unsigned int) ntohs (msg->type),
12270 (unsigned int) ntohs (msg->size));
12271 /* @a handlers only covers the encapsulations *we* add; anything else is a
12272 payload for CORE and leaves through #handle_raw_message() below. So
12273 #GNUNET_NO is the common case here -- one per delivered CORE message --
12274 and not something to log about, which is why this is the "try" variant. */
12276 if (GNUNET_SYSERR == ret)
12277 {
12278 /* @a msg is the message a *remote peer* sent us: #handle_incoming_msg()
12279 points @e mh into the payload of the
12280 #GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG the communicator
12281 delivered, and every other caller unwraps it from remote traffic as
12282 well. So failing a check here is that peer's protocol violation, and
12283 it says nothing at all about the communicator that carried it.
12284
12285 Dropping the client therefore punishes the wrong party, and it
12286 punishes it hard: #GNUNET_SERVICE_client_drop() disconnects the
12287 communicator *process*, which takes down every queue it owns and thus
12288 every neighbour reachable through it. One malformed DV box on a
12289 shared UDP communicator disconnects every peer we have on it, CORE
12290 tears the sessions down, and the key exchanges that would rebuild
12291 them have to wait for the communicator to come back and revalidate.
12292 Since the offending bytes arrive from the network, any peer can do
12293 this to us at will, repeatedly.
12294
12295 Drop the message and keep the communicator: resume it exactly as the
12296 success path does, so it still gets its flow-control ACK and its
12297 GNUNET_SERVICE_client_continue(). */
12298 GNUNET_break_op (0);
12300 "# malformed messages discarded",
12301 1,
12302 GNUNET_NO);
12304 return;
12305 }
12306 if (GNUNET_NO == ret)
12307 {
12308 /* unencapsulated 'raw' message */
12309 handle_raw_message (cmc, msg);
12310 }
12311}
12312
12313
12320static int
12321check_add_queue_message (void *cls,
12322 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
12323{
12324 struct TransportClient *tc = cls;
12325
12326 if (CT_COMMUNICATOR != tc->type)
12327 {
12328 GNUNET_break (0);
12329 return GNUNET_SYSERR;
12330 }
12332 return GNUNET_OK;
12333}
12334
12335
12341static void
12343{
12344 if (pm->msg_uuid_set)
12345 return;
12346 pm->msg_uuid.uuid = pm->vl->message_uuid_ctr++;
12348}
12349
12350
12359static struct PendingAcknowledgement *
12361 struct DistanceVectorHop *dvh,
12362 struct PendingMessage *pm)
12363{
12364 struct PendingAcknowledgement *pa;
12365
12366 pa = GNUNET_new (struct PendingAcknowledgement);
12367 pa->queue = queue;
12368 pa->dvh = dvh;
12369 pa->pm = pm;
12370 do
12371 {
12373 sizeof(pa->ack_uuid));
12374 }
12377 &pa->ack_uuid.value,
12378 pa,
12380 GNUNET_CONTAINER_MDLL_insert (queue, queue->pa_head, queue->pa_tail, pa);
12382 if (NULL != dvh)
12385 pa->message_size = pm->bytes_msg;
12387 "Waiting for ACKnowledgment `%s' for <%" PRIu64 ">\n",
12389 pm->logging_uuid);
12390 return pa;
12391}
12392
12393
12405static struct PendingMessage *
12407 struct DistanceVectorHop *dvh,
12408 struct PendingMessage *pm)
12409{
12410 struct PendingAcknowledgement *pa;
12411 struct PendingMessage *ff;
12412 uint16_t mtu;
12413 uint16_t msize;
12414
12415 mtu = (UINT16_MAX == queue->mtu)
12416 ? UINT16_MAX - sizeof(struct GNUNET_TRANSPORT_SendMessageTo)
12417 : queue->mtu;
12419 "Fragmenting message <%" PRIu64
12420 "> with size %u to %s for MTU %u\n",
12421 pm->logging_uuid,
12422 pm->bytes_msg,
12423 GNUNET_i2s (&pm->vl->target),
12424 (unsigned int) mtu);
12427 "Fragmenting message %" PRIu64 " <%" PRIu64
12428 "> with size %u to %s for MTU %u\n",
12429 pm->msg_uuid.uuid,
12430 pm->logging_uuid,
12431 pm->bytes_msg,
12432 GNUNET_i2s (&pm->vl->target),
12433 (unsigned int) mtu);
12434
12435 /* This invariant is established in #handle_add_queue_message() */
12436 GNUNET_assert (mtu > sizeof(struct TransportFragmentBoxMessage));
12437
12438 /* select fragment for transmission, descending the tree if it has
12439 been expanded until we are at a leaf or at a fragment that is small
12440 enough
12441 */
12442 ff = pm;
12443 msize = ff->bytes_msg;
12444
12445 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
12446 (ff->frag_off == msize) && (NULL != ff->head_frag))
12447 {
12448 ff = ff->head_frag; /* descent into fragmented fragments */
12449 msize = ff->bytes_msg - sizeof(struct TransportFragmentBoxMessage);
12450 }
12451
12452 if (((ff->bytes_msg > mtu) || (pm == ff)) && (ff->frag_off < msize))
12453 {
12454 /* Did not yet calculate all fragments, calculate next fragment */
12455 struct PendingMessage *frag;
12456 struct TransportFragmentBoxMessage tfb;
12457 const char *orig;
12458 char *msg;
12459 uint16_t fragmax;
12460 uint16_t fragsize;
12461 uint16_t msize_ff;
12462 uint16_t xoff = 0;
12463 pm->frag_count++;
12464
12465 orig = (const char *) &ff[1];
12466 msize_ff = ff->bytes_msg;
12467 if (pm != ff)
12468 {
12469 const struct TransportFragmentBoxMessage *tfbo;
12470
12471 tfbo = (const struct TransportFragmentBoxMessage *) orig;
12472 orig += sizeof(struct TransportFragmentBoxMessage);
12473 msize_ff -= sizeof(struct TransportFragmentBoxMessage);
12474 xoff = ntohs (tfbo->frag_off);
12475 }
12476 fragmax = mtu - sizeof(struct TransportFragmentBoxMessage);
12477 fragsize = GNUNET_MIN (msize_ff - ff->frag_off, fragmax);
12478 frag =
12479 GNUNET_malloc (sizeof(struct PendingMessage)
12480 + sizeof(struct TransportFragmentBoxMessage) + fragsize);
12482 "3 created pm %p from pm %p storing vl %p from pm %p\n",
12483 frag,
12484 ff,
12485 pm->vl,
12486 pm);
12488 frag->vl = pm->vl;
12489 frag->frag_parent = ff;
12490 frag->timeout = pm->timeout;
12491 frag->bytes_msg = sizeof(struct TransportFragmentBoxMessage) + fragsize;
12492 frag->pmt = PMT_FRAGMENT_BOX;
12493 msg = (char *) &frag[1];
12494 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
12495 tfb.header.size =
12496 htons (sizeof(struct TransportFragmentBoxMessage) + fragsize);
12497 pa = prepare_pending_acknowledgement (queue, dvh, frag);
12498 tfb.ack_uuid = pa->ack_uuid;
12499 tfb.msg_uuid = pm->msg_uuid;
12500 tfb.frag_off = htons (ff->frag_off + xoff);
12501 tfb.msg_size = htons (pm->bytes_msg);
12502 memcpy (msg, &tfb, sizeof(tfb));
12503 memcpy (&msg[sizeof(tfb)], &orig[ff->frag_off], fragsize);
12505 ff->tail_frag, frag);
12506 ff->frag_off += fragsize;
12507 ff = frag;
12508 }
12509
12510 if (pm == ff)
12511 {
12512 /* Neither the descent nor the branch above moved us off @a pm, so there
12513 is no fragment to send: @e head_frag is empty *and* @e frag_off says
12514 everything was already cut. completed_pending_message() leaves
12515 exactly that state behind when the last outstanding fragment is
12516 acknowledged but its condition for finishing the root does not hold
12517 (@e frag_off having been advanced past the boxed payload size, or the
12518 root being a reliability box). The rotate below then dereferences
12519 @e frag_parent, which is NULL for the message on @e pending_msg_head.
12520
12521 Report "nothing to fragment" instead; the caller reschedules. */
12522 GNUNET_break (0);
12523 return NULL;
12524 }
12525 /* Move head to the tail and return it */
12529 ff);
12533 ff);
12534
12535 return ff;
12536}
12537
12538
12551static struct PendingMessage *
12553 struct DistanceVectorHop *dvh,
12554 struct PendingMessage *pm)
12555{
12557 struct PendingAcknowledgement *pa;
12558 struct PendingMessage *bpm;
12559 char *msg;
12560
12561 if ((PMT_CORE != pm->pmt) && (PMT_DV_BOX != pm->pmt))
12562 return pm; /* already fragmented or reliability boxed, or control message:
12563 do nothing */
12564 if (NULL != pm->bpm)
12565 return pm->bpm; /* already computed earlier: do nothing */
12566 // TODO I guess we do not need this assertion. We might have a DLL with
12567 // fragments, because the MTU changed, and we do not need to fragment anymore.
12568 // But we should keep the fragments until message was completed, because
12569 // the MTU might change again.
12570 // GNUNET_assert (NULL == pm->head_frag);
12571 if (pm->bytes_msg + sizeof(rbox) > UINT16_MAX)
12572 {
12573 /* failed hard */
12574 GNUNET_break (0);
12576 return NULL;
12577 }
12578
12579 pa = prepare_pending_acknowledgement (queue, dvh, pm);
12580
12581 bpm = GNUNET_malloc (sizeof(struct PendingMessage) + sizeof(rbox)
12582 + pm->bytes_msg);
12584 "4 created pm %p storing vl %p from pm %p\n",
12585 bpm,
12586 pm->vl,
12587 pm);
12589 bpm->vl = pm->vl;
12590 bpm->frag_parent = pm;
12591 // Why was this needed?
12592 // GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
12593 bpm->timeout = pm->timeout;
12595 bpm->bytes_msg = pm->bytes_msg + sizeof(rbox);
12597 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
12598 rbox.header.size = htons (sizeof(rbox) + pm->bytes_msg);
12599 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
12600
12601 rbox.ack_uuid = pa->ack_uuid;
12602 msg = (char *) &bpm[1];
12603 memcpy (msg, &rbox, sizeof(rbox));
12604 memcpy (&msg[sizeof(rbox)], &pm[1], pm->bytes_msg);
12605 pm->bpm = bpm;
12607 "Preparing reliability box for message <%" PRIu64
12608 "> of size %d (%d) to %s on queue %s\n",
12609 pm->logging_uuid,
12610 pm->bytes_msg,
12611 ntohs (((const struct GNUNET_MessageHeader *) &pm[1])->size),
12612 GNUNET_i2s (&pm->vl->target),
12613 queue->address);
12614 return bpm;
12615}
12616
12617
12618static void
12621{
12622 struct VirtualLink *vl = pm->vl;
12623 struct PendingMessage *pos;
12624
12625 /* Only a message without a parent is on vl->pending_msg_head; anything
12626 else is not ours to reorder and MDLL_remove() would abort on it. */
12627 if ((NULL == vl) ||
12628 (NULL != pm->frag_parent) ||
12629 ((NULL == pm->prev_vl) && (vl->pending_msg_head != pm)))
12630 {
12631 GNUNET_break (0);
12632 return;
12633 }
12634 /* re-insert sort in neighbour list */
12638 pm);
12639 pos = vl->pending_msg_tail;
12640 while ((NULL != pos) &&
12642 pos = pos->prev_vl;
12646 pos,
12647 pm);
12648}
12649
12650
12651static unsigned int
12652check_next_attempt_tree (struct PendingMessage *pm, struct PendingMessage *root)
12653{
12654 struct PendingMessage *pos;
12655 /* MUST be initialised: for a leaf the loop below never runs */
12657
12658 pos = pm->head_frag;
12659 while (NULL != pos)
12660 {
12662 GNUNET_NO == check_next_attempt_tree (pos, root))
12664 else
12665 {
12667 break;
12668 }
12669 pos = pos->next_frag;
12670 }
12671
12672 return frags_in_flight;
12673}
12674
12675
12676static void
12678{
12679 struct PendingMessage *pos;
12680
12681 pos = pm->head_frag;
12682 while (NULL != pos)
12683 {
12686 pos = pos->next_frag;
12687 }
12688}
12689
12690
12699static void
12702{
12703 if (NULL == pm->frag_parent)
12704 {
12707 "Next attempt for message <%" PRIu64 "> set to %" PRIu64 "\n",
12708 pm->logging_uuid,
12711 }
12712 else if ((PMT_RELIABILITY_BOX == pm->pmt) || (PMT_DV_BOX == pm->pmt))// || (PMT_FRAGMENT_BOX == pm->pmt))
12713 {
12714 struct PendingMessage *root = pm->frag_parent;
12715
12716 while (NULL != root->frag_parent)
12717 root = root->frag_parent;
12719 "Next attempt for root message <%" PRIu64 "> set to %s\n",
12720 root->logging_uuid,
12722 root->next_attempt = next_attempt;
12724 }
12725 else
12726 {
12727 struct PendingMessage *root = pm->frag_parent;
12728
12729 while (NULL != root->frag_parent && PMT_DV_BOX != root->pmt)
12730 root = root->frag_parent;
12731
12733 "frag_count next attempt %u\n",
12734 root->frag_count);
12735
12736 if (GNUNET_NO == root->frags_in_flight)
12737 {
12738 root->next_attempt = next_attempt;
12740 root->frags_in_flight_round++;
12742 "Next attempt for fragmented message <%" PRIu64 "> (<%" PRIu64
12743 ">)set to %" PRIu64 "\n",
12744 pm->logging_uuid,
12745 root->logging_uuid,
12747 }
12748
12749 pm->next_attempt = root->next_attempt;
12752
12753 if (root->bytes_msg == root->frag_off)
12754 root->frags_in_flight = check_next_attempt_tree (root, root);
12755 else
12757
12758 if (GNUNET_NO == root->frags_in_flight)
12759 {
12760 /* `root' deliberately stops at a DV box, which is itself a child of
12761 the message on vl->pending_msg_head. Walk the rest of the way for
12762 the reorder: only the parentless message is on that list. */
12763 struct PendingMessage *vl_root = root;
12764
12765 while (NULL != vl_root->frag_parent)
12766 vl_root = vl_root->frag_parent;
12767 vl_root->next_attempt = root->next_attempt;
12769 "We have no fragments in flight for message %" PRIu64
12770 ", reorder root %" PRIu64 "! Next attempt is %" PRIu64 "\n",
12771 root->logging_uuid,
12772 vl_root->logging_uuid,
12773 vl_root->next_attempt.abs_value_us);
12774 reorder_root_pm (vl_root, vl_root->next_attempt);
12775 }
12776 else
12777 {
12778 double factor = ((double) root->frag_count - 1)
12779 / (double) root->frag_count;
12780 struct GNUNET_TIME_Relative s1;
12781 struct GNUNET_TIME_Relative s2;
12782 struct GNUNET_TIME_Relative plus_mean =
12785 next_attempt);
12786
12788 "frag_count %u after factor\n",
12789 root->frag_count);
12791 factor);
12792 s2 = GNUNET_TIME_relative_divide (plus,
12793 root->frag_count);
12794 plus_mean = GNUNET_TIME_relative_add (s1, s2);
12797 "We have fragments in flight for message %" PRIu64
12798 ", do not reorder root! Actual next attempt %" PRIu64 "\n",
12799 root->logging_uuid,
12801 }
12802 }
12803}
12804
12805
12810{
12814 struct PendingMessage *best;
12815
12819 struct DistanceVectorHop *dvh;
12820
12824 size_t real_overhead;
12825
12829 unsigned int consideration_counter;
12830
12834 int frag;
12835
12839 int relb;
12840
12844 int to_early;
12845
12849 unsigned int frags_in_flight;
12850
12855};
12856
12857
12869static void
12871 struct Queue *queue,
12872 struct VirtualLink *vl,
12873 struct DistanceVectorHop *dvh,
12874 size_t overhead)
12875{
12876 struct GNUNET_TIME_Absolute now;
12877
12878 now = GNUNET_TIME_absolute_get ();
12879 /* NOTE: @a sc accumulates across calls -- #transmit_on_queue() zeroes it
12880 once and then runs us for the direct link and for every DV hop in turn.
12881 Clearing the verdict here made each call discard what the previous ones
12882 found, so a message that was too early on the direct link was forgotten
12883 as soon as one DV hop had nothing to offer, and nothing rescheduled the
12884 queue at all. */
12885 for (struct PendingMessage *pos = vl->pending_msg_head; NULL != pos;
12886 pos = pos->next_vl)
12887 {
12888 size_t real_overhead = overhead;
12889 int frag;
12890 int relb;
12891
12892 if ((NULL != dvh) && (PMT_DV_BOX == pos->pmt))
12893 {
12895 "DV messages must not be DV-routed to next hop!\n");
12896 continue; /* DV messages must not be DV-routed to next hop! */
12897 }
12898 if (pos->next_attempt.abs_value_us > now.abs_value_us)
12899 {
12900 if (GNUNET_YES == pos->frags_in_flight)
12901 {
12902 sc->frags_in_flight = GNUNET_YES;
12904 "Fragments in flight for message %" PRIu64 "\n",
12905 pos->logging_uuid);
12906 }
12907 else
12908 {
12910 "Maybe too early, because message are sorted by next_attempt, if there are no fragments in flight.Checked message %"
12911 PRIu64 "\n",
12912 pos->logging_uuid);
12913 /* The *earliest* deadline is the one to come back for: @e
12914 pending_msg_head is sorted by @e next_attempt, so overwriting
12915 this on every iteration left the largest delay of the whole
12916 list -- the queue then slept past every message but the last
12917 one. Across the calls for the direct link and each DV hop the
12918 same argument applies, hence the min() rather than an
12919 assignment. */
12920 sc->to_early_retry_delay =
12921 (GNUNET_YES == sc->to_early)
12922 ? GNUNET_TIME_relative_min (sc->to_early_retry_delay,
12924 pos->next_attempt))
12925 : GNUNET_TIME_absolute_get_remaining (pos->next_attempt);
12926 sc->to_early = GNUNET_YES;
12927 continue;
12928 }
12929 // break; /* too early for all messages, they are sorted by next_attempt */
12930 }
12931 if (NULL != pos->qe)
12932 {
12934 "not eligible\n");
12935 continue; /* not eligible */
12936 }
12937 sc->consideration_counter++;
12938 /* determine if we have to fragment, if so add fragmentation
12939 overhead! */
12941 "check %" PRIu64 " for sc->best\n",
12942 pos->logging_uuid);
12943 frag = GNUNET_NO;
12944 if (((0 != queue->mtu) &&
12945 (pos->bytes_msg + real_overhead > queue->mtu)) ||
12946 (pos->bytes_msg > UINT16_MAX - sizeof(struct
12948 ||
12949 (NULL != pos->head_frag /* fragments already exist, should
12950 respect that even if MTU is UINT16_MAX for
12951 this queue */))
12952 {
12954 "fragment msg with size %u, realoverhead is %lu\n",
12955 pos->bytes_msg,
12956 real_overhead);
12957 frag = GNUNET_YES;
12958 if (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc)
12959 {
12960 /* FIXME-FRAG-REL-UUID: we could use an optimized, shorter fragmentation
12961 header without the ACK UUID when using a *reliable* channel! */
12962 }
12963 real_overhead = overhead + sizeof(struct TransportFragmentBoxMessage);
12964 }
12965 /* determine if we have to reliability-box, if so add reliability box
12966 overhead */
12967 relb = GNUNET_NO;
12968 if ((GNUNET_NO == frag) &&
12969 (0 == (pos->prefs & GNUNET_MQ_PREF_UNRELIABLE)) &&
12970 (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc))
12971 {
12972 real_overhead += sizeof(struct TransportReliabilityBoxMessage);
12973
12974 if ((0 != queue->mtu) && (pos->bytes_msg + real_overhead > queue->mtu))
12975 {
12976 frag = GNUNET_YES;
12977 real_overhead = overhead + sizeof(struct TransportFragmentBoxMessage);
12978 }
12979 else
12980 {
12981 relb = GNUNET_YES;
12982 }
12984 "Create reliability box of msg with size %u, realoverhead is %lu %u %u %u\n",
12985 pos->bytes_msg,
12986 real_overhead,
12987 queue->mtu,
12988 frag,
12989 relb);
12990 }
12991
12992 /* Finally, compare to existing 'best' in sc to see if this 'pos' pending
12993 message would beat it! */
12994 if (GNUNET_NO == sc->frags_in_flight && NULL != sc->best)
12995 {
12996 /* CHECK if pos fits queue BETTER (=smaller) than pm, if not: continue;
12997 OPTIMIZE-ME: This is a heuristic, which so far has NOT been
12998 experimentally validated. There may be some huge potential for
12999 improvement here. Also, we right now only compare how well the
13000 given message fits _this_ queue, and do not consider how well other
13001 queues might suit the message. Taking other queues into consideration
13002 may further improve the result, but could also be expensive
13003 in terms of CPU time. */
13004 long long sc_score = sc->frag * 40 + sc->relb * 20 + sc->real_overhead;
13005 long long pm_score = frag * 40 + relb * 20 + real_overhead;
13006 long long time_delta =
13007 (sc->best->next_attempt.abs_value_us - pos->next_attempt.abs_value_us)
13008 / 1000LL;
13009
13010 /* "time_delta" considers which message has been 'ready' for transmission
13011 for longer, if a message has a preference for low latency, increase
13012 the weight of the time_delta by 10x if it is favorable for that message */
13013 if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
13014 (0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)))
13015 time_delta *= 10; /* increase weight (always, both are low latency) */
13016 else if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
13017 (time_delta > 0))
13018 time_delta *= 10; /* increase weight, favors 'pos', which is low latency */
13019 else if ((0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
13020 (time_delta < 0))
13021 time_delta *= 10; /* increase weight, favors 'sc->best', which is low latency */
13022 if (0 != queue->mtu)
13023 {
13024 /* Grant bonus if we are below MTU, larger bonus the closer we will
13025 be to the MTU */
13026 if (queue->mtu > sc->real_overhead + sc->best->bytes_msg)
13027 sc_score -= queue->mtu - (sc->real_overhead + sc->best->bytes_msg);
13028 if (queue->mtu > real_overhead + pos->bytes_msg)
13029 pm_score -= queue->mtu - (real_overhead + pos->bytes_msg);
13030 }
13031 if (sc_score + time_delta > pm_score)
13032 {
13034 "sc_score of %" PRIu64 " larger, keep sc->best %" PRIu64
13035 "\n",
13036 pos->logging_uuid,
13037 sc->best->logging_uuid);
13038 continue; /* sc_score larger, keep sc->best */
13039 }
13040 }
13041 sc->best = pos;
13042 sc->dvh = dvh;
13043 sc->frag = frag;
13044 sc->relb = relb;
13045 sc->real_overhead = real_overhead;
13046 }
13047}
13048
13049
13060static void
13061extract_box_cb (void *cls,
13062 struct Neighbour *next_hop,
13063 const struct GNUNET_MessageHeader *hdr,
13065{
13066 struct PendingMessageScoreContext *sc = cls;
13067 struct PendingMessage *pm = sc->best;
13068 struct PendingMessage *bpm;
13069 uint16_t bsize = ntohs (hdr->size);
13070
13071 GNUNET_assert (NULL == pm->bpm);
13072 bpm = GNUNET_malloc (sizeof(struct PendingMessage) + bsize);
13074 "5 created pm %p storing vl %p from pm %p\n",
13075 bpm,
13076 pm->vl,
13077 pm);
13079 bpm->pmt = PMT_DV_BOX;
13080 bpm->vl = pm->vl;
13081 bpm->timeout = pm->timeout;
13082 bpm->bytes_msg = bsize;
13083 bpm->frag_parent = pm;
13086 "Creating DV Box %" PRIu64 " for original message %" PRIu64
13087 " (next hop is %s)\n",
13089 pm->logging_uuid,
13090 GNUNET_i2s (&next_hop->pid));
13091 memcpy (&bpm[1], hdr, bsize);
13092 pm->bpm = bpm;
13093}
13094
13095
13111static void
13112transmit_on_queue (void *cls)
13113{
13114 struct Queue *queue = cls;
13115 struct Neighbour *n = queue->neighbour;
13117 struct PendingMessage *pm;
13118
13119 queue->transmit_task = NULL;
13120 if ((NULL == n->vl) && (NULL == n->dv_head))
13121 {
13123 "Virtual link `%s' is down, cannot have PM for queue `%s'\n",
13124 GNUNET_i2s (&n->pid),
13125 queue->address);
13126 queue->idle = GNUNET_YES;
13127 return;
13128 }
13129 memset (&sc, 0, sizeof(sc));
13130 /* @e n need not have a link of its own: it may serve only as the first
13131 hop of DV paths, and the traffic queued for those still has to go out. */
13132 if (NULL != n->vl)
13133 select_best_pending_from_link (&sc, queue, n->vl, NULL, 0);
13134 if (NULL == sc.best)
13135 {
13136 /* Also look at DVH that have the n as first hop! */
13137 for (struct DistanceVectorHop *dvh = n->dv_head; NULL != dvh;
13138 dvh = dvh->next_neighbour)
13139 {
13140 if (NULL == dvh->dv->vl)
13141 continue; /* route not (yet) visible to CORE, no messages for it */
13143 queue,
13144 dvh->dv->vl,
13145 dvh,
13146 sizeof(struct GNUNET_PeerIdentity)
13147 * (1 + dvh->distance)
13148 + sizeof(struct TransportDVBoxMessage)
13149 + sizeof(struct TransportDVBoxPayloadP));
13150 }
13151 }
13152 if (NULL == sc.best)
13153 {
13154 /* no message pending, nothing to do here! */
13156 "No pending messages, queue `%s' to %s now idle\n",
13157 queue->address,
13158 GNUNET_i2s (&n->pid));
13159 if (GNUNET_YES == sc.to_early)
13160 schedule_transmit_on_queue (sc.to_early_retry_delay,
13161 queue,
13163 queue->idle = GNUNET_YES;
13164 return;
13165 }
13166 /* There is a message pending, we are certainly not idle */
13167 queue->idle = GNUNET_NO;
13168
13169 /* Given selection in `sc`, do transmission */
13170 pm = sc.best;
13172 "Selected message <%" PRIu64 ">\n",
13173 pm->logging_uuid);
13174 if (NULL != sc.dvh)
13175 {
13177 "Is this %u a DV box?\n",
13178 pm->pmt);
13179 GNUNET_assert (PMT_DV_BOX != pm->pmt);
13180 if ((NULL != sc.best->bpm) && (sc.best->bpm->used_dvh != sc.dvh))
13181 {
13183 "Discard old box, because we have a new DV path.\n");
13184 free_pending_message (sc.best->bpm);
13185 sc.best->bpm = NULL;
13186 }
13187
13188 if (NULL == sc.best->bpm)
13189 {
13191 "encapsulate_for_dv 2\n");
13192 encapsulate_for_dv (sc.dvh->dv,
13193 1,
13194 &sc.dvh,
13195 (const struct GNUNET_MessageHeader *) &sc.best[1],
13197 &sc,
13198 RMO_NONE,
13199 GNUNET_NO);
13200 GNUNET_assert (NULL != sc.best->bpm);
13202 "%lu %lu %lu %lu %u\n",
13203 sizeof(struct GNUNET_PeerIdentity),
13204 sizeof(struct TransportDVBoxMessage),
13205 sizeof(struct TransportDVBoxPayloadP),
13206 sizeof(struct TransportFragmentBoxMessage),
13207 ((const struct GNUNET_MessageHeader *) &sc.best[1])->size);
13208 sc.best->bpm->used_dvh = sc.dvh;
13209 }
13210 pm = sc.best->bpm;
13211 }
13212 if (GNUNET_YES == sc.frag)
13213 {
13214 pm = fragment_message (queue, sc.dvh, pm);
13215 if (NULL == pm)
13216 {
13218 "Fragmentation failed queue %s to %s for <%" PRIu64
13219 ">, trying again\n",
13220 queue->address,
13221 GNUNET_i2s (&n->pid),
13222 sc.best->logging_uuid);
13223 /* NOT with a zero delay: nothing about @a queue or about the message
13224 changed between here and the next pass, so "trying again" at once
13225 is a busy loop that reproduces the failure at scheduler speed. */
13227 queue,
13229 return;
13230 }
13231 }
13232 else if (GNUNET_YES == sc.relb)
13233 {
13234 pm = reliability_box_message (queue, sc.dvh, pm);
13235 if (NULL == pm)
13236 {
13237 /* Reliability boxing failed, try next message... */
13238 GNUNET_log (
13240 "Reliability boxing failed queue %s to %s for <%" PRIu64
13241 ">, trying again\n",
13242 queue->address,
13243 GNUNET_i2s (&n->pid),
13244 sc.best->logging_uuid);
13245 /* Same reasoning as for the fragmentation failure above. */
13247 queue,
13249 return;
13250 }
13251 }
13252
13253 /* Pass 'pm' for transission to the communicator */
13254 GNUNET_log (
13256 "Passing message <%" PRIu64
13257 "> to queue %s for peer %s (considered %u others)\n",
13258 pm->logging_uuid,
13259 queue->address,
13260 GNUNET_i2s (&n->pid),
13261 sc.consideration_counter);
13262
13263 /* Flow control: increment amount of traffic sent; if we are routing
13264 via DV (and thus the ultimate target of the pending message is for
13265 a different virtual link than the one of the queue), then we need
13266 to use up not only the window of the direct link but also the
13267 flow control window for the DV link! */
13269
13270 if (pm->vl != queue->neighbour->vl)
13271 {
13272 /* If the virtual link of the queue differs, this better be distance
13273 vector routing! */
13274 GNUNET_assert (NULL != sc.dvh);
13275 /* If we do distance vector routing, we better not do this for a
13276 message that was itself DV-routed */
13277 GNUNET_assert (PMT_DV_BOX != sc.best->pmt);
13278 /* We use the size of the unboxed message here, to avoid counting
13279 the DV-Box header which is eaten up on the way by intermediaries.
13280 The next hop need not have a link of its own, in which case there is
13281 no window of it to charge. */
13282 if (NULL != queue->neighbour->vl)
13283 queue->neighbour->vl->outbound_fc_window_size_used += sc.best->bytes_msg;
13284 }
13285 else
13286 {
13287 GNUNET_assert (NULL == sc.dvh);
13288 }
13289
13290 queue_send_msg (queue, pm, &pm[1], pm->bytes_msg);
13291
13292 /* The message is with the communicator now, so return the CORE send
13293 window credit for it -- see #credit_client().
13294
13295 It used to be returned here only for an unboxed message or a reliable
13296 communicator, and otherwise not until the *peer* acknowledged the
13297 message below. That makes a window into a delivery confirmation: over
13298 an unreliable communicator every reliability-boxed or fragmented
13299 message holds one of the client's #SEND_WINDOW_SIZE slots for as long
13300 as its ACK takes, and a lost ACK holds it for the whole retransmission
13301 chain. Four of those and CORE cannot send to that peer at all -- not
13302 payload, but also not its HEARTBEATs and not one message of its key
13303 exchange. So the session times out for want of a heartbeat that is
13304 sitting in a queue, and the handshake that would rebuild it cannot go
13305 out either; CORE only recovers when a reconnect resets the window
13306 wholesale. Acknowledgements still drive retransmission below, they
13307 just no longer gate the client. */
13308 credit_client (sc.best);
13309
13310 /* Check if this transmission somehow conclusively finished handing 'pm'
13311 even without any explicit ACKs */
13312 if ((PMT_CORE == pm->pmt) ||
13313 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc))
13314 {
13316 }
13317 else
13318 {
13319 struct GNUNET_TIME_Relative wait_duration;
13320 unsigned int wait_multiplier;
13321
13322 if (PMT_FRAGMENT_BOX == pm->pmt)
13323 {
13324 struct PendingMessage *root;
13325
13326 root = pm->frag_parent;
13327 while (NULL != root->frag_parent && PMT_DV_BOX != root->pmt)
13328 root = root->frag_parent;
13329
13330 if ((0 == root->frag_off) || (0 == root->frag_count))
13331 {
13332 wait_multiplier = 4;
13333 }
13334 else
13335 {
13336 double wm = ceil ((double) root->bytes_msg
13337 / ((double) root->frag_off
13338 / (double) root->frag_count)) * 4.0;
13339
13340 if ((! (wm >= 1.0)) || (wm > 1024.0))
13341 wm = 4.0; /* NaN, infinity or absurd: fall back to the default */
13342 wait_multiplier = (unsigned int) wm;
13343 }
13344 }
13345 else
13346 {
13347 // No fragments, we use 4 RTT before retransmitting.
13348 wait_multiplier = 4;
13349 }
13350
13351 // Depending on how much pending message the VirtualLink is queueing, we wait longer.
13352 // wait_multiplier = wait_multiplier * pm->vl->pending_msg_num;
13353
13355 "Wait multiplier %u\n",
13356 wait_multiplier);
13357
13358 /* Message not finished, waiting for acknowledgement.
13359 Update time by which we might retransmit 's' based on queue
13360 characteristics (i.e. RTT); it takes one RTT for the message to
13361 arrive and the ACK to come back in the best case; but the other
13362 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
13363 retransmitting.
13364
13365 OPTIMIZE: Note that in the future this heuristic should likely
13366 be improved further (measure RTT stability, consider message
13367 urgency and size when delaying ACKs, etc.) */
13368
13369 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us !=
13370 queue->pd.aged_rtt.rel_value_us)
13371 wait_duration = GNUNET_TIME_relative_max (queue->pd.aged_rtt,
13373 else
13374 {
13375 wait_duration = DEFAULT_ACK_WAIT_DURATION;
13376 wait_multiplier = 4;
13377 }
13378 {
13381 wait_duration, wait_multiplier));
13383 wait_duration, wait_multiplier);
13385 "Waiting %s for ACK until %s\n",
13390 GNUNET_TIME_relative_multiply (wait_duration,
13391 wait_multiplier))
13392 );
13393 }
13394 }
13395 /* finally, re-schedule queue transmission task itself */
13397 queue,
13399}
13400
13401
13408static void
13409handle_del_queue_message (void *cls,
13410 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
13411{
13412 struct TransportClient *tc = cls;
13413
13414 if (CT_COMMUNICATOR != tc->type)
13415 {
13416 GNUNET_break (0);
13418 return;
13419 }
13420 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
13421 queue = queue->next_client)
13422 {
13423 struct Neighbour *neighbour = queue->neighbour;
13424
13425 if ((ntohl (dqm->qid) != queue->qid) ||
13426 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
13427 continue;
13429 "Dropped queue %s to peer %s\n",
13430 queue->address,
13431 GNUNET_i2s (&neighbour->pid));
13432 free_queue (queue);
13434 return;
13435 }
13436 /* Not finding the queue is a race, not a protocol violation: we may have
13437 freed it ourselves already, or the communicator may be tearing down a
13438 queue we never fully learned about. Do NOT drop the client over it --
13439 that runs #client_disconnect_cb(), which frees *every* queue this
13440 communicator owns, so one stale QUEUE_TEARDOWN would disconnect us from
13441 every peer it serves at once. Compare #handle_send_message_ack(), which
13442 tolerates the same lookup miss. */
13444 "QUEUE_TEARDOWN for unknown queue QID %u to peer %s ignored\n",
13445 ntohl (dqm->qid),
13446 GNUNET_i2s (&dqm->receiver));
13448 "# QUEUE_TEARDOWN dropped: queue unknown",
13449 1,
13450 GNUNET_NO);
13452}
13453
13454
13455static void
13457 struct TransportClient *tc)
13458{
13459 struct PendingMessage *pm;
13460
13461 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
13462 qe->queue->queue_tail,
13463 qe);
13464 qe->queue->queue_length--;
13465 tc->details.communicator.total_queue_length--;
13467 "Received ACK on queue %s (QID %u) to peer %s (new length: %u/%u)\n",
13468 qe->queue->address,
13469 qe->queue->qid,
13470 GNUNET_i2s (&qe->queue->neighbour->pid),
13471 qe->queue->queue_length,
13472 tc->details.communicator.total_queue_length);
13473
13474 /* if applicable, resume transmissions that waited on ACK */
13476 tc->details.communicator.total_queue_length)
13477 {
13478 /* Communicator dropped below threshold, resume all queues
13479 incident with this client! */
13481 GST_stats,
13482 "# Transmission throttled due to communicator queue limit",
13483 -1,
13484 GNUNET_NO);
13485 for (struct Queue *queue = tc->details.communicator.queue_head;
13486 NULL != queue;
13487 queue = queue->next_client)
13488 {
13490 queue,
13492 }
13493 }
13494 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
13495 {
13496 /* queue dropped below threshold; only resume this one queue */
13498 "# Transmission throttled due to queue queue limit",
13499 -1,
13500 GNUNET_NO);
13502 qe->queue,
13504 }
13505 else if (1 == qe->queue->q_capacity)
13506 {
13507 // TODO I guess this will never happen, because the communicator triggers this by updating its queue length itself.
13509 "Transmission rescheduled due to communicator message queue with qid %u has capacity %"
13510 PRIu64 ".\n",
13511 qe->queue->qid,
13512 qe->queue->q_capacity);
13513 /* message queue has capacity; only resume this one queue */
13514 /* queue dropped below threshold; only resume this one queue */
13516 "# Transmission throttled due to message queue capacity",
13517 -1,
13518 GNUNET_NO);
13520 qe->queue,
13522 }
13523
13524 if (NULL != (pm = qe->pm))
13525 {
13526 struct VirtualLink *vl;
13527
13528 // GNUNET_assert (qe == pm->qe);
13529 pm->qe = NULL;
13530 /* If waiting for this communicator may have blocked transmission
13531 of pm on other queues for this neighbour, force schedule
13532 transmit on queue for queues of the neighbour */
13533 if (NULL == pm->frag_parent)
13534 {
13535 vl = pm->vl;
13536 if ((NULL != vl) &&
13537 (NULL != vl->pending_msg_head) &&
13538 (vl->pending_msg_head == pm))
13540 }
13541 }
13542 GNUNET_free (qe);
13543}
13544
13545
13552static void
13553handle_send_message_ack (void *cls,
13554 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
13555{
13556 struct TransportClient *tc = cls;
13557 struct QueueEntry *qe;
13558 struct Queue *failed_queue = NULL;
13559
13560 if (CT_COMMUNICATOR != tc->type)
13561 {
13562 GNUNET_break (0);
13564 return;
13565 }
13566
13567 /* find our queue entry matching the ACK */
13568 qe = NULL;
13570 "Looking for queue for PID %s\n",
13571 GNUNET_i2s (&sma->receiver));
13572 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
13573 queue = queue->next_client)
13574 {
13575 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
13576 continue;
13578 "Found PID %s\n",
13579 GNUNET_i2s (&queue->neighbour->pid));
13580
13581
13582 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
13583 qep = qep->next)
13584 {
13585 if (qep->mid != GNUNET_ntohll (sma->mid) || queue->qid != ntohl (
13586 sma->qid))
13587 continue;
13589 "QueueEntry MID: %" PRIu64 " on queue QID: %u, Ack MID: %"
13590 PRIu64 " Ack QID %u\n",
13591 qep->mid,
13592 queue->qid,
13593 GNUNET_ntohll (sma->mid),
13594 ntohl (sma->qid));
13595 qe = qep;
13596 if ((NULL != qe->pm) && (qe->pm->qe != qe))
13598 "For pending message %" PRIu64 " we had retransmissions.\n",
13599 qe->pm->logging_uuid);
13600 break;
13601 }
13602 }
13603 if (GNUNET_OK != (int) ntohl (sma->status))
13604 {
13605 /* The communicator could not hand the message to the peer. The only
13606 thing that produces this today is #handle_send_msg()'s "queue no
13607 longer exists" branch in `transport_api_communication.c', i.e. the
13608 communicator has already torn the queue down on its side and the
13609 QUEUE_TEARDOWN is merely still in flight (or was lost).
13610
13611 Ignoring the status, as we used to, makes this self-sustaining:
13612 #free_queue_entry() releases the pending message and immediately
13613 reschedules transmission, #transmit_on_queue() picks the very same
13614 queue again -- transport still has it -- and we get another failure.
13615 Every round adds an envelope to the client MQ that is already
13616 congested, which is what shows up at the other end as
13617
13618 communicator INFO Transmission failed, queue no longer exists.
13619
13620 repeating at scheduler speed, and (because the service is busy
13621 servicing that loop) as
13622
13623 communicator WARNING Dropping message: transport is too slow,
13624 queue length N exceeded
13625
13626 on every *other* communicator. Treat the failure as the queue
13627 teardown it is and stop selecting this queue. */
13629 "Communicator could not send MID %" PRIu64
13630 " on QID %u to %s; dropping that queue\n",
13631 GNUNET_ntohll (sma->mid),
13632 ntohl (sma->qid),
13633 GNUNET_i2s (&sma->receiver));
13635 "# queues dropped (communicator send failed)",
13636 1,
13637 GNUNET_NO);
13638 if (NULL != qe)
13639 failed_queue = qe->queue;
13640 else
13641 for (struct Queue *queue = tc->details.communicator.queue_head;
13642 NULL != queue;
13643 queue = queue->next_client)
13644 if ((ntohl (sma->qid) == queue->qid) &&
13645 (0 == GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver)))
13646 {
13647 failed_queue = queue;
13648 break;
13649 }
13650 if (NULL != failed_queue)
13651 {
13652 /* #free_queue() releases every `struct QueueEntry' still on it --
13653 including @a qe -- and detaches their pending messages, so they are
13654 retried on whatever other queue this neighbour has. */
13655 free_queue (failed_queue);
13657 return;
13658 }
13659 }
13660 if (NULL == qe)
13661 {
13663 "No QueueEntry found for Ack MID %" PRIu64 " QID: %u\n",
13664 GNUNET_ntohll (sma->mid),
13665 ntohl (sma->qid));
13666 // TODO I guess this can happen, if the Ack from the peer comes before the Ack from the queue.
13667 // Update: Maybe QueueEntry was accidentally freed during freeing PendingMessage.
13668 /* this should never happen */
13669 // GNUNET_break (0);
13670 // GNUNET_SERVICE_client_drop (tc->client);
13672 return;
13673 }
13676}
13677
13678
13684static void
13685handle_burst_finished (void *cls,
13686 const struct GNUNET_TRANSPORT_BurstFinished *bf)
13687{
13688 struct TransportClient *tc = cls;
13689
13690 (void) bf;
13693}
13694
13695
13705static int
13706notify_client_queues (void *cls,
13707 const struct GNUNET_PeerIdentity *pid,
13708 void *value)
13709{
13710 struct TransportClient *tc = cls;
13711 struct Neighbour *neighbour = value;
13712
13713 GNUNET_assert (CT_MONITOR == tc->type);
13714 for (struct Queue *q = neighbour->queue_head; NULL != q;
13715 q = q->next_neighbour)
13716 {
13717 struct MonitorEvent me = { .rtt = q->pd.aged_rtt,
13718 .cs = q->cs,
13719 .num_msg_pending = q->num_msg_pending,
13720 .num_bytes_pending = q->num_bytes_pending };
13721
13722 notify_monitor (tc, pid, q->address, q->nt, &me);
13723 }
13724 return GNUNET_OK;
13725}
13726
13727
13734static void
13735handle_monitor_start (void *cls,
13737{
13738 struct TransportClient *tc = cls;
13739
13740 if (CT_NONE != tc->type)
13741 {
13742 GNUNET_break (0);
13744 return;
13745 }
13746 tc->type = CT_MONITOR;
13747 tc->details.monitor.peer = start->peer;
13748 tc->details.monitor.one_shot = ntohl (start->one_shot);
13752}
13753
13754
13758struct LinkListContext
13759{
13763 struct TransportClient *tc;
13764
13769};
13770
13771
13780static char *
13781communicator_list (struct Neighbour *n,
13782 unsigned int *num_queues)
13783{
13784 char *ret = GNUNET_strdup ("");
13785
13786 *num_queues = 0;
13787 if (NULL == n)
13788 return ret;
13789 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
13790 {
13791 const char *prefix = q->tc->details.communicator.address_prefix;
13792 size_t plen = strlen (prefix);
13793 const char *pos;
13794 char *tmp;
13795
13796 (*num_queues)++;
13797 if (0 == plen)
13798 continue;
13799 /* Several queues to one neighbour routinely share a communicator;
13800 name each one once. */
13801 for (pos = strstr (ret, prefix);
13802 NULL != pos;
13803 pos = strstr (pos + 1, prefix))
13804 if (((pos == ret) || (',' == pos[-1])) &&
13805 (('\0' == pos[plen]) || (',' == pos[plen])))
13806 break;
13807 if (NULL != pos)
13808 continue;
13809 GNUNET_asprintf (&tmp, "%s%s%s", ret, ('\0' == ret[0]) ? "" : ",", prefix);
13810 GNUNET_free (ret);
13811 ret = tmp;
13812 }
13813 return ret;
13814}
13815
13816
13825static enum GNUNET_GenericReturnValue
13826report_link (void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
13827{
13828 struct LinkListContext *llc = cls;
13829 struct VirtualLink *vl = value;
13831 struct GNUNET_MQ_Envelope *env;
13832 unsigned int pending = 0;
13833 unsigned int num_queues = 0;
13834 unsigned int distance = 0;
13835 struct Neighbour *hop;
13836 char *ccs;
13837 size_t clen;
13838
13839 if ((GNUNET_YES != llc->include_unconfirmed) &&
13840 (GNUNET_YES != vl->confirmed))
13841 return GNUNET_OK;
13842 for (struct PendingMessage *pm = vl->pending_msg_head;
13843 NULL != pm;
13844 pm = pm->next_vl)
13845 pending++;
13846 if (NULL != vl->n)
13847 {
13848 hop = vl->n;
13849 }
13850 else
13851 {
13852 /* Report the best (shortest) of the paths we currently know, and the
13853 communicators that carry its first hop. */
13854 struct DistanceVectorHop *best = NULL;
13855
13856 distance = UINT_MAX;
13857 if (NULL != vl->dv)
13858 for (struct DistanceVectorHop *pos = vl->dv->dv_head;
13859 NULL != pos;
13860 pos = pos->next_dv)
13861 if (pos->distance < distance)
13862 {
13863 distance = pos->distance;
13864 best = pos;
13865 }
13866 if (NULL == best)
13867 distance = 0; /* no paths left; report the link as adjacent */
13868 hop = (NULL != best) ? best->next_hop : NULL;
13869 }
13870 ccs = communicator_list (hop, &num_queues);
13871 clen = strlen (ccs) + 1;
13872 env = GNUNET_MQ_msg_extra (resp,
13873 clen,
13875 memcpy (&resp[1], ccs, clen);
13876 GNUNET_free (ccs);
13877 resp->target = *pid;
13878 resp->confirmed = htonl ((uint32_t) vl->confirmed);
13879 resp->route = htonl ((uint32_t) ((NULL != vl->n)
13882 resp->distance = htonl ((uint32_t) distance);
13883 resp->num_queues = htonl ((uint32_t) num_queues);
13884 resp->core_recv_window = htonl ((int32_t) vl->core_recv_window);
13885 resp->stalled = htonl ((uint32_t) vl->cmc_count);
13886 resp->pending = htonl (pending);
13887 resp->fc_retransmit_count = htonl ((uint32_t) vl->fc_retransmit_count);
13906 GNUNET_MQ_send (llc->tc->mq, env);
13907 return GNUNET_OK;
13908}
13909
13910
13919static void
13921 void *cls,
13923{
13924 struct TransportClient *tc = cls;
13925 struct LinkListContext llc = {
13926 .tc = tc,
13927 .include_unconfirmed = (int) ntohl (lr->include_unconfirmed)
13928 };
13929 struct GNUNET_MQ_Envelope *env;
13930 struct GNUNET_MessageHeader *end;
13931
13932 if (CT_NONE != tc->type)
13933 {
13934 GNUNET_break (0);
13936 return;
13937 }
13938 if (GNUNET_YES == GNUNET_is_zero (&lr->peer))
13939 {
13941 }
13942 else
13943 {
13944 struct VirtualLink *vl = lookup_virtual_link (&lr->peer);
13945
13946 if (NULL != vl)
13947 report_link (&llc, &lr->peer, vl);
13948 }
13951 GNUNET_MQ_send (tc->mq, env);
13953}
13954
13955
13963static struct TransportClient *
13964lookup_communicator (const char *prefix)
13965{
13966 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
13967 {
13968 if (CT_COMMUNICATOR != tc->type)
13969 continue;
13970 if (NULL == tc->details.communicator.address_prefix)
13971 continue; /* receive-only communicator */
13972 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
13973 return tc;
13974 }
13975 GNUNET_log (
13977 "Someone suggested use of communicator for `%s', but we do not have such a communicator!\n",
13978 prefix);
13979 return NULL;
13980}
13981
13982
13990static void
13991suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address)
13992{
13993 static uint32_t idgen = 0;
13994 struct TransportClient *tc;
13995 char *prefix;
13996 struct GNUNET_TRANSPORT_CreateQueue *cqm;
13997 struct GNUNET_MQ_Envelope *env;
13998 size_t alen;
13999
14001 if (NULL == prefix)
14002 {
14003 GNUNET_break (0); /* We got an invalid address!? */
14004 return;
14005 }
14007 if (NULL == tc)
14008 {
14010 "# Suggestions ignored due to missing communicator",
14011 1,
14012 GNUNET_NO);
14014 "Cannot connect to %s at `%s', no matching communicator present\n",
14015 GNUNET_i2s (pid),
14016 address);
14018 return;
14019 }
14020 /* forward suggestion for queue creation to communicator */
14022 "Request #%u for `%s' communicator to create queue to `%s' at `%s'\n",
14023 (unsigned int) idgen,
14024 prefix,
14025 GNUNET_i2s (pid),
14026 address);
14028 alen = strlen (address) + 1;
14029 env =
14031 cqm->request_id = htonl (idgen++);
14032 cqm->receiver = *pid;
14033 memcpy (&cqm[1], address, alen);
14034 GNUNET_MQ_send (tc->mq, env);
14035}
14036
14037
14045static void
14047{
14049 struct GNUNET_TIME_Absolute monotonic_time;
14050
14051 if (NULL != vs->revalidation_task)
14052 {
14053 GNUNET_SCHEDULER_cancel (vs->revalidation_task);
14054 vs->revalidation_task = NULL;
14055 }
14056 /*memcpy (&hkey,
14057 &hc,
14058 sizeof (hkey));*/
14060 "Remove key %s for address %s map size %u contains %u\n",
14061 GNUNET_h2s (&vs->hc),
14062 vs->address,
14065 &vs->hc));
14067
14069 if (GNUNET_TIME_UNIT_ZERO_ABS.abs_value_us ==
14070 vs->last_challenge_use.abs_value_us)
14071 {
14072 vs->first_challenge_use = monotonic_time;
14073 }
14074 vs->last_challenge_use = monotonic_time;
14075 tvc.header.type =
14077 tvc.header.size = htons (sizeof(tvc));
14078 tvc.reserved = htonl (0);
14079 tvc.challenge = vs->challenge;
14080 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
14082 "Sending address validation challenge %s to %s\n",
14084 GNUNET_i2s (&q->neighbour->pid));
14085 queue_send_msg (q, NULL, &tvc, sizeof(tvc));
14086}
14087
14088
14100static struct GNUNET_TIME_Relative
14102{
14103 const struct VirtualLink *vl = lookup_virtual_link (pid);
14104
14105 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
14106 return MAX_VALIDATION_CHALLENGE_FREQ; /* we have what we want */
14107 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
14108 {
14109 if (CT_APPLICATION != tc->type)
14110 continue;
14112 tc->details.application.requests,
14113 pid))
14115 }
14117}
14118
14119
14125static void
14126validation_start_cb (void *cls)
14127{
14128 struct ValidationState *vs;
14129 struct Queue *q;
14131 GST_cfg);
14132
14133 (void) cls;
14134 validation_task = NULL;
14136 /* drop validations past their expiration */
14137 while (
14138 (NULL != vs) &&
14140 {
14142 "Validation response %s cleaned up\n",
14143 GNUNET_sh2s (&vs->challenge.value));
14146 }
14147 if (NULL == vs)
14148 {
14150 "Address validation task not scheduled anymore, nothing to do\n");
14151 return; /* woopsie, no more addresses known, should only
14152 happen if we're really a lonely peer */
14153 }
14154 q = find_queue (&vs->pid, vs->address);
14155 if (GNUNET_TIME_absolute_cmp (vs->first_challenge_use, >, now))
14156 {
14158 "To early to start next address validation for challenge %s\n",
14159 GNUNET_sh2s (&vs->challenge.value));
14160 /* Do NOT just return: @e validation_task was set to NULL above and
14161 nothing re-arms it by itself. #update_next_challenge_time() only
14162 schedules us again when it is called with a *changed* time for some
14163 validation state, so bailing out here leaves a non-empty
14164 #validation_heap with no task attached: address (re)validation and
14165 the #suggest_to_connect() retries that go with it stop for *every*
14166 peer until some unrelated event happens to come along. A peer that
14167 just lost its only connection has no such events left. */
14170 now,
14171 vs->first_challenge_use),
14173 NULL);
14174 return;
14175 }
14176 if (NULL == q)
14177 {
14178 vs->awaiting_queue = GNUNET_YES;
14179 suggest_to_connect (&vs->pid, vs->address);
14180 }
14181 else
14183 /* Finally, reschedule next attempt */
14184 vs->challenge_backoff =
14185 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
14188 "Address validation task will run again in %s\n",
14189 GNUNET_STRINGS_relative_time_to_string (vs->challenge_backoff,
14190 GNUNET_YES));
14193 vs->challenge_backoff));
14194}
14195
14196
14201{
14205 struct Queue *q;
14206
14210 unsigned int quality_count;
14211
14215 unsigned int num_queues;
14216
14221 unsigned int k;
14222};
14223
14224
14236static int
14237check_connection_quality (void *cls,
14238 const struct GNUNET_PeerIdentity *pid,
14239 void *value)
14240{
14241 struct QueueQualityContext *ctx = cls;
14242 struct Neighbour *n = value;
14243 int do_inc;
14244
14245 (void) pid;
14246 do_inc = GNUNET_NO;
14247 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
14248 {
14249 ctx->num_queues++;
14250 if (0 == ctx->k--)
14251 ctx->q = q;
14252 /* FIXME-CONQ-STATISTICS: in the future, add reliability / goodput
14253 statistics and consider those as well here? */
14254 if (q->pd.aged_rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
14255 do_inc = GNUNET_YES;
14256 }
14257 if (GNUNET_YES == do_inc)
14258 ctx->quality_count++;
14259 return GNUNET_OK;
14260}
14261
14262
14274static void
14275start_dv_learn (void *cls);
14276
14277
14285static void
14287 struct LearnLaunchEntry *lle,
14288 struct QueueQualityContext qqc)
14289{
14290 if (0 == qqc.num_queues)
14291 {
14293 "# DV learn aborted: no queue left",
14294 1,
14295 GNUNET_NO);
14296 return;
14297 }
14298 qqc.quality_count = 0;
14300 qqc.num_queues = 0;
14301 qqc.q = NULL;
14304 &qqc);
14305 if (NULL == qqc.q)
14306 {
14308 "# DV learn aborted: no queue left",
14309 1,
14310 GNUNET_NO);
14311 return;
14312 }
14313
14314 /* Do this as close to transmission time as possible! */
14316
14317 queue_send_msg (qqc.q, NULL, &dvl, sizeof(dvl));
14318 /* reschedule this job, randomizing the time it runs (but no
14319 actual backoff!) */
14320 if (NULL != dvlearn_task)
14325 NULL);
14326}
14327
14328
14340static void
14341start_dv_learn (void *cls)
14342{
14343 struct LearnLaunchEntry *lle;
14344 struct QueueQualityContext qqc;
14345 struct TransportDVLearnMessage dvl;
14346 const struct GNUNET_PeerIdentity *my_identity;
14347
14348 (void) cls;
14349 dvlearn_task = NULL;
14350 if ((GNUNET_YES == in_shutdown) || (NULL == pils))
14351 return;
14353 return; /* lost all connectivity, cannot do learning */
14355 if (NULL == my_identity)
14356 {
14357 /* PILS has not handed us an identity yet. The first queue arriving
14358 schedules us with add_now(), which routinely wins that race; retry
14359 instead of taking the service down. */
14363 NULL);
14364 return;
14365 }
14367 qqc.quality_count = 0;
14368 qqc.num_queues = 0;
14372 &qqc);
14374 {
14375 struct GNUNET_TIME_Relative delay;
14376 unsigned int factor;
14377
14378 /* scale our retries by how far we are above the threshold */
14382 "At connection quality %u, will launch DV learn in %s\n",
14383 qqc.quality_count,
14386 return;
14387 }
14388 /* remove old entries in #dvlearn_map if it has grown too big */
14389 while (MAX_DV_LEARN_PENDING <=
14391 {
14392 lle = lle_tail;
14395 &lle->challenge.value,
14396 lle));
14398 GNUNET_free (lle);
14399 }
14400 /* setup data structure for learning */
14401 lle = GNUNET_new (struct LearnLaunchEntry);
14403 sizeof(lle->challenge));
14405 "Starting launch DV learn with challenge %s\n",
14406 GNUNET_sh2s (&lle->challenge.value));
14411 &lle->challenge.value,
14412 lle,
14415 dvl.header.size = htons (sizeof(dvl));
14416 dvl.num_hops = htons (0);
14417 dvl.bidirectional = htons (0);
14419 dvl.monotonic_time =
14421 // We will set the below again later
14422 memset (&dvl.init_sig, 0, sizeof dvl.init_sig);
14423 dvl.challenge = lle->challenge;
14424 dvl.initiator = *my_identity;
14425 {
14426 struct DvInitPS dvip = {
14427 .purpose.purpose = htonl (
14429 .purpose.size = htonl (sizeof(dvip)),
14430 .monotonic_time = dvl.monotonic_time,
14431 .challenge = lle->challenge
14432 };
14433
14434 if (GNUNET_OK != sign_by_my_identity (&dvip.purpose, &dvl.init_sig))
14435 return;
14436 }
14437 transmit_dv_init (dvl, lle, qqc);
14438}
14439
14440
14450static char *
14452{
14453 const char *dash;
14454 const char *colon;
14455
14456 if (NULL == address)
14457 return NULL;
14458 dash = strchr (address, '-');
14459 if (NULL == dash)
14460 return NULL;
14461 colon = strchr (dash, ':');
14462 if (NULL == colon)
14463 return NULL;
14464 return GNUNET_strndup (dash + 1,
14465 colon - (dash + 1));
14466}
14467
14468
14478static int
14480 const struct GNUNET_PeerIdentity *pid,
14481 void *value)
14482{
14483 struct Queue *q = cls;
14484 struct ValidationState *vs = value;
14485 char *address_without_port_vs;
14486 char *address_without_port_q;
14487 char *prefix_vs;
14488 char *prefix_q;
14489 int success = GNUNET_YES;
14490
14491 // TODO Check if this is really necessary.
14492 address_without_port_vs = get_address_without_port (vs->address);
14493 address_without_port_q = get_address_without_port (q->address);
14494 prefix_vs = GNUNET_HELLO_address_to_prefix (vs->address);
14495 prefix_q = GNUNET_HELLO_address_to_prefix (q->address);
14496
14498 "Check validation request pending for `%s' at `%s'/`%s' (vs)/(q)\n",
14499 GNUNET_i2s (pid),
14500 (NULL == address_without_port_vs) ? "<unparsable>"
14501 : address_without_port_vs,
14502 (NULL == address_without_port_q) ? "<unparsable>"
14503 : address_without_port_q);
14504 (void) pid;
14505 /* Only the port may differ: the address we asked to connect to is
14506 `PROTO-IP:0' for a NATed peer, while the queue that then materializes
14507 sits at `PROTO-IP:port'. The communicator must match all the same --
14508 a challenge for a `tcp-' address is not answered by a `udp-' queue. */
14509 if ((GNUNET_YES == vs->awaiting_queue) &&
14510 (NULL != address_without_port_vs) &&
14511 (NULL != address_without_port_q) &&
14512 (NULL != prefix_vs) &&
14513 (NULL != prefix_q) &&
14514 (0 == strcmp (prefix_vs, prefix_q)) &&
14515 (0 == strcmp (address_without_port_vs, address_without_port_q)))
14516 {
14517
14518 vs->awaiting_queue = GNUNET_NO;
14520 success = GNUNET_NO;
14521 }
14522
14523 GNUNET_free (address_without_port_vs);
14524 GNUNET_free (address_without_port_q);
14525 GNUNET_free (prefix_vs);
14526 GNUNET_free (prefix_q);
14527 return success;
14528}
14529
14530
14539static void
14540neighbour_dv_monotime_cb (void *cls,
14541 const struct GNUNET_PEERSTORE_Record *record,
14542 const char *emsg)
14543{
14544 struct Neighbour *n = cls;
14545 struct GNUNET_TIME_AbsoluteNBO *mtbe;
14546
14547 (void) emsg;
14548 if (NULL == record)
14549 {
14550 /* we're done with #neighbour_dv_monotime_cb() invocations,
14551 continue normal processing */
14552 n->get = NULL;
14554 return;
14555 }
14556 if (0 == record->value_size)
14557 {
14559 GNUNET_break (0);
14560 return;
14561 }
14562 mtbe = record->value;
14567}
14568
14569
14570static void
14572 const struct GNUNET_PeerIdentity *pid,
14573 const char *uri)
14574{
14575 struct Queue *queue = cls;
14576 struct sockaddr_in v4;
14577 const char *slash;
14578 char *address_uri;
14579 char *prefix;
14580 char *uri_without_port;
14581 char *address_uri_without_port;
14582
14583 slash = strrchr (uri, '/');
14584 if ((NULL == slash) || (slash - uri < 2))
14585 {
14586 GNUNET_break_op (0); /* @a uri comes from a remote HELLO */
14587 return;
14588 }
14589 prefix = GNUNET_strndup (uri, (slash - uri) - 2);
14590 slash++;
14591 GNUNET_asprintf (&address_uri,
14592 "%s-%s",
14593 prefix,
14594 slash);
14595
14597 "1 not global natted_address %u %s %s %s\n",
14598 queue->is_global_natted,
14599 uri,
14600 queue->address,
14601 slash);
14602
14603 uri_without_port = get_address_without_port (address_uri);
14604 if ((NULL == uri_without_port) ||
14605 (1 != inet_pton (AF_INET, uri_without_port, &v4.sin_addr)))
14606 {
14608 GNUNET_free (address_uri);
14609 GNUNET_free (uri_without_port);
14610 return;
14611 }
14612
14614 "2 not global natted_address %u %s %s\n",
14615 queue->is_global_natted,
14616 uri,
14617 queue->address);
14618
14619 if (GNUNET_NO == queue->is_global_natted)
14620 {
14622 GNUNET_free (address_uri);
14623 GNUNET_free (uri_without_port);
14624 return;
14625 }
14626
14628 "3 not global natted_address %u %s %s\n",
14629 queue->is_global_natted,
14630 uri,
14631 queue->address);
14632
14633 if (0 == strcmp (uri_without_port, address_uri))
14634 {
14636 GNUNET_free (address_uri);
14637 GNUNET_free (uri_without_port);
14638 return;
14639 }
14640
14642 "4 not global natted_address %u %s %s\n",
14643 queue->is_global_natted,
14644 uri,
14645 queue->address);
14646
14647 address_uri_without_port = get_address_without_port (queue->address);
14648 if ((NULL != address_uri_without_port) &&
14649 (0 == strcmp (uri_without_port, address_uri_without_port)))
14650 {
14651 queue->is_global_natted = GNUNET_NO;
14652 }
14653
14655 "not global natted_address %u %s %s %s %s %s %u\n",
14656 queue->is_global_natted,
14657 uri,
14658 queue->address,
14659 uri_without_port,
14660 address_uri_without_port,
14661 prefix,
14662 GNUNET_NO);
14664 GNUNET_free (address_uri);
14665 GNUNET_free (address_uri_without_port);
14666 GNUNET_free (uri_without_port);
14667}
14668
14669
14671{
14675 char *addr;
14676
14681};
14682
14683
14684static enum GNUNET_GenericReturnValue
14685contains_address (void *cls,
14686 const struct GNUNET_PeerIdentity *pid,
14687 void *value)
14688{
14689 struct TransportGlobalNattedAddressClosure *tgna_cls = cls;
14690 struct TransportGlobalNattedAddress *tgna = value;
14691 char *addr = (char *) &tgna[1];
14692
14693 /* NOTE: @a addr is NOT 0-terminated. */
14695 "Checking tgna %p with addr %.*s and length %u compare length %lu\n",
14696 tgna,
14697 (int) ntohl (tgna->address_length),
14698 addr,
14699 ntohl (tgna->address_length),
14700 strlen (tgna_cls->addr));
14701 if (strlen (tgna_cls->addr) == ntohl (tgna->address_length)
14702 && 0 == strncmp (addr, tgna_cls->addr, ntohl (tgna->address_length)))
14703 {
14704 tgna_cls->tgna = tgna;
14705 return GNUNET_NO;
14706 }
14707 return GNUNET_YES;
14708}
14709
14710
14711static void
14713{
14715 "Error in PEERSTORE monitoring for checking global natted\n");
14716}
14717
14718
14719static void
14721{
14723 "Done with initial PEERSTORE iteration during monitoring for checking global natted\n");
14724}
14725
14726
14727static void
14728check_for_global_natted (void *cls,
14729 const struct GNUNET_PEERSTORE_Record *record,
14730 const char *emsg)
14731{
14732 struct Queue *queue = cls;
14733 struct Neighbour *neighbour = queue->neighbour;
14735 const struct GNUNET_MessageHeader *hello;
14737 size_t address_len_without_port;
14738
14739 if (NULL != emsg)
14740 {
14742 "Got failure from PEERSTORE: %s\n",
14743 emsg);
14745 return;
14746 }
14747 if (NULL == record)
14748 {
14749 GNUNET_break (0);
14751 return;
14752 }
14753 /* @a hello was published by a remote peer and may be malformed. */
14754 hello = hello_from_record (record);
14755 if (NULL == hello)
14756 {
14758 return;
14759 }
14760 queue->is_global_natted = GNUNET_YES;
14761 parser = GNUNET_HELLO_parser_from_msg (hello, &record->peer);
14762 if (NULL == parser)
14763 {
14765 "HELLO cannot be parsed!\n");
14767 return;
14768 }
14770 "before not global natted %u\n",
14771 queue->is_global_natted);
14774 queue);
14776 "after not global natted %u\n",
14777 queue->is_global_natted);
14778 GNUNET_HELLO_parser_free (parser);
14779
14780 tgna_cls.addr = get_address_without_port (queue->address);
14781 if (NULL == tgna_cls.addr)
14782 {
14783 GNUNET_break (0);
14785 return;
14786 }
14787 address_len_without_port = strlen (tgna_cls.addr);
14788 /*{
14789 char buf[address_len_without_port + 1];
14790
14791 GNUNET_memcpy (&buf, addr, address_len_without_port);
14792 buf[address_len_without_port] = '\0';
14793 GNUNET_free (addr);
14794 GNUNET_memcpy (tgna_cls.addr, buf, address_len_without_port + 1);
14795 }*/
14796 tgna_cls.tgna = NULL;
14798 &neighbour->pid,
14800 &tgna_cls);
14801 if (NULL != tgna_cls.tgna)
14803 " tgna_cls.tgna tgna %p %lu %u %u\n",
14804 tgna_cls.tgna,
14805 neighbour->size_of_global_addresses,
14806 ntohl (tgna_cls.tgna->address_length),
14807 neighbour->number_of_addresses);
14808 if (NULL == tgna_cls.tgna && GNUNET_YES == queue->is_global_natted)
14809 {
14810 struct TransportGlobalNattedAddress *tgna;
14811
14812 tgna = GNUNET_malloc (sizeof (struct TransportGlobalNattedAddress)
14813 + address_len_without_port);
14814 tgna->address_length = htonl (address_len_without_port);
14815 GNUNET_memcpy (&tgna[1], tgna_cls.addr, address_len_without_port);
14817 &neighbour->pid,
14818 tgna,
14820 neighbour->number_of_addresses++;
14821 /* MUST match what is subtracted on removal (and what
14822 #add_global_addresses() actually copies), or the accounting drifts. */
14823 neighbour->size_of_global_addresses += address_len_without_port;
14825 "Created tgna %p with address %s and length %lu\n",
14826 tgna,
14827 tgna_cls.addr,
14828 address_len_without_port + 1);
14829 }
14830 else if (NULL != tgna_cls.tgna && GNUNET_NO == queue->is_global_natted)
14831 {
14833 &neighbour->pid,
14834 tgna_cls.tgna);
14835 GNUNET_assert (neighbour->size_of_global_addresses >= ntohl (tgna_cls.tgna->
14837 );
14838 neighbour->size_of_global_addresses -= ntohl (tgna_cls.tgna->address_length)
14839 ;
14840 GNUNET_assert (0 < neighbour->number_of_addresses);
14841 neighbour->number_of_addresses--;
14843 "removed tgna %p\n",
14844 tgna_cls.tgna);
14845 GNUNET_free (tgna_cls.tgna);
14846 }
14848 GNUNET_free (tgna_cls.addr);
14849}
14850
14851
14858static void
14859handle_add_queue_message (void *cls,
14860 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
14861{
14862 struct TransportClient *tc = cls;
14863 struct Queue *queue;
14864 struct Neighbour *neighbour;
14865 const char *addr;
14866 uint16_t addr_len;
14867
14868 if (ntohl (aqm->mtu) <= sizeof(struct TransportFragmentBoxMessage))
14869 {
14870 /* MTU so small as to be useless for transmissions,
14871 required for #fragment_message()! */
14872 GNUNET_break_op (0);
14874 return;
14875 }
14876 /* This may simply be a queue update. Match on the peer as well as the
14877 QID: the communicator's key for a queue is the pair, and
14878 #handle_send_msg() on its side looks both of them up. Matching on the
14879 QID alone let an ADD_QUEUE for a *different* peer be folded into an
14880 existing queue, leaving @e neighbour pointing at the old peer -- after
14881 which every SEND_MSG we put on it carries a receiver the communicator
14882 cannot match, and comes straight back as "queue no longer exists". */
14883 for (queue = tc->details.communicator.queue_head;
14884 NULL != queue;
14885 queue = queue->next_client)
14886 {
14887 if (queue->qid != ntohl (aqm->qid))
14888 continue;
14889 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &aqm->receiver))
14890 continue;
14891 break;
14892 }
14893
14894 if (NULL != queue)
14895 {
14896 neighbour = queue->neighbour;
14897 }
14898 else
14899 {
14900 struct GNUNET_TIME_Absolute validated_until = GNUNET_TIME_UNIT_ZERO_ABS;
14901
14902 neighbour = lookup_neighbour (&aqm->receiver);
14903 if (NULL == neighbour)
14904 {
14905 neighbour = GNUNET_new (struct Neighbour);
14907 GNUNET_YES);
14908 neighbour->pid = aqm->receiver;
14909 /* Give a fresh neighbour a full window to say something. */
14910 neighbour->last_inbound = GNUNET_TIME_absolute_get ();
14913 neighbours,
14914 &neighbour->pid,
14915 neighbour,
14917 neighbour->get =
14919 "transport",
14920 &neighbour->pid,
14923 neighbour);
14924 }
14925 addr_len = ntohs (aqm->header.size) - sizeof(*aqm);
14926 addr = (const char *) &aqm[1];
14928 "New queue %s to %s available with QID %u and q_len %" PRIu64
14929 " and mtu %u\n",
14930 addr,
14931 GNUNET_i2s (&aqm->receiver),
14932 ntohl (aqm->qid),
14933 GNUNET_ntohll (aqm->q_len),
14934 ntohl (aqm->mtu));
14935 queue = GNUNET_malloc (sizeof(struct Queue) + addr_len);
14936 queue->tc = tc;
14937 for (struct Queue *q = neighbour->queue_head; NULL != q; q = q->
14938 next_neighbour)
14939 validated_until = GNUNET_TIME_absolute_max (validated_until, q->
14940 validated_until);
14941 /* Inherit the validity of the sibling queues, but only while it is
14942 still in the future -- copying an already expired timestamp is
14943 pointless (and the condition used to be inverted). */
14944 if (0 != GNUNET_TIME_absolute_get_remaining (validated_until).rel_value_us)
14945 {
14947 "New queue with QID %u inherit validated until\n",
14948 ntohl (aqm->qid));
14949 queue->validated_until = validated_until;
14950 }
14951 queue->address = (const char *) &queue[1];
14952 queue->pd.aged_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
14953 queue->qid = ntohl (aqm->qid);
14954 queue->neighbour = neighbour;
14956 queue->unlimited_length = GNUNET_YES;
14957 queue->q_capacity = GNUNET_ntohll (aqm->q_len);
14958 memcpy (&queue[1], addr, addr_len);
14959 /* notify monitors about new queue */
14960 {
14961 struct MonitorEvent me = { .rtt = queue->pd.aged_rtt, .cs = queue->cs };
14962
14963 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
14964 }
14966 neighbour->queue_head,
14967 neighbour->queue_tail,
14968 queue);
14970 tc->details.communicator.queue_head,
14971 tc->details.communicator.queue_tail,
14972 queue);
14973
14974 }
14975 queue->mtu = ntohl (aqm->mtu);
14976 queue->nt = ntohl (aqm->nt);
14977 queue->cs = ntohl (aqm->cs);
14978 queue->idle = GNUNET_YES;
14979
14980 if (NULL == queue->mo)
14981 {
14982 /* Only for a NEW queue: on a queue update this used to start a second
14983 monitor and leak the first one. */
14984 struct sockaddr_in v4;
14985 char *addr_without = get_address_without_port (queue->address);
14986 if ((NULL != addr_without) &&
14987 (1 == inet_pton (AF_INET, addr_without, &v4.sin_addr)))
14988 {
14990 "start not global natted\n");
14992 GNUNET_YES,
14993 "peerstore",
14994 &neighbour->pid,
14996 &
14998 NULL,
14999 &
15001 NULL,
15003 queue);
15004 }
15005 GNUNET_free (addr_without);
15006 }
15007 /* check if valdiations are waiting for the queue */
15009 &aqm->receiver))
15012 &aqm->receiver,
15014 queue);
15015 /* Always (also) validate the address of the queue itself. A pending
15016 validation served above may well be for a *different* address string:
15017 #check_validation_request_pending() matches on the IP only, so a
15018 validation state waiting for the NAT address `PROTO-IP:0' is happily
15019 satisfied by a queue at `PROTO-IP:12345'. If we stopped here,
15020 #handle_validation_response() would later look for a queue at
15021 `PROTO-IP:0' -- which never exists -- and drop the successful
15022 validation on the floor without ever creating the virtual link. That
15023 is exactly what happens to the second of two peers behind the same
15024 NAT, as both of them advertise the very same `PROTO-IP:0'. */
15025 start_address_validation (&aqm->receiver, queue->address);
15026 /* look for traffic for this queue */
15027 // TODO Check whether this makes any sense at all.
15028 /*schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
15029 queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);*/
15030 /* might be our first queue, try launching DV learning */
15031 if (NULL == dvlearn_task)
15034}
15035
15036
15043static void
15045 const struct
15047{
15048 struct TransportClient *tc = cls;
15049 struct Queue *target_queue = NULL;
15050
15051 if (CT_COMMUNICATOR != tc->type)
15052 {
15053 /* Without this we walk `details.communicator.queue_head' for a client
15054 whose union holds something else entirely. */
15055 GNUNET_break (0);
15057 return;
15058 }
15060 "Received queue update message for %u with q_len %llu and mtu %u\n",
15061 ntohl (msg->qid),
15062 (unsigned long long) GNUNET_ntohll (msg->q_len),
15063 ntohl (msg->mtu));
15064 for (target_queue = tc->details.communicator.queue_head;
15065 NULL != target_queue;
15066 target_queue = target_queue->next_client)
15067 {
15068 if (ntohl (msg->qid) == target_queue->qid)
15069 break;
15070 }
15071 if (NULL == target_queue)
15072 {
15074 "Queue to update no longer exists! Discarding update.\n");
15076 return;
15077 }
15078
15079 target_queue->nt = ntohl (msg->nt);
15080 target_queue->mtu = ntohl (msg->mtu);
15081 target_queue->cs = ntohl (msg->cs);
15082 target_queue->priority = ntohl (msg->priority);
15083 /* The update message indicates how many messages
15084 * the queue should be able to handle.
15085 */
15087 target_queue->unlimited_length = GNUNET_YES;
15088 else
15089 target_queue->unlimited_length = GNUNET_NO;
15090 target_queue->q_capacity += GNUNET_ntohll (msg->q_len);
15091 if (0 < target_queue->q_capacity)
15093 target_queue,
15096}
15097
15098
15106static void
15107handle_queue_create_ok (void *cls,
15108 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
15109{
15110 struct TransportClient *tc = cls;
15111
15112 if (CT_COMMUNICATOR != tc->type)
15113 {
15114 GNUNET_break (0);
15116 return;
15117 }
15119 "# Suggestions succeeded at communicator",
15120 1,
15121 GNUNET_NO);
15123 "Request #%u for communicator to create queue succeeded\n",
15124 (unsigned int) ntohs (cqr->request_id));
15126}
15127
15128
15137static void
15139 void *cls,
15140 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
15141{
15142 struct TransportClient *tc = cls;
15143
15144 if (CT_COMMUNICATOR != tc->type)
15145 {
15146 GNUNET_break (0);
15148 return;
15149 }
15151 "Request #%u for communicator to create queue failed\n",
15152 (unsigned int) ntohl (cqr->request_id));
15154 "# Suggestions failed in queue creation at communicator",
15155 1,
15156 GNUNET_NO);
15158}
15159
15160
15168static void
15169handle_suggest_cancel (void *cls, const struct ExpressPreferenceMessage *msg)
15170{
15171 struct TransportClient *tc = cls;
15172 struct PeerRequest *pr;
15173
15174 if (CT_APPLICATION != tc->type)
15175 {
15176 GNUNET_break (0);
15178 return;
15179 }
15180 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
15181 &msg->peer);
15182 if (NULL == pr)
15183 {
15184 GNUNET_break (0);
15186 return;
15187 }
15188 (void) stop_peer_request (tc, &pr->pid, pr);
15190}
15191
15192
15193static void
15194hello_for_client_cb (void *cls,
15195 const struct GNUNET_PeerIdentity *pid,
15196 const char *uri)
15197{
15198 struct Queue *q;
15199 int pfx_len;
15200 const char *eou;
15201 char *address;
15202 (void) cls;
15203
15204 eou = strstr (uri,
15205 "://");
15206 if ((NULL == eou) || (eou == uri))
15207 {
15208 /* @a uri comes from a HELLO some remote peer published. */
15209 GNUNET_break_op (0);
15210 return;
15211 }
15212 pfx_len = eou - uri;
15213 eou += 3;
15215 "%.*s-%s",
15216 pfx_len,
15217 uri,
15218 eou);
15219
15221 "hello for client %s\n",
15222 address);
15223
15224 q = find_queue (pid, address);
15225 if (NULL == q)
15226 {
15228 }
15229 else
15232}
15233
15234
15242static void
15243handle_hello_for_client (void *cls,
15244 const struct GNUNET_PEERSTORE_Record *record,
15245 const char *emsg)
15246{
15247 const struct GNUNET_PeerIdentity *my_identity;
15248 struct PeerRequest *pr = cls;
15250 const struct GNUNET_MessageHeader *hello;
15251
15252 if (NULL != emsg)
15253 {
15255 "Got failure from PEERSTORE: %s\n",
15256 emsg);
15258 return;
15259 }
15260 if (NULL == record)
15261 {
15262 GNUNET_break (0);
15264 return;
15265 }
15267 if (NULL == my_identity)
15268 {
15270 "No identity given yet!\n");
15272 return;
15273 }
15274 hello = hello_from_record (record);
15275 if (NULL == hello)
15276 {
15277 /* MUST still ask for the next record: a bad one is not a reason to
15278 stall this monitor forever. */
15280 return;
15281 }
15282 if (0 == GNUNET_memcmp (&record->peer, my_identity))
15283 {
15285 return;
15286 }
15287 parser = GNUNET_HELLO_parser_from_msg (hello, &record->peer);
15288 if (NULL == parser)
15289 {
15291 "HELLO cannot be parsed!\n");
15293 return;
15294 }
15296 "HELLO for `%s' could be parsed, iterating addresses...!\n",
15300 NULL);
15301 GNUNET_HELLO_parser_free (parser);
15302 /* MUST ask for the next record, or this monitor stalls after one HELLO */
15304}
15305
15306
15307static void
15308hello_for_client_error_cb (void *cls)
15309{
15311 "Error in PEERSTORE monitoring\n");
15312}
15313
15314
15315static void
15316hello_for_client_sync_cb (void *cls)
15317{
15319 "Done with initial PEERSTORE iteration during monitoring\n");
15320}
15321
15322
15334static void
15336{
15337 if (NULL != pr->nc)
15339 /* Monitor only @e pid. With NULL every application request sees every
15340 HELLO in PEERSTORE, so a client asking for one peer made us suggest a
15341 connection to -- and start an address validation for -- every peer we
15342 have ever heard of, once per request. #try_to_bring_link_up() had the
15343 same bug and was already fixed the same way. */
15344 pr->nc =
15346 GNUNET_YES,
15347 "peerstore",
15348 &pr->pid,
15351 NULL,
15353 NULL,
15355 pr);
15356}
15357
15358
15368static void
15369suggest_retry_cb (void *cls)
15370{
15371 struct PeerRequest *pr = cls;
15372 struct VirtualLink *vl;
15373
15374 pr->retry_task = NULL;
15375 vl = lookup_virtual_link (&pr->pid);
15376 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
15377 {
15378 /* The client has what it asked for. Keep watching cheaply, and start
15379 over from the short interval when the link goes away again. */
15383 pr);
15384 return;
15385 }
15387 "Retrying to connect to %s, an application client wants it\n",
15388 GNUNET_i2s (&pr->pid));
15390 "# link setup retries for application clients",
15391 1,
15392 GNUNET_NO);
15393 /* Addresses we already track, queues we still have, and a fresh look in
15394 PEERSTORE. */
15396 /* ... plus a replay of what PEERSTORE has for this peer, which is the
15397 only way back once the validation state expired and the queues are
15398 gone. */
15404 pr);
15405}
15406
15407
15415static void
15416handle_suggest (void *cls, const struct ExpressPreferenceMessage *msg)
15417{
15418 struct TransportClient *tc = cls;
15419 const struct GNUNET_PeerIdentity *my_identity;
15420 struct PeerRequest *pr;
15421
15422 if (CT_NONE == tc->type)
15423 {
15424 tc->type = CT_APPLICATION;
15425 tc->details.application.requests =
15427 }
15428 if (CT_APPLICATION != tc->type)
15429 {
15430 GNUNET_break (0);
15432 return;
15433 }
15435 if (NULL == my_identity)
15436 {
15438 "Still waiting for own identity!\n");
15440 return;
15441 }
15443 "Client suggested we talk to %s with preference %d at rate %u\n",
15444 GNUNET_i2s (&msg->peer),
15445 (int) ntohl (msg->pk),
15446 (int) ntohl (msg->bw.value__));
15447 if (0 == GNUNET_memcmp (my_identity, &msg->peer))
15448 {
15450 "Client suggested connection to ourselves, ignoring...\n");
15452 return;
15453 }
15454 pr = GNUNET_new (struct PeerRequest);
15455 pr->tc = tc;
15456 pr->pid = msg->peer;
15457 pr->bw = msg->bw;
15458 pr->pk = ntohl (msg->pk);
15460 tc->details.application.requests,
15461 &pr->pid,
15462 pr,
15464 {
15465 GNUNET_break (0);
15466 GNUNET_free (pr);
15468 return;
15469 }
15471 /* The monitor alone only ever fires again if the HELLO *changes*. Keep
15472 asking for the link ourselves for as long as the client wants it. */
15473 pr->retry_backoff = SUGGEST_RETRY_MIN;
15474 pr->retry_task = GNUNET_SCHEDULER_add_delayed (pr->retry_backoff,
15476 pr);
15478}
15479
15480
15489static int
15491 const struct RequestHelloValidationMessage *m)
15492{
15493 (void) cls;
15495 return GNUNET_OK;
15496}
15497
15498
15506static void
15508 const struct RequestHelloValidationMessage *m)
15509{
15510 struct TransportClient *tc = cls;
15511 struct Queue *q;
15512
15513 q = find_queue (&m->peer, (const char *) &m[1]);
15514 if (NULL == q)
15515 {
15516 suggest_to_connect (&m->peer, (const char *) &m[1]);
15517 }
15518 else
15519 start_address_validation (&m->peer, (const char *) &m[1]);
15521}
15522
15523
15532static int
15533free_neighbour_cb (void *cls,
15534 const struct GNUNET_PeerIdentity *pid,
15535 void *value)
15536{
15537 struct Neighbour *neighbour = value;
15538
15539 (void) cls;
15540 (void) pid;
15541 GNUNET_break (0); // should this ever happen?
15542 free_neighbour (neighbour, GNUNET_YES);
15543
15544 return GNUNET_OK;
15545}
15546
15547
15562static int
15563free_virtual_link_cb (void *cls,
15564 const struct GNUNET_PeerIdentity *pid,
15565 void *value)
15566{
15567 struct VirtualLink *vl = value;
15568
15569 (void) cls;
15570 (void) pid;
15571 free_virtual_link (vl);
15572
15573 return GNUNET_OK;
15574}
15575
15576
15585static int
15586free_dv_routes_cb (void *cls,
15587 const struct GNUNET_PeerIdentity *pid,
15588 void *value)
15589{
15590 struct DistanceVector *dv = value;
15591
15592 (void) cls;
15593 (void) pid;
15594 free_dv_route (dv);
15595
15596 return GNUNET_OK;
15597}
15598
15599
15608static int
15609free_validation_state_cb (void *cls,
15610 const struct GNUNET_PeerIdentity *pid,
15611 void *value)
15612{
15613 struct ValidationState *vs = value;
15614
15615 (void) cls;
15616 (void) pid;
15618 return GNUNET_OK;
15619}
15620
15621
15630static int
15631free_pending_ack_cb (void *cls, const struct GNUNET_Uuid *key, void *value)
15632{
15633 struct PendingAcknowledgement *pa = value;
15634
15635 (void) cls;
15636 (void) key;
15638 return GNUNET_OK;
15639}
15640
15641
15650static int
15651free_ack_cummulator_cb (void *cls,
15652 const struct GNUNET_PeerIdentity *pid,
15653 void *value)
15654{
15655 struct AcknowledgementCummulator *ac = value;
15656
15657 (void) cls;
15658 (void) pid;
15659 /* @e task is armed for the whole life of @a ac -- but
15660 #transmit_cummulative_ack_cb() clears it before re-arming, and it
15661 routes a message while it is clear. #GNUNET_SCHEDULER_cancel()
15662 dereferences its argument unconditionally. */
15663 if (NULL != ac->task)
15664 {
15666 ac->task = NULL;
15667 }
15668 GNUNET_free (ac);
15669 return GNUNET_OK;
15670}
15671
15672
15679static void
15680do_shutdown (void *cls)
15681{
15682 static int shutdown_done;
15683 struct LearnLaunchEntry *lle;
15684 struct PilsRequest *pr;
15685 (void) cls;
15686
15688 "shutdown logic\n");
15689 if (GNUNET_YES == shutdown_done)
15690 return; /* reachable both from #shutdown_task() and #client_disconnect_cb() */
15691 shutdown_done = GNUNET_YES;
15692 if (NULL != client_grace_task)
15693 {
15695 client_grace_task = NULL;
15696 }
15697 if (NULL != nh)
15698 {
15700 nh = NULL;
15701 }
15703 &free_neighbour_cb, NULL);
15704 /* Freeing a neighbour takes its virtual link with it, so whatever is
15705 left here is ownerless: a link we created from an inbound FLOW_CONTROL
15706 message that never got confirmed, kept alive only by its @e
15707 unconfirmed_timeout_task. #GNUNET_SCHEDULER_shutdown() does not run
15708 that task, so leaving the link in place left the task armed against a
15709 map we destroy further down -- it fired afterwards and
15710 #free_virtual_link() called GNUNET_CONTAINER_multipeermap_remove() on
15711 NULL. Drop them here, while every structure they touch is still
15712 alive. */
15715 NULL);
15716 if (NULL != validation_task)
15717 {
15719 validation_task = NULL;
15720 }
15721 if (NULL != dvlearn_task)
15722 {
15724 dvlearn_task = NULL;
15725 }
15726 if (NULL != burst_task)
15727 {
15729 burst_task = NULL;
15730 }
15731 if (NULL != burst_timeout_task)
15732 {
15734 burst_timeout_task = NULL;
15735 }
15738 dvlearn_map = NULL;
15741 dv_routes = NULL;
15742 if (NULL != GST_stats)
15743 {
15745 GST_stats = NULL;
15746 }
15747 if (NULL != GST_my_hello)
15748 {
15750 GST_my_hello = NULL;
15751 }
15754 NULL);
15756 ack_cummulators = NULL;
15759 NULL);
15761 pending_acks = NULL;
15764 neighbours = NULL;
15767 links = NULL;
15770 NULL);
15772 backtalkers = NULL;
15775 NULL);
15777 validation_map = NULL;
15779 validation_heap = NULL;
15781 revalidation_map = NULL;
15782 while (NULL != ir_head)
15784 GNUNET_assert (0 == ir_total);
15785 while (NULL != (lle = lle_head))
15786 {
15788 GNUNET_free (lle);
15789 }
15790 while (NULL != (pr = pils_requests_head))
15791 {
15794 pr);
15795 if (NULL != pr->op)
15796 GNUNET_PILS_cancel (pr->op);
15797 GNUNET_free (pr);
15798 }
15799 if (NULL != pils_feed_task)
15800 {
15802 pils_feed_task = NULL;
15803 }
15804 if (NULL != pils)
15805 {
15807 pils = NULL;
15808 }
15809 if (NULL != peerstore)
15810 {
15812 "Disconnecting from PEERSTORE service\n");
15814 peerstore = NULL;
15815 }
15817}
15818
15819
15820static const char*
15822{
15823 switch (type)
15824 {
15825 case CT_CORE:
15826 return "CORE";
15827 case CT_MONITOR:
15828 return "MONITOR";
15829 case CT_COMMUNICATOR:
15830 return "COMMUNICATOR";
15831 case CT_APPLICATION:
15832 return "APPLICATION";
15833 default:
15834 return "UNKNOWN";
15835 }
15836}
15837
15838
15846static void
15847drop_remaining_clients (void *cls)
15848{
15849 client_grace_task = NULL;
15850 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
15851 {
15853 "Client did not disconnect within the shutdown grace period, "
15854 "dropping it: %s\n",
15855 get_client_type_name (tc->type));
15856 }
15857 /* We use #GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN, so the service will NOT
15858 drop clients for us. Without this we would wait forever for them to
15859 leave on their own and never reach #do_shutdown(). */
15861 /* Dropping the clients ran #client_disconnect_cb() for each of them, so
15862 #do_shutdown() has normally run by now; it is idempotent, and this
15863 covers the case where there was nothing left to drop. */
15864 do_shutdown (cls);
15865}
15866
15867
15868static void
15869shutdown_task (void *cls)
15870{
15872
15874 "Shutdown task executed\n");
15875 if (NULL != clients_head)
15876 {
15877 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
15878 {
15880 "Waiting for client to disconnect: %s\n",
15881 get_client_type_name (tc->type));
15882 }
15883 /* Give them a chance to shut down cleanly; #client_disconnect_cb() calls
15884 #do_shutdown() once the last one is gone, and #do_shutdown() cancels
15885 this task. */
15889 cls);
15890 return;
15891 }
15892 do_shutdown (cls);
15893}
15894
15895
15897{
15899};
15900
15901static void
15902update_hello_from_pid_change_cb (void *cls, int success)
15903{
15904 struct UpdateHelloFromPidCtx *pc = cls;
15905
15906 /* NOTE: @a success is GNUNET_OK even when #hello_add_iter() decided not to
15907 store anything because PEERSTORE already holds a HELLO that expires
15908 later; the API reports the desired state, not whether it wrote. So this
15909 says "we have a current HELLO on record", not "we just wrote one". */
15910 if (GNUNET_OK != success)
15912 "Failed to store our new hello with peerstore\n");
15913 else
15915 "Our hello is current in peerstore\n");
15916 GNUNET_free (pc);
15917}
15918
15919
15920void
15921print_address_list (void *cls,
15922 const struct GNUNET_PeerIdentity *pid,
15923 const char *uri)
15924{
15926 "%s\n", uri);
15927}
15928
15929
15939static void
15940pils_pid_change_cb (void *cls,
15941 const struct GNUNET_HELLO_Parser *parser,
15942 const struct GNUNET_HashCode *hash)
15943{
15944 const struct GNUNET_PeerIdentity *my_identity;
15945 struct GNUNET_MQ_Envelope *env;
15946 const struct GNUNET_MessageHeader *msg;
15947 struct UpdateHelloFromPidCtx *sc;
15948 struct GNUNET_HELLO_Builder *nbuilder;
15949 struct GNUNET_PeerIdentity npid;
15950
15953
15954 if (NULL == GST_my_hello)
15957 "My current identity is `%s'\n",
15969 nbuilder = GNUNET_HELLO_builder_from_parser (parser,
15970 &npid);
15971 if (GNUNET_NO ==
15973 {
15975 "New PID from PILS is derived from address list inconsistent with ours. Ignoring...\n");
15977 "Proposed address list:\n");
15980 "Current address list:\n");
15982 GNUNET_HELLO_builder_free (nbuilder);
15983 return;
15984 }
15986 GST_my_hello = nbuilder;
15988 "My new identity is `%s'\n",
15994 msg,
15996 sc);
15997 GNUNET_free (env);
15998}
15999
16000
16008static void
16009run (void *cls,
16010 const struct GNUNET_CONFIGURATION_Handle *c,
16012{
16013 (void) cls;
16014 /* setup globals */
16018 GST_cfg = c;
16026 GNUNET_YES);
16031 // TODO check for all uses of GST_my_hello that it is not used uninitialized
16033 "transport",
16034 "USE_BURST_NAT");
16035 if (GNUNET_SYSERR == use_burst)
16037 "Could not configure burst nat use. Default to no.\n");
16043 "transport",
16044 0,
16045 0,
16046 NULL,
16047 0,
16048 NULL,
16049 NULL,
16050 NULL);
16051 if (NULL == peerstore)
16052 {
16053 GNUNET_break (0);
16055 return;
16056 }
16059 NULL); // FIXME we need to wait for
16060 // our first peer id before
16061 // we can start the service
16062 // completely - PILS in turn
16063 // waits for the first
16064 // addresses from the
16065 // communicators in order to
16066 // be able to generate a
16067 // peer id
16068 if (NULL == pils)
16069 {
16070 GNUNET_break (0);
16072 return;
16073 }
16074 /* Decapsulate DV box ephemeral keys ourselves. #handle_dv_box() needs
16075 the key material while it still has the box, which points into the
16076 communicator's inbound message and is gone the moment the handler
16077 returns -- so the asynchronous answer arrived to a dangling @a dvb. */
16078 if (GNUNET_OK !=
16081 _ ("Failed to load our private key, "
16082 "cannot open DV boxes addressed to us\n"));
16083}
16084
16085
16091 "transport",
16093 &run,
16096 NULL,
16097 /* communication with applications */
16098 GNUNET_MQ_hd_fixed_size (suggest,
16101 NULL),
16102 GNUNET_MQ_hd_fixed_size (suggest_cancel,
16105 NULL),
16106 GNUNET_MQ_hd_var_size (request_hello_validation,
16109 NULL),
16110 /* communication with core */
16111 GNUNET_MQ_hd_fixed_size (client_start,
16113 struct StartMessage,
16114 NULL),
16115 GNUNET_MQ_hd_var_size (client_send,
16117 struct OutboundMessage,
16118 NULL),
16119 GNUNET_MQ_hd_fixed_size (client_recv_ok,
16121 struct RecvOkMessage,
16122 NULL),
16123 /* communication with communicators */
16124 GNUNET_MQ_hd_var_size (communicator_available,
16127 NULL),
16128 GNUNET_MQ_hd_var_size (communicator_backchannel,
16131 NULL),
16132 GNUNET_MQ_hd_var_size (add_address,
16135 NULL),
16136 GNUNET_MQ_hd_fixed_size (del_address,
16139 NULL),
16140 GNUNET_MQ_hd_var_size (incoming_msg,
16143 NULL),
16144 GNUNET_MQ_hd_fixed_size (queue_create_ok,
16147 NULL),
16148 GNUNET_MQ_hd_fixed_size (queue_create_fail,
16151 NULL),
16152 GNUNET_MQ_hd_var_size (add_queue_message,
16155 NULL),
16156 GNUNET_MQ_hd_fixed_size (update_queue_message,
16159 NULL),
16160 GNUNET_MQ_hd_fixed_size (del_queue_message,
16163 NULL),
16164 GNUNET_MQ_hd_fixed_size (send_message_ack,
16167 NULL),
16168 GNUNET_MQ_hd_fixed_size (burst_finished,
16171 NULL),
16172 /* communication with monitors */
16173 GNUNET_MQ_hd_fixed_size (monitor_start,
16176 NULL),
16177 GNUNET_MQ_hd_fixed_size (link_list_request,
16180 NULL),
16182
16183
16184/* 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...
#define MAX_DV_PICK_TRIES
How often pick_random_dv_hops() may redraw before settling for the paths it has.
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 void speed_up_challenge(struct ValidationState *vs)
Speed the next challenge for vs up because we heard something about that address again – but never fa...
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_PICK_TRIES

#define MAX_DV_PICK_TRIES   1000

How often pick_random_dv_hops() may redraw before settling for the paths it has.

Weighted rejection sampling converges in a handful of draws; past this it is a set it cannot sample distinctly.

Definition at line 225 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 231 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 236 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 244 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 252 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 259 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 265 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 284 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 292 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 299 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 306 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 313 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 319 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 325 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 334 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 340 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 346 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 354 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 361 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 370 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 378 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 385 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 391 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 396 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 402 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 421 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 452 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 461 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 470 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 478 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 486 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 493 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 498 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 505 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 514 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 5871 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 1220 of file gnunet-service-transport.c.

1221{
1225 CT_NONE = 0,
1226
1230 CT_CORE = 1,
1231
1235 CT_MONITOR = 2,
1236
1240 CT_COMMUNICATOR = 3,
1241
1245 CT_APPLICATION = 4
1246};

◆ 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 1253 of file gnunet-service-transport.c.

1254{
1258 RMO_NONE = 0,
1259
1263 RMO_DV_ALLOWED = 1,
1264
1269
1274
1280 RMO_REDUNDANT = 4
1281};

◆ 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 2440 of file gnunet-service-transport.c.

2441{
2445 PMT_CORE = 0,
2446
2450 PMT_FRAGMENT_BOX = 1,
2451
2456
2460 PMT_DV_BOX = 3
2461};

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 3336 of file gnunet-service-transport.c.

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

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 3448 of file gnunet-service-transport.c.

3449{
3450 struct GNUNET_TIME_Absolute now;
3451
3452 now = GNUNET_TIME_absolute_get ();
3453 return now.abs_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us / 15;
3454}

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 3463 of file gnunet-service-transport.c.

3464{
3466 GNUNET_assert (ir_total > 0);
3467 ir_total--;
3468 if (NULL != ir->nc)
3470 ir->nc = NULL;
3471 GNUNET_free (ir);
3472}

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 3481 of file gnunet-service-transport.c.

3482{
3483 struct Queue *q = pa->queue;
3484 struct PendingMessage *pm = pa->pm;
3485 struct DistanceVectorHop *dvh = pa->dvh;
3486
3488 "free_pending_acknowledgement\n");
3489 if (NULL != q)
3490 {
3491 GNUNET_CONTAINER_MDLL_remove (queue, q->pa_head, q->pa_tail, pa);
3492 pa->queue = NULL;
3493 }
3494 if (NULL != pm)
3495 {
3497 "remove pa from message\n");
3499 "remove pa from message %" PRIu64 "\n",
3500 pm->logging_uuid);
3502 "remove pa from message %u\n",
3503 pm->pmt);
3505 "remove pa from message %s\n",
3507 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
3508 pa->pm = NULL;
3509 }
3510 if (NULL != dvh)
3511 {
3512 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
3513 pa->dvh = NULL;
3514 }
3517 &pa->ack_uuid.value,
3518 pa));
3519 GNUNET_free (pa);
3520}

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 3532 of file gnunet-service-transport.c.

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

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 3571 of file gnunet-service-transport.c.

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

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 3649 of file gnunet-service-transport.c.

3650{
3651 struct VirtualLink *vl = rc->virtual_link;
3652
3656 rc->msg_uuid.uuid,
3657 rc));
3658 GNUNET_free (rc);
3659}

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 3668 of file gnunet-service-transport.c.

3669{
3670 struct VirtualLink *vl = cls;
3671 struct ReassemblyContext *rc;
3672
3673 vl->reassembly_timeout_task = NULL;
3674 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (vl->reassembly_heap)))
3675 {
3677 .rel_value_us)
3678 {
3680 continue;
3681 }
3686 vl);
3687 return;
3688 }
3689}

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 3701 of file gnunet-service-transport.c.

3702{
3703 struct ReassemblyContext *rc = value;
3704
3705 (void) cls;
3706 (void) key;
3708 return GNUNET_OK;
3709}

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 5356 of file gnunet-service-transport.c.

5359{
5360 send_cmc_ack (cmc);
5361 resume_cmc_client (cmc);
5362 if (GNUNET_YES == free_cmc)
5363 {
5364 GNUNET_free (cmc);
5365 }
5366}

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 5370 of file gnunet-service-transport.c.

5372{
5374 GNUNET_assert (0 < vl->cmc_count);
5375 vl->cmc_count--;
5377}

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 11860 of file gnunet-service-transport.c.

11861{
11862 struct VirtualLink *vl = sb_cls->vl;
11863
11864 if (burst_task_cls == sb_cls)
11865 {
11866 if (NULL != burst_task)
11867 {
11869 burst_task = NULL;
11870 }
11871 burst_task_cls = NULL;
11872 }
11873 if ((NULL != vl) && (vl->sb_cls == sb_cls))
11874 vl->sb_cls = NULL;
11876}

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 3763 of file gnunet-service-transport.c.

3765{
3766 struct GNUNET_MQ_Envelope *env;
3767 struct SendOkMessage *so_msg;
3768
3769 if (NULL == tc)
3770 return;
3772 so_msg->peer = *pid;
3773 GNUNET_MQ_send (tc->mq, env);
3774}

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 3790 of file gnunet-service-transport.c.

3791{
3792 if ((NULL == pm->client) || (GNUNET_YES == pm->client_credited))
3793 return;
3795 send_ok_to_client (pm->client, &pm->vl->target);
3796}

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 3805 of file gnunet-service-transport.c.

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

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 3902 of file gnunet-service-transport.c.

3903{
3904 if (NULL != vs->revalidation_task)
3905 {
3906 GNUNET_SCHEDULER_cancel (vs->revalidation_task);
3907 vs->revalidation_task = NULL;
3908 }
3909 /*memcpy (&hkey,
3910 &hc,
3911 sizeof (hkey));*/
3913 "Remove key %s for address %s map size %u contains %u during freeing state\n",
3914 GNUNET_h2s (&vs->hc),
3915 vs->address,
3918 &vs->hc));
3921 GNUNET_YES ==
3924 vs->hn = NULL;
3925 if (NULL != vs->sc)
3926 {
3928 "store cancel\n");
3930 vs->sc = NULL;
3931 }
3932 GNUNET_free (vs->address);
3933 GNUNET_free (vs);
3934}

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 3944 of file gnunet-service-transport.c.

3945{
3947}

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 3957 of file gnunet-service-transport.c.

3958{
3960}

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 4006 of file gnunet-service-transport.c.

4007{
4008 struct Neighbour *n = dvh->next_hop;
4009 struct DistanceVector *dv = dvh->dv;
4010 struct PendingAcknowledgement *pa;
4011
4012 while (NULL != (pa = dvh->pa_head))
4013 {
4015 pa->dvh = NULL;
4016 }
4017 GNUNET_CONTAINER_MDLL_remove (neighbour, n->dv_head, n->dv_tail, dvh);
4019 GNUNET_free (dvh);
4020}

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 4526 of file gnunet-service-transport.c.

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

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 4039 of file gnunet-service-transport.c.

4040{
4042 "Informing CORE clients about disconnect from %s\n",
4043 GNUNET_i2s (pid));
4044 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
4045 {
4046 struct GNUNET_MQ_Envelope *env;
4047 struct DisconnectInfoMessage *dim;
4048
4049 if (CT_CORE != tc->type)
4050 continue;
4052 dim->peer = *pid;
4053 GNUNET_MQ_send (tc->mq, env);
4054 }
4055}

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 10951 of file gnunet-service-transport.c.

10952{
10953 struct Neighbour *n;
10954 struct IncomingRequest *ir;
10955
10956 if (GNUNET_YES == in_shutdown)
10957 return;
10958 /* (1) Addresses we already track. These outlive the queues, which is the
10959 point: once a link is down the queue that carried it is usually gone,
10960 so there is no address string left for #start_address_validation(). */
10962 pid,
10964 NULL);
10965 /* (2) Queues we still have; may cover an address with no validation state
10966 yet. After (1), because it may insert into #validation_map. */
10967 n = lookup_neighbour (pid);
10968 if (NULL != n)
10969 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
10970 start_address_validation (pid, q->address);
10971 /* (3) Failing that, look for an address in PEERSTORE. */
10972 for (ir = ir_head; NULL != ir; ir = ir->next)
10973 {
10974 if (0 == GNUNET_memcmp (&ir->pid, pid))
10975 return; /* we are already trying */
10976 }
10977 ir = GNUNET_new (struct IncomingRequest);
10978 ir->pid = *pid;
10980 /* Monitor only @a pid: with NULL every request sees every HELLO in
10981 PEERSTORE, so each of the up to #MAX_INCOMING_REQUEST requests started
10982 a connection attempt and an address validation for peers it was not
10983 created for. */
10985 GNUNET_YES,
10986 "peerstore",
10987 &ir->pid,
10990 NULL,
10992 NULL,
10994 ir);
10995 ir_total++;
10996 /* Bound attempts we do in parallel here, might otherwise get excessive.
10997 Drop the OLDEST request: #ir_head is the one we just inserted, so
10998 freeing that would immediately undo the work above. */
11001}

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 4085 of file gnunet-service-transport.c.

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

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 4109 of file gnunet-service-transport.c.

4110{
4111 struct DistanceVectorHop *dvh;
4112 struct VirtualLink *vl;
4113
4114 while (NULL != (dvh = dv->dv_head))
4116
4118 GNUNET_YES ==
4120 if (NULL != (vl = dv->vl))
4121 {
4122 GNUNET_assert (dv == vl->dv);
4123 vl->dv = NULL;
4124 if (NULL == vl->n)
4125 {
4127 }
4128 else
4129 {
4130 /* @e visibility_task is NULL while #check_link_down() itself runs, and
4131 #GNUNET_SCHEDULER_cancel() dereferences its argument. */
4132 if (NULL != vl->visibility_task)
4135 }
4136 dv->vl = NULL;
4137 }
4138
4139 if (NULL != dv->timeout_task)
4140 {
4142 dv->timeout_task = NULL;
4143 }
4144 GNUNET_free (dv->km);
4145 GNUNET_free (dv);
4146}

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 4163 of file gnunet-service-transport.c.

4168{
4169 struct GNUNET_MQ_Envelope *env;
4171 size_t addr_len = strlen (address) + 1;
4172
4174 addr_len,
4176 md->nt = htonl ((uint32_t) nt);
4177 md->peer = *peer;
4178 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
4179 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
4180 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
4181 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
4182 md->cs = htonl ((uint32_t) me->cs);
4183 md->num_msg_pending = htonl (me->num_msg_pending);
4184 md->num_bytes_pending = htonl (me->num_bytes_pending);
4185 memcpy (&md[1], address, addr_len);
4186 GNUNET_MQ_send (tc->mq, env);
4187}

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 4200 of file gnunet-service-transport.c.

4204{
4205 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
4206 {
4207 if (CT_MONITOR != tc->type)
4208 continue;
4209 if (tc->details.monitor.one_shot)
4210 continue;
4211 if ((GNUNET_NO == GNUNET_is_zero (&tc->details.monitor.peer)) &&
4212 (0 != GNUNET_memcmp (&tc->details.monitor.peer, peer)))
4213 continue;
4214 notify_monitor (tc, peer, address, nt, me);
4215 }
4216}

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 4229 of file gnunet-service-transport.c.

4232{
4233 struct TransportClient *tc;
4234
4235 (void) cls;
4236 tc = GNUNET_new (struct TransportClient);
4237 tc->client = client;
4238 tc->mq = mq;
4241 "Client %p of type %u connected\n",
4242 tc,
4243 tc->type);
4244 return tc;
4245}

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 4249 of file gnunet-service-transport.c.

4252{
4253 struct TransportGlobalNattedAddress *tgna = value;
4254 (void) cls;
4255
4256 GNUNET_free (tgna);
4257
4258 return GNUNET_OK;
4259}

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 4269 of file gnunet-service-transport.c.

4271{
4272 struct DistanceVectorHop *dvh;
4273 struct VirtualLink *vl;
4274
4275 GNUNET_assert (NULL == neighbour->queue_head);
4278 &neighbour->pid,
4279 neighbour));
4281 "Freeing neighbour\n");
4284 NULL);
4286 while (NULL != (dvh = neighbour->dv_head))
4287 {
4288 struct DistanceVector *dv = dvh->dv;
4289
4291 if (NULL == dv->dv_head)
4292 free_dv_route (dv);
4293 }
4294 if (NULL != neighbour->get)
4295 {
4297 neighbour->get = NULL;
4298 }
4299 if (NULL != neighbour->sc)
4300 {
4302 "store cancel\n");
4303 GNUNET_PEERSTORE_store_cancel (neighbour->sc);
4304 neighbour->sc = NULL;
4305 }
4306 if (NULL != (vl = neighbour->vl))
4307 {
4308 GNUNET_assert (neighbour == vl->n);
4309 vl->n = NULL;
4310 if ((GNUNET_YES == drop_link) || (NULL == vl->dv))
4311 {
4313 }
4314 else
4315 {
4316 /* See #free_dv_route(): may be NULL under #check_link_down(). */
4317 if (NULL != vl->visibility_task)
4320 }
4321 neighbour->vl = NULL;
4322 }
4323 GNUNET_free (neighbour);
4324}

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 4334 of file gnunet-service-transport.c.

4336{
4337 struct GNUNET_MQ_Envelope *env;
4338 struct ConnectInfoMessage *cim;
4339
4340 GNUNET_assert (CT_CORE == tc->type);
4342 cim->id = *pid;
4343 GNUNET_MQ_send (tc->mq, env);
4344}

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 4353 of file gnunet-service-transport.c.

4354{
4356 "Informing CORE clients about connection to %s\n",
4357 GNUNET_i2s (pid));
4358 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
4359 {
4360 if (CT_CORE != tc->type)
4361 continue;
4363 }
4364}

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 13113 of file gnunet-service-transport.c.

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

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 4387 of file gnunet-service-transport.c.

4388{
4389 for (struct Queue *s = queue_head; NULL != s;
4390 s = s->next_neighbour)
4391 {
4392 if (s == queue)
4393 continue;
4394 if (s->tc->details.communicator.address_prefix !=
4395 queue->tc->details.communicator.address_prefix)
4396 {
4398 "queue address %s qid %u compare with queue: address %s qid %u\n",
4399 queue->address,
4400 queue->qid,
4401 s->address,
4402 s->qid);
4403 if ((s->priority > queue->priority) && (0 < s->q_capacity) &&
4404 (QUEUE_LENGTH_LIMIT > s->queue_length) )
4405 return GNUNET_YES;
4407 "Lower prio\n");
4408 }
4409 }
4410 return GNUNET_NO;
4411}

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 5627 of file gnunet-service-transport.c.

5628{
5629 if (NULL != tc->details.communicator.free_queue_entry_task)
5630 return;
5631 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
5632 queue = queue->next_client)
5633 {
5634 if (NULL == queue->queue_head)
5635 continue;
5636 tc->details.communicator.free_queue_entry_task =
5639 tc);
5640 return;
5641 }
5642}

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 4432 of file gnunet-service-transport.c.

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

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 10683 of file gnunet-service-transport.c.

10685{
10686 struct GNUNET_TIME_Absolute now;
10687 struct ValidationState *vs;
10688 struct CheckKnownAddressContext ckac = { .address = address, .vs = NULL };
10689
10691 pid,
10693 &ckac);
10695 if (NULL != (vs = ckac.vs))
10696 {
10697 const struct VirtualLink *vl = lookup_virtual_link (pid);
10698
10699 /* Speed up retrying the validation if 'vs' is not currently valid, or if
10700 * we have no confirmed virtual link to @a pid. In the latter case the
10701 * address may still be well inside its validity window -- but the link is
10702 * down, and #handle_validation_response() is the only thing that can
10703 * rebuild it and tell CORE about the peer again. Without this we would
10704 * wait for @e revalidation_task, which does not fire until
10705 * #ADDRESS_VALIDATION_LIFETIME is nearly over. */
10706 if ((vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us) ||
10707 (NULL == vl) ||
10708 (GNUNET_NO == vl->confirmed))
10709 {
10710 /* reduce backoff as we got a fresh advertisement */
10711 speed_up_challenge (vs);
10712 /* A successful validation parks @e first_challenge_use just before
10713 @e validated_until, so that the *next* challenge is not used before
10714 the current validation is about to expire. #validation_start_cb()
10715 refuses to run while that time is still in the future, so pulling
10716 @e next_challenge in without this would only make it reschedule
10717 itself four hours out. The challenge has not been used yet, so
10718 moving the start of its window to now stays truthful -- it is what
10719 the fresh-@a vs path below does as well. */
10720 if (GNUNET_TIME_absolute_cmp (vs->first_challenge_use, >, now))
10721 vs->first_challenge_use = now;
10724 vs->challenge_backoff));
10725 }
10726 return;
10727 }
10728 vs = GNUNET_new (struct ValidationState);
10729 vs->pid = *pid;
10730 vs->valid_until =
10732 vs->first_challenge_use = now;
10733 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
10734 GNUNET_CRYPTO_random_block (&vs->challenge,
10735 sizeof(vs->challenge));
10736 vs->address = GNUNET_strdup (address);
10737 {
10738 /* The peer identity MUST be part of @e hc: two peers behind the same NAT
10739 advertise the very same address string (`PROTO-IP:0'), and with an
10740 address-only key the second one's #revalidation_map entry would be
10741 rejected as a duplicate of the first one's. */
10742 struct GNUNET_HashContext *hsh;
10743
10745 GNUNET_CRYPTO_hash_context_read (hsh, vs->address, strlen (vs->address));
10746 GNUNET_CRYPTO_hash_context_read (hsh, &vs->pid, sizeof(vs->pid));
10747 GNUNET_CRYPTO_hash_context_finish (hsh, &vs->hc);
10748 }
10750 "Starting address validation `%s' of peer %s using challenge %s\n",
10751 address,
10752 GNUNET_i2s (pid),
10753 GNUNET_sh2s (&vs->challenge.value));
10757 &vs->pid,
10758 vs,
10761}

References GNUNET_TIME_Absolute::abs_value_us, address, CheckKnownAddressContext::address, ADDRESS_VALIDATION_LIFETIME, check_known_address(), VirtualLink::confirmed, 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_to_absolute(), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, GST_cfg, lookup_virtual_link(), ValidationState::pid, speed_up_challenge(), 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 4623 of file gnunet-service-transport.c.

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

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 6777 of file gnunet-service-transport.c.

6778{
6779 struct PilsAddressSignContext *pc = ale->pc;
6780
6781 if (NULL == pc)
6782 return;
6783 ale->pc = NULL;
6784 /* Each stage of the chain passes @a pc as its closure, so every handle
6785 that could still deliver one has to go before @a pc is released. */
6786 if (NULL != ale->sc)
6787 {
6789 ale->sc = NULL;
6790 }
6791 if (NULL != ale->shc)
6792 {
6794 ale->shc = NULL;
6795 }
6796 if (NULL != pc->req)
6797 {
6798 if (NULL != pc->req->op)
6799 GNUNET_PILS_cancel (pc->req->op);
6802 pc->req);
6803 GNUNET_free (pc->req);
6804 pc->req = NULL;
6805 }
6806 GNUNET_free (pc);
6807}

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 4730 of file gnunet-service-transport.c.

4731{
4732 struct TransportClient *tc = ale->tc;
4733
4734 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
4735 tc->details.communicator.addr_tail,
4736 ale);
4737 /* Cancels @e sc, @e shc and the pending PILS signature request, all of
4738 which would otherwise run their callbacks on this freed entry. */
4740 if (NULL != ale->sc)
4741 {
4743 "store cancel\n");
4745 ale->sc = NULL;
4746 }
4747 if (NULL != ale->shc)
4748 {
4750 ale->shc = NULL;
4751 }
4752 if (NULL != ale->st)
4753 {
4755 ale->st = NULL;
4756 }
4757 if (NULL != ale->signed_address)
4759 GNUNET_free (ale);
4760}

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 4772 of file gnunet-service-transport.c.

4775{
4776 struct TransportClient *tc = cls;
4777 struct PeerRequest *pr = value;
4778
4779 if (NULL != pr->retry_task)
4780 {
4781 GNUNET_SCHEDULER_cancel (pr->retry_task);
4782 pr->retry_task = NULL;
4783 }
4784 if (NULL != pr->nc)
4786 pr->nc = NULL;
4788 GNUNET_YES ==
4789 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
4790 pid,
4791 pr));
4792 GNUNET_free (pr);
4793
4794 return GNUNET_OK;
4795}

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 15681 of file gnunet-service-transport.c.

15682{
15683 static int shutdown_done;
15684 struct LearnLaunchEntry *lle;
15685 struct PilsRequest *pr;
15686 (void) cls;
15687
15689 "shutdown logic\n");
15690 if (GNUNET_YES == shutdown_done)
15691 return; /* reachable both from #shutdown_task() and #client_disconnect_cb() */
15692 shutdown_done = GNUNET_YES;
15693 if (NULL != client_grace_task)
15694 {
15696 client_grace_task = NULL;
15697 }
15698 if (NULL != nh)
15699 {
15701 nh = NULL;
15702 }
15704 &free_neighbour_cb, NULL);
15705 /* Freeing a neighbour takes its virtual link with it, so whatever is
15706 left here is ownerless: a link we created from an inbound FLOW_CONTROL
15707 message that never got confirmed, kept alive only by its @e
15708 unconfirmed_timeout_task. #GNUNET_SCHEDULER_shutdown() does not run
15709 that task, so leaving the link in place left the task armed against a
15710 map we destroy further down -- it fired afterwards and
15711 #free_virtual_link() called GNUNET_CONTAINER_multipeermap_remove() on
15712 NULL. Drop them here, while every structure they touch is still
15713 alive. */
15716 NULL);
15717 if (NULL != validation_task)
15718 {
15720 validation_task = NULL;
15721 }
15722 if (NULL != dvlearn_task)
15723 {
15725 dvlearn_task = NULL;
15726 }
15727 if (NULL != burst_task)
15728 {
15730 burst_task = NULL;
15731 }
15732 if (NULL != burst_timeout_task)
15733 {
15735 burst_timeout_task = NULL;
15736 }
15739 dvlearn_map = NULL;
15742 dv_routes = NULL;
15743 if (NULL != GST_stats)
15744 {
15746 GST_stats = NULL;
15747 }
15748 if (NULL != GST_my_hello)
15749 {
15751 GST_my_hello = NULL;
15752 }
15755 NULL);
15757 ack_cummulators = NULL;
15760 NULL);
15762 pending_acks = NULL;
15765 neighbours = NULL;
15768 links = NULL;
15771 NULL);
15773 backtalkers = NULL;
15776 NULL);
15778 validation_map = NULL;
15780 validation_heap = NULL;
15782 revalidation_map = NULL;
15783 while (NULL != ir_head)
15785 GNUNET_assert (0 == ir_total);
15786 while (NULL != (lle = lle_head))
15787 {
15789 GNUNET_free (lle);
15790 }
15791 while (NULL != (pr = pils_requests_head))
15792 {
15795 pr);
15796 if (NULL != pr->op)
15797 GNUNET_PILS_cancel (pr->op);
15798 GNUNET_free (pr);
15799 }
15800 if (NULL != pils_feed_task)
15801 {
15803 pils_feed_task = NULL;
15804 }
15805 if (NULL != pils)
15806 {
15808 pils = NULL;
15809 }
15810 if (NULL != peerstore)
15811 {
15813 "Disconnecting from PEERSTORE service\n");
15815 peerstore = NULL;
15816 }
15818}

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 4812 of file gnunet-service-transport.c.

4815{
4816 const struct TransportClient *tc = cls;
4817 struct VirtualLink *vl = value;
4818
4819 (void) pid;
4820 for (struct CommunicatorMessageContext *cmc = vl->cmc_head;
4821 NULL != cmc;
4822 cmc = cmc->next)
4823 if (tc == cmc->tc)
4824 cmc->tc = NULL;
4825 return GNUNET_OK;
4826}

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 4839 of file gnunet-service-transport.c.

4842{
4843 const struct TransportClient *tc = cls;
4844 struct Backtalker *b = value;
4845
4846 (void) pid;
4847 if ((NULL != b->cmc) && (tc == b->cmc->tc))
4848 b->cmc->tc = NULL;
4849 return GNUNET_OK;
4850}

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 4872 of file gnunet-service-transport.c.

4873{
4876 (void *) tc);
4879 (void *) tc);
4880 for (unsigned int i = 0; i < RING_BUFFER_SIZE; i++)
4881 if ((NULL != ring_buffer[i]) &&
4882 (tc == ring_buffer[i]->cmc->tc))
4883 ring_buffer[i]->cmc->tc = NULL;
4884}

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 4896 of file gnunet-service-transport.c.

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

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 4991 of file gnunet-service-transport.c.

4994{
4995 struct TransportClient *tc = cls;
4996 struct VirtualLink *vl = value;
4997
4998 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
4999 return GNUNET_OK;
5000
5002 "Telling new CORE client about existing connection to %s\n",
5003 GNUNET_i2s (pid));
5005 return GNUNET_OK;
5006}

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 5020 of file gnunet-service-transport.c.

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

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 5056 of file gnunet-service-transport.c.

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

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 5103 of file gnunet-service-transport.c.

5104{
5105 struct TransportClient *tc = cls;
5106 uint16_t size;
5107 const struct GNUNET_MessageHeader *obmm;
5108
5109 if (CT_CORE != tc->type)
5110 {
5111 GNUNET_break (0);
5112 return GNUNET_SYSERR;
5113 }
5114 size = ntohs (obm->header.size) - sizeof(struct OutboundMessage);
5115 if (size < sizeof(struct GNUNET_MessageHeader))
5116 {
5117 GNUNET_break (0);
5118 return GNUNET_SYSERR;
5119 }
5120 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5121 if (size != ntohs (obmm->size))
5122 {
5123 GNUNET_break (0);
5124 return GNUNET_SYSERR;
5125 }
5126 return GNUNET_OK;
5127}

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 5138 of file gnunet-service-transport.c.

5139{
5140 struct TransportClient *tc = pm->client;
5141 struct VirtualLink *vl = pm->vl;
5142
5144 "client send response\n");
5145 if (NULL != tc)
5146 {
5148 "Confirming transmission of <%" PRIu64 "> to %s\n",
5149 pm->logging_uuid,
5150 GNUNET_i2s (&vl->target));
5151 credit_client (pm);
5152 }
5154}

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 5167 of file gnunet-service-transport.c.

5171{
5172 uint64_t choices[hops_array_length];
5173 uint64_t num_dv;
5174 unsigned int dv_count;
5175
5176 /* Pick random vectors, but weighted by distance, giving more weight
5177 to shorter vectors */
5178 num_dv = 0;
5179 dv_count = 0;
5180 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5181 pos = pos->next_dv)
5182 {
5183 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
5184 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
5185 .rel_value_us == 0))
5186 continue; /* pos unconfirmed and confirmed required */
5187 /* A hop at (or past) the limit has weight zero -- past it, unsigned
5188 arithmetic makes the weight huge. Either way it can never be picked
5189 below, so it must not be counted: the sampling loop draws
5190 @a hops_array_length distinct values out of @e num_dv, and counting a
5191 hop that contributes nothing to @e num_dv can leave it with fewer
5192 values than draws, which never terminates. #learn_dv_path() caps
5193 @e distance well below the limit today, so this is defence in depth. */
5194 if (pos->distance >= MAX_DV_HOPS_ALLOWED)
5195 continue;
5196 num_dv += MAX_DV_HOPS_ALLOWED - pos->distance;
5197 dv_count++;
5198 }
5199 if (0 == dv_count)
5200 return 0;
5201 if (dv_count <= hops_array_length)
5202 {
5203 dv_count = 0;
5204 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5205 pos = pos->next_dv)
5206 hops_array[dv_count++] = pos;
5207 return dv_count;
5208 }
5209 for (unsigned int i = 0; i < hops_array_length; i++)
5210 {
5211 int ok = GNUNET_NO;
5212 unsigned int tries = 0;
5213
5214 while (GNUNET_NO == ok)
5215 {
5216 choices[i] =
5217 GNUNET_CRYPTO_random_u64 (num_dv);
5218 ok = GNUNET_YES;
5219 for (unsigned int j = 0; j < i; j++)
5220 if (choices[i] == choices[j])
5221 {
5222 ok = GNUNET_NO;
5223 break;
5224 }
5225 /* Give up rather than spin: with weight >= 2 per hop the expected
5226 number of draws per pick is below four, so this many failures is a
5227 set we cannot sample distinctly. Returning fewer paths is a routing
5228 nuisance, hanging here is a deaf service; and a duplicated choice
5229 would at worst repeat a path, so stopping is safe. */
5230 if (MAX_DV_PICK_TRIES < ++tries)
5231 break;
5232 }
5233 if (GNUNET_NO == ok)
5234 {
5235 hops_array_length = i;
5236 break;
5237 }
5238 }
5239 dv_count = 0;
5240 num_dv = 0;
5241 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5242 pos = pos->next_dv)
5243 {
5244 uint64_t delta;
5245
5246 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
5247 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
5248 .rel_value_us == 0))
5249 continue; /* pos unconfirmed and confirmed required */
5250 if (pos->distance >= MAX_DV_HOPS_ALLOWED)
5251 continue; /* zero weight: not counted in @e num_dv above either */
5252 delta = MAX_DV_HOPS_ALLOWED - pos->distance;
5253 for (unsigned int i = 0; i < hops_array_length; i++)
5254 if ((num_dv <= choices[i]) && (num_dv + delta > choices[i]))
5255 hops_array[dv_count++] = pos;
5256 num_dv += delta;
5257 }
5258 return dv_count;
5259}

References delta, VirtualLink::dv, DistanceVector::dv_head, GNUNET_CRYPTO_random_u64(), GNUNET_NO, GNUNET_TIME_absolute_get_remaining(), GNUNET_YES, MAX_DV_HOPS_ALLOWED, MAX_DV_PICK_TRIES, 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 5269 of file gnunet-service-transport.c.

5272{
5273 struct TransportClient *tc = cls;
5274 uint16_t size;
5275
5276 if (CT_NONE != tc->type)
5277 {
5278 GNUNET_break (0);
5279 return GNUNET_SYSERR;
5280 }
5281 tc->type = CT_COMMUNICATOR;
5282 size = ntohs (cam->header.size) - sizeof(*cam);
5283 if (0 == size)
5284 return GNUNET_OK; /* receive-only communicator */
5286 return GNUNET_OK;
5287}

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 5302 of file gnunet-service-transport.c.

5303{
5304 struct GNUNET_MQ_Envelope *env;
5306
5307 if (GNUNET_YES == cmc->ack_sent)
5308 return;
5309 cmc->ack_sent = GNUNET_YES;
5310 if (NULL == cmc->tc)
5311 return; /* communicator is gone, see #detach_cmcs_from_client() */
5312 if (0 == ntohl (cmc->im.fc_on))
5313 return; /* communicator did not ask for flow control */
5315 "Acknowledge message with flow control id %" PRIu64 "\n",
5316 cmc->im.fc_id);
5318 ack->reserved = htonl (0);
5319 ack->fc_id = cmc->im.fc_id;
5320 ack->sender = cmc->im.neighbour_sender;
5321 GNUNET_MQ_send (cmc->tc->mq, env);
5322}

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 5336 of file gnunet-service-transport.c.

5337{
5338 if (GNUNET_YES == cmc->client_resumed)
5339 return;
5341 if (NULL == cmc->tc)
5342 return; /* communicator is gone, see #detach_cmcs_from_client() */
5344}

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 5381 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 5397 of file gnunet-service-transport.c.

5398{
5399 struct TransportClient *tc = cls;
5400 struct VirtualLink *vl;
5401 uint32_t delta;
5402 struct CommunicatorMessageContext *cmc;
5403
5404 if (CT_CORE != tc->type)
5405 {
5406 GNUNET_break (0);
5408 return;
5409 }
5410 vl = lookup_virtual_link (&rom->peer);
5411 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
5412 {
5414 "# RECV_OK dropped: virtual link unknown",
5415 1,
5416 GNUNET_NO);
5418 return;
5419 }
5420 delta = ntohl (rom->increase_window_delta);
5421 vl->core_recv_window += delta;
5423 "CORE ack receiving message, increased CORE recv window to %d\n",
5424 vl->core_recv_window);
5426 if (vl->core_recv_window <= 0)
5427 return;
5428 /* release the flow control credit we withheld from the communicators */
5429 while (NULL != (cmc = vl->cmc_tail))
5430 release_stalled_cmc (vl, cmc);
5431 if (NULL != vl->core_fc_stall_task)
5432 {
5434 vl->core_fc_stall_task = NULL;
5435 }
5436}

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 5446 of file gnunet-service-transport.c.

5449{
5450 const struct GNUNET_PeerIdentity *my_identity;
5451 struct TransportClient *tc = cls;
5452 uint16_t size;
5453
5454 size = ntohs (cam->header.size) - sizeof(*cam);
5455 if (0 == size)
5456 {
5458 "Receive-only communicator connected\n");
5459 /* Receive-only communicator: it has no address prefix, but we still
5460 MUST resume the client or we will never read from it again. Use an
5461 empty prefix so that the various strcmp()s do not see NULL. */
5462 tc->details.communicator.address_prefix = GNUNET_strdup ("");
5464 return;
5465 }
5466 tc->details.communicator.address_prefix =
5467 GNUNET_strdup ((const char *) &cam[1]);
5468 tc->details.communicator.cc = ntohl (cam->cc);
5469 tc->details.communicator.can_burst = ntohl (cam->can_burst);
5471 if (NULL != my_identity)
5472 {
5474 "Communicator for peer %s with prefix '%s' connected %s\n",
5476 tc->details.communicator.address_prefix,
5477 tc->details.communicator.can_burst ? "can burst" :
5478 "can not burst");
5479 }
5480 else
5481 {
5483 "Communicator for local peer with prefix '%s' connected %s\n",
5484 tc->details.communicator.address_prefix,
5485 tc->details.communicator.can_burst ? "can burst" :
5486 "can not burst");
5487 }
5489}

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 5500 of file gnunet-service-transport.c.

5503{
5504 const struct GNUNET_MessageHeader *inbox;
5505 const char *is;
5506 uint16_t msize;
5507 uint16_t isize;
5508
5509 (void) cls;
5510 msize = ntohs (cb->header.size) - sizeof(*cb);
5511 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
5512 /* MUST bound the buffer before dereferencing @a inbox. */
5513 if (msize <= sizeof(struct GNUNET_MessageHeader))
5514 {
5515 GNUNET_break (0);
5516 return GNUNET_SYSERR;
5517 }
5518 isize = ntohs (inbox->size);
5519 if (isize >= msize)
5520 {
5521 GNUNET_break (0);
5522 return GNUNET_SYSERR;
5523 }
5524 is = (const char *) inbox;
5525 is += isize;
5526 msize -= isize;
5527 GNUNET_assert (0 < msize);
5528 if ('\0' != is[msize - 1])
5529 {
5530 GNUNET_break (0);
5531 return GNUNET_SYSERR;
5532 }
5533 return GNUNET_OK;
5534}

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 5552 of file gnunet-service-transport.c.

5553{
5554 struct EphemeralConfirmationPS ec;
5555
5557 dv->ephemeral_validity =
5559 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
5560 ec.target = dv->target;
5561 ec.ephemeral_key = dv->ephemeral_key;
5562 ec.sender_monotonic_time = GNUNET_TIME_absolute_hton (dv->monotime);
5563 ec.purpose.size = htonl (sizeof(ec));
5564 return sign_by_my_identity (&ec.purpose, &dv->sender_sig);
5565}

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 13457 of file gnunet-service-transport.c.

13459{
13460 struct PendingMessage *pm;
13461
13462 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
13463 qe->queue->queue_tail,
13464 qe);
13465 qe->queue->queue_length--;
13466 tc->details.communicator.total_queue_length--;
13468 "Received ACK on queue %s (QID %u) to peer %s (new length: %u/%u)\n",
13469 qe->queue->address,
13470 qe->queue->qid,
13471 GNUNET_i2s (&qe->queue->neighbour->pid),
13472 qe->queue->queue_length,
13473 tc->details.communicator.total_queue_length);
13474
13475 /* if applicable, resume transmissions that waited on ACK */
13477 tc->details.communicator.total_queue_length)
13478 {
13479 /* Communicator dropped below threshold, resume all queues
13480 incident with this client! */
13482 GST_stats,
13483 "# Transmission throttled due to communicator queue limit",
13484 -1,
13485 GNUNET_NO);
13486 for (struct Queue *queue = tc->details.communicator.queue_head;
13487 NULL != queue;
13488 queue = queue->next_client)
13489 {
13491 queue,
13493 }
13494 }
13495 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
13496 {
13497 /* queue dropped below threshold; only resume this one queue */
13499 "# Transmission throttled due to queue queue limit",
13500 -1,
13501 GNUNET_NO);
13503 qe->queue,
13505 }
13506 else if (1 == qe->queue->q_capacity)
13507 {
13508 // TODO I guess this will never happen, because the communicator triggers this by updating its queue length itself.
13510 "Transmission rescheduled due to communicator message queue with qid %u has capacity %"
13511 PRIu64 ".\n",
13512 qe->queue->qid,
13513 qe->queue->q_capacity);
13514 /* message queue has capacity; only resume this one queue */
13515 /* queue dropped below threshold; only resume this one queue */
13517 "# Transmission throttled due to message queue capacity",
13518 -1,
13519 GNUNET_NO);
13521 qe->queue,
13523 }
13524
13525 if (NULL != (pm = qe->pm))
13526 {
13527 struct VirtualLink *vl;
13528
13529 // GNUNET_assert (qe == pm->qe);
13530 pm->qe = NULL;
13531 /* If waiting for this communicator may have blocked transmission
13532 of pm on other queues for this neighbour, force schedule
13533 transmit on queue for queues of the neighbour */
13534 if (NULL == pm->frag_parent)
13535 {
13536 vl = pm->vl;
13537 if ((NULL != vl) &&
13538 (NULL != vl->pending_msg_head) &&
13539 (vl->pending_msg_head == pm))
13541 }
13542 }
13543 GNUNET_free (qe);
13544}

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 5574 of file gnunet-service-transport.c.

5575{
5576 struct TransportClient *tc = cls;
5578
5580 "freeing timedout queue entries\n");
5581
5582 tc->details.communicator.free_queue_entry_task = NULL;
5583 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
5584 queue = queue->next_client)
5585 {
5586 struct QueueEntry *qep = queue->queue_head;
5587
5589 "checking QID %u for timedout queue entries\n",
5590 queue->qid);
5591 while (NULL != qep)
5592 {
5593 struct QueueEntry *pos = qep;
5595 pos->creation_timestamp, now);
5596 qep = qep->next;
5597
5599 "diff to now %s \n",
5602 {
5604 "Freeing timed out QueueEntry with MID %" PRIu64
5605 " and QID %u\n",
5606 pos->mid,
5607 queue->qid);
5609 "# QueueEntries timed out",
5610 1,
5611 GNUNET_NO);
5612 free_queue_entry (pos, tc);
5613 }
5614 }
5615 }
5616 /* Entries younger than #QUEUE_ENTRY_TIMEOUT are still to be reclaimed, and
5617 this task used to be a one-shot armed only by #queue_send_msg(). So the
5618 sweep that was supposed to bound how long an unacknowledged entry holds
5619 its slot only ever ran while *new* messages were being queued -- exactly
5620 not the case once the throttles in #schedule_transmit_on_queue() have
5621 stopped transmission. Keep going as long as anything is outstanding. */
5623}

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 5655 of file gnunet-service-transport.c.

5659{
5660 struct Neighbour *n = queue->neighbour;
5662 struct GNUNET_MQ_Envelope *env;
5663 struct PendingAcknowledgement *pa;
5664
5665 GNUNET_log (
5667 "Queueing %u bytes of payload for transmission <%" PRIu64
5668 "> on queue %llu to %s\n",
5669 (unsigned int) payload_size,
5670 (NULL == pm) ? 0 : pm->logging_uuid,
5671 (unsigned long long) queue->qid,
5672 GNUNET_i2s (&queue->neighbour->pid));
5673 env = GNUNET_MQ_msg_extra (smt,
5674 payload_size,
5676 smt->qid = htonl (queue->qid);
5677 smt->mid = GNUNET_htonll (queue->mid_gen);
5678 smt->receiver = n->pid;
5679 memcpy (&smt[1], payload, payload_size);
5680 {
5681 /* Pass the env to the communicator of queue for transmission. */
5682 struct QueueEntry *qe;
5683
5684 qe = GNUNET_new (struct QueueEntry);
5685 qe->creation_timestamp = GNUNET_TIME_absolute_get ();
5686 qe->mid = queue->mid_gen;
5688 "Create QueueEntry with MID %" PRIu64
5689 " and QID %u and prefix %s\n",
5690 qe->mid,
5691 queue->qid,
5692 queue->tc->details.communicator.address_prefix);
5693 queue->mid_gen++;
5694 qe->queue = queue;
5695 if (NULL != pm)
5696 {
5697 qe->pm = pm;
5698 // TODO Why do we have a retransmission. When we know, make decision if we still want this.
5699 // GNUNET_assert (NULL == pm->qe);
5700 if (NULL != pm->qe)
5701 {
5703 "Retransmitting message <%" PRIu64
5704 "> remove pm from qe with MID: %llu \n",
5706 (unsigned long long) pm->qe->mid);
5707 pm->qe->pm = NULL;
5708 }
5709 pm->qe = qe;
5710 }
5711 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
5712 if (0 == queue->q_capacity)
5713 {
5714 // Messages without FC or fragments can get here.
5715 if (NULL != pm)
5716 {
5718 "Message %" PRIu64
5719 " (pm type %u) was not send because queue has no capacity.\n",
5721 pm->pmt);
5722 pm->qe = NULL;
5723 }
5724 GNUNET_free (env);
5725 GNUNET_free (qe);
5726 return;
5727 }
5728 GNUNET_CONTAINER_DLL_insert (queue->queue_head, queue->queue_tail, qe);
5729 queue->queue_length++;
5730 queue->tc->details.communicator.total_queue_length++;
5731 if (GNUNET_NO == queue->unlimited_length)
5732 queue->q_capacity--;
5734 "Queue %s with qid %u has capacity %" PRIu64 "\n",
5735 queue->address,
5736 queue->qid,
5737 queue->q_capacity);
5739 queue->tc->details.communicator.total_queue_length)
5740 queue->idle = GNUNET_NO;
5741 if (QUEUE_LENGTH_LIMIT == queue->queue_length)
5742 queue->idle = GNUNET_NO;
5743 if (0 == queue->q_capacity)
5744 queue->idle = GNUNET_NO;
5745
5746 if (GNUNET_NO == queue->idle)
5748 if (NULL != pm)
5749 {
5750 /* NOTE: @e next_pa was never the link of this list -- nothing ever
5751 assigned it, so it was NULL on every entry. The MDLL that
5752 #prepare_pending_acknowledgement() inserts into is keyed `pm', and
5753 thus threaded through @e next_pm. Walking @e next_pa dereferenced
5754 NULL the moment the head was not the entry we wanted. */
5755 for (pa = pm->pa_head; NULL != pa; pa = pa->next_pm)
5756 if (pm == pa->pm)
5757 {
5758 pa->num_send++;
5759 break;
5760 }
5761 }
5762 // GNUNET_CONTAINER_multiuuidmap_get (pending_acks, &ack[i].ack_uuid.value);
5764 "Sending message MID %" PRIu64
5765 " of type %u (%u) and size %lu with MQ %p queue %s (QID %u) pending %"
5766 PRIu64 "\n",
5767 GNUNET_ntohll (smt->mid),
5768 ntohs (((const struct GNUNET_MessageHeader *) payload)->type),
5769 ntohs (smt->header.size),
5770 (unsigned long) payload_size,
5771 queue->tc->mq,
5772 queue->address,
5773 queue->qid,
5774 (NULL == pm) ? 0 : pm->logging_uuid);
5775 GNUNET_MQ_send (queue->tc->mq, env);
5776 }
5777}

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 5791 of file gnunet-service-transport.c.

5794{
5795 struct GNUNET_TIME_Absolute now;
5796 unsigned int candidates;
5797 unsigned int sel1;
5798 unsigned int sel2;
5799 struct GNUNET_TIME_Relative rtt;
5800
5801 /* Pick one or two 'random' queues from n (under constraints of options) */
5802 now = GNUNET_TIME_absolute_get ();
5803 /* FIXME-OPTIMIZE: give queues 'weights' and pick proportional to
5804 weight in the future; weight could be assigned by observed
5805 bandwidth (note: not sure if we should do this for this type
5806 of control traffic though). */
5807 candidates = 0;
5808 for (struct Queue *pos = n->queue_head; NULL != pos;
5809 pos = pos->next_neighbour)
5810 {
5811 if ((0 != (options & RMO_UNCONFIRMED_ALLOWED)) ||
5812 (pos->validated_until.abs_value_us > now.abs_value_us))
5813 candidates++;
5814 }
5815 if (0 == candidates)
5816 {
5817 /* This can happen rarely if the last confirmed queue timed
5818 out just as we were beginning to process this message. */
5820 "Could not route message of type %u to %s: no valid queue\n",
5821 ntohs (hdr->type),
5822 GNUNET_i2s (&n->pid));
5824 "# route selection failed (all no valid queue)",
5825 1,
5826 GNUNET_NO);
5828 }
5829
5831 sel1 = GNUNET_CRYPTO_random_u32 (candidates);
5832 if (0 == (options & RMO_REDUNDANT))
5833 sel2 = candidates; /* picks none! */
5834 else
5835 sel2 = GNUNET_CRYPTO_random_u32 (candidates);
5836 candidates = 0;
5837 for (struct Queue *pos = n->queue_head; NULL != pos;
5838 pos = pos->next_neighbour)
5839 {
5840 if ((0 != (options & RMO_UNCONFIRMED_ALLOWED)) ||
5841 (pos->validated_until.abs_value_us > now.abs_value_us))
5842 {
5843 if ((sel1 == candidates) || (sel2 == candidates))
5844 {
5846 "Routing message of type %u to %s using %s (#%u)\n",
5847 ntohs (hdr->type),
5848 GNUNET_i2s (&n->pid),
5849 pos->address,
5850 (sel1 == candidates) ? 1 : 2);
5851 rtt = GNUNET_TIME_relative_min (rtt, pos->pd.aged_rtt);
5852 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
5853 }
5854 candidates++;
5855 }
5856 }
5857 return rtt;
5858}

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 5891 of file gnunet-service-transport.c.

5899{
5900 const struct GNUNET_PeerIdentity *my_identity;
5901 struct TransportDVBoxMessage box_hdr;
5902 struct TransportDVBoxPayloadP *payload_hdr;
5903 uint16_t body_len_hbo = ntohs (hdr->size);
5904 unsigned char pt[sizeof(struct TransportDVBoxPayloadP) + body_len_hbo]
5906 unsigned char ct[sizeof(struct TransportDVBoxPayloadP) + body_len_hbo]
5908 struct GNUNET_TIME_Relative rtt;
5910
5911 payload_hdr = (struct TransportDVBoxPayloadP*) pt;
5914
5915 /* Encrypt payload */
5916 memset (&box_hdr, 0, sizeof (box_hdr));
5917 box_hdr.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
5918 box_hdr.total_hops = htons (0);
5919 box_hdr.without_fc = htonl (without_fc);
5920 // update_ephemeral (dv);
5921 if ((0 ==
5923 || (NULL == dv->km))
5924 {
5926 &dv->ephemeral_key,
5927 (struct GNUNET_ShortHashCode*) &km);
5928 GNUNET_free (dv->km); /* do not leak the previous key material */
5929 dv->km = GNUNET_new (struct GNUNET_ShortHashCode);
5930 GNUNET_memcpy (dv->km, &km, sizeof(struct GNUNET_ShortHashCode));
5931 if (GNUNET_OK != sign_ephemeral (dv))
5932 {
5933 /* Without a matching signature the box is undecryptable noise to the
5934 receiver; do not spend the bandwidth. Expire the ephemeral so the
5935 next attempt re-derives and re-signs rather than reusing it. */
5938 }
5939 }
5940 else
5941 {
5942 /* The ephemeral key is still valid, so reuse the cached key material.
5943 Without this @a km stayed UNINITIALISED stack memory and the
5944 receiver could not decrypt the box. */
5945 GNUNET_memcpy (&km, dv->km, sizeof(struct GNUNET_ShortHashCode));
5946 }
5947 box_hdr.ephemeral_key = dv->ephemeral_key;
5948 payload_hdr->sender_sig = dv->sender_sig;
5949 memcpy (&payload_hdr[1], hdr, body_len_hbo);
5950 GNUNET_CRYPTO_random_block (&box_hdr.iv,
5951 sizeof(box_hdr.iv));
5952 payload_hdr->sender = *my_identity;
5954 GNUNET_CRYPTO_aead_encrypt (sizeof pt,
5955 pt,
5956 0,
5957 NULL,
5958 &km,
5959 &box_hdr.iv,
5960 ct,
5961 &box_hdr.mac);
5963 /* For each selected path, take the pre-computed header and body
5964 and add the path in the middle of the message; then send it. */
5965 for (unsigned int i = 0; i < num_dvhs; i++)
5966 {
5967 struct DistanceVectorHop *dvh = dvhs[i];
5968 unsigned int num_hops = dvh->distance + 1;
5969 char buf[sizeof(struct TransportDVBoxMessage)
5970 + sizeof(struct GNUNET_PeerIdentity) * num_hops
5971 + sizeof(struct TransportDVBoxPayloadP)
5972 + body_len_hbo] GNUNET_ALIGN;
5973 struct GNUNET_PeerIdentity *dhops;
5974
5975 box_hdr.header.size = htons (sizeof(buf));
5976 box_hdr.orig_size = htons (sizeof(buf));
5977 box_hdr.num_hops = htons (num_hops);
5978 memcpy (buf, &box_hdr, sizeof(box_hdr));
5979 dhops = (struct GNUNET_PeerIdentity *) &buf[sizeof(box_hdr)];
5980 memcpy (dhops,
5981 dvh->path,
5982 dvh->distance * sizeof(struct GNUNET_PeerIdentity));
5983 dhops[dvh->distance] = dv->target;
5984 if (GNUNET_EXTRA_LOGGING > 0)
5985 {
5986 char *path;
5987
5989 for (unsigned int j = 0; j < num_hops; j++)
5990 {
5991 char *tmp;
5992
5993 GNUNET_asprintf (&tmp, "%s-%s", path, GNUNET_i2s (&dhops[j]));
5994 GNUNET_free (path);
5995 path = tmp;
5996 }
5998 "Routing message of type %u to %s using DV (#%u/%u) via %s\n",
5999 ntohs (hdr->type),
6000 GNUNET_i2s (&dv->target),
6001 i + 1,
6002 num_dvhs,
6003 path);
6004 GNUNET_free (path);
6005 }
6006 rtt = GNUNET_TIME_relative_min (rtt, dvh->pd.aged_rtt);
6007 memcpy (&dhops[num_hops], ct, sizeof(ct));
6008 use (use_cls,
6009 dvh->next_hop,
6010 (const struct GNUNET_MessageHeader *) buf,
6011 options);
6012 }
6013 return rtt;
6014}

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 6027 of file gnunet-service-transport.c.

6031{
6032 (void) cls;
6033 (void) route_via_neighbour (next_hop, hdr, RMO_UNCONFIRMED_ALLOWED);
6034}

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 6049 of file gnunet-service-transport.c.

6053{
6054 // struct VirtualLink *vl;
6055 struct Neighbour *n;
6056 struct DistanceVector *dv;
6057 struct GNUNET_TIME_Relative rtt1;
6058 struct GNUNET_TIME_Relative rtt2;
6059 const struct GNUNET_PeerIdentity *target = &vl->target;
6060
6062 "Trying to route message of type %u to %s without fc\n",
6063 ntohs (hdr->type),
6064 GNUNET_i2s (target));
6065
6066 // TODO Do this elsewhere. vl should be given as parameter to method.
6067 // vl = lookup_virtual_link (target);
6068 /* An unconfirmed link is allowed here: it has no @e n and no @e dv of its
6069 own, so the "confirmed required" branch below resolves the route from
6070 #neighbours / #dv_routes. Refusing to route at all is what deadlocks a
6071 pair of peers, see #consider_sending_fc(). */
6072 GNUNET_assert (NULL != vl);
6073 n = vl->n;
6074 dv = (0 != (options & RMO_DV_ALLOWED)) ? vl->dv : NULL;
6075 /* An unconfirmed link has neither @e n nor @e dv of its own, so resolve
6076 the route from #neighbours / #dv_routes. This used to be done only
6077 while #RMO_UNCONFIRMED_ALLOWED was *not* set -- exactly backwards: with
6078 the flag set (the caller that needs it most) we would find no route at
6079 all and drop the message. Whether an unvalidated queue or an
6080 unvalidated path may then be used is still decided by @a options, in
6081 #route_via_neighbour() and #pick_random_dv_hops(). */
6082 if (NULL == n)
6083 n = lookup_neighbour (target);
6084 if ((NULL == dv) && (0 != (options & RMO_DV_ALLOWED)))
6086 if ((NULL == n) && (NULL == dv))
6087 {
6089 "Cannot route message of type %u to %s: no route\n",
6090 ntohs (hdr->type),
6091 GNUNET_i2s (target));
6093 "# Messages dropped in routing: no acceptable method",
6094 1,
6095 GNUNET_NO);
6097 }
6099 "Routing message of type %u to %s with options %X\n",
6100 ntohs (hdr->type),
6101 GNUNET_i2s (target),
6102 (unsigned int) options);
6103 /* If both dv and n are possible and we must choose:
6104 flip a coin for the choice between the two; for now 50/50 */
6105 if ((NULL != n) && (NULL != dv) && (0 == (options & RMO_REDUNDANT)))
6106 {
6107 if (0 == GNUNET_CRYPTO_random_u32 (2))
6108 n = NULL;
6109 else
6110 dv = NULL;
6111 }
6112 if ((NULL != n) && (NULL != dv))
6113 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
6114 enough for redundancy, so clear the flag. */
6117 if (NULL != n)
6118 {
6120 "Try to route message of type %u to %s without fc via neighbour\n",
6121 ntohs (hdr->type),
6122 GNUNET_i2s (target));
6123 rtt1 = route_via_neighbour (n, hdr, options);
6124 }
6125 if (NULL != dv)
6126 {
6127 struct DistanceVectorHop *hops[2];
6128 unsigned int res;
6129
6131 options,
6132 hops,
6133 (0 == (options & RMO_REDUNDANT)) ? 1 : 2);
6134 if (0 == res)
6135 {
6137 "Failed to route message, could not determine DV path\n");
6138 return rtt1;
6139 }
6141 "encapsulate_for_dv 1\n");
6142 rtt2 = encapsulate_for_dv (dv,
6143 res,
6144 hops,
6145 hdr,
6147 NULL,
6149 GNUNET_YES);
6150 }
6151 return GNUNET_TIME_relative_min (rtt1, rtt2);
6152}

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 6233 of file gnunet-service-transport.c.

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

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 6165 of file gnunet-service-transport.c.

6166{
6167 struct VirtualLink *vl = cls;
6168 vl->fc_retransmit_task = NULL;
6169 consider_sending_fc (cls);
6170}

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 14452 of file gnunet-service-transport.c.

14453{
14454 const char *dash;
14455 const char *colon;
14456
14457 if (NULL == address)
14458 return NULL;
14459 dash = strchr (address, '-');
14460 if (NULL == dash)
14461 return NULL;
14462 colon = strchr (dash, ':');
14463 if (NULL == colon)
14464 return NULL;
14465 return GNUNET_strndup (dash + 1,
14466 colon - (dash + 1));
14467}

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 6193 of file gnunet-service-transport.c.

6196{
6197 struct AddGlobalAddressesContext *ctx = cls;
6198 struct TransportGlobalNattedAddress *tgna = value;
6199 char *addr = (char *) &tgna[1];
6200 size_t alen = ntohl (tgna->address_length);
6201 size_t need = sizeof (struct TransportGlobalNattedAddress) + alen;
6202
6203 /* NOTE: the address is NOT 0-terminated, it must be printed with an
6204 explicit precision. */
6206 "sending address %.*s length %lu\n",
6207 (int) alen,
6208 addr,
6209 (unsigned long) alen);
6210 if (ctx->off + need > ctx->size)
6211 {
6212 GNUNET_break (0);
6213 return GNUNET_NO;
6214 }
6215 GNUNET_memcpy (&(ctx->tgnas[ctx->off]), tgna, need);
6216 ctx->off += need;
6217
6218 return GNUNET_OK;
6219}

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 11657 of file gnunet-service-transport.c.

11658{
11660 unsigned int n_hops = 0;
11661
11663 "calculate_rtt\n");
11664 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
11665 pos = pos->next_dv)
11666 {
11668 "calculate_rtt %lu\n",
11669 (unsigned long) pos->pd.aged_rtt.rel_value_us);
11670 n_hops++;
11672 aged_rtt, pos
11673 ->distance
11674 + 2), ret);
11675 }
11676
11677 if (0 == n_hops)
11679 return ret;
11680}

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 6434 of file gnunet-service-transport.c.

6435{
6436 struct Neighbour *n = vl->n;
6437 struct DistanceVector *dv = vl->dv;
6438 struct GNUNET_TIME_Absolute now;
6439 struct VirtualLink *vl_next_hop;
6440 int elig;
6441
6443 "check_vl_transmission to target %s\n",
6444 GNUNET_i2s (&vl->target));
6445 /* Check that we have an eligible pending message!
6446 (cheaper than having #transmit_on_queue() find out!) */
6447 elig = GNUNET_NO;
6448 for (struct PendingMessage *pm = vl->pending_msg_head; NULL != pm;
6449 pm = pm->next_vl)
6450 {
6452 "check_vl_transmission loop\n");
6453 if (NULL != pm->qe)
6454 continue; /* not eligible, is in a queue! */
6455 if (pm->bytes_msg + vl->outbound_fc_window_size_used >
6457 {
6459 "Stalled message %" PRIu64
6460 " transmission on VL %s due to flow control: %llu < %llu\n",
6461 pm->logging_uuid,
6462 GNUNET_i2s (&vl->target),
6463 (unsigned long long) vl->outbound_fc_window_size,
6464 (unsigned long long) (pm->bytes_msg
6467 return; /* We have a message, but flow control says "nope" */
6468 }
6470 "Target window on VL %s not stalled. Scheduling transmission on queue\n",
6471 GNUNET_i2s (&vl->target));
6472 /* Notify queues at direct neighbours that we are interested */
6473 now = GNUNET_TIME_absolute_get ();
6474 if (NULL != n)
6475 {
6476 for (struct Queue *queue = n->queue_head; NULL != queue;
6477 queue = queue->next_neighbour)
6478 {
6479 if ((GNUNET_YES == queue->idle) &&
6480 (queue->validated_until.abs_value_us > now.abs_value_us))
6481 {
6483 "Direct neighbour %s not stalled\n",
6484 GNUNET_i2s (&n->pid));
6486 queue,
6488 elig = GNUNET_YES;
6489 }
6490 else
6492 "Neighbour Queue QID: %u (%u) busy or invalid\n",
6493 queue->qid,
6494 queue->idle);
6495 }
6496 }
6497 /* Notify queues via DV that we are interested */
6498 if (NULL != dv)
6499 {
6500 /* Do DV with lower scheduler priority, which effectively means that
6501 IF a neighbour exists and is available, we prefer it. */
6502 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
6503 pos = pos->next_dv)
6504 {
6505 struct Neighbour *nh_iter = pos->next_hop;
6506
6507
6508 if (pos->path_valid_until.abs_value_us <= now.abs_value_us)
6509 continue; /* skip this one: path not validated */
6510 else
6511 {
6512 /* The next hop is a neighbour we have queues to; it need not have
6513 a virtual link of its own, and then there is no window of it to
6514 respect either. */
6515 vl_next_hop = lookup_virtual_link (&nh_iter->pid);
6516 if ((NULL != vl_next_hop) &&
6517 (pm->bytes_msg + vl_next_hop->outbound_fc_window_size_used >
6518 vl_next_hop->outbound_fc_window_size))
6519 {
6521 "Stalled message %" PRIu64
6522 " transmission on next hop %s due to flow control: %llu < %llu\n",
6523 pm->logging_uuid,
6524 GNUNET_i2s (&vl_next_hop->target),
6525 (unsigned long
6526 long) vl_next_hop->outbound_fc_window_size,
6527 (unsigned long long) (pm->bytes_msg
6528 + vl_next_hop->
6529 outbound_fc_window_size_used));
6530 consider_sending_fc (vl_next_hop);
6531 continue; /* We have a message, but flow control says "nope" for the first hop of this path */
6532 }
6533 for (struct Queue *queue = nh_iter->queue_head; NULL != queue;
6534 queue = queue->next_neighbour)
6535 if ((GNUNET_YES == queue->idle) &&
6536 (queue->validated_until.abs_value_us > now.abs_value_us))
6537 {
6539 "Next hop neighbour %s not stalled\n",
6540 GNUNET_i2s (&nh_iter->pid));
6542 queue,
6544 elig = GNUNET_YES;
6545 }
6546 else
6548 "DV Queue QID: %u (%u) busy or invalid\n",
6549 queue->qid,
6550 queue->idle);
6551 }
6552 }
6553 }
6554 if (GNUNET_YES == elig)
6556 "Eligible message %" PRIu64 " of size %u to %s: %llu/%llu\n",
6557 pm->logging_uuid,
6558 pm->bytes_msg,
6559 GNUNET_i2s (&vl->target),
6560 (unsigned long long) vl->outbound_fc_window_size,
6561 (unsigned long long) (pm->bytes_msg
6563 break;
6564 }
6565}

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 6575 of file gnunet-service-transport.c.

6576{
6577 struct TransportClient *tc = cls;
6578 struct PendingMessage *pm;
6579 const struct GNUNET_MessageHeader *obmm;
6580 uint32_t bytes_msg;
6581 struct VirtualLink *vl;
6583
6584 GNUNET_assert (CT_CORE == tc->type);
6585 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
6586 bytes_msg = ntohs (obmm->size);
6587 pp = ntohl (obm->priority);
6588 vl = lookup_virtual_link (&obm->peer);
6589 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
6590 {
6592 "Don't have %s as a neighbour (anymore).\n",
6593 GNUNET_i2s (&obm->peer));
6594 /* Failure: don't have this peer as a neighbour (anymore).
6595 Might have gone down asynchronously, so this is NOT
6596 a protocol violation by CORE. Still count the event,
6597 as this should be rare. */
6598 /* Precisely because this is not a protocol violation we leave the
6599 client's `struct Neighbour' -- and its send window -- in place, so we
6600 owe it the SEND_OK for the message we are dropping here. Without it
6601 the window shrinks by one every time this happens and never grows
6602 back; after #SEND_WINDOW_SIZE such drops #mq_send_impl() parks every
6603 further message for this peer forever ("Flow control delays
6604 transmission to CORE until we see SEND_OK") and CORE goes mute
6605 towards a peer it still believes it is connected to -- while
6606 continuing to receive from it, so its own idle timeout is what
6607 eventually reports the peer down. */
6608 send_ok_to_client (tc, &obm->peer);
6611 "# messages dropped (neighbour unknown)",
6612 1,
6613 GNUNET_NO);
6614 return;
6615 }
6616
6617 pm = GNUNET_malloc (sizeof(struct PendingMessage) + bytes_msg);
6619 "1 created pm %p storing vl %p\n",
6620 pm,
6621 vl);
6623 pm->prefs = pp;
6624 pm->client = tc;
6625 pm->vl = vl;
6626 pm->bytes_msg = bytes_msg;
6627 memcpy (&pm[1], obmm, bytes_msg);
6629 "Sending message of type %u with %u bytes as <%" PRIu64
6630 "> to %s\n",
6631 ntohs (obmm->type),
6632 bytes_msg,
6633 pm->logging_uuid,
6634 GNUNET_i2s (&obm->peer));
6636 tc->details.core.pending_msg_head,
6637 tc->details.core.pending_msg_tail,
6638 pm);
6640 vl->pending_msg_head,
6641 vl->pending_msg_tail,
6642 pm);
6645}

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 6658 of file gnunet-service-transport.c.

6661{
6662 struct Neighbour *n;
6663 struct VirtualLink *vl;
6664 struct TransportClient *tc = cls;
6665 const struct GNUNET_MessageHeader *inbox =
6666 (const struct GNUNET_MessageHeader *) &cb[1];
6667 uint16_t isize = ntohs (inbox->size);
6668 const char *is = ((const char *) &cb[1]) + isize;
6669 size_t slen = strlen (is) + 1;
6670 char
6671 mbuf[slen + isize
6672 + sizeof(struct
6676
6677 /* 0-termination of 'is' was checked already in
6678 #check_communicator_backchannel() */
6680 "Preparing backchannel transmission to %s:%s of type %u and size %u\n",
6681 GNUNET_i2s (&cb->pid),
6682 is,
6683 ntohs (inbox->type),
6684 ntohs (inbox->size));
6685 /* encapsulate and encrypt message */
6686 be->header.type =
6688 be->header.size = htons (sizeof(mbuf));
6689 memcpy (&be[1], inbox, isize);
6690 memcpy (&mbuf[sizeof(struct TransportBackchannelEncapsulationMessage)
6691 + isize],
6692 is,
6693 strlen (is) + 1);
6694 // route_control_message_without_fc (&cb->pid, &be->header, RMO_DV_ALLOWED);
6695 vl = lookup_virtual_link (&cb->pid);
6696 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
6697 {
6699 }
6700 else
6701 {
6702 /* Use route via neighbour */
6703 n = lookup_neighbour (&cb->pid);
6704 if (NULL != n)
6706 n,
6707 &be->header,
6708 RMO_NONE);
6709 }
6711}

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 6722 of file gnunet-service-transport.c.

6724{
6725 struct TransportClient *tc = cls;
6726
6727 if (CT_COMMUNICATOR != tc->type)
6728 {
6729 GNUNET_break (0);
6730 return GNUNET_SYSERR;
6731 }
6733 return GNUNET_OK;
6734}

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 7058 of file gnunet-service-transport.c.

7059{
7060 struct AddressListEntry *ale = cls;
7061 const char *dash;
7062 char *address_uri;
7063 char *prefix;
7064 unsigned int add_success;
7065
7066 if ((GNUNET_YES == in_shutdown) || (NULL == pils))
7067 {
7068 ale->st = NULL;
7069 return;
7070 }
7071 if (NULL == GNUNET_PILS_get_identity (pils))
7072 {
7073 /* Do NOT poll at 1kHz: that burns CPU and keeps the scheduler task
7074 list non-empty, which prevents the service from ever exiting. */
7077 &store_pi,
7078 ale);
7079 return;
7080 }
7083 dash = strchr (ale->address, '-');
7084 GNUNET_assert (NULL != dash);
7085 dash++;
7086 GNUNET_asprintf (&address_uri,
7087 "%s://%s",
7088 prefix,
7089 dash);
7091 ale->st = NULL;
7093 "Storing our address `%s' in peerstore until %s!\n",
7094 ale->address,
7097 address_uri);
7098 /* NOTE: #GNUNET_HELLO_builder_add_address() answers GNUNET_NO for an
7099 address that is already in the builder, and on every call after the
7100 first one for a given address that is exactly what happens: nothing
7101 ever removes an address from @a GST_my_hello except
7102 #handle_del_address(). This function is the *refresh* cycle --
7103 #peerstore_store_own_cb() re-arms it at a quarter of the address'
7104 expiration -- so bailing out on GNUNET_NO here stopped the refresh
7105 after precisely one round. Our own HELLO then expired
7106 (#GNUNET_HELLO_ADDRESS_EXPIRATION, twelve hours) and was never
7107 renewed: peers can no longer learn how to reach us, and a link that
7108 drops after that never comes back. Only GNUNET_SYSERR -- a malformed
7109 URI, which retrying cannot fix -- is a reason not to store. */
7110 if (GNUNET_SYSERR == add_success)
7111 {
7113 "Not storing our address `%s': not a valid HELLO URI\n",
7114 address_uri);
7115 GNUNET_free (address_uri);
7116 return;
7117 }
7118 GNUNET_log ((GNUNET_NO == add_success) ?
7120 "%s our address `%s' in PEERSTORE\n",
7121 (GNUNET_NO == add_success) ? "Refreshing" : "Storing",
7122 address_uri);
7123 // FIXME hello_mono_time used here?? What about expiration in ale?
7124 pils_sign_address (ale,
7126 // TODO keep track of op and potentially cancel/clean
7127 GNUNET_free (address_uri);
7128}

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 6811 of file gnunet-service-transport.c.

6812{
6813 struct PilsAddressSignContext *pc = cls;
6814
6815 GNUNET_assert (NULL == pc->req);
6816 /* The store completed; the handle is dead and must not be cancelled
6817 later by #free_address_list_entry(). */
6818 pc->ale->shc = NULL;
6819 pc->ale->pc = NULL;
6820 if (GNUNET_OK != success)
6821 {
6823 "Failed to store our address `%s' with peerstore\n",
6824 pc->ale->address);
6825 if (NULL == pc->ale->st)
6826 {
6828 &store_pi,
6829 pc->ale);
6830 }
6831 }
6832 GNUNET_free (pc);
6833}

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 6840 of file gnunet-service-transport.c.

6843{
6844 struct PilsAddressSignContext *pc = cls;
6845 struct GNUNET_MQ_Envelope *env;
6846 const struct GNUNET_MessageHeader *msg;
6847
6848 pc->req->op = NULL;
6851 pc->req);
6852 GNUNET_free (pc->req);
6853 pc->req = NULL;
6856 pid,
6857 sig,
6858 pc->et);
6861 "store_pi 1\n");
6863 msg,
6864 shc_cont,
6865 pc);
6866 GNUNET_free (env);
6867}

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 6877 of file gnunet-service-transport.c.

6878{
6879 struct PilsAddressSignContext *pc = cls;
6880
6881 pc->ale->sc = NULL;
6882 if (GNUNET_YES != success)
6884 "Failed to store our own address `%s' in peerstore!\n",
6885 pc->ale->address);
6886 else
6888 "Successfully stored our own address `%s' in peerstore!\n",
6889 pc->ale->address);
6890 /* refresh period is 1/4 of expiration time, that should be plenty
6891 without being excessive. */
6892 if (NULL == pc->ale->st)
6893 {
6894 /* @e expiration comes straight off the wire in ADD_ADDRESS and is not
6895 validated anywhere, so a communicator reporting a very short (or
6896 zero) lifetime would have us re-sign the HELLO and store it again on
6897 the next scheduler pass, forever. That is an EdDSA signature and a
6898 PEERSTORE round trip per iteration. */
6899 pc->ale->st =
6903 GNUNET_TIME_relative_divide (pc->ale->expiration,
6904 4ULL)),
6905 &store_pi,
6906 pc->ale);
6907 }
6908
6909 /* Now we have to update our HELLO! */
6911 pc->req = GNUNET_new (struct PilsRequest);
6914 pc->req);
6915 pc->req->op = GNUNET_PILS_sign_hello (pils,
6917 pc->et,
6919 pc);
6920}

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 6931 of file gnunet-service-transport.c.

6934{
6935 char *sig_str;
6936 void *result;
6937 size_t result_size;
6938
6939 sig_str = NULL;
6940 (void) GNUNET_STRINGS_base64_encode (sig, sizeof(*sig), &sig_str);
6941 result_size =
6942 1 + GNUNET_asprintf (
6943 (char **) &result,
6944 "%s;%llu;%u;%s",
6945 sig_str,
6946 (unsigned long long) pc->et.abs_value_us,
6947 (unsigned int) pc->ale->nt,
6948 pc->ale->address);
6949 GNUNET_free (sig_str);
6950
6952 "Build our HELLO URI `%s'\n",
6953 (char*) result);
6954
6955 GNUNET_free (pc->ale->signed_address);
6956 pc->ale->signed_address = result;
6957 pc->ale->signed_address_len = result_size;
6959
6960 expiration = GNUNET_TIME_relative_to_absolute (pc->ale->expiration);
6962 "transport",
6963 pid,
6965 result,
6966 result_size,
6967 expiration,
6970 pc);
6971}

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 7010 of file gnunet-service-transport.c.

7013{
7014 struct SignedAddress sa;
7015 struct PilsAddressSignContext *pc;
7017 const struct GNUNET_PeerIdentity *my_identity;
7018
7019 sa.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_ADDRESS);
7020 sa.purpose.size = htonl (sizeof(sa));
7021 sa.mono_time = GNUNET_TIME_absolute_hton (mono_time);
7022 GNUNET_CRYPTO_hash (ale->address, strlen (ale->address), &sa.addr_hash);
7023 /* Only ever one chain per entry: the previous one (if any) still holds a
7024 pointer to @a ale and must be torn down first. */
7027 if ((NULL == my_identity) ||
7028 (GNUNET_OK != sign_by_my_identity (&sa.purpose, &sig)))
7029 {
7030 /* Nothing else re-arms @e st: #store_pi() cleared it before calling us,
7031 and the only other thing that sets it is #peerstore_store_own_cb(),
7032 which is on the far side of the store we just failed to start. So a
7033 single failure to sign used to end the refresh cycle for this address
7034 for the rest of the process' life. */
7035 if (NULL == ale->st)
7036 {
7039 &store_pi,
7040 ale);
7041 }
7042 return;
7043 }
7045 pc->ale = ale;
7046 pc->et = mono_time;
7047 ale->pc = pc;
7049}

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 7132 of file gnunet-service-transport.c.

7138{
7139 struct AddressListEntry *ale;
7140 char *address_without_port;
7141
7142 ale = GNUNET_malloc (sizeof(struct AddressListEntry) + slen);
7143 ale->tc = tc;
7144 ale->address = (const char *) &ale[1];
7145 ale->expiration = expiration;
7146 ale->aid = aid;
7147 ale->nt = nt;
7148 memcpy (&ale[1], address, slen);
7149 address_without_port = get_address_without_port (ale->address);
7151 "Is this %s a local address (%s)\n",
7152 (NULL == address_without_port) ? "<unparsable>"
7153 : address_without_port,
7154 ale->address);
7155 if ((NULL == address_without_port) ||
7156 (0 != strcmp ("127.0.0.1", address_without_port)))
7157 {
7158 if (NULL != ale->st)
7159 {
7161 }
7162 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
7163 }
7164 GNUNET_free (address_without_port);
7165
7166 return ale;
7167}

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 7171 of file gnunet-service-transport.c.

7172{
7173
7175 "Feeding addresses to PILS\n");
7176 pils_feed_task = NULL;
7177
7179 GST_my_hello);
7180}

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 7190 of file gnunet-service-transport.c.

7192{
7193 struct TransportClient *tc = cls;
7194 struct AddressListEntry *ale;
7195 size_t slen;
7196 char *address;
7197
7198 /* 0-termination of &aam[1] was checked in #check_add_address */
7200 "Communicator added address `%s'!\n",
7201 (const char *) &aam[1]);
7202 slen = ntohs (aam->header.size) - sizeof(*aam);
7203 address = GNUNET_malloc (slen);
7204 memcpy (address, &aam[1], slen);
7205 ale = create_address_entry (tc,
7207 ntohl (aam->nt),
7208 address,
7209 aam->aid,
7210 slen);
7211 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
7212 tc->details.communicator.addr_tail,
7213 ale);
7214 {
7215 for (struct AddressListEntry *iter = tc->details.communicator.addr_head;
7216 NULL != iter;
7217 iter = iter->next)
7218 {
7219 char *address_uri;
7220 const char *dash = strchr (iter->address, '-');
7221 char *prefix = GNUNET_HELLO_address_to_prefix (iter->address);
7222 GNUNET_assert (NULL != dash);
7223 dash++;
7224 GNUNET_asprintf (&address_uri,
7225 "%s://%s",
7226 prefix,
7227 dash);
7230 GNUNET_free (address_uri);
7231 }
7232 if (NULL != pils_feed_task)
7236 NULL);
7237 }
7240}

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 7250 of file gnunet-service-transport.c.

7252{
7253 struct TransportClient *tc = cls;
7254 struct AddressListEntry *alen;
7255
7256 if (CT_COMMUNICATOR != tc->type)
7257 {
7258 GNUNET_break (0);
7260 return;
7261 }
7262 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
7263 NULL != ale;
7264 ale = alen)
7265 {
7266 alen = ale->next;
7267 if (dam->aid != ale->aid)
7268 continue;
7269 GNUNET_assert (ale->tc == tc);
7271 "Communicator deleted address `%s'!\n",
7272 ale->address);
7274 ale->address);
7275 if (NULL != pils_feed_task)
7279 NULL);
7282 return;
7283 }
7285 "Communicator removed address we did not even have.\n");
7287 // GNUNET_SERVICE_client_drop (tc->client);
7288}

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 12223 of file gnunet-service-transport.c.

12224{
12226 { GNUNET_MQ_hd_var_size (fragment_box,
12229 cmc),
12230 GNUNET_MQ_hd_var_size (reliability_box,
12233 cmc),
12234 GNUNET_MQ_hd_var_size (reliability_ack,
12237 cmc),
12238 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
12241 cmc),
12242 GNUNET_MQ_hd_var_size (dv_learn,
12245 cmc),
12246 GNUNET_MQ_hd_var_size (dv_box,
12248 struct TransportDVBoxMessage,
12249 cmc),
12250 GNUNET_MQ_hd_var_size (flow_control,
12253 cmc),
12255 validation_challenge,
12258 cmc),
12260 validation_response,
12263 cmc),
12265 int ret;
12266 const struct GNUNET_MessageHeader *msg = cmc->mh;
12267
12269 "Handling message of type %u with %u bytes\n",
12270 (unsigned int) ntohs (msg->type),
12271 (unsigned int) ntohs (msg->size));
12272 /* @a handlers only covers the encapsulations *we* add; anything else is a
12273 payload for CORE and leaves through #handle_raw_message() below. So
12274 #GNUNET_NO is the common case here -- one per delivered CORE message --
12275 and not something to log about, which is why this is the "try" variant. */
12277 if (GNUNET_SYSERR == ret)
12278 {
12279 /* @a msg is the message a *remote peer* sent us: #handle_incoming_msg()
12280 points @e mh into the payload of the
12281 #GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG the communicator
12282 delivered, and every other caller unwraps it from remote traffic as
12283 well. So failing a check here is that peer's protocol violation, and
12284 it says nothing at all about the communicator that carried it.
12285
12286 Dropping the client therefore punishes the wrong party, and it
12287 punishes it hard: #GNUNET_SERVICE_client_drop() disconnects the
12288 communicator *process*, which takes down every queue it owns and thus
12289 every neighbour reachable through it. One malformed DV box on a
12290 shared UDP communicator disconnects every peer we have on it, CORE
12291 tears the sessions down, and the key exchanges that would rebuild
12292 them have to wait for the communicator to come back and revalidate.
12293 Since the offending bytes arrive from the network, any peer can do
12294 this to us at will, repeatedly.
12295
12296 Drop the message and keep the communicator: resume it exactly as the
12297 success path does, so it still gets its flow-control ACK and its
12298 GNUNET_SERVICE_client_continue(). */
12299 GNUNET_break_op (0);
12301 "# malformed messages discarded",
12302 1,
12303 GNUNET_NO);
12305 return;
12306 }
12307 if (GNUNET_NO == ret)
12308 {
12309 /* unencapsulated 'raw' message */
12310 handle_raw_message (cmc, msg);
12311 }
12312}

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 7310 of file gnunet-service-transport.c.

7311{
7312 struct CoreSentContext *ctx = cls;
7313 struct VirtualLink *vl = ctx->vl;
7314
7315 if (NULL == vl)
7316 {
7317 /* lost the link in the meantime, ignore */
7318 GNUNET_free (ctx);
7319 return;
7320 }
7323 vl->incoming_fc_window_size_ram -= ctx->size;
7324 vl->incoming_fc_window_size_used += ctx->isize;
7326 GNUNET_free (ctx);
7327}

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 7352 of file gnunet-service-transport.c.

7353{
7354 struct VirtualLink *vl = cls;
7355 struct CommunicatorMessageContext *cmc;
7356
7357 vl->core_fc_stall_task = NULL;
7359 "CORE did not acknowledge messages from %s within %s; "
7360 "releasing the flow control credit anyway\n",
7361 GNUNET_i2s (&vl->target),
7363 GNUNET_YES));
7365 "# CORE flow control stalls",
7366 1,
7367 GNUNET_NO);
7368 while (NULL != (cmc = vl->cmc_tail))
7369 release_stalled_cmc (vl, cmc);
7372}

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 7376 of file gnunet-service-transport.c.

7380{
7381 uint16_t size = ntohs (mh->size);
7382 int have_core;
7383
7384 if (vl->incoming_fc_window_size_ram > UINT_MAX - size)
7385 {
7387 "# CORE messages dropped (FC arithmetic overflow)",
7388 1,
7389 GNUNET_NO);
7391 "CORE messages of type %u with %u bytes dropped (FC arithmetic overflow)\n",
7392 (unsigned int) ntohs (mh->type),
7393 (unsigned int) ntohs (mh->size));
7394 if (GNUNET_YES == free_cmc)
7396 return;
7397 }
7399 {
7401 "# CORE messages dropped (FC window overflow)",
7402 1,
7403 GNUNET_NO);
7405 "CORE messages of type %u with %u bytes dropped (FC window overflow)\n",
7406 (unsigned int) ntohs (mh->type),
7407 (unsigned int) ntohs (mh->size));
7408 if (GNUNET_YES == free_cmc)
7410 return;
7411 }
7412
7413 /* Forward to all CORE clients */
7414 have_core = GNUNET_NO;
7415 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
7416 {
7417 struct GNUNET_MQ_Envelope *env;
7418 struct InboundMessage *im;
7419 struct CoreSentContext *ctx;
7420
7421 if (CT_CORE != tc->type)
7422 continue;
7425 ctx = GNUNET_new (struct CoreSentContext);
7426 ctx->vl = vl;
7427 ctx->size = size;
7428 ctx->isize = (GNUNET_NO == have_core) ? size : 0;
7429 have_core = GNUNET_YES;
7432 im->peer = cmc->im.sender;
7433 memcpy (&im[1], mh, size);
7434 GNUNET_MQ_send (tc->mq, env);
7436 }
7437 if (GNUNET_NO == have_core)
7438 {
7440 "Dropped message to CORE: no CORE client connected!\n");
7441 /* Nevertheless, count window as used, as it is from the
7442 perspective of the other peer! */
7444 /* TODO-M1 */
7446 "Dropped message of type %u with %u bytes to CORE: no CORE client connected!\n",
7447 (unsigned int) ntohs (mh->type),
7448 (unsigned int) ntohs (mh->size));
7449 if (GNUNET_YES == free_cmc)
7451 return;
7452 }
7454 "Delivered message from %s of type %u to CORE recv window %d\n",
7455 GNUNET_i2s (&cmc->im.sender),
7456 ntohs (mh->type),
7458 if (vl->core_recv_window > 0)
7459 {
7460 if (GNUNET_YES == free_cmc)
7462 return;
7463 }
7464 /* CORE ran out of receive window for *this* link. Withhold the
7465 per-message ACK -- that is what expresses the backpressure -- but
7466 resume the client immediately. The client is the communicator
7467 *process*, which carries every peer we reach through it, and a
7468 communicator we stop reading from does not stop receiving: it starts
7469 discarding, see "transport is too slow" in
7470 #GNUNET_TRANSPORT_communicator_receive(). Discarding is precisely
7471 what we cannot afford here, because among the messages dropped are
7472 the ones CORE needs in order to reopen the window it is waiting on. */
7473 if (GNUNET_YES == free_cmc)
7474 {
7475 resume_cmc_client (cmc);
7477 vl->cmc_count++;
7478 /* Nothing stalls the producer any more, so bound the list ourselves. */
7479 while (MAX_STALLED_CMCS < vl->cmc_count)
7481 /* ... and do not withhold the ACKs forever: see #core_fc_stalled(). */
7482 if (NULL == vl->core_fc_stall_task)
7486 vl);
7487 }
7488}

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 7500 of file gnunet-service-transport.c.

7501{
7502 struct CommunicatorMessageContext *cmc = cls;
7503 // struct CommunicatorMessageContext *cmc_copy =
7504 // GNUNET_new (struct CommunicatorMessageContext);
7505 struct GNUNET_MessageHeader *mh_copy;
7506 struct RingBufferEntry *rbe;
7507 struct VirtualLink *vl;
7508 uint16_t size = ntohs (mh->size);
7509
7511 "Handling raw message of type %u with %u bytes\n",
7512 (unsigned int) ntohs (mh->type),
7513 (unsigned int) ntohs (mh->size));
7514
7515 if ((size > UINT16_MAX - sizeof(struct InboundMessage)) ||
7516 (size < sizeof(struct GNUNET_MessageHeader)))
7517 {
7518 /* @a mh was unwrapped from what a *remote peer* sent us, so a bad size
7519 is that peer's protocol violation and says nothing about the
7520 communicator that carried it. Dropping the client here disconnects
7521 the communicator process and with it every neighbour reachable
7522 through it -- see the rationale in #demultiplex_with_cmc(). */
7523 GNUNET_break_op (0);
7525 "# CORE messages dropped (bad size)",
7526 1,
7527 GNUNET_NO);
7528 finish_cmc_handling (cmc);
7529 return;
7530 }
7531 vl = lookup_virtual_link (&cmc->im.sender);
7532 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
7533 {
7534 /* FIXME: sender is giving us messages for CORE but we don't have
7535 the link up yet! I *suspect* this can happen right now (i.e.
7536 sender has verified us, but we didn't verify sender), but if
7537 we pass this on, CORE would be confused (link down, messages
7538 arrive). We should investigate more if this happens often,
7539 or in a persistent manner, and possibly do "something" about
7540 it. Thus logging as error for now. */
7541
7542 mh_copy = GNUNET_malloc (size);
7543 rbe = GNUNET_new (struct RingBufferEntry);
7544 rbe->cmc = cmc;
7545 /*cmc_copy->tc = cmc->tc;
7546 cmc_copy->im = cmc->im;*/
7547 GNUNET_memcpy (mh_copy, mh, size);
7548
7549 rbe->mh = mh_copy;
7550
7552 {
7553 struct RingBufferEntry *rbe_old = ring_buffer[ring_buffer_head];
7554 GNUNET_free (rbe_old->cmc);
7555 GNUNET_free (rbe_old->mh);
7556 GNUNET_free (rbe_old);
7557 }
7558 ring_buffer[ring_buffer_head] = rbe;// cmc_copy;
7559 // cmc_copy->mh = (const struct GNUNET_MessageHeader *) mh_copy;
7560 cmc->mh = (const struct GNUNET_MessageHeader *) mh_copy;
7562 "Storing message for %s and type %u (%u) in ring buffer head %u is full %u\n",
7563 GNUNET_i2s (&cmc->im.sender),
7564 (unsigned int) ntohs (mh->type),
7565 (unsigned int) ntohs (mh_copy->type),
7569 {
7570 ring_buffer_head = 0;
7572 }
7573 else
7575
7577 "%u items stored in ring buffer\n",
7580
7581 /*GNUNET_break_op (0);
7582 GNUNET_STATISTICS_update (GST_stats,
7583 "# CORE messages dropped (virtual link still down)",
7584 1,
7585 GNUNET_NO);
7586
7587 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7588 "CORE messages of type %u with %u bytes dropped (virtual link still down)\n",
7589 (unsigned int) ntohs (mh->type),
7590 (unsigned int) ntohs (mh->size));
7591 finish_cmc_handling (cmc);*/
7592 /* @a cmc lives on in the ring buffer; #send_cmc_ack() and
7593 #resume_cmc_client() have recorded that they ran, so replaying it
7594 from #send_msg_from_cache() cannot ACK or continue a second time. */
7596 return;
7597 }
7599}

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 7610 of file gnunet-service-transport.c.

7611{
7612 uint16_t size = ntohs (fb->header.size);
7613 uint16_t bsize = size - sizeof(*fb);
7614
7615 (void) cls;
7616 if (0 == bsize)
7617 {
7618 GNUNET_break_op (0);
7619 return GNUNET_SYSERR;
7620 }
7621 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
7622 {
7623 GNUNET_break_op (0);
7624 return GNUNET_SYSERR;
7625 }
7626 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
7627 {
7628 GNUNET_break_op (0);
7629 return GNUNET_SYSERR;
7630 }
7631 return GNUNET_YES;
7632}

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 7641 of file gnunet-service-transport.c.

7642{
7643 struct AcknowledgementCummulator *ac = cls;
7644
7645 ac->task = NULL;
7646 GNUNET_assert (0 == ac->num_acks);
7648 GNUNET_YES ==
7650 GNUNET_free (ac);
7651}

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 7660 of file gnunet-service-transport.c.

7661{
7662 struct Neighbour *n;
7663 struct VirtualLink *vl;
7664 struct AcknowledgementCummulator *ac = cls;
7665 char buf[sizeof(struct TransportReliabilityAckMessage)
7666 + ac->num_acks
7668 struct TransportReliabilityAckMessage *ack =
7669 (struct TransportReliabilityAckMessage *) buf;
7671
7672 ac->task = NULL;
7674 "Sending ACK with %u components to %s\n",
7675 ac->num_acks,
7676 GNUNET_i2s (&ac->target));
7677 GNUNET_assert (0 < ac->num_acks);
7679 ack->header.size =
7680 htons (sizeof(*ack)
7681 + ac->num_acks * sizeof(struct TransportCummulativeAckPayloadP));
7682 ack->ack_counter = htonl (ac->ack_counter += ac->num_acks);
7683 ap = (struct TransportCummulativeAckPayloadP *) &ack[1];
7684 for (unsigned int i = 0; i < ac->num_acks; i++)
7685 {
7686 ap[i].ack_uuid = ac->ack_uuids[i].ack_uuid;
7689 }
7690 /*route_control_message_without_fc (
7691 &ac->target,
7692 &ack->header,
7693 RMO_DV_ALLOWED);*/
7694 vl = lookup_virtual_link (&ac->target);
7695 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
7696 {
7698 vl,
7699 &ack->header,
7701 }
7702 else
7703 {
7704 /* Use route via neighbour */
7705 n = lookup_neighbour (&ac->target);
7706 if (NULL != n)
7708 n,
7709 &ack->header,
7710 RMO_NONE);
7711 }
7712 ac->num_acks = 0;
7713 /* The deadline belonged to the batch we just sent. #cummulative_ack()
7714 only ever lowers it (GNUNET_TIME_absolute_min), so leaving it behind
7715 means every later ACK is armed with GNUNET_SCHEDULER_add_at() on a time
7716 that has already passed: the task fires on the next scheduler pass and
7717 the batching this whole structure exists for is gone for good -- one
7718 ACK message per received message, for the rest of the process' life. */
7722 ac);
7723}

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 7735 of file gnunet-service-transport.c.

7738{
7739 struct AcknowledgementCummulator *ac;
7740
7742 "Scheduling ACK %s for transmission to %s\n",
7743 GNUNET_uuid2s (&ack_uuid->value),
7744 GNUNET_i2s (pid));
7746 if (NULL == ac)
7747 {
7749 ac->target = *pid;
7750 ac->min_transmission_time = max_delay;
7754 &ac->target,
7755 ac,
7757 }
7758 else
7759 {
7760 if (MAX_CUMMULATIVE_ACKS == ac->num_acks)
7761 {
7762 /* Must run immediately, ack buffer full. Cancel the pending task
7763 FIRST: #transmit_cummulative_ack_cb() clears @e task without
7764 cancelling it, which would leave the old task armed with its
7765 handle lost. */
7767 ac->task = NULL;
7769 }
7773 }
7776 ac->ack_uuids[ac->num_acks].ack_uuid = *ack_uuid;
7777 ac->num_acks++;
7780 ac);
7781}

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 7811 of file gnunet-service-transport.c.

7812{
7813 struct FindByMessageUuidContext *fc = cls;
7814 struct ReassemblyContext *rc = value;
7815
7816 (void) key;
7817 if (0 == GNUNET_memcmp (&fc->message_uuid, &rc->msg_uuid))
7818 {
7819 fc->rc = rc;
7820 return GNUNET_NO;
7821 }
7822 return GNUNET_YES;
7823}

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 7834 of file gnunet-service-transport.c.

7835{
7836 struct CommunicatorMessageContext *cmc = cls;
7837 struct VirtualLink *vl;
7838 struct ReassemblyContext *rc;
7839 const struct GNUNET_MessageHeader *msg;
7840 uint16_t msize;
7841 uint16_t fsize;
7842 uint16_t frag_off;
7843 char *target;
7844 struct GNUNET_TIME_Relative cdelay;
7845 struct FindByMessageUuidContext fc;
7846
7847 vl = lookup_virtual_link (&cmc->im.sender);
7848 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
7849 {
7850 /* Entirely normal: fragments of a message that was already in flight
7851 keep arriving for a while after a link goes down, and a peer that has
7852 validated us may start sending before we have validated it. This used
7853 to call #GNUNET_SERVICE_client_drop(), which disconnects the
7854 communicator *process* -- every queue it owns, hence every neighbour
7855 reachable through it, hence every CORE session. On a peer with many
7856 neighbours a single ill-timed fragment therefore dropped all
7857 connections at once, and since the fragment comes from the network,
7858 any peer could cause it at will. Drop the fragment, keep the
7859 communicator; see #demultiplex_with_cmc() for the same reasoning. */
7861 "No virtual link for %s to handle fragment\n",
7862 GNUNET_i2s (&cmc->im.sender));
7864 "# fragments dropped (virtual link down)",
7865 1,
7866 GNUNET_NO);
7867 finish_cmc_handling (cmc);
7868 return;
7869 }
7870 if (NULL == vl->reassembly_map)
7871 {
7873 vl->reassembly_heap =
7878 vl);
7879 }
7880 msize = ntohs (fb->msg_size);
7881 fc.message_uuid = fb->msg_uuid;
7882 fc.rc = NULL;
7884 fb->msg_uuid.uuid,
7886 &fc);
7887 fsize = ntohs (fb->header.size) - sizeof(*fb);
7888 if (NULL == (rc = fc.rc))
7889 {
7890 /* Bound the RAM a single sender can pin here: @e msg_size is chosen by
7891 the peer, not by us. */
7894 {
7895 struct ReassemblyContext *drop;
7896
7898 GNUNET_assert (NULL != drop);
7900 "# Reassembly contexts dropped (limit reached)",
7901 1,
7902 GNUNET_NO);
7904 }
7905 rc = GNUNET_malloc (sizeof(*rc) + msize /* reassembly payload buffer */
7906 + (msize + 7) / 8 * sizeof(uint8_t) /* bitfield */);
7907 rc->msg_uuid = fb->msg_uuid;
7908 rc->virtual_link = vl;
7909 rc->msg_size = msize;
7910 rc->reassembly_timeout =
7914 rc,
7918 vl->reassembly_map,
7919 rc->msg_uuid.uuid,
7920 rc,
7922 target = (char *) &rc[1];
7923 rc->bitfield = (uint8_t *) (target + rc->msg_size);
7924 /* The bitfield loop below decrements @e msg_missing once per newly
7925 received byte, so this must always start at the full message size:
7926 initialising it to 0 for a single-fragment message made it
7927 underflow, and the message was then never delivered. */
7928 rc->msg_missing = rc->msg_size;
7930 "Received fragment with size %u at offset %u/%u %u bytes missing from %s for NEW message %"
7931 PRIu64 "\n",
7932 fsize,
7933 ntohs (fb->frag_off),
7934 msize,
7935 rc->msg_missing,
7936 GNUNET_i2s (&cmc->im.sender),
7937 fb->msg_uuid.uuid);
7938 }
7939 else
7940 {
7941 target = (char *) &rc[1];
7943 "Received fragment at offset %u/%u from %s for message %u\n",
7944 ntohs (fb->frag_off),
7945 msize,
7946 GNUNET_i2s (&cmc->im.sender),
7947 (unsigned int) fb->msg_uuid.uuid);
7948 }
7949 if (msize != rc->msg_size)
7950 {
7951 GNUNET_break (0);
7952 finish_cmc_handling (cmc);
7953 return;
7954 }
7955
7956 /* reassemble */
7957 if (0 == fsize)
7958 {
7959 GNUNET_break (0);
7960 finish_cmc_handling (cmc);
7961 return;
7962 }
7963 frag_off = ntohs (fb->frag_off);
7964 if (frag_off + fsize > msize)
7965 {
7966 /* Fragment (plus fragment size) exceeds message size! */
7967 GNUNET_break_op (0);
7968 finish_cmc_handling (cmc);
7969 return;
7970 }
7971 memcpy (&target[frag_off], &fb[1], fsize);
7972 /* update bitfield and msg_missing */
7973 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
7974 {
7975 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
7976 {
7977 rc->bitfield[i / 8] |= (1 << (i % 8));
7978 rc->msg_missing--;
7979 }
7980 }
7981
7982 /* Compute cumulative ACK */
7984 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->msg_missing / fsize);
7985 if (0 == rc->msg_missing)
7986 cdelay = GNUNET_TIME_UNIT_ZERO;
7987 cummulative_ack (&cmc->im.sender,
7988 &fb->ack_uuid,
7991 /* is reassembly complete? */
7992 if (0 != rc->msg_missing)
7993 {
7994 finish_cmc_handling (cmc);
7995 return;
7996 }
7997 /* reassembly is complete, verify result */
7998 msg = (const struct GNUNET_MessageHeader *) &rc[1];
7999 if (ntohs (msg->size) != rc->msg_size)
8000 {
8001 GNUNET_break (0);
8003 finish_cmc_handling (cmc);
8004 return;
8005 }
8006 /* successful reassembly */
8008 "Fragment reassembly complete for message %u\n",
8009 (unsigned int) fb->msg_uuid.uuid);
8010 /* FIXME: check that the resulting msg is NOT a
8011 DV Box or Reliability Box, as that is NOT allowed! */
8012 {
8013 uint16_t rsize = rc->msg_size;
8014 char rbuf[rsize] GNUNET_ALIGN;
8015
8016 /* Copy the reassembled message out and release `rc' BEFORE
8017 demultiplexing: the inner message may tear down the virtual link,
8018 which frees every reassembly context of that link -- the old code
8019 then used and freed `rc' a second time afterwards. */
8020 memcpy (rbuf, msg, rsize);
8022 cmc->mh = (const struct GNUNET_MessageHeader *) rbuf;
8024 }
8025}

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 8036 of file gnunet-service-transport.c.

8038{
8039 const struct GNUNET_MessageHeader *box = (const struct
8040 GNUNET_MessageHeader *) &rb[1];
8041 (void) cls;
8042
8044 "check_send_msg with size %u: inner msg type %u and size %u (%lu %lu)\n",
8045 ntohs (rb->header.size),
8046 ntohs (box->type),
8047 ntohs (box->size),
8048 sizeof (struct TransportReliabilityBoxMessage),
8049 sizeof (struct GNUNET_MessageHeader));
8051 return GNUNET_YES;
8052}

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 8063 of file gnunet-service-transport.c.

8065{
8066 struct CommunicatorMessageContext *cmc = cls;
8067 const struct GNUNET_MessageHeader *inbox =
8068 (const struct GNUNET_MessageHeader *) &rb[1];
8069 struct GNUNET_TIME_Relative rtt;
8070
8072 "Received reliability box from %s with UUID %s of type %u\n",
8073 GNUNET_i2s (&cmc->im.sender),
8075 (unsigned int) ntohs (inbox->type));
8076 rtt = GNUNET_TIME_UNIT_SECONDS; /* FIXME: should base this on "RTT", but we
8077 do not really have an RTT for the
8078 * incoming* queue (should we have
8079 the sender add it to the rb message?) */
8081 &cmc->im.sender,
8082 &rb->ack_uuid,
8083 (0 == ntohl (rb->ack_countdown))
8086 GNUNET_TIME_relative_divide (rtt, 8 /* FIXME: magic constant */)));
8087 /* continue with inner message */
8088 /* FIXME: check that inbox is NOT a DV Box, fragment or another
8089 reliability box (not allowed!) */
8090 cmc->mh = inbox;
8092}

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 8104 of file gnunet-service-transport.c.

8105{
8106 unsigned int sage;
8107
8108 if (age == pd->last_age)
8109 return; /* nothing to do */
8110 sage = GNUNET_MAX (pd->last_age, age - 2 * GOODPUT_AGING_SLOTS);
8111 for (unsigned int i = sage; i <= age - GOODPUT_AGING_SLOTS; i++)
8112 {
8113 struct TransmissionHistoryEntry *the = &pd->the[i % GOODPUT_AGING_SLOTS];
8114
8115 the->bytes_sent = 0;
8116 the->bytes_received = 0;
8117 }
8118 pd->last_age = age;
8119}

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 8131 of file gnunet-service-transport.c.

8134{
8135 uint64_t nval = rtt.rel_value_us;
8136 uint64_t oval = pd->aged_rtt.rel_value_us;
8137 unsigned int age = get_age ();
8138 struct TransmissionHistoryEntry *the = &pd->the[age % GOODPUT_AGING_SLOTS];
8139
8140 if (oval == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
8141 pd->aged_rtt = rtt;
8142 else
8143 pd->aged_rtt.rel_value_us = (nval + 7 * oval) / 8;
8144 update_pd_age (pd, age);
8145 the->bytes_received += bytes_transmitted_ok;
8146}

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 8157 of file gnunet-service-transport.c.

8160{
8161 update_performance_data (&q->pd, rtt, bytes_transmitted_ok);
8162}

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 8173 of file gnunet-service-transport.c.

8176{
8177 update_performance_data (&dvh->pd, rtt, bytes_transmitted_ok);
8178}

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 8189 of file gnunet-service-transport.c.

8190{
8191 struct PendingMessage *pos;
8192
8194 "Complete transmission of message %" PRIu64 " %u\n",
8195 pm->logging_uuid,
8196 pm->pmt);
8197 switch (pm->pmt)
8198 {
8199 case PMT_CORE:
8201 /* Full message sent, we are done */
8203 return;
8204
8205 case PMT_FRAGMENT_BOX:
8206 /* Fragment sent over reliable channel */
8207 pos = pm->frag_parent;
8208 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
8211 "pos frag_off %lu pos bytes_msg %lu pmt %u parent %u\n",
8212 (unsigned long) pos->frag_off,
8213 (unsigned long) pos->bytes_msg,
8214 pos->pmt,
8215 NULL == pos->frag_parent ? 1 : 0);
8216 /* check if subtree is done */
8217 while ((NULL == pos->head_frag) && (pos->frag_off == (pos->bytes_msg
8218 - sizeof(struct
8220 &&
8221 (NULL != pos->frag_parent))
8222 {
8223 pm = pos;
8224 pos = pm->frag_parent;
8225 if ((NULL == pos) && (PMT_DV_BOX == pm->pmt))
8226 {
8228 return;
8229 }
8230 else if (PMT_DV_BOX == pm->pmt)
8231 {
8233 return;
8234 }
8235 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
8237 }
8238
8239 /* Was this the last applicable fragment?
8240
8241 NOTE: @a pos may be a DV box here, and then it is NOT the message the
8242 client is waiting for -- its @e frag_parent is, and that parent's
8243 @e bpm points at @a pos. Answering the client directly (and thereby
8244 releasing @a pos through #free_pending_message()) left @e bpm of a
8245 message that is still queued pointing at freed memory, which
8246 #transmit_on_queue() reads and may free a second time. Hand it to
8247 ourselves instead: the #PMT_DV_BOX case below clears @e bpm and
8248 answers for the parent, and for every other @e pmt it does exactly
8249 what the direct call did. */
8250 if ((NULL == pos->head_frag) && (NULL == pos->frag_parent || PMT_DV_BOX ==
8251 pos->pmt) &&
8252 (pos->frag_off == pos->bytes_msg))
8254 return;
8255
8256 case PMT_DV_BOX:
8258 "Completed transmission of message %" PRIu64 " (DV Box)\n",
8259 pm->logging_uuid);
8260 if (NULL != pm->frag_parent)
8261 {
8262 pos = pm->frag_parent;
8264 pos->bpm = NULL;
8266 }
8267 else
8269 return;
8270 }
8271}

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 8282 of file gnunet-service-transport.c.

8284{
8285 struct GNUNET_TIME_Relative delay;
8286 struct PendingMessage *pm = pa->pm;
8287
8289 delay = GNUNET_TIME_relative_subtract (delay, ack_delay);
8290 if (NULL != pa->queue && 1 == pa->num_send)
8292 if (NULL != pa->dvh && 1 == pa->num_send)
8293 update_dvh_performance (pa->dvh, delay, pa->message_size);
8294 /* Retire @a pa BEFORE handing its message on. completed_pending_message()
8295 ends in free_pending_message() for anything it finishes, and that now
8296 releases every acknowledgement still attached to the message -- this one
8297 included. Freeing it afterwards is a double free, and it aborts on the
8298 GNUNET_assert() over multiuuidmap_remove() in
8299 free_pending_acknowledgement(), the map entry having gone with the first
8300 release. Nothing below needs @a pa, only its message. */
8302 if (NULL != pm)
8304}

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 8315 of file gnunet-service-transport.c.

8317{
8318 unsigned int n_acks;
8319
8320 (void) cls;
8321 n_acks = (ntohs (ra->header.size) - sizeof(*ra))
8322 / sizeof(struct TransportCummulativeAckPayloadP);
8323 if (0 == n_acks)
8324 {
8325 GNUNET_break_op (0);
8326 return GNUNET_SYSERR;
8327 }
8328 if ((ntohs (ra->header.size) - sizeof(*ra)) !=
8329 n_acks * sizeof(struct TransportCummulativeAckPayloadP))
8330 {
8331 GNUNET_break_op (0);
8332 return GNUNET_SYSERR;
8333 }
8334 return GNUNET_OK;
8335}

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 8346 of file gnunet-service-transport.c.

8348{
8349 struct CommunicatorMessageContext *cmc = cls;
8350 const struct TransportCummulativeAckPayloadP *ack;
8351 unsigned int n_acks;
8352 uint32_t ack_counter;
8353
8354 n_acks = (ntohs (ra->header.size) - sizeof(*ra))
8355 / sizeof(struct TransportCummulativeAckPayloadP);
8356 ack = (const struct TransportCummulativeAckPayloadP *) &ra[1];
8357 for (unsigned int i = 0; i < n_acks; i++)
8358 {
8359 struct PendingAcknowledgement *pa =
8361 if (NULL == pa)
8362 {
8364 "Received ACK from %s with UUID %s which is unknown to us!\n",
8365 GNUNET_i2s (&cmc->im.sender),
8366 GNUNET_uuid2s (&ack[i].ack_uuid.value));
8368 GST_stats,
8369 "# FRAGMENT_ACKS dropped, no matching pending message",
8370 1,
8371 GNUNET_NO);
8372 continue;
8373 }
8375 "Received ACK from %s with UUID %s\n",
8376 GNUNET_i2s (&cmc->im.sender),
8377 GNUNET_uuid2s (&ack[i].ack_uuid.value));
8378 handle_acknowledged (pa, GNUNET_TIME_relative_ntoh (ack[i].ack_delay));
8379 }
8380
8381 ack_counter = ntohl (ra->ack_counter);
8382 (void) ack_counter; /* silence compiler warning for now */
8383 // FIXME-OPTIMIZE: track ACK losses based on ack_counter somewhere!
8384 // (DV and/or Neighbour?)
8385 finish_cmc_handling (cmc);
8386}

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 8397 of file gnunet-service-transport.c.

8400{
8401 uint16_t size = ntohs (be->header.size) - sizeof(*be);
8402 const struct GNUNET_MessageHeader *inbox =
8403 (const struct GNUNET_MessageHeader *) &be[1];
8404 const char *is;
8405 uint16_t isize;
8406
8407 (void) cls;
8408 /* MUST bound the buffer before reading @a inbox: the size check below
8409 dereferences it, and a message consisting of nothing but the header
8410 leaves no bytes to read. */
8411 if (size <= sizeof(struct GNUNET_MessageHeader))
8412 {
8413 GNUNET_break_op (0);
8414 return GNUNET_SYSERR;
8415 }
8416 if (ntohs (inbox->size) >= size)
8417 {
8418 GNUNET_break_op (0);
8419 return GNUNET_SYSERR;
8420 }
8421 isize = ntohs (inbox->size);
8422 is = ((const char *) inbox) + isize;
8423 size -= isize;
8424 if ('\0' != is[size - 1])
8425 {
8426 GNUNET_break_op (0);
8427 return GNUNET_SYSERR;
8428 }
8429 return GNUNET_YES;
8430}

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 8442 of file gnunet-service-transport.c.

8445{
8446 const struct GNUNET_PeerIdentity *my_identity;
8447 struct CommunicatorMessageContext *cmc = cls;
8449 struct GNUNET_MQ_Envelope *env;
8450 struct TransportClient *tc;
8451 const struct GNUNET_MessageHeader *inbox =
8452 (const struct GNUNET_MessageHeader *) &be[1];
8453 uint16_t isize = ntohs (inbox->size);
8454 const char *target_communicator = ((const char *) inbox) + isize;
8455 char *sender;
8456 char *self;
8457
8460
8461 GNUNET_asprintf (&sender,
8462 "%s",
8463 GNUNET_i2s (&cmc->im.sender));
8464 GNUNET_asprintf (&self,
8465 "%s",
8467
8468 /* Find client providing this communicator */
8469 for (tc = clients_head; NULL != tc; tc = tc->next)
8470 if ((CT_COMMUNICATOR == tc->type) &&
8471 (NULL != tc->details.communicator.address_prefix) &&
8472 (0 ==
8473 strcmp (tc->details.communicator.address_prefix, target_communicator)))
8474 break;
8475 if (NULL == tc)
8476 {
8477 char *stastr;
8478
8480 &stastr,
8481 "# Backchannel message dropped: target communicator `%s' unknown",
8482 target_communicator);
8484 GNUNET_free (stastr);
8485 GNUNET_free (sender);
8486 GNUNET_free (self);
8487 finish_cmc_handling (cmc);
8488 return;
8489 }
8490 /* Finally, deliver backchannel message to communicator */
8492 "Delivering backchannel message from %s to %s of type %u to %s\n",
8493 sender,
8494 self,
8495 ntohs (inbox->type),
8496 target_communicator);
8498 cbi,
8499 isize,
8501 cbi->pid = cmc->im.sender;
8502 memcpy (&cbi[1], inbox, isize);
8503 GNUNET_MQ_send (tc->mq, env);
8504 GNUNET_free (sender);
8505 GNUNET_free (self);
8506 finish_cmc_handling (cmc);
8507}

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 8520 of file gnunet-service-transport.c.

8521{
8522 struct DistanceVector *dv = cls;
8523 struct DistanceVectorHop *pos;
8524 struct GNUNET_TIME_Absolute next;
8525
8526 dv->timeout_task = NULL;
8527 /* @e dv_head is NOT sorted by @e timeout: learn_dv_path() inserts a new
8528 hop at the head, and moves a rediscovered one back to the head, so the
8529 list runs newest (i.e. latest deadline) first. Stopping at the first
8530 live entry therefore inspected exactly the youngest hop and re-armed
8531 for *its* deadline, which is the last one of the whole set: expired
8532 hops behind it were never collected, and check_vl_transmission() kept
8533 skipping them one by one for as long as the route lived. Sweep all of
8534 them and come back for the earliest survivor. */
8536 pos = dv->dv_head;
8537 while (NULL != pos)
8538 {
8539 struct DistanceVectorHop *next_pos = pos->next_dv;
8540
8541 GNUNET_assert (dv == pos->dv);
8544 else
8545 next = GNUNET_TIME_absolute_min (next, pos->timeout);
8546 pos = next_pos;
8547 }
8548 if (NULL == dv->dv_head)
8549 {
8550 free_dv_route (dv);
8551 return;
8552 }
8553 dv->timeout_task =
8555}

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 8559 of file gnunet-service-transport.c.

8560{
8561
8562 const struct GNUNET_PeerIdentity target = vl->target;
8563
8564
8566 {
8567 struct RingBufferEntry *ring_buffer_copy[RING_BUFFER_SIZE];
8568 unsigned int tail = GNUNET_YES == is_ring_buffer_full ? ring_buffer_head :
8569 0;
8570 unsigned int head = GNUNET_YES == is_ring_buffer_full ? RING_BUFFER_SIZE :
8573 struct CommunicatorMessageContext *cmc;
8574 struct RingBufferEntry *rbe;
8575 struct GNUNET_MessageHeader *mh;
8576
8578 "Sending from ring buffer, which has %u items\n",
8579 head);
8580
8581 ring_buffer_head = 0;
8582 for (unsigned int i = 0; i < head; i++)
8583 {
8584 rbe = ring_buffer[(i + tail) % RING_BUFFER_SIZE];
8585 cmc = rbe->cmc;
8586 mh = rbe->mh;
8587
8588 im = cmc->im;
8589 // mh = cmc->mh;
8591 "Sending message of type %u to ring buffer target %s using vl target %s index %u\n",
8592 mh->type,
8593 GNUNET_i2s (&im.sender),
8594 GNUNET_i2s2 (&target),
8595 (i + tail) % RING_BUFFER_SIZE);
8596 if (0 == GNUNET_memcmp (&target, &im.sender))
8597 {
8599 "Finish handling message of type %u and size %u\n",
8600 (unsigned int) ntohs (mh->type),
8601 (unsigned int) ntohs (mh->size));
8603 GNUNET_free (mh);
8604 GNUNET_free (rbe->cmc);
8605 GNUNET_free (rbe);
8606 }
8607 else
8608 {
8609 ring_buffer_copy[ring_buffer_head] = rbe;
8611 }
8612 }
8613
8616 {
8618 }
8619
8620 for (unsigned int i = 0; i < ring_buffer_head; i++)
8621 {
8622 ring_buffer[i] = ring_buffer_copy[i];
8624 "ring_buffer[i]->mh->type for i %u %u\n",
8625 i,
8626 ring_buffer[i]->mh->type);
8627 }
8628 /* MUST clear the consumed slots, we freed those entries above */
8629 for (unsigned int i = ring_buffer_head; i < RING_BUFFER_SIZE; i++)
8630 ring_buffer[i] = NULL;
8631
8633 "%u items still in ring buffer\n",
8635 /* If we consumed nothing, compaction rewrote the buffer in place and
8636 left the write index one past the end. #handle_raw_message() would
8637 then read ring_buffer[RING_BUFFER_SIZE] and free whatever that is.
8638 The buffer is still full, and compaction moved the oldest entry to
8639 slot 0, so that is where the next write belongs. */
8641 ring_buffer_head = 0;
8642 }
8643
8645 {
8646 struct PendingMessage *ring_buffer_dv_copy[RING_BUFFER_SIZE];
8647 struct PendingMessage *pm;
8648 unsigned int tail = GNUNET_YES == is_ring_buffer_dv_full ?
8650 0;
8651 unsigned int head = GNUNET_YES == is_ring_buffer_dv_full ?
8654
8656 "Sending from ring buffer dv, which has %u items\n",
8657 head);
8658
8660 for (unsigned int i = 0; i < head; i++)
8661 {
8662 pm = ring_buffer_dv[(i + tail) % RING_BUFFER_SIZE];
8663
8665 "Sending to ring buffer target %s using vl target %s\n",
8666 GNUNET_i2s (&pm->target),
8667 GNUNET_i2s2 (&target));
8668 if (0 == GNUNET_memcmp (&target, &pm->target))
8669 {
8671 "Adding PendingMessage to vl, checking transmission.\n");
8672 pm->vl = vl;
8676 pm);
8677
8679 }
8680 else
8681 {
8682 ring_buffer_dv_copy[ring_buffer_dv_head] = pm;
8684 }
8685 }
8686
8688 {
8690 }
8691
8692 for (unsigned int i = 0; i < ring_buffer_dv_head; i++)
8693 ring_buffer_dv[i] = ring_buffer_dv_copy[i];
8694 /* MUST clear the consumed slots: entries we handed to a VirtualLink are
8695 now owned by that link, and #forward_dv_box() would GNUNET_free() them
8696 again once the ring buffer wraps around. */
8697 for (unsigned int i = ring_buffer_dv_head; i < RING_BUFFER_SIZE; i++)
8698 ring_buffer_dv[i] = NULL;
8699
8701 "%u items still in ring buffer dv.\n",
8703 /* Same one-past-the-end hazard as above: #forward_dv_box() reads
8704 ring_buffer_dv[ring_buffer_dv_head] and GNUNET_free()s it. */
8707 }
8708}

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 8719 of file gnunet-service-transport.c.

8720{
8721 struct DistanceVector *dv = hop->dv;
8722 struct VirtualLink *vl;
8723
8724 vl = lookup_virtual_link (&dv->target);
8725 if (NULL == vl)
8726 {
8727
8728 vl = GNUNET_new (struct VirtualLink);
8730 "Creating new virtual link %p to %s using DV!\n",
8731 vl,
8732 GNUNET_i2s (&dv->target));
8733 vl->burst_addr = NULL;
8734 vl->confirmed = GNUNET_YES;
8735 vl->message_uuid_ctr =
8736 GNUNET_CRYPTO_random_u64 (UINT64_MAX);
8737 vl->target = dv->target;
8741 /* What the peer will grant us in its very first FLOW_CONTROL anyway
8742 (@e incoming_fc_window_size plus what we have sent, i.e. nothing).
8743 Starting at zero instead means a link that is up, validated and
8744 working carries nothing at all until an FC round trip completes --
8745 and if the peer cannot answer, not ever. */
8749 links,
8750 &vl->target,
8751 vl,
8753 vl->dv = dv;
8754 dv->vl = vl;
8755 vl->visibility_task =
8758 /* We lacked a confirmed connection to the target
8759 before, so tell CORE about it (finally!) */
8762 }
8763 else
8764 {
8765 /* Link was already up, remember dv is also now available and we are done */
8766 vl->dv = dv;
8767 dv->vl = vl;
8768 if (GNUNET_NO == vl->confirmed)
8769 {
8770 vl->confirmed = GNUNET_YES;
8771 vl->visibility_task =
8774 /* We lacked a confirmed connection to the target
8775 before, so tell CORE about it (finally!) */
8778 }
8779 else
8781 "Virtual link to %s could now also use DV!\n",
8782 GNUNET_i2s (&dv->target));
8783 }
8784}

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 8813 of file gnunet-service-transport.c.

8817{
8818 const struct GNUNET_PeerIdentity *my_identity;
8819 struct DistanceVectorHop *hop;
8820 struct DistanceVector *dv;
8821 struct Neighbour *next_hop;
8822 unsigned int shorter_distance;
8823
8824 if (path_len < 3)
8825 {
8826 /* what a boring path! not allowed! */
8827 GNUNET_break (0);
8828 return GNUNET_SYSERR;
8829 }
8830
8833
8834 GNUNET_assert (0 == GNUNET_memcmp (my_identity, &path[0]));
8835 next_hop = lookup_neighbour (&path[1]);
8836 if (NULL == next_hop)
8837 {
8838 /* next hop must be a neighbour, otherwise this whole thing is useless! */
8839 GNUNET_break (0);
8840 return GNUNET_SYSERR;
8841 }
8842 for (unsigned int i = 2; i < path_len; i++)
8843 {
8844 struct Neighbour *n = lookup_neighbour (&path[i]);
8845 struct GNUNET_TIME_Absolute q_timeout;
8846
8847 if (NULL != n)
8848 {
8849 q_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
8850 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
8851 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
8853 "remaining %lu to %s\n",
8854 (unsigned long) GNUNET_TIME_absolute_get_remaining (q_timeout)
8855 .rel_value_us,
8856 GNUNET_i2s (&n->pid));
8857 if (0 != GNUNET_TIME_absolute_get_remaining (q_timeout).rel_value_us)
8858 {
8859 /* Useless path: we have a direct active connection to some hop
8860 in the middle of the path, so this one is not even
8861 terribly useful for redundancy */
8863 "Path of %u hops useless: directly link to hop %u (%s)\n",
8864 path_len,
8865 i,
8866 GNUNET_i2s (&path[i]));
8868 "# Useless DV path ignored: hop is neighbour",
8869 1,
8870 GNUNET_NO);
8871 return GNUNET_SYSERR;
8872 }
8873 }
8874 }
8875 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
8876 if (NULL == dv)
8877 {
8878 dv = GNUNET_new (struct DistanceVector);
8879 dv->target = path[path_len - 1];
8882 dv);
8885 dv_routes,
8886 &dv->target,
8887 dv,
8889 }
8890 /* Check if we have this path already! */
8891 shorter_distance = 0;
8892 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
8893 pos = pos->next_dv)
8894 {
8895 if (pos->distance < path_len - 3)
8896 shorter_distance++;
8897 /* Note that the distances in 'pos' excludes us (path[0]),
8898 the next_hop (path[1]) and the target so we need to subtract three
8899 and check next_hop explicitly */
8900 if ((pos->distance == path_len - 3) && (pos->next_hop == next_hop))
8901 {
8902 int match = GNUNET_YES;
8903
8904 for (unsigned int i = 0; i < pos->distance; i++)
8905 {
8906 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
8907 {
8908 match = GNUNET_NO;
8909 break;
8910 }
8911 }
8912 if (GNUNET_YES == match)
8913 {
8914 struct GNUNET_TIME_Relative last_timeout;
8915
8916 /* Re-discovered known path, update timeout */
8918 "# Known DV path refreshed",
8919 1,
8920 GNUNET_NO);
8921 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
8922 pos->timeout =
8924 pos->path_valid_until =
8925 GNUNET_TIME_absolute_max (pos->path_valid_until, path_valid_until);
8926 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
8927 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
8928 if (0 <
8931 if (last_timeout.rel_value_us <
8934 .rel_value_us)
8935 {
8936 /* Some peer send DV learn messages too often, we are learning
8937 the same path faster than it would be useful; do not forward! */
8939 "Rediscovered path too quickly, not forwarding further\n")
8940 ;
8941 return GNUNET_NO;
8942 }
8944 "Refreshed known path to %s valid until %s, forwarding further\n",
8945 GNUNET_i2s (&dv->target),
8947 pos->path_valid_until));
8948 return GNUNET_YES;
8949 }
8950 }
8951 }
8952 /* Count how many shorter paths we have (incl. direct
8953 neighbours) before simply giving up on this one! */
8954 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
8955 {
8956 /* We have a shorter path already! */
8958 "Have many shorter DV paths %s, not forwarding further\n",
8959 GNUNET_i2s (&dv->target));
8960 return GNUNET_NO;
8961 }
8962 /* create new DV path entry */
8964 "Discovered new DV path to %s valid until %s\n",
8965 GNUNET_i2s (&dv->target),
8966 GNUNET_STRINGS_absolute_time_to_string (path_valid_until));
8967 hop = GNUNET_malloc (sizeof(struct DistanceVectorHop)
8968 + sizeof(struct GNUNET_PeerIdentity) * (path_len - 3));
8969 hop->next_hop = next_hop;
8970 hop->dv = dv;
8971 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
8972 memcpy (&hop[1],
8973 &path[2],
8974 sizeof(struct GNUNET_PeerIdentity) * (path_len - 3));
8976 hop->path_valid_until = path_valid_until;
8977 hop->distance = path_len - 3;
8978 hop->pd.aged_rtt = network_latency;
8979 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
8981 next_hop->dv_head,
8982 next_hop->dv_tail,
8983 hop);
8984 if (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
8986 return GNUNET_YES;
8987}

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 8998 of file gnunet-service-transport.c.

8999{
9000 const struct GNUNET_PeerIdentity *my_identity;
9001 uint16_t size = ntohs (dvl->header.size);
9002 uint16_t num_hops = ntohs (dvl->num_hops);
9003 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
9004
9005 (void) cls;
9006 if (size != sizeof(*dvl) + num_hops * sizeof(struct DVPathEntryP))
9007 {
9008 GNUNET_break_op (0);
9009 return GNUNET_SYSERR;
9010 }
9011 if (num_hops > MAX_DV_HOPS_ALLOWED)
9012 {
9013 GNUNET_break_op (0);
9014 return GNUNET_SYSERR;
9015 }
9016
9019
9020 for (unsigned int i = 0; i < num_hops; i++)
9021 {
9022 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
9023 {
9024 GNUNET_break_op (0);
9025 return GNUNET_SYSERR;
9026 }
9027 if (0 == GNUNET_memcmp (my_identity, &hops[i].hop))
9028 {
9029 GNUNET_break_op (0);
9030 return GNUNET_SYSERR;
9031 }
9032 }
9033 return GNUNET_YES;
9034}

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 9049 of file gnunet-service-transport.c.

9055{
9056 struct DVPathEntryP *dhops;
9057 size_t fwd_size = sizeof(struct TransportDVLearnMessage)
9058 + (nhops + 1) * sizeof(struct DVPathEntryP);
9059 /* Signing is synchronous and the routing calls below copy the message,
9060 so this never outlives the frame. Keeping it on the stack matters:
9061 a hub forwards a DV learn to every eligible neighbour, so this is one
9062 of the hottest allocation sites in the service. Size it by the hop
9063 limit rather than by @a nhops -- @a nhops is only asserted to be below
9064 that limit further down, and a VLA is sized before we get there. */
9065 char fwd_buf[sizeof(struct TransportDVLearnMessage)
9066 + (MAX_DV_HOPS_ALLOWED + 1)
9067 * sizeof(struct DVPathEntryP)] GNUNET_ALIGN;
9068 struct TransportDVLearnMessage *fwd
9069 = (struct TransportDVLearnMessage *) fwd_buf;
9070 struct GNUNET_TIME_Relative nnd;
9071 const struct GNUNET_PeerIdentity *my_identity;
9072 struct VirtualLink *vl;
9073 struct Neighbour *n;
9074
9076 memset (fwd_buf, 0, fwd_size);
9077
9078 /* compute message for forwarding */
9080 "Forwarding DV learn message originating from %s to %s\n",
9081 GNUNET_i2s (&msg->initiator),
9082 GNUNET_i2s2 (next_hop));
9085 fwd->header.size = htons (sizeof(struct TransportDVLearnMessage)
9086 + (nhops + 1) * sizeof(struct DVPathEntryP));
9087 fwd->num_hops = htons (nhops + 1);
9088 fwd->bidirectional = htons (bi_history);
9091 msg->non_network_delay));
9093 fwd->init_sig = msg->init_sig;
9094 fwd->initiator = msg->initiator;
9095 fwd->challenge = msg->challenge;
9096 fwd->monotonic_time = msg->monotonic_time;
9097
9100
9101 dhops = (struct DVPathEntryP *) &fwd[1];
9102 GNUNET_memcpy (dhops, hops, sizeof(struct DVPathEntryP) * nhops);
9103 dhops[nhops].hop = *my_identity;
9104 {
9105 struct DvHopPS dhp = {
9107 .purpose.size = htonl (sizeof(dhp)),
9108 .pred = (0 == nhops) ? msg->initiator : dhops[nhops - 1].hop,
9109 .succ = *next_hop,
9111 };
9112
9114 &dhops[nhops].hop_sig))
9115 return; /* nobody would accept the path without our hop signature */
9116 }
9117 vl = lookup_virtual_link (next_hop);
9118 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
9119 {
9121 &fwd->header,
9123 return;
9124 }
9125 /* Use route via neighbour */
9126 n = lookup_neighbour (next_hop);
9127 if (NULL != n)
9129 &fwd->header,
9131}

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 9144 of file gnunet-service-transport.c.

9149{
9150 struct DvInitPS ip = { .purpose.purpose = htonl (
9152 .purpose.size = htonl (sizeof(ip)),
9153 .monotonic_time = sender_monotonic_time,
9154 .challenge = *challenge };
9155
9156 if (
9157 GNUNET_OK !=
9159 &ip,
9160 init_sig,
9161 &init->public_key))
9162 {
9163 GNUNET_break_op (0);
9164 return GNUNET_SYSERR;
9165 }
9166 return GNUNET_OK;
9167}

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 9226 of file gnunet-service-transport.c.

9229{
9230 struct NeighbourSelectionContext *nsc = cls;
9231
9232 (void) value;
9233 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
9234 return GNUNET_YES; /* skip initiator */
9235 for (unsigned int i = 0; i < nsc->nhops; i++)
9236 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
9237 return GNUNET_YES;
9238 /* skip peers on path */
9239 nsc->num_eligible++;
9240 return GNUNET_YES;
9241}

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 9255 of file gnunet-service-transport.c.

9258{
9259 struct NeighbourSelectionContext *nsc = cls;
9260
9262 "transmission %s\n",
9263 GNUNET_i2s (pid));
9264 (void) value;
9265 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
9266 return GNUNET_YES; /* skip initiator */
9267 for (unsigned int i = 0; i < nsc->nhops; i++)
9268 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
9269 return GNUNET_YES;
9270 /* skip peers on path */
9271 for (unsigned int i = 0; i < nsc->num_selections; i++)
9272 {
9273 if (nsc->selections[i] == nsc->num_eligible)
9274 {
9275 forward_dv_learn (pid,
9276 nsc->dvl,
9277 nsc->bi_history,
9278 nsc->nhops,
9279 nsc->hops,
9280 nsc->in_time);
9281 break;
9282 }
9283 }
9284 nsc->num_eligible++;
9285 return GNUNET_YES;
9286}

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 9333 of file gnunet-service-transport.c.

9336{
9337 double target_total = 50.0; /* FIXME: use LOG(NSE)? */
9338 double eligible_ratio =
9339 ((double) eligible_count) / ((double) neighbour_count);
9340 double boost_factor = eligible_ratio * eligible_ratio;
9341 unsigned int rnd;
9342 double left;
9343
9344 if (hops_taken >= 64)
9345 {
9346 GNUNET_break (0);
9347 return 0; /* precaution given bitshift below */
9348 }
9349 for (unsigned int i = 1; i < hops_taken; i++)
9350 {
9351 /* For each hop, subtract the expected number of targets
9352 reached at distance d (so what remains divided by 2^d) */
9353 target_total -= (target_total * boost_factor / (1LLU << i));
9354 }
9355 {
9356 double degree = target_total * boost_factor / (1LLU << hops_taken);
9357
9358 rnd = (unsigned int) floor (degree);
9359 /* round up or down probabilistically depending on how close we were
9360 when floor()ing to rnd. NOTE: this must be the fractional part of
9361 @e degree; using `target_total - rnd' here made the condition below
9362 true essentially always, so we always rounded up. */
9363 left = degree - (double) rnd;
9364 }
9365 if (UINT32_MAX * left >
9366 GNUNET_CRYPTO_random_u64 (UINT32_MAX))
9367 rnd++; /* round up */
9369 "Forwarding DV learn message of %u hops %u(/%u/%u) times\n",
9370 hops_taken,
9371 rnd,
9372 eligible_count,
9373 neighbour_count);
9374 return rnd;
9375}

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 9385 of file gnunet-service-transport.c.

9386{
9387 struct Neighbour *n = cls;
9388
9389 n->sc = NULL;
9390 if (GNUNET_YES != success)
9392 "Failed to store other peer's monotonic time in peerstore!\n");
9393}

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 9397 of file gnunet-service-transport.c.

9398{
9399 struct GNUNET_TIME_Relative host_latency_sum;
9400 struct GNUNET_TIME_Relative latency;
9401 struct GNUNET_TIME_Relative network_latency;
9402 uint16_t nhops = ntohs (dvl->num_hops);;
9403
9404 /* We initiated this, learn the forward path! */
9405 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
9406
9407 // Need also something to lookup initiation time
9408 // to compute RTT! -> add RTT argument here?
9410 dvl->monotonic_time));
9411 /* @e non_network_delay is fully attacker-controlled, and our clock may
9412 simply be behind the initiator's: never assert on this. */
9413 if (latency.rel_value_us < host_latency_sum.rel_value_us)
9414 {
9416 "# DV learn with implausible non-network delay",
9417 1,
9418 GNUNET_NO);
9420 }
9421 // latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
9422 // (based on dvl->challenge, we can identify time of origin!)
9423
9424 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
9425 /* assumption: latency on all links is the same */
9426 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
9427
9428 return network_latency;
9429}

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 9440 of file gnunet-service-transport.c.

9441{
9442 struct CommunicatorMessageContext *cmc = cls;
9444 int bi_hop;
9445 uint16_t nhops;
9446 uint16_t bi_history;
9447 const struct DVPathEntryP *hops;
9448 int do_fwd;
9449 int did_initiator;
9450 struct GNUNET_TIME_Absolute in_time;
9451 struct Neighbour *n;
9452 const struct GNUNET_PeerIdentity *my_identity;
9453
9454 nhops = ntohs (dvl->num_hops); /* 0 = sender is initiator */
9455 bi_history = ntohs (dvl->bidirectional);
9456 hops = (const struct DVPathEntryP *) &dvl[1];
9457 if (0 == nhops)
9458 {
9459 /* sanity check */
9460 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
9461 {
9462 GNUNET_break (0);
9463 finish_cmc_handling (cmc);
9464 return;
9465 }
9466 /* A zero-hop message we supposedly initiated ourselves would make the
9467 "we are the initiator" branch below read hops[0] and write past the
9468 end of its `path[nhops + 1]' array. */
9470 {
9471 GNUNET_break_op (0);
9472 finish_cmc_handling (cmc);
9473 return;
9474 }
9475 }
9476 else
9477 {
9479 "handle dv learn message last hop %s\n",
9480 GNUNET_i2s (&hops[nhops - 1].hop));
9481 /* sanity check */
9482 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
9483 {
9484 GNUNET_break (0);
9485 finish_cmc_handling (cmc);
9486 return;
9487 }
9488 }
9489
9491 cc = cmc->tc->details.communicator.cc;
9492 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
9493 cc); // FIXME: add bi-directional flag to cc?
9494 in_time = GNUNET_TIME_absolute_get ();
9495
9496 /* continue communicator here, everything else can happen asynchronous! */
9497 finish_cmc_handling (cmc);
9498
9499 n = lookup_neighbour (&dvl->initiator);
9500 if (NULL != n)
9501 {
9502 if ((n->dv_monotime_available == GNUNET_YES) &&
9505 {
9507 "DV learn from %s discarded due to time travel",
9508 GNUNET_i2s (&dvl->initiator));
9510 "# DV learn discarded due to time travel",
9511 1,
9512 GNUNET_NO);
9513 return;
9514 }
9516 &dvl->initiator,
9517 &dvl->challenge,
9518 &dvl->init_sig))
9519 {
9521 "DV learn signature from %s invalid\n",
9522 GNUNET_i2s (&dvl->initiator));
9523 GNUNET_break_op (0);
9524 return;
9525 }
9528 {
9529 if (NULL != n->sc)
9530 {
9532 "store cancel\n");
9534 }
9535 n->sc =
9537 "transport",
9538 &dvl->initiator,
9540 &dvl->monotonic_time,
9541 sizeof(dvl->monotonic_time),
9545 n);
9546 }
9547 }
9548
9551
9552 /* OPTIMIZE-FIXME: asynchronously (!) verify signatures!,
9553 If signature verification load too high, implement random drop strategy */
9554 for (unsigned int i = 0; i < nhops; i++)
9555 {
9556 struct DvHopPS dhp = { .purpose.purpose =
9558 .purpose.size = htonl (sizeof(dhp)),
9559 .pred = (0 == i) ? dvl->initiator : hops[i - 1].hop,
9560 .succ = (nhops == i + 1) ? *my_identity
9561 : hops[i + 1].hop,
9562 .challenge = dvl->challenge };
9563
9564 if (GNUNET_OK !=
9566 &dhp,
9567 &hops[i].hop_sig,
9568 &hops[i].hop.public_key))
9569 {
9571 "DV learn from %s signature of hop %u invalid\n",
9572 GNUNET_i2s (&dvl->initiator),
9573 i);
9575 "signature of hop %s invalid\n",
9576 GNUNET_i2s (&hops[i].hop));
9578 "pred %s\n",
9579 GNUNET_i2s (&dhp.pred));
9581 "succ %s\n",
9582 GNUNET_i2s (&dhp.succ));
9584 "hash %s\n",
9585 GNUNET_sh2s (&dhp.challenge.value));
9586 GNUNET_break_op (0);
9587 return;
9588 }
9589 }
9590 if (GNUNET_EXTRA_LOGGING > 0)
9591 {
9592 char *path;
9593
9594 path = GNUNET_strdup (GNUNET_i2s (&dvl->initiator));
9595 for (unsigned int i = 0; i < nhops; i++)
9596 {
9597 char *tmp;
9598
9599 GNUNET_asprintf (&tmp,
9600 "%s%s%s",
9601 path,
9602 (bi_history & (1 << (nhops - i))) ? "<->" : "-->",
9603 GNUNET_i2s (&hops[i].hop));
9604 GNUNET_free (path);
9605 path = tmp;
9606 }
9608 "Received DVInit via %s%s%s\n",
9609 path,
9610 bi_hop ? "<->" : "-->",
9612 GNUNET_free (path);
9613 }
9614 do_fwd = GNUNET_YES;
9615 if (0 == GNUNET_memcmp (my_identity, &dvl->initiator))
9616 {
9617 struct GNUNET_PeerIdentity path[nhops + 1];
9618 struct GNUNET_TIME_Relative network_latency;
9619
9620 /* We initiated this, learn the forward path! */
9621 path[0] = *my_identity;
9622 path[1] = hops[0].hop;
9623
9624 network_latency = get_network_latency (dvl);
9625
9626 for (unsigned int i = 2; i <= nhops; i++)
9627 {
9628 struct GNUNET_TIME_Relative ilat;
9629
9630 /* assumption: linear latency increase per hop */
9631 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
9632 path[i] = hops[i - 1].hop;
9634 "Learned path with %u hops to %s with latency %s\n",
9635 i,
9636 GNUNET_i2s (&path[i]),
9638 learn_dv_path (path,
9639 i + 1,
9640 ilat,
9643 }
9644 /* as we initiated, do not forward again (would be circular!) */
9645 do_fwd = GNUNET_NO;
9646 return;
9647 }
9648 if (bi_hop)
9649 {
9650 /* last hop was bi-directional, we could learn something here! */
9651 struct GNUNET_PeerIdentity path[nhops + 2];
9652 struct GNUNET_TIME_Relative ilat;
9653 struct GNUNET_TIME_Relative network_latency;
9654
9655 path[0] = *my_identity;
9656 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
9657 for (unsigned int i = 0; i < nhops; i++)
9658 {
9659 int iret;
9660
9661 if (0 == (bi_history & (1 << i)))
9662 break; /* i-th hop not bi-directional, stop learning! */
9663 if (i == nhops - 1)
9664 {
9665 path[i + 2] = dvl->initiator;
9666 }
9667 else
9668 {
9669 path[i + 2] = hops[nhops - i - 2].hop;
9670 }
9671
9673 "Learned inverse path with %u hops to %s\n",
9674 i + 2,
9675 GNUNET_i2s (&path[i + 2]));
9676 network_latency = get_network_latency (dvl);
9677 ilat = GNUNET_TIME_relative_multiply (network_latency, i + 2);
9678 iret = learn_dv_path (path,
9679 i + 3,
9680 ilat,
9683 if (GNUNET_SYSERR == iret)
9684 {
9685 /* path invalid or too long to be interesting for US, thus should also
9686 not be interesting to our neighbours, cut path when forwarding to
9687 'i' hops, except of course for the one that goes back to the
9688 initiator */
9690 "# DV learn not forwarded due invalidity of path",
9691 1,
9692 GNUNET_NO);
9693 do_fwd = GNUNET_NO;
9694 break;
9695 }
9696 if ((GNUNET_NO == iret) && (nhops == i + 1))
9697 {
9698 /* we have better paths, and this is the longest target,
9699 so there cannot be anything interesting later */
9701 "# DV learn not forwarded, got better paths",
9702 1,
9703 GNUNET_NO);
9704 do_fwd = GNUNET_NO;
9705 break;
9706 }
9707 }
9708 }
9709 if (MAX_DV_HOPS_ALLOWED == nhops)
9710 {
9711 /* At limit, we're out of here! */
9712 return;
9713 }
9714
9715 /* Forward to initiator, if path non-trivial and possible */
9716 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
9717 did_initiator = GNUNET_NO;
9718 if ((1 <= nhops) &&
9719 (GNUNET_YES ==
9721 {
9722 /* send back to origin! */
9724 "Sending DVL back to initiator %s\n",
9725 GNUNET_i2s (&dvl->initiator));
9726 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
9727 did_initiator = GNUNET_YES;
9728 }
9729 /* We forward under two conditions: either we still learned something
9730 ourselves (do_fwd), or the path was darn short and thus the initiator is
9731 likely to still be very interested in this (and we did NOT already
9732 send it back to the initiator) */
9733 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
9734 (GNUNET_NO == did_initiator)))
9735 {
9736 /* Pick random neighbours that are not yet on the path */
9737 struct NeighbourSelectionContext nsc;
9738 unsigned int n_cnt;
9739 unsigned int n_eligible;
9740
9742 nsc.nhops = nhops;
9743 nsc.dvl = dvl;
9744 nsc.bi_history = bi_history;
9745 nsc.hops = hops;
9746 nsc.in_time = in_time;
9747 nsc.num_eligible = 0;
9750 &nsc);
9751 if (0 == nsc.num_eligible)
9752 return; /* done here, cannot forward to anyone else */
9753 n_eligible = nsc.num_eligible;
9754 nsc.num_selections = calculate_fork_degree (nhops, n_cnt, n_eligible);
9755 nsc.num_selections =
9756 GNUNET_MIN (MAX_DV_DISCOVERY_SELECTION, nsc.num_selections);
9758 "Forwarding DVL to %u other peers\n",
9759 nsc.num_selections);
9760 /* #dv_neighbour_transmission() counts ELIGIBLE peers only, so the
9761 offsets must be drawn from that range -- drawing from the total
9762 number of neighbours made us silently forward to fewer peers than
9763 #calculate_fork_degree() asked for. */
9764 for (unsigned int i = 0; i < nsc.num_selections; i++)
9765 nsc.selections[i] =
9766 (nsc.num_selections == n_eligible)
9767 ? i /* all were selected, avoid collisions by chance */
9768 : GNUNET_CRYPTO_random_u32 (n_eligible);
9769 nsc.num_eligible = 0;
9772 &nsc);
9773 }
9774}

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 9785 of file gnunet-service-transport.c.

9786{
9787 uint16_t size = ntohs (dvb->header.size);
9788 uint16_t num_hops = ntohs (dvb->num_hops);
9789 uint16_t total_hops = ntohs (dvb->total_hops);
9790 uint16_t orig_size = ntohs (dvb->orig_size);
9791 const struct GNUNET_PeerIdentity *hops =
9792 (const struct GNUNET_PeerIdentity *) &dvb[1];
9793 const struct GNUNET_PeerIdentity *my_identity;
9794
9795 (void) cls;
9796 if (size < sizeof(*dvb) + num_hops * sizeof(struct GNUNET_PeerIdentity)
9797 + sizeof(struct GNUNET_MessageHeader))
9798 {
9799 GNUNET_break_op (0);
9800 return GNUNET_SYSERR;
9801 }
9802 if ((num_hops > MAX_DV_HOPS_ALLOWED) ||
9803 (total_hops > MAX_DV_HOPS_ALLOWED))
9804 {
9805 GNUNET_break_op (0);
9806 return GNUNET_SYSERR;
9807 }
9808 /* #decaps_dv_box_cb() derives a VLA size from
9809 orig_size - sizeof(*dvb) - total_hops * sizeof (struct
9810 GNUNET_PeerIdentity); make sure that cannot underflow and that the
9811 remainder can plausibly hold a payload header plus a message. */
9812 if ((orig_size < size) ||
9813 (orig_size < sizeof(*dvb)
9814 + total_hops * sizeof(struct GNUNET_PeerIdentity)
9815 + sizeof(struct TransportDVBoxPayloadP)
9816 + sizeof(struct GNUNET_MessageHeader)))
9817 {
9818 GNUNET_break_op (0);
9819 return GNUNET_SYSERR;
9820 }
9821
9824
9825 /* This peer must not be on the path */
9826 for (unsigned int i = 0; i < num_hops; i++)
9827 if (0 == GNUNET_memcmp (&hops[i], my_identity))
9828 {
9829 GNUNET_break_op (0);
9830 return GNUNET_SYSERR;
9831 }
9832 return GNUNET_YES;
9833}

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 9849 of file gnunet-service-transport.c.

9856{
9857 struct VirtualLink *vl = next_hop->vl;
9858 struct PendingMessage *pm;
9859 size_t msg_size = sizeof(struct TransportDVBoxMessage)
9860 + num_hops * sizeof(struct GNUNET_PeerIdentity)
9861 + enc_payload_size;
9862 char *buf;
9863 char msg_buf[msg_size] GNUNET_ALIGN;
9864 struct GNUNET_PeerIdentity *dhops;
9865
9866 hdr->num_hops = htons (num_hops);
9867 hdr->total_hops = htons (total_hops);
9868 hdr->header.size = htons (msg_size);
9869 memcpy (msg_buf, hdr, sizeof(*hdr));
9870 dhops = (struct GNUNET_PeerIdentity *) &msg_buf[sizeof(struct
9872 ;
9873 memcpy (dhops, hops, num_hops * sizeof(struct GNUNET_PeerIdentity));
9874 memcpy (&dhops[num_hops], enc_payload, enc_payload_size);
9875
9876 if (GNUNET_YES == ntohl (hdr->without_fc))
9877 {
9879 "Forwarding control message (payload size %u) in DV Box to next hop %s (%u/%u) \n",
9880 enc_payload_size,
9881 GNUNET_i2s (&next_hop->pid),
9882 (unsigned int) num_hops,
9883 (unsigned int) total_hops);
9884 route_via_neighbour (next_hop, (const struct
9885 GNUNET_MessageHeader *) msg_buf,
9887 }
9888 else
9889 {
9890 pm = GNUNET_malloc (sizeof(struct PendingMessage) + msg_size);
9892 "2 created pm %p storing vl %p \n",
9893 pm,
9894 vl);
9895 pm->pmt = PMT_DV_BOX;
9896 pm->vl = vl;
9897 pm->target = next_hop->pid;
9901 pm->bytes_msg = msg_size;
9902 buf = (char *) &pm[1];
9903 memcpy (buf, msg_buf, msg_size);
9904
9906 "Created pending message %" PRIu64
9907 " for DV Box with next hop %s (%u/%u)\n",
9908 pm->logging_uuid,
9909 GNUNET_i2s (&next_hop->pid),
9910 (unsigned int) num_hops,
9911 (unsigned int) total_hops);
9912
9913 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
9914 {
9916 vl->pending_msg_head,
9917 vl->pending_msg_tail,
9918 pm);
9919
9921 }
9922 else
9923 {
9925 "The virtual link is not ready for forwarding a DV Box with payload, storing PendingMessage in ring buffer.\n");
9926
9928 {
9930
9931 GNUNET_free (pm_old);
9932 }
9935 {
9938 }
9939 else
9941
9943 "%u items stored in DV ring buffer\n",
9946 }
9947 }
9948}

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 9957 of file gnunet-service-transport.c.

9958{
9959 if (NULL != b->get)
9960 {
9962 b->get = NULL;
9963 GNUNET_assert (NULL != b->cmc);
9965 b->cmc = NULL;
9966 }
9967 if (NULL != b->task)
9968 {
9970 b->task = NULL;
9971 }
9972 if (NULL != b->sc)
9973 {
9975 "store cancel\n");
9977 b->sc = NULL;
9978 }
9980 "Removing backtalker for %s\n",
9981 GNUNET_i2s (&b->pid));
9983 GNUNET_YES ==
9985 GNUNET_free (b);
9986}

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 9998 of file gnunet-service-transport.c.

10001{
10002 struct Backtalker *b = value;
10003
10004 (void) cls;
10005 (void) pid;
10006 free_backtalker (b);
10007 return GNUNET_OK;
10008}

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 10017 of file gnunet-service-transport.c.

10018{
10019 struct Backtalker *b = cls;
10020
10022 "backtalker timeout.\n");
10023 b->task = NULL;
10025 {
10027 return;
10028 }
10029 /* A monotime store may well still be in flight -- @e timeout is about how
10030 long the *peer* has been quiet, and says nothing about PEERSTORE. This
10031 used to `GNUNET_assert (NULL == b->sc)', which aborted the service in
10032 exactly that case. #free_backtalker() cancels the store. */
10033 free_backtalker (b);
10034}

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 10046 of file gnunet-service-transport.c.

10049{
10050 struct Backtalker *b = cls;
10051 struct GNUNET_TIME_AbsoluteNBO *mtbe;
10052 struct GNUNET_TIME_Absolute mt;
10053
10054 (void) emsg;
10055 if (NULL == record)
10056 {
10057 struct CommunicatorMessageContext *cmc;
10058
10059 /* we're done with #backtalker_monotime_cb() invocations,
10060 continue normal processing */
10061 b->get = NULL;
10062 GNUNET_assert (NULL != b->cmc);
10063 /* Take @e cmc out of @a b *before* dispatching: the dispatch runs
10064 arbitrary message handling, and writing `b->cmc = NULL' afterwards
10065 is a write to freed memory should anything on that path have
10066 released @a b. #free_backtalker() keys its "must finish the parked
10067 cmc" decision off @e get, which is already NULL here, so clearing
10068 @e cmc early cannot lose the message either. */
10069 cmc = b->cmc;
10070 b->cmc = NULL;
10071 cmc->mh = (const struct GNUNET_MessageHeader *) &b[1];
10072 if (0 != b->body_size)
10074 else
10075 finish_cmc_handling (cmc);
10076 return;
10077 }
10078 if (sizeof(*mtbe) != record->value_size)
10079 {
10081 GNUNET_break (0);
10082 return;
10083 }
10084 mtbe = record->value;
10085 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
10086 if (mt.abs_value_us > b->monotonic_time.abs_value_us)
10087 {
10089 "Backtalker message from %s dropped, monotime in the past\n",
10090 GNUNET_i2s (&b->pid));
10092 GST_stats,
10093 "# Backchannel messages dropped: monotonic time not increasing",
10094 1,
10095 GNUNET_NO);
10096 b->monotonic_time = mt;
10097 /* Setting body_size to 0 prevents call to #forward_backchannel_payload()
10098 */
10099 b->body_size = 0;
10100 }
10102}

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 10113 of file gnunet-service-transport.c.

10114{
10115 struct Backtalker *b = cls;
10116
10117 if (GNUNET_OK != success)
10118 {
10120 "Failed to store backtalker's monotonic time in PEERSTORE!\n");
10121 }
10122 b->sc = NULL;
10123 /* @e task is armed for the whole life of @a b -- #backtalker_timeout_cb()
10124 re-arms itself whenever @e timeout has moved forward -- so there is
10125 nothing to do here beyond releasing the store. It used to cancel and
10126 re-add the task, which is what made the task's existence depend on this
10127 callback ever running. */
10128 GNUNET_assert (NULL != b->task);
10129}

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 10138 of file gnunet-service-transport.c.

10139{
10140 struct GNUNET_TIME_AbsoluteNBO mtbe;
10141
10142 /* At most one store may be outstanding. The value we are about to write
10143 supersedes whatever the previous one carried, and leaving the old
10144 context alive means its completion clears @e sc while the newer store
10145 is still in flight -- after which the next update sees a NULL @e sc and
10146 starts a third one. Cancelling is also what keeps @e sc from being
10147 silently overwritten and leaked.
10148
10149 Note what this must NOT do: touch @e task. That task is the only thing
10150 that ever releases a `struct CommunicatorMessageContext' parked in
10151 @e cmc, and cancelling it here left its re-arming up to
10152 #backtalker_monotime_store_cb() -- i.e. up to PEERSTORE answering. A
10153 lost store completion then stalled the parked communicator client for
10154 the life of the process. #backtalker_timeout_cb() already re-arms
10155 itself against the current @e timeout, so the task needs no help. */
10156 if (NULL != b->sc)
10157 {
10159 "Superseding in-flight backtalker monotime store %p\n",
10160 b->sc);
10162 b->sc = NULL;
10163 }
10165 b->sc =
10167 "transport",
10168 &b->pid,
10170 &mtbe,
10171 sizeof(mtbe),
10175 b);
10176}

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 10188 of file gnunet-service-transport.c.

10191{
10192 const unsigned char *hdr;
10193 size_t hdr_len;
10195
10196 key = (struct GNUNET_CRYPTO_AeadSecretKey*) km;
10197 /* We are the ultimate target, so #handle_dv_box() has established that no
10198 hop entries are left: the ciphertext directly follows the header, and
10199 its length is what we actually received. Deriving it from orig_size
10200 and total_hops instead would only be equivalent if every forwarder
10201 accounted its skipped hops exactly. */
10202 hdr = (const unsigned char *) &dvb[1];
10203 {
10204 uint16_t size = ntohs (dvb->header.size);
10205
10206 if (size < sizeof(*dvb)
10207 + sizeof(struct TransportDVBoxPayloadP)
10208 + sizeof(struct GNUNET_MessageHeader))
10209 {
10210 GNUNET_break_op (0);
10211 finish_cmc_handling (cmc);
10212 return;
10213 }
10214 hdr_len = size - sizeof(*dvb);
10215 }
10216
10217 /* begin actual decryption */
10218 {
10219 struct Backtalker *b;
10220 struct GNUNET_TIME_Absolute monotime;
10221 struct TransportDVBoxPayloadP *ppay;
10222 unsigned char pt[hdr_len + sizeof *ppay] GNUNET_ALIGN;
10223 unsigned char *body;
10224 const struct GNUNET_MessageHeader *mh;
10225
10226 ppay = (struct TransportDVBoxPayloadP *) pt;
10227 body = &pt[sizeof *ppay];
10228 GNUNET_assert (hdr_len >=
10229 sizeof(*ppay) + sizeof(struct GNUNET_MessageHeader));
10230 if (GNUNET_OK != GNUNET_CRYPTO_aead_decrypt (hdr_len,
10231 hdr,
10232 0,
10233 NULL,
10234 key,
10235 &dvb->iv,
10236 &dvb->mac,
10237 pt))
10238 {
10240 "Error decrypting DV payload header\n");
10241 GNUNET_break_op (0);
10242 finish_cmc_handling (cmc);
10243 return;
10244 }
10245 mh = (const struct GNUNET_MessageHeader *) body;
10246 /* NOTE: this used to compare against `sizeof (body)', i.e. the size of
10247 a pointer, which meant only 8-byte payloads were ever accepted. */
10248 if (ntohs (mh->size) != hdr_len - sizeof(*ppay))
10249 {
10250 GNUNET_break_op (0);
10251 finish_cmc_handling (cmc);
10252 return;
10253 }
10254 /* need to prevent box-in-a-box (and DV_LEARN) so check inbox type! */
10255 switch (ntohs (mh->type))
10256 {
10258 GNUNET_break_op (0);
10259 finish_cmc_handling (cmc);
10260 return;
10261
10263 GNUNET_break_op (0);
10264 finish_cmc_handling (cmc);
10265 return;
10266
10267 default:
10268 /* permitted, continue */
10269 break;
10270 }
10271 monotime = GNUNET_TIME_absolute_ntoh (ppay->monotonic_time);
10273 "Decrypted backtalk from %s\n",
10274 GNUNET_i2s (&ppay->sender));
10276 &ppay->sender);
10277 if ((NULL != b) && (monotime.abs_value_us < b->monotonic_time.abs_value_us))
10278 {
10280 GST_stats,
10281 "# Backchannel messages dropped: monotonic time not increasing",
10282 1,
10283 GNUNET_NO);
10284 finish_cmc_handling (cmc);
10285 return;
10286 }
10287 if ((NULL == b) ||
10288 (0 != GNUNET_memcmp (&b->last_ephemeral, &dvb->ephemeral_key)))
10289 {
10290 /* Check signature */
10291 const struct GNUNET_PeerIdentity *my_identity;
10292 struct EphemeralConfirmationPS ec;
10293
10296
10297 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
10298 ec.target = *my_identity;
10299 ec.ephemeral_key = dvb->ephemeral_key;
10300 ec.purpose.size = htonl (sizeof(ec));
10301 ec.sender_monotonic_time = ppay->monotonic_time;
10302 if (
10303 GNUNET_OK !=
10306 &ec,
10307 &ppay->sender_sig,
10308 &ppay->sender.public_key))
10309 {
10310 /* Signature invalid, discard! */
10311 GNUNET_break_op (0);
10312 finish_cmc_handling (cmc);
10313 return;
10314 }
10315 }
10316 /* Update sender, we now know the real origin! */
10318 "DVBox received for me from %s via %s\n",
10319 GNUNET_i2s2 (&ppay->sender),
10320 GNUNET_i2s (&cmc->im.sender));
10321 cmc->im.sender = ppay->sender;
10322
10323 if (NULL != b)
10324 {
10325 /* update key cache and mono time */
10326 b->last_ephemeral = dvb->ephemeral_key;
10327 b->monotonic_time = monotime;
10329 b->timeout =
10331 cmc->mh = mh;
10333 return;
10334 }
10335 /* setup data structure to cache signature AND check
10336 monotonic time with PEERSTORE before forwarding backchannel payload */
10337 b = GNUNET_malloc (sizeof(struct Backtalker) + (hdr_len - sizeof(*ppay)));
10338 b->pid = ppay->sender;
10339 b->body_size = hdr_len - sizeof(*ppay);
10340 memcpy (&b[1], body, hdr_len - sizeof(*ppay));
10344 &b->pid,
10345 b,
10347 b->monotonic_time = monotime; /* NOTE: to be checked still! */
10348 b->cmc = cmc;
10349 b->timeout =
10352 b->get =
10354 "transport",
10355 &b->pid,
10358 b);
10359 } /* end actual decryption */
10360}

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 10371 of file gnunet-service-transport.c.

10372{
10373 struct CommunicatorMessageContext *cmc = cls;
10374 uint16_t size = ntohs (dvb->header.size) - sizeof(*dvb);
10375 uint16_t num_hops = ntohs (dvb->num_hops);
10376 const struct GNUNET_PeerIdentity *hops =
10377 (const struct GNUNET_PeerIdentity *) &dvb[1];
10378 const char *enc_payload = (const char *) &hops[num_hops];
10379 uint16_t enc_payload_size =
10380 size - (num_hops * sizeof(struct GNUNET_PeerIdentity));
10381 const struct GNUNET_PeerIdentity *my_identity;
10382
10385
10386 if (GNUNET_EXTRA_LOGGING > 0)
10387 {
10388 char *path;
10389
10391 for (unsigned int i = 0; i < num_hops; i++)
10392 {
10393 char *tmp;
10394
10395 GNUNET_asprintf (&tmp, "%s->%s", path, GNUNET_i2s (&hops[i]));
10396 GNUNET_free (path);
10397 path = tmp;
10398 }
10400 "Received DVBox with remaining path %s\n",
10401 path);
10402 GNUNET_free (path);
10403 }
10404
10405 if (num_hops > 0)
10406 {
10407 /* We're trying from the end of the hops array, as we may be
10408 able to find a shortcut unknown to the origin that way */
10409 for (int i = num_hops - 1; i >= 0; i--)
10410 {
10411 struct Neighbour *n;
10412
10413 if (0 == GNUNET_memcmp (&hops[i], my_identity))
10414 {
10415 GNUNET_break_op (0);
10416 finish_cmc_handling (cmc);
10417 return;
10418 }
10419 n = lookup_neighbour (&hops[i]);
10420 if (NULL == n)
10421 continue;
10423 "Skipping %u/%u hops ahead while routing DV Box\n",
10424 i,
10425 num_hops);
10426
10427 forward_dv_box (n,
10428 (struct TransportDVBoxMessage *) dvb,
10429 /* we strip i+1 entries, and the receiver reconstructs
10430 the ciphertext offset from total_hops */
10431 ntohs (dvb->total_hops) + i + 1,
10432 num_hops - i - 1, /* number of hops left */
10433 &hops[i + 1], /* remaining hops */
10434 enc_payload,
10435 enc_payload_size);
10437 "# DV hops skipped routing boxes",
10438 i,
10439 GNUNET_NO);
10441 "# DV boxes routed (total)",
10442 1,
10443 GNUNET_NO);
10444 finish_cmc_handling (cmc);
10445 return;
10446 }
10447 /* Woopsie, next hop not in neighbours, drop! */
10449 "# DV Boxes dropped: next hop unknown",
10450 1,
10451 GNUNET_NO);
10452 finish_cmc_handling (cmc);
10453 return;
10454 }
10455 /* We are the target. Unbox and handle message. */
10457 "# DV boxes opened (ultimate target)",
10458 1,
10459 GNUNET_NO);
10460 cmc->total_hops = ntohs (dvb->total_hops);
10461
10462 {
10463 // DH key derivation with received DV, could be garbage.
10465 struct GNUNET_ShortHashCode km;
10466
10468 if ( (NULL == my_private_key) ||
10469 (GNUNET_OK !=
10471 &dvb->ephemeral_key,
10472 &km)) )
10473 {
10474 GNUNET_break_op (0);
10475 finish_cmc_handling (cmc);
10476 return;
10477 }
10478 decaps_dv_box_cont (cmc,
10479 dvb,
10480 &km);
10481 }
10482}

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 10493 of file gnunet-service-transport.c.

10495{
10496 struct TransportClient *tc = cls;
10497
10498 if (CT_COMMUNICATOR != tc->type)
10499 {
10500 GNUNET_break (0);
10501 return GNUNET_SYSERR;
10502 }
10504 return GNUNET_OK;
10505}

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 10535 of file gnunet-service-transport.c.

10538{
10539 struct CheckKnownAddressContext *ckac = cls;
10540 struct ValidationState *vs = value;
10541
10542 (void) pid;
10543 if (0 != strcmp (vs->address, ckac->address))
10544 return GNUNET_OK;
10545 ckac->vs = vs;
10546 return GNUNET_NO;
10547}

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 14127 of file gnunet-service-transport.c.

14128{
14129 struct ValidationState *vs;
14130 struct Queue *q;
14132 GST_cfg);
14133
14134 (void) cls;
14135 validation_task = NULL;
14137 /* drop validations past their expiration */
14138 while (
14139 (NULL != vs) &&
14141 {
14143 "Validation response %s cleaned up\n",
14144 GNUNET_sh2s (&vs->challenge.value));
14147 }
14148 if (NULL == vs)
14149 {
14151 "Address validation task not scheduled anymore, nothing to do\n");
14152 return; /* woopsie, no more addresses known, should only
14153 happen if we're really a lonely peer */
14154 }
14155 q = find_queue (&vs->pid, vs->address);
14156 if (GNUNET_TIME_absolute_cmp (vs->first_challenge_use, >, now))
14157 {
14159 "To early to start next address validation for challenge %s\n",
14160 GNUNET_sh2s (&vs->challenge.value));
14161 /* Do NOT just return: @e validation_task was set to NULL above and
14162 nothing re-arms it by itself. #update_next_challenge_time() only
14163 schedules us again when it is called with a *changed* time for some
14164 validation state, so bailing out here leaves a non-empty
14165 #validation_heap with no task attached: address (re)validation and
14166 the #suggest_to_connect() retries that go with it stop for *every*
14167 peer until some unrelated event happens to come along. A peer that
14168 just lost its only connection has no such events left. */
14171 now,
14172 vs->first_challenge_use),
14174 NULL);
14175 return;
14176 }
14177 if (NULL == q)
14178 {
14179 vs->awaiting_queue = GNUNET_YES;
14180 suggest_to_connect (&vs->pid, vs->address);
14181 }
14182 else
14184 /* Finally, reschedule next attempt */
14185 vs->challenge_backoff =
14186 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
14189 "Address validation task will run again in %s\n",
14190 GNUNET_STRINGS_relative_time_to_string (vs->challenge_backoff,
14191 GNUNET_YES));
14194 vs->challenge_backoff));
14195}

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 10567 of file gnunet-service-transport.c.

10569{
10571 struct ValidationState *next;
10572
10573 /* NOTE: "be lazy" must not apply while #validation_task is unset. Our
10574 only caller that can leave it unset is #validation_start_cb(), which
10575 NULLs it on entry and relies on us to arm it again -- and nothing else
10576 ever does. Returning early there stops address (re)validation and the
10577 #suggest_to_connect() retries that go with it for *every* peer, for
10578 good. */
10579 if ((new_time.abs_value_us == vs->next_challenge.abs_value_us) &&
10580 (NULL != validation_task) &&
10581 (NULL != vs->hn))
10582 return; /* be lazy */
10583 vs->next_challenge = new_time;
10584 if (NULL == vs->hn)
10585 vs->hn =
10587 else
10590 (NULL != validation_task))
10591 return;
10592 if (NULL != validation_task)
10594 /* Arm for the earliest entry in the heap, which need NOT be @a vs:
10595 #validation_start_cb() calls us with @e validation_task unset and with
10596 @a vs already pushed out to its new @e challenge_backoff, which doubles
10597 up to #MAX_VALIDATION_CHALLENGE_FREQ (one day) while an address stays
10598 unanswered. Arming for @a vs there parks the single global validation
10599 task for that long, no matter how many other addresses are due right
10600 now -- and every address of a peer we cannot reach (NAT) is such an
10601 address. Everything that needs a validation then stops with it:
10602 bringing a lost link back up, and confirming the link to a peer that
10603 contacted us. */
10605 if (NULL == next)
10606 return;
10607 /* randomize a bit */
10612 delta),
10614 NULL);
10615}

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:

◆ speed_up_challenge()

static void speed_up_challenge ( struct ValidationState *  vs)
static

Speed the next challenge for vs up because we heard something about that address again – but never faster than FAST_VALIDATION_CHALLENGE_FREQ.

The callers used to write min (FAST, backoff / 2), which is ZERO whenever challenge_backoff is zero – and handle_validation_response() clears it after every successful validation, while update_next_challenge_time() then arms the global validation_task for "now". Since send_t_validation_response() ends in try_to_bring_link_up() for every challenge we answer on an unconfirmed link, two peers that cannot confirm each other then challenge each other once per round trip – two EdDSA signatures, two verifications and a PEERSTORE store per exchange, per peer, forever. FAST is documented as the fastest rate at which we challenge an address we keep hearing about, so it is both cap and floor here; the first challenge for a new address is still immediate.

Parameters
vsaddress validation state to speed up

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

10638{
10639 vs->challenge_backoff = FAST_VALIDATION_CHALLENGE_FREQ;
10640}

References FAST_VALIDATION_CHALLENGE_FREQ.

Referenced by revalidate_now_cb(), and start_address_validation().

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 10654 of file gnunet-service-transport.c.

10657{
10658 struct ValidationState *vs = value;
10659 const struct GNUNET_TIME_Absolute now =
10661
10662 (void) cls;
10663 (void) pid;
10664 /* What #start_address_validation() does for an address it hears about
10665 again, but without needing the address string. */
10666 speed_up_challenge (vs);
10667 if (GNUNET_TIME_absolute_cmp (vs->first_challenge_use, >, now))
10668 vs->first_challenge_use = now;
10671 vs->challenge_backoff));
10672 return GNUNET_OK;
10673}

References GNUNET_OK, GNUNET_TIME_absolute_cmp, GNUNET_TIME_absolute_get_monotonic(), GNUNET_TIME_relative_to_absolute(), GST_cfg, speed_up_challenge(), 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 11194 of file gnunet-service-transport.c.

11195{
11196 struct Neighbour *n;
11197
11198 n = lookup_neighbour (pid);
11199 if (NULL == n)
11200 return NULL;
11201 for (struct Queue *pos = n->queue_head; NULL != pos;
11202 pos = pos->next_neighbour)
11203 {
11204 if (0 == strcmp (pos->address, address))
11205 return pos;
11206 }
11207 return NULL;
11208}

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 13992 of file gnunet-service-transport.c.

13993{
13994 static uint32_t idgen = 0;
13995 struct TransportClient *tc;
13996 char *prefix;
13997 struct GNUNET_TRANSPORT_CreateQueue *cqm;
13998 struct GNUNET_MQ_Envelope *env;
13999 size_t alen;
14000
14002 if (NULL == prefix)
14003 {
14004 GNUNET_break (0); /* We got an invalid address!? */
14005 return;
14006 }
14008 if (NULL == tc)
14009 {
14011 "# Suggestions ignored due to missing communicator",
14012 1,
14013 GNUNET_NO);
14015 "Cannot connect to %s at `%s', no matching communicator present\n",
14016 GNUNET_i2s (pid),
14017 address);
14019 return;
14020 }
14021 /* forward suggestion for queue creation to communicator */
14023 "Request #%u for `%s' communicator to create queue to `%s' at `%s'\n",
14024 (unsigned int) idgen,
14025 prefix,
14026 GNUNET_i2s (pid),
14027 address);
14029 alen = strlen (address) + 1;
14030 env =
14032 cqm->request_id = htonl (idgen++);
14033 cqm->receiver = *pid;
14034 memcpy (&cqm[1], address, alen);
14035 GNUNET_MQ_send (tc->mq, env);
14036}

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 10773 of file gnunet-service-transport.c.

10776{
10777 struct Queue *q;
10778 int pfx_len;
10779 const char *eou;
10780 char *address;
10781 (void) cls;
10782
10783 eou = strstr (uri,
10784 "://");
10785 if ((NULL == eou) || (eou == uri))
10786 {
10787 /* @a uri comes from a HELLO some remote peer published. */
10788 GNUNET_break_op (0);
10789 return;
10790 }
10791 pfx_len = eou - uri;
10792 eou += 3;
10794 "%.*s-%s",
10795 pfx_len,
10796 uri,
10797 eou);
10798
10800 "helo for client %s\n",
10801 address);
10802 q = find_queue (pid, address);
10803 if (NULL == q)
10804 {
10806 }
10807 else
10810}

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 10836 of file gnunet-service-transport.c.

10837{
10838 const struct GNUNET_MessageHeader *hello;
10839
10840 if ((NULL == record) ||
10841 (NULL == record->value) ||
10842 (record->value_size < sizeof(*hello)))
10843 {
10844 GNUNET_break_op (0);
10845 return NULL;
10846 }
10847 hello = record->value;
10848 if (ntohs (hello->size) > record->value_size)
10849 {
10850 GNUNET_break_op (0);
10851 return NULL;
10852 }
10853 return hello;
10854}

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 10865 of file gnunet-service-transport.c.

10868{
10869 struct IncomingRequest *ir = cls;
10871 const struct GNUNET_MessageHeader *hello;
10872 const struct GNUNET_PeerIdentity *my_identity;
10873
10874 if (NULL != emsg)
10875 {
10877 "Got failure from PEERSTORE: %s\n",
10878 emsg);
10880 return;
10881 }
10882 if (NULL == record)
10883 {
10884 GNUNET_break (0);
10886 return;
10887 }
10888 hello = hello_from_record (record);
10889 if (NULL == hello)
10890 {
10891 /* MUST still ask for the next record: a bad one is not a reason to
10892 stall this monitor forever. */
10894 return;
10895 }
10897 if (NULL == my_identity)
10898 {
10900 return;
10901 }
10902 if (0 == GNUNET_memcmp (&record->peer, my_identity))
10903 {
10905 return;
10906 }
10907 if (0 != GNUNET_memcmp (&record->peer, &ir->pid))
10908 {
10909 /* Not the peer this request is about. */
10911 return;
10912 }
10913 parser = GNUNET_HELLO_parser_from_msg (hello, &record->peer);
10914 if (NULL != parser)
10915 {
10918 NULL);
10919 GNUNET_HELLO_parser_free (parser);
10920 }
10921 /* MUST ask for the next record, or this monitor stalls after one HELLO */
10923}

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 10927 of file gnunet-service-transport.c.

10928{
10930 "Error in PEERSTORE monitoring\n");
10931}

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 10935 of file gnunet-service-transport.c.

10936{
10938 "Done with initial PEERSTORE iteration during monitoring\n");
10939}

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 11012 of file gnunet-service-transport.c.

11014{
11015 struct VirtualLink *vl;
11016 struct Neighbour *n;
11017 struct GNUNET_PeerIdentity sender;
11018
11019 sender = cmc->im.sender;
11020 vl = lookup_virtual_link (&sender);
11021 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
11022 {
11023 // route_control_message_without_fc (&cmc->im.sender,
11025 &tvr.header,
11027 }
11028 else
11029 {
11030 /* Use route via neighbour */
11031 n = lookup_neighbour (&sender);
11032 if (NULL != n)
11033 route_via_neighbour (n, &tvr.header,
11036 }
11037
11038 finish_cmc_handling (cmc);
11039 /* An *unconfirmed* link is not a link -- it carries nothing, and CORE has
11040 never been told about the peer. Bailing out on one merely because it
11041 exists is what deadlocks a pair of peers into permanent one-way state:
11042 the challenger validated us, so it believes the connection is up and
11043 starts sending us FLOW_CONTROL; #handle_flow_control() answers an
11044 unknown sender by allocating exactly such an unconfirmed link; and from
11045 then on every challenge it retransmits lands here, gets a response --
11046 which keeps *its* side confirmed and its RTT healthy -- and returns
11047 without ever validating an address of its own. The unconfirmed link
11048 reaps itself after #UNCONFIRMED_LINK_TIMEOUT, but the next FLOW_CONTROL
11049 recreates it, and the peer keeps sending those precisely because it
11050 thinks it is connected. Nothing ever breaks the tie, so CORE on this
11051 side never hears about the peer and never answers its handshake.
11052 Only a confirmed link means there is nothing left to do. */
11053 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
11054 return;
11055
11056 /* For us, the link is still down, but we need bi-directional
11057 connections (for flow-control and for this to be useful for
11058 CORE), so we must try to bring the link up! */
11059 try_to_bring_link_up (&sender);
11060}

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 11072 of file gnunet-service-transport.c.

11075{
11076 struct CommunicatorMessageContext *cmc = cls;
11077 struct TransportValidationResponseMessage tvr = { 0 };
11078 struct GNUNET_TIME_RelativeNBO validity_duration;
11079
11080 /* DV-routed messages are not allowed for validation challenges */
11081 if (cmc->total_hops > 0)
11082 {
11083 GNUNET_break_op (0);
11084 finish_cmc_handling (cmc);
11085 return;
11086 }
11087 validity_duration = cmc->im.expected_address_validity;
11089 "Received address validation challenge %s\n",
11090 GNUNET_sh2s (&tvc->challenge.value));
11091 /* If we have a virtual link, we use this mechanism to signal the
11092 size of the flow control window, and to allow the sender
11093 to ask for increases. If for us the virtual link is still down,
11094 we will always give a window size of zero. */
11095 tvr.header.type =
11097 tvr.header.size = htons (sizeof(tvr));
11098 tvr.reserved = htonl (0);
11099 tvr.challenge = tvc->challenge;
11100 tvr.origin_time = tvc->sender_time;
11101 tvr.validity_duration = validity_duration;
11102 {
11103 /* create signature */
11104 struct TransportValidationPS tvp = {
11106 .purpose.size = htonl (sizeof(tvp)),
11107 .validity_duration = validity_duration,
11108 .challenge = tvc->challenge
11109 };
11110 if (GNUNET_OK != sign_by_my_identity (&tvp.purpose, &tvr.signature))
11111 {
11112 /* Not answering costs us this address validation; leaving @a cmc
11113 behind would cost us the communicator. */
11114 finish_cmc_handling (cmc);
11115 return;
11116 }
11117 }
11118 send_t_validation_response (cmc, tvr);
11119}

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 11149 of file gnunet-service-transport.c.

11152{
11153 struct CheckKnownChallengeContext *ckac = cls;
11154 struct ValidationState *vs = value;
11155
11156 (void) pid;
11157 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
11158 return GNUNET_OK;
11159 ckac->vs = vs;
11160 return GNUNET_NO;
11161}

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 11172 of file gnunet-service-transport.c.

11173{
11174 struct ValidationState *vs = cls;
11175
11176 vs->sc = NULL;
11177 if (GNUNET_YES == success)
11178 return;
11180 "# Peerstore failed to store foreign address",
11181 1,
11182 GNUNET_NO);
11183}

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 11227 of file gnunet-service-transport.c.

11228{
11229 struct Neighbour *n;
11230 struct Queue *ret = NULL;
11231 char *prefix;
11232 char *ip;
11233
11234 n = lookup_neighbour (pid);
11235 if (NULL == n)
11236 return NULL;
11239 if ((NULL == prefix) || (NULL == ip))
11240 {
11242 GNUNET_free (ip);
11243 return NULL;
11244 }
11245 for (struct Queue *pos = n->queue_head; NULL != pos;
11246 pos = pos->next_neighbour)
11247 {
11248 char *q_prefix = GNUNET_HELLO_address_to_prefix (pos->address);
11249 char *q_ip = get_address_without_port (pos->address);
11250
11251 /* Same communicator and same host -- only the port may differ. */
11252 if ((NULL != q_prefix) && (NULL != q_ip) &&
11253 (0 == strcmp (q_prefix, prefix)) &&
11254 (0 == strcmp (q_ip, ip)))
11255 ret = pos;
11256 GNUNET_free (q_prefix);
11257 GNUNET_free (q_ip);
11258 if (NULL != ret)
11259 break;
11260 }
11262 GNUNET_free (ip);
11263 return ret;
11264}

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 14047 of file gnunet-service-transport.c.

14048{
14050 struct GNUNET_TIME_Absolute monotonic_time;
14051
14052 if (NULL != vs->revalidation_task)
14053 {
14054 GNUNET_SCHEDULER_cancel (vs->revalidation_task);
14055 vs->revalidation_task = NULL;
14056 }
14057 /*memcpy (&hkey,
14058 &hc,
14059 sizeof (hkey));*/
14061 "Remove key %s for address %s map size %u contains %u\n",
14062 GNUNET_h2s (&vs->hc),
14063 vs->address,
14066 &vs->hc));
14068
14070 if (GNUNET_TIME_UNIT_ZERO_ABS.abs_value_us ==
14071 vs->last_challenge_use.abs_value_us)
14072 {
14073 vs->first_challenge_use = monotonic_time;
14074 }
14075 vs->last_challenge_use = monotonic_time;
14076 tvc.header.type =
14078 tvc.header.size = htons (sizeof(tvc));
14079 tvc.reserved = htonl (0);
14080 tvc.challenge = vs->challenge;
14081 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
14083 "Sending address validation challenge %s to %s\n",
14084 GNUNET_sh2s (&tvc.challenge.value),
14085 GNUNET_i2s (&q->neighbour->pid));
14086 queue_send_msg (q, NULL, &tvc, sizeof(tvc));
14087}

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 11271 of file gnunet-service-transport.c.

11272{
11273 struct ValidationState *vs = cls;
11274 struct Queue *q;
11275 struct GNUNET_TIME_Absolute now;
11276
11277 vs->revalidation_task = NULL;
11278 q = find_queue (&vs->pid, vs->address);
11279 if (NULL == q)
11280 {
11281 now = GNUNET_TIME_absolute_get ();
11282 vs->awaiting_queue = GNUNET_YES;
11283 suggest_to_connect (&vs->pid, vs->address);
11285 }
11286 else
11288}

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 11292 of file gnunet-service-transport.c.

11296{
11297 (void) cls;
11299 "Key in revalidate map %s \n",
11300 GNUNET_h2s (key));
11301 return GNUNET_YES;
11302}

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 11314 of file gnunet-service-transport.c.

11317{
11318 struct CommunicatorMessageContext *cmc = cls;
11319 struct ValidationState *vs;
11320 struct CheckKnownChallengeContext ckac = { .challenge = &tvr->challenge,
11321 .vs = NULL};
11322 struct GNUNET_TIME_Absolute origin_time;
11323 struct Queue *q;
11324 struct Neighbour *n;
11325 struct VirtualLink *vl;
11327 GST_cfg);
11328
11329 /* check this is one of our challenges */
11331 &cmc->im.sender,
11333 &ckac);
11334 if (NULL == (vs = ckac.vs))
11335 {
11336 /* This can happen simply if we 'forgot' the challenge by now,
11337 i.e. because we received the validation response twice */
11339 "# Validations dropped, challenge unknown",
11340 1,
11341 GNUNET_NO);
11343 "Validation response %s dropped, challenge unknown\n",
11344 GNUNET_sh2s (&tvr->challenge.value));
11345 finish_cmc_handling (cmc);
11346 return;
11347 }
11348
11349 /* sanity check on origin time */
11350 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
11351 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
11352 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
11353 {
11355 "Diff first use %" PRIu64 " and last use %" PRIu64 "\n",
11356 vs->first_challenge_use.abs_value_us - origin_time.abs_value_us,
11357 origin_time.abs_value_us - vs->last_challenge_use.abs_value_us);
11358 GNUNET_break_op (0);
11359 finish_cmc_handling (cmc);
11360 return;
11361 }
11362
11363 {
11364 /* check signature */
11365 struct TransportValidationPS tvp = {
11367 .purpose.size = htonl (sizeof(tvp)),
11368 .validity_duration = tvr->validity_duration,
11369 .challenge = tvr->challenge
11370 };
11371
11372 if (
11373 GNUNET_OK !=
11375 &tvp,
11376 &tvr->signature,
11377 &cmc->im.sender.public_key))
11378 {
11379 GNUNET_break_op (0);
11380 finish_cmc_handling (cmc);
11381 return;
11382 }
11383 }
11384
11385 /* validity is capped by our willingness to keep track of the
11386 validation entry and the maximum the other peer allows */
11389 tvr->validity_duration),
11391 vs->validated_until =
11395 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
11396 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
11397 GNUNET_CRYPTO_random_block (&vs->challenge,
11398 sizeof(vs->challenge));
11399 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
11400 vs->validated_until,
11401 GNUNET_TIME_relative_multiply (vs->validation_rtt,
11403 if (GNUNET_TIME_absolute_cmp (vs->first_challenge_use, <, now))
11404 {
11406 "First challenge use is now %" PRIu64 " %s \n",
11407 vs->first_challenge_use.abs_value_us,
11408 GNUNET_sh2s (&vs->challenge.value));
11409 vs->first_challenge_use = now;
11410 }
11411 else
11413 "First challenge use is later %" PRIu64 " %s \n",
11414 vs->first_challenge_use.abs_value_us,
11415 GNUNET_sh2s (&vs->challenge.value));
11416 vs->last_challenge_use =
11417 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
11418 update_next_challenge_time (vs, vs->first_challenge_use);
11420 "Validation response %s from %s accepted, address valid until %s\n",
11421 GNUNET_sh2s (&tvr->challenge.value),
11422 GNUNET_i2s (&cmc->im.sender),
11424 /*memcpy (&hkey,
11425 &hc,
11426 sizeof (hkey));*/
11428 "Key %s for address %s map size %u contains %u\n",
11429 GNUNET_h2s (&vs->hc),
11430 vs->address,
11433 &vs->hc));
11434 /* NOTE: @e hc hashes the address only, so two `struct ValidationState's
11435 for different peers can collide here. That must not abort us. */
11436 if (GNUNET_YES !=
11439 &vs->hc,
11440 vs,
11443 "Address `%s' already tracked for revalidation\n",
11444 vs->address);
11447 NULL);
11448 vs->revalidation_task =
11453 "transport",
11454 &cmc->im.sender,
11456 vs->address,
11457 strlen (vs->address) + 1,
11458 vs->valid_until,
11461 vs);
11462 finish_cmc_handling (cmc);
11463
11464 /* Finally, we now possibly have a confirmed (!) working queue,
11465 update queue status (if queue still is around) */
11466 q = find_queue (&vs->pid, vs->address);
11467 if (NULL == q)
11468 {
11469 /* The challenge may have gone out on a queue whose address is not
11470 literally @e address: #check_validation_request_pending() matches on
11471 the IP alone, precisely so that a validation waiting for the NAT
11472 address `PROTO-IP:0' can be answered over the queue that the peer
11473 actually established from `PROTO-IP:port'. Insisting on an exact
11474 match here would silently discard that (successful!) validation and
11475 never bring the virtual link up. */
11476 q = find_queue_by_ip (&vs->pid, vs->address);
11477 }
11478 if (NULL == q)
11479 {
11481 "# Queues lost at time of successful validation",
11482 1,
11483 GNUNET_NO);
11484 return;
11485 }
11486 q->validated_until = vs->validated_until;
11487 q->pd.aged_rtt = vs->validation_rtt;
11488 n = q->neighbour;
11489 vl = lookup_virtual_link (&vs->pid);
11490 if (NULL == vl)
11491 {
11492 vl = GNUNET_new (struct VirtualLink);
11494 "Creating new virtual link %p to %s using direct neighbour!\n",
11495 vl,
11496 GNUNET_i2s (&vs->pid));
11497 vl->burst_addr = NULL;
11498 vl->confirmed = GNUNET_YES;
11499 vl->message_uuid_ctr =
11500 GNUNET_CRYPTO_random_u64 (UINT64_MAX);
11501 vl->target = n->pid;
11505 /* What the peer will grant us in its very first FLOW_CONTROL anyway
11506 (@e incoming_fc_window_size plus what we have sent, i.e. nothing).
11507 Starting at zero instead means a link that is up, validated and
11508 working carries nothing at all until an FC round trip completes --
11509 and if the peer cannot answer, not ever. */
11513 links,
11514 &vl->target,
11515 vl,
11517 vl->n = n;
11518 n->vl = vl;
11519 q->idle = GNUNET_YES;
11520 vl->visibility_task =
11521 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
11523 /* We lacked a confirmed connection to the target
11524 before, so tell CORE about it (finally!) */
11527 }
11528 else
11529 {
11530 /* Link was already up, remember n is also now available and we are done */
11531 if (NULL == vl->n)
11532 {
11533 vl->n = n;
11534 n->vl = vl;
11535 if (GNUNET_YES == vl->confirmed)
11537 "Virtual link to %s could now also use direct neighbour!\n",
11538 GNUNET_i2s (&vs->pid));
11539 }
11540 else
11541 {
11542 GNUNET_assert (n == vl->n);
11543 }
11544 if (GNUNET_NO == vl->confirmed)
11545 {
11546 vl->confirmed = GNUNET_YES;
11547 q->idle = GNUNET_YES;
11548 vl->visibility_task =
11549 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
11551 /* We lacked a confirmed connection to the target
11552 before, so tell CORE about it (finally!) */
11555 }
11556 }
11557}

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 11566 of file gnunet-service-transport.c.

11568{
11569 struct TransportClient *tc = cls;
11570 struct Neighbour *n;
11571 struct CommunicatorMessageContext *cmc =
11573
11574 cmc->tc = tc;
11575 cmc->im = *im;
11577 "Received message with size %u and flow control id %" PRIu64
11578 " via communicator from peer %s\n",
11579 ntohs (im->header.size),
11580 im->fc_id,
11581 GNUNET_i2s (&im->sender));
11582 cmc->im.neighbour_sender = cmc->im.sender;
11583 /* A communicator got this straight from @a im->sender, so the queues to
11584 that neighbour demonstrably still work. This is what #check_link_down()
11585 uses to bound how long a communicator that stopped working (without
11586 telling us) can keep a virtual link -- and CORE -- fooled. */
11587 if (NULL != (n = lookup_neighbour (&im->sender)))
11589 cmc->mh = (const struct GNUNET_MessageHeader *) &im[1];
11591}

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 11603 of file gnunet-service-transport.c.

11604{
11605 unsigned int number_of_addresses = ntohl (fc->number_of_addresses);
11606 uint16_t msize = ntohs (fc->header.size);
11607 const char *tgnas;
11608 size_t avail;
11609 size_t off;
11610
11611 (void) cls;
11613 "Flow control header size %u size of addresses %u number of addresses %u size of message struct %lu second struct %lu\n",
11614 ntohs (fc->header.size),
11615 ntohl (fc->size_of_addresses),
11616 ntohl (fc->number_of_addresses),
11617 sizeof(struct TransportFlowControlMessage),
11618 sizeof (struct TransportGlobalNattedAddress));
11619 if (0 == number_of_addresses)
11620 return GNUNET_OK;
11621 if (msize < sizeof(struct TransportFlowControlMessage))
11622 {
11623 GNUNET_break_op (0);
11624 return GNUNET_SYSERR;
11625 }
11626 avail = msize - sizeof(struct TransportFlowControlMessage);
11627 tgnas = (const char *) &fc[1];
11628 off = 0;
11629 /* Validate EVERY entry: checking only the aggregate size lets a single
11630 entry claim a bogus address_length and send #handle_flow_control()
11631 out of bounds. */
11632 for (unsigned int i = 0; i < number_of_addresses; i++)
11633 {
11634 const struct TransportGlobalNattedAddress *tgna;
11635 size_t alen;
11636
11637 if (avail - off < sizeof(struct TransportGlobalNattedAddress))
11638 {
11639 GNUNET_break_op (0);
11640 return GNUNET_SYSERR;
11641 }
11642 tgna = (const struct TransportGlobalNattedAddress *) &tgnas[off];
11643 off += sizeof(struct TransportGlobalNattedAddress);
11644 alen = ntohl (tgna->address_length);
11645 if (avail - off < alen)
11646 {
11647 GNUNET_break_op (0);
11648 return GNUNET_SYSERR;
11649 }
11650 off += alen;
11651 }
11652 return GNUNET_OK;
11653}

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 11684 of file gnunet-service-transport.c.

11687{
11688 struct VirtualLink *vl = cls;
11689 const char *slash;
11690 char *address_uri;
11691 char *prefix;
11692 char *uri_without_port;
11693
11694 slash = strrchr (uri, '/');
11695 if ((NULL == slash) || (slash - uri < 2))
11696 {
11697 GNUNET_break_op (0); /* @a uri comes from a remote HELLO */
11698 return;
11699 }
11700 prefix = GNUNET_strndup (uri, (slash - uri) - 2);
11701 slash++;
11702 GNUNET_asprintf (&address_uri,
11703 "%s-%s",
11704 prefix,
11705 slash);
11706
11707 uri_without_port = get_address_without_port (address_uri);
11709 "iterate_address_start_burst %s %s %s %s\n",
11710 (NULL == uri_without_port) ? "<unparsable>" : uri_without_port,
11711 uri,
11712 address_uri,
11713 slash);
11714 GNUNET_free (vl->burst_addr);
11715 if ((NULL != uri_without_port) &&
11716 (0 == strcmp (uri_without_port, slash)))
11717 vl->burst_addr = GNUNET_strdup (uri_without_port);
11718
11720 GNUNET_free (address_uri);
11721 GNUNET_free (uri_without_port);
11722}

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 11726 of file gnunet-service-transport.c.

11729{
11730 struct GNUNET_StartBurstCls *sb_cls = cls;
11731 struct VirtualLink *vl = sb_cls->vl;
11732 const struct GNUNET_MessageHeader *hello;
11734
11735 if (NULL != emsg)
11736 {
11738 "Got failure from PEERSTORE: %s\n",
11739 emsg);
11740 /* @a emsg comes with a NULL record, which means the iteration is over
11741 and PEERSTORE is releasing the context itself -- stopping it here as
11742 well would free it twice. Just drop our handle. */
11743 vl->ic = NULL;
11744 free_burst_cls (sb_cls);
11745 return;
11746 }
11747 if (NULL == record)
11748 {
11750 "Hello iteration end for %s\n",
11751 GNUNET_i2s (&vl->target));
11752 /* PEERSTORE destroys the context itself once it signals the end. */
11753 vl->ic = NULL;
11754 free_burst_cls (sb_cls);
11755 return;
11756 }
11757
11759 "check_for_burst_address\n");
11760 /* @a hello was published by a remote peer, it may well be malformed. */
11761 hello = hello_from_record (record);
11762 if (NULL != hello)
11763 {
11764 parser = GNUNET_HELLO_parser_from_msg (hello, &record->peer);
11765 if (NULL != parser)
11766 {
11769 vl);
11770 GNUNET_HELLO_parser_free (parser);
11771 }
11772 }
11773
11774 /* MUST clear @e ic: #GNUNET_PEERSTORE_iteration_stop() frees it, and
11775 #free_virtual_link() would otherwise stop it a second time. */
11776 if (NULL != vl->ic)
11777 {
11779 vl->ic = NULL;
11780 }
11781 free_burst_cls (sb_cls);
11782}

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 11786 of file gnunet-service-transport.c.

11787{
11789}

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 11793 of file gnunet-service-transport.c.

11794{
11795 struct GNUNET_StartBurstCls *sb_cls = cls;
11796 struct VirtualLink *vl = sb_cls->vl;
11797 struct GNUNET_TRANSPORT_StartBurst *sb;
11798 struct GNUNET_MQ_Envelope *env;
11799 char *uri_without_port = vl->burst_addr;
11800
11801 burst_task = NULL;
11802 burst_task_cls = NULL;
11803 if (NULL == uri_without_port)
11804 {
11805 /* Lost the address in the meantime, nothing to burst to. */
11806 free_burst_cls (sb_cls);
11807 return;
11808 }
11809 /*char buf[strlen (uri_without_port) + 1];
11810
11811 GNUNET_memcpy (buf, uri_without_port, strlen (uri_without_port));
11812 buf[strlen (uri_without_port)] = '\0';*/
11813 env =
11815 strlen (uri_without_port) + 1,
11817 sb->rtt = GNUNET_TIME_relative_hton (sb_cls->rtt);
11818 sb->pid = vl->target;
11819 memcpy (&sb[1], uri_without_port, strlen (uri_without_port) + 1);
11820 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
11821 {
11822 if (CT_COMMUNICATOR != tc->type)
11823 continue; /* MUST come first: the log below reads the union! */
11825 "iterate_address_start_burst client tc prefix %s\n",
11826 tc->details.communicator.address_prefix);
11827 if (GNUNET_YES == tc->details.communicator.can_burst)
11828 {
11830 "iterate_address_start_burst %s call %lu %u rtt %lu\n",
11831 uri_without_port,
11832 strlen (uri_without_port),
11833 ntohs (sb->header.size),
11834 (unsigned long) sb_cls->rtt.rel_value_us);
11835 GNUNET_MQ_send (tc->mq, env);
11836 env = NULL; /* MQ took ownership */
11840 60),
11842 NULL);
11843 // TODO We need some algo to choose from available communicators. Can we run two bursts at once? Atm we only implemented udp burst.
11844 break;
11845 }
11846 }
11847 if (NULL != env)
11849 free_burst_cls (sb_cls);
11850}

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 11880 of file gnunet-service-transport.c.

11881{
11882 struct GNUNET_StartBurstCls *sb_cls = cls;
11883 struct VirtualLink *vl = sb_cls->vl;
11884
11885 if (GNUNET_YES != use_burst)
11886 {
11887 /* MUST release: nobody else owns @a sb_cls, and #handle_flow_control()
11888 allocates one for every FLOW_CONTROL message we receive. */
11890 return;
11891 }
11893 "burst_task %p ready %s burst addr %s (%p)\n",
11894 burst_task,
11895 sb_cls->sync_ready ? "yes" : "no",
11896 vl->burst_addr,
11897 vl->burst_addr);
11898 if (NULL != burst_task && GNUNET_NO == sb_cls->sync_ready)
11899 {
11900 /* Cancel the pending burst. Both closures (the scheduled task's and
11901 ours) are ours to release. */
11903
11905 burst_task = NULL;
11906 burst_task_cls = NULL;
11907 if ((NULL != pending) && (pending != sb_cls))
11909 free_burst_cls (sb_cls);
11910 return;
11911 }
11912 if (GNUNET_NO == burst_running && NULL != vl->burst_addr && NULL == burst_task
11913 )
11914 {
11916 &start_burst,
11917 sb_cls);
11918 burst_task_cls = sb_cls;
11919 }
11920 else if (NULL == vl->burst_addr)
11921 {
11922 if (NULL != vl->ic)
11923 {
11924 /* An address lookup is already running for this link; starting a
11925 second one would leak the first. */
11926 free_burst_cls (sb_cls);
11927 return;
11928 }
11930 "peerstore",
11931 &vl->target,
11934 sb_cls);
11935 }
11936 else
11937 {
11938 /* A burst is already running or already scheduled; we have no use for
11939 this closure. */
11940 free_burst_cls (sb_cls);
11941 }
11942}

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 11952 of file gnunet-service-transport.c.

11953{
11954 struct VirtualLink *vl = cls;
11955
11956 vl->unconfirmed_timeout_task = NULL;
11957 if ((GNUNET_YES == vl->confirmed) ||
11958 (NULL != vl->n) ||
11959 (NULL != vl->dv))
11960 return; /* got promoted in the meantime, its owner will clean up */
11962 "Discarding unconfirmed virtual link to %s\n",
11963 GNUNET_i2s (&vl->target));
11965 "# Unconfirmed virtual links timed out",
11966 1,
11967 GNUNET_NO);
11968 free_virtual_link (vl);
11969}

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 11981 of file gnunet-service-transport.c.

11982{
11983 struct CommunicatorMessageContext *cmc = cls;
11984 struct VirtualLink *vl;
11986 uint32_t seq;
11987 struct GNUNET_TIME_Absolute st;
11988 uint64_t os;
11989 uint64_t wnd;
11990 uint32_t random;
11991
11993 "Received FC from %s\n", GNUNET_i2s (&cmc->im.sender));
11994 vl = lookup_virtual_link (&cmc->im.sender);
11995 if (NULL == vl)
11996 {
11997 vl = GNUNET_new (struct VirtualLink);
11999 "No virtual link for %p FC creating new unconfirmed virtual link to %s!\n",
12000 vl,
12001 GNUNET_i2s (&cmc->im.sender));
12002 vl->burst_addr = NULL;
12003 vl->confirmed = GNUNET_NO;
12004 vl->message_uuid_ctr =
12005 GNUNET_CRYPTO_random_u64 (UINT64_MAX);
12006 vl->target = cmc->im.sender;
12010 /* What the peer will grant us in its very first FLOW_CONTROL anyway
12011 (@e incoming_fc_window_size plus what we have sent, i.e. nothing).
12012 Starting at zero instead means a link that is up, validated and
12013 working carries nothing at all until an FC round trip completes --
12014 and if the peer cannot answer, not ever. */
12018 links,
12019 &vl->target,
12020 vl,
12022 /* Nothing else owns this link yet, so it must reap itself if it never
12023 becomes confirmed -- otherwise any peer can make us allocate
12024 VirtualLinks without bound. */
12028 vl);
12029 }
12030 if (GNUNET_YES != vl->confirmed)
12031 {
12032 /* The peer flow-controls us, so it has a confirmed link to us -- but an
12033 unconfirmed link carries nothing and is never reported to CORE. Only
12034 #handle_validation_response() breaks that tie, and nothing here used
12035 to ask for one, so the pair could sit one-way until the peer's own
12036 four hour revalidation came round. */
12038 }
12039 if (NULL != vl->n)
12040 {
12041 for (struct Queue *q = vl->n->queue_head; NULL != q; q = q->next_neighbour)
12042 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
12043 }
12044
12046 "remaining %lu timeout for neighbour %p\n",
12047 (unsigned long) GNUNET_TIME_absolute_get_remaining (q_timeout).
12048 rel_value_us,
12049 vl->n);
12050 if (NULL == vl->n ||
12051 0 == GNUNET_TIME_absolute_get_remaining (q_timeout).rel_value_us)
12052 {
12053 struct GNUNET_TIME_Relative rtt;
12054 struct GNUNET_BurstSync burst_sync;
12055 struct GNUNET_StartBurstCls *bcls;
12056
12057 if (NULL != vl->sb_cls)
12058 {
12059 /* A burst attempt for this link is already in flight. Allocating a
12060 second closure would orphan the first one: @e sb_cls is how
12061 #free_virtual_link() finds (and cancels) the pending #burst_task,
12062 and a peer that just keeps sending us FLOW_CONTROL messages would
12063 otherwise make us leak one closure per message. */
12065 "Burst attempt to %s already pending\n",
12066 GNUNET_i2s (&vl->target));
12067 }
12068 else
12069 {
12070 bcls = GNUNET_new (struct GNUNET_StartBurstCls);
12071 bcls->vl = vl;
12072 vl->sb_cls = bcls;
12073 if (NULL != vl->dv)
12074 rtt = calculate_rtt (vl->dv);
12075 else
12077 burst_sync.rtt_average = fc->rtt;
12078 bcls->rtt = GNUNET_TIME_relative_ntoh (burst_sync.rtt_average);
12079 /* @e sync_ready of `struct GNUNET_BurstSync' is a host-order enum. */
12080 burst_sync.sync_ready =
12081 (enum GNUNET_GenericReturnValue) ntohl (fc->sync_ready);
12082
12083 /* NOTE: #GNUNET_is_burst_ready() does NOT invoke the task unless both
12084 RTT estimates are known and close; #queue_burst() is thus not
12085 guaranteed to run, which is why @e sb_cls stays owned by @a vl. */
12087 &burst_sync,
12088 &queue_burst,
12089 bcls);
12090 }
12091 }
12092 if (0 != ntohl (fc->number_of_addresses))
12093 {
12094 unsigned int number_of_addresses = ntohl (fc->number_of_addresses);
12095 const char *tgnas;
12096 unsigned int off = 0;
12097
12098 tgnas = (const char *) &fc[1];
12099
12100 for (unsigned int i = 0; i < number_of_addresses; i++)
12101 {
12102 struct TransportGlobalNattedAddress *tgna;
12103 char *addr;
12104 uint32_t address_length;
12105
12106 tgna = (struct TransportGlobalNattedAddress*) &tgnas[off];
12107 addr = (char *) &tgna[1];
12108 address_length = ntohl (tgna->address_length);
12109 off += sizeof(struct TransportGlobalNattedAddress) + address_length;
12110
12111 /* NOTE: the address is NOT 0-terminated (it comes straight off the
12112 wire), it must be printed with an explicit precision. */
12114 "received address %.*s length %u\n",
12115 (int) address_length,
12116 addr,
12118
12119 if (NULL != nh)
12120 GNUNET_NAT_add_global_address (nh, addr, ntohl (tgna->address_length));
12121 }
12122 }
12124 if (st.abs_value_us < vl->last_fc_timestamp.abs_value_us)
12125 {
12127 "FC dropped: Message out of order\n");
12128 /* out of order, drop */
12130 "# FC dropped: message out of order",
12131 1,
12132 GNUNET_NO);
12133 finish_cmc_handling (cmc);
12134 return;
12135 }
12136 seq = ntohl (fc->seq);
12137 if (seq < vl->last_fc_seq)
12138 {
12139 /* Wrap-around/reset of other peer; start all counters from zero */
12141 }
12142 vl->last_fc_seq = seq;
12143 vl->last_fc_timestamp = st;
12144 /* The peer is answering, so the backoff in #consider_sending_fc() starts
12145 over: @e fc_retransmit_count counts *unanswered* rounds. */
12146 vl->fc_retransmit_count = 0;
12148 os = GNUNET_ntohll (fc->outbound_sent);
12150 (int64_t) (os - vl->incoming_fc_window_size_used);
12152 "Received FC from %s, seq %u, new window %llu (loss at %lld)\n",
12153 GNUNET_i2s (&vl->target),
12154 (unsigned int) seq,
12155 (unsigned long long) vl->outbound_fc_window_size,
12156 (long long) vl->incoming_fc_window_size_loss);
12158 random = GNUNET_CRYPTO_random_u32 (UINT32_MAX);
12159 /* NOTE: this must NOT be restricted to a confirmed link. @e
12160 outbound_fc_window_size starts at zero and is raised *only* here, from
12161 the peer's FC. So a peer whose link to us is confirmed while ours to it
12162 is not cannot send us a single byte until we answer -- and it is exactly
12163 that peer that keeps asking. Staying quiet deadlocks the pair: it shows
12164 an established virtual link with messages pending forever, we show none,
12165 and CORE never completes its handshake in either direction. */
12166 if ((wnd < vl->incoming_fc_window_size
12170 (0 == random % FC_NO_CHANGE_REPLY_PROBABILITY))
12171 {
12173 "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",
12174 (unsigned long long) wnd,
12175 (unsigned long long) vl->incoming_fc_window_size,
12176 (unsigned long long) vl->last_outbound_window_size_received,
12179 }
12180 if ((wnd == vl->incoming_fc_window_size
12184 {
12186 "Slowing FC transmission to %s to keepalive rate: peer is current at window %llu\n",
12187 GNUNET_i2s (&vl->target),
12188 (unsigned long long) wnd);
12189 /* NOTE: this used to also require @e fc_retransmit_task to be non-NULL
12190 and did nothing at all otherwise -- so a link whose chain had ended
12191 (see #consider_sending_fc()) could never pick the keepalive back up,
12192 even though the peer was demonstrably still talking to us. */
12193 if (NULL != vl->fc_retransmit_task)
12195 vl->fc_retransmit_count = 0;
12196 /* Drop to the keepalive rate rather than stopping outright. There is
12197 nothing left to retransmit -- but if we go completely quiet, and the
12198 peer does the same for the same reason, then neither end sees any
12199 traffic and #check_link_down() tears down a perfectly healthy link
12200 after #NEIGHBOUR_LIVENESS_TIMEOUT. One tiny FC message every
12201 #FC_KEEPALIVE_INTERVAL is what keeps @e last_inbound moving on the
12202 other side (and, via their reply, on ours). */
12203 vl->fc_retransmit_task =
12206 vl);
12207 }
12209 /* FC window likely increased, check transmission possibilities! */
12211 finish_cmc_handling (cmc);
12212}

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 12322 of file gnunet-service-transport.c.

12324{
12325 struct TransportClient *tc = cls;
12326
12327 if (CT_COMMUNICATOR != tc->type)
12328 {
12329 GNUNET_break (0);
12330 return GNUNET_SYSERR;
12331 }
12333 return GNUNET_OK;
12334}

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 12343 of file gnunet-service-transport.c.

12344{
12345 if (pm->msg_uuid_set)
12346 return;
12347 pm->msg_uuid.uuid = pm->vl->message_uuid_ctr++;
12349}

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 12361 of file gnunet-service-transport.c.

12364{
12365 struct PendingAcknowledgement *pa;
12366
12367 pa = GNUNET_new (struct PendingAcknowledgement);
12368 pa->queue = queue;
12369 pa->dvh = dvh;
12370 pa->pm = pm;
12371 do
12372 {
12374 sizeof(pa->ack_uuid));
12375 }
12378 &pa->ack_uuid.value,
12379 pa,
12381 GNUNET_CONTAINER_MDLL_insert (queue, queue->pa_head, queue->pa_tail, pa);
12383 if (NULL != dvh)
12386 pa->message_size = pm->bytes_msg;
12388 "Waiting for ACKnowledgment `%s' for <%" PRIu64 ">\n",
12390 pm->logging_uuid);
12391 return pa;
12392}

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 12407 of file gnunet-service-transport.c.

12410{
12411 struct PendingAcknowledgement *pa;
12412 struct PendingMessage *ff;
12413 uint16_t mtu;
12414 uint16_t msize;
12415
12416 mtu = (UINT16_MAX == queue->mtu)
12417 ? UINT16_MAX - sizeof(struct GNUNET_TRANSPORT_SendMessageTo)
12418 : queue->mtu;
12420 "Fragmenting message <%" PRIu64
12421 "> with size %u to %s for MTU %u\n",
12422 pm->logging_uuid,
12423 pm->bytes_msg,
12424 GNUNET_i2s (&pm->vl->target),
12425 (unsigned int) mtu);
12428 "Fragmenting message %" PRIu64 " <%" PRIu64
12429 "> with size %u to %s for MTU %u\n",
12430 pm->msg_uuid.uuid,
12431 pm->logging_uuid,
12432 pm->bytes_msg,
12433 GNUNET_i2s (&pm->vl->target),
12434 (unsigned int) mtu);
12435
12436 /* This invariant is established in #handle_add_queue_message() */
12437 GNUNET_assert (mtu > sizeof(struct TransportFragmentBoxMessage));
12438
12439 /* select fragment for transmission, descending the tree if it has
12440 been expanded until we are at a leaf or at a fragment that is small
12441 enough
12442 */
12443 ff = pm;
12444 msize = ff->bytes_msg;
12445
12446 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
12447 (ff->frag_off == msize) && (NULL != ff->head_frag))
12448 {
12449 ff = ff->head_frag; /* descent into fragmented fragments */
12450 msize = ff->bytes_msg - sizeof(struct TransportFragmentBoxMessage);
12451 }
12452
12453 if (((ff->bytes_msg > mtu) || (pm == ff)) && (ff->frag_off < msize))
12454 {
12455 /* Did not yet calculate all fragments, calculate next fragment */
12456 struct PendingMessage *frag;
12457 struct TransportFragmentBoxMessage tfb;
12458 const char *orig;
12459 char *msg;
12460 uint16_t fragmax;
12461 uint16_t fragsize;
12462 uint16_t msize_ff;
12463 uint16_t xoff = 0;
12464 pm->frag_count++;
12465
12466 orig = (const char *) &ff[1];
12467 msize_ff = ff->bytes_msg;
12468 if (pm != ff)
12469 {
12470 const struct TransportFragmentBoxMessage *tfbo;
12471
12472 tfbo = (const struct TransportFragmentBoxMessage *) orig;
12473 orig += sizeof(struct TransportFragmentBoxMessage);
12474 msize_ff -= sizeof(struct TransportFragmentBoxMessage);
12475 xoff = ntohs (tfbo->frag_off);
12476 }
12477 fragmax = mtu - sizeof(struct TransportFragmentBoxMessage);
12478 fragsize = GNUNET_MIN (msize_ff - ff->frag_off, fragmax);
12479 frag =
12480 GNUNET_malloc (sizeof(struct PendingMessage)
12481 + sizeof(struct TransportFragmentBoxMessage) + fragsize);
12483 "3 created pm %p from pm %p storing vl %p from pm %p\n",
12484 frag,
12485 ff,
12486 pm->vl,
12487 pm);
12489 frag->vl = pm->vl;
12490 frag->frag_parent = ff;
12491 frag->timeout = pm->timeout;
12492 frag->bytes_msg = sizeof(struct TransportFragmentBoxMessage) + fragsize;
12493 frag->pmt = PMT_FRAGMENT_BOX;
12494 msg = (char *) &frag[1];
12495 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
12496 tfb.header.size =
12497 htons (sizeof(struct TransportFragmentBoxMessage) + fragsize);
12498 pa = prepare_pending_acknowledgement (queue, dvh, frag);
12499 tfb.ack_uuid = pa->ack_uuid;
12500 tfb.msg_uuid = pm->msg_uuid;
12501 tfb.frag_off = htons (ff->frag_off + xoff);
12502 tfb.msg_size = htons (pm->bytes_msg);
12503 memcpy (msg, &tfb, sizeof(tfb));
12504 memcpy (&msg[sizeof(tfb)], &orig[ff->frag_off], fragsize);
12506 ff->tail_frag, frag);
12507 ff->frag_off += fragsize;
12508 ff = frag;
12509 }
12510
12511 if (pm == ff)
12512 {
12513 /* Neither the descent nor the branch above moved us off @a pm, so there
12514 is no fragment to send: @e head_frag is empty *and* @e frag_off says
12515 everything was already cut. completed_pending_message() leaves
12516 exactly that state behind when the last outstanding fragment is
12517 acknowledged but its condition for finishing the root does not hold
12518 (@e frag_off having been advanced past the boxed payload size, or the
12519 root being a reliability box). The rotate below then dereferences
12520 @e frag_parent, which is NULL for the message on @e pending_msg_head.
12521
12522 Report "nothing to fragment" instead; the caller reschedules. */
12523 GNUNET_break (0);
12524 return NULL;
12525 }
12526 /* Move head to the tail and return it */
12530 ff);
12534 ff);
12535
12536 return ff;
12537}

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 12553 of file gnunet-service-transport.c.

12556{
12558 struct PendingAcknowledgement *pa;
12559 struct PendingMessage *bpm;
12560 char *msg;
12561
12562 if ((PMT_CORE != pm->pmt) && (PMT_DV_BOX != pm->pmt))
12563 return pm; /* already fragmented or reliability boxed, or control message:
12564 do nothing */
12565 if (NULL != pm->bpm)
12566 return pm->bpm; /* already computed earlier: do nothing */
12567 // TODO I guess we do not need this assertion. We might have a DLL with
12568 // fragments, because the MTU changed, and we do not need to fragment anymore.
12569 // But we should keep the fragments until message was completed, because
12570 // the MTU might change again.
12571 // GNUNET_assert (NULL == pm->head_frag);
12572 if (pm->bytes_msg + sizeof(rbox) > UINT16_MAX)
12573 {
12574 /* failed hard */
12575 GNUNET_break (0);
12577 return NULL;
12578 }
12579
12580 pa = prepare_pending_acknowledgement (queue, dvh, pm);
12581
12582 bpm = GNUNET_malloc (sizeof(struct PendingMessage) + sizeof(rbox)
12583 + pm->bytes_msg);
12585 "4 created pm %p storing vl %p from pm %p\n",
12586 bpm,
12587 pm->vl,
12588 pm);
12590 bpm->vl = pm->vl;
12591 bpm->frag_parent = pm;
12592 // Why was this needed?
12593 // GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
12594 bpm->timeout = pm->timeout;
12596 bpm->bytes_msg = pm->bytes_msg + sizeof(rbox);
12598 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
12599 rbox.header.size = htons (sizeof(rbox) + pm->bytes_msg);
12600 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
12601
12602 rbox.ack_uuid = pa->ack_uuid;
12603 msg = (char *) &bpm[1];
12604 memcpy (msg, &rbox, sizeof(rbox));
12605 memcpy (&msg[sizeof(rbox)], &pm[1], pm->bytes_msg);
12606 pm->bpm = bpm;
12608 "Preparing reliability box for message <%" PRIu64
12609 "> of size %d (%d) to %s on queue %s\n",
12610 pm->logging_uuid,
12611 pm->bytes_msg,
12612 ntohs (((const struct GNUNET_MessageHeader *) &pm[1])->size),
12613 GNUNET_i2s (&pm->vl->target),
12614 queue->address);
12615 return bpm;
12616}

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 12620 of file gnunet-service-transport.c.

12622{
12623 struct VirtualLink *vl = pm->vl;
12624 struct PendingMessage *pos;
12625
12626 /* Only a message without a parent is on vl->pending_msg_head; anything
12627 else is not ours to reorder and MDLL_remove() would abort on it. */
12628 if ((NULL == vl) ||
12629 (NULL != pm->frag_parent) ||
12630 ((NULL == pm->prev_vl) && (vl->pending_msg_head != pm)))
12631 {
12632 GNUNET_break (0);
12633 return;
12634 }
12635 /* re-insert sort in neighbour list */
12639 pm);
12640 pos = vl->pending_msg_tail;
12641 while ((NULL != pos) &&
12643 pos = pos->prev_vl;
12647 pos,
12648 pm);
12649}

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 12653 of file gnunet-service-transport.c.

12654{
12655 struct PendingMessage *pos;
12656 /* MUST be initialised: for a leaf the loop below never runs */
12658
12659 pos = pm->head_frag;
12660 while (NULL != pos)
12661 {
12663 GNUNET_NO == check_next_attempt_tree (pos, root))
12665 else
12666 {
12668 break;
12669 }
12670 pos = pos->next_frag;
12671 }
12672
12673 return frags_in_flight;
12674}

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 12678 of file gnunet-service-transport.c.

12679{
12680 struct PendingMessage *pos;
12681
12682 pos = pm->head_frag;
12683 while (NULL != pos)
12684 {
12687 pos = pos->next_frag;
12688 }
12689}

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 12701 of file gnunet-service-transport.c.

12703{
12704 if (NULL == pm->frag_parent)
12705 {
12706 pm->next_attempt = next_attempt;
12708 "Next attempt for message <%" PRIu64 "> set to %" PRIu64 "\n",
12709 pm->logging_uuid,
12710 next_attempt.abs_value_us);
12711 reorder_root_pm (pm, next_attempt);
12712 }
12713 else if ((PMT_RELIABILITY_BOX == pm->pmt) || (PMT_DV_BOX == pm->pmt))// || (PMT_FRAGMENT_BOX == pm->pmt))
12714 {
12715 struct PendingMessage *root = pm->frag_parent;
12716
12717 while (NULL != root->frag_parent)
12718 root = root->frag_parent;
12720 "Next attempt for root message <%" PRIu64 "> set to %s\n",
12721 root->logging_uuid,
12723 root->next_attempt = next_attempt;
12725 }
12726 else
12727 {
12728 struct PendingMessage *root = pm->frag_parent;
12729
12730 while (NULL != root->frag_parent && PMT_DV_BOX != root->pmt)
12731 root = root->frag_parent;
12732
12734 "frag_count next attempt %u\n",
12735 root->frag_count);
12736
12737 if (GNUNET_NO == root->frags_in_flight)
12738 {
12739 root->next_attempt = next_attempt;
12741 root->frags_in_flight_round++;
12743 "Next attempt for fragmented message <%" PRIu64 "> (<%" PRIu64
12744 ">)set to %" PRIu64 "\n",
12745 pm->logging_uuid,
12746 root->logging_uuid,
12748 }
12749
12750 pm->next_attempt = root->next_attempt;
12753
12754 if (root->bytes_msg == root->frag_off)
12755 root->frags_in_flight = check_next_attempt_tree (root, root);
12756 else
12758
12759 if (GNUNET_NO == root->frags_in_flight)
12760 {
12761 /* `root' deliberately stops at a DV box, which is itself a child of
12762 the message on vl->pending_msg_head. Walk the rest of the way for
12763 the reorder: only the parentless message is on that list. */
12764 struct PendingMessage *vl_root = root;
12765
12766 while (NULL != vl_root->frag_parent)
12767 vl_root = vl_root->frag_parent;
12768 vl_root->next_attempt = root->next_attempt;
12770 "We have no fragments in flight for message %" PRIu64
12771 ", reorder root %" PRIu64 "! Next attempt is %" PRIu64 "\n",
12772 root->logging_uuid,
12773 vl_root->logging_uuid,
12774 vl_root->next_attempt.abs_value_us);
12775 reorder_root_pm (vl_root, vl_root->next_attempt);
12776 }
12777 else
12778 {
12779 double factor = ((double) root->frag_count - 1)
12780 / (double) root->frag_count;
12781 struct GNUNET_TIME_Relative s1;
12782 struct GNUNET_TIME_Relative s2;
12783 struct GNUNET_TIME_Relative plus_mean =
12786 next_attempt);
12787
12789 "frag_count %u after factor\n",
12790 root->frag_count);
12792 factor);
12793 s2 = GNUNET_TIME_relative_divide (plus,
12794 root->frag_count);
12795 plus_mean = GNUNET_TIME_relative_add (s1, s2);
12798 "We have fragments in flight for message %" PRIu64
12799 ", do not reorder root! Actual next attempt %" PRIu64 "\n",
12800 root->logging_uuid,
12802 }
12803 }
12804}

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 12871 of file gnunet-service-transport.c.

12876{
12877 struct GNUNET_TIME_Absolute now;
12878
12879 now = GNUNET_TIME_absolute_get ();
12880 /* NOTE: @a sc accumulates across calls -- #transmit_on_queue() zeroes it
12881 once and then runs us for the direct link and for every DV hop in turn.
12882 Clearing the verdict here made each call discard what the previous ones
12883 found, so a message that was too early on the direct link was forgotten
12884 as soon as one DV hop had nothing to offer, and nothing rescheduled the
12885 queue at all. */
12886 for (struct PendingMessage *pos = vl->pending_msg_head; NULL != pos;
12887 pos = pos->next_vl)
12888 {
12889 size_t real_overhead = overhead;
12890 int frag;
12891 int relb;
12892
12893 if ((NULL != dvh) && (PMT_DV_BOX == pos->pmt))
12894 {
12896 "DV messages must not be DV-routed to next hop!\n");
12897 continue; /* DV messages must not be DV-routed to next hop! */
12898 }
12899 if (pos->next_attempt.abs_value_us > now.abs_value_us)
12900 {
12901 if (GNUNET_YES == pos->frags_in_flight)
12902 {
12903 sc->frags_in_flight = GNUNET_YES;
12905 "Fragments in flight for message %" PRIu64 "\n",
12906 pos->logging_uuid);
12907 }
12908 else
12909 {
12911 "Maybe too early, because message are sorted by next_attempt, if there are no fragments in flight.Checked message %"
12912 PRIu64 "\n",
12913 pos->logging_uuid);
12914 /* The *earliest* deadline is the one to come back for: @e
12915 pending_msg_head is sorted by @e next_attempt, so overwriting
12916 this on every iteration left the largest delay of the whole
12917 list -- the queue then slept past every message but the last
12918 one. Across the calls for the direct link and each DV hop the
12919 same argument applies, hence the min() rather than an
12920 assignment. */
12921 sc->to_early_retry_delay =
12922 (GNUNET_YES == sc->to_early)
12923 ? GNUNET_TIME_relative_min (sc->to_early_retry_delay,
12925 pos->next_attempt))
12926 : GNUNET_TIME_absolute_get_remaining (pos->next_attempt);
12927 sc->to_early = GNUNET_YES;
12928 continue;
12929 }
12930 // break; /* too early for all messages, they are sorted by next_attempt */
12931 }
12932 if (NULL != pos->qe)
12933 {
12935 "not eligible\n");
12936 continue; /* not eligible */
12937 }
12938 sc->consideration_counter++;
12939 /* determine if we have to fragment, if so add fragmentation
12940 overhead! */
12942 "check %" PRIu64 " for sc->best\n",
12943 pos->logging_uuid);
12944 frag = GNUNET_NO;
12945 if (((0 != queue->mtu) &&
12946 (pos->bytes_msg + real_overhead > queue->mtu)) ||
12947 (pos->bytes_msg > UINT16_MAX - sizeof(struct
12949 ||
12950 (NULL != pos->head_frag /* fragments already exist, should
12951 respect that even if MTU is UINT16_MAX for
12952 this queue */))
12953 {
12955 "fragment msg with size %u, realoverhead is %lu\n",
12956 pos->bytes_msg,
12957 real_overhead);
12958 frag = GNUNET_YES;
12959 if (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc)
12960 {
12961 /* FIXME-FRAG-REL-UUID: we could use an optimized, shorter fragmentation
12962 header without the ACK UUID when using a *reliable* channel! */
12963 }
12964 real_overhead = overhead + sizeof(struct TransportFragmentBoxMessage);
12965 }
12966 /* determine if we have to reliability-box, if so add reliability box
12967 overhead */
12968 relb = GNUNET_NO;
12969 if ((GNUNET_NO == frag) &&
12970 (0 == (pos->prefs & GNUNET_MQ_PREF_UNRELIABLE)) &&
12971 (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc))
12972 {
12973 real_overhead += sizeof(struct TransportReliabilityBoxMessage);
12974
12975 if ((0 != queue->mtu) && (pos->bytes_msg + real_overhead > queue->mtu))
12976 {
12977 frag = GNUNET_YES;
12978 real_overhead = overhead + sizeof(struct TransportFragmentBoxMessage);
12979 }
12980 else
12981 {
12982 relb = GNUNET_YES;
12983 }
12985 "Create reliability box of msg with size %u, realoverhead is %lu %u %u %u\n",
12986 pos->bytes_msg,
12987 real_overhead,
12988 queue->mtu,
12989 frag,
12990 relb);
12991 }
12992
12993 /* Finally, compare to existing 'best' in sc to see if this 'pos' pending
12994 message would beat it! */
12995 if (GNUNET_NO == sc->frags_in_flight && NULL != sc->best)
12996 {
12997 /* CHECK if pos fits queue BETTER (=smaller) than pm, if not: continue;
12998 OPTIMIZE-ME: This is a heuristic, which so far has NOT been
12999 experimentally validated. There may be some huge potential for
13000 improvement here. Also, we right now only compare how well the
13001 given message fits _this_ queue, and do not consider how well other
13002 queues might suit the message. Taking other queues into consideration
13003 may further improve the result, but could also be expensive
13004 in terms of CPU time. */
13005 long long sc_score = sc->frag * 40 + sc->relb * 20 + sc->real_overhead;
13006 long long pm_score = frag * 40 + relb * 20 + real_overhead;
13007 long long time_delta =
13008 (sc->best->next_attempt.abs_value_us - pos->next_attempt.abs_value_us)
13009 / 1000LL;
13010
13011 /* "time_delta" considers which message has been 'ready' for transmission
13012 for longer, if a message has a preference for low latency, increase
13013 the weight of the time_delta by 10x if it is favorable for that message */
13014 if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
13015 (0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)))
13016 time_delta *= 10; /* increase weight (always, both are low latency) */
13017 else if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
13018 (time_delta > 0))
13019 time_delta *= 10; /* increase weight, favors 'pos', which is low latency */
13020 else if ((0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
13021 (time_delta < 0))
13022 time_delta *= 10; /* increase weight, favors 'sc->best', which is low latency */
13023 if (0 != queue->mtu)
13024 {
13025 /* Grant bonus if we are below MTU, larger bonus the closer we will
13026 be to the MTU */
13027 if (queue->mtu > sc->real_overhead + sc->best->bytes_msg)
13028 sc_score -= queue->mtu - (sc->real_overhead + sc->best->bytes_msg);
13029 if (queue->mtu > real_overhead + pos->bytes_msg)
13030 pm_score -= queue->mtu - (real_overhead + pos->bytes_msg);
13031 }
13032 if (sc_score + time_delta > pm_score)
13033 {
13035 "sc_score of %" PRIu64 " larger, keep sc->best %" PRIu64
13036 "\n",
13037 pos->logging_uuid,
13038 sc->best->logging_uuid);
13039 continue; /* sc_score larger, keep sc->best */
13040 }
13041 }
13042 sc->best = pos;
13043 sc->dvh = dvh;
13044 sc->frag = frag;
13045 sc->relb = relb;
13046 sc->real_overhead = real_overhead;
13047 }
13048}

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 13062 of file gnunet-service-transport.c.

13066{
13067 struct PendingMessageScoreContext *sc = cls;
13068 struct PendingMessage *pm = sc->best;
13069 struct PendingMessage *bpm;
13070 uint16_t bsize = ntohs (hdr->size);
13071
13072 GNUNET_assert (NULL == pm->bpm);
13073 bpm = GNUNET_malloc (sizeof(struct PendingMessage) + bsize);
13075 "5 created pm %p storing vl %p from pm %p\n",
13076 bpm,
13077 pm->vl,
13078 pm);
13080 bpm->pmt = PMT_DV_BOX;
13081 bpm->vl = pm->vl;
13082 bpm->timeout = pm->timeout;
13083 bpm->bytes_msg = bsize;
13084 bpm->frag_parent = pm;
13087 "Creating DV Box %" PRIu64 " for original message %" PRIu64
13088 " (next hop is %s)\n",
13090 pm->logging_uuid,
13091 GNUNET_i2s (&next_hop->pid));
13092 memcpy (&bpm[1], hdr, bsize);
13093 pm->bpm = bpm;
13094}

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 13410 of file gnunet-service-transport.c.

13412{
13413 struct TransportClient *tc = cls;
13414
13415 if (CT_COMMUNICATOR != tc->type)
13416 {
13417 GNUNET_break (0);
13419 return;
13420 }
13421 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
13422 queue = queue->next_client)
13423 {
13424 struct Neighbour *neighbour = queue->neighbour;
13425
13426 if ((ntohl (dqm->qid) != queue->qid) ||
13427 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
13428 continue;
13430 "Dropped queue %s to peer %s\n",
13431 queue->address,
13432 GNUNET_i2s (&neighbour->pid));
13433 free_queue (queue);
13435 return;
13436 }
13437 /* Not finding the queue is a race, not a protocol violation: we may have
13438 freed it ourselves already, or the communicator may be tearing down a
13439 queue we never fully learned about. Do NOT drop the client over it --
13440 that runs #client_disconnect_cb(), which frees *every* queue this
13441 communicator owns, so one stale QUEUE_TEARDOWN would disconnect us from
13442 every peer it serves at once. Compare #handle_send_message_ack(), which
13443 tolerates the same lookup miss. */
13445 "QUEUE_TEARDOWN for unknown queue QID %u to peer %s ignored\n",
13446 ntohl (dqm->qid),
13447 GNUNET_i2s (&dqm->receiver));
13449 "# QUEUE_TEARDOWN dropped: queue unknown",
13450 1,
13451 GNUNET_NO);
13453}

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 13554 of file gnunet-service-transport.c.

13556{
13557 struct TransportClient *tc = cls;
13558 struct QueueEntry *qe;
13559 struct Queue *failed_queue = NULL;
13560
13561 if (CT_COMMUNICATOR != tc->type)
13562 {
13563 GNUNET_break (0);
13565 return;
13566 }
13567
13568 /* find our queue entry matching the ACK */
13569 qe = NULL;
13571 "Looking for queue for PID %s\n",
13572 GNUNET_i2s (&sma->receiver));
13573 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
13574 queue = queue->next_client)
13575 {
13576 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
13577 continue;
13579 "Found PID %s\n",
13580 GNUNET_i2s (&queue->neighbour->pid));
13581
13582
13583 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
13584 qep = qep->next)
13585 {
13586 if (qep->mid != GNUNET_ntohll (sma->mid) || queue->qid != ntohl (
13587 sma->qid))
13588 continue;
13590 "QueueEntry MID: %" PRIu64 " on queue QID: %u, Ack MID: %"
13591 PRIu64 " Ack QID %u\n",
13592 qep->mid,
13593 queue->qid,
13594 GNUNET_ntohll (sma->mid),
13595 ntohl (sma->qid));
13596 qe = qep;
13597 if ((NULL != qe->pm) && (qe->pm->qe != qe))
13599 "For pending message %" PRIu64 " we had retransmissions.\n",
13600 qe->pm->logging_uuid);
13601 break;
13602 }
13603 }
13604 if (GNUNET_OK != (int) ntohl (sma->status))
13605 {
13606 /* The communicator could not hand the message to the peer. The only
13607 thing that produces this today is #handle_send_msg()'s "queue no
13608 longer exists" branch in `transport_api_communication.c', i.e. the
13609 communicator has already torn the queue down on its side and the
13610 QUEUE_TEARDOWN is merely still in flight (or was lost).
13611
13612 Ignoring the status, as we used to, makes this self-sustaining:
13613 #free_queue_entry() releases the pending message and immediately
13614 reschedules transmission, #transmit_on_queue() picks the very same
13615 queue again -- transport still has it -- and we get another failure.
13616 Every round adds an envelope to the client MQ that is already
13617 congested, which is what shows up at the other end as
13618
13619 communicator INFO Transmission failed, queue no longer exists.
13620
13621 repeating at scheduler speed, and (because the service is busy
13622 servicing that loop) as
13623
13624 communicator WARNING Dropping message: transport is too slow,
13625 queue length N exceeded
13626
13627 on every *other* communicator. Treat the failure as the queue
13628 teardown it is and stop selecting this queue. */
13630 "Communicator could not send MID %" PRIu64
13631 " on QID %u to %s; dropping that queue\n",
13632 GNUNET_ntohll (sma->mid),
13633 ntohl (sma->qid),
13634 GNUNET_i2s (&sma->receiver));
13636 "# queues dropped (communicator send failed)",
13637 1,
13638 GNUNET_NO);
13639 if (NULL != qe)
13640 failed_queue = qe->queue;
13641 else
13642 for (struct Queue *queue = tc->details.communicator.queue_head;
13643 NULL != queue;
13644 queue = queue->next_client)
13645 if ((ntohl (sma->qid) == queue->qid) &&
13646 (0 == GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver)))
13647 {
13648 failed_queue = queue;
13649 break;
13650 }
13651 if (NULL != failed_queue)
13652 {
13653 /* #free_queue() releases every `struct QueueEntry' still on it --
13654 including @a qe -- and detaches their pending messages, so they are
13655 retried on whatever other queue this neighbour has. */
13656 free_queue (failed_queue);
13658 return;
13659 }
13660 }
13661 if (NULL == qe)
13662 {
13664 "No QueueEntry found for Ack MID %" PRIu64 " QID: %u\n",
13665 GNUNET_ntohll (sma->mid),
13666 ntohl (sma->qid));
13667 // TODO I guess this can happen, if the Ack from the peer comes before the Ack from the queue.
13668 // Update: Maybe QueueEntry was accidentally freed during freeing PendingMessage.
13669 /* this should never happen */
13670 // GNUNET_break (0);
13671 // GNUNET_SERVICE_client_drop (tc->client);
13673 return;
13674 }
13677}

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 13686 of file gnunet-service-transport.c.

13688{
13689 struct TransportClient *tc = cls;
13690
13691 (void) bf;
13694}

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 13707 of file gnunet-service-transport.c.

13710{
13711 struct TransportClient *tc = cls;
13712 struct Neighbour *neighbour = value;
13713
13714 GNUNET_assert (CT_MONITOR == tc->type);
13715 for (struct Queue *q = neighbour->queue_head; NULL != q;
13716 q = q->next_neighbour)
13717 {
13718 struct MonitorEvent me = { .rtt = q->pd.aged_rtt,
13719 .cs = q->cs,
13720 .num_msg_pending = q->num_msg_pending,
13721 .num_bytes_pending = q->num_bytes_pending };
13722
13723 notify_monitor (tc, pid, q->address, q->nt, &me);
13724 }
13725 return GNUNET_OK;
13726}

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 13736 of file gnunet-service-transport.c.

13738{
13739 struct TransportClient *tc = cls;
13740
13741 if (CT_NONE != tc->type)
13742 {
13743 GNUNET_break (0);
13745 return;
13746 }
13747 tc->type = CT_MONITOR;
13748 tc->details.monitor.peer = start->peer;
13749 tc->details.monitor.one_shot = ntohl (start->one_shot);
13753}

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 13782 of file gnunet-service-transport.c.

13784{
13785 char *ret = GNUNET_strdup ("");
13786
13787 *num_queues = 0;
13788 if (NULL == n)
13789 return ret;
13790 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
13791 {
13792 const char *prefix = q->tc->details.communicator.address_prefix;
13793 size_t plen = strlen (prefix);
13794 const char *pos;
13795 char *tmp;
13796
13797 (*num_queues)++;
13798 if (0 == plen)
13799 continue;
13800 /* Several queues to one neighbour routinely share a communicator;
13801 name each one once. */
13802 for (pos = strstr (ret, prefix);
13803 NULL != pos;
13804 pos = strstr (pos + 1, prefix))
13805 if (((pos == ret) || (',' == pos[-1])) &&
13806 (('\0' == pos[plen]) || (',' == pos[plen])))
13807 break;
13808 if (NULL != pos)
13809 continue;
13810 GNUNET_asprintf (&tmp, "%s%s%s", ret, ('\0' == ret[0]) ? "" : ",", prefix);
13811 GNUNET_free (ret);
13812 ret = tmp;
13813 }
13814 return ret;
13815}

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 13827 of file gnunet-service-transport.c.

13828{
13829 struct LinkListContext *llc = cls;
13830 struct VirtualLink *vl = value;
13832 struct GNUNET_MQ_Envelope *env;
13833 unsigned int pending = 0;
13834 unsigned int num_queues = 0;
13835 unsigned int distance = 0;
13836 struct Neighbour *hop;
13837 char *ccs;
13838 size_t clen;
13839
13840 if ((GNUNET_YES != llc->include_unconfirmed) &&
13841 (GNUNET_YES != vl->confirmed))
13842 return GNUNET_OK;
13843 for (struct PendingMessage *pm = vl->pending_msg_head;
13844 NULL != pm;
13845 pm = pm->next_vl)
13846 pending++;
13847 if (NULL != vl->n)
13848 {
13849 hop = vl->n;
13850 }
13851 else
13852 {
13853 /* Report the best (shortest) of the paths we currently know, and the
13854 communicators that carry its first hop. */
13855 struct DistanceVectorHop *best = NULL;
13856
13857 distance = UINT_MAX;
13858 if (NULL != vl->dv)
13859 for (struct DistanceVectorHop *pos = vl->dv->dv_head;
13860 NULL != pos;
13861 pos = pos->next_dv)
13862 if (pos->distance < distance)
13863 {
13864 distance = pos->distance;
13865 best = pos;
13866 }
13867 if (NULL == best)
13868 distance = 0; /* no paths left; report the link as adjacent */
13869 hop = (NULL != best) ? best->next_hop : NULL;
13870 }
13871 ccs = communicator_list (hop, &num_queues);
13872 clen = strlen (ccs) + 1;
13873 env = GNUNET_MQ_msg_extra (resp,
13874 clen,
13876 memcpy (&resp[1], ccs, clen);
13877 GNUNET_free (ccs);
13878 resp->target = *pid;
13879 resp->confirmed = htonl ((uint32_t) vl->confirmed);
13880 resp->route = htonl ((uint32_t) ((NULL != vl->n)
13883 resp->distance = htonl ((uint32_t) distance);
13884 resp->num_queues = htonl ((uint32_t) num_queues);
13885 resp->core_recv_window = htonl ((int32_t) vl->core_recv_window);
13886 resp->stalled = htonl ((uint32_t) vl->cmc_count);
13887 resp->pending = htonl (pending);
13888 resp->fc_retransmit_count = htonl ((uint32_t) vl->fc_retransmit_count);
13907 GNUNET_MQ_send (llc->tc->mq, env);
13908 return GNUNET_OK;
13909}

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 13921 of file gnunet-service-transport.c.

13924{
13925 struct TransportClient *tc = cls;
13926 struct LinkListContext llc = {
13927 .tc = tc,
13928 .include_unconfirmed = (int) ntohl (lr->include_unconfirmed)
13929 };
13930 struct GNUNET_MQ_Envelope *env;
13931 struct GNUNET_MessageHeader *end;
13932
13933 if (CT_NONE != tc->type)
13934 {
13935 GNUNET_break (0);
13937 return;
13938 }
13939 if (GNUNET_YES == GNUNET_is_zero (&lr->peer))
13940 {
13942 }
13943 else
13944 {
13945 struct VirtualLink *vl = lookup_virtual_link (&lr->peer);
13946
13947 if (NULL != vl)
13948 report_link (&llc, &lr->peer, vl);
13949 }
13952 GNUNET_MQ_send (tc->mq, env);
13954}

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 13965 of file gnunet-service-transport.c.

13966{
13967 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
13968 {
13969 if (CT_COMMUNICATOR != tc->type)
13970 continue;
13971 if (NULL == tc->details.communicator.address_prefix)
13972 continue; /* receive-only communicator */
13973 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
13974 return tc;
13975 }
13976 GNUNET_log (
13978 "Someone suggested use of communicator for `%s', but we do not have such a communicator!\n",
13979 prefix);
13980 return NULL;
13981}

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 14102 of file gnunet-service-transport.c.

14103{
14104 const struct VirtualLink *vl = lookup_virtual_link (pid);
14105
14106 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
14107 return MAX_VALIDATION_CHALLENGE_FREQ; /* we have what we want */
14108 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
14109 {
14110 if (CT_APPLICATION != tc->type)
14111 continue;
14113 tc->details.application.requests,
14114 pid))
14116 }
14118}

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 14238 of file gnunet-service-transport.c.

14241{
14242 struct QueueQualityContext *ctx = cls;
14243 struct Neighbour *n = value;
14244 int do_inc;
14245
14246 (void) pid;
14247 do_inc = GNUNET_NO;
14248 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
14249 {
14250 ctx->num_queues++;
14251 if (0 == ctx->k--)
14252 ctx->q = q;
14253 /* FIXME-CONQ-STATISTICS: in the future, add reliability / goodput
14254 statistics and consider those as well here? */
14255 if (q->pd.aged_rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
14256 do_inc = GNUNET_YES;
14257 }
14258 if (GNUNET_YES == do_inc)
14259 ctx->quality_count++;
14260 return GNUNET_OK;
14261}

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 14342 of file gnunet-service-transport.c.

14343{
14344 struct LearnLaunchEntry *lle;
14345 struct QueueQualityContext qqc;
14346 struct TransportDVLearnMessage dvl;
14347 const struct GNUNET_PeerIdentity *my_identity;
14348
14349 (void) cls;
14350 dvlearn_task = NULL;
14351 if ((GNUNET_YES == in_shutdown) || (NULL == pils))
14352 return;
14354 return; /* lost all connectivity, cannot do learning */
14356 if (NULL == my_identity)
14357 {
14358 /* PILS has not handed us an identity yet. The first queue arriving
14359 schedules us with add_now(), which routinely wins that race; retry
14360 instead of taking the service down. */
14364 NULL);
14365 return;
14366 }
14368 qqc.quality_count = 0;
14369 qqc.num_queues = 0;
14373 &qqc);
14374 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
14375 {
14376 struct GNUNET_TIME_Relative delay;
14377 unsigned int factor;
14378
14379 /* scale our retries by how far we are above the threshold */
14380 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
14383 "At connection quality %u, will launch DV learn in %s\n",
14384 qqc.quality_count,
14387 return;
14388 }
14389 /* remove old entries in #dvlearn_map if it has grown too big */
14390 while (MAX_DV_LEARN_PENDING <=
14392 {
14393 lle = lle_tail;
14396 &lle->challenge.value,
14397 lle));
14399 GNUNET_free (lle);
14400 }
14401 /* setup data structure for learning */
14402 lle = GNUNET_new (struct LearnLaunchEntry);
14404 sizeof(lle->challenge));
14406 "Starting launch DV learn with challenge %s\n",
14407 GNUNET_sh2s (&lle->challenge.value));
14412 &lle->challenge.value,
14413 lle,
14415 dvl.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
14416 dvl.header.size = htons (sizeof(dvl));
14417 dvl.num_hops = htons (0);
14418 dvl.bidirectional = htons (0);
14419 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
14420 dvl.monotonic_time =
14422 // We will set the below again later
14423 memset (&dvl.init_sig, 0, sizeof dvl.init_sig);
14424 dvl.challenge = lle->challenge;
14425 dvl.initiator = *my_identity;
14426 {
14427 struct DvInitPS dvip = {
14428 .purpose.purpose = htonl (
14430 .purpose.size = htonl (sizeof(dvip)),
14431 .monotonic_time = dvl.monotonic_time,
14432 .challenge = lle->challenge
14433 };
14434
14435 if (GNUNET_OK != sign_by_my_identity (&dvip.purpose, &dvl.init_sig))
14436 return;
14437 }
14438 transmit_dv_init (dvl, lle, qqc);
14439}

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 14287 of file gnunet-service-transport.c.

14290{
14291 if (0 == qqc.num_queues)
14292 {
14294 "# DV learn aborted: no queue left",
14295 1,
14296 GNUNET_NO);
14297 return;
14298 }
14299 qqc.quality_count = 0;
14301 qqc.num_queues = 0;
14302 qqc.q = NULL;
14305 &qqc);
14306 if (NULL == qqc.q)
14307 {
14309 "# DV learn aborted: no queue left",
14310 1,
14311 GNUNET_NO);
14312 return;
14313 }
14314
14315 /* Do this as close to transmission time as possible! */
14317
14318 queue_send_msg (qqc.q, NULL, &dvl, sizeof(dvl));
14319 /* reschedule this job, randomizing the time it runs (but no
14320 actual backoff!) */
14321 if (NULL != dvlearn_task)
14326 NULL);
14327}

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 14480 of file gnunet-service-transport.c.

14483{
14484 struct Queue *q = cls;
14485 struct ValidationState *vs = value;
14486 char *address_without_port_vs;
14487 char *address_without_port_q;
14488 char *prefix_vs;
14489 char *prefix_q;
14490 int success = GNUNET_YES;
14491
14492 // TODO Check if this is really necessary.
14493 address_without_port_vs = get_address_without_port (vs->address);
14494 address_without_port_q = get_address_without_port (q->address);
14495 prefix_vs = GNUNET_HELLO_address_to_prefix (vs->address);
14496 prefix_q = GNUNET_HELLO_address_to_prefix (q->address);
14497
14499 "Check validation request pending for `%s' at `%s'/`%s' (vs)/(q)\n",
14500 GNUNET_i2s (pid),
14501 (NULL == address_without_port_vs) ? "<unparsable>"
14502 : address_without_port_vs,
14503 (NULL == address_without_port_q) ? "<unparsable>"
14504 : address_without_port_q);
14505 (void) pid;
14506 /* Only the port may differ: the address we asked to connect to is
14507 `PROTO-IP:0' for a NATed peer, while the queue that then materializes
14508 sits at `PROTO-IP:port'. The communicator must match all the same --
14509 a challenge for a `tcp-' address is not answered by a `udp-' queue. */
14510 if ((GNUNET_YES == vs->awaiting_queue) &&
14511 (NULL != address_without_port_vs) &&
14512 (NULL != address_without_port_q) &&
14513 (NULL != prefix_vs) &&
14514 (NULL != prefix_q) &&
14515 (0 == strcmp (prefix_vs, prefix_q)) &&
14516 (0 == strcmp (address_without_port_vs, address_without_port_q)))
14517 {
14518
14519 vs->awaiting_queue = GNUNET_NO;
14521 success = GNUNET_NO;
14522 }
14523
14524 GNUNET_free (address_without_port_vs);
14525 GNUNET_free (address_without_port_q);
14526 GNUNET_free (prefix_vs);
14527 GNUNET_free (prefix_q);
14528 return success;
14529}

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 14541 of file gnunet-service-transport.c.

14544{
14545 struct Neighbour *n = cls;
14546 struct GNUNET_TIME_AbsoluteNBO *mtbe;
14547
14548 (void) emsg;
14549 if (NULL == record)
14550 {
14551 /* we're done with #neighbour_dv_monotime_cb() invocations,
14552 continue normal processing */
14553 n->get = NULL;
14555 return;
14556 }
14557 if (0 == record->value_size)
14558 {
14560 GNUNET_break (0);
14561 return;
14562 }
14563 mtbe = record->value;
14568}

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 14572 of file gnunet-service-transport.c.

14575{
14576 struct Queue *queue = cls;
14577 struct sockaddr_in v4;
14578 const char *slash;
14579 char *address_uri;
14580 char *prefix;
14581 char *uri_without_port;
14582 char *address_uri_without_port;
14583
14584 slash = strrchr (uri, '/');
14585 if ((NULL == slash) || (slash - uri < 2))
14586 {
14587 GNUNET_break_op (0); /* @a uri comes from a remote HELLO */
14588 return;
14589 }
14590 prefix = GNUNET_strndup (uri, (slash - uri) - 2);
14591 slash++;
14592 GNUNET_asprintf (&address_uri,
14593 "%s-%s",
14594 prefix,
14595 slash);
14596
14598 "1 not global natted_address %u %s %s %s\n",
14599 queue->is_global_natted,
14600 uri,
14601 queue->address,
14602 slash);
14603
14604 uri_without_port = get_address_without_port (address_uri);
14605 if ((NULL == uri_without_port) ||
14606 (1 != inet_pton (AF_INET, uri_without_port, &v4.sin_addr)))
14607 {
14609 GNUNET_free (address_uri);
14610 GNUNET_free (uri_without_port);
14611 return;
14612 }
14613
14615 "2 not global natted_address %u %s %s\n",
14616 queue->is_global_natted,
14617 uri,
14618 queue->address);
14619
14620 if (GNUNET_NO == queue->is_global_natted)
14621 {
14623 GNUNET_free (address_uri);
14624 GNUNET_free (uri_without_port);
14625 return;
14626 }
14627
14629 "3 not global natted_address %u %s %s\n",
14630 queue->is_global_natted,
14631 uri,
14632 queue->address);
14633
14634 if (0 == strcmp (uri_without_port, address_uri))
14635 {
14637 GNUNET_free (address_uri);
14638 GNUNET_free (uri_without_port);
14639 return;
14640 }
14641
14643 "4 not global natted_address %u %s %s\n",
14644 queue->is_global_natted,
14645 uri,
14646 queue->address);
14647
14648 address_uri_without_port = get_address_without_port (queue->address);
14649 if ((NULL != address_uri_without_port) &&
14650 (0 == strcmp (uri_without_port, address_uri_without_port)))
14651 {
14652 queue->is_global_natted = GNUNET_NO;
14653 }
14654
14656 "not global natted_address %u %s %s %s %s %s %u\n",
14657 queue->is_global_natted,
14658 uri,
14659 queue->address,
14660 uri_without_port,
14661 address_uri_without_port,
14662 prefix,
14663 GNUNET_NO);
14665 GNUNET_free (address_uri);
14666 GNUNET_free (address_uri_without_port);
14667 GNUNET_free (uri_without_port);
14668}

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 14686 of file gnunet-service-transport.c.

14689{
14690 struct TransportGlobalNattedAddressClosure *tgna_cls = cls;
14691 struct TransportGlobalNattedAddress *tgna = value;
14692 char *addr = (char *) &tgna[1];
14693
14694 /* NOTE: @a addr is NOT 0-terminated. */
14696 "Checking tgna %p with addr %.*s and length %u compare length %lu\n",
14697 tgna,
14698 (int) ntohl (tgna->address_length),
14699 addr,
14700 ntohl (tgna->address_length),
14701 strlen (tgna_cls->addr));
14702 if (strlen (tgna_cls->addr) == ntohl (tgna->address_length)
14703 && 0 == strncmp (addr, tgna_cls->addr, ntohl (tgna->address_length)))
14704 {
14705 tgna_cls->tgna = tgna;
14706 return GNUNET_NO;
14707 }
14708 return GNUNET_YES;
14709}

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 14713 of file gnunet-service-transport.c.

14714{
14716 "Error in PEERSTORE monitoring for checking global natted\n");
14717}

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 14721 of file gnunet-service-transport.c.

14722{
14724 "Done with initial PEERSTORE iteration during monitoring for checking global natted\n");
14725}

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 14729 of file gnunet-service-transport.c.

14732{
14733 struct Queue *queue = cls;
14734 struct Neighbour *neighbour = queue->neighbour;
14736 const struct GNUNET_MessageHeader *hello;
14738 size_t address_len_without_port;
14739
14740 if (NULL != emsg)
14741 {
14743 "Got failure from PEERSTORE: %s\n",
14744 emsg);
14746 return;
14747 }
14748 if (NULL == record)
14749 {
14750 GNUNET_break (0);
14752 return;
14753 }
14754 /* @a hello was published by a remote peer and may be malformed. */
14755 hello = hello_from_record (record);
14756 if (NULL == hello)
14757 {
14759 return;
14760 }
14761 queue->is_global_natted = GNUNET_YES;
14762 parser = GNUNET_HELLO_parser_from_msg (hello, &record->peer);
14763 if (NULL == parser)
14764 {
14766 "HELLO cannot be parsed!\n");
14768 return;
14769 }
14771 "before not global natted %u\n",
14772 queue->is_global_natted);
14775 queue);
14777 "after not global natted %u\n",
14778 queue->is_global_natted);
14779 GNUNET_HELLO_parser_free (parser);
14780
14781 tgna_cls.addr = get_address_without_port (queue->address);
14782 if (NULL == tgna_cls.addr)
14783 {
14784 GNUNET_break (0);
14786 return;
14787 }
14788 address_len_without_port = strlen (tgna_cls.addr);
14789 /*{
14790 char buf[address_len_without_port + 1];
14791
14792 GNUNET_memcpy (&buf, addr, address_len_without_port);
14793 buf[address_len_without_port] = '\0';
14794 GNUNET_free (addr);
14795 GNUNET_memcpy (tgna_cls.addr, buf, address_len_without_port + 1);
14796 }*/
14797 tgna_cls.tgna = NULL;
14799 &neighbour->pid,
14801 &tgna_cls);
14802 if (NULL != tgna_cls.tgna)
14804 " tgna_cls.tgna tgna %p %lu %u %u\n",
14805 tgna_cls.tgna,
14806 neighbour->size_of_global_addresses,
14807 ntohl (tgna_cls.tgna->address_length),
14808 neighbour->number_of_addresses);
14809 if (NULL == tgna_cls.tgna && GNUNET_YES == queue->is_global_natted)
14810 {
14811 struct TransportGlobalNattedAddress *tgna;
14812
14813 tgna = GNUNET_malloc (sizeof (struct TransportGlobalNattedAddress)
14814 + address_len_without_port);
14815 tgna->address_length = htonl (address_len_without_port);
14816 GNUNET_memcpy (&tgna[1], tgna_cls.addr, address_len_without_port);
14818 &neighbour->pid,
14819 tgna,
14821 neighbour->number_of_addresses++;
14822 /* MUST match what is subtracted on removal (and what
14823 #add_global_addresses() actually copies), or the accounting drifts. */
14824 neighbour->size_of_global_addresses += address_len_without_port;
14826 "Created tgna %p with address %s and length %lu\n",
14827 tgna,
14828 tgna_cls.addr,
14829 address_len_without_port + 1);
14830 }
14831 else if (NULL != tgna_cls.tgna && GNUNET_NO == queue->is_global_natted)
14832 {
14834 &neighbour->pid,
14835 tgna_cls.tgna);
14836 GNUNET_assert (neighbour->size_of_global_addresses >= ntohl (tgna_cls.tgna->
14838 );
14839 neighbour->size_of_global_addresses -= ntohl (tgna_cls.tgna->address_length)
14840 ;
14841 GNUNET_assert (0 < neighbour->number_of_addresses);
14842 neighbour->number_of_addresses--;
14844 "removed tgna %p\n",
14845 tgna_cls.tgna);
14846 GNUNET_free (tgna_cls.tgna);
14847 }
14849 GNUNET_free (tgna_cls.addr);
14850}

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 14860 of file gnunet-service-transport.c.

14862{
14863 struct TransportClient *tc = cls;
14864 struct Queue *queue;
14865 struct Neighbour *neighbour;
14866 const char *addr;
14867 uint16_t addr_len;
14868
14869 if (ntohl (aqm->mtu) <= sizeof(struct TransportFragmentBoxMessage))
14870 {
14871 /* MTU so small as to be useless for transmissions,
14872 required for #fragment_message()! */
14873 GNUNET_break_op (0);
14875 return;
14876 }
14877 /* This may simply be a queue update. Match on the peer as well as the
14878 QID: the communicator's key for a queue is the pair, and
14879 #handle_send_msg() on its side looks both of them up. Matching on the
14880 QID alone let an ADD_QUEUE for a *different* peer be folded into an
14881 existing queue, leaving @e neighbour pointing at the old peer -- after
14882 which every SEND_MSG we put on it carries a receiver the communicator
14883 cannot match, and comes straight back as "queue no longer exists". */
14884 for (queue = tc->details.communicator.queue_head;
14885 NULL != queue;
14886 queue = queue->next_client)
14887 {
14888 if (queue->qid != ntohl (aqm->qid))
14889 continue;
14890 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &aqm->receiver))
14891 continue;
14892 break;
14893 }
14894
14895 if (NULL != queue)
14896 {
14897 neighbour = queue->neighbour;
14898 }
14899 else
14900 {
14901 struct GNUNET_TIME_Absolute validated_until = GNUNET_TIME_UNIT_ZERO_ABS;
14902
14903 neighbour = lookup_neighbour (&aqm->receiver);
14904 if (NULL == neighbour)
14905 {
14906 neighbour = GNUNET_new (struct Neighbour);
14908 GNUNET_YES);
14909 neighbour->pid = aqm->receiver;
14910 /* Give a fresh neighbour a full window to say something. */
14911 neighbour->last_inbound = GNUNET_TIME_absolute_get ();
14914 neighbours,
14915 &neighbour->pid,
14916 neighbour,
14918 neighbour->get =
14920 "transport",
14921 &neighbour->pid,
14924 neighbour);
14925 }
14926 addr_len = ntohs (aqm->header.size) - sizeof(*aqm);
14927 addr = (const char *) &aqm[1];
14929 "New queue %s to %s available with QID %u and q_len %" PRIu64
14930 " and mtu %u\n",
14931 addr,
14932 GNUNET_i2s (&aqm->receiver),
14933 ntohl (aqm->qid),
14934 GNUNET_ntohll (aqm->q_len),
14935 ntohl (aqm->mtu));
14936 queue = GNUNET_malloc (sizeof(struct Queue) + addr_len);
14937 queue->tc = tc;
14938 for (struct Queue *q = neighbour->queue_head; NULL != q; q = q->
14939 next_neighbour)
14940 validated_until = GNUNET_TIME_absolute_max (validated_until, q->
14941 validated_until);
14942 /* Inherit the validity of the sibling queues, but only while it is
14943 still in the future -- copying an already expired timestamp is
14944 pointless (and the condition used to be inverted). */
14945 if (0 != GNUNET_TIME_absolute_get_remaining (validated_until).rel_value_us)
14946 {
14948 "New queue with QID %u inherit validated until\n",
14949 ntohl (aqm->qid));
14950 queue->validated_until = validated_until;
14951 }
14952 queue->address = (const char *) &queue[1];
14953 queue->pd.aged_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
14954 queue->qid = ntohl (aqm->qid);
14955 queue->neighbour = neighbour;
14957 queue->unlimited_length = GNUNET_YES;
14958 queue->q_capacity = GNUNET_ntohll (aqm->q_len);
14959 memcpy (&queue[1], addr, addr_len);
14960 /* notify monitors about new queue */
14961 {
14962 struct MonitorEvent me = { .rtt = queue->pd.aged_rtt, .cs = queue->cs };
14963
14964 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
14965 }
14967 neighbour->queue_head,
14968 neighbour->queue_tail,
14969 queue);
14971 tc->details.communicator.queue_head,
14972 tc->details.communicator.queue_tail,
14973 queue);
14974
14975 }
14976 queue->mtu = ntohl (aqm->mtu);
14977 queue->nt = ntohl (aqm->nt);
14978 queue->cs = ntohl (aqm->cs);
14979 queue->idle = GNUNET_YES;
14980
14981 if (NULL == queue->mo)
14982 {
14983 /* Only for a NEW queue: on a queue update this used to start a second
14984 monitor and leak the first one. */
14985 struct sockaddr_in v4;
14986 char *addr_without = get_address_without_port (queue->address);
14987 if ((NULL != addr_without) &&
14988 (1 == inet_pton (AF_INET, addr_without, &v4.sin_addr)))
14989 {
14991 "start not global natted\n");
14993 GNUNET_YES,
14994 "peerstore",
14995 &neighbour->pid,
14997 &
14999 NULL,
15000 &
15002 NULL,
15004 queue);
15005 }
15006 GNUNET_free (addr_without);
15007 }
15008 /* check if valdiations are waiting for the queue */
15010 &aqm->receiver))
15013 &aqm->receiver,
15015 queue);
15016 /* Always (also) validate the address of the queue itself. A pending
15017 validation served above may well be for a *different* address string:
15018 #check_validation_request_pending() matches on the IP only, so a
15019 validation state waiting for the NAT address `PROTO-IP:0' is happily
15020 satisfied by a queue at `PROTO-IP:12345'. If we stopped here,
15021 #handle_validation_response() would later look for a queue at
15022 `PROTO-IP:0' -- which never exists -- and drop the successful
15023 validation on the floor without ever creating the virtual link. That
15024 is exactly what happens to the second of two peers behind the same
15025 NAT, as both of them advertise the very same `PROTO-IP:0'. */
15026 start_address_validation (&aqm->receiver, queue->address);
15027 /* look for traffic for this queue */
15028 // TODO Check whether this makes any sense at all.
15029 /*schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
15030 queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);*/
15031 /* might be our first queue, try launching DV learning */
15032 if (NULL == dvlearn_task)
15035}

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 15045 of file gnunet-service-transport.c.

15048{
15049 struct TransportClient *tc = cls;
15050 struct Queue *target_queue = NULL;
15051
15052 if (CT_COMMUNICATOR != tc->type)
15053 {
15054 /* Without this we walk `details.communicator.queue_head' for a client
15055 whose union holds something else entirely. */
15056 GNUNET_break (0);
15058 return;
15059 }
15061 "Received queue update message for %u with q_len %llu and mtu %u\n",
15062 ntohl (msg->qid),
15063 (unsigned long long) GNUNET_ntohll (msg->q_len),
15064 ntohl (msg->mtu));
15065 for (target_queue = tc->details.communicator.queue_head;
15066 NULL != target_queue;
15067 target_queue = target_queue->next_client)
15068 {
15069 if (ntohl (msg->qid) == target_queue->qid)
15070 break;
15071 }
15072 if (NULL == target_queue)
15073 {
15075 "Queue to update no longer exists! Discarding update.\n");
15077 return;
15078 }
15079
15080 target_queue->nt = ntohl (msg->nt);
15081 target_queue->mtu = ntohl (msg->mtu);
15082 target_queue->cs = ntohl (msg->cs);
15083 target_queue->priority = ntohl (msg->priority);
15084 /* The update message indicates how many messages
15085 * the queue should be able to handle.
15086 */
15088 target_queue->unlimited_length = GNUNET_YES;
15089 else
15090 target_queue->unlimited_length = GNUNET_NO;
15091 target_queue->q_capacity += GNUNET_ntohll (msg->q_len);
15092 if (0 < target_queue->q_capacity)
15094 target_queue,
15097}

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 15108 of file gnunet-service-transport.c.

15110{
15111 struct TransportClient *tc = cls;
15112
15113 if (CT_COMMUNICATOR != tc->type)
15114 {
15115 GNUNET_break (0);
15117 return;
15118 }
15120 "# Suggestions succeeded at communicator",
15121 1,
15122 GNUNET_NO);
15124 "Request #%u for communicator to create queue succeeded\n",
15125 (unsigned int) ntohs (cqr->request_id));
15127}

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 15139 of file gnunet-service-transport.c.

15142{
15143 struct TransportClient *tc = cls;
15144
15145 if (CT_COMMUNICATOR != tc->type)
15146 {
15147 GNUNET_break (0);
15149 return;
15150 }
15152 "Request #%u for communicator to create queue failed\n",
15153 (unsigned int) ntohl (cqr->request_id));
15155 "# Suggestions failed in queue creation at communicator",
15156 1,
15157 GNUNET_NO);
15159}

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 15170 of file gnunet-service-transport.c.

15171{
15172 struct TransportClient *tc = cls;
15173 struct PeerRequest *pr;
15174
15175 if (CT_APPLICATION != tc->type)
15176 {
15177 GNUNET_break (0);
15179 return;
15180 }
15181 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
15182 &msg->peer);
15183 if (NULL == pr)
15184 {
15185 GNUNET_break (0);
15187 return;
15188 }
15189 (void) stop_peer_request (tc, &pr->pid, pr);
15191}

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 15195 of file gnunet-service-transport.c.

15198{
15199 struct Queue *q;
15200 int pfx_len;
15201 const char *eou;
15202 char *address;
15203 (void) cls;
15204
15205 eou = strstr (uri,
15206 "://");
15207 if ((NULL == eou) || (eou == uri))
15208 {
15209 /* @a uri comes from a HELLO some remote peer published. */
15210 GNUNET_break_op (0);
15211 return;
15212 }
15213 pfx_len = eou - uri;
15214 eou += 3;
15216 "%.*s-%s",
15217 pfx_len,
15218 uri,
15219 eou);
15220
15222 "hello for client %s\n",
15223 address);
15224
15225 q = find_queue (pid, address);
15226 if (NULL == q)
15227 {
15229 }
15230 else
15233}

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 15244 of file gnunet-service-transport.c.

15247{
15248 const struct GNUNET_PeerIdentity *my_identity;
15249 struct PeerRequest *pr = cls;
15251 const struct GNUNET_MessageHeader *hello;
15252
15253 if (NULL != emsg)
15254 {
15256 "Got failure from PEERSTORE: %s\n",
15257 emsg);
15259 return;
15260 }
15261 if (NULL == record)
15262 {
15263 GNUNET_break (0);
15265 return;
15266 }
15268 if (NULL == my_identity)
15269 {
15271 "No identity given yet!\n");
15273 return;
15274 }
15275 hello = hello_from_record (record);
15276 if (NULL == hello)
15277 {
15278 /* MUST still ask for the next record: a bad one is not a reason to
15279 stall this monitor forever. */
15281 return;
15282 }
15283 if (0 == GNUNET_memcmp (&record->peer, my_identity))
15284 {
15286 return;
15287 }
15288 parser = GNUNET_HELLO_parser_from_msg (hello, &record->peer);
15289 if (NULL == parser)
15290 {
15292 "HELLO cannot be parsed!\n");
15294 return;
15295 }
15297 "HELLO for `%s' could be parsed, iterating addresses...!\n",
15301 NULL);
15302 GNUNET_HELLO_parser_free (parser);
15303 /* MUST ask for the next record, or this monitor stalls after one HELLO */
15305}

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 15309 of file gnunet-service-transport.c.

15310{
15312 "Error in PEERSTORE monitoring\n");
15313}

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 15317 of file gnunet-service-transport.c.

15318{
15320 "Done with initial PEERSTORE iteration during monitoring\n");
15321}

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 15336 of file gnunet-service-transport.c.

15337{
15338 if (NULL != pr->nc)
15340 /* Monitor only @e pid. With NULL every application request sees every
15341 HELLO in PEERSTORE, so a client asking for one peer made us suggest a
15342 connection to -- and start an address validation for -- every peer we
15343 have ever heard of, once per request. #try_to_bring_link_up() had the
15344 same bug and was already fixed the same way. */
15345 pr->nc =
15347 GNUNET_YES,
15348 "peerstore",
15349 &pr->pid,
15352 NULL,
15354 NULL,
15356 pr);
15357}

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 15370 of file gnunet-service-transport.c.

15371{
15372 struct PeerRequest *pr = cls;
15373 struct VirtualLink *vl;
15374
15375 pr->retry_task = NULL;
15376 vl = lookup_virtual_link (&pr->pid);
15377 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
15378 {
15379 /* The client has what it asked for. Keep watching cheaply, and start
15380 over from the short interval when the link goes away again. */
15384 pr);
15385 return;
15386 }
15388 "Retrying to connect to %s, an application client wants it\n",
15389 GNUNET_i2s (&pr->pid));
15391 "# link setup retries for application clients",
15392 1,
15393 GNUNET_NO);
15394 /* Addresses we already track, queues we still have, and a fresh look in
15395 PEERSTORE. */
15397 /* ... plus a replay of what PEERSTORE has for this peer, which is the
15398 only way back once the validation state expired and the queues are
15399 gone. */
15405 pr);
15406}

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 15417 of file gnunet-service-transport.c.

15418{
15419 struct TransportClient *tc = cls;
15420 const struct GNUNET_PeerIdentity *my_identity;
15421 struct PeerRequest *pr;
15422
15423 if (CT_NONE == tc->type)
15424 {
15425 tc->type = CT_APPLICATION;
15426 tc->details.application.requests =
15428 }
15429 if (CT_APPLICATION != tc->type)
15430 {
15431 GNUNET_break (0);
15433 return;
15434 }
15436 if (NULL == my_identity)
15437 {
15439 "Still waiting for own identity!\n");
15441 return;
15442 }
15444 "Client suggested we talk to %s with preference %d at rate %u\n",
15445 GNUNET_i2s (&msg->peer),
15446 (int) ntohl (msg->pk),
15447 (int) ntohl (msg->bw.value__));
15448 if (0 == GNUNET_memcmp (my_identity, &msg->peer))
15449 {
15451 "Client suggested connection to ourselves, ignoring...\n");
15453 return;
15454 }
15455 pr = GNUNET_new (struct PeerRequest);
15456 pr->tc = tc;
15457 pr->pid = msg->peer;
15458 pr->bw = msg->bw;
15459 pr->pk = ntohl (msg->pk);
15461 tc->details.application.requests,
15462 &pr->pid,
15463 pr,
15465 {
15466 GNUNET_break (0);
15467 GNUNET_free (pr);
15469 return;
15470 }
15472 /* The monitor alone only ever fires again if the HELLO *changes*. Keep
15473 asking for the link ourselves for as long as the client wants it. */
15474 pr->retry_backoff = SUGGEST_RETRY_MIN;
15475 pr->retry_task = GNUNET_SCHEDULER_add_delayed (pr->retry_backoff,
15477 pr);
15479}

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 15491 of file gnunet-service-transport.c.

15493{
15494 (void) cls;
15496 return GNUNET_OK;
15497}

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 15508 of file gnunet-service-transport.c.

15510{
15511 struct TransportClient *tc = cls;
15512 struct Queue *q;
15513
15514 q = find_queue (&m->peer, (const char *) &m[1]);
15515 if (NULL == q)
15516 {
15517 suggest_to_connect (&m->peer, (const char *) &m[1]);
15518 }
15519 else
15520 start_address_validation (&m->peer, (const char *) &m[1]);
15522}

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 15534 of file gnunet-service-transport.c.

15537{
15538 struct Neighbour *neighbour = value;
15539
15540 (void) cls;
15541 (void) pid;
15542 GNUNET_break (0); // should this ever happen?
15543 free_neighbour (neighbour, GNUNET_YES);
15544
15545 return GNUNET_OK;
15546}

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 15564 of file gnunet-service-transport.c.

15567{
15568 struct VirtualLink *vl = value;
15569
15570 (void) cls;
15571 (void) pid;
15572 free_virtual_link (vl);
15573
15574 return GNUNET_OK;
15575}

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 15587 of file gnunet-service-transport.c.

15590{
15591 struct DistanceVector *dv = value;
15592
15593 (void) cls;
15594 (void) pid;
15595 free_dv_route (dv);
15596
15597 return GNUNET_OK;
15598}

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 15610 of file gnunet-service-transport.c.

15613{
15614 struct ValidationState *vs = value;
15615
15616 (void) cls;
15617 (void) pid;
15619 return GNUNET_OK;
15620}

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 15632 of file gnunet-service-transport.c.

15633{
15634 struct PendingAcknowledgement *pa = value;
15635
15636 (void) cls;
15637 (void) key;
15639 return GNUNET_OK;
15640}

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 15652 of file gnunet-service-transport.c.

15655{
15656 struct AcknowledgementCummulator *ac = value;
15657
15658 (void) cls;
15659 (void) pid;
15660 /* @e task is armed for the whole life of @a ac -- but
15661 #transmit_cummulative_ack_cb() clears it before re-arming, and it
15662 routes a message while it is clear. #GNUNET_SCHEDULER_cancel()
15663 dereferences its argument unconditionally. */
15664 if (NULL != ac->task)
15665 {
15667 ac->task = NULL;
15668 }
15669 GNUNET_free (ac);
15670 return GNUNET_OK;
15671}

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 15822 of file gnunet-service-transport.c.

15823{
15824 switch (type)
15825 {
15826 case CT_CORE:
15827 return "CORE";
15828 case CT_MONITOR:
15829 return "MONITOR";
15830 case CT_COMMUNICATOR:
15831 return "COMMUNICATOR";
15832 case CT_APPLICATION:
15833 return "APPLICATION";
15834 default:
15835 return "UNKNOWN";
15836 }
15837}

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 15848 of file gnunet-service-transport.c.

15849{
15850 client_grace_task = NULL;
15851 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
15852 {
15854 "Client did not disconnect within the shutdown grace period, "
15855 "dropping it: %s\n",
15856 get_client_type_name (tc->type));
15857 }
15858 /* We use #GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN, so the service will NOT
15859 drop clients for us. Without this we would wait forever for them to
15860 leave on their own and never reach #do_shutdown(). */
15862 /* Dropping the clients ran #client_disconnect_cb() for each of them, so
15863 #do_shutdown() has normally run by now; it is idempotent, and this
15864 covers the case where there was nothing left to drop. */
15865 do_shutdown (cls);
15866}

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 15870 of file gnunet-service-transport.c.

15871{
15873
15875 "Shutdown task executed\n");
15876 if (NULL != clients_head)
15877 {
15878 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
15879 {
15881 "Waiting for client to disconnect: %s\n",
15882 get_client_type_name (tc->type));
15883 }
15884 /* Give them a chance to shut down cleanly; #client_disconnect_cb() calls
15885 #do_shutdown() once the last one is gone, and #do_shutdown() cancels
15886 this task. */
15890 cls);
15891 return;
15892 }
15893 do_shutdown (cls);
15894}

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 15903 of file gnunet-service-transport.c.

15904{
15905 struct UpdateHelloFromPidCtx *pc = cls;
15906
15907 /* NOTE: @a success is GNUNET_OK even when #hello_add_iter() decided not to
15908 store anything because PEERSTORE already holds a HELLO that expires
15909 later; the API reports the desired state, not whether it wrote. So this
15910 says "we have a current HELLO on record", not "we just wrote one". */
15911 if (GNUNET_OK != success)
15913 "Failed to store our new hello with peerstore\n");
15914 else
15916 "Our hello is current in peerstore\n");
15917 GNUNET_free (pc);
15918}

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 15922 of file gnunet-service-transport.c.

15925{
15927 "%s\n", uri);
15928}

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 15941 of file gnunet-service-transport.c.

15944{
15945 const struct GNUNET_PeerIdentity *my_identity;
15946 struct GNUNET_MQ_Envelope *env;
15947 const struct GNUNET_MessageHeader *msg;
15948 struct UpdateHelloFromPidCtx *sc;
15949 struct GNUNET_HELLO_Builder *nbuilder;
15950 struct GNUNET_PeerIdentity npid;
15951
15954
15955 if (NULL == GST_my_hello)
15958 "My current identity is `%s'\n",
15970 nbuilder = GNUNET_HELLO_builder_from_parser (parser,
15971 &npid);
15972 if (GNUNET_NO ==
15974 {
15976 "New PID from PILS is derived from address list inconsistent with ours. Ignoring...\n");
15978 "Proposed address list:\n");
15981 "Current address list:\n");
15983 GNUNET_HELLO_builder_free (nbuilder);
15984 return;
15985 }
15987 GST_my_hello = nbuilder;
15989 "My new identity is `%s'\n",
15995 msg,
15997 sc);
15998 GNUNET_free (env);
15999}

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 16010 of file gnunet-service-transport.c.

16013{
16014 (void) cls;
16015 /* setup globals */
16019 GST_cfg = c;
16027 GNUNET_YES);
16032 // TODO check for all uses of GST_my_hello that it is not used uninitialized
16034 "transport",
16035 "USE_BURST_NAT");
16036 if (GNUNET_SYSERR == use_burst)
16038 "Could not configure burst nat use. Default to no.\n");
16044 "transport",
16045 0,
16046 0,
16047 NULL,
16048 0,
16049 NULL,
16050 NULL,
16051 NULL);
16052 if (NULL == peerstore)
16053 {
16054 GNUNET_break (0);
16056 return;
16057 }
16060 NULL); // FIXME we need to wait for
16061 // our first peer id before
16062 // we can start the service
16063 // completely - PILS in turn
16064 // waits for the first
16065 // addresses from the
16066 // communicators in order to
16067 // be able to generate a
16068 // peer id
16069 if (NULL == pils)
16070 {
16071 GNUNET_break (0);
16073 return;
16074 }
16075 /* Decapsulate DV box ephemeral keys ourselves. #handle_dv_box() needs
16076 the key material while it still has the box, which points into the
16077 communicator's inbound message and is gone the moment the handler
16078 returns -- so the asynchronous answer arrived to a dangling @a dvb. */
16079 if (GNUNET_OK !=
16082 _ ("Failed to load our private key, "
16083 "cannot open DV boxes addressed to us\n"));
16084}

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 3130 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 3135 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 3140 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 3145 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 3150 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 3155 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 3165 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 3182 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 3188 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 3199 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 3205 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 3211 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 3217 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 3223 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 3229 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 3235 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 3246 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 3251 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 3256 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 3263 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 3268 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 3361 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 3366 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 3371 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 3376 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 3383 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 3388 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 3393 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 3398 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 3403 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 3413 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 3419 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 3424 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 3431 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 3433 of file gnunet-service-transport.c.

Referenced by do_shutdown(), and start_burst().

◆ use_burst

enum GNUNET_GenericReturnValue use_burst

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

Referenced by queue_burst(), and run().