GNUnet 0.28.1-dev.3-2-g4c5d45bb5
 
Loading...
Searching...
No Matches
gnunet-service-transport.c File Reference

main for gnunet-service-transport More...

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

Go to the source code of this file.

Data Structures

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

Macros

#define RING_BUFFER_SIZE   16
 Size of ring buffer to cache CORE and forwarded DVBox messages.
 
#define MAX_FC_RETRANSMIT_COUNT   1000
 Maximum number of FC retransmissions for a running retransmission task.
 
#define MIN_FC_RETRANSMIT_DELAY    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100)
 Lower bound on the delay between two flow control transmissions on the same virtual link.
 
#define UNCONFIRMED_LINK_TIMEOUT    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
 How long do we keep a virtual link that only exists because some peer sent us a FLOW_CONTROL message, without it ever becoming confirmed?
 
#define MAX_CUMMULATIVE_ACKS   64
 Maximum number of messages we acknowledge together in one cumulative ACK.
 
#define FC_NO_CHANGE_REPLY_PROBABILITY   8
 What is the 1:n chance that we send a Flow control response when receiving a flow control message that did not change anything for us? Basically, this is used in the case where both peers are stuck on flow control (no window changes), but one might continue sending flow control messages to the other peer as the first FC message when things stalled got lost, and then subsequently the other peer does usually not respond as nothing changed.
 
#define IN_PACKET_SIZE_WITHOUT_MTU   128
 What is the size we assume for a read operation in the absence of an MTU for the purpose of flow control?
 
#define GOODPUT_AGING_SLOTS   4
 Number of slots we keep of historic data for computation of goodput / message loss ratio.
 
#define DEFAULT_WINDOW_SIZE   (128 * 1024)
 How big is the flow control window size by default; limits per-neighbour RAM utilization.
 
#define MAX_INCOMING_REQUEST   16
 For how many incoming connections do we try to create a virtual link for (at the same time!).
 
#define MAX_DV_DISCOVERY_SELECTION   16
 Maximum number of peers we select for forwarding DVInit messages at the same time (excluding initiator).
 
#define RECV_WINDOW_SIZE   4
 Window size.
 
#define CORE_FC_STALL_TIMEOUT    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2)
 How long do we wait for CORE to return the flow control credit for the messages we handed it before we give up on them?
 
#define MAX_STALLED_CMCS   (4 * RECV_WINDOW_SIZE)
 How many messages may wait on VirtualLink::core_recv_window before we stop deferring their flow control ACKs?
 
#define MIN_DV_PATH_LENGTH_FOR_INITIATOR   3
 Minimum number of hops we should forward DV learn messages even if they are NOT useful for us in hope of looping back to the initiator?
 
#define MAX_DV_HOPS_ALLOWED   16
 Maximum DV distance allowed ever.
 
#define MAX_DV_LEARN_PENDING   64
 Maximum number of DV learning activities we may have pending at the same time.
 
#define MAX_DV_PATHS_TO_TARGET   3
 Maximum number of DV paths we keep simultaneously to the same target.
 
#define PILS_FEED_ADDRESSES_DELAY    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3)
 Delay between added/removed addresses and PILS feed call.
 
#define DELAY_WARN_THRESHOLD    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
 If a queue delays the next message by more than this number of seconds we log a warning.
 
#define DV_FORWARD_TIMEOUT    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
 If a DVBox could not be forwarded after this number of seconds we drop it.
 
#define DEFAULT_ACK_WAIT_DURATION    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
 Default value for how long we wait for reliability ack.
 
#define 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 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_DELAY_ADDRESS_VALIDATION   GNUNET_TIME_UNIT_MILLISECONDS
 What is the maximum frequency at which we do address validation? A random value between 0 and this value is added when scheduling the validation_task (both to ensure we do not validate too often, and to randomize a bit).
 
#define VALIDATION_RTT_BUFFER_FACTOR   3
 How many network RTTs before an address validation expires should we begin trying to revalidate? (Note that the RTT used here is the one that we experienced during the last validation, not necessarily the latest RTT observed).
 
#define COMMUNICATOR_TOTAL_QUEUE_LIMIT   512
 How many messages can we have pending for a given communicator process before we start to throttle that communicator?
 
#define QUEUE_LENGTH_LIMIT   32
 How many messages can we have pending for a given queue (queue to a particular peer via a communicator) process before we start to throttle that queue?
 
#define QUEUE_ENTRY_TIMEOUT    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
 
#define RTT_DIFF    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
 Difference of the average RTT for the DistanceVector calculate by us and the target we are willing to accept for starting the burst.
 
#define SHUTDOWN_CLIENT_GRACE_PERIOD    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
 How long do we wait during shutdown for our clients to disconnect on their own before we drop them? We run with GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN, so nobody drops them for us and a single wedged client would otherwise keep us alive forever.
 

Typedefs

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

Enumerations

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

Functions

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

Variables

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

Detailed Description

main for gnunet-service-transport

Author
Christian Grothoff

TODO: Implement next:

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

Optimizations-Statistics:

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

Optimizations-DV:

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

Optimizations-Fragmentation:

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

Optimizations-internals:

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

Definition in file gnunet-service-transport.c.

Macro Definition Documentation

◆ RING_BUFFER_SIZE

#define RING_BUFFER_SIZE   16

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

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

◆ MAX_FC_RETRANSMIT_COUNT

#define MAX_FC_RETRANSMIT_COUNT   1000

Maximum number of FC retransmissions for a running retransmission task.

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

◆ MIN_FC_RETRANSMIT_DELAY

#define MIN_FC_RETRANSMIT_DELAY    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100)

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

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

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

464{
469 uint64_t uuid GNUNET_PACKED;
470};
471
472
477{
481 struct GNUNET_Uuid value;
482};
483
488{
493
494 /* Followed by *another* message header which is the message to
495 the communicator */
496
497 /* Followed by a 0-terminated name of the communicator */
498};
499
500
505{
510
526
531
537};
538
539
545{
550
556
568
569 /* Followed by a `struct GNUNET_MessageHeader` with a message
570 for the target peer */
571};
572
573
579{
584
592
599};
600
601
606{
614
619};
620
621
630{
635
640 uint32_t ack_counter GNUNET_PACKED;
641
642 /* followed by any number of `struct TransportCummulativeAckPayloadP`
643 messages providing ACKs */
644};
645
646
651{
656
660 uint16_t frag_off GNUNET_PACKED;
661
665 uint16_t msg_size GNUNET_PACKED;
666
675
680 struct MessageUUIDP msg_uuid;
681};
682
683
701struct DvInitPS
702{
707
721
726};
727
728
745struct DvHopPS
746{
751
756
761
766};
767
768
773struct DVPathEntryP
774{
779
785};
786
787
802{
807
812 uint16_t num_hops GNUNET_PACKED;
813
823
830
844
850
855
860
861 /* Followed by @e num_hops `struct DVPathEntryP` values,
862 excluding the initiator of the DV trace; the last entry is the
863 current sender; the current peer must not be included. */
864};
865
866
890{
895
899 uint32_t without_fc GNUNET_PACKED;
900
907 uint16_t total_hops GNUNET_PACKED;
908
914 uint16_t num_hops GNUNET_PACKED;
915
921
928
935
941 uint16_t orig_size GNUNET_PACKED;
942
943 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values;
944 excluding the @e origin and the current peer, the last must be
945 the ultimate target; if @e num_hops is zero, the receiver of this
946 message is the ultimate target. */
947
948 /* Followed by encrypted, variable-size payload, which
949 must begin with a `struct TransportDVBoxPayloadP` */
950
951 /* Followed by the actual message, which itself must not be a
952 a DV_LEARN or DV_BOX message! */
953};
954
955
961{
966
970 uint32_t reserved GNUNET_PACKED;
971
976
982};
983
984
990{
995
1001
1006};
1007
1008
1014{
1019
1023 uint32_t reserved GNUNET_PACKED;
1024
1030
1035
1040 struct GNUNET_TIME_AbsoluteNBO origin_time;
1041
1046 struct GNUNET_TIME_RelativeNBO validity_duration;
1047};
1048
1050{
1055
1056 /* Followed by @e address_length bytes of the address. */
1057};
1058
1068{
1073
1081 uint32_t seq GNUNET_PACKED;
1082
1088
1095
1105
1115
1120
1124 uint32_t sync_ready GNUNET_PACKED;
1125
1130
1136
1137 /* Followed by @e number_of_addresses struct TransportGlobalNattedAddress. */
1138};
1139
1141
1142/* GNUNET_NETWORK_STRUCT_BEGIN/_END expand to nothing; only the per-member
1143 GNUNET_PACKED keeps these layouts free of compiler padding. Pin the sizes
1144 so that adding an unpacked or non-fixed-width member cannot silently put
1145 padding bytes -- i.e. uninitialised stack -- on the wire again. */
1147
1149GNUNET_static_assert (sizeof(struct TransportDVBoxMessage) == 86);
1150GNUNET_static_assert (sizeof(struct TransportDVLearnMessage) == 152);
1156
1157
1161enum ClientType
1162{
1166 CT_NONE = 0,
1167
1171 CT_CORE = 1,
1172
1176 CT_MONITOR = 2,
1177
1181 CT_COMMUNICATOR = 3,
1182
1186 CT_APPLICATION = 4
1187};
1188
1189
1195{
1199 RMO_NONE = 0,
1200
1204 RMO_DV_ALLOWED = 1,
1205
1210
1215
1221 RMO_REDUNDANT = 4
1222};
1223
1224
1228struct LearnLaunchEntry
1229{
1233 struct LearnLaunchEntry *prev;
1234
1238 struct LearnLaunchEntry *next;
1239
1244
1250};
1251
1252
1258{
1262 uint64_t bytes_sent;
1263
1268 uint64_t bytes_received;
1269};
1270
1271
1275struct PerformanceData
1276{
1281
1287
1292 unsigned int last_age;
1293};
1294
1295
1299struct TransportClient;
1300
1304struct Neighbour;
1305
1310struct DistanceVector;
1311
1316struct Queue;
1317
1321struct PendingMessage;
1322
1326struct DistanceVectorHop;
1327
1336struct VirtualLink;
1337
1338
1344{
1350
1356
1360 struct TransportClient *tc;
1361
1366
1370 const struct GNUNET_MessageHeader *mh;
1371
1376 uint16_t total_hops;
1377
1383 unsigned int ack_sent;
1384
1391 unsigned int client_resumed;
1392};
1393
1394
1398struct RingBufferEntry
1399{
1404
1408 struct GNUNET_MessageHeader *mh;
1409};
1410
1411
1415struct CoreSentContext
1416{
1420 struct CoreSentContext *next;
1421
1425 struct CoreSentContext *prev;
1426
1430 struct VirtualLink *vl;
1431
1435 uint16_t size;
1436
1443 uint16_t isize;
1444};
1445
1446
1450struct ReassemblyContext
1451{
1456 struct MessageUUIDP msg_uuid;
1457
1461 struct VirtualLink *virtual_link;
1462
1467
1475 uint8_t *bitfield;
1476
1481
1487
1491 uint16_t msg_size;
1492
1497 uint16_t msg_missing;
1498
1499 /* Followed by @e msg_size bytes of the (partially) defragmented original
1500 * message */
1501
1502 /* Followed by @e bitfield data */
1503};
1504
1505
1514struct VirtualLink
1515{
1520
1527
1534
1539
1545
1551
1556 unsigned int cmc_count;
1557
1564
1569
1574
1578 struct CoreSentContext *csc_tail;
1579
1583 struct CoreSentContext *csc_head;
1584
1592
1598
1604
1609
1613 char *burst_addr;
1614
1618 unsigned int fc_retransmit_count;
1619
1624 unsigned int confirmed;
1625
1629 struct Neighbour *n;
1630
1634 struct DistanceVector *dv;
1635
1642
1649
1658
1664
1670
1675
1680 uint64_t message_uuid_ctr;
1681
1689 uint64_t available_fc_window_size;
1690
1698
1704 uint64_t incoming_fc_window_size;
1705
1714
1727
1732 uint64_t outbound_fc_window_size;
1733
1740
1751
1756 uint32_t fc_seq_gen;
1757
1763 uint32_t last_fc_seq;
1764
1776 int core_recv_window;
1777
1782};
1783
1784
1789{
1795
1801
1808
1815
1822
1829
1836
1843
1848
1853 struct PendingMessage *pm;
1854
1859 struct DistanceVectorHop *dvh;
1860
1865 struct Queue *queue;
1866
1871
1875 uint16_t message_size;
1876
1880 unsigned int num_send;
1881};
1882
1883
1887struct DistanceVectorHop
1888{
1892 struct DistanceVectorHop *next_dv;
1893
1897 struct DistanceVectorHop *prev_dv;
1898
1903
1908
1913
1918
1922 struct Neighbour *next_hop;
1923
1927 struct DistanceVector *dv;
1928
1934 const struct GNUNET_PeerIdentity *path;
1935
1941
1950
1954 struct PerformanceData pd;
1955
1961 unsigned int distance;
1962};
1963
1964
1969struct DistanceVector
1970{
1975
1979 struct DistanceVectorHop *dv_head;
1980
1984 struct DistanceVectorHop *dv_tail;
1985
1990
1995 struct VirtualLink *vl;
1996
2002
2007
2012
2017
2021 struct GNUNET_ShortHashCode *km;
2022};
2023
2024
2034struct QueueEntry
2035{
2039 struct QueueEntry *next;
2040
2044 struct QueueEntry *prev;
2045
2049 struct Queue *queue;
2050
2054 struct PendingMessage *pm;
2055
2059 uint64_t mid;
2060
2065};
2066
2067
2072struct Queue
2073{
2077 struct Queue *next_neighbour;
2078
2082 struct Queue *prev_neighbour;
2083
2087 struct Queue *prev_client;
2088
2092 struct Queue *next_client;
2093
2098
2103
2107 struct QueueEntry *queue_head;
2108
2112 struct QueueEntry *queue_tail;
2113
2117 struct Neighbour *neighbour;
2118
2122 struct TransportClient *tc;
2123
2127 const char *address;
2128
2132 unsigned int unlimited_length;
2133
2139
2148
2152 struct PerformanceData pd;
2153
2159
2164 uint64_t mid_gen;
2165
2169 uint32_t qid;
2170
2174 uint32_t mtu;
2175
2179 uint32_t num_msg_pending;
2180
2184 uint32_t num_bytes_pending;
2185
2189 unsigned int queue_length;
2190
2194 uint64_t q_capacity;
2195
2199 uint32_t priority;
2200
2205
2210
2215 int idle;
2216
2221};
2222
2223
2227struct Neighbour
2228{
2232 struct GNUNET_PeerIdentity pid;
2233
2238 struct DistanceVectorHop *dv_head;
2239
2244 struct DistanceVectorHop *dv_tail;
2245
2253
2257 struct Queue *queue_head;
2258
2262 struct Queue *queue_tail;
2263
2269
2275
2280 struct VirtualLink *vl;
2281
2287
2293
2298
2302 unsigned int number_of_addresses;
2303
2308
2313};
2314
2315
2320struct IncomingRequest
2321{
2325 struct IncomingRequest *next;
2326
2330 struct IncomingRequest *prev;
2331
2336
2340 struct GNUNET_PeerIdentity pid;
2341};
2342
2343
2347struct PeerRequest
2348{
2352 struct GNUNET_PeerIdentity pid;
2353
2357 struct TransportClient *tc;
2358
2363
2370
2375};
2376
2377
2382{
2386 PMT_CORE = 0,
2387
2391 PMT_FRAGMENT_BOX = 1,
2392
2397
2401 PMT_DV_BOX = 3
2402};
2403
2404
2431struct PendingMessage
2432{
2436 struct PendingMessage *next_vl;
2437
2441 struct PendingMessage *prev_vl;
2442
2447
2452
2457 struct PendingMessage *next_frag;
2458
2463 struct PendingMessage *prev_frag;
2464
2469
2474
2479 struct PendingMessage *bpm;
2480
2485 struct VirtualLink *vl;
2486
2491
2500 struct QueueEntry *qe;
2501
2505 struct TransportClient *client;
2506
2510 struct PendingMessage *head_frag;
2511
2515 struct PendingMessage *tail_frag;
2516
2521
2526
2531
2536 struct MessageUUIDP msg_uuid;
2537
2542 uint64_t logging_uuid;
2543
2548
2554
2559
2563 uint16_t bytes_msg;
2564
2568 uint16_t frag_off;
2569
2573 uint32_t frags_in_flight;
2574
2578 uint32_t frags_in_flight_round;
2579
2583 uint16_t frag_count;
2584
2588 int16_t msg_uuid_set;
2589
2597 int16_t client_credited;
2598
2599 /* Followed by @e bytes_msg to transmit */
2600};
2601
2602
2607{
2613
2618};
2619
2620
2626{
2631
2636
2643
2648
2654 uint32_t ack_counter;
2655
2659 unsigned int num_acks;
2660};
2661
2662
2668
2669
2673struct AddressListEntry
2674{
2678 struct AddressListEntry *next;
2679
2683 struct AddressListEntry *prev;
2684
2688 struct TransportClient *tc;
2689
2694
2701 struct PilsAddressSignContext *pc;
2702
2706 const char *address;
2707
2711 void *signed_address;
2712
2716 size_t signed_address_len;
2717
2722
2726 struct GNUNET_SCHEDULER_Task *st;
2727
2733
2738
2742 uint32_t aid;
2743
2748};
2749
2750
2754struct TransportClient
2755{
2759 struct TransportClient *next;
2760
2764 struct TransportClient *prev;
2765
2770
2774 struct GNUNET_MQ_Handle *mq;
2775
2779 enum ClientType type;
2780
2781 union
2782 {
2786 struct
2787 {
2793
2798 } core;
2799
2803 struct
2804 {
2811
2815 int one_shot;
2816 } monitor;
2817
2818
2822 struct
2823 {
2828 char *address_prefix;
2829
2833 struct Queue *queue_head;
2834
2838 struct Queue *queue_tail;
2839
2845
2851
2857 unsigned int total_queue_length;
2858
2863
2868
2873
2874 } communicator;
2875
2879 struct
2880 {
2886 } application;
2887 } details;
2888};
2889
2890
2895struct ValidationState
2896{
2901 struct GNUNET_PeerIdentity pid;
2902
2910
2916
2923 struct GNUNET_TIME_Absolute first_challenge_use;
2924
2931 struct GNUNET_TIME_Absolute last_challenge_use;
2932
2940 struct GNUNET_TIME_Absolute next_challenge;
2941
2950 struct GNUNET_TIME_Relative challenge_backoff;
2951
2956 struct GNUNET_TIME_Relative validation_rtt;
2957
2965 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
2966
2970 struct GNUNET_HashCode hc;
2971
2975 struct GNUNET_SCHEDULER_Task *revalidation_task;
2976
2980 char *address;
2981
2987 struct GNUNET_CONTAINER_HeapNode *hn;
2988
2994
3000 uint32_t last_window_consum_limit;
3001
3006 int awaiting_queue;
3007};
3008
3009
3016struct Backtalker
3017{
3021 struct GNUNET_PeerIdentity pid;
3022
3027
3032
3037
3043
3048
3054
3060
3065 size_t body_size;
3066};
3067
3072
3076static unsigned int ring_buffer_head;
3077
3081static unsigned int is_ring_buffer_full;
3082
3087
3091static unsigned int ring_buffer_dv_head;
3092
3096static unsigned int is_ring_buffer_dv_full;
3097
3101static struct TransportClient *clients_head;
3102
3106static struct TransportClient *clients_tail;
3107
3111static struct GNUNET_STATISTICS_Handle *GST_stats;
3112
3116static const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
3117
3123static struct GNUNET_SERVICE_Handle *GST_service;
3124
3130
3135
3141
3147
3153
3159
3165
3171
3177
3183
3188
3192static struct LearnLaunchEntry *lle_head = NULL;
3193
3197static struct LearnLaunchEntry *lle_tail = NULL;
3198
3205
3209struct GNUNET_NAT_Handle *nh;
3210
3214static struct GNUNET_PEERSTORE_Handle *peerstore;
3215
3219static struct GNUNET_PILS_Handle *pils;
3220
3224struct PilsRequest
3225{
3229 struct PilsRequest *prev;
3230
3234 struct PilsRequest *next;
3235
3239 struct GNUNET_PILS_Operation *op;
3240};
3241
3245static struct PilsRequest *pils_requests_head;
3246
3250static struct PilsRequest *pils_requests_tail;
3251
3276static enum GNUNET_GenericReturnValue
3278 struct GNUNET_CRYPTO_EddsaSignature *sig)
3279{
3281
3283 if (NULL == my_private_key)
3284 {
3285 /* #run() enables local key access, so this means the key on disk does
3286 not match the identity PILS announced, or no identity is known yet. */
3288 "No private key for our peer identity, cannot sign\n");
3290 "# signatures failed (no private key)",
3291 1,
3292 GNUNET_NO);
3293 return GNUNET_SYSERR;
3294 }
3295 return GNUNET_CRYPTO_eddsa_sign_ (my_private_key, purpose, sig);
3296}
3297
3298
3302static struct GNUNET_SCHEDULER_Task *dvlearn_task;
3303
3308
3313
3318
3324static struct IncomingRequest *ir_head;
3325
3329static struct IncomingRequest *ir_tail;
3330
3334static unsigned int ir_total;
3335
3339static unsigned long long logging_uuid_gen;
3340
3345
3355
3360static int in_shutdown;
3361
3365static struct GNUNET_SCHEDULER_Task *burst_task;
3366
3373
3375
3377
3388static unsigned int
3389get_age ()
3390{
3391 struct GNUNET_TIME_Absolute now;
3392
3393 now = GNUNET_TIME_absolute_get ();
3394 return now.abs_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us / 15;
3395}
3396
3397
3403static void
3405{
3407 GNUNET_assert (ir_total > 0);
3408 ir_total--;
3409 if (NULL != ir->nc)
3411 ir->nc = NULL;
3412 GNUNET_free (ir);
3413}
3414
3415
3421static void
3423{
3424 struct Queue *q = pa->queue;
3425 struct PendingMessage *pm = pa->pm;
3426 struct DistanceVectorHop *dvh = pa->dvh;
3427
3429 "free_pending_acknowledgement\n");
3430 if (NULL != q)
3431 {
3432 GNUNET_CONTAINER_MDLL_remove (queue, q->pa_head, q->pa_tail, pa);
3433 pa->queue = NULL;
3434 }
3435 if (NULL != pm)
3436 {
3438 "remove pa from message\n");
3440 "remove pa from message %" PRIu64 "\n",
3441 pm->logging_uuid);
3443 "remove pa from message %u\n",
3444 pm->pmt);
3446 "remove pa from message %s\n",
3448 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
3449 pa->pm = NULL;
3450 }
3451 if (NULL != dvh)
3452 {
3453 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
3454 pa->dvh = NULL;
3455 }
3458 &pa->ack_uuid.value,
3459 pa));
3460 GNUNET_free (pa);
3461}
3462
3463
3472static void
3474{
3475 struct PendingMessage *frag;
3476
3477 while (NULL != (frag = root->head_frag))
3478 {
3479 struct PendingAcknowledgement *pa;
3480
3481 free_fragment_tree (frag);
3482 while (NULL != (pa = frag->pa_head))
3483 {
3484 GNUNET_CONTAINER_MDLL_remove (pm, frag->pa_head, frag->pa_tail, pa);
3485 pa->pm = NULL;
3486 }
3487 GNUNET_CONTAINER_MDLL_remove (frag, root->head_frag, root->tail_frag, frag);
3488 if (NULL != frag->qe)
3489 {
3490 GNUNET_assert (frag == frag->qe->pm);
3491 frag->qe->pm = NULL;
3492 }
3494 "Free frag %p\n",
3495 frag);
3496 GNUNET_free (frag);
3497 }
3498}
3499
3500
3508static void
3510{
3511 struct TransportClient *tc = pm->client;
3512 struct VirtualLink *vl = pm->vl;
3513 struct PendingAcknowledgement *pa;
3514
3516 "Freeing pm %p\n",
3517 pm);
3518 if (NULL != tc)
3519 {
3521 tc->details.core.pending_msg_head,
3522 tc->details.core.pending_msg_tail,
3523 pm);
3524 }
3525 if ((NULL != vl) && (NULL == pm->frag_parent))
3526 {
3528 "Removing pm %" PRIu64 "\n",
3529 pm->logging_uuid);
3531 vl->pending_msg_head,
3532 vl->pending_msg_tail,
3533 pm);
3534 }
3535 else if (NULL != pm->frag_parent && PMT_DV_BOX != pm->pmt)
3536 {
3537 struct PendingMessage *root = pm->frag_parent;
3538
3539 while (NULL != root->frag_parent && PMT_DV_BOX != root->pmt)
3540 root = root->frag_parent;
3541
3542 root->frag_count--;
3543 }
3544 while (NULL != (pa = pm->pa_head))
3545 {
3546 if (NULL == pa)
3548 "free pending pa null\n");
3549 if (NULL == pm->pa_tail)
3551 "free pending pa_tail null\n");
3552 if (NULL == pa->prev_pa)
3554 "free pending pa prev null\n");
3555 if (NULL == pa->next_pa)
3557 "free pending pa next null\n");
3558 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
3559 pa->pm = NULL;
3560 }
3561
3562 free_fragment_tree (pm);
3563 if (NULL != pm->qe)
3564 {
3565 GNUNET_assert (pm == pm->qe->pm);
3566 pm->qe->pm = NULL;
3567 }
3568 if (NULL != pm->bpm)
3569 {
3570 free_fragment_tree (pm->bpm);
3571 if (NULL != pm->bpm->qe)
3572 {
3573 struct QueueEntry *qe = pm->bpm->qe;
3574
3575 qe->pm = NULL;
3576 }
3577 GNUNET_free (pm->bpm);
3578 }
3579
3580 GNUNET_free (pm);
3582 "Freeing pm done\n");
3583}
3584
3585
3591static void
3593{
3594 struct VirtualLink *vl = rc->virtual_link;
3595
3599 rc->msg_uuid.uuid,
3600 rc));
3601 GNUNET_free (rc);
3602}
3603
3604
3610static void
3611reassembly_cleanup_task (void *cls)
3612{
3613 struct VirtualLink *vl = cls;
3614 struct ReassemblyContext *rc;
3615
3616 vl->reassembly_timeout_task = NULL;
3617 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (vl->reassembly_heap)))
3618 {
3620 .rel_value_us)
3621 {
3623 continue;
3624 }
3629 vl);
3630 return;
3631 }
3632}
3633
3634
3643static int
3644free_reassembly_cb (void *cls, uint32_t key, void *value)
3645{
3646 struct ReassemblyContext *rc = value;
3647
3648 (void) cls;
3649 (void) key;
3651 return GNUNET_OK;
3652}
3653
3654
3661static void
3663 unsigned int free_cmc);
3664
3665
3673static void
3675 struct CommunicatorMessageContext *cmc);
3676
3677
3684static void
3685free_burst_cls (struct GNUNET_StartBurstCls *sb_cls);
3686
3687
3705static void
3707 const struct GNUNET_PeerIdentity *pid)
3708{
3709 struct GNUNET_MQ_Envelope *env;
3710 struct SendOkMessage *so_msg;
3711
3712 if (NULL == tc)
3713 return;
3715 so_msg->peer = *pid;
3716 GNUNET_MQ_send (tc->mq, env);
3717}
3718
3719
3732static void
3733credit_client (struct PendingMessage *pm)
3734{
3735 if ((NULL == pm->client) || (GNUNET_YES == pm->client_credited))
3736 return;
3738 send_ok_to_client (pm->client, &pm->vl->target);
3739}
3740
3741
3747static void
3748free_virtual_link (struct VirtualLink *vl)
3749{
3750 struct PendingMessage *pm;
3751 struct CoreSentContext *csc;
3752 struct CommunicatorMessageContext *cmc;
3753
3755 "free virtual link %p\n",
3756 vl);
3757
3758 /* Communicators that are blocked on CORE flow control for this link MUST
3759 be resumed here. Otherwise their `struct CommunicatorMessageContext's
3760 leak and -- worse -- those clients never get their
3761 GNUNET_SERVICE_client_continue() and stall forever. */
3762 while (NULL != (cmc = vl->cmc_head))
3763 release_stalled_cmc (vl, cmc);
3764 if (NULL != vl->core_fc_stall_task)
3765 {
3767 vl->core_fc_stall_task = NULL;
3768 }
3769
3770 if (NULL != vl->reassembly_map)
3771 {
3774 NULL);
3776 vl->reassembly_map = NULL;
3778 vl->reassembly_heap = NULL;
3779 }
3780 if (NULL != vl->reassembly_timeout_task)
3781 {
3783 vl->reassembly_timeout_task = NULL;
3784 }
3785 while (NULL != (pm = vl->pending_msg_head))
3786 {
3787 /* These never got transmitted, so #completed_pending_message() will not
3788 run for them and nobody else answers their SEND either. Return the
3789 window credit anyway: CORE keeps its `struct Neighbour' -- and thus
3790 the window -- until it sees our DISCONNECT, and #handle_client_send()
3791 deliberately tolerates a SEND for a link that is already gone, so a
3792 client can easily still be sending while we free this. */
3793 credit_client (pm);
3795 }
3798 if (NULL != vl->visibility_task)
3799 {
3801 vl->visibility_task = NULL;
3802 }
3803 if (NULL != vl->fc_retransmit_task)
3804 {
3806 vl->fc_retransmit_task = NULL;
3807 }
3808 while (NULL != (csc = vl->csc_head))
3809 {
3811 GNUNET_assert (vl == csc->vl);
3812 csc->vl = NULL;
3813 }
3814 if (NULL != vl->unconfirmed_timeout_task)
3815 {
3817 vl->unconfirmed_timeout_task = NULL;
3818 }
3819 if (NULL != vl->ic)
3820 {
3821 /* the closure of this iteration is @e sb_cls, released just below */
3823 vl->ic = NULL;
3824 }
3825 if (NULL != vl->sb_cls)
3826 {
3827 /* Cancels #burst_task if that task's closure is ours: it would
3828 otherwise run on this (freed) link. */
3829 free_burst_cls (vl->sb_cls);
3830 GNUNET_assert (NULL == vl->sb_cls);
3831 }
3832 GNUNET_free (vl->burst_addr);
3833 GNUNET_break (NULL == vl->n);
3834 GNUNET_break (NULL == vl->dv);
3835 GNUNET_free (vl);
3836}
3837
3838
3844static void
3846{
3847 if (NULL != vs->revalidation_task)
3848 {
3849 GNUNET_SCHEDULER_cancel (vs->revalidation_task);
3850 vs->revalidation_task = NULL;
3851 }
3852 /*memcpy (&hkey,
3853 &hc,
3854 sizeof (hkey));*/
3856 "Remove key %s for address %s map size %u contains %u during freeing state\n",
3857 GNUNET_h2s (&vs->hc),
3858 vs->address,
3861 &vs->hc));
3864 GNUNET_YES ==
3867 vs->hn = NULL;
3868 if (NULL != vs->sc)
3869 {
3871 "store cancel\n");
3873 vs->sc = NULL;
3874 }
3875 GNUNET_free (vs->address);
3876 GNUNET_free (vs);
3877}
3878
3879
3886static struct Neighbour *
3888{
3890}
3891
3892
3899static struct VirtualLink *
3900lookup_virtual_link (const struct GNUNET_PeerIdentity *pid)
3901{
3903}
3904
3905
3909struct MonitorEvent
3910{
3917
3922
3927
3931 uint32_t num_msg_pending;
3932
3936 uint32_t num_bytes_pending;
3937};
3938
3939
3948static void
3950{
3951 struct Neighbour *n = dvh->next_hop;
3952 struct DistanceVector *dv = dvh->dv;
3953 struct PendingAcknowledgement *pa;
3954
3955 while (NULL != (pa = dvh->pa_head))
3956 {
3958 pa->dvh = NULL;
3959 }
3960 GNUNET_CONTAINER_MDLL_remove (neighbour, n->dv_head, n->dv_tail, dvh);
3962 GNUNET_free (dvh);
3963}
3964
3965
3972static void
3973check_link_down (void *cls);
3974
3975
3981static void
3983{
3985 "Informing CORE clients about disconnect from %s\n",
3986 GNUNET_i2s (pid));
3987 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3988 {
3989 struct GNUNET_MQ_Envelope *env;
3990 struct DisconnectInfoMessage *dim;
3991
3992 if (CT_CORE != tc->type)
3993 continue;
3995 dim->peer = *pid;
3996 GNUNET_MQ_send (tc->mq, env);
3997 }
3998}
3999
4000
4001static void
4002try_to_bring_link_up (const struct GNUNET_PeerIdentity *pid);
4003
4004
4027static void
4029{
4030 struct GNUNET_PeerIdentity target = vl->target;
4031
4032 for (struct PendingMessage *pm = vl->pending_msg_head;
4033 NULL != pm;
4034 pm = pm->next_vl)
4035 credit_client (pm);
4037 free_virtual_link (vl);
4038 /* Start getting it back now. Only #handle_validation_response() can
4039 rebuild it, and a successful validation parks @e revalidation_task just
4040 short of #ADDRESS_VALIDATION_LIFETIME -- four hours away. */
4041 try_to_bring_link_up (&target);
4042}
4043
4044
4051static void
4052free_dv_route (struct DistanceVector *dv)
4053{
4054 struct DistanceVectorHop *dvh;
4055 struct VirtualLink *vl;
4056
4057 while (NULL != (dvh = dv->dv_head))
4059
4061 GNUNET_YES ==
4063 if (NULL != (vl = dv->vl))
4064 {
4065 GNUNET_assert (dv == vl->dv);
4066 vl->dv = NULL;
4067 if (NULL == vl->n)
4068 {
4070 }
4071 else
4072 {
4075 }
4076 dv->vl = NULL;
4077 }
4078
4079 if (NULL != dv->timeout_task)
4080 {
4082 dv->timeout_task = NULL;
4083 }
4084 GNUNET_free (dv->km);
4085 GNUNET_free (dv);
4086}
4087
4088
4102static void
4104 const struct GNUNET_PeerIdentity *peer,
4105 const char *address,
4107 const struct MonitorEvent *me)
4108{
4109 struct GNUNET_MQ_Envelope *env;
4111 size_t addr_len = strlen (address) + 1;
4112
4114 addr_len,
4116 md->nt = htonl ((uint32_t) nt);
4117 md->peer = *peer;
4118 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
4119 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
4120 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
4121 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
4122 md->cs = htonl ((uint32_t) me->cs);
4123 md->num_msg_pending = htonl (me->num_msg_pending);
4124 md->num_bytes_pending = htonl (me->num_bytes_pending);
4125 memcpy (&md[1], address, addr_len);
4126 GNUNET_MQ_send (tc->mq, env);
4127}
4128
4129
4139static void
4141 const char *address,
4143 const struct MonitorEvent *me)
4144{
4145 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
4146 {
4147 if (CT_MONITOR != tc->type)
4148 continue;
4149 if (tc->details.monitor.one_shot)
4150 continue;
4151 if ((GNUNET_NO == GNUNET_is_zero (&tc->details.monitor.peer)) &&
4152 (0 != GNUNET_memcmp (&tc->details.monitor.peer, peer)))
4153 continue;
4155 }
4156}
4157
4158
4168static void *
4169client_connect_cb (void *cls,
4170 struct GNUNET_SERVICE_Client *client,
4171 struct GNUNET_MQ_Handle *mq)
4172{
4173 struct TransportClient *tc;
4174
4175 (void) cls;
4176 tc = GNUNET_new (struct TransportClient);
4177 tc->client = client;
4178 tc->mq = mq;
4181 "Client %p of type %u connected\n",
4182 tc,
4183 tc->type);
4184 return tc;
4185}
4186
4187
4188static enum GNUNET_GenericReturnValue
4189remove_global_addresses (void *cls,
4190 const struct GNUNET_PeerIdentity *pid,
4191 void *value)
4192{
4193 struct TransportGlobalNattedAddress *tgna = value;
4194 (void) cls;
4195
4196 GNUNET_free (tgna);
4197
4198 return GNUNET_OK;
4199}
4200
4201
4208static void
4209free_neighbour (struct Neighbour *neighbour,
4210 enum GNUNET_GenericReturnValue drop_link)
4211{
4212 struct DistanceVectorHop *dvh;
4213 struct VirtualLink *vl;
4214
4215 GNUNET_assert (NULL == neighbour->queue_head);
4218 &neighbour->pid,
4219 neighbour));
4221 "Freeing neighbour\n");
4224 NULL);
4226 while (NULL != (dvh = neighbour->dv_head))
4227 {
4228 struct DistanceVector *dv = dvh->dv;
4229
4231 if (NULL == dv->dv_head)
4232 free_dv_route (dv);
4233 }
4234 if (NULL != neighbour->get)
4235 {
4237 neighbour->get = NULL;
4238 }
4239 if (NULL != neighbour->sc)
4240 {
4242 "store cancel\n");
4243 GNUNET_PEERSTORE_store_cancel (neighbour->sc);
4244 neighbour->sc = NULL;
4245 }
4246 if (NULL != (vl = neighbour->vl))
4247 {
4248 GNUNET_assert (neighbour == vl->n);
4249 vl->n = NULL;
4250 if ((GNUNET_YES == drop_link) || (NULL == vl->dv))
4251 {
4253 }
4254 else
4255 {
4258 }
4259 neighbour->vl = NULL;
4260 }
4261 GNUNET_free (neighbour);
4262}
4263
4264
4271static void
4273 const struct GNUNET_PeerIdentity *pid)
4274{
4275 struct GNUNET_MQ_Envelope *env;
4276 struct ConnectInfoMessage *cim;
4277
4278 GNUNET_assert (CT_CORE == tc->type);
4280 cim->id = *pid;
4281 GNUNET_MQ_send (tc->mq, env);
4282}
4283
4284
4290static void
4292{
4294 "Informing CORE clients about connection to %s\n",
4295 GNUNET_i2s (pid));
4296 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
4297 {
4298 if (CT_CORE != tc->type)
4299 continue;
4301 }
4302}
4303
4304
4312static void
4313transmit_on_queue (void *cls);
4314
4315
4319static unsigned int
4321{
4322 for (struct Queue *s = queue_head; NULL != s;
4323 s = s->next_client)
4324 {
4325 if (s->tc->details.communicator.address_prefix !=
4326 queue->tc->details.communicator.address_prefix)
4327 {
4329 "queue address %s qid %u compare with queue: address %s qid %u\n",
4330 queue->address,
4331 queue->qid,
4332 s->address,
4333 s->qid);
4334 if ((s->priority > queue->priority) && (0 < s->q_capacity) &&
4335 (QUEUE_LENGTH_LIMIT > s->queue_length) )
4336 return GNUNET_YES;
4338 "Lower prio\n");
4339 }
4340 }
4341 return GNUNET_NO;
4342}
4343
4344
4351static void
4353
4354
4362static void
4364 struct Queue *queue,
4366{
4368
4369 if (queue->validated_until.abs_value_us < now.abs_value_us)
4370 return;
4372 queue->tc->details.communicator.
4373 queue_head))
4374 return;
4375
4376 if (queue->tc->details.communicator.total_queue_length >=
4378 {
4380 "Transmission on queue %s (QID %u) throttled due to communicator queue limit\n",
4381 queue->address,
4382 queue->qid);
4384 GST_stats,
4385 "# Transmission throttled due to communicator queue limit",
4386 1,
4387 GNUNET_NO);
4388 queue->idle = GNUNET_NO;
4389 /* @e total_queue_length is shared by every peer this communicator serves,
4390 so at the limit we can send to none of them, and the only things that
4391 lower it again are an ACK from the communicator, #free_queue() and
4392 #free_timedout_queue_entry(). If we got here because a peer stopped
4393 acknowledging, no ACK is coming; and we just declined to arm
4394 @e transmit_task, so #queue_send_msg() -- the *only* place that arms
4395 the sweeper -- will not run either. That leaves nothing at all to
4396 recover the count, and the communicator stays mute towards every peer
4397 until some unrelated queue happens to go down. Keep the sweeper
4398 going. */
4400 return;
4401 }
4402 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
4403 {
4405 "Transmission on queue %s (QID %u) throttled due to communicator queue length limit\n",
4406 queue->address,
4407 queue->qid);
4409 "# Transmission throttled due to queue queue limit",
4410 1,
4411 GNUNET_NO);
4412 queue->idle = GNUNET_NO;
4413 /* Same reasoning as above, for the per-queue limit. */
4415 return;
4416 }
4417 if (0 == queue->q_capacity)
4418 {
4420 "Transmission on queue %s (QID %u) throttled due to communicator message has capacity %"
4421 PRIu64 ".\n",
4422 queue->address,
4423 queue->qid,
4424 queue->q_capacity);
4426 "# Transmission throttled due to message queue capacity",
4427 1,
4428 GNUNET_NO);
4429 queue->idle = GNUNET_NO;
4430 return;
4431 }
4432 /* queue might indeed be ready, schedule it */
4433 if (NULL != queue->transmit_task)
4434 GNUNET_SCHEDULER_cancel (queue->transmit_task);
4435 queue->transmit_task =
4437 queue);
4439 "Considering transmission on queue `%s' QID %llu to %s\n",
4440 queue->address,
4441 (unsigned long long) queue->qid,
4442 GNUNET_i2s (&queue->neighbour->pid));
4443}
4444
4445
4446static void
4448 const char *address);
4449
4450
4457static void
4458check_link_down (void *cls)
4459{
4460 struct VirtualLink *vl = cls;
4461 struct DistanceVector *dv = vl->dv;
4462 struct Neighbour *n = vl->n;
4463 struct GNUNET_TIME_Absolute dvh_timeout;
4464 struct GNUNET_TIME_Absolute q_timeout;
4465
4467 "Checking if link is down\n");
4468 vl->visibility_task = NULL;
4469 dvh_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
4470 if (NULL != dv)
4471 {
4472 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4473 pos = pos->next_dv)
4474 dvh_timeout = GNUNET_TIME_absolute_max (dvh_timeout,
4475 pos->path_valid_until);
4476 if (0 == GNUNET_TIME_absolute_get_remaining (dvh_timeout).rel_value_us)
4477 {
4478 vl->dv->vl = NULL;
4479 vl->dv = NULL;
4480 }
4481 }
4482 q_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
4483 /* NOTE: @e n may be NULL here: #free_neighbour() clears vl->n and then
4484 schedules us when the link still has a DV route. */
4485 if (NULL != n)
4486 {
4487 struct GNUNET_TIME_Absolute liveness_deadline;
4488
4489 /* A successful validation is good for #ADDRESS_VALIDATION_LIFETIME (four
4490 hours). Do not take a communicator's word for that long: cap what the
4491 queues are worth by how recently this neighbour actually said anything
4492 to us. Otherwise a communicator that stops working without sending a
4493 QUEUE_TEARDOWN keeps this link -- and CORE's idea of the connection --
4494 alive until the validation expires. */
4495 liveness_deadline = GNUNET_TIME_absolute_add (n->last_inbound,
4497 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
4498 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
4499 if (GNUNET_TIME_absolute_cmp (liveness_deadline, <, q_timeout))
4500 {
4501 if (0 ==
4503 {
4504 /* Only reachable if a communicator failed to tear its queue down. */
4506 "Neighbour %s was silent for %s while its communicator "
4507 "kept claiming the queue works; treating link as down\n",
4508 GNUNET_i2s (&vl->target),
4511 GNUNET_YES));
4513 "# links dropped (neighbour silent)",
4514 1,
4515 GNUNET_NO);
4516 }
4517 q_timeout = liveness_deadline;
4518 }
4519 if (0 == GNUNET_TIME_absolute_get_remaining (q_timeout).rel_value_us)
4520 {
4521 vl->n->vl = NULL;
4522 vl->n = NULL;
4523 }
4524 }
4525 if ((NULL == vl->n) && (NULL == vl->dv))
4526 {
4528 /* @e n (if any) outlives the link, and so do its queues: the liveness cap
4529 above drops a link whose addresses are still well inside
4530 #ADDRESS_VALIDATION_LIFETIME. In that state nothing would ever ask for
4531 a fresh challenge -- @e revalidation_task does not fire until the four
4532 hour validity is nearly over, and the HELLO path reaches
4533 #start_address_validation() only to find an address that still counts
4534 as valid. Since #handle_validation_response() is the only thing that
4535 can rebuild this link and tell CORE about the peer again, ask for that
4536 validation now, or CORE never hears about this peer again. */
4537 if (NULL != n)
4538 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
4539 start_address_validation (&n->pid, q->address);
4540 return;
4541 }
4542 vl->visibility_task =
4543 GNUNET_SCHEDULER_add_at (GNUNET_TIME_absolute_max (q_timeout, dvh_timeout),
4545 vl);
4546}
4547
4548
4554static void
4555free_queue (struct Queue *queue)
4556{
4557 struct Neighbour *neighbour = queue->neighbour;
4558 struct TransportClient *tc = queue->tc;
4559 struct MonitorEvent me = { .cs = GNUNET_TRANSPORT_CS_DOWN,
4561 struct QueueEntry *qe;
4562 int maxxed;
4563 struct PendingAcknowledgement *pa;
4564 struct VirtualLink *vl;
4565
4567 "Cleaning up queue %u\n", queue->qid);
4568 if (NULL != queue->mo)
4569 {
4571 queue->mo = NULL;
4572 }
4573 if (NULL != queue->transmit_task)
4574 {
4575 GNUNET_SCHEDULER_cancel (queue->transmit_task);
4576 queue->transmit_task = NULL;
4577 }
4578 while (NULL != (pa = queue->pa_head))
4579 {
4580 GNUNET_CONTAINER_MDLL_remove (queue, queue->pa_head, queue->pa_tail, pa);
4581 pa->queue = NULL;
4582 }
4583
4585 neighbour->queue_head,
4586 neighbour->queue_tail,
4587 queue);
4589 tc->details.communicator.queue_head,
4590 tc->details.communicator.queue_tail,
4591 queue);
4593 tc->details.communicator.total_queue_length);
4595 "Cleaning up queue with length %u\n",
4596 queue->queue_length);
4597 while (NULL != (qe = queue->queue_head))
4598 {
4599 GNUNET_CONTAINER_DLL_remove (queue->queue_head, queue->queue_tail, qe);
4600 queue->queue_length--;
4601 tc->details.communicator.total_queue_length--;
4602 if (NULL != qe->pm)
4603 {
4604 GNUNET_assert (qe == qe->pm->qe);
4605 qe->pm->qe = NULL;
4606 }
4607 GNUNET_free (qe);
4608 }
4609 GNUNET_assert (0 == queue->queue_length);
4610 if ((maxxed) && (COMMUNICATOR_TOTAL_QUEUE_LIMIT >
4611 tc->details.communicator.total_queue_length))
4612 {
4613 /* Communicator dropped below threshold, resume all _other_ queues */
4615 GST_stats,
4616 "# Transmission throttled due to communicator queue limit",
4617 -1,
4618 GNUNET_NO);
4619 for (struct Queue *s = tc->details.communicator.queue_head; NULL != s;
4620 s = s->next_client)
4622 s,
4624 }
4625 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
4627
4628 vl = lookup_virtual_link (&neighbour->pid);
4629 if ((NULL != vl) && (neighbour == vl->n))
4630 {
4632 check_link_down (vl);
4633 }
4634 if (NULL == neighbour->queue_head)
4635 {
4636 free_neighbour (neighbour, GNUNET_NO);
4637 }
4638}
4639
4640
4648static void
4650
4651
4657static void
4659{
4660 struct TransportClient *tc = ale->tc;
4661
4662 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
4663 tc->details.communicator.addr_tail,
4664 ale);
4665 /* Cancels @e sc, @e shc and the pending PILS signature request, all of
4666 which would otherwise run their callbacks on this freed entry. */
4668 if (NULL != ale->sc)
4669 {
4671 "store cancel\n");
4673 ale->sc = NULL;
4674 }
4675 if (NULL != ale->shc)
4676 {
4678 ale->shc = NULL;
4679 }
4680 if (NULL != ale->st)
4681 {
4683 ale->st = NULL;
4684 }
4685 if (NULL != ale->signed_address)
4687 GNUNET_free (ale);
4688}
4689
4690
4699static int
4700stop_peer_request (void *cls,
4701 const struct GNUNET_PeerIdentity *pid,
4702 void *value)
4703{
4704 struct TransportClient *tc = cls;
4705 struct PeerRequest *pr = value;
4706
4707 if (NULL != pr->nc)
4709 pr->nc = NULL;
4711 GNUNET_YES ==
4712 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
4713 pid,
4714 pr));
4715 GNUNET_free (pr);
4716
4717 return GNUNET_OK;
4718}
4719
4720
4721static void
4722do_shutdown (void *cls);
4723
4732static void
4733client_disconnect_cb (void *cls,
4734 struct GNUNET_SERVICE_Client *client,
4735 void *app_ctx)
4736{
4737 struct TransportClient *tc = app_ctx;
4738
4739 (void) cls;
4740 (void) client;
4742 switch (tc->type)
4743 {
4744 case CT_NONE:
4746 "Unknown Client %p disconnected, cleaning up.\n",
4747 tc);
4748 break;
4749
4750 case CT_CORE: {
4751 struct PendingMessage *pm;
4753 "CORE Client %p disconnected, cleaning up.\n",
4754 tc);
4755
4756
4757 while (NULL != (pm = tc->details.core.pending_msg_head))
4758 {
4760 tc->details.core.pending_msg_head,
4761 tc->details.core.pending_msg_tail,
4762 pm);
4763 pm->client = NULL;
4764 }
4765 }
4766 break;
4767
4768 case CT_MONITOR:
4770 "MONITOR Client %p disconnected, cleaning up.\n",
4771 tc);
4772
4773 break;
4774
4775 case CT_COMMUNICATOR: {
4776 struct Queue *q;
4777 struct AddressListEntry *ale;
4778
4780 "COMMUNICATOR Client %p disconnected, cleaning up.\n",
4781 tc);
4782
4783 if (NULL != tc->details.communicator.free_queue_entry_task)
4785 tc->details.communicator.free_queue_entry_task);
4786 while (NULL != (q = tc->details.communicator.queue_head))
4787 free_queue (q);
4788 while (NULL != (ale = tc->details.communicator.addr_head))
4790 GNUNET_free (tc->details.communicator.address_prefix);
4791 }
4792 break;
4793
4794 case CT_APPLICATION:
4796 "APPLICATION Client %p disconnected, cleaning up.\n",
4797 tc);
4798
4799 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
4801 tc);
4802 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
4803 break;
4804 }
4805 GNUNET_free (tc);
4806 if ((GNUNET_YES == in_shutdown) && (NULL == clients_head))
4807 {
4809 "Our last client disconnected\n");
4810 do_shutdown (cls);
4811 }
4812}
4813
4814
4824static int
4826 const struct GNUNET_PeerIdentity *pid,
4827 void *value)
4828{
4829 struct TransportClient *tc = cls;
4830 struct VirtualLink *vl = value;
4831
4832 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
4833 return GNUNET_OK;
4834
4836 "Telling new CORE client about existing connection to %s\n",
4837 GNUNET_i2s (pid));
4839 return GNUNET_OK;
4840}
4841
4842
4848static void
4850 unsigned
4851 int free_cmc);
4852
4853static enum GNUNET_GenericReturnValue
4854resume_communicators (void *cls,
4855 const struct GNUNET_PeerIdentity *pid,
4856 void *value)
4857{
4858 struct VirtualLink *vl = value;
4859 struct CommunicatorMessageContext *cmc;
4860
4861 /* resume communicators */
4862 while (NULL != (cmc = vl->cmc_tail))
4863 release_stalled_cmc (vl, cmc);
4864 if (NULL != vl->core_fc_stall_task)
4865 {
4867 vl->core_fc_stall_task = NULL;
4868 }
4869 /* A CORE client that just attached has nothing outstanding, so give it a
4870 full window. The RECV_OKs that would have returned the credit spent by
4871 its predecessor died with that client, and #handle_client_recv_ok() is
4872 the only thing that ever raises this counter -- so without the reset
4873 every message on this link takes the "CORE ran out of window" path from
4874 here on, and only #core_fc_stalled() (after CORE_FC_STALL_TIMEOUT, and
4875 once per round) ever lets any through. */
4877 return GNUNET_OK;
4878}
4879
4880
4889static void
4890handle_client_start (void *cls, const struct StartMessage *start)
4891{
4892 // const struct GNUNET_PeerIdentity *my_identity;
4893 struct TransportClient *tc = cls;
4894 // uint32_t options;
4895 //
4896 // my_identity = GNUNET_PILS_get_identity (pils);
4897 // GNUNET_assert (my_identity);
4898 //
4899 // FIXME ignore the check of the peer ids for now.
4900 // (also deprecate the old way of obtaining our own peer ID)
4901 // options = ntohl (start->options);
4902 // if ((0 != (1 & options)) &&
4903 // (0 != GNUNET_memcmp (&start->self, my_identity)))
4904 // {
4905 // /* client thinks this is a different peer, reject */
4906 // GNUNET_break (0);
4907 // GNUNET_SERVICE_client_drop (tc->client);
4908 // return;
4909 // }
4910 if (CT_NONE != tc->type)
4911 {
4912 GNUNET_break (0);
4914 return;
4915 }
4916 tc->type = CT_CORE;
4918 "New CORE client with PID %s registered\n",
4919 GNUNET_i2s (&start->self));
4922 tc);
4925 NULL);
4927}
4928
4929
4936static int
4937check_client_send (void *cls, const struct OutboundMessage *obm)
4938{
4939 struct TransportClient *tc = cls;
4940 uint16_t size;
4941 const struct GNUNET_MessageHeader *obmm;
4942
4943 if (CT_CORE != tc->type)
4944 {
4945 GNUNET_break (0);
4946 return GNUNET_SYSERR;
4947 }
4948 size = ntohs (obm->header.size) - sizeof(struct OutboundMessage);
4949 if (size < sizeof(struct GNUNET_MessageHeader))
4950 {
4951 GNUNET_break (0);
4952 return GNUNET_SYSERR;
4953 }
4954 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
4955 if (size != ntohs (obmm->size))
4956 {
4957 GNUNET_break (0);
4958 return GNUNET_SYSERR;
4959 }
4960 return GNUNET_OK;
4961}
4962
4963
4971static void
4973{
4974 struct TransportClient *tc = pm->client;
4975 struct VirtualLink *vl = pm->vl;
4976
4978 "client send response\n");
4979 if (NULL != tc)
4980 {
4982 "Confirming transmission of <%" PRIu64 "> to %s\n",
4983 pm->logging_uuid,
4984 GNUNET_i2s (&vl->target));
4985 credit_client (pm);
4986 }
4988}
4989
4990
5000static unsigned int
5003 struct DistanceVectorHop **hops_array,
5004 unsigned int hops_array_length)
5005{
5006 uint64_t choices[hops_array_length];
5007 uint64_t num_dv;
5008 unsigned int dv_count;
5009
5010 /* Pick random vectors, but weighted by distance, giving more weight
5011 to shorter vectors */
5012 num_dv = 0;
5013 dv_count = 0;
5014 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5015 pos = pos->next_dv)
5016 {
5017 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
5018 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
5019 .rel_value_us == 0))
5020 continue; /* pos unconfirmed and confirmed required */
5021 num_dv += MAX_DV_HOPS_ALLOWED - pos->distance;
5022 dv_count++;
5023 }
5024 if (0 == dv_count)
5025 return 0;
5026 if (dv_count <= hops_array_length)
5027 {
5028 dv_count = 0;
5029 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5030 pos = pos->next_dv)
5031 hops_array[dv_count++] = pos;
5032 return dv_count;
5033 }
5034 for (unsigned int i = 0; i < hops_array_length; i++)
5035 {
5036 int ok = GNUNET_NO;
5037 while (GNUNET_NO == ok)
5038 {
5039 choices[i] =
5040 GNUNET_CRYPTO_random_u64 (num_dv);
5041 ok = GNUNET_YES;
5042 for (unsigned int j = 0; j < i; j++)
5043 if (choices[i] == choices[j])
5044 {
5045 ok = GNUNET_NO;
5046 break;
5047 }
5048 }
5049 }
5050 dv_count = 0;
5051 num_dv = 0;
5052 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5053 pos = pos->next_dv)
5054 {
5055 uint32_t delta = MAX_DV_HOPS_ALLOWED - pos->distance;
5056
5057 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
5058 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
5059 .rel_value_us == 0))
5060 continue; /* pos unconfirmed and confirmed required */
5061 for (unsigned int i = 0; i < hops_array_length; i++)
5062 if ((num_dv <= choices[i]) && (num_dv + delta > choices[i]))
5063 hops_array[dv_count++] = pos;
5064 num_dv += delta;
5065 }
5066 return dv_count;
5067}
5068
5069
5076static int
5078 void *cls,
5080{
5081 struct TransportClient *tc = cls;
5082 uint16_t size;
5083
5084 if (CT_NONE != tc->type)
5085 {
5086 GNUNET_break (0);
5087 return GNUNET_SYSERR;
5088 }
5089 tc->type = CT_COMMUNICATOR;
5090 size = ntohs (cam->header.size) - sizeof(*cam);
5091 if (0 == size)
5092 return GNUNET_OK; /* receive-only communicator */
5094 return GNUNET_OK;
5095}
5096
5097
5109static void
5111{
5112 struct GNUNET_MQ_Envelope *env;
5114
5115 if (GNUNET_YES == cmc->ack_sent)
5116 return;
5117 cmc->ack_sent = GNUNET_YES;
5118 if (0 == ntohl (cmc->im.fc_on))
5119 return; /* communicator did not ask for flow control */
5121 "Acknowledge message with flow control id %" PRIu64 "\n",
5122 cmc->im.fc_id);
5124 ack->reserved = htonl (0);
5125 ack->fc_id = cmc->im.fc_id;
5126 ack->sender = cmc->im.neighbour_sender;
5127 GNUNET_MQ_send (cmc->tc->mq, env);
5128}
5129
5130
5141static void
5143{
5144 if (GNUNET_YES == cmc->client_resumed)
5145 return;
5148}
5149
5150
5159static void
5161 unsigned
5162 int free_cmc)
5163{
5164 send_cmc_ack (cmc);
5165 resume_cmc_client (cmc);
5166 if (GNUNET_YES == free_cmc)
5167 {
5168 GNUNET_free (cmc);
5169 }
5170}
5171
5172
5173static void
5175 struct CommunicatorMessageContext *cmc)
5176{
5178 GNUNET_assert (0 < vl->cmc_count);
5179 vl->cmc_count--;
5181}
5182
5183
5184static void
5186{
5188}
5189
5190
5200static void
5201handle_client_recv_ok (void *cls, const struct RecvOkMessage *rom)
5202{
5203 struct TransportClient *tc = cls;
5204 struct VirtualLink *vl;
5205 uint32_t delta;
5206 struct CommunicatorMessageContext *cmc;
5207
5208 if (CT_CORE != tc->type)
5209 {
5210 GNUNET_break (0);
5212 return;
5213 }
5214 vl = lookup_virtual_link (&rom->peer);
5215 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
5216 {
5218 "# RECV_OK dropped: virtual link unknown",
5219 1,
5220 GNUNET_NO);
5222 return;
5223 }
5224 delta = ntohl (rom->increase_window_delta);
5225 vl->core_recv_window += delta;
5227 "CORE ack receiving message, increased CORE recv window to %d\n",
5228 vl->core_recv_window);
5230 if (vl->core_recv_window <= 0)
5231 return;
5232 /* release the flow control credit we withheld from the communicators */
5233 while (NULL != (cmc = vl->cmc_tail))
5234 release_stalled_cmc (vl, cmc);
5235 if (NULL != vl->core_fc_stall_task)
5236 {
5238 vl->core_fc_stall_task = NULL;
5239 }
5240}
5241
5242
5249static void
5251 void *cls,
5253{
5254 const struct GNUNET_PeerIdentity *my_identity;
5255 struct TransportClient *tc = cls;
5256 uint16_t size;
5257
5258 size = ntohs (cam->header.size) - sizeof(*cam);
5259 if (0 == size)
5260 {
5262 "Receive-only communicator connected\n");
5263 /* Receive-only communicator: it has no address prefix, but we still
5264 MUST resume the client or we will never read from it again. Use an
5265 empty prefix so that the various strcmp()s do not see NULL. */
5266 tc->details.communicator.address_prefix = GNUNET_strdup ("");
5268 return;
5269 }
5270 tc->details.communicator.address_prefix =
5271 GNUNET_strdup ((const char *) &cam[1]);
5272 tc->details.communicator.cc = ntohl (cam->cc);
5273 tc->details.communicator.can_burst = ntohl (cam->can_burst);
5275 if (NULL != my_identity)
5276 {
5278 "Communicator for peer %s with prefix '%s' connected %s\n",
5280 tc->details.communicator.address_prefix,
5281 tc->details.communicator.can_burst ? "can burst" :
5282 "can not burst");
5283 }
5284 else
5285 {
5287 "Communicator for local peer with prefix '%s' connected %s\n",
5288 tc->details.communicator.address_prefix,
5289 tc->details.communicator.can_burst ? "can burst" :
5290 "can not burst");
5291 }
5293}
5294
5295
5303static int
5305 void *cls,
5307{
5308 const struct GNUNET_MessageHeader *inbox;
5309 const char *is;
5310 uint16_t msize;
5311 uint16_t isize;
5312
5313 (void) cls;
5314 msize = ntohs (cb->header.size) - sizeof(*cb);
5315 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
5316 /* MUST bound the buffer before dereferencing @a inbox. */
5317 if (msize <= sizeof(struct GNUNET_MessageHeader))
5318 {
5319 GNUNET_break (0);
5320 return GNUNET_SYSERR;
5321 }
5322 isize = ntohs (inbox->size);
5323 if (isize >= msize)
5324 {
5325 GNUNET_break (0);
5326 return GNUNET_SYSERR;
5327 }
5328 is = (const char *) inbox;
5329 is += isize;
5330 msize -= isize;
5331 GNUNET_assert (0 < msize);
5332 if ('\0' != is[msize - 1])
5333 {
5334 GNUNET_break (0);
5335 return GNUNET_SYSERR;
5336 }
5337 return GNUNET_OK;
5338}
5339
5340
5355static enum GNUNET_GenericReturnValue
5356sign_ephemeral (struct DistanceVector *dv)
5357{
5358 struct EphemeralConfirmationPS ec;
5359
5361 dv->ephemeral_validity =
5363 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
5364 ec.target = dv->target;
5365 ec.ephemeral_key = dv->ephemeral_key;
5366 ec.sender_monotonic_time = GNUNET_TIME_absolute_hton (dv->monotime);
5367 ec.purpose.size = htonl (sizeof(ec));
5368 return sign_by_my_identity (&ec.purpose, &dv->sender_sig);
5369}
5370
5371
5372static void
5374 struct TransportClient *tc);
5375
5376
5377static void
5378free_timedout_queue_entry (void *cls)
5379{
5380 struct TransportClient *tc = cls;
5382
5384 "freeing timedout queue entries\n");
5385
5386 tc->details.communicator.free_queue_entry_task = NULL;
5387 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
5388 queue = queue->next_client)
5389 {
5390 struct QueueEntry *qep = queue->queue_head;
5391
5393 "checking QID %u for timedout queue entries\n",
5394 queue->qid);
5395 while (NULL != qep)
5396 {
5397 struct QueueEntry *pos = qep;
5399 pos->creation_timestamp, now);
5400 qep = qep->next;
5401
5403 "diff to now %s \n",
5406 {
5408 "Freeing timed out QueueEntry with MID %" PRIu64
5409 " and QID %u\n",
5410 pos->mid,
5411 queue->qid);
5413 "# QueueEntries timed out",
5414 1,
5415 GNUNET_NO);
5416 free_queue_entry (pos, tc);
5417 }
5418 }
5419 }
5420 /* Entries younger than #QUEUE_ENTRY_TIMEOUT are still to be reclaimed, and
5421 this task used to be a one-shot armed only by #queue_send_msg(). So the
5422 sweep that was supposed to bound how long an unacknowledged entry holds
5423 its slot only ever ran while *new* messages were being queued -- exactly
5424 not the case once the throttles in #schedule_transmit_on_queue() have
5425 stopped transmission. Keep going as long as anything is outstanding. */
5427}
5428
5429
5430static void
5432{
5433 if (NULL != tc->details.communicator.free_queue_entry_task)
5434 return;
5435 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
5436 queue = queue->next_client)
5437 {
5438 if (NULL == queue->queue_head)
5439 continue;
5440 tc->details.communicator.free_queue_entry_task =
5443 tc);
5444 return;
5445 }
5446}
5447
5448
5458static void
5459queue_send_msg (struct Queue *queue,
5460 struct PendingMessage *pm,
5461 const void *payload,
5462 size_t payload_size)
5463{
5464 struct Neighbour *n = queue->neighbour;
5466 struct GNUNET_MQ_Envelope *env;
5467 struct PendingAcknowledgement *pa;
5468
5469 GNUNET_log (
5471 "Queueing %u bytes of payload for transmission <%" PRIu64
5472 "> on queue %llu to %s\n",
5473 (unsigned int) payload_size,
5474 (NULL == pm) ? 0 : pm->logging_uuid,
5475 (unsigned long long) queue->qid,
5476 GNUNET_i2s (&queue->neighbour->pid));
5477 env = GNUNET_MQ_msg_extra (smt,
5478 payload_size,
5480 smt->qid = htonl (queue->qid);
5481 smt->mid = GNUNET_htonll (queue->mid_gen);
5482 smt->receiver = n->pid;
5483 memcpy (&smt[1], payload, payload_size);
5484 {
5485 /* Pass the env to the communicator of queue for transmission. */
5486 struct QueueEntry *qe;
5487
5488 qe = GNUNET_new (struct QueueEntry);
5489 qe->creation_timestamp = GNUNET_TIME_absolute_get ();
5490 qe->mid = queue->mid_gen;
5492 "Create QueueEntry with MID %" PRIu64
5493 " and QID %u and prefix %s\n",
5494 qe->mid,
5495 queue->qid,
5496 queue->tc->details.communicator.address_prefix);
5497 queue->mid_gen++;
5498 qe->queue = queue;
5499 if (NULL != pm)
5500 {
5501 qe->pm = pm;
5502 // TODO Why do we have a retransmission. When we know, make decision if we still want this.
5503 // GNUNET_assert (NULL == pm->qe);
5504 if (NULL != pm->qe)
5505 {
5507 "Retransmitting message <%" PRIu64
5508 "> remove pm from qe with MID: %llu \n",
5510 (unsigned long long) pm->qe->mid);
5511 pm->qe->pm = NULL;
5512 }
5513 pm->qe = qe;
5514 }
5515 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
5516 if (0 == queue->q_capacity)
5517 {
5518 // Messages without FC or fragments can get here.
5519 if (NULL != pm)
5520 {
5522 "Message %" PRIu64
5523 " (pm type %u) was not send because queue has no capacity.\n",
5525 pm->pmt);
5526 pm->qe = NULL;
5527 }
5528 GNUNET_free (env);
5529 GNUNET_free (qe);
5530 return;
5531 }
5532 GNUNET_CONTAINER_DLL_insert (queue->queue_head, queue->queue_tail, qe);
5533 queue->queue_length++;
5534 queue->tc->details.communicator.total_queue_length++;
5535 if (GNUNET_NO == queue->unlimited_length)
5536 queue->q_capacity--;
5538 "Queue %s with qid %u has capacity %" PRIu64 "\n",
5539 queue->address,
5540 queue->qid,
5541 queue->q_capacity);
5543 queue->tc->details.communicator.total_queue_length)
5544 queue->idle = GNUNET_NO;
5545 if (QUEUE_LENGTH_LIMIT == queue->queue_length)
5546 queue->idle = GNUNET_NO;
5547 if (0 == queue->q_capacity)
5548 queue->idle = GNUNET_NO;
5549
5550 if (GNUNET_NO == queue->idle)
5552 if (NULL != pm && NULL != (pa = pm->pa_head))
5553 {
5554 while (pm != pa->pm)
5555 pa = pa->next_pa;
5556 pa->num_send++;
5557 }
5558 // GNUNET_CONTAINER_multiuuidmap_get (pending_acks, &ack[i].ack_uuid.value);
5560 "Sending message MID %" PRIu64
5561 " of type %u (%u) and size %lu with MQ %p queue %s (QID %u) pending %"
5562 PRIu64 "\n",
5563 GNUNET_ntohll (smt->mid),
5564 ntohs (((const struct GNUNET_MessageHeader *) payload)->type),
5565 ntohs (smt->header.size),
5566 (unsigned long) payload_size,
5567 queue->tc->mq,
5568 queue->address,
5569 queue->qid,
5570 (NULL == pm) ? 0 : pm->logging_uuid);
5571 GNUNET_MQ_send (queue->tc->mq, env);
5572 }
5573}
5574
5575
5586static struct GNUNET_TIME_Relative
5587route_via_neighbour (const struct Neighbour *n,
5588 const struct GNUNET_MessageHeader *hdr,
5590{
5591 struct GNUNET_TIME_Absolute now;
5592 unsigned int candidates;
5593 unsigned int sel1;
5594 unsigned int sel2;
5595 struct GNUNET_TIME_Relative rtt;
5596
5597 /* Pick one or two 'random' queues from n (under constraints of options) */
5598 now = GNUNET_TIME_absolute_get ();
5599 /* FIXME-OPTIMIZE: give queues 'weights' and pick proportional to
5600 weight in the future; weight could be assigned by observed
5601 bandwidth (note: not sure if we should do this for this type
5602 of control traffic though). */
5603 candidates = 0;
5604 for (struct Queue *pos = n->queue_head; NULL != pos;
5605 pos = pos->next_neighbour)
5606 {
5607 if ((0 != (options & RMO_UNCONFIRMED_ALLOWED)) ||
5608 (pos->validated_until.abs_value_us > now.abs_value_us))
5609 candidates++;
5610 }
5611 if (0 == candidates)
5612 {
5613 /* This can happen rarely if the last confirmed queue timed
5614 out just as we were beginning to process this message. */
5616 "Could not route message of type %u to %s: no valid queue\n",
5617 ntohs (hdr->type),
5618 GNUNET_i2s (&n->pid));
5620 "# route selection failed (all no valid queue)",
5621 1,
5622 GNUNET_NO);
5624 }
5625
5627 sel1 = GNUNET_CRYPTO_random_u32 (candidates);
5628 if (0 == (options & RMO_REDUNDANT))
5629 sel2 = candidates; /* picks none! */
5630 else
5631 sel2 = GNUNET_CRYPTO_random_u32 (candidates);
5632 candidates = 0;
5633 for (struct Queue *pos = n->queue_head; NULL != pos;
5634 pos = pos->next_neighbour)
5635 {
5636 if ((0 != (options & RMO_UNCONFIRMED_ALLOWED)) ||
5637 (pos->validated_until.abs_value_us > now.abs_value_us))
5638 {
5639 if ((sel1 == candidates) || (sel2 == candidates))
5640 {
5642 "Routing message of type %u to %s using %s (#%u)\n",
5643 ntohs (hdr->type),
5644 GNUNET_i2s (&n->pid),
5645 pos->address,
5646 (sel1 == candidates) ? 1 : 2);
5647 rtt = GNUNET_TIME_relative_min (rtt, pos->pd.aged_rtt);
5648 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
5649 }
5650 candidates++;
5651 }
5652 }
5653 return rtt;
5654}
5655
5656
5667typedef void (*DVMessageHandler) (void *cls,
5668 struct Neighbour *next_hop,
5669 const struct GNUNET_MessageHeader *hdr,
5671
5686static struct GNUNET_TIME_Relative
5688 unsigned int num_dvhs,
5689 struct DistanceVectorHop **dvhs,
5690 const struct GNUNET_MessageHeader *hdr,
5691 DVMessageHandler use,
5692 void *use_cls,
5694 enum GNUNET_GenericReturnValue without_fc)
5695{
5696 const struct GNUNET_PeerIdentity *my_identity;
5697 struct TransportDVBoxMessage box_hdr;
5698 struct TransportDVBoxPayloadP *payload_hdr;
5699 uint16_t body_len_hbo = ntohs (hdr->size);
5700 unsigned char pt[sizeof(struct TransportDVBoxPayloadP) + body_len_hbo]
5702 unsigned char ct[sizeof(struct TransportDVBoxPayloadP) + body_len_hbo]
5704 struct GNUNET_TIME_Relative rtt;
5706
5707 payload_hdr = (struct TransportDVBoxPayloadP*) pt;
5710
5711 /* Encrypt payload */
5712 memset (&box_hdr, 0, sizeof (box_hdr));
5713 box_hdr.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
5714 box_hdr.total_hops = htons (0);
5715 box_hdr.without_fc = htonl (without_fc);
5716 // update_ephemeral (dv);
5717 if ((0 ==
5718 GNUNET_TIME_absolute_get_remaining (dv->ephemeral_validity).rel_value_us)
5719 || (NULL == dv->km))
5720 {
5721 GNUNET_CRYPTO_eddsa_kem_encaps (&dv->target.public_key,
5722 &dv->ephemeral_key,
5723 (struct GNUNET_ShortHashCode*) &km);
5724 GNUNET_free (dv->km); /* do not leak the previous key material */
5725 dv->km = GNUNET_new (struct GNUNET_ShortHashCode);
5726 GNUNET_memcpy (dv->km, &km, sizeof(struct GNUNET_ShortHashCode));
5727 if (GNUNET_OK != sign_ephemeral (dv))
5728 {
5729 /* Without a matching signature the box is undecryptable noise to the
5730 receiver; do not spend the bandwidth. Expire the ephemeral so the
5731 next attempt re-derives and re-signs rather than reusing it. */
5732 dv->ephemeral_validity = GNUNET_TIME_UNIT_ZERO_ABS;
5734 }
5735 }
5736 else
5737 {
5738 /* The ephemeral key is still valid, so reuse the cached key material.
5739 Without this @a km stayed UNINITIALISED stack memory and the
5740 receiver could not decrypt the box. */
5741 GNUNET_memcpy (&km, dv->km, sizeof(struct GNUNET_ShortHashCode));
5742 }
5743 box_hdr.ephemeral_key = dv->ephemeral_key;
5744 payload_hdr->sender_sig = dv->sender_sig;
5745 memcpy (&payload_hdr[1], hdr, body_len_hbo);
5746 GNUNET_CRYPTO_random_block (&box_hdr.iv,
5747 sizeof(box_hdr.iv));
5748 payload_hdr->sender = *my_identity;
5749 payload_hdr->monotonic_time = GNUNET_TIME_absolute_hton (dv->monotime);
5750 GNUNET_CRYPTO_aead_encrypt (sizeof pt,
5751 pt,
5752 0,
5753 NULL,
5754 &km,
5755 &box_hdr.iv,
5756 ct,
5757 &box_hdr.mac);
5759 /* For each selected path, take the pre-computed header and body
5760 and add the path in the middle of the message; then send it. */
5761 for (unsigned int i = 0; i < num_dvhs; i++)
5762 {
5763 struct DistanceVectorHop *dvh = dvhs[i];
5764 unsigned int num_hops = dvh->distance + 1;
5765 char buf[sizeof(struct TransportDVBoxMessage)
5766 + sizeof(struct GNUNET_PeerIdentity) * num_hops
5767 + sizeof(struct TransportDVBoxPayloadP)
5768 + body_len_hbo] GNUNET_ALIGN;
5769 struct GNUNET_PeerIdentity *dhops;
5770
5771 box_hdr.header.size = htons (sizeof(buf));
5772 box_hdr.orig_size = htons (sizeof(buf));
5773 box_hdr.num_hops = htons (num_hops);
5774 memcpy (buf, &box_hdr, sizeof(box_hdr));
5775 dhops = (struct GNUNET_PeerIdentity *) &buf[sizeof(box_hdr)];
5776 memcpy (dhops,
5777 dvh->path,
5778 dvh->distance * sizeof(struct GNUNET_PeerIdentity));
5779 dhops[dvh->distance] = dv->target;
5780 if (GNUNET_EXTRA_LOGGING > 0)
5781 {
5782 char *path;
5783
5785 for (unsigned int j = 0; j < num_hops; j++)
5786 {
5787 char *tmp;
5788
5789 GNUNET_asprintf (&tmp, "%s-%s", path, GNUNET_i2s (&dhops[j]));
5790 GNUNET_free (path);
5791 path = tmp;
5792 }
5794 "Routing message of type %u to %s using DV (#%u/%u) via %s\n",
5795 ntohs (hdr->type),
5796 GNUNET_i2s (&dv->target),
5797 i + 1,
5798 num_dvhs,
5799 path);
5800 GNUNET_free (path);
5801 }
5802 rtt = GNUNET_TIME_relative_min (rtt, dvh->pd.aged_rtt);
5803 memcpy (&dhops[num_hops], ct, sizeof(ct));
5804 use (use_cls,
5805 dvh->next_hop,
5806 (const struct GNUNET_MessageHeader *) buf,
5807 options);
5808 }
5809 return rtt;
5810}
5811
5812
5822static void
5823send_dv_to_neighbour (void *cls,
5824 struct Neighbour *next_hop,
5825 const struct GNUNET_MessageHeader *hdr,
5827{
5828 (void) cls;
5829 (void) route_via_neighbour (next_hop, hdr, RMO_UNCONFIRMED_ALLOWED);
5830}
5831
5832
5844static struct GNUNET_TIME_Relative
5846// route_control_message_without_fc (const struct GNUNET_PeerIdentity *target,
5847 const struct GNUNET_MessageHeader *hdr,
5849{
5850 // struct VirtualLink *vl;
5851 struct Neighbour *n;
5852 struct DistanceVector *dv;
5853 struct GNUNET_TIME_Relative rtt1;
5854 struct GNUNET_TIME_Relative rtt2;
5855 const struct GNUNET_PeerIdentity *target = &vl->target;
5856
5858 "Trying to route message of type %u to %s without fc\n",
5859 ntohs (hdr->type),
5860 GNUNET_i2s (target));
5861
5862 // TODO Do this elsewhere. vl should be given as parameter to method.
5863 // vl = lookup_virtual_link (target);
5864 GNUNET_assert (NULL != vl && GNUNET_YES == vl->confirmed);
5865 if (NULL == vl)
5867 n = vl->n;
5868 dv = (0 != (options & RMO_DV_ALLOWED)) ? vl->dv : NULL;
5869 if (0 == (options & RMO_UNCONFIRMED_ALLOWED))
5870 {
5871 /* if confirmed is required, and we do not have anything
5872 confirmed, drop respective options */
5873 if (NULL == n)
5874 n = lookup_neighbour (target);
5875 if ((NULL == dv) && (0 != (options & RMO_DV_ALLOWED)))
5877 }
5878 if ((NULL == n) && (NULL == dv))
5879 {
5881 "Cannot route message of type %u to %s: no route\n",
5882 ntohs (hdr->type),
5883 GNUNET_i2s (target));
5885 "# Messages dropped in routing: no acceptable method",
5886 1,
5887 GNUNET_NO);
5889 }
5891 "Routing message of type %u to %s with options %X\n",
5892 ntohs (hdr->type),
5893 GNUNET_i2s (target),
5894 (unsigned int) options);
5895 /* If both dv and n are possible and we must choose:
5896 flip a coin for the choice between the two; for now 50/50 */
5897 if ((NULL != n) && (NULL != dv) && (0 == (options & RMO_REDUNDANT)))
5898 {
5899 if (0 == GNUNET_CRYPTO_random_u32 (2))
5900 n = NULL;
5901 else
5902 dv = NULL;
5903 }
5904 if ((NULL != n) && (NULL != dv))
5905 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
5906 enough for redundancy, so clear the flag. */
5909 if (NULL != n)
5910 {
5912 "Try to route message of type %u to %s without fc via neighbour\n",
5913 ntohs (hdr->type),
5914 GNUNET_i2s (target));
5915 rtt1 = route_via_neighbour (n, hdr, options);
5916 }
5917 if (NULL != dv)
5918 {
5919 struct DistanceVectorHop *hops[2];
5920 unsigned int res;
5921
5923 options,
5924 hops,
5925 (0 == (options & RMO_REDUNDANT)) ? 1 : 2);
5926 if (0 == res)
5927 {
5929 "Failed to route message, could not determine DV path\n");
5930 return rtt1;
5931 }
5933 "encapsulate_for_dv 1\n");
5934 rtt2 = encapsulate_for_dv (dv,
5935 res,
5936 hops,
5937 hdr,
5939 NULL,
5941 GNUNET_YES);
5942 }
5943 return GNUNET_TIME_relative_min (rtt1, rtt2);
5944}
5945
5946
5947static void
5948consider_sending_fc (void *cls);
5949
5956static void
5957task_consider_sending_fc (void *cls)
5958{
5959 struct VirtualLink *vl = cls;
5960 vl->fc_retransmit_task = NULL;
5961 consider_sending_fc (cls);
5962}
5963
5964
5965static char *
5966get_address_without_port (const char *address);
5967
5968
5970{
5971 size_t off;
5972
5978 size_t size;
5979
5980 char *tgnas;
5981};
5982
5983
5984static enum GNUNET_GenericReturnValue
5985add_global_addresses (void *cls,
5986 const struct GNUNET_PeerIdentity *pid,
5987 void *value)
5988{
5989 struct AddGlobalAddressesContext *ctx = cls;
5990 struct TransportGlobalNattedAddress *tgna = value;
5991 char *addr = (char *) &tgna[1];
5992 size_t alen = ntohl (tgna->address_length);
5993 size_t need = sizeof (struct TransportGlobalNattedAddress) + alen;
5994
5995 /* NOTE: the address is NOT 0-terminated, it must be printed with an
5996 explicit precision. */
5998 "sending address %.*s length %lu\n",
5999 (int) alen,
6000 addr,
6001 (unsigned long) alen);
6002 if (ctx->off + need > ctx->size)
6003 {
6004 GNUNET_break (0);
6005 return GNUNET_NO;
6006 }
6007 GNUNET_memcpy (&(ctx->tgnas[ctx->off]), tgna, need);
6008 ctx->off += need;
6009
6010 return GNUNET_OK;
6011}
6012
6013
6014static struct GNUNET_TIME_Relative
6015calculate_rtt (struct DistanceVector *dv);
6016
6017
6024static void
6025consider_sending_fc (void *cls)
6026{
6027 struct VirtualLink *vl = cls;
6028 struct GNUNET_TIME_Absolute monotime;
6029 struct TransportFlowControlMessage *fc;
6031 struct GNUNET_TIME_Relative rtt;
6032 struct GNUNET_TIME_Relative rtt_average;
6033 struct Neighbour *n = vl->n;
6034 size_t addresses_size;
6035
6036 if (GNUNET_YES != vl->confirmed)
6037 {
6038 /* We cannot route anything over an unconfirmed link, and
6039 #route_control_message_without_fc() asserts on exactly that. Links
6040 created from an inbound FLOW_CONTROL message start out unconfirmed,
6041 so a remote peer could otherwise abort us here.
6042
6043 Do NOT just return: #task_consider_sending_fc() cleared
6044 @e fc_retransmit_task before calling us, and the only other place that
6045 arms it is #handle_flow_control() -- which only does so when it is
6046 already non-NULL. Leaving without re-arming therefore ends the
6047 keepalive chain for this link permanently, and #check_link_down()
6048 tears it down #NEIGHBOUR_LIVENESS_TIMEOUT later. */
6050 "Not sending FC to %s: virtual link not confirmed\n",
6051 GNUNET_i2s (&vl->target));
6052 if (NULL == vl->fc_retransmit_task)
6056 vl);
6057 return;
6058 }
6059 addresses_size = 0;
6060 if (NULL != n && 0 < n->number_of_addresses)
6061 {
6062 addresses_size =
6063 n->number_of_addresses * sizeof (struct TransportGlobalNattedAddress) + n
6064 ->size_of_global_addresses;
6065 if (addresses_size >
6066 UINT16_MAX - sizeof (struct TransportFlowControlMessage))
6067 {
6068 /* htons() below would silently truncate `header.size', leaving a
6069 message whose declared length does not match its contents. */
6070 GNUNET_break (0);
6071 addresses_size = 0;
6072 }
6073 }
6074 if (0 != addresses_size)
6075 {
6076 char *tgnas = GNUNET_malloc (addresses_size);
6078 ctx.off = 0;
6079 ctx.size = addresses_size;
6080 ctx.tgnas = tgnas;
6081
6083 + addresses_size);
6084 fc->header.size = htons (sizeof(struct TransportFlowControlMessage)
6085 + addresses_size);
6086 fc->size_of_addresses = htonl ((uint32_t) n->size_of_global_addresses);
6087 fc->number_of_addresses = htonl (n->number_of_addresses);
6090 &ctx);
6093 }
6094 else
6095 {
6096 fc = GNUNET_malloc (sizeof (struct TransportFlowControlMessage));
6097 fc->header.size = htons (sizeof(struct TransportFlowControlMessage));
6098 }
6099
6101 /* OPTIMIZE-FC-BDP: decide sane criteria on when to do this, instead of doing
6102 it always! */
6103 /* For example, we should probably ONLY do this if a bit more than
6104 an RTT has passed, or if the window changed "significantly" since
6105 then. See vl->last_fc_rtt! NOTE: to do this properly, we also
6106 need an estimate for the bandwidth-delay-product for the entire
6107 VL, as that determines "significantly". We have the delay, but
6108 the bandwidth statistics need to be added for the VL!*/(void) duration;
6109
6110 if (NULL != vl->dv)
6111 rtt_average = calculate_rtt (vl->dv);
6112 else
6113 rtt_average = GNUNET_TIME_UNIT_FOREVER_REL;
6114 fc->rtt = GNUNET_TIME_relative_hton (rtt_average);
6116 "Sending FC seq %u to %s with new window %llu %lu %u\n",
6117 (unsigned int) vl->fc_seq_gen,
6118 GNUNET_i2s (&vl->target),
6119 (unsigned long long) vl->incoming_fc_window_size,
6120 (unsigned long) rtt_average.rel_value_us,
6121 vl->sync_ready);
6123 vl->last_fc_transmission = monotime;
6124 fc->sync_ready = htonl ((uint32_t) vl->sync_ready);
6126 fc->seq = htonl (vl->fc_seq_gen++);
6127 fc->inbound_window_size = GNUNET_htonll (vl->incoming_fc_window_size
6130 fc->outbound_sent = GNUNET_htonll (vl->outbound_fc_window_size_used);
6131 fc->outbound_window_size = GNUNET_htonll (vl->outbound_fc_window_size);
6132 fc->sender_time = GNUNET_TIME_absolute_hton (monotime);
6134 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == rtt.rel_value_us)
6135 {
6138 "FC retransmission to %s failed, will retry in %s\n",
6139 GNUNET_i2s (&vl->target),
6142 }
6143 else
6144 {
6145 /* OPTIMIZE-FC-BDP: rtt is not ideal, we can do better! */
6146 vl->last_fc_rtt = rtt;
6147 }
6148 if (NULL != vl->fc_retransmit_task)
6150 if (MAX_FC_RETRANSMIT_COUNT <= vl->fc_retransmit_count)
6151 {
6153 vl->fc_retransmit_count = 0;
6154 }
6155 /* Never re-arm with (near) zero delay: @a rtt is zero whenever we have no
6156 RTT sample yet, which turned this into a tight send loop. */
6158 vl->fc_retransmit_task =
6160 vl->fc_retransmit_count++;
6161 GNUNET_free (fc);
6162}
6163
6164
6181static void
6183{
6184 struct Neighbour *n = vl->n;
6185 struct DistanceVector *dv = vl->dv;
6186 struct GNUNET_TIME_Absolute now;
6187 struct VirtualLink *vl_next_hop;
6188 int elig;
6189
6191 "check_vl_transmission to target %s\n",
6192 GNUNET_i2s (&vl->target));
6193 /* Check that we have an eligible pending message!
6194 (cheaper than having #transmit_on_queue() find out!) */
6195 elig = GNUNET_NO;
6196 for (struct PendingMessage *pm = vl->pending_msg_head; NULL != pm;
6197 pm = pm->next_vl)
6198 {
6200 "check_vl_transmission loop\n");
6201 if (NULL != pm->qe)
6202 continue; /* not eligible, is in a queue! */
6205 {
6207 "Stalled message %" PRIu64
6208 " transmission on VL %s due to flow control: %llu < %llu\n",
6209 pm->logging_uuid,
6210 GNUNET_i2s (&vl->target),
6211 (unsigned long long) vl->outbound_fc_window_size,
6212 (unsigned long long) (pm->bytes_msg
6215 return; /* We have a message, but flow control says "nope" */
6216 }
6218 "Target window on VL %s not stalled. Scheduling transmission on queue\n",
6219 GNUNET_i2s (&vl->target));
6220 /* Notify queues at direct neighbours that we are interested */
6221 now = GNUNET_TIME_absolute_get ();
6222 if (NULL != n)
6223 {
6224 for (struct Queue *queue = n->queue_head; NULL != queue;
6225 queue = queue->next_neighbour)
6226 {
6227 if ((GNUNET_YES == queue->idle) &&
6228 (queue->validated_until.abs_value_us > now.abs_value_us))
6229 {
6231 "Direct neighbour %s not stalled\n",
6232 GNUNET_i2s (&n->pid));
6234 queue,
6236 elig = GNUNET_YES;
6237 }
6238 else
6240 "Neighbour Queue QID: %u (%u) busy or invalid\n",
6241 queue->qid,
6242 queue->idle);
6243 }
6244 }
6245 /* Notify queues via DV that we are interested */
6246 if (NULL != dv)
6247 {
6248 /* Do DV with lower scheduler priority, which effectively means that
6249 IF a neighbour exists and is available, we prefer it. */
6250 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
6251 pos = pos->next_dv)
6252 {
6253 struct Neighbour *nh_iter = pos->next_hop;
6254
6255
6256 if (pos->path_valid_until.abs_value_us <= now.abs_value_us)
6257 continue; /* skip this one: path not validated */
6258 else
6259 {
6260 vl_next_hop = lookup_virtual_link (&nh_iter->pid);
6261 if (NULL == vl_next_hop)
6262 continue; /* no link to that next hop (anymore) */
6263 if (pm->bytes_msg + vl_next_hop->outbound_fc_window_size_used >
6264 vl_next_hop->outbound_fc_window_size)
6265 {
6267 "Stalled message %" PRIu64
6268 " transmission on next hop %s due to flow control: %llu < %llu\n",
6269 pm->logging_uuid,
6270 GNUNET_i2s (&vl_next_hop->target),
6271 (unsigned long
6272 long) vl_next_hop->outbound_fc_window_size,
6273 (unsigned long long) (pm->bytes_msg
6274 + vl_next_hop->
6275 outbound_fc_window_size_used));
6276 consider_sending_fc (vl_next_hop);
6277 continue; /* We have a message, but flow control says "nope" for the first hop of this path */
6278 }
6279 for (struct Queue *queue = nh_iter->queue_head; NULL != queue;
6280 queue = queue->next_neighbour)
6281 if ((GNUNET_YES == queue->idle) &&
6282 (queue->validated_until.abs_value_us > now.abs_value_us))
6283 {
6285 "Next hop neighbour %s not stalled\n",
6286 GNUNET_i2s (&nh_iter->pid));
6288 queue,
6290 elig = GNUNET_YES;
6291 }
6292 else
6294 "DV Queue QID: %u (%u) busy or invalid\n",
6295 queue->qid,
6296 queue->idle);
6297 }
6298 }
6299 }
6300 if (GNUNET_YES == elig)
6302 "Eligible message %" PRIu64 " of size %u to %s: %llu/%llu\n",
6303 pm->logging_uuid,
6304 pm->bytes_msg,
6305 GNUNET_i2s (&vl->target),
6306 (unsigned long long) vl->outbound_fc_window_size,
6307 (unsigned long long) (pm->bytes_msg
6309 break;
6310 }
6311}
6312
6313
6320static void
6321handle_client_send (void *cls, const struct OutboundMessage *obm)
6322{
6323 struct TransportClient *tc = cls;
6324 struct PendingMessage *pm;
6325 const struct GNUNET_MessageHeader *obmm;
6326 uint32_t bytes_msg;
6327 struct VirtualLink *vl;
6329
6330 GNUNET_assert (CT_CORE == tc->type);
6331 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
6332 bytes_msg = ntohs (obmm->size);
6333 pp = ntohl (obm->priority);
6334 vl = lookup_virtual_link (&obm->peer);
6335 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
6336 {
6338 "Don't have %s as a neighbour (anymore).\n",
6339 GNUNET_i2s (&obm->peer));
6340 /* Failure: don't have this peer as a neighbour (anymore).
6341 Might have gone down asynchronously, so this is NOT
6342 a protocol violation by CORE. Still count the event,
6343 as this should be rare. */
6344 /* Precisely because this is not a protocol violation we leave the
6345 client's `struct Neighbour' -- and its send window -- in place, so we
6346 owe it the SEND_OK for the message we are dropping here. Without it
6347 the window shrinks by one every time this happens and never grows
6348 back; after #SEND_WINDOW_SIZE such drops #mq_send_impl() parks every
6349 further message for this peer forever ("Flow control delays
6350 transmission to CORE until we see SEND_OK") and CORE goes mute
6351 towards a peer it still believes it is connected to -- while
6352 continuing to receive from it, so its own idle timeout is what
6353 eventually reports the peer down. */
6354 send_ok_to_client (tc, &obm->peer);
6357 "# messages dropped (neighbour unknown)",
6358 1,
6359 GNUNET_NO);
6360 return;
6361 }
6362
6363 pm = GNUNET_malloc (sizeof(struct PendingMessage) + bytes_msg);
6365 "1 created pm %p storing vl %p\n",
6366 pm,
6367 vl);
6369 pm->prefs = pp;
6370 pm->client = tc;
6371 pm->vl = vl;
6372 pm->bytes_msg = bytes_msg;
6373 memcpy (&pm[1], obmm, bytes_msg);
6375 "Sending message of type %u with %u bytes as <%" PRIu64
6376 "> to %s\n",
6377 ntohs (obmm->type),
6378 bytes_msg,
6379 pm->logging_uuid,
6380 GNUNET_i2s (&obm->peer));
6382 tc->details.core.pending_msg_head,
6383 tc->details.core.pending_msg_tail,
6384 pm);
6386 vl->pending_msg_head,
6387 vl->pending_msg_tail,
6388 pm);
6391}
6392
6393
6403static void
6405 void *cls,
6407{
6408 struct Neighbour *n;
6409 struct VirtualLink *vl;
6410 struct TransportClient *tc = cls;
6411 const struct GNUNET_MessageHeader *inbox =
6412 (const struct GNUNET_MessageHeader *) &cb[1];
6413 uint16_t isize = ntohs (inbox->size);
6414 const char *is = ((const char *) &cb[1]) + isize;
6415 size_t slen = strlen (is) + 1;
6416 char
6417 mbuf[slen + isize
6418 + sizeof(struct
6422
6423 /* 0-termination of 'is' was checked already in
6424 #check_communicator_backchannel() */
6426 "Preparing backchannel transmission to %s:%s of type %u and size %u\n",
6427 GNUNET_i2s (&cb->pid),
6428 is,
6429 ntohs (inbox->type),
6430 ntohs (inbox->size));
6431 /* encapsulate and encrypt message */
6432 be->header.type =
6434 be->header.size = htons (sizeof(mbuf));
6435 memcpy (&be[1], inbox, isize);
6436 memcpy (&mbuf[sizeof(struct TransportBackchannelEncapsulationMessage)
6437 + isize],
6438 is,
6439 strlen (is) + 1);
6440 // route_control_message_without_fc (&cb->pid, &be->header, RMO_DV_ALLOWED);
6441 vl = lookup_virtual_link (&cb->pid);
6442 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
6443 {
6445 }
6446 else
6447 {
6448 /* Use route via neighbour */
6449 n = lookup_neighbour (&cb->pid);
6450 if (NULL != n)
6452 n,
6453 &be->header,
6454 RMO_NONE);
6455 }
6457}
6458
6459
6467static int
6468check_add_address (void *cls,
6469 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
6470{
6471 struct TransportClient *tc = cls;
6472
6473 if (CT_COMMUNICATOR != tc->type)
6474 {
6475 GNUNET_break (0);
6476 return GNUNET_SYSERR;
6477 }
6479 return GNUNET_OK;
6480}
6481
6482
6488static void
6489store_pi (void *cls);
6490
6491
6496{
6497
6501 struct AddressListEntry *ale;
6502
6506 struct PilsRequest *req;
6507
6508
6512 struct GNUNET_TIME_Absolute et;
6513};
6514
6515
6522static void
6524{
6525 struct PilsAddressSignContext *pc = ale->pc;
6526
6527 if (NULL == pc)
6528 return;
6529 ale->pc = NULL;
6530 /* Each stage of the chain passes @a pc as its closure, so every handle
6531 that could still deliver one has to go before @a pc is released. */
6532 if (NULL != ale->sc)
6533 {
6535 ale->sc = NULL;
6536 }
6537 if (NULL != ale->shc)
6538 {
6540 ale->shc = NULL;
6541 }
6542 if (NULL != pc->req)
6543 {
6544 if (NULL != pc->req->op)
6545 GNUNET_PILS_cancel (pc->req->op);
6548 pc->req);
6549 GNUNET_free (pc->req);
6550 pc->req = NULL;
6551 }
6552 GNUNET_free (pc);
6553}
6554
6555
6556static void
6557shc_cont (void *cls, int success)
6558{
6559 struct PilsAddressSignContext *pc = cls;
6560
6561 GNUNET_assert (NULL == pc->req);
6562 /* The store completed; the handle is dead and must not be cancelled
6563 later by #free_address_list_entry(). */
6564 pc->ale->shc = NULL;
6565 pc->ale->pc = NULL;
6566 if (GNUNET_OK != success)
6567 {
6569 "Failed to store our address `%s' with peerstore\n",
6570 pc->ale->address);
6571 if (NULL == pc->ale->st)
6572 {
6574 &store_pi,
6575 pc->ale);
6576 }
6577 }
6578 GNUNET_free (pc);
6579}
6580
6581
6585static void
6586pils_sign_hello_cb (void *cls,
6587 const struct GNUNET_PeerIdentity *pid,
6588 const struct GNUNET_CRYPTO_EddsaSignature *sig)
6589{
6590 struct PilsAddressSignContext *pc = cls;
6591 struct GNUNET_MQ_Envelope *env;
6592 const struct GNUNET_MessageHeader *msg;
6593
6594 pc->req->op = NULL;
6597 pc->req);
6598 GNUNET_free (pc->req);
6599 pc->req = NULL;
6602 pid,
6603 sig,
6604 pc->et);
6607 "store_pi 1\n");
6609 msg,
6610 shc_cont,
6611 pc);
6612 GNUNET_free (env);
6613}
6614
6615
6622static void
6623peerstore_store_own_cb (void *cls, int success)
6624{
6625 struct PilsAddressSignContext *pc = cls;
6626
6627 pc->ale->sc = NULL;
6628 if (GNUNET_YES != success)
6630 "Failed to store our own address `%s' in peerstore!\n",
6631 pc->ale->address);
6632 else
6634 "Successfully stored our own address `%s' in peerstore!\n",
6635 pc->ale->address);
6636 /* refresh period is 1/4 of expiration time, that should be plenty
6637 without being excessive. */
6638 if (NULL == pc->ale->st)
6639 {
6640 pc->ale->st =
6642 GNUNET_TIME_relative_divide (pc->ale->expiration,
6643 4ULL),
6644 &store_pi,
6645 pc->ale);
6646 }
6647
6648 /* Now we have to update our HELLO! */
6650 pc->req = GNUNET_new (struct PilsRequest);
6653 pc->req);
6654 pc->req->op = GNUNET_PILS_sign_hello (pils,
6656 pc->et,
6658 pc);
6659}
6660
6661
6669static void
6671 const struct GNUNET_PeerIdentity *pid,
6672 const struct GNUNET_CRYPTO_EddsaSignature *sig)
6673{
6674 char *sig_str;
6675 void *result;
6676 size_t result_size;
6677
6678 sig_str = NULL;
6679 (void) GNUNET_STRINGS_base64_encode (sig, sizeof(*sig), &sig_str);
6680 result_size =
6681 1 + GNUNET_asprintf (
6682 (char **) &result,
6683 "%s;%llu;%u;%s",
6684 sig_str,
6685 (unsigned long long) pc->et.abs_value_us,
6686 (unsigned int) pc->ale->nt,
6687 pc->ale->address);
6688 GNUNET_free (sig_str);
6689
6691 "Build our HELLO URI `%s'\n",
6692 (char*) result);
6693
6694 GNUNET_free (pc->ale->signed_address);
6695 pc->ale->signed_address = result;
6696 pc->ale->signed_address_len = result_size;
6698
6699 expiration = GNUNET_TIME_relative_to_absolute (pc->ale->expiration);
6701 "transport",
6702 pid,
6704 result,
6705 result_size,
6706 expiration,
6709 pc);
6710}
6711
6712
6716struct SignedAddress
6717{
6722
6727
6731 struct GNUNET_HashCode addr_hash GNUNET_PACKED;
6732};
6733
6734
6748void
6750 struct AddressListEntry *ale,
6751 struct GNUNET_TIME_Absolute mono_time)
6752{
6753 struct SignedAddress sa;
6754 struct PilsAddressSignContext *pc;
6756 const struct GNUNET_PeerIdentity *my_identity;
6757
6758 sa.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_ADDRESS);
6759 sa.purpose.size = htonl (sizeof(sa));
6760 sa.mono_time = GNUNET_TIME_absolute_hton (mono_time);
6761 GNUNET_CRYPTO_hash (ale->address, strlen (ale->address), &sa.addr_hash);
6762 /* Only ever one chain per entry: the previous one (if any) still holds a
6763 pointer to @a ale and must be torn down first. */
6766 if ((NULL == my_identity) ||
6767 (GNUNET_OK != sign_by_my_identity (&sa.purpose, &sig)))
6768 {
6769 /* Nothing else re-arms @e st: #store_pi() cleared it before calling us,
6770 and the only other thing that sets it is #peerstore_store_own_cb(),
6771 which is on the far side of the store we just failed to start. So a
6772 single failure to sign used to end the refresh cycle for this address
6773 for the rest of the process' life. */
6774 if (NULL == ale->st)
6775 {
6778 &store_pi,
6779 ale);
6780 }
6781 return;
6782 }
6784 pc->ale = ale;
6785 pc->et = mono_time;
6786 ale->pc = pc;
6788}
6789
6790
6796static void
6797store_pi (void *cls)
6798{
6799 struct AddressListEntry *ale = cls;
6800 const char *dash;
6801 char *address_uri;
6802 char *prefix;
6803 unsigned int add_success;
6804
6805 if ((GNUNET_YES == in_shutdown) || (NULL == pils))
6806 {
6807 ale->st = NULL;
6808 return;
6809 }
6810 if (NULL == GNUNET_PILS_get_identity (pils))
6811 {
6812 /* Do NOT poll at 1kHz: that burns CPU and keeps the scheduler task
6813 list non-empty, which prevents the service from ever exiting. */
6816 &store_pi,
6817 ale);
6818 return;
6819 }
6822 dash = strchr (ale->address, '-');
6823 GNUNET_assert (NULL != dash);
6824 dash++;
6825 GNUNET_asprintf (&address_uri,
6826 "%s://%s",
6827 prefix,
6828 dash);
6830 ale->st = NULL;
6832 "Storing our address `%s' in peerstore until %s!\n",
6833 ale->address,
6836 address_uri);
6837 /* NOTE: #GNUNET_HELLO_builder_add_address() answers GNUNET_NO for an
6838 address that is already in the builder, and on every call after the
6839 first one for a given address that is exactly what happens: nothing
6840 ever removes an address from @a GST_my_hello except
6841 #handle_del_address(). This function is the *refresh* cycle --
6842 #peerstore_store_own_cb() re-arms it at a quarter of the address'
6843 expiration -- so bailing out on GNUNET_NO here stopped the refresh
6844 after precisely one round. Our own HELLO then expired
6845 (#GNUNET_HELLO_ADDRESS_EXPIRATION, twelve hours) and was never
6846 renewed: peers can no longer learn how to reach us, and a link that
6847 drops after that never comes back. Only GNUNET_SYSERR -- a malformed
6848 URI, which retrying cannot fix -- is a reason not to store. */
6849 if (GNUNET_SYSERR == add_success)
6850 {
6852 "Not storing our address `%s': not a valid HELLO URI\n",
6853 address_uri);
6854 GNUNET_free (address_uri);
6855 return;
6856 }
6857 GNUNET_log ((GNUNET_NO == add_success) ?
6859 "%s our address `%s' in PEERSTORE\n",
6860 (GNUNET_NO == add_success) ? "Refreshing" : "Storing",
6861 address_uri);
6862 // FIXME hello_mono_time used here?? What about expiration in ale?
6863 pils_sign_address (ale,
6865 // TODO keep track of op and potentially cancel/clean
6866 GNUNET_free (address_uri);
6867}
6868
6869
6870static struct AddressListEntry *
6874 const char *address,
6875 uint32_t aid,
6876 size_t slen)
6877{
6878 struct AddressListEntry *ale;
6879 char *address_without_port;
6880
6881 ale = GNUNET_malloc (sizeof(struct AddressListEntry) + slen);
6882 ale->tc = tc;
6883 ale->address = (const char *) &ale[1];
6884 ale->expiration = expiration;
6885 ale->aid = aid;
6886 ale->nt = nt;
6887 memcpy (&ale[1], address, slen);
6888 address_without_port = get_address_without_port (ale->address);
6890 "Is this %s a local address (%s)\n",
6891 (NULL == address_without_port) ? "<unparsable>"
6892 : address_without_port,
6893 ale->address);
6894 if ((NULL == address_without_port) ||
6895 (0 != strcmp ("127.0.0.1", address_without_port)))
6896 {
6897 if (NULL != ale->st)
6898 {
6900 }
6901 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
6902 }
6903 GNUNET_free (address_without_port);
6904
6905 return ale;
6906}
6907
6908
6909static void
6910feed_addresses_to_pils (void *cls)
6911{
6912
6914 "Feeding addresses to PILS\n");
6915 pils_feed_task = NULL;
6916
6918 GST_my_hello);
6919}
6920
6921
6928static void
6929handle_add_address (void *cls,
6930 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
6931{
6932 struct TransportClient *tc = cls;
6933 struct AddressListEntry *ale;
6934 size_t slen;
6935 char *address;
6936
6937 /* 0-termination of &aam[1] was checked in #check_add_address */
6939 "Communicator added address `%s'!\n",
6940 (const char *) &aam[1]);
6941 slen = ntohs (aam->header.size) - sizeof(*aam);
6942 address = GNUNET_malloc (slen);
6943 memcpy (address, &aam[1], slen);
6944 ale = create_address_entry (tc,
6946 ntohl (aam->nt),
6947 address,
6948 aam->aid,
6949 slen);
6950 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
6951 tc->details.communicator.addr_tail,
6952 ale);
6953 {
6954 for (struct AddressListEntry *iter = tc->details.communicator.addr_head;
6955 NULL != iter;
6956 iter = iter->next)
6957 {
6958 char *address_uri;
6959 const char *dash = strchr (iter->address, '-');
6960 char *prefix = GNUNET_HELLO_address_to_prefix (iter->address);
6961 GNUNET_assert (NULL != dash);
6962 dash++;
6963 GNUNET_asprintf (&address_uri,
6964 "%s://%s",
6965 prefix,
6966 dash);
6969 GNUNET_free (address_uri);
6970 }
6971 if (NULL != pils_feed_task)
6975 NULL);
6976 }
6979}
6980
6981
6988static void
6989handle_del_address (void *cls,
6990 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
6991{
6992 struct TransportClient *tc = cls;
6993 struct AddressListEntry *alen;
6994
6995 if (CT_COMMUNICATOR != tc->type)
6996 {
6997 GNUNET_break (0);
6999 return;
7000 }
7001 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
7002 NULL != ale;
7003 ale = alen)
7004 {
7005 alen = ale->next;
7006 if (dam->aid != ale->aid)
7007 continue;
7008 GNUNET_assert (ale->tc == tc);
7010 "Communicator deleted address `%s'!\n",
7011 ale->address);
7013 ale->address);
7014 if (NULL != pils_feed_task)
7018 NULL);
7021 return;
7022 }
7024 "Communicator removed address we did not even have.\n");
7026 // GNUNET_SERVICE_client_drop (tc->client);
7027}
7028
7029
7037static void
7039
7040
7048static void
7049core_env_sent_cb (void *cls)
7050{
7051 struct CoreSentContext *ctx = cls;
7052 struct VirtualLink *vl = ctx->vl;
7053
7054 if (NULL == vl)
7055 {
7056 /* lost the link in the meantime, ignore */
7057 GNUNET_free (ctx);
7058 return;
7059 }
7062 vl->incoming_fc_window_size_ram -= ctx->size;
7063 vl->incoming_fc_window_size_used += ctx->isize;
7065 GNUNET_free (ctx);
7066}
7067
7068
7090static void
7091core_fc_stalled (void *cls)
7092{
7093 struct VirtualLink *vl = cls;
7094 struct CommunicatorMessageContext *cmc;
7095
7096 vl->core_fc_stall_task = NULL;
7098 "CORE did not acknowledge messages from %s within %s; "
7099 "releasing the flow control credit anyway\n",
7100 GNUNET_i2s (&vl->target),
7102 GNUNET_YES));
7104 "# CORE flow control stalls",
7105 1,
7106 GNUNET_NO);
7107 while (NULL != (cmc = vl->cmc_tail))
7108 release_stalled_cmc (vl, cmc);
7111}
7112
7113
7114static void
7116 const struct GNUNET_MessageHeader *mh,
7117 struct CommunicatorMessageContext *cmc,
7118 unsigned int free_cmc)
7119{
7120 uint16_t size = ntohs (mh->size);
7121 int have_core;
7122
7123 if (vl->incoming_fc_window_size_ram > UINT_MAX - size)
7124 {
7126 "# CORE messages dropped (FC arithmetic overflow)",
7127 1,
7128 GNUNET_NO);
7130 "CORE messages of type %u with %u bytes dropped (FC arithmetic overflow)\n",
7131 (unsigned int) ntohs (mh->type),
7132 (unsigned int) ntohs (mh->size));
7133 if (GNUNET_YES == free_cmc)
7135 return;
7136 }
7138 {
7140 "# CORE messages dropped (FC window overflow)",
7141 1,
7142 GNUNET_NO);
7144 "CORE messages of type %u with %u bytes dropped (FC window overflow)\n",
7145 (unsigned int) ntohs (mh->type),
7146 (unsigned int) ntohs (mh->size));
7147 if (GNUNET_YES == free_cmc)
7149 return;
7150 }
7151
7152 /* Forward to all CORE clients */
7153 have_core = GNUNET_NO;
7154 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
7155 {
7156 struct GNUNET_MQ_Envelope *env;
7157 struct InboundMessage *im;
7158 struct CoreSentContext *ctx;
7159
7160 if (CT_CORE != tc->type)
7161 continue;
7164 ctx = GNUNET_new (struct CoreSentContext);
7165 ctx->vl = vl;
7166 ctx->size = size;
7167 ctx->isize = (GNUNET_NO == have_core) ? size : 0;
7168 have_core = GNUNET_YES;
7171 im->peer = cmc->im.sender;
7172 memcpy (&im[1], mh, size);
7173 GNUNET_MQ_send (tc->mq, env);
7175 }
7176 if (GNUNET_NO == have_core)
7177 {
7179 "Dropped message to CORE: no CORE client connected!\n");
7180 /* Nevertheless, count window as used, as it is from the
7181 perspective of the other peer! */
7183 /* TODO-M1 */
7185 "Dropped message of type %u with %u bytes to CORE: no CORE client connected!\n",
7186 (unsigned int) ntohs (mh->type),
7187 (unsigned int) ntohs (mh->size));
7188 if (GNUNET_YES == free_cmc)
7190 return;
7191 }
7193 "Delivered message from %s of type %u to CORE recv window %d\n",
7194 GNUNET_i2s (&cmc->im.sender),
7195 ntohs (mh->type),
7197 if (vl->core_recv_window > 0)
7198 {
7199 if (GNUNET_YES == free_cmc)
7201 return;
7202 }
7203 /* CORE ran out of receive window for *this* link. Withhold the
7204 per-message ACK -- that is what expresses the backpressure -- but
7205 resume the client immediately. The client is the communicator
7206 *process*, which carries every peer we reach through it, and a
7207 communicator we stop reading from does not stop receiving: it starts
7208 discarding, see "transport is too slow" in
7209 #GNUNET_TRANSPORT_communicator_receive(). Discarding is precisely
7210 what we cannot afford here, because among the messages dropped are
7211 the ones CORE needs in order to reopen the window it is waiting on. */
7212 if (GNUNET_YES == free_cmc)
7213 {
7214 resume_cmc_client (cmc);
7216 vl->cmc_count++;
7217 /* Nothing stalls the producer any more, so bound the list ourselves. */
7218 while (MAX_STALLED_CMCS < vl->cmc_count)
7220 /* ... and do not withhold the ACKs forever: see #core_fc_stalled(). */
7221 if (NULL == vl->core_fc_stall_task)
7225 vl);
7226 }
7227}
7228
7229
7238static void
7239handle_raw_message (void *cls, const struct GNUNET_MessageHeader *mh)
7240{
7241 struct CommunicatorMessageContext *cmc = cls;
7242 // struct CommunicatorMessageContext *cmc_copy =
7243 // GNUNET_new (struct CommunicatorMessageContext);
7244 struct GNUNET_MessageHeader *mh_copy;
7245 struct RingBufferEntry *rbe;
7246 struct VirtualLink *vl;
7247 uint16_t size = ntohs (mh->size);
7248
7250 "Handling raw message of type %u with %u bytes\n",
7251 (unsigned int) ntohs (mh->type),
7252 (unsigned int) ntohs (mh->size));
7253
7254 if ((size > UINT16_MAX - sizeof(struct InboundMessage)) ||
7255 (size < sizeof(struct GNUNET_MessageHeader)))
7256 {
7257 /* @a mh was unwrapped from what a *remote peer* sent us, so a bad size
7258 is that peer's protocol violation and says nothing about the
7259 communicator that carried it. Dropping the client here disconnects
7260 the communicator process and with it every neighbour reachable
7261 through it -- see the rationale in #demultiplex_with_cmc(). */
7262 GNUNET_break_op (0);
7264 "# CORE messages dropped (bad size)",
7265 1,
7266 GNUNET_NO);
7267 finish_cmc_handling (cmc);
7268 return;
7269 }
7270 vl = lookup_virtual_link (&cmc->im.sender);
7271 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
7272 {
7273 /* FIXME: sender is giving us messages for CORE but we don't have
7274 the link up yet! I *suspect* this can happen right now (i.e.
7275 sender has verified us, but we didn't verify sender), but if
7276 we pass this on, CORE would be confused (link down, messages
7277 arrive). We should investigate more if this happens often,
7278 or in a persistent manner, and possibly do "something" about
7279 it. Thus logging as error for now. */
7280
7281 mh_copy = GNUNET_malloc (size);
7282 rbe = GNUNET_new (struct RingBufferEntry);
7283 rbe->cmc = cmc;
7284 /*cmc_copy->tc = cmc->tc;
7285 cmc_copy->im = cmc->im;*/
7286 GNUNET_memcpy (mh_copy, mh, size);
7287
7288 rbe->mh = mh_copy;
7289
7291 {
7292 struct RingBufferEntry *rbe_old = ring_buffer[ring_buffer_head];
7293 GNUNET_free (rbe_old->cmc);
7294 GNUNET_free (rbe_old->mh);
7295 GNUNET_free (rbe_old);
7296 }
7297 ring_buffer[ring_buffer_head] = rbe;// cmc_copy;
7298 // cmc_copy->mh = (const struct GNUNET_MessageHeader *) mh_copy;
7299 cmc->mh = (const struct GNUNET_MessageHeader *) mh_copy;
7301 "Storing message for %s and type %u (%u) in ring buffer head %u is full %u\n",
7302 GNUNET_i2s (&cmc->im.sender),
7303 (unsigned int) ntohs (mh->type),
7304 (unsigned int) ntohs (mh_copy->type),
7308 {
7309 ring_buffer_head = 0;
7311 }
7312 else
7314
7316 "%u items stored in ring buffer\n",
7319
7320 /*GNUNET_break_op (0);
7321 GNUNET_STATISTICS_update (GST_stats,
7322 "# CORE messages dropped (virtual link still down)",
7323 1,
7324 GNUNET_NO);
7325
7326 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7327 "CORE messages of type %u with %u bytes dropped (virtual link still down)\n",
7328 (unsigned int) ntohs (mh->type),
7329 (unsigned int) ntohs (mh->size));
7330 finish_cmc_handling (cmc);*/
7331 /* @a cmc lives on in the ring buffer; #send_cmc_ack() and
7332 #resume_cmc_client() have recorded that they ran, so replaying it
7333 from #send_msg_from_cache() cannot ACK or continue a second time. */
7335 return;
7336 }
7338}
7339
7340
7348static int
7349check_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
7350{
7351 uint16_t size = ntohs (fb->header.size);
7352 uint16_t bsize = size - sizeof(*fb);
7353
7354 (void) cls;
7355 if (0 == bsize)
7356 {
7357 GNUNET_break_op (0);
7358 return GNUNET_SYSERR;
7359 }
7360 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
7361 {
7362 GNUNET_break_op (0);
7363 return GNUNET_SYSERR;
7364 }
7365 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
7366 {
7367 GNUNET_break_op (0);
7368 return GNUNET_SYSERR;
7369 }
7370 return GNUNET_YES;
7371}
7372
7373
7379static void
7380destroy_ack_cummulator (void *cls)
7381{
7382 struct AcknowledgementCummulator *ac = cls;
7383
7384 ac->task = NULL;
7385 GNUNET_assert (0 == ac->num_acks);
7387 GNUNET_YES ==
7389 GNUNET_free (ac);
7390}
7391
7392
7398static void
7400{
7401 struct Neighbour *n;
7402 struct VirtualLink *vl;
7403 struct AcknowledgementCummulator *ac = cls;
7404 char buf[sizeof(struct TransportReliabilityAckMessage)
7405 + ac->num_acks
7407 struct TransportReliabilityAckMessage *ack =
7408 (struct TransportReliabilityAckMessage *) buf;
7410
7411 ac->task = NULL;
7413 "Sending ACK with %u components to %s\n",
7414 ac->num_acks,
7415 GNUNET_i2s (&ac->target));
7416 GNUNET_assert (0 < ac->num_acks);
7418 ack->header.size =
7419 htons (sizeof(*ack)
7420 + ac->num_acks * sizeof(struct TransportCummulativeAckPayloadP));
7421 ack->ack_counter = htonl (ac->ack_counter += ac->num_acks);
7422 ap = (struct TransportCummulativeAckPayloadP *) &ack[1];
7423 for (unsigned int i = 0; i < ac->num_acks; i++)
7424 {
7425 ap[i].ack_uuid = ac->ack_uuids[i].ack_uuid;
7428 }
7429 /*route_control_message_without_fc (
7430 &ac->target,
7431 &ack->header,
7432 RMO_DV_ALLOWED);*/
7433 vl = lookup_virtual_link (&ac->target);
7434 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
7435 {
7437 vl,
7438 &ack->header,
7440 }
7441 else
7442 {
7443 /* Use route via neighbour */
7444 n = lookup_neighbour (&ac->target);
7445 if (NULL != n)
7447 n,
7448 &ack->header,
7449 RMO_NONE);
7450 }
7451 ac->num_acks = 0;
7454 ac);
7455}
7456
7457
7466static void
7467cummulative_ack (const struct GNUNET_PeerIdentity *pid,
7468 const struct AcknowledgementUUIDP *ack_uuid,
7469 struct GNUNET_TIME_Absolute max_delay)
7470{
7471 struct AcknowledgementCummulator *ac;
7472
7474 "Scheduling ACK %s for transmission to %s\n",
7475 GNUNET_uuid2s (&ack_uuid->value),
7476 GNUNET_i2s (pid));
7478 if (NULL == ac)
7479 {
7481 ac->target = *pid;
7482 ac->min_transmission_time = max_delay;
7486 &ac->target,
7487 ac,
7489 }
7490 else
7491 {
7492 if (MAX_CUMMULATIVE_ACKS == ac->num_acks)
7493 {
7494 /* Must run immediately, ack buffer full. Cancel the pending task
7495 FIRST: #transmit_cummulative_ack_cb() clears @e task without
7496 cancelling it, which would leave the old task armed with its
7497 handle lost. */
7499 ac->task = NULL;
7501 }
7505 }
7508 ac->ack_uuids[ac->num_acks].ack_uuid = *ack_uuid;
7509 ac->num_acks++;
7512 ac);
7513}
7514
7515
7520{
7525
7529 struct ReassemblyContext *rc;
7530};
7531
7532
7542static int
7543find_by_message_uuid (void *cls, uint32_t key, void *value)
7544{
7545 struct FindByMessageUuidContext *fc = cls;
7546 struct ReassemblyContext *rc = value;
7547
7548 (void) key;
7549 if (0 == GNUNET_memcmp (&fc->message_uuid, &rc->msg_uuid))
7550 {
7551 fc->rc = rc;
7552 return GNUNET_NO;
7553 }
7554 return GNUNET_YES;
7555}
7556
7557
7565static void
7566handle_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
7567{
7568 struct CommunicatorMessageContext *cmc = cls;
7569 struct VirtualLink *vl;
7570 struct ReassemblyContext *rc;
7571 const struct GNUNET_MessageHeader *msg;
7572 uint16_t msize;
7573 uint16_t fsize;
7574 uint16_t frag_off;
7575 char *target;
7576 struct GNUNET_TIME_Relative cdelay;
7577 struct FindByMessageUuidContext fc;
7578
7579 vl = lookup_virtual_link (&cmc->im.sender);
7580 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
7581 {
7582 /* Entirely normal: fragments of a message that was already in flight
7583 keep arriving for a while after a link goes down, and a peer that has
7584 validated us may start sending before we have validated it. This used
7585 to call #GNUNET_SERVICE_client_drop(), which disconnects the
7586 communicator *process* -- every queue it owns, hence every neighbour
7587 reachable through it, hence every CORE session. On a peer with many
7588 neighbours a single ill-timed fragment therefore dropped all
7589 connections at once, and since the fragment comes from the network,
7590 any peer could cause it at will. Drop the fragment, keep the
7591 communicator; see #demultiplex_with_cmc() for the same reasoning. */
7593 "No virtual link for %s to handle fragment\n",
7594 GNUNET_i2s (&cmc->im.sender));
7596 "# fragments dropped (virtual link down)",
7597 1,
7598 GNUNET_NO);
7599 finish_cmc_handling (cmc);
7600 return;
7601 }
7602 if (NULL == vl->reassembly_map)
7603 {
7605 vl->reassembly_heap =
7610 vl);
7611 }
7612 msize = ntohs (fb->msg_size);
7613 fc.message_uuid = fb->msg_uuid;
7614 fc.rc = NULL;
7616 fb->msg_uuid.uuid,
7618 &fc);
7619 fsize = ntohs (fb->header.size) - sizeof(*fb);
7620 if (NULL == (rc = fc.rc))
7621 {
7622 /* Bound the RAM a single sender can pin here: @e msg_size is chosen by
7623 the peer, not by us. */
7626 {
7627 struct ReassemblyContext *drop;
7628
7630 GNUNET_assert (NULL != drop);
7632 "# Reassembly contexts dropped (limit reached)",
7633 1,
7634 GNUNET_NO);
7636 }
7637 rc = GNUNET_malloc (sizeof(*rc) + msize /* reassembly payload buffer */
7638 + (msize + 7) / 8 * sizeof(uint8_t) /* bitfield */);
7639 rc->msg_uuid = fb->msg_uuid;
7640 rc->virtual_link = vl;
7641 rc->msg_size = msize;
7642 rc->reassembly_timeout =
7646 rc,
7650 vl->reassembly_map,
7651 rc->msg_uuid.uuid,
7652 rc,
7654 target = (char *) &rc[1];
7655 rc->bitfield = (uint8_t *) (target + rc->msg_size);
7656 /* The bitfield loop below decrements @e msg_missing once per newly
7657 received byte, so this must always start at the full message size:
7658 initialising it to 0 for a single-fragment message made it
7659 underflow, and the message was then never delivered. */
7660 rc->msg_missing = rc->msg_size;
7662 "Received fragment with size %u at offset %u/%u %u bytes missing from %s for NEW message %"
7663 PRIu64 "\n",
7664 fsize,
7665 ntohs (fb->frag_off),
7666 msize,
7667 rc->msg_missing,
7668 GNUNET_i2s (&cmc->im.sender),
7669 fb->msg_uuid.uuid);
7670 }
7671 else
7672 {
7673 target = (char *) &rc[1];
7675 "Received fragment at offset %u/%u from %s for message %u\n",
7676 ntohs (fb->frag_off),
7677 msize,
7678 GNUNET_i2s (&cmc->im.sender),
7679 (unsigned int) fb->msg_uuid.uuid);
7680 }
7681 if (msize != rc->msg_size)
7682 {
7683 GNUNET_break (0);
7684 finish_cmc_handling (cmc);
7685 return;
7686 }
7687
7688 /* reassemble */
7689 if (0 == fsize)
7690 {
7691 GNUNET_break (0);
7692 finish_cmc_handling (cmc);
7693 return;
7694 }
7695 frag_off = ntohs (fb->frag_off);
7696 if (frag_off + fsize > msize)
7697 {
7698 /* Fragment (plus fragment size) exceeds message size! */
7699 GNUNET_break_op (0);
7700 finish_cmc_handling (cmc);
7701 return;
7702 }
7703 memcpy (&target[frag_off], &fb[1], fsize);
7704 /* update bitfield and msg_missing */
7705 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
7706 {
7707 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
7708 {
7709 rc->bitfield[i / 8] |= (1 << (i % 8));
7710 rc->msg_missing--;
7711 }
7712 }
7713
7714 /* Compute cumulative ACK */
7716 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->msg_missing / fsize);
7717 if (0 == rc->msg_missing)
7718 cdelay = GNUNET_TIME_UNIT_ZERO;
7719 cummulative_ack (&cmc->im.sender,
7720 &fb->ack_uuid,
7723 /* is reassembly complete? */
7724 if (0 != rc->msg_missing)
7725 {
7726 finish_cmc_handling (cmc);
7727 return;
7728 }
7729 /* reassembly is complete, verify result */
7730 msg = (const struct GNUNET_MessageHeader *) &rc[1];
7731 if (ntohs (msg->size) != rc->msg_size)
7732 {
7733 GNUNET_break (0);
7735 finish_cmc_handling (cmc);
7736 return;
7737 }
7738 /* successful reassembly */
7740 "Fragment reassembly complete for message %u\n",
7741 (unsigned int) fb->msg_uuid.uuid);
7742 /* FIXME: check that the resulting msg is NOT a
7743 DV Box or Reliability Box, as that is NOT allowed! */
7744 {
7745 uint16_t rsize = rc->msg_size;
7746 char rbuf[rsize] GNUNET_ALIGN;
7747
7748 /* Copy the reassembled message out and release `rc' BEFORE
7749 demultiplexing: the inner message may tear down the virtual link,
7750 which frees every reassembly context of that link -- the old code
7751 then used and freed `rc' a second time afterwards. */
7752 memcpy (rbuf, msg, rsize);
7754 cmc->mh = (const struct GNUNET_MessageHeader *) rbuf;
7756 }
7757}
7758
7759
7767static int
7768check_reliability_box (void *cls,
7769 const struct TransportReliabilityBoxMessage *rb)
7770{
7771 const struct GNUNET_MessageHeader *box = (const struct
7772 GNUNET_MessageHeader *) &rb[1];
7773 (void) cls;
7774
7776 "check_send_msg with size %u: inner msg type %u and size %u (%lu %lu)\n",
7777 ntohs (rb->header.size),
7778 ntohs (box->type),
7779 ntohs (box->size),
7780 sizeof (struct TransportReliabilityBoxMessage),
7781 sizeof (struct GNUNET_MessageHeader));
7783 return GNUNET_YES;
7784}
7785
7786
7794static void
7795handle_reliability_box (void *cls,
7796 const struct TransportReliabilityBoxMessage *rb)
7797{
7798 struct CommunicatorMessageContext *cmc = cls;
7799 const struct GNUNET_MessageHeader *inbox =
7800 (const struct GNUNET_MessageHeader *) &rb[1];
7801 struct GNUNET_TIME_Relative rtt;
7802
7804 "Received reliability box from %s with UUID %s of type %u\n",
7805 GNUNET_i2s (&cmc->im.sender),
7807 (unsigned int) ntohs (inbox->type));
7808 rtt = GNUNET_TIME_UNIT_SECONDS; /* FIXME: should base this on "RTT", but we
7809 do not really have an RTT for the
7810 * incoming* queue (should we have
7811 the sender add it to the rb message?) */
7813 &cmc->im.sender,
7814 &rb->ack_uuid,
7815 (0 == ntohl (rb->ack_countdown))
7818 GNUNET_TIME_relative_divide (rtt, 8 /* FIXME: magic constant */)));
7819 /* continue with inner message */
7820 /* FIXME: check that inbox is NOT a DV Box, fragment or another
7821 reliability box (not allowed!) */
7822 cmc->mh = inbox;
7824}
7825
7826
7835static void
7836update_pd_age (struct PerformanceData *pd, unsigned int age)
7837{
7838 unsigned int sage;
7839
7840 if (age == pd->last_age)
7841 return; /* nothing to do */
7842 sage = GNUNET_MAX (pd->last_age, age - 2 * GOODPUT_AGING_SLOTS);
7843 for (unsigned int i = sage; i <= age - GOODPUT_AGING_SLOTS; i++)
7844 {
7845 struct TransmissionHistoryEntry *the = &pd->the[i % GOODPUT_AGING_SLOTS];
7846
7847 the->bytes_sent = 0;
7848 the->bytes_received = 0;
7849 }
7850 pd->last_age = age;
7851}
7852
7853
7862static void
7864 struct GNUNET_TIME_Relative rtt,
7865 uint16_t bytes_transmitted_ok)
7866{
7867 uint64_t nval = rtt.rel_value_us;
7868 uint64_t oval = pd->aged_rtt.rel_value_us;
7869 unsigned int age = get_age ();
7870 struct TransmissionHistoryEntry *the = &pd->the[age % GOODPUT_AGING_SLOTS];
7871
7872 if (oval == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
7873 pd->aged_rtt = rtt;
7874 else
7875 pd->aged_rtt.rel_value_us = (nval + 7 * oval) / 8;
7876 update_pd_age (pd, age);
7877 the->bytes_received += bytes_transmitted_ok;
7878}
7879
7880
7888static void
7890 struct GNUNET_TIME_Relative rtt,
7891 uint16_t bytes_transmitted_ok)
7892{
7893 update_performance_data (&q->pd, rtt, bytes_transmitted_ok);
7894}
7895
7896
7904static void
7906 struct GNUNET_TIME_Relative rtt,
7907 uint16_t bytes_transmitted_ok)
7908{
7909 update_performance_data (&dvh->pd, rtt, bytes_transmitted_ok);
7910}
7911
7912
7920static void
7922{
7923 struct PendingMessage *pos;
7924
7926 "Complete transmission of message %" PRIu64 " %u\n",
7927 pm->logging_uuid,
7928 pm->pmt);
7929 switch (pm->pmt)
7930 {
7931 case PMT_CORE:
7933 /* Full message sent, we are done */
7935 return;
7936
7937 case PMT_FRAGMENT_BOX:
7938 /* Fragment sent over reliable channel */
7939 pos = pm->frag_parent;
7940 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
7943 "pos frag_off %lu pos bytes_msg %lu pmt %u parent %u\n",
7944 (unsigned long) pos->frag_off,
7945 (unsigned long) pos->bytes_msg,
7946 pos->pmt,
7947 NULL == pos->frag_parent ? 1 : 0);
7948 /* check if subtree is done */
7949 while ((NULL == pos->head_frag) && (pos->frag_off == (pos->bytes_msg
7950 - sizeof(struct
7952 &&
7953 (NULL != pos->frag_parent))
7954 {
7955 pm = pos;
7956 pos = pm->frag_parent;
7957 if ((NULL == pos) && (PMT_DV_BOX == pm->pmt))
7958 {
7960 return;
7961 }
7962 else if (PMT_DV_BOX == pm->pmt)
7963 {
7965 return;
7966 }
7967 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
7969 }
7970
7971 /* Was this the last applicable fragment? */
7972 if ((NULL == pos->head_frag) && (NULL == pos->frag_parent || PMT_DV_BOX ==
7973 pos->pmt) &&
7974 (pos->frag_off == pos->bytes_msg))
7976 return;
7977
7978 case PMT_DV_BOX:
7980 "Completed transmission of message %" PRIu64 " (DV Box)\n",
7981 pm->logging_uuid);
7982 if (NULL != pm->frag_parent)
7983 {
7984 pos = pm->frag_parent;
7986 pos->bpm = NULL;
7988 }
7989 else
7991 return;
7992 }
7993}
7994
7995
8003static void
8005 struct GNUNET_TIME_Relative ack_delay)
8006{
8007 struct GNUNET_TIME_Relative delay;
8008
8010 delay = GNUNET_TIME_relative_subtract (delay, ack_delay);
8011 if (NULL != pa->queue && 1 == pa->num_send)
8013 if (NULL != pa->dvh && 1 == pa->num_send)
8014 update_dvh_performance (pa->dvh, delay, pa->message_size);
8015 if (NULL != pa->pm)
8018}
8019
8020
8028static int
8029check_reliability_ack (void *cls,
8030 const struct TransportReliabilityAckMessage *ra)
8031{
8032 unsigned int n_acks;
8033
8034 (void) cls;
8035 n_acks = (ntohs (ra->header.size) - sizeof(*ra))
8036 / sizeof(struct TransportCummulativeAckPayloadP);
8037 if (0 == n_acks)
8038 {
8039 GNUNET_break_op (0);
8040 return GNUNET_SYSERR;
8041 }
8042 if ((ntohs (ra->header.size) - sizeof(*ra)) !=
8043 n_acks * sizeof(struct TransportCummulativeAckPayloadP))
8044 {
8045 GNUNET_break_op (0);
8046 return GNUNET_SYSERR;
8047 }
8048 return GNUNET_OK;
8049}
8050
8051
8059static void
8060handle_reliability_ack (void *cls,
8061 const struct TransportReliabilityAckMessage *ra)
8062{
8063 struct CommunicatorMessageContext *cmc = cls;
8064 const struct TransportCummulativeAckPayloadP *ack;
8065 unsigned int n_acks;
8066 uint32_t ack_counter;
8067
8068 n_acks = (ntohs (ra->header.size) - sizeof(*ra))
8069 / sizeof(struct TransportCummulativeAckPayloadP);
8070 ack = (const struct TransportCummulativeAckPayloadP *) &ra[1];
8071 for (unsigned int i = 0; i < n_acks; i++)
8072 {
8073 struct PendingAcknowledgement *pa =
8075 if (NULL == pa)
8076 {
8078 "Received ACK from %s with UUID %s which is unknown to us!\n",
8079 GNUNET_i2s (&cmc->im.sender),
8080 GNUNET_uuid2s (&ack[i].ack_uuid.value));
8082 GST_stats,
8083 "# FRAGMENT_ACKS dropped, no matching pending message",
8084 1,
8085 GNUNET_NO);
8086 continue;
8087 }
8089 "Received ACK from %s with UUID %s\n",
8090 GNUNET_i2s (&cmc->im.sender),
8091 GNUNET_uuid2s (&ack[i].ack_uuid.value));
8092 handle_acknowledged (pa, GNUNET_TIME_relative_ntoh (ack[i].ack_delay));
8093 }
8094
8095 ack_counter = ntohl (ra->ack_counter);
8096 (void) ack_counter; /* silence compiler warning for now */
8097 // FIXME-OPTIMIZE: track ACK losses based on ack_counter somewhere!
8098 // (DV and/or Neighbour?)
8099 finish_cmc_handling (cmc);
8100}
8101
8102
8110static int
8112 void *cls,
8114{
8115 uint16_t size = ntohs (be->header.size) - sizeof(*be);
8116 const struct GNUNET_MessageHeader *inbox =
8117 (const struct GNUNET_MessageHeader *) &be[1];
8118 const char *is;
8119 uint16_t isize;
8120
8121 (void) cls;
8122 /* MUST bound the buffer before reading @a inbox: the size check below
8123 dereferences it, and a message consisting of nothing but the header
8124 leaves no bytes to read. */
8125 if (size <= sizeof(struct GNUNET_MessageHeader))
8126 {
8127 GNUNET_break_op (0);
8128 return GNUNET_SYSERR;
8129 }
8130 if (ntohs (inbox->size) >= size)
8131 {
8132 GNUNET_break_op (0);
8133 return GNUNET_SYSERR;
8134 }
8135 isize = ntohs (inbox->size);
8136 is = ((const char *) inbox) + isize;
8137 size -= isize;
8138 if ('\0' != is[size - 1])
8139 {
8140 GNUNET_break_op (0);
8141 return GNUNET_SYSERR;
8142 }
8143 return GNUNET_YES;
8144}
8145
8146
8155static void
8157 void *cls,
8159{
8160 const struct GNUNET_PeerIdentity *my_identity;
8161 struct CommunicatorMessageContext *cmc = cls;
8163 struct GNUNET_MQ_Envelope *env;
8164 struct TransportClient *tc;
8165 const struct GNUNET_MessageHeader *inbox =
8166 (const struct GNUNET_MessageHeader *) &be[1];
8167 uint16_t isize = ntohs (inbox->size);
8168 const char *target_communicator = ((const char *) inbox) + isize;
8169 char *sender;
8170 char *self;
8171
8174
8175 GNUNET_asprintf (&sender,
8176 "%s",
8177 GNUNET_i2s (&cmc->im.sender));
8178 GNUNET_asprintf (&self,
8179 "%s",
8181
8182 /* Find client providing this communicator */
8183 for (tc = clients_head; NULL != tc; tc = tc->next)
8184 if ((CT_COMMUNICATOR == tc->type) &&
8185 (NULL != tc->details.communicator.address_prefix) &&
8186 (0 ==
8187 strcmp (tc->details.communicator.address_prefix, target_communicator)))
8188 break;
8189 if (NULL == tc)
8190 {
8191 char *stastr;
8192
8194 &stastr,
8195 "# Backchannel message dropped: target communicator `%s' unknown",
8196 target_communicator);
8198 GNUNET_free (stastr);
8199 GNUNET_free (sender);
8200 GNUNET_free (self);
8201 finish_cmc_handling (cmc);
8202 return;
8203 }
8204 /* Finally, deliver backchannel message to communicator */
8206 "Delivering backchannel message from %s to %s of type %u to %s\n",
8207 sender,
8208 self,
8209 ntohs (inbox->type),
8210 target_communicator);
8212 cbi,
8213 isize,
8215 cbi->pid = cmc->im.sender;
8216 memcpy (&cbi[1], inbox, isize);
8217 GNUNET_MQ_send (tc->mq, env);
8218 GNUNET_free (sender);
8219 GNUNET_free (self);
8220 finish_cmc_handling (cmc);
8221}
8222
8223
8233static void
8234path_cleanup_cb (void *cls)
8235{
8236 struct DistanceVector *dv = cls;
8237 struct DistanceVectorHop *pos;
8238
8239 dv->timeout_task = NULL;
8240 while (NULL != (pos = dv->dv_head))
8241 {
8242 GNUNET_assert (dv == pos->dv);
8244 break;
8246 }
8247 if (NULL == pos)
8248 {
8249 free_dv_route (dv);
8250 return;
8251 }
8252 dv->timeout_task =
8254}
8255
8256
8257static void
8259{
8260
8261 const struct GNUNET_PeerIdentity target = vl->target;
8262
8263
8265 {
8266 struct RingBufferEntry *ring_buffer_copy[RING_BUFFER_SIZE];
8267 unsigned int tail = GNUNET_YES == is_ring_buffer_full ? ring_buffer_head :
8268 0;
8269 unsigned int head = GNUNET_YES == is_ring_buffer_full ? RING_BUFFER_SIZE :
8272 struct CommunicatorMessageContext *cmc;
8273 struct RingBufferEntry *rbe;
8274 struct GNUNET_MessageHeader *mh;
8275
8277 "Sending from ring buffer, which has %u items\n",
8278 head);
8279
8280 ring_buffer_head = 0;
8281 for (unsigned int i = 0; i < head; i++)
8282 {
8283 rbe = ring_buffer[(i + tail) % RING_BUFFER_SIZE];
8284 cmc = rbe->cmc;
8285 mh = rbe->mh;
8286
8287 im = cmc->im;
8288 // mh = cmc->mh;
8290 "Sending message of type %u to ring buffer target %s using vl target %s index %u\n",
8291 mh->type,
8292 GNUNET_i2s (&im.sender),
8293 GNUNET_i2s2 (&target),
8294 (i + tail) % RING_BUFFER_SIZE);
8295 if (0 == GNUNET_memcmp (&target, &im.sender))
8296 {
8298 "Finish handling message of type %u and size %u\n",
8299 (unsigned int) ntohs (mh->type),
8300 (unsigned int) ntohs (mh->size));
8302 GNUNET_free (mh);
8303 GNUNET_free (rbe->cmc);
8304 GNUNET_free (rbe);
8305 }
8306 else
8307 {
8308 ring_buffer_copy[ring_buffer_head] = rbe;
8310 }
8311 }
8312
8315 {
8317 }
8318
8319 for (unsigned int i = 0; i < ring_buffer_head; i++)
8320 {
8321 ring_buffer[i] = ring_buffer_copy[i];
8323 "ring_buffer[i]->mh->type for i %u %u\n",
8324 i,
8325 ring_buffer[i]->mh->type);
8326 }
8327 /* MUST clear the consumed slots, we freed those entries above */
8328 for (unsigned int i = ring_buffer_head; i < RING_BUFFER_SIZE; i++)
8329 ring_buffer[i] = NULL;
8330
8332 "%u items still in ring buffer\n",
8334 /* If we consumed nothing, compaction rewrote the buffer in place and
8335 left the write index one past the end. #handle_raw_message() would
8336 then read ring_buffer[RING_BUFFER_SIZE] and free whatever that is.
8337 The buffer is still full, and compaction moved the oldest entry to
8338 slot 0, so that is where the next write belongs. */
8340 ring_buffer_head = 0;
8341 }
8342
8344 {
8345 struct PendingMessage *ring_buffer_dv_copy[RING_BUFFER_SIZE];
8346 struct PendingMessage *pm;
8347 unsigned int tail = GNUNET_YES == is_ring_buffer_dv_full ?
8349 0;
8350 unsigned int head = GNUNET_YES == is_ring_buffer_dv_full ?
8353
8355 "Sending from ring buffer dv, which has %u items\n",
8356 head);
8357
8359 for (unsigned int i = 0; i < head; i++)
8360 {
8361 pm = ring_buffer_dv[(i + tail) % RING_BUFFER_SIZE];
8362
8364 "Sending to ring buffer target %s using vl target %s\n",
8365 GNUNET_i2s (&pm->target),
8366 GNUNET_i2s2 (&target));
8367 if (0 == GNUNET_memcmp (&target, &pm->target))
8368 {
8370 "Adding PendingMessage to vl, checking transmission.\n");
8371 pm->vl = vl;
8375 pm);
8376
8378 }
8379 else
8380 {
8381 ring_buffer_dv_copy[ring_buffer_dv_head] = pm;
8383 }
8384 }
8385
8387 {
8389 }
8390
8391 for (unsigned int i = 0; i < ring_buffer_dv_head; i++)
8392 ring_buffer_dv[i] = ring_buffer_dv_copy[i];
8393 /* MUST clear the consumed slots: entries we handed to a VirtualLink are
8394 now owned by that link, and #forward_dv_box() would GNUNET_free() them
8395 again once the ring buffer wraps around. */
8396 for (unsigned int i = ring_buffer_dv_head; i < RING_BUFFER_SIZE; i++)
8397 ring_buffer_dv[i] = NULL;
8398
8400 "%u items still in ring buffer dv.\n",
8402 /* Same one-past-the-end hazard as above: #forward_dv_box() reads
8403 ring_buffer_dv[ring_buffer_dv_head] and GNUNET_free()s it. */
8406 }
8407}
8408
8409
8417static void
8419{
8420 struct DistanceVector *dv = hop->dv;
8421 struct VirtualLink *vl;
8422
8423 vl = lookup_virtual_link (&dv->target);
8424 if (NULL == vl)
8425 {
8426
8427 vl = GNUNET_new (struct VirtualLink);
8429 "Creating new virtual link %p to %s using DV!\n",
8430 vl,
8431 GNUNET_i2s (&dv->target));
8432 vl->burst_addr = NULL;
8433 vl->confirmed = GNUNET_YES;
8434 vl->message_uuid_ctr =
8435 GNUNET_CRYPTO_random_u64 (UINT64_MAX);
8436 vl->target = dv->target;
8442 links,
8443 &vl->target,
8444 vl,
8446 vl->dv = dv;
8447 dv->vl = vl;
8448 vl->visibility_task =
8451 /* We lacked a confirmed connection to the target
8452 before, so tell CORE about it (finally!) */
8455 }
8456 else
8457 {
8458 /* Link was already up, remember dv is also now available and we are done */
8459 vl->dv = dv;
8460 dv->vl = vl;
8461 if (GNUNET_NO == vl->confirmed)
8462 {
8463 vl->confirmed = GNUNET_YES;
8464 vl->visibility_task =
8467 /* We lacked a confirmed connection to the target
8468 before, so tell CORE about it (finally!) */
8471 }
8472 else
8474 "Virtual link to %s could now also use DV!\n",
8475 GNUNET_i2s (&dv->target));
8476 }
8477}
8478
8479
8505static int
8506learn_dv_path (const struct GNUNET_PeerIdentity *path,
8507 unsigned int path_len,
8508 struct GNUNET_TIME_Relative network_latency,
8509 struct GNUNET_TIME_Absolute path_valid_until)
8510{
8511 const struct GNUNET_PeerIdentity *my_identity;
8512 struct DistanceVectorHop *hop;
8513 struct DistanceVector *dv;
8514 struct Neighbour *next_hop;
8515 unsigned int shorter_distance;
8516
8517 if (path_len < 3)
8518 {
8519 /* what a boring path! not allowed! */
8520 GNUNET_break (0);
8521 return GNUNET_SYSERR;
8522 }
8523
8526
8527 GNUNET_assert (0 == GNUNET_memcmp (my_identity, &path[0]));
8528 next_hop = lookup_neighbour (&path[1]);
8529 if (NULL == next_hop)
8530 {
8531 /* next hop must be a neighbour, otherwise this whole thing is useless! */
8532 GNUNET_break (0);
8533 return GNUNET_SYSERR;
8534 }
8535 for (unsigned int i = 2; i < path_len; i++)
8536 {
8537 struct Neighbour *n = lookup_neighbour (&path[i]);
8538 struct GNUNET_TIME_Absolute q_timeout;
8539
8540 if (NULL != n)
8541 {
8542 q_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
8543 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
8544 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
8546 "remaining %lu to %s\n",
8547 (unsigned long) GNUNET_TIME_absolute_get_remaining (q_timeout)
8548 .rel_value_us,
8549 GNUNET_i2s (&n->pid));
8550 if (0 != GNUNET_TIME_absolute_get_remaining (q_timeout).rel_value_us)
8551 {
8552 /* Useless path: we have a direct active connection to some hop
8553 in the middle of the path, so this one is not even
8554 terribly useful for redundancy */
8556 "Path of %u hops useless: directly link to hop %u (%s)\n",
8557 path_len,
8558 i,
8559 GNUNET_i2s (&path[i]));
8561 "# Useless DV path ignored: hop is neighbour",
8562 1,
8563 GNUNET_NO);
8564 return GNUNET_SYSERR;
8565 }
8566 }
8567 }
8568 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
8569 if (NULL == dv)
8570 {
8571 dv = GNUNET_new (struct DistanceVector);
8572 dv->target = path[path_len - 1];
8575 dv);
8578 dv_routes,
8579 &dv->target,
8580 dv,
8582 }
8583 /* Check if we have this path already! */
8584 shorter_distance = 0;
8585 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
8586 pos = pos->next_dv)
8587 {
8588 if (pos->distance < path_len - 3)
8589 shorter_distance++;
8590 /* Note that the distances in 'pos' excludes us (path[0]),
8591 the next_hop (path[1]) and the target so we need to subtract three
8592 and check next_hop explicitly */
8593 if ((pos->distance == path_len - 3) && (pos->next_hop == next_hop))
8594 {
8595 int match = GNUNET_YES;
8596
8597 for (unsigned int i = 0; i < pos->distance; i++)
8598 {
8599 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
8600 {
8601 match = GNUNET_NO;
8602 break;
8603 }
8604 }
8605 if (GNUNET_YES == match)
8606 {
8607 struct GNUNET_TIME_Relative last_timeout;
8608
8609 /* Re-discovered known path, update timeout */
8611 "# Known DV path refreshed",
8612 1,
8613 GNUNET_NO);
8614 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
8615 pos->timeout =
8617 pos->path_valid_until =
8618 GNUNET_TIME_absolute_max (pos->path_valid_until, path_valid_until);
8619 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
8620 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
8621 if (0 <
8624 if (last_timeout.rel_value_us <
8627 .rel_value_us)
8628 {
8629 /* Some peer send DV learn messages too often, we are learning
8630 the same path faster than it would be useful; do not forward! */
8632 "Rediscovered path too quickly, not forwarding further\n")
8633 ;
8634 return GNUNET_NO;
8635 }
8637 "Refreshed known path to %s valid until %s, forwarding further\n",
8638 GNUNET_i2s (&dv->target),
8640 pos->path_valid_until));
8641 return GNUNET_YES;
8642 }
8643 }
8644 }
8645 /* Count how many shorter paths we have (incl. direct
8646 neighbours) before simply giving up on this one! */
8647 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
8648 {
8649 /* We have a shorter path already! */
8651 "Have many shorter DV paths %s, not forwarding further\n",
8652 GNUNET_i2s (&dv->target));
8653 return GNUNET_NO;
8654 }
8655 /* create new DV path entry */
8657 "Discovered new DV path to %s valid until %s\n",
8658 GNUNET_i2s (&dv->target),
8659 GNUNET_STRINGS_absolute_time_to_string (path_valid_until));
8660 hop = GNUNET_malloc (sizeof(struct DistanceVectorHop)
8661 + sizeof(struct GNUNET_PeerIdentity) * (path_len - 3));
8662 hop->next_hop = next_hop;
8663 hop->dv = dv;
8664 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
8665 memcpy (&hop[1],
8666 &path[2],
8667 sizeof(struct GNUNET_PeerIdentity) * (path_len - 3));
8669 hop->path_valid_until = path_valid_until;
8670 hop->distance = path_len - 3;
8671 hop->pd.aged_rtt = network_latency;
8672 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
8674 next_hop->dv_head,
8675 next_hop->dv_tail,
8676 hop);
8677 if (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
8679 return GNUNET_YES;
8680}
8681
8682
8690static int
8691check_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
8692{
8693 const struct GNUNET_PeerIdentity *my_identity;
8694 uint16_t size = ntohs (dvl->header.size);
8695 uint16_t num_hops = ntohs (dvl->num_hops);
8696 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
8697
8698 (void) cls;
8699 if (size != sizeof(*dvl) + num_hops * sizeof(struct DVPathEntryP))
8700 {
8701 GNUNET_break_op (0);
8702 return GNUNET_SYSERR;
8703 }
8704 if (num_hops > MAX_DV_HOPS_ALLOWED)
8705 {
8706 GNUNET_break_op (0);
8707 return GNUNET_SYSERR;
8708 }
8709
8712
8713 for (unsigned int i = 0; i < num_hops; i++)
8714 {
8715 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
8716 {
8717 GNUNET_break_op (0);
8718 return GNUNET_SYSERR;
8719 }
8720 if (0 == GNUNET_memcmp (my_identity, &hops[i].hop))
8721 {
8722 GNUNET_break_op (0);
8723 return GNUNET_SYSERR;
8724 }
8725 }
8726 return GNUNET_YES;
8727}
8728
8729
8741static void
8742forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
8743 const struct TransportDVLearnMessage *msg,
8744 uint16_t bi_history,
8745 uint16_t nhops,
8746 const struct DVPathEntryP *hops,
8747 struct GNUNET_TIME_Absolute in_time)
8748{
8749 struct DVPathEntryP *dhops;
8750 size_t fwd_size = sizeof(struct TransportDVLearnMessage)
8751 + (nhops + 1) * sizeof(struct DVPathEntryP);
8752 /* Signing is synchronous and the routing calls below copy the message,
8753 so this never outlives the frame. Keeping it on the stack matters:
8754 a hub forwards a DV learn to every eligible neighbour, so this is one
8755 of the hottest allocation sites in the service. Size it by the hop
8756 limit rather than by @a nhops -- @a nhops is only asserted to be below
8757 that limit further down, and a VLA is sized before we get there. */
8758 char fwd_buf[sizeof(struct TransportDVLearnMessage)
8759 + (MAX_DV_HOPS_ALLOWED + 1)
8760 * sizeof(struct DVPathEntryP)] GNUNET_ALIGN;
8761 struct TransportDVLearnMessage *fwd
8762 = (struct TransportDVLearnMessage *) fwd_buf;
8763 struct GNUNET_TIME_Relative nnd;
8764 const struct GNUNET_PeerIdentity *my_identity;
8765 struct VirtualLink *vl;
8766 struct Neighbour *n;
8767
8769 memset (fwd_buf, 0, fwd_size);
8770
8771 /* compute message for forwarding */
8773 "Forwarding DV learn message originating from %s to %s\n",
8774 GNUNET_i2s (&msg->initiator),
8775 GNUNET_i2s2 (next_hop));
8778 fwd->header.size = htons (sizeof(struct TransportDVLearnMessage)
8779 + (nhops + 1) * sizeof(struct DVPathEntryP));
8780 fwd->num_hops = htons (nhops + 1);
8781 fwd->bidirectional = htons (bi_history);
8784 msg->non_network_delay));
8786 fwd->init_sig = msg->init_sig;
8787 fwd->initiator = msg->initiator;
8788 fwd->challenge = msg->challenge;
8789 fwd->monotonic_time = msg->monotonic_time;
8790
8793
8794 dhops = (struct DVPathEntryP *) &fwd[1];
8795 GNUNET_memcpy (dhops, hops, sizeof(struct DVPathEntryP) * nhops);
8796 dhops[nhops].hop = *my_identity;
8797 {
8798 struct DvHopPS dhp = {
8800 .purpose.size = htonl (sizeof(dhp)),
8801 .pred = (0 == nhops) ? msg->initiator : dhops[nhops - 1].hop,
8802 .succ = *next_hop,
8804 };
8805
8807 &dhops[nhops].hop_sig))
8808 return; /* nobody would accept the path without our hop signature */
8809 }
8810 vl = lookup_virtual_link (next_hop);
8811 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
8812 {
8814 &fwd->header,
8816 return;
8817 }
8818 /* Use route via neighbour */
8819 n = lookup_neighbour (next_hop);
8820 if (NULL != n)
8822 &fwd->header,
8824}
8825
8826
8836static int
8838 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time,
8839 const struct GNUNET_PeerIdentity *init,
8841 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
8842{
8843 struct DvInitPS ip = { .purpose.purpose = htonl (
8845 .purpose.size = htonl (sizeof(ip)),
8846 .monotonic_time = sender_monotonic_time,
8847 .challenge = *challenge };
8848
8849 if (
8850 GNUNET_OK !=
8852 &ip,
8853 init_sig,
8854 &init->public_key))
8855 {
8856 GNUNET_break_op (0);
8857 return GNUNET_SYSERR;
8858 }
8859 return GNUNET_OK;
8860}
8861
8862
8867{
8871 const struct TransportDVLearnMessage *dvl;
8872
8876 const struct DVPathEntryP *hops;
8877
8882
8887
8891 unsigned int num_eligible;
8892
8896 unsigned int num_selections;
8897
8901 uint16_t nhops;
8902
8906 uint16_t bi_history;
8907};
8908
8909
8918static int
8919dv_neighbour_selection (void *cls,
8920 const struct GNUNET_PeerIdentity *pid,
8921 void *value)
8922{
8923 struct NeighbourSelectionContext *nsc = cls;
8924
8925 (void) value;
8926 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
8927 return GNUNET_YES; /* skip initiator */
8928 for (unsigned int i = 0; i < nsc->nhops; i++)
8929 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
8930 return GNUNET_YES;
8931 /* skip peers on path */
8932 nsc->num_eligible++;
8933 return GNUNET_YES;
8934}
8935
8936
8947static int
8948dv_neighbour_transmission (void *cls,
8949 const struct GNUNET_PeerIdentity *pid,
8950 void *value)
8951{
8952 struct NeighbourSelectionContext *nsc = cls;
8953
8955 "transmission %s\n",
8956 GNUNET_i2s (pid));
8957 (void) value;
8958 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
8959 return GNUNET_YES; /* skip initiator */
8960 for (unsigned int i = 0; i < nsc->nhops; i++)
8961 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
8962 return GNUNET_YES;
8963 /* skip peers on path */
8964 for (unsigned int i = 0; i < nsc->num_selections; i++)
8965 {
8966 if (nsc->selections[i] == nsc->num_eligible)
8967 {
8968 forward_dv_learn (pid,
8969 nsc->dvl,
8970 nsc->bi_history,
8971 nsc->nhops,
8972 nsc->hops,
8973 nsc->in_time);
8974 break;
8975 }
8976 }
8977 nsc->num_eligible++;
8978 return GNUNET_YES;
8979}
8980
8981
9025static unsigned int
9026calculate_fork_degree (unsigned int hops_taken,
9027 unsigned int neighbour_count,
9028 unsigned int eligible_count)
9029{
9030 double target_total = 50.0; /* FIXME: use LOG(NSE)? */
9031 double eligible_ratio =
9032 ((double) eligible_count) / ((double) neighbour_count);
9033 double boost_factor = eligible_ratio * eligible_ratio;
9034 unsigned int rnd;
9035 double left;
9036
9037 if (hops_taken >= 64)
9038 {
9039 GNUNET_break (0);
9040 return 0; /* precaution given bitshift below */
9041 }
9042 for (unsigned int i = 1; i < hops_taken; i++)
9043 {
9044 /* For each hop, subtract the expected number of targets
9045 reached at distance d (so what remains divided by 2^d) */
9046 target_total -= (target_total * boost_factor / (1LLU << i));
9047 }
9048 {
9049 double degree = target_total * boost_factor / (1LLU << hops_taken);
9050
9051 rnd = (unsigned int) floor (degree);
9052 /* round up or down probabilistically depending on how close we were
9053 when floor()ing to rnd. NOTE: this must be the fractional part of
9054 @e degree; using `target_total - rnd' here made the condition below
9055 true essentially always, so we always rounded up. */
9056 left = degree - (double) rnd;
9057 }
9058 if (UINT32_MAX * left >
9059 GNUNET_CRYPTO_random_u64 (UINT32_MAX))
9060 rnd++; /* round up */
9062 "Forwarding DV learn message of %u hops %u(/%u/%u) times\n",
9063 hops_taken,
9064 rnd,
9065 eligible_count,
9066 neighbour_count);
9067 return rnd;
9068}
9069
9070
9077static void
9078neighbour_store_dvmono_cb (void *cls, int success)
9079{
9080 struct Neighbour *n = cls;
9081
9082 n->sc = NULL;
9083 if (GNUNET_YES != success)
9085 "Failed to store other peer's monotonic time in peerstore!\n");
9086}
9087
9088
9089static struct GNUNET_TIME_Relative
9091{
9092 struct GNUNET_TIME_Relative host_latency_sum;
9093 struct GNUNET_TIME_Relative latency;
9094 struct GNUNET_TIME_Relative network_latency;
9095 uint16_t nhops = ntohs (dvl->num_hops);;
9096
9097 /* We initiated this, learn the forward path! */
9098 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
9099
9100 // Need also something to lookup initiation time
9101 // to compute RTT! -> add RTT argument here?
9103 dvl->monotonic_time));
9104 /* @e non_network_delay is fully attacker-controlled, and our clock may
9105 simply be behind the initiator's: never assert on this. */
9106 if (latency.rel_value_us < host_latency_sum.rel_value_us)
9107 {
9109 "# DV learn with implausible non-network delay",
9110 1,
9111 GNUNET_NO);
9113 }
9114 // latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
9115 // (based on dvl->challenge, we can identify time of origin!)
9116
9117 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
9118 /* assumption: latency on all links is the same */
9119 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
9120
9121 return network_latency;
9122}
9123
9124
9132static void
9133handle_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
9134{
9135 struct CommunicatorMessageContext *cmc = cls;
9137 int bi_hop;
9138 uint16_t nhops;
9139 uint16_t bi_history;
9140 const struct DVPathEntryP *hops;
9141 int do_fwd;
9142 int did_initiator;
9143 struct GNUNET_TIME_Absolute in_time;
9144 struct Neighbour *n;
9145 const struct GNUNET_PeerIdentity *my_identity;
9146
9147 nhops = ntohs (dvl->num_hops); /* 0 = sender is initiator */
9148 bi_history = ntohs (dvl->bidirectional);
9149 hops = (const struct DVPathEntryP *) &dvl[1];
9150 if (0 == nhops)
9151 {
9152 /* sanity check */
9153 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
9154 {
9155 GNUNET_break (0);
9156 finish_cmc_handling (cmc);
9157 return;
9158 }
9159 /* A zero-hop message we supposedly initiated ourselves would make the
9160 "we are the initiator" branch below read hops[0] and write past the
9161 end of its `path[nhops + 1]' array. */
9163 {
9164 GNUNET_break_op (0);
9165 finish_cmc_handling (cmc);
9166 return;
9167 }
9168 }
9169 else
9170 {
9172 "handle dv learn message last hop %s\n",
9173 GNUNET_i2s (&hops[nhops - 1].hop));
9174 /* sanity check */
9175 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
9176 {
9177 GNUNET_break (0);
9178 finish_cmc_handling (cmc);
9179 return;
9180 }
9181 }
9182
9184 cc = cmc->tc->details.communicator.cc;
9185 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
9186 cc); // FIXME: add bi-directional flag to cc?
9187 in_time = GNUNET_TIME_absolute_get ();
9188
9189 /* continue communicator here, everything else can happen asynchronous! */
9190 finish_cmc_handling (cmc);
9191
9192 n = lookup_neighbour (&dvl->initiator);
9193 if (NULL != n)
9194 {
9195 if ((n->dv_monotime_available == GNUNET_YES) &&
9198 {
9200 "DV learn from %s discarded due to time travel",
9201 GNUNET_i2s (&dvl->initiator));
9203 "# DV learn discarded due to time travel",
9204 1,
9205 GNUNET_NO);
9206 return;
9207 }
9209 &dvl->initiator,
9210 &dvl->challenge,
9211 &dvl->init_sig))
9212 {
9214 "DV learn signature from %s invalid\n",
9215 GNUNET_i2s (&dvl->initiator));
9216 GNUNET_break_op (0);
9217 return;
9218 }
9221 {
9222 if (NULL != n->sc)
9223 {
9225 "store cancel\n");
9227 }
9228 n->sc =
9230 "transport",
9231 &dvl->initiator,
9233 &dvl->monotonic_time,
9234 sizeof(dvl->monotonic_time),
9238 n);
9239 }
9240 }
9241
9244
9245 /* OPTIMIZE-FIXME: asynchronously (!) verify signatures!,
9246 If signature verification load too high, implement random drop strategy */
9247 for (unsigned int i = 0; i < nhops; i++)
9248 {
9249 struct DvHopPS dhp = { .purpose.purpose =
9251 .purpose.size = htonl (sizeof(dhp)),
9252 .pred = (0 == i) ? dvl->initiator : hops[i - 1].hop,
9253 .succ = (nhops == i + 1) ? *my_identity
9254 : hops[i + 1].hop,
9255 .challenge = dvl->challenge };
9256
9257 if (GNUNET_OK !=
9259 &dhp,
9260 &hops[i].hop_sig,
9261 &hops[i].hop.public_key))
9262 {
9264 "DV learn from %s signature of hop %u invalid\n",
9265 GNUNET_i2s (&dvl->initiator),
9266 i);
9268 "signature of hop %s invalid\n",
9269 GNUNET_i2s (&hops[i].hop));
9271 "pred %s\n",
9272 GNUNET_i2s (&dhp.pred));
9274 "succ %s\n",
9275 GNUNET_i2s (&dhp.succ));
9277 "hash %s\n",
9278 GNUNET_sh2s (&dhp.challenge.value));
9279 GNUNET_break_op (0);
9280 return;
9281 }
9282 }
9283 if (GNUNET_EXTRA_LOGGING > 0)
9284 {
9285 char *path;
9286
9287 path = GNUNET_strdup (GNUNET_i2s (&dvl->initiator));
9288 for (unsigned int i = 0; i < nhops; i++)
9289 {
9290 char *tmp;
9291
9292 GNUNET_asprintf (&tmp,
9293 "%s%s%s",
9294 path,
9295 (bi_history & (1 << (nhops - i))) ? "<->" : "-->",
9296 GNUNET_i2s (&hops[i].hop));
9297 GNUNET_free (path);
9298 path = tmp;
9299 }
9301 "Received DVInit via %s%s%s\n",
9302 path,
9303 bi_hop ? "<->" : "-->",
9305 GNUNET_free (path);
9306 }
9307 do_fwd = GNUNET_YES;
9308 if (0 == GNUNET_memcmp (my_identity, &dvl->initiator))
9309 {
9310 struct GNUNET_PeerIdentity path[nhops + 1];
9311 struct GNUNET_TIME_Relative network_latency;
9312
9313 /* We initiated this, learn the forward path! */
9314 path[0] = *my_identity;
9315 path[1] = hops[0].hop;
9316
9317 network_latency = get_network_latency (dvl);
9318
9319 for (unsigned int i = 2; i <= nhops; i++)
9320 {
9321 struct GNUNET_TIME_Relative ilat;
9322
9323 /* assumption: linear latency increase per hop */
9324 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
9325 path[i] = hops[i - 1].hop;
9327 "Learned path with %u hops to %s with latency %s\n",
9328 i,
9329 GNUNET_i2s (&path[i]),
9331 learn_dv_path (path,
9332 i + 1,
9333 ilat,
9336 }
9337 /* as we initiated, do not forward again (would be circular!) */
9338 do_fwd = GNUNET_NO;
9339 return;
9340 }
9341 if (bi_hop)
9342 {
9343 /* last hop was bi-directional, we could learn something here! */
9344 struct GNUNET_PeerIdentity path[nhops + 2];
9345 struct GNUNET_TIME_Relative ilat;
9346 struct GNUNET_TIME_Relative network_latency;
9347
9348 path[0] = *my_identity;
9349 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
9350 for (unsigned int i = 0; i < nhops; i++)
9351 {
9352 int iret;
9353
9354 if (0 == (bi_history & (1 << i)))
9355 break; /* i-th hop not bi-directional, stop learning! */
9356 if (i == nhops - 1)
9357 {
9358 path[i + 2] = dvl->initiator;
9359 }
9360 else
9361 {
9362 path[i + 2] = hops[nhops - i - 2].hop;
9363 }
9364
9366 "Learned inverse path with %u hops to %s\n",
9367 i + 2,
9368 GNUNET_i2s (&path[i + 2]));
9369 network_latency = get_network_latency (dvl);
9370 ilat = GNUNET_TIME_relative_multiply (network_latency, i + 2);
9371 iret = learn_dv_path (path,
9372 i + 3,
9373 ilat,
9376 if (GNUNET_SYSERR == iret)
9377 {
9378 /* path invalid or too long to be interesting for US, thus should also
9379 not be interesting to our neighbours, cut path when forwarding to
9380 'i' hops, except of course for the one that goes back to the
9381 initiator */
9383 "# DV learn not forwarded due invalidity of path",
9384 1,
9385 GNUNET_NO);
9386 do_fwd = GNUNET_NO;
9387 break;
9388 }
9389 if ((GNUNET_NO == iret) && (nhops == i + 1))
9390 {
9391 /* we have better paths, and this is the longest target,
9392 so there cannot be anything interesting later */
9394 "# DV learn not forwarded, got better paths",
9395 1,
9396 GNUNET_NO);
9397 do_fwd = GNUNET_NO;
9398 break;
9399 }
9400 }
9401 }
9402 if (MAX_DV_HOPS_ALLOWED == nhops)
9403 {
9404 /* At limit, we're out of here! */
9405 return;
9406 }
9407
9408 /* Forward to initiator, if path non-trivial and possible */
9409 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
9410 did_initiator = GNUNET_NO;
9411 if ((1 <= nhops) &&
9412 (GNUNET_YES ==
9414 {
9415 /* send back to origin! */
9417 "Sending DVL back to initiator %s\n",
9418 GNUNET_i2s (&dvl->initiator));
9419 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
9420 did_initiator = GNUNET_YES;
9421 }
9422 /* We forward under two conditions: either we still learned something
9423 ourselves (do_fwd), or the path was darn short and thus the initiator is
9424 likely to still be very interested in this (and we did NOT already
9425 send it back to the initiator) */
9426 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
9427 (GNUNET_NO == did_initiator)))
9428 {
9429 /* Pick random neighbours that are not yet on the path */
9430 struct NeighbourSelectionContext nsc;
9431 unsigned int n_cnt;
9432 unsigned int n_eligible;
9433
9435 nsc.nhops = nhops;
9436 nsc.dvl = dvl;
9437 nsc.bi_history = bi_history;
9438 nsc.hops = hops;
9439 nsc.in_time = in_time;
9440 nsc.num_eligible = 0;
9443 &nsc);
9444 if (0 == nsc.num_eligible)
9445 return; /* done here, cannot forward to anyone else */
9446 n_eligible = nsc.num_eligible;
9447 nsc.num_selections = calculate_fork_degree (nhops, n_cnt, n_eligible);
9448 nsc.num_selections =
9451 "Forwarding DVL to %u other peers\n",
9452 nsc.num_selections);
9453 /* #dv_neighbour_transmission() counts ELIGIBLE peers only, so the
9454 offsets must be drawn from that range -- drawing from the total
9455 number of neighbours made us silently forward to fewer peers than
9456 #calculate_fork_degree() asked for. */
9457 for (unsigned int i = 0; i < nsc.num_selections; i++)
9458 nsc.selections[i] =
9459 (nsc.num_selections == n_eligible)
9460 ? i /* all were selected, avoid collisions by chance */
9461 : GNUNET_CRYPTO_random_u32 (n_eligible);
9462 nsc.num_eligible = 0;
9465 &nsc);
9466 }
9467}
9468
9469
9477static int
9478check_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
9479{
9480 uint16_t size = ntohs (dvb->header.size);
9481 uint16_t num_hops = ntohs (dvb->num_hops);
9482 uint16_t total_hops = ntohs (dvb->total_hops);
9483 uint16_t orig_size = ntohs (dvb->orig_size);
9484 const struct GNUNET_PeerIdentity *hops =
9485 (const struct GNUNET_PeerIdentity *) &dvb[1];
9486 const struct GNUNET_PeerIdentity *my_identity;
9487
9488 (void) cls;
9489 if (size < sizeof(*dvb) + num_hops * sizeof(struct GNUNET_PeerIdentity)
9490 + sizeof(struct GNUNET_MessageHeader))
9491 {
9492 GNUNET_break_op (0);
9493 return GNUNET_SYSERR;
9494 }
9495 if ((num_hops > MAX_DV_HOPS_ALLOWED) ||
9496 (total_hops > MAX_DV_HOPS_ALLOWED))
9497 {
9498 GNUNET_break_op (0);
9499 return GNUNET_SYSERR;
9500 }
9501 /* #decaps_dv_box_cb() derives a VLA size from
9502 orig_size - sizeof(*dvb) - total_hops * sizeof (struct
9503 GNUNET_PeerIdentity); make sure that cannot underflow and that the
9504 remainder can plausibly hold a payload header plus a message. */
9505 if ((orig_size < size) ||
9506 (orig_size < sizeof(*dvb)
9507 + total_hops * sizeof(struct GNUNET_PeerIdentity)
9508 + sizeof(struct TransportDVBoxPayloadP)
9509 + sizeof(struct GNUNET_MessageHeader)))
9510 {
9511 GNUNET_break_op (0);
9512 return GNUNET_SYSERR;
9513 }
9514
9517
9518 /* This peer must not be on the path */
9519 for (unsigned int i = 0; i < num_hops; i++)
9520 if (0 == GNUNET_memcmp (&hops[i], my_identity))
9521 {
9522 GNUNET_break_op (0);
9523 return GNUNET_SYSERR;
9524 }
9525 return GNUNET_YES;
9526}
9527
9528
9541static void
9542forward_dv_box (struct Neighbour *next_hop,
9543 struct TransportDVBoxMessage *hdr,
9544 uint16_t total_hops,
9545 uint16_t num_hops,
9546 const struct GNUNET_PeerIdentity *hops,
9547 const void *enc_payload,
9548 uint16_t enc_payload_size)
9549{
9550 struct VirtualLink *vl = next_hop->vl;
9551 struct PendingMessage *pm;
9552 size_t msg_size = sizeof(struct TransportDVBoxMessage)
9553 + num_hops * sizeof(struct GNUNET_PeerIdentity)
9554 + enc_payload_size;
9555 char *buf;
9556 char msg_buf[msg_size] GNUNET_ALIGN;
9557 struct GNUNET_PeerIdentity *dhops;
9558
9559 hdr->num_hops = htons (num_hops);
9560 hdr->total_hops = htons (total_hops);
9561 hdr->header.size = htons (msg_size);
9562 memcpy (msg_buf, hdr, sizeof(*hdr));
9563 dhops = (struct GNUNET_PeerIdentity *) &msg_buf[sizeof(struct
9565 ;
9566 memcpy (dhops, hops, num_hops * sizeof(struct GNUNET_PeerIdentity));
9567 memcpy (&dhops[num_hops], enc_payload, enc_payload_size);
9568
9569 if (GNUNET_YES == ntohl (hdr->without_fc))
9570 {
9572 "Forwarding control message (payload size %u) in DV Box to next hop %s (%u/%u) \n",
9573 enc_payload_size,
9574 GNUNET_i2s (&next_hop->pid),
9575 (unsigned int) num_hops,
9576 (unsigned int) total_hops);
9577 route_via_neighbour (next_hop, (const struct
9578 GNUNET_MessageHeader *) msg_buf,
9580 }
9581 else
9582 {
9583 pm = GNUNET_malloc (sizeof(struct PendingMessage) + msg_size);
9585 "2 created pm %p storing vl %p \n",
9586 pm,
9587 vl);
9588 pm->pmt = PMT_DV_BOX;
9589 pm->vl = vl;
9590 pm->target = next_hop->pid;
9594 pm->bytes_msg = msg_size;
9595 buf = (char *) &pm[1];
9596 memcpy (buf, msg_buf, msg_size);
9597
9599 "Created pending message %" PRIu64
9600 " for DV Box with next hop %s (%u/%u)\n",
9601 pm->logging_uuid,
9602 GNUNET_i2s (&next_hop->pid),
9603 (unsigned int) num_hops,
9604 (unsigned int) total_hops);
9605
9606 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
9607 {
9609 vl->pending_msg_head,
9610 vl->pending_msg_tail,
9611 pm);
9612
9614 }
9615 else
9616 {
9618 "The virtual link is not ready for forwarding a DV Box with payload, storing PendingMessage in ring buffer.\n");
9619
9621 {
9623
9624 GNUNET_free (pm_old);
9625 }
9628 {
9631 }
9632 else
9634
9636 "%u items stored in DV ring buffer\n",
9639 }
9640 }
9641}
9642
9643
9649static void
9650free_backtalker (struct Backtalker *b)
9651{
9652 if (NULL != b->get)
9653 {
9655 b->get = NULL;
9656 GNUNET_assert (NULL != b->cmc);
9658 b->cmc = NULL;
9659 }
9660 if (NULL != b->task)
9661 {
9663 b->task = NULL;
9664 }
9665 if (NULL != b->sc)
9666 {
9668 "store cancel\n");
9670 b->sc = NULL;
9671 }
9673 "Removing backtalker for %s\n",
9674 GNUNET_i2s (&b->pid));
9676 GNUNET_YES ==
9678 GNUNET_free (b);
9679}
9680
9681
9690static int
9691free_backtalker_cb (void *cls,
9692 const struct GNUNET_PeerIdentity *pid,
9693 void *value)
9694{
9695 struct Backtalker *b = value;
9696
9697 (void) cls;
9698 (void) pid;
9699 free_backtalker (b);
9700 return GNUNET_OK;
9701}
9702
9703
9709static void
9710backtalker_timeout_cb (void *cls)
9711{
9712 struct Backtalker *b = cls;
9713
9715 "backtalker timeout.\n");
9716 b->task = NULL;
9718 {
9720 return;
9721 }
9722 /* A monotime store may well still be in flight -- @e timeout is about how
9723 long the *peer* has been quiet, and says nothing about PEERSTORE. This
9724 used to `GNUNET_assert (NULL == b->sc)', which aborted the service in
9725 exactly that case. #free_backtalker() cancels the store. */
9726 free_backtalker (b);
9727}
9728
9729
9738static void
9739backtalker_monotime_cb (void *cls,
9740 const struct GNUNET_PEERSTORE_Record *record,
9741 const char *emsg)
9742{
9743 struct Backtalker *b = cls;
9744 struct GNUNET_TIME_AbsoluteNBO *mtbe;
9745 struct GNUNET_TIME_Absolute mt;
9746
9747 (void) emsg;
9748 if (NULL == record)
9749 {
9750 struct CommunicatorMessageContext *cmc;
9751
9752 /* we're done with #backtalker_monotime_cb() invocations,
9753 continue normal processing */
9754 b->get = NULL;
9755 GNUNET_assert (NULL != b->cmc);
9756 /* Take @e cmc out of @a b *before* dispatching: the dispatch runs
9757 arbitrary message handling, and writing `b->cmc = NULL' afterwards
9758 is a write to freed memory should anything on that path have
9759 released @a b. #free_backtalker() keys its "must finish the parked
9760 cmc" decision off @e get, which is already NULL here, so clearing
9761 @e cmc early cannot lose the message either. */
9762 cmc = b->cmc;
9763 b->cmc = NULL;
9764 cmc->mh = (const struct GNUNET_MessageHeader *) &b[1];
9765 if (0 != b->body_size)
9767 else
9768 finish_cmc_handling (cmc);
9769 return;
9770 }
9771 if (sizeof(*mtbe) != record->value_size)
9772 {
9774 GNUNET_break (0);
9775 return;
9776 }
9777 mtbe = record->value;
9778 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
9779 if (mt.abs_value_us > b->monotonic_time.abs_value_us)
9780 {
9782 "Backtalker message from %s dropped, monotime in the past\n",
9783 GNUNET_i2s (&b->pid));
9785 GST_stats,
9786 "# Backchannel messages dropped: monotonic time not increasing",
9787 1,
9788 GNUNET_NO);
9789 b->monotonic_time = mt;
9790 /* Setting body_size to 0 prevents call to #forward_backchannel_payload()
9791 */
9792 b->body_size = 0;
9793 }
9795}
9796
9797
9805static void
9806backtalker_monotime_store_cb (void *cls, int success)
9807{
9808 struct Backtalker *b = cls;
9809
9810 if (GNUNET_OK != success)
9811 {
9813 "Failed to store backtalker's monotonic time in PEERSTORE!\n");
9814 }
9815 b->sc = NULL;
9816 /* @e task is armed for the whole life of @a b -- #backtalker_timeout_cb()
9817 re-arms itself whenever @e timeout has moved forward -- so there is
9818 nothing to do here beyond releasing the store. It used to cancel and
9819 re-add the task, which is what made the task's existence depend on this
9820 callback ever running. */
9821 GNUNET_assert (NULL != b->task);
9822}
9823
9824
9830static void
9832{
9833 struct GNUNET_TIME_AbsoluteNBO mtbe;
9834
9835 /* At most one store may be outstanding. The value we are about to write
9836 supersedes whatever the previous one carried, and leaving the old
9837 context alive means its completion clears @e sc while the newer store
9838 is still in flight -- after which the next update sees a NULL @e sc and
9839 starts a third one. Cancelling is also what keeps @e sc from being
9840 silently overwritten and leaked.
9841
9842 Note what this must NOT do: touch @e task. That task is the only thing
9843 that ever releases a `struct CommunicatorMessageContext' parked in
9844 @e cmc, and cancelling it here left its re-arming up to
9845 #backtalker_monotime_store_cb() -- i.e. up to PEERSTORE answering. A
9846 lost store completion then stalled the parked communicator client for
9847 the life of the process. #backtalker_timeout_cb() already re-arms
9848 itself against the current @e timeout, so the task needs no help. */
9849 if (NULL != b->sc)
9850 {
9852 "Superseding in-flight backtalker monotime store %p\n",
9853 b->sc);
9855 b->sc = NULL;
9856 }
9858 b->sc =
9860 "transport",
9861 &b->pid,
9863 &mtbe,
9864 sizeof(mtbe),
9868 b);
9869}
9870
9871
9880static void
9882 const struct TransportDVBoxMessage *dvb,
9883 const struct GNUNET_ShortHashCode *km)
9884{
9885 const unsigned char *hdr;
9886 size_t hdr_len;
9888
9889 key = (struct GNUNET_CRYPTO_AeadSecretKey*) km;
9890 /* We are the ultimate target, so #handle_dv_box() has established that no
9891 hop entries are left: the ciphertext directly follows the header, and
9892 its length is what we actually received. Deriving it from orig_size
9893 and total_hops instead would only be equivalent if every forwarder
9894 accounted its skipped hops exactly. */
9895 hdr = (const unsigned char *) &dvb[1];
9896 {
9897 uint16_t size = ntohs (dvb->header.size);
9898
9899 if (size < sizeof(*dvb)
9900 + sizeof(struct TransportDVBoxPayloadP)
9901 + sizeof(struct GNUNET_MessageHeader))
9902 {
9903 GNUNET_break_op (0);
9904 finish_cmc_handling (cmc);
9905 return;
9906 }
9907 hdr_len = size - sizeof(*dvb);
9908 }
9909
9910 /* begin actual decryption */
9911 {
9912 struct Backtalker *b;
9913 struct GNUNET_TIME_Absolute monotime;
9914 struct TransportDVBoxPayloadP *ppay;
9915 unsigned char pt[hdr_len + sizeof *ppay] GNUNET_ALIGN;
9916 unsigned char *body;
9917 const struct GNUNET_MessageHeader *mh;
9918
9919 ppay = (struct TransportDVBoxPayloadP *) pt;
9920 body = &pt[sizeof *ppay];
9921 GNUNET_assert (hdr_len >=
9922 sizeof(*ppay) + sizeof(struct GNUNET_MessageHeader));
9923 if (GNUNET_OK != GNUNET_CRYPTO_aead_decrypt (hdr_len,
9924 hdr,
9925 0,
9926 NULL,
9927 key,
9928 &dvb->iv,
9929 &dvb->mac,
9930 pt))
9931 {
9933 "Error decrypting DV payload header\n");
9934 GNUNET_break_op (0);
9935 finish_cmc_handling (cmc);
9936 return;
9937 }
9938 mh = (const struct GNUNET_MessageHeader *) body;
9939 /* NOTE: this used to compare against `sizeof (body)', i.e. the size of
9940 a pointer, which meant only 8-byte payloads were ever accepted. */
9941 if (ntohs (mh->size) != hdr_len - sizeof(*ppay))
9942 {
9943 GNUNET_break_op (0);
9944 finish_cmc_handling (cmc);
9945 return;
9946 }
9947 /* need to prevent box-in-a-box (and DV_LEARN) so check inbox type! */
9948 switch (ntohs (mh->type))
9949 {
9951 GNUNET_break_op (0);
9952 finish_cmc_handling (cmc);
9953 return;
9954
9956 GNUNET_break_op (0);
9957 finish_cmc_handling (cmc);
9958 return;
9959
9960 default:
9961 /* permitted, continue */
9962 break;
9963 }
9964 monotime = GNUNET_TIME_absolute_ntoh (ppay->monotonic_time);
9966 "Decrypted backtalk from %s\n",
9967 GNUNET_i2s (&ppay->sender));
9969 &ppay->sender);
9970 if ((NULL != b) && (monotime.abs_value_us < b->monotonic_time.abs_value_us))
9971 {
9973 GST_stats,
9974 "# Backchannel messages dropped: monotonic time not increasing",
9975 1,
9976 GNUNET_NO);
9977 finish_cmc_handling (cmc);
9978 return;
9979 }
9980 if ((NULL == b) ||
9981 (0 != GNUNET_memcmp (&b->last_ephemeral, &dvb->ephemeral_key)))
9982 {
9983 /* Check signature */
9984 const struct GNUNET_PeerIdentity *my_identity;
9985 struct EphemeralConfirmationPS ec;
9986
9989
9990 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
9991 ec.target = *my_identity;
9992 ec.ephemeral_key = dvb->ephemeral_key;
9993 ec.purpose.size = htonl (sizeof(ec));
9994 ec.sender_monotonic_time = ppay->monotonic_time;
9995 if (
9996 GNUNET_OK !=
9999 &ec,
10000 &ppay->sender_sig,
10001 &ppay->sender.public_key))
10002 {
10003 /* Signature invalid, discard! */
10004 GNUNET_break_op (0);
10005 finish_cmc_handling (cmc);
10006 return;
10007 }
10008 }
10009 /* Update sender, we now know the real origin! */
10011 "DVBox received for me from %s via %s\n",
10012 GNUNET_i2s2 (&ppay->sender),
10013 GNUNET_i2s (&cmc->im.sender));
10014 cmc->im.sender = ppay->sender;
10015
10016 if (NULL != b)
10017 {
10018 /* update key cache and mono time */
10019 b->last_ephemeral = dvb->ephemeral_key;
10020 b->monotonic_time = monotime;
10022 b->timeout =
10024 cmc->mh = mh;
10026 return;
10027 }
10028 /* setup data structure to cache signature AND check
10029 monotonic time with PEERSTORE before forwarding backchannel payload */
10030 b = GNUNET_malloc (sizeof(struct Backtalker) + (hdr_len - sizeof(*ppay)));
10031 b->pid = ppay->sender;
10032 b->body_size = hdr_len - sizeof(*ppay);
10033 memcpy (&b[1], body, hdr_len - sizeof(*ppay));
10037 &b->pid,
10038 b,
10040 b->monotonic_time = monotime; /* NOTE: to be checked still! */
10041 b->cmc = cmc;
10042 b->timeout =
10045 b->get =
10047 "transport",
10048 &b->pid,
10051 b);
10052 } /* end actual decryption */
10053}
10054
10055
10063static void
10064handle_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
10065{
10066 struct CommunicatorMessageContext *cmc = cls;
10067 uint16_t size = ntohs (dvb->header.size) - sizeof(*dvb);
10068 uint16_t num_hops = ntohs (dvb->num_hops);
10069 const struct GNUNET_PeerIdentity *hops =
10070 (const struct GNUNET_PeerIdentity *) &dvb[1];
10071 const char *enc_payload = (const char *) &hops[num_hops];
10072 uint16_t enc_payload_size =
10073 size - (num_hops * sizeof(struct GNUNET_PeerIdentity));
10074 const struct GNUNET_PeerIdentity *my_identity;
10075
10078
10079 if (GNUNET_EXTRA_LOGGING > 0)
10080 {
10081 char *path;
10082
10084 for (unsigned int i = 0; i < num_hops; i++)
10085 {
10086 char *tmp;
10087
10088 GNUNET_asprintf (&tmp, "%s->%s", path, GNUNET_i2s (&hops[i]));
10089 GNUNET_free (path);
10090 path = tmp;
10091 }
10093 "Received DVBox with remaining path %s\n",
10094 path);
10095 GNUNET_free (path);
10096 }
10097
10098 if (num_hops > 0)
10099 {
10100 /* We're trying from the end of the hops array, as we may be
10101 able to find a shortcut unknown to the origin that way */
10102 for (int i = num_hops - 1; i >= 0; i--)
10103 {
10104 struct Neighbour *n;
10105
10106 if (0 == GNUNET_memcmp (&hops[i], my_identity))
10107 {
10108 GNUNET_break_op (0);
10109 finish_cmc_handling (cmc);
10110 return;
10111 }
10112 n = lookup_neighbour (&hops[i]);
10113 if (NULL == n)
10114 continue;
10116 "Skipping %u/%u hops ahead while routing DV Box\n",
10117 i,
10118 num_hops);
10119
10120 forward_dv_box (n,
10121 (struct TransportDVBoxMessage *) dvb,
10122 /* we strip i+1 entries, and the receiver reconstructs
10123 the ciphertext offset from total_hops */
10124 ntohs (dvb->total_hops) + i + 1,
10125 num_hops - i - 1, /* number of hops left */
10126 &hops[i + 1], /* remaining hops */
10127 enc_payload,
10128 enc_payload_size);
10130 "# DV hops skipped routing boxes",
10131 i,
10132 GNUNET_NO);
10134 "# DV boxes routed (total)",
10135 1,
10136 GNUNET_NO);
10137 finish_cmc_handling (cmc);
10138 return;
10139 }
10140 /* Woopsie, next hop not in neighbours, drop! */
10142 "# DV Boxes dropped: next hop unknown",
10143 1,
10144 GNUNET_NO);
10145 finish_cmc_handling (cmc);
10146 return;
10147 }
10148 /* We are the target. Unbox and handle message. */
10150 "# DV boxes opened (ultimate target)",
10151 1,
10152 GNUNET_NO);
10153 cmc->total_hops = ntohs (dvb->total_hops);
10154
10155 {
10156 // DH key derivation with received DV, could be garbage.
10158 struct GNUNET_ShortHashCode km;
10159
10161 if ( (NULL == my_private_key) ||
10162 (GNUNET_OK !=
10164 &dvb->ephemeral_key,
10165 &km)) )
10166 {
10167 GNUNET_break_op (0);
10168 finish_cmc_handling (cmc);
10169 return;
10170 }
10171 decaps_dv_box_cont (cmc,
10172 dvb,
10173 &km);
10174 }
10175}
10176
10177
10185static int
10186check_incoming_msg (void *cls,
10187 const struct GNUNET_TRANSPORT_IncomingMessage *im)
10188{
10189 struct TransportClient *tc = cls;
10190
10191 if (CT_COMMUNICATOR != tc->type)
10192 {
10193 GNUNET_break (0);
10194 return GNUNET_SYSERR;
10195 }
10197 return GNUNET_OK;
10198}
10199
10200
10205{
10209 const char *address;
10210
10214 struct ValidationState *vs;
10215};
10216
10217
10227static int
10228check_known_address (void *cls,
10229 const struct GNUNET_PeerIdentity *pid,
10230 void *value)
10231{
10232 struct CheckKnownAddressContext *ckac = cls;
10233 struct ValidationState *vs = value;
10234
10235 (void) pid;
10236 if (0 != strcmp (vs->address, ckac->address))
10237 return GNUNET_OK;
10238 ckac->vs = vs;
10239 return GNUNET_NO;
10240}
10241
10242
10248static void
10249validation_start_cb (void *cls);
10250
10251
10259static void
10261 struct GNUNET_TIME_Absolute new_time)
10262{
10264
10265 /* NOTE: "be lazy" must not apply while #validation_task is unset. Our
10266 only caller that can leave it unset is #validation_start_cb(), which
10267 NULLs it on entry and relies on us to arm it again -- and nothing else
10268 ever does. Returning early there stops address (re)validation and the
10269 #suggest_to_connect() retries that go with it for *every* peer, for
10270 good. */
10271 if ((new_time.abs_value_us == vs->next_challenge.abs_value_us) &&
10272 (NULL != validation_task) &&
10273 (NULL != vs->hn))
10274 return; /* be lazy */
10275 vs->next_challenge = new_time;
10276 if (NULL == vs->hn)
10277 vs->hn =
10279 else
10282 (NULL != validation_task))
10283 return;
10284 if (NULL != validation_task)
10286 /* randomize a bit */
10289 new_time = GNUNET_TIME_absolute_add (new_time, delta);
10292}
10293
10294
10305static enum GNUNET_GenericReturnValue
10306revalidate_now_cb (void *cls,
10307 const struct GNUNET_PeerIdentity *pid,
10308 void *value)
10309{
10310 struct ValidationState *vs = value;
10311 const struct GNUNET_TIME_Absolute now =
10313
10314 (void) cls;
10315 (void) pid;
10316 /* What #start_address_validation() does for an address it hears about
10317 again, but without needing the address string. */
10318 vs->challenge_backoff =
10321 vs->challenge_backoff,
10322 2));
10323 if (GNUNET_TIME_absolute_cmp (vs->first_challenge_use, >, now))
10324 vs->first_challenge_use = now;
10327 vs->challenge_backoff));
10328 return GNUNET_OK;
10329}
10330
10331
10338static void
10340 const char *address)
10341{
10342 struct GNUNET_TIME_Absolute now;
10343 struct ValidationState *vs;
10344 struct CheckKnownAddressContext ckac = { .address = address, .vs = NULL };
10345
10347 pid,
10349 &ckac);
10351 if (NULL != (vs = ckac.vs))
10352 {
10353 const struct VirtualLink *vl = lookup_virtual_link (pid);
10354
10355 /* Speed up retrying the validation if 'vs' is not currently valid, or if
10356 * we have no confirmed virtual link to @a pid. In the latter case the
10357 * address may still be well inside its validity window -- but the link is
10358 * down, and #handle_validation_response() is the only thing that can
10359 * rebuild it and tell CORE about the peer again. Without this we would
10360 * wait for @e revalidation_task, which does not fire until
10361 * #ADDRESS_VALIDATION_LIFETIME is nearly over. */
10362 if ((vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us) ||
10363 (NULL == vl) ||
10364 (GNUNET_NO == vl->confirmed))
10365 {
10366 /* reduce backoff as we got a fresh advertisement */
10367 vs->challenge_backoff =
10370 vs->challenge_backoff,
10371 2));
10372 /* A successful validation parks @e first_challenge_use just before
10373 @e validated_until, so that the *next* challenge is not used before
10374 the current validation is about to expire. #validation_start_cb()
10375 refuses to run while that time is still in the future, so pulling
10376 @e next_challenge in without this would only make it reschedule
10377 itself four hours out. The challenge has not been used yet, so
10378 moving the start of its window to now stays truthful -- it is what
10379 the fresh-@a vs path below does as well. */
10380 if (GNUNET_TIME_absolute_cmp (vs->first_challenge_use, >, now))
10381 vs->first_challenge_use = now;
10384 vs->challenge_backoff));
10385 }
10386 return;
10387 }
10388 vs = GNUNET_new (struct ValidationState);
10389 vs->pid = *pid;
10390 vs->valid_until =
10392 vs->first_challenge_use = now;
10393 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
10394 GNUNET_CRYPTO_random_block (&vs->challenge,
10395 sizeof(vs->challenge));
10396 vs->address = GNUNET_strdup (address);
10397 {
10398 /* The peer identity MUST be part of @e hc: two peers behind the same NAT
10399 advertise the very same address string (`PROTO-IP:0'), and with an
10400 address-only key the second one's #revalidation_map entry would be
10401 rejected as a duplicate of the first one's. */
10402 struct GNUNET_HashContext *hsh;
10403
10405 GNUNET_CRYPTO_hash_context_read (hsh, vs->address, strlen (vs->address));
10406 GNUNET_CRYPTO_hash_context_read (hsh, &vs->pid, sizeof(vs->pid));
10407 GNUNET_CRYPTO_hash_context_finish (hsh, &vs->hc);
10408 }
10410 "Starting address validation `%s' of peer %s using challenge %s\n",
10411 address,
10412 GNUNET_i2s (pid),
10413 GNUNET_sh2s (&vs->challenge.value));
10417 &vs->pid,
10418 vs,
10421}
10422
10423
10424static struct Queue *
10425find_queue (const struct GNUNET_PeerIdentity *pid, const char *address);
10426
10427
10428static void
10429suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address);
10430
10431
10432static void
10433hello_for_incoming_cb (void *cls,
10434 const struct GNUNET_PeerIdentity *pid,
10435 const char *uri)
10436{
10437 struct Queue *q;
10438 int pfx_len;
10439 const char *eou;
10440 char *address;
10441 (void) cls;
10442
10443 eou = strstr (uri,
10444 "://");
10445 pfx_len = eou - uri;
10446 eou += 3;
10448 "%.*s-%s",
10449 pfx_len,
10450 uri,
10451 eou);
10452
10454 "helo for client %s\n",
10455 address);
10456 q = find_queue (pid, address);
10457 if (NULL == q)
10458 {
10460 }
10461 else
10464}
10465
10466
10489static const struct GNUNET_MessageHeader *
10491{
10492 const struct GNUNET_MessageHeader *hello;
10493
10494 if ((NULL == record) ||
10495 (NULL == record->value) ||
10496 (record->value_size < sizeof(*hello)))
10497 {
10498 GNUNET_break_op (0);
10499 return NULL;
10500 }
10501 hello = record->value;
10502 if (ntohs (hello->size) > record->value_size)
10503 {
10504 GNUNET_break_op (0);
10505 return NULL;
10506 }
10507 return hello;
10508}
10509
10510
10518static void
10519handle_hello_for_incoming (void *cls,
10520 const struct GNUNET_PEERSTORE_Record *record,
10521 const char *emsg)
10522{
10523 struct IncomingRequest *ir = cls;
10525 const struct GNUNET_MessageHeader *hello;
10526 const struct GNUNET_PeerIdentity *my_identity;
10527
10528 if (NULL != emsg)
10529 {
10531 "Got failure from PEERSTORE: %s\n",
10532 emsg);
10534 return;
10535 }
10536 if (NULL == record)
10537 {
10538 GNUNET_break (0);
10540 return;
10541 }
10542 hello = hello_from_record (record);
10543 if (NULL == hello)
10544 {
10545 /* MUST still ask for the next record: a bad one is not a reason to
10546 stall this monitor forever. */
10548 return;
10549 }
10551 if (NULL == my_identity)
10552 {
10554 return;
10555 }
10556 if (0 == GNUNET_memcmp (&record->peer, my_identity))
10557 {
10559 return;
10560 }
10561 parser = GNUNET_HELLO_parser_from_msg (hello, &record->peer);
10562 if (NULL != parser)
10563 {
10566 NULL);
10567 GNUNET_HELLO_parser_free (parser);
10568 }
10569 /* MUST ask for the next record, or this monitor stalls after one HELLO */
10571}
10572
10573
10574static void
10576{
10578 "Error in PEERSTORE monitoring\n");
10579}
10580
10581
10582static void
10584{
10586 "Done with initial PEERSTORE iteration during monitoring\n");
10587}
10588
10589
10598static void
10599try_to_bring_link_up (const struct GNUNET_PeerIdentity *pid)
10600{
10601 struct Neighbour *n;
10602 struct IncomingRequest *ir;
10603
10604 if (GNUNET_YES == in_shutdown)
10605 return;
10606 /* (1) Addresses we already track. These outlive the queues, which is the
10607 point: once a link is down the queue that carried it is usually gone,
10608 so there is no address string left for #start_address_validation(). */
10610 pid,
10612 NULL);
10613 /* (2) Queues we still have; may cover an address with no validation state
10614 yet. After (1), because it may insert into #validation_map. */
10615 n = lookup_neighbour (pid);
10616 if (NULL != n)
10617 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
10618 start_address_validation (pid, q->address);
10619 /* (3) Failing that, look for an address in PEERSTORE. */
10620 for (ir = ir_head; NULL != ir; ir = ir->next)
10621 {
10622 if (0 == GNUNET_memcmp (&ir->pid, pid))
10623 return; /* we are already trying */
10624 }
10625 ir = GNUNET_new (struct IncomingRequest);
10626 ir->pid = *pid;
10629 GNUNET_YES,
10630 "peerstore",
10631 NULL,
10634 NULL,
10636 NULL,
10638 ir);
10639 ir_total++;
10640 /* Bound attempts we do in parallel here, might otherwise get excessive.
10641 Drop the OLDEST request: #ir_head is the one we just inserted, so
10642 freeing that would immediately undo the work above. */
10645}
10646
10647
10655static void
10658{
10659 struct VirtualLink *vl;
10660 struct Neighbour *n;
10661 struct GNUNET_PeerIdentity sender;
10662
10663 sender = cmc->im.sender;
10664 vl = lookup_virtual_link (&sender);
10665 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
10666 {
10667 // route_control_message_without_fc (&cmc->im.sender,
10669 &tvr.header,
10671 }
10672 else
10673 {
10674 /* Use route via neighbour */
10675 n = lookup_neighbour (&sender);
10676 if (NULL != n)
10677 route_via_neighbour (n, &tvr.header,
10680 }
10681
10682 finish_cmc_handling (cmc);
10683 /* An *unconfirmed* link is not a link -- it carries nothing, and CORE has
10684 never been told about the peer. Bailing out on one merely because it
10685 exists is what deadlocks a pair of peers into permanent one-way state:
10686 the challenger validated us, so it believes the connection is up and
10687 starts sending us FLOW_CONTROL; #handle_flow_control() answers an
10688 unknown sender by allocating exactly such an unconfirmed link; and from
10689 then on every challenge it retransmits lands here, gets a response --
10690 which keeps *its* side confirmed and its RTT healthy -- and returns
10691 without ever validating an address of its own. The unconfirmed link
10692 reaps itself after #UNCONFIRMED_LINK_TIMEOUT, but the next FLOW_CONTROL
10693 recreates it, and the peer keeps sending those precisely because it
10694 thinks it is connected. Nothing ever breaks the tie, so CORE on this
10695 side never hears about the peer and never answers its handshake.
10696 Only a confirmed link means there is nothing left to do. */
10697 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
10698 return;
10699
10700 /* For us, the link is still down, but we need bi-directional
10701 connections (for flow-control and for this to be useful for
10702 CORE), so we must try to bring the link up! */
10703 try_to_bring_link_up (&sender);
10704}
10705
10706
10715static void
10717 void *cls,
10718 const struct TransportValidationChallengeMessage *tvc)
10719{
10720 struct CommunicatorMessageContext *cmc = cls;
10721 struct TransportValidationResponseMessage tvr = { 0 };
10722 struct GNUNET_TIME_RelativeNBO validity_duration;
10723
10724 /* DV-routed messages are not allowed for validation challenges */
10725 if (cmc->total_hops > 0)
10726 {
10727 GNUNET_break_op (0);
10728 finish_cmc_handling (cmc);
10729 return;
10730 }
10731 validity_duration = cmc->im.expected_address_validity;
10733 "Received address validation challenge %s\n",
10734 GNUNET_sh2s (&tvc->challenge.value));
10735 /* If we have a virtual link, we use this mechanism to signal the
10736 size of the flow control window, and to allow the sender
10737 to ask for increases. If for us the virtual link is still down,
10738 we will always give a window size of zero. */
10739 tvr.header.type =
10741 tvr.header.size = htons (sizeof(tvr));
10742 tvr.reserved = htonl (0);
10743 tvr.challenge = tvc->challenge;
10744 tvr.origin_time = tvc->sender_time;
10745 tvr.validity_duration = validity_duration;
10746 {
10747 /* create signature */
10748 struct TransportValidationPS tvp = {
10750 .purpose.size = htonl (sizeof(tvp)),
10751 .validity_duration = validity_duration,
10752 .challenge = tvc->challenge
10753 };
10754 if (GNUNET_OK != sign_by_my_identity (&tvp.purpose, &tvr.signature))
10755 {
10756 /* Not answering costs us this address validation; leaving @a cmc
10757 behind would cost us the communicator. */
10758 finish_cmc_handling (cmc);
10759 return;
10760 }
10761 }
10762 send_t_validation_response (cmc, tvr);
10763}
10764
10765
10770{
10775
10779 struct ValidationState *vs;
10780};
10781
10782
10792static int
10793check_known_challenge (void *cls,
10794 const struct GNUNET_PeerIdentity *pid,
10795 void *value)
10796{
10797 struct CheckKnownChallengeContext *ckac = cls;
10798 struct ValidationState *vs = value;
10799
10800 (void) pid;
10801 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
10802 return GNUNET_OK;
10803 ckac->vs = vs;
10804 return GNUNET_NO;
10805}
10806
10807
10815static void
10816peerstore_store_validation_cb (void *cls, int success)
10817{
10818 struct ValidationState *vs = cls;
10819
10820 vs->sc = NULL;
10821 if (GNUNET_YES == success)
10822 return;
10824 "# Peerstore failed to store foreign address",
10825 1,
10826 GNUNET_NO);
10827}
10828
10829
10837static struct Queue *
10838find_queue (const struct GNUNET_PeerIdentity *pid, const char *address)
10839{
10840 struct Neighbour *n;
10841
10842 n = lookup_neighbour (pid);
10843 if (NULL == n)
10844 return NULL;
10845 for (struct Queue *pos = n->queue_head; NULL != pos;
10846 pos = pos->next_neighbour)
10847 {
10848 if (0 == strcmp (pos->address, address))
10849 return pos;
10850 }
10851 return NULL;
10852}
10853
10854
10870static struct Queue *
10871find_queue_by_ip (const struct GNUNET_PeerIdentity *pid, const char *address)
10872{
10873 struct Neighbour *n;
10874 struct Queue *ret = NULL;
10875 char *prefix;
10876 char *ip;
10877
10878 n = lookup_neighbour (pid);
10879 if (NULL == n)
10880 return NULL;
10883 if ((NULL == prefix) || (NULL == ip))
10884 {
10886 GNUNET_free (ip);
10887 return NULL;
10888 }
10889 for (struct Queue *pos = n->queue_head; NULL != pos;
10890 pos = pos->next_neighbour)
10891 {
10892 char *q_prefix = GNUNET_HELLO_address_to_prefix (pos->address);
10893 char *q_ip = get_address_without_port (pos->address);
10894
10895 /* Same communicator and same host -- only the port may differ. */
10896 if ((NULL != q_prefix) && (NULL != q_ip) &&
10897 (0 == strcmp (q_prefix, prefix)) &&
10898 (0 == strcmp (q_ip, ip)))
10899 ret = pos;
10900 GNUNET_free (q_prefix);
10901 GNUNET_free (q_ip);
10902 if (NULL != ret)
10903 break;
10904 }
10906 GNUNET_free (ip);
10907 return ret;
10908}
10909
10910
10911static void
10913
10914static void
10915revalidation_start_cb (void *cls)
10916{
10917 struct ValidationState *vs = cls;
10918 struct Queue *q;
10919 struct GNUNET_TIME_Absolute now;
10920
10921 vs->revalidation_task = NULL;
10922 q = find_queue (&vs->pid, vs->address);
10923 if (NULL == q)
10924 {
10925 now = GNUNET_TIME_absolute_get ();
10926 vs->awaiting_queue = GNUNET_YES;
10927 suggest_to_connect (&vs->pid, vs->address);
10929 }
10930 else
10932}
10933
10934
10935static enum GNUNET_GenericReturnValue
10937 void *cls,
10938 const struct GNUNET_HashCode *key,
10939 void *value)
10940{
10941 (void) cls;
10943 "Key in revalidate map %s \n",
10944 GNUNET_h2s (key));
10945 return GNUNET_YES;
10946}
10947
10948
10957static void
10959 void *cls,
10960 const struct TransportValidationResponseMessage *tvr)
10961{
10962 struct CommunicatorMessageContext *cmc = cls;
10963 struct ValidationState *vs;
10964 struct CheckKnownChallengeContext ckac = { .challenge = &tvr->challenge,
10965 .vs = NULL};
10966 struct GNUNET_TIME_Absolute origin_time;
10967 struct Queue *q;
10968 struct Neighbour *n;
10969 struct VirtualLink *vl;
10971 GST_cfg);
10972
10973 /* check this is one of our challenges */
10975 &cmc->im.sender,
10977 &ckac);
10978 if (NULL == (vs = ckac.vs))
10979 {
10980 /* This can happen simply if we 'forgot' the challenge by now,
10981 i.e. because we received the validation response twice */
10983 "# Validations dropped, challenge unknown",
10984 1,
10985 GNUNET_NO);
10987 "Validation response %s dropped, challenge unknown\n",
10988 GNUNET_sh2s (&tvr->challenge.value));
10989 finish_cmc_handling (cmc);
10990 return;
10991 }
10992
10993 /* sanity check on origin time */
10994 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
10995 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
10996 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
10997 {
10999 "Diff first use %" PRIu64 " and last use %" PRIu64 "\n",
11000 vs->first_challenge_use.abs_value_us - origin_time.abs_value_us,
11001 origin_time.abs_value_us - vs->last_challenge_use.abs_value_us);
11002 GNUNET_break_op (0);
11003 finish_cmc_handling (cmc);
11004 return;
11005 }
11006
11007 {
11008 /* check signature */
11009 struct TransportValidationPS tvp = {
11011 .purpose.size = htonl (sizeof(tvp)),
11012 .validity_duration = tvr->validity_duration,
11013 .challenge = tvr->challenge
11014 };
11015
11016 if (
11017 GNUNET_OK !=
11019 &tvp,
11020 &tvr->signature,
11021 &cmc->im.sender.public_key))
11022 {
11023 GNUNET_break_op (0);
11024 finish_cmc_handling (cmc);
11025 return;
11026 }
11027 }
11028
11029 /* validity is capped by our willingness to keep track of the
11030 validation entry and the maximum the other peer allows */
11033 tvr->validity_duration),
11035 vs->validated_until =
11039 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
11040 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
11041 GNUNET_CRYPTO_random_block (&vs->challenge,
11042 sizeof(vs->challenge));
11043 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
11044 vs->validated_until,
11045 GNUNET_TIME_relative_multiply (vs->validation_rtt,
11047 if (GNUNET_TIME_absolute_cmp (vs->first_challenge_use, <, now))
11048 {
11050 "First challenge use is now %" PRIu64 " %s \n",
11051 vs->first_challenge_use.abs_value_us,
11052 GNUNET_sh2s (&vs->challenge.value));
11053 vs->first_challenge_use = now;
11054 }
11055 else
11057 "First challenge use is later %" PRIu64 " %s \n",
11058 vs->first_challenge_use.abs_value_us,
11059 GNUNET_sh2s (&vs->challenge.value));
11060 vs->last_challenge_use =
11061 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
11062 update_next_challenge_time (vs, vs->first_challenge_use);
11064 "Validation response %s from %s accepted, address valid until %s\n",
11065 GNUNET_sh2s (&tvr->challenge.value),
11066 GNUNET_i2s (&cmc->im.sender),
11068 /*memcpy (&hkey,
11069 &hc,
11070 sizeof (hkey));*/
11072 "Key %s for address %s map size %u contains %u\n",
11073 GNUNET_h2s (&vs->hc),
11074 vs->address,
11077 &vs->hc));
11078 /* NOTE: @e hc hashes the address only, so two `struct ValidationState's
11079 for different peers can collide here. That must not abort us. */
11080 if (GNUNET_YES !=
11083 &vs->hc,
11084 vs,
11087 "Address `%s' already tracked for revalidation\n",
11088 vs->address);
11091 NULL);
11092 vs->revalidation_task =
11097 "transport",
11098 &cmc->im.sender,
11100 vs->address,
11101 strlen (vs->address) + 1,
11102 vs->valid_until,
11105 vs);
11106 finish_cmc_handling (cmc);
11107
11108 /* Finally, we now possibly have a confirmed (!) working queue,
11109 update queue status (if queue still is around) */
11110 q = find_queue (&vs->pid, vs->address);
11111 if (NULL == q)
11112 {
11113 /* The challenge may have gone out on a queue whose address is not
11114 literally @e address: #check_validation_request_pending() matches on
11115 the IP alone, precisely so that a validation waiting for the NAT
11116 address `PROTO-IP:0' can be answered over the queue that the peer
11117 actually established from `PROTO-IP:port'. Insisting on an exact
11118 match here would silently discard that (successful!) validation and
11119 never bring the virtual link up. */
11120 q = find_queue_by_ip (&vs->pid, vs->address);
11121 }
11122 if (NULL == q)
11123 {
11125 "# Queues lost at time of successful validation",
11126 1,
11127 GNUNET_NO);
11128 return;
11129 }
11130 q->validated_until = vs->validated_until;
11131 q->pd.aged_rtt = vs->validation_rtt;
11132 n = q->neighbour;
11133 vl = lookup_virtual_link (&vs->pid);
11134 if (NULL == vl)
11135 {
11136 vl = GNUNET_new (struct VirtualLink);
11138 "Creating new virtual link %p to %s using direct neighbour!\n",
11139 vl,
11140 GNUNET_i2s (&vs->pid));
11141 vl->burst_addr = NULL;
11142 vl->confirmed = GNUNET_YES;
11143 vl->message_uuid_ctr =
11144 GNUNET_CRYPTO_random_u64 (UINT64_MAX);
11145 vl->target = n->pid;
11151 links,
11152 &vl->target,
11153 vl,
11155 vl->n = n;
11156 n->vl = vl;
11157 q->idle = GNUNET_YES;
11158 vl->visibility_task =
11159 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
11161 /* We lacked a confirmed connection to the target
11162 before, so tell CORE about it (finally!) */
11165 }
11166 else
11167 {
11168 /* Link was already up, remember n is also now available and we are done */
11169 if (NULL == vl->n)
11170 {
11171 vl->n = n;
11172 n->vl = vl;
11173 if (GNUNET_YES == vl->confirmed)
11175 "Virtual link to %s could now also use direct neighbour!\n",
11176 GNUNET_i2s (&vs->pid));
11177 }
11178 else
11179 {
11180 GNUNET_assert (n == vl->n);
11181 }
11182 if (GNUNET_NO == vl->confirmed)
11183 {
11184 vl->confirmed = GNUNET_YES;
11185 q->idle = GNUNET_YES;
11186 vl->visibility_task =
11187 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
11189 /* We lacked a confirmed connection to the target
11190 before, so tell CORE about it (finally!) */
11193 }
11194 }
11195}
11196
11197
11203static void
11204handle_incoming_msg (void *cls,
11205 const struct GNUNET_TRANSPORT_IncomingMessage *im)
11206{
11207 struct TransportClient *tc = cls;
11208 struct Neighbour *n;
11209 struct CommunicatorMessageContext *cmc =
11211
11212 cmc->tc = tc;
11213 cmc->im = *im;
11215 "Received message with size %u and flow control id %" PRIu64
11216 " via communicator from peer %s\n",
11217 ntohs (im->header.size),
11218 im->fc_id,
11219 GNUNET_i2s (&im->sender));
11220 cmc->im.neighbour_sender = cmc->im.sender;
11221 /* A communicator got this straight from @a im->sender, so the queues to
11222 that neighbour demonstrably still work. This is what #check_link_down()
11223 uses to bound how long a communicator that stopped working (without
11224 telling us) can keep a virtual link -- and CORE -- fooled. */
11225 if (NULL != (n = lookup_neighbour (&im->sender)))
11227 cmc->mh = (const struct GNUNET_MessageHeader *) &im[1];
11229}
11230
11231
11240static int
11241check_flow_control (void *cls, const struct TransportFlowControlMessage *fc)
11242{
11243 unsigned int number_of_addresses = ntohl (fc->number_of_addresses);
11244 uint16_t msize = ntohs (fc->header.size);
11245 const char *tgnas;
11246 size_t avail;
11247 size_t off;
11248
11249 (void) cls;
11251 "Flow control header size %u size of addresses %u number of addresses %u size of message struct %lu second struct %lu\n",
11252 ntohs (fc->header.size),
11253 ntohl (fc->size_of_addresses),
11254 ntohl (fc->number_of_addresses),
11255 sizeof(struct TransportFlowControlMessage),
11256 sizeof (struct TransportGlobalNattedAddress));
11257 if (0 == number_of_addresses)
11258 return GNUNET_OK;
11259 if (msize < sizeof(struct TransportFlowControlMessage))
11260 {
11261 GNUNET_break_op (0);
11262 return GNUNET_SYSERR;
11263 }
11264 avail = msize - sizeof(struct TransportFlowControlMessage);
11265 tgnas = (const char *) &fc[1];
11266 off = 0;
11267 /* Validate EVERY entry: checking only the aggregate size lets a single
11268 entry claim a bogus address_length and send #handle_flow_control()
11269 out of bounds. */
11270 for (unsigned int i = 0; i < number_of_addresses; i++)
11271 {
11272 const struct TransportGlobalNattedAddress *tgna;
11273 size_t alen;
11274
11275 if (avail - off < sizeof(struct TransportGlobalNattedAddress))
11276 {
11277 GNUNET_break_op (0);
11278 return GNUNET_SYSERR;
11279 }
11280 tgna = (const struct TransportGlobalNattedAddress *) &tgnas[off];
11281 off += sizeof(struct TransportGlobalNattedAddress);
11282 alen = ntohl (tgna->address_length);
11283 if (avail - off < alen)
11284 {
11285 GNUNET_break_op (0);
11286 return GNUNET_SYSERR;
11287 }
11288 off += alen;
11289 }
11290 return GNUNET_OK;
11291}
11292
11293
11294static struct GNUNET_TIME_Relative
11295calculate_rtt (struct DistanceVector *dv)
11296{
11298 unsigned int n_hops = 0;
11299
11301 "calculate_rtt\n");
11302 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
11303 pos = pos->next_dv)
11304 {
11306 "calculate_rtt %lu\n",
11307 (unsigned long) pos->pd.aged_rtt.rel_value_us);
11308 n_hops++;
11310 aged_rtt, pos
11311 ->distance
11312 + 2), ret);
11313 }
11314
11315 if (0 == n_hops)
11317 return ret;
11318}
11319
11320
11321static void
11323 const struct GNUNET_PeerIdentity *pid,
11324 const char *uri)
11325{
11326 struct VirtualLink *vl = cls;
11327 const char *slash;
11328 char *address_uri;
11329 char *prefix;
11330 char *uri_without_port;
11331
11332 slash = strrchr (uri, '/');
11333 if ((NULL == slash) || (slash - uri < 2))
11334 {
11335 GNUNET_break_op (0); /* @a uri comes from a remote HELLO */
11336 return;
11337 }
11338 prefix = GNUNET_strndup (uri, (slash - uri) - 2);
11339 slash++;
11340 GNUNET_asprintf (&address_uri,
11341 "%s-%s",
11342 prefix,
11343 slash);
11344
11345 uri_without_port = get_address_without_port (address_uri);
11347 "iterate_address_start_burst %s %s %s %s\n",
11348 (NULL == uri_without_port) ? "<unparsable>" : uri_without_port,
11349 uri,
11350 address_uri,
11351 slash);
11352 GNUNET_free (vl->burst_addr);
11353 if ((NULL != uri_without_port) &&
11354 (0 == strcmp (uri_without_port, slash)))
11355 vl->burst_addr = GNUNET_strdup (uri_without_port);
11356
11358 GNUNET_free (address_uri);
11359 GNUNET_free (uri_without_port);
11360}
11361
11362
11363static void
11364check_for_burst_address (void *cls,
11365 const struct GNUNET_PEERSTORE_Record *record,
11366 const char *emsg)
11367{
11368 struct GNUNET_StartBurstCls *sb_cls = cls;
11369 struct VirtualLink *vl = sb_cls->vl;
11370 const struct GNUNET_MessageHeader *hello;
11372
11373 if (NULL != emsg)
11374 {
11376 "Got failure from PEERSTORE: %s\n",
11377 emsg);
11378 /* @a emsg comes with a NULL record, which means the iteration is over
11379 and PEERSTORE is releasing the context itself -- stopping it here as
11380 well would free it twice. Just drop our handle. */
11381 vl->ic = NULL;
11382 free_burst_cls (sb_cls);
11383 return;
11384 }
11385 if (NULL == record)
11386 {
11388 "Hello iteration end for %s\n",
11389 GNUNET_i2s (&vl->target));
11390 /* PEERSTORE destroys the context itself once it signals the end. */
11391 vl->ic = NULL;
11392 free_burst_cls (sb_cls);
11393 return;
11394 }
11395
11397 "check_for_burst_address\n");
11398 /* @a hello was published by a remote peer, it may well be malformed. */
11399 hello = hello_from_record (record);
11400 if (NULL != hello)
11401 {
11402 parser = GNUNET_HELLO_parser_from_msg (hello, &record->peer);
11403 if (NULL != parser)
11404 {
11407 vl);
11408 GNUNET_HELLO_parser_free (parser);
11409 }
11410 }
11411
11412 /* MUST clear @e ic: #GNUNET_PEERSTORE_iteration_stop() frees it, and
11413 #free_virtual_link() would otherwise stop it a second time. */
11414 if (NULL != vl->ic)
11415 {
11417 vl->ic = NULL;
11418 }
11419 free_burst_cls (sb_cls);
11420}
11421
11422
11423static void
11424burst_timeout (void *cls)
11425{
11427}
11428
11429
11430static void
11431start_burst (void *cls)
11432{
11433 struct GNUNET_StartBurstCls *sb_cls = cls;
11434 struct VirtualLink *vl = sb_cls->vl;
11435 struct GNUNET_TRANSPORT_StartBurst *sb;
11436 struct GNUNET_MQ_Envelope *env;
11437 char *uri_without_port = vl->burst_addr;
11438
11439 burst_task = NULL;
11440 burst_task_cls = NULL;
11441 if (NULL == uri_without_port)
11442 {
11443 /* Lost the address in the meantime, nothing to burst to. */
11444 free_burst_cls (sb_cls);
11445 return;
11446 }
11447 /*char buf[strlen (uri_without_port) + 1];
11448
11449 GNUNET_memcpy (buf, uri_without_port, strlen (uri_without_port));
11450 buf[strlen (uri_without_port)] = '\0';*/
11451 env =
11453 strlen (uri_without_port) + 1,
11455 sb->rtt = GNUNET_TIME_relative_hton (sb_cls->rtt);
11456 sb->pid = vl->target;
11457 memcpy (&sb[1], uri_without_port, strlen (uri_without_port) + 1);
11458 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
11459 {
11460 if (CT_COMMUNICATOR != tc->type)
11461 continue; /* MUST come first: the log below reads the union! */
11463 "iterate_address_start_burst client tc prefix %s\n",
11464 tc->details.communicator.address_prefix);
11465 if (GNUNET_YES == tc->details.communicator.can_burst)
11466 {
11468 "iterate_address_start_burst %s call %lu %u rtt %lu\n",
11469 uri_without_port,
11470 strlen (uri_without_port),
11471 ntohs (sb->header.size),
11472 (unsigned long) sb_cls->rtt.rel_value_us);
11473 GNUNET_MQ_send (tc->mq, env);
11474 env = NULL; /* MQ took ownership */
11478 60),
11480 NULL);
11481 // TODO We need some algo to choose from available communicators. Can we run two bursts at once? Atm we only implemented udp burst.
11482 break;
11483 }
11484 }
11485 if (NULL != env)
11487 free_burst_cls (sb_cls);
11488}
11489
11490
11497static void
11498free_burst_cls (struct GNUNET_StartBurstCls *sb_cls)
11499{
11500 struct VirtualLink *vl = sb_cls->vl;
11501
11502 if (burst_task_cls == sb_cls)
11503 {
11504 if (NULL != burst_task)
11505 {
11507 burst_task = NULL;
11508 }
11509 burst_task_cls = NULL;
11510 }
11511 if ((NULL != vl) && (vl->sb_cls == sb_cls))
11512 vl->sb_cls = NULL;
11514}
11515
11516
11517static void
11518queue_burst (void *cls)
11519{
11520 struct GNUNET_StartBurstCls *sb_cls = cls;
11521 struct VirtualLink *vl = sb_cls->vl;
11522
11523 if (GNUNET_YES != use_burst)
11524 {
11525 /* MUST release: nobody else owns @a sb_cls, and #handle_flow_control()
11526 allocates one for every FLOW_CONTROL message we receive. */
11528 return;
11529 }
11531 "burst_task %p ready %s burst addr %s (%p)\n",
11532 burst_task,
11533 sb_cls->sync_ready ? "yes" : "no",
11534 vl->burst_addr,
11535 vl->burst_addr);
11536 if (NULL != burst_task && GNUNET_NO == sb_cls->sync_ready)
11537 {
11538 /* Cancel the pending burst. Both closures (the scheduled task's and
11539 ours) are ours to release. */
11541
11543 burst_task = NULL;
11544 burst_task_cls = NULL;
11545 if ((NULL != pending) && (pending != sb_cls))
11547 free_burst_cls (sb_cls);
11548 return;
11549 }
11550 if (GNUNET_NO == burst_running && NULL != vl->burst_addr && NULL == burst_task
11551 )
11552 {
11554 &start_burst,
11555 sb_cls);
11556 burst_task_cls = sb_cls;
11557 }
11558 else if (NULL == vl->burst_addr)
11559 {
11560 if (NULL != vl->ic)
11561 {
11562 /* An address lookup is already running for this link; starting a
11563 second one would leak the first. */
11564 free_burst_cls (sb_cls);
11565 return;
11566 }
11568 "peerstore",
11569 &vl->target,
11572 sb_cls);
11573 }
11574 else
11575 {
11576 /* A burst is already running or already scheduled; we have no use for
11577 this closure. */
11578 free_burst_cls (sb_cls);
11579 }
11580}
11581
11582
11589static void
11590unconfirmed_link_timeout (void *cls)
11591{
11592 struct VirtualLink *vl = cls;
11593
11594 vl->unconfirmed_timeout_task = NULL;
11595 if ((GNUNET_YES == vl->confirmed) ||
11596 (NULL != vl->n) ||
11597 (NULL != vl->dv))
11598 return; /* got promoted in the meantime, its owner will clean up */
11600 "Discarding unconfirmed virtual link to %s\n",
11601 GNUNET_i2s (&vl->target));
11603 "# Unconfirmed virtual links timed out",
11604 1,
11605 GNUNET_NO);
11606 free_virtual_link (vl);
11607}
11608
11609
11618static void
11619handle_flow_control (void *cls, const struct TransportFlowControlMessage *fc)
11620{
11621 struct CommunicatorMessageContext *cmc = cls;
11622 struct VirtualLink *vl;
11624 uint32_t seq;
11625 struct GNUNET_TIME_Absolute st;
11626 uint64_t os;
11627 uint64_t wnd;
11628 uint32_t random;
11629
11631 "Received FC from %s\n", GNUNET_i2s (&cmc->im.sender));
11632 vl = lookup_virtual_link (&cmc->im.sender);
11633 if (NULL == vl)
11634 {
11635 vl = GNUNET_new (struct VirtualLink);
11637 "No virtual link for %p FC creating new unconfirmed virtual link to %s!\n",
11638 vl,
11639 GNUNET_i2s (&cmc->im.sender));
11640 vl->burst_addr = NULL;
11641 vl->confirmed = GNUNET_NO;
11642 vl->message_uuid_ctr =
11643 GNUNET_CRYPTO_random_u64 (UINT64_MAX);
11644 vl->target = cmc->im.sender;
11650 links,
11651 &vl->target,
11652 vl,
11654 /* Nothing else owns this link yet, so it must reap itself if it never
11655 becomes confirmed -- otherwise any peer can make us allocate
11656 VirtualLinks without bound. */
11660 vl);
11661 }
11662 if (GNUNET_YES != vl->confirmed)
11663 {
11664 /* The peer flow-controls us, so it has a confirmed link to us -- but an
11665 unconfirmed link carries nothing and is never reported to CORE. Only
11666 #handle_validation_response() breaks that tie, and nothing here used
11667 to ask for one, so the pair could sit one-way until the peer's own
11668 four hour revalidation came round. */
11670 }
11671 if (NULL != vl->n)
11672 {
11673 for (struct Queue *q = vl->n->queue_head; NULL != q; q = q->next_neighbour)
11674 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
11675 }
11676
11678 "remaining %lu timeout for neighbour %p\n",
11679 (unsigned long) GNUNET_TIME_absolute_get_remaining (q_timeout).
11680 rel_value_us,
11681 vl->n);
11682 if (NULL == vl->n ||
11683 0 == GNUNET_TIME_absolute_get_remaining (q_timeout).rel_value_us)
11684 {
11685 struct GNUNET_TIME_Relative rtt;
11686 struct GNUNET_BurstSync burst_sync;
11687 struct GNUNET_StartBurstCls *bcls;
11688
11689 if (NULL != vl->sb_cls)
11690 {
11691 /* A burst attempt for this link is already in flight. Allocating a
11692 second closure would orphan the first one: @e sb_cls is how
11693 #free_virtual_link() finds (and cancels) the pending #burst_task,
11694 and a peer that just keeps sending us FLOW_CONTROL messages would
11695 otherwise make us leak one closure per message. */
11697 "Burst attempt to %s already pending\n",
11698 GNUNET_i2s (&vl->target));
11699 }
11700 else
11701 {
11702 bcls = GNUNET_new (struct GNUNET_StartBurstCls);
11703 bcls->vl = vl;
11704 vl->sb_cls = bcls;
11705 if (NULL != vl->dv)
11706 rtt = calculate_rtt (vl->dv);
11707 else
11709 burst_sync.rtt_average = fc->rtt;
11710 bcls->rtt = GNUNET_TIME_relative_ntoh (burst_sync.rtt_average);
11711 /* @e sync_ready of `struct GNUNET_BurstSync' is a host-order enum. */
11712 burst_sync.sync_ready =
11713 (enum GNUNET_GenericReturnValue) ntohl (fc->sync_ready);
11714
11715 /* NOTE: #GNUNET_is_burst_ready() does NOT invoke the task unless both
11716 RTT estimates are known and close; #queue_burst() is thus not
11717 guaranteed to run, which is why @e sb_cls stays owned by @a vl. */
11719 &burst_sync,
11720 &queue_burst,
11721 bcls);
11722 }
11723 }
11724 if (0 != ntohl (fc->number_of_addresses))
11725 {
11726 unsigned int number_of_addresses = ntohl (fc->number_of_addresses);
11727 const char *tgnas;
11728 unsigned int off = 0;
11729
11730 tgnas = (const char *) &fc[1];
11731
11732 for (unsigned int i = 0; i < number_of_addresses; i++)
11733 {
11734 struct TransportGlobalNattedAddress *tgna;
11735 char *addr;
11736 uint32_t address_length;
11737
11738 tgna = (struct TransportGlobalNattedAddress*) &tgnas[off];
11739 addr = (char *) &tgna[1];
11740 address_length = ntohl (tgna->address_length);
11741 off += sizeof(struct TransportGlobalNattedAddress) + address_length;
11742
11743 /* NOTE: the address is NOT 0-terminated (it comes straight off the
11744 wire), it must be printed with an explicit precision. */
11746 "received address %.*s length %u\n",
11747 (int) address_length,
11748 addr,
11750
11751 if (NULL != nh)
11752 GNUNET_NAT_add_global_address (nh, addr, ntohl (tgna->address_length));
11753 }
11754 }
11756 if (st.abs_value_us < vl->last_fc_timestamp.abs_value_us)
11757 {
11759 "FC dropped: Message out of order\n");
11760 /* out of order, drop */
11762 "# FC dropped: message out of order",
11763 1,
11764 GNUNET_NO);
11765 finish_cmc_handling (cmc);
11766 return;
11767 }
11768 seq = ntohl (fc->seq);
11769 if (seq < vl->last_fc_seq)
11770 {
11771 /* Wrap-around/reset of other peer; start all counters from zero */
11773 }
11774 vl->last_fc_seq = seq;
11775 vl->last_fc_timestamp = st;
11777 os = GNUNET_ntohll (fc->outbound_sent);
11779 (int64_t) (os - vl->incoming_fc_window_size_used);
11781 "Received FC from %s, seq %u, new window %llu (loss at %lld)\n",
11782 GNUNET_i2s (&vl->target),
11783 (unsigned int) seq,
11784 (unsigned long long) vl->outbound_fc_window_size,
11785 (long long) vl->incoming_fc_window_size_loss);
11787 random = GNUNET_CRYPTO_random_u32 (UINT32_MAX);
11788 if ((GNUNET_YES == vl->confirmed) && ((wnd < vl->incoming_fc_window_size
11792 != wnd) ||
11793 (0 == random
11795 {
11797 "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",
11798 (unsigned long long) wnd,
11799 (unsigned long long) vl->incoming_fc_window_size,
11800 (unsigned long long) vl->last_outbound_window_size_received,
11803 }
11804 if ((GNUNET_YES == vl->confirmed) &&
11805 (wnd == vl->incoming_fc_window_size
11809 {
11811 "Slowing FC transmission to %s to keepalive rate: peer is current at window %llu\n",
11812 GNUNET_i2s (&vl->target),
11813 (unsigned long long) wnd);
11814 /* NOTE: this used to also require @e fc_retransmit_task to be non-NULL
11815 and did nothing at all otherwise -- so a link whose chain had ended
11816 (see #consider_sending_fc()) could never pick the keepalive back up,
11817 even though the peer was demonstrably still talking to us. */
11818 if (NULL != vl->fc_retransmit_task)
11820 vl->fc_retransmit_count = 0;
11821 /* Drop to the keepalive rate rather than stopping outright. There is
11822 nothing left to retransmit -- but if we go completely quiet, and the
11823 peer does the same for the same reason, then neither end sees any
11824 traffic and #check_link_down() tears down a perfectly healthy link
11825 after #NEIGHBOUR_LIVENESS_TIMEOUT. One tiny FC message every
11826 #FC_KEEPALIVE_INTERVAL is what keeps @e last_inbound moving on the
11827 other side (and, via their reply, on ours). */
11828 vl->fc_retransmit_task =
11831 vl);
11832 }
11834 /* FC window likely increased, check transmission possibilities! */
11836 finish_cmc_handling (cmc);
11837}
11838
11839
11847static void
11849{
11851 { GNUNET_MQ_hd_var_size (fragment_box,
11854 cmc),
11855 GNUNET_MQ_hd_var_size (reliability_box,
11858 cmc),
11859 GNUNET_MQ_hd_var_size (reliability_ack,
11862 cmc),
11863 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
11866 cmc),
11867 GNUNET_MQ_hd_var_size (dv_learn,
11870 cmc),
11871 GNUNET_MQ_hd_var_size (dv_box,
11873 struct TransportDVBoxMessage,
11874 cmc),
11875 GNUNET_MQ_hd_var_size (flow_control,
11878 cmc),
11880 validation_challenge,
11883 cmc),
11885 validation_response,
11888 cmc),
11890 int ret;
11891 const struct GNUNET_MessageHeader *msg = cmc->mh;
11892
11894 "Handling message of type %u with %u bytes\n",
11895 (unsigned int) ntohs (msg->type),
11896 (unsigned int) ntohs (msg->size));
11897 /* @a handlers only covers the encapsulations *we* add; anything else is a
11898 payload for CORE and leaves through #handle_raw_message() below. So
11899 #GNUNET_NO is the common case here -- one per delivered CORE message --
11900 and not something to log about, which is why this is the "try" variant. */
11902 if (GNUNET_SYSERR == ret)
11903 {
11904 /* @a msg is the message a *remote peer* sent us: #handle_incoming_msg()
11905 points @e mh into the payload of the
11906 #GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG the communicator
11907 delivered, and every other caller unwraps it from remote traffic as
11908 well. So failing a check here is that peer's protocol violation, and
11909 it says nothing at all about the communicator that carried it.
11910
11911 Dropping the client therefore punishes the wrong party, and it
11912 punishes it hard: #GNUNET_SERVICE_client_drop() disconnects the
11913 communicator *process*, which takes down every queue it owns and thus
11914 every neighbour reachable through it. One malformed DV box on a
11915 shared UDP communicator disconnects every peer we have on it, CORE
11916 tears the sessions down, and the key exchanges that would rebuild
11917 them have to wait for the communicator to come back and revalidate.
11918 Since the offending bytes arrive from the network, any peer can do
11919 this to us at will, repeatedly.
11920
11921 Drop the message and keep the communicator: resume it exactly as the
11922 success path does, so it still gets its flow-control ACK and its
11923 GNUNET_SERVICE_client_continue(). */
11924 GNUNET_break_op (0);
11926 "# malformed messages discarded",
11927 1,
11928 GNUNET_NO);
11930 return;
11931 }
11932 if (GNUNET_NO == ret)
11933 {
11934 /* unencapsulated 'raw' message */
11935 handle_raw_message (cmc, msg);
11936 }
11937}
11938
11939
11946static int
11947check_add_queue_message (void *cls,
11948 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
11949{
11950 struct TransportClient *tc = cls;
11951
11952 if (CT_COMMUNICATOR != tc->type)
11953 {
11954 GNUNET_break (0);
11955 return GNUNET_SYSERR;
11956 }
11958 return GNUNET_OK;
11959}
11960
11961
11967static void
11969{
11970 if (pm->msg_uuid_set)
11971 return;
11972 pm->msg_uuid.uuid = pm->vl->message_uuid_ctr++;
11974}
11975
11976
11985static struct PendingAcknowledgement *
11987 struct DistanceVectorHop *dvh,
11988 struct PendingMessage *pm)
11989{
11990 struct PendingAcknowledgement *pa;
11991
11992 pa = GNUNET_new (struct PendingAcknowledgement);
11993 pa->queue = queue;
11994 pa->dvh = dvh;
11995 pa->pm = pm;
11996 do
11997 {
11999 sizeof(pa->ack_uuid));
12000 }
12003 &pa->ack_uuid.value,
12004 pa,
12006 GNUNET_CONTAINER_MDLL_insert (queue, queue->pa_head, queue->pa_tail, pa);
12008 if (NULL != dvh)
12011 pa->message_size = pm->bytes_msg;
12013 "Waiting for ACKnowledgment `%s' for <%" PRIu64 ">\n",
12015 pm->logging_uuid);
12016 return pa;
12017}
12018
12019
12031static struct PendingMessage *
12033 struct DistanceVectorHop *dvh,
12034 struct PendingMessage *pm)
12035{
12036 struct PendingAcknowledgement *pa;
12037 struct PendingMessage *ff;
12038 uint16_t mtu;
12039 uint16_t msize;
12040
12041 mtu = (UINT16_MAX == queue->mtu)
12042 ? UINT16_MAX - sizeof(struct GNUNET_TRANSPORT_SendMessageTo)
12043 : queue->mtu;
12045 "Fragmenting message <%" PRIu64
12046 "> with size %u to %s for MTU %u\n",
12047 pm->logging_uuid,
12048 pm->bytes_msg,
12049 GNUNET_i2s (&pm->vl->target),
12050 (unsigned int) mtu);
12053 "Fragmenting message %" PRIu64 " <%" PRIu64
12054 "> with size %u to %s for MTU %u\n",
12055 pm->msg_uuid.uuid,
12056 pm->logging_uuid,
12057 pm->bytes_msg,
12058 GNUNET_i2s (&pm->vl->target),
12059 (unsigned int) mtu);
12060
12061 /* This invariant is established in #handle_add_queue_message() */
12062 GNUNET_assert (mtu > sizeof(struct TransportFragmentBoxMessage));
12063
12064 /* select fragment for transmission, descending the tree if it has
12065 been expanded until we are at a leaf or at a fragment that is small
12066 enough
12067 */
12068 ff = pm;
12069 msize = ff->bytes_msg;
12070
12071 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
12072 (ff->frag_off == msize) && (NULL != ff->head_frag))
12073 {
12074 ff = ff->head_frag; /* descent into fragmented fragments */
12075 msize = ff->bytes_msg - sizeof(struct TransportFragmentBoxMessage);
12076 }
12077
12078 if (((ff->bytes_msg > mtu) || (pm == ff)) && (ff->frag_off < msize))
12079 {
12080 /* Did not yet calculate all fragments, calculate next fragment */
12081 struct PendingMessage *frag;
12082 struct TransportFragmentBoxMessage tfb;
12083 const char *orig;
12084 char *msg;
12085 uint16_t fragmax;
12086 uint16_t fragsize;
12087 uint16_t msize_ff;
12088 uint16_t xoff = 0;
12089 pm->frag_count++;
12090
12091 orig = (const char *) &ff[1];
12092 msize_ff = ff->bytes_msg;
12093 if (pm != ff)
12094 {
12095 const struct TransportFragmentBoxMessage *tfbo;
12096
12097 tfbo = (const struct TransportFragmentBoxMessage *) orig;
12098 orig += sizeof(struct TransportFragmentBoxMessage);
12099 msize_ff -= sizeof(struct TransportFragmentBoxMessage);
12100 xoff = ntohs (tfbo->frag_off);
12101 }
12102 fragmax = mtu - sizeof(struct TransportFragmentBoxMessage);
12103 fragsize = GNUNET_MIN (msize_ff - ff->frag_off, fragmax);
12104 frag =
12105 GNUNET_malloc (sizeof(struct PendingMessage)
12106 + sizeof(struct TransportFragmentBoxMessage) + fragsize);
12108 "3 created pm %p from pm %p storing vl %p from pm %p\n",
12109 frag,
12110 ff,
12111 pm->vl,
12112 pm);
12114 frag->vl = pm->vl;
12115 frag->frag_parent = ff;
12116 frag->timeout = pm->timeout;
12117 frag->bytes_msg = sizeof(struct TransportFragmentBoxMessage) + fragsize;
12118 frag->pmt = PMT_FRAGMENT_BOX;
12119 msg = (char *) &frag[1];
12120 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
12121 tfb.header.size =
12122 htons (sizeof(struct TransportFragmentBoxMessage) + fragsize);
12123 pa = prepare_pending_acknowledgement (queue, dvh, frag);
12124 tfb.ack_uuid = pa->ack_uuid;
12125 tfb.msg_uuid = pm->msg_uuid;
12126 tfb.frag_off = htons (ff->frag_off + xoff);
12127 tfb.msg_size = htons (pm->bytes_msg);
12128 memcpy (msg, &tfb, sizeof(tfb));
12129 memcpy (&msg[sizeof(tfb)], &orig[ff->frag_off], fragsize);
12131 ff->tail_frag, frag);
12132 ff->frag_off += fragsize;
12133 ff = frag;
12134 }
12135
12136 /* Move head to the tail and return it */
12140 ff);
12144 ff);
12145
12146 return ff;
12147}
12148
12149
12162static struct PendingMessage *
12164 struct DistanceVectorHop *dvh,
12165 struct PendingMessage *pm)
12166{
12168 struct PendingAcknowledgement *pa;
12169 struct PendingMessage *bpm;
12170 char *msg;
12171
12172 if ((PMT_CORE != pm->pmt) && (PMT_DV_BOX != pm->pmt))
12173 return pm; /* already fragmented or reliability boxed, or control message:
12174 do nothing */
12175 if (NULL != pm->bpm)
12176 return pm->bpm; /* already computed earlier: do nothing */
12177 // TODO I guess we do not need this assertion. We might have a DLL with
12178 // fragments, because the MTU changed, and we do not need to fragment anymore.
12179 // But we should keep the fragments until message was completed, because
12180 // the MTU might change again.
12181 // GNUNET_assert (NULL == pm->head_frag);
12182 if (pm->bytes_msg + sizeof(rbox) > UINT16_MAX)
12183 {
12184 /* failed hard */
12185 GNUNET_break (0);
12187 return NULL;
12188 }
12189
12190 pa = prepare_pending_acknowledgement (queue, dvh, pm);
12191
12192 bpm = GNUNET_malloc (sizeof(struct PendingMessage) + sizeof(rbox)
12193 + pm->bytes_msg);
12195 "4 created pm %p storing vl %p from pm %p\n",
12196 bpm,
12197 pm->vl,
12198 pm);
12200 bpm->vl = pm->vl;
12201 bpm->frag_parent = pm;
12202 // Why was this needed?
12203 // GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
12204 bpm->timeout = pm->timeout;
12206 bpm->bytes_msg = pm->bytes_msg + sizeof(rbox);
12208 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
12209 rbox.header.size = htons (sizeof(rbox) + pm->bytes_msg);
12210 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
12211
12212 rbox.ack_uuid = pa->ack_uuid;
12213 msg = (char *) &bpm[1];
12214 memcpy (msg, &rbox, sizeof(rbox));
12215 memcpy (&msg[sizeof(rbox)], &pm[1], pm->bytes_msg);
12216 pm->bpm = bpm;
12218 "Preparing reliability box for message <%" PRIu64
12219 "> of size %d (%d) to %s on queue %s\n",
12220 pm->logging_uuid,
12221 pm->bytes_msg,
12222 ntohs (((const struct GNUNET_MessageHeader *) &pm[1])->size),
12223 GNUNET_i2s (&pm->vl->target),
12224 queue->address);
12225 return bpm;
12226}
12227
12228
12229static void
12232{
12233 struct VirtualLink *vl = pm->vl;
12234 struct PendingMessage *pos;
12235
12236 /* Only a message without a parent is on vl->pending_msg_head; anything
12237 else is not ours to reorder and MDLL_remove() would abort on it. */
12238 if ((NULL == vl) ||
12239 (NULL != pm->frag_parent) ||
12240 ((NULL == pm->prev_vl) && (vl->pending_msg_head != pm)))
12241 {
12242 GNUNET_break (0);
12243 return;
12244 }
12245 /* re-insert sort in neighbour list */
12249 pm);
12250 pos = vl->pending_msg_tail;
12251 while ((NULL != pos) &&
12253 pos = pos->prev_vl;
12257 pos,
12258 pm);
12259}
12260
12261
12262static unsigned int
12263check_next_attempt_tree (struct PendingMessage *pm, struct PendingMessage *root)
12264{
12265 struct PendingMessage *pos;
12266 /* MUST be initialised: for a leaf the loop below never runs */
12268
12269 pos = pm->head_frag;
12270 while (NULL != pos)
12271 {
12273 GNUNET_NO == check_next_attempt_tree (pos, root))
12275 else
12276 {
12278 break;
12279 }
12280 pos = pos->next_frag;
12281 }
12282
12283 return frags_in_flight;
12284}
12285
12286
12287static void
12289{
12290 struct PendingMessage *pos;
12291
12292 pos = pm->head_frag;
12293 while (NULL != pos)
12294 {
12297 pos = pos->next_frag;
12298 }
12299}
12300
12301
12310static void
12313{
12314 if (NULL == pm->frag_parent)
12315 {
12318 "Next attempt for message <%" PRIu64 "> set to %" PRIu64 "\n",
12319 pm->logging_uuid,
12322 }
12323 else if ((PMT_RELIABILITY_BOX == pm->pmt) || (PMT_DV_BOX == pm->pmt))// || (PMT_FRAGMENT_BOX == pm->pmt))
12324 {
12325 struct PendingMessage *root = pm->frag_parent;
12326
12327 while (NULL != root->frag_parent)
12328 root = root->frag_parent;
12330 "Next attempt for root message <%" PRIu64 "> set to %s\n",
12331 root->logging_uuid,
12333 root->next_attempt = next_attempt;
12335 }
12336 else
12337 {
12338 struct PendingMessage *root = pm->frag_parent;
12339
12340 while (NULL != root->frag_parent && PMT_DV_BOX != root->pmt)
12341 root = root->frag_parent;
12342
12344 "frag_count next attempt %u\n",
12345 root->frag_count);
12346
12347 if (GNUNET_NO == root->frags_in_flight)
12348 {
12349 root->next_attempt = next_attempt;
12351 root->frags_in_flight_round++;
12353 "Next attempt for fragmented message <%" PRIu64 "> (<%" PRIu64
12354 ">)set to %" PRIu64 "\n",
12355 pm->logging_uuid,
12356 root->logging_uuid,
12358 }
12359
12360 pm->next_attempt = root->next_attempt;
12363
12364 if (root->bytes_msg == root->frag_off)
12365 root->frags_in_flight = check_next_attempt_tree (root, root);
12366 else
12368
12369 if (GNUNET_NO == root->frags_in_flight)
12370 {
12371 /* `root' deliberately stops at a DV box, which is itself a child of
12372 the message on vl->pending_msg_head. Walk the rest of the way for
12373 the reorder: only the parentless message is on that list. */
12374 struct PendingMessage *vl_root = root;
12375
12376 while (NULL != vl_root->frag_parent)
12377 vl_root = vl_root->frag_parent;
12378 vl_root->next_attempt = root->next_attempt;
12380 "We have no fragments in flight for message %" PRIu64
12381 ", reorder root %" PRIu64 "! Next attempt is %" PRIu64 "\n",
12382 root->logging_uuid,
12383 vl_root->logging_uuid,
12384 vl_root->next_attempt.abs_value_us);
12385 reorder_root_pm (vl_root, vl_root->next_attempt);
12386 }
12387 else
12388 {
12389 double factor = ((double) root->frag_count - 1)
12390 / (double) root->frag_count;
12391 struct GNUNET_TIME_Relative s1;
12392 struct GNUNET_TIME_Relative s2;
12393 struct GNUNET_TIME_Relative plus_mean =
12396 next_attempt);
12397
12399 "frag_count %u after factor\n",
12400 root->frag_count);
12402 factor);
12403 s2 = GNUNET_TIME_relative_divide (plus,
12404 root->frag_count);
12405 plus_mean = GNUNET_TIME_relative_add (s1, s2);
12408 "We have fragments in flight for message %" PRIu64
12409 ", do not reorder root! Actual next attempt %" PRIu64 "\n",
12410 root->logging_uuid,
12412 }
12413 }
12414}
12415
12416
12421{
12425 struct PendingMessage *best;
12426
12430 struct DistanceVectorHop *dvh;
12431
12435 size_t real_overhead;
12436
12440 unsigned int consideration_counter;
12441
12445 int frag;
12446
12450 int relb;
12451
12455 int to_early;
12456
12460 unsigned int frags_in_flight;
12461
12466};
12467
12468
12480static void
12482 struct Queue *queue,
12483 struct VirtualLink *vl,
12484 struct DistanceVectorHop *dvh,
12485 size_t overhead)
12486{
12487 struct GNUNET_TIME_Absolute now;
12488
12489 now = GNUNET_TIME_absolute_get ();
12490 sc->to_early = GNUNET_NO;
12491 sc->frags_in_flight = GNUNET_NO;
12492 for (struct PendingMessage *pos = vl->pending_msg_head; NULL != pos;
12493 pos = pos->next_vl)
12494 {
12495 size_t real_overhead = overhead;
12496 int frag;
12497 int relb;
12498
12499 if ((NULL != dvh) && (PMT_DV_BOX == pos->pmt))
12500 {
12502 "DV messages must not be DV-routed to next hop!\n");
12503 continue; /* DV messages must not be DV-routed to next hop! */
12504 }
12505 if (pos->next_attempt.abs_value_us > now.abs_value_us)
12506 {
12507 if (GNUNET_YES == pos->frags_in_flight)
12508 {
12509 sc->frags_in_flight = GNUNET_YES;
12511 "Fragments in flight for message %" PRIu64 "\n",
12512 pos->logging_uuid);
12513 }
12514 else
12515 {
12517 "Maybe too early, because message are sorted by next_attempt, if there are no fragments in flight.Checked message %"
12518 PRIu64 "\n",
12519 pos->logging_uuid);
12520 sc->to_early = GNUNET_YES;
12521 sc->to_early_retry_delay = GNUNET_TIME_absolute_get_remaining (
12522 pos->next_attempt);
12523 continue;
12524 }
12525 // break; /* too early for all messages, they are sorted by next_attempt */
12526 }
12527 if (NULL != pos->qe)
12528 {
12530 "not eligible\n");
12531 continue; /* not eligible */
12532 }
12533 sc->consideration_counter++;
12534 /* determine if we have to fragment, if so add fragmentation
12535 overhead! */
12537 "check %" PRIu64 " for sc->best\n",
12538 pos->logging_uuid);
12539 frag = GNUNET_NO;
12540 if (((0 != queue->mtu) &&
12541 (pos->bytes_msg + real_overhead > queue->mtu)) ||
12542 (pos->bytes_msg > UINT16_MAX - sizeof(struct
12544 ||
12545 (NULL != pos->head_frag /* fragments already exist, should
12546 respect that even if MTU is UINT16_MAX for
12547 this queue */))
12548 {
12550 "fragment msg with size %u, realoverhead is %lu\n",
12551 pos->bytes_msg,
12552 real_overhead);
12553 frag = GNUNET_YES;
12554 if (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc)
12555 {
12556 /* FIXME-FRAG-REL-UUID: we could use an optimized, shorter fragmentation
12557 header without the ACK UUID when using a *reliable* channel! */
12558 }
12559 real_overhead = overhead + sizeof(struct TransportFragmentBoxMessage);
12560 }
12561 /* determine if we have to reliability-box, if so add reliability box
12562 overhead */
12563 relb = GNUNET_NO;
12564 if ((GNUNET_NO == frag) &&
12565 (0 == (pos->prefs & GNUNET_MQ_PREF_UNRELIABLE)) &&
12566 (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc))
12567 {
12568 real_overhead += sizeof(struct TransportReliabilityBoxMessage);
12569
12570 if ((0 != queue->mtu) && (pos->bytes_msg + real_overhead > queue->mtu))
12571 {
12572 frag = GNUNET_YES;
12573 real_overhead = overhead + sizeof(struct TransportFragmentBoxMessage);
12574 }
12575 else
12576 {
12577 relb = GNUNET_YES;
12578 }
12580 "Create reliability box of msg with size %u, realoverhead is %lu %u %u %u\n",
12581 pos->bytes_msg,
12582 real_overhead,
12583 queue->mtu,
12584 frag,
12585 relb);
12586 }
12587
12588 /* Finally, compare to existing 'best' in sc to see if this 'pos' pending
12589 message would beat it! */
12590 if (GNUNET_NO == sc->frags_in_flight && NULL != sc->best)
12591 {
12592 /* CHECK if pos fits queue BETTER (=smaller) than pm, if not: continue;
12593 OPTIMIZE-ME: This is a heuristic, which so far has NOT been
12594 experimentally validated. There may be some huge potential for
12595 improvement here. Also, we right now only compare how well the
12596 given message fits _this_ queue, and do not consider how well other
12597 queues might suit the message. Taking other queues into consideration
12598 may further improve the result, but could also be expensive
12599 in terms of CPU time. */
12600 long long sc_score = sc->frag * 40 + sc->relb * 20 + sc->real_overhead;
12601 long long pm_score = frag * 40 + relb * 20 + real_overhead;
12602 long long time_delta =
12603 (sc->best->next_attempt.abs_value_us - pos->next_attempt.abs_value_us)
12604 / 1000LL;
12605
12606 /* "time_delta" considers which message has been 'ready' for transmission
12607 for longer, if a message has a preference for low latency, increase
12608 the weight of the time_delta by 10x if it is favorable for that message */
12609 if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
12610 (0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)))
12611 time_delta *= 10; /* increase weight (always, both are low latency) */
12612 else if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
12613 (time_delta > 0))
12614 time_delta *= 10; /* increase weight, favors 'pos', which is low latency */
12615 else if ((0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
12616 (time_delta < 0))
12617 time_delta *= 10; /* increase weight, favors 'sc->best', which is low latency */
12618 if (0 != queue->mtu)
12619 {
12620 /* Grant bonus if we are below MTU, larger bonus the closer we will
12621 be to the MTU */
12622 if (queue->mtu > sc->real_overhead + sc->best->bytes_msg)
12623 sc_score -= queue->mtu - (sc->real_overhead + sc->best->bytes_msg);
12624 if (queue->mtu > real_overhead + pos->bytes_msg)
12625 pm_score -= queue->mtu - (real_overhead + pos->bytes_msg);
12626 }
12627 if (sc_score + time_delta > pm_score)
12628 {
12630 "sc_score of %" PRIu64 " larger, keep sc->best %" PRIu64
12631 "\n",
12632 pos->logging_uuid,
12633 sc->best->logging_uuid);
12634 continue; /* sc_score larger, keep sc->best */
12635 }
12636 }
12637 sc->best = pos;
12638 sc->dvh = dvh;
12639 sc->frag = frag;
12640 sc->relb = relb;
12641 sc->real_overhead = real_overhead;
12642 }
12643}
12644
12645
12656static void
12657extract_box_cb (void *cls,
12658 struct Neighbour *next_hop,
12659 const struct GNUNET_MessageHeader *hdr,
12661{
12662 struct PendingMessageScoreContext *sc = cls;
12663 struct PendingMessage *pm = sc->best;
12664 struct PendingMessage *bpm;
12665 uint16_t bsize = ntohs (hdr->size);
12666
12667 GNUNET_assert (NULL == pm->bpm);
12668 bpm = GNUNET_malloc (sizeof(struct PendingMessage) + bsize);
12670 "5 created pm %p storing vl %p from pm %p\n",
12671 bpm,
12672 pm->vl,
12673 pm);
12675 bpm->pmt = PMT_DV_BOX;
12676 bpm->vl = pm->vl;
12677 bpm->timeout = pm->timeout;
12678 bpm->bytes_msg = bsize;
12679 bpm->frag_parent = pm;
12682 "Creating DV Box %" PRIu64 " for original message %" PRIu64
12683 " (next hop is %s)\n",
12685 pm->logging_uuid,
12686 GNUNET_i2s (&next_hop->pid));
12687 memcpy (&bpm[1], hdr, bsize);
12688 pm->bpm = bpm;
12689}
12690
12691
12707static void
12708transmit_on_queue (void *cls)
12709{
12710 struct Queue *queue = cls;
12711 struct Neighbour *n = queue->neighbour;
12713 struct PendingMessage *pm;
12714
12715 queue->transmit_task = NULL;
12716 if (NULL == n->vl)
12717 {
12719 "Virtual link `%s' is down, cannot have PM for queue `%s'\n",
12720 GNUNET_i2s (&n->pid),
12721 queue->address);
12722 queue->idle = GNUNET_YES;
12723 return;
12724 }
12725 memset (&sc, 0, sizeof(sc));
12726 select_best_pending_from_link (&sc, queue, n->vl, NULL, 0);
12727 if (NULL == sc.best)
12728 {
12729 /* Also look at DVH that have the n as first hop! */
12730 for (struct DistanceVectorHop *dvh = n->dv_head; NULL != dvh;
12731 dvh = dvh->next_neighbour)
12732 {
12733 if (NULL == dvh->dv->vl)
12734 continue; /* route not (yet) visible to CORE, no messages for it */
12736 queue,
12737 dvh->dv->vl,
12738 dvh,
12739 sizeof(struct GNUNET_PeerIdentity)
12740 * (1 + dvh->distance)
12741 + sizeof(struct TransportDVBoxMessage)
12742 + sizeof(struct TransportDVBoxPayloadP));
12743 }
12744 }
12745 if (NULL == sc.best)
12746 {
12747 /* no message pending, nothing to do here! */
12749 "No pending messages, queue `%s' to %s now idle\n",
12750 queue->address,
12751 GNUNET_i2s (&n->pid));
12752 if (GNUNET_YES == sc.to_early)
12753 schedule_transmit_on_queue (sc.to_early_retry_delay,
12754 queue,
12756 queue->idle = GNUNET_YES;
12757 return;
12758 }
12759 /* There is a message pending, we are certainly not idle */
12760 queue->idle = GNUNET_NO;
12761
12762 /* Given selection in `sc`, do transmission */
12763 pm = sc.best;
12765 "Selected message <%" PRIu64 ">\n",
12766 pm->logging_uuid);
12767 if (NULL != sc.dvh)
12768 {
12770 "Is this %u a DV box?\n",
12771 pm->pmt);
12772 GNUNET_assert (PMT_DV_BOX != pm->pmt);
12773 if ((NULL != sc.best->bpm) && (sc.best->bpm->used_dvh != sc.dvh))
12774 {
12776 "Discard old box, because we have a new DV path.\n");
12777 free_pending_message (sc.best->bpm);
12778 sc.best->bpm = NULL;
12779 }
12780
12781 if (NULL == sc.best->bpm)
12782 {
12784 "encapsulate_for_dv 2\n");
12785 encapsulate_for_dv (sc.dvh->dv,
12786 1,
12787 &sc.dvh,
12788 (const struct GNUNET_MessageHeader *) &sc.best[1],
12790 &sc,
12791 RMO_NONE,
12792 GNUNET_NO);
12793 GNUNET_assert (NULL != sc.best->bpm);
12795 "%lu %lu %lu %lu %u\n",
12796 sizeof(struct GNUNET_PeerIdentity),
12797 sizeof(struct TransportDVBoxMessage),
12798 sizeof(struct TransportDVBoxPayloadP),
12799 sizeof(struct TransportFragmentBoxMessage),
12800 ((const struct GNUNET_MessageHeader *) &sc.best[1])->size);
12801 sc.best->bpm->used_dvh = sc.dvh;
12802 }
12803 pm = sc.best->bpm;
12804 }
12805 if (GNUNET_YES == sc.frag)
12806 {
12807 pm = fragment_message (queue, sc.dvh, pm);
12808 if (NULL == pm)
12809 {
12811 "Fragmentation failed queue %s to %s for <%" PRIu64
12812 ">, trying again\n",
12813 queue->address,
12814 GNUNET_i2s (&n->pid),
12815 sc.best->logging_uuid);
12817 queue,
12819 return;
12820 }
12821 }
12822 else if (GNUNET_YES == sc.relb)
12823 {
12824 pm = reliability_box_message (queue, sc.dvh, pm);
12825 if (NULL == pm)
12826 {
12827 /* Reliability boxing failed, try next message... */
12828 GNUNET_log (
12830 "Reliability boxing failed queue %s to %s for <%" PRIu64
12831 ">, trying again\n",
12832 queue->address,
12833 GNUNET_i2s (&n->pid),
12834 sc.best->logging_uuid);
12836 queue,
12838 return;
12839 }
12840 }
12841
12842 /* Pass 'pm' for transission to the communicator */
12843 GNUNET_log (
12845 "Passing message <%" PRIu64
12846 "> to queue %s for peer %s (considered %u others)\n",
12847 pm->logging_uuid,
12848 queue->address,
12849 GNUNET_i2s (&n->pid),
12850 sc.consideration_counter);
12851
12852 /* Flow control: increment amount of traffic sent; if we are routing
12853 via DV (and thus the ultimate target of the pending message is for
12854 a different virtual link than the one of the queue), then we need
12855 to use up not only the window of the direct link but also the
12856 flow control window for the DV link! */
12858
12859 if (pm->vl != queue->neighbour->vl)
12860 {
12861 /* If the virtual link of the queue differs, this better be distance
12862 vector routing! */
12863 GNUNET_assert (NULL != sc.dvh);
12864 /* If we do distance vector routing, we better not do this for a
12865 message that was itself DV-routed */
12866 GNUNET_assert (PMT_DV_BOX != sc.best->pmt);
12867 /* We use the size of the unboxed message here, to avoid counting
12868 the DV-Box header which is eaten up on the way by intermediaries */
12869 queue->neighbour->vl->outbound_fc_window_size_used += sc.best->bytes_msg;
12870 }
12871 else
12872 {
12873 GNUNET_assert (NULL == sc.dvh);
12874 }
12875
12876 queue_send_msg (queue, pm, &pm[1], pm->bytes_msg);
12877
12878 /* The message is with the communicator now, so return the CORE send
12879 window credit for it -- see #credit_client().
12880
12881 It used to be returned here only for an unboxed message or a reliable
12882 communicator, and otherwise not until the *peer* acknowledged the
12883 message below. That makes a window into a delivery confirmation: over
12884 an unreliable communicator every reliability-boxed or fragmented
12885 message holds one of the client's #SEND_WINDOW_SIZE slots for as long
12886 as its ACK takes, and a lost ACK holds it for the whole retransmission
12887 chain. Four of those and CORE cannot send to that peer at all -- not
12888 payload, but also not its HEARTBEATs and not one message of its key
12889 exchange. So the session times out for want of a heartbeat that is
12890 sitting in a queue, and the handshake that would rebuild it cannot go
12891 out either; CORE only recovers when a reconnect resets the window
12892 wholesale. Acknowledgements still drive retransmission below, they
12893 just no longer gate the client. */
12894 credit_client (sc.best);
12895
12896 /* Check if this transmission somehow conclusively finished handing 'pm'
12897 even without any explicit ACKs */
12898 if ((PMT_CORE == pm->pmt) ||
12899 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc))
12900 {
12902 }
12903 else
12904 {
12905 struct GNUNET_TIME_Relative wait_duration;
12906 unsigned int wait_multiplier;
12907
12908 if (PMT_FRAGMENT_BOX == pm->pmt)
12909 {
12910 struct PendingMessage *root;
12911
12912 root = pm->frag_parent;
12913 while (NULL != root->frag_parent && PMT_DV_BOX != root->pmt)
12914 root = root->frag_parent;
12915
12916 if ((0 == root->frag_off) || (0 == root->frag_count))
12917 {
12918 wait_multiplier = 4;
12919 }
12920 else
12921 {
12922 double wm = ceil ((double) root->bytes_msg
12923 / ((double) root->frag_off
12924 / (double) root->frag_count)) * 4.0;
12925
12926 if ((! (wm >= 1.0)) || (wm > 1024.0))
12927 wm = 4.0; /* NaN, infinity or absurd: fall back to the default */
12928 wait_multiplier = (unsigned int) wm;
12929 }
12930 }
12931 else
12932 {
12933 // No fragments, we use 4 RTT before retransmitting.
12934 wait_multiplier = 4;
12935 }
12936
12937 // Depending on how much pending message the VirtualLink is queueing, we wait longer.
12938 // wait_multiplier = wait_multiplier * pm->vl->pending_msg_num;
12939
12941 "Wait multiplier %u\n",
12942 wait_multiplier);
12943
12944 /* Message not finished, waiting for acknowledgement.
12945 Update time by which we might retransmit 's' based on queue
12946 characteristics (i.e. RTT); it takes one RTT for the message to
12947 arrive and the ACK to come back in the best case; but the other
12948 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
12949 retransmitting.
12950
12951 OPTIMIZE: Note that in the future this heuristic should likely
12952 be improved further (measure RTT stability, consider message
12953 urgency and size when delaying ACKs, etc.) */
12954
12955 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us !=
12956 queue->pd.aged_rtt.rel_value_us)
12957 wait_duration = queue->pd.aged_rtt;
12958 else
12959 {
12960 wait_duration = DEFAULT_ACK_WAIT_DURATION;
12961 wait_multiplier = 4;
12962 }
12963 {
12966 wait_duration, wait_multiplier));
12968 wait_duration, wait_multiplier);
12970 "Waiting %s for ACK until %s\n",
12975 GNUNET_TIME_relative_multiply (wait_duration,
12976 wait_multiplier))
12977 );
12978 }
12979 }
12980 /* finally, re-schedule queue transmission task itself */
12982 queue,
12984}
12985
12986
12993static void
12994handle_del_queue_message (void *cls,
12995 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
12996{
12997 struct TransportClient *tc = cls;
12998
12999 if (CT_COMMUNICATOR != tc->type)
13000 {
13001 GNUNET_break (0);
13003 return;
13004 }
13005 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
13006 queue = queue->next_client)
13007 {
13008 struct Neighbour *neighbour = queue->neighbour;
13009
13010 if ((ntohl (dqm->qid) != queue->qid) ||
13011 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
13012 continue;
13014 "Dropped queue %s to peer %s\n",
13015 queue->address,
13016 GNUNET_i2s (&neighbour->pid));
13017 free_queue (queue);
13019 return;
13020 }
13021 /* Not finding the queue is a race, not a protocol violation: we may have
13022 freed it ourselves already, or the communicator may be tearing down a
13023 queue we never fully learned about. Do NOT drop the client over it --
13024 that runs #client_disconnect_cb(), which frees *every* queue this
13025 communicator owns, so one stale QUEUE_TEARDOWN would disconnect us from
13026 every peer it serves at once. Compare #handle_send_message_ack(), which
13027 tolerates the same lookup miss. */
13029 "QUEUE_TEARDOWN for unknown queue QID %u to peer %s ignored\n",
13030 ntohl (dqm->qid),
13031 GNUNET_i2s (&dqm->receiver));
13033 "# QUEUE_TEARDOWN dropped: queue unknown",
13034 1,
13035 GNUNET_NO);
13037}
13038
13039
13040static void
13042 struct TransportClient *tc)
13043{
13044 struct PendingMessage *pm;
13045
13046 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
13047 qe->queue->queue_tail,
13048 qe);
13049 qe->queue->queue_length--;
13050 tc->details.communicator.total_queue_length--;
13052 "Received ACK on queue %s (QID %u) to peer %s (new length: %u/%u)\n",
13053 qe->queue->address,
13054 qe->queue->qid,
13055 GNUNET_i2s (&qe->queue->neighbour->pid),
13056 qe->queue->queue_length,
13057 tc->details.communicator.total_queue_length);
13058
13059 /* if applicable, resume transmissions that waited on ACK */
13061 tc->details.communicator.total_queue_length)
13062 {
13063 /* Communicator dropped below threshold, resume all queues
13064 incident with this client! */
13066 GST_stats,
13067 "# Transmission throttled due to communicator queue limit",
13068 -1,
13069 GNUNET_NO);
13070 for (struct Queue *queue = tc->details.communicator.queue_head;
13071 NULL != queue;
13072 queue = queue->next_client)
13073 {
13075 queue,
13077 }
13078 }
13079 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
13080 {
13081 /* queue dropped below threshold; only resume this one queue */
13083 "# Transmission throttled due to queue queue limit",
13084 -1,
13085 GNUNET_NO);
13087 qe->queue,
13089 }
13090 else if (1 == qe->queue->q_capacity)
13091 {
13092 // TODO I guess this will never happen, because the communicator triggers this by updating its queue length itself.
13094 "Transmission rescheduled due to communicator message queue with qid %u has capacity %"
13095 PRIu64 ".\n",
13096 qe->queue->qid,
13097 qe->queue->q_capacity);
13098 /* message queue has capacity; only resume this one queue */
13099 /* queue dropped below threshold; only resume this one queue */
13101 "# Transmission throttled due to message queue capacity",
13102 -1,
13103 GNUNET_NO);
13105 qe->queue,
13107 }
13108
13109 if (NULL != (pm = qe->pm))
13110 {
13111 struct VirtualLink *vl;
13112
13113 // GNUNET_assert (qe == pm->qe);
13114 pm->qe = NULL;
13115 /* If waiting for this communicator may have blocked transmission
13116 of pm on other queues for this neighbour, force schedule
13117 transmit on queue for queues of the neighbour */
13118 if (NULL == pm->frag_parent)
13119 {
13120 vl = pm->vl;
13121 if ((NULL != vl) &&
13122 (NULL != vl->pending_msg_head) &&
13123 (vl->pending_msg_head == pm))
13125 }
13126 }
13127 GNUNET_free (qe);
13128}
13129
13130
13137static void
13138handle_send_message_ack (void *cls,
13139 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
13140{
13141 struct TransportClient *tc = cls;
13142 struct QueueEntry *qe;
13143 struct Queue *failed_queue = NULL;
13144
13145 if (CT_COMMUNICATOR != tc->type)
13146 {
13147 GNUNET_break (0);
13149 return;
13150 }
13151
13152 /* find our queue entry matching the ACK */
13153 qe = NULL;
13155 "Looking for queue for PID %s\n",
13156 GNUNET_i2s (&sma->receiver));
13157 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
13158 queue = queue->next_client)
13159 {
13160 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
13161 continue;
13163 "Found PID %s\n",
13164 GNUNET_i2s (&queue->neighbour->pid));
13165
13166
13167 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
13168 qep = qep->next)
13169 {
13170 if (qep->mid != GNUNET_ntohll (sma->mid) || queue->qid != ntohl (
13171 sma->qid))
13172 continue;
13174 "QueueEntry MID: %" PRIu64 " on queue QID: %u, Ack MID: %"
13175 PRIu64 " Ack QID %u\n",
13176 qep->mid,
13177 queue->qid,
13178 GNUNET_ntohll (sma->mid),
13179 ntohl (sma->qid));
13180 qe = qep;
13181 if ((NULL != qe->pm) && (qe->pm->qe != qe))
13183 "For pending message %" PRIu64 " we had retransmissions.\n",
13184 qe->pm->logging_uuid);
13185 break;
13186 }
13187 }
13188 if (GNUNET_OK != (int) ntohl (sma->status))
13189 {
13190 /* The communicator could not hand the message to the peer. The only
13191 thing that produces this today is #handle_send_msg()'s "queue no
13192 longer exists" branch in `transport_api_communication.c', i.e. the
13193 communicator has already torn the queue down on its side and the
13194 QUEUE_TEARDOWN is merely still in flight (or was lost).
13195
13196 Ignoring the status, as we used to, makes this self-sustaining:
13197 #free_queue_entry() releases the pending message and immediately
13198 reschedules transmission, #transmit_on_queue() picks the very same
13199 queue again -- transport still has it -- and we get another failure.
13200 Every round adds an envelope to the client MQ that is already
13201 congested, which is what shows up at the other end as
13202
13203 communicator INFO Transmission failed, queue no longer exists.
13204
13205 repeating at scheduler speed, and (because the service is busy
13206 servicing that loop) as
13207
13208 communicator WARNING Dropping message: transport is too slow,
13209 queue length N exceeded
13210
13211 on every *other* communicator. Treat the failure as the queue
13212 teardown it is and stop selecting this queue. */
13214 "Communicator could not send MID %" PRIu64
13215 " on QID %u to %s; dropping that queue\n",
13216 GNUNET_ntohll (sma->mid),
13217 ntohl (sma->qid),
13218 GNUNET_i2s (&sma->receiver));
13220 "# queues dropped (communicator send failed)",
13221 1,
13222 GNUNET_NO);
13223 if (NULL != qe)
13224 failed_queue = qe->queue;
13225 else
13226 for (struct Queue *queue = tc->details.communicator.queue_head;
13227 NULL != queue;
13228 queue = queue->next_client)
13229 if ((ntohl (sma->qid) == queue->qid) &&
13230 (0 == GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver)))
13231 {
13232 failed_queue = queue;
13233 break;
13234 }
13235 if (NULL != failed_queue)
13236 {
13237 /* #free_queue() releases every `struct QueueEntry' still on it --
13238 including @a qe -- and detaches their pending messages, so they are
13239 retried on whatever other queue this neighbour has. */
13240 free_queue (failed_queue);
13242 return;
13243 }
13244 }
13245 if (NULL == qe)
13246 {
13248 "No QueueEntry found for Ack MID %" PRIu64 " QID: %u\n",
13249 GNUNET_ntohll (sma->mid),
13250 ntohl (sma->qid));
13251 // TODO I guess this can happen, if the Ack from the peer comes before the Ack from the queue.
13252 // Update: Maybe QueueEntry was accidentally freed during freeing PendingMessage.
13253 /* this should never happen */
13254 // GNUNET_break (0);
13255 // GNUNET_SERVICE_client_drop (tc->client);
13257 return;
13258 }
13261}
13262
13263
13269static void
13270handle_burst_finished (void *cls,
13271 const struct GNUNET_TRANSPORT_BurstFinished *bf)
13272{
13273 struct TransportClient *tc = cls;
13274
13275 (void) bf;
13278}
13279
13280
13290static int
13291notify_client_queues (void *cls,
13292 const struct GNUNET_PeerIdentity *pid,
13293 void *value)
13294{
13295 struct TransportClient *tc = cls;
13296 struct Neighbour *neighbour = value;
13297
13298 GNUNET_assert (CT_MONITOR == tc->type);
13299 for (struct Queue *q = neighbour->queue_head; NULL != q;
13300 q = q->next_neighbour)
13301 {
13302 struct MonitorEvent me = { .rtt = q->pd.aged_rtt,
13303 .cs = q->cs,
13304 .num_msg_pending = q->num_msg_pending,
13305 .num_bytes_pending = q->num_bytes_pending };
13306
13307 notify_monitor (tc, pid, q->address, q->nt, &me);
13308 }
13309 return GNUNET_OK;
13310}
13311
13312
13319static void
13320handle_monitor_start (void *cls,
13322{
13323 struct TransportClient *tc = cls;
13324
13325 if (CT_NONE != tc->type)
13326 {
13327 GNUNET_break (0);
13329 return;
13330 }
13331 tc->type = CT_MONITOR;
13332 tc->details.monitor.peer = start->peer;
13333 tc->details.monitor.one_shot = ntohl (start->one_shot);
13337}
13338
13339
13343struct LinkListContext
13344{
13348 struct TransportClient *tc;
13349
13354};
13355
13356
13365static char *
13366communicator_list (struct Neighbour *n,
13367 unsigned int *num_queues)
13368{
13369 char *ret = GNUNET_strdup ("");
13370
13371 *num_queues = 0;
13372 if (NULL == n)
13373 return ret;
13374 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
13375 {
13376 const char *prefix = q->tc->details.communicator.address_prefix;
13377 size_t plen = strlen (prefix);
13378 const char *pos;
13379 char *tmp;
13380
13381 (*num_queues)++;
13382 if (0 == plen)
13383 continue;
13384 /* Several queues to one neighbour routinely share a communicator;
13385 name each one once. */
13386 for (pos = strstr (ret, prefix);
13387 NULL != pos;
13388 pos = strstr (pos + 1, prefix))
13389 if (((pos == ret) || (',' == pos[-1])) &&
13390 (('\0' == pos[plen]) || (',' == pos[plen])))
13391 break;
13392 if (NULL != pos)
13393 continue;
13394 GNUNET_asprintf (&tmp, "%s%s%s", ret, ('\0' == ret[0]) ? "" : ",", prefix);
13395 GNUNET_free (ret);
13396 ret = tmp;
13397 }
13398 return ret;
13399}
13400
13401
13410static enum GNUNET_GenericReturnValue
13411report_link (void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
13412{
13413 struct LinkListContext *llc = cls;
13414 struct VirtualLink *vl = value;
13416 struct GNUNET_MQ_Envelope *env;
13417 unsigned int pending = 0;
13418 unsigned int num_queues = 0;
13419 unsigned int distance = 0;
13420 struct Neighbour *hop;
13421 char *ccs;
13422 size_t clen;
13423
13424 if ((GNUNET_YES != llc->include_unconfirmed) &&
13425 (GNUNET_YES != vl->confirmed))
13426 return GNUNET_OK;
13427 for (struct PendingMessage *pm = vl->pending_msg_head;
13428 NULL != pm;
13429 pm = pm->next_vl)
13430 pending++;
13431 if (NULL != vl->n)
13432 {
13433 hop = vl->n;
13434 }
13435 else
13436 {
13437 /* Report the best (shortest) of the paths we currently know, and the
13438 communicators that carry its first hop. */
13439 struct DistanceVectorHop *best = NULL;
13440
13441 distance = UINT_MAX;
13442 if (NULL != vl->dv)
13443 for (struct DistanceVectorHop *pos = vl->dv->dv_head;
13444 NULL != pos;
13445 pos = pos->next_dv)
13446 if (pos->distance < distance)
13447 {
13448 distance = pos->distance;
13449 best = pos;
13450 }
13451 if (NULL == best)
13452 distance = 0; /* no paths left; report the link as adjacent */
13453 hop = (NULL != best) ? best->next_hop : NULL;
13454 }
13455 ccs = communicator_list (hop, &num_queues);
13456 clen = strlen (ccs) + 1;
13457 env = GNUNET_MQ_msg_extra (resp,
13458 clen,
13460 memcpy (&resp[1], ccs, clen);
13461 GNUNET_free (ccs);
13462 resp->target = *pid;
13463 resp->confirmed = htonl ((uint32_t) vl->confirmed);
13464 resp->route = htonl ((uint32_t) ((NULL != vl->n)
13467 resp->distance = htonl ((uint32_t) distance);
13468 resp->num_queues = htonl ((uint32_t) num_queues);
13469 resp->core_recv_window = htonl ((int32_t) vl->core_recv_window);
13470 resp->stalled = htonl ((uint32_t) vl->cmc_count);
13471 resp->pending = htonl (pending);
13472 resp->fc_retransmit_count = htonl ((uint32_t) vl->fc_retransmit_count);
13491 GNUNET_MQ_send (llc->tc->mq, env);
13492 return GNUNET_OK;
13493}
13494
13495
13504static void
13506 void *cls,
13508{
13509 struct TransportClient *tc = cls;
13510 struct LinkListContext llc = {
13511 .tc = tc,
13512 .include_unconfirmed = (int) ntohl (lr->include_unconfirmed)
13513 };
13514 struct GNUNET_MQ_Envelope *env;
13515 struct GNUNET_MessageHeader *end;
13516
13517 if (CT_NONE != tc->type)
13518 {
13519 GNUNET_break (0);
13521 return;
13522 }
13523 if (GNUNET_YES == GNUNET_is_zero (&lr->peer))
13524 {
13526 }
13527 else
13528 {
13529 struct VirtualLink *vl = lookup_virtual_link (&lr->peer);
13530
13531 if (NULL != vl)
13532 report_link (&llc, &lr->peer, vl);
13533 }
13536 GNUNET_MQ_send (tc->mq, env);
13538}
13539
13540
13548static struct TransportClient *
13549lookup_communicator (const char *prefix)
13550{
13551 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
13552 {
13553 if (CT_COMMUNICATOR != tc->type)
13554 continue;
13555 if (NULL == tc->details.communicator.address_prefix)
13556 continue; /* receive-only communicator */
13557 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
13558 return tc;
13559 }
13560 GNUNET_log (
13562 "Someone suggested use of communicator for `%s', but we do not have such a communicator!\n",
13563 prefix);
13564 return NULL;
13565}
13566
13567
13575static void
13576suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address)
13577{
13578 static uint32_t idgen = 0;
13579 struct TransportClient *tc;
13580 char *prefix;
13581 struct GNUNET_TRANSPORT_CreateQueue *cqm;
13582 struct GNUNET_MQ_Envelope *env;
13583 size_t alen;
13584
13586 if (NULL == prefix)
13587 {
13588 GNUNET_break (0); /* We got an invalid address!? */
13589 return;
13590 }
13592 if (NULL == tc)
13593 {
13595 "# Suggestions ignored due to missing communicator",
13596 1,
13597 GNUNET_NO);
13599 "Cannot connect to %s at `%s', no matching communicator present\n",
13600 GNUNET_i2s (pid),
13601 address);
13603 return;
13604 }
13605 /* forward suggestion for queue creation to communicator */
13607 "Request #%u for `%s' communicator to create queue to `%s' at `%s'\n",
13608 (unsigned int) idgen,
13609 prefix,
13610 GNUNET_i2s (pid),
13611 address);
13613 alen = strlen (address) + 1;
13614 env =
13616 cqm->request_id = htonl (idgen++);
13617 cqm->receiver = *pid;
13618 memcpy (&cqm[1], address, alen);
13619 GNUNET_MQ_send (tc->mq, env);
13620}
13621
13622
13630static void
13632{
13634 struct GNUNET_TIME_Absolute monotonic_time;
13635
13636 if (NULL != vs->revalidation_task)
13637 {
13638 GNUNET_SCHEDULER_cancel (vs->revalidation_task);
13639 vs->revalidation_task = NULL;
13640 }
13641 /*memcpy (&hkey,
13642 &hc,
13643 sizeof (hkey));*/
13645 "Remove key %s for address %s map size %u contains %u\n",
13646 GNUNET_h2s (&vs->hc),
13647 vs->address,
13650 &vs->hc));
13652
13654 if (GNUNET_TIME_UNIT_ZERO_ABS.abs_value_us ==
13655 vs->last_challenge_use.abs_value_us)
13656 {
13657 vs->first_challenge_use = monotonic_time;
13658 }
13659 vs->last_challenge_use = monotonic_time;
13660 tvc.header.type =
13662 tvc.header.size = htons (sizeof(tvc));
13663 tvc.reserved = htonl (0);
13664 tvc.challenge = vs->challenge;
13665 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
13667 "Sending address validation challenge %s to %s\n",
13669 GNUNET_i2s (&q->neighbour->pid));
13670 queue_send_msg (q, NULL, &tvc, sizeof(tvc));
13671}
13672
13673
13679static void
13680validation_start_cb (void *cls)
13681{
13682 struct ValidationState *vs;
13683 struct Queue *q;
13685 GST_cfg);
13686
13687 (void) cls;
13688 validation_task = NULL;
13690 /* drop validations past their expiration */
13691 while (
13692 (NULL != vs) &&
13694 {
13696 "Validation response %s cleaned up\n",
13697 GNUNET_sh2s (&vs->challenge.value));
13700 }
13701 if (NULL == vs)
13702 {
13704 "Address validation task not scheduled anymore, nothing to do\n");
13705 return; /* woopsie, no more addresses known, should only
13706 happen if we're really a lonely peer */
13707 }
13708 q = find_queue (&vs->pid, vs->address);
13709 if (GNUNET_TIME_absolute_cmp (vs->first_challenge_use, >, now))
13710 {
13712 "To early to start next address validation for challenge %s\n",
13713 GNUNET_sh2s (&vs->challenge.value));
13714 /* Do NOT just return: @e validation_task was set to NULL above and
13715 nothing re-arms it by itself. #update_next_challenge_time() only
13716 schedules us again when it is called with a *changed* time for some
13717 validation state, so bailing out here leaves a non-empty
13718 #validation_heap with no task attached: address (re)validation and
13719 the #suggest_to_connect() retries that go with it stop for *every*
13720 peer until some unrelated event happens to come along. A peer that
13721 just lost its only connection has no such events left. */
13724 now,
13725 vs->first_challenge_use),
13727 NULL);
13728 return;
13729 }
13730 if (NULL == q)
13731 {
13732 vs->awaiting_queue = GNUNET_YES;
13733 suggest_to_connect (&vs->pid, vs->address);
13734 }
13735 else
13737 /* Finally, reschedule next attempt */
13738 vs->challenge_backoff =
13739 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
13742 "Address validation task will run again in %s\n",
13743 GNUNET_STRINGS_relative_time_to_string (vs->challenge_backoff,
13744 GNUNET_YES));
13747 vs->challenge_backoff));
13748}
13749
13750
13755{
13759 struct Queue *q;
13760
13764 unsigned int quality_count;
13765
13769 unsigned int num_queues;
13770
13775 unsigned int k;
13776};
13777
13778
13790static int
13791check_connection_quality (void *cls,
13792 const struct GNUNET_PeerIdentity *pid,
13793 void *value)
13794{
13795 struct QueueQualityContext *ctx = cls;
13796 struct Neighbour *n = value;
13797 int do_inc;
13798
13799 (void) pid;
13800 do_inc = GNUNET_NO;
13801 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
13802 {
13803 ctx->num_queues++;
13804 if (0 == ctx->k--)
13805 ctx->q = q;
13806 /* FIXME-CONQ-STATISTICS: in the future, add reliability / goodput
13807 statistics and consider those as well here? */
13808 if (q->pd.aged_rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
13809 do_inc = GNUNET_YES;
13810 }
13811 if (GNUNET_YES == do_inc)
13812 ctx->quality_count++;
13813 return GNUNET_OK;
13814}
13815
13816
13828static void
13829start_dv_learn (void *cls);
13830
13831
13839static void
13841 struct LearnLaunchEntry *lle,
13842 struct QueueQualityContext qqc)
13843{
13844 if (0 == qqc.num_queues)
13845 {
13847 "# DV learn aborted: no queue left",
13848 1,
13849 GNUNET_NO);
13850 return;
13851 }
13852 qqc.quality_count = 0;
13854 qqc.num_queues = 0;
13855 qqc.q = NULL;
13858 &qqc);
13859 if (NULL == qqc.q)
13860 {
13862 "# DV learn aborted: no queue left",
13863 1,
13864 GNUNET_NO);
13865 return;
13866 }
13867
13868 /* Do this as close to transmission time as possible! */
13870
13871 queue_send_msg (qqc.q, NULL, &dvl, sizeof(dvl));
13872 /* reschedule this job, randomizing the time it runs (but no
13873 actual backoff!) */
13874 if (NULL != dvlearn_task)
13879 NULL);
13880}
13881
13882
13894static void
13895start_dv_learn (void *cls)
13896{
13897 struct LearnLaunchEntry *lle;
13898 struct QueueQualityContext qqc;
13899 struct TransportDVLearnMessage dvl;
13900 const struct GNUNET_PeerIdentity *my_identity;
13901
13902 (void) cls;
13903 dvlearn_task = NULL;
13904 if ((GNUNET_YES == in_shutdown) || (NULL == pils))
13905 return;
13907 return; /* lost all connectivity, cannot do learning */
13909 if (NULL == my_identity)
13910 {
13911 /* PILS has not handed us an identity yet. The first queue arriving
13912 schedules us with add_now(), which routinely wins that race; retry
13913 instead of taking the service down. */
13917 NULL);
13918 return;
13919 }
13921 qqc.quality_count = 0;
13922 qqc.num_queues = 0;
13926 &qqc);
13928 {
13929 struct GNUNET_TIME_Relative delay;
13930 unsigned int factor;
13931
13932 /* scale our retries by how far we are above the threshold */
13936 "At connection quality %u, will launch DV learn in %s\n",
13937 qqc.quality_count,
13940 return;
13941 }
13942 /* remove old entries in #dvlearn_map if it has grown too big */
13943 while (MAX_DV_LEARN_PENDING <=
13945 {
13946 lle = lle_tail;
13949 &lle->challenge.value,
13950 lle));
13952 GNUNET_free (lle);
13953 }
13954 /* setup data structure for learning */
13955 lle = GNUNET_new (struct LearnLaunchEntry);
13957 sizeof(lle->challenge));
13959 "Starting launch DV learn with challenge %s\n",
13960 GNUNET_sh2s (&lle->challenge.value));
13965 &lle->challenge.value,
13966 lle,
13969 dvl.header.size = htons (sizeof(dvl));
13970 dvl.num_hops = htons (0);
13971 dvl.bidirectional = htons (0);
13973 dvl.monotonic_time =
13975 // We will set the below again later
13976 memset (&dvl.init_sig, 0, sizeof dvl.init_sig);
13977 dvl.challenge = lle->challenge;
13978 dvl.initiator = *my_identity;
13979 {
13980 struct DvInitPS dvip = {
13981 .purpose.purpose = htonl (
13983 .purpose.size = htonl (sizeof(dvip)),
13984 .monotonic_time = dvl.monotonic_time,
13985 .challenge = lle->challenge
13986 };
13987
13988 if (GNUNET_OK != sign_by_my_identity (&dvip.purpose, &dvl.init_sig))
13989 return;
13990 }
13991 transmit_dv_init (dvl, lle, qqc);
13992}
13993
13994
14004static char *
14006{
14007 const char *dash;
14008 const char *colon;
14009
14010 if (NULL == address)
14011 return NULL;
14012 dash = strchr (address, '-');
14013 if (NULL == dash)
14014 return NULL;
14015 colon = strchr (dash, ':');
14016 if (NULL == colon)
14017 return NULL;
14018 return GNUNET_strndup (dash + 1,
14019 colon - (dash + 1));
14020}
14021
14022
14032static int
14034 const struct GNUNET_PeerIdentity *pid,
14035 void *value)
14036{
14037 struct Queue *q = cls;
14038 struct ValidationState *vs = value;
14039 char *address_without_port_vs;
14040 char *address_without_port_q;
14041 char *prefix_vs;
14042 char *prefix_q;
14043 int success = GNUNET_YES;
14044
14045 // TODO Check if this is really necessary.
14046 address_without_port_vs = get_address_without_port (vs->address);
14047 address_without_port_q = get_address_without_port (q->address);
14048 prefix_vs = GNUNET_HELLO_address_to_prefix (vs->address);
14049 prefix_q = GNUNET_HELLO_address_to_prefix (q->address);
14050
14052 "Check validation request pending for `%s' at `%s'/`%s' (vs)/(q)\n",
14053 GNUNET_i2s (pid),
14054 (NULL == address_without_port_vs) ? "<unparsable>"
14055 : address_without_port_vs,
14056 (NULL == address_without_port_q) ? "<unparsable>"
14057 : address_without_port_q);
14058 (void) pid;
14059 /* Only the port may differ: the address we asked to connect to is
14060 `PROTO-IP:0' for a NATed peer, while the queue that then materializes
14061 sits at `PROTO-IP:port'. The communicator must match all the same --
14062 a challenge for a `tcp-' address is not answered by a `udp-' queue. */
14063 if ((GNUNET_YES == vs->awaiting_queue) &&
14064 (NULL != address_without_port_vs) &&
14065 (NULL != address_without_port_q) &&
14066 (NULL != prefix_vs) &&
14067 (NULL != prefix_q) &&
14068 (0 == strcmp (prefix_vs, prefix_q)) &&
14069 (0 == strcmp (address_without_port_vs, address_without_port_q)))
14070 {
14071
14072 vs->awaiting_queue = GNUNET_NO;
14074 success = GNUNET_NO;
14075 }
14076
14077 GNUNET_free (address_without_port_vs);
14078 GNUNET_free (address_without_port_q);
14079 GNUNET_free (prefix_vs);
14080 GNUNET_free (prefix_q);
14081 return success;
14082}
14083
14084
14093static void
14094neighbour_dv_monotime_cb (void *cls,
14095 const struct GNUNET_PEERSTORE_Record *record,
14096 const char *emsg)
14097{
14098 struct Neighbour *n = cls;
14099 struct GNUNET_TIME_AbsoluteNBO *mtbe;
14100
14101 (void) emsg;
14102 if (NULL == record)
14103 {
14104 /* we're done with #neighbour_dv_monotime_cb() invocations,
14105 continue normal processing */
14106 n->get = NULL;
14108 return;
14109 }
14110 if (0 == record->value_size)
14111 {
14113 GNUNET_break (0);
14114 return;
14115 }
14116 mtbe = record->value;
14121}
14122
14123
14124static void
14126 const struct GNUNET_PeerIdentity *pid,
14127 const char *uri)
14128{
14129 struct Queue *queue = cls;
14130 struct sockaddr_in v4;
14131 const char *slash;
14132 char *address_uri;
14133 char *prefix;
14134 char *uri_without_port;
14135 char *address_uri_without_port;
14136
14137 slash = strrchr (uri, '/');
14138 if ((NULL == slash) || (slash - uri < 2))
14139 {
14140 GNUNET_break_op (0); /* @a uri comes from a remote HELLO */
14141 return;
14142 }
14143 prefix = GNUNET_strndup (uri, (slash - uri) - 2);
14144 slash++;
14145 GNUNET_asprintf (&address_uri,
14146 "%s-%s",
14147 prefix,
14148 slash);
14149
14151 "1 not global natted_address %u %s %s %s\n",
14152 queue->is_global_natted,
14153 uri,
14154 queue->address,
14155 slash);
14156
14157 uri_without_port = get_address_without_port (address_uri);
14158 if ((NULL == uri_without_port) ||
14159 (1 != inet_pton (AF_INET, uri_without_port, &v4.sin_addr)))
14160 {
14162 GNUNET_free (address_uri);
14163 GNUNET_free (uri_without_port);
14164 return;
14165 }
14166
14168 "2 not global natted_address %u %s %s\n",
14169 queue->is_global_natted,
14170 uri,
14171 queue->address);
14172
14173 if (GNUNET_NO == queue->is_global_natted)
14174 {
14176 GNUNET_free (address_uri);
14177 GNUNET_free (uri_without_port);
14178 return;
14179 }
14180
14182 "3 not global natted_address %u %s %s\n",
14183 queue->is_global_natted,
14184 uri,
14185 queue->address);
14186
14187 if (0 == strcmp (uri_without_port, address_uri))
14188 {
14190 GNUNET_free (address_uri);
14191 GNUNET_free (uri_without_port);
14192 return;
14193 }
14194
14196 "4 not global natted_address %u %s %s\n",
14197 queue->is_global_natted,
14198 uri,
14199 queue->address);
14200
14201 address_uri_without_port = get_address_without_port (queue->address);
14202 if ((NULL != address_uri_without_port) &&
14203 (0 == strcmp (uri_without_port, address_uri_without_port)))
14204 {
14205 queue->is_global_natted = GNUNET_NO;
14206 }
14207
14209 "not global natted_address %u %s %s %s %s %s %u\n",
14210 queue->is_global_natted,
14211 uri,
14212 queue->address,
14213 uri_without_port,
14214 address_uri_without_port,
14215 prefix,
14216 GNUNET_NO);
14218 GNUNET_free (address_uri);
14219 GNUNET_free (address_uri_without_port);
14220 GNUNET_free (uri_without_port);
14221}
14222
14223
14225{
14229 char *addr;
14230
14235};
14236
14237
14238static enum GNUNET_GenericReturnValue
14239contains_address (void *cls,
14240 const struct GNUNET_PeerIdentity *pid,
14241 void *value)
14242{
14243 struct TransportGlobalNattedAddressClosure *tgna_cls = cls;
14244 struct TransportGlobalNattedAddress *tgna = value;
14245 char *addr = (char *) &tgna[1];
14246
14247 /* NOTE: @a addr is NOT 0-terminated. */
14249 "Checking tgna %p with addr %.*s and length %u compare length %lu\n",
14250 tgna,
14251 (int) ntohl (tgna->address_length),
14252 addr,
14253 ntohl (tgna->address_length),
14254 strlen (tgna_cls->addr));
14255 if (strlen (tgna_cls->addr) == ntohl (tgna->address_length)
14256 && 0 == strncmp (addr, tgna_cls->addr, ntohl (tgna->address_length)))
14257 {
14258 tgna_cls->tgna = tgna;
14259 return GNUNET_NO;
14260 }
14261 return GNUNET_YES;
14262}
14263
14264
14265static void
14267{
14269 "Error in PEERSTORE monitoring for checking global natted\n");
14270}
14271
14272
14273static void
14275{
14277 "Done with initial PEERSTORE iteration during monitoring for checking global natted\n");
14278}
14279
14280
14281static void
14282check_for_global_natted (void *cls,
14283 const struct GNUNET_PEERSTORE_Record *record,
14284 const char *emsg)
14285{
14286 struct Queue *queue = cls;
14287 struct Neighbour *neighbour = queue->neighbour;
14289 const struct GNUNET_MessageHeader *hello;
14291 size_t address_len_without_port;
14292
14293 if (NULL != emsg)
14294 {
14296 "Got failure from PEERSTORE: %s\n",
14297 emsg);
14299 return;
14300 }
14301 if (NULL == record)
14302 {
14303 GNUNET_break (0);
14305 return;
14306 }
14307 /* @a hello was published by a remote peer and may be malformed. */
14308 hello = hello_from_record (record);
14309 if (NULL == hello)
14310 {
14312 return;
14313 }
14314 queue->is_global_natted = GNUNET_YES;
14315 parser = GNUNET_HELLO_parser_from_msg (hello, &record->peer);
14316 if (NULL == parser)
14317 {
14319 "HELLO cannot be parsed!\n");
14321 return;
14322 }
14324 "before not global natted %u\n",
14325 queue->is_global_natted);
14328 queue);
14330 "after not global natted %u\n",
14331 queue->is_global_natted);
14332 GNUNET_HELLO_parser_free (parser);
14333
14334 tgna_cls.addr = get_address_without_port (queue->address);
14335 if (NULL == tgna_cls.addr)
14336 {
14337 GNUNET_break (0);
14339 return;
14340 }
14341 address_len_without_port = strlen (tgna_cls.addr);
14342 /*{
14343 char buf[address_len_without_port + 1];
14344
14345 GNUNET_memcpy (&buf, addr, address_len_without_port);
14346 buf[address_len_without_port] = '\0';
14347 GNUNET_free (addr);
14348 GNUNET_memcpy (tgna_cls.addr, buf, address_len_without_port + 1);
14349 }*/
14350 tgna_cls.tgna = NULL;
14352 &neighbour->pid,
14354 &tgna_cls);
14355 if (NULL != tgna_cls.tgna)
14357 " tgna_cls.tgna tgna %p %lu %u %u\n",
14358 tgna_cls.tgna,
14359 neighbour->size_of_global_addresses,
14360 ntohl (tgna_cls.tgna->address_length),
14361 neighbour->number_of_addresses);
14362 if (NULL == tgna_cls.tgna && GNUNET_YES == queue->is_global_natted)
14363 {
14364 struct TransportGlobalNattedAddress *tgna;
14365
14366 tgna = GNUNET_malloc (sizeof (struct TransportGlobalNattedAddress)
14367 + address_len_without_port);
14368 tgna->address_length = htonl (address_len_without_port);
14369 GNUNET_memcpy (&tgna[1], tgna_cls.addr, address_len_without_port);
14371 &neighbour->pid,
14372 tgna,
14374 neighbour->number_of_addresses++;
14375 /* MUST match what is subtracted on removal (and what
14376 #add_global_addresses() actually copies), or the accounting drifts. */
14377 neighbour->size_of_global_addresses += address_len_without_port;
14379 "Created tgna %p with address %s and length %lu\n",
14380 tgna,
14381 tgna_cls.addr,
14382 address_len_without_port + 1);
14383 }
14384 else if (NULL != tgna_cls.tgna && GNUNET_NO == queue->is_global_natted)
14385 {
14387 &neighbour->pid,
14388 tgna_cls.tgna);
14389 GNUNET_assert (neighbour->size_of_global_addresses >= ntohl (tgna_cls.tgna->
14391 );
14392 neighbour->size_of_global_addresses -= ntohl (tgna_cls.tgna->address_length)
14393 ;
14394 GNUNET_assert (0 < neighbour->number_of_addresses);
14395 neighbour->number_of_addresses--;
14397 "removed tgna %p\n",
14398 tgna_cls.tgna);
14399 GNUNET_free (tgna_cls.tgna);
14400 }
14402 GNUNET_free (tgna_cls.addr);
14403}
14404
14405
14412static void
14413handle_add_queue_message (void *cls,
14414 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
14415{
14416 struct TransportClient *tc = cls;
14417 struct Queue *queue;
14418 struct Neighbour *neighbour;
14419 const char *addr;
14420 uint16_t addr_len;
14421
14422 if (ntohl (aqm->mtu) <= sizeof(struct TransportFragmentBoxMessage))
14423 {
14424 /* MTU so small as to be useless for transmissions,
14425 required for #fragment_message()! */
14426 GNUNET_break_op (0);
14428 return;
14429 }
14430 /* This may simply be a queue update. Match on the peer as well as the
14431 QID: the communicator's key for a queue is the pair, and
14432 #handle_send_msg() on its side looks both of them up. Matching on the
14433 QID alone let an ADD_QUEUE for a *different* peer be folded into an
14434 existing queue, leaving @e neighbour pointing at the old peer -- after
14435 which every SEND_MSG we put on it carries a receiver the communicator
14436 cannot match, and comes straight back as "queue no longer exists". */
14437 for (queue = tc->details.communicator.queue_head;
14438 NULL != queue;
14439 queue = queue->next_client)
14440 {
14441 if (queue->qid != ntohl (aqm->qid))
14442 continue;
14443 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &aqm->receiver))
14444 continue;
14445 break;
14446 }
14447
14448 if (NULL != queue)
14449 {
14450 neighbour = queue->neighbour;
14451 }
14452 else
14453 {
14454 struct GNUNET_TIME_Absolute validated_until = GNUNET_TIME_UNIT_ZERO_ABS;
14455
14456 neighbour = lookup_neighbour (&aqm->receiver);
14457 if (NULL == neighbour)
14458 {
14459 neighbour = GNUNET_new (struct Neighbour);
14461 GNUNET_YES);
14462 neighbour->pid = aqm->receiver;
14463 /* Give a fresh neighbour a full window to say something. */
14464 neighbour->last_inbound = GNUNET_TIME_absolute_get ();
14467 neighbours,
14468 &neighbour->pid,
14469 neighbour,
14471 neighbour->get =
14473 "transport",
14474 &neighbour->pid,
14477 neighbour);
14478 }
14479 addr_len = ntohs (aqm->header.size) - sizeof(*aqm);
14480 addr = (const char *) &aqm[1];
14482 "New queue %s to %s available with QID %u and q_len %" PRIu64
14483 " and mtu %u\n",
14484 addr,
14485 GNUNET_i2s (&aqm->receiver),
14486 ntohl (aqm->qid),
14487 GNUNET_ntohll (aqm->q_len),
14488 ntohl (aqm->mtu));
14489 queue = GNUNET_malloc (sizeof(struct Queue) + addr_len);
14490 queue->tc = tc;
14491 for (struct Queue *q = neighbour->queue_head; NULL != q; q = q->
14492 next_neighbour)
14493 validated_until = GNUNET_TIME_absolute_max (validated_until, q->
14494 validated_until);
14495 /* Inherit the validity of the sibling queues, but only while it is
14496 still in the future -- copying an already expired timestamp is
14497 pointless (and the condition used to be inverted). */
14498 if (0 != GNUNET_TIME_absolute_get_remaining (validated_until).rel_value_us)
14499 {
14501 "New queue with QID %u inherit validated until\n",
14502 ntohl (aqm->qid));
14503 queue->validated_until = validated_until;
14504 }
14505 queue->address = (const char *) &queue[1];
14506 queue->pd.aged_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
14507 queue->qid = ntohl (aqm->qid);
14508 queue->neighbour = neighbour;
14510 queue->unlimited_length = GNUNET_YES;
14511 queue->q_capacity = GNUNET_ntohll (aqm->q_len);
14512 memcpy (&queue[1], addr, addr_len);
14513 /* notify monitors about new queue */
14514 {
14515 struct MonitorEvent me = { .rtt = queue->pd.aged_rtt, .cs = queue->cs };
14516
14517 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
14518 }
14520 neighbour->queue_head,
14521 neighbour->queue_tail,
14522 queue);
14524 tc->details.communicator.queue_head,
14525 tc->details.communicator.queue_tail,
14526 queue);
14527
14528 }
14529 queue->mtu = ntohl (aqm->mtu);
14530 queue->nt = ntohl (aqm->nt);
14531 queue->cs = ntohl (aqm->cs);
14532 queue->idle = GNUNET_YES;
14533
14534 if (NULL == queue->mo)
14535 {
14536 /* Only for a NEW queue: on a queue update this used to start a second
14537 monitor and leak the first one. */
14538 struct sockaddr_in v4;
14539 char *addr_without = get_address_without_port (queue->address);
14540 if ((NULL != addr_without) &&
14541 (1 == inet_pton (AF_INET, addr_without, &v4.sin_addr)))
14542 {
14544 "start not global natted\n");
14546 GNUNET_YES,
14547 "peerstore",
14548 &neighbour->pid,
14550 &
14552 NULL,
14553 &
14555 NULL,
14557 queue);
14558 }
14559 GNUNET_free (addr_without);
14560 }
14561 /* check if valdiations are waiting for the queue */
14563 &aqm->receiver))
14566 &aqm->receiver,
14568 queue);
14569 /* Always (also) validate the address of the queue itself. A pending
14570 validation served above may well be for a *different* address string:
14571 #check_validation_request_pending() matches on the IP only, so a
14572 validation state waiting for the NAT address `PROTO-IP:0' is happily
14573 satisfied by a queue at `PROTO-IP:12345'. If we stopped here,
14574 #handle_validation_response() would later look for a queue at
14575 `PROTO-IP:0' -- which never exists -- and drop the successful
14576 validation on the floor without ever creating the virtual link. That
14577 is exactly what happens to the second of two peers behind the same
14578 NAT, as both of them advertise the very same `PROTO-IP:0'. */
14579 start_address_validation (&aqm->receiver, queue->address);
14580 /* look for traffic for this queue */
14581 // TODO Check whether this makes any sense at all.
14582 /*schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
14583 queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);*/
14584 /* might be our first queue, try launching DV learning */
14585 if (NULL == dvlearn_task)
14588}
14589
14590
14597static void
14599 const struct
14601{
14602 struct TransportClient *tc = cls;
14603 struct Queue *target_queue = NULL;
14604
14605 if (CT_COMMUNICATOR != tc->type)
14606 {
14607 /* Without this we walk `details.communicator.queue_head' for a client
14608 whose union holds something else entirely. */
14609 GNUNET_break (0);
14611 return;
14612 }
14614 "Received queue update message for %u with q_len %llu and mtu %u\n",
14615 ntohl (msg->qid),
14616 (unsigned long long) GNUNET_ntohll (msg->q_len),
14617 ntohl (msg->mtu));
14618 for (target_queue = tc->details.communicator.queue_head;
14619 NULL != target_queue;
14620 target_queue = target_queue->next_client)
14621 {
14622 if (ntohl (msg->qid) == target_queue->qid)
14623 break;
14624 }
14625 if (NULL == target_queue)
14626 {
14628 "Queue to update no longer exists! Discarding update.\n");
14630 return;
14631 }
14632
14633 target_queue->nt = ntohl (msg->nt);
14634 target_queue->mtu = ntohl (msg->mtu);
14635 target_queue->cs = ntohl (msg->cs);
14636 target_queue->priority = ntohl (msg->priority);
14637 /* The update message indicates how many messages
14638 * the queue should be able to handle.
14639 */
14641 target_queue->unlimited_length = GNUNET_YES;
14642 else
14643 target_queue->unlimited_length = GNUNET_NO;
14644 target_queue->q_capacity += GNUNET_ntohll (msg->q_len);
14645 if (0 < target_queue->q_capacity)
14647 target_queue,
14650}
14651
14652
14660static void
14661handle_queue_create_ok (void *cls,
14662 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
14663{
14664 struct TransportClient *tc = cls;
14665
14666 if (CT_COMMUNICATOR != tc->type)
14667 {
14668 GNUNET_break (0);
14670 return;
14671 }
14673 "# Suggestions succeeded at communicator",
14674 1,
14675 GNUNET_NO);
14677 "Request #%u for communicator to create queue succeeded\n",
14678 (unsigned int) ntohs (cqr->request_id));
14680}
14681
14682
14691static void
14693 void *cls,
14694 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
14695{
14696 struct TransportClient *tc = cls;
14697
14698 if (CT_COMMUNICATOR != tc->type)
14699 {
14700 GNUNET_break (0);
14702 return;
14703 }
14705 "Request #%u for communicator to create queue failed\n",
14706 (unsigned int) ntohl (cqr->request_id));
14708 "# Suggestions failed in queue creation at communicator",
14709 1,
14710 GNUNET_NO);
14712}
14713
14714
14722static void
14723handle_suggest_cancel (void *cls, const struct ExpressPreferenceMessage *msg)
14724{
14725 struct TransportClient *tc = cls;
14726 struct PeerRequest *pr;
14727
14728 if (CT_APPLICATION != tc->type)
14729 {
14730 GNUNET_break (0);
14732 return;
14733 }
14734 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
14735 &msg->peer);
14736 if (NULL == pr)
14737 {
14738 GNUNET_break (0);
14740 return;
14741 }
14742 (void) stop_peer_request (tc, &pr->pid, pr);
14744}
14745
14746
14747static void
14748hello_for_client_cb (void *cls,
14749 const struct GNUNET_PeerIdentity *pid,
14750 const char *uri)
14751{
14752 struct Queue *q;
14753 int pfx_len;
14754 const char *eou;
14755 char *address;
14756 (void) cls;
14757
14758 eou = strstr (uri,
14759 "://");
14760 pfx_len = eou - uri;
14761 eou += 3;
14763 "%.*s-%s",
14764 pfx_len,
14765 uri,
14766 eou);
14767
14769 "hello for client %s\n",
14770 address);
14771
14772 q = find_queue (pid, address);
14773 if (NULL == q)
14774 {
14776 }
14777 else
14780}
14781
14782
14790static void
14791handle_hello_for_client (void *cls,
14792 const struct GNUNET_PEERSTORE_Record *record,
14793 const char *emsg)
14794{
14795 const struct GNUNET_PeerIdentity *my_identity;
14796 struct PeerRequest *pr = cls;
14798 const struct GNUNET_MessageHeader *hello;
14799
14800 if (NULL != emsg)
14801 {
14803 "Got failure from PEERSTORE: %s\n",
14804 emsg);
14806 return;
14807 }
14808 if (NULL == record)
14809 {
14810 GNUNET_break (0);
14812 return;
14813 }
14815 if (NULL == my_identity)
14816 {
14818 "No identity given yet!\n");
14820 return;
14821 }
14822 hello = hello_from_record (record);
14823 if (NULL == hello)
14824 {
14825 /* MUST still ask for the next record: a bad one is not a reason to
14826 stall this monitor forever. */
14828 return;
14829 }
14830 if (0 == GNUNET_memcmp (&record->peer, my_identity))
14831 {
14833 return;
14834 }
14835 parser = GNUNET_HELLO_parser_from_msg (hello, &record->peer);
14836 if (NULL == parser)
14837 {
14839 "HELLO cannot be parsed!\n");
14841 return;
14842 }
14844 "HELLO for `%s' could be parsed, iterating addresses...!\n",
14848 NULL);
14849 GNUNET_HELLO_parser_free (parser);
14850 /* MUST ask for the next record, or this monitor stalls after one HELLO */
14852}
14853
14854
14855static void
14856hello_for_client_error_cb (void *cls)
14857{
14859 "Error in PEERSTORE monitoring\n");
14860}
14861
14862
14863static void
14864hello_for_client_sync_cb (void *cls)
14865{
14867 "Done with initial PEERSTORE iteration during monitoring\n");
14868}
14869
14870
14878static void
14879handle_suggest (void *cls, const struct ExpressPreferenceMessage *msg)
14880{
14881 struct TransportClient *tc = cls;
14882 const struct GNUNET_PeerIdentity *my_identity;
14883 struct PeerRequest *pr;
14884
14885 if (CT_NONE == tc->type)
14886 {
14887 tc->type = CT_APPLICATION;
14888 tc->details.application.requests =
14890 }
14891 if (CT_APPLICATION != tc->type)
14892 {
14893 GNUNET_break (0);
14895 return;
14896 }
14898 if (NULL == my_identity)
14899 {
14901 "Still waiting for own identity!\n");
14903 return;
14904 }
14906 "Client suggested we talk to %s with preference %d at rate %u\n",
14907 GNUNET_i2s (&msg->peer),
14908 (int) ntohl (msg->pk),
14909 (int) ntohl (msg->bw.value__));
14910 if (0 == GNUNET_memcmp (my_identity, &msg->peer))
14911 {
14913 "Client suggested connection to ourselves, ignoring...\n");
14915 return;
14916 }
14917 pr = GNUNET_new (struct PeerRequest);
14918 pr->tc = tc;
14919 pr->pid = msg->peer;
14920 pr->bw = msg->bw;
14921 pr->pk = ntohl (msg->pk);
14923 tc->details.application.requests,
14924 &pr->pid,
14925 pr,
14927 {
14928 GNUNET_break (0);
14929 GNUNET_free (pr);
14931 return;
14932 }
14933 pr->nc =
14935 GNUNET_YES,
14936 "peerstore",
14937 NULL,
14940 NULL,
14942 NULL,
14944 pr);
14946}
14947
14948
14957static int
14959 const struct RequestHelloValidationMessage *m)
14960{
14961 (void) cls;
14963 return GNUNET_OK;
14964}
14965
14966
14974static void
14976 const struct RequestHelloValidationMessage *m)
14977{
14978 struct TransportClient *tc = cls;
14979 struct Queue *q;
14980
14981 q = find_queue (&m->peer, (const char *) &m[1]);
14982 if (NULL == q)
14983 {
14984 suggest_to_connect (&m->peer, (const char *) &m[1]);
14985 }
14986 else
14987 start_address_validation (&m->peer, (const char *) &m[1]);
14989}
14990
14991
15000static int
15001free_neighbour_cb (void *cls,
15002 const struct GNUNET_PeerIdentity *pid,
15003 void *value)
15004{
15005 struct Neighbour *neighbour = value;
15006
15007 (void) cls;
15008 (void) pid;
15009 GNUNET_break (0); // should this ever happen?
15010 free_neighbour (neighbour, GNUNET_YES);
15011
15012 return GNUNET_OK;
15013}
15014
15015
15030static int
15031free_virtual_link_cb (void *cls,
15032 const struct GNUNET_PeerIdentity *pid,
15033 void *value)
15034{
15035 struct VirtualLink *vl = value;
15036
15037 (void) cls;
15038 (void) pid;
15039 free_virtual_link (vl);
15040
15041 return GNUNET_OK;
15042}
15043
15044
15053static int
15054free_dv_routes_cb (void *cls,
15055 const struct GNUNET_PeerIdentity *pid,
15056 void *value)
15057{
15058 struct DistanceVector *dv = value;
15059
15060 (void) cls;
15061 (void) pid;
15062 free_dv_route (dv);
15063
15064 return GNUNET_OK;
15065}
15066
15067
15076static int
15077free_validation_state_cb (void *cls,
15078 const struct GNUNET_PeerIdentity *pid,
15079 void *value)
15080{
15081 struct ValidationState *vs = value;
15082
15083 (void) cls;
15084 (void) pid;
15086 return GNUNET_OK;
15087}
15088
15089
15098static int
15099free_pending_ack_cb (void *cls, const struct GNUNET_Uuid *key, void *value)
15100{
15101 struct PendingAcknowledgement *pa = value;
15102
15103 (void) cls;
15104 (void) key;
15106 return GNUNET_OK;
15107}
15108
15109
15118static int
15119free_ack_cummulator_cb (void *cls,
15120 const struct GNUNET_PeerIdentity *pid,
15121 void *value)
15122{
15123 struct AcknowledgementCummulator *ac = value;
15124
15125 (void) cls;
15126 (void) pid;
15128 GNUNET_free (ac);
15129 return GNUNET_OK;
15130}
15131
15132
15139static void
15140do_shutdown (void *cls)
15141{
15142 static int shutdown_done;
15143 struct LearnLaunchEntry *lle;
15144 struct PilsRequest *pr;
15145 (void) cls;
15146
15148 "shutdown logic\n");
15149 if (GNUNET_YES == shutdown_done)
15150 return; /* reachable both from #shutdown_task() and #client_disconnect_cb() */
15151 shutdown_done = GNUNET_YES;
15152 if (NULL != client_grace_task)
15153 {
15155 client_grace_task = NULL;
15156 }
15157 if (NULL != nh)
15158 {
15160 nh = NULL;
15161 }
15163 &free_neighbour_cb, NULL);
15164 /* Freeing a neighbour takes its virtual link with it, so whatever is
15165 left here is ownerless: a link we created from an inbound FLOW_CONTROL
15166 message that never got confirmed, kept alive only by its @e
15167 unconfirmed_timeout_task. #GNUNET_SCHEDULER_shutdown() does not run
15168 that task, so leaving the link in place left the task armed against a
15169 map we destroy further down -- it fired afterwards and
15170 #free_virtual_link() called GNUNET_CONTAINER_multipeermap_remove() on
15171 NULL. Drop them here, while every structure they touch is still
15172 alive. */
15175 NULL);
15176 if (NULL != validation_task)
15177 {
15179 validation_task = NULL;
15180 }
15181 if (NULL != dvlearn_task)
15182 {
15184 dvlearn_task = NULL;
15185 }
15186 if (NULL != burst_task)
15187 {
15189 burst_task = NULL;
15190 }
15191 if (NULL != burst_timeout_task)
15192 {
15194 burst_timeout_task = NULL;
15195 }
15198 dvlearn_map = NULL;
15201 dv_routes = NULL;
15202 if (NULL != GST_stats)
15203 {
15205 GST_stats = NULL;
15206 }
15207 if (NULL != GST_my_hello)
15208 {
15210 GST_my_hello = NULL;
15211 }
15214 NULL);
15216 ack_cummulators = NULL;
15219 NULL);
15221 pending_acks = NULL;
15224 neighbours = NULL;
15227 links = NULL;
15230 NULL);
15232 backtalkers = NULL;
15235 NULL);
15237 validation_map = NULL;
15239 validation_heap = NULL;
15241 revalidation_map = NULL;
15242 while (NULL != ir_head)
15244 GNUNET_assert (0 == ir_total);
15245 while (NULL != (lle = lle_head))
15246 {
15248 GNUNET_free (lle);
15249 }
15250 while (NULL != (pr = pils_requests_head))
15251 {
15254 pr);
15255 if (NULL != pr->op)
15256 GNUNET_PILS_cancel (pr->op);
15257 GNUNET_free (pr);
15258 }
15259 if (NULL != pils_feed_task)
15260 {
15262 pils_feed_task = NULL;
15263 }
15264 if (NULL != pils)
15265 {
15267 pils = NULL;
15268 }
15269 if (NULL != peerstore)
15270 {
15272 "Disconnecting from PEERSTORE service\n");
15274 peerstore = NULL;
15275 }
15277}
15278
15279
15280static const char*
15282{
15283 switch (type)
15284 {
15285 case CT_CORE:
15286 return "CORE";
15287 case CT_MONITOR:
15288 return "MONITOR";
15289 case CT_COMMUNICATOR:
15290 return "COMMUNICATOR";
15291 case CT_APPLICATION:
15292 return "APPLICATION";
15293 default:
15294 return "UNKNOWN";
15295 }
15296}
15297
15298
15306static void
15307drop_remaining_clients (void *cls)
15308{
15309 client_grace_task = NULL;
15310 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
15311 {
15313 "Client did not disconnect within the shutdown grace period, "
15314 "dropping it: %s\n",
15315 get_client_type_name (tc->type));
15316 }
15317 /* We use #GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN, so the service will NOT
15318 drop clients for us. Without this we would wait forever for them to
15319 leave on their own and never reach #do_shutdown(). */
15321 /* Dropping the clients ran #client_disconnect_cb() for each of them, so
15322 #do_shutdown() has normally run by now; it is idempotent, and this
15323 covers the case where there was nothing left to drop. */
15324 do_shutdown (cls);
15325}
15326
15327
15328static void
15329shutdown_task (void *cls)
15330{
15332
15334 "Shutdown task executed\n");
15335 if (NULL != clients_head)
15336 {
15337 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
15338 {
15340 "Waiting for client to disconnect: %s\n",
15341 get_client_type_name (tc->type));
15342 }
15343 /* Give them a chance to shut down cleanly; #client_disconnect_cb() calls
15344 #do_shutdown() once the last one is gone, and #do_shutdown() cancels
15345 this task. */
15349 cls);
15350 return;
15351 }
15352 do_shutdown (cls);
15353}
15354
15355
15357{
15359};
15360
15361static void
15362update_hello_from_pid_change_cb (void *cls, int success)
15363{
15364 struct UpdateHelloFromPidCtx *pc = cls;
15365
15366 /* NOTE: @a success is GNUNET_OK even when #hello_add_iter() decided not to
15367 store anything because PEERSTORE already holds a HELLO that expires
15368 later; the API reports the desired state, not whether it wrote. So this
15369 says "we have a current HELLO on record", not "we just wrote one". */
15370 if (GNUNET_OK != success)
15372 "Failed to store our new hello with peerstore\n");
15373 else
15375 "Our hello is current in peerstore\n");
15376 GNUNET_free (pc);
15377}
15378
15379
15380void
15381print_address_list (void *cls,
15382 const struct GNUNET_PeerIdentity *pid,
15383 const char *uri)
15384{
15386 "%s\n", uri);
15387}
15388
15389
15399static void
15400pils_pid_change_cb (void *cls,
15401 const struct GNUNET_HELLO_Parser *parser,
15402 const struct GNUNET_HashCode *hash)
15403{
15404 const struct GNUNET_PeerIdentity *my_identity;
15405 struct GNUNET_MQ_Envelope *env;
15406 const struct GNUNET_MessageHeader *msg;
15407 struct UpdateHelloFromPidCtx *sc;
15408 struct GNUNET_HELLO_Builder *nbuilder;
15409 struct GNUNET_PeerIdentity npid;
15410
15413
15414 if (NULL == GST_my_hello)
15417 "My current identity is `%s'\n",
15429 nbuilder = GNUNET_HELLO_builder_from_parser (parser,
15430 &npid);
15431 if (GNUNET_NO ==
15433 {
15435 "New PID from PILS is derived from address list inconsistent with ours. Ignoring...\n");
15437 "Proposed address list:\n");
15440 "Current address list:\n");
15442 GNUNET_HELLO_builder_free (nbuilder);
15443 return;
15444 }
15446 GST_my_hello = nbuilder;
15448 "My new identity is `%s'\n",
15454 msg,
15456 sc);
15457 GNUNET_free (env);
15458}
15459
15460
15468static void
15469run (void *cls,
15470 const struct GNUNET_CONFIGURATION_Handle *c,
15472{
15473 (void) cls;
15474 /* setup globals */
15478 GST_cfg = c;
15486 GNUNET_YES);
15491 // TODO check for all uses of GST_my_hello that it is not used uninitialized
15493 "transport",
15494 "USE_BURST_NAT");
15495 if (GNUNET_SYSERR == use_burst)
15497 "Could not configure burst nat use. Default to no.\n");
15503 "transport",
15504 0,
15505 0,
15506 NULL,
15507 0,
15508 NULL,
15509 NULL,
15510 NULL);
15511 if (NULL == peerstore)
15512 {
15513 GNUNET_break (0);
15515 return;
15516 }
15519 NULL); // FIXME we need to wait for
15520 // our first peer id before
15521 // we can start the service
15522 // completely - PILS in turn
15523 // waits for the first
15524 // addresses from the
15525 // communicators in order to
15526 // be able to generate a
15527 // peer id
15528 if (NULL == pils)
15529 {
15530 GNUNET_break (0);
15532 return;
15533 }
15534 /* Decapsulate DV box ephemeral keys ourselves. #handle_dv_box() needs
15535 the key material while it still has the box, which points into the
15536 communicator's inbound message and is gone the moment the handler
15537 returns -- so the asynchronous answer arrived to a dangling @a dvb. */
15538 if (GNUNET_OK !=
15541 _ ("Failed to load our private key, "
15542 "cannot open DV boxes addressed to us\n"));
15543}
15544
15545
15551 "transport",
15553 &run,
15556 NULL,
15557 /* communication with applications */
15558 GNUNET_MQ_hd_fixed_size (suggest,
15561 NULL),
15562 GNUNET_MQ_hd_fixed_size (suggest_cancel,
15565 NULL),
15566 GNUNET_MQ_hd_var_size (request_hello_validation,
15569 NULL),
15570 /* communication with core */
15571 GNUNET_MQ_hd_fixed_size (client_start,
15573 struct StartMessage,
15574 NULL),
15575 GNUNET_MQ_hd_var_size (client_send,
15577 struct OutboundMessage,
15578 NULL),
15579 GNUNET_MQ_hd_fixed_size (client_recv_ok,
15581 struct RecvOkMessage,
15582 NULL),
15583 /* communication with communicators */
15584 GNUNET_MQ_hd_var_size (communicator_available,
15587 NULL),
15588 GNUNET_MQ_hd_var_size (communicator_backchannel,
15591 NULL),
15592 GNUNET_MQ_hd_var_size (add_address,
15595 NULL),
15596 GNUNET_MQ_hd_fixed_size (del_address,
15599 NULL),
15600 GNUNET_MQ_hd_var_size (incoming_msg,
15603 NULL),
15604 GNUNET_MQ_hd_fixed_size (queue_create_ok,
15607 NULL),
15608 GNUNET_MQ_hd_fixed_size (queue_create_fail,
15611 NULL),
15612 GNUNET_MQ_hd_var_size (add_queue_message,
15615 NULL),
15616 GNUNET_MQ_hd_fixed_size (update_queue_message,
15619 NULL),
15620 GNUNET_MQ_hd_fixed_size (del_queue_message,
15623 NULL),
15624 GNUNET_MQ_hd_fixed_size (send_message_ack,
15627 NULL),
15628 GNUNET_MQ_hd_fixed_size (burst_finished,
15631 NULL),
15632 /* communication with monitors */
15633 GNUNET_MQ_hd_fixed_size (monitor_start,
15636 NULL),
15637 GNUNET_MQ_hd_fixed_size (link_list_request,
15640 NULL),
15642
15643
15644/* 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 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.
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?
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.
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.
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.
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 the communicator has another queue with higher prio ready for sending.
#define GOODPUT_AGING_SLOTS
Number of slots we keep of historic data for computation of goodput / message loss ratio.
static int free_validation_state_cb(void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
Free validation state.
static int free_neighbour_cb(void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
Free neighbour entry.
static void handle_client_send(void *cls, const struct OutboundMessage *obm)
Client asked for transmission to a peer.
static void decaps_dv_box_cont(struct CommunicatorMessageContext *cmc, const struct TransportDVBoxMessage *dvb, const struct GNUNET_ShortHashCode *km)
Open the DV box dvb addressed to us, using the key material km decapsulated from its ephemeral key.
static enum GNUNET_GenericReturnValue burst_running
Is there a burst running?
struct GNUNET_HELLO_Builder * GST_my_hello
Our HELLO.
static void start_burst(void *cls)
#define DV_QUALITY_RTT_THRESHOLD
We only consider queues as "quality" connections when suppressing the generation of DV initiation mes...
static struct TransportClient * clients_head
Head of linked list of all clients to this service.
static void handle_validation_challenge(void *cls, const struct TransportValidationChallengeMessage *tvc)
Communicator gave us a transport address validation challenge.
static struct PilsRequest * pils_requests_head
PILS Operation DLL.
#define COMMUNICATOR_TOTAL_QUEUE_LIMIT
How many messages can we have pending for a given communicator process before we start to throttle th...
static void free_reassembly_context(struct ReassemblyContext *rc)
Free rc.
static struct VirtualLink * lookup_virtual_link(const struct GNUNET_PeerIdentity *pid)
Lookup virtual link for peer pid.
static int check_connection_quality(void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
Check whether any queue to the given neighbour is of a good "quality" and if so, increment the counte...
static void reorder_root_pm(struct PendingMessage *pm, struct GNUNET_TIME_Absolute next_attempt)
static void core_env_sent_cb(void *cls)
Function called when we are done giving a message of a certain size to CORE and should thus decrement...
static unsigned int ir_total
Length of the DLL starting at ir_head.
static int in_shutdown
Indication if we have received a shutdown signal and are in the process of cleaning up.
static void select_best_pending_from_link(struct PendingMessageScoreContext *sc, struct Queue *queue, struct VirtualLink *vl, struct DistanceVectorHop *dvh, size_t overhead)
Select the best pending message from vl for transmission via queue.
static void suggest_to_connect(const struct GNUNET_PeerIdentity *pid, const char *address)
Signature of a function called with a communicator address of a peer pid that an application wants us...
static void free_timedout_queue_entry(void *cls)
static void handle_send_message_ack(void *cls, const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
Message was transmitted.
static void update_pd_age(struct PerformanceData *pd, unsigned int age)
Check if we have advanced to another age since the last time.
#define DV_LEARN_BASE_FREQUENCY
What is the non-randomized base frequency at which we would initiate DV learn messages?
struct GNUNET_SCHEDULER_Task * burst_timeout_task
static void free_pending_acknowledgement(struct PendingAcknowledgement *pa)
Release pa data structure.
static struct GNUNET_CONTAINER_MultiUuidmap * pending_acks
Map of pending acknowledgements, mapping struct AcknowledgementUUID to a struct PendingAcknowledgemen...
static struct GNUNET_CONTAINER_MultiShortmap * dvlearn_map
Map from challenges to struct LearnLaunchEntry values.
#define DV_FORWARD_TIMEOUT
If a DVBox could not be forwarded after this number of seconds we drop it.
static void finish_handling_raw_message(struct VirtualLink *vl, const struct GNUNET_MessageHeader *mh, struct CommunicatorMessageContext *cmc, unsigned int free_cmc)
static void handle_add_queue_message(void *cls, const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
New queue became available.
static void update_queue_performance(struct Queue *q, struct GNUNET_TIME_Relative rtt, uint16_t bytes_transmitted_ok)
We have successfully transmitted data via q, update metrics.
static void schedule_transmit_on_queue(struct GNUNET_TIME_Relative delay, struct Queue *queue, enum GNUNET_SCHEDULER_Priority p)
Called whenever something changed that might effect when we try to do the next transmission on queue ...
static void set_pending_message_uuid(struct PendingMessage *pm)
If necessary, generates the UUID for a pm.
static void free_pending_message(struct PendingMessage *pm)
Release memory associated with pm and remove pm from associated data structures.
static void revalidation_start_cb(void *cls)
static void backtalker_monotime_store_cb(void *cls, int success)
Function called by PEERSTORE when the store operation of a backtalker's monotonic time is complete.
static int free_reassembly_cb(void *cls, uint32_t key, void *value)
function called to free_reassembly_context().
static void * client_connect_cb(void *cls, struct GNUNET_SERVICE_Client *client, struct GNUNET_MQ_Handle *mq)
Called whenever a client connects.
#define DV_PATH_VALIDITY_TIMEOUT
How long do we consider a DV path valid if we see no further updates on it? Note: the value chosen he...
static enum GNUNET_GenericReturnValue sign_ephemeral(struct DistanceVector *dv)
Sign the ephemeral key in dv, and mark it current.
#define RING_BUFFER_SIZE
Size of ring buffer to cache CORE and forwarded DVBox messages.
static void check_vl_transmission(struct VirtualLink *vl)
There is a message at the head of the pending messages for vl which may be ready for transmission.
static int find_by_message_uuid(void *cls, uint32_t key, void *value)
Iterator called to find a reassembly context by the message UUID in the multihashmap32.
static struct TransportClient * lookup_communicator(const char *prefix)
Find transport client providing communication service for the protocol prefix.
static unsigned int ring_buffer_head
Head of the ring buffer.
#define MAX_ADDRESS_VALID_UNTIL
When do we forget an invalid address for sure?
static void handle_hello_for_client(void *cls, const struct GNUNET_PEERSTORE_Record *record, const char *emsg)
Function called by PEERSTORE for each matching record.
#define SHUTDOWN_CLIENT_GRACE_PERIOD
How long do we wait during shutdown for our clients to disconnect on their own before we drop them?...
static void transmit_dv_init(struct TransportDVLearnMessage dvl, struct LearnLaunchEntry *lle, struct QueueQualityContext qqc)
Finish and transmit the DV learn message dvl we initiated.
static void handle_suggest_cancel(void *cls, const struct ExpressPreferenceMessage *msg)
We have received a struct ExpressPreferenceMessage from an application client.
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 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.
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 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.
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:1020
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:1039
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:967
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:1395
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:996
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:688
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:1126
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:1206
#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.
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_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_pa
Pointers for the DLL of all pending acknowledgements.
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_pa
Pointers for the DLL of all pending acknowledgements.
struct PendingAcknowledgement * prev_queue
If queue is non-NULL, this is the DLL in which this acknowledgement is kept in relation to the queue ...
struct PendingAcknowledgement * prev_pm
If pm is non-NULL, this is the DLL in which this acknowledgement is kept in relation to its pending m...
struct PendingAcknowledgement * prev_dvh
If dvh is non-NULL, this is the DLL in which this acknowledgement is kept in relation to the DVH that...
Context for select_best_pending_from_link().
struct GNUNET_TIME_Relative to_early_retry_delay
When will we try to transmit the message again for which it was to early to retry.
struct PendingMessage * best
Set to the best message that was found, NULL for none.
int to_early
There are pending messages, but it was to early to send one of them.
unsigned int consideration_counter
Number of pending messages we seriously considered this time.
struct DistanceVectorHop * dvh
DVH that best should take, or NULL for direct transmission.
size_t real_overhead
What is the estimated total overhead for this message?
unsigned int frags_in_flight
There is a pending messages we are sending fragments at the moment.
int frag
Did we have to fragment?
int relb
Did we have to reliability box?
List containing all messages that are yet to be send.
struct PendingMessage * tail_frag
Tail of a MDLL of fragments created for this core message.
struct PendingMessage * frag_parent
Our parent in the fragmentation tree.
enum GNUNET_MQ_PriorityPreferences prefs
Preferences for this message.
struct TransportClient * client
Client that issued the transmission request, if pmt is PMT_CORE.
struct QueueEntry * qe
Set to non-NULL value if this message is currently being given to a communicator and we are awaiting ...
struct MessageUUIDP msg_uuid
UUID to use for this message (used for reassembly of fragments, only initialized if msg_uuid_set is G...
struct PendingMessage * head_frag
Head of a MDLL of fragments created for this core message.
uint16_t bytes_msg
Size of the original message.
enum PendingMessageType pmt
Type of the pending message.
struct PendingMessage * prev_client
Kept in a MDLL of messages from this client (if pmt is PMT_CORE)
struct PendingMessage * prev_vl
Kept in a MDLL of messages for this vl.
struct PendingAcknowledgement * pa_tail
Tail of DLL of PAs for this pending message.
struct PendingMessage * next_vl
Kept in a MDLL of messages for this vl.
struct VirtualLink * vl
Target of the request (always the ultimate destination!).
struct PendingAcknowledgement * pa_head
Head of DLL of PAs for this pending message.
struct DistanceVectorHop * used_dvh
If pmt is of type PMT_DV_BOX we store the used path here.
int16_t msg_uuid_set
GNUNET_YES once msg_uuid was initialized
uint32_t frags_in_flight_round
The round we are (re)-sending fragments.
struct PendingMessage * next_client
Kept in a MDLL of messages from this client (if pmt is PMT_CORE)
uint32_t frags_in_flight
Are we sending fragments at the moment?
uint16_t frag_off
Offset at which we should generate the next fragment.
struct PendingMessage * next_frag
Kept in a MDLL of messages from this cpm (if pmt is #PMT_FRAGMENT_BOx)
uint64_t logging_uuid
UUID we use to identify this message in our logs.
uint16_t frag_count
How many fragments do we have?
struct PendingMessage * prev_frag
Kept in a MDLL of messages from this cpm (if pmt is PMT_FRAGMENT_BOX)
struct PendingMessage * bpm
This message, reliability or DV-boxed.
int16_t client_credited
GNUNET_YES once the CORE send window credit for this message has been returned to client.
struct GNUNET_TIME_Absolute next_attempt
What is the earliest time for us to retry transmission of this message?
struct GNUNET_TIME_Absolute timeout
At what time should we give up on the transmission (and no longer retry)?
struct GNUNET_PeerIdentity target
In case of a not validated neighbour, we store the target peer.
Performance data for a transmission possibility.
struct GNUNET_TIME_Relative aged_rtt
Weighted average for the RTT.
struct TransmissionHistoryEntry the[4]
Historic performance data, using a ring buffer of::GOODPUT_AGING_SLOTS entries.
unsigned int last_age
What was the last age when we wrote to the? Used to clear old entries when the age advances.
Helper context struct for HELLO update.
struct GNUNET_TIME_Absolute et
Signature expiration.
struct AddressListEntry * ale
The ale to update.
struct PilsRequest * req
Any pending PILS requests.
struct GNUNET_PILS_Operation * op
The pils operation.
struct PilsRequest * next
DLL.
struct PilsRequest * prev
DLL.
Entry identifying transmission in one of our struct Queue which still awaits an ACK.
struct QueueEntry * next
Kept as a DLL.
struct QueueEntry * prev
Kept as a DLL.
struct GNUNET_TIME_Absolute creation_timestamp
Timestamp this QueueEntry was created.
uint64_t mid
Message ID used for this message with the queue used for transmission.
struct PendingMessage * pm
Pending message this entry is for, or NULL for none.
struct Queue * queue
Queue this entry is queued with.
Closure for check_connection_quality.
unsigned int k
Decremented for each queue, for selection of the k-th queue in q.
struct Queue * q
Set to the k'th queue encountered.
unsigned int num_queues
Set to the total number of queues encountered.
unsigned int quality_count
Set to the number of quality queues encountered.
Handle for a queue.
uint32_t qid
Unique identifier of this queue with the communicator.
struct QueueEntry * queue_tail
End of DLL of unacked transmission requests.
struct Queue * prev_client
Kept in a MDLL.
unsigned int queue_length
Length of the DLL starting at queue_head.
uint32_t num_msg_pending
Messages pending.
struct GNUNET_PEERSTORE_Monitor * mo
Handle for an operation to iterate through all hellos to compare the hello addresses with address whi...
uint64_t q_capacity
Capacity of the queue.
struct Queue * next_neighbour
Kept in a MDLL.
uint32_t num_bytes_pending
Bytes pending.
uint32_t priority
Queue priority.
struct Neighbour * neighbour
Which neighbour is this queue for?
int idle
Set to GNUNET_YES if this queue is idle waiting for some virtual link to give it a pending message.
struct Queue * prev_neighbour
Kept in a MDLL.
struct PerformanceData pd
Performance data for this queue.
enum GNUNET_NetworkType nt
Which network type does this queue use?
struct GNUNET_SCHEDULER_Task * transmit_task
Task scheduled for the time when this queue can (likely) transmit the next message.
struct QueueEntry * queue_head
Head of DLL of unacked transmission requests.
struct PendingAcknowledgement * pa_tail
Tail of DLL of PAs that used this queue.
struct TransportClient * tc
Which communicator offers this queue?
struct Queue * next_client
Kept in a MDLL.
enum GNUNET_GenericReturnValue is_global_natted
Set to GNUNET_YES, if this queues address is a global natted one.
struct GNUNET_TIME_Absolute validated_until
How long do we consider this address to be valid? In the past or zero if we have not yet validated it...
uint32_t mtu
Maximum transmission unit supported by this queue.
unsigned int unlimited_length
Is this queue of unlimited length.
enum GNUNET_TRANSPORT_ConnectionStatus cs
The connection status of this queue.
uint64_t mid_gen
Message ID generator for transmissions on this queue to the communicator.
struct PendingAcknowledgement * pa_head
Head of DLL of PAs that used this queue.
struct sockaddr * address
Address of the other peer.
Information we keep for a message that we are reassembling.
struct GNUNET_CONTAINER_HeapNode * hn
Entry in the reassembly heap (sorted by expiration).
struct GNUNET_TIME_Absolute last_frag
Time we received the last fragment.
struct MessageUUIDP msg_uuid
Original message ID for of the message that all the fragments belong to.
struct VirtualLink * virtual_link
Which neighbour is this context for?
uint8_t * bitfield
Bitfield with msg_size bits representing the positions where we have received fragments.
uint16_t msg_size
How big is the message we are reassembling in total?
struct GNUNET_TIME_Absolute reassembly_timeout
At what time will we give up reassembly of this message?
uint16_t msg_missing
How many bytes of the message are still missing? Defragmentation is complete when msg_missing == 0.
Message used to notify the transport API that it can send another message to the transport service.
Definition transport.h:207
struct GNUNET_PeerIdentity peer
Which peer can CORE handle more from now?
Definition transport.h:222
uint32_t increase_window_delta
Number of messages by which to increase the window, greater or equal to one.
Definition transport.h:217
We got an address of another peer, TRANSPORT service should validate it.
Definition transport.h:979
Entry for the ring buffer caching messages send to core, when virtual link is available.
struct CommunicatorMessageContext * cmc
Communicator context for this ring buffer entry.
struct GNUNET_MessageHeader * mh
The message in this entry.
Message used to notify the transport API that it can send another message to the transport service.
Definition transport.h:163
struct GNUNET_PeerIdentity peer
Which peer can send more now?
Definition transport.h:197
Binary block we sign when we sign an address.
struct GNUNET_TIME_AbsoluteNBO mono_time
When was the address generated.
struct GNUNET_HashCode addr_hash GNUNET_PACKED
Hash of the address.
struct GNUNET_CRYPTO_SignaturePurpose purpose
Purpose must be GNUNET_SIGNATURE_PURPOSE_TRANSPORT_ADDRESS.
Message from the transport service to the library asking to check if both processes agree about this ...
Definition transport.h:63
Information we keep per GOODPUT_AGING_SLOTS about historic (or current) transmission performance.
uint64_t bytes_received
Number of bytes received and acknowledged by the other peer in the interval.
uint64_t bytes_sent
Number of bytes actually sent in the interval.
Outer layer of an encapsulated backchannel message.
struct GNUNET_MessageHeader header
Type is GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION.
Client connected to the transport service.
enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc
Characteristics of this communicator.
struct PendingMessage * pending_msg_head
Head of list of messages pending for this client, sorted by transmission time ("next_attempt" + possi...
enum ClientType type
What type of client is this?
struct AddressListEntry * addr_tail
Tail of list of the addresses of this peer offered by this communicator.
union TransportClient::@68 details
struct TransportClient * next
Kept in a DLL.
struct GNUNET_MQ_Handle * mq
Message queue to the client.
struct GNUNET_SCHEDULER_Task * free_queue_entry_task
Task to check for timed out QueueEntry.
struct PendingMessage * pending_msg_tail
Tail of list of messages pending for this client.
struct TransportClient::@68::@72 application
Information for type CT_APPLICATION.
struct TransportClient::@68::@70 monitor
Information for type CT_MONITOR.
struct Queue * queue_head
Head of DLL of queues offered by this communicator.
struct AddressListEntry * addr_head
Head of list of the addresses of this peer offered by this communicator.
struct TransportClient::@68::@69 core
Information for type CT_CORE.
struct GNUNET_CONTAINER_MultiPeerMap * requests
Map of requests for peers the given client application would like to see connections for.
struct GNUNET_SERVICE_Client * client
Handle to the client.
struct TransportClient * prev
Kept in a DLL.
struct TransportClient::@68::@71 communicator
Information for type CT_COMMUNICATOR.
char * address_prefix
If type is CT_COMMUNICATOR, this communicator supports communicating using these addresses.
struct Queue * queue_tail
Tail of DLL of queues offered by this communicator.
unsigned int total_queue_length
Number of queue entries in all queues to this communicator.
int one_shot
Is this a one-shot monitor?
struct GNUNET_PeerIdentity peer
Peer identity to monitor the addresses of.
enum GNUNET_GenericReturnValue can_burst
Can be used for burst messages.
struct GNUNET_TIME_RelativeNBO ack_delay
How long was the ACK delayed for generating cumulative ACKs? Used to calculate the correct network RT...
struct AcknowledgementUUIDP ack_uuid
UUID of a message being acknowledged.
struct GNUNET_TIME_Absolute receive_time
When did we receive the message we are ACKing? Used to calculate the delay we introduced by cummulati...
struct AcknowledgementUUIDP ack_uuid
UUID of a message being acknowledged.
Outer layer of an encapsulated message send over multiple hops.
struct GNUNET_CRYPTO_AeadNonce iv
We use an IV here as the ephemeral_key is reused for EPHEMERAL_VALIDITY time to avoid re-signing it a...
struct GNUNET_MessageHeader header
Type is GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX.
uint16_t num_hops
Number of hops this messages includes.
uint16_t orig_size
Size this msg had initially.
struct GNUNET_CRYPTO_HpkeEncapsulation ephemeral_key
Ephemeral key setup by the sender for target, used to encrypt the payload.
struct GNUNET_CRYPTO_AeadMac mac
HMAC over the ciphertext of the encrypted, variable-size body that follows.
uint16_t total_hops
Number of total hops this messages travelled.
uint32_t without_fc
Flag if the payload is a control message.
Plaintext of the variable-size payload that is encrypted within a struct TransportBackchannelEncapsul...
struct GNUNET_CRYPTO_EddsaSignature sender_sig
Signature of the sender over an GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL.
struct GNUNET_TIME_AbsoluteNBO monotonic_time
Current monotonic time of the sending transport service.
struct GNUNET_PeerIdentity sender
Sender's peer identity.
Internal message used by transport for distance vector learning.
struct GNUNET_PeerIdentity initiator
Identity of the peer that started this learning activity.
struct GNUNET_CRYPTO_ChallengeNonceP challenge
Challenge value used by the initiator to re-identify the path.
struct GNUNET_MessageHeader header
Type is GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN.
struct GNUNET_TIME_RelativeNBO non_network_delay
Peers receiving this message and delaying forwarding to other peers for any reason should increment t...
struct GNUNET_TIME_AbsoluteNBO monotonic_time
Time at the initiator when generating the signature.
struct GNUNET_CRYPTO_EddsaSignature init_sig
Signature of this hop over the path, of purpose GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR.
uint16_t num_hops
Number of hops this messages has travelled, in NBO.
uint16_t bidirectional
Bitmask of the last 16 hops indicating whether they are confirmed available (without DV) in both dire...
Message for Transport-to-Transport Flow control.
uint64_t outbound_window_size
Latest flow control window size we learned from the other peer, in bytes, in NBO.
uint32_t number_of_addresses
Number of TransportGlobalNattedAddress following the struct.
uint64_t inbound_window_size
Flow control window size in bytes, in NBO.
struct GNUNET_TIME_AbsoluteNBO sender_time
Timestamp of the sender.
uint32_t seq
Sequence number of the flow control message.
uint32_t size_of_addresses
Size of all the addresses attached to all TransportGlobalNattedAddress.
uint64_t outbound_sent
How many bytes has the sender sent that count for flow control at this time.
struct GNUNET_TIME_RelativeNBO rtt
Average RTT for the DistanceVector of the VirtualLink we tell the target.
struct GNUNET_MessageHeader header
Type is GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL.
uint32_t sync_ready
We tell the target, if we are ready to start the burst.
Outer layer of an encapsulated fragmented application message.
uint16_t frag_off
Offset of this fragment in the overall message.
struct MessageUUIDP msg_uuid
Original message ID for of the message that all the fragments belong to.
struct AcknowledgementUUIDP ack_uuid
Unique ID of this fragment (and fragment transmission!).
struct GNUNET_MessageHeader header
Type is GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT.
uint16_t msg_size
Total size of the message that is being fragmented.
struct TransportGlobalNattedAddress * tgna
The struct TransportGlobalNattedAddress to set.
uint32_t address_length
Length of the address following the struct in NBO.
Confirmation that the receiver got a GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX.
uint32_t ack_counter
Counter of ACKs transmitted by the sender to us.
struct GNUNET_MessageHeader header
Type is GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK.
Outer layer of an encapsulated unfragmented application message sent over an unreliable channel.
uint32_t ack_countdown
Number of messages still to be sent before a commulative ACK is requested.
struct GNUNET_MessageHeader header
Type is GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX.
struct AcknowledgementUUIDP ack_uuid
Unique ID of the message used for signalling receipt of messages sent over possibly unreliable channe...
Message send to another peer to validate that it can indeed receive messages at a particular address.
struct GNUNET_MessageHeader header
Type is GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE.
struct GNUNET_CRYPTO_ChallengeNonceP challenge
Challenge to be signed by the receiving peer.
struct GNUNET_TIME_AbsoluteNBO sender_time
Timestamp of the sender, to be copied into the reply to allow sender to calculate RTT.
Message signed by a peer to confirm that it can indeed receive messages at a particular address.
struct GNUNET_TIME_RelativeNBO validity_duration
How long does the sender believe the address on which the challenge was received to remain valid?
struct GNUNET_CRYPTO_SignaturePurpose purpose
Purpose is GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE.
struct GNUNET_CRYPTO_ChallengeNonceP challenge
Challenge signed by the receiving peer.
Message send to a peer to respond to a #GNUNET_MESSAGE_TYPE_ADDRESS_VALIDATION_CHALLENGE.
struct GNUNET_MessageHeader header
Type is GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE.
struct GNUNET_CRYPTO_ChallengeNonceP challenge
The challenge that was signed by the receiving peer.
struct GNUNET_CRYPTO_EddsaSignature signature
The peer's signature matching the GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE purpose.
struct GNUNET_PEERSTORE_StoreHelloContext * sc
State we keep for validation activities.
struct GNUNET_TIME_Absolute valid_until
How long did the peer claim this address to be valid? Capped at minimum of MAX_ADDRESS_VALID_UNTIL re...
struct GNUNET_PeerIdentity pid
For which peer is address to be validated (or possibly valid)? Serves as key in the validation_map.
struct GNUNET_TIME_Absolute validated_until
How long do we consider this address to be valid? In the past or zero if we have not yet validated it...

◆ UNCONFIRMED_LINK_TIMEOUT

#define UNCONFIRMED_LINK_TIMEOUT    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)

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

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

◆ MAX_CUMMULATIVE_ACKS

#define MAX_CUMMULATIVE_ACKS   64

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

Larger values may save a bit of bandwidth.

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

◆ FC_NO_CHANGE_REPLY_PROBABILITY

#define FC_NO_CHANGE_REPLY_PROBABILITY   8

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

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

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

◆ IN_PACKET_SIZE_WITHOUT_MTU

#define IN_PACKET_SIZE_WITHOUT_MTU   128

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

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

◆ GOODPUT_AGING_SLOTS

#define GOODPUT_AGING_SLOTS   4

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

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

◆ DEFAULT_WINDOW_SIZE

#define DEFAULT_WINDOW_SIZE   (128 * 1024)

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

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

◆ MAX_INCOMING_REQUEST

#define MAX_INCOMING_REQUEST   16

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

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

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

◆ MAX_DV_DISCOVERY_SELECTION

#define MAX_DV_DISCOVERY_SELECTION   16

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

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

◆ RECV_WINDOW_SIZE

#define RECV_WINDOW_SIZE   4

Window size.

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

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

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

◆ CORE_FC_STALL_TIMEOUT

#define CORE_FC_STALL_TIMEOUT    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2)

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

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

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

◆ MAX_STALLED_CMCS

#define MAX_STALLED_CMCS   (4 * RECV_WINDOW_SIZE)

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

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

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

◆ MIN_DV_PATH_LENGTH_FOR_INITIATOR

#define MIN_DV_PATH_LENGTH_FOR_INITIATOR   3

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

FIXME: allow initiator some control here instead?

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

◆ MAX_DV_HOPS_ALLOWED

#define MAX_DV_HOPS_ALLOWED   16

Maximum DV distance allowed ever.

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

◆ MAX_DV_LEARN_PENDING

#define MAX_DV_LEARN_PENDING   64

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

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

◆ MAX_DV_PATHS_TO_TARGET

#define MAX_DV_PATHS_TO_TARGET   3

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

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

◆ PILS_FEED_ADDRESSES_DELAY

#define PILS_FEED_ADDRESSES_DELAY    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3)

Delay between added/removed addresses and PILS feed call.

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

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

◆ DELAY_WARN_THRESHOLD

#define DELAY_WARN_THRESHOLD    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)

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

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

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

◆ DV_FORWARD_TIMEOUT

#define DV_FORWARD_TIMEOUT    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)

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

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

◆ DEFAULT_ACK_WAIT_DURATION

#define DEFAULT_ACK_WAIT_DURATION    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)

Default value for how long we wait for reliability ack.

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

◆ 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 266 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 273 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 280 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 287 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 293 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 299 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 308 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 314 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 320 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 328 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 335 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 341 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 346 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 352 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 371 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 402 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 412 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 420 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 428 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 435 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 440 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 447 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 456 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 5668 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 1162 of file gnunet-service-transport.c.

1163{
1167 CT_NONE = 0,
1168
1172 CT_CORE = 1,
1173
1177 CT_MONITOR = 2,
1178
1182 CT_COMMUNICATOR = 3,
1183
1187 CT_APPLICATION = 4
1188};

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

1196{
1200 RMO_NONE = 0,
1201
1205 RMO_DV_ALLOWED = 1,
1206
1211
1216
1222 RMO_REDUNDANT = 4
1223};

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

2383{
2387 PMT_CORE = 0,
2388
2392 PMT_FRAGMENT_BOX = 1,
2393
2398
2402 PMT_DV_BOX = 3
2403};

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

3280{
3282
3284 if (NULL == my_private_key)
3285 {
3286 /* #run() enables local key access, so this means the key on disk does
3287 not match the identity PILS announced, or no identity is known yet. */
3289 "No private key for our peer identity, cannot sign\n");
3291 "# signatures failed (no private key)",
3292 1,
3293 GNUNET_NO);
3294 return GNUNET_SYSERR;
3295 }
3296 return GNUNET_CRYPTO_eddsa_sign_ (my_private_key, purpose, sig);
3297}

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

3391{
3392 struct GNUNET_TIME_Absolute now;
3393
3394 now = GNUNET_TIME_absolute_get ();
3395 return now.abs_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us / 15;
3396}

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

3406{
3408 GNUNET_assert (ir_total > 0);
3409 ir_total--;
3410 if (NULL != ir->nc)
3412 ir->nc = NULL;
3413 GNUNET_free (ir);
3414}

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

3424{
3425 struct Queue *q = pa->queue;
3426 struct PendingMessage *pm = pa->pm;
3427 struct DistanceVectorHop *dvh = pa->dvh;
3428
3430 "free_pending_acknowledgement\n");
3431 if (NULL != q)
3432 {
3433 GNUNET_CONTAINER_MDLL_remove (queue, q->pa_head, q->pa_tail, pa);
3434 pa->queue = NULL;
3435 }
3436 if (NULL != pm)
3437 {
3439 "remove pa from message\n");
3441 "remove pa from message %" PRIu64 "\n",
3442 pm->logging_uuid);
3444 "remove pa from message %u\n",
3445 pm->pmt);
3447 "remove pa from message %s\n",
3449 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
3450 pa->pm = NULL;
3451 }
3452 if (NULL != dvh)
3453 {
3454 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
3455 pa->dvh = NULL;
3456 }
3459 &pa->ack_uuid.value,
3460 pa));
3461 GNUNET_free (pa);
3462}

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_pending_ack_cb(), 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 3474 of file gnunet-service-transport.c.

3475{
3476 struct PendingMessage *frag;
3477
3478 while (NULL != (frag = root->head_frag))
3479 {
3480 struct PendingAcknowledgement *pa;
3481
3482 free_fragment_tree (frag);
3483 while (NULL != (pa = frag->pa_head))
3484 {
3485 GNUNET_CONTAINER_MDLL_remove (pm, frag->pa_head, frag->pa_tail, pa);
3486 pa->pm = NULL;
3487 }
3488 GNUNET_CONTAINER_MDLL_remove (frag, root->head_frag, root->tail_frag, frag);
3489 if (NULL != frag->qe)
3490 {
3491 GNUNET_assert (frag == frag->qe->pm);
3492 frag->qe->pm = NULL;
3493 }
3495 "Free frag %p\n",
3496 frag);
3497 GNUNET_free (frag);
3498 }
3499}

References free_fragment_tree(), GNUNET_assert, GNUNET_CONTAINER_MDLL_remove, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_log, PendingMessage::head_frag, PendingMessage::pa_head, PendingMessage::pa_tail, PendingAcknowledgement::pm, 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 3510 of file gnunet-service-transport.c.

3511{
3512 struct TransportClient *tc = pm->client;
3513 struct VirtualLink *vl = pm->vl;
3514 struct PendingAcknowledgement *pa;
3515
3517 "Freeing pm %p\n",
3518 pm);
3519 if (NULL != tc)
3520 {
3522 tc->details.core.pending_msg_head,
3523 tc->details.core.pending_msg_tail,
3524 pm);
3525 }
3526 if ((NULL != vl) && (NULL == pm->frag_parent))
3527 {
3529 "Removing pm %" PRIu64 "\n",
3530 pm->logging_uuid);
3532 vl->pending_msg_head,
3533 vl->pending_msg_tail,
3534 pm);
3535 }
3536 else if (NULL != pm->frag_parent && PMT_DV_BOX != pm->pmt)
3537 {
3538 struct PendingMessage *root = pm->frag_parent;
3539
3540 while (NULL != root->frag_parent && PMT_DV_BOX != root->pmt)
3541 root = root->frag_parent;
3542
3543 root->frag_count--;
3544 }
3545 while (NULL != (pa = pm->pa_head))
3546 {
3547 if (NULL == pa)
3549 "free pending pa null\n");
3550 if (NULL == pm->pa_tail)
3552 "free pending pa_tail null\n");
3553 if (NULL == pa->prev_pa)
3555 "free pending pa prev null\n");
3556 if (NULL == pa->next_pa)
3558 "free pending pa next null\n");
3559 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
3560 pa->pm = NULL;
3561 }
3562
3563 free_fragment_tree (pm);
3564 if (NULL != pm->qe)
3565 {
3566 GNUNET_assert (pm == pm->qe->pm);
3567 pm->qe->pm = NULL;
3568 }
3569 if (NULL != pm->bpm)
3570 {
3571 free_fragment_tree (pm->bpm);
3572 if (NULL != pm->bpm->qe)
3573 {
3574 struct QueueEntry *qe = pm->bpm->qe;
3575
3576 qe->pm = NULL;
3577 }
3578 GNUNET_free (pm->bpm);
3579 }
3580
3581 GNUNET_free (pm);
3583 "Freeing pm done\n");
3584}

References PendingMessage::bpm, PendingMessage::client, PendingMessage::frag_count, PendingMessage::frag_parent, free_fragment_tree(), GNUNET_assert, GNUNET_CONTAINER_MDLL_remove, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_log, PendingMessage::logging_uuid, PendingAcknowledgement::next_pa, PendingMessage::pa_head, PendingMessage::pa_tail, VirtualLink::pending_msg_head, VirtualLink::pending_msg_tail, PendingAcknowledgement::pm, QueueEntry::pm, PendingMessage::pmt, PMT_DV_BOX, PendingAcknowledgement::prev_pa, 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 3593 of file gnunet-service-transport.c.

3594{
3595 struct VirtualLink *vl = rc->virtual_link;
3596
3600 rc->msg_uuid.uuid,
3601 rc));
3602 GNUNET_free (rc);
3603}

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

3613{
3614 struct VirtualLink *vl = cls;
3615 struct ReassemblyContext *rc;
3616
3617 vl->reassembly_timeout_task = NULL;
3618 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (vl->reassembly_heap)))
3619 {
3621 .rel_value_us)
3622 {
3624 continue;
3625 }
3630 vl);
3631 return;
3632 }
3633}

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

3646{
3647 struct ReassemblyContext *rc = value;
3648
3649 (void) cls;
3650 (void) key;
3652 return GNUNET_OK;
3653}

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

5164{
5165 send_cmc_ack (cmc);
5166 resume_cmc_client (cmc);
5167 if (GNUNET_YES == free_cmc)
5168 {
5169 GNUNET_free (cmc);
5170 }
5171}

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

5177{
5179 GNUNET_assert (0 < vl->cmc_count);
5180 vl->cmc_count--;
5182}

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

11500{
11501 struct VirtualLink *vl = sb_cls->vl;
11502
11503 if (burst_task_cls == sb_cls)
11504 {
11505 if (NULL != burst_task)
11506 {
11508 burst_task = NULL;
11509 }
11510 burst_task_cls = NULL;
11511 }
11512 if ((NULL != vl) && (vl->sb_cls == sb_cls))
11513 vl->sb_cls = NULL;
11515}

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

3709{
3710 struct GNUNET_MQ_Envelope *env;
3711 struct SendOkMessage *so_msg;
3712
3713 if (NULL == tc)
3714 return;
3716 so_msg->peer = *pid;
3717 GNUNET_MQ_send (tc->mq, env);
3718}

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

3735{
3736 if ((NULL == pm->client) || (GNUNET_YES == pm->client_credited))
3737 return;
3739 send_ok_to_client (pm->client, &pm->vl->target);
3740}

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

3750{
3751 struct PendingMessage *pm;
3752 struct CoreSentContext *csc;
3753 struct CommunicatorMessageContext *cmc;
3754
3756 "free virtual link %p\n",
3757 vl);
3758
3759 /* Communicators that are blocked on CORE flow control for this link MUST
3760 be resumed here. Otherwise their `struct CommunicatorMessageContext's
3761 leak and -- worse -- those clients never get their
3762 GNUNET_SERVICE_client_continue() and stall forever. */
3763 while (NULL != (cmc = vl->cmc_head))
3764 release_stalled_cmc (vl, cmc);
3765 if (NULL != vl->core_fc_stall_task)
3766 {
3768 vl->core_fc_stall_task = NULL;
3769 }
3770
3771 if (NULL != vl->reassembly_map)
3772 {
3775 NULL);
3777 vl->reassembly_map = NULL;
3779 vl->reassembly_heap = NULL;
3780 }
3781 if (NULL != vl->reassembly_timeout_task)
3782 {
3784 vl->reassembly_timeout_task = NULL;
3785 }
3786 while (NULL != (pm = vl->pending_msg_head))
3787 {
3788 /* These never got transmitted, so #completed_pending_message() will not
3789 run for them and nobody else answers their SEND either. Return the
3790 window credit anyway: CORE keeps its `struct Neighbour' -- and thus
3791 the window -- until it sees our DISCONNECT, and #handle_client_send()
3792 deliberately tolerates a SEND for a link that is already gone, so a
3793 client can easily still be sending while we free this. */
3794 credit_client (pm);
3796 }
3799 if (NULL != vl->visibility_task)
3800 {
3802 vl->visibility_task = NULL;
3803 }
3804 if (NULL != vl->fc_retransmit_task)
3805 {
3807 vl->fc_retransmit_task = NULL;
3808 }
3809 while (NULL != (csc = vl->csc_head))
3810 {
3812 GNUNET_assert (vl == csc->vl);
3813 csc->vl = NULL;
3814 }
3815 if (NULL != vl->unconfirmed_timeout_task)
3816 {
3818 vl->unconfirmed_timeout_task = NULL;
3819 }
3820 if (NULL != vl->ic)
3821 {
3822 /* the closure of this iteration is @e sb_cls, released just below */
3824 vl->ic = NULL;
3825 }
3826 if (NULL != vl->sb_cls)
3827 {
3828 /* Cancels #burst_task if that task's closure is ours: it would
3829 otherwise run on this (freed) link. */
3830 free_burst_cls (vl->sb_cls);
3831 GNUNET_assert (NULL == vl->sb_cls);
3832 }
3833 GNUNET_free (vl->burst_addr);
3834 GNUNET_break (NULL == vl->n);
3835 GNUNET_break (NULL == vl->dv);
3836 GNUNET_free (vl);
3837}

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

3847{
3848 if (NULL != vs->revalidation_task)
3849 {
3850 GNUNET_SCHEDULER_cancel (vs->revalidation_task);
3851 vs->revalidation_task = NULL;
3852 }
3853 /*memcpy (&hkey,
3854 &hc,
3855 sizeof (hkey));*/
3857 "Remove key %s for address %s map size %u contains %u during freeing state\n",
3858 GNUNET_h2s (&vs->hc),
3859 vs->address,
3862 &vs->hc));
3865 GNUNET_YES ==
3868 vs->hn = NULL;
3869 if (NULL != vs->sc)
3870 {
3872 "store cancel\n");
3874 vs->sc = NULL;
3875 }
3876 GNUNET_free (vs->address);
3877 GNUNET_free (vs);
3878}

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

3889{
3891}

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

Referenced by 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 3901 of file gnunet-service-transport.c.

3902{
3904}

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(), and transmit_cummulative_ack_cb().

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

3951{
3952 struct Neighbour *n = dvh->next_hop;
3953 struct DistanceVector *dv = dvh->dv;
3954 struct PendingAcknowledgement *pa;
3955
3956 while (NULL != (pa = dvh->pa_head))
3957 {
3959 pa->dvh = NULL;
3960 }
3961 GNUNET_CONTAINER_MDLL_remove (neighbour, n->dv_head, n->dv_tail, dvh);
3963 GNUNET_free (dvh);
3964}

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

4460{
4461 struct VirtualLink *vl = cls;
4462 struct DistanceVector *dv = vl->dv;
4463 struct Neighbour *n = vl->n;
4464 struct GNUNET_TIME_Absolute dvh_timeout;
4465 struct GNUNET_TIME_Absolute q_timeout;
4466
4468 "Checking if link is down\n");
4469 vl->visibility_task = NULL;
4470 dvh_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
4471 if (NULL != dv)
4472 {
4473 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4474 pos = pos->next_dv)
4475 dvh_timeout = GNUNET_TIME_absolute_max (dvh_timeout,
4476 pos->path_valid_until);
4477 if (0 == GNUNET_TIME_absolute_get_remaining (dvh_timeout).rel_value_us)
4478 {
4479 vl->dv->vl = NULL;
4480 vl->dv = NULL;
4481 }
4482 }
4483 q_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
4484 /* NOTE: @e n may be NULL here: #free_neighbour() clears vl->n and then
4485 schedules us when the link still has a DV route. */
4486 if (NULL != n)
4487 {
4488 struct GNUNET_TIME_Absolute liveness_deadline;
4489
4490 /* A successful validation is good for #ADDRESS_VALIDATION_LIFETIME (four
4491 hours). Do not take a communicator's word for that long: cap what the
4492 queues are worth by how recently this neighbour actually said anything
4493 to us. Otherwise a communicator that stops working without sending a
4494 QUEUE_TEARDOWN keeps this link -- and CORE's idea of the connection --
4495 alive until the validation expires. */
4496 liveness_deadline = GNUNET_TIME_absolute_add (n->last_inbound,
4498 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
4499 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
4500 if (GNUNET_TIME_absolute_cmp (liveness_deadline, <, q_timeout))
4501 {
4502 if (0 ==
4504 {
4505 /* Only reachable if a communicator failed to tear its queue down. */
4507 "Neighbour %s was silent for %s while its communicator "
4508 "kept claiming the queue works; treating link as down\n",
4509 GNUNET_i2s (&vl->target),
4512 GNUNET_YES));
4514 "# links dropped (neighbour silent)",
4515 1,
4516 GNUNET_NO);
4517 }
4518 q_timeout = liveness_deadline;
4519 }
4520 if (0 == GNUNET_TIME_absolute_get_remaining (q_timeout).rel_value_us)
4521 {
4522 vl->n->vl = NULL;
4523 vl->n = NULL;
4524 }
4525 }
4526 if ((NULL == vl->n) && (NULL == vl->dv))
4527 {
4529 /* @e n (if any) outlives the link, and so do its queues: the liveness cap
4530 above drops a link whose addresses are still well inside
4531 #ADDRESS_VALIDATION_LIFETIME. In that state nothing would ever ask for
4532 a fresh challenge -- @e revalidation_task does not fire until the four
4533 hour validity is nearly over, and the HELLO path reaches
4534 #start_address_validation() only to find an address that still counts
4535 as valid. Since #handle_validation_response() is the only thing that
4536 can rebuild this link and tell CORE about the peer again, ask for that
4537 validation now, or CORE never hears about this peer again. */
4538 if (NULL != n)
4539 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
4540 start_address_validation (&n->pid, q->address);
4541 return;
4542 }
4543 vl->visibility_task =
4544 GNUNET_SCHEDULER_add_at (GNUNET_TIME_absolute_max (q_timeout, dvh_timeout),
4546 vl);
4547}

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

3984{
3986 "Informing CORE clients about disconnect from %s\n",
3987 GNUNET_i2s (pid));
3988 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3989 {
3990 struct GNUNET_MQ_Envelope *env;
3991 struct DisconnectInfoMessage *dim;
3992
3993 if (CT_CORE != tc->type)
3994 continue;
3996 dim->peer = *pid;
3997 GNUNET_MQ_send (tc->mq, env);
3998 }
3999}

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

10601{
10602 struct Neighbour *n;
10603 struct IncomingRequest *ir;
10604
10605 if (GNUNET_YES == in_shutdown)
10606 return;
10607 /* (1) Addresses we already track. These outlive the queues, which is the
10608 point: once a link is down the queue that carried it is usually gone,
10609 so there is no address string left for #start_address_validation(). */
10611 pid,
10613 NULL);
10614 /* (2) Queues we still have; may cover an address with no validation state
10615 yet. After (1), because it may insert into #validation_map. */
10616 n = lookup_neighbour (pid);
10617 if (NULL != n)
10618 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
10619 start_address_validation (pid, q->address);
10620 /* (3) Failing that, look for an address in PEERSTORE. */
10621 for (ir = ir_head; NULL != ir; ir = ir->next)
10622 {
10623 if (0 == GNUNET_memcmp (&ir->pid, pid))
10624 return; /* we are already trying */
10625 }
10626 ir = GNUNET_new (struct IncomingRequest);
10627 ir->pid = *pid;
10630 GNUNET_YES,
10631 "peerstore",
10632 NULL,
10635 NULL,
10637 NULL,
10639 ir);
10640 ir_total++;
10641 /* Bound attempts we do in parallel here, might otherwise get excessive.
10642 Drop the OLDEST request: #ir_head is the one we just inserted, so
10643 freeing that would immediately undo the work above. */
10646}

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(), and send_t_validation_response().

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

4030{
4031 struct GNUNET_PeerIdentity target = vl->target;
4032
4033 for (struct PendingMessage *pm = vl->pending_msg_head;
4034 NULL != pm;
4035 pm = pm->next_vl)
4036 credit_client (pm);
4038 free_virtual_link (vl);
4039 /* Start getting it back now. Only #handle_validation_response() can
4040 rebuild it, and a successful validation parks @e revalidation_task just
4041 short of #ADDRESS_VALIDATION_LIFETIME -- four hours away. */
4042 try_to_bring_link_up (&target);
4043}

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

4054{
4055 struct DistanceVectorHop *dvh;
4056 struct VirtualLink *vl;
4057
4058 while (NULL != (dvh = dv->dv_head))
4060
4062 GNUNET_YES ==
4064 if (NULL != (vl = dv->vl))
4065 {
4066 GNUNET_assert (dv == vl->dv);
4067 vl->dv = NULL;
4068 if (NULL == vl->n)
4069 {
4071 }
4072 else
4073 {
4076 }
4077 dv->vl = NULL;
4078 }
4079
4080 if (NULL != dv->timeout_task)
4081 {
4083 dv->timeout_task = NULL;
4084 }
4085 GNUNET_free (dv->km);
4086 GNUNET_free (dv);
4087}

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

4109{
4110 struct GNUNET_MQ_Envelope *env;
4112 size_t addr_len = strlen (address) + 1;
4113
4115 addr_len,
4117 md->nt = htonl ((uint32_t) nt);
4118 md->peer = *peer;
4119 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
4120 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
4121 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
4122 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
4123 md->cs = htonl ((uint32_t) me->cs);
4124 md->num_msg_pending = htonl (me->num_msg_pending);
4125 md->num_bytes_pending = htonl (me->num_bytes_pending);
4126 memcpy (&md[1], address, addr_len);
4127 GNUNET_MQ_send (tc->mq, env);
4128}

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

4145{
4146 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
4147 {
4148 if (CT_MONITOR != tc->type)
4149 continue;
4150 if (tc->details.monitor.one_shot)
4151 continue;
4152 if ((GNUNET_NO == GNUNET_is_zero (&tc->details.monitor.peer)) &&
4153 (0 != GNUNET_memcmp (&tc->details.monitor.peer, peer)))
4154 continue;
4155 notify_monitor (tc, peer, address, nt, me);
4156 }
4157}

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

4173{
4174 struct TransportClient *tc;
4175
4176 (void) cls;
4177 tc = GNUNET_new (struct TransportClient);
4178 tc->client = client;
4179 tc->mq = mq;
4182 "Client %p of type %u connected\n",
4183 tc,
4184 tc->type);
4185 return tc;
4186}

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

4193{
4194 struct TransportGlobalNattedAddress *tgna = value;
4195 (void) cls;
4196
4197 GNUNET_free (tgna);
4198
4199 return GNUNET_OK;
4200}

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

4212{
4213 struct DistanceVectorHop *dvh;
4214 struct VirtualLink *vl;
4215
4216 GNUNET_assert (NULL == neighbour->queue_head);
4219 &neighbour->pid,
4220 neighbour));
4222 "Freeing neighbour\n");
4225 NULL);
4227 while (NULL != (dvh = neighbour->dv_head))
4228 {
4229 struct DistanceVector *dv = dvh->dv;
4230
4232 if (NULL == dv->dv_head)
4233 free_dv_route (dv);
4234 }
4235 if (NULL != neighbour->get)
4236 {
4238 neighbour->get = NULL;
4239 }
4240 if (NULL != neighbour->sc)
4241 {
4243 "store cancel\n");
4244 GNUNET_PEERSTORE_store_cancel (neighbour->sc);
4245 neighbour->sc = NULL;
4246 }
4247 if (NULL != (vl = neighbour->vl))
4248 {
4249 GNUNET_assert (neighbour == vl->n);
4250 vl->n = NULL;
4251 if ((GNUNET_YES == drop_link) || (NULL == vl->dv))
4252 {
4254 }
4255 else
4256 {
4259 }
4260 neighbour->vl = NULL;
4261 }
4262 GNUNET_free (neighbour);
4263}

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

4275{
4276 struct GNUNET_MQ_Envelope *env;
4277 struct ConnectInfoMessage *cim;
4278
4279 GNUNET_assert (CT_CORE == tc->type);
4281 cim->id = *pid;
4282 GNUNET_MQ_send (tc->mq, env);
4283}

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

4293{
4295 "Informing CORE clients about connection to %s\n",
4296 GNUNET_i2s (pid));
4297 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
4298 {
4299 if (CT_CORE != tc->type)
4300 continue;
4302 }
4303}

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

12710{
12711 struct Queue *queue = cls;
12712 struct Neighbour *n = queue->neighbour;
12714 struct PendingMessage *pm;
12715
12716 queue->transmit_task = NULL;
12717 if (NULL == n->vl)
12718 {
12720 "Virtual link `%s' is down, cannot have PM for queue `%s'\n",
12721 GNUNET_i2s (&n->pid),
12722 queue->address);
12723 queue->idle = GNUNET_YES;
12724 return;
12725 }
12726 memset (&sc, 0, sizeof(sc));
12727 select_best_pending_from_link (&sc, queue, n->vl, NULL, 0);
12728 if (NULL == sc.best)
12729 {
12730 /* Also look at DVH that have the n as first hop! */
12731 for (struct DistanceVectorHop *dvh = n->dv_head; NULL != dvh;
12732 dvh = dvh->next_neighbour)
12733 {
12734 if (NULL == dvh->dv->vl)
12735 continue; /* route not (yet) visible to CORE, no messages for it */
12737 queue,
12738 dvh->dv->vl,
12739 dvh,
12740 sizeof(struct GNUNET_PeerIdentity)
12741 * (1 + dvh->distance)
12742 + sizeof(struct TransportDVBoxMessage)
12743 + sizeof(struct TransportDVBoxPayloadP));
12744 }
12745 }
12746 if (NULL == sc.best)
12747 {
12748 /* no message pending, nothing to do here! */
12750 "No pending messages, queue `%s' to %s now idle\n",
12751 queue->address,
12752 GNUNET_i2s (&n->pid));
12753 if (GNUNET_YES == sc.to_early)
12754 schedule_transmit_on_queue (sc.to_early_retry_delay,
12755 queue,
12757 queue->idle = GNUNET_YES;
12758 return;
12759 }
12760 /* There is a message pending, we are certainly not idle */
12761 queue->idle = GNUNET_NO;
12762
12763 /* Given selection in `sc`, do transmission */
12764 pm = sc.best;
12766 "Selected message <%" PRIu64 ">\n",
12767 pm->logging_uuid);
12768 if (NULL != sc.dvh)
12769 {
12771 "Is this %u a DV box?\n",
12772 pm->pmt);
12773 GNUNET_assert (PMT_DV_BOX != pm->pmt);
12774 if ((NULL != sc.best->bpm) && (sc.best->bpm->used_dvh != sc.dvh))
12775 {
12777 "Discard old box, because we have a new DV path.\n");
12778 free_pending_message (sc.best->bpm);
12779 sc.best->bpm = NULL;
12780 }
12781
12782 if (NULL == sc.best->bpm)
12783 {
12785 "encapsulate_for_dv 2\n");
12786 encapsulate_for_dv (sc.dvh->dv,
12787 1,
12788 &sc.dvh,
12789 (const struct GNUNET_MessageHeader *) &sc.best[1],
12791 &sc,
12792 RMO_NONE,
12793 GNUNET_NO);
12794 GNUNET_assert (NULL != sc.best->bpm);
12796 "%lu %lu %lu %lu %u\n",
12797 sizeof(struct GNUNET_PeerIdentity),
12798 sizeof(struct TransportDVBoxMessage),
12799 sizeof(struct TransportDVBoxPayloadP),
12800 sizeof(struct TransportFragmentBoxMessage),
12801 ((const struct GNUNET_MessageHeader *) &sc.best[1])->size);
12802 sc.best->bpm->used_dvh = sc.dvh;
12803 }
12804 pm = sc.best->bpm;
12805 }
12806 if (GNUNET_YES == sc.frag)
12807 {
12808 pm = fragment_message (queue, sc.dvh, pm);
12809 if (NULL == pm)
12810 {
12812 "Fragmentation failed queue %s to %s for <%" PRIu64
12813 ">, trying again\n",
12814 queue->address,
12815 GNUNET_i2s (&n->pid),
12816 sc.best->logging_uuid);
12818 queue,
12820 return;
12821 }
12822 }
12823 else if (GNUNET_YES == sc.relb)
12824 {
12825 pm = reliability_box_message (queue, sc.dvh, pm);
12826 if (NULL == pm)
12827 {
12828 /* Reliability boxing failed, try next message... */
12829 GNUNET_log (
12831 "Reliability boxing failed queue %s to %s for <%" PRIu64
12832 ">, trying again\n",
12833 queue->address,
12834 GNUNET_i2s (&n->pid),
12835 sc.best->logging_uuid);
12837 queue,
12839 return;
12840 }
12841 }
12842
12843 /* Pass 'pm' for transission to the communicator */
12844 GNUNET_log (
12846 "Passing message <%" PRIu64
12847 "> to queue %s for peer %s (considered %u others)\n",
12848 pm->logging_uuid,
12849 queue->address,
12850 GNUNET_i2s (&n->pid),
12851 sc.consideration_counter);
12852
12853 /* Flow control: increment amount of traffic sent; if we are routing
12854 via DV (and thus the ultimate target of the pending message is for
12855 a different virtual link than the one of the queue), then we need
12856 to use up not only the window of the direct link but also the
12857 flow control window for the DV link! */
12859
12860 if (pm->vl != queue->neighbour->vl)
12861 {
12862 /* If the virtual link of the queue differs, this better be distance
12863 vector routing! */
12864 GNUNET_assert (NULL != sc.dvh);
12865 /* If we do distance vector routing, we better not do this for a
12866 message that was itself DV-routed */
12867 GNUNET_assert (PMT_DV_BOX != sc.best->pmt);
12868 /* We use the size of the unboxed message here, to avoid counting
12869 the DV-Box header which is eaten up on the way by intermediaries */
12870 queue->neighbour->vl->outbound_fc_window_size_used += sc.best->bytes_msg;
12871 }
12872 else
12873 {
12874 GNUNET_assert (NULL == sc.dvh);
12875 }
12876
12877 queue_send_msg (queue, pm, &pm[1], pm->bytes_msg);
12878
12879 /* The message is with the communicator now, so return the CORE send
12880 window credit for it -- see #credit_client().
12881
12882 It used to be returned here only for an unboxed message or a reliable
12883 communicator, and otherwise not until the *peer* acknowledged the
12884 message below. That makes a window into a delivery confirmation: over
12885 an unreliable communicator every reliability-boxed or fragmented
12886 message holds one of the client's #SEND_WINDOW_SIZE slots for as long
12887 as its ACK takes, and a lost ACK holds it for the whole retransmission
12888 chain. Four of those and CORE cannot send to that peer at all -- not
12889 payload, but also not its HEARTBEATs and not one message of its key
12890 exchange. So the session times out for want of a heartbeat that is
12891 sitting in a queue, and the handshake that would rebuild it cannot go
12892 out either; CORE only recovers when a reconnect resets the window
12893 wholesale. Acknowledgements still drive retransmission below, they
12894 just no longer gate the client. */
12895 credit_client (sc.best);
12896
12897 /* Check if this transmission somehow conclusively finished handing 'pm'
12898 even without any explicit ACKs */
12899 if ((PMT_CORE == pm->pmt) ||
12900 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc))
12901 {
12903 }
12904 else
12905 {
12906 struct GNUNET_TIME_Relative wait_duration;
12907 unsigned int wait_multiplier;
12908
12909 if (PMT_FRAGMENT_BOX == pm->pmt)
12910 {
12911 struct PendingMessage *root;
12912
12913 root = pm->frag_parent;
12914 while (NULL != root->frag_parent && PMT_DV_BOX != root->pmt)
12915 root = root->frag_parent;
12916
12917 if ((0 == root->frag_off) || (0 == root->frag_count))
12918 {
12919 wait_multiplier = 4;
12920 }
12921 else
12922 {
12923 double wm = ceil ((double) root->bytes_msg
12924 / ((double) root->frag_off
12925 / (double) root->frag_count)) * 4.0;
12926
12927 if ((! (wm >= 1.0)) || (wm > 1024.0))
12928 wm = 4.0; /* NaN, infinity or absurd: fall back to the default */
12929 wait_multiplier = (unsigned int) wm;
12930 }
12931 }
12932 else
12933 {
12934 // No fragments, we use 4 RTT before retransmitting.
12935 wait_multiplier = 4;
12936 }
12937
12938 // Depending on how much pending message the VirtualLink is queueing, we wait longer.
12939 // wait_multiplier = wait_multiplier * pm->vl->pending_msg_num;
12940
12942 "Wait multiplier %u\n",
12943 wait_multiplier);
12944
12945 /* Message not finished, waiting for acknowledgement.
12946 Update time by which we might retransmit 's' based on queue
12947 characteristics (i.e. RTT); it takes one RTT for the message to
12948 arrive and the ACK to come back in the best case; but the other
12949 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
12950 retransmitting.
12951
12952 OPTIMIZE: Note that in the future this heuristic should likely
12953 be improved further (measure RTT stability, consider message
12954 urgency and size when delaying ACKs, etc.) */
12955
12956 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us !=
12957 queue->pd.aged_rtt.rel_value_us)
12958 wait_duration = queue->pd.aged_rtt;
12959 else
12960 {
12961 wait_duration = DEFAULT_ACK_WAIT_DURATION;
12962 wait_multiplier = 4;
12963 }
12964 {
12967 wait_duration, wait_multiplier));
12969 wait_duration, wait_multiplier);
12971 "Waiting %s for ACK until %s\n",
12976 GNUNET_TIME_relative_multiply (wait_duration,
12977 wait_multiplier))
12978 );
12979 }
12980 }
12981 /* finally, re-schedule queue transmission task itself */
12983 queue,
12985}

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_multiply(), GNUNET_TIME_relative_to_absolute(), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_TIME_UNIT_ZERO, GNUNET_TRANSPORT_CC_RELIABLE, GNUNET_YES, PendingMessage::logging_uuid, 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 the communicator has another queue with higher prio ready for sending.

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

4322{
4323 for (struct Queue *s = queue_head; NULL != s;
4324 s = s->next_client)
4325 {
4326 if (s->tc->details.communicator.address_prefix !=
4327 queue->tc->details.communicator.address_prefix)
4328 {
4330 "queue address %s qid %u compare with queue: address %s qid %u\n",
4331 queue->address,
4332 queue->qid,
4333 s->address,
4334 s->qid);
4335 if ((s->priority > queue->priority) && (0 < s->q_capacity) &&
4336 (QUEUE_LENGTH_LIMIT > s->queue_length) )
4337 return GNUNET_YES;
4339 "Lower prio\n");
4340 }
4341 }
4342 return GNUNET_NO;
4343}

References GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_NO, GNUNET_YES, Queue::next_client, 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 5432 of file gnunet-service-transport.c.

5433{
5434 if (NULL != tc->details.communicator.free_queue_entry_task)
5435 return;
5436 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
5437 queue = queue->next_client)
5438 {
5439 if (NULL == queue->queue_head)
5440 continue;
5441 tc->details.communicator.free_queue_entry_task =
5444 tc);
5445 return;
5446 }
5447}

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

4367{
4369
4370 if (queue->validated_until.abs_value_us < now.abs_value_us)
4371 return;
4373 queue->tc->details.communicator.
4374 queue_head))
4375 return;
4376
4377 if (queue->tc->details.communicator.total_queue_length >=
4379 {
4381 "Transmission on queue %s (QID %u) throttled due to communicator queue limit\n",
4382 queue->address,
4383 queue->qid);
4385 GST_stats,
4386 "# Transmission throttled due to communicator queue limit",
4387 1,
4388 GNUNET_NO);
4389 queue->idle = GNUNET_NO;
4390 /* @e total_queue_length is shared by every peer this communicator serves,
4391 so at the limit we can send to none of them, and the only things that
4392 lower it again are an ACK from the communicator, #free_queue() and
4393 #free_timedout_queue_entry(). If we got here because a peer stopped
4394 acknowledging, no ACK is coming; and we just declined to arm
4395 @e transmit_task, so #queue_send_msg() -- the *only* place that arms
4396 the sweeper -- will not run either. That leaves nothing at all to
4397 recover the count, and the communicator stays mute towards every peer
4398 until some unrelated queue happens to go down. Keep the sweeper
4399 going. */
4401 return;
4402 }
4403 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
4404 {
4406 "Transmission on queue %s (QID %u) throttled due to communicator queue length limit\n",
4407 queue->address,
4408 queue->qid);
4410 "# Transmission throttled due to queue queue limit",
4411 1,
4412 GNUNET_NO);
4413 queue->idle = GNUNET_NO;
4414 /* Same reasoning as above, for the per-queue limit. */
4416 return;
4417 }
4418 if (0 == queue->q_capacity)
4419 {
4421 "Transmission on queue %s (QID %u) throttled due to communicator message has capacity %"
4422 PRIu64 ".\n",
4423 queue->address,
4424 queue->qid,
4425 queue->q_capacity);
4427 "# Transmission throttled due to message queue capacity",
4428 1,
4429 GNUNET_NO);
4430 queue->idle = GNUNET_NO;
4431 return;
4432 }
4433 /* queue might indeed be ready, schedule it */
4434 if (NULL != queue->transmit_task)
4435 GNUNET_SCHEDULER_cancel (queue->transmit_task);
4436 queue->transmit_task =
4438 queue);
4440 "Considering transmission on queue `%s' QID %llu to %s\n",
4441 queue->address,
4442 (unsigned long long) queue->qid,
4443 GNUNET_i2s (&queue->neighbour->pid));
4444}

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_head, 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 10340 of file gnunet-service-transport.c.

10342{
10343 struct GNUNET_TIME_Absolute now;
10344 struct ValidationState *vs;
10345 struct CheckKnownAddressContext ckac = { .address = address, .vs = NULL };
10346
10348 pid,
10350 &ckac);
10352 if (NULL != (vs = ckac.vs))
10353 {
10354 const struct VirtualLink *vl = lookup_virtual_link (pid);
10355
10356 /* Speed up retrying the validation if 'vs' is not currently valid, or if
10357 * we have no confirmed virtual link to @a pid. In the latter case the
10358 * address may still be well inside its validity window -- but the link is
10359 * down, and #handle_validation_response() is the only thing that can
10360 * rebuild it and tell CORE about the peer again. Without this we would
10361 * wait for @e revalidation_task, which does not fire until
10362 * #ADDRESS_VALIDATION_LIFETIME is nearly over. */
10363 if ((vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us) ||
10364 (NULL == vl) ||
10365 (GNUNET_NO == vl->confirmed))
10366 {
10367 /* reduce backoff as we got a fresh advertisement */
10368 vs->challenge_backoff =
10371 vs->challenge_backoff,
10372 2));
10373 /* A successful validation parks @e first_challenge_use just before
10374 @e validated_until, so that the *next* challenge is not used before
10375 the current validation is about to expire. #validation_start_cb()
10376 refuses to run while that time is still in the future, so pulling
10377 @e next_challenge in without this would only make it reschedule
10378 itself four hours out. The challenge has not been used yet, so
10379 moving the start of its window to now stays truthful -- it is what
10380 the fresh-@a vs path below does as well. */
10381 if (GNUNET_TIME_absolute_cmp (vs->first_challenge_use, >, now))
10382 vs->first_challenge_use = now;
10385 vs->challenge_backoff));
10386 }
10387 return;
10388 }
10389 vs = GNUNET_new (struct ValidationState);
10390 vs->pid = *pid;
10391 vs->valid_until =
10393 vs->first_challenge_use = now;
10394 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
10395 GNUNET_CRYPTO_random_block (&vs->challenge,
10396 sizeof(vs->challenge));
10397 vs->address = GNUNET_strdup (address);
10398 {
10399 /* The peer identity MUST be part of @e hc: two peers behind the same NAT
10400 advertise the very same address string (`PROTO-IP:0'), and with an
10401 address-only key the second one's #revalidation_map entry would be
10402 rejected as a duplicate of the first one's. */
10403 struct GNUNET_HashContext *hsh;
10404
10406 GNUNET_CRYPTO_hash_context_read (hsh, vs->address, strlen (vs->address));
10407 GNUNET_CRYPTO_hash_context_read (hsh, &vs->pid, sizeof(vs->pid));
10408 GNUNET_CRYPTO_hash_context_finish (hsh, &vs->hc);
10409 }
10411 "Starting address validation `%s' of peer %s using challenge %s\n",
10412 address,
10413 GNUNET_i2s (pid),
10414 GNUNET_sh2s (&vs->challenge.value));
10418 &vs->pid,
10419 vs,
10422}

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

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

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

◆ free_queue()

static void free_queue ( struct Queue queue)
static

Free queue.

Parameters
queuethe queue to free

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

4557{
4558 struct Neighbour *neighbour = queue->neighbour;
4559 struct TransportClient *tc = queue->tc;
4560 struct MonitorEvent me = { .cs = GNUNET_TRANSPORT_CS_DOWN,
4562 struct QueueEntry *qe;
4563 int maxxed;
4564 struct PendingAcknowledgement *pa;
4565 struct VirtualLink *vl;
4566
4568 "Cleaning up queue %u\n", queue->qid);
4569 if (NULL != queue->mo)
4570 {
4572 queue->mo = NULL;
4573 }
4574 if (NULL != queue->transmit_task)
4575 {
4576 GNUNET_SCHEDULER_cancel (queue->transmit_task);
4577 queue->transmit_task = NULL;
4578 }
4579 while (NULL != (pa = queue->pa_head))
4580 {
4581 GNUNET_CONTAINER_MDLL_remove (queue, queue->pa_head, queue->pa_tail, pa);
4582 pa->queue = NULL;
4583 }
4584
4586 neighbour->queue_head,
4587 neighbour->queue_tail,
4588 queue);
4590 tc->details.communicator.queue_head,
4591 tc->details.communicator.queue_tail,
4592 queue);
4594 tc->details.communicator.total_queue_length);
4596 "Cleaning up queue with length %u\n",
4597 queue->queue_length);
4598 while (NULL != (qe = queue->queue_head))
4599 {
4600 GNUNET_CONTAINER_DLL_remove (queue->queue_head, queue->queue_tail, qe);
4601 queue->queue_length--;
4602 tc->details.communicator.total_queue_length--;
4603 if (NULL != qe->pm)
4604 {
4605 GNUNET_assert (qe == qe->pm->qe);
4606 qe->pm->qe = NULL;
4607 }
4608 GNUNET_free (qe);
4609 }
4610 GNUNET_assert (0 == queue->queue_length);
4611 if ((maxxed) && (COMMUNICATOR_TOTAL_QUEUE_LIMIT >
4612 tc->details.communicator.total_queue_length))
4613 {
4614 /* Communicator dropped below threshold, resume all _other_ queues */
4616 GST_stats,
4617 "# Transmission throttled due to communicator queue limit",
4618 -1,
4619 GNUNET_NO);
4620 for (struct Queue *s = tc->details.communicator.queue_head; NULL != s;
4621 s = s->next_client)
4623 s,
4625 }
4626 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
4628
4629 vl = lookup_virtual_link (&neighbour->pid);
4630 if ((NULL != vl) && (neighbour == vl->n))
4631 {
4633 check_link_down (vl);
4634 }
4635 if (NULL == neighbour->queue_head)
4636 {
4637 free_neighbour (neighbour, GNUNET_NO);
4638 }
4639}

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

6525{
6526 struct PilsAddressSignContext *pc = ale->pc;
6527
6528 if (NULL == pc)
6529 return;
6530 ale->pc = NULL;
6531 /* Each stage of the chain passes @a pc as its closure, so every handle
6532 that could still deliver one has to go before @a pc is released. */
6533 if (NULL != ale->sc)
6534 {
6536 ale->sc = NULL;
6537 }
6538 if (NULL != ale->shc)
6539 {
6541 ale->shc = NULL;
6542 }
6543 if (NULL != pc->req)
6544 {
6545 if (NULL != pc->req->op)
6546 GNUNET_PILS_cancel (pc->req->op);
6549 pc->req);
6550 GNUNET_free (pc->req);
6551 pc->req = NULL;
6552 }
6553 GNUNET_free (pc);
6554}

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

4660{
4661 struct TransportClient *tc = ale->tc;
4662
4663 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
4664 tc->details.communicator.addr_tail,
4665 ale);
4666 /* Cancels @e sc, @e shc and the pending PILS signature request, all of
4667 which would otherwise run their callbacks on this freed entry. */
4669 if (NULL != ale->sc)
4670 {
4672 "store cancel\n");
4674 ale->sc = NULL;
4675 }
4676 if (NULL != ale->shc)
4677 {
4679 ale->shc = NULL;
4680 }
4681 if (NULL != ale->st)
4682 {
4684 ale->st = NULL;
4685 }
4686 if (NULL != ale->signed_address)
4688 GNUNET_free (ale);
4689}

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

4704{
4705 struct TransportClient *tc = cls;
4706 struct PeerRequest *pr = value;
4707
4708 if (NULL != pr->nc)
4710 pr->nc = NULL;
4712 GNUNET_YES ==
4713 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
4714 pid,
4715 pr));
4716 GNUNET_free (pr);
4717
4718 return GNUNET_OK;
4719}

References GNUNET_assert, GNUNET_CONTAINER_multipeermap_remove(), GNUNET_free, GNUNET_OK, GNUNET_PEERSTORE_monitor_stop(), 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 15141 of file gnunet-service-transport.c.

15142{
15143 static int shutdown_done;
15144 struct LearnLaunchEntry *lle;
15145 struct PilsRequest *pr;
15146 (void) cls;
15147
15149 "shutdown logic\n");
15150 if (GNUNET_YES == shutdown_done)
15151 return; /* reachable both from #shutdown_task() and #client_disconnect_cb() */
15152 shutdown_done = GNUNET_YES;
15153 if (NULL != client_grace_task)
15154 {
15156 client_grace_task = NULL;
15157 }
15158 if (NULL != nh)
15159 {
15161 nh = NULL;
15162 }
15164 &free_neighbour_cb, NULL);
15165 /* Freeing a neighbour takes its virtual link with it, so whatever is
15166 left here is ownerless: a link we created from an inbound FLOW_CONTROL
15167 message that never got confirmed, kept alive only by its @e
15168 unconfirmed_timeout_task. #GNUNET_SCHEDULER_shutdown() does not run
15169 that task, so leaving the link in place left the task armed against a
15170 map we destroy further down -- it fired afterwards and
15171 #free_virtual_link() called GNUNET_CONTAINER_multipeermap_remove() on
15172 NULL. Drop them here, while every structure they touch is still
15173 alive. */
15176 NULL);
15177 if (NULL != validation_task)
15178 {
15180 validation_task = NULL;
15181 }
15182 if (NULL != dvlearn_task)
15183 {
15185 dvlearn_task = NULL;
15186 }
15187 if (NULL != burst_task)
15188 {
15190 burst_task = NULL;
15191 }
15192 if (NULL != burst_timeout_task)
15193 {
15195 burst_timeout_task = NULL;
15196 }
15199 dvlearn_map = NULL;
15202 dv_routes = NULL;
15203 if (NULL != GST_stats)
15204 {
15206 GST_stats = NULL;
15207 }
15208 if (NULL != GST_my_hello)
15209 {
15211 GST_my_hello = NULL;
15212 }
15215 NULL);
15217 ack_cummulators = NULL;
15220 NULL);
15222 pending_acks = NULL;
15225 neighbours = NULL;
15228 links = NULL;
15231 NULL);
15233 backtalkers = NULL;
15236 NULL);
15238 validation_map = NULL;
15240 validation_heap = NULL;
15242 revalidation_map = NULL;
15243 while (NULL != ir_head)
15245 GNUNET_assert (0 == ir_total);
15246 while (NULL != (lle = lle_head))
15247 {
15249 GNUNET_free (lle);
15250 }
15251 while (NULL != (pr = pils_requests_head))
15252 {
15255 pr);
15256 if (NULL != pr->op)
15257 GNUNET_PILS_cancel (pr->op);
15258 GNUNET_free (pr);
15259 }
15260 if (NULL != pils_feed_task)
15261 {
15263 pils_feed_task = NULL;
15264 }
15265 if (NULL != pils)
15266 {
15268 pils = NULL;
15269 }
15270 if (NULL != peerstore)
15271 {
15273 "Disconnecting from PEERSTORE service\n");
15275 peerstore = NULL;
15276 }
15278}

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:

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

4737{
4738 struct TransportClient *tc = app_ctx;
4739
4740 (void) cls;
4741 (void) client;
4743 switch (tc->type)
4744 {
4745 case CT_NONE:
4747 "Unknown Client %p disconnected, cleaning up.\n",
4748 tc);
4749 break;
4750
4751 case CT_CORE: {
4752 struct PendingMessage *pm;
4754 "CORE Client %p disconnected, cleaning up.\n",
4755 tc);
4756
4757
4758 while (NULL != (pm = tc->details.core.pending_msg_head))
4759 {
4761 tc->details.core.pending_msg_head,
4762 tc->details.core.pending_msg_tail,
4763 pm);
4764 pm->client = NULL;
4765 }
4766 }
4767 break;
4768
4769 case CT_MONITOR:
4771 "MONITOR Client %p disconnected, cleaning up.\n",
4772 tc);
4773
4774 break;
4775
4776 case CT_COMMUNICATOR: {
4777 struct Queue *q;
4778 struct AddressListEntry *ale;
4779
4781 "COMMUNICATOR Client %p disconnected, cleaning up.\n",
4782 tc);
4783
4784 if (NULL != tc->details.communicator.free_queue_entry_task)
4786 tc->details.communicator.free_queue_entry_task);
4787 while (NULL != (q = tc->details.communicator.queue_head))
4788 free_queue (q);
4789 while (NULL != (ale = tc->details.communicator.addr_head))
4791 GNUNET_free (tc->details.communicator.address_prefix);
4792 }
4793 break;
4794
4795 case CT_APPLICATION:
4797 "APPLICATION Client %p disconnected, cleaning up.\n",
4798 tc);
4799
4800 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
4802 tc);
4803 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
4804 break;
4805 }
4806 GNUNET_free (tc);
4807 if ((GNUNET_YES == in_shutdown) && (NULL == clients_head))
4808 {
4810 "Our last client disconnected\n");
4811 do_shutdown (cls);
4812 }
4813}

References PendingMessage::client, TransportClient::client, clients_head, clients_tail, CT_APPLICATION, CT_COMMUNICATOR, CT_CORE, CT_MONITOR, CT_NONE, 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 4826 of file gnunet-service-transport.c.

4829{
4830 struct TransportClient *tc = cls;
4831 struct VirtualLink *vl = value;
4832
4833 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
4834 return GNUNET_OK;
4835
4837 "Telling new CORE client about existing connection to %s\n",
4838 GNUNET_i2s (pid));
4840 return GNUNET_OK;
4841}

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

4858{
4859 struct VirtualLink *vl = value;
4860 struct CommunicatorMessageContext *cmc;
4861
4862 /* resume communicators */
4863 while (NULL != (cmc = vl->cmc_tail))
4864 release_stalled_cmc (vl, cmc);
4865 if (NULL != vl->core_fc_stall_task)
4866 {
4868 vl->core_fc_stall_task = NULL;
4869 }
4870 /* A CORE client that just attached has nothing outstanding, so give it a
4871 full window. The RECV_OKs that would have returned the credit spent by
4872 its predecessor died with that client, and #handle_client_recv_ok() is
4873 the only thing that ever raises this counter -- so without the reset
4874 every message on this link takes the "CORE ran out of window" path from
4875 here on, and only #core_fc_stalled() (after CORE_FC_STALL_TIMEOUT, and
4876 once per round) ever lets any through. */
4878 return GNUNET_OK;
4879}

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

4892{
4893 // const struct GNUNET_PeerIdentity *my_identity;
4894 struct TransportClient *tc = cls;
4895 // uint32_t options;
4896 //
4897 // my_identity = GNUNET_PILS_get_identity (pils);
4898 // GNUNET_assert (my_identity);
4899 //
4900 // FIXME ignore the check of the peer ids for now.
4901 // (also deprecate the old way of obtaining our own peer ID)
4902 // options = ntohl (start->options);
4903 // if ((0 != (1 & options)) &&
4904 // (0 != GNUNET_memcmp (&start->self, my_identity)))
4905 // {
4906 // /* client thinks this is a different peer, reject */
4907 // GNUNET_break (0);
4908 // GNUNET_SERVICE_client_drop (tc->client);
4909 // return;
4910 // }
4911 if (CT_NONE != tc->type)
4912 {
4913 GNUNET_break (0);
4915 return;
4916 }
4917 tc->type = CT_CORE;
4919 "New CORE client with PID %s registered\n",
4920 GNUNET_i2s (&start->self));
4923 tc);
4926 NULL);
4928}

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

4939{
4940 struct TransportClient *tc = cls;
4941 uint16_t size;
4942 const struct GNUNET_MessageHeader *obmm;
4943
4944 if (CT_CORE != tc->type)
4945 {
4946 GNUNET_break (0);
4947 return GNUNET_SYSERR;
4948 }
4949 size = ntohs (obm->header.size) - sizeof(struct OutboundMessage);
4950 if (size < sizeof(struct GNUNET_MessageHeader))
4951 {
4952 GNUNET_break (0);
4953 return GNUNET_SYSERR;
4954 }
4955 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
4956 if (size != ntohs (obmm->size))
4957 {
4958 GNUNET_break (0);
4959 return GNUNET_SYSERR;
4960 }
4961 return GNUNET_OK;
4962}

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

4974{
4975 struct TransportClient *tc = pm->client;
4976 struct VirtualLink *vl = pm->vl;
4977
4979 "client send response\n");
4980 if (NULL != tc)
4981 {
4983 "Confirming transmission of <%" PRIu64 "> to %s\n",
4984 pm->logging_uuid,
4985 GNUNET_i2s (&vl->target));
4986 credit_client (pm);
4987 }
4989}

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

5006{
5007 uint64_t choices[hops_array_length];
5008 uint64_t num_dv;
5009 unsigned int dv_count;
5010
5011 /* Pick random vectors, but weighted by distance, giving more weight
5012 to shorter vectors */
5013 num_dv = 0;
5014 dv_count = 0;
5015 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5016 pos = pos->next_dv)
5017 {
5018 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
5019 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
5020 .rel_value_us == 0))
5021 continue; /* pos unconfirmed and confirmed required */
5022 num_dv += MAX_DV_HOPS_ALLOWED - pos->distance;
5023 dv_count++;
5024 }
5025 if (0 == dv_count)
5026 return 0;
5027 if (dv_count <= hops_array_length)
5028 {
5029 dv_count = 0;
5030 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5031 pos = pos->next_dv)
5032 hops_array[dv_count++] = pos;
5033 return dv_count;
5034 }
5035 for (unsigned int i = 0; i < hops_array_length; i++)
5036 {
5037 int ok = GNUNET_NO;
5038 while (GNUNET_NO == ok)
5039 {
5040 choices[i] =
5041 GNUNET_CRYPTO_random_u64 (num_dv);
5042 ok = GNUNET_YES;
5043 for (unsigned int j = 0; j < i; j++)
5044 if (choices[i] == choices[j])
5045 {
5046 ok = GNUNET_NO;
5047 break;
5048 }
5049 }
5050 }
5051 dv_count = 0;
5052 num_dv = 0;
5053 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5054 pos = pos->next_dv)
5055 {
5056 uint32_t delta = MAX_DV_HOPS_ALLOWED - pos->distance;
5057
5058 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
5059 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
5060 .rel_value_us == 0))
5061 continue; /* pos unconfirmed and confirmed required */
5062 for (unsigned int i = 0; i < hops_array_length; i++)
5063 if ((num_dv <= choices[i]) && (num_dv + delta > choices[i]))
5064 hops_array[dv_count++] = pos;
5065 num_dv += delta;
5066 }
5067 return dv_count;
5068}

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

Referenced by route_control_message_without_fc().

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

◆ check_communicator_available()

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

Communicator started.

Test message is well-formed.

Parameters
clsthe client
camthe send message that was sent

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

5081{
5082 struct TransportClient *tc = cls;
5083 uint16_t size;
5084
5085 if (CT_NONE != tc->type)
5086 {
5087 GNUNET_break (0);
5088 return GNUNET_SYSERR;
5089 }
5090 tc->type = CT_COMMUNICATOR;
5091 size = ntohs (cam->header.size) - sizeof(*cam);
5092 if (0 == size)
5093 return GNUNET_OK; /* receive-only communicator */
5095 return GNUNET_OK;
5096}

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

5112{
5113 struct GNUNET_MQ_Envelope *env;
5115
5116 if (GNUNET_YES == cmc->ack_sent)
5117 return;
5118 cmc->ack_sent = GNUNET_YES;
5119 if (0 == ntohl (cmc->im.fc_on))
5120 return; /* communicator did not ask for flow control */
5122 "Acknowledge message with flow control id %" PRIu64 "\n",
5123 cmc->im.fc_id);
5125 ack->reserved = htonl (0);
5126 ack->fc_id = cmc->im.fc_id;
5127 ack->sender = cmc->im.neighbour_sender;
5128 GNUNET_MQ_send (cmc->tc->mq, env);
5129}

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

5144{
5145 if (GNUNET_YES == cmc->client_resumed)
5146 return;
5149}

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

5203{
5204 struct TransportClient *tc = cls;
5205 struct VirtualLink *vl;
5206 uint32_t delta;
5207 struct CommunicatorMessageContext *cmc;
5208
5209 if (CT_CORE != tc->type)
5210 {
5211 GNUNET_break (0);
5213 return;
5214 }
5215 vl = lookup_virtual_link (&rom->peer);
5216 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
5217 {
5219 "# RECV_OK dropped: virtual link unknown",
5220 1,
5221 GNUNET_NO);
5223 return;
5224 }
5225 delta = ntohl (rom->increase_window_delta);
5226 vl->core_recv_window += delta;
5228 "CORE ack receiving message, increased CORE recv window to %d\n",
5229 vl->core_recv_window);
5231 if (vl->core_recv_window <= 0)
5232 return;
5233 /* release the flow control credit we withheld from the communicators */
5234 while (NULL != (cmc = vl->cmc_tail))
5235 release_stalled_cmc (vl, cmc);
5236 if (NULL != vl->core_fc_stall_task)
5237 {
5239 vl->core_fc_stall_task = NULL;
5240 }
5241}

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

5254{
5255 const struct GNUNET_PeerIdentity *my_identity;
5256 struct TransportClient *tc = cls;
5257 uint16_t size;
5258
5259 size = ntohs (cam->header.size) - sizeof(*cam);
5260 if (0 == size)
5261 {
5263 "Receive-only communicator connected\n");
5264 /* Receive-only communicator: it has no address prefix, but we still
5265 MUST resume the client or we will never read from it again. Use an
5266 empty prefix so that the various strcmp()s do not see NULL. */
5267 tc->details.communicator.address_prefix = GNUNET_strdup ("");
5269 return;
5270 }
5271 tc->details.communicator.address_prefix =
5272 GNUNET_strdup ((const char *) &cam[1]);
5273 tc->details.communicator.cc = ntohl (cam->cc);
5274 tc->details.communicator.can_burst = ntohl (cam->can_burst);
5276 if (NULL != my_identity)
5277 {
5279 "Communicator for peer %s with prefix '%s' connected %s\n",
5281 tc->details.communicator.address_prefix,
5282 tc->details.communicator.can_burst ? "can burst" :
5283 "can not burst");
5284 }
5285 else
5286 {
5288 "Communicator for local peer with prefix '%s' connected %s\n",
5289 tc->details.communicator.address_prefix,
5290 tc->details.communicator.can_burst ? "can burst" :
5291 "can not burst");
5292 }
5294}

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

5308{
5309 const struct GNUNET_MessageHeader *inbox;
5310 const char *is;
5311 uint16_t msize;
5312 uint16_t isize;
5313
5314 (void) cls;
5315 msize = ntohs (cb->header.size) - sizeof(*cb);
5316 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
5317 /* MUST bound the buffer before dereferencing @a inbox. */
5318 if (msize <= sizeof(struct GNUNET_MessageHeader))
5319 {
5320 GNUNET_break (0);
5321 return GNUNET_SYSERR;
5322 }
5323 isize = ntohs (inbox->size);
5324 if (isize >= msize)
5325 {
5326 GNUNET_break (0);
5327 return GNUNET_SYSERR;
5328 }
5329 is = (const char *) inbox;
5330 is += isize;
5331 msize -= isize;
5332 GNUNET_assert (0 < msize);
5333 if ('\0' != is[msize - 1])
5334 {
5335 GNUNET_break (0);
5336 return GNUNET_SYSERR;
5337 }
5338 return GNUNET_OK;
5339}

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

5358{
5359 struct EphemeralConfirmationPS ec;
5360
5362 dv->ephemeral_validity =
5364 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
5365 ec.target = dv->target;
5366 ec.ephemeral_key = dv->ephemeral_key;
5367 ec.sender_monotonic_time = GNUNET_TIME_absolute_hton (dv->monotime);
5368 ec.purpose.size = htonl (sizeof(ec));
5369 return sign_by_my_identity (&ec.purpose, &dv->sender_sig);
5370}

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

13044{
13045 struct PendingMessage *pm;
13046
13047 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
13048 qe->queue->queue_tail,
13049 qe);
13050 qe->queue->queue_length--;
13051 tc->details.communicator.total_queue_length--;
13053 "Received ACK on queue %s (QID %u) to peer %s (new length: %u/%u)\n",
13054 qe->queue->address,
13055 qe->queue->qid,
13056 GNUNET_i2s (&qe->queue->neighbour->pid),
13057 qe->queue->queue_length,
13058 tc->details.communicator.total_queue_length);
13059
13060 /* if applicable, resume transmissions that waited on ACK */
13062 tc->details.communicator.total_queue_length)
13063 {
13064 /* Communicator dropped below threshold, resume all queues
13065 incident with this client! */
13067 GST_stats,
13068 "# Transmission throttled due to communicator queue limit",
13069 -1,
13070 GNUNET_NO);
13071 for (struct Queue *queue = tc->details.communicator.queue_head;
13072 NULL != queue;
13073 queue = queue->next_client)
13074 {
13076 queue,
13078 }
13079 }
13080 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
13081 {
13082 /* queue dropped below threshold; only resume this one queue */
13084 "# Transmission throttled due to queue queue limit",
13085 -1,
13086 GNUNET_NO);
13088 qe->queue,
13090 }
13091 else if (1 == qe->queue->q_capacity)
13092 {
13093 // TODO I guess this will never happen, because the communicator triggers this by updating its queue length itself.
13095 "Transmission rescheduled due to communicator message queue with qid %u has capacity %"
13096 PRIu64 ".\n",
13097 qe->queue->qid,
13098 qe->queue->q_capacity);
13099 /* message queue has capacity; only resume this one queue */
13100 /* queue dropped below threshold; only resume this one queue */
13102 "# Transmission throttled due to message queue capacity",
13103 -1,
13104 GNUNET_NO);
13106 qe->queue,
13108 }
13109
13110 if (NULL != (pm = qe->pm))
13111 {
13112 struct VirtualLink *vl;
13113
13114 // GNUNET_assert (qe == pm->qe);
13115 pm->qe = NULL;
13116 /* If waiting for this communicator may have blocked transmission
13117 of pm on other queues for this neighbour, force schedule
13118 transmit on queue for queues of the neighbour */
13119 if (NULL == pm->frag_parent)
13120 {
13121 vl = pm->vl;
13122 if ((NULL != vl) &&
13123 (NULL != vl->pending_msg_head) &&
13124 (vl->pending_msg_head == pm))
13126 }
13127 }
13128 GNUNET_free (qe);
13129}

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

5380{
5381 struct TransportClient *tc = cls;
5383
5385 "freeing timedout queue entries\n");
5386
5387 tc->details.communicator.free_queue_entry_task = NULL;
5388 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
5389 queue = queue->next_client)
5390 {
5391 struct QueueEntry *qep = queue->queue_head;
5392
5394 "checking QID %u for timedout queue entries\n",
5395 queue->qid);
5396 while (NULL != qep)
5397 {
5398 struct QueueEntry *pos = qep;
5400 pos->creation_timestamp, now);
5401 qep = qep->next;
5402
5404 "diff to now %s \n",
5407 {
5409 "Freeing timed out QueueEntry with MID %" PRIu64
5410 " and QID %u\n",
5411 pos->mid,
5412 queue->qid);
5414 "# QueueEntries timed out",
5415 1,
5416 GNUNET_NO);
5417 free_queue_entry (pos, tc);
5418 }
5419 }
5420 }
5421 /* Entries younger than #QUEUE_ENTRY_TIMEOUT are still to be reclaimed, and
5422 this task used to be a one-shot armed only by #queue_send_msg(). So the
5423 sweep that was supposed to bound how long an unacknowledged entry holds
5424 its slot only ever ran while *new* messages were being queued -- exactly
5425 not the case once the throttles in #schedule_transmit_on_queue() have
5426 stopped transmission. Keep going as long as anything is outstanding. */
5428}

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

5464{
5465 struct Neighbour *n = queue->neighbour;
5467 struct GNUNET_MQ_Envelope *env;
5468 struct PendingAcknowledgement *pa;
5469
5470 GNUNET_log (
5472 "Queueing %u bytes of payload for transmission <%" PRIu64
5473 "> on queue %llu to %s\n",
5474 (unsigned int) payload_size,
5475 (NULL == pm) ? 0 : pm->logging_uuid,
5476 (unsigned long long) queue->qid,
5477 GNUNET_i2s (&queue->neighbour->pid));
5478 env = GNUNET_MQ_msg_extra (smt,
5479 payload_size,
5481 smt->qid = htonl (queue->qid);
5482 smt->mid = GNUNET_htonll (queue->mid_gen);
5483 smt->receiver = n->pid;
5484 memcpy (&smt[1], payload, payload_size);
5485 {
5486 /* Pass the env to the communicator of queue for transmission. */
5487 struct QueueEntry *qe;
5488
5489 qe = GNUNET_new (struct QueueEntry);
5490 qe->creation_timestamp = GNUNET_TIME_absolute_get ();
5491 qe->mid = queue->mid_gen;
5493 "Create QueueEntry with MID %" PRIu64
5494 " and QID %u and prefix %s\n",
5495 qe->mid,
5496 queue->qid,
5497 queue->tc->details.communicator.address_prefix);
5498 queue->mid_gen++;
5499 qe->queue = queue;
5500 if (NULL != pm)
5501 {
5502 qe->pm = pm;
5503 // TODO Why do we have a retransmission. When we know, make decision if we still want this.
5504 // GNUNET_assert (NULL == pm->qe);
5505 if (NULL != pm->qe)
5506 {
5508 "Retransmitting message <%" PRIu64
5509 "> remove pm from qe with MID: %llu \n",
5511 (unsigned long long) pm->qe->mid);
5512 pm->qe->pm = NULL;
5513 }
5514 pm->qe = qe;
5515 }
5516 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
5517 if (0 == queue->q_capacity)
5518 {
5519 // Messages without FC or fragments can get here.
5520 if (NULL != pm)
5521 {
5523 "Message %" PRIu64
5524 " (pm type %u) was not send because queue has no capacity.\n",
5526 pm->pmt);
5527 pm->qe = NULL;
5528 }
5529 GNUNET_free (env);
5530 GNUNET_free (qe);
5531 return;
5532 }
5533 GNUNET_CONTAINER_DLL_insert (queue->queue_head, queue->queue_tail, qe);
5534 queue->queue_length++;
5535 queue->tc->details.communicator.total_queue_length++;
5536 if (GNUNET_NO == queue->unlimited_length)
5537 queue->q_capacity--;
5539 "Queue %s with qid %u has capacity %" PRIu64 "\n",
5540 queue->address,
5541 queue->qid,
5542 queue->q_capacity);
5544 queue->tc->details.communicator.total_queue_length)
5545 queue->idle = GNUNET_NO;
5546 if (QUEUE_LENGTH_LIMIT == queue->queue_length)
5547 queue->idle = GNUNET_NO;
5548 if (0 == queue->q_capacity)
5549 queue->idle = GNUNET_NO;
5550
5551 if (GNUNET_NO == queue->idle)
5553 if (NULL != pm && NULL != (pa = pm->pa_head))
5554 {
5555 while (pm != pa->pm)
5556 pa = pa->next_pa;
5557 pa->num_send++;
5558 }
5559 // GNUNET_CONTAINER_multiuuidmap_get (pending_acks, &ack[i].ack_uuid.value);
5561 "Sending message MID %" PRIu64
5562 " of type %u (%u) and size %lu with MQ %p queue %s (QID %u) pending %"
5563 PRIu64 "\n",
5564 GNUNET_ntohll (smt->mid),
5565 ntohs (((const struct GNUNET_MessageHeader *) payload)->type),
5566 ntohs (smt->header.size),
5567 (unsigned long) payload_size,
5568 queue->tc->mq,
5569 queue->address,
5570 queue->qid,
5571 (NULL == pm) ? 0 : pm->logging_uuid);
5572 GNUNET_MQ_send (queue->tc->mq, env);
5573 }
5574}

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_pa, 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 5588 of file gnunet-service-transport.c.

5591{
5592 struct GNUNET_TIME_Absolute now;
5593 unsigned int candidates;
5594 unsigned int sel1;
5595 unsigned int sel2;
5596 struct GNUNET_TIME_Relative rtt;
5597
5598 /* Pick one or two 'random' queues from n (under constraints of options) */
5599 now = GNUNET_TIME_absolute_get ();
5600 /* FIXME-OPTIMIZE: give queues 'weights' and pick proportional to
5601 weight in the future; weight could be assigned by observed
5602 bandwidth (note: not sure if we should do this for this type
5603 of control traffic though). */
5604 candidates = 0;
5605 for (struct Queue *pos = n->queue_head; NULL != pos;
5606 pos = pos->next_neighbour)
5607 {
5608 if ((0 != (options & RMO_UNCONFIRMED_ALLOWED)) ||
5609 (pos->validated_until.abs_value_us > now.abs_value_us))
5610 candidates++;
5611 }
5612 if (0 == candidates)
5613 {
5614 /* This can happen rarely if the last confirmed queue timed
5615 out just as we were beginning to process this message. */
5617 "Could not route message of type %u to %s: no valid queue\n",
5618 ntohs (hdr->type),
5619 GNUNET_i2s (&n->pid));
5621 "# route selection failed (all no valid queue)",
5622 1,
5623 GNUNET_NO);
5625 }
5626
5628 sel1 = GNUNET_CRYPTO_random_u32 (candidates);
5629 if (0 == (options & RMO_REDUNDANT))
5630 sel2 = candidates; /* picks none! */
5631 else
5632 sel2 = GNUNET_CRYPTO_random_u32 (candidates);
5633 candidates = 0;
5634 for (struct Queue *pos = n->queue_head; NULL != pos;
5635 pos = pos->next_neighbour)
5636 {
5637 if ((0 != (options & RMO_UNCONFIRMED_ALLOWED)) ||
5638 (pos->validated_until.abs_value_us > now.abs_value_us))
5639 {
5640 if ((sel1 == candidates) || (sel2 == candidates))
5641 {
5643 "Routing message of type %u to %s using %s (#%u)\n",
5644 ntohs (hdr->type),
5645 GNUNET_i2s (&n->pid),
5646 pos->address,
5647 (sel1 == candidates) ? 1 : 2);
5648 rtt = GNUNET_TIME_relative_min (rtt, pos->pd.aged_rtt);
5649 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
5650 }
5651 candidates++;
5652 }
5653 }
5654 return rtt;
5655}

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

5696{
5697 const struct GNUNET_PeerIdentity *my_identity;
5698 struct TransportDVBoxMessage box_hdr;
5699 struct TransportDVBoxPayloadP *payload_hdr;
5700 uint16_t body_len_hbo = ntohs (hdr->size);
5701 unsigned char pt[sizeof(struct TransportDVBoxPayloadP) + body_len_hbo]
5703 unsigned char ct[sizeof(struct TransportDVBoxPayloadP) + body_len_hbo]
5705 struct GNUNET_TIME_Relative rtt;
5707
5708 payload_hdr = (struct TransportDVBoxPayloadP*) pt;
5711
5712 /* Encrypt payload */
5713 memset (&box_hdr, 0, sizeof (box_hdr));
5714 box_hdr.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
5715 box_hdr.total_hops = htons (0);
5716 box_hdr.without_fc = htonl (without_fc);
5717 // update_ephemeral (dv);
5718 if ((0 ==
5720 || (NULL == dv->km))
5721 {
5723 &dv->ephemeral_key,
5724 (struct GNUNET_ShortHashCode*) &km);
5725 GNUNET_free (dv->km); /* do not leak the previous key material */
5726 dv->km = GNUNET_new (struct GNUNET_ShortHashCode);
5727 GNUNET_memcpy (dv->km, &km, sizeof(struct GNUNET_ShortHashCode));
5728 if (GNUNET_OK != sign_ephemeral (dv))
5729 {
5730 /* Without a matching signature the box is undecryptable noise to the
5731 receiver; do not spend the bandwidth. Expire the ephemeral so the
5732 next attempt re-derives and re-signs rather than reusing it. */
5735 }
5736 }
5737 else
5738 {
5739 /* The ephemeral key is still valid, so reuse the cached key material.
5740 Without this @a km stayed UNINITIALISED stack memory and the
5741 receiver could not decrypt the box. */
5742 GNUNET_memcpy (&km, dv->km, sizeof(struct GNUNET_ShortHashCode));
5743 }
5744 box_hdr.ephemeral_key = dv->ephemeral_key;
5745 payload_hdr->sender_sig = dv->sender_sig;
5746 memcpy (&payload_hdr[1], hdr, body_len_hbo);
5747 GNUNET_CRYPTO_random_block (&box_hdr.iv,
5748 sizeof(box_hdr.iv));
5749 payload_hdr->sender = *my_identity;
5751 GNUNET_CRYPTO_aead_encrypt (sizeof pt,
5752 pt,
5753 0,
5754 NULL,
5755 &km,
5756 &box_hdr.iv,
5757 ct,
5758 &box_hdr.mac);
5760 /* For each selected path, take the pre-computed header and body
5761 and add the path in the middle of the message; then send it. */
5762 for (unsigned int i = 0; i < num_dvhs; i++)
5763 {
5764 struct DistanceVectorHop *dvh = dvhs[i];
5765 unsigned int num_hops = dvh->distance + 1;
5766 char buf[sizeof(struct TransportDVBoxMessage)
5767 + sizeof(struct GNUNET_PeerIdentity) * num_hops
5768 + sizeof(struct TransportDVBoxPayloadP)
5769 + body_len_hbo] GNUNET_ALIGN;
5770 struct GNUNET_PeerIdentity *dhops;
5771
5772 box_hdr.header.size = htons (sizeof(buf));
5773 box_hdr.orig_size = htons (sizeof(buf));
5774 box_hdr.num_hops = htons (num_hops);
5775 memcpy (buf, &box_hdr, sizeof(box_hdr));
5776 dhops = (struct GNUNET_PeerIdentity *) &buf[sizeof(box_hdr)];
5777 memcpy (dhops,
5778 dvh->path,
5779 dvh->distance * sizeof(struct GNUNET_PeerIdentity));
5780 dhops[dvh->distance] = dv->target;
5781 if (GNUNET_EXTRA_LOGGING > 0)
5782 {
5783 char *path;
5784
5786 for (unsigned int j = 0; j < num_hops; j++)
5787 {
5788 char *tmp;
5789
5790 GNUNET_asprintf (&tmp, "%s-%s", path, GNUNET_i2s (&dhops[j]));
5791 GNUNET_free (path);
5792 path = tmp;
5793 }
5795 "Routing message of type %u to %s using DV (#%u/%u) via %s\n",
5796 ntohs (hdr->type),
5797 GNUNET_i2s (&dv->target),
5798 i + 1,
5799 num_dvhs,
5800 path);
5801 GNUNET_free (path);
5802 }
5803 rtt = GNUNET_TIME_relative_min (rtt, dvh->pd.aged_rtt);
5804 memcpy (&dhops[num_hops], ct, sizeof(ct));
5805 use (use_cls,
5806 dvh->next_hop,
5807 (const struct GNUNET_MessageHeader *) buf,
5808 options);
5809 }
5810 return rtt;
5811}

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

5828{
5829 (void) cls;
5830 (void) route_via_neighbour (next_hop, hdr, RMO_UNCONFIRMED_ALLOWED);
5831}

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

5850{
5851 // struct VirtualLink *vl;
5852 struct Neighbour *n;
5853 struct DistanceVector *dv;
5854 struct GNUNET_TIME_Relative rtt1;
5855 struct GNUNET_TIME_Relative rtt2;
5856 const struct GNUNET_PeerIdentity *target = &vl->target;
5857
5859 "Trying to route message of type %u to %s without fc\n",
5860 ntohs (hdr->type),
5861 GNUNET_i2s (target));
5862
5863 // TODO Do this elsewhere. vl should be given as parameter to method.
5864 // vl = lookup_virtual_link (target);
5865 GNUNET_assert (NULL != vl && GNUNET_YES == vl->confirmed);
5866 if (NULL == vl)
5868 n = vl->n;
5869 dv = (0 != (options & RMO_DV_ALLOWED)) ? vl->dv : NULL;
5870 if (0 == (options & RMO_UNCONFIRMED_ALLOWED))
5871 {
5872 /* if confirmed is required, and we do not have anything
5873 confirmed, drop respective options */
5874 if (NULL == n)
5875 n = lookup_neighbour (target);
5876 if ((NULL == dv) && (0 != (options & RMO_DV_ALLOWED)))
5878 }
5879 if ((NULL == n) && (NULL == dv))
5880 {
5882 "Cannot route message of type %u to %s: no route\n",
5883 ntohs (hdr->type),
5884 GNUNET_i2s (target));
5886 "# Messages dropped in routing: no acceptable method",
5887 1,
5888 GNUNET_NO);
5890 }
5892 "Routing message of type %u to %s with options %X\n",
5893 ntohs (hdr->type),
5894 GNUNET_i2s (target),
5895 (unsigned int) options);
5896 /* If both dv and n are possible and we must choose:
5897 flip a coin for the choice between the two; for now 50/50 */
5898 if ((NULL != n) && (NULL != dv) && (0 == (options & RMO_REDUNDANT)))
5899 {
5900 if (0 == GNUNET_CRYPTO_random_u32 (2))
5901 n = NULL;
5902 else
5903 dv = NULL;
5904 }
5905 if ((NULL != n) && (NULL != dv))
5906 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
5907 enough for redundancy, so clear the flag. */
5910 if (NULL != n)
5911 {
5913 "Try to route message of type %u to %s without fc via neighbour\n",
5914 ntohs (hdr->type),
5915 GNUNET_i2s (target));
5916 rtt1 = route_via_neighbour (n, hdr, options);
5917 }
5918 if (NULL != dv)
5919 {
5920 struct DistanceVectorHop *hops[2];
5921 unsigned int res;
5922
5924 options,
5925 hops,
5926 (0 == (options & RMO_REDUNDANT)) ? 1 : 2);
5927 if (0 == res)
5928 {
5930 "Failed to route message, could not determine DV path\n");
5931 return rtt1;
5932 }
5934 "encapsulate_for_dv 1\n");
5935 rtt2 = encapsulate_for_dv (dv,
5936 res,
5937 hops,
5938 hdr,
5940 NULL,
5942 GNUNET_YES);
5943 }
5944 return GNUNET_TIME_relative_min (rtt1, rtt2);
5945}

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, RMO_UNCONFIRMED_ALLOWED, 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 6026 of file gnunet-service-transport.c.

6027{
6028 struct VirtualLink *vl = cls;
6029 struct GNUNET_TIME_Absolute monotime;
6030 struct TransportFlowControlMessage *fc;
6032 struct GNUNET_TIME_Relative rtt;
6033 struct GNUNET_TIME_Relative rtt_average;
6034 struct Neighbour *n = vl->n;
6035 size_t addresses_size;
6036
6037 if (GNUNET_YES != vl->confirmed)
6038 {
6039 /* We cannot route anything over an unconfirmed link, and
6040 #route_control_message_without_fc() asserts on exactly that. Links
6041 created from an inbound FLOW_CONTROL message start out unconfirmed,
6042 so a remote peer could otherwise abort us here.
6043
6044 Do NOT just return: #task_consider_sending_fc() cleared
6045 @e fc_retransmit_task before calling us, and the only other place that
6046 arms it is #handle_flow_control() -- which only does so when it is
6047 already non-NULL. Leaving without re-arming therefore ends the
6048 keepalive chain for this link permanently, and #check_link_down()
6049 tears it down #NEIGHBOUR_LIVENESS_TIMEOUT later. */
6051 "Not sending FC to %s: virtual link not confirmed\n",
6052 GNUNET_i2s (&vl->target));
6053 if (NULL == vl->fc_retransmit_task)
6057 vl);
6058 return;
6059 }
6060 addresses_size = 0;
6061 if (NULL != n && 0 < n->number_of_addresses)
6062 {
6063 addresses_size =
6064 n->number_of_addresses * sizeof (struct TransportGlobalNattedAddress) + n
6065 ->size_of_global_addresses;
6066 if (addresses_size >
6067 UINT16_MAX - sizeof (struct TransportFlowControlMessage))
6068 {
6069 /* htons() below would silently truncate `header.size', leaving a
6070 message whose declared length does not match its contents. */
6071 GNUNET_break (0);
6072 addresses_size = 0;
6073 }
6074 }
6075 if (0 != addresses_size)
6076 {
6077 char *tgnas = GNUNET_malloc (addresses_size);
6079 ctx.off = 0;
6080 ctx.size = addresses_size;
6081 ctx.tgnas = tgnas;
6082
6084 + addresses_size);
6085 fc->header.size = htons (sizeof(struct TransportFlowControlMessage)
6086 + addresses_size);
6087 fc->size_of_addresses = htonl ((uint32_t) n->size_of_global_addresses);
6088 fc->number_of_addresses = htonl (n->number_of_addresses);
6091 &ctx);
6094 }
6095 else
6096 {
6097 fc = GNUNET_malloc (sizeof (struct TransportFlowControlMessage));
6098 fc->header.size = htons (sizeof(struct TransportFlowControlMessage));
6099 }
6100
6102 /* OPTIMIZE-FC-BDP: decide sane criteria on when to do this, instead of doing
6103 it always! */
6104 /* For example, we should probably ONLY do this if a bit more than
6105 an RTT has passed, or if the window changed "significantly" since
6106 then. See vl->last_fc_rtt! NOTE: to do this properly, we also
6107 need an estimate for the bandwidth-delay-product for the entire
6108 VL, as that determines "significantly". We have the delay, but
6109 the bandwidth statistics need to be added for the VL!*/(void) duration;
6110
6111 if (NULL != vl->dv)
6112 rtt_average = calculate_rtt (vl->dv);
6113 else
6114 rtt_average = GNUNET_TIME_UNIT_FOREVER_REL;
6115 fc->rtt = GNUNET_TIME_relative_hton (rtt_average);
6117 "Sending FC seq %u to %s with new window %llu %lu %u\n",
6118 (unsigned int) vl->fc_seq_gen,
6119 GNUNET_i2s (&vl->target),
6120 (unsigned long long) vl->incoming_fc_window_size,
6121 (unsigned long) rtt_average.rel_value_us,
6122 vl->sync_ready);
6124 vl->last_fc_transmission = monotime;
6125 fc->sync_ready = htonl ((uint32_t) vl->sync_ready);
6127 fc->seq = htonl (vl->fc_seq_gen++);
6128 fc->inbound_window_size = GNUNET_htonll (vl->incoming_fc_window_size
6131 fc->outbound_sent = GNUNET_htonll (vl->outbound_fc_window_size_used);
6132 fc->outbound_window_size = GNUNET_htonll (vl->outbound_fc_window_size);
6133 fc->sender_time = GNUNET_TIME_absolute_hton (monotime);
6135 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == rtt.rel_value_us)
6136 {
6139 "FC retransmission to %s failed, will retry in %s\n",
6140 GNUNET_i2s (&vl->target),
6143 }
6144 else
6145 {
6146 /* OPTIMIZE-FC-BDP: rtt is not ideal, we can do better! */
6147 vl->last_fc_rtt = rtt;
6148 }
6149 if (NULL != vl->fc_retransmit_task)
6151 if (MAX_FC_RETRANSMIT_COUNT <= vl->fc_retransmit_count)
6152 {
6154 vl->fc_retransmit_count = 0;
6155 }
6156 /* Never re-arm with (near) zero delay: @a rtt is zero whenever we have no
6157 RTT sample yet, which turned this into a tight send loop. */
6159 vl->fc_retransmit_task =
6161 vl->fc_retransmit_count++;
6162 GNUNET_free (fc);
6163}

References add_global_addresses(), calculate_rtt(), VirtualLink::confirmed, ctx, duration, VirtualLink::dv, FC_KEEPALIVE_INTERVAL, VirtualLink::fc_retransmit_count, VirtualLink::fc_retransmit_task, VirtualLink::fc_seq_gen, GNUNET_break, 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_UNIT_FOREVER_REL, GNUNET_TIME_UNIT_MINUTES, 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, 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_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 5958 of file gnunet-service-transport.c.

5959{
5960 struct VirtualLink *vl = cls;
5961 vl->fc_retransmit_task = NULL;
5962 consider_sending_fc (cls);
5963}

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

14007{
14008 const char *dash;
14009 const char *colon;
14010
14011 if (NULL == address)
14012 return NULL;
14013 dash = strchr (address, '-');
14014 if (NULL == dash)
14015 return NULL;
14016 colon = strchr (dash, ':');
14017 if (NULL == colon)
14018 return NULL;
14019 return GNUNET_strndup (dash + 1,
14020 colon - (dash + 1));
14021}

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

5989{
5990 struct AddGlobalAddressesContext *ctx = cls;
5991 struct TransportGlobalNattedAddress *tgna = value;
5992 char *addr = (char *) &tgna[1];
5993 size_t alen = ntohl (tgna->address_length);
5994 size_t need = sizeof (struct TransportGlobalNattedAddress) + alen;
5995
5996 /* NOTE: the address is NOT 0-terminated, it must be printed with an
5997 explicit precision. */
5999 "sending address %.*s length %lu\n",
6000 (int) alen,
6001 addr,
6002 (unsigned long) alen);
6003 if (ctx->off + need > ctx->size)
6004 {
6005 GNUNET_break (0);
6006 return GNUNET_NO;
6007 }
6008 GNUNET_memcpy (&(ctx->tgnas[ctx->off]), tgna, need);
6009 ctx->off += need;
6010
6011 return GNUNET_OK;
6012}

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

11297{
11299 unsigned int n_hops = 0;
11300
11302 "calculate_rtt\n");
11303 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
11304 pos = pos->next_dv)
11305 {
11307 "calculate_rtt %lu\n",
11308 (unsigned long) pos->pd.aged_rtt.rel_value_us);
11309 n_hops++;
11311 aged_rtt, pos
11312 ->distance
11313 + 2), ret);
11314 }
11315
11316 if (0 == n_hops)
11318 return ret;
11319}

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

6184{
6185 struct Neighbour *n = vl->n;
6186 struct DistanceVector *dv = vl->dv;
6187 struct GNUNET_TIME_Absolute now;
6188 struct VirtualLink *vl_next_hop;
6189 int elig;
6190
6192 "check_vl_transmission to target %s\n",
6193 GNUNET_i2s (&vl->target));
6194 /* Check that we have an eligible pending message!
6195 (cheaper than having #transmit_on_queue() find out!) */
6196 elig = GNUNET_NO;
6197 for (struct PendingMessage *pm = vl->pending_msg_head; NULL != pm;
6198 pm = pm->next_vl)
6199 {
6201 "check_vl_transmission loop\n");
6202 if (NULL != pm->qe)
6203 continue; /* not eligible, is in a queue! */
6204 if (pm->bytes_msg + vl->outbound_fc_window_size_used >
6206 {
6208 "Stalled message %" PRIu64
6209 " transmission on VL %s due to flow control: %llu < %llu\n",
6210 pm->logging_uuid,
6211 GNUNET_i2s (&vl->target),
6212 (unsigned long long) vl->outbound_fc_window_size,
6213 (unsigned long long) (pm->bytes_msg
6216 return; /* We have a message, but flow control says "nope" */
6217 }
6219 "Target window on VL %s not stalled. Scheduling transmission on queue\n",
6220 GNUNET_i2s (&vl->target));
6221 /* Notify queues at direct neighbours that we are interested */
6222 now = GNUNET_TIME_absolute_get ();
6223 if (NULL != n)
6224 {
6225 for (struct Queue *queue = n->queue_head; NULL != queue;
6226 queue = queue->next_neighbour)
6227 {
6228 if ((GNUNET_YES == queue->idle) &&
6229 (queue->validated_until.abs_value_us > now.abs_value_us))
6230 {
6232 "Direct neighbour %s not stalled\n",
6233 GNUNET_i2s (&n->pid));
6235 queue,
6237 elig = GNUNET_YES;
6238 }
6239 else
6241 "Neighbour Queue QID: %u (%u) busy or invalid\n",
6242 queue->qid,
6243 queue->idle);
6244 }
6245 }
6246 /* Notify queues via DV that we are interested */
6247 if (NULL != dv)
6248 {
6249 /* Do DV with lower scheduler priority, which effectively means that
6250 IF a neighbour exists and is available, we prefer it. */
6251 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
6252 pos = pos->next_dv)
6253 {
6254 struct Neighbour *nh_iter = pos->next_hop;
6255
6256
6257 if (pos->path_valid_until.abs_value_us <= now.abs_value_us)
6258 continue; /* skip this one: path not validated */
6259 else
6260 {
6261 vl_next_hop = lookup_virtual_link (&nh_iter->pid);
6262 if (NULL == vl_next_hop)
6263 continue; /* no link to that next hop (anymore) */
6264 if (pm->bytes_msg + vl_next_hop->outbound_fc_window_size_used >
6265 vl_next_hop->outbound_fc_window_size)
6266 {
6268 "Stalled message %" PRIu64
6269 " transmission on next hop %s due to flow control: %llu < %llu\n",
6270 pm->logging_uuid,
6271 GNUNET_i2s (&vl_next_hop->target),
6272 (unsigned long
6273 long) vl_next_hop->outbound_fc_window_size,
6274 (unsigned long long) (pm->bytes_msg
6275 + vl_next_hop->
6276 outbound_fc_window_size_used));
6277 consider_sending_fc (vl_next_hop);
6278 continue; /* We have a message, but flow control says "nope" for the first hop of this path */
6279 }
6280 for (struct Queue *queue = nh_iter->queue_head; NULL != queue;
6281 queue = queue->next_neighbour)
6282 if ((GNUNET_YES == queue->idle) &&
6283 (queue->validated_until.abs_value_us > now.abs_value_us))
6284 {
6286 "Next hop neighbour %s not stalled\n",
6287 GNUNET_i2s (&nh_iter->pid));
6289 queue,
6291 elig = GNUNET_YES;
6292 }
6293 else
6295 "DV Queue QID: %u (%u) busy or invalid\n",
6296 queue->qid,
6297 queue->idle);
6298 }
6299 }
6300 }
6301 if (GNUNET_YES == elig)
6303 "Eligible message %" PRIu64 " of size %u to %s: %llu/%llu\n",
6304 pm->logging_uuid,
6305 pm->bytes_msg,
6306 GNUNET_i2s (&vl->target),
6307 (unsigned long long) vl->outbound_fc_window_size,
6308 (unsigned long long) (pm->bytes_msg
6310 break;
6311 }
6312}

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

6323{
6324 struct TransportClient *tc = cls;
6325 struct PendingMessage *pm;
6326 const struct GNUNET_MessageHeader *obmm;
6327 uint32_t bytes_msg;
6328 struct VirtualLink *vl;
6330
6331 GNUNET_assert (CT_CORE == tc->type);
6332 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
6333 bytes_msg = ntohs (obmm->size);
6334 pp = ntohl (obm->priority);
6335 vl = lookup_virtual_link (&obm->peer);
6336 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
6337 {
6339 "Don't have %s as a neighbour (anymore).\n",
6340 GNUNET_i2s (&obm->peer));
6341 /* Failure: don't have this peer as a neighbour (anymore).
6342 Might have gone down asynchronously, so this is NOT
6343 a protocol violation by CORE. Still count the event,
6344 as this should be rare. */
6345 /* Precisely because this is not a protocol violation we leave the
6346 client's `struct Neighbour' -- and its send window -- in place, so we
6347 owe it the SEND_OK for the message we are dropping here. Without it
6348 the window shrinks by one every time this happens and never grows
6349 back; after #SEND_WINDOW_SIZE such drops #mq_send_impl() parks every
6350 further message for this peer forever ("Flow control delays
6351 transmission to CORE until we see SEND_OK") and CORE goes mute
6352 towards a peer it still believes it is connected to -- while
6353 continuing to receive from it, so its own idle timeout is what
6354 eventually reports the peer down. */
6355 send_ok_to_client (tc, &obm->peer);
6358 "# messages dropped (neighbour unknown)",
6359 1,
6360 GNUNET_NO);
6361 return;
6362 }
6363
6364 pm = GNUNET_malloc (sizeof(struct PendingMessage) + bytes_msg);
6366 "1 created pm %p storing vl %p\n",
6367 pm,
6368 vl);
6370 pm->prefs = pp;
6371 pm->client = tc;
6372 pm->vl = vl;
6373 pm->bytes_msg = bytes_msg;
6374 memcpy (&pm[1], obmm, bytes_msg);
6376 "Sending message of type %u with %u bytes as <%" PRIu64
6377 "> to %s\n",
6378 ntohs (obmm->type),
6379 bytes_msg,
6380 pm->logging_uuid,
6381 GNUNET_i2s (&obm->peer));
6383 tc->details.core.pending_msg_head,
6384 tc->details.core.pending_msg_tail,
6385 pm);
6387 vl->pending_msg_head,
6388 vl->pending_msg_tail,
6389 pm);
6392}

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

6408{
6409 struct Neighbour *n;
6410 struct VirtualLink *vl;
6411 struct TransportClient *tc = cls;
6412 const struct GNUNET_MessageHeader *inbox =
6413 (const struct GNUNET_MessageHeader *) &cb[1];
6414 uint16_t isize = ntohs (inbox->size);
6415 const char *is = ((const char *) &cb[1]) + isize;
6416 size_t slen = strlen (is) + 1;
6417 char
6418 mbuf[slen + isize
6419 + sizeof(struct
6423
6424 /* 0-termination of 'is' was checked already in
6425 #check_communicator_backchannel() */
6427 "Preparing backchannel transmission to %s:%s of type %u and size %u\n",
6428 GNUNET_i2s (&cb->pid),
6429 is,
6430 ntohs (inbox->type),
6431 ntohs (inbox->size));
6432 /* encapsulate and encrypt message */
6433 be->header.type =
6435 be->header.size = htons (sizeof(mbuf));
6436 memcpy (&be[1], inbox, isize);
6437 memcpy (&mbuf[sizeof(struct TransportBackchannelEncapsulationMessage)
6438 + isize],
6439 is,
6440 strlen (is) + 1);
6441 // route_control_message_without_fc (&cb->pid, &be->header, RMO_DV_ALLOWED);
6442 vl = lookup_virtual_link (&cb->pid);
6443 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
6444 {
6446 }
6447 else
6448 {
6449 /* Use route via neighbour */
6450 n = lookup_neighbour (&cb->pid);
6451 if (NULL != n)
6453 n,
6454 &be->header,
6455 RMO_NONE);
6456 }
6458}

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

6471{
6472 struct TransportClient *tc = cls;
6473
6474 if (CT_COMMUNICATOR != tc->type)
6475 {
6476 GNUNET_break (0);
6477 return GNUNET_SYSERR;
6478 }
6480 return GNUNET_OK;
6481}

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

6799{
6800 struct AddressListEntry *ale = cls;
6801 const char *dash;
6802 char *address_uri;
6803 char *prefix;
6804 unsigned int add_success;
6805
6806 if ((GNUNET_YES == in_shutdown) || (NULL == pils))
6807 {
6808 ale->st = NULL;
6809 return;
6810 }
6811 if (NULL == GNUNET_PILS_get_identity (pils))
6812 {
6813 /* Do NOT poll at 1kHz: that burns CPU and keeps the scheduler task
6814 list non-empty, which prevents the service from ever exiting. */
6817 &store_pi,
6818 ale);
6819 return;
6820 }
6823 dash = strchr (ale->address, '-');
6824 GNUNET_assert (NULL != dash);
6825 dash++;
6826 GNUNET_asprintf (&address_uri,
6827 "%s://%s",
6828 prefix,
6829 dash);
6831 ale->st = NULL;
6833 "Storing our address `%s' in peerstore until %s!\n",
6834 ale->address,
6837 address_uri);
6838 /* NOTE: #GNUNET_HELLO_builder_add_address() answers GNUNET_NO for an
6839 address that is already in the builder, and on every call after the
6840 first one for a given address that is exactly what happens: nothing
6841 ever removes an address from @a GST_my_hello except
6842 #handle_del_address(). This function is the *refresh* cycle --
6843 #peerstore_store_own_cb() re-arms it at a quarter of the address'
6844 expiration -- so bailing out on GNUNET_NO here stopped the refresh
6845 after precisely one round. Our own HELLO then expired
6846 (#GNUNET_HELLO_ADDRESS_EXPIRATION, twelve hours) and was never
6847 renewed: peers can no longer learn how to reach us, and a link that
6848 drops after that never comes back. Only GNUNET_SYSERR -- a malformed
6849 URI, which retrying cannot fix -- is a reason not to store. */
6850 if (GNUNET_SYSERR == add_success)
6851 {
6853 "Not storing our address `%s': not a valid HELLO URI\n",
6854 address_uri);
6855 GNUNET_free (address_uri);
6856 return;
6857 }
6858 GNUNET_log ((GNUNET_NO == add_success) ?
6860 "%s our address `%s' in PEERSTORE\n",
6861 (GNUNET_NO == add_success) ? "Refreshing" : "Storing",
6862 address_uri);
6863 // FIXME hello_mono_time used here?? What about expiration in ale?
6864 pils_sign_address (ale,
6866 // TODO keep track of op and potentially cancel/clean
6867 GNUNET_free (address_uri);
6868}

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

6559{
6560 struct PilsAddressSignContext *pc = cls;
6561
6562 GNUNET_assert (NULL == pc->req);
6563 /* The store completed; the handle is dead and must not be cancelled
6564 later by #free_address_list_entry(). */
6565 pc->ale->shc = NULL;
6566 pc->ale->pc = NULL;
6567 if (GNUNET_OK != success)
6568 {
6570 "Failed to store our address `%s' with peerstore\n",
6571 pc->ale->address);
6572 if (NULL == pc->ale->st)
6573 {
6575 &store_pi,
6576 pc->ale);
6577 }
6578 }
6579 GNUNET_free (pc);
6580}

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

6590{
6591 struct PilsAddressSignContext *pc = cls;
6592 struct GNUNET_MQ_Envelope *env;
6593 const struct GNUNET_MessageHeader *msg;
6594
6595 pc->req->op = NULL;
6598 pc->req);
6599 GNUNET_free (pc->req);
6600 pc->req = NULL;
6603 pid,
6604 sig,
6605 pc->et);
6608 "store_pi 1\n");
6610 msg,
6611 shc_cont,
6612 pc);
6613 GNUNET_free (env);
6614}

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

6625{
6626 struct PilsAddressSignContext *pc = cls;
6627
6628 pc->ale->sc = NULL;
6629 if (GNUNET_YES != success)
6631 "Failed to store our own address `%s' in peerstore!\n",
6632 pc->ale->address);
6633 else
6635 "Successfully stored our own address `%s' in peerstore!\n",
6636 pc->ale->address);
6637 /* refresh period is 1/4 of expiration time, that should be plenty
6638 without being excessive. */
6639 if (NULL == pc->ale->st)
6640 {
6641 pc->ale->st =
6643 GNUNET_TIME_relative_divide (pc->ale->expiration,
6644 4ULL),
6645 &store_pi,
6646 pc->ale);
6647 }
6648
6649 /* Now we have to update our HELLO! */
6651 pc->req = GNUNET_new (struct PilsRequest);
6654 pc->req);
6655 pc->req->op = GNUNET_PILS_sign_hello (pils,
6657 pc->et,
6659 pc);
6660}

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_to_absolute(), GNUNET_YES, GST_my_hello, 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 6671 of file gnunet-service-transport.c.

6674{
6675 char *sig_str;
6676 void *result;
6677 size_t result_size;
6678
6679 sig_str = NULL;
6680 (void) GNUNET_STRINGS_base64_encode (sig, sizeof(*sig), &sig_str);
6681 result_size =
6682 1 + GNUNET_asprintf (
6683 (char **) &result,
6684 "%s;%llu;%u;%s",
6685 sig_str,
6686 (unsigned long long) pc->et.abs_value_us,
6687 (unsigned int) pc->ale->nt,
6688 pc->ale->address);
6689 GNUNET_free (sig_str);
6690
6692 "Build our HELLO URI `%s'\n",
6693 (char*) result);
6694
6695 GNUNET_free (pc->ale->signed_address);
6696 pc->ale->signed_address = result;
6697 pc->ale->signed_address_len = result_size;
6699
6700 expiration = GNUNET_TIME_relative_to_absolute (pc->ale->expiration);
6702 "transport",
6703 pid,
6705 result,
6706 result_size,
6707 expiration,
6710 pc);
6711}

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

6753{
6754 struct SignedAddress sa;
6755 struct PilsAddressSignContext *pc;
6757 const struct GNUNET_PeerIdentity *my_identity;
6758
6759 sa.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_ADDRESS);
6760 sa.purpose.size = htonl (sizeof(sa));
6761 sa.mono_time = GNUNET_TIME_absolute_hton (mono_time);
6762 GNUNET_CRYPTO_hash (ale->address, strlen (ale->address), &sa.addr_hash);
6763 /* Only ever one chain per entry: the previous one (if any) still holds a
6764 pointer to @a ale and must be torn down first. */
6767 if ((NULL == my_identity) ||
6768 (GNUNET_OK != sign_by_my_identity (&sa.purpose, &sig)))
6769 {
6770 /* Nothing else re-arms @e st: #store_pi() cleared it before calling us,
6771 and the only other thing that sets it is #peerstore_store_own_cb(),
6772 which is on the far side of the store we just failed to start. So a
6773 single failure to sign used to end the refresh cycle for this address
6774 for the rest of the process' life. */
6775 if (NULL == ale->st)
6776 {
6779 &store_pi,
6780 ale);
6781 }
6782 return;
6783 }
6785 pc->ale = ale;
6786 pc->et = mono_time;
6787 ale->pc = pc;
6789}

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

6878{
6879 struct AddressListEntry *ale;
6880 char *address_without_port;
6881
6882 ale = GNUNET_malloc (sizeof(struct AddressListEntry) + slen);
6883 ale->tc = tc;
6884 ale->address = (const char *) &ale[1];
6885 ale->expiration = expiration;
6886 ale->aid = aid;
6887 ale->nt = nt;
6888 memcpy (&ale[1], address, slen);
6889 address_without_port = get_address_without_port (ale->address);
6891 "Is this %s a local address (%s)\n",
6892 (NULL == address_without_port) ? "<unparsable>"
6893 : address_without_port,
6894 ale->address);
6895 if ((NULL == address_without_port) ||
6896 (0 != strcmp ("127.0.0.1", address_without_port)))
6897 {
6898 if (NULL != ale->st)
6899 {
6901 }
6902 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
6903 }
6904 GNUNET_free (address_without_port);
6905
6906 return ale;
6907}

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

6912{
6913
6915 "Feeding addresses to PILS\n");
6916 pils_feed_task = NULL;
6917
6919 GST_my_hello);
6920}

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

6932{
6933 struct TransportClient *tc = cls;
6934 struct AddressListEntry *ale;
6935 size_t slen;
6936 char *address;
6937
6938 /* 0-termination of &aam[1] was checked in #check_add_address */
6940 "Communicator added address `%s'!\n",
6941 (const char *) &aam[1]);
6942 slen = ntohs (aam->header.size) - sizeof(*aam);
6943 address = GNUNET_malloc (slen);
6944 memcpy (address, &aam[1], slen);
6945 ale = create_address_entry (tc,
6947 ntohl (aam->nt),
6948 address,
6949 aam->aid,
6950 slen);
6951 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
6952 tc->details.communicator.addr_tail,
6953 ale);
6954 {
6955 for (struct AddressListEntry *iter = tc->details.communicator.addr_head;
6956 NULL != iter;
6957 iter = iter->next)
6958 {
6959 char *address_uri;
6960 const char *dash = strchr (iter->address, '-');
6961 char *prefix = GNUNET_HELLO_address_to_prefix (iter->address);
6962 GNUNET_assert (NULL != dash);
6963 dash++;
6964 GNUNET_asprintf (&address_uri,
6965 "%s://%s",
6966 prefix,
6967 dash);
6970 GNUNET_free (address_uri);
6971 }
6972 if (NULL != pils_feed_task)
6976 NULL);
6977 }
6980}

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

6992{
6993 struct TransportClient *tc = cls;
6994 struct AddressListEntry *alen;
6995
6996 if (CT_COMMUNICATOR != tc->type)
6997 {
6998 GNUNET_break (0);
7000 return;
7001 }
7002 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
7003 NULL != ale;
7004 ale = alen)
7005 {
7006 alen = ale->next;
7007 if (dam->aid != ale->aid)
7008 continue;
7009 GNUNET_assert (ale->tc == tc);
7011 "Communicator deleted address `%s'!\n",
7012 ale->address);
7014 ale->address);
7015 if (NULL != pils_feed_task)
7019 NULL);
7022 return;
7023 }
7025 "Communicator removed address we did not even have.\n");
7027 // GNUNET_SERVICE_client_drop (tc->client);
7028}

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

11850{
11852 { GNUNET_MQ_hd_var_size (fragment_box,
11855 cmc),
11856 GNUNET_MQ_hd_var_size (reliability_box,
11859 cmc),
11860 GNUNET_MQ_hd_var_size (reliability_ack,
11863 cmc),
11864 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
11867 cmc),
11868 GNUNET_MQ_hd_var_size (dv_learn,
11871 cmc),
11872 GNUNET_MQ_hd_var_size (dv_box,
11874 struct TransportDVBoxMessage,
11875 cmc),
11876 GNUNET_MQ_hd_var_size (flow_control,
11879 cmc),
11881 validation_challenge,
11884 cmc),
11886 validation_response,
11889 cmc),
11891 int ret;
11892 const struct GNUNET_MessageHeader *msg = cmc->mh;
11893
11895 "Handling message of type %u with %u bytes\n",
11896 (unsigned int) ntohs (msg->type),
11897 (unsigned int) ntohs (msg->size));
11898 /* @a handlers only covers the encapsulations *we* add; anything else is a
11899 payload for CORE and leaves through #handle_raw_message() below. So
11900 #GNUNET_NO is the common case here -- one per delivered CORE message --
11901 and not something to log about, which is why this is the "try" variant. */
11903 if (GNUNET_SYSERR == ret)
11904 {
11905 /* @a msg is the message a *remote peer* sent us: #handle_incoming_msg()
11906 points @e mh into the payload of the
11907 #GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG the communicator
11908 delivered, and every other caller unwraps it from remote traffic as
11909 well. So failing a check here is that peer's protocol violation, and
11910 it says nothing at all about the communicator that carried it.
11911
11912 Dropping the client therefore punishes the wrong party, and it
11913 punishes it hard: #GNUNET_SERVICE_client_drop() disconnects the
11914 communicator *process*, which takes down every queue it owns and thus
11915 every neighbour reachable through it. One malformed DV box on a
11916 shared UDP communicator disconnects every peer we have on it, CORE
11917 tears the sessions down, and the key exchanges that would rebuild
11918 them have to wait for the communicator to come back and revalidate.
11919 Since the offending bytes arrive from the network, any peer can do
11920 this to us at will, repeatedly.
11921
11922 Drop the message and keep the communicator: resume it exactly as the
11923 success path does, so it still gets its flow-control ACK and its
11924 GNUNET_SERVICE_client_continue(). */
11925 GNUNET_break_op (0);
11927 "# malformed messages discarded",
11928 1,
11929 GNUNET_NO);
11931 return;
11932 }
11933 if (GNUNET_NO == ret)
11934 {
11935 /* unencapsulated 'raw' message */
11936 handle_raw_message (cmc, msg);
11937 }
11938}

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

7051{
7052 struct CoreSentContext *ctx = cls;
7053 struct VirtualLink *vl = ctx->vl;
7054
7055 if (NULL == vl)
7056 {
7057 /* lost the link in the meantime, ignore */
7058 GNUNET_free (ctx);
7059 return;
7060 }
7063 vl->incoming_fc_window_size_ram -= ctx->size;
7064 vl->incoming_fc_window_size_used += ctx->isize;
7066 GNUNET_free (ctx);
7067}

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

7093{
7094 struct VirtualLink *vl = cls;
7095 struct CommunicatorMessageContext *cmc;
7096
7097 vl->core_fc_stall_task = NULL;
7099 "CORE did not acknowledge messages from %s within %s; "
7100 "releasing the flow control credit anyway\n",
7101 GNUNET_i2s (&vl->target),
7103 GNUNET_YES));
7105 "# CORE flow control stalls",
7106 1,
7107 GNUNET_NO);
7108 while (NULL != (cmc = vl->cmc_tail))
7109 release_stalled_cmc (vl, cmc);
7112}

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

7120{
7121 uint16_t size = ntohs (mh->size);
7122 int have_core;
7123
7124 if (vl->incoming_fc_window_size_ram > UINT_MAX - size)
7125 {
7127 "# CORE messages dropped (FC arithmetic overflow)",
7128 1,
7129 GNUNET_NO);
7131 "CORE messages of type %u with %u bytes dropped (FC arithmetic overflow)\n",
7132 (unsigned int) ntohs (mh->type),
7133 (unsigned int) ntohs (mh->size));
7134 if (GNUNET_YES == free_cmc)
7136 return;
7137 }
7139 {
7141 "# CORE messages dropped (FC window overflow)",
7142 1,
7143 GNUNET_NO);
7145 "CORE messages of type %u with %u bytes dropped (FC window overflow)\n",
7146 (unsigned int) ntohs (mh->type),
7147 (unsigned int) ntohs (mh->size));
7148 if (GNUNET_YES == free_cmc)
7150 return;
7151 }
7152
7153 /* Forward to all CORE clients */
7154 have_core = GNUNET_NO;
7155 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
7156 {
7157 struct GNUNET_MQ_Envelope *env;
7158 struct InboundMessage *im;
7159 struct CoreSentContext *ctx;
7160
7161 if (CT_CORE != tc->type)
7162 continue;
7165 ctx = GNUNET_new (struct CoreSentContext);
7166 ctx->vl = vl;
7167 ctx->size = size;
7168 ctx->isize = (GNUNET_NO == have_core) ? size : 0;
7169 have_core = GNUNET_YES;
7172 im->peer = cmc->im.sender;
7173 memcpy (&im[1], mh, size);
7174 GNUNET_MQ_send (tc->mq, env);
7176 }
7177 if (GNUNET_NO == have_core)
7178 {
7180 "Dropped message to CORE: no CORE client connected!\n");
7181 /* Nevertheless, count window as used, as it is from the
7182 perspective of the other peer! */
7184 /* TODO-M1 */
7186 "Dropped message of type %u with %u bytes to CORE: no CORE client connected!\n",
7187 (unsigned int) ntohs (mh->type),
7188 (unsigned int) ntohs (mh->size));
7189 if (GNUNET_YES == free_cmc)
7191 return;
7192 }
7194 "Delivered message from %s of type %u to CORE recv window %d\n",
7195 GNUNET_i2s (&cmc->im.sender),
7196 ntohs (mh->type),
7198 if (vl->core_recv_window > 0)
7199 {
7200 if (GNUNET_YES == free_cmc)
7202 return;
7203 }
7204 /* CORE ran out of receive window for *this* link. Withhold the
7205 per-message ACK -- that is what expresses the backpressure -- but
7206 resume the client immediately. The client is the communicator
7207 *process*, which carries every peer we reach through it, and a
7208 communicator we stop reading from does not stop receiving: it starts
7209 discarding, see "transport is too slow" in
7210 #GNUNET_TRANSPORT_communicator_receive(). Discarding is precisely
7211 what we cannot afford here, because among the messages dropped are
7212 the ones CORE needs in order to reopen the window it is waiting on. */
7213 if (GNUNET_YES == free_cmc)
7214 {
7215 resume_cmc_client (cmc);
7217 vl->cmc_count++;
7218 /* Nothing stalls the producer any more, so bound the list ourselves. */
7219 while (MAX_STALLED_CMCS < vl->cmc_count)
7221 /* ... and do not withhold the ACKs forever: see #core_fc_stalled(). */
7222 if (NULL == vl->core_fc_stall_task)
7226 vl);
7227 }
7228}

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

7241{
7242 struct CommunicatorMessageContext *cmc = cls;
7243 // struct CommunicatorMessageContext *cmc_copy =
7244 // GNUNET_new (struct CommunicatorMessageContext);
7245 struct GNUNET_MessageHeader *mh_copy;
7246 struct RingBufferEntry *rbe;
7247 struct VirtualLink *vl;
7248 uint16_t size = ntohs (mh->size);
7249
7251 "Handling raw message of type %u with %u bytes\n",
7252 (unsigned int) ntohs (mh->type),
7253 (unsigned int) ntohs (mh->size));
7254
7255 if ((size > UINT16_MAX - sizeof(struct InboundMessage)) ||
7256 (size < sizeof(struct GNUNET_MessageHeader)))
7257 {
7258 /* @a mh was unwrapped from what a *remote peer* sent us, so a bad size
7259 is that peer's protocol violation and says nothing about the
7260 communicator that carried it. Dropping the client here disconnects
7261 the communicator process and with it every neighbour reachable
7262 through it -- see the rationale in #demultiplex_with_cmc(). */
7263 GNUNET_break_op (0);
7265 "# CORE messages dropped (bad size)",
7266 1,
7267 GNUNET_NO);
7268 finish_cmc_handling (cmc);
7269 return;
7270 }
7271 vl = lookup_virtual_link (&cmc->im.sender);
7272 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
7273 {
7274 /* FIXME: sender is giving us messages for CORE but we don't have
7275 the link up yet! I *suspect* this can happen right now (i.e.
7276 sender has verified us, but we didn't verify sender), but if
7277 we pass this on, CORE would be confused (link down, messages
7278 arrive). We should investigate more if this happens often,
7279 or in a persistent manner, and possibly do "something" about
7280 it. Thus logging as error for now. */
7281
7282 mh_copy = GNUNET_malloc (size);
7283 rbe = GNUNET_new (struct RingBufferEntry);
7284 rbe->cmc = cmc;
7285 /*cmc_copy->tc = cmc->tc;
7286 cmc_copy->im = cmc->im;*/
7287 GNUNET_memcpy (mh_copy, mh, size);
7288
7289 rbe->mh = mh_copy;
7290
7292 {
7293 struct RingBufferEntry *rbe_old = ring_buffer[ring_buffer_head];
7294 GNUNET_free (rbe_old->cmc);
7295 GNUNET_free (rbe_old->mh);
7296 GNUNET_free (rbe_old);
7297 }
7298 ring_buffer[ring_buffer_head] = rbe;// cmc_copy;
7299 // cmc_copy->mh = (const struct GNUNET_MessageHeader *) mh_copy;
7300 cmc->mh = (const struct GNUNET_MessageHeader *) mh_copy;
7302 "Storing message for %s and type %u (%u) in ring buffer head %u is full %u\n",
7303 GNUNET_i2s (&cmc->im.sender),
7304 (unsigned int) ntohs (mh->type),
7305 (unsigned int) ntohs (mh_copy->type),
7309 {
7310 ring_buffer_head = 0;
7312 }
7313 else
7315
7317 "%u items stored in ring buffer\n",
7320
7321 /*GNUNET_break_op (0);
7322 GNUNET_STATISTICS_update (GST_stats,
7323 "# CORE messages dropped (virtual link still down)",
7324 1,
7325 GNUNET_NO);
7326
7327 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7328 "CORE messages of type %u with %u bytes dropped (virtual link still down)\n",
7329 (unsigned int) ntohs (mh->type),
7330 (unsigned int) ntohs (mh->size));
7331 finish_cmc_handling (cmc);*/
7332 /* @a cmc lives on in the ring buffer; #send_cmc_ack() and
7333 #resume_cmc_client() have recorded that they ran, so replaying it
7334 from #send_msg_from_cache() cannot ACK or continue a second time. */
7336 return;
7337 }
7339}

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

7351{
7352 uint16_t size = ntohs (fb->header.size);
7353 uint16_t bsize = size - sizeof(*fb);
7354
7355 (void) cls;
7356 if (0 == bsize)
7357 {
7358 GNUNET_break_op (0);
7359 return GNUNET_SYSERR;
7360 }
7361 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
7362 {
7363 GNUNET_break_op (0);
7364 return GNUNET_SYSERR;
7365 }
7366 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
7367 {
7368 GNUNET_break_op (0);
7369 return GNUNET_SYSERR;
7370 }
7371 return GNUNET_YES;
7372}

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

7382{
7383 struct AcknowledgementCummulator *ac = cls;
7384
7385 ac->task = NULL;
7386 GNUNET_assert (0 == ac->num_acks);
7388 GNUNET_YES ==
7390 GNUNET_free (ac);
7391}

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

7401{
7402 struct Neighbour *n;
7403 struct VirtualLink *vl;
7404 struct AcknowledgementCummulator *ac = cls;
7405 char buf[sizeof(struct TransportReliabilityAckMessage)
7406 + ac->num_acks
7408 struct TransportReliabilityAckMessage *ack =
7409 (struct TransportReliabilityAckMessage *) buf;
7411
7412 ac->task = NULL;
7414 "Sending ACK with %u components to %s\n",
7415 ac->num_acks,
7416 GNUNET_i2s (&ac->target));
7417 GNUNET_assert (0 < ac->num_acks);
7419 ack->header.size =
7420 htons (sizeof(*ack)
7421 + ac->num_acks * sizeof(struct TransportCummulativeAckPayloadP));
7422 ack->ack_counter = htonl (ac->ack_counter += ac->num_acks);
7423 ap = (struct TransportCummulativeAckPayloadP *) &ack[1];
7424 for (unsigned int i = 0; i < ac->num_acks; i++)
7425 {
7426 ap[i].ack_uuid = ac->ack_uuids[i].ack_uuid;
7429 }
7430 /*route_control_message_without_fc (
7431 &ac->target,
7432 &ack->header,
7433 RMO_DV_ALLOWED);*/
7434 vl = lookup_virtual_link (&ac->target);
7435 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
7436 {
7438 vl,
7439 &ack->header,
7441 }
7442 else
7443 {
7444 /* Use route via neighbour */
7445 n = lookup_neighbour (&ac->target);
7446 if (NULL != n)
7448 n,
7449 &ack->header,
7450 RMO_NONE);
7451 }
7452 ac->num_acks = 0;
7455 ac);
7456}

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_YES, TransportReliabilityAckMessage::header, lookup_neighbour(), lookup_virtual_link(), 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 7468 of file gnunet-service-transport.c.

7471{
7472 struct AcknowledgementCummulator *ac;
7473
7475 "Scheduling ACK %s for transmission to %s\n",
7476 GNUNET_uuid2s (&ack_uuid->value),
7477 GNUNET_i2s (pid));
7479 if (NULL == ac)
7480 {
7482 ac->target = *pid;
7483 ac->min_transmission_time = max_delay;
7487 &ac->target,
7488 ac,
7490 }
7491 else
7492 {
7493 if (MAX_CUMMULATIVE_ACKS == ac->num_acks)
7494 {
7495 /* Must run immediately, ack buffer full. Cancel the pending task
7496 FIRST: #transmit_cummulative_ack_cb() clears @e task without
7497 cancelling it, which would leave the old task armed with its
7498 handle lost. */
7500 ac->task = NULL;
7502 }
7506 }
7509 ac->ack_uuids[ac->num_acks].ack_uuid = *ack_uuid;
7510 ac->num_acks++;
7513 ac);
7514}

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

7545{
7546 struct FindByMessageUuidContext *fc = cls;
7547 struct ReassemblyContext *rc = value;
7548
7549 (void) key;
7550 if (0 == GNUNET_memcmp (&fc->message_uuid, &rc->msg_uuid))
7551 {
7552 fc->rc = rc;
7553 return GNUNET_NO;
7554 }
7555 return GNUNET_YES;
7556}

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

7568{
7569 struct CommunicatorMessageContext *cmc = cls;
7570 struct VirtualLink *vl;
7571 struct ReassemblyContext *rc;
7572 const struct GNUNET_MessageHeader *msg;
7573 uint16_t msize;
7574 uint16_t fsize;
7575 uint16_t frag_off;
7576 char *target;
7577 struct GNUNET_TIME_Relative cdelay;
7578 struct FindByMessageUuidContext fc;
7579
7580 vl = lookup_virtual_link (&cmc->im.sender);
7581 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
7582 {
7583 /* Entirely normal: fragments of a message that was already in flight
7584 keep arriving for a while after a link goes down, and a peer that has
7585 validated us may start sending before we have validated it. This used
7586 to call #GNUNET_SERVICE_client_drop(), which disconnects the
7587 communicator *process* -- every queue it owns, hence every neighbour
7588 reachable through it, hence every CORE session. On a peer with many
7589 neighbours a single ill-timed fragment therefore dropped all
7590 connections at once, and since the fragment comes from the network,
7591 any peer could cause it at will. Drop the fragment, keep the
7592 communicator; see #demultiplex_with_cmc() for the same reasoning. */
7594 "No virtual link for %s to handle fragment\n",
7595 GNUNET_i2s (&cmc->im.sender));
7597 "# fragments dropped (virtual link down)",
7598 1,
7599 GNUNET_NO);
7600 finish_cmc_handling (cmc);
7601 return;
7602 }
7603 if (NULL == vl->reassembly_map)
7604 {
7606 vl->reassembly_heap =
7611 vl);
7612 }
7613 msize = ntohs (fb->msg_size);
7614 fc.message_uuid = fb->msg_uuid;
7615 fc.rc = NULL;
7617 fb->msg_uuid.uuid,
7619 &fc);
7620 fsize = ntohs (fb->header.size) - sizeof(*fb);
7621 if (NULL == (rc = fc.rc))
7622 {
7623 /* Bound the RAM a single sender can pin here: @e msg_size is chosen by
7624 the peer, not by us. */
7627 {
7628 struct ReassemblyContext *drop;
7629
7631 GNUNET_assert (NULL != drop);
7633 "# Reassembly contexts dropped (limit reached)",
7634 1,
7635 GNUNET_NO);
7637 }
7638 rc = GNUNET_malloc (sizeof(*rc) + msize /* reassembly payload buffer */
7639 + (msize + 7) / 8 * sizeof(uint8_t) /* bitfield */);
7640 rc->msg_uuid = fb->msg_uuid;
7641 rc->virtual_link = vl;
7642 rc->msg_size = msize;
7643 rc->reassembly_timeout =
7647 rc,
7651 vl->reassembly_map,
7652 rc->msg_uuid.uuid,
7653 rc,
7655 target = (char *) &rc[1];
7656 rc->bitfield = (uint8_t *) (target + rc->msg_size);
7657 /* The bitfield loop below decrements @e msg_missing once per newly
7658 received byte, so this must always start at the full message size:
7659 initialising it to 0 for a single-fragment message made it
7660 underflow, and the message was then never delivered. */
7661 rc->msg_missing = rc->msg_size;
7663 "Received fragment with size %u at offset %u/%u %u bytes missing from %s for NEW message %"
7664 PRIu64 "\n",
7665 fsize,
7666 ntohs (fb->frag_off),
7667 msize,
7668 rc->msg_missing,
7669 GNUNET_i2s (&cmc->im.sender),
7670 fb->msg_uuid.uuid);
7671 }
7672 else
7673 {
7674 target = (char *) &rc[1];
7676 "Received fragment at offset %u/%u from %s for message %u\n",
7677 ntohs (fb->frag_off),
7678 msize,
7679 GNUNET_i2s (&cmc->im.sender),
7680 (unsigned int) fb->msg_uuid.uuid);
7681 }
7682 if (msize != rc->msg_size)
7683 {
7684 GNUNET_break (0);
7685 finish_cmc_handling (cmc);
7686 return;
7687 }
7688
7689 /* reassemble */
7690 if (0 == fsize)
7691 {
7692 GNUNET_break (0);
7693 finish_cmc_handling (cmc);
7694 return;
7695 }
7696 frag_off = ntohs (fb->frag_off);
7697 if (frag_off + fsize > msize)
7698 {
7699 /* Fragment (plus fragment size) exceeds message size! */
7700 GNUNET_break_op (0);
7701 finish_cmc_handling (cmc);
7702 return;
7703 }
7704 memcpy (&target[frag_off], &fb[1], fsize);
7705 /* update bitfield and msg_missing */
7706 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
7707 {
7708 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
7709 {
7710 rc->bitfield[i / 8] |= (1 << (i % 8));
7711 rc->msg_missing--;
7712 }
7713 }
7714
7715 /* Compute cumulative ACK */
7717 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->msg_missing / fsize);
7718 if (0 == rc->msg_missing)
7719 cdelay = GNUNET_TIME_UNIT_ZERO;
7720 cummulative_ack (&cmc->im.sender,
7721 &fb->ack_uuid,
7724 /* is reassembly complete? */
7725 if (0 != rc->msg_missing)
7726 {
7727 finish_cmc_handling (cmc);
7728 return;
7729 }
7730 /* reassembly is complete, verify result */
7731 msg = (const struct GNUNET_MessageHeader *) &rc[1];
7732 if (ntohs (msg->size) != rc->msg_size)
7733 {
7734 GNUNET_break (0);
7736 finish_cmc_handling (cmc);
7737 return;
7738 }
7739 /* successful reassembly */
7741 "Fragment reassembly complete for message %u\n",
7742 (unsigned int) fb->msg_uuid.uuid);
7743 /* FIXME: check that the resulting msg is NOT a
7744 DV Box or Reliability Box, as that is NOT allowed! */
7745 {
7746 uint16_t rsize = rc->msg_size;
7747 char rbuf[rsize] GNUNET_ALIGN;
7748
7749 /* Copy the reassembled message out and release `rc' BEFORE
7750 demultiplexing: the inner message may tear down the virtual link,
7751 which frees every reassembly context of that link -- the old code
7752 then used and freed `rc' a second time afterwards. */
7753 memcpy (rbuf, msg, rsize);
7755 cmc->mh = (const struct GNUNET_MessageHeader *) rbuf;
7757 }
7758}

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

7771{
7772 const struct GNUNET_MessageHeader *box = (const struct
7773 GNUNET_MessageHeader *) &rb[1];
7774 (void) cls;
7775
7777 "check_send_msg with size %u: inner msg type %u and size %u (%lu %lu)\n",
7778 ntohs (rb->header.size),
7779 ntohs (box->type),
7780 ntohs (box->size),
7781 sizeof (struct TransportReliabilityBoxMessage),
7782 sizeof (struct GNUNET_MessageHeader));
7784 return GNUNET_YES;
7785}

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

7798{
7799 struct CommunicatorMessageContext *cmc = cls;
7800 const struct GNUNET_MessageHeader *inbox =
7801 (const struct GNUNET_MessageHeader *) &rb[1];
7802 struct GNUNET_TIME_Relative rtt;
7803
7805 "Received reliability box from %s with UUID %s of type %u\n",
7806 GNUNET_i2s (&cmc->im.sender),
7808 (unsigned int) ntohs (inbox->type));
7809 rtt = GNUNET_TIME_UNIT_SECONDS; /* FIXME: should base this on "RTT", but we
7810 do not really have an RTT for the
7811 * incoming* queue (should we have
7812 the sender add it to the rb message?) */
7814 &cmc->im.sender,
7815 &rb->ack_uuid,
7816 (0 == ntohl (rb->ack_countdown))
7819 GNUNET_TIME_relative_divide (rtt, 8 /* FIXME: magic constant */)));
7820 /* continue with inner message */
7821 /* FIXME: check that inbox is NOT a DV Box, fragment or another
7822 reliability box (not allowed!) */
7823 cmc->mh = inbox;
7825}

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

7838{
7839 unsigned int sage;
7840
7841 if (age == pd->last_age)
7842 return; /* nothing to do */
7843 sage = GNUNET_MAX (pd->last_age, age - 2 * GOODPUT_AGING_SLOTS);
7844 for (unsigned int i = sage; i <= age - GOODPUT_AGING_SLOTS; i++)
7845 {
7846 struct TransmissionHistoryEntry *the = &pd->the[i % GOODPUT_AGING_SLOTS];
7847
7848 the->bytes_sent = 0;
7849 the->bytes_received = 0;
7850 }
7851 pd->last_age = age;
7852}

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

7867{
7868 uint64_t nval = rtt.rel_value_us;
7869 uint64_t oval = pd->aged_rtt.rel_value_us;
7870 unsigned int age = get_age ();
7871 struct TransmissionHistoryEntry *the = &pd->the[age % GOODPUT_AGING_SLOTS];
7872
7873 if (oval == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
7874 pd->aged_rtt = rtt;
7875 else
7876 pd->aged_rtt.rel_value_us = (nval + 7 * oval) / 8;
7877 update_pd_age (pd, age);
7878 the->bytes_received += bytes_transmitted_ok;
7879}

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

7893{
7894 update_performance_data (&q->pd, rtt, bytes_transmitted_ok);
7895}

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

7909{
7910 update_performance_data (&dvh->pd, rtt, bytes_transmitted_ok);
7911}

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

7923{
7924 struct PendingMessage *pos;
7925
7927 "Complete transmission of message %" PRIu64 " %u\n",
7928 pm->logging_uuid,
7929 pm->pmt);
7930 switch (pm->pmt)
7931 {
7932 case PMT_CORE:
7934 /* Full message sent, we are done */
7936 return;
7937
7938 case PMT_FRAGMENT_BOX:
7939 /* Fragment sent over reliable channel */
7940 pos = pm->frag_parent;
7941 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
7944 "pos frag_off %lu pos bytes_msg %lu pmt %u parent %u\n",
7945 (unsigned long) pos->frag_off,
7946 (unsigned long) pos->bytes_msg,
7947 pos->pmt,
7948 NULL == pos->frag_parent ? 1 : 0);
7949 /* check if subtree is done */
7950 while ((NULL == pos->head_frag) && (pos->frag_off == (pos->bytes_msg
7951 - sizeof(struct
7953 &&
7954 (NULL != pos->frag_parent))
7955 {
7956 pm = pos;
7957 pos = pm->frag_parent;
7958 if ((NULL == pos) && (PMT_DV_BOX == pm->pmt))
7959 {
7961 return;
7962 }
7963 else if (PMT_DV_BOX == pm->pmt)
7964 {
7966 return;
7967 }
7968 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
7970 }
7971
7972 /* Was this the last applicable fragment? */
7973 if ((NULL == pos->head_frag) && (NULL == pos->frag_parent || PMT_DV_BOX ==
7974 pos->pmt) &&
7975 (pos->frag_off == pos->bytes_msg))
7977 return;
7978
7979 case PMT_DV_BOX:
7981 "Completed transmission of message %" PRIu64 " (DV Box)\n",
7982 pm->logging_uuid);
7983 if (NULL != pm->frag_parent)
7984 {
7985 pos = pm->frag_parent;
7987 pos->bpm = NULL;
7989 }
7990 else
7992 return;
7993 }
7994}

References PendingMessage::bpm, PendingMessage::bytes_msg, client_send_response(), 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 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 8005 of file gnunet-service-transport.c.

8007{
8008 struct GNUNET_TIME_Relative delay;
8009
8011 delay = GNUNET_TIME_relative_subtract (delay, ack_delay);
8012 if (NULL != pa->queue && 1 == pa->num_send)
8014 if (NULL != pa->dvh && 1 == pa->num_send)
8015 update_dvh_performance (pa->dvh, delay, pa->message_size);
8016 if (NULL != pa->pm)
8019}

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

8032{
8033 unsigned int n_acks;
8034
8035 (void) cls;
8036 n_acks = (ntohs (ra->header.size) - sizeof(*ra))
8037 / sizeof(struct TransportCummulativeAckPayloadP);
8038 if (0 == n_acks)
8039 {
8040 GNUNET_break_op (0);
8041 return GNUNET_SYSERR;
8042 }
8043 if ((ntohs (ra->header.size) - sizeof(*ra)) !=
8044 n_acks * sizeof(struct TransportCummulativeAckPayloadP))
8045 {
8046 GNUNET_break_op (0);
8047 return GNUNET_SYSERR;
8048 }
8049 return GNUNET_OK;
8050}

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

8063{
8064 struct CommunicatorMessageContext *cmc = cls;
8065 const struct TransportCummulativeAckPayloadP *ack;
8066 unsigned int n_acks;
8067 uint32_t ack_counter;
8068
8069 n_acks = (ntohs (ra->header.size) - sizeof(*ra))
8070 / sizeof(struct TransportCummulativeAckPayloadP);
8071 ack = (const struct TransportCummulativeAckPayloadP *) &ra[1];
8072 for (unsigned int i = 0; i < n_acks; i++)
8073 {
8074 struct PendingAcknowledgement *pa =
8076 if (NULL == pa)
8077 {
8079 "Received ACK from %s with UUID %s which is unknown to us!\n",
8080 GNUNET_i2s (&cmc->im.sender),
8081 GNUNET_uuid2s (&ack[i].ack_uuid.value));
8083 GST_stats,
8084 "# FRAGMENT_ACKS dropped, no matching pending message",
8085 1,
8086 GNUNET_NO);
8087 continue;
8088 }
8090 "Received ACK from %s with UUID %s\n",
8091 GNUNET_i2s (&cmc->im.sender),
8092 GNUNET_uuid2s (&ack[i].ack_uuid.value));
8093 handle_acknowledged (pa, GNUNET_TIME_relative_ntoh (ack[i].ack_delay));
8094 }
8095
8096 ack_counter = ntohl (ra->ack_counter);
8097 (void) ack_counter; /* silence compiler warning for now */
8098 // FIXME-OPTIMIZE: track ACK losses based on ack_counter somewhere!
8099 // (DV and/or Neighbour?)
8100 finish_cmc_handling (cmc);
8101}

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

8115{
8116 uint16_t size = ntohs (be->header.size) - sizeof(*be);
8117 const struct GNUNET_MessageHeader *inbox =
8118 (const struct GNUNET_MessageHeader *) &be[1];
8119 const char *is;
8120 uint16_t isize;
8121
8122 (void) cls;
8123 /* MUST bound the buffer before reading @a inbox: the size check below
8124 dereferences it, and a message consisting of nothing but the header
8125 leaves no bytes to read. */
8126 if (size <= sizeof(struct GNUNET_MessageHeader))
8127 {
8128 GNUNET_break_op (0);
8129 return GNUNET_SYSERR;
8130 }
8131 if (ntohs (inbox->size) >= size)
8132 {
8133 GNUNET_break_op (0);
8134 return GNUNET_SYSERR;
8135 }
8136 isize = ntohs (inbox->size);
8137 is = ((const char *) inbox) + isize;
8138 size -= isize;
8139 if ('\0' != is[size - 1])
8140 {
8141 GNUNET_break_op (0);
8142 return GNUNET_SYSERR;
8143 }
8144 return GNUNET_YES;
8145}

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

8160{
8161 const struct GNUNET_PeerIdentity *my_identity;
8162 struct CommunicatorMessageContext *cmc = cls;
8164 struct GNUNET_MQ_Envelope *env;
8165 struct TransportClient *tc;
8166 const struct GNUNET_MessageHeader *inbox =
8167 (const struct GNUNET_MessageHeader *) &be[1];
8168 uint16_t isize = ntohs (inbox->size);
8169 const char *target_communicator = ((const char *) inbox) + isize;
8170 char *sender;
8171 char *self;
8172
8175
8176 GNUNET_asprintf (&sender,
8177 "%s",
8178 GNUNET_i2s (&cmc->im.sender));
8179 GNUNET_asprintf (&self,
8180 "%s",
8182
8183 /* Find client providing this communicator */
8184 for (tc = clients_head; NULL != tc; tc = tc->next)
8185 if ((CT_COMMUNICATOR == tc->type) &&
8186 (NULL != tc->details.communicator.address_prefix) &&
8187 (0 ==
8188 strcmp (tc->details.communicator.address_prefix, target_communicator)))
8189 break;
8190 if (NULL == tc)
8191 {
8192 char *stastr;
8193
8195 &stastr,
8196 "# Backchannel message dropped: target communicator `%s' unknown",
8197 target_communicator);
8199 GNUNET_free (stastr);
8200 GNUNET_free (sender);
8201 GNUNET_free (self);
8202 finish_cmc_handling (cmc);
8203 return;
8204 }
8205 /* Finally, deliver backchannel message to communicator */
8207 "Delivering backchannel message from %s to %s of type %u to %s\n",
8208 sender,
8209 self,
8210 ntohs (inbox->type),
8211 target_communicator);
8213 cbi,
8214 isize,
8216 cbi->pid = cmc->im.sender;
8217 memcpy (&cbi[1], inbox, isize);
8218 GNUNET_MQ_send (tc->mq, env);
8219 GNUNET_free (sender);
8220 GNUNET_free (self);
8221 finish_cmc_handling (cmc);
8222}

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

8236{
8237 struct DistanceVector *dv = cls;
8238 struct DistanceVectorHop *pos;
8239
8240 dv->timeout_task = NULL;
8241 while (NULL != (pos = dv->dv_head))
8242 {
8243 GNUNET_assert (dv == pos->dv);
8245 break;
8247 }
8248 if (NULL == pos)
8249 {
8250 free_dv_route (dv);
8251 return;
8252 }
8253 dv->timeout_task =
8255}

References DistanceVectorHop::dv, DistanceVector::dv_head, free_distance_vector_hop(), free_dv_route(), GNUNET_assert, GNUNET_SCHEDULER_add_at(), GNUNET_TIME_absolute_get_remaining(), 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 8259 of file gnunet-service-transport.c.

8260{
8261
8262 const struct GNUNET_PeerIdentity target = vl->target;
8263
8264
8266 {
8267 struct RingBufferEntry *ring_buffer_copy[RING_BUFFER_SIZE];
8268 unsigned int tail = GNUNET_YES == is_ring_buffer_full ? ring_buffer_head :
8269 0;
8270 unsigned int head = GNUNET_YES == is_ring_buffer_full ? RING_BUFFER_SIZE :
8273 struct CommunicatorMessageContext *cmc;
8274 struct RingBufferEntry *rbe;
8275 struct GNUNET_MessageHeader *mh;
8276
8278 "Sending from ring buffer, which has %u items\n",
8279 head);
8280
8281 ring_buffer_head = 0;
8282 for (unsigned int i = 0; i < head; i++)
8283 {
8284 rbe = ring_buffer[(i + tail) % RING_BUFFER_SIZE];
8285 cmc = rbe->cmc;
8286 mh = rbe->mh;
8287
8288 im = cmc->im;
8289 // mh = cmc->mh;
8291 "Sending message of type %u to ring buffer target %s using vl target %s index %u\n",
8292 mh->type,
8293 GNUNET_i2s (&im.sender),
8294 GNUNET_i2s2 (&target),
8295 (i + tail) % RING_BUFFER_SIZE);
8296 if (0 == GNUNET_memcmp (&target, &im.sender))
8297 {
8299 "Finish handling message of type %u and size %u\n",
8300 (unsigned int) ntohs (mh->type),
8301 (unsigned int) ntohs (mh->size));
8303 GNUNET_free (mh);
8304 GNUNET_free (rbe->cmc);
8305 GNUNET_free (rbe);
8306 }
8307 else
8308 {
8309 ring_buffer_copy[ring_buffer_head] = rbe;
8311 }
8312 }
8313
8316 {
8318 }
8319
8320 for (unsigned int i = 0; i < ring_buffer_head; i++)
8321 {
8322 ring_buffer[i] = ring_buffer_copy[i];
8324 "ring_buffer[i]->mh->type for i %u %u\n",
8325 i,
8326 ring_buffer[i]->mh->type);
8327 }
8328 /* MUST clear the consumed slots, we freed those entries above */
8329 for (unsigned int i = ring_buffer_head; i < RING_BUFFER_SIZE; i++)
8330 ring_buffer[i] = NULL;
8331
8333 "%u items still in ring buffer\n",
8335 /* If we consumed nothing, compaction rewrote the buffer in place and
8336 left the write index one past the end. #handle_raw_message() would
8337 then read ring_buffer[RING_BUFFER_SIZE] and free whatever that is.
8338 The buffer is still full, and compaction moved the oldest entry to
8339 slot 0, so that is where the next write belongs. */
8341 ring_buffer_head = 0;
8342 }
8343
8345 {
8346 struct PendingMessage *ring_buffer_dv_copy[RING_BUFFER_SIZE];
8347 struct PendingMessage *pm;
8348 unsigned int tail = GNUNET_YES == is_ring_buffer_dv_full ?
8350 0;
8351 unsigned int head = GNUNET_YES == is_ring_buffer_dv_full ?
8354
8356 "Sending from ring buffer dv, which has %u items\n",
8357 head);
8358
8360 for (unsigned int i = 0; i < head; i++)
8361 {
8362 pm = ring_buffer_dv[(i + tail) % RING_BUFFER_SIZE];
8363
8365 "Sending to ring buffer target %s using vl target %s\n",
8366 GNUNET_i2s (&pm->target),
8367 GNUNET_i2s2 (&target));
8368 if (0 == GNUNET_memcmp (&target, &pm->target))
8369 {
8371 "Adding PendingMessage to vl, checking transmission.\n");
8372 pm->vl = vl;
8376 pm);
8377
8379 }
8380 else
8381 {
8382 ring_buffer_dv_copy[ring_buffer_dv_head] = pm;
8384 }
8385 }
8386
8388 {
8390 }
8391
8392 for (unsigned int i = 0; i < ring_buffer_dv_head; i++)
8393 ring_buffer_dv[i] = ring_buffer_dv_copy[i];
8394 /* MUST clear the consumed slots: entries we handed to a VirtualLink are
8395 now owned by that link, and #forward_dv_box() would GNUNET_free() them
8396 again once the ring buffer wraps around. */
8397 for (unsigned int i = ring_buffer_dv_head; i < RING_BUFFER_SIZE; i++)
8398 ring_buffer_dv[i] = NULL;
8399
8401 "%u items still in ring buffer dv.\n",
8403 /* Same one-past-the-end hazard as above: #forward_dv_box() reads
8404 ring_buffer_dv[ring_buffer_dv_head] and GNUNET_free()s it. */
8407 }
8408}

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

8420{
8421 struct DistanceVector *dv = hop->dv;
8422 struct VirtualLink *vl;
8423
8424 vl = lookup_virtual_link (&dv->target);
8425 if (NULL == vl)
8426 {
8427
8428 vl = GNUNET_new (struct VirtualLink);
8430 "Creating new virtual link %p to %s using DV!\n",
8431 vl,
8432 GNUNET_i2s (&dv->target));
8433 vl->burst_addr = NULL;
8434 vl->confirmed = GNUNET_YES;
8435 vl->message_uuid_ctr =
8436 GNUNET_CRYPTO_random_u64 (UINT64_MAX);
8437 vl->target = dv->target;
8443 links,
8444 &vl->target,
8445 vl,
8447 vl->dv = dv;
8448 dv->vl = vl;
8449 vl->visibility_task =
8452 /* We lacked a confirmed connection to the target
8453 before, so tell CORE about it (finally!) */
8456 }
8457 else
8458 {
8459 /* Link was already up, remember dv is also now available and we are done */
8460 vl->dv = dv;
8461 dv->vl = vl;
8462 if (GNUNET_NO == vl->confirmed)
8463 {
8464 vl->confirmed = GNUNET_YES;
8465 vl->visibility_task =
8468 /* We lacked a confirmed connection to the target
8469 before, so tell CORE about it (finally!) */
8472 }
8473 else
8475 "Virtual link to %s could now also use DV!\n",
8476 GNUNET_i2s (&dv->target));
8477 }
8478}

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

8511{
8512 const struct GNUNET_PeerIdentity *my_identity;
8513 struct DistanceVectorHop *hop;
8514 struct DistanceVector *dv;
8515 struct Neighbour *next_hop;
8516 unsigned int shorter_distance;
8517
8518 if (path_len < 3)
8519 {
8520 /* what a boring path! not allowed! */
8521 GNUNET_break (0);
8522 return GNUNET_SYSERR;
8523 }
8524
8527
8528 GNUNET_assert (0 == GNUNET_memcmp (my_identity, &path[0]));
8529 next_hop = lookup_neighbour (&path[1]);
8530 if (NULL == next_hop)
8531 {
8532 /* next hop must be a neighbour, otherwise this whole thing is useless! */
8533 GNUNET_break (0);
8534 return GNUNET_SYSERR;
8535 }
8536 for (unsigned int i = 2; i < path_len; i++)
8537 {
8538 struct Neighbour *n = lookup_neighbour (&path[i]);
8539 struct GNUNET_TIME_Absolute q_timeout;
8540
8541 if (NULL != n)
8542 {
8543 q_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
8544 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
8545 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
8547 "remaining %lu to %s\n",
8548 (unsigned long) GNUNET_TIME_absolute_get_remaining (q_timeout)
8549 .rel_value_us,
8550 GNUNET_i2s (&n->pid));
8551 if (0 != GNUNET_TIME_absolute_get_remaining (q_timeout).rel_value_us)
8552 {
8553 /* Useless path: we have a direct active connection to some hop
8554 in the middle of the path, so this one is not even
8555 terribly useful for redundancy */
8557 "Path of %u hops useless: directly link to hop %u (%s)\n",
8558 path_len,
8559 i,
8560 GNUNET_i2s (&path[i]));
8562 "# Useless DV path ignored: hop is neighbour",
8563 1,
8564 GNUNET_NO);
8565 return GNUNET_SYSERR;
8566 }
8567 }
8568 }
8569 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
8570 if (NULL == dv)
8571 {
8572 dv = GNUNET_new (struct DistanceVector);
8573 dv->target = path[path_len - 1];
8576 dv);
8579 dv_routes,
8580 &dv->target,
8581 dv,
8583 }
8584 /* Check if we have this path already! */
8585 shorter_distance = 0;
8586 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
8587 pos = pos->next_dv)
8588 {
8589 if (pos->distance < path_len - 3)
8590 shorter_distance++;
8591 /* Note that the distances in 'pos' excludes us (path[0]),
8592 the next_hop (path[1]) and the target so we need to subtract three
8593 and check next_hop explicitly */
8594 if ((pos->distance == path_len - 3) && (pos->next_hop == next_hop))
8595 {
8596 int match = GNUNET_YES;
8597
8598 for (unsigned int i = 0; i < pos->distance; i++)
8599 {
8600 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
8601 {
8602 match = GNUNET_NO;
8603 break;
8604 }
8605 }
8606 if (GNUNET_YES == match)
8607 {
8608 struct GNUNET_TIME_Relative last_timeout;
8609
8610 /* Re-discovered known path, update timeout */
8612 "# Known DV path refreshed",
8613 1,
8614 GNUNET_NO);
8615 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
8616 pos->timeout =
8618 pos->path_valid_until =
8619 GNUNET_TIME_absolute_max (pos->path_valid_until, path_valid_until);
8620 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
8621 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
8622 if (0 <
8625 if (last_timeout.rel_value_us <
8628 .rel_value_us)
8629 {
8630 /* Some peer send DV learn messages too often, we are learning
8631 the same path faster than it would be useful; do not forward! */
8633 "Rediscovered path too quickly, not forwarding further\n")
8634 ;
8635 return GNUNET_NO;
8636 }
8638 "Refreshed known path to %s valid until %s, forwarding further\n",
8639 GNUNET_i2s (&dv->target),
8641 pos->path_valid_until));
8642 return GNUNET_YES;
8643 }
8644 }
8645 }
8646 /* Count how many shorter paths we have (incl. direct
8647 neighbours) before simply giving up on this one! */
8648 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
8649 {
8650 /* We have a shorter path already! */
8652 "Have many shorter DV paths %s, not forwarding further\n",
8653 GNUNET_i2s (&dv->target));
8654 return GNUNET_NO;
8655 }
8656 /* create new DV path entry */
8658 "Discovered new DV path to %s valid until %s\n",
8659 GNUNET_i2s (&dv->target),
8660 GNUNET_STRINGS_absolute_time_to_string (path_valid_until));
8661 hop = GNUNET_malloc (sizeof(struct DistanceVectorHop)
8662 + sizeof(struct GNUNET_PeerIdentity) * (path_len - 3));
8663 hop->next_hop = next_hop;
8664 hop->dv = dv;
8665 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
8666 memcpy (&hop[1],
8667 &path[2],
8668 sizeof(struct GNUNET_PeerIdentity) * (path_len - 3));
8670 hop->path_valid_until = path_valid_until;
8671 hop->distance = path_len - 3;
8672 hop->pd.aged_rtt = network_latency;
8673 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
8675 next_hop->dv_head,
8676 next_hop->dv_tail,
8677 hop);
8678 if (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
8680 return GNUNET_YES;
8681}

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

8693{
8694 const struct GNUNET_PeerIdentity *my_identity;
8695 uint16_t size = ntohs (dvl->header.size);
8696 uint16_t num_hops = ntohs (dvl->num_hops);
8697 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
8698
8699 (void) cls;
8700 if (size != sizeof(*dvl) + num_hops * sizeof(struct DVPathEntryP))
8701 {
8702 GNUNET_break_op (0);
8703 return GNUNET_SYSERR;
8704 }
8705 if (num_hops > MAX_DV_HOPS_ALLOWED)
8706 {
8707 GNUNET_break_op (0);
8708 return GNUNET_SYSERR;
8709 }
8710
8713
8714 for (unsigned int i = 0; i < num_hops; i++)
8715 {
8716 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
8717 {
8718 GNUNET_break_op (0);
8719 return GNUNET_SYSERR;
8720 }
8721 if (0 == GNUNET_memcmp (my_identity, &hops[i].hop))
8722 {
8723 GNUNET_break_op (0);
8724 return GNUNET_SYSERR;
8725 }
8726 }
8727 return GNUNET_YES;
8728}

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

8749{
8750 struct DVPathEntryP *dhops;
8751 size_t fwd_size = sizeof(struct TransportDVLearnMessage)
8752 + (nhops + 1) * sizeof(struct DVPathEntryP);
8753 /* Signing is synchronous and the routing calls below copy the message,
8754 so this never outlives the frame. Keeping it on the stack matters:
8755 a hub forwards a DV learn to every eligible neighbour, so this is one
8756 of the hottest allocation sites in the service. Size it by the hop
8757 limit rather than by @a nhops -- @a nhops is only asserted to be below
8758 that limit further down, and a VLA is sized before we get there. */
8759 char fwd_buf[sizeof(struct TransportDVLearnMessage)
8760 + (MAX_DV_HOPS_ALLOWED + 1)
8761 * sizeof(struct DVPathEntryP)] GNUNET_ALIGN;
8762 struct TransportDVLearnMessage *fwd
8763 = (struct TransportDVLearnMessage *) fwd_buf;
8764 struct GNUNET_TIME_Relative nnd;
8765 const struct GNUNET_PeerIdentity *my_identity;
8766 struct VirtualLink *vl;
8767 struct Neighbour *n;
8768
8770 memset (fwd_buf, 0, fwd_size);
8771
8772 /* compute message for forwarding */
8774 "Forwarding DV learn message originating from %s to %s\n",
8775 GNUNET_i2s (&msg->initiator),
8776 GNUNET_i2s2 (next_hop));
8779 fwd->header.size = htons (sizeof(struct TransportDVLearnMessage)
8780 + (nhops + 1) * sizeof(struct DVPathEntryP));
8781 fwd->num_hops = htons (nhops + 1);
8782 fwd->bidirectional = htons (bi_history);
8785 msg->non_network_delay));
8787 fwd->init_sig = msg->init_sig;
8788 fwd->initiator = msg->initiator;
8789 fwd->challenge = msg->challenge;
8790 fwd->monotonic_time = msg->monotonic_time;
8791
8794
8795 dhops = (struct DVPathEntryP *) &fwd[1];
8796 GNUNET_memcpy (dhops, hops, sizeof(struct DVPathEntryP) * nhops);
8797 dhops[nhops].hop = *my_identity;
8798 {
8799 struct DvHopPS dhp = {
8801 .purpose.size = htonl (sizeof(dhp)),
8802 .pred = (0 == nhops) ? msg->initiator : dhops[nhops - 1].hop,
8803 .succ = *next_hop,
8805 };
8806
8808 &dhops[nhops].hop_sig))
8809 return; /* nobody would accept the path without our hop signature */
8810 }
8811 vl = lookup_virtual_link (next_hop);
8812 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
8813 {
8815 &fwd->header,
8817 return;
8818 }
8819 /* Use route via neighbour */
8820 n = lookup_neighbour (next_hop);
8821 if (NULL != n)
8823 &fwd->header,
8825}

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

8843{
8844 struct DvInitPS ip = { .purpose.purpose = htonl (
8846 .purpose.size = htonl (sizeof(ip)),
8847 .monotonic_time = sender_monotonic_time,
8848 .challenge = *challenge };
8849
8850 if (
8851 GNUNET_OK !=
8853 &ip,
8854 init_sig,
8855 &init->public_key))
8856 {
8857 GNUNET_break_op (0);
8858 return GNUNET_SYSERR;
8859 }
8860 return GNUNET_OK;
8861}

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

8923{
8924 struct NeighbourSelectionContext *nsc = cls;
8925
8926 (void) value;
8927 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
8928 return GNUNET_YES; /* skip initiator */
8929 for (unsigned int i = 0; i < nsc->nhops; i++)
8930 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
8931 return GNUNET_YES;
8932 /* skip peers on path */
8933 nsc->num_eligible++;
8934 return GNUNET_YES;
8935}

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

8952{
8953 struct NeighbourSelectionContext *nsc = cls;
8954
8956 "transmission %s\n",
8957 GNUNET_i2s (pid));
8958 (void) value;
8959 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
8960 return GNUNET_YES; /* skip initiator */
8961 for (unsigned int i = 0; i < nsc->nhops; i++)
8962 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
8963 return GNUNET_YES;
8964 /* skip peers on path */
8965 for (unsigned int i = 0; i < nsc->num_selections; i++)
8966 {
8967 if (nsc->selections[i] == nsc->num_eligible)
8968 {
8969 forward_dv_learn (pid,
8970 nsc->dvl,
8971 nsc->bi_history,
8972 nsc->nhops,
8973 nsc->hops,
8974 nsc->in_time);
8975 break;
8976 }
8977 }
8978 nsc->num_eligible++;
8979 return GNUNET_YES;
8980}

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

9030{
9031 double target_total = 50.0; /* FIXME: use LOG(NSE)? */
9032 double eligible_ratio =
9033 ((double) eligible_count) / ((double) neighbour_count);
9034 double boost_factor = eligible_ratio * eligible_ratio;
9035 unsigned int rnd;
9036 double left;
9037
9038 if (hops_taken >= 64)
9039 {
9040 GNUNET_break (0);
9041 return 0; /* precaution given bitshift below */
9042 }
9043 for (unsigned int i = 1; i < hops_taken; i++)
9044 {
9045 /* For each hop, subtract the expected number of targets
9046 reached at distance d (so what remains divided by 2^d) */
9047 target_total -= (target_total * boost_factor / (1LLU << i));
9048 }
9049 {
9050 double degree = target_total * boost_factor / (1LLU << hops_taken);
9051
9052 rnd = (unsigned int) floor (degree);
9053 /* round up or down probabilistically depending on how close we were
9054 when floor()ing to rnd. NOTE: this must be the fractional part of
9055 @e degree; using `target_total - rnd' here made the condition below
9056 true essentially always, so we always rounded up. */
9057 left = degree - (double) rnd;
9058 }
9059 if (UINT32_MAX * left >
9060 GNUNET_CRYPTO_random_u64 (UINT32_MAX))
9061 rnd++; /* round up */
9063 "Forwarding DV learn message of %u hops %u(/%u/%u) times\n",
9064 hops_taken,
9065 rnd,
9066 eligible_count,
9067 neighbour_count);
9068 return rnd;
9069}

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

9080{
9081 struct Neighbour *n = cls;
9082
9083 n->sc = NULL;
9084 if (GNUNET_YES != success)
9086 "Failed to store other peer's monotonic time in peerstore!\n");
9087}

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

9092{
9093 struct GNUNET_TIME_Relative host_latency_sum;
9094 struct GNUNET_TIME_Relative latency;
9095 struct GNUNET_TIME_Relative network_latency;
9096 uint16_t nhops = ntohs (dvl->num_hops);;
9097
9098 /* We initiated this, learn the forward path! */
9099 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
9100
9101 // Need also something to lookup initiation time
9102 // to compute RTT! -> add RTT argument here?
9104 dvl->monotonic_time));
9105 /* @e non_network_delay is fully attacker-controlled, and our clock may
9106 simply be behind the initiator's: never assert on this. */
9107 if (latency.rel_value_us < host_latency_sum.rel_value_us)
9108 {
9110 "# DV learn with implausible non-network delay",
9111 1,
9112 GNUNET_NO);
9114 }
9115 // latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
9116 // (based on dvl->challenge, we can identify time of origin!)
9117
9118 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
9119 /* assumption: latency on all links is the same */
9120 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
9121
9122 return network_latency;
9123}

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

9135{
9136 struct CommunicatorMessageContext *cmc = cls;
9138 int bi_hop;
9139 uint16_t nhops;
9140 uint16_t bi_history;
9141 const struct DVPathEntryP *hops;
9142 int do_fwd;
9143 int did_initiator;
9144 struct GNUNET_TIME_Absolute in_time;
9145 struct Neighbour *n;
9146 const struct GNUNET_PeerIdentity *my_identity;
9147
9148 nhops = ntohs (dvl->num_hops); /* 0 = sender is initiator */
9149 bi_history = ntohs (dvl->bidirectional);
9150 hops = (const struct DVPathEntryP *) &dvl[1];
9151 if (0 == nhops)
9152 {
9153 /* sanity check */
9154 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
9155 {
9156 GNUNET_break (0);
9157 finish_cmc_handling (cmc);
9158 return;
9159 }
9160 /* A zero-hop message we supposedly initiated ourselves would make the
9161 "we are the initiator" branch below read hops[0] and write past the
9162 end of its `path[nhops + 1]' array. */
9164 {
9165 GNUNET_break_op (0);
9166 finish_cmc_handling (cmc);
9167 return;
9168 }
9169 }
9170 else
9171 {
9173 "handle dv learn message last hop %s\n",
9174 GNUNET_i2s (&hops[nhops - 1].hop));
9175 /* sanity check */
9176 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
9177 {
9178 GNUNET_break (0);
9179 finish_cmc_handling (cmc);
9180 return;
9181 }
9182 }
9183
9185 cc = cmc->tc->details.communicator.cc;
9186 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
9187 cc); // FIXME: add bi-directional flag to cc?
9188 in_time = GNUNET_TIME_absolute_get ();
9189
9190 /* continue communicator here, everything else can happen asynchronous! */
9191 finish_cmc_handling (cmc);
9192
9193 n = lookup_neighbour (&dvl->initiator);
9194 if (NULL != n)
9195 {
9196 if ((n->dv_monotime_available == GNUNET_YES) &&
9199 {
9201 "DV learn from %s discarded due to time travel",
9202 GNUNET_i2s (&dvl->initiator));
9204 "# DV learn discarded due to time travel",
9205 1,
9206 GNUNET_NO);
9207 return;
9208 }
9210 &dvl->initiator,
9211 &dvl->challenge,
9212 &dvl->init_sig))
9213 {
9215 "DV learn signature from %s invalid\n",
9216 GNUNET_i2s (&dvl->initiator));
9217 GNUNET_break_op (0);
9218 return;
9219 }
9222 {
9223 if (NULL != n->sc)
9224 {
9226 "store cancel\n");
9228 }
9229 n->sc =
9231 "transport",
9232 &dvl->initiator,
9234 &dvl->monotonic_time,
9235 sizeof(dvl->monotonic_time),
9239 n);
9240 }
9241 }
9242
9245
9246 /* OPTIMIZE-FIXME: asynchronously (!) verify signatures!,
9247 If signature verification load too high, implement random drop strategy */
9248 for (unsigned int i = 0; i < nhops; i++)
9249 {
9250 struct DvHopPS dhp = { .purpose.purpose =
9252 .purpose.size = htonl (sizeof(dhp)),
9253 .pred = (0 == i) ? dvl->initiator : hops[i - 1].hop,
9254 .succ = (nhops == i + 1) ? *my_identity
9255 : hops[i + 1].hop,
9256 .challenge = dvl->challenge };
9257
9258 if (GNUNET_OK !=
9260 &dhp,
9261 &hops[i].hop_sig,
9262 &hops[i].hop.public_key))
9263 {
9265 "DV learn from %s signature of hop %u invalid\n",
9266 GNUNET_i2s (&dvl->initiator),
9267 i);
9269 "signature of hop %s invalid\n",
9270 GNUNET_i2s (&hops[i].hop));
9272 "pred %s\n",
9273 GNUNET_i2s (&dhp.pred));
9275 "succ %s\n",
9276 GNUNET_i2s (&dhp.succ));
9278 "hash %s\n",
9279 GNUNET_sh2s (&dhp.challenge.value));
9280 GNUNET_break_op (0);
9281 return;
9282 }
9283 }
9284 if (GNUNET_EXTRA_LOGGING > 0)
9285 {
9286 char *path;
9287
9288 path = GNUNET_strdup (GNUNET_i2s (&dvl->initiator));
9289 for (unsigned int i = 0; i < nhops; i++)
9290 {
9291 char *tmp;
9292
9293 GNUNET_asprintf (&tmp,
9294 "%s%s%s",
9295 path,
9296 (bi_history & (1 << (nhops - i))) ? "<->" : "-->",
9297 GNUNET_i2s (&hops[i].hop));
9298 GNUNET_free (path);
9299 path = tmp;
9300 }
9302 "Received DVInit via %s%s%s\n",
9303 path,
9304 bi_hop ? "<->" : "-->",
9306 GNUNET_free (path);
9307 }
9308 do_fwd = GNUNET_YES;
9309 if (0 == GNUNET_memcmp (my_identity, &dvl->initiator))
9310 {
9311 struct GNUNET_PeerIdentity path[nhops + 1];
9312 struct GNUNET_TIME_Relative network_latency;
9313
9314 /* We initiated this, learn the forward path! */
9315 path[0] = *my_identity;
9316 path[1] = hops[0].hop;
9317
9318 network_latency = get_network_latency (dvl);
9319
9320 for (unsigned int i = 2; i <= nhops; i++)
9321 {
9322 struct GNUNET_TIME_Relative ilat;
9323
9324 /* assumption: linear latency increase per hop */
9325 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
9326 path[i] = hops[i - 1].hop;
9328 "Learned path with %u hops to %s with latency %s\n",
9329 i,
9330 GNUNET_i2s (&path[i]),
9332 learn_dv_path (path,
9333 i + 1,
9334 ilat,
9337 }
9338 /* as we initiated, do not forward again (would be circular!) */
9339 do_fwd = GNUNET_NO;
9340 return;
9341 }
9342 if (bi_hop)
9343 {
9344 /* last hop was bi-directional, we could learn something here! */
9345 struct GNUNET_PeerIdentity path[nhops + 2];
9346 struct GNUNET_TIME_Relative ilat;
9347 struct GNUNET_TIME_Relative network_latency;
9348
9349 path[0] = *my_identity;
9350 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
9351 for (unsigned int i = 0; i < nhops; i++)
9352 {
9353 int iret;
9354
9355 if (0 == (bi_history & (1 << i)))
9356 break; /* i-th hop not bi-directional, stop learning! */
9357 if (i == nhops - 1)
9358 {
9359 path[i + 2] = dvl->initiator;
9360 }
9361 else
9362 {
9363 path[i + 2] = hops[nhops - i - 2].hop;
9364 }
9365
9367 "Learned inverse path with %u hops to %s\n",
9368 i + 2,
9369 GNUNET_i2s (&path[i + 2]));
9370 network_latency = get_network_latency (dvl);
9371 ilat = GNUNET_TIME_relative_multiply (network_latency, i + 2);
9372 iret = learn_dv_path (path,
9373 i + 3,
9374 ilat,
9377 if (GNUNET_SYSERR == iret)
9378 {
9379 /* path invalid or too long to be interesting for US, thus should also
9380 not be interesting to our neighbours, cut path when forwarding to
9381 'i' hops, except of course for the one that goes back to the
9382 initiator */
9384 "# DV learn not forwarded due invalidity of path",
9385 1,
9386 GNUNET_NO);
9387 do_fwd = GNUNET_NO;
9388 break;
9389 }
9390 if ((GNUNET_NO == iret) && (nhops == i + 1))
9391 {
9392 /* we have better paths, and this is the longest target,
9393 so there cannot be anything interesting later */
9395 "# DV learn not forwarded, got better paths",
9396 1,
9397 GNUNET_NO);
9398 do_fwd = GNUNET_NO;
9399 break;
9400 }
9401 }
9402 }
9403 if (MAX_DV_HOPS_ALLOWED == nhops)
9404 {
9405 /* At limit, we're out of here! */
9406 return;
9407 }
9408
9409 /* Forward to initiator, if path non-trivial and possible */
9410 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
9411 did_initiator = GNUNET_NO;
9412 if ((1 <= nhops) &&
9413 (GNUNET_YES ==
9415 {
9416 /* send back to origin! */
9418 "Sending DVL back to initiator %s\n",
9419 GNUNET_i2s (&dvl->initiator));
9420 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
9421 did_initiator = GNUNET_YES;
9422 }
9423 /* We forward under two conditions: either we still learned something
9424 ourselves (do_fwd), or the path was darn short and thus the initiator is
9425 likely to still be very interested in this (and we did NOT already
9426 send it back to the initiator) */
9427 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
9428 (GNUNET_NO == did_initiator)))
9429 {
9430 /* Pick random neighbours that are not yet on the path */
9431 struct NeighbourSelectionContext nsc;
9432 unsigned int n_cnt;
9433 unsigned int n_eligible;
9434
9436 nsc.nhops = nhops;
9437 nsc.dvl = dvl;
9438 nsc.bi_history = bi_history;
9439 nsc.hops = hops;
9440 nsc.in_time = in_time;
9441 nsc.num_eligible = 0;
9444 &nsc);
9445 if (0 == nsc.num_eligible)
9446 return; /* done here, cannot forward to anyone else */
9447 n_eligible = nsc.num_eligible;
9448 nsc.num_selections = calculate_fork_degree (nhops, n_cnt, n_eligible);
9449 nsc.num_selections =
9450 GNUNET_MIN (MAX_DV_DISCOVERY_SELECTION, nsc.num_selections);
9452 "Forwarding DVL to %u other peers\n",
9453 nsc.num_selections);
9454 /* #dv_neighbour_transmission() counts ELIGIBLE peers only, so the
9455 offsets must be drawn from that range -- drawing from the total
9456 number of neighbours made us silently forward to fewer peers than
9457 #calculate_fork_degree() asked for. */
9458 for (unsigned int i = 0; i < nsc.num_selections; i++)
9459 nsc.selections[i] =
9460 (nsc.num_selections == n_eligible)
9461 ? i /* all were selected, avoid collisions by chance */
9462 : GNUNET_CRYPTO_random_u32 (n_eligible);
9463 nsc.num_eligible = 0;
9466 &nsc);
9467 }
9468}

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

9480{
9481 uint16_t size = ntohs (dvb->header.size);
9482 uint16_t num_hops = ntohs (dvb->num_hops);
9483 uint16_t total_hops = ntohs (dvb->total_hops);
9484 uint16_t orig_size = ntohs (dvb->orig_size);
9485 const struct GNUNET_PeerIdentity *hops =
9486 (const struct GNUNET_PeerIdentity *) &dvb[1];
9487 const struct GNUNET_PeerIdentity *my_identity;
9488
9489 (void) cls;
9490 if (size < sizeof(*dvb) + num_hops * sizeof(struct GNUNET_PeerIdentity)
9491 + sizeof(struct GNUNET_MessageHeader))
9492 {
9493 GNUNET_break_op (0);
9494 return GNUNET_SYSERR;
9495 }
9496 if ((num_hops > MAX_DV_HOPS_ALLOWED) ||
9497 (total_hops > MAX_DV_HOPS_ALLOWED))
9498 {
9499 GNUNET_break_op (0);
9500 return GNUNET_SYSERR;
9501 }
9502 /* #decaps_dv_box_cb() derives a VLA size from
9503 orig_size - sizeof(*dvb) - total_hops * sizeof (struct
9504 GNUNET_PeerIdentity); make sure that cannot underflow and that the
9505 remainder can plausibly hold a payload header plus a message. */
9506 if ((orig_size < size) ||
9507 (orig_size < sizeof(*dvb)
9508 + total_hops * sizeof(struct GNUNET_PeerIdentity)
9509 + sizeof(struct TransportDVBoxPayloadP)
9510 + sizeof(struct GNUNET_MessageHeader)))
9511 {
9512 GNUNET_break_op (0);
9513 return GNUNET_SYSERR;
9514 }
9515
9518
9519 /* This peer must not be on the path */
9520 for (unsigned int i = 0; i < num_hops; i++)
9521 if (0 == GNUNET_memcmp (&hops[i], my_identity))
9522 {
9523 GNUNET_break_op (0);
9524 return GNUNET_SYSERR;
9525 }
9526 return GNUNET_YES;
9527}

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

9550{
9551 struct VirtualLink *vl = next_hop->vl;
9552 struct PendingMessage *pm;
9553 size_t msg_size = sizeof(struct TransportDVBoxMessage)
9554 + num_hops * sizeof(struct GNUNET_PeerIdentity)
9555 + enc_payload_size;
9556 char *buf;
9557 char msg_buf[msg_size] GNUNET_ALIGN;
9558 struct GNUNET_PeerIdentity *dhops;
9559
9560 hdr->num_hops = htons (num_hops);
9561 hdr->total_hops = htons (total_hops);
9562 hdr->header.size = htons (msg_size);
9563 memcpy (msg_buf, hdr, sizeof(*hdr));
9564 dhops = (struct GNUNET_PeerIdentity *) &msg_buf[sizeof(struct
9566 ;
9567 memcpy (dhops, hops, num_hops * sizeof(struct GNUNET_PeerIdentity));
9568 memcpy (&dhops[num_hops], enc_payload, enc_payload_size);
9569
9570 if (GNUNET_YES == ntohl (hdr->without_fc))
9571 {
9573 "Forwarding control message (payload size %u) in DV Box to next hop %s (%u/%u) \n",
9574 enc_payload_size,
9575 GNUNET_i2s (&next_hop->pid),
9576 (unsigned int) num_hops,
9577 (unsigned int) total_hops);
9578 route_via_neighbour (next_hop, (const struct
9579 GNUNET_MessageHeader *) msg_buf,
9581 }
9582 else
9583 {
9584 pm = GNUNET_malloc (sizeof(struct PendingMessage) + msg_size);
9586 "2 created pm %p storing vl %p \n",
9587 pm,
9588 vl);
9589 pm->pmt = PMT_DV_BOX;
9590 pm->vl = vl;
9591 pm->target = next_hop->pid;
9595 pm->bytes_msg = msg_size;
9596 buf = (char *) &pm[1];
9597 memcpy (buf, msg_buf, msg_size);
9598
9600 "Created pending message %" PRIu64
9601 " for DV Box with next hop %s (%u/%u)\n",
9602 pm->logging_uuid,
9603 GNUNET_i2s (&next_hop->pid),
9604 (unsigned int) num_hops,
9605 (unsigned int) total_hops);
9606
9607 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
9608 {
9610 vl->pending_msg_head,
9611 vl->pending_msg_tail,
9612 pm);
9613
9615 }
9616 else
9617 {
9619 "The virtual link is not ready for forwarding a DV Box with payload, storing PendingMessage in ring buffer.\n");
9620
9622 {
9624
9625 GNUNET_free (pm_old);
9626 }
9629 {
9632 }
9633 else
9635
9637 "%u items stored in DV ring buffer\n",
9640 }
9641 }
9642}

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

9652{
9653 if (NULL != b->get)
9654 {
9656 b->get = NULL;
9657 GNUNET_assert (NULL != b->cmc);
9659 b->cmc = NULL;
9660 }
9661 if (NULL != b->task)
9662 {
9664 b->task = NULL;
9665 }
9666 if (NULL != b->sc)
9667 {
9669 "store cancel\n");
9671 b->sc = NULL;
9672 }
9674 "Removing backtalker for %s\n",
9675 GNUNET_i2s (&b->pid));
9677 GNUNET_YES ==
9679 GNUNET_free (b);
9680}

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

9695{
9696 struct Backtalker *b = value;
9697
9698 (void) cls;
9699 (void) pid;
9700 free_backtalker (b);
9701 return GNUNET_OK;
9702}

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

9712{
9713 struct Backtalker *b = cls;
9714
9716 "backtalker timeout.\n");
9717 b->task = NULL;
9719 {
9721 return;
9722 }
9723 /* A monotime store may well still be in flight -- @e timeout is about how
9724 long the *peer* has been quiet, and says nothing about PEERSTORE. This
9725 used to `GNUNET_assert (NULL == b->sc)', which aborted the service in
9726 exactly that case. #free_backtalker() cancels the store. */
9727 free_backtalker (b);
9728}

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

9743{
9744 struct Backtalker *b = cls;
9745 struct GNUNET_TIME_AbsoluteNBO *mtbe;
9746 struct GNUNET_TIME_Absolute mt;
9747
9748 (void) emsg;
9749 if (NULL == record)
9750 {
9751 struct CommunicatorMessageContext *cmc;
9752
9753 /* we're done with #backtalker_monotime_cb() invocations,
9754 continue normal processing */
9755 b->get = NULL;
9756 GNUNET_assert (NULL != b->cmc);
9757 /* Take @e cmc out of @a b *before* dispatching: the dispatch runs
9758 arbitrary message handling, and writing `b->cmc = NULL' afterwards
9759 is a write to freed memory should anything on that path have
9760 released @a b. #free_backtalker() keys its "must finish the parked
9761 cmc" decision off @e get, which is already NULL here, so clearing
9762 @e cmc early cannot lose the message either. */
9763 cmc = b->cmc;
9764 b->cmc = NULL;
9765 cmc->mh = (const struct GNUNET_MessageHeader *) &b[1];
9766 if (0 != b->body_size)
9768 else
9769 finish_cmc_handling (cmc);
9770 return;
9771 }
9772 if (sizeof(*mtbe) != record->value_size)
9773 {
9775 GNUNET_break (0);
9776 return;
9777 }
9778 mtbe = record->value;
9779 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
9780 if (mt.abs_value_us > b->monotonic_time.abs_value_us)
9781 {
9783 "Backtalker message from %s dropped, monotime in the past\n",
9784 GNUNET_i2s (&b->pid));
9786 GST_stats,
9787 "# Backchannel messages dropped: monotonic time not increasing",
9788 1,
9789 GNUNET_NO);
9790 b->monotonic_time = mt;
9791 /* Setting body_size to 0 prevents call to #forward_backchannel_payload()
9792 */
9793 b->body_size = 0;
9794 }
9796}

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

9808{
9809 struct Backtalker *b = cls;
9810
9811 if (GNUNET_OK != success)
9812 {
9814 "Failed to store backtalker's monotonic time in PEERSTORE!\n");
9815 }
9816 b->sc = NULL;
9817 /* @e task is armed for the whole life of @a b -- #backtalker_timeout_cb()
9818 re-arms itself whenever @e timeout has moved forward -- so there is
9819 nothing to do here beyond releasing the store. It used to cancel and
9820 re-add the task, which is what made the task's existence depend on this
9821 callback ever running. */
9822 GNUNET_assert (NULL != b->task);
9823}

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

9833{
9834 struct GNUNET_TIME_AbsoluteNBO mtbe;
9835
9836 /* At most one store may be outstanding. The value we are about to write
9837 supersedes whatever the previous one carried, and leaving the old
9838 context alive means its completion clears @e sc while the newer store
9839 is still in flight -- after which the next update sees a NULL @e sc and
9840 starts a third one. Cancelling is also what keeps @e sc from being
9841 silently overwritten and leaked.
9842
9843 Note what this must NOT do: touch @e task. That task is the only thing
9844 that ever releases a `struct CommunicatorMessageContext' parked in
9845 @e cmc, and cancelling it here left its re-arming up to
9846 #backtalker_monotime_store_cb() -- i.e. up to PEERSTORE answering. A
9847 lost store completion then stalled the parked communicator client for
9848 the life of the process. #backtalker_timeout_cb() already re-arms
9849 itself against the current @e timeout, so the task needs no help. */
9850 if (NULL != b->sc)
9851 {
9853 "Superseding in-flight backtalker monotime store %p\n",
9854 b->sc);
9856 b->sc = NULL;
9857 }
9859 b->sc =
9861 "transport",
9862 &b->pid,
9864 &mtbe,
9865 sizeof(mtbe),
9869 b);
9870}

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

9885{
9886 const unsigned char *hdr;
9887 size_t hdr_len;
9889
9890 key = (struct GNUNET_CRYPTO_AeadSecretKey*) km;
9891 /* We are the ultimate target, so #handle_dv_box() has established that no
9892 hop entries are left: the ciphertext directly follows the header, and
9893 its length is what we actually received. Deriving it from orig_size
9894 and total_hops instead would only be equivalent if every forwarder
9895 accounted its skipped hops exactly. */
9896 hdr = (const unsigned char *) &dvb[1];
9897 {
9898 uint16_t size = ntohs (dvb->header.size);
9899
9900 if (size < sizeof(*dvb)
9901 + sizeof(struct TransportDVBoxPayloadP)
9902 + sizeof(struct GNUNET_MessageHeader))
9903 {
9904 GNUNET_break_op (0);
9905 finish_cmc_handling (cmc);
9906 return;
9907 }
9908 hdr_len = size - sizeof(*dvb);
9909 }
9910
9911 /* begin actual decryption */
9912 {
9913 struct Backtalker *b;
9914 struct GNUNET_TIME_Absolute monotime;
9915 struct TransportDVBoxPayloadP *ppay;
9916 unsigned char pt[hdr_len + sizeof *ppay] GNUNET_ALIGN;
9917 unsigned char *body;
9918 const struct GNUNET_MessageHeader *mh;
9919
9920 ppay = (struct TransportDVBoxPayloadP *) pt;
9921 body = &pt[sizeof *ppay];
9922 GNUNET_assert (hdr_len >=
9923 sizeof(*ppay) + sizeof(struct GNUNET_MessageHeader));
9924 if (GNUNET_OK != GNUNET_CRYPTO_aead_decrypt (hdr_len,
9925 hdr,
9926 0,
9927 NULL,
9928 key,
9929 &dvb->iv,
9930 &dvb->mac,
9931 pt))
9932 {
9934 "Error decrypting DV payload header\n");
9935 GNUNET_break_op (0);
9936 finish_cmc_handling (cmc);
9937 return;
9938 }
9939 mh = (const struct GNUNET_MessageHeader *) body;
9940 /* NOTE: this used to compare against `sizeof (body)', i.e. the size of
9941 a pointer, which meant only 8-byte payloads were ever accepted. */
9942 if (ntohs (mh->size) != hdr_len - sizeof(*ppay))
9943 {
9944 GNUNET_break_op (0);
9945 finish_cmc_handling (cmc);
9946 return;
9947 }
9948 /* need to prevent box-in-a-box (and DV_LEARN) so check inbox type! */
9949 switch (ntohs (mh->type))
9950 {
9952 GNUNET_break_op (0);
9953 finish_cmc_handling (cmc);
9954 return;
9955
9957 GNUNET_break_op (0);
9958 finish_cmc_handling (cmc);
9959 return;
9960
9961 default:
9962 /* permitted, continue */
9963 break;
9964 }
9965 monotime = GNUNET_TIME_absolute_ntoh (ppay->monotonic_time);
9967 "Decrypted backtalk from %s\n",
9968 GNUNET_i2s (&ppay->sender));
9970 &ppay->sender);
9971 if ((NULL != b) && (monotime.abs_value_us < b->monotonic_time.abs_value_us))
9972 {
9974 GST_stats,
9975 "# Backchannel messages dropped: monotonic time not increasing",
9976 1,
9977 GNUNET_NO);
9978 finish_cmc_handling (cmc);
9979 return;
9980 }
9981 if ((NULL == b) ||
9982 (0 != GNUNET_memcmp (&b->last_ephemeral, &dvb->ephemeral_key)))
9983 {
9984 /* Check signature */
9985 const struct GNUNET_PeerIdentity *my_identity;
9986 struct EphemeralConfirmationPS ec;
9987
9990
9991 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
9992 ec.target = *my_identity;
9993 ec.ephemeral_key = dvb->ephemeral_key;
9994 ec.purpose.size = htonl (sizeof(ec));
9995 ec.sender_monotonic_time = ppay->monotonic_time;
9996 if (
9997 GNUNET_OK !=
10000 &ec,
10001 &ppay->sender_sig,
10002 &ppay->sender.public_key))
10003 {
10004 /* Signature invalid, discard! */
10005 GNUNET_break_op (0);
10006 finish_cmc_handling (cmc);
10007 return;
10008 }
10009 }
10010 /* Update sender, we now know the real origin! */
10012 "DVBox received for me from %s via %s\n",
10013 GNUNET_i2s2 (&ppay->sender),
10014 GNUNET_i2s (&cmc->im.sender));
10015 cmc->im.sender = ppay->sender;
10016
10017 if (NULL != b)
10018 {
10019 /* update key cache and mono time */
10020 b->last_ephemeral = dvb->ephemeral_key;
10021 b->monotonic_time = monotime;
10023 b->timeout =
10025 cmc->mh = mh;
10027 return;
10028 }
10029 /* setup data structure to cache signature AND check
10030 monotonic time with PEERSTORE before forwarding backchannel payload */
10031 b = GNUNET_malloc (sizeof(struct Backtalker) + (hdr_len - sizeof(*ppay)));
10032 b->pid = ppay->sender;
10033 b->body_size = hdr_len - sizeof(*ppay);
10034 memcpy (&b[1], body, hdr_len - sizeof(*ppay));
10038 &b->pid,
10039 b,
10041 b->monotonic_time = monotime; /* NOTE: to be checked still! */
10042 b->cmc = cmc;
10043 b->timeout =
10046 b->get =
10048 "transport",
10049 &b->pid,
10052 b);
10053 } /* end actual decryption */
10054}

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

10066{
10067 struct CommunicatorMessageContext *cmc = cls;
10068 uint16_t size = ntohs (dvb->header.size) - sizeof(*dvb);
10069 uint16_t num_hops = ntohs (dvb->num_hops);
10070 const struct GNUNET_PeerIdentity *hops =
10071 (const struct GNUNET_PeerIdentity *) &dvb[1];
10072 const char *enc_payload = (const char *) &hops[num_hops];
10073 uint16_t enc_payload_size =
10074 size - (num_hops * sizeof(struct GNUNET_PeerIdentity));
10075 const struct GNUNET_PeerIdentity *my_identity;
10076
10079
10080 if (GNUNET_EXTRA_LOGGING > 0)
10081 {
10082 char *path;
10083
10085 for (unsigned int i = 0; i < num_hops; i++)
10086 {
10087 char *tmp;
10088
10089 GNUNET_asprintf (&tmp, "%s->%s", path, GNUNET_i2s (&hops[i]));
10090 GNUNET_free (path);
10091 path = tmp;
10092 }
10094 "Received DVBox with remaining path %s\n",
10095 path);
10096 GNUNET_free (path);
10097 }
10098
10099 if (num_hops > 0)
10100 {
10101 /* We're trying from the end of the hops array, as we may be
10102 able to find a shortcut unknown to the origin that way */
10103 for (int i = num_hops - 1; i >= 0; i--)
10104 {
10105 struct Neighbour *n;
10106
10107 if (0 == GNUNET_memcmp (&hops[i], my_identity))
10108 {
10109 GNUNET_break_op (0);
10110 finish_cmc_handling (cmc);
10111 return;
10112 }
10113 n = lookup_neighbour (&hops[i]);
10114 if (NULL == n)
10115 continue;
10117 "Skipping %u/%u hops ahead while routing DV Box\n",
10118 i,
10119 num_hops);
10120
10121 forward_dv_box (n,
10122 (struct TransportDVBoxMessage *) dvb,
10123 /* we strip i+1 entries, and the receiver reconstructs
10124 the ciphertext offset from total_hops */
10125 ntohs (dvb->total_hops) + i + 1,
10126 num_hops - i - 1, /* number of hops left */
10127 &hops[i + 1], /* remaining hops */
10128 enc_payload,
10129 enc_payload_size);
10131 "# DV hops skipped routing boxes",
10132 i,
10133 GNUNET_NO);
10135 "# DV boxes routed (total)",
10136 1,
10137 GNUNET_NO);
10138 finish_cmc_handling (cmc);
10139 return;
10140 }
10141 /* Woopsie, next hop not in neighbours, drop! */
10143 "# DV Boxes dropped: next hop unknown",
10144 1,
10145 GNUNET_NO);
10146 finish_cmc_handling (cmc);
10147 return;
10148 }
10149 /* We are the target. Unbox and handle message. */
10151 "# DV boxes opened (ultimate target)",
10152 1,
10153 GNUNET_NO);
10154 cmc->total_hops = ntohs (dvb->total_hops);
10155
10156 {
10157 // DH key derivation with received DV, could be garbage.
10159 struct GNUNET_ShortHashCode km;
10160
10162 if ( (NULL == my_private_key) ||
10163 (GNUNET_OK !=
10165 &dvb->ephemeral_key,
10166 &km)) )
10167 {
10168 GNUNET_break_op (0);
10169 finish_cmc_handling (cmc);
10170 return;
10171 }
10172 decaps_dv_box_cont (cmc,
10173 dvb,
10174 &km);
10175 }
10176}

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

10189{
10190 struct TransportClient *tc = cls;
10191
10192 if (CT_COMMUNICATOR != tc->type)
10193 {
10194 GNUNET_break (0);
10195 return GNUNET_SYSERR;
10196 }
10198 return GNUNET_OK;
10199}

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

10232{
10233 struct CheckKnownAddressContext *ckac = cls;
10234 struct ValidationState *vs = value;
10235
10236 (void) pid;
10237 if (0 != strcmp (vs->address, ckac->address))
10238 return GNUNET_OK;
10239 ckac->vs = vs;
10240 return GNUNET_NO;
10241}

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

13682{
13683 struct ValidationState *vs;
13684 struct Queue *q;
13686 GST_cfg);
13687
13688 (void) cls;
13689 validation_task = NULL;
13691 /* drop validations past their expiration */
13692 while (
13693 (NULL != vs) &&
13695 {
13697 "Validation response %s cleaned up\n",
13698 GNUNET_sh2s (&vs->challenge.value));
13701 }
13702 if (NULL == vs)
13703 {
13705 "Address validation task not scheduled anymore, nothing to do\n");
13706 return; /* woopsie, no more addresses known, should only
13707 happen if we're really a lonely peer */
13708 }
13709 q = find_queue (&vs->pid, vs->address);
13710 if (GNUNET_TIME_absolute_cmp (vs->first_challenge_use, >, now))
13711 {
13713 "To early to start next address validation for challenge %s\n",
13714 GNUNET_sh2s (&vs->challenge.value));
13715 /* Do NOT just return: @e validation_task was set to NULL above and
13716 nothing re-arms it by itself. #update_next_challenge_time() only
13717 schedules us again when it is called with a *changed* time for some
13718 validation state, so bailing out here leaves a non-empty
13719 #validation_heap with no task attached: address (re)validation and
13720 the #suggest_to_connect() retries that go with it stop for *every*
13721 peer until some unrelated event happens to come along. A peer that
13722 just lost its only connection has no such events left. */
13725 now,
13726 vs->first_challenge_use),
13728 NULL);
13729 return;
13730 }
13731 if (NULL == q)
13732 {
13733 vs->awaiting_queue = GNUNET_YES;
13734 suggest_to_connect (&vs->pid, vs->address);
13735 }
13736 else
13738 /* Finally, reschedule next attempt */
13739 vs->challenge_backoff =
13740 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
13743 "Address validation task will run again in %s\n",
13744 GNUNET_STRINGS_relative_time_to_string (vs->challenge_backoff,
13745 GNUNET_YES));
13748 vs->challenge_backoff));
13749}

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, MAX_VALIDATION_CHALLENGE_FREQ, ValidationState::pid, q, GNUNET_TIME_Relative::rel_value_us, suggest_to_connect(), update_next_challenge_time(), ValidationState::valid_until, 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 10261 of file gnunet-service-transport.c.

10263{
10265
10266 /* NOTE: "be lazy" must not apply while #validation_task is unset. Our
10267 only caller that can leave it unset is #validation_start_cb(), which
10268 NULLs it on entry and relies on us to arm it again -- and nothing else
10269 ever does. Returning early there stops address (re)validation and the
10270 #suggest_to_connect() retries that go with it for *every* peer, for
10271 good. */
10272 if ((new_time.abs_value_us == vs->next_challenge.abs_value_us) &&
10273 (NULL != validation_task) &&
10274 (NULL != vs->hn))
10275 return; /* be lazy */
10276 vs->next_challenge = new_time;
10277 if (NULL == vs->hn)
10278 vs->hn =
10280 else
10283 (NULL != validation_task))
10284 return;
10285 if (NULL != validation_task)
10287 /* randomize a bit */
10290 new_time = GNUNET_TIME_absolute_add (new_time, delta);
10293}

References GNUNET_TIME_Absolute::abs_value_us, delta, GNUNET_CONTAINER_heap_insert(), GNUNET_CONTAINER_heap_peek(), GNUNET_CONTAINER_heap_update_cost(), GNUNET_CRYPTO_random_u64(), GNUNET_SCHEDULER_add_at(), GNUNET_SCHEDULER_cancel(), GNUNET_TIME_absolute_add(), MIN_DELAY_ADDRESS_VALIDATION, GNUNET_TIME_Relative::rel_value_us, validation_heap, validation_start_cb(), and validation_task.

Referenced by handle_validation_response(), revalidate_now_cb(), revalidation_start_cb(), start_address_validation(), and validation_start_cb().

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

◆ revalidate_now_cb()

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

Pull value's next challenge forward: the link to that peer is not up.

Touches only validation_heap, so it is safe to run while iterating validation_map.

Parameters
clsNULL
pidpeer the validation state belongs to
valuea struct ValidationState
Returns
GNUNET_OK (continue to iterate)

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

10310{
10311 struct ValidationState *vs = value;
10312 const struct GNUNET_TIME_Absolute now =
10314
10315 (void) cls;
10316 (void) pid;
10317 /* What #start_address_validation() does for an address it hears about
10318 again, but without needing the address string. */
10319 vs->challenge_backoff =
10322 vs->challenge_backoff,
10323 2));
10324 if (GNUNET_TIME_absolute_cmp (vs->first_challenge_use, >, now))
10325 vs->first_challenge_use = now;
10328 vs->challenge_backoff));
10329 return GNUNET_OK;
10330}

References FAST_VALIDATION_CHALLENGE_FREQ, GNUNET_OK, GNUNET_TIME_absolute_cmp, GNUNET_TIME_absolute_get_monotonic(), GNUNET_TIME_relative_divide(), GNUNET_TIME_relative_min(), GNUNET_TIME_relative_to_absolute(), GST_cfg, update_next_challenge_time(), and value.

Referenced by try_to_bring_link_up().

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

◆ find_queue()

static struct Queue * find_queue ( const struct GNUNET_PeerIdentity pid,
const char *  address 
)
static

Find the queue matching pid and address.

Parameters
pidpeer the queue must go to
addressaddress the queue must use
Returns
NULL if no such queue exists

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

10840{
10841 struct Neighbour *n;
10842
10843 n = lookup_neighbour (pid);
10844 if (NULL == n)
10845 return NULL;
10846 for (struct Queue *pos = n->queue_head; NULL != pos;
10847 pos = pos->next_neighbour)
10848 {
10849 if (0 == strcmp (pos->address, address))
10850 return pos;
10851 }
10852 return NULL;
10853}

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

13578{
13579 static uint32_t idgen = 0;
13580 struct TransportClient *tc;
13581 char *prefix;
13582 struct GNUNET_TRANSPORT_CreateQueue *cqm;
13583 struct GNUNET_MQ_Envelope *env;
13584 size_t alen;
13585
13587 if (NULL == prefix)
13588 {
13589 GNUNET_break (0); /* We got an invalid address!? */
13590 return;
13591 }
13593 if (NULL == tc)
13594 {
13596 "# Suggestions ignored due to missing communicator",
13597 1,
13598 GNUNET_NO);
13600 "Cannot connect to %s at `%s', no matching communicator present\n",
13601 GNUNET_i2s (pid),
13602 address);
13604 return;
13605 }
13606 /* forward suggestion for queue creation to communicator */
13608 "Request #%u for `%s' communicator to create queue to `%s' at `%s'\n",
13609 (unsigned int) idgen,
13610 prefix,
13611 GNUNET_i2s (pid),
13612 address);
13614 alen = strlen (address) + 1;
13615 env =
13617 cqm->request_id = htonl (idgen++);
13618 cqm->receiver = *pid;
13619 memcpy (&cqm[1], address, alen);
13620 GNUNET_MQ_send (tc->mq, env);
13621}

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

10437{
10438 struct Queue *q;
10439 int pfx_len;
10440 const char *eou;
10441 char *address;
10442 (void) cls;
10443
10444 eou = strstr (uri,
10445 "://");
10446 pfx_len = eou - uri;
10447 eou += 3;
10449 "%.*s-%s",
10450 pfx_len,
10451 uri,
10452 eou);
10453
10455 "helo for client %s\n",
10456 address);
10457 q = find_queue (pid, address);
10458 if (NULL == q)
10459 {
10461 }
10462 else
10465}

References address, find_queue(), GNUNET_asprintf(), 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 10491 of file gnunet-service-transport.c.

10492{
10493 const struct GNUNET_MessageHeader *hello;
10494
10495 if ((NULL == record) ||
10496 (NULL == record->value) ||
10497 (record->value_size < sizeof(*hello)))
10498 {
10499 GNUNET_break_op (0);
10500 return NULL;
10501 }
10502 hello = record->value;
10503 if (ntohs (hello->size) > record->value_size)
10504 {
10505 GNUNET_break_op (0);
10506 return NULL;
10507 }
10508 return hello;
10509}

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

10523{
10524 struct IncomingRequest *ir = cls;
10526 const struct GNUNET_MessageHeader *hello;
10527 const struct GNUNET_PeerIdentity *my_identity;
10528
10529 if (NULL != emsg)
10530 {
10532 "Got failure from PEERSTORE: %s\n",
10533 emsg);
10535 return;
10536 }
10537 if (NULL == record)
10538 {
10539 GNUNET_break (0);
10541 return;
10542 }
10543 hello = hello_from_record (record);
10544 if (NULL == hello)
10545 {
10546 /* MUST still ask for the next record: a bad one is not a reason to
10547 stall this monitor forever. */
10549 return;
10550 }
10552 if (NULL == my_identity)
10553 {
10555 return;
10556 }
10557 if (0 == GNUNET_memcmp (&record->peer, my_identity))
10558 {
10560 return;
10561 }
10562 parser = GNUNET_HELLO_parser_from_msg (hello, &record->peer);
10563 if (NULL != parser)
10564 {
10567 NULL);
10568 GNUNET_HELLO_parser_free (parser);
10569 }
10570 /* MUST ask for the next record, or this monitor stalls after one HELLO */
10572}

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

10577{
10579 "Error in PEERSTORE monitoring\n");
10580}

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

10585{
10587 "Done with initial PEERSTORE iteration during monitoring\n");
10588}

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

10659{
10660 struct VirtualLink *vl;
10661 struct Neighbour *n;
10662 struct GNUNET_PeerIdentity sender;
10663
10664 sender = cmc->im.sender;
10665 vl = lookup_virtual_link (&sender);
10666 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
10667 {
10668 // route_control_message_without_fc (&cmc->im.sender,
10670 &tvr.header,
10672 }
10673 else
10674 {
10675 /* Use route via neighbour */
10676 n = lookup_neighbour (&sender);
10677 if (NULL != n)
10678 route_via_neighbour (n, &tvr.header,
10681 }
10682
10683 finish_cmc_handling (cmc);
10684 /* An *unconfirmed* link is not a link -- it carries nothing, and CORE has
10685 never been told about the peer. Bailing out on one merely because it
10686 exists is what deadlocks a pair of peers into permanent one-way state:
10687 the challenger validated us, so it believes the connection is up and
10688 starts sending us FLOW_CONTROL; #handle_flow_control() answers an
10689 unknown sender by allocating exactly such an unconfirmed link; and from
10690 then on every challenge it retransmits lands here, gets a response --
10691 which keeps *its* side confirmed and its RTT healthy -- and returns
10692 without ever validating an address of its own. The unconfirmed link
10693 reaps itself after #UNCONFIRMED_LINK_TIMEOUT, but the next FLOW_CONTROL
10694 recreates it, and the peer keeps sending those precisely because it
10695 thinks it is connected. Nothing ever breaks the tie, so CORE on this
10696 side never hears about the peer and never answers its handshake.
10697 Only a confirmed link means there is nothing left to do. */
10698 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
10699 return;
10700
10701 /* For us, the link is still down, but we need bi-directional
10702 connections (for flow-control and for this to be useful for
10703 CORE), so we must try to bring the link up! */
10704 try_to_bring_link_up (&sender);
10705}

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

10720{
10721 struct CommunicatorMessageContext *cmc = cls;
10722 struct TransportValidationResponseMessage tvr = { 0 };
10723 struct GNUNET_TIME_RelativeNBO validity_duration;
10724
10725 /* DV-routed messages are not allowed for validation challenges */
10726 if (cmc->total_hops > 0)
10727 {
10728 GNUNET_break_op (0);
10729 finish_cmc_handling (cmc);
10730 return;
10731 }
10732 validity_duration = cmc->im.expected_address_validity;
10734 "Received address validation challenge %s\n",
10735 GNUNET_sh2s (&tvc->challenge.value));
10736 /* If we have a virtual link, we use this mechanism to signal the
10737 size of the flow control window, and to allow the sender
10738 to ask for increases. If for us the virtual link is still down,
10739 we will always give a window size of zero. */
10740 tvr.header.type =
10742 tvr.header.size = htons (sizeof(tvr));
10743 tvr.reserved = htonl (0);
10744 tvr.challenge = tvc->challenge;
10745 tvr.origin_time = tvc->sender_time;
10746 tvr.validity_duration = validity_duration;
10747 {
10748 /* create signature */
10749 struct TransportValidationPS tvp = {
10751 .purpose.size = htonl (sizeof(tvp)),
10752 .validity_duration = validity_duration,
10753 .challenge = tvc->challenge
10754 };
10755 if (GNUNET_OK != sign_by_my_identity (&tvp.purpose, &tvr.signature))
10756 {
10757 /* Not answering costs us this address validation; leaving @a cmc
10758 behind would cost us the communicator. */
10759 finish_cmc_handling (cmc);
10760 return;
10761 }
10762 }
10763 send_t_validation_response (cmc, tvr);
10764}

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

10797{
10798 struct CheckKnownChallengeContext *ckac = cls;
10799 struct ValidationState *vs = value;
10800
10801 (void) pid;
10802 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
10803 return GNUNET_OK;
10804 ckac->vs = vs;
10805 return GNUNET_NO;
10806}

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

10818{
10819 struct ValidationState *vs = cls;
10820
10821 vs->sc = NULL;
10822 if (GNUNET_YES == success)
10823 return;
10825 "# Peerstore failed to store foreign address",
10826 1,
10827 GNUNET_NO);
10828}

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

10873{
10874 struct Neighbour *n;
10875 struct Queue *ret = NULL;
10876 char *prefix;
10877 char *ip;
10878
10879 n = lookup_neighbour (pid);
10880 if (NULL == n)
10881 return NULL;
10884 if ((NULL == prefix) || (NULL == ip))
10885 {
10887 GNUNET_free (ip);
10888 return NULL;
10889 }
10890 for (struct Queue *pos = n->queue_head; NULL != pos;
10891 pos = pos->next_neighbour)
10892 {
10893 char *q_prefix = GNUNET_HELLO_address_to_prefix (pos->address);
10894 char *q_ip = get_address_without_port (pos->address);
10895
10896 /* Same communicator and same host -- only the port may differ. */
10897 if ((NULL != q_prefix) && (NULL != q_ip) &&
10898 (0 == strcmp (q_prefix, prefix)) &&
10899 (0 == strcmp (q_ip, ip)))
10900 ret = pos;
10901 GNUNET_free (q_prefix);
10902 GNUNET_free (q_ip);
10903 if (NULL != ret)
10904 break;
10905 }
10907 GNUNET_free (ip);
10908 return ret;
10909}

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

13633{
13635 struct GNUNET_TIME_Absolute monotonic_time;
13636
13637 if (NULL != vs->revalidation_task)
13638 {
13639 GNUNET_SCHEDULER_cancel (vs->revalidation_task);
13640 vs->revalidation_task = NULL;
13641 }
13642 /*memcpy (&hkey,
13643 &hc,
13644 sizeof (hkey));*/
13646 "Remove key %s for address %s map size %u contains %u\n",
13647 GNUNET_h2s (&vs->hc),
13648 vs->address,
13651 &vs->hc));
13653
13655 if (GNUNET_TIME_UNIT_ZERO_ABS.abs_value_us ==
13656 vs->last_challenge_use.abs_value_us)
13657 {
13658 vs->first_challenge_use = monotonic_time;
13659 }
13660 vs->last_challenge_use = monotonic_time;
13661 tvc.header.type =
13663 tvc.header.size = htons (sizeof(tvc));
13664 tvc.reserved = htonl (0);
13665 tvc.challenge = vs->challenge;
13666 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
13668 "Sending address validation challenge %s to %s\n",
13669 GNUNET_sh2s (&tvc.challenge.value),
13670 GNUNET_i2s (&q->neighbour->pid));
13671 queue_send_msg (q, NULL, &tvc, sizeof(tvc));
13672}

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

10917{
10918 struct ValidationState *vs = cls;
10919 struct Queue *q;
10920 struct GNUNET_TIME_Absolute now;
10921
10922 vs->revalidation_task = NULL;
10923 q = find_queue (&vs->pid, vs->address);
10924 if (NULL == q)
10925 {
10926 now = GNUNET_TIME_absolute_get ();
10927 vs->awaiting_queue = GNUNET_YES;
10928 suggest_to_connect (&vs->pid, vs->address);
10930 }
10931 else
10933}

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

10941{
10942 (void) cls;
10944 "Key in revalidate map %s \n",
10945 GNUNET_h2s (key));
10946 return GNUNET_YES;
10947}

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

10962{
10963 struct CommunicatorMessageContext *cmc = cls;
10964 struct ValidationState *vs;
10965 struct CheckKnownChallengeContext ckac = { .challenge = &tvr->challenge,
10966 .vs = NULL};
10967 struct GNUNET_TIME_Absolute origin_time;
10968 struct Queue *q;
10969 struct Neighbour *n;
10970 struct VirtualLink *vl;
10972 GST_cfg);
10973
10974 /* check this is one of our challenges */
10976 &cmc->im.sender,
10978 &ckac);
10979 if (NULL == (vs = ckac.vs))
10980 {
10981 /* This can happen simply if we 'forgot' the challenge by now,
10982 i.e. because we received the validation response twice */
10984 "# Validations dropped, challenge unknown",
10985 1,
10986 GNUNET_NO);
10988 "Validation response %s dropped, challenge unknown\n",
10989 GNUNET_sh2s (&tvr->challenge.value));
10990 finish_cmc_handling (cmc);
10991 return;
10992 }
10993
10994 /* sanity check on origin time */
10995 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
10996 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
10997 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
10998 {
11000 "Diff first use %" PRIu64 " and last use %" PRIu64 "\n",
11001 vs->first_challenge_use.abs_value_us - origin_time.abs_value_us,
11002 origin_time.abs_value_us - vs->last_challenge_use.abs_value_us);
11003 GNUNET_break_op (0);
11004 finish_cmc_handling (cmc);
11005 return;
11006 }
11007
11008 {
11009 /* check signature */
11010 struct TransportValidationPS tvp = {
11012 .purpose.size = htonl (sizeof(tvp)),
11013 .validity_duration = tvr->validity_duration,
11014 .challenge = tvr->challenge
11015 };
11016
11017 if (
11018 GNUNET_OK !=
11020 &tvp,
11021 &tvr->signature,
11022 &cmc->im.sender.public_key))
11023 {
11024 GNUNET_break_op (0);
11025 finish_cmc_handling (cmc);
11026 return;
11027 }
11028 }
11029
11030 /* validity is capped by our willingness to keep track of the
11031 validation entry and the maximum the other peer allows */
11034 tvr->validity_duration),
11036 vs->validated_until =
11040 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
11041 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
11042 GNUNET_CRYPTO_random_block (&vs->challenge,
11043 sizeof(vs->challenge));
11044 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
11045 vs->validated_until,
11046 GNUNET_TIME_relative_multiply (vs->validation_rtt,
11048 if (GNUNET_TIME_absolute_cmp (vs->first_challenge_use, <, now))
11049 {
11051 "First challenge use is now %" PRIu64 " %s \n",
11052 vs->first_challenge_use.abs_value_us,
11053 GNUNET_sh2s (&vs->challenge.value));
11054 vs->first_challenge_use = now;
11055 }
11056 else
11058 "First challenge use is later %" PRIu64 " %s \n",
11059 vs->first_challenge_use.abs_value_us,
11060 GNUNET_sh2s (&vs->challenge.value));
11061 vs->last_challenge_use =
11062 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
11063 update_next_challenge_time (vs, vs->first_challenge_use);
11065 "Validation response %s from %s accepted, address valid until %s\n",
11066 GNUNET_sh2s (&tvr->challenge.value),
11067 GNUNET_i2s (&cmc->im.sender),
11069 /*memcpy (&hkey,
11070 &hc,
11071 sizeof (hkey));*/
11073 "Key %s for address %s map size %u contains %u\n",
11074 GNUNET_h2s (&vs->hc),
11075 vs->address,
11078 &vs->hc));
11079 /* NOTE: @e hc hashes the address only, so two `struct ValidationState's
11080 for different peers can collide here. That must not abort us. */
11081 if (GNUNET_YES !=
11084 &vs->hc,
11085 vs,
11088 "Address `%s' already tracked for revalidation\n",
11089 vs->address);
11092 NULL);
11093 vs->revalidation_task =
11098 "transport",
11099 &cmc->im.sender,
11101 vs->address,
11102 strlen (vs->address) + 1,
11103 vs->valid_until,
11106 vs);
11107 finish_cmc_handling (cmc);
11108
11109 /* Finally, we now possibly have a confirmed (!) working queue,
11110 update queue status (if queue still is around) */
11111 q = find_queue (&vs->pid, vs->address);
11112 if (NULL == q)
11113 {
11114 /* The challenge may have gone out on a queue whose address is not
11115 literally @e address: #check_validation_request_pending() matches on
11116 the IP alone, precisely so that a validation waiting for the NAT
11117 address `PROTO-IP:0' can be answered over the queue that the peer
11118 actually established from `PROTO-IP:port'. Insisting on an exact
11119 match here would silently discard that (successful!) validation and
11120 never bring the virtual link up. */
11121 q = find_queue_by_ip (&vs->pid, vs->address);
11122 }
11123 if (NULL == q)
11124 {
11126 "# Queues lost at time of successful validation",
11127 1,
11128 GNUNET_NO);
11129 return;
11130 }
11131 q->validated_until = vs->validated_until;
11132 q->pd.aged_rtt = vs->validation_rtt;
11133 n = q->neighbour;
11134 vl = lookup_virtual_link (&vs->pid);
11135 if (NULL == vl)
11136 {
11137 vl = GNUNET_new (struct VirtualLink);
11139 "Creating new virtual link %p to %s using direct neighbour!\n",
11140 vl,
11141 GNUNET_i2s (&vs->pid));
11142 vl->burst_addr = NULL;
11143 vl->confirmed = GNUNET_YES;
11144 vl->message_uuid_ctr =
11145 GNUNET_CRYPTO_random_u64 (UINT64_MAX);
11146 vl->target = n->pid;
11152 links,
11153 &vl->target,
11154 vl,
11156 vl->n = n;
11157 n->vl = vl;
11158 q->idle = GNUNET_YES;
11159 vl->visibility_task =
11160 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
11162 /* We lacked a confirmed connection to the target
11163 before, so tell CORE about it (finally!) */
11166 }
11167 else
11168 {
11169 /* Link was already up, remember n is also now available and we are done */
11170 if (NULL == vl->n)
11171 {
11172 vl->n = n;
11173 n->vl = vl;
11174 if (GNUNET_YES == vl->confirmed)
11176 "Virtual link to %s could now also use direct neighbour!\n",
11177 GNUNET_i2s (&vs->pid));
11178 }
11179 else
11180 {
11181 GNUNET_assert (n == vl->n);
11182 }
11183 if (GNUNET_NO == vl->confirmed)
11184 {
11185 vl->confirmed = GNUNET_YES;
11186 q->idle = GNUNET_YES;
11187 vl->visibility_task =
11188 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
11190 /* We lacked a confirmed connection to the target
11191 before, so tell CORE about it (finally!) */
11194 }
11195 }
11196}

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

11207{
11208 struct TransportClient *tc = cls;
11209 struct Neighbour *n;
11210 struct CommunicatorMessageContext *cmc =
11212
11213 cmc->tc = tc;
11214 cmc->im = *im;
11216 "Received message with size %u and flow control id %" PRIu64
11217 " via communicator from peer %s\n",
11218 ntohs (im->header.size),
11219 im->fc_id,
11220 GNUNET_i2s (&im->sender));
11221 cmc->im.neighbour_sender = cmc->im.sender;
11222 /* A communicator got this straight from @a im->sender, so the queues to
11223 that neighbour demonstrably still work. This is what #check_link_down()
11224 uses to bound how long a communicator that stopped working (without
11225 telling us) can keep a virtual link -- and CORE -- fooled. */
11226 if (NULL != (n = lookup_neighbour (&im->sender)))
11228 cmc->mh = (const struct GNUNET_MessageHeader *) &im[1];
11230}

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

11243{
11244 unsigned int number_of_addresses = ntohl (fc->number_of_addresses);
11245 uint16_t msize = ntohs (fc->header.size);
11246 const char *tgnas;
11247 size_t avail;
11248 size_t off;
11249
11250 (void) cls;
11252 "Flow control header size %u size of addresses %u number of addresses %u size of message struct %lu second struct %lu\n",
11253 ntohs (fc->header.size),
11254 ntohl (fc->size_of_addresses),
11255 ntohl (fc->number_of_addresses),
11256 sizeof(struct TransportFlowControlMessage),
11257 sizeof (struct TransportGlobalNattedAddress));
11258 if (0 == number_of_addresses)
11259 return GNUNET_OK;
11260 if (msize < sizeof(struct TransportFlowControlMessage))
11261 {
11262 GNUNET_break_op (0);
11263 return GNUNET_SYSERR;
11264 }
11265 avail = msize - sizeof(struct TransportFlowControlMessage);
11266 tgnas = (const char *) &fc[1];
11267 off = 0;
11268 /* Validate EVERY entry: checking only the aggregate size lets a single
11269 entry claim a bogus address_length and send #handle_flow_control()
11270 out of bounds. */
11271 for (unsigned int i = 0; i < number_of_addresses; i++)
11272 {
11273 const struct TransportGlobalNattedAddress *tgna;
11274 size_t alen;
11275
11276 if (avail - off < sizeof(struct TransportGlobalNattedAddress))
11277 {
11278 GNUNET_break_op (0);
11279 return GNUNET_SYSERR;
11280 }
11281 tgna = (const struct TransportGlobalNattedAddress *) &tgnas[off];
11282 off += sizeof(struct TransportGlobalNattedAddress);
11283 alen = ntohl (tgna->address_length);
11284 if (avail - off < alen)
11285 {
11286 GNUNET_break_op (0);
11287 return GNUNET_SYSERR;
11288 }
11289 off += alen;
11290 }
11291 return GNUNET_OK;
11292}

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

11326{
11327 struct VirtualLink *vl = cls;
11328 const char *slash;
11329 char *address_uri;
11330 char *prefix;
11331 char *uri_without_port;
11332
11333 slash = strrchr (uri, '/');
11334 if ((NULL == slash) || (slash - uri < 2))
11335 {
11336 GNUNET_break_op (0); /* @a uri comes from a remote HELLO */
11337 return;
11338 }
11339 prefix = GNUNET_strndup (uri, (slash - uri) - 2);
11340 slash++;
11341 GNUNET_asprintf (&address_uri,
11342 "%s-%s",
11343 prefix,
11344 slash);
11345
11346 uri_without_port = get_address_without_port (address_uri);
11348 "iterate_address_start_burst %s %s %s %s\n",
11349 (NULL == uri_without_port) ? "<unparsable>" : uri_without_port,
11350 uri,
11351 address_uri,
11352 slash);
11353 GNUNET_free (vl->burst_addr);
11354 if ((NULL != uri_without_port) &&
11355 (0 == strcmp (uri_without_port, slash)))
11356 vl->burst_addr = GNUNET_strdup (uri_without_port);
11357
11359 GNUNET_free (address_uri);
11360 GNUNET_free (uri_without_port);
11361}

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

11368{
11369 struct GNUNET_StartBurstCls *sb_cls = cls;
11370 struct VirtualLink *vl = sb_cls->vl;
11371 const struct GNUNET_MessageHeader *hello;
11373
11374 if (NULL != emsg)
11375 {
11377 "Got failure from PEERSTORE: %s\n",
11378 emsg);
11379 /* @a emsg comes with a NULL record, which means the iteration is over
11380 and PEERSTORE is releasing the context itself -- stopping it here as
11381 well would free it twice. Just drop our handle. */
11382 vl->ic = NULL;
11383 free_burst_cls (sb_cls);
11384 return;
11385 }
11386 if (NULL == record)
11387 {
11389 "Hello iteration end for %s\n",
11390 GNUNET_i2s (&vl->target));
11391 /* PEERSTORE destroys the context itself once it signals the end. */
11392 vl->ic = NULL;
11393 free_burst_cls (sb_cls);
11394 return;
11395 }
11396
11398 "check_for_burst_address\n");
11399 /* @a hello was published by a remote peer, it may well be malformed. */
11400 hello = hello_from_record (record);
11401 if (NULL != hello)
11402 {
11403 parser = GNUNET_HELLO_parser_from_msg (hello, &record->peer);
11404 if (NULL != parser)
11405 {
11408 vl);
11409 GNUNET_HELLO_parser_free (parser);
11410 }
11411 }
11412
11413 /* MUST clear @e ic: #GNUNET_PEERSTORE_iteration_stop() frees it, and
11414 #free_virtual_link() would otherwise stop it a second time. */
11415 if (NULL != vl->ic)
11416 {
11418 vl->ic = NULL;
11419 }
11420 free_burst_cls (sb_cls);
11421}

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

11426{
11428}

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

11433{
11434 struct GNUNET_StartBurstCls *sb_cls = cls;
11435 struct VirtualLink *vl = sb_cls->vl;
11436 struct GNUNET_TRANSPORT_StartBurst *sb;
11437 struct GNUNET_MQ_Envelope *env;
11438 char *uri_without_port = vl->burst_addr;
11439
11440 burst_task = NULL;
11441 burst_task_cls = NULL;
11442 if (NULL == uri_without_port)
11443 {
11444 /* Lost the address in the meantime, nothing to burst to. */
11445 free_burst_cls (sb_cls);
11446 return;
11447 }
11448 /*char buf[strlen (uri_without_port) + 1];
11449
11450 GNUNET_memcpy (buf, uri_without_port, strlen (uri_without_port));
11451 buf[strlen (uri_without_port)] = '\0';*/
11452 env =
11454 strlen (uri_without_port) + 1,
11456 sb->rtt = GNUNET_TIME_relative_hton (sb_cls->rtt);
11457 sb->pid = vl->target;
11458 memcpy (&sb[1], uri_without_port, strlen (uri_without_port) + 1);
11459 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
11460 {
11461 if (CT_COMMUNICATOR != tc->type)
11462 continue; /* MUST come first: the log below reads the union! */
11464 "iterate_address_start_burst client tc prefix %s\n",
11465 tc->details.communicator.address_prefix);
11466 if (GNUNET_YES == tc->details.communicator.can_burst)
11467 {
11469 "iterate_address_start_burst %s call %lu %u rtt %lu\n",
11470 uri_without_port,
11471 strlen (uri_without_port),
11472 ntohs (sb->header.size),
11473 (unsigned long) sb_cls->rtt.rel_value_us);
11474 GNUNET_MQ_send (tc->mq, env);
11475 env = NULL; /* MQ took ownership */
11479 60),
11481 NULL);
11482 // TODO We need some algo to choose from available communicators. Can we run two bursts at once? Atm we only implemented udp burst.
11483 break;
11484 }
11485 }
11486 if (NULL != env)
11488 free_burst_cls (sb_cls);
11489}

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

11520{
11521 struct GNUNET_StartBurstCls *sb_cls = cls;
11522 struct VirtualLink *vl = sb_cls->vl;
11523
11524 if (GNUNET_YES != use_burst)
11525 {
11526 /* MUST release: nobody else owns @a sb_cls, and #handle_flow_control()
11527 allocates one for every FLOW_CONTROL message we receive. */
11529 return;
11530 }
11532 "burst_task %p ready %s burst addr %s (%p)\n",
11533 burst_task,
11534 sb_cls->sync_ready ? "yes" : "no",
11535 vl->burst_addr,
11536 vl->burst_addr);
11537 if (NULL != burst_task && GNUNET_NO == sb_cls->sync_ready)
11538 {
11539 /* Cancel the pending burst. Both closures (the scheduled task's and
11540 ours) are ours to release. */
11542
11544 burst_task = NULL;
11545 burst_task_cls = NULL;
11546 if ((NULL != pending) && (pending != sb_cls))
11548 free_burst_cls (sb_cls);
11549 return;
11550 }
11551 if (GNUNET_NO == burst_running && NULL != vl->burst_addr && NULL == burst_task
11552 )
11553 {
11555 &start_burst,
11556 sb_cls);
11557 burst_task_cls = sb_cls;
11558 }
11559 else if (NULL == vl->burst_addr)
11560 {
11561 if (NULL != vl->ic)
11562 {
11563 /* An address lookup is already running for this link; starting a
11564 second one would leak the first. */
11565 free_burst_cls (sb_cls);
11566 return;
11567 }
11569 "peerstore",
11570 &vl->target,
11573 sb_cls);
11574 }
11575 else
11576 {
11577 /* A burst is already running or already scheduled; we have no use for
11578 this closure. */
11579 free_burst_cls (sb_cls);
11580 }
11581}

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

11592{
11593 struct VirtualLink *vl = cls;
11594
11595 vl->unconfirmed_timeout_task = NULL;
11596 if ((GNUNET_YES == vl->confirmed) ||
11597 (NULL != vl->n) ||
11598 (NULL != vl->dv))
11599 return; /* got promoted in the meantime, its owner will clean up */
11601 "Discarding unconfirmed virtual link to %s\n",
11602 GNUNET_i2s (&vl->target));
11604 "# Unconfirmed virtual links timed out",
11605 1,
11606 GNUNET_NO);
11607 free_virtual_link (vl);
11608}

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

11621{
11622 struct CommunicatorMessageContext *cmc = cls;
11623 struct VirtualLink *vl;
11625 uint32_t seq;
11626 struct GNUNET_TIME_Absolute st;
11627 uint64_t os;
11628 uint64_t wnd;
11629 uint32_t random;
11630
11632 "Received FC from %s\n", GNUNET_i2s (&cmc->im.sender));
11633 vl = lookup_virtual_link (&cmc->im.sender);
11634 if (NULL == vl)
11635 {
11636 vl = GNUNET_new (struct VirtualLink);
11638 "No virtual link for %p FC creating new unconfirmed virtual link to %s!\n",
11639 vl,
11640 GNUNET_i2s (&cmc->im.sender));
11641 vl->burst_addr = NULL;
11642 vl->confirmed = GNUNET_NO;
11643 vl->message_uuid_ctr =
11644 GNUNET_CRYPTO_random_u64 (UINT64_MAX);
11645 vl->target = cmc->im.sender;
11651 links,
11652 &vl->target,
11653 vl,
11655 /* Nothing else owns this link yet, so it must reap itself if it never
11656 becomes confirmed -- otherwise any peer can make us allocate
11657 VirtualLinks without bound. */
11661 vl);
11662 }
11663 if (GNUNET_YES != vl->confirmed)
11664 {
11665 /* The peer flow-controls us, so it has a confirmed link to us -- but an
11666 unconfirmed link carries nothing and is never reported to CORE. Only
11667 #handle_validation_response() breaks that tie, and nothing here used
11668 to ask for one, so the pair could sit one-way until the peer's own
11669 four hour revalidation came round. */
11671 }
11672 if (NULL != vl->n)
11673 {
11674 for (struct Queue *q = vl->n->queue_head; NULL != q; q = q->next_neighbour)
11675 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
11676 }
11677
11679 "remaining %lu timeout for neighbour %p\n",
11680 (unsigned long) GNUNET_TIME_absolute_get_remaining (q_timeout).
11681 rel_value_us,
11682 vl->n);
11683 if (NULL == vl->n ||
11684 0 == GNUNET_TIME_absolute_get_remaining (q_timeout).rel_value_us)
11685 {
11686 struct GNUNET_TIME_Relative rtt;
11687 struct GNUNET_BurstSync burst_sync;
11688 struct GNUNET_StartBurstCls *bcls;
11689
11690 if (NULL != vl->sb_cls)
11691 {
11692 /* A burst attempt for this link is already in flight. Allocating a
11693 second closure would orphan the first one: @e sb_cls is how
11694 #free_virtual_link() finds (and cancels) the pending #burst_task,
11695 and a peer that just keeps sending us FLOW_CONTROL messages would
11696 otherwise make us leak one closure per message. */
11698 "Burst attempt to %s already pending\n",
11699 GNUNET_i2s (&vl->target));
11700 }
11701 else
11702 {
11703 bcls = GNUNET_new (struct GNUNET_StartBurstCls);
11704 bcls->vl = vl;
11705 vl->sb_cls = bcls;
11706 if (NULL != vl->dv)
11707 rtt = calculate_rtt (vl->dv);
11708 else
11710 burst_sync.rtt_average = fc->rtt;
11711 bcls->rtt = GNUNET_TIME_relative_ntoh (burst_sync.rtt_average);
11712 /* @e sync_ready of `struct GNUNET_BurstSync' is a host-order enum. */
11713 burst_sync.sync_ready =
11714 (enum GNUNET_GenericReturnValue) ntohl (fc->sync_ready);
11715
11716 /* NOTE: #GNUNET_is_burst_ready() does NOT invoke the task unless both
11717 RTT estimates are known and close; #queue_burst() is thus not
11718 guaranteed to run, which is why @e sb_cls stays owned by @a vl. */
11720 &burst_sync,
11721 &queue_burst,
11722 bcls);
11723 }
11724 }
11725 if (0 != ntohl (fc->number_of_addresses))
11726 {
11727 unsigned int number_of_addresses = ntohl (fc->number_of_addresses);
11728 const char *tgnas;
11729 unsigned int off = 0;
11730
11731 tgnas = (const char *) &fc[1];
11732
11733 for (unsigned int i = 0; i < number_of_addresses; i++)
11734 {
11735 struct TransportGlobalNattedAddress *tgna;
11736 char *addr;
11737 uint32_t address_length;
11738
11739 tgna = (struct TransportGlobalNattedAddress*) &tgnas[off];
11740 addr = (char *) &tgna[1];
11741 address_length = ntohl (tgna->address_length);
11742 off += sizeof(struct TransportGlobalNattedAddress) + address_length;
11743
11744 /* NOTE: the address is NOT 0-terminated (it comes straight off the
11745 wire), it must be printed with an explicit precision. */
11747 "received address %.*s length %u\n",
11748 (int) address_length,
11749 addr,
11751
11752 if (NULL != nh)
11753 GNUNET_NAT_add_global_address (nh, addr, ntohl (tgna->address_length));
11754 }
11755 }
11757 if (st.abs_value_us < vl->last_fc_timestamp.abs_value_us)
11758 {
11760 "FC dropped: Message out of order\n");
11761 /* out of order, drop */
11763 "# FC dropped: message out of order",
11764 1,
11765 GNUNET_NO);
11766 finish_cmc_handling (cmc);
11767 return;
11768 }
11769 seq = ntohl (fc->seq);
11770 if (seq < vl->last_fc_seq)
11771 {
11772 /* Wrap-around/reset of other peer; start all counters from zero */
11774 }
11775 vl->last_fc_seq = seq;
11776 vl->last_fc_timestamp = st;
11778 os = GNUNET_ntohll (fc->outbound_sent);
11780 (int64_t) (os - vl->incoming_fc_window_size_used);
11782 "Received FC from %s, seq %u, new window %llu (loss at %lld)\n",
11783 GNUNET_i2s (&vl->target),
11784 (unsigned int) seq,
11785 (unsigned long long) vl->outbound_fc_window_size,
11786 (long long) vl->incoming_fc_window_size_loss);
11788 random = GNUNET_CRYPTO_random_u32 (UINT32_MAX);
11789 if ((GNUNET_YES == vl->confirmed) && ((wnd < vl->incoming_fc_window_size
11793 != wnd) ||
11794 (0 == random
11796 {
11798 "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",
11799 (unsigned long long) wnd,
11800 (unsigned long long) vl->incoming_fc_window_size,
11801 (unsigned long long) vl->last_outbound_window_size_received,
11804 }
11805 if ((GNUNET_YES == vl->confirmed) &&
11806 (wnd == vl->incoming_fc_window_size
11810 {
11812 "Slowing FC transmission to %s to keepalive rate: peer is current at window %llu\n",
11813 GNUNET_i2s (&vl->target),
11814 (unsigned long long) wnd);
11815 /* NOTE: this used to also require @e fc_retransmit_task to be non-NULL
11816 and did nothing at all otherwise -- so a link whose chain had ended
11817 (see #consider_sending_fc()) could never pick the keepalive back up,
11818 even though the peer was demonstrably still talking to us. */
11819 if (NULL != vl->fc_retransmit_task)
11821 vl->fc_retransmit_count = 0;
11822 /* Drop to the keepalive rate rather than stopping outright. There is
11823 nothing left to retransmit -- but if we go completely quiet, and the
11824 peer does the same for the same reason, then neither end sees any
11825 traffic and #check_link_down() tears down a perfectly healthy link
11826 after #NEIGHBOUR_LIVENESS_TIMEOUT. One tiny FC message every
11827 #FC_KEEPALIVE_INTERVAL is what keeps @e last_inbound moving on the
11828 other side (and, via their reply, on ours). */
11829 vl->fc_retransmit_task =
11832 vl);
11833 }
11835 /* FC window likely increased, check transmission possibilities! */
11837 finish_cmc_handling (cmc);
11838}

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

11950{
11951 struct TransportClient *tc = cls;
11952
11953 if (CT_COMMUNICATOR != tc->type)
11954 {
11955 GNUNET_break (0);
11956 return GNUNET_SYSERR;
11957 }
11959 return GNUNET_OK;
11960}

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

11970{
11971 if (pm->msg_uuid_set)
11972 return;
11973 pm->msg_uuid.uuid = pm->vl->message_uuid_ctr++;
11975}

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

11990{
11991 struct PendingAcknowledgement *pa;
11992
11993 pa = GNUNET_new (struct PendingAcknowledgement);
11994 pa->queue = queue;
11995 pa->dvh = dvh;
11996 pa->pm = pm;
11997 do
11998 {
12000 sizeof(pa->ack_uuid));
12001 }
12004 &pa->ack_uuid.value,
12005 pa,
12007 GNUNET_CONTAINER_MDLL_insert (queue, queue->pa_head, queue->pa_tail, pa);
12009 if (NULL != dvh)
12012 pa->message_size = pm->bytes_msg;
12014 "Waiting for ACKnowledgment `%s' for <%" PRIu64 ">\n",
12016 pm->logging_uuid);
12017 return pa;
12018}

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

12036{
12037 struct PendingAcknowledgement *pa;
12038 struct PendingMessage *ff;
12039 uint16_t mtu;
12040 uint16_t msize;
12041
12042 mtu = (UINT16_MAX == queue->mtu)
12043 ? UINT16_MAX - sizeof(struct GNUNET_TRANSPORT_SendMessageTo)
12044 : queue->mtu;
12046 "Fragmenting message <%" PRIu64
12047 "> with size %u to %s for MTU %u\n",
12048 pm->logging_uuid,
12049 pm->bytes_msg,
12050 GNUNET_i2s (&pm->vl->target),
12051 (unsigned int) mtu);
12054 "Fragmenting message %" PRIu64 " <%" PRIu64
12055 "> with size %u to %s for MTU %u\n",
12056 pm->msg_uuid.uuid,
12057 pm->logging_uuid,
12058 pm->bytes_msg,
12059 GNUNET_i2s (&pm->vl->target),
12060 (unsigned int) mtu);
12061
12062 /* This invariant is established in #handle_add_queue_message() */
12063 GNUNET_assert (mtu > sizeof(struct TransportFragmentBoxMessage));
12064
12065 /* select fragment for transmission, descending the tree if it has
12066 been expanded until we are at a leaf or at a fragment that is small
12067 enough
12068 */
12069 ff = pm;
12070 msize = ff->bytes_msg;
12071
12072 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
12073 (ff->frag_off == msize) && (NULL != ff->head_frag))
12074 {
12075 ff = ff->head_frag; /* descent into fragmented fragments */
12076 msize = ff->bytes_msg - sizeof(struct TransportFragmentBoxMessage);
12077 }
12078
12079 if (((ff->bytes_msg > mtu) || (pm == ff)) && (ff->frag_off < msize))
12080 {
12081 /* Did not yet calculate all fragments, calculate next fragment */
12082 struct PendingMessage *frag;
12083 struct TransportFragmentBoxMessage tfb;
12084 const char *orig;
12085 char *msg;
12086 uint16_t fragmax;
12087 uint16_t fragsize;
12088 uint16_t msize_ff;
12089 uint16_t xoff = 0;
12090 pm->frag_count++;
12091
12092 orig = (const char *) &ff[1];
12093 msize_ff = ff->bytes_msg;
12094 if (pm != ff)
12095 {
12096 const struct TransportFragmentBoxMessage *tfbo;
12097
12098 tfbo = (const struct TransportFragmentBoxMessage *) orig;
12099 orig += sizeof(struct TransportFragmentBoxMessage);
12100 msize_ff -= sizeof(struct TransportFragmentBoxMessage);
12101 xoff = ntohs (tfbo->frag_off);
12102 }
12103 fragmax = mtu - sizeof(struct TransportFragmentBoxMessage);
12104 fragsize = GNUNET_MIN (msize_ff - ff->frag_off, fragmax);
12105 frag =
12106 GNUNET_malloc (sizeof(struct PendingMessage)
12107 + sizeof(struct TransportFragmentBoxMessage) + fragsize);
12109 "3 created pm %p from pm %p storing vl %p from pm %p\n",
12110 frag,
12111 ff,
12112 pm->vl,
12113 pm);
12115 frag->vl = pm->vl;
12116 frag->frag_parent = ff;
12117 frag->timeout = pm->timeout;
12118 frag->bytes_msg = sizeof(struct TransportFragmentBoxMessage) + fragsize;
12119 frag->pmt = PMT_FRAGMENT_BOX;
12120 msg = (char *) &frag[1];
12121 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
12122 tfb.header.size =
12123 htons (sizeof(struct TransportFragmentBoxMessage) + fragsize);
12124 pa = prepare_pending_acknowledgement (queue, dvh, frag);
12125 tfb.ack_uuid = pa->ack_uuid;
12126 tfb.msg_uuid = pm->msg_uuid;
12127 tfb.frag_off = htons (ff->frag_off + xoff);
12128 tfb.msg_size = htons (pm->bytes_msg);
12129 memcpy (msg, &tfb, sizeof(tfb));
12130 memcpy (&msg[sizeof(tfb)], &orig[ff->frag_off], fragsize);
12132 ff->tail_frag, frag);
12133 ff->frag_off += fragsize;
12134 ff = frag;
12135 }
12136
12137 /* Move head to the tail and return it */
12141 ff);
12145 ff);
12146
12147 return ff;
12148}

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

12167{
12169 struct PendingAcknowledgement *pa;
12170 struct PendingMessage *bpm;
12171 char *msg;
12172
12173 if ((PMT_CORE != pm->pmt) && (PMT_DV_BOX != pm->pmt))
12174 return pm; /* already fragmented or reliability boxed, or control message:
12175 do nothing */
12176 if (NULL != pm->bpm)
12177 return pm->bpm; /* already computed earlier: do nothing */
12178 // TODO I guess we do not need this assertion. We might have a DLL with
12179 // fragments, because the MTU changed, and we do not need to fragment anymore.
12180 // But we should keep the fragments until message was completed, because
12181 // the MTU might change again.
12182 // GNUNET_assert (NULL == pm->head_frag);
12183 if (pm->bytes_msg + sizeof(rbox) > UINT16_MAX)
12184 {
12185 /* failed hard */
12186 GNUNET_break (0);
12188 return NULL;
12189 }
12190
12191 pa = prepare_pending_acknowledgement (queue, dvh, pm);
12192
12193 bpm = GNUNET_malloc (sizeof(struct PendingMessage) + sizeof(rbox)
12194 + pm->bytes_msg);
12196 "4 created pm %p storing vl %p from pm %p\n",
12197 bpm,
12198 pm->vl,
12199 pm);
12201 bpm->vl = pm->vl;
12202 bpm->frag_parent = pm;
12203 // Why was this needed?
12204 // GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
12205 bpm->timeout = pm->timeout;
12207 bpm->bytes_msg = pm->bytes_msg + sizeof(rbox);
12209 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
12210 rbox.header.size = htons (sizeof(rbox) + pm->bytes_msg);
12211 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
12212
12213 rbox.ack_uuid = pa->ack_uuid;
12214 msg = (char *) &bpm[1];
12215 memcpy (msg, &rbox, sizeof(rbox));
12216 memcpy (&msg[sizeof(rbox)], &pm[1], pm->bytes_msg);
12217 pm->bpm = bpm;
12219 "Preparing reliability box for message <%" PRIu64
12220 "> of size %d (%d) to %s on queue %s\n",
12221 pm->logging_uuid,
12222 pm->bytes_msg,
12223 ntohs (((const struct GNUNET_MessageHeader *) &pm[1])->size),
12224 GNUNET_i2s (&pm->vl->target),
12225 queue->address);
12226 return bpm;
12227}

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

12233{
12234 struct VirtualLink *vl = pm->vl;
12235 struct PendingMessage *pos;
12236
12237 /* Only a message without a parent is on vl->pending_msg_head; anything
12238 else is not ours to reorder and MDLL_remove() would abort on it. */
12239 if ((NULL == vl) ||
12240 (NULL != pm->frag_parent) ||
12241 ((NULL == pm->prev_vl) && (vl->pending_msg_head != pm)))
12242 {
12243 GNUNET_break (0);
12244 return;
12245 }
12246 /* re-insert sort in neighbour list */
12250 pm);
12251 pos = vl->pending_msg_tail;
12252 while ((NULL != pos) &&
12254 pos = pos->prev_vl;
12258 pos,
12259 pm);
12260}

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

12265{
12266 struct PendingMessage *pos;
12267 /* MUST be initialised: for a leaf the loop below never runs */
12269
12270 pos = pm->head_frag;
12271 while (NULL != pos)
12272 {
12274 GNUNET_NO == check_next_attempt_tree (pos, root))
12276 else
12277 {
12279 break;
12280 }
12281 pos = pos->next_frag;
12282 }
12283
12284 return frags_in_flight;
12285}

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

12290{
12291 struct PendingMessage *pos;
12292
12293 pos = pm->head_frag;
12294 while (NULL != pos)
12295 {
12298 pos = pos->next_frag;
12299 }
12300}

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

12314{
12315 if (NULL == pm->frag_parent)
12316 {
12317 pm->next_attempt = next_attempt;
12319 "Next attempt for message <%" PRIu64 "> set to %" PRIu64 "\n",
12320 pm->logging_uuid,
12321 next_attempt.abs_value_us);
12322 reorder_root_pm (pm, next_attempt);
12323 }
12324 else if ((PMT_RELIABILITY_BOX == pm->pmt) || (PMT_DV_BOX == pm->pmt))// || (PMT_FRAGMENT_BOX == pm->pmt))
12325 {
12326 struct PendingMessage *root = pm->frag_parent;
12327
12328 while (NULL != root->frag_parent)
12329 root = root->frag_parent;
12331 "Next attempt for root message <%" PRIu64 "> set to %s\n",
12332 root->logging_uuid,
12334 root->next_attempt = next_attempt;
12336 }
12337 else
12338 {
12339 struct PendingMessage *root = pm->frag_parent;
12340
12341 while (NULL != root->frag_parent && PMT_DV_BOX != root->pmt)
12342 root = root->frag_parent;
12343
12345 "frag_count next attempt %u\n",
12346 root->frag_count);
12347
12348 if (GNUNET_NO == root->frags_in_flight)
12349 {
12350 root->next_attempt = next_attempt;
12352 root->frags_in_flight_round++;
12354 "Next attempt for fragmented message <%" PRIu64 "> (<%" PRIu64
12355 ">)set to %" PRIu64 "\n",
12356 pm->logging_uuid,
12357 root->logging_uuid,
12359 }
12360
12361 pm->next_attempt = root->next_attempt;
12364
12365 if (root->bytes_msg == root->frag_off)
12366 root->frags_in_flight = check_next_attempt_tree (root, root);
12367 else
12369
12370 if (GNUNET_NO == root->frags_in_flight)
12371 {
12372 /* `root' deliberately stops at a DV box, which is itself a child of
12373 the message on vl->pending_msg_head. Walk the rest of the way for
12374 the reorder: only the parentless message is on that list. */
12375 struct PendingMessage *vl_root = root;
12376
12377 while (NULL != vl_root->frag_parent)
12378 vl_root = vl_root->frag_parent;
12379 vl_root->next_attempt = root->next_attempt;
12381 "We have no fragments in flight for message %" PRIu64
12382 ", reorder root %" PRIu64 "! Next attempt is %" PRIu64 "\n",
12383 root->logging_uuid,
12384 vl_root->logging_uuid,
12385 vl_root->next_attempt.abs_value_us);
12386 reorder_root_pm (vl_root, vl_root->next_attempt);
12387 }
12388 else
12389 {
12390 double factor = ((double) root->frag_count - 1)
12391 / (double) root->frag_count;
12392 struct GNUNET_TIME_Relative s1;
12393 struct GNUNET_TIME_Relative s2;
12394 struct GNUNET_TIME_Relative plus_mean =
12397 next_attempt);
12398
12400 "frag_count %u after factor\n",
12401 root->frag_count);
12403 factor);
12404 s2 = GNUNET_TIME_relative_divide (plus,
12405 root->frag_count);
12406 plus_mean = GNUNET_TIME_relative_add (s1, s2);
12409 "We have fragments in flight for message %" PRIu64
12410 ", do not reorder root! Actual next attempt %" PRIu64 "\n",
12411 root->logging_uuid,
12413 }
12414 }
12415}

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

12487{
12488 struct GNUNET_TIME_Absolute now;
12489
12490 now = GNUNET_TIME_absolute_get ();
12491 sc->to_early = GNUNET_NO;
12492 sc->frags_in_flight = GNUNET_NO;
12493 for (struct PendingMessage *pos = vl->pending_msg_head; NULL != pos;
12494 pos = pos->next_vl)
12495 {
12496 size_t real_overhead = overhead;
12497 int frag;
12498 int relb;
12499
12500 if ((NULL != dvh) && (PMT_DV_BOX == pos->pmt))
12501 {
12503 "DV messages must not be DV-routed to next hop!\n");
12504 continue; /* DV messages must not be DV-routed to next hop! */
12505 }
12506 if (pos->next_attempt.abs_value_us > now.abs_value_us)
12507 {
12508 if (GNUNET_YES == pos->frags_in_flight)
12509 {
12510 sc->frags_in_flight = GNUNET_YES;
12512 "Fragments in flight for message %" PRIu64 "\n",
12513 pos->logging_uuid);
12514 }
12515 else
12516 {
12518 "Maybe too early, because message are sorted by next_attempt, if there are no fragments in flight.Checked message %"
12519 PRIu64 "\n",
12520 pos->logging_uuid);
12521 sc->to_early = GNUNET_YES;
12522 sc->to_early_retry_delay = GNUNET_TIME_absolute_get_remaining (
12523 pos->next_attempt);
12524 continue;
12525 }
12526 // break; /* too early for all messages, they are sorted by next_attempt */
12527 }
12528 if (NULL != pos->qe)
12529 {
12531 "not eligible\n");
12532 continue; /* not eligible */
12533 }
12534 sc->consideration_counter++;
12535 /* determine if we have to fragment, if so add fragmentation
12536 overhead! */
12538 "check %" PRIu64 " for sc->best\n",
12539 pos->logging_uuid);
12540 frag = GNUNET_NO;
12541 if (((0 != queue->mtu) &&
12542 (pos->bytes_msg + real_overhead > queue->mtu)) ||
12543 (pos->bytes_msg > UINT16_MAX - sizeof(struct
12545 ||
12546 (NULL != pos->head_frag /* fragments already exist, should
12547 respect that even if MTU is UINT16_MAX for
12548 this queue */))
12549 {
12551 "fragment msg with size %u, realoverhead is %lu\n",
12552 pos->bytes_msg,
12553 real_overhead);
12554 frag = GNUNET_YES;
12555 if (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc)
12556 {
12557 /* FIXME-FRAG-REL-UUID: we could use an optimized, shorter fragmentation
12558 header without the ACK UUID when using a *reliable* channel! */
12559 }
12560 real_overhead = overhead + sizeof(struct TransportFragmentBoxMessage);
12561 }
12562 /* determine if we have to reliability-box, if so add reliability box
12563 overhead */
12564 relb = GNUNET_NO;
12565 if ((GNUNET_NO == frag) &&
12566 (0 == (pos->prefs & GNUNET_MQ_PREF_UNRELIABLE)) &&
12567 (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc))
12568 {
12569 real_overhead += sizeof(struct TransportReliabilityBoxMessage);
12570
12571 if ((0 != queue->mtu) && (pos->bytes_msg + real_overhead > queue->mtu))
12572 {
12573 frag = GNUNET_YES;
12574 real_overhead = overhead + sizeof(struct TransportFragmentBoxMessage);
12575 }
12576 else
12577 {
12578 relb = GNUNET_YES;
12579 }
12581 "Create reliability box of msg with size %u, realoverhead is %lu %u %u %u\n",
12582 pos->bytes_msg,
12583 real_overhead,
12584 queue->mtu,
12585 frag,
12586 relb);
12587 }
12588
12589 /* Finally, compare to existing 'best' in sc to see if this 'pos' pending
12590 message would beat it! */
12591 if (GNUNET_NO == sc->frags_in_flight && NULL != sc->best)
12592 {
12593 /* CHECK if pos fits queue BETTER (=smaller) than pm, if not: continue;
12594 OPTIMIZE-ME: This is a heuristic, which so far has NOT been
12595 experimentally validated. There may be some huge potential for
12596 improvement here. Also, we right now only compare how well the
12597 given message fits _this_ queue, and do not consider how well other
12598 queues might suit the message. Taking other queues into consideration
12599 may further improve the result, but could also be expensive
12600 in terms of CPU time. */
12601 long long sc_score = sc->frag * 40 + sc->relb * 20 + sc->real_overhead;
12602 long long pm_score = frag * 40 + relb * 20 + real_overhead;
12603 long long time_delta =
12604 (sc->best->next_attempt.abs_value_us - pos->next_attempt.abs_value_us)
12605 / 1000LL;
12606
12607 /* "time_delta" considers which message has been 'ready' for transmission
12608 for longer, if a message has a preference for low latency, increase
12609 the weight of the time_delta by 10x if it is favorable for that message */
12610 if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
12611 (0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)))
12612 time_delta *= 10; /* increase weight (always, both are low latency) */
12613 else if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
12614 (time_delta > 0))
12615 time_delta *= 10; /* increase weight, favors 'pos', which is low latency */
12616 else if ((0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
12617 (time_delta < 0))
12618 time_delta *= 10; /* increase weight, favors 'sc->best', which is low latency */
12619 if (0 != queue->mtu)
12620 {
12621 /* Grant bonus if we are below MTU, larger bonus the closer we will
12622 be to the MTU */
12623 if (queue->mtu > sc->real_overhead + sc->best->bytes_msg)
12624 sc_score -= queue->mtu - (sc->real_overhead + sc->best->bytes_msg);
12625 if (queue->mtu > real_overhead + pos->bytes_msg)
12626 pm_score -= queue->mtu - (real_overhead + pos->bytes_msg);
12627 }
12628 if (sc_score + time_delta > pm_score)
12629 {
12631 "sc_score of %" PRIu64 " larger, keep sc->best %" PRIu64
12632 "\n",
12633 pos->logging_uuid,
12634 sc->best->logging_uuid);
12635 continue; /* sc_score larger, keep sc->best */
12636 }
12637 }
12638 sc->best = pos;
12639 sc->dvh = dvh;
12640 sc->frag = frag;
12641 sc->relb = relb;
12642 sc->real_overhead = real_overhead;
12643 }
12644}

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

12662{
12663 struct PendingMessageScoreContext *sc = cls;
12664 struct PendingMessage *pm = sc->best;
12665 struct PendingMessage *bpm;
12666 uint16_t bsize = ntohs (hdr->size);
12667
12668 GNUNET_assert (NULL == pm->bpm);
12669 bpm = GNUNET_malloc (sizeof(struct PendingMessage) + bsize);
12671 "5 created pm %p storing vl %p from pm %p\n",
12672 bpm,
12673 pm->vl,
12674 pm);
12676 bpm->pmt = PMT_DV_BOX;
12677 bpm->vl = pm->vl;
12678 bpm->timeout = pm->timeout;
12679 bpm->bytes_msg = bsize;
12680 bpm->frag_parent = pm;
12683 "Creating DV Box %" PRIu64 " for original message %" PRIu64
12684 " (next hop is %s)\n",
12686 pm->logging_uuid,
12687 GNUNET_i2s (&next_hop->pid));
12688 memcpy (&bpm[1], hdr, bsize);
12689 pm->bpm = bpm;
12690}

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

12997{
12998 struct TransportClient *tc = cls;
12999
13000 if (CT_COMMUNICATOR != tc->type)
13001 {
13002 GNUNET_break (0);
13004 return;
13005 }
13006 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
13007 queue = queue->next_client)
13008 {
13009 struct Neighbour *neighbour = queue->neighbour;
13010
13011 if ((ntohl (dqm->qid) != queue->qid) ||
13012 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
13013 continue;
13015 "Dropped queue %s to peer %s\n",
13016 queue->address,
13017 GNUNET_i2s (&neighbour->pid));
13018 free_queue (queue);
13020 return;
13021 }
13022 /* Not finding the queue is a race, not a protocol violation: we may have
13023 freed it ourselves already, or the communicator may be tearing down a
13024 queue we never fully learned about. Do NOT drop the client over it --
13025 that runs #client_disconnect_cb(), which frees *every* queue this
13026 communicator owns, so one stale QUEUE_TEARDOWN would disconnect us from
13027 every peer it serves at once. Compare #handle_send_message_ack(), which
13028 tolerates the same lookup miss. */
13030 "QUEUE_TEARDOWN for unknown queue QID %u to peer %s ignored\n",
13031 ntohl (dqm->qid),
13032 GNUNET_i2s (&dqm->receiver));
13034 "# QUEUE_TEARDOWN dropped: queue unknown",
13035 1,
13036 GNUNET_NO);
13038}

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

13141{
13142 struct TransportClient *tc = cls;
13143 struct QueueEntry *qe;
13144 struct Queue *failed_queue = NULL;
13145
13146 if (CT_COMMUNICATOR != tc->type)
13147 {
13148 GNUNET_break (0);
13150 return;
13151 }
13152
13153 /* find our queue entry matching the ACK */
13154 qe = NULL;
13156 "Looking for queue for PID %s\n",
13157 GNUNET_i2s (&sma->receiver));
13158 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
13159 queue = queue->next_client)
13160 {
13161 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
13162 continue;
13164 "Found PID %s\n",
13165 GNUNET_i2s (&queue->neighbour->pid));
13166
13167
13168 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
13169 qep = qep->next)
13170 {
13171 if (qep->mid != GNUNET_ntohll (sma->mid) || queue->qid != ntohl (
13172 sma->qid))
13173 continue;
13175 "QueueEntry MID: %" PRIu64 " on queue QID: %u, Ack MID: %"
13176 PRIu64 " Ack QID %u\n",
13177 qep->mid,
13178 queue->qid,
13179 GNUNET_ntohll (sma->mid),
13180 ntohl (sma->qid));
13181 qe = qep;
13182 if ((NULL != qe->pm) && (qe->pm->qe != qe))
13184 "For pending message %" PRIu64 " we had retransmissions.\n",
13185 qe->pm->logging_uuid);
13186 break;
13187 }
13188 }
13189 if (GNUNET_OK != (int) ntohl (sma->status))
13190 {
13191 /* The communicator could not hand the message to the peer. The only
13192 thing that produces this today is #handle_send_msg()'s "queue no
13193 longer exists" branch in `transport_api_communication.c', i.e. the
13194 communicator has already torn the queue down on its side and the
13195 QUEUE_TEARDOWN is merely still in flight (or was lost).
13196
13197 Ignoring the status, as we used to, makes this self-sustaining:
13198 #free_queue_entry() releases the pending message and immediately
13199 reschedules transmission, #transmit_on_queue() picks the very same
13200 queue again -- transport still has it -- and we get another failure.
13201 Every round adds an envelope to the client MQ that is already
13202 congested, which is what shows up at the other end as
13203
13204 communicator INFO Transmission failed, queue no longer exists.
13205
13206 repeating at scheduler speed, and (because the service is busy
13207 servicing that loop) as
13208
13209 communicator WARNING Dropping message: transport is too slow,
13210 queue length N exceeded
13211
13212 on every *other* communicator. Treat the failure as the queue
13213 teardown it is and stop selecting this queue. */
13215 "Communicator could not send MID %" PRIu64
13216 " on QID %u to %s; dropping that queue\n",
13217 GNUNET_ntohll (sma->mid),
13218 ntohl (sma->qid),
13219 GNUNET_i2s (&sma->receiver));
13221 "# queues dropped (communicator send failed)",
13222 1,
13223 GNUNET_NO);
13224 if (NULL != qe)
13225 failed_queue = qe->queue;
13226 else
13227 for (struct Queue *queue = tc->details.communicator.queue_head;
13228 NULL != queue;
13229 queue = queue->next_client)
13230 if ((ntohl (sma->qid) == queue->qid) &&
13231 (0 == GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver)))
13232 {
13233 failed_queue = queue;
13234 break;
13235 }
13236 if (NULL != failed_queue)
13237 {
13238 /* #free_queue() releases every `struct QueueEntry' still on it --
13239 including @a qe -- and detaches their pending messages, so they are
13240 retried on whatever other queue this neighbour has. */
13241 free_queue (failed_queue);
13243 return;
13244 }
13245 }
13246 if (NULL == qe)
13247 {
13249 "No QueueEntry found for Ack MID %" PRIu64 " QID: %u\n",
13250 GNUNET_ntohll (sma->mid),
13251 ntohl (sma->qid));
13252 // TODO I guess this can happen, if the Ack from the peer comes before the Ack from the queue.
13253 // Update: Maybe QueueEntry was accidentally freed during freeing PendingMessage.
13254 /* this should never happen */
13255 // GNUNET_break (0);
13256 // GNUNET_SERVICE_client_drop (tc->client);
13258 return;
13259 }
13262}

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

13273{
13274 struct TransportClient *tc = cls;
13275
13276 (void) bf;
13279}

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

13295{
13296 struct TransportClient *tc = cls;
13297 struct Neighbour *neighbour = value;
13298
13299 GNUNET_assert (CT_MONITOR == tc->type);
13300 for (struct Queue *q = neighbour->queue_head; NULL != q;
13301 q = q->next_neighbour)
13302 {
13303 struct MonitorEvent me = { .rtt = q->pd.aged_rtt,
13304 .cs = q->cs,
13305 .num_msg_pending = q->num_msg_pending,
13306 .num_bytes_pending = q->num_bytes_pending };
13307
13308 notify_monitor (tc, pid, q->address, q->nt, &me);
13309 }
13310 return GNUNET_OK;
13311}

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

13323{
13324 struct TransportClient *tc = cls;
13325
13326 if (CT_NONE != tc->type)
13327 {
13328 GNUNET_break (0);
13330 return;
13331 }
13332 tc->type = CT_MONITOR;
13333 tc->details.monitor.peer = start->peer;
13334 tc->details.monitor.one_shot = ntohl (start->one_shot);
13338}

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

13369{
13370 char *ret = GNUNET_strdup ("");
13371
13372 *num_queues = 0;
13373 if (NULL == n)
13374 return ret;
13375 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
13376 {
13377 const char *prefix = q->tc->details.communicator.address_prefix;
13378 size_t plen = strlen (prefix);
13379 const char *pos;
13380 char *tmp;
13381
13382 (*num_queues)++;
13383 if (0 == plen)
13384 continue;
13385 /* Several queues to one neighbour routinely share a communicator;
13386 name each one once. */
13387 for (pos = strstr (ret, prefix);
13388 NULL != pos;
13389 pos = strstr (pos + 1, prefix))
13390 if (((pos == ret) || (',' == pos[-1])) &&
13391 (('\0' == pos[plen]) || (',' == pos[plen])))
13392 break;
13393 if (NULL != pos)
13394 continue;
13395 GNUNET_asprintf (&tmp, "%s%s%s", ret, ('\0' == ret[0]) ? "" : ",", prefix);
13396 GNUNET_free (ret);
13397 ret = tmp;
13398 }
13399 return ret;
13400}

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

13413{
13414 struct LinkListContext *llc = cls;
13415 struct VirtualLink *vl = value;
13417 struct GNUNET_MQ_Envelope *env;
13418 unsigned int pending = 0;
13419 unsigned int num_queues = 0;
13420 unsigned int distance = 0;
13421 struct Neighbour *hop;
13422 char *ccs;
13423 size_t clen;
13424
13425 if ((GNUNET_YES != llc->include_unconfirmed) &&
13426 (GNUNET_YES != vl->confirmed))
13427 return GNUNET_OK;
13428 for (struct PendingMessage *pm = vl->pending_msg_head;
13429 NULL != pm;
13430 pm = pm->next_vl)
13431 pending++;
13432 if (NULL != vl->n)
13433 {
13434 hop = vl->n;
13435 }
13436 else
13437 {
13438 /* Report the best (shortest) of the paths we currently know, and the
13439 communicators that carry its first hop. */
13440 struct DistanceVectorHop *best = NULL;
13441
13442 distance = UINT_MAX;
13443 if (NULL != vl->dv)
13444 for (struct DistanceVectorHop *pos = vl->dv->dv_head;
13445 NULL != pos;
13446 pos = pos->next_dv)
13447 if (pos->distance < distance)
13448 {
13449 distance = pos->distance;
13450 best = pos;
13451 }
13452 if (NULL == best)
13453 distance = 0; /* no paths left; report the link as adjacent */
13454 hop = (NULL != best) ? best->next_hop : NULL;
13455 }
13456 ccs = communicator_list (hop, &num_queues);
13457 clen = strlen (ccs) + 1;
13458 env = GNUNET_MQ_msg_extra (resp,
13459 clen,
13461 memcpy (&resp[1], ccs, clen);
13462 GNUNET_free (ccs);
13463 resp->target = *pid;
13464 resp->confirmed = htonl ((uint32_t) vl->confirmed);
13465 resp->route = htonl ((uint32_t) ((NULL != vl->n)
13468 resp->distance = htonl ((uint32_t) distance);
13469 resp->num_queues = htonl ((uint32_t) num_queues);
13470 resp->core_recv_window = htonl ((int32_t) vl->core_recv_window);
13471 resp->stalled = htonl ((uint32_t) vl->cmc_count);
13472 resp->pending = htonl (pending);
13473 resp->fc_retransmit_count = htonl ((uint32_t) vl->fc_retransmit_count);
13492 GNUNET_MQ_send (llc->tc->mq, env);
13493 return GNUNET_OK;
13494}

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

13509{
13510 struct TransportClient *tc = cls;
13511 struct LinkListContext llc = {
13512 .tc = tc,
13513 .include_unconfirmed = (int) ntohl (lr->include_unconfirmed)
13514 };
13515 struct GNUNET_MQ_Envelope *env;
13516 struct GNUNET_MessageHeader *end;
13517
13518 if (CT_NONE != tc->type)
13519 {
13520 GNUNET_break (0);
13522 return;
13523 }
13524 if (GNUNET_YES == GNUNET_is_zero (&lr->peer))
13525 {
13527 }
13528 else
13529 {
13530 struct VirtualLink *vl = lookup_virtual_link (&lr->peer);
13531
13532 if (NULL != vl)
13533 report_link (&llc, &lr->peer, vl);
13534 }
13537 GNUNET_MQ_send (tc->mq, env);
13539}

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

13551{
13552 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
13553 {
13554 if (CT_COMMUNICATOR != tc->type)
13555 continue;
13556 if (NULL == tc->details.communicator.address_prefix)
13557 continue; /* receive-only communicator */
13558 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
13559 return tc;
13560 }
13561 GNUNET_log (
13563 "Someone suggested use of communicator for `%s', but we do not have such a communicator!\n",
13564 prefix);
13565 return NULL;
13566}

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:

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

13795{
13796 struct QueueQualityContext *ctx = cls;
13797 struct Neighbour *n = value;
13798 int do_inc;
13799
13800 (void) pid;
13801 do_inc = GNUNET_NO;
13802 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
13803 {
13804 ctx->num_queues++;
13805 if (0 == ctx->k--)
13806 ctx->q = q;
13807 /* FIXME-CONQ-STATISTICS: in the future, add reliability / goodput
13808 statistics and consider those as well here? */
13809 if (q->pd.aged_rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
13810 do_inc = GNUNET_YES;
13811 }
13812 if (GNUNET_YES == do_inc)
13813 ctx->quality_count++;
13814 return GNUNET_OK;
13815}

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

13897{
13898 struct LearnLaunchEntry *lle;
13899 struct QueueQualityContext qqc;
13900 struct TransportDVLearnMessage dvl;
13901 const struct GNUNET_PeerIdentity *my_identity;
13902
13903 (void) cls;
13904 dvlearn_task = NULL;
13905 if ((GNUNET_YES == in_shutdown) || (NULL == pils))
13906 return;
13908 return; /* lost all connectivity, cannot do learning */
13910 if (NULL == my_identity)
13911 {
13912 /* PILS has not handed us an identity yet. The first queue arriving
13913 schedules us with add_now(), which routinely wins that race; retry
13914 instead of taking the service down. */
13918 NULL);
13919 return;
13920 }
13922 qqc.quality_count = 0;
13923 qqc.num_queues = 0;
13927 &qqc);
13928 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
13929 {
13930 struct GNUNET_TIME_Relative delay;
13931 unsigned int factor;
13932
13933 /* scale our retries by how far we are above the threshold */
13934 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
13937 "At connection quality %u, will launch DV learn in %s\n",
13938 qqc.quality_count,
13941 return;
13942 }
13943 /* remove old entries in #dvlearn_map if it has grown too big */
13944 while (MAX_DV_LEARN_PENDING <=
13946 {
13947 lle = lle_tail;
13950 &lle->challenge.value,
13951 lle));
13953 GNUNET_free (lle);
13954 }
13955 /* setup data structure for learning */
13956 lle = GNUNET_new (struct LearnLaunchEntry);
13958 sizeof(lle->challenge));
13960 "Starting launch DV learn with challenge %s\n",
13961 GNUNET_sh2s (&lle->challenge.value));
13966 &lle->challenge.value,
13967 lle,
13969 dvl.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
13970 dvl.header.size = htons (sizeof(dvl));
13971 dvl.num_hops = htons (0);
13972 dvl.bidirectional = htons (0);
13973 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
13974 dvl.monotonic_time =
13976 // We will set the below again later
13977 memset (&dvl.init_sig, 0, sizeof dvl.init_sig);
13978 dvl.challenge = lle->challenge;
13979 dvl.initiator = *my_identity;
13980 {
13981 struct DvInitPS dvip = {
13982 .purpose.purpose = htonl (
13984 .purpose.size = htonl (sizeof(dvip)),
13985 .monotonic_time = dvl.monotonic_time,
13986 .challenge = lle->challenge
13987 };
13988
13989 if (GNUNET_OK != sign_by_my_identity (&dvip.purpose, &dvl.init_sig))
13990 return;
13991 }
13992 transmit_dv_init (dvl, lle, qqc);
13993}

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

13844{
13845 if (0 == qqc.num_queues)
13846 {
13848 "# DV learn aborted: no queue left",
13849 1,
13850 GNUNET_NO);
13851 return;
13852 }
13853 qqc.quality_count = 0;
13855 qqc.num_queues = 0;
13856 qqc.q = NULL;
13859 &qqc);
13860 if (NULL == qqc.q)
13861 {
13863 "# DV learn aborted: no queue left",
13864 1,
13865 GNUNET_NO);
13866 return;
13867 }
13868
13869 /* Do this as close to transmission time as possible! */
13871
13872 queue_send_msg (qqc.q, NULL, &dvl, sizeof(dvl));
13873 /* reschedule this job, randomizing the time it runs (but no
13874 actual backoff!) */
13875 if (NULL != dvlearn_task)
13880 NULL);
13881}

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

14037{
14038 struct Queue *q = cls;
14039 struct ValidationState *vs = value;
14040 char *address_without_port_vs;
14041 char *address_without_port_q;
14042 char *prefix_vs;
14043 char *prefix_q;
14044 int success = GNUNET_YES;
14045
14046 // TODO Check if this is really necessary.
14047 address_without_port_vs = get_address_without_port (vs->address);
14048 address_without_port_q = get_address_without_port (q->address);
14049 prefix_vs = GNUNET_HELLO_address_to_prefix (vs->address);
14050 prefix_q = GNUNET_HELLO_address_to_prefix (q->address);
14051
14053 "Check validation request pending for `%s' at `%s'/`%s' (vs)/(q)\n",
14054 GNUNET_i2s (pid),
14055 (NULL == address_without_port_vs) ? "<unparsable>"
14056 : address_without_port_vs,
14057 (NULL == address_without_port_q) ? "<unparsable>"
14058 : address_without_port_q);
14059 (void) pid;
14060 /* Only the port may differ: the address we asked to connect to is
14061 `PROTO-IP:0' for a NATed peer, while the queue that then materializes
14062 sits at `PROTO-IP:port'. The communicator must match all the same --
14063 a challenge for a `tcp-' address is not answered by a `udp-' queue. */
14064 if ((GNUNET_YES == vs->awaiting_queue) &&
14065 (NULL != address_without_port_vs) &&
14066 (NULL != address_without_port_q) &&
14067 (NULL != prefix_vs) &&
14068 (NULL != prefix_q) &&
14069 (0 == strcmp (prefix_vs, prefix_q)) &&
14070 (0 == strcmp (address_without_port_vs, address_without_port_q)))
14071 {
14072
14073 vs->awaiting_queue = GNUNET_NO;
14075 success = GNUNET_NO;
14076 }
14077
14078 GNUNET_free (address_without_port_vs);
14079 GNUNET_free (address_without_port_q);
14080 GNUNET_free (prefix_vs);
14081 GNUNET_free (prefix_q);
14082 return success;
14083}

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

14098{
14099 struct Neighbour *n = cls;
14100 struct GNUNET_TIME_AbsoluteNBO *mtbe;
14101
14102 (void) emsg;
14103 if (NULL == record)
14104 {
14105 /* we're done with #neighbour_dv_monotime_cb() invocations,
14106 continue normal processing */
14107 n->get = NULL;
14109 return;
14110 }
14111 if (0 == record->value_size)
14112 {
14114 GNUNET_break (0);
14115 return;
14116 }
14117 mtbe = record->value;
14122}

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

14129{
14130 struct Queue *queue = cls;
14131 struct sockaddr_in v4;
14132 const char *slash;
14133 char *address_uri;
14134 char *prefix;
14135 char *uri_without_port;
14136 char *address_uri_without_port;
14137
14138 slash = strrchr (uri, '/');
14139 if ((NULL == slash) || (slash - uri < 2))
14140 {
14141 GNUNET_break_op (0); /* @a uri comes from a remote HELLO */
14142 return;
14143 }
14144 prefix = GNUNET_strndup (uri, (slash - uri) - 2);
14145 slash++;
14146 GNUNET_asprintf (&address_uri,
14147 "%s-%s",
14148 prefix,
14149 slash);
14150
14152 "1 not global natted_address %u %s %s %s\n",
14153 queue->is_global_natted,
14154 uri,
14155 queue->address,
14156 slash);
14157
14158 uri_without_port = get_address_without_port (address_uri);
14159 if ((NULL == uri_without_port) ||
14160 (1 != inet_pton (AF_INET, uri_without_port, &v4.sin_addr)))
14161 {
14163 GNUNET_free (address_uri);
14164 GNUNET_free (uri_without_port);
14165 return;
14166 }
14167
14169 "2 not global natted_address %u %s %s\n",
14170 queue->is_global_natted,
14171 uri,
14172 queue->address);
14173
14174 if (GNUNET_NO == queue->is_global_natted)
14175 {
14177 GNUNET_free (address_uri);
14178 GNUNET_free (uri_without_port);
14179 return;
14180 }
14181
14183 "3 not global natted_address %u %s %s\n",
14184 queue->is_global_natted,
14185 uri,
14186 queue->address);
14187
14188 if (0 == strcmp (uri_without_port, address_uri))
14189 {
14191 GNUNET_free (address_uri);
14192 GNUNET_free (uri_without_port);
14193 return;
14194 }
14195
14197 "4 not global natted_address %u %s %s\n",
14198 queue->is_global_natted,
14199 uri,
14200 queue->address);
14201
14202 address_uri_without_port = get_address_without_port (queue->address);
14203 if ((NULL != address_uri_without_port) &&
14204 (0 == strcmp (uri_without_port, address_uri_without_port)))
14205 {
14206 queue->is_global_natted = GNUNET_NO;
14207 }
14208
14210 "not global natted_address %u %s %s %s %s %s %u\n",
14211 queue->is_global_natted,
14212 uri,
14213 queue->address,
14214 uri_without_port,
14215 address_uri_without_port,
14216 prefix,
14217 GNUNET_NO);
14219 GNUNET_free (address_uri);
14220 GNUNET_free (address_uri_without_port);
14221 GNUNET_free (uri_without_port);
14222}

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

14243{
14244 struct TransportGlobalNattedAddressClosure *tgna_cls = cls;
14245 struct TransportGlobalNattedAddress *tgna = value;
14246 char *addr = (char *) &tgna[1];
14247
14248 /* NOTE: @a addr is NOT 0-terminated. */
14250 "Checking tgna %p with addr %.*s and length %u compare length %lu\n",
14251 tgna,
14252 (int) ntohl (tgna->address_length),
14253 addr,
14254 ntohl (tgna->address_length),
14255 strlen (tgna_cls->addr));
14256 if (strlen (tgna_cls->addr) == ntohl (tgna->address_length)
14257 && 0 == strncmp (addr, tgna_cls->addr, ntohl (tgna->address_length)))
14258 {
14259 tgna_cls->tgna = tgna;
14260 return GNUNET_NO;
14261 }
14262 return GNUNET_YES;
14263}

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

14268{
14270 "Error in PEERSTORE monitoring for checking global natted\n");
14271}

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

14276{
14278 "Done with initial PEERSTORE iteration during monitoring for checking global natted\n");
14279}

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

14286{
14287 struct Queue *queue = cls;
14288 struct Neighbour *neighbour = queue->neighbour;
14290 const struct GNUNET_MessageHeader *hello;
14292 size_t address_len_without_port;
14293
14294 if (NULL != emsg)
14295 {
14297 "Got failure from PEERSTORE: %s\n",
14298 emsg);
14300 return;
14301 }
14302 if (NULL == record)
14303 {
14304 GNUNET_break (0);
14306 return;
14307 }
14308 /* @a hello was published by a remote peer and may be malformed. */
14309 hello = hello_from_record (record);
14310 if (NULL == hello)
14311 {
14313 return;
14314 }
14315 queue->is_global_natted = GNUNET_YES;
14316 parser = GNUNET_HELLO_parser_from_msg (hello, &record->peer);
14317 if (NULL == parser)
14318 {
14320 "HELLO cannot be parsed!\n");
14322 return;
14323 }
14325 "before not global natted %u\n",
14326 queue->is_global_natted);
14329 queue);
14331 "after not global natted %u\n",
14332 queue->is_global_natted);
14333 GNUNET_HELLO_parser_free (parser);
14334
14335 tgna_cls.addr = get_address_without_port (queue->address);
14336 if (NULL == tgna_cls.addr)
14337 {
14338 GNUNET_break (0);
14340 return;
14341 }
14342 address_len_without_port = strlen (tgna_cls.addr);
14343 /*{
14344 char buf[address_len_without_port + 1];
14345
14346 GNUNET_memcpy (&buf, addr, address_len_without_port);
14347 buf[address_len_without_port] = '\0';
14348 GNUNET_free (addr);
14349 GNUNET_memcpy (tgna_cls.addr, buf, address_len_without_port + 1);
14350 }*/
14351 tgna_cls.tgna = NULL;
14353 &neighbour->pid,
14355 &tgna_cls);
14356 if (NULL != tgna_cls.tgna)
14358 " tgna_cls.tgna tgna %p %lu %u %u\n",
14359 tgna_cls.tgna,
14360 neighbour->size_of_global_addresses,
14361 ntohl (tgna_cls.tgna->address_length),
14362 neighbour->number_of_addresses);
14363 if (NULL == tgna_cls.tgna && GNUNET_YES == queue->is_global_natted)
14364 {
14365 struct TransportGlobalNattedAddress *tgna;
14366
14367 tgna = GNUNET_malloc (sizeof (struct TransportGlobalNattedAddress)
14368 + address_len_without_port);
14369 tgna->address_length = htonl (address_len_without_port);
14370 GNUNET_memcpy (&tgna[1], tgna_cls.addr, address_len_without_port);
14372 &neighbour->pid,
14373 tgna,
14375 neighbour->number_of_addresses++;
14376 /* MUST match what is subtracted on removal (and what
14377 #add_global_addresses() actually copies), or the accounting drifts. */
14378 neighbour->size_of_global_addresses += address_len_without_port;
14380 "Created tgna %p with address %s and length %lu\n",
14381 tgna,
14382 tgna_cls.addr,
14383 address_len_without_port + 1);
14384 }
14385 else if (NULL != tgna_cls.tgna && GNUNET_NO == queue->is_global_natted)
14386 {
14388 &neighbour->pid,
14389 tgna_cls.tgna);
14390 GNUNET_assert (neighbour->size_of_global_addresses >= ntohl (tgna_cls.tgna->
14392 );
14393 neighbour->size_of_global_addresses -= ntohl (tgna_cls.tgna->address_length)
14394 ;
14395 GNUNET_assert (0 < neighbour->number_of_addresses);
14396 neighbour->number_of_addresses--;
14398 "removed tgna %p\n",
14399 tgna_cls.tgna);
14400 GNUNET_free (tgna_cls.tgna);
14401 }
14403 GNUNET_free (tgna_cls.addr);
14404}

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

14416{
14417 struct TransportClient *tc = cls;
14418 struct Queue *queue;
14419 struct Neighbour *neighbour;
14420 const char *addr;
14421 uint16_t addr_len;
14422
14423 if (ntohl (aqm->mtu) <= sizeof(struct TransportFragmentBoxMessage))
14424 {
14425 /* MTU so small as to be useless for transmissions,
14426 required for #fragment_message()! */
14427 GNUNET_break_op (0);
14429 return;
14430 }
14431 /* This may simply be a queue update. Match on the peer as well as the
14432 QID: the communicator's key for a queue is the pair, and
14433 #handle_send_msg() on its side looks both of them up. Matching on the
14434 QID alone let an ADD_QUEUE for a *different* peer be folded into an
14435 existing queue, leaving @e neighbour pointing at the old peer -- after
14436 which every SEND_MSG we put on it carries a receiver the communicator
14437 cannot match, and comes straight back as "queue no longer exists". */
14438 for (queue = tc->details.communicator.queue_head;
14439 NULL != queue;
14440 queue = queue->next_client)
14441 {
14442 if (queue->qid != ntohl (aqm->qid))
14443 continue;
14444 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &aqm->receiver))
14445 continue;
14446 break;
14447 }
14448
14449 if (NULL != queue)
14450 {
14451 neighbour = queue->neighbour;
14452 }
14453 else
14454 {
14455 struct GNUNET_TIME_Absolute validated_until = GNUNET_TIME_UNIT_ZERO_ABS;
14456
14457 neighbour = lookup_neighbour (&aqm->receiver);
14458 if (NULL == neighbour)
14459 {
14460 neighbour = GNUNET_new (struct Neighbour);
14462 GNUNET_YES);
14463 neighbour->pid = aqm->receiver;
14464 /* Give a fresh neighbour a full window to say something. */
14465 neighbour->last_inbound = GNUNET_TIME_absolute_get ();
14468 neighbours,
14469 &neighbour->pid,
14470 neighbour,
14472 neighbour->get =
14474 "transport",
14475 &neighbour->pid,
14478 neighbour);
14479 }
14480 addr_len = ntohs (aqm->header.size) - sizeof(*aqm);
14481 addr = (const char *) &aqm[1];
14483 "New queue %s to %s available with QID %u and q_len %" PRIu64
14484 " and mtu %u\n",
14485 addr,
14486 GNUNET_i2s (&aqm->receiver),
14487 ntohl (aqm->qid),
14488 GNUNET_ntohll (aqm->q_len),
14489 ntohl (aqm->mtu));
14490 queue = GNUNET_malloc (sizeof(struct Queue) + addr_len);
14491 queue->tc = tc;
14492 for (struct Queue *q = neighbour->queue_head; NULL != q; q = q->
14493 next_neighbour)
14494 validated_until = GNUNET_TIME_absolute_max (validated_until, q->
14495 validated_until);
14496 /* Inherit the validity of the sibling queues, but only while it is
14497 still in the future -- copying an already expired timestamp is
14498 pointless (and the condition used to be inverted). */
14499 if (0 != GNUNET_TIME_absolute_get_remaining (validated_until).rel_value_us)
14500 {
14502 "New queue with QID %u inherit validated until\n",
14503 ntohl (aqm->qid));
14504 queue->validated_until = validated_until;
14505 }
14506 queue->address = (const char *) &queue[1];
14507 queue->pd.aged_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
14508 queue->qid = ntohl (aqm->qid);
14509 queue->neighbour = neighbour;
14511 queue->unlimited_length = GNUNET_YES;
14512 queue->q_capacity = GNUNET_ntohll (aqm->q_len);
14513 memcpy (&queue[1], addr, addr_len);
14514 /* notify monitors about new queue */
14515 {
14516 struct MonitorEvent me = { .rtt = queue->pd.aged_rtt, .cs = queue->cs };
14517
14518 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
14519 }
14521 neighbour->queue_head,
14522 neighbour->queue_tail,
14523 queue);
14525 tc->details.communicator.queue_head,
14526 tc->details.communicator.queue_tail,
14527 queue);
14528
14529 }
14530 queue->mtu = ntohl (aqm->mtu);
14531 queue->nt = ntohl (aqm->nt);
14532 queue->cs = ntohl (aqm->cs);
14533 queue->idle = GNUNET_YES;
14534
14535 if (NULL == queue->mo)
14536 {
14537 /* Only for a NEW queue: on a queue update this used to start a second
14538 monitor and leak the first one. */
14539 struct sockaddr_in v4;
14540 char *addr_without = get_address_without_port (queue->address);
14541 if ((NULL != addr_without) &&
14542 (1 == inet_pton (AF_INET, addr_without, &v4.sin_addr)))
14543 {
14545 "start not global natted\n");
14547 GNUNET_YES,
14548 "peerstore",
14549 &neighbour->pid,
14551 &
14553 NULL,
14554 &
14556 NULL,
14558 queue);
14559 }
14560 GNUNET_free (addr_without);
14561 }
14562 /* check if valdiations are waiting for the queue */
14564 &aqm->receiver))
14567 &aqm->receiver,
14569 queue);
14570 /* Always (also) validate the address of the queue itself. A pending
14571 validation served above may well be for a *different* address string:
14572 #check_validation_request_pending() matches on the IP only, so a
14573 validation state waiting for the NAT address `PROTO-IP:0' is happily
14574 satisfied by a queue at `PROTO-IP:12345'. If we stopped here,
14575 #handle_validation_response() would later look for a queue at
14576 `PROTO-IP:0' -- which never exists -- and drop the successful
14577 validation on the floor without ever creating the virtual link. That
14578 is exactly what happens to the second of two peers behind the same
14579 NAT, as both of them advertise the very same `PROTO-IP:0'. */
14580 start_address_validation (&aqm->receiver, queue->address);
14581 /* look for traffic for this queue */
14582 // TODO Check whether this makes any sense at all.
14583 /*schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
14584 queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);*/
14585 /* might be our first queue, try launching DV learning */
14586 if (NULL == dvlearn_task)
14589}

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

14602{
14603 struct TransportClient *tc = cls;
14604 struct Queue *target_queue = NULL;
14605
14606 if (CT_COMMUNICATOR != tc->type)
14607 {
14608 /* Without this we walk `details.communicator.queue_head' for a client
14609 whose union holds something else entirely. */
14610 GNUNET_break (0);
14612 return;
14613 }
14615 "Received queue update message for %u with q_len %llu and mtu %u\n",
14616 ntohl (msg->qid),
14617 (unsigned long long) GNUNET_ntohll (msg->q_len),
14618 ntohl (msg->mtu));
14619 for (target_queue = tc->details.communicator.queue_head;
14620 NULL != target_queue;
14621 target_queue = target_queue->next_client)
14622 {
14623 if (ntohl (msg->qid) == target_queue->qid)
14624 break;
14625 }
14626 if (NULL == target_queue)
14627 {
14629 "Queue to update no longer exists! Discarding update.\n");
14631 return;
14632 }
14633
14634 target_queue->nt = ntohl (msg->nt);
14635 target_queue->mtu = ntohl (msg->mtu);
14636 target_queue->cs = ntohl (msg->cs);
14637 target_queue->priority = ntohl (msg->priority);
14638 /* The update message indicates how many messages
14639 * the queue should be able to handle.
14640 */
14642 target_queue->unlimited_length = GNUNET_YES;
14643 else
14644 target_queue->unlimited_length = GNUNET_NO;
14645 target_queue->q_capacity += GNUNET_ntohll (msg->q_len);
14646 if (0 < target_queue->q_capacity)
14648 target_queue,
14651}

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

14664{
14665 struct TransportClient *tc = cls;
14666
14667 if (CT_COMMUNICATOR != tc->type)
14668 {
14669 GNUNET_break (0);
14671 return;
14672 }
14674 "# Suggestions succeeded at communicator",
14675 1,
14676 GNUNET_NO);
14678 "Request #%u for communicator to create queue succeeded\n",
14679 (unsigned int) ntohs (cqr->request_id));
14681}

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

14696{
14697 struct TransportClient *tc = cls;
14698
14699 if (CT_COMMUNICATOR != tc->type)
14700 {
14701 GNUNET_break (0);
14703 return;
14704 }
14706 "Request #%u for communicator to create queue failed\n",
14707 (unsigned int) ntohl (cqr->request_id));
14709 "# Suggestions failed in queue creation at communicator",
14710 1,
14711 GNUNET_NO);
14713}

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

We have received a struct ExpressPreferenceMessage from an application client.

Parameters
clshandle to the client
msgthe start message

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

14725{
14726 struct TransportClient *tc = cls;
14727 struct PeerRequest *pr;
14728
14729 if (CT_APPLICATION != tc->type)
14730 {
14731 GNUNET_break (0);
14733 return;
14734 }
14735 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
14736 &msg->peer);
14737 if (NULL == pr)
14738 {
14739 GNUNET_break (0);
14741 return;
14742 }
14743 (void) stop_peer_request (tc, &pr->pid, pr);
14745}

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

14752{
14753 struct Queue *q;
14754 int pfx_len;
14755 const char *eou;
14756 char *address;
14757 (void) cls;
14758
14759 eou = strstr (uri,
14760 "://");
14761 pfx_len = eou - uri;
14762 eou += 3;
14764 "%.*s-%s",
14765 pfx_len,
14766 uri,
14767 eou);
14768
14770 "hello for client %s\n",
14771 address);
14772
14773 q = find_queue (pid, address);
14774 if (NULL == q)
14775 {
14777 }
14778 else
14781}

References address, find_queue(), GNUNET_asprintf(), 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 14792 of file gnunet-service-transport.c.

14795{
14796 const struct GNUNET_PeerIdentity *my_identity;
14797 struct PeerRequest *pr = cls;
14799 const struct GNUNET_MessageHeader *hello;
14800
14801 if (NULL != emsg)
14802 {
14804 "Got failure from PEERSTORE: %s\n",
14805 emsg);
14807 return;
14808 }
14809 if (NULL == record)
14810 {
14811 GNUNET_break (0);
14813 return;
14814 }
14816 if (NULL == my_identity)
14817 {
14819 "No identity given yet!\n");
14821 return;
14822 }
14823 hello = hello_from_record (record);
14824 if (NULL == hello)
14825 {
14826 /* MUST still ask for the next record: a bad one is not a reason to
14827 stall this monitor forever. */
14829 return;
14830 }
14831 if (0 == GNUNET_memcmp (&record->peer, my_identity))
14832 {
14834 return;
14835 }
14836 parser = GNUNET_HELLO_parser_from_msg (hello, &record->peer);
14837 if (NULL == parser)
14838 {
14840 "HELLO cannot be parsed!\n");
14842 return;
14843 }
14845 "HELLO for `%s' could be parsed, iterating addresses...!\n",
14849 NULL);
14850 GNUNET_HELLO_parser_free (parser);
14851 /* MUST ask for the next record, or this monitor stalls after one HELLO */
14853}

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 handle_suggest().

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

14858{
14860 "Error in PEERSTORE monitoring\n");
14861}

References GNUNET_ERROR_TYPE_WARNING, and GNUNET_log.

Referenced by handle_suggest().

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

14866{
14868 "Done with initial PEERSTORE iteration during monitoring\n");
14869}

References GNUNET_ERROR_TYPE_DEBUG, and GNUNET_log.

Referenced by handle_suggest().

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

14881{
14882 struct TransportClient *tc = cls;
14883 const struct GNUNET_PeerIdentity *my_identity;
14884 struct PeerRequest *pr;
14885
14886 if (CT_NONE == tc->type)
14887 {
14888 tc->type = CT_APPLICATION;
14889 tc->details.application.requests =
14891 }
14892 if (CT_APPLICATION != tc->type)
14893 {
14894 GNUNET_break (0);
14896 return;
14897 }
14899 if (NULL == my_identity)
14900 {
14902 "Still waiting for own identity!\n");
14904 return;
14905 }
14907 "Client suggested we talk to %s with preference %d at rate %u\n",
14908 GNUNET_i2s (&msg->peer),
14909 (int) ntohl (msg->pk),
14910 (int) ntohl (msg->bw.value__));
14911 if (0 == GNUNET_memcmp (my_identity, &msg->peer))
14912 {
14914 "Client suggested connection to ourselves, ignoring...\n");
14916 return;
14917 }
14918 pr = GNUNET_new (struct PeerRequest);
14919 pr->tc = tc;
14920 pr->pid = msg->peer;
14921 pr->bw = msg->bw;
14922 pr->pk = ntohl (msg->pk);
14924 tc->details.application.requests,
14925 &pr->pid,
14926 pr,
14928 {
14929 GNUNET_break (0);
14930 GNUNET_free (pr);
14932 return;
14933 }
14934 pr->nc =
14936 GNUNET_YES,
14937 "peerstore",
14938 NULL,
14941 NULL,
14943 NULL,
14945 pr);
14947}

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_PEERSTORE_HELLO_KEY, GNUNET_PEERSTORE_monitor_start(), GNUNET_PILS_get_identity(), GNUNET_SERVICE_client_continue(), GNUNET_SERVICE_client_drop(), GNUNET_YES, GST_cfg, handle_hello_for_client(), hello_for_client_error_cb(), hello_for_client_sync_cb(), msg, my_identity, pils, PeerRequest::pr, 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 14959 of file gnunet-service-transport.c.

14961{
14962 (void) cls;
14964 return GNUNET_OK;
14965}

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

14978{
14979 struct TransportClient *tc = cls;
14980 struct Queue *q;
14981
14982 q = find_queue (&m->peer, (const char *) &m[1]);
14983 if (NULL == q)
14984 {
14985 suggest_to_connect (&m->peer, (const char *) &m[1]);
14986 }
14987 else
14988 start_address_validation (&m->peer, (const char *) &m[1]);
14990}

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

15005{
15006 struct Neighbour *neighbour = value;
15007
15008 (void) cls;
15009 (void) pid;
15010 GNUNET_break (0); // should this ever happen?
15011 free_neighbour (neighbour, GNUNET_YES);
15012
15013 return GNUNET_OK;
15014}

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

15035{
15036 struct VirtualLink *vl = value;
15037
15038 (void) cls;
15039 (void) pid;
15040 free_virtual_link (vl);
15041
15042 return GNUNET_OK;
15043}

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

15058{
15059 struct DistanceVector *dv = value;
15060
15061 (void) cls;
15062 (void) pid;
15063 free_dv_route (dv);
15064
15065 return GNUNET_OK;
15066}

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

15081{
15082 struct ValidationState *vs = value;
15083
15084 (void) cls;
15085 (void) pid;
15087 return GNUNET_OK;
15088}

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

15101{
15102 struct PendingAcknowledgement *pa = value;
15103
15104 (void) cls;
15105 (void) key;
15107 return GNUNET_OK;
15108}

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

15123{
15124 struct AcknowledgementCummulator *ac = value;
15125
15126 (void) cls;
15127 (void) pid;
15129 GNUNET_free (ac);
15130 return GNUNET_OK;
15131}

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

15283{
15284 switch (type)
15285 {
15286 case CT_CORE:
15287 return "CORE";
15288 case CT_MONITOR:
15289 return "MONITOR";
15290 case CT_COMMUNICATOR:
15291 return "COMMUNICATOR";
15292 case CT_APPLICATION:
15293 return "APPLICATION";
15294 default:
15295 return "UNKNOWN";
15296 }
15297}

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

15309{
15310 client_grace_task = NULL;
15311 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
15312 {
15314 "Client did not disconnect within the shutdown grace period, "
15315 "dropping it: %s\n",
15316 get_client_type_name (tc->type));
15317 }
15318 /* We use #GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN, so the service will NOT
15319 drop clients for us. Without this we would wait forever for them to
15320 leave on their own and never reach #do_shutdown(). */
15322 /* Dropping the clients ran #client_disconnect_cb() for each of them, so
15323 #do_shutdown() has normally run by now; it is idempotent, and this
15324 covers the case where there was nothing left to drop. */
15325 do_shutdown (cls);
15326}

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

15331{
15333
15335 "Shutdown task executed\n");
15336 if (NULL != clients_head)
15337 {
15338 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
15339 {
15341 "Waiting for client to disconnect: %s\n",
15342 get_client_type_name (tc->type));
15343 }
15344 /* Give them a chance to shut down cleanly; #client_disconnect_cb() calls
15345 #do_shutdown() once the last one is gone, and #do_shutdown() cancels
15346 this task. */
15350 cls);
15351 return;
15352 }
15353 do_shutdown (cls);
15354}

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

15364{
15365 struct UpdateHelloFromPidCtx *pc = cls;
15366
15367 /* NOTE: @a success is GNUNET_OK even when #hello_add_iter() decided not to
15368 store anything because PEERSTORE already holds a HELLO that expires
15369 later; the API reports the desired state, not whether it wrote. So this
15370 says "we have a current HELLO on record", not "we just wrote one". */
15371 if (GNUNET_OK != success)
15373 "Failed to store our new hello with peerstore\n");
15374 else
15376 "Our hello is current in peerstore\n");
15377 GNUNET_free (pc);
15378}

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

15385{
15387 "%s\n", uri);
15388}

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

15404{
15405 const struct GNUNET_PeerIdentity *my_identity;
15406 struct GNUNET_MQ_Envelope *env;
15407 const struct GNUNET_MessageHeader *msg;
15408 struct UpdateHelloFromPidCtx *sc;
15409 struct GNUNET_HELLO_Builder *nbuilder;
15410 struct GNUNET_PeerIdentity npid;
15411
15414
15415 if (NULL == GST_my_hello)
15418 "My current identity is `%s'\n",
15430 nbuilder = GNUNET_HELLO_builder_from_parser (parser,
15431 &npid);
15432 if (GNUNET_NO ==
15434 {
15436 "New PID from PILS is derived from address list inconsistent with ours. Ignoring...\n");
15438 "Proposed address list:\n");
15441 "Current address list:\n");
15443 GNUNET_HELLO_builder_free (nbuilder);
15444 return;
15445 }
15447 GST_my_hello = nbuilder;
15449 "My new identity is `%s'\n",
15455 msg,
15457 sc);
15458 GNUNET_free (env);
15459}

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

15473{
15474 (void) cls;
15475 /* setup globals */
15479 GST_cfg = c;
15487 GNUNET_YES);
15492 // TODO check for all uses of GST_my_hello that it is not used uninitialized
15494 "transport",
15495 "USE_BURST_NAT");
15496 if (GNUNET_SYSERR == use_burst)
15498 "Could not configure burst nat use. Default to no.\n");
15504 "transport",
15505 0,
15506 0,
15507 NULL,
15508 0,
15509 NULL,
15510 NULL,
15511 NULL);
15512 if (NULL == peerstore)
15513 {
15514 GNUNET_break (0);
15516 return;
15517 }
15520 NULL); // FIXME we need to wait for
15521 // our first peer id before
15522 // we can start the service
15523 // completely - PILS in turn
15524 // waits for the first
15525 // addresses from the
15526 // communicators in order to
15527 // be able to generate a
15528 // peer id
15529 if (NULL == pils)
15530 {
15531 GNUNET_break (0);
15533 return;
15534 }
15535 /* Decapsulate DV box ephemeral keys ourselves. #handle_dv_box() needs
15536 the key material while it still has the box, which points into the
15537 communicator's inbound message and is gone the moment the handler
15538 returns -- so the asynchronous answer arrived to a dangling @a dvb. */
15539 if (GNUNET_OK !=
15542 _ ("Failed to load our private key, "
15543 "cannot open DV boxes addressed to us\n"));
15544}

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

Referenced by 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 3077 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 3082 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 3087 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 3092 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 3097 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 3107 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 3124 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 3130 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 3141 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 3147 of file gnunet-service-transport.c.

Referenced by decaps_dv_box_cont(), 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 3153 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 3159 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 3165 of file gnunet-service-transport.c.

Referenced by 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 3171 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 3177 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 3188 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 3193 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 3198 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 3205 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 3210 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 3303 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 3308 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 3313 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 3318 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 3325 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 3330 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 3335 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 3340 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 3345 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 3355 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 3361 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 3366 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 3373 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 3375 of file gnunet-service-transport.c.

Referenced by do_shutdown(), and start_burst().

◆ use_burst

enum GNUNET_GenericReturnValue use_burst

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

Referenced by queue_burst(), and run().