Use the vararg list constructor in quick mode task
[strongswan.git] / src / libcharon / sa / trap_manager.c
index c7a8a6e..b3d9e15 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2011 Tobias Brunner
  * Copyright (C) 2009 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
@@ -74,8 +75,10 @@ typedef struct {
        peer_cfg_t *peer_cfg;
        /** ref to instanciated CHILD_SA */
        child_sa_t *child_sa;
+       /** TRUE if an acquire is pending */
+       bool pending;
        /** pending IKE_SA connecting upon acquire */
-       ike_sa_t *pending;
+       ike_sa_t *ike_sa;
 } entry_t;
 
 /**
@@ -124,14 +127,14 @@ METHOD(trap_manager_t, install, u_int32_t,
 
        /* try to resolve addresses */
        ike_cfg = peer->get_ike_cfg(peer);
-       other = host_create_from_dns(ike_cfg->get_other_addr(ike_cfg),
+       other = host_create_from_dns(ike_cfg->get_other_addr(ike_cfg, NULL),
                                                                 0, ike_cfg->get_other_port(ike_cfg));
        if (!other || other->is_anyaddr(other))
        {
                DBG1(DBG_CFG, "installing trap failed, remote address unknown");
                return 0;
        }
-       me = host_create_from_dns(ike_cfg->get_my_addr(ike_cfg),
+       me = host_create_from_dns(ike_cfg->get_my_addr(ike_cfg, NULL),
                                        other->get_family(other), ike_cfg->get_my_port(ike_cfg));
        if (!me || me->is_anyaddr(me))
        {
@@ -170,10 +173,10 @@ METHOD(trap_manager_t, install, u_int32_t,
        }
 
        reqid = child_sa->get_reqid(child_sa);
-       entry = malloc_thing(entry_t);
-       entry->child_sa = child_sa;
-       entry->peer_cfg = peer->get_ref(peer);
-       entry->pending = NULL;
+       INIT(entry,
+               .child_sa = child_sa,
+               .peer_cfg = peer->get_ref(peer),
+       );
 
        this->lock->write_lock(this->lock);
        this->traps->insert_last(this->traps, entry);
@@ -263,26 +266,45 @@ METHOD(trap_manager_t, acquire, void,
        if (!found)
        {
                DBG1(DBG_CFG, "trap not found, unable to acquire reqid %d",reqid);
+               this->lock->unlock(this->lock);
+               return;
        }
-       else if (found->pending)
+       if (!cas_bool(&found->pending, FALSE, TRUE))
        {
                DBG1(DBG_CFG, "ignoring acquire, connection attempt pending");
+               this->lock->unlock(this->lock);
+               return;
        }
-       else
+       peer = found->peer_cfg->get_ref(found->peer_cfg);
+       child = found->child_sa->get_config(found->child_sa);
+       child = child->get_ref(child);
+       reqid = found->child_sa->get_reqid(found->child_sa);
+       /* don't hold the lock while checking out the IKE_SA */
+       this->lock->unlock(this->lock);
+
+       ike_sa = charon->ike_sa_manager->checkout_by_config(
+                                                                                       charon->ike_sa_manager, peer);
+       if (ike_sa)
        {
-               child = found->child_sa->get_config(found->child_sa);
-               peer = found->peer_cfg;
-               ike_sa = charon->ike_sa_manager->checkout_by_config(
-                                                                                               charon->ike_sa_manager, peer);
                if (ike_sa->get_peer_cfg(ike_sa) == NULL)
                {
                        ike_sa->set_peer_cfg(ike_sa, peer);
                }
-               child->get_ref(child);
-               reqid = found->child_sa->get_reqid(found->child_sa);
+               if (ike_sa->get_version(ike_sa) == IKEV1)
+               {       /* in IKEv1, don't prepend the acquiring packet TS, as we only
+                        * have a single TS that we can establish in a Quick Mode. */
+                       src = dst = NULL;
+               }
                if (ike_sa->initiate(ike_sa, child, reqid, src, dst) != DESTROY_ME)
                {
-                       found->pending = ike_sa;
+                       /* make sure the entry is still there */
+                       this->lock->read_lock(this->lock);
+                       if (this->traps->find_first(this->traps, NULL,
+                                                                               (void**)&found) == SUCCESS)
+                       {
+                               found->ike_sa = ike_sa;
+                       }
+                       this->lock->unlock(this->lock);
                        charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
                }
                else
@@ -291,7 +313,7 @@ METHOD(trap_manager_t, acquire, void,
                                                                                                charon->ike_sa_manager, ike_sa);
                }
        }
-       this->lock->unlock(this->lock);
+       peer->destroy(peer);
 }
 
 /**
@@ -307,7 +329,7 @@ static void complete(private_trap_manager_t *this, ike_sa_t *ike_sa,
        enumerator = this->traps->create_enumerator(this->traps);
        while (enumerator->enumerate(enumerator, &entry))
        {
-               if (entry->pending != ike_sa)
+               if (entry->ike_sa != ike_sa)
                {
                        continue;
                }
@@ -316,7 +338,8 @@ static void complete(private_trap_manager_t *this, ike_sa_t *ike_sa,
                {
                        continue;
                }
-               entry->pending = NULL;
+               entry->ike_sa = NULL;
+               entry->pending = FALSE;
        }
        enumerator->destroy(enumerator);
        this->lock->unlock(this->lock);