GNUnet 0.26.2-114-g7c6b613e3
 
Loading...
Searching...
No Matches
gnunet-service-core_sessions.c
Go to the documentation of this file.
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2014, 2016, 2026 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
26#include "gnunet_common.h"
27#include "platform.h"
28#include "gnunet-service-core.h"
31#include "gnunet_constants.h"
32#include "core.h"
33
34
39#define MAX_ENCRYPTED_MESSAGE_QUEUE_SIZE 4
40
41
77
78
82struct Session
83{
88
93
99
105
110
115
116 // TODO
117 // struct GSC_ServicesInfo *services;
118
123
128};
129
130
135
136
144static struct Session *
146{
147 if (NULL == sessions)
148 return NULL;
150}
151
152
159void
161{
162 struct Session *session;
163 struct GSC_ClientActiveRequest *car;
164 struct SessionMessageEntry *sme;
165
166 if (NULL == pid)
167 {
168 /* We might not know the peer_id yet. */
169 return;
170 }
171 session = find_session (pid);
172 if (NULL == session)
173 return;
175 "Destroying session for peer `%s'\n",
176 GNUNET_i2s (session->peer));
177 if (NULL != session->cork_task)
178 {
180 session->cork_task = NULL;
181 }
182 while (NULL != (car = session->active_client_request_head))
183 {
186 car);
188 }
189 while (NULL != (sme = session->sme_head))
190 {
191 GNUNET_CONTAINER_DLL_remove (session->sme_head, session->sme_tail, sme);
192 GNUNET_free (sme);
193 }
194 // TODO
196 session->class);
198 GNUNET_YES ==
201 gettext_noop ("# peers connected"),
203 GNUNET_NO);
204 // TODO
205 // GSC_SVCI_destroy (session->services);
206 GNUNET_free (session);
207}
208
209
217void
219 struct GSC_KeyExchangeInfo *kx,
220 enum GNUNET_CORE_PeerClass class)
221{
222 struct Session *session;
223
225 "Creating session for peer `%s'\n",
226 GNUNET_i2s (peer));
227 session = GNUNET_new (struct Session);
228 // TODO
229 // session->services = GSC_SVCI_init ();
230 session->peer = peer;
231 session->kx = kx;
232 session->class = class;
235 sessions,
236 session->peer,
237 session,
240 gettext_noop ("# peers connected"),
242 GNUNET_NO);
243 // TODO
245 session->class);
246}
247
248
257void
259{
260 struct Session *session;
261
262 session = find_session (peer);
263 if (NULL == session)
264 {
265 /* KX/session is new for both sides; thus no need to restart what
266 has not yet begun */
267 return;
268 }
269}
270
271
280static int
282 const struct GNUNET_PeerIdentity *key,
283 void *value)
284{
285 struct GSC_Client *client = cls;
286 struct Session *session = value;
287
288 // TODO
290 session->peer,
291 session->class);
292 return GNUNET_OK;
293}
294
295
301void
303{
304 /* notify new client about existing sessions */
307 client);
308}
309
310
317static void
318try_transmission (struct Session *session);
319
320
330void
332{
333 struct Session *session;
334
335 session = find_session (&car->target);
336 if (NULL == session)
337 {
339 "Dropped client request for transmission (am disconnected)\n");
340 GNUNET_break (0); /* should have been rejected earlier */
342 return;
343 }
345 {
346 GNUNET_break (0);
348 return;
349 }
351 "Received client transmission request. queueing\n");
354 car);
355 try_transmission (session);
356}
357
358
365void
367{
368 const struct GNUNET_PeerIdentity *my_identity;
369 struct Session *session;
371 if (NULL == my_identity)
372 return;
373
374 if (0 == memcmp (&car->target,
376 sizeof(struct GNUNET_PeerIdentity)))
377 return;
378 session = find_session (&car->target);
379 GNUNET_assert (NULL != session);
382 car);
383 /* dequeueing of 'high' priority messages may unblock
384 transmission for lower-priority messages, so we also
385 need to try in this case. */
386 try_transmission (session);
387}
388
389
397static void
398solicit_messages (struct Session *session, size_t msize)
399{
400 struct GSC_ClientActiveRequest *car;
401 struct GSC_ClientActiveRequest *nxt;
402 size_t so_size;
404
405 so_size = msize;
407 for (car = session->active_client_request_head; NULL != car; car = car->next)
408 {
409 if (GNUNET_YES == car->was_solicited)
410 continue;
411 pmax = GNUNET_MAX (pmax, car->priority & GNUNET_MQ_PRIORITY_MASK);
412 }
413 nxt = session->active_client_request_head;
414 while (NULL != (car = nxt))
415 {
416 nxt = car->next;
417 if (car->priority < pmax)
418 continue;
420 break;
421 so_size += car->msize;
422 if (GNUNET_YES == car->was_solicited)
423 continue;
426 "Soliciting message with priority %u\n",
427 car->priority);
429 /* The above call may *dequeue* requests and thereby
430 clobber 'nxt'. Hence we need to restart from the
431 head of the list. */
432 nxt = session->active_client_request_head;
433 so_size = msize;
434 }
435}
436
437
444static void
445pop_cork_task (void *cls)
446{
447 struct Session *session = cls;
448
449 session->cork_task = NULL;
450 try_transmission (session);
451}
452
453
461static void
462try_transmission (struct Session *session)
463{
464 struct SessionMessageEntry *pos;
465 size_t msize;
466 struct GNUNET_TIME_Absolute now;
467 struct GNUNET_TIME_Absolute min_deadline;
470 struct GSC_ClientActiveRequest *car;
471 int excess;
472
473 msize = 0;
474 min_deadline = GNUNET_TIME_UNIT_FOREVER_ABS;
475 /* if the peer has excess bandwidth, background traffic is allowed,
476 otherwise not */
479 {
481 "Transmission queue already very long, waiting...\n");
482 return; /* queue already too long */
483 }
484 excess = GSC_NEIGHBOURS_check_excess_bandwidth (session->kx);
485 if (GNUNET_YES == excess)
487 else
489 /* determine highest priority of 'ready' messages we already solicited from clients */
490 pos = session->sme_head;
491 while ((NULL != pos) &&
493 {
495 msize += pos->size;
496 maxp = GNUNET_MAX (maxp, pos->priority & GNUNET_MQ_PRIORITY_MASK);
497 min_deadline = GNUNET_TIME_absolute_min (min_deadline, pos->deadline);
498 pos = pos->next;
499 }
500 GNUNET_log (
502 "Calculating transmission set with %u priority (%s) and %s earliest deadline\n",
503 maxp,
504 (GNUNET_YES == excess) ? "excess bandwidth" : "limited bandwidth",
506 min_deadline),
507 GNUNET_YES));
508
510 {
511 /* if highest already solicited priority from clients is not critical,
512 check if there are higher-priority messages to be solicited from clients */
513 if (GNUNET_YES == excess)
515 else
517 for (car = session->active_client_request_head; NULL != car;
518 car = car->next)
519 {
520 if (GNUNET_YES == car->was_solicited)
521 continue;
522 maxpc = GNUNET_MAX (maxpc, car->priority & GNUNET_MQ_PRIORITY_MASK);
523 }
524 if (maxpc > maxp)
525 {
526 /* we have messages waiting for solicitation that have a higher
527 priority than those that we already accepted; solicit the
528 high-priority messages first */
530 "Soliciting messages based on priority (%u > %u)\n",
531 maxpc,
532 maxp);
533 solicit_messages (session, 0);
534 return;
535 }
536 }
537 else
538 {
539 /* never solicit more, we have critical messages to process */
540 excess = GNUNET_NO;
542 }
544 if (((GNUNET_YES == excess) || (maxpc >= GNUNET_MQ_PRIO_BEST_EFFORT)) &&
545 ((0 == msize) ||
547 (min_deadline.abs_value_us > now.abs_value_us))))
548 {
549 /* not enough ready yet (tiny message & cork possible), or no messages at all,
550 and either excess bandwidth or best-effort or higher message waiting at
551 client; in this case, we try to solicit more */
552 GNUNET_log (
554 "Soliciting messages (excess %d, maxpc %d, message size %u, deadline %s)\n",
555 excess,
556 maxpc,
557 (unsigned int) msize,
560 min_deadline),
561 GNUNET_YES));
562 solicit_messages (session, msize);
563 if (msize > 0)
564 {
565 /* if there is data to send, just not yet, make sure we do transmit
566 * it once the deadline is reached */
568 "Corking until %s\n",
571 GNUNET_YES));
572 if (NULL != session->cork_task)
574 session->cork_task =
575 GNUNET_SCHEDULER_add_at (min_deadline, &pop_cork_task, session);
576 }
577 else
578 {
580 "Queue empty, waiting for solicitations\n");
581 }
582 return;
583 }
585 "Building combined plaintext buffer to transmit message!\n");
586 /* create plaintext buffer of all messages (that fit), encrypt and
587 transmit */
588 {
589 static unsigned long long total_bytes;
590 static unsigned int total_msgs;
591 char pbuf[msize]; /* plaintext */
592 size_t used;
593
594 used = 0;
595 while ((NULL != (pos = session->sme_head)) && (used + pos->size <= msize))
596 {
598 "Adding message of type %d to payload for %s\n",
599 ntohs (((const struct GNUNET_MessageHeader *) &pos[1])->type),
600 GNUNET_i2s (session->peer));
601 GNUNET_memcpy (&pbuf[used], &pos[1], pos->size);
602 used += pos->size;
603 GNUNET_CONTAINER_DLL_remove (session->sme_head, session->sme_tail, pos);
604 GNUNET_free (pos);
605 }
606 /* compute average payload size */
607 total_bytes += used;
608 total_msgs++;
609 if (0 == total_msgs)
610 {
611 /* 2^32 messages, wrap around... */
612 total_msgs = 1;
613 total_bytes = used;
614 }
616 "# avg payload per encrypted message",
617 total_bytes / total_msgs,
618 GNUNET_NO);
619 /* now actually transmit... */
620 GSC_KX_encrypt_and_transmit (session->kx, pbuf, used);
621 }
622}
623
624
632void
634{
635 struct Session *session;
636
638 "Transport solicits for %s\n",
639 GNUNET_i2s (pid));
640 session = find_session (pid);
641 if (NULL == session)
642 return;
643 try_transmission (session);
644}
645
646
647void
649 const struct GNUNET_MessageHeader *msg,
650 enum GNUNET_MQ_PriorityPreferences priority)
651{
652 struct Session *session;
653 struct SessionMessageEntry *sme;
654 struct SessionMessageEntry *pos;
655 size_t msize;
656
657 session = find_session (&car->target);
658 if (NULL == session)
659 {
661 return;
662 }
663 msize = ntohs (msg->size);
664 sme = GNUNET_malloc (sizeof(struct SessionMessageEntry) + msize);
665 GNUNET_memcpy (&sme[1], msg, msize);
666 sme->size = msize;
667 sme->priority = priority;
669 {
670 sme->deadline =
673 "Message corked, delaying transmission\n");
674 }
675 pos = session->sme_head;
676 while ((NULL != pos) && (pos->priority >= sme->priority))
677 pos = pos->next;
678 if (NULL == pos)
680 session->sme_tail,
681 sme);
682 else
684 session->sme_tail,
685 pos->prev,
686 sme);
687 try_transmission (session);
688}
689
690
694void
699
700
710static int
712 const struct GNUNET_PeerIdentity *key,
713 void *value)
714{
715 /* struct Session *session = value; */
716
718 return GNUNET_OK;
719}
720
721
725void
737
738
739/* end of gnunet-service-core_sessions.c */
struct GNUNET_MessageHeader * msg
Definition 005.c:2
common internal definitions for core service
#define gettext_noop(String)
Definition gettext.h:74
struct GNUNET_HashCode key
The key used in the DHT.
static char * value
Value of the record to add/remove.
static uint32_t type
Type string converted to DNS type value.
static struct GNUNET_PeerIdentity my_identity
Identity of this peer.
void GSC_CLIENTS_notify_client_about_neighbour(struct GSC_Client *client, const struct GNUNET_PeerIdentity *neighbour, enum GNUNET_CORE_PeerClass class)
Notify a particular client about a change to existing connection to one of our neighbours (check if t...
void GSC_CLIENTS_reject_request(struct GSC_ClientActiveRequest *car, int drop_client)
We will never be ready to transmit the given message in (disconnect or invalid request).
struct GNUNET_PILS_Handle * GSC_pils
For peer identity access.
void GSC_CLIENTS_notify_clients_about_neighbour(const struct GNUNET_PeerIdentity *neighbour, enum GNUNET_CORE_PeerClass class)
Notify all clients about a change to existing session.
struct GNUNET_STATISTICS_Handle * GSC_stats
For creating statistics.
void GSC_CLIENTS_solicit_request(struct GSC_ClientActiveRequest *car)
Tell a client that we are ready to receive the message.
Globals for gnunet-service-core.
unsigned int GSC_NEIGHBOURS_get_queue_length(const struct GSC_KeyExchangeInfo *kxinfo)
Check how many messages are queued for the given neighbour.
int GSC_NEIGHBOURS_check_excess_bandwidth(const struct GSC_KeyExchangeInfo *kxinfo)
Check if the given neighbour has excess bandwidth available.
void GSC_KX_encrypt_and_transmit(struct GSC_KeyExchangeInfo *kx, const void *payload, size_t payload_size)
Encrypt and transmit payload.
code for managing the key exchange (SET_KEY, PING, PONG) with other peers
void GSC_SESSIONS_dequeue_request(struct GSC_ClientActiveRequest *car)
Dequeue a request from a client from transmission to a particular peer.
void GSC_SESSIONS_reinit(const struct GNUNET_PeerIdentity *peer)
The other peer has indicated that it 'lost' the session (KX down), reinitialize the session on our en...
static struct Session * find_session(const struct GNUNET_PeerIdentity *peer)
Find the session for the given peer.
static int free_session_helper(void *cls, const struct GNUNET_PeerIdentity *key, void *value)
Helper function for GSC_SESSIONS_done() to free all active sessions.
static int notify_client_about_session(void *cls, const struct GNUNET_PeerIdentity *key, void *value)
Notify the given client about the session (client is new).
void GSC_SESSIONS_transmit(struct GSC_ClientActiveRequest *car, const struct GNUNET_MessageHeader *msg, enum GNUNET_MQ_PriorityPreferences priority)
Transmit a message to a particular peer.
void GSC_SESSIONS_end(const struct GNUNET_PeerIdentity *pid)
End the session with the given peer (we are no longer connected).
void GSC_SESSIONS_solicit(const struct GNUNET_PeerIdentity *pid)
Traffic is being solicited for the given peer.
static struct GNUNET_CONTAINER_MultiPeerMap * sessions
Map of peer identities to struct Session.
void GSC_SESSIONS_create(const struct GNUNET_PeerIdentity *peer, struct GSC_KeyExchangeInfo *kx, enum GNUNET_CORE_PeerClass class)
Create a session, a key exchange was just completed.
void GSC_SESSIONS_notify_client_about_sessions(struct GSC_Client *client)
We have a new client, notify it about all current sessions.
static void pop_cork_task(void *cls)
Some messages were delayed (corked), but the timeout has now expired.
static void try_transmission(struct Session *session)
Try to perform a transmission on the given session.
static void solicit_messages(struct Session *session, size_t msize)
Solicit messages for transmission, starting with those of the highest priority.
void GSC_SESSIONS_init()
Initialize sessions subsystem.
#define MAX_ENCRYPTED_MESSAGE_QUEUE_SIZE
How many encrypted messages do we queue at most? Needed to bound memory consumption.
void GSC_SESSIONS_queue_request(struct GSC_ClientActiveRequest *car)
Queue a request from a client for transmission to a particular peer.
void GSC_SESSIONS_done()
Shutdown sessions subsystem.
static struct GNUNET_PeerIdentity pid
Identity of the peer we transmit to / connect to.
commonly used definitions; globals in this file are exempt from the rule that the module name ("commo...
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:727
#define GNUNET_CONSTANTS_MAX_CORK_DELAY
How long do we delay messages to get larger packet sizes (CORKing)?
#define GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE
What is the maximum size for encrypted messages? Note that this number imposes a clear limit on the m...
GNUNET_CORE_PeerClass
The peer class gives a hint about the capabilities of a peer.
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert_after(head, tail, other, element)
Insert an element into a DLL after the given other element.
#define GNUNET_CONTAINER_DLL_insert_tail(head, tail, element)
Insert an element at the tail of a DLL.
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.
void GNUNET_CONTAINER_multipeermap_destroy(struct GNUNET_CONTAINER_MultiPeerMap *map)
Destroy a hash 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.
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).
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.
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_UNIQUE_ONLY
There must only be one value per key; storing a value should fail if a value under the same key alrea...
#define GNUNET_log(kind,...)
#define GNUNET_MAX(a, b)
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format.
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
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.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
@ GNUNET_ERROR_TYPE_DEBUG
#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.
GNUNET_MQ_PriorityPreferences
Per envelope preferences and priorities.
@ GNUNET_MQ_PRIO_CRITICAL_CONTROL
Highest priority, control traffic (e.g.
@ GNUNET_MQ_PRIORITY_MASK
Bit mask to apply to extract the priority bits.
@ GNUNET_MQ_PRIO_BACKGROUND
Lowest priority, i.e.
@ GNUNET_MQ_PREF_CORK_ALLOWED
Flag to indicate that CORKing is acceptable.
@ GNUNET_MQ_PRIO_BEST_EFFORT
Best-effort traffic (e.g.
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
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition scheduler.c:986
void GNUNET_STATISTICS_set(struct GNUNET_STATISTICS_Handle *handle, const char *name, uint64_t value, int make_persistent)
Set statistic value for the peer.
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
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:604
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition time.c:111
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_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_FOREVER_ABS
Constant used to specify "forever".
Internal representation of the hash map.
Header for all communications.
The identity of the host (wraps the signing key of the peer).
Entry in list of pending tasks.
Definition scheduler.c:141
Time for absolute times used by GNUnet, in microseconds.
uint64_t abs_value_us
The actual value.
Record kept for each request for transmission issued by a client that is still pending.
struct GSC_ClientActiveRequest * next
Active requests are kept in a doubly-linked list of the respective target peer.
struct GNUNET_PeerIdentity target
Which peer is the message going to be for?
int was_solicited
Has this request been solicited yet?
uint16_t msize
How many bytes does the client intend to send?
enum GNUNET_MQ_PriorityPreferences priority
How important is this request.
Data structure for each client connected to the CORE service.
struct GNUNET_SERVICE_Client * client
Handle for the client with the server API.
Information about the status of a key exchange with another peer.
Message ready for encryption.
struct GNUNET_TIME_Absolute deadline
Deadline for transmission, 1s after we received it (if we are not corking), otherwise "now".
size_t size
How long is the message? (number of bytes following the struct MessageEntry, but not including the si...
struct SessionMessageEntry * next
We keep messages in a doubly linked list.
struct SessionMessageEntry * prev
We keep messages in a doubly linked list.
enum GNUNET_MQ_PriorityPreferences priority
How important is this message.
Data kept per session.
struct SessionMessageEntry * sme_head
Head of list of messages ready for encryption.
struct SessionMessageEntry * sme_tail
Tail of list of messages ready for encryption.
const struct GNUNET_PeerIdentity * peer
Identity of the other peer.
struct GSC_ClientActiveRequest * active_client_request_head
Head of list of requests from clients for transmission to this peer.
enum GNUNET_CORE_PeerClass class
Class of the peer.
struct GNUNET_SCHEDULER_Task * cork_task
Task to transmit corked messages with a delay.
struct GSC_KeyExchangeInfo * kx
Key exchange state for this peer.
struct GSC_ClientActiveRequest * active_client_request_tail
Tail of list of requests from clients for transmission to this peer.