From: Martin Willi Date: Thu, 2 May 2013 15:45:58 +0000 (+0200) Subject: xpc: support termination of IKE_SAs using XPC RPC on connection channel X-Git-Tag: 5.1.0rc1~25^2~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d60c8d2c740d6cb02776974fa3cd1c0a3f8613cf;p=thirdparty%2Fstrongswan.git xpc: support termination of IKE_SAs using XPC RPC on connection channel --- diff --git a/src/frontends/osx/charon-xpc/xpc_channels.c b/src/frontends/osx/charon-xpc/xpc_channels.c index 0d82d7032e..ce2c83bfbb 100644 --- a/src/frontends/osx/charon-xpc/xpc_channels.c +++ b/src/frontends/osx/charon-xpc/xpc_channels.c @@ -76,34 +76,128 @@ static void destroy_entry(entry_t *entry) } /** - * Remove an entry for a given XPC connection + * Find an IKE_SA unique identifier by a given XPC channel */ -static void remove_conn(private_xpc_channels_t *this, xpc_connection_t conn) +static u_int32_t find_ike_sa_by_conn(private_xpc_channels_t *this, + xpc_connection_t conn) { enumerator_t *enumerator; entry_t *entry; + u_int32_t ike_sa = 0; - this->lock->write_lock(this->lock); + this->lock->read_lock(this->lock); enumerator = this->channels->create_enumerator(this->channels); while (enumerator->enumerate(enumerator, NULL, &entry)) { if (entry->conn == conn) { - this->channels->remove(this->channels, enumerator); - destroy_entry(entry); + ike_sa = entry->sa; break; } } enumerator->destroy(enumerator); this->lock->unlock(this->lock); + + return ike_sa; +} + +/** + * Remove an entry for a given XPC connection + */ +static void remove_conn(private_xpc_channels_t *this, xpc_connection_t conn) +{ + uintptr_t ike_sa; + entry_t *entry; + + ike_sa = find_ike_sa_by_conn(this, conn); + if (ike_sa) + { + this->lock->write_lock(this->lock); + entry = this->channels->remove(this->channels, (void*)ike_sa); + this->lock->unlock(this->lock); + + if (entry) + { + destroy_entry(entry); + } + } } +/** + * Trigger termination of a connection + */ +static void stop_connection(private_xpc_channels_t *this, u_int32_t ike_sa, + xpc_object_t request, xpc_object_t reply) +{ + status_t status; + + status = charon->controller->terminate_ike(charon->controller, ike_sa, + NULL, NULL, 0); + xpc_dictionary_set_bool(reply, "success", status != NOT_FOUND); +} + +/** + * XPC RPC command dispatch table + */ +static struct { + char *name; + void (*handler)(private_xpc_channels_t *this, u_int32_t ike_sa, + xpc_object_t request, xpc_object_t reply); +} commands[] = { + { "stop_connection", stop_connection }, +}; + /** * Handle a request message from App */ -static void handle(private_xpc_channels_t *this, xpc_object_t request) +static void handle(private_xpc_channels_t *this, xpc_connection_t conn, + xpc_object_t request) { - /* TODO: */ + xpc_object_t reply; + const char *type, *rpc; + bool found = FALSE; + u_int32_t ike_sa; + int i; + + type = xpc_dictionary_get_string(request, "type"); + if (type) + { + if (streq(type, "rpc")) + { + reply = xpc_dictionary_create_reply(request); + rpc = xpc_dictionary_get_string(request, "rpc"); + ike_sa = find_ike_sa_by_conn(this, conn); + if (reply && rpc && ike_sa) + { + for (i = 0; i < countof(commands); i++) + { + if (streq(commands[i].name, rpc)) + { + found = TRUE; + commands[i].handler(this, ike_sa, request, reply); + break; + } + } + } + if (!found) + { + DBG1(DBG_CFG, "received invalid XPC rpc command: %s", rpc); + } + if (reply) + { + xpc_connection_send_message(conn, reply); + xpc_release(reply); + } + } + else + { + DBG1(DBG_CFG, "received unknown XPC message type: %s", type); + } + } + else + { + DBG1(DBG_CFG, "received XPC message without a type"); + } } METHOD(xpc_channels_t, add, void, @@ -126,7 +220,7 @@ METHOD(xpc_channels_t, add, void, } else if (xpc_get_type(event) == XPC_TYPE_DICTIONARY) { - handle(this, event); + handle(this, conn, event); } });