and another
[strongswan.git] / src / charon / sa / connect_manager.c
1 /*
2 * Copyright (C) 2007-2008 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 *
15 * $Id$
16 */
17
18 #include "connect_manager.h"
19
20 #include <pthread.h>
21 #include <math.h>
22
23 #include <daemon.h>
24 #include <utils/linked_list.h>
25 #include <crypto/hashers/hasher.h>
26
27 #include <processing/jobs/callback_job.h>
28 #include <processing/jobs/initiate_mediation_job.h>
29 #include <encoding/payloads/endpoint_notify.h>
30
31 /* base timeout
32 * the check interval is ME_INTERVAL * active checklists (N) */
33 #define ME_INTERVAL 20 /* ms */
34 /* retransmission timeout is first ME_RTO_B * N for ME_BOOST retransmissions
35 * then gets reduced to ME_RTO * N. */
36 /* number of initial retransmissions sent in short interval */
37 #define ME_BOOST 2
38 /* retransmission timeout */
39 #define ME_RTO 100 /* ms */
40 /* max number of retransmissions */
41 #define ME_MAX_RETRANS 9
42
43
44 typedef struct private_connect_manager_t private_connect_manager_t;
45
46 /**
47 * Additional private members of connect_manager_t.
48 */
49 struct private_connect_manager_t {
50 /**
51 * Public interface of connect_manager_t.
52 */
53 connect_manager_t public;
54
55 /**
56 * Lock for exclusivly accessing the manager.
57 */
58 pthread_mutex_t mutex;
59
60 /**
61 * Hasher to generate signatures
62 */
63 hasher_t *hasher;
64
65 /**
66 * Linked list with initiated mediated connections
67 */
68 linked_list_t *initiated;
69
70 /**
71 * Linked list with checklists (hash table with connect ID as key would be better).
72 */
73 linked_list_t *checklists;
74 };
75
76 typedef enum check_state_t check_state_t;
77
78 enum check_state_t {
79 CHECK_NONE,
80 CHECK_WAITING,
81 CHECK_IN_PROGRESS,
82 CHECK_SUCCEEDED,
83 CHECK_FAILED
84 };
85
86 typedef struct endpoint_pair_t endpoint_pair_t;
87
88 /**
89 * An entry in the check list.
90 */
91 struct endpoint_pair_t {
92 /** pair id */
93 u_int32_t id;
94
95 /** priority */
96 u_int64_t priority;
97
98 /** local endpoint */
99 host_t *local;
100
101 /** remote endpoint */
102 host_t *remote;
103
104 /** state */
105 check_state_t state;
106
107 /** number of retransmissions */
108 u_int32_t retransmitted;
109
110 /** the generated packet */
111 packet_t *packet;
112 };
113
114 /**
115 * Destroys an endpoint pair
116 */
117 static void endpoint_pair_destroy(endpoint_pair_t *this)
118 {
119 DESTROY_IF(this->local);
120 DESTROY_IF(this->remote);
121 DESTROY_IF(this->packet);
122 free(this);
123 }
124
125 /**
126 * Creates a new entry for the list.
127 */
128 static endpoint_pair_t *endpoint_pair_create(endpoint_notify_t *initiator,
129 endpoint_notify_t *responder, bool initiator_is_local)
130 {
131 endpoint_pair_t *this = malloc_thing(endpoint_pair_t);
132
133 this->id = 0;
134
135 u_int32_t pi = initiator->get_priority(initiator);
136 u_int32_t pr = responder->get_priority(responder);
137 this->priority = pow(2, 32) * min(pi, pr) + 2 * max(pi, pr) + (pi > pr ? 1 : 0);
138
139 this->local = initiator_is_local ? initiator->get_base(initiator) : responder->get_base(responder);
140 this->local = this->local->clone(this->local);
141 this->remote = initiator_is_local ? responder->get_host(responder) : initiator->get_host(initiator);
142 this->remote = this->remote->clone(this->remote);
143
144 this->state = CHECK_WAITING;
145 this->retransmitted = 0;
146 this->packet = NULL;
147
148 return this;
149 }
150
151
152 typedef struct check_list_t check_list_t;
153
154 /**
155 * An entry in the linked list.
156 */
157 struct check_list_t {
158
159 struct {
160 /** initiator's id */
161 identification_t *id;
162
163 /** initiator's key */
164 chunk_t key;
165
166 /** initiator's endpoints */
167 linked_list_t *endpoints;
168 } initiator;
169
170 struct {
171 /** responder's id */
172 identification_t *id;
173
174 /** responder's key */
175 chunk_t key;
176
177 /** responder's endpoints */
178 linked_list_t *endpoints;
179 } responder;
180
181 /** connect id */
182 chunk_t connect_id;
183
184 /** list of endpoint pairs */
185 linked_list_t *pairs;
186
187 /** pairs queued for triggered checks */
188 linked_list_t *triggered;
189
190 /** state */
191 check_state_t state;
192
193 /** TRUE if this is the initiator */
194 bool is_initiator;
195
196 };
197
198 /**
199 * Destroys a checklist
200 */
201 static void check_list_destroy(check_list_t *this)
202 {
203 DESTROY_IF(this->initiator.id);
204 DESTROY_IF(this->responder.id);
205
206 chunk_free(&this->connect_id);
207 chunk_free(&this->initiator.key);
208 chunk_free(&this->responder.key);
209
210 DESTROY_OFFSET_IF(this->initiator.endpoints, offsetof(endpoint_notify_t, destroy));
211 DESTROY_OFFSET_IF(this->responder.endpoints, offsetof(endpoint_notify_t, destroy));
212
213 DESTROY_FUNCTION_IF(this->pairs, (void*)endpoint_pair_destroy);
214 /* this list contains some of the same elements as contained in this->pairs */
215 DESTROY_IF(this->triggered);
216
217 free(this);
218 }
219
220 /**
221 * Creates a new checklist
222 */
223 static check_list_t *check_list_create(identification_t *initiator, identification_t *responder,
224 chunk_t connect_id, chunk_t initiator_key, linked_list_t *initiator_endpoints,
225 bool is_initiator)
226 {
227 check_list_t *this = malloc_thing(check_list_t);
228
229 this->connect_id = chunk_clone(connect_id);
230
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));
234
235 this->responder.id = responder->clone(responder);
236 this->responder.key = chunk_empty;
237 this->responder.endpoints = NULL;
238
239 this->pairs = linked_list_create();
240 this->triggered = linked_list_create();
241 this->state = CHECK_NONE;
242 this->is_initiator = is_initiator;
243
244 return this;
245 }
246
247
248 typedef struct waiting_sa_t waiting_sa_t;
249
250 /**
251 * For an initiator, the data stored about a waiting mediated sa
252 */
253 struct waiting_sa_t {
254 /** ike sa id */
255 ike_sa_id_t *ike_sa_id;
256
257 /** list of child_cfg_t */
258 linked_list_t *childs;
259 };
260
261 /**
262 * Destroys a queued mediated sa
263 */
264 static void waiting_sa_destroy(waiting_sa_t *this)
265 {
266 DESTROY_IF(this->ike_sa_id);
267 this->childs->destroy_offset(this->childs, offsetof(child_cfg_t, destroy));
268 free(this);
269 }
270
271 /**
272 * Creates a new mediated sa object
273 */
274 static waiting_sa_t *waiting_sa_create(ike_sa_id_t *ike_sa_id)
275 {
276 waiting_sa_t *this = malloc_thing(waiting_sa_t);
277
278 this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
279 this->childs = linked_list_create();
280
281 return this;
282 }
283
284 typedef struct initiated_t initiated_t;
285
286 /**
287 * For an initiator, the data stored about initiated mediation connections
288 */
289 struct initiated_t {
290 /** my id */
291 identification_t *id;
292
293 /** peer id */
294 identification_t *peer_id;
295
296 /** list of mediated sas */
297 linked_list_t *mediated;
298 };
299
300 /**
301 * Destroys a queued initiation
302 */
303 static void initiated_destroy(initiated_t *this)
304 {
305 DESTROY_IF(this->id);
306 DESTROY_IF(this->peer_id);
307 this->mediated->destroy_function(this->mediated, (void*)waiting_sa_destroy);
308 free(this);
309 }
310
311 /**
312 * Creates a queued initiation
313 */
314 static initiated_t *initiated_create(identification_t *id, identification_t *peer_id)
315 {
316 initiated_t *this = malloc_thing(initiated_t);
317
318 this->id = id->clone(id);
319 this->peer_id = peer_id->clone(peer_id);
320 this->mediated = linked_list_create();
321
322 return this;
323 }
324
325
326 typedef struct check_t check_t;
327
328 /**
329 * Data exchanged in a connectivity check
330 */
331 struct check_t {
332 /** message id */
333 u_int32_t mid;
334
335 /** source of the connectivity check */
336 host_t *src;
337
338 /** destination of the connectivity check */
339 host_t *dst;
340
341 /** connect id */
342 chunk_t connect_id;
343
344 /** endpoint */
345 endpoint_notify_t *endpoint;
346
347 /** raw endpoint payload (to verify the signature) */
348 chunk_t endpoint_raw;
349
350 /** connect auth */
351 chunk_t auth;
352 };
353
354 /**
355 * Destroys a connectivity check
356 */
357 static void check_destroy(check_t *this)
358 {
359 chunk_free(&this->connect_id);
360 chunk_free(&this->endpoint_raw);
361 chunk_free(&this->auth);
362 DESTROY_IF(this->src);
363 DESTROY_IF(this->dst);
364 DESTROY_IF(this->endpoint);
365 free(this);
366 }
367
368 /**
369 * Creates a new connectivity check
370 */
371 static check_t *check_create()
372 {
373 check_t *this = malloc_thing(check_t);
374
375 this->connect_id = chunk_empty;
376 this->auth = chunk_empty;
377 this->endpoint_raw = chunk_empty;
378 this->src = NULL;
379 this->dst = NULL;
380 this->endpoint = NULL;
381
382 this->mid = 0;
383
384 return this;
385 }
386
387 typedef struct sender_data_t sender_data_t;
388
389 /**
390 * Data required by the sender
391 */
392 struct sender_data_t {
393 /** connect manager */
394 private_connect_manager_t *connect_manager;
395
396 /** connect id */
397 chunk_t connect_id;
398 };
399
400 /**
401 * Destroys a sender data object
402 */
403 static void sender_data_destroy(sender_data_t *this)
404 {
405 chunk_free(&this->connect_id);
406 free(this);
407 }
408
409 /**
410 * Creates a new sender data object
411 */
412 static sender_data_t *sender_data_create(private_connect_manager_t *connect_manager, chunk_t connect_id)
413 {
414 sender_data_t *this = malloc_thing(sender_data_t);
415 this->connect_manager = connect_manager;
416 this->connect_id = connect_id;
417 return this;
418 }
419
420 typedef struct retransmit_data_t retransmit_data_t;
421
422 /**
423 * Data required by the retransmission job
424 */
425 struct retransmit_data_t {
426 /** connect manager */
427 private_connect_manager_t *connect_manager;
428
429 /** connect id */
430 chunk_t connect_id;
431
432 /** message (pair) id */
433 u_int32_t mid;
434 };
435
436 /**
437 * Destroys a retransmission data object
438 */
439 static void retransmit_data_destroy(retransmit_data_t *this)
440 {
441 chunk_free(&this->connect_id);
442 free(this);
443 }
444
445 /**
446 * Creates a new retransmission data object
447 */
448 static retransmit_data_t *retransmit_data_create(private_connect_manager_t *connect_manager,
449 chunk_t connect_id, u_int32_t mid)
450 {
451 retransmit_data_t *this = malloc_thing(retransmit_data_t);
452
453 this->connect_manager = connect_manager;
454 this->connect_id = connect_id;
455 this->mid = mid;
456
457 return this;
458 }
459
460 typedef struct initiate_data_t initiate_data_t;
461
462 /**
463 * Data required by the initiate mediated
464 */
465 struct initiate_data_t {
466 /** checklist */
467 check_list_t *checklist;
468
469 /** waiting mediated connections */
470 initiated_t *initiated;
471 };
472
473 /**
474 * Destroys a initiate data object
475 */
476 static void initiate_data_destroy(initiate_data_t *this)
477 {
478 check_list_destroy(this->checklist);
479 initiated_destroy(this->initiated);
480 free(this);
481 }
482
483 /**
484 * Creates a new initiate data object
485 */
486 static initiate_data_t *initiate_data_create(check_list_t *checklist, initiated_t *initiated)
487 {
488 initiate_data_t *this = malloc_thing(initiate_data_t);
489
490 this->checklist = checklist;
491 this->initiated = initiated;
492
493 return this;
494 }
495
496 /**
497 * Find an initiated connection by the peers' ids
498 */
499 static bool match_initiated_by_ids(initiated_t *current, identification_t *id,
500 identification_t *peer_id)
501 {
502 return id->equals(id, current->id) && peer_id->equals(peer_id, current->peer_id);
503 }
504
505 static status_t get_initiated_by_ids(private_connect_manager_t *this,
506 identification_t *id, identification_t *peer_id, initiated_t **initiated)
507 {
508 return this->initiated->find_first(this->initiated,
509 (linked_list_match_t)match_initiated_by_ids,
510 (void**)initiated, id, peer_id);
511 }
512
513 /**
514 * Removes data about initiated connections
515 */
516 static void remove_initiated(private_connect_manager_t *this, initiated_t *initiated)
517 {
518 iterator_t *iterator;
519 initiated_t *current;
520
521 iterator = this->initiated->create_iterator(this->initiated, TRUE);
522 while (iterator->iterate(iterator, (void**)&current))
523 {
524 if (current == initiated)
525 {
526 iterator->remove(iterator);
527 break;
528 }
529 }
530 iterator->destroy(iterator);
531 }
532
533 /**
534 * Finds a waiting sa
535 */
536 static bool match_waiting_sa(waiting_sa_t *current, ike_sa_id_t *ike_sa_id)
537 {
538 return ike_sa_id->equals(ike_sa_id, current->ike_sa_id);
539 }
540
541 static status_t get_waiting_sa(initiated_t *initiated, ike_sa_id_t *ike_sa_id, waiting_sa_t **waiting_sa)
542 {
543 return initiated->mediated->find_first(initiated->mediated,
544 (linked_list_match_t)match_waiting_sa,
545 (void**)waiting_sa, ike_sa_id);
546 }
547
548 /**
549 * Find the checklist with a specific connect ID
550 */
551 static bool match_checklist_by_id(check_list_t *current, chunk_t *connect_id)
552 {
553 return chunk_equals(*connect_id, current->connect_id);
554 }
555
556 static status_t get_checklist_by_id(private_connect_manager_t *this,
557 chunk_t connect_id, check_list_t **check_list)
558 {
559 return this->checklists->find_first(this->checklists,
560 (linked_list_match_t)match_checklist_by_id,
561 (void**)check_list, &connect_id);
562 }
563
564 /**
565 * Removes a checklist
566 */
567 static void remove_checklist(private_connect_manager_t *this, check_list_t *checklist)
568 {
569 iterator_t *iterator;
570 check_list_t *current;
571
572 iterator = this->checklists->create_iterator(this->checklists, TRUE);
573 while (iterator->iterate(iterator, (void**)&current))
574 {
575 if (current == checklist)
576 {
577 iterator->remove(iterator);
578 break;
579 }
580 }
581 iterator->destroy(iterator);
582 }
583
584 /**
585 * Checks if a list of endpoint_notify_t contains a certain host_t
586 */
587 static bool match_endpoint_by_host(endpoint_notify_t *current, host_t *host)
588 {
589 return host->equals(host, current->get_host(current));
590 }
591
592 static status_t endpoints_contain(linked_list_t *endpoints, host_t *host, endpoint_notify_t **endpoint)
593 {
594 return endpoints->find_first(endpoints,
595 (linked_list_match_t)match_endpoint_by_host,
596 (void**)endpoint, host);
597 }
598
599 /**
600 * Updates the state of the whole checklist
601 */
602 static void update_checklist_state(check_list_t *checklist)
603 {
604 iterator_t *iterator;
605 endpoint_pair_t *current;
606 bool in_progress = FALSE, succeeded = FALSE;
607
608 iterator = checklist->pairs->create_iterator(checklist->pairs, TRUE);
609 while (iterator->iterate(iterator, (void**)&current))
610 {
611 switch(current->state)
612 {
613 case CHECK_WAITING:
614 /* at least one is still waiting -> checklist remains
615 * in waiting state */
616 iterator->destroy(iterator);
617 return;
618 case CHECK_IN_PROGRESS:
619 in_progress = TRUE;
620 break;
621 case CHECK_SUCCEEDED:
622 succeeded = TRUE;
623 break;
624 default:
625 break;
626 }
627 }
628 iterator->destroy(iterator);
629
630 if (in_progress)
631 {
632 checklist->state = CHECK_IN_PROGRESS;
633 }
634 else if (succeeded)
635 {
636 checklist->state = CHECK_SUCCEEDED;
637 }
638 else
639 {
640 checklist->state = CHECK_FAILED;
641 }
642 }
643
644 /**
645 * Inserts an endpoint pair into the list of pairs ordered by priority (high to low)
646 */
647 static void insert_pair_by_priority(linked_list_t *pairs, endpoint_pair_t *pair)
648 {
649 iterator_t *iterator;
650 endpoint_pair_t *current;
651 bool inserted = FALSE;
652
653 iterator = pairs->create_iterator(pairs, TRUE);
654 while (iterator->iterate(iterator, (void**)&current))
655 {
656 if (current->priority < pair->priority)
657 {
658 iterator->insert_before(iterator, pair);
659 inserted = TRUE;
660 break;
661 }
662 }
663 iterator->destroy(iterator);
664
665 if (!inserted)
666 {
667 pairs->insert_last(pairs, pair);
668 }
669 }
670
671 /**
672 * Searches a list of endpoint_pair_t for a pair with specific host_ts
673 */
674 static bool match_pair_by_hosts(endpoint_pair_t *current, host_t *local, host_t *remote)
675 {
676 return local->equals(local, current->local) && remote->equals(remote, current->remote);
677 }
678
679 static status_t get_pair_by_hosts(linked_list_t *pairs, host_t *local, host_t *remote, endpoint_pair_t **pair)
680 {
681 return pairs->find_first(pairs,
682 (linked_list_match_t)match_pair_by_hosts,
683 (void**)pair, local, remote);
684 }
685
686 static bool match_pair_by_id(endpoint_pair_t *current, u_int32_t *id)
687 {
688 return current->id == *id;
689 }
690
691 /**
692 * Searches for a pair with a specific id
693 */
694 static status_t get_pair_by_id(check_list_t *checklist, u_int32_t id, endpoint_pair_t **pair)
695 {
696 return checklist->pairs->find_first(checklist->pairs,
697 (linked_list_match_t)match_pair_by_id,
698 (void**)pair, &id);
699 }
700
701 static bool match_succeeded_pair(endpoint_pair_t *current)
702 {
703 return current->state == CHECK_SUCCEEDED;
704 }
705
706 /**
707 * Returns the best pair of state CHECK_SUCCEEDED from a checklist.
708 */
709 static status_t get_best_valid_pair(check_list_t *checklist, endpoint_pair_t **pair)
710 {
711 return checklist->pairs->find_first(checklist->pairs,
712 (linked_list_match_t)match_succeeded_pair,
713 (void**)pair);
714 }
715
716 static bool match_waiting_pair(endpoint_pair_t *current)
717 {
718 return current->state == CHECK_WAITING;
719 }
720
721 /**
722 * Returns and *removes* the first triggered pair in state CHECK_WAITING.
723 */
724 static status_t get_triggered_pair(check_list_t *checklist, endpoint_pair_t **pair)
725 {
726 iterator_t *iterator;
727 endpoint_pair_t *current;
728 status_t status = NOT_FOUND;
729
730 iterator = checklist->triggered->create_iterator(checklist->triggered, TRUE);
731 while (iterator->iterate(iterator, (void**)&current))
732 {
733 iterator->remove(iterator);
734
735 if (current->state == CHECK_WAITING)
736 {
737 if (pair)
738 {
739 *pair = current;
740 }
741 status = SUCCESS;
742 break;
743 }
744 }
745 iterator->destroy(iterator);
746
747 return status;
748 }
749
750 /**
751 * Prunes identical pairs with lower priority from the list
752 * Note: this function also numbers the remaining pairs serially
753 */
754 static void prune_pairs(linked_list_t *pairs)
755 {
756 iterator_t *iterator, *search;
757 endpoint_pair_t *current, *other;
758 u_int32_t id = 0;
759
760 iterator = pairs->create_iterator(pairs, TRUE);
761 search = pairs->create_iterator(pairs, TRUE);
762 while (iterator->iterate(iterator, (void**)&current))
763 {
764 current->id = ++id;
765
766 while (search->iterate(search, (void**)&other))
767 {
768 if (current == other)
769 {
770 continue;
771 }
772
773 if (current->local->equals(current->local, other->local) &&
774 current->remote->equals(current->remote, other->remote))
775 {
776 /* since the list of pairs is sorted by priority in descending
777 * order, and we iterate the list from the beginning, we are
778 * sure that the priority of 'other' is lower than that of
779 * 'current', remove it */
780 DBG1(DBG_IKE, "pruning endpoint pair %H - %H with priority %d",
781 other->local, other->remote, other->priority);
782 search->remove(search);
783 endpoint_pair_destroy(other);
784 }
785 }
786 search->reset(search);
787 }
788 search->destroy(search);
789 iterator->destroy(iterator);
790 }
791
792 /**
793 * Builds a list of endpoint pairs
794 */
795 static void build_pairs(check_list_t *checklist)
796 {
797 iterator_t *iterator_i, *iterator_r;
798 endpoint_notify_t *initiator, *responder;
799
800 iterator_i = checklist->initiator.endpoints->create_iterator(checklist->initiator.endpoints, TRUE);
801 while (iterator_i->iterate(iterator_i, (void**)&initiator))
802 {
803 iterator_r = checklist->responder.endpoints->create_iterator(checklist->responder.endpoints, TRUE);
804 while (iterator_r->iterate(iterator_r, (void**)&responder))
805 {
806 if (initiator->get_family(initiator) != responder->get_family(responder))
807 {
808 continue;
809 }
810
811 insert_pair_by_priority(checklist->pairs,
812 endpoint_pair_create(initiator, responder, checklist->is_initiator));
813 }
814 iterator_r->destroy(iterator_r);
815 }
816 iterator_i->destroy(iterator_i);
817
818 prune_pairs(checklist->pairs);
819 }
820
821 /**
822 * Processes the payloads of a connectivity check and returns the extracted data
823 */
824 static status_t process_payloads(message_t *message, check_t *check)
825 {
826 iterator_t *iterator;
827 payload_t *payload;
828
829 iterator = message->get_payload_iterator(message);
830 while (iterator->iterate(iterator, (void**)&payload))
831 {
832 if (payload->get_type(payload) != NOTIFY)
833 {
834 DBG1(DBG_IKE, "ignoring payload of type '%N' while processing "
835 "connectivity check", payload_type_names, payload->get_type(payload));
836 continue;
837 }
838
839 notify_payload_t *notify = (notify_payload_t*)payload;
840
841 switch (notify->get_notify_type(notify))
842 {
843 case ME_ENDPOINT:
844 {
845 if (check->endpoint)
846 {
847 DBG1(DBG_IKE, "connectivity check contains multiple ME_ENDPOINT notifies");
848 break;
849 }
850
851 endpoint_notify_t *endpoint = endpoint_notify_create_from_payload(notify);
852 if (!endpoint)
853 {
854 DBG1(DBG_IKE, "received invalid ME_ENDPOINT notify");
855 break;
856 }
857 check->endpoint = endpoint;
858 check->endpoint_raw = chunk_clone(notify->get_notification_data(notify));
859 DBG2(DBG_IKE, "received ME_ENDPOINT notify");
860 break;
861 }
862 case ME_CONNECTID:
863 {
864 if (check->connect_id.ptr)
865 {
866 DBG1(DBG_IKE, "connectivity check contains multiple ME_CONNECTID notifies");
867 break;
868 }
869 check->connect_id = chunk_clone(notify->get_notification_data(notify));
870 DBG2(DBG_IKE, "received ME_CONNECTID %#B", &check->connect_id);
871 break;
872 }
873 case ME_CONNECTAUTH:
874 {
875 if (check->auth.ptr)
876 {
877 DBG1(DBG_IKE, "connectivity check contains multiple ME_CONNECTAUTH notifies");
878 break;
879 }
880 check->auth = chunk_clone(notify->get_notification_data(notify));
881 DBG2(DBG_IKE, "received ME_CONNECTAUTH %#B", &check->auth);
882 break;
883 }
884 default:
885 break;
886 }
887 }
888 iterator->destroy(iterator);
889
890 if (!check->connect_id.ptr || !check->endpoint || !check->auth.ptr)
891 {
892 DBG1(DBG_IKE, "at least one payload was missing from the connectivity check");
893 return FAILED;
894 }
895
896 return SUCCESS;
897 }
898
899 /**
900 * Builds the signature for a connectivity check
901 */
902 static chunk_t build_signature(private_connect_manager_t *this,
903 check_list_t *checklist, check_t *check, bool outbound)
904 {
905 chunk_t mid_chunk, key_chunk, sig_chunk;
906 chunk_t sig_hash;
907
908 mid_chunk = chunk_from_thing(check->mid);
909
910 key_chunk = (checklist->is_initiator && outbound) || (!checklist->is_initiator && !outbound)
911 ? checklist->initiator.key : checklist->responder.key;
912
913 /* signature = SHA1( MID | ME_CONNECTID | ME_ENDPOINT | ME_CONNECTKEY ) */
914 sig_chunk = chunk_cat("cccc", mid_chunk, check->connect_id, check->endpoint_raw, key_chunk);
915 this->hasher->allocate_hash(this->hasher, sig_chunk, &sig_hash);
916 DBG3(DBG_IKE, "sig_chunk %B", &sig_chunk);
917 DBG3(DBG_IKE, "sig_hash %B", &sig_hash);
918
919 chunk_free(&sig_chunk);
920 return sig_hash;
921 }
922
923 static void queue_retransmission(private_connect_manager_t *this, check_list_t *checklist, endpoint_pair_t *pair);
924 static void schedule_checks(private_connect_manager_t *this, check_list_t *checklist, u_int32_t time);
925 static void finish_checks(private_connect_manager_t *this, check_list_t *checklist);
926
927 /**
928 * This function is triggered for each sent check after a specific timeout
929 */
930 static job_requeue_t retransmit(retransmit_data_t *data)
931 {
932 private_connect_manager_t *this = data->connect_manager;
933
934 pthread_mutex_lock(&(this->mutex));
935
936 check_list_t *checklist;
937 if (get_checklist_by_id(this, data->connect_id, &checklist) != SUCCESS)
938 {
939 DBG1(DBG_IKE, "checklist with id '%B' not found, can't retransmit connectivity check",
940 &data->connect_id);
941 pthread_mutex_unlock(&(this->mutex));
942 return JOB_REQUEUE_NONE;
943 }
944
945 endpoint_pair_t *pair;
946 if (get_pair_by_id(checklist, data->mid, &pair) != SUCCESS)
947 {
948 DBG1(DBG_IKE, "pair with id '%d' not found, can't retransmit connectivity check",
949 data->mid);
950 goto retransmit_end;
951 }
952
953 if (pair->state != CHECK_IN_PROGRESS)
954 {
955 DBG2(DBG_IKE, "pair with id '%d' is in wrong state [%d], don't retransmit the connectivity check",
956 data->mid, pair->state);
957 goto retransmit_end;
958 }
959
960 if (++pair->retransmitted >= ME_MAX_RETRANS)
961 {
962 DBG2(DBG_IKE, "pair with id '%d' failed after %d retransmissions",
963 data->mid, pair->retransmitted);
964 pair->state = CHECK_FAILED;
965 goto retransmit_end;
966 }
967
968 charon->sender->send(charon->sender, pair->packet->clone(pair->packet));
969
970 queue_retransmission(this, checklist, pair);
971
972 retransmit_end:
973 update_checklist_state(checklist);
974
975 switch(checklist->state)
976 {
977 case CHECK_SUCCEEDED:
978 case CHECK_FAILED:
979 finish_checks(this, checklist);
980 break;
981 default:
982 break;
983 }
984
985 pthread_mutex_unlock(&(this->mutex));
986
987 /* we reschedule it manually */
988 return JOB_REQUEUE_NONE;
989 }
990
991 /**
992 * Queues a retransmission job
993 */
994 static void queue_retransmission(private_connect_manager_t *this, check_list_t *checklist, endpoint_pair_t *pair)
995 {
996 retransmit_data_t *data = retransmit_data_create(this, chunk_clone(checklist->connect_id), pair->id);
997 job_t *job = (job_t*)callback_job_create((callback_job_cb_t)retransmit, data, (callback_job_cleanup_t)retransmit_data_destroy, NULL);
998
999 /*
1000 u_int32_t NW = 0;
1001 checklist->pairs->invoke_function(checklist->pairs, (linked_list_invoke_t)count_waiting_pairs, &NW);
1002 u_int32_t rto = max(ME_INTERVAL * N * (NW + 1), ME_RTO_MIN);
1003 */
1004 u_int32_t N = this->checklists->get_count(this->checklists);
1005 u_int32_t rto = ME_INTERVAL * N;
1006 if (pair->retransmitted > ME_BOOST)
1007 {
1008 rto = ME_RTO * N;
1009 }
1010 DBG2(DBG_IKE, "retransmission of pair '%d' in %dms - %d active checklist(s)", pair->id, rto, N);
1011 charon->scheduler->schedule_job(charon->scheduler, (job_t*)job, rto);
1012 }
1013
1014 /**
1015 * Sends a check
1016 */
1017 static void send_check(private_connect_manager_t *this, check_list_t *checklist,
1018 check_t *check, endpoint_pair_t *pair, bool request)
1019 {
1020 message_t *message = message_create();
1021 message->set_message_id(message, check->mid);
1022 message->set_exchange_type(message, INFORMATIONAL);
1023 message->set_request(message, request);
1024 message->set_destination(message, check->dst->clone(check->dst));
1025 message->set_source(message, check->src->clone(check->src));
1026
1027 ike_sa_id_t *ike_sa_id = ike_sa_id_create(0, 0, request);
1028 message->set_ike_sa_id(message, ike_sa_id);
1029 ike_sa_id->destroy(ike_sa_id);
1030
1031 message->add_notify(message, FALSE, ME_CONNECTID, check->connect_id);
1032 DBG2(DBG_IKE, "send ME_CONNECTID %#B", &check->connect_id);
1033
1034 notify_payload_t *endpoint = check->endpoint->build_notify(check->endpoint);
1035 check->endpoint_raw = chunk_clone(endpoint->get_notification_data(endpoint));
1036 message->add_payload(message, (payload_t*)endpoint);
1037 DBG2(DBG_IKE, "send ME_ENDPOINT notify");
1038
1039 check->auth = build_signature(this, checklist, check, TRUE);
1040 message->add_notify(message, FALSE, ME_CONNECTAUTH, check->auth);
1041 DBG2(DBG_IKE, "send ME_CONNECTAUTH %#B", &check->auth);
1042
1043 packet_t *packet;
1044 if (message->generate(message, NULL, NULL, &packet) == SUCCESS)
1045 {
1046 charon->sender->send(charon->sender, packet->clone(packet));
1047
1048 if (request)
1049 {
1050 DESTROY_IF(pair->packet);
1051 pair->packet = packet;
1052 queue_retransmission(this, checklist, pair);
1053 }
1054 else
1055 {
1056 packet->destroy(packet);
1057 }
1058 }
1059 message->destroy(message);
1060 }
1061
1062 /**
1063 * Queues a triggered check
1064 */
1065 static void queue_triggered_check(check_list_t *checklist, endpoint_pair_t *pair)
1066 {
1067 pair->state = CHECK_WAITING;
1068 checklist->triggered->insert_last(checklist->triggered, pair);
1069 }
1070
1071 /**
1072 * This function is triggered for each checklist at a specific interval
1073 */
1074 static job_requeue_t sender(sender_data_t *data)
1075 {
1076 private_connect_manager_t *this = data->connect_manager;
1077
1078 pthread_mutex_lock(&(this->mutex));
1079
1080 check_list_t *checklist;
1081 if (get_checklist_by_id(this, data->connect_id, &checklist) != SUCCESS)
1082 {
1083 DBG1(DBG_IKE, "checklist with id '%B' not found, can't send connectivity check",
1084 &data->connect_id);
1085 pthread_mutex_unlock(&(this->mutex));
1086 return JOB_REQUEUE_NONE;
1087 }
1088
1089 endpoint_pair_t *pair;
1090 if (get_triggered_pair(checklist, &pair) != SUCCESS)
1091 {
1092 DBG1(DBG_IKE, "no triggered check queued, sending an ordinary check");
1093
1094 if (checklist->pairs->find_first(checklist->pairs,
1095 (linked_list_match_t)match_waiting_pair, (void**)&pair) != SUCCESS)
1096 {
1097 pthread_mutex_unlock(&(this->mutex));
1098 DBG1(DBG_IKE, "no pairs in waiting state, aborting");
1099 return JOB_REQUEUE_NONE;
1100 }
1101 }
1102 else
1103 {
1104 DBG1(DBG_IKE, "triggered check found");
1105 }
1106
1107 check_t *check = check_create();
1108 check->mid = pair->id;
1109 check->src = pair->local->clone(pair->local);
1110 check->dst = pair->remote->clone(pair->remote);
1111 check->connect_id = chunk_clone(checklist->connect_id);
1112 check->endpoint = endpoint_notify_create();
1113
1114 pair->state = CHECK_IN_PROGRESS;
1115
1116 send_check(this, checklist, check, pair, TRUE);
1117
1118 check_destroy(check);
1119
1120 /* schedule this job again */
1121 u_int32_t N = this->checklists->get_count(this->checklists);
1122 schedule_checks(this, checklist, ME_INTERVAL * N);
1123
1124 pthread_mutex_unlock(&(this->mutex));
1125
1126 /* we reschedule it manually */
1127 return JOB_REQUEUE_NONE;
1128 }
1129
1130 /**
1131 * Schedules checks for a checklist (time in ms)
1132 */
1133 static void schedule_checks(private_connect_manager_t *this, check_list_t *checklist, u_int32_t time)
1134 {
1135 chunk_t connect_id = chunk_clone(checklist->connect_id);
1136 sender_data_t *data = sender_data_create(this, connect_id);
1137 job_t *job = (job_t*)callback_job_create((callback_job_cb_t)sender, data, (callback_job_cleanup_t)sender_data_destroy, NULL);
1138 charon->scheduler->schedule_job(charon->scheduler, job, time);
1139 }
1140
1141 /**
1142 * Initiates waiting mediated connections
1143 */
1144 static job_requeue_t initiate_mediated(initiate_data_t *data)
1145 {
1146 check_list_t *checklist = data->checklist;
1147 initiated_t *initiated = data->initiated;
1148
1149 endpoint_pair_t *pair;
1150 if (get_best_valid_pair(checklist, &pair) == SUCCESS)
1151 {
1152 waiting_sa_t *waiting_sa;
1153 iterator_t *iterator = initiated->mediated->create_iterator(initiated->mediated, TRUE);
1154 while (iterator->iterate(iterator, (void**)&waiting_sa))
1155 {
1156 ike_sa_t *sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, waiting_sa->ike_sa_id);
1157 if (sa->initiate_mediated(sa, pair->local, pair->remote, waiting_sa->childs,
1158 checklist->connect_id) != SUCCESS)
1159 {
1160 SIG(IKE_UP_FAILED, "establishing the mediated connection failed");
1161 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, sa);
1162 }
1163 charon->ike_sa_manager->checkin(charon->ike_sa_manager, sa);
1164 }
1165 iterator->destroy(iterator);
1166 }
1167 else
1168 {
1169 /* this should (can?) not happen */
1170 }
1171
1172 return JOB_REQUEUE_NONE;
1173 }
1174
1175 /**
1176 * Finishes checks for a checklist
1177 */
1178 static void finish_checks(private_connect_manager_t *this, check_list_t *checklist)
1179 {
1180 if (checklist->is_initiator)
1181 {
1182 initiated_t *initiated;
1183 if (get_initiated_by_ids(this, checklist->initiator.id,
1184 checklist->responder.id, &initiated) == SUCCESS)
1185 {
1186 remove_checklist(this, checklist);
1187 remove_initiated(this, initiated);
1188
1189 initiate_data_t *data = initiate_data_create(checklist, initiated);
1190 job_t *job = (job_t*)callback_job_create((callback_job_cb_t)initiate_mediated, data, (callback_job_cleanup_t)initiate_data_destroy, NULL);
1191 charon->processor->queue_job(charon->processor, job);
1192 return;
1193 }
1194 else
1195 {
1196 DBG1(DBG_IKE, "there is no mediated connection waiting between '%D' "
1197 "and '%D'", checklist->initiator.id, checklist->responder.id);
1198 }
1199 }
1200 }
1201
1202 /**
1203 * Process the response to one of our requests
1204 */
1205 static void process_response(private_connect_manager_t *this, check_t *check,
1206 check_list_t *checklist)
1207 {
1208 endpoint_pair_t *pair;
1209 if (get_pair_by_id(checklist, check->mid, &pair) == SUCCESS)
1210 {
1211 if (pair->local->equals(pair->local, check->dst) &&
1212 pair->remote->equals(pair->remote, check->src))
1213 {
1214 DBG1(DBG_IKE, "endpoint pair '%d' is valid: '%#H' - '%#H'", pair->id,
1215 pair->local, pair->remote);
1216 pair->state = CHECK_SUCCEEDED;
1217 }
1218
1219 linked_list_t *local_endpoints = checklist->is_initiator ?
1220 checklist->initiator.endpoints : checklist->responder.endpoints;
1221
1222 endpoint_notify_t *local_endpoint;
1223 if (endpoints_contain(local_endpoints,
1224 check->endpoint->get_host(check->endpoint), &local_endpoint) != SUCCESS)
1225 {
1226 local_endpoint = endpoint_notify_create_from_host(PEER_REFLEXIVE,
1227 check->endpoint->get_host(check->endpoint), pair->local);
1228 local_endpoint->set_priority(local_endpoint, check->endpoint->get_priority(check->endpoint));
1229 local_endpoints->insert_last(local_endpoints, local_endpoint);
1230 }
1231
1232 update_checklist_state(checklist);
1233
1234 switch(checklist->state)
1235 {
1236 case CHECK_SUCCEEDED:
1237 case CHECK_FAILED:
1238 finish_checks(this, checklist);
1239 break;
1240 default:
1241 break;
1242 }
1243 }
1244 else
1245 {
1246 DBG1(DBG_IKE, "pair with id '%d' not found", check->mid);
1247 }
1248 }
1249
1250 static void process_request(private_connect_manager_t *this, check_t *check,
1251 check_list_t *checklist)
1252 {
1253 linked_list_t *remote_endpoints = checklist->is_initiator ?
1254 checklist->responder.endpoints : checklist->initiator.endpoints;
1255
1256 endpoint_notify_t *peer_reflexive, *remote_endpoint;
1257 peer_reflexive = endpoint_notify_create_from_host(PEER_REFLEXIVE, check->src, NULL);
1258 peer_reflexive->set_priority(peer_reflexive, check->endpoint->get_priority(check->endpoint));
1259
1260 if (endpoints_contain(remote_endpoints, check->src, &remote_endpoint) != SUCCESS)
1261 {
1262 remote_endpoint = peer_reflexive->clone(peer_reflexive);
1263 remote_endpoints->insert_last(remote_endpoints, remote_endpoint);
1264 }
1265
1266 endpoint_pair_t *pair;
1267 if (get_pair_by_hosts(checklist->pairs, check->dst, check->src, &pair) == SUCCESS)
1268 {
1269 switch(pair->state)
1270 {
1271 case CHECK_IN_PROGRESS:
1272 /* prevent retransmissions */
1273 pair->retransmitted = ME_MAX_RETRANS;
1274 /* FIXME: we should wait to the next rto to send the triggered check
1275 * fall-through */
1276 case CHECK_WAITING:
1277 case CHECK_FAILED:
1278 queue_triggered_check(checklist, pair);
1279 break;
1280 case CHECK_SUCCEEDED:
1281 default:
1282 break;
1283 }
1284 }
1285 else
1286 {
1287 endpoint_notify_t *local_endpoint = endpoint_notify_create_from_host(HOST, check->dst, NULL);
1288
1289 endpoint_notify_t *initiator = checklist->is_initiator ? local_endpoint : remote_endpoint;
1290 endpoint_notify_t *responder = checklist->is_initiator ? remote_endpoint : local_endpoint;
1291
1292 pair = endpoint_pair_create(initiator, responder, checklist->is_initiator);
1293 pair->id = checklist->pairs->get_count(checklist->pairs) + 1;
1294
1295 insert_pair_by_priority(checklist->pairs, pair);
1296
1297 queue_triggered_check(checklist, pair);
1298
1299 local_endpoint->destroy(local_endpoint);
1300 }
1301
1302
1303 check_t *response = check_create();
1304
1305 response->mid = check->mid;
1306 response->src = check->dst->clone(check->dst);
1307 response->dst = check->src->clone(check->src);
1308 response->connect_id = chunk_clone(check->connect_id);
1309 response->endpoint = peer_reflexive;
1310
1311 send_check(this, checklist, response, pair, FALSE);
1312
1313 check_destroy(response);
1314 }
1315
1316 /**
1317 * Implementation of connect_manager_t.process_check.
1318 */
1319 static void process_check(private_connect_manager_t *this, message_t *message)
1320 {
1321 if (message->parse_body(message, NULL, NULL) != SUCCESS)
1322 {
1323 DBG1(DBG_IKE, "%N %s with message ID %d processing failed",
1324 exchange_type_names, message->get_exchange_type(message),
1325 message->get_request(message) ? "request" : "response",
1326 message->get_message_id(message));
1327 return;
1328 }
1329
1330 check_t *check = check_create();
1331 check->mid = message->get_message_id(message);
1332 check->src = message->get_source(message);
1333 check->src = check->src->clone(check->src);
1334 check->dst = message->get_destination(message);
1335 check->dst = check->dst->clone(check->dst);
1336
1337 if (process_payloads(message, check) != SUCCESS)
1338 {
1339 DBG1(DBG_IKE, "invalid connectivity check %s received",
1340 message->get_request(message) ? "request" : "response");
1341 check_destroy(check);
1342 return;
1343 }
1344
1345 pthread_mutex_lock(&(this->mutex));
1346
1347 check_list_t *checklist;
1348 if (get_checklist_by_id(this, check->connect_id, &checklist) != SUCCESS)
1349 {
1350 DBG1(DBG_IKE, "checklist with id '%B' not found",
1351 &check->connect_id);
1352 check_destroy(check);
1353 pthread_mutex_unlock(&(this->mutex));
1354 return;
1355 }
1356
1357 chunk_t sig = build_signature(this, checklist, check, FALSE);
1358 if (!chunk_equals(sig, check->auth))
1359 {
1360 DBG1(DBG_IKE, "connectivity check verification failed");
1361 check_destroy(check);
1362 chunk_free(&sig);
1363 pthread_mutex_unlock(&(this->mutex));
1364 return;
1365 }
1366 chunk_free(&sig);
1367
1368 if (message->get_request(message))
1369 {
1370 process_request(this, check, checklist);
1371 }
1372 else
1373 {
1374 process_response(this, check, checklist);
1375 }
1376
1377 pthread_mutex_unlock(&(this->mutex));
1378
1379 check_destroy(check);
1380 }
1381
1382 /**
1383 * Implementation of connect_manager_t.check_and_register.
1384 */
1385 static bool check_and_register(private_connect_manager_t *this,
1386 identification_t *id, identification_t *peer_id,
1387 ike_sa_id_t *mediated_sa, child_cfg_t *child)
1388 {
1389 initiated_t *initiated;
1390 bool already_there = TRUE;
1391
1392 pthread_mutex_lock(&(this->mutex));
1393
1394 if (get_initiated_by_ids(this, id, peer_id, &initiated) != SUCCESS)
1395 {
1396 DBG2(DBG_IKE, "registered waiting mediated connection with '%D'", peer_id);
1397 initiated = initiated_create(id, peer_id);
1398 this->initiated->insert_last(this->initiated, initiated);
1399 already_there = FALSE;
1400 }
1401
1402 waiting_sa_t *waiting_sa;
1403 if (get_waiting_sa(initiated, mediated_sa, &waiting_sa) != SUCCESS)
1404 {
1405 waiting_sa = waiting_sa_create(mediated_sa);
1406 initiated->mediated->insert_last(initiated->mediated, waiting_sa);
1407 }
1408
1409 child->get_ref(child);
1410 waiting_sa->childs->insert_last(waiting_sa->childs, child);
1411
1412 pthread_mutex_unlock(&(this->mutex));
1413
1414 return already_there;
1415 }
1416
1417 /**
1418 * Implementation of connect_manager_t.check_and_initiate.
1419 */
1420 static void check_and_initiate(private_connect_manager_t *this, ike_sa_id_t *mediation_sa,
1421 identification_t *id, identification_t *peer_id)
1422 {
1423 initiated_t *initiated;
1424
1425 pthread_mutex_lock(&(this->mutex));
1426
1427 if (get_initiated_by_ids(this, id, peer_id, &initiated) != SUCCESS)
1428 {
1429 DBG2(DBG_IKE, "no waiting mediated connections with '%D'", peer_id);
1430 pthread_mutex_unlock(&(this->mutex));
1431 return;
1432 }
1433
1434 waiting_sa_t *waiting_sa;
1435 iterator_t *iterator = initiated->mediated->create_iterator(initiated->mediated, TRUE);
1436 while (iterator->iterate(iterator, (void**)&waiting_sa))
1437 {
1438 job_t *job = (job_t*)reinitiate_mediation_job_create(mediation_sa,
1439 waiting_sa->ike_sa_id);
1440 charon->processor->queue_job(charon->processor, job);
1441 }
1442 iterator->destroy(iterator);
1443
1444 pthread_mutex_unlock(&(this->mutex));
1445 }
1446
1447 /**
1448 * Implementation of connect_manager_t.set_initiator_data.
1449 */
1450 static status_t set_initiator_data(private_connect_manager_t *this,
1451 identification_t *initiator, identification_t *responder,
1452 chunk_t connect_id, chunk_t key, linked_list_t *endpoints, bool is_initiator)
1453 {
1454 check_list_t *checklist;
1455
1456 pthread_mutex_lock(&(this->mutex));
1457
1458 if (get_checklist_by_id(this, connect_id, NULL) == SUCCESS)
1459 {
1460 DBG1(DBG_IKE, "checklist with id '%B' already exists, aborting",
1461 &connect_id);
1462 pthread_mutex_unlock(&(this->mutex));
1463 return FAILED;
1464 }
1465
1466 checklist = check_list_create(initiator, responder, connect_id, key, endpoints, is_initiator);
1467 this->checklists->insert_last(this->checklists, checklist);
1468
1469 pthread_mutex_unlock(&(this->mutex));
1470
1471 return SUCCESS;
1472 }
1473
1474 /**
1475 * Implementation of connect_manager_t.set_responder_data.
1476 */
1477 static status_t set_responder_data(private_connect_manager_t *this,
1478 chunk_t connect_id, chunk_t key, linked_list_t *endpoints)
1479 {
1480 check_list_t *checklist;
1481
1482 pthread_mutex_lock(&(this->mutex));
1483
1484 if (get_checklist_by_id(this, connect_id, &checklist) != SUCCESS)
1485 {
1486 DBG1(DBG_IKE, "checklist with id '%B' not found",
1487 &connect_id);
1488 pthread_mutex_unlock(&(this->mutex));
1489 return NOT_FOUND;
1490 }
1491
1492 checklist->responder.key = chunk_clone(key);
1493 checklist->responder.endpoints = endpoints->clone_offset(endpoints, offsetof(endpoint_notify_t, clone));
1494 checklist->state = CHECK_WAITING;
1495
1496 build_pairs(checklist);
1497
1498 /* send the first check immediately */
1499 schedule_checks(this, checklist, 0);
1500
1501 pthread_mutex_unlock(&(this->mutex));
1502
1503 return SUCCESS;
1504 }
1505
1506 /**
1507 * Implementation of connect_manager_t.stop_checks.
1508 */
1509 static status_t stop_checks(private_connect_manager_t *this, chunk_t connect_id)
1510 {
1511 check_list_t *checklist;
1512
1513 pthread_mutex_lock(&(this->mutex));
1514
1515 if (get_checklist_by_id(this, connect_id, &checklist) != SUCCESS)
1516 {
1517 DBG1(DBG_IKE, "checklist with id '%B' not found",
1518 &connect_id);
1519 pthread_mutex_unlock(&(this->mutex));
1520 return NOT_FOUND;
1521 }
1522
1523 DBG1(DBG_IKE, "removing checklist with id '%B'", &connect_id);
1524
1525 remove_checklist(this, checklist);
1526 check_list_destroy(checklist);
1527
1528 pthread_mutex_unlock(&(this->mutex));
1529
1530 return SUCCESS;
1531 }
1532
1533 /**
1534 * Implementation of connect_manager_t.destroy.
1535 */
1536 static void destroy(private_connect_manager_t *this)
1537 {
1538 pthread_mutex_lock(&(this->mutex));
1539
1540 this->hasher->destroy(this->hasher);
1541 this->checklists->destroy_function(this->checklists, (void*)check_list_destroy);
1542 this->initiated->destroy_function(this->initiated, (void*)initiated_destroy);
1543
1544 pthread_mutex_unlock(&(this->mutex));
1545 pthread_mutex_destroy(&(this->mutex));
1546 free(this);
1547 }
1548
1549 /*
1550 * Described in header.
1551 */
1552 connect_manager_t *connect_manager_create()
1553 {
1554 private_connect_manager_t *this = malloc_thing(private_connect_manager_t);
1555
1556 this->public.destroy = (void(*)(connect_manager_t*))destroy;
1557 this->public.check_and_register = (bool(*)(connect_manager_t*,identification_t*,identification_t*,ike_sa_id_t*,child_cfg_t*))check_and_register;
1558 this->public.check_and_initiate = (void(*)(connect_manager_t*,ike_sa_id_t*,identification_t*,identification_t*))check_and_initiate;
1559 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;
1560 this->public.set_responder_data = (status_t(*)(connect_manager_t*,chunk_t,chunk_t,linked_list_t*))set_responder_data;
1561 this->public.process_check = (void(*)(connect_manager_t*,message_t*))process_check;
1562 this->public.stop_checks = (status_t(*)(connect_manager_t*,chunk_t))stop_checks;
1563
1564 this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
1565 if (this->hasher == NULL)
1566 {
1567 DBG1(DBG_IKE, "unable to create connect manager, SHA1 not supported");
1568 free(this);
1569 return NULL;
1570 }
1571
1572 this->checklists = linked_list_create();
1573 this->initiated = linked_list_create();
1574
1575 pthread_mutex_init(&(this->mutex), NULL);
1576
1577 return (connect_manager_t*)this;
1578 }