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