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