improving [3361]: moved one of the added return values
[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 // 20 ms
39 // min retransmission timeout (RTO is P2P_INTERVAL * N * checks in waiting state)
40 #define P2P_RTO_MIN 100 // 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 DESTROY_IF(this->triggered); // this list contains some of the same elements as contained in this->pairs
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 session_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->session_id = chunk_clone(session_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 /** session id */
342 chunk_t session_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 /** cookie */
351 chunk_t cookie;
352 };
353
354 /**
355 * Destroys a connectivity check
356 */
357 static void check_destroy(check_t *this)
358 {
359 chunk_free(&this->session_id);
360 chunk_free(&this->endpoint_raw);
361 chunk_free(&this->cookie);
362 DESTROY_IF(this->endpoint);
363 free(this);
364 }
365
366 /**
367 * Creates a new connectivity check
368 */
369 static check_t *check_create()
370 {
371 check_t *this = malloc_thing(check_t);
372
373 this->session_id = chunk_empty;
374 this->cookie = chunk_empty;
375 this->endpoint_raw = chunk_empty;
376 this->endpoint = NULL;
377
378 this->mid = 0;
379
380 return this;
381 }
382
383 typedef struct sender_data_t sender_data_t;
384
385 /**
386 * Data required by the sender
387 */
388 struct sender_data_t {
389 /** connect manager */
390 private_connect_manager_t *connect_manager;
391
392 /** session id */
393 chunk_t session_id;
394 };
395
396 /**
397 * Destroys a sender data object
398 */
399 static void sender_data_destroy(sender_data_t *this)
400 {
401 chunk_free(&this->session_id);
402 free(this);
403 }
404
405 /**
406 * Creates a new sender data object
407 */
408 static sender_data_t *sender_data_create(private_connect_manager_t *connect_manager, chunk_t session_id)
409 {
410 sender_data_t *this = malloc_thing(sender_data_t);
411 this->connect_manager = connect_manager;
412 this->session_id = session_id;
413 return this;
414 }
415
416 typedef struct retransmit_data_t retransmit_data_t;
417
418 /**
419 * Data required by the retransmission job
420 */
421 struct retransmit_data_t {
422 /** connect manager */
423 private_connect_manager_t *connect_manager;
424
425 /** session id */
426 chunk_t session_id;
427
428 /** message (pair) id */
429 u_int32_t mid;
430 };
431
432 /**
433 * Destroys a retransmission data object
434 */
435 static void retransmit_data_destroy(retransmit_data_t *this)
436 {
437 chunk_free(&this->session_id);
438 free(this);
439 }
440
441 /**
442 * Creates a new retransmission data object
443 */
444 static retransmit_data_t *retransmit_data_create(private_connect_manager_t *connect_manager,
445 chunk_t session_id, u_int32_t mid)
446 {
447 retransmit_data_t *this = malloc_thing(retransmit_data_t);
448
449 this->connect_manager = connect_manager;
450 this->session_id = session_id;
451 this->mid = mid;
452
453 return this;
454 }
455
456 typedef struct initiate_data_t initiate_data_t;
457
458 /**
459 * Data required by the initiate mediated
460 */
461 struct initiate_data_t {
462 /** checklist */
463 check_list_t *checklist;
464
465 /** waiting mediated connections */
466 initiated_t *initiated;
467 };
468
469 /**
470 * Destroys a initiate data object
471 */
472 static void initiate_data_destroy(initiate_data_t *this)
473 {
474 check_list_destroy(this->checklist);
475 initiated_destroy(this->initiated);
476 free(this);
477 }
478
479 /**
480 * Creates a new initiate data object
481 */
482 static initiate_data_t *initiate_data_create(check_list_t *checklist, initiated_t *initiated)
483 {
484 initiate_data_t *this = malloc_thing(initiate_data_t);
485
486 this->checklist = checklist;
487 this->initiated = initiated;
488
489 return this;
490 }
491
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
646
647 /**
648 * Updates the state of the whole checklist
649 */
650 static void update_checklist_state(check_list_t *checklist)
651 {
652 iterator_t *iterator;
653 endpoint_pair_t *current;
654 bool in_progress = FALSE, succeeded = FALSE;
655
656 iterator = checklist->pairs->create_iterator(checklist->pairs, TRUE);
657 while (iterator->iterate(iterator, (void**)&current))
658 {
659 switch(current->state)
660 {
661 case CHECK_WAITING:
662 // at least one is still waiting -> checklist remains in waiting state
663 iterator->destroy(iterator);
664 return;
665 case CHECK_IN_PROGRESS:
666 in_progress = TRUE;
667 break;
668 case CHECK_SUCCEEDED:
669 succeeded = TRUE;
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 bool inserted = FALSE;
836 u_int32_t id = 0;
837
838 iterator = pairs->create_iterator(pairs, TRUE);
839 search = pairs->create_iterator(pairs, TRUE);
840 while (iterator->iterate(iterator, (void**)&current))
841 {
842 current->id = ++id;
843
844 while (search->iterate(search, (void**)&other))
845 {
846 if (current == other)
847 {
848 continue;
849 }
850
851 if (current->local->equals(current->local, other->local) &&
852 current->remote->equals(current->remote, other->remote))
853 {
854 // since the list of pairs is sorted by priority in descending
855 // order, and we iterate the list from the beginning, we are
856 // sure that the priority of 'other' is lower than that of
857 // 'current', remove it
858 DBG1(DBG_IKE, "pruning endpoint pair %H - %H with priority %d",
859 other->local, other->remote, other->priority);
860 search->remove(search);
861 endpoint_pair_destroy(other);
862 }
863 }
864 search->reset(search);
865 }
866 search->destroy(search);
867 iterator->destroy(iterator);
868 }
869
870 /**
871 * Builds a list of endpoint pairs
872 */
873 static void build_pairs(check_list_t *checklist)
874 {
875 iterator_t *iterator_i, *iterator_r;
876 endpoint_notify_t *initiator, *responder;
877
878 iterator_i = checklist->initiator.endpoints->create_iterator(checklist->initiator.endpoints, TRUE);
879 while (iterator_i->iterate(iterator_i, (void**)&initiator))
880 {
881 iterator_r = checklist->responder.endpoints->create_iterator(checklist->responder.endpoints, TRUE);
882 while (iterator_r->iterate(iterator_r, (void**)&responder))
883 {
884 if (initiator->get_family(initiator) != responder->get_family(responder))
885 {
886 continue;
887 }
888
889 insert_pair_by_priority(checklist->pairs,
890 endpoint_pair_create(initiator, responder, checklist->is_initiator));
891 }
892 iterator_r->destroy(iterator_r);
893 }
894 iterator_i->destroy(iterator_i);
895
896 prune_pairs(checklist->pairs);
897 }
898
899 // -----------------------------------------------------------------------------
900
901 /**
902 * Processes the payloads of a connectivity check and returns the extracted data
903 */
904 static status_t process_payloads(message_t *message, check_t *check)
905 {
906 iterator_t *iterator;
907 payload_t *payload;
908
909 iterator = message->get_payload_iterator(message);
910 while (iterator->iterate(iterator, (void**)&payload))
911 {
912 if (payload->get_type(payload) != NOTIFY)
913 {
914 DBG1(DBG_IKE, "ignoring payload of type '%N' while processing "
915 "connectivity check", payload_type_names, payload->get_type(payload));
916 continue;
917 }
918
919 notify_payload_t *notify = (notify_payload_t*)payload;
920
921 switch (notify->get_notify_type(notify))
922 {
923 case P2P_ENDPOINT:
924 {
925 if (check->endpoint)
926 {
927 DBG1(DBG_IKE, "connectivity check contains multiple P2P_ENDPOINT notifies");
928 break;
929 }
930
931 endpoint_notify_t *endpoint = endpoint_notify_create_from_payload(notify);
932 if (!endpoint)
933 {
934 DBG1(DBG_IKE, "received invalid P2P_ENDPOINT notify");
935 break;
936 }
937 check->endpoint = endpoint;
938 check->endpoint_raw = chunk_clone(notify->get_notification_data(notify));
939 DBG3(DBG_IKE, "received P2P_ENDPOINT notify");
940 break;
941 }
942 case P2P_SESSIONID:
943 {
944 if (check->session_id.ptr)
945 {
946 DBG1(DBG_IKE, "connectivity check contains multiple P2P_SESSIONID notifies");
947 break;
948 }
949 check->session_id = chunk_clone(notify->get_notification_data(notify));
950 DBG3(DBG_IKE, "received p2p_sessionid %B", &check->session_id);
951 break;
952 }
953 case COOKIE:
954 {
955 if (check->cookie.ptr)
956 {
957 DBG1(DBG_IKE, "connectivity check contains multiple COOKIE notifies");
958 break;
959 }
960 check->cookie = chunk_clone(notify->get_notification_data(notify));
961 DBG3(DBG_IKE, "received cookie %B", &check->cookie);
962 break;
963 }
964 default:
965 break;
966 }
967 }
968 iterator->destroy(iterator);
969
970 if (!check->session_id.ptr || !check->endpoint || !check->cookie.ptr)
971 {
972 DBG1(DBG_IKE, "at least one payload was missing from the connectivity check");
973 return FAILED;
974 }
975
976 return SUCCESS;
977 }
978
979 /**
980 * Builds the signature for a connectivity check
981 */
982 static chunk_t build_signature(private_connect_manager_t *this,
983 check_list_t *checklist, check_t *check, bool outbound)
984 {
985 chunk_t mid_chunk, key_chunk, sig_chunk;
986 chunk_t sig_hash;
987
988 mid_chunk = chunk_from_thing(check->mid);
989
990 key_chunk = (checklist->is_initiator && outbound) || (!checklist->is_initiator && !outbound)
991 ? checklist->initiator.key : checklist->responder.key;
992
993 /* signature = SHA1( MID | P2P_SESSIONID | P2P_ENDPOINT | P2P_SESSIONKEY ) */
994 sig_chunk = chunk_cat("cccc", mid_chunk, check->session_id, check->endpoint_raw, key_chunk);
995 this->hasher->allocate_hash(this->hasher, sig_chunk, &sig_hash);
996 DBG3(DBG_IKE, "sig_chunk %B", &sig_chunk);
997 DBG3(DBG_IKE, "sig_hash %B", &sig_hash);
998
999 chunk_free(&sig_chunk);
1000 return sig_hash;
1001 }
1002
1003 // -----------------------------------------------------------------------------
1004
1005 // forward declarations
1006 static void queue_retransmission(private_connect_manager_t *this, chunk_t session_id, u_int32_t mid);
1007 static void schedule_checks(private_connect_manager_t *this, check_list_t *checklist, u_int32_t time);
1008 static void finish_checks(private_connect_manager_t *this, check_list_t *checklist);
1009
1010 /**
1011 * This function is triggered for each sent check after a specific timeout
1012 */
1013 static job_requeue_t retransmit(retransmit_data_t *data)
1014 {
1015 private_connect_manager_t *this = data->connect_manager;
1016
1017 pthread_mutex_lock(&(this->mutex));
1018
1019 check_list_t *checklist;
1020 if (get_checklist_by_id(this, data->session_id, &checklist) != SUCCESS)
1021 {
1022 DBG1(DBG_IKE, "checklist with id '%B' not found, can't retransmit connectivity check",
1023 &data->session_id);
1024 pthread_mutex_unlock(&(this->mutex));
1025 return JOB_REQUEUE_NONE;
1026 }
1027
1028 endpoint_pair_t *pair;
1029 if (get_pair_by_id(checklist, data->mid, &pair) != SUCCESS)
1030 {
1031 DBG1(DBG_IKE, "pair with id '%d' not found, can't retransmit connectivity check",
1032 data->mid);
1033 goto retransmit_end;
1034 }
1035
1036 if (pair->state != CHECK_IN_PROGRESS)
1037 {
1038 DBG2(DBG_IKE, "pair with id '%d' is in wrong state [%d], don't retransmit the connectivity check",
1039 data->mid, pair->state);
1040 goto retransmit_end;
1041 }
1042
1043 if (++pair->retransmitted >= P2P_MAX_RETRANS)
1044 {
1045 DBG2(DBG_IKE, "pair with id '%d' failed after %d tries",
1046 data->mid, pair->retransmitted);
1047 pair->state = CHECK_FAILED;
1048 goto retransmit_end;
1049 }
1050
1051 charon->sender->send(charon->sender, pair->packet->clone(pair->packet));
1052
1053 queue_retransmission(this, checklist->session_id, pair->id);
1054
1055 retransmit_end:
1056 update_checklist_state(checklist);
1057
1058 switch(checklist->state)
1059 {
1060 case CHECK_SUCCEEDED:
1061 case CHECK_FAILED:
1062 finish_checks(this, checklist);
1063 break;
1064 }
1065
1066 pthread_mutex_unlock(&(this->mutex));
1067
1068 // we reschedule it manually
1069 return JOB_REQUEUE_NONE;
1070 }
1071
1072 /**
1073 * Queues a retransmission job
1074 */
1075 static void queue_retransmission(private_connect_manager_t *this, chunk_t session_id, u_int32_t mid)
1076 {
1077 retransmit_data_t *data = retransmit_data_create(this, chunk_clone(session_id), mid);
1078 job_t *job = (job_t*)callback_job_create((callback_job_cb_t)retransmit, data, (callback_job_cleanup_t)retransmit_data_destroy, NULL);
1079 charon->scheduler->schedule_job(charon->scheduler, (job_t*)job, P2P_RTO_MIN);
1080 }
1081
1082 /**
1083 * Sends a check
1084 */
1085 static void send_check(private_connect_manager_t *this, check_list_t *checklist,
1086 check_t *check, endpoint_pair_t *pair, bool request)
1087 {
1088 message_t *message = message_create();
1089 message->set_message_id(message, check->mid);
1090 message->set_exchange_type(message, INFORMATIONAL);
1091 message->set_request(message, request);
1092 message->set_destination(message, check->dst->clone(check->dst));
1093 message->set_source(message, check->src->clone(check->src));
1094
1095 message->set_ike_sa_id(message, ike_sa_id_create(0, 0, request));
1096
1097 message->add_notify(message, FALSE, P2P_SESSIONID, check->session_id);
1098
1099 notify_payload_t *endpoint = check->endpoint->build_notify(check->endpoint);
1100 check->endpoint_raw = chunk_clone(endpoint->get_notification_data(endpoint));
1101 message->add_payload(message, (payload_t*)endpoint);
1102
1103 check->cookie = build_signature(this, checklist, check, TRUE);
1104 message->add_notify(message, FALSE, COOKIE, check->cookie);
1105
1106 packet_t *packet;
1107 if (message->generate(message, NULL, NULL, &packet) == SUCCESS)
1108 {
1109 charon->sender->send(charon->sender, packet->clone(packet));
1110
1111 if (request)
1112 {
1113 DESTROY_IF(pair->packet);
1114 pair->packet = packet;
1115 queue_retransmission(this, checklist->session_id, pair->id);
1116 }
1117 else
1118 {
1119 packet->destroy(packet);
1120 }
1121 }
1122 }
1123
1124 /**
1125 * Queues a triggered check
1126 */
1127 static void queue_triggered_check(check_list_t *checklist, endpoint_pair_t *pair)
1128 {
1129 pair->state = CHECK_WAITING;
1130 checklist->triggered->insert_last(checklist->triggered, pair);
1131 }
1132
1133 /**
1134 * This function is triggered for each checklist at a specific interval
1135 */
1136 static job_requeue_t sender(sender_data_t *data)
1137 {
1138 private_connect_manager_t *this = data->connect_manager;
1139
1140 pthread_mutex_lock(&(this->mutex));
1141
1142 check_list_t *checklist;
1143 if (get_checklist_by_id(this, data->session_id, &checklist) != SUCCESS)
1144 {
1145 DBG1(DBG_IKE, "checklist with id '%B' not found, can't send connectivity check",
1146 &data->session_id);
1147 pthread_mutex_unlock(&(this->mutex));
1148 return JOB_REQUEUE_NONE;
1149 }
1150
1151 endpoint_pair_t *pair;
1152 if (get_triggered_pair(checklist, &pair) != SUCCESS)
1153 {
1154 DBG1(DBG_IKE, "no triggered check queued, sending an ordinary check");
1155
1156 iterator_t *iterator;
1157 bool found_one = FALSE;
1158
1159 iterator = checklist->pairs->create_iterator(checklist->pairs, TRUE);
1160 while (iterator->iterate(iterator, (void**)&pair))
1161 {
1162 if (pair->state == CHECK_WAITING)
1163 {
1164 found_one = TRUE;
1165 break;
1166 }
1167 }
1168 iterator->destroy(iterator);
1169
1170 if (!found_one)
1171 {
1172 pthread_mutex_unlock(&(this->mutex));
1173 DBG1(DBG_IKE, "no pairs in waiting state, aborting");
1174 return JOB_REQUEUE_NONE;
1175 }
1176 }
1177 else
1178 {
1179 DBG1(DBG_IKE, "triggered check found");
1180 }
1181
1182 check_t *check = check_create();
1183 check->mid = pair->id;
1184 check->src = pair->local->clone(pair->local);
1185 check->dst = pair->remote->clone(pair->remote);
1186 check->session_id = chunk_clone(checklist->session_id);
1187 check->endpoint = endpoint_notify_create();
1188
1189 pair->state = CHECK_IN_PROGRESS;
1190
1191 send_check(this, checklist, check, pair, TRUE);
1192
1193 check_destroy(check);
1194
1195 // schedule this job again
1196 u_int32_t N = this->checklists->get_count(this->checklists);
1197 schedule_checks(this, checklist, P2P_INTERVAL * N);
1198
1199 pthread_mutex_unlock(&(this->mutex));
1200
1201 // we reschedule it manually
1202 return JOB_REQUEUE_NONE;
1203 }
1204
1205 /**
1206 * Schedules checks for a checklist (time in ms)
1207 */
1208 static void schedule_checks(private_connect_manager_t *this, check_list_t *checklist, u_int32_t time)
1209 {
1210 chunk_t session_id = chunk_clone(checklist->session_id);
1211 sender_data_t *data = sender_data_create(this, session_id);
1212 job_t *job = (job_t*)callback_job_create((callback_job_cb_t)sender, data, (callback_job_cleanup_t)sender_data_destroy, NULL);
1213 charon->scheduler->schedule_job(charon->scheduler, job, time);
1214 }
1215
1216 /**
1217 * Initiates waiting mediated connections
1218 */
1219 static job_requeue_t initiate_mediated(initiate_data_t *data)
1220 {
1221 check_list_t *checklist = data->checklist;
1222 initiated_t *initiated = data->initiated;
1223
1224 endpoint_pair_t *pair;
1225 if (get_best_valid_pair(checklist, &pair) == SUCCESS)
1226 {
1227 waiting_sa_t *waiting_sa;
1228 iterator_t *iterator = initiated->mediated->create_iterator(initiated->mediated, TRUE);
1229 while (iterator->iterate(iterator, (void**)&waiting_sa))
1230 {
1231 ike_sa_t *sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, waiting_sa->ike_sa_id);
1232 if (sa->initiate_mediated(sa, pair->local, pair->remote, waiting_sa->childs) != SUCCESS)
1233 {
1234 SIG(IKE_UP_FAILED, "establishing the mediated connection failed");
1235 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, sa);
1236 }
1237 charon->ike_sa_manager->checkin(charon->ike_sa_manager, sa);
1238 }
1239 iterator->destroy(iterator);
1240 }
1241 else
1242 {
1243 /* this should (can?) not happen */
1244 }
1245
1246 return JOB_REQUEUE_NONE;
1247 }
1248
1249 /**
1250 * Finishes checks for a checklist
1251 */
1252 static void finish_checks(private_connect_manager_t *this, check_list_t *checklist)
1253 {
1254 if (checklist->is_initiator)
1255 {
1256 initiated_t *initiated;
1257 if (get_initiated_by_ids(this, checklist->initiator.id,
1258 checklist->responder.id, &initiated) == SUCCESS)
1259 {
1260 remove_checklist(this, checklist);
1261 remove_initiated(this, initiated);
1262
1263 initiate_data_t *data = initiate_data_create(checklist, initiated);
1264 job_t *job = (job_t*)callback_job_create((callback_job_cb_t)initiate_mediated, data, (callback_job_cleanup_t)initiate_data_destroy, NULL);
1265 charon->processor->queue_job(charon->processor, job);
1266 return;
1267 }
1268 else
1269 {
1270 DBG1(DBG_IKE, "there is no mediated connection waiting between '%D' "
1271 "and '%D'", checklist->initiator.id, checklist->responder.id);
1272 }
1273 }
1274
1275 //remove_checklist(this, checklist);
1276 //check_list_destroy(checklist);
1277 // FIXME: we should do this ^^^ after a specific timeout on the responder side
1278 }
1279
1280 /**
1281 * Process the response to one of our requests
1282 */
1283 static void process_response(private_connect_manager_t *this, check_t *check,
1284 check_list_t *checklist)
1285 {
1286 endpoint_pair_t *pair;
1287 if (get_pair_by_id(checklist, check->mid, &pair) == SUCCESS)
1288 {
1289 if (pair->local->equals(pair->local, check->dst) &&
1290 pair->remote->equals(pair->remote, check->src))
1291 {
1292 DBG1(DBG_IKE, "endpoint pair '%d' is valid: '%#H' - '%#H'", pair->id,
1293 pair->local, pair->remote);
1294 pair->state = CHECK_SUCCEEDED;
1295 }
1296
1297 linked_list_t *local_endpoints = checklist->is_initiator ?
1298 checklist->initiator.endpoints : checklist->responder.endpoints;
1299
1300 endpoint_notify_t *local_endpoint;
1301 if (endpoints_contain(local_endpoints,
1302 check->endpoint->get_host(check->endpoint), &local_endpoint) != SUCCESS)
1303 {
1304 local_endpoint = endpoint_notify_create_from_host(PEER_REFLEXIVE,
1305 check->endpoint->get_host(check->endpoint), pair->local);
1306 local_endpoint->set_priority(local_endpoint, check->endpoint->get_priority(check->endpoint));
1307 local_endpoints->insert_last(local_endpoints, local_endpoint);
1308 }
1309
1310 update_checklist_state(checklist);
1311
1312 switch(checklist->state)
1313 {
1314 case CHECK_SUCCEEDED:
1315 case CHECK_FAILED:
1316 finish_checks(this, checklist);
1317 break;
1318 }
1319 }
1320 else
1321 {
1322 DBG1(DBG_IKE, "pair with id '%d' not found", check->mid);
1323 }
1324 }
1325
1326 static void process_request(private_connect_manager_t *this, check_t *check,
1327 check_list_t *checklist)
1328 {
1329 linked_list_t *remote_endpoints = checklist->is_initiator ?
1330 checklist->responder.endpoints : checklist->initiator.endpoints;
1331
1332 endpoint_notify_t *peer_reflexive, *remote_endpoint;
1333 peer_reflexive = endpoint_notify_create_from_host(PEER_REFLEXIVE, check->src, NULL);
1334 peer_reflexive->set_priority(peer_reflexive, check->endpoint->get_priority(check->endpoint));
1335
1336 if (endpoints_contain(remote_endpoints, check->src, &remote_endpoint) != SUCCESS)
1337 {
1338 remote_endpoint = peer_reflexive->clone(peer_reflexive);
1339 remote_endpoints->insert_last(remote_endpoints, remote_endpoint);
1340 }
1341
1342 endpoint_pair_t *pair;
1343 if (get_pair_by_hosts(checklist->pairs, check->dst, check->src, &pair) == SUCCESS)
1344 {
1345 switch(pair->state)
1346 {
1347 case CHECK_IN_PROGRESS:
1348 pair->retransmitted = P2P_MAX_RETRANS; // prevent retransmissions
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 // do nothing
1358 break;
1359 }
1360 }
1361 else
1362 {
1363 endpoint_notify_t *local_endpoint = endpoint_notify_create_from_host(HOST, check->dst, NULL);
1364
1365 endpoint_notify_t *initiator = checklist->is_initiator ? local_endpoint : remote_endpoint;
1366 endpoint_notify_t *responder = checklist->is_initiator ? remote_endpoint : local_endpoint;
1367
1368 pair = endpoint_pair_create(initiator, responder, checklist->is_initiator);
1369 pair->id = checklist->pairs->get_count(checklist->pairs) + 1;
1370
1371 insert_pair_by_priority(checklist->pairs, pair);
1372
1373 queue_triggered_check(checklist, pair);
1374
1375 local_endpoint->destroy(local_endpoint);
1376 }
1377
1378
1379 check_t *response = check_create();
1380
1381 response->mid = check->mid;
1382 response->src = check->dst->clone(check->dst);
1383 response->dst = check->src->clone(check->src);
1384 response->session_id = chunk_clone(check->session_id);
1385 response->endpoint = peer_reflexive;
1386
1387 send_check(this, checklist, response, pair, FALSE);
1388
1389 check_destroy(response);
1390 }
1391
1392 /**
1393 * Implementation of connect_manager_t.process_check.
1394 */
1395 static void process_check(private_connect_manager_t *this, message_t *message)
1396 {
1397 if (message->parse_body(message, NULL, NULL) != SUCCESS)
1398 {
1399 DBG1(DBG_IKE, "%N %s with message ID %d processing failed",
1400 exchange_type_names, message->get_exchange_type(message),
1401 message->get_request(message) ? "request" : "response",
1402 message->get_message_id(message));
1403 return;
1404 }
1405
1406 check_t *check = check_create();
1407 check->mid = message->get_message_id(message);
1408 check->src = message->get_source(message);
1409 check->dst = message->get_destination(message);
1410
1411 if (process_payloads(message, check) != SUCCESS)
1412 {
1413 DBG1(DBG_IKE, "invalid connectivity check %s received",
1414 message->get_request(message) ? "request" : "response");
1415 check_destroy(check);
1416 return;
1417 }
1418
1419 pthread_mutex_lock(&(this->mutex));
1420
1421 check_list_t *checklist;
1422 if (get_checklist_by_id(this, check->session_id, &checklist) != SUCCESS)
1423 {
1424 DBG1(DBG_IKE, "checklist with id '%B' not found",
1425 &check->session_id);
1426 check_destroy(check);
1427 pthread_mutex_unlock(&(this->mutex));
1428 return;
1429 }
1430
1431 chunk_t sig = build_signature(this, checklist, check, FALSE);
1432 if (!chunk_equals(sig, check->cookie))
1433 {
1434 DBG1(DBG_IKE, "connectivity check verification failed");
1435 check_destroy(check);
1436 chunk_free(&sig);
1437 pthread_mutex_unlock(&(this->mutex));
1438 return;
1439 }
1440 chunk_free(&sig);
1441
1442 if (message->get_request(message))
1443 {
1444 process_request(this, check, checklist);
1445 }
1446 else
1447 {
1448 process_response(this, check, checklist);
1449 }
1450
1451 pthread_mutex_unlock(&(this->mutex));
1452
1453 check_destroy(check);
1454 }
1455
1456 // -----------------------------------------------------------------------------
1457
1458 /**
1459 * Implementation of connect_manager_t.check_and_register.
1460 */
1461 static bool check_and_register(private_connect_manager_t *this,
1462 identification_t *id, identification_t *peer_id,
1463 ike_sa_id_t *mediated_sa, child_cfg_t *child)
1464 {
1465 initiated_t *initiated;
1466 bool already_there = TRUE;
1467
1468 pthread_mutex_lock(&(this->mutex));
1469
1470 if (get_initiated_by_ids(this, id, peer_id, &initiated) != SUCCESS)
1471 {
1472 DBG2(DBG_IKE, "registered waiting mediated connection with '%D'", peer_id);
1473 initiated = initiated_create(id, peer_id);
1474 this->initiated->insert_last(this->initiated, initiated);
1475 already_there = FALSE;
1476 }
1477
1478 waiting_sa_t *waiting_sa;
1479 if (get_waiting_sa(initiated, mediated_sa, &waiting_sa) != SUCCESS)
1480 {
1481 waiting_sa = waiting_sa_create(mediated_sa);
1482 initiated->mediated->insert_last(initiated->mediated, waiting_sa);
1483 }
1484
1485 child->get_ref(child);
1486 waiting_sa->childs->insert_last(waiting_sa->childs, child);
1487
1488 pthread_mutex_unlock(&(this->mutex));
1489
1490 return already_there;
1491 }
1492
1493 /**
1494 * Implementation of connect_manager_t.check_and_initiate.
1495 */
1496 static void check_and_initiate(private_connect_manager_t *this, ike_sa_id_t *mediation_sa,
1497 identification_t *id, identification_t *peer_id)
1498 {
1499 initiated_t *initiated;
1500
1501 pthread_mutex_lock(&(this->mutex));
1502
1503 if (get_initiated_by_ids(this, id, peer_id, &initiated) != SUCCESS)
1504 {
1505 DBG2(DBG_IKE, "no waiting mediated connections with '%D'", peer_id);
1506 pthread_mutex_unlock(&(this->mutex));
1507 return;
1508 }
1509
1510 waiting_sa_t *waiting_sa;
1511 iterator_t *iterator = initiated->mediated->create_iterator(initiated->mediated, TRUE);
1512 while (iterator->iterate(iterator, (void**)&waiting_sa))
1513 {
1514 job_t *job = (job_t*)reinitiate_mediation_job_create(mediation_sa,
1515 waiting_sa->ike_sa_id);
1516 charon->processor->queue_job(charon->processor, job);
1517 }
1518
1519 pthread_mutex_unlock(&(this->mutex));
1520 }
1521
1522 /**
1523 * Implementation of connect_manager_t.set_initiator_data.
1524 */
1525 static status_t set_initiator_data(private_connect_manager_t *this,
1526 identification_t *initiator, identification_t *responder,
1527 chunk_t session_id, chunk_t key, linked_list_t *endpoints, bool is_initiator)
1528 {
1529 check_list_t *checklist;
1530
1531 pthread_mutex_lock(&(this->mutex));
1532
1533 if (get_checklist_by_id(this, session_id, NULL) == SUCCESS)
1534 {
1535 DBG1(DBG_IKE, "checklist with id '%B' already exists, aborting",
1536 &session_id);
1537 pthread_mutex_unlock(&(this->mutex));
1538 return FAILED;
1539 }
1540
1541 checklist = check_list_create(initiator, responder, session_id, key, endpoints, is_initiator);
1542 this->checklists->insert_last(this->checklists, checklist);
1543
1544 pthread_mutex_unlock(&(this->mutex));
1545
1546 return SUCCESS;
1547 }
1548
1549 /**
1550 * Implementation of connect_manager_t.set_responder_data.
1551 */
1552 static status_t set_responder_data(private_connect_manager_t *this,
1553 chunk_t session_id, chunk_t key, linked_list_t *endpoints)
1554 {
1555 check_list_t *checklist;
1556
1557 pthread_mutex_lock(&(this->mutex));
1558
1559 if (get_checklist_by_id(this, session_id, &checklist) != SUCCESS)
1560 {
1561 DBG1(DBG_IKE, "checklist with id '%B' not found",
1562 &session_id);
1563 pthread_mutex_unlock(&(this->mutex));
1564 return NOT_FOUND;
1565 }
1566
1567 checklist->responder.key = chunk_clone(key);
1568 checklist->responder.endpoints = endpoints->clone_offset(endpoints, offsetof(endpoint_notify_t, clone));
1569 checklist->state = CHECK_WAITING;
1570
1571 build_pairs(checklist);
1572
1573 schedule_checks(this, checklist, 0); // send the first check immediately
1574
1575 pthread_mutex_unlock(&(this->mutex));
1576
1577 return SUCCESS;
1578 }
1579
1580 /**
1581 * Implementation of connect_manager_t.destroy.
1582 */
1583 static void destroy(private_connect_manager_t *this)
1584 {
1585 pthread_mutex_lock(&(this->mutex));
1586
1587 this->hasher->destroy(this->hasher);
1588 this->checklists->destroy_function(this->checklists, (void*)check_list_destroy);
1589 this->initiated->destroy_function(this->initiated, (void*)initiated_destroy);
1590
1591 pthread_mutex_unlock(&(this->mutex));
1592 pthread_mutex_destroy(&(this->mutex));
1593 free(this);
1594 }
1595
1596 /*
1597 * Described in header.
1598 */
1599 connect_manager_t *connect_manager_create()
1600 {
1601 private_connect_manager_t *this = malloc_thing(private_connect_manager_t);
1602
1603 this->public.destroy = (void(*)(connect_manager_t*))destroy;
1604 this->public.check_and_register = (bool(*)(connect_manager_t*,identification_t*,identification_t*,ike_sa_id_t*,child_cfg_t*))check_and_register;
1605 this->public.check_and_initiate = (void(*)(connect_manager_t*,ike_sa_id_t*,identification_t*,identification_t*))check_and_initiate;
1606 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;
1607 this->public.set_responder_data = (status_t(*)(connect_manager_t*,chunk_t,chunk_t,linked_list_t*))set_responder_data;
1608 this->public.process_check = (void(*)(connect_manager_t*,message_t*))process_check;
1609
1610 this->hasher = hasher_create(HASH_SHA1);
1611 this->checklists = linked_list_create();
1612 this->initiated = linked_list_create();
1613
1614 pthread_mutex_init(&(this->mutex), NULL);
1615
1616 return (connect_manager_t*)this;
1617 }