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 /* ms */
39 /* min retransmission timeout (RTO is P2P_INTERVAL * N * checks in waiting state) */
40 #define P2P_RTO_MIN 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 /* this list contains some of the same elements as contained in this->pairs */
216 DESTROY_IF(this->triggered
);
222 * Creates a new checklist
224 static check_list_t
*check_list_create(identification_t
*initiator
, identification_t
*responder
,
225 chunk_t session_id
, chunk_t initiator_key
, linked_list_t
*initiator_endpoints
,
228 check_list_t
*this = malloc_thing(check_list_t
);
230 this->session_id
= chunk_clone(session_id
);
232 this->initiator
.id
= initiator
->clone(initiator
);
233 this->initiator
.key
= chunk_clone(initiator_key
);
234 this->initiator
.endpoints
= initiator_endpoints
->clone_offset(initiator_endpoints
, offsetof(endpoint_notify_t
, clone
));
236 this->responder
.id
= responder
->clone(responder
);
237 this->responder
.key
= chunk_empty
;
238 this->responder
.endpoints
= NULL
;
240 this->pairs
= linked_list_create();
241 this->triggered
= linked_list_create();
242 this->state
= CHECK_NONE
;
243 this->is_initiator
= is_initiator
;
249 typedef struct waiting_sa_t waiting_sa_t
;
252 * For an initiator, the data stored about a waiting mediated sa
254 struct waiting_sa_t
{
256 ike_sa_id_t
*ike_sa_id
;
258 /** list of child_cfg_t */
259 linked_list_t
*childs
;
263 * Destroys a queued mediated sa
265 static void waiting_sa_destroy(waiting_sa_t
*this)
267 DESTROY_IF(this->ike_sa_id
);
268 this->childs
->destroy_offset(this->childs
, offsetof(child_cfg_t
, destroy
));
273 * Creates a new mediated sa object
275 static waiting_sa_t
*waiting_sa_create(ike_sa_id_t
*ike_sa_id
)
277 waiting_sa_t
*this = malloc_thing(waiting_sa_t
);
279 this->ike_sa_id
= ike_sa_id
->clone(ike_sa_id
);
280 this->childs
= linked_list_create();
285 typedef struct initiated_t initiated_t
;
288 * For an initiator, the data stored about initiated mediation connections
292 identification_t
*id
;
295 identification_t
*peer_id
;
297 /** list of mediated sas */
298 linked_list_t
*mediated
;
302 * Destroys a queued initiation
304 static void initiated_destroy(initiated_t
*this)
306 DESTROY_IF(this->id
);
307 DESTROY_IF(this->peer_id
);
308 this->mediated
->destroy_function(this->mediated
, (void*)waiting_sa_destroy
);
313 * Creates a queued initiation
315 static initiated_t
*initiated_create(identification_t
*id
, identification_t
*peer_id
)
317 initiated_t
*this = malloc_thing(initiated_t
);
319 this->id
= id
->clone(id
);
320 this->peer_id
= peer_id
->clone(peer_id
);
321 this->mediated
= linked_list_create();
327 typedef struct check_t check_t
;
330 * Data exchanged in a connectivity check
336 /** source of the connectivity check */
339 /** destination of the connectivity check */
346 endpoint_notify_t
*endpoint
;
348 /** raw endpoint payload (to verify the signature) */
349 chunk_t endpoint_raw
;
356 * Destroys a connectivity check
358 static void check_destroy(check_t
*this)
360 chunk_free(&this->session_id
);
361 chunk_free(&this->endpoint_raw
);
362 chunk_free(&this->cookie
);
363 DESTROY_IF(this->endpoint
);
368 * Creates a new connectivity check
370 static check_t
*check_create()
372 check_t
*this = malloc_thing(check_t
);
374 this->session_id
= chunk_empty
;
375 this->cookie
= chunk_empty
;
376 this->endpoint_raw
= chunk_empty
;
377 this->endpoint
= NULL
;
384 typedef struct sender_data_t sender_data_t
;
387 * Data required by the sender
389 struct sender_data_t
{
390 /** connect manager */
391 private_connect_manager_t
*connect_manager
;
398 * Destroys a sender data object
400 static void sender_data_destroy(sender_data_t
*this)
402 chunk_free(&this->session_id
);
407 * Creates a new sender data object
409 static sender_data_t
*sender_data_create(private_connect_manager_t
*connect_manager
, chunk_t session_id
)
411 sender_data_t
*this = malloc_thing(sender_data_t
);
412 this->connect_manager
= connect_manager
;
413 this->session_id
= session_id
;
417 typedef struct retransmit_data_t retransmit_data_t
;
420 * Data required by the retransmission job
422 struct retransmit_data_t
{
423 /** connect manager */
424 private_connect_manager_t
*connect_manager
;
429 /** message (pair) id */
434 * Destroys a retransmission data object
436 static void retransmit_data_destroy(retransmit_data_t
*this)
438 chunk_free(&this->session_id
);
443 * Creates a new retransmission data object
445 static retransmit_data_t
*retransmit_data_create(private_connect_manager_t
*connect_manager
,
446 chunk_t session_id
, u_int32_t mid
)
448 retransmit_data_t
*this = malloc_thing(retransmit_data_t
);
450 this->connect_manager
= connect_manager
;
451 this->session_id
= session_id
;
457 typedef struct initiate_data_t initiate_data_t
;
460 * Data required by the initiate mediated
462 struct initiate_data_t
{
464 check_list_t
*checklist
;
466 /** waiting mediated connections */
467 initiated_t
*initiated
;
471 * Destroys a initiate data object
473 static void initiate_data_destroy(initiate_data_t
*this)
475 check_list_destroy(this->checklist
);
476 initiated_destroy(this->initiated
);
481 * Creates a new initiate data object
483 static initiate_data_t
*initiate_data_create(check_list_t
*checklist
, initiated_t
*initiated
)
485 initiate_data_t
*this = malloc_thing(initiate_data_t
);
487 this->checklist
= checklist
;
488 this->initiated
= initiated
;
494 * Find an initiated connection by the peers' ids
496 static status_t
get_initiated_by_ids(private_connect_manager_t
*this,
497 identification_t
*id
, identification_t
*peer_id
, initiated_t
**initiated
)
499 iterator_t
*iterator
;
500 initiated_t
*current
;
501 status_t status
= NOT_FOUND
;
503 iterator
= this->initiated
->create_iterator(this->initiated
, TRUE
);
504 while (iterator
->iterate(iterator
, (void**)¤t
))
506 if (id
->equals(id
, current
->id
) && peer_id
->equals(peer_id
, current
->peer_id
))
510 *initiated
= current
;
516 iterator
->destroy(iterator
);
522 * Removes data about initiated connections
524 static void remove_initiated(private_connect_manager_t
*this, initiated_t
*initiated
)
526 iterator_t
*iterator
;
527 initiated_t
*current
;
529 iterator
= this->initiated
->create_iterator(this->initiated
, TRUE
);
530 while (iterator
->iterate(iterator
, (void**)¤t
))
532 if (current
== initiated
)
534 iterator
->remove(iterator
);
538 iterator
->destroy(iterator
);
544 static status_t
get_waiting_sa(initiated_t
*initiated
, ike_sa_id_t
*ike_sa_id
, waiting_sa_t
**waiting_sa
)
546 iterator_t
*iterator
;
547 waiting_sa_t
*current
;
548 status_t status
= NOT_FOUND
;
550 iterator
= initiated
->mediated
->create_iterator(initiated
->mediated
, TRUE
);
551 while (iterator
->iterate(iterator
, (void**)¤t
))
553 if (ike_sa_id
->equals(ike_sa_id
, current
->ike_sa_id
))
557 *waiting_sa
= current
;
563 iterator
->destroy(iterator
);
569 * Find the checklist with a specific session ID
571 static status_t
get_checklist_by_id(private_connect_manager_t
*this,
572 chunk_t session_id
, check_list_t
**check_list
)
574 iterator_t
*iterator
;
575 check_list_t
*current
;
576 status_t status
= NOT_FOUND
;
578 iterator
= this->checklists
->create_iterator(this->checklists
, TRUE
);
579 while (iterator
->iterate(iterator
, (void**)¤t
))
581 if (chunk_equals(session_id
, current
->session_id
))
585 *check_list
= current
;
591 iterator
->destroy(iterator
);
597 * Removes a checklist
599 static void remove_checklist(private_connect_manager_t
*this, check_list_t
*checklist
)
601 iterator_t
*iterator
;
602 check_list_t
*current
;
604 iterator
= this->checklists
->create_iterator(this->checklists
, TRUE
);
605 while (iterator
->iterate(iterator
, (void**)¤t
))
607 if (current
== checklist
)
609 iterator
->remove(iterator
);
613 iterator
->destroy(iterator
);
617 * Checks if a list of endpoint_notify_t contains a certain host_t
619 static status_t
endpoints_contain(linked_list_t
*endpoints
, host_t
*host
, endpoint_notify_t
**endpoint
)
621 iterator_t
*iterator
;
622 endpoint_notify_t
*current
;
623 status_t status
= NOT_FOUND
;
625 iterator
= endpoints
->create_iterator(endpoints
, TRUE
);
626 while (iterator
->iterate(iterator
, (void**)¤t
))
628 if (host
->equals(host
, current
->get_host(current
)))
638 iterator
->destroy(iterator
);
644 * Updates the state of the whole checklist
646 static void update_checklist_state(check_list_t
*checklist
)
648 iterator_t
*iterator
;
649 endpoint_pair_t
*current
;
650 bool in_progress
= FALSE
, succeeded
= FALSE
;
652 iterator
= checklist
->pairs
->create_iterator(checklist
->pairs
, TRUE
);
653 while (iterator
->iterate(iterator
, (void**)¤t
))
655 switch(current
->state
)
658 /* at least one is still waiting -> checklist remains
659 * in waiting state */
660 iterator
->destroy(iterator
);
662 case CHECK_IN_PROGRESS
:
665 case CHECK_SUCCEEDED
:
672 iterator
->destroy(iterator
);
676 checklist
->state
= CHECK_IN_PROGRESS
;
680 checklist
->state
= CHECK_SUCCEEDED
;
684 checklist
->state
= CHECK_FAILED
;
689 * Inserts an endpoint pair into the list of pairs ordered by priority (high to low)
691 static void insert_pair_by_priority(linked_list_t
*pairs
, endpoint_pair_t
*pair
)
693 iterator_t
*iterator
;
694 endpoint_pair_t
*current
;
695 bool inserted
= FALSE
;
697 iterator
= pairs
->create_iterator(pairs
, TRUE
);
698 while (iterator
->iterate(iterator
, (void**)¤t
))
700 if (current
->priority
< pair
->priority
)
702 iterator
->insert_before(iterator
, pair
);
707 iterator
->destroy(iterator
);
711 pairs
->insert_last(pairs
, pair
);
716 * Searches a list of endpoint_pair_t for a pair with specific host_ts
718 static status_t
get_pair_by_hosts(linked_list_t
*pairs
, host_t
*local
, host_t
*remote
, endpoint_pair_t
**pair
)
720 iterator_t
*iterator
;
721 endpoint_pair_t
*current
;
722 status_t status
= NOT_FOUND
;
724 iterator
= pairs
->create_iterator(pairs
, TRUE
);
725 while (iterator
->iterate(iterator
, (void**)¤t
))
727 if (local
->equals(local
, current
->local
) &&
728 remote
->equals(remote
, current
->remote
))
738 iterator
->destroy(iterator
);
744 * Searches for a pair with a specific id
746 static status_t
get_pair_by_id(check_list_t
*checklist
, u_int32_t id
, endpoint_pair_t
**pair
)
748 iterator_t
*iterator
;
749 endpoint_pair_t
*current
;
750 status_t status
= NOT_FOUND
;
752 iterator
= checklist
->pairs
->create_iterator(checklist
->pairs
, TRUE
);
753 while (iterator
->iterate(iterator
, (void**)¤t
))
755 if (current
->id
== id
)
765 iterator
->destroy(iterator
);
771 * Returns the best pair of state CHECK_SUCCEEDED from a checklist.
773 static status_t
get_best_valid_pair(check_list_t
*checklist
, endpoint_pair_t
**pair
)
775 iterator_t
*iterator
;
776 endpoint_pair_t
*current
;
777 status_t status
= NOT_FOUND
;
779 iterator
= checklist
->pairs
->create_iterator(checklist
->pairs
, TRUE
);
780 while (iterator
->iterate(iterator
, (void**)¤t
))
782 if (current
->state
== CHECK_SUCCEEDED
)
792 iterator
->destroy(iterator
);
798 * Returns and removes the first triggered pair in state CHECK_WAITING.
800 static status_t
get_triggered_pair(check_list_t
*checklist
, endpoint_pair_t
**pair
)
802 iterator_t
*iterator
;
803 endpoint_pair_t
*current
;
804 status_t status
= NOT_FOUND
;
806 iterator
= checklist
->triggered
->create_iterator(checklist
->triggered
, TRUE
);
807 while (iterator
->iterate(iterator
, (void**)¤t
))
809 iterator
->remove(iterator
);
811 if (current
->state
== CHECK_WAITING
)
821 iterator
->destroy(iterator
);
827 * Prunes identical pairs with lower priority from the list
828 * Note: this function also numbers the remaining pairs serially
830 static void prune_pairs(linked_list_t
*pairs
)
832 iterator_t
*iterator
, *search
;
833 endpoint_pair_t
*current
, *other
;
836 iterator
= pairs
->create_iterator(pairs
, TRUE
);
837 search
= pairs
->create_iterator(pairs
, TRUE
);
838 while (iterator
->iterate(iterator
, (void**)¤t
))
842 while (search
->iterate(search
, (void**)&other
))
844 if (current
== other
)
849 if (current
->local
->equals(current
->local
, other
->local
) &&
850 current
->remote
->equals(current
->remote
, other
->remote
))
852 /* since the list of pairs is sorted by priority in descending
853 * order, and we iterate the list from the beginning, we are
854 * sure that the priority of 'other' is lower than that of
855 * 'current', remove it */
856 DBG1(DBG_IKE
, "pruning endpoint pair %H - %H with priority %d",
857 other
->local
, other
->remote
, other
->priority
);
858 search
->remove(search
);
859 endpoint_pair_destroy(other
);
862 search
->reset(search
);
864 search
->destroy(search
);
865 iterator
->destroy(iterator
);
869 * Builds a list of endpoint pairs
871 static void build_pairs(check_list_t
*checklist
)
873 iterator_t
*iterator_i
, *iterator_r
;
874 endpoint_notify_t
*initiator
, *responder
;
876 iterator_i
= checklist
->initiator
.endpoints
->create_iterator(checklist
->initiator
.endpoints
, TRUE
);
877 while (iterator_i
->iterate(iterator_i
, (void**)&initiator
))
879 iterator_r
= checklist
->responder
.endpoints
->create_iterator(checklist
->responder
.endpoints
, TRUE
);
880 while (iterator_r
->iterate(iterator_r
, (void**)&responder
))
882 if (initiator
->get_family(initiator
) != responder
->get_family(responder
))
887 insert_pair_by_priority(checklist
->pairs
,
888 endpoint_pair_create(initiator
, responder
, checklist
->is_initiator
));
890 iterator_r
->destroy(iterator_r
);
892 iterator_i
->destroy(iterator_i
);
894 prune_pairs(checklist
->pairs
);
898 * Processes the payloads of a connectivity check and returns the extracted data
900 static status_t
process_payloads(message_t
*message
, check_t
*check
)
902 iterator_t
*iterator
;
905 iterator
= message
->get_payload_iterator(message
);
906 while (iterator
->iterate(iterator
, (void**)&payload
))
908 if (payload
->get_type(payload
) != NOTIFY
)
910 DBG1(DBG_IKE
, "ignoring payload of type '%N' while processing "
911 "connectivity check", payload_type_names
, payload
->get_type(payload
));
915 notify_payload_t
*notify
= (notify_payload_t
*)payload
;
917 switch (notify
->get_notify_type(notify
))
923 DBG1(DBG_IKE
, "connectivity check contains multiple P2P_ENDPOINT notifies");
927 endpoint_notify_t
*endpoint
= endpoint_notify_create_from_payload(notify
);
930 DBG1(DBG_IKE
, "received invalid P2P_ENDPOINT notify");
933 check
->endpoint
= endpoint
;
934 check
->endpoint_raw
= chunk_clone(notify
->get_notification_data(notify
));
935 DBG2(DBG_IKE
, "received P2P_ENDPOINT notify");
940 if (check
->session_id
.ptr
)
942 DBG1(DBG_IKE
, "connectivity check contains multiple P2P_SESSIONID notifies");
945 check
->session_id
= chunk_clone(notify
->get_notification_data(notify
));
946 DBG3(DBG_IKE
, "received p2p_sessionid %B", &check
->session_id
);
951 if (check
->cookie
.ptr
)
953 DBG1(DBG_IKE
, "connectivity check contains multiple COOKIE notifies");
956 check
->cookie
= chunk_clone(notify
->get_notification_data(notify
));
957 DBG3(DBG_IKE
, "received cookie %B", &check
->cookie
);
964 iterator
->destroy(iterator
);
966 if (!check
->session_id
.ptr
|| !check
->endpoint
|| !check
->cookie
.ptr
)
968 DBG1(DBG_IKE
, "at least one payload was missing from the connectivity check");
976 * Builds the signature for a connectivity check
978 static chunk_t
build_signature(private_connect_manager_t
*this,
979 check_list_t
*checklist
, check_t
*check
, bool outbound
)
981 chunk_t mid_chunk
, key_chunk
, sig_chunk
;
984 mid_chunk
= chunk_from_thing(check
->mid
);
986 key_chunk
= (checklist
->is_initiator
&& outbound
) || (!checklist
->is_initiator
&& !outbound
)
987 ? checklist
->initiator
.key
: checklist
->responder
.key
;
989 /* signature = SHA1( MID | P2P_SESSIONID | P2P_ENDPOINT | P2P_SESSIONKEY ) */
990 sig_chunk
= chunk_cat("cccc", mid_chunk
, check
->session_id
, check
->endpoint_raw
, key_chunk
);
991 this->hasher
->allocate_hash(this->hasher
, sig_chunk
, &sig_hash
);
992 DBG3(DBG_IKE
, "sig_chunk %B", &sig_chunk
);
993 DBG3(DBG_IKE
, "sig_hash %B", &sig_hash
);
995 chunk_free(&sig_chunk
);
999 static void queue_retransmission(private_connect_manager_t
*this, chunk_t session_id
, u_int32_t mid
);
1000 static void schedule_checks(private_connect_manager_t
*this, check_list_t
*checklist
, u_int32_t time
);
1001 static void finish_checks(private_connect_manager_t
*this, check_list_t
*checklist
);
1004 * This function is triggered for each sent check after a specific timeout
1006 static job_requeue_t
retransmit(retransmit_data_t
*data
)
1008 private_connect_manager_t
*this = data
->connect_manager
;
1010 pthread_mutex_lock(&(this->mutex
));
1012 check_list_t
*checklist
;
1013 if (get_checklist_by_id(this, data
->session_id
, &checklist
) != SUCCESS
)
1015 DBG1(DBG_IKE
, "checklist with id '%B' not found, can't retransmit connectivity check",
1017 pthread_mutex_unlock(&(this->mutex
));
1018 return JOB_REQUEUE_NONE
;
1021 endpoint_pair_t
*pair
;
1022 if (get_pair_by_id(checklist
, data
->mid
, &pair
) != SUCCESS
)
1024 DBG1(DBG_IKE
, "pair with id '%d' not found, can't retransmit connectivity check",
1026 goto retransmit_end
;
1029 if (pair
->state
!= CHECK_IN_PROGRESS
)
1031 DBG2(DBG_IKE
, "pair with id '%d' is in wrong state [%d], don't retransmit the connectivity check",
1032 data
->mid
, pair
->state
);
1033 goto retransmit_end
;
1036 if (++pair
->retransmitted
>= P2P_MAX_RETRANS
)
1038 DBG2(DBG_IKE
, "pair with id '%d' failed after %d tries",
1039 data
->mid
, pair
->retransmitted
);
1040 pair
->state
= CHECK_FAILED
;
1041 goto retransmit_end
;
1044 charon
->sender
->send(charon
->sender
, pair
->packet
->clone(pair
->packet
));
1046 queue_retransmission(this, checklist
->session_id
, pair
->id
);
1049 update_checklist_state(checklist
);
1051 switch(checklist
->state
)
1053 case CHECK_SUCCEEDED
:
1055 finish_checks(this, checklist
);
1061 pthread_mutex_unlock(&(this->mutex
));
1063 /* we reschedule it manually */
1064 return JOB_REQUEUE_NONE
;
1068 * Queues a retransmission job
1070 static void queue_retransmission(private_connect_manager_t
*this, chunk_t session_id
, u_int32_t mid
)
1072 retransmit_data_t
*data
= retransmit_data_create(this, chunk_clone(session_id
), mid
);
1073 job_t
*job
= (job_t
*)callback_job_create((callback_job_cb_t
)retransmit
, data
, (callback_job_cleanup_t
)retransmit_data_destroy
, NULL
);
1074 charon
->scheduler
->schedule_job(charon
->scheduler
, (job_t
*)job
, P2P_RTO_MIN
);
1080 static void send_check(private_connect_manager_t
*this, check_list_t
*checklist
,
1081 check_t
*check
, endpoint_pair_t
*pair
, bool request
)
1083 message_t
*message
= message_create();
1084 message
->set_message_id(message
, check
->mid
);
1085 message
->set_exchange_type(message
, INFORMATIONAL
);
1086 message
->set_request(message
, request
);
1087 message
->set_destination(message
, check
->dst
->clone(check
->dst
));
1088 message
->set_source(message
, check
->src
->clone(check
->src
));
1090 message
->set_ike_sa_id(message
, ike_sa_id_create(0, 0, request
));
1092 message
->add_notify(message
, FALSE
, P2P_SESSIONID
, check
->session_id
);
1094 notify_payload_t
*endpoint
= check
->endpoint
->build_notify(check
->endpoint
);
1095 check
->endpoint_raw
= chunk_clone(endpoint
->get_notification_data(endpoint
));
1096 message
->add_payload(message
, (payload_t
*)endpoint
);
1098 check
->cookie
= build_signature(this, checklist
, check
, TRUE
);
1099 message
->add_notify(message
, FALSE
, COOKIE
, check
->cookie
);
1102 if (message
->generate(message
, NULL
, NULL
, &packet
) == SUCCESS
)
1104 charon
->sender
->send(charon
->sender
, packet
->clone(packet
));
1108 DESTROY_IF(pair
->packet
);
1109 pair
->packet
= packet
;
1110 queue_retransmission(this, checklist
->session_id
, pair
->id
);
1114 packet
->destroy(packet
);
1120 * Queues a triggered check
1122 static void queue_triggered_check(check_list_t
*checklist
, endpoint_pair_t
*pair
)
1124 pair
->state
= CHECK_WAITING
;
1125 checklist
->triggered
->insert_last(checklist
->triggered
, pair
);
1129 * This function is triggered for each checklist at a specific interval
1131 static job_requeue_t
sender(sender_data_t
*data
)
1133 private_connect_manager_t
*this = data
->connect_manager
;
1135 pthread_mutex_lock(&(this->mutex
));
1137 check_list_t
*checklist
;
1138 if (get_checklist_by_id(this, data
->session_id
, &checklist
) != SUCCESS
)
1140 DBG1(DBG_IKE
, "checklist with id '%B' not found, can't send connectivity check",
1142 pthread_mutex_unlock(&(this->mutex
));
1143 return JOB_REQUEUE_NONE
;
1146 endpoint_pair_t
*pair
;
1147 if (get_triggered_pair(checklist
, &pair
) != SUCCESS
)
1149 DBG1(DBG_IKE
, "no triggered check queued, sending an ordinary check");
1151 iterator_t
*iterator
;
1152 bool found_one
= FALSE
;
1154 iterator
= checklist
->pairs
->create_iterator(checklist
->pairs
, TRUE
);
1155 while (iterator
->iterate(iterator
, (void**)&pair
))
1157 if (pair
->state
== CHECK_WAITING
)
1163 iterator
->destroy(iterator
);
1167 pthread_mutex_unlock(&(this->mutex
));
1168 DBG1(DBG_IKE
, "no pairs in waiting state, aborting");
1169 return JOB_REQUEUE_NONE
;
1174 DBG1(DBG_IKE
, "triggered check found");
1177 check_t
*check
= check_create();
1178 check
->mid
= pair
->id
;
1179 check
->src
= pair
->local
->clone(pair
->local
);
1180 check
->dst
= pair
->remote
->clone(pair
->remote
);
1181 check
->session_id
= chunk_clone(checklist
->session_id
);
1182 check
->endpoint
= endpoint_notify_create();
1184 pair
->state
= CHECK_IN_PROGRESS
;
1186 send_check(this, checklist
, check
, pair
, TRUE
);
1188 check_destroy(check
);
1190 /* schedule this job again */
1191 u_int32_t N
= this->checklists
->get_count(this->checklists
);
1192 schedule_checks(this, checklist
, P2P_INTERVAL
* N
);
1194 pthread_mutex_unlock(&(this->mutex
));
1196 /* we reschedule it manually */
1197 return JOB_REQUEUE_NONE
;
1201 * Schedules checks for a checklist (time in ms)
1203 static void schedule_checks(private_connect_manager_t
*this, check_list_t
*checklist
, u_int32_t time
)
1205 chunk_t session_id
= chunk_clone(checklist
->session_id
);
1206 sender_data_t
*data
= sender_data_create(this, session_id
);
1207 job_t
*job
= (job_t
*)callback_job_create((callback_job_cb_t
)sender
, data
, (callback_job_cleanup_t
)sender_data_destroy
, NULL
);
1208 charon
->scheduler
->schedule_job(charon
->scheduler
, job
, time
);
1212 * Initiates waiting mediated connections
1214 static job_requeue_t
initiate_mediated(initiate_data_t
*data
)
1216 check_list_t
*checklist
= data
->checklist
;
1217 initiated_t
*initiated
= data
->initiated
;
1219 endpoint_pair_t
*pair
;
1220 if (get_best_valid_pair(checklist
, &pair
) == SUCCESS
)
1222 waiting_sa_t
*waiting_sa
;
1223 iterator_t
*iterator
= initiated
->mediated
->create_iterator(initiated
->mediated
, TRUE
);
1224 while (iterator
->iterate(iterator
, (void**)&waiting_sa
))
1226 ike_sa_t
*sa
= charon
->ike_sa_manager
->checkout(charon
->ike_sa_manager
, waiting_sa
->ike_sa_id
);
1227 if (sa
->initiate_mediated(sa
, pair
->local
, pair
->remote
, waiting_sa
->childs
) != SUCCESS
)
1229 SIG(IKE_UP_FAILED
, "establishing the mediated connection failed");
1230 charon
->ike_sa_manager
->checkin_and_destroy(charon
->ike_sa_manager
, sa
);
1232 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, sa
);
1234 iterator
->destroy(iterator
);
1238 /* this should (can?) not happen */
1241 return JOB_REQUEUE_NONE
;
1245 * Finishes checks for a checklist
1247 static void finish_checks(private_connect_manager_t
*this, check_list_t
*checklist
)
1249 if (checklist
->is_initiator
)
1251 initiated_t
*initiated
;
1252 if (get_initiated_by_ids(this, checklist
->initiator
.id
,
1253 checklist
->responder
.id
, &initiated
) == SUCCESS
)
1255 remove_checklist(this, checklist
);
1256 remove_initiated(this, initiated
);
1258 initiate_data_t
*data
= initiate_data_create(checklist
, initiated
);
1259 job_t
*job
= (job_t
*)callback_job_create((callback_job_cb_t
)initiate_mediated
, data
, (callback_job_cleanup_t
)initiate_data_destroy
, NULL
);
1260 charon
->processor
->queue_job(charon
->processor
, job
);
1265 DBG1(DBG_IKE
, "there is no mediated connection waiting between '%D' "
1266 "and '%D'", checklist
->initiator
.id
, checklist
->responder
.id
);
1270 /* remove_checklist(this, checklist);
1271 * check_list_destroy(checklist);
1272 * FIXME: we should do this ^^^ after a specific timeout on the
1277 * Process the response to one of our requests
1279 static void process_response(private_connect_manager_t
*this, check_t
*check
,
1280 check_list_t
*checklist
)
1282 endpoint_pair_t
*pair
;
1283 if (get_pair_by_id(checklist
, check
->mid
, &pair
) == SUCCESS
)
1285 if (pair
->local
->equals(pair
->local
, check
->dst
) &&
1286 pair
->remote
->equals(pair
->remote
, check
->src
))
1288 DBG1(DBG_IKE
, "endpoint pair '%d' is valid: '%#H' - '%#H'", pair
->id
,
1289 pair
->local
, pair
->remote
);
1290 pair
->state
= CHECK_SUCCEEDED
;
1293 linked_list_t
*local_endpoints
= checklist
->is_initiator ?
1294 checklist
->initiator
.endpoints
: checklist
->responder
.endpoints
;
1296 endpoint_notify_t
*local_endpoint
;
1297 if (endpoints_contain(local_endpoints
,
1298 check
->endpoint
->get_host(check
->endpoint
), &local_endpoint
) != SUCCESS
)
1300 local_endpoint
= endpoint_notify_create_from_host(PEER_REFLEXIVE
,
1301 check
->endpoint
->get_host(check
->endpoint
), pair
->local
);
1302 local_endpoint
->set_priority(local_endpoint
, check
->endpoint
->get_priority(check
->endpoint
));
1303 local_endpoints
->insert_last(local_endpoints
, local_endpoint
);
1306 update_checklist_state(checklist
);
1308 switch(checklist
->state
)
1310 case CHECK_SUCCEEDED
:
1312 finish_checks(this, checklist
);
1320 DBG1(DBG_IKE
, "pair with id '%d' not found", check
->mid
);
1324 static void process_request(private_connect_manager_t
*this, check_t
*check
,
1325 check_list_t
*checklist
)
1327 linked_list_t
*remote_endpoints
= checklist
->is_initiator ?
1328 checklist
->responder
.endpoints
: checklist
->initiator
.endpoints
;
1330 endpoint_notify_t
*peer_reflexive
, *remote_endpoint
;
1331 peer_reflexive
= endpoint_notify_create_from_host(PEER_REFLEXIVE
, check
->src
, NULL
);
1332 peer_reflexive
->set_priority(peer_reflexive
, check
->endpoint
->get_priority(check
->endpoint
));
1334 if (endpoints_contain(remote_endpoints
, check
->src
, &remote_endpoint
) != SUCCESS
)
1336 remote_endpoint
= peer_reflexive
->clone(peer_reflexive
);
1337 remote_endpoints
->insert_last(remote_endpoints
, remote_endpoint
);
1340 endpoint_pair_t
*pair
;
1341 if (get_pair_by_hosts(checklist
->pairs
, check
->dst
, check
->src
, &pair
) == SUCCESS
)
1345 case CHECK_IN_PROGRESS
:
1346 /* prevent retransmissions */
1347 pair
->retransmitted
= P2P_MAX_RETRANS
;
1348 /* FIXME: we should wait to the next rto to send the triggered check
1352 queue_triggered_check(checklist
, pair
);
1354 case CHECK_SUCCEEDED
:
1361 endpoint_notify_t
*local_endpoint
= endpoint_notify_create_from_host(HOST
, check
->dst
, NULL
);
1363 endpoint_notify_t
*initiator
= checklist
->is_initiator ? local_endpoint
: remote_endpoint
;
1364 endpoint_notify_t
*responder
= checklist
->is_initiator ? remote_endpoint
: local_endpoint
;
1366 pair
= endpoint_pair_create(initiator
, responder
, checklist
->is_initiator
);
1367 pair
->id
= checklist
->pairs
->get_count(checklist
->pairs
) + 1;
1369 insert_pair_by_priority(checklist
->pairs
, pair
);
1371 queue_triggered_check(checklist
, pair
);
1373 local_endpoint
->destroy(local_endpoint
);
1377 check_t
*response
= check_create();
1379 response
->mid
= check
->mid
;
1380 response
->src
= check
->dst
->clone(check
->dst
);
1381 response
->dst
= check
->src
->clone(check
->src
);
1382 response
->session_id
= chunk_clone(check
->session_id
);
1383 response
->endpoint
= peer_reflexive
;
1385 send_check(this, checklist
, response
, pair
, FALSE
);
1387 check_destroy(response
);
1391 * Implementation of connect_manager_t.process_check.
1393 static void process_check(private_connect_manager_t
*this, message_t
*message
)
1395 if (message
->parse_body(message
, NULL
, NULL
) != SUCCESS
)
1397 DBG1(DBG_IKE
, "%N %s with message ID %d processing failed",
1398 exchange_type_names
, message
->get_exchange_type(message
),
1399 message
->get_request(message
) ?
"request" : "response",
1400 message
->get_message_id(message
));
1404 check_t
*check
= check_create();
1405 check
->mid
= message
->get_message_id(message
);
1406 check
->src
= message
->get_source(message
);
1407 check
->dst
= message
->get_destination(message
);
1409 if (process_payloads(message
, check
) != SUCCESS
)
1411 DBG1(DBG_IKE
, "invalid connectivity check %s received",
1412 message
->get_request(message
) ?
"request" : "response");
1413 check_destroy(check
);
1417 pthread_mutex_lock(&(this->mutex
));
1419 check_list_t
*checklist
;
1420 if (get_checklist_by_id(this, check
->session_id
, &checklist
) != SUCCESS
)
1422 DBG1(DBG_IKE
, "checklist with id '%B' not found",
1423 &check
->session_id
);
1424 check_destroy(check
);
1425 pthread_mutex_unlock(&(this->mutex
));
1429 chunk_t sig
= build_signature(this, checklist
, check
, FALSE
);
1430 if (!chunk_equals(sig
, check
->cookie
))
1432 DBG1(DBG_IKE
, "connectivity check verification failed");
1433 check_destroy(check
);
1435 pthread_mutex_unlock(&(this->mutex
));
1440 if (message
->get_request(message
))
1442 process_request(this, check
, checklist
);
1446 process_response(this, check
, checklist
);
1449 pthread_mutex_unlock(&(this->mutex
));
1451 check_destroy(check
);
1455 * Implementation of connect_manager_t.check_and_register.
1457 static bool check_and_register(private_connect_manager_t
*this,
1458 identification_t
*id
, identification_t
*peer_id
,
1459 ike_sa_id_t
*mediated_sa
, child_cfg_t
*child
)
1461 initiated_t
*initiated
;
1462 bool already_there
= TRUE
;
1464 pthread_mutex_lock(&(this->mutex
));
1466 if (get_initiated_by_ids(this, id
, peer_id
, &initiated
) != SUCCESS
)
1468 DBG2(DBG_IKE
, "registered waiting mediated connection with '%D'", peer_id
);
1469 initiated
= initiated_create(id
, peer_id
);
1470 this->initiated
->insert_last(this->initiated
, initiated
);
1471 already_there
= FALSE
;
1474 waiting_sa_t
*waiting_sa
;
1475 if (get_waiting_sa(initiated
, mediated_sa
, &waiting_sa
) != SUCCESS
)
1477 waiting_sa
= waiting_sa_create(mediated_sa
);
1478 initiated
->mediated
->insert_last(initiated
->mediated
, waiting_sa
);
1481 child
->get_ref(child
);
1482 waiting_sa
->childs
->insert_last(waiting_sa
->childs
, child
);
1484 pthread_mutex_unlock(&(this->mutex
));
1486 return already_there
;
1490 * Implementation of connect_manager_t.check_and_initiate.
1492 static void check_and_initiate(private_connect_manager_t
*this, ike_sa_id_t
*mediation_sa
,
1493 identification_t
*id
, identification_t
*peer_id
)
1495 initiated_t
*initiated
;
1497 pthread_mutex_lock(&(this->mutex
));
1499 if (get_initiated_by_ids(this, id
, peer_id
, &initiated
) != SUCCESS
)
1501 DBG2(DBG_IKE
, "no waiting mediated connections with '%D'", peer_id
);
1502 pthread_mutex_unlock(&(this->mutex
));
1506 waiting_sa_t
*waiting_sa
;
1507 iterator_t
*iterator
= initiated
->mediated
->create_iterator(initiated
->mediated
, TRUE
);
1508 while (iterator
->iterate(iterator
, (void**)&waiting_sa
))
1510 job_t
*job
= (job_t
*)reinitiate_mediation_job_create(mediation_sa
,
1511 waiting_sa
->ike_sa_id
);
1512 charon
->processor
->queue_job(charon
->processor
, job
);
1515 pthread_mutex_unlock(&(this->mutex
));
1519 * Implementation of connect_manager_t.set_initiator_data.
1521 static status_t
set_initiator_data(private_connect_manager_t
*this,
1522 identification_t
*initiator
, identification_t
*responder
,
1523 chunk_t session_id
, chunk_t key
, linked_list_t
*endpoints
, bool is_initiator
)
1525 check_list_t
*checklist
;
1527 pthread_mutex_lock(&(this->mutex
));
1529 if (get_checklist_by_id(this, session_id
, NULL
) == SUCCESS
)
1531 DBG1(DBG_IKE
, "checklist with id '%B' already exists, aborting",
1533 pthread_mutex_unlock(&(this->mutex
));
1537 checklist
= check_list_create(initiator
, responder
, session_id
, key
, endpoints
, is_initiator
);
1538 this->checklists
->insert_last(this->checklists
, checklist
);
1540 pthread_mutex_unlock(&(this->mutex
));
1546 * Implementation of connect_manager_t.set_responder_data.
1548 static status_t
set_responder_data(private_connect_manager_t
*this,
1549 chunk_t session_id
, chunk_t key
, linked_list_t
*endpoints
)
1551 check_list_t
*checklist
;
1553 pthread_mutex_lock(&(this->mutex
));
1555 if (get_checklist_by_id(this, session_id
, &checklist
) != SUCCESS
)
1557 DBG1(DBG_IKE
, "checklist with id '%B' not found",
1559 pthread_mutex_unlock(&(this->mutex
));
1563 checklist
->responder
.key
= chunk_clone(key
);
1564 checklist
->responder
.endpoints
= endpoints
->clone_offset(endpoints
, offsetof(endpoint_notify_t
, clone
));
1565 checklist
->state
= CHECK_WAITING
;
1567 build_pairs(checklist
);
1569 /* send the first check immediately */
1570 schedule_checks(this, checklist
, 0);
1572 pthread_mutex_unlock(&(this->mutex
));
1578 * Implementation of connect_manager_t.destroy.
1580 static void destroy(private_connect_manager_t
*this)
1582 pthread_mutex_lock(&(this->mutex
));
1584 this->hasher
->destroy(this->hasher
);
1585 this->checklists
->destroy_function(this->checklists
, (void*)check_list_destroy
);
1586 this->initiated
->destroy_function(this->initiated
, (void*)initiated_destroy
);
1588 pthread_mutex_unlock(&(this->mutex
));
1589 pthread_mutex_destroy(&(this->mutex
));
1594 * Described in header.
1596 connect_manager_t
*connect_manager_create()
1598 private_connect_manager_t
*this = malloc_thing(private_connect_manager_t
);
1600 this->public.destroy
= (void(*)(connect_manager_t
*))destroy
;
1601 this->public.check_and_register
= (bool(*)(connect_manager_t
*,identification_t
*,identification_t
*,ike_sa_id_t
*,child_cfg_t
*))check_and_register
;
1602 this->public.check_and_initiate
= (void(*)(connect_manager_t
*,ike_sa_id_t
*,identification_t
*,identification_t
*))check_and_initiate
;
1603 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
;
1604 this->public.set_responder_data
= (status_t(*)(connect_manager_t
*,chunk_t
,chunk_t
,linked_list_t
*))set_responder_data
;
1605 this->public.process_check
= (void(*)(connect_manager_t
*,message_t
*))process_check
;
1607 this->hasher
= hasher_create(HASH_SHA1
);
1608 this->checklists
= linked_list_create();
1609 this->initiated
= linked_list_create();
1611 pthread_mutex_init(&(this->mutex
), NULL
);
1613 return (connect_manager_t
*)this;