2 * @file connect_manager.c
4 * @brief Implementation of connect_manager_t.
9 * Copyright (C) 2007 Tobias Brunner
10 * Hochschule fuer Technik Rapperswil
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 #include "connect_manager.h"
29 #include <utils/linked_list.h>
31 #include <processing/jobs/callback_job.h>
32 #include <processing/jobs/initiate_mediation_job.h>
33 #include <encoding/payloads/endpoint_notify.h>
36 // the sending interval is P2P_INTERVAL * active checklists (N)
37 // retransmission timeout is P2P_INTERVAL * N * checks in waiting state (NW)
38 #define P2P_INTERVAL 20 // 20 ms
39 // min retransmission timeout (RTO is P2P_INTERVAL * N * checks in waiting state)
40 #define P2P_RTO_MIN 100 // 100 ms
41 // max number of retransmissions (+ the initial check)
42 #define P2P_MAX_RETRANS 2
45 typedef struct private_connect_manager_t private_connect_manager_t
;
48 * Additional private members of connect_manager_t.
50 struct private_connect_manager_t
{
52 * Public interface of connect_manager_t.
54 connect_manager_t
public;
57 * Lock for exclusivly accessing the manager.
59 pthread_mutex_t mutex
;
62 * Hasher to generate signatures
67 * Linked list with initiated mediated connections
69 linked_list_t
*initiated
;
72 * Linked list with checklists (hash table with session ID as key would be better).
74 linked_list_t
*checklists
;
77 typedef enum check_state_t check_state_t
;
87 typedef struct endpoint_pair_t endpoint_pair_t
;
90 * An entry in the check list.
92 struct endpoint_pair_t
{
102 /** remote endpoint */
108 /** number of retransmissions */
109 u_int32_t retransmitted
;
111 /** the generated packet */
116 * Destroys an endpoint pair
118 static void endpoint_pair_destroy(endpoint_pair_t
*this)
120 DESTROY_IF(this->local
);
121 DESTROY_IF(this->remote
);
122 DESTROY_IF(this->packet
);
127 * Creates a new entry for the list.
129 static endpoint_pair_t
*endpoint_pair_create(endpoint_notify_t
*initiator
,
130 endpoint_notify_t
*responder
, bool initiator_is_local
)
132 endpoint_pair_t
*this = malloc_thing(endpoint_pair_t
);
136 u_int32_t pi
= initiator
->get_priority(initiator
);
137 u_int32_t pr
= responder
->get_priority(responder
);
138 this->priority
= pow(2, 32) * min(pi
, pr
) + 2 * max(pi
, pr
) + (pi
> pr ?
1 : 0);
140 this->local
= initiator_is_local ? initiator
->get_base(initiator
) : responder
->get_base(responder
);
141 this->local
= this->local
->clone(this->local
);
142 this->remote
= initiator_is_local ? responder
->get_host(responder
) : initiator
->get_host(initiator
);
143 this->remote
= this->remote
->clone(this->remote
);
145 this->state
= CHECK_WAITING
;
146 this->retransmitted
= 0;
153 typedef struct check_list_t check_list_t
;
156 * An entry in the linked list.
158 struct check_list_t
{
161 /** initiator's id */
162 identification_t
*id
;
164 /** initiator's key */
167 /** initiator's endpoints */
168 linked_list_t
*endpoints
;
172 /** responder's id */
173 identification_t
*id
;
175 /** responder's key */
178 /** responder's endpoints */
179 linked_list_t
*endpoints
;
185 /** list of endpoint pairs */
186 linked_list_t
*pairs
;
188 /** pairs queued for triggered checks */
189 linked_list_t
*triggered
;
194 /** TRUE if this is the initiator */
200 * Destroys a checklist
202 static void check_list_destroy(check_list_t
*this)
204 DESTROY_IF(this->initiator
.id
);
205 DESTROY_IF(this->responder
.id
);
207 chunk_free(&this->session_id
);
208 chunk_free(&this->initiator
.key
);
209 chunk_free(&this->responder
.key
);
211 DESTROY_OFFSET_IF(this->initiator
.endpoints
, offsetof(endpoint_notify_t
, destroy
));
212 DESTROY_OFFSET_IF(this->responder
.endpoints
, offsetof(endpoint_notify_t
, destroy
));
214 DESTROY_FUNCTION_IF(this->pairs
, (void*)endpoint_pair_destroy
);
215 DESTROY_IF(this->triggered
); // this list contains some of the same elements as contained in this->pairs
221 * Creates a new checklist
223 static check_list_t
*check_list_create(identification_t
*initiator
, identification_t
*responder
,
224 chunk_t session_id
, chunk_t initiator_key
, linked_list_t
*initiator_endpoints
,
227 check_list_t
*this = malloc_thing(check_list_t
);
229 this->session_id
= chunk_clone(session_id
);
231 this->initiator
.id
= initiator
->clone(initiator
);
232 this->initiator
.key
= chunk_clone(initiator_key
);
233 this->initiator
.endpoints
= initiator_endpoints
->clone_offset(initiator_endpoints
, offsetof(endpoint_notify_t
, clone
));
235 this->responder
.id
= responder
->clone(responder
);
236 this->responder
.key
= chunk_empty
;
237 this->responder
.endpoints
= NULL
;
239 this->pairs
= linked_list_create();
240 this->triggered
= linked_list_create();
241 this->state
= CHECK_NONE
;
242 this->is_initiator
= is_initiator
;
248 typedef struct waiting_sa_t waiting_sa_t
;
251 * For an initiator, the data stored about a waiting mediated sa
253 struct waiting_sa_t
{
255 ike_sa_id_t
*ike_sa_id
;
257 /** list of child_cfg_t */
258 linked_list_t
*childs
;
262 * Destroys a queued mediated sa
264 static void waiting_sa_destroy(waiting_sa_t
*this)
266 DESTROY_IF(this->ike_sa_id
);
267 this->childs
->destroy_offset(this->childs
, offsetof(child_cfg_t
, destroy
));
272 * Creates a new mediated sa object
274 static waiting_sa_t
*waiting_sa_create(ike_sa_id_t
*ike_sa_id
)
276 waiting_sa_t
*this = malloc_thing(waiting_sa_t
);
278 this->ike_sa_id
= ike_sa_id
->clone(ike_sa_id
);
279 this->childs
= linked_list_create();
284 typedef struct initiated_t initiated_t
;
287 * For an initiator, the data stored about initiated mediation connections
291 identification_t
*id
;
294 identification_t
*peer_id
;
296 /** list of mediated sas */
297 linked_list_t
*mediated
;
301 * Destroys a queued initiation
303 static void initiated_destroy(initiated_t
*this)
305 DESTROY_IF(this->id
);
306 DESTROY_IF(this->peer_id
);
307 this->mediated
->destroy_function(this->mediated
, (void*)waiting_sa_destroy
);
312 * Creates a queued initiation
314 static initiated_t
*initiated_create(identification_t
*id
, identification_t
*peer_id
)
316 initiated_t
*this = malloc_thing(initiated_t
);
318 this->id
= id
->clone(id
);
319 this->peer_id
= peer_id
->clone(peer_id
);
320 this->mediated
= linked_list_create();
326 typedef struct check_t check_t
;
329 * Data exchanged in a connectivity check
335 /** source of the connectivity check */
338 /** destination of the connectivity check */
345 endpoint_notify_t
*endpoint
;
347 /** raw endpoint payload (to verify the signature) */
348 chunk_t endpoint_raw
;
355 * Destroys a connectivity check
357 static void check_destroy(check_t
*this)
359 chunk_free(&this->session_id
);
360 chunk_free(&this->endpoint_raw
);
361 chunk_free(&this->cookie
);
362 DESTROY_IF(this->endpoint
);
367 * Creates a new connectivity check
369 static check_t
*check_create()
371 check_t
*this = malloc_thing(check_t
);
373 this->session_id
= chunk_empty
;
374 this->cookie
= chunk_empty
;
375 this->endpoint_raw
= chunk_empty
;
376 this->endpoint
= NULL
;
383 typedef struct sender_data_t sender_data_t
;
386 * Data required by the sender
388 struct sender_data_t
{
389 /** connect manager */
390 private_connect_manager_t
*connect_manager
;
397 * Destroys a sender data object
399 static void sender_data_destroy(sender_data_t
*this)
401 chunk_free(&this->session_id
);
406 * Creates a new sender data object
408 static sender_data_t
*sender_data_create(private_connect_manager_t
*connect_manager
, chunk_t session_id
)
410 sender_data_t
*this = malloc_thing(sender_data_t
);
411 this->connect_manager
= connect_manager
;
412 this->session_id
= session_id
;
416 typedef struct retransmit_data_t retransmit_data_t
;
419 * Data required by the retransmission job
421 struct retransmit_data_t
{
422 /** connect manager */
423 private_connect_manager_t
*connect_manager
;
428 /** message (pair) id */
433 * Destroys a retransmission data object
435 static void retransmit_data_destroy(retransmit_data_t
*this)
437 chunk_free(&this->session_id
);
442 * Creates a new retransmission data object
444 static retransmit_data_t
*retransmit_data_create(private_connect_manager_t
*connect_manager
,
445 chunk_t session_id
, u_int32_t mid
)
447 retransmit_data_t
*this = malloc_thing(retransmit_data_t
);
449 this->connect_manager
= connect_manager
;
450 this->session_id
= session_id
;
456 typedef struct initiate_data_t initiate_data_t
;
459 * Data required by the initiate mediated
461 struct initiate_data_t
{
463 check_list_t
*checklist
;
465 /** waiting mediated connections */
466 initiated_t
*initiated
;
470 * Destroys a initiate data object
472 static void initiate_data_destroy(initiate_data_t
*this)
474 check_list_destroy(this->checklist
);
475 initiated_destroy(this->initiated
);
480 * Creates a new initiate data object
482 static initiate_data_t
*initiate_data_create(check_list_t
*checklist
, initiated_t
*initiated
)
484 initiate_data_t
*this = malloc_thing(initiate_data_t
);
486 this->checklist
= checklist
;
487 this->initiated
= initiated
;
492 // -----------------------------------------------------------------------------
495 * Find an initiated connection by the peers' ids
497 static status_t
get_initiated_by_ids(private_connect_manager_t
*this,
498 identification_t
*id
, identification_t
*peer_id
, initiated_t
**initiated
)
500 iterator_t
*iterator
;
501 initiated_t
*current
;
502 status_t status
= NOT_FOUND
;
504 iterator
= this->initiated
->create_iterator(this->initiated
, TRUE
);
505 while (iterator
->iterate(iterator
, (void**)¤t
))
507 if (id
->equals(id
, current
->id
) && peer_id
->equals(peer_id
, current
->peer_id
))
511 *initiated
= current
;
517 iterator
->destroy(iterator
);
523 * Removes data about initiated connections
525 static void remove_initiated(private_connect_manager_t
*this, initiated_t
*initiated
)
527 iterator_t
*iterator
;
528 initiated_t
*current
;
530 iterator
= this->initiated
->create_iterator(this->initiated
, TRUE
);
531 while (iterator
->iterate(iterator
, (void**)¤t
))
533 if (current
== initiated
)
535 iterator
->remove(iterator
);
539 iterator
->destroy(iterator
);
545 static status_t
get_waiting_sa(initiated_t
*initiated
, ike_sa_id_t
*ike_sa_id
, waiting_sa_t
**waiting_sa
)
547 iterator_t
*iterator
;
548 waiting_sa_t
*current
;
549 status_t status
= NOT_FOUND
;
551 iterator
= initiated
->mediated
->create_iterator(initiated
->mediated
, TRUE
);
552 while (iterator
->iterate(iterator
, (void**)¤t
))
554 if (ike_sa_id
->equals(ike_sa_id
, current
->ike_sa_id
))
558 *waiting_sa
= current
;
564 iterator
->destroy(iterator
);
570 * Find the checklist with a specific session ID
572 static status_t
get_checklist_by_id(private_connect_manager_t
*this,
573 chunk_t session_id
, check_list_t
**check_list
)
575 iterator_t
*iterator
;
576 check_list_t
*current
;
577 status_t status
= NOT_FOUND
;
579 iterator
= this->checklists
->create_iterator(this->checklists
, TRUE
);
580 while (iterator
->iterate(iterator
, (void**)¤t
))
582 if (chunk_equals(session_id
, current
->session_id
))
586 *check_list
= current
;
592 iterator
->destroy(iterator
);
598 * Removes a checklist
600 static void remove_checklist(private_connect_manager_t
*this, check_list_t
*checklist
)
602 iterator_t
*iterator
;
603 check_list_t
*current
;
605 iterator
= this->checklists
->create_iterator(this->checklists
, TRUE
);
606 while (iterator
->iterate(iterator
, (void**)¤t
))
608 if (current
== checklist
)
610 iterator
->remove(iterator
);
614 iterator
->destroy(iterator
);
618 * Checks if a list of endpoint_notify_t contains a certain host_t
620 static status_t
endpoints_contain(linked_list_t
*endpoints
, host_t
*host
, endpoint_notify_t
**endpoint
)
622 iterator_t
*iterator
;
623 endpoint_notify_t
*current
;
624 status_t status
= NOT_FOUND
;
626 iterator
= endpoints
->create_iterator(endpoints
, TRUE
);
627 while (iterator
->iterate(iterator
, (void**)¤t
))
629 if (host
->equals(host
, current
->get_host(current
)))
639 iterator
->destroy(iterator
);
644 // -----------------------------------------------------------------------------
648 * Updates the state of the whole checklist
650 static void update_checklist_state(check_list_t
*checklist
)
652 iterator_t
*iterator
;
653 endpoint_pair_t
*current
;
654 bool in_progress
= FALSE
, succeeded
= FALSE
;
656 iterator
= checklist
->pairs
->create_iterator(checklist
->pairs
, TRUE
);
657 while (iterator
->iterate(iterator
, (void**)¤t
))
659 switch(current
->state
)
662 // at least one is still waiting -> checklist remains in waiting state
663 iterator
->destroy(iterator
);
665 case CHECK_IN_PROGRESS
:
668 case CHECK_SUCCEEDED
:
673 iterator
->destroy(iterator
);
677 checklist
->state
= CHECK_IN_PROGRESS
;
681 checklist
->state
= CHECK_SUCCEEDED
;
685 checklist
->state
= CHECK_FAILED
;
690 * Inserts an endpoint pair into the list of pairs ordered by priority (high to low)
692 static void insert_pair_by_priority(linked_list_t
*pairs
, endpoint_pair_t
*pair
)
694 iterator_t
*iterator
;
695 endpoint_pair_t
*current
;
696 bool inserted
= FALSE
;
698 iterator
= pairs
->create_iterator(pairs
, TRUE
);
699 while (iterator
->iterate(iterator
, (void**)¤t
))
701 if (current
->priority
< pair
->priority
)
703 iterator
->insert_before(iterator
, pair
);
708 iterator
->destroy(iterator
);
712 pairs
->insert_last(pairs
, pair
);
717 * Searches a list of endpoint_pair_t for a pair with specific host_ts
719 static status_t
get_pair_by_hosts(linked_list_t
*pairs
, host_t
*local
, host_t
*remote
, endpoint_pair_t
**pair
)
721 iterator_t
*iterator
;
722 endpoint_pair_t
*current
;
723 status_t status
= NOT_FOUND
;
725 iterator
= pairs
->create_iterator(pairs
, TRUE
);
726 while (iterator
->iterate(iterator
, (void**)¤t
))
728 if (local
->equals(local
, current
->local
) &&
729 remote
->equals(remote
, current
->remote
))
739 iterator
->destroy(iterator
);
745 * Searches for a pair with a specific id
747 static status_t
get_pair_by_id(check_list_t
*checklist
, u_int32_t id
, endpoint_pair_t
**pair
)
749 iterator_t
*iterator
;
750 endpoint_pair_t
*current
;
751 status_t status
= NOT_FOUND
;
753 iterator
= checklist
->pairs
->create_iterator(checklist
->pairs
, TRUE
);
754 while (iterator
->iterate(iterator
, (void**)¤t
))
756 if (current
->id
== id
)
766 iterator
->destroy(iterator
);
772 * Returns the best pair of state CHECK_SUCCEEDED from a checklist.
774 static status_t
get_best_valid_pair(check_list_t
*checklist
, endpoint_pair_t
**pair
)
776 iterator_t
*iterator
;
777 endpoint_pair_t
*current
;
778 status_t status
= NOT_FOUND
;
780 iterator
= checklist
->pairs
->create_iterator(checklist
->pairs
, TRUE
);
781 while (iterator
->iterate(iterator
, (void**)¤t
))
783 if (current
->state
== CHECK_SUCCEEDED
)
793 iterator
->destroy(iterator
);
799 * Returns and removes the first triggered pair in state CHECK_WAITING.
801 static status_t
get_triggered_pair(check_list_t
*checklist
, endpoint_pair_t
**pair
)
803 iterator_t
*iterator
;
804 endpoint_pair_t
*current
;
805 status_t status
= NOT_FOUND
;
807 iterator
= checklist
->triggered
->create_iterator(checklist
->triggered
, TRUE
);
808 while (iterator
->iterate(iterator
, (void**)¤t
))
810 iterator
->remove(iterator
);
812 if (current
->state
== CHECK_WAITING
)
822 iterator
->destroy(iterator
);
828 * Prunes identical pairs with lower priority from the list
829 * Note: this function also numbers the remaining pairs serially
831 static void prune_pairs(linked_list_t
*pairs
)
833 iterator_t
*iterator
, *search
;
834 endpoint_pair_t
*current
, *other
;
835 bool inserted
= FALSE
;
838 iterator
= pairs
->create_iterator(pairs
, TRUE
);
839 search
= pairs
->create_iterator(pairs
, TRUE
);
840 while (iterator
->iterate(iterator
, (void**)¤t
))
844 while (search
->iterate(search
, (void**)&other
))
846 if (current
== other
)
851 if (current
->local
->equals(current
->local
, other
->local
) &&
852 current
->remote
->equals(current
->remote
, other
->remote
))
854 // since the list of pairs is sorted by priority in descending
855 // order, and we iterate the list from the beginning, we are
856 // sure that the priority of 'other' is lower than that of
857 // 'current', remove it
858 DBG1(DBG_IKE
, "pruning endpoint pair %H - %H with priority %d",
859 other
->local
, other
->remote
, other
->priority
);
860 search
->remove(search
);
861 endpoint_pair_destroy(other
);
864 search
->reset(search
);
866 search
->destroy(search
);
867 iterator
->destroy(iterator
);
871 * Builds a list of endpoint pairs
873 static void build_pairs(check_list_t
*checklist
)
875 iterator_t
*iterator_i
, *iterator_r
;
876 endpoint_notify_t
*initiator
, *responder
;
878 iterator_i
= checklist
->initiator
.endpoints
->create_iterator(checklist
->initiator
.endpoints
, TRUE
);
879 while (iterator_i
->iterate(iterator_i
, (void**)&initiator
))
881 iterator_r
= checklist
->responder
.endpoints
->create_iterator(checklist
->responder
.endpoints
, TRUE
);
882 while (iterator_r
->iterate(iterator_r
, (void**)&responder
))
884 if (initiator
->get_family(initiator
) != responder
->get_family(responder
))
889 insert_pair_by_priority(checklist
->pairs
,
890 endpoint_pair_create(initiator
, responder
, checklist
->is_initiator
));
892 iterator_r
->destroy(iterator_r
);
894 iterator_i
->destroy(iterator_i
);
896 prune_pairs(checklist
->pairs
);
899 // -----------------------------------------------------------------------------
902 * Processes the payloads of a connectivity check and returns the extracted data
904 static status_t
process_payloads(message_t
*message
, check_t
*check
)
906 iterator_t
*iterator
;
909 iterator
= message
->get_payload_iterator(message
);
910 while (iterator
->iterate(iterator
, (void**)&payload
))
912 if (payload
->get_type(payload
) != NOTIFY
)
914 DBG1(DBG_IKE
, "ignoring payload of type '%N' while processing "
915 "connectivity check", payload_type_names
, payload
->get_type(payload
));
919 notify_payload_t
*notify
= (notify_payload_t
*)payload
;
921 switch (notify
->get_notify_type(notify
))
927 DBG1(DBG_IKE
, "connectivity check contains multiple P2P_ENDPOINT notifies");
931 endpoint_notify_t
*endpoint
= endpoint_notify_create_from_payload(notify
);
934 DBG1(DBG_IKE
, "received invalid P2P_ENDPOINT notify");
937 check
->endpoint
= endpoint
;
938 check
->endpoint_raw
= chunk_clone(notify
->get_notification_data(notify
));
939 DBG2(DBG_IKE
, "received P2P_ENDPOINT notify");
944 if (check
->session_id
.ptr
)
946 DBG1(DBG_IKE
, "connectivity check contains multiple P2P_SESSIONID notifies");
949 check
->session_id
= chunk_clone(notify
->get_notification_data(notify
));
950 DBG3(DBG_IKE
, "received p2p_sessionid %B", &check
->session_id
);
955 if (check
->cookie
.ptr
)
957 DBG1(DBG_IKE
, "connectivity check contains multiple COOKIE notifies");
960 check
->cookie
= chunk_clone(notify
->get_notification_data(notify
));
961 DBG3(DBG_IKE
, "received cookie %B", &check
->cookie
);
968 iterator
->destroy(iterator
);
970 if (!check
->session_id
.ptr
|| !check
->endpoint
|| !check
->cookie
.ptr
)
972 DBG1(DBG_IKE
, "at least one payload was missing from the connectivity check");
980 * Builds the signature for a connectivity check
982 static chunk_t
build_signature(private_connect_manager_t
*this,
983 check_list_t
*checklist
, check_t
*check
, bool outbound
)
985 chunk_t mid_chunk
, key_chunk
, sig_chunk
;
988 mid_chunk
= chunk_from_thing(check
->mid
);
990 key_chunk
= (checklist
->is_initiator
&& outbound
) || (!checklist
->is_initiator
&& !outbound
)
991 ? checklist
->initiator
.key
: checklist
->responder
.key
;
993 /* signature = SHA1( MID | P2P_SESSIONID | P2P_ENDPOINT | P2P_SESSIONKEY ) */
994 sig_chunk
= chunk_cat("cccc", mid_chunk
, check
->session_id
, check
->endpoint_raw
, key_chunk
);
995 this->hasher
->allocate_hash(this->hasher
, sig_chunk
, &sig_hash
);
996 DBG3(DBG_IKE
, "sig_chunk %B", &sig_chunk
);
997 DBG3(DBG_IKE
, "sig_hash %B", &sig_hash
);
999 chunk_free(&sig_chunk
);
1003 // -----------------------------------------------------------------------------
1005 // forward declarations
1006 static void queue_retransmission(private_connect_manager_t
*this, chunk_t session_id
, u_int32_t mid
);
1007 static void schedule_checks(private_connect_manager_t
*this, check_list_t
*checklist
, u_int32_t time
);
1008 static void finish_checks(private_connect_manager_t
*this, check_list_t
*checklist
);
1011 * This function is triggered for each sent check after a specific timeout
1013 static job_requeue_t
retransmit(retransmit_data_t
*data
)
1015 private_connect_manager_t
*this = data
->connect_manager
;
1017 pthread_mutex_lock(&(this->mutex
));
1019 check_list_t
*checklist
;
1020 if (get_checklist_by_id(this, data
->session_id
, &checklist
) != SUCCESS
)
1022 DBG1(DBG_IKE
, "checklist with id '%B' not found, can't retransmit connectivity check",
1024 pthread_mutex_unlock(&(this->mutex
));
1025 return JOB_REQUEUE_NONE
;
1028 endpoint_pair_t
*pair
;
1029 if (get_pair_by_id(checklist
, data
->mid
, &pair
) != SUCCESS
)
1031 DBG1(DBG_IKE
, "pair with id '%d' not found, can't retransmit connectivity check",
1033 goto retransmit_end
;
1036 if (pair
->state
!= CHECK_IN_PROGRESS
)
1038 DBG2(DBG_IKE
, "pair with id '%d' is in wrong state [%d], don't retransmit the connectivity check",
1039 data
->mid
, pair
->state
);
1040 goto retransmit_end
;
1043 if (++pair
->retransmitted
>= P2P_MAX_RETRANS
)
1045 DBG2(DBG_IKE
, "pair with id '%d' failed after %d tries",
1046 data
->mid
, pair
->retransmitted
);
1047 pair
->state
= CHECK_FAILED
;
1048 goto retransmit_end
;
1051 charon
->sender
->send(charon
->sender
, pair
->packet
->clone(pair
->packet
));
1053 queue_retransmission(this, checklist
->session_id
, pair
->id
);
1056 update_checklist_state(checklist
);
1058 switch(checklist
->state
)
1060 case CHECK_SUCCEEDED
:
1062 finish_checks(this, checklist
);
1066 pthread_mutex_unlock(&(this->mutex
));
1068 // we reschedule it manually
1069 return JOB_REQUEUE_NONE
;
1073 * Queues a retransmission job
1075 static void queue_retransmission(private_connect_manager_t
*this, chunk_t session_id
, u_int32_t mid
)
1077 retransmit_data_t
*data
= retransmit_data_create(this, chunk_clone(session_id
), mid
);
1078 job_t
*job
= (job_t
*)callback_job_create((callback_job_cb_t
)retransmit
, data
, (callback_job_cleanup_t
)retransmit_data_destroy
, NULL
);
1079 charon
->scheduler
->schedule_job(charon
->scheduler
, (job_t
*)job
, P2P_RTO_MIN
);
1085 static void send_check(private_connect_manager_t
*this, check_list_t
*checklist
,
1086 check_t
*check
, endpoint_pair_t
*pair
, bool request
)
1088 message_t
*message
= message_create();
1089 message
->set_message_id(message
, check
->mid
);
1090 message
->set_exchange_type(message
, INFORMATIONAL
);
1091 message
->set_request(message
, request
);
1092 message
->set_destination(message
, check
->dst
->clone(check
->dst
));
1093 message
->set_source(message
, check
->src
->clone(check
->src
));
1095 message
->set_ike_sa_id(message
, ike_sa_id_create(0, 0, request
));
1097 message
->add_notify(message
, FALSE
, P2P_SESSIONID
, check
->session_id
);
1099 notify_payload_t
*endpoint
= check
->endpoint
->build_notify(check
->endpoint
);
1100 check
->endpoint_raw
= chunk_clone(endpoint
->get_notification_data(endpoint
));
1101 message
->add_payload(message
, (payload_t
*)endpoint
);
1103 check
->cookie
= build_signature(this, checklist
, check
, TRUE
);
1104 message
->add_notify(message
, FALSE
, COOKIE
, check
->cookie
);
1107 if (message
->generate(message
, NULL
, NULL
, &packet
) == SUCCESS
)
1109 charon
->sender
->send(charon
->sender
, packet
->clone(packet
));
1113 DESTROY_IF(pair
->packet
);
1114 pair
->packet
= packet
;
1115 queue_retransmission(this, checklist
->session_id
, pair
->id
);
1119 packet
->destroy(packet
);
1125 * Queues a triggered check
1127 static void queue_triggered_check(check_list_t
*checklist
, endpoint_pair_t
*pair
)
1129 pair
->state
= CHECK_WAITING
;
1130 checklist
->triggered
->insert_last(checklist
->triggered
, pair
);
1134 * This function is triggered for each checklist at a specific interval
1136 static job_requeue_t
sender(sender_data_t
*data
)
1138 private_connect_manager_t
*this = data
->connect_manager
;
1140 pthread_mutex_lock(&(this->mutex
));
1142 check_list_t
*checklist
;
1143 if (get_checklist_by_id(this, data
->session_id
, &checklist
) != SUCCESS
)
1145 DBG1(DBG_IKE
, "checklist with id '%B' not found, can't send connectivity check",
1147 pthread_mutex_unlock(&(this->mutex
));
1148 return JOB_REQUEUE_NONE
;
1151 endpoint_pair_t
*pair
;
1152 if (get_triggered_pair(checklist
, &pair
) != SUCCESS
)
1154 DBG1(DBG_IKE
, "no triggered check queued, sending an ordinary check");
1156 iterator_t
*iterator
;
1157 bool found_one
= FALSE
;
1159 iterator
= checklist
->pairs
->create_iterator(checklist
->pairs
, TRUE
);
1160 while (iterator
->iterate(iterator
, (void**)&pair
))
1162 if (pair
->state
== CHECK_WAITING
)
1168 iterator
->destroy(iterator
);
1172 pthread_mutex_unlock(&(this->mutex
));
1173 DBG1(DBG_IKE
, "no pairs in waiting state, aborting");
1174 return JOB_REQUEUE_NONE
;
1179 DBG1(DBG_IKE
, "triggered check found");
1182 check_t
*check
= check_create();
1183 check
->mid
= pair
->id
;
1184 check
->src
= pair
->local
->clone(pair
->local
);
1185 check
->dst
= pair
->remote
->clone(pair
->remote
);
1186 check
->session_id
= chunk_clone(checklist
->session_id
);
1187 check
->endpoint
= endpoint_notify_create();
1189 pair
->state
= CHECK_IN_PROGRESS
;
1191 send_check(this, checklist
, check
, pair
, TRUE
);
1193 check_destroy(check
);
1195 // schedule this job again
1196 u_int32_t N
= this->checklists
->get_count(this->checklists
);
1197 schedule_checks(this, checklist
, P2P_INTERVAL
* N
);
1199 pthread_mutex_unlock(&(this->mutex
));
1201 // we reschedule it manually
1202 return JOB_REQUEUE_NONE
;
1206 * Schedules checks for a checklist (time in ms)
1208 static void schedule_checks(private_connect_manager_t
*this, check_list_t
*checklist
, u_int32_t time
)
1210 chunk_t session_id
= chunk_clone(checklist
->session_id
);
1211 sender_data_t
*data
= sender_data_create(this, session_id
);
1212 job_t
*job
= (job_t
*)callback_job_create((callback_job_cb_t
)sender
, data
, (callback_job_cleanup_t
)sender_data_destroy
, NULL
);
1213 charon
->scheduler
->schedule_job(charon
->scheduler
, job
, time
);
1217 * Initiates waiting mediated connections
1219 static job_requeue_t
initiate_mediated(initiate_data_t
*data
)
1221 check_list_t
*checklist
= data
->checklist
;
1222 initiated_t
*initiated
= data
->initiated
;
1224 endpoint_pair_t
*pair
;
1225 if (get_best_valid_pair(checklist
, &pair
) == SUCCESS
)
1227 waiting_sa_t
*waiting_sa
;
1228 iterator_t
*iterator
= initiated
->mediated
->create_iterator(initiated
->mediated
, TRUE
);
1229 while (iterator
->iterate(iterator
, (void**)&waiting_sa
))
1231 ike_sa_t
*sa
= charon
->ike_sa_manager
->checkout(charon
->ike_sa_manager
, waiting_sa
->ike_sa_id
);
1232 if (sa
->initiate_mediated(sa
, pair
->local
, pair
->remote
, waiting_sa
->childs
) != SUCCESS
)
1234 SIG(IKE_UP_FAILED
, "establishing the mediated connection failed");
1235 charon
->ike_sa_manager
->checkin_and_destroy(charon
->ike_sa_manager
, sa
);
1237 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, sa
);
1239 iterator
->destroy(iterator
);
1243 /* this should (can?) not happen */
1246 return JOB_REQUEUE_NONE
;
1250 * Finishes checks for a checklist
1252 static void finish_checks(private_connect_manager_t
*this, check_list_t
*checklist
)
1254 if (checklist
->is_initiator
)
1256 initiated_t
*initiated
;
1257 if (get_initiated_by_ids(this, checklist
->initiator
.id
,
1258 checklist
->responder
.id
, &initiated
) == SUCCESS
)
1260 remove_checklist(this, checklist
);
1261 remove_initiated(this, initiated
);
1263 initiate_data_t
*data
= initiate_data_create(checklist
, initiated
);
1264 job_t
*job
= (job_t
*)callback_job_create((callback_job_cb_t
)initiate_mediated
, data
, (callback_job_cleanup_t
)initiate_data_destroy
, NULL
);
1265 charon
->processor
->queue_job(charon
->processor
, job
);
1270 DBG1(DBG_IKE
, "there is no mediated connection waiting between '%D' "
1271 "and '%D'", checklist
->initiator
.id
, checklist
->responder
.id
);
1275 //remove_checklist(this, checklist);
1276 //check_list_destroy(checklist);
1277 // FIXME: we should do this ^^^ after a specific timeout on the responder side
1281 * Process the response to one of our requests
1283 static void process_response(private_connect_manager_t
*this, check_t
*check
,
1284 check_list_t
*checklist
)
1286 endpoint_pair_t
*pair
;
1287 if (get_pair_by_id(checklist
, check
->mid
, &pair
) == SUCCESS
)
1289 if (pair
->local
->equals(pair
->local
, check
->dst
) &&
1290 pair
->remote
->equals(pair
->remote
, check
->src
))
1292 DBG1(DBG_IKE
, "endpoint pair '%d' is valid: '%#H' - '%#H'", pair
->id
,
1293 pair
->local
, pair
->remote
);
1294 pair
->state
= CHECK_SUCCEEDED
;
1297 linked_list_t
*local_endpoints
= checklist
->is_initiator ?
1298 checklist
->initiator
.endpoints
: checklist
->responder
.endpoints
;
1300 endpoint_notify_t
*local_endpoint
;
1301 if (endpoints_contain(local_endpoints
,
1302 check
->endpoint
->get_host(check
->endpoint
), &local_endpoint
) != SUCCESS
)
1304 local_endpoint
= endpoint_notify_create_from_host(PEER_REFLEXIVE
,
1305 check
->endpoint
->get_host(check
->endpoint
), pair
->local
);
1306 local_endpoint
->set_priority(local_endpoint
, check
->endpoint
->get_priority(check
->endpoint
));
1307 local_endpoints
->insert_last(local_endpoints
, local_endpoint
);
1310 update_checklist_state(checklist
);
1312 switch(checklist
->state
)
1314 case CHECK_SUCCEEDED
:
1316 finish_checks(this, checklist
);
1322 DBG1(DBG_IKE
, "pair with id '%d' not found", check
->mid
);
1326 static void process_request(private_connect_manager_t
*this, check_t
*check
,
1327 check_list_t
*checklist
)
1329 linked_list_t
*remote_endpoints
= checklist
->is_initiator ?
1330 checklist
->responder
.endpoints
: checklist
->initiator
.endpoints
;
1332 endpoint_notify_t
*peer_reflexive
, *remote_endpoint
;
1333 peer_reflexive
= endpoint_notify_create_from_host(PEER_REFLEXIVE
, check
->src
, NULL
);
1334 peer_reflexive
->set_priority(peer_reflexive
, check
->endpoint
->get_priority(check
->endpoint
));
1336 if (endpoints_contain(remote_endpoints
, check
->src
, &remote_endpoint
) != SUCCESS
)
1338 remote_endpoint
= peer_reflexive
->clone(peer_reflexive
);
1339 remote_endpoints
->insert_last(remote_endpoints
, remote_endpoint
);
1342 endpoint_pair_t
*pair
;
1343 if (get_pair_by_hosts(checklist
->pairs
, check
->dst
, check
->src
, &pair
) == SUCCESS
)
1347 case CHECK_IN_PROGRESS
:
1348 pair
->retransmitted
= P2P_MAX_RETRANS
; // prevent retransmissions
1349 // FIXME: we should wait to the next rto to send the triggered check
1353 queue_triggered_check(checklist
, pair
);
1355 case CHECK_SUCCEEDED
:
1363 endpoint_notify_t
*local_endpoint
= endpoint_notify_create_from_host(HOST
, check
->dst
, NULL
);
1365 endpoint_notify_t
*initiator
= checklist
->is_initiator ? local_endpoint
: remote_endpoint
;
1366 endpoint_notify_t
*responder
= checklist
->is_initiator ? remote_endpoint
: local_endpoint
;
1368 pair
= endpoint_pair_create(initiator
, responder
, checklist
->is_initiator
);
1369 pair
->id
= checklist
->pairs
->get_count(checklist
->pairs
) + 1;
1371 insert_pair_by_priority(checklist
->pairs
, pair
);
1373 queue_triggered_check(checklist
, pair
);
1375 local_endpoint
->destroy(local_endpoint
);
1379 check_t
*response
= check_create();
1381 response
->mid
= check
->mid
;
1382 response
->src
= check
->dst
->clone(check
->dst
);
1383 response
->dst
= check
->src
->clone(check
->src
);
1384 response
->session_id
= chunk_clone(check
->session_id
);
1385 response
->endpoint
= peer_reflexive
;
1387 send_check(this, checklist
, response
, pair
, FALSE
);
1389 check_destroy(response
);
1393 * Implementation of connect_manager_t.process_check.
1395 static void process_check(private_connect_manager_t
*this, message_t
*message
)
1397 if (message
->parse_body(message
, NULL
, NULL
) != SUCCESS
)
1399 DBG1(DBG_IKE
, "%N %s with message ID %d processing failed",
1400 exchange_type_names
, message
->get_exchange_type(message
),
1401 message
->get_request(message
) ?
"request" : "response",
1402 message
->get_message_id(message
));
1406 check_t
*check
= check_create();
1407 check
->mid
= message
->get_message_id(message
);
1408 check
->src
= message
->get_source(message
);
1409 check
->dst
= message
->get_destination(message
);
1411 if (process_payloads(message
, check
) != SUCCESS
)
1413 DBG1(DBG_IKE
, "invalid connectivity check %s received",
1414 message
->get_request(message
) ?
"request" : "response");
1415 check_destroy(check
);
1419 pthread_mutex_lock(&(this->mutex
));
1421 check_list_t
*checklist
;
1422 if (get_checklist_by_id(this, check
->session_id
, &checklist
) != SUCCESS
)
1424 DBG1(DBG_IKE
, "checklist with id '%B' not found",
1425 &check
->session_id
);
1426 check_destroy(check
);
1427 pthread_mutex_unlock(&(this->mutex
));
1431 chunk_t sig
= build_signature(this, checklist
, check
, FALSE
);
1432 if (!chunk_equals(sig
, check
->cookie
))
1434 DBG1(DBG_IKE
, "connectivity check verification failed");
1435 check_destroy(check
);
1437 pthread_mutex_unlock(&(this->mutex
));
1442 if (message
->get_request(message
))
1444 process_request(this, check
, checklist
);
1448 process_response(this, check
, checklist
);
1451 pthread_mutex_unlock(&(this->mutex
));
1453 check_destroy(check
);
1456 // -----------------------------------------------------------------------------
1459 * Implementation of connect_manager_t.check_and_register.
1461 static bool check_and_register(private_connect_manager_t
*this,
1462 identification_t
*id
, identification_t
*peer_id
,
1463 ike_sa_id_t
*mediated_sa
, child_cfg_t
*child
)
1465 initiated_t
*initiated
;
1466 bool already_there
= TRUE
;
1468 pthread_mutex_lock(&(this->mutex
));
1470 if (get_initiated_by_ids(this, id
, peer_id
, &initiated
) != SUCCESS
)
1472 DBG2(DBG_IKE
, "registered waiting mediated connection with '%D'", peer_id
);
1473 initiated
= initiated_create(id
, peer_id
);
1474 this->initiated
->insert_last(this->initiated
, initiated
);
1475 already_there
= FALSE
;
1478 waiting_sa_t
*waiting_sa
;
1479 if (get_waiting_sa(initiated
, mediated_sa
, &waiting_sa
) != SUCCESS
)
1481 waiting_sa
= waiting_sa_create(mediated_sa
);
1482 initiated
->mediated
->insert_last(initiated
->mediated
, waiting_sa
);
1485 child
->get_ref(child
);
1486 waiting_sa
->childs
->insert_last(waiting_sa
->childs
, child
);
1488 pthread_mutex_unlock(&(this->mutex
));
1490 return already_there
;
1494 * Implementation of connect_manager_t.check_and_initiate.
1496 static void check_and_initiate(private_connect_manager_t
*this, ike_sa_id_t
*mediation_sa
,
1497 identification_t
*id
, identification_t
*peer_id
)
1499 initiated_t
*initiated
;
1501 pthread_mutex_lock(&(this->mutex
));
1503 if (get_initiated_by_ids(this, id
, peer_id
, &initiated
) != SUCCESS
)
1505 DBG2(DBG_IKE
, "no waiting mediated connections with '%D'", peer_id
);
1506 pthread_mutex_unlock(&(this->mutex
));
1510 waiting_sa_t
*waiting_sa
;
1511 iterator_t
*iterator
= initiated
->mediated
->create_iterator(initiated
->mediated
, TRUE
);
1512 while (iterator
->iterate(iterator
, (void**)&waiting_sa
))
1514 job_t
*job
= (job_t
*)reinitiate_mediation_job_create(mediation_sa
,
1515 waiting_sa
->ike_sa_id
);
1516 charon
->processor
->queue_job(charon
->processor
, job
);
1519 pthread_mutex_unlock(&(this->mutex
));
1523 * Implementation of connect_manager_t.set_initiator_data.
1525 static status_t
set_initiator_data(private_connect_manager_t
*this,
1526 identification_t
*initiator
, identification_t
*responder
,
1527 chunk_t session_id
, chunk_t key
, linked_list_t
*endpoints
, bool is_initiator
)
1529 check_list_t
*checklist
;
1531 pthread_mutex_lock(&(this->mutex
));
1533 if (get_checklist_by_id(this, session_id
, NULL
) == SUCCESS
)
1535 DBG1(DBG_IKE
, "checklist with id '%B' already exists, aborting",
1537 pthread_mutex_unlock(&(this->mutex
));
1541 checklist
= check_list_create(initiator
, responder
, session_id
, key
, endpoints
, is_initiator
);
1542 this->checklists
->insert_last(this->checklists
, checklist
);
1544 pthread_mutex_unlock(&(this->mutex
));
1550 * Implementation of connect_manager_t.set_responder_data.
1552 static status_t
set_responder_data(private_connect_manager_t
*this,
1553 chunk_t session_id
, chunk_t key
, linked_list_t
*endpoints
)
1555 check_list_t
*checklist
;
1557 pthread_mutex_lock(&(this->mutex
));
1559 if (get_checklist_by_id(this, session_id
, &checklist
) != SUCCESS
)
1561 DBG1(DBG_IKE
, "checklist with id '%B' not found",
1563 pthread_mutex_unlock(&(this->mutex
));
1567 checklist
->responder
.key
= chunk_clone(key
);
1568 checklist
->responder
.endpoints
= endpoints
->clone_offset(endpoints
, offsetof(endpoint_notify_t
, clone
));
1569 checklist
->state
= CHECK_WAITING
;
1571 build_pairs(checklist
);
1573 schedule_checks(this, checklist
, 0); // send the first check immediately
1575 pthread_mutex_unlock(&(this->mutex
));
1581 * Implementation of connect_manager_t.destroy.
1583 static void destroy(private_connect_manager_t
*this)
1585 pthread_mutex_lock(&(this->mutex
));
1587 this->hasher
->destroy(this->hasher
);
1588 this->checklists
->destroy_function(this->checklists
, (void*)check_list_destroy
);
1589 this->initiated
->destroy_function(this->initiated
, (void*)initiated_destroy
);
1591 pthread_mutex_unlock(&(this->mutex
));
1592 pthread_mutex_destroy(&(this->mutex
));
1597 * Described in header.
1599 connect_manager_t
*connect_manager_create()
1601 private_connect_manager_t
*this = malloc_thing(private_connect_manager_t
);
1603 this->public.destroy
= (void(*)(connect_manager_t
*))destroy
;
1604 this->public.check_and_register
= (bool(*)(connect_manager_t
*,identification_t
*,identification_t
*,ike_sa_id_t
*,child_cfg_t
*))check_and_register
;
1605 this->public.check_and_initiate
= (void(*)(connect_manager_t
*,ike_sa_id_t
*,identification_t
*,identification_t
*))check_and_initiate
;
1606 this->public.set_initiator_data
= (status_t(*)(connect_manager_t
*,identification_t
*,identification_t
*,chunk_t
,chunk_t
,linked_list_t
*,bool))set_initiator_data
;
1607 this->public.set_responder_data
= (status_t(*)(connect_manager_t
*,chunk_t
,chunk_t
,linked_list_t
*))set_responder_data
;
1608 this->public.process_check
= (void(*)(connect_manager_t
*,message_t
*))process_check
;
1610 this->hasher
= hasher_create(HASH_SHA1
);
1611 this->checklists
= linked_list_create();
1612 this->initiated
= linked_list_create();
1614 pthread_mutex_init(&(this->mutex
), NULL
);
1616 return (connect_manager_t
*)this;