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>
30 #include <crypto/hashers/hasher.h>
32 #include <processing/jobs/callback_job.h>
33 #include <processing/jobs/initiate_mediation_job.h>
34 #include <encoding/payloads/endpoint_notify.h>
37 * the sending interval is P2P_INTERVAL * active checklists (N)
38 * retransmission timeout is P2P_INTERVAL * N * checks in waiting state (NW) */
39 #define P2P_INTERVAL 20 /* ms */
40 /* min retransmission timeout (RTO is P2P_INTERVAL * N * checks in waiting state) */
41 #define P2P_RTO_MIN 100 /* ms */
42 /* max number of retransmissions (+ the initial check) */
43 #define P2P_MAX_RETRANS 2
46 typedef struct private_connect_manager_t private_connect_manager_t
;
49 * Additional private members of connect_manager_t.
51 struct private_connect_manager_t
{
53 * Public interface of connect_manager_t.
55 connect_manager_t
public;
58 * Lock for exclusivly accessing the manager.
60 pthread_mutex_t mutex
;
63 * Hasher to generate signatures
68 * Linked list with initiated mediated connections
70 linked_list_t
*initiated
;
73 * Linked list with checklists (hash table with session ID as key would be better).
75 linked_list_t
*checklists
;
78 typedef enum check_state_t check_state_t
;
88 typedef struct endpoint_pair_t endpoint_pair_t
;
91 * An entry in the check list.
93 struct endpoint_pair_t
{
100 /** local endpoint */
103 /** remote endpoint */
109 /** number of retransmissions */
110 u_int32_t retransmitted
;
112 /** the generated packet */
117 * Destroys an endpoint pair
119 static void endpoint_pair_destroy(endpoint_pair_t
*this)
121 DESTROY_IF(this->local
);
122 DESTROY_IF(this->remote
);
123 DESTROY_IF(this->packet
);
128 * Creates a new entry for the list.
130 static endpoint_pair_t
*endpoint_pair_create(endpoint_notify_t
*initiator
,
131 endpoint_notify_t
*responder
, bool initiator_is_local
)
133 endpoint_pair_t
*this = malloc_thing(endpoint_pair_t
);
137 u_int32_t pi
= initiator
->get_priority(initiator
);
138 u_int32_t pr
= responder
->get_priority(responder
);
139 this->priority
= pow(2, 32) * min(pi
, pr
) + 2 * max(pi
, pr
) + (pi
> pr ?
1 : 0);
141 this->local
= initiator_is_local ? initiator
->get_base(initiator
) : responder
->get_base(responder
);
142 this->local
= this->local
->clone(this->local
);
143 this->remote
= initiator_is_local ? responder
->get_host(responder
) : initiator
->get_host(initiator
);
144 this->remote
= this->remote
->clone(this->remote
);
146 this->state
= CHECK_WAITING
;
147 this->retransmitted
= 0;
154 typedef struct check_list_t check_list_t
;
157 * An entry in the linked list.
159 struct check_list_t
{
162 /** initiator's id */
163 identification_t
*id
;
165 /** initiator's key */
168 /** initiator's endpoints */
169 linked_list_t
*endpoints
;
173 /** responder's id */
174 identification_t
*id
;
176 /** responder's key */
179 /** responder's endpoints */
180 linked_list_t
*endpoints
;
186 /** list of endpoint pairs */
187 linked_list_t
*pairs
;
189 /** pairs queued for triggered checks */
190 linked_list_t
*triggered
;
195 /** TRUE if this is the initiator */
201 * Destroys a checklist
203 static void check_list_destroy(check_list_t
*this)
205 DESTROY_IF(this->initiator
.id
);
206 DESTROY_IF(this->responder
.id
);
208 chunk_free(&this->session_id
);
209 chunk_free(&this->initiator
.key
);
210 chunk_free(&this->responder
.key
);
212 DESTROY_OFFSET_IF(this->initiator
.endpoints
, offsetof(endpoint_notify_t
, destroy
));
213 DESTROY_OFFSET_IF(this->responder
.endpoints
, offsetof(endpoint_notify_t
, destroy
));
215 DESTROY_FUNCTION_IF(this->pairs
, (void*)endpoint_pair_destroy
);
216 /* this list contains some of the same elements as contained in this->pairs */
217 DESTROY_IF(this->triggered
);
223 * Creates a new checklist
225 static check_list_t
*check_list_create(identification_t
*initiator
, identification_t
*responder
,
226 chunk_t session_id
, chunk_t initiator_key
, linked_list_t
*initiator_endpoints
,
229 check_list_t
*this = malloc_thing(check_list_t
);
231 this->session_id
= chunk_clone(session_id
);
233 this->initiator
.id
= initiator
->clone(initiator
);
234 this->initiator
.key
= chunk_clone(initiator_key
);
235 this->initiator
.endpoints
= initiator_endpoints
->clone_offset(initiator_endpoints
, offsetof(endpoint_notify_t
, clone
));
237 this->responder
.id
= responder
->clone(responder
);
238 this->responder
.key
= chunk_empty
;
239 this->responder
.endpoints
= NULL
;
241 this->pairs
= linked_list_create();
242 this->triggered
= linked_list_create();
243 this->state
= CHECK_NONE
;
244 this->is_initiator
= is_initiator
;
250 typedef struct waiting_sa_t waiting_sa_t
;
253 * For an initiator, the data stored about a waiting mediated sa
255 struct waiting_sa_t
{
257 ike_sa_id_t
*ike_sa_id
;
259 /** list of child_cfg_t */
260 linked_list_t
*childs
;
264 * Destroys a queued mediated sa
266 static void waiting_sa_destroy(waiting_sa_t
*this)
268 DESTROY_IF(this->ike_sa_id
);
269 this->childs
->destroy_offset(this->childs
, offsetof(child_cfg_t
, destroy
));
274 * Creates a new mediated sa object
276 static waiting_sa_t
*waiting_sa_create(ike_sa_id_t
*ike_sa_id
)
278 waiting_sa_t
*this = malloc_thing(waiting_sa_t
);
280 this->ike_sa_id
= ike_sa_id
->clone(ike_sa_id
);
281 this->childs
= linked_list_create();
286 typedef struct initiated_t initiated_t
;
289 * For an initiator, the data stored about initiated mediation connections
293 identification_t
*id
;
296 identification_t
*peer_id
;
298 /** list of mediated sas */
299 linked_list_t
*mediated
;
303 * Destroys a queued initiation
305 static void initiated_destroy(initiated_t
*this)
307 DESTROY_IF(this->id
);
308 DESTROY_IF(this->peer_id
);
309 this->mediated
->destroy_function(this->mediated
, (void*)waiting_sa_destroy
);
314 * Creates a queued initiation
316 static initiated_t
*initiated_create(identification_t
*id
, identification_t
*peer_id
)
318 initiated_t
*this = malloc_thing(initiated_t
);
320 this->id
= id
->clone(id
);
321 this->peer_id
= peer_id
->clone(peer_id
);
322 this->mediated
= linked_list_create();
328 typedef struct check_t check_t
;
331 * Data exchanged in a connectivity check
337 /** source of the connectivity check */
340 /** destination of the connectivity check */
347 endpoint_notify_t
*endpoint
;
349 /** raw endpoint payload (to verify the signature) */
350 chunk_t endpoint_raw
;
357 * Destroys a connectivity check
359 static void check_destroy(check_t
*this)
361 chunk_free(&this->session_id
);
362 chunk_free(&this->endpoint_raw
);
363 chunk_free(&this->cookie
);
364 DESTROY_IF(this->endpoint
);
369 * Creates a new connectivity check
371 static check_t
*check_create()
373 check_t
*this = malloc_thing(check_t
);
375 this->session_id
= chunk_empty
;
376 this->cookie
= chunk_empty
;
377 this->endpoint_raw
= chunk_empty
;
378 this->endpoint
= NULL
;
385 typedef struct sender_data_t sender_data_t
;
388 * Data required by the sender
390 struct sender_data_t
{
391 /** connect manager */
392 private_connect_manager_t
*connect_manager
;
399 * Destroys a sender data object
401 static void sender_data_destroy(sender_data_t
*this)
403 chunk_free(&this->session_id
);
408 * Creates a new sender data object
410 static sender_data_t
*sender_data_create(private_connect_manager_t
*connect_manager
, chunk_t session_id
)
412 sender_data_t
*this = malloc_thing(sender_data_t
);
413 this->connect_manager
= connect_manager
;
414 this->session_id
= session_id
;
418 typedef struct retransmit_data_t retransmit_data_t
;
421 * Data required by the retransmission job
423 struct retransmit_data_t
{
424 /** connect manager */
425 private_connect_manager_t
*connect_manager
;
430 /** message (pair) id */
435 * Destroys a retransmission data object
437 static void retransmit_data_destroy(retransmit_data_t
*this)
439 chunk_free(&this->session_id
);
444 * Creates a new retransmission data object
446 static retransmit_data_t
*retransmit_data_create(private_connect_manager_t
*connect_manager
,
447 chunk_t session_id
, u_int32_t mid
)
449 retransmit_data_t
*this = malloc_thing(retransmit_data_t
);
451 this->connect_manager
= connect_manager
;
452 this->session_id
= session_id
;
458 typedef struct initiate_data_t initiate_data_t
;
461 * Data required by the initiate mediated
463 struct initiate_data_t
{
465 check_list_t
*checklist
;
467 /** waiting mediated connections */
468 initiated_t
*initiated
;
472 * Destroys a initiate data object
474 static void initiate_data_destroy(initiate_data_t
*this)
476 check_list_destroy(this->checklist
);
477 initiated_destroy(this->initiated
);
482 * Creates a new initiate data object
484 static initiate_data_t
*initiate_data_create(check_list_t
*checklist
, initiated_t
*initiated
)
486 initiate_data_t
*this = malloc_thing(initiate_data_t
);
488 this->checklist
= checklist
;
489 this->initiated
= initiated
;
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
);
645 * Updates the state of the whole checklist
647 static void update_checklist_state(check_list_t
*checklist
)
649 iterator_t
*iterator
;
650 endpoint_pair_t
*current
;
651 bool in_progress
= FALSE
, succeeded
= FALSE
;
653 iterator
= checklist
->pairs
->create_iterator(checklist
->pairs
, TRUE
);
654 while (iterator
->iterate(iterator
, (void**)¤t
))
656 switch(current
->state
)
659 /* at least one is still waiting -> checklist remains
660 * in waiting state */
661 iterator
->destroy(iterator
);
663 case CHECK_IN_PROGRESS
:
666 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
;
837 iterator
= pairs
->create_iterator(pairs
, TRUE
);
838 search
= pairs
->create_iterator(pairs
, TRUE
);
839 while (iterator
->iterate(iterator
, (void**)¤t
))
843 while (search
->iterate(search
, (void**)&other
))
845 if (current
== other
)
850 if (current
->local
->equals(current
->local
, other
->local
) &&
851 current
->remote
->equals(current
->remote
, other
->remote
))
853 /* since the list of pairs is sorted by priority in descending
854 * order, and we iterate the list from the beginning, we are
855 * sure that the priority of 'other' is lower than that of
856 * 'current', remove it */
857 DBG1(DBG_IKE
, "pruning endpoint pair %H - %H with priority %d",
858 other
->local
, other
->remote
, other
->priority
);
859 search
->remove(search
);
860 endpoint_pair_destroy(other
);
863 search
->reset(search
);
865 search
->destroy(search
);
866 iterator
->destroy(iterator
);
870 * Builds a list of endpoint pairs
872 static void build_pairs(check_list_t
*checklist
)
874 iterator_t
*iterator_i
, *iterator_r
;
875 endpoint_notify_t
*initiator
, *responder
;
877 iterator_i
= checklist
->initiator
.endpoints
->create_iterator(checklist
->initiator
.endpoints
, TRUE
);
878 while (iterator_i
->iterate(iterator_i
, (void**)&initiator
))
880 iterator_r
= checklist
->responder
.endpoints
->create_iterator(checklist
->responder
.endpoints
, TRUE
);
881 while (iterator_r
->iterate(iterator_r
, (void**)&responder
))
883 if (initiator
->get_family(initiator
) != responder
->get_family(responder
))
888 insert_pair_by_priority(checklist
->pairs
,
889 endpoint_pair_create(initiator
, responder
, checklist
->is_initiator
));
891 iterator_r
->destroy(iterator_r
);
893 iterator_i
->destroy(iterator_i
);
895 prune_pairs(checklist
->pairs
);
899 * Processes the payloads of a connectivity check and returns the extracted data
901 static status_t
process_payloads(message_t
*message
, check_t
*check
)
903 iterator_t
*iterator
;
906 iterator
= message
->get_payload_iterator(message
);
907 while (iterator
->iterate(iterator
, (void**)&payload
))
909 if (payload
->get_type(payload
) != NOTIFY
)
911 DBG1(DBG_IKE
, "ignoring payload of type '%N' while processing "
912 "connectivity check", payload_type_names
, payload
->get_type(payload
));
916 notify_payload_t
*notify
= (notify_payload_t
*)payload
;
918 switch (notify
->get_notify_type(notify
))
924 DBG1(DBG_IKE
, "connectivity check contains multiple P2P_ENDPOINT notifies");
928 endpoint_notify_t
*endpoint
= endpoint_notify_create_from_payload(notify
);
931 DBG1(DBG_IKE
, "received invalid P2P_ENDPOINT notify");
934 check
->endpoint
= endpoint
;
935 check
->endpoint_raw
= chunk_clone(notify
->get_notification_data(notify
));
936 DBG2(DBG_IKE
, "received P2P_ENDPOINT notify");
941 if (check
->session_id
.ptr
)
943 DBG1(DBG_IKE
, "connectivity check contains multiple P2P_SESSIONID notifies");
946 check
->session_id
= chunk_clone(notify
->get_notification_data(notify
));
947 DBG3(DBG_IKE
, "received p2p_sessionid %B", &check
->session_id
);
952 if (check
->cookie
.ptr
)
954 DBG1(DBG_IKE
, "connectivity check contains multiple COOKIE notifies");
957 check
->cookie
= chunk_clone(notify
->get_notification_data(notify
));
958 DBG3(DBG_IKE
, "received cookie %B", &check
->cookie
);
965 iterator
->destroy(iterator
);
967 if (!check
->session_id
.ptr
|| !check
->endpoint
|| !check
->cookie
.ptr
)
969 DBG1(DBG_IKE
, "at least one payload was missing from the connectivity check");
977 * Builds the signature for a connectivity check
979 static chunk_t
build_signature(private_connect_manager_t
*this,
980 check_list_t
*checklist
, check_t
*check
, bool outbound
)
982 chunk_t mid_chunk
, key_chunk
, sig_chunk
;
985 mid_chunk
= chunk_from_thing(check
->mid
);
987 key_chunk
= (checklist
->is_initiator
&& outbound
) || (!checklist
->is_initiator
&& !outbound
)
988 ? checklist
->initiator
.key
: checklist
->responder
.key
;
990 /* signature = SHA1( MID | P2P_SESSIONID | P2P_ENDPOINT | P2P_SESSIONKEY ) */
991 sig_chunk
= chunk_cat("cccc", mid_chunk
, check
->session_id
, check
->endpoint_raw
, key_chunk
);
992 this->hasher
->allocate_hash(this->hasher
, sig_chunk
, &sig_hash
);
993 DBG3(DBG_IKE
, "sig_chunk %B", &sig_chunk
);
994 DBG3(DBG_IKE
, "sig_hash %B", &sig_hash
);
996 chunk_free(&sig_chunk
);
1000 static void queue_retransmission(private_connect_manager_t
*this, chunk_t session_id
, u_int32_t mid
);
1001 static void schedule_checks(private_connect_manager_t
*this, check_list_t
*checklist
, u_int32_t time
);
1002 static void finish_checks(private_connect_manager_t
*this, check_list_t
*checklist
);
1005 * This function is triggered for each sent check after a specific timeout
1007 static job_requeue_t
retransmit(retransmit_data_t
*data
)
1009 private_connect_manager_t
*this = data
->connect_manager
;
1011 pthread_mutex_lock(&(this->mutex
));
1013 check_list_t
*checklist
;
1014 if (get_checklist_by_id(this, data
->session_id
, &checklist
) != SUCCESS
)
1016 DBG1(DBG_IKE
, "checklist with id '%B' not found, can't retransmit connectivity check",
1018 pthread_mutex_unlock(&(this->mutex
));
1019 return JOB_REQUEUE_NONE
;
1022 endpoint_pair_t
*pair
;
1023 if (get_pair_by_id(checklist
, data
->mid
, &pair
) != SUCCESS
)
1025 DBG1(DBG_IKE
, "pair with id '%d' not found, can't retransmit connectivity check",
1027 goto retransmit_end
;
1030 if (pair
->state
!= CHECK_IN_PROGRESS
)
1032 DBG2(DBG_IKE
, "pair with id '%d' is in wrong state [%d], don't retransmit the connectivity check",
1033 data
->mid
, pair
->state
);
1034 goto retransmit_end
;
1037 if (++pair
->retransmitted
>= P2P_MAX_RETRANS
)
1039 DBG2(DBG_IKE
, "pair with id '%d' failed after %d tries",
1040 data
->mid
, pair
->retransmitted
);
1041 pair
->state
= CHECK_FAILED
;
1042 goto retransmit_end
;
1045 charon
->sender
->send(charon
->sender
, pair
->packet
->clone(pair
->packet
));
1047 queue_retransmission(this, checklist
->session_id
, pair
->id
);
1050 update_checklist_state(checklist
);
1052 switch(checklist
->state
)
1054 case CHECK_SUCCEEDED
:
1056 finish_checks(this, checklist
);
1062 pthread_mutex_unlock(&(this->mutex
));
1064 /* we reschedule it manually */
1065 return JOB_REQUEUE_NONE
;
1069 * Queues a retransmission job
1071 static void queue_retransmission(private_connect_manager_t
*this, chunk_t session_id
, u_int32_t mid
)
1073 retransmit_data_t
*data
= retransmit_data_create(this, chunk_clone(session_id
), mid
);
1074 job_t
*job
= (job_t
*)callback_job_create((callback_job_cb_t
)retransmit
, data
, (callback_job_cleanup_t
)retransmit_data_destroy
, NULL
);
1075 charon
->scheduler
->schedule_job(charon
->scheduler
, (job_t
*)job
, P2P_RTO_MIN
);
1081 static void send_check(private_connect_manager_t
*this, check_list_t
*checklist
,
1082 check_t
*check
, endpoint_pair_t
*pair
, bool request
)
1084 message_t
*message
= message_create();
1085 message
->set_message_id(message
, check
->mid
);
1086 message
->set_exchange_type(message
, INFORMATIONAL
);
1087 message
->set_request(message
, request
);
1088 message
->set_destination(message
, check
->dst
->clone(check
->dst
));
1089 message
->set_source(message
, check
->src
->clone(check
->src
));
1091 message
->set_ike_sa_id(message
, ike_sa_id_create(0, 0, request
));
1093 message
->add_notify(message
, FALSE
, P2P_SESSIONID
, check
->session_id
);
1095 notify_payload_t
*endpoint
= check
->endpoint
->build_notify(check
->endpoint
);
1096 check
->endpoint_raw
= chunk_clone(endpoint
->get_notification_data(endpoint
));
1097 message
->add_payload(message
, (payload_t
*)endpoint
);
1099 check
->cookie
= build_signature(this, checklist
, check
, TRUE
);
1100 message
->add_notify(message
, FALSE
, COOKIE
, check
->cookie
);
1103 if (message
->generate(message
, NULL
, NULL
, &packet
) == SUCCESS
)
1105 charon
->sender
->send(charon
->sender
, packet
->clone(packet
));
1109 DESTROY_IF(pair
->packet
);
1110 pair
->packet
= packet
;
1111 queue_retransmission(this, checklist
->session_id
, pair
->id
);
1115 packet
->destroy(packet
);
1121 * Queues a triggered check
1123 static void queue_triggered_check(check_list_t
*checklist
, endpoint_pair_t
*pair
)
1125 pair
->state
= CHECK_WAITING
;
1126 checklist
->triggered
->insert_last(checklist
->triggered
, pair
);
1130 * This function is triggered for each checklist at a specific interval
1132 static job_requeue_t
sender(sender_data_t
*data
)
1134 private_connect_manager_t
*this = data
->connect_manager
;
1136 pthread_mutex_lock(&(this->mutex
));
1138 check_list_t
*checklist
;
1139 if (get_checklist_by_id(this, data
->session_id
, &checklist
) != SUCCESS
)
1141 DBG1(DBG_IKE
, "checklist with id '%B' not found, can't send connectivity check",
1143 pthread_mutex_unlock(&(this->mutex
));
1144 return JOB_REQUEUE_NONE
;
1147 endpoint_pair_t
*pair
;
1148 if (get_triggered_pair(checklist
, &pair
) != SUCCESS
)
1150 DBG1(DBG_IKE
, "no triggered check queued, sending an ordinary check");
1152 iterator_t
*iterator
;
1153 bool found_one
= FALSE
;
1155 iterator
= checklist
->pairs
->create_iterator(checklist
->pairs
, TRUE
);
1156 while (iterator
->iterate(iterator
, (void**)&pair
))
1158 if (pair
->state
== CHECK_WAITING
)
1164 iterator
->destroy(iterator
);
1168 pthread_mutex_unlock(&(this->mutex
));
1169 DBG1(DBG_IKE
, "no pairs in waiting state, aborting");
1170 return JOB_REQUEUE_NONE
;
1175 DBG1(DBG_IKE
, "triggered check found");
1178 check_t
*check
= check_create();
1179 check
->mid
= pair
->id
;
1180 check
->src
= pair
->local
->clone(pair
->local
);
1181 check
->dst
= pair
->remote
->clone(pair
->remote
);
1182 check
->session_id
= chunk_clone(checklist
->session_id
);
1183 check
->endpoint
= endpoint_notify_create();
1185 pair
->state
= CHECK_IN_PROGRESS
;
1187 send_check(this, checklist
, check
, pair
, TRUE
);
1189 check_destroy(check
);
1191 /* schedule this job again */
1192 u_int32_t N
= this->checklists
->get_count(this->checklists
);
1193 schedule_checks(this, checklist
, P2P_INTERVAL
* N
);
1195 pthread_mutex_unlock(&(this->mutex
));
1197 /* we reschedule it manually */
1198 return JOB_REQUEUE_NONE
;
1202 * Schedules checks for a checklist (time in ms)
1204 static void schedule_checks(private_connect_manager_t
*this, check_list_t
*checklist
, u_int32_t time
)
1206 chunk_t session_id
= chunk_clone(checklist
->session_id
);
1207 sender_data_t
*data
= sender_data_create(this, session_id
);
1208 job_t
*job
= (job_t
*)callback_job_create((callback_job_cb_t
)sender
, data
, (callback_job_cleanup_t
)sender_data_destroy
, NULL
);
1209 charon
->scheduler
->schedule_job(charon
->scheduler
, job
, time
);
1213 * Initiates waiting mediated connections
1215 static job_requeue_t
initiate_mediated(initiate_data_t
*data
)
1217 check_list_t
*checklist
= data
->checklist
;
1218 initiated_t
*initiated
= data
->initiated
;
1220 endpoint_pair_t
*pair
;
1221 if (get_best_valid_pair(checklist
, &pair
) == SUCCESS
)
1223 waiting_sa_t
*waiting_sa
;
1224 iterator_t
*iterator
= initiated
->mediated
->create_iterator(initiated
->mediated
, TRUE
);
1225 while (iterator
->iterate(iterator
, (void**)&waiting_sa
))
1227 ike_sa_t
*sa
= charon
->ike_sa_manager
->checkout(charon
->ike_sa_manager
, waiting_sa
->ike_sa_id
);
1228 if (sa
->initiate_mediated(sa
, pair
->local
, pair
->remote
, waiting_sa
->childs
) != SUCCESS
)
1230 SIG(IKE_UP_FAILED
, "establishing the mediated connection failed");
1231 charon
->ike_sa_manager
->checkin_and_destroy(charon
->ike_sa_manager
, sa
);
1233 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, sa
);
1235 iterator
->destroy(iterator
);
1239 /* this should (can?) not happen */
1242 return JOB_REQUEUE_NONE
;
1246 * Finishes checks for a checklist
1248 static void finish_checks(private_connect_manager_t
*this, check_list_t
*checklist
)
1250 if (checklist
->is_initiator
)
1252 initiated_t
*initiated
;
1253 if (get_initiated_by_ids(this, checklist
->initiator
.id
,
1254 checklist
->responder
.id
, &initiated
) == SUCCESS
)
1256 remove_checklist(this, checklist
);
1257 remove_initiated(this, initiated
);
1259 initiate_data_t
*data
= initiate_data_create(checklist
, initiated
);
1260 job_t
*job
= (job_t
*)callback_job_create((callback_job_cb_t
)initiate_mediated
, data
, (callback_job_cleanup_t
)initiate_data_destroy
, NULL
);
1261 charon
->processor
->queue_job(charon
->processor
, job
);
1266 DBG1(DBG_IKE
, "there is no mediated connection waiting between '%D' "
1267 "and '%D'", checklist
->initiator
.id
, checklist
->responder
.id
);
1271 /* remove_checklist(this, checklist);
1272 * check_list_destroy(checklist);
1273 * FIXME: we should do this ^^^ after a specific timeout on the
1278 * Process the response to one of our requests
1280 static void process_response(private_connect_manager_t
*this, check_t
*check
,
1281 check_list_t
*checklist
)
1283 endpoint_pair_t
*pair
;
1284 if (get_pair_by_id(checklist
, check
->mid
, &pair
) == SUCCESS
)
1286 if (pair
->local
->equals(pair
->local
, check
->dst
) &&
1287 pair
->remote
->equals(pair
->remote
, check
->src
))
1289 DBG1(DBG_IKE
, "endpoint pair '%d' is valid: '%#H' - '%#H'", pair
->id
,
1290 pair
->local
, pair
->remote
);
1291 pair
->state
= CHECK_SUCCEEDED
;
1294 linked_list_t
*local_endpoints
= checklist
->is_initiator ?
1295 checklist
->initiator
.endpoints
: checklist
->responder
.endpoints
;
1297 endpoint_notify_t
*local_endpoint
;
1298 if (endpoints_contain(local_endpoints
,
1299 check
->endpoint
->get_host(check
->endpoint
), &local_endpoint
) != SUCCESS
)
1301 local_endpoint
= endpoint_notify_create_from_host(PEER_REFLEXIVE
,
1302 check
->endpoint
->get_host(check
->endpoint
), pair
->local
);
1303 local_endpoint
->set_priority(local_endpoint
, check
->endpoint
->get_priority(check
->endpoint
));
1304 local_endpoints
->insert_last(local_endpoints
, local_endpoint
);
1307 update_checklist_state(checklist
);
1309 switch(checklist
->state
)
1311 case CHECK_SUCCEEDED
:
1313 finish_checks(this, checklist
);
1321 DBG1(DBG_IKE
, "pair with id '%d' not found", check
->mid
);
1325 static void process_request(private_connect_manager_t
*this, check_t
*check
,
1326 check_list_t
*checklist
)
1328 linked_list_t
*remote_endpoints
= checklist
->is_initiator ?
1329 checklist
->responder
.endpoints
: checklist
->initiator
.endpoints
;
1331 endpoint_notify_t
*peer_reflexive
, *remote_endpoint
;
1332 peer_reflexive
= endpoint_notify_create_from_host(PEER_REFLEXIVE
, check
->src
, NULL
);
1333 peer_reflexive
->set_priority(peer_reflexive
, check
->endpoint
->get_priority(check
->endpoint
));
1335 if (endpoints_contain(remote_endpoints
, check
->src
, &remote_endpoint
) != SUCCESS
)
1337 remote_endpoint
= peer_reflexive
->clone(peer_reflexive
);
1338 remote_endpoints
->insert_last(remote_endpoints
, remote_endpoint
);
1341 endpoint_pair_t
*pair
;
1342 if (get_pair_by_hosts(checklist
->pairs
, check
->dst
, check
->src
, &pair
) == SUCCESS
)
1346 case CHECK_IN_PROGRESS
:
1347 /* prevent retransmissions */
1348 pair
->retransmitted
= P2P_MAX_RETRANS
;
1349 /* FIXME: we should wait to the next rto to send the triggered check
1353 queue_triggered_check(checklist
, pair
);
1355 case CHECK_SUCCEEDED
:
1362 endpoint_notify_t
*local_endpoint
= endpoint_notify_create_from_host(HOST
, check
->dst
, NULL
);
1364 endpoint_notify_t
*initiator
= checklist
->is_initiator ? local_endpoint
: remote_endpoint
;
1365 endpoint_notify_t
*responder
= checklist
->is_initiator ? remote_endpoint
: local_endpoint
;
1367 pair
= endpoint_pair_create(initiator
, responder
, checklist
->is_initiator
);
1368 pair
->id
= checklist
->pairs
->get_count(checklist
->pairs
) + 1;
1370 insert_pair_by_priority(checklist
->pairs
, pair
);
1372 queue_triggered_check(checklist
, pair
);
1374 local_endpoint
->destroy(local_endpoint
);
1378 check_t
*response
= check_create();
1380 response
->mid
= check
->mid
;
1381 response
->src
= check
->dst
->clone(check
->dst
);
1382 response
->dst
= check
->src
->clone(check
->src
);
1383 response
->session_id
= chunk_clone(check
->session_id
);
1384 response
->endpoint
= peer_reflexive
;
1386 send_check(this, checklist
, response
, pair
, FALSE
);
1388 check_destroy(response
);
1392 * Implementation of connect_manager_t.process_check.
1394 static void process_check(private_connect_manager_t
*this, message_t
*message
)
1396 if (message
->parse_body(message
, NULL
, NULL
) != SUCCESS
)
1398 DBG1(DBG_IKE
, "%N %s with message ID %d processing failed",
1399 exchange_type_names
, message
->get_exchange_type(message
),
1400 message
->get_request(message
) ?
"request" : "response",
1401 message
->get_message_id(message
));
1405 check_t
*check
= check_create();
1406 check
->mid
= message
->get_message_id(message
);
1407 check
->src
= message
->get_source(message
);
1408 check
->dst
= message
->get_destination(message
);
1410 if (process_payloads(message
, check
) != SUCCESS
)
1412 DBG1(DBG_IKE
, "invalid connectivity check %s received",
1413 message
->get_request(message
) ?
"request" : "response");
1414 check_destroy(check
);
1418 pthread_mutex_lock(&(this->mutex
));
1420 check_list_t
*checklist
;
1421 if (get_checklist_by_id(this, check
->session_id
, &checklist
) != SUCCESS
)
1423 DBG1(DBG_IKE
, "checklist with id '%B' not found",
1424 &check
->session_id
);
1425 check_destroy(check
);
1426 pthread_mutex_unlock(&(this->mutex
));
1430 chunk_t sig
= build_signature(this, checklist
, check
, FALSE
);
1431 if (!chunk_equals(sig
, check
->cookie
))
1433 DBG1(DBG_IKE
, "connectivity check verification failed");
1434 check_destroy(check
);
1436 pthread_mutex_unlock(&(this->mutex
));
1441 if (message
->get_request(message
))
1443 process_request(this, check
, checklist
);
1447 process_response(this, check
, checklist
);
1450 pthread_mutex_unlock(&(this->mutex
));
1452 check_destroy(check
);
1456 * Implementation of connect_manager_t.check_and_register.
1458 static bool check_and_register(private_connect_manager_t
*this,
1459 identification_t
*id
, identification_t
*peer_id
,
1460 ike_sa_id_t
*mediated_sa
, child_cfg_t
*child
)
1462 initiated_t
*initiated
;
1463 bool already_there
= TRUE
;
1465 pthread_mutex_lock(&(this->mutex
));
1467 if (get_initiated_by_ids(this, id
, peer_id
, &initiated
) != SUCCESS
)
1469 DBG2(DBG_IKE
, "registered waiting mediated connection with '%D'", peer_id
);
1470 initiated
= initiated_create(id
, peer_id
);
1471 this->initiated
->insert_last(this->initiated
, initiated
);
1472 already_there
= FALSE
;
1475 waiting_sa_t
*waiting_sa
;
1476 if (get_waiting_sa(initiated
, mediated_sa
, &waiting_sa
) != SUCCESS
)
1478 waiting_sa
= waiting_sa_create(mediated_sa
);
1479 initiated
->mediated
->insert_last(initiated
->mediated
, waiting_sa
);
1482 child
->get_ref(child
);
1483 waiting_sa
->childs
->insert_last(waiting_sa
->childs
, child
);
1485 pthread_mutex_unlock(&(this->mutex
));
1487 return already_there
;
1491 * Implementation of connect_manager_t.check_and_initiate.
1493 static void check_and_initiate(private_connect_manager_t
*this, ike_sa_id_t
*mediation_sa
,
1494 identification_t
*id
, identification_t
*peer_id
)
1496 initiated_t
*initiated
;
1498 pthread_mutex_lock(&(this->mutex
));
1500 if (get_initiated_by_ids(this, id
, peer_id
, &initiated
) != SUCCESS
)
1502 DBG2(DBG_IKE
, "no waiting mediated connections with '%D'", peer_id
);
1503 pthread_mutex_unlock(&(this->mutex
));
1507 waiting_sa_t
*waiting_sa
;
1508 iterator_t
*iterator
= initiated
->mediated
->create_iterator(initiated
->mediated
, TRUE
);
1509 while (iterator
->iterate(iterator
, (void**)&waiting_sa
))
1511 job_t
*job
= (job_t
*)reinitiate_mediation_job_create(mediation_sa
,
1512 waiting_sa
->ike_sa_id
);
1513 charon
->processor
->queue_job(charon
->processor
, job
);
1516 pthread_mutex_unlock(&(this->mutex
));
1520 * Implementation of connect_manager_t.set_initiator_data.
1522 static status_t
set_initiator_data(private_connect_manager_t
*this,
1523 identification_t
*initiator
, identification_t
*responder
,
1524 chunk_t session_id
, chunk_t key
, linked_list_t
*endpoints
, bool is_initiator
)
1526 check_list_t
*checklist
;
1528 pthread_mutex_lock(&(this->mutex
));
1530 if (get_checklist_by_id(this, session_id
, NULL
) == SUCCESS
)
1532 DBG1(DBG_IKE
, "checklist with id '%B' already exists, aborting",
1534 pthread_mutex_unlock(&(this->mutex
));
1538 checklist
= check_list_create(initiator
, responder
, session_id
, key
, endpoints
, is_initiator
);
1539 this->checklists
->insert_last(this->checklists
, checklist
);
1541 pthread_mutex_unlock(&(this->mutex
));
1547 * Implementation of connect_manager_t.set_responder_data.
1549 static status_t
set_responder_data(private_connect_manager_t
*this,
1550 chunk_t session_id
, chunk_t key
, linked_list_t
*endpoints
)
1552 check_list_t
*checklist
;
1554 pthread_mutex_lock(&(this->mutex
));
1556 if (get_checklist_by_id(this, session_id
, &checklist
) != SUCCESS
)
1558 DBG1(DBG_IKE
, "checklist with id '%B' not found",
1560 pthread_mutex_unlock(&(this->mutex
));
1564 checklist
->responder
.key
= chunk_clone(key
);
1565 checklist
->responder
.endpoints
= endpoints
->clone_offset(endpoints
, offsetof(endpoint_notify_t
, clone
));
1566 checklist
->state
= CHECK_WAITING
;
1568 build_pairs(checklist
);
1570 /* send the first check immediately */
1571 schedule_checks(this, checklist
, 0);
1573 pthread_mutex_unlock(&(this->mutex
));
1579 * Implementation of connect_manager_t.destroy.
1581 static void destroy(private_connect_manager_t
*this)
1583 pthread_mutex_lock(&(this->mutex
));
1585 this->hasher
->destroy(this->hasher
);
1586 this->checklists
->destroy_function(this->checklists
, (void*)check_list_destroy
);
1587 this->initiated
->destroy_function(this->initiated
, (void*)initiated_destroy
);
1589 pthread_mutex_unlock(&(this->mutex
));
1590 pthread_mutex_destroy(&(this->mutex
));
1595 * Described in header.
1597 connect_manager_t
*connect_manager_create()
1599 private_connect_manager_t
*this = malloc_thing(private_connect_manager_t
);
1601 this->public.destroy
= (void(*)(connect_manager_t
*))destroy
;
1602 this->public.check_and_register
= (bool(*)(connect_manager_t
*,identification_t
*,identification_t
*,ike_sa_id_t
*,child_cfg_t
*))check_and_register
;
1603 this->public.check_and_initiate
= (void(*)(connect_manager_t
*,ike_sa_id_t
*,identification_t
*,identification_t
*))check_and_initiate
;
1604 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
;
1605 this->public.set_responder_data
= (status_t(*)(connect_manager_t
*,chunk_t
,chunk_t
,linked_list_t
*))set_responder_data
;
1606 this->public.process_check
= (void(*)(connect_manager_t
*,message_t
*))process_check
;
1608 this->hasher
= hasher_create(HASH_SHA1
);
1609 this->checklists
= linked_list_create();
1610 this->initiated
= linked_list_create();
1612 pthread_mutex_init(&(this->mutex
), NULL
);
1614 return (connect_manager_t
*)this;