mirror of
https://github.com/darlinghq/darling-libxpc.git
synced 2024-11-23 11:49:42 +00:00
Initial import.
This code is based on original libxpc from NextBSD. Improvements: * MessagePack serialization instead of heavily-modified libnv * Support for multiple transports (UNIX domain sockets and Mach IPC)
This commit is contained in:
parent
9072def42d
commit
404e5c1b70
66
CMakeLists.txt
Normal file
66
CMakeLists.txt
Normal file
@ -0,0 +1,66 @@
|
||||
#
|
||||
# Copyright 2015 iXsystems, Inc.
|
||||
# All rights reserved
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted providing that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
# OR SERVICES LOSS OF USE, DATA, OR PROFITS OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
project(libxpc)
|
||||
|
||||
set(BASE_SOURCES
|
||||
mpack.c
|
||||
xpc_array.c
|
||||
xpc_connection.c
|
||||
xpc_dictionary.c
|
||||
xpc_misc.c
|
||||
xpc_type.c
|
||||
)
|
||||
|
||||
set(HEADERS
|
||||
activity.h
|
||||
base.h
|
||||
connection.h
|
||||
debug.h
|
||||
endpoint.h
|
||||
launchd.h
|
||||
xpc.h
|
||||
)
|
||||
|
||||
set(UNIX_TRANSPORT_SOURCES
|
||||
transports/unix.c
|
||||
)
|
||||
|
||||
set(MACH_TRANSPORT_SOURCES
|
||||
transports/mach.c
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
${BASE_SOURCES}
|
||||
${UNIX_TRANSPORT_SOURCES}
|
||||
)
|
||||
|
||||
include_directories(/usr/local/include)
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fblocks")
|
||||
add_library(libxpc SHARED ${SOURCES})
|
||||
add_subdirectory(examples)
|
29
examples/CMakeLists.txt
Normal file
29
examples/CMakeLists.txt
Normal file
@ -0,0 +1,29 @@
|
||||
#
|
||||
# Copyright 2015 iXsystems, Inc.
|
||||
# All rights reserved
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted providing that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
# OR SERVICES LOSS OF USE, DATA, OR PROFITS OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
add_subdirectory(echo-client)
|
||||
add_subdirectory(echo-server)
|
||||
add_subdirectory(credentials)
|
30
examples/credentials/CMakeLists.txt
Normal file
30
examples/credentials/CMakeLists.txt
Normal file
@ -0,0 +1,30 @@
|
||||
#
|
||||
# Copyright 2015 iXsystems, Inc.
|
||||
# All rights reserved
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted providing that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
# OR SERVICES LOSS OF USE, DATA, OR PROFITS OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
include_directories(../..)
|
||||
link_directories(/usr/local/lib ../..)
|
||||
add_executable(xpc-credentials-server xpc-credentials-server.c)
|
||||
target_link_libraries(xpc-credentials-server BlocksRuntime dispatch sbuf xpc)
|
63
examples/credentials/xpc-credentials-server.c
Normal file
63
examples/credentials/xpc-credentials-server.c
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2014-2015 iXsystems, Inc.
|
||||
* All rights reserved
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted providing that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <dispatch/dispatch.h>
|
||||
#include <xpc/xpc.h>
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
xpc_connection_t conn;
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Usage: %s <mach service name>\n", argv[0]);
|
||||
return (1);
|
||||
}
|
||||
|
||||
conn = xpc_connection_create_mach_service(argv[1], NULL,
|
||||
XPC_CONNECTION_MACH_SERVICE_LISTENER);
|
||||
|
||||
xpc_connection_set_event_handler(conn, ^(xpc_object_t peer) {
|
||||
xpc_connection_set_event_handler(peer, ^(xpc_object_t event) {
|
||||
printf("Message received: %p\n", event);
|
||||
printf("Client UID: %d\n", xpc_connection_get_euid(peer));
|
||||
printf("Client GID: %d\n", xpc_connection_get_guid(peer));
|
||||
printf("Client PID: %d\n", xpc_connection_get_pid(peer));
|
||||
|
||||
xpc_object_t resp = xpc_dictionary_create(NULL, NULL, 0);
|
||||
xpc_dictionary_set_string(resp, "foo", "bar");
|
||||
xpc_connection_send_message(peer, resp);
|
||||
});
|
||||
|
||||
xpc_connection_resume(peer);
|
||||
});
|
||||
|
||||
xpc_connection_resume(conn);
|
||||
dispatch_main();
|
||||
}
|
30
examples/echo-client/CMakeLists.txt
Normal file
30
examples/echo-client/CMakeLists.txt
Normal file
@ -0,0 +1,30 @@
|
||||
#
|
||||
# Copyright 2015 iXsystems, Inc.
|
||||
# All rights reserved
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted providing that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
# OR SERVICES LOSS OF USE, DATA, OR PROFITS OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
include_directories(../..)
|
||||
link_directories(/usr/local/lib ../..)
|
||||
add_executable(xpc-echo-client xpc-echo-client.c)
|
||||
target_link_libraries(xpc-echo-client BlocksRuntime dispatch sbuf xpc)
|
84
examples/echo-client/xpc-echo-client.c
Normal file
84
examples/echo-client/xpc-echo-client.c
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2014-2015 iXsystems, Inc.
|
||||
* All rights reserved
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted providing that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <xpc/xpc.h>
|
||||
|
||||
static void
|
||||
connection_handler(xpc_connection_t peer)
|
||||
{
|
||||
xpc_connection_set_event_handler(peer, ^(xpc_object_t event) {
|
||||
printf("Message received: %p\n", event);
|
||||
});
|
||||
|
||||
xpc_connection_resume(peer);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
xpc_connection_t conn;
|
||||
xpc_object_t msg;
|
||||
|
||||
msg = xpc_dictionary_create(NULL, NULL, 0);
|
||||
xpc_dictionary_set_string(msg, "Hello", "world");
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Usage: %s <mach service name>\n", argv[0]);
|
||||
return (1);
|
||||
}
|
||||
|
||||
conn = xpc_connection_create_mach_service(argv[1], NULL, 0);
|
||||
if (conn == NULL) {
|
||||
perror("xpc_connection_create_mach_service");
|
||||
return (1);
|
||||
}
|
||||
|
||||
xpc_connection_set_event_handler(conn, ^(xpc_object_t obj) {
|
||||
printf("Received message in generic event handler: %p\n", obj);
|
||||
printf("%s\n", xpc_copy_description(obj));
|
||||
});
|
||||
|
||||
xpc_connection_resume(conn);
|
||||
xpc_connection_send_message_with_reply(conn, msg, NULL, ^(xpc_object_t resp) {
|
||||
printf("Received first message: %p\n", resp);
|
||||
printf("%s\n", xpc_copy_description(resp));
|
||||
});
|
||||
|
||||
xpc_connection_send_message_with_reply(conn, msg, NULL, ^(xpc_object_t resp) {
|
||||
printf("Received second message: %p\n", resp);
|
||||
printf("%s\n", xpc_copy_description(resp));
|
||||
});
|
||||
|
||||
xpc_connection_send_message_with_reply(conn, msg, NULL, ^(xpc_object_t resp) {
|
||||
printf("Received third message: %p\n", resp);
|
||||
printf("%s\n", xpc_copy_description(resp));
|
||||
});
|
||||
|
||||
dispatch_main();
|
||||
}
|
30
examples/echo-server/CMakeLists.txt
Normal file
30
examples/echo-server/CMakeLists.txt
Normal file
@ -0,0 +1,30 @@
|
||||
#
|
||||
# Copyright 2015 iXsystems, Inc.
|
||||
# All rights reserved
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted providing that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
# OR SERVICES LOSS OF USE, DATA, OR PROFITS OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
include_directories(../..)
|
||||
link_directories(/usr/local/lib ../..)
|
||||
add_executable(xpc-echo-server xpc-echo-server.c)
|
||||
target_link_libraries(xpc-echo-server BlocksRuntime dispatch sbuf xpc)
|
61
examples/echo-server/xpc-echo-server.c
Normal file
61
examples/echo-server/xpc-echo-server.c
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2014-2015 iXsystems, Inc.
|
||||
* All rights reserved
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted providing that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <dispatch/dispatch.h>
|
||||
#include <xpc/xpc.h>
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
xpc_connection_t conn;
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Usage: %s <mach service name>\n", argv[0]);
|
||||
return (1);
|
||||
}
|
||||
|
||||
conn = xpc_connection_create_mach_service(argv[1], NULL,
|
||||
XPC_CONNECTION_MACH_SERVICE_LISTENER);
|
||||
|
||||
xpc_connection_set_event_handler(conn, ^(xpc_object_t peer) {
|
||||
xpc_connection_set_event_handler(peer, ^(xpc_object_t event) {
|
||||
printf("Message received: %p\n", event);
|
||||
printf("%s\n", xpc_copy_description(event));
|
||||
|
||||
xpc_object_t resp = xpc_dictionary_create(NULL, NULL, 0);
|
||||
xpc_dictionary_set_string(resp, "foo", "bar");
|
||||
xpc_connection_send_message(peer, resp);
|
||||
});
|
||||
|
||||
xpc_connection_resume(peer);
|
||||
});
|
||||
|
||||
xpc_connection_resume(conn);
|
||||
dispatch_main();
|
||||
}
|
13
examples/json-client/Makefile
Normal file
13
examples/json-client/Makefile
Normal file
@ -0,0 +1,13 @@
|
||||
.include <src.opts.mk>
|
||||
PROG= xpc-json-client
|
||||
SRCS= xpc-json-client.c
|
||||
BINDIR?= /usr/bin
|
||||
|
||||
NO_WERROR= yes
|
||||
MK_MAN=no
|
||||
CFLAGS+= -g -D__APPLE__ -fblocks
|
||||
CFLAGS+= -I${.CURDIR}/../../../include/apple -I${.CURDIR}/../../../include
|
||||
CFLAGS+= -I${.CURDIR}/../../../sys
|
||||
LDADD+= -lmach -lBlocksRuntime -ldispatch -losxsupport -llaunch -lbsm -lnv -lsbuf -lxpc -pthread -ljansson
|
||||
|
||||
.include <bsd.prog.mk>
|
162
examples/json-client/xpc-json-client.c
Normal file
162
examples/json-client/xpc-json-client.c
Normal file
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright 2014-2015 iXsystems, Inc.
|
||||
* All rights reserved
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted providing that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <jansson.h>
|
||||
#include <xpc/xpc.h>
|
||||
|
||||
static xpc_object_t
|
||||
to_xpc(json_t *json)
|
||||
{
|
||||
size_t idx;
|
||||
xpc_object_t arr, dict;
|
||||
const char *key;
|
||||
json_t *val;
|
||||
|
||||
switch (json_typeof(json)) {
|
||||
case JSON_STRING:
|
||||
return xpc_string_create(json_string_value(json));
|
||||
|
||||
case JSON_INTEGER:
|
||||
return xpc_int64_create(json_integer_value(json));
|
||||
|
||||
case JSON_TRUE:
|
||||
return xpc_bool_create(true);
|
||||
|
||||
case JSON_FALSE:
|
||||
return xpc_bool_create(false);
|
||||
|
||||
case JSON_ARRAY:
|
||||
arr = xpc_array_create(NULL, 0);
|
||||
json_array_foreach(json, idx, val) {
|
||||
xpc_array_append_value(arr, to_xpc(val));
|
||||
}
|
||||
|
||||
return arr;
|
||||
|
||||
case JSON_OBJECT:
|
||||
dict = xpc_dictionary_create(NULL, NULL, 0);
|
||||
json_object_foreach(json, key, val) {
|
||||
xpc_dictionary_set_value(dict, key, to_xpc(val));
|
||||
}
|
||||
|
||||
return dict;
|
||||
|
||||
default:
|
||||
return xpc_null_create();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static json_t *
|
||||
to_json(xpc_object_t xo)
|
||||
{
|
||||
char *txt;
|
||||
json_t *arr, *obj;
|
||||
xpc_type_t type;
|
||||
size_t i;
|
||||
|
||||
type = xpc_get_type(xo);
|
||||
|
||||
printf("to_json: type=%p\n", type);
|
||||
|
||||
if (type == XPC_TYPE_STRING)
|
||||
return json_string(xpc_string_get_string_ptr(xo));
|
||||
|
||||
if (type == XPC_TYPE_INT64)
|
||||
return json_integer(xpc_int64_get_value(xo));
|
||||
|
||||
if (type == XPC_TYPE_UINT64)
|
||||
return json_integer(xpc_uint64_get_value(xo));
|
||||
|
||||
if (type == XPC_TYPE_BOOL)
|
||||
return json_boolean(xpc_bool_get_value(xo));
|
||||
|
||||
if (type == XPC_TYPE_ARRAY) {
|
||||
arr = json_array();
|
||||
xpc_array_apply(xo, ^(size_t index, xpc_object_t value) {
|
||||
json_array_append_new(arr, to_json(value));
|
||||
return ((bool)true);
|
||||
});
|
||||
|
||||
return (arr);
|
||||
}
|
||||
|
||||
if (type == XPC_TYPE_DICTIONARY) {
|
||||
obj = json_object();
|
||||
xpc_dictionary_apply(xo, ^(const char *key, xpc_object_t value) {
|
||||
json_object_set_new(obj, key, to_json(value));
|
||||
return ((bool)true);
|
||||
});
|
||||
|
||||
return (obj);
|
||||
}
|
||||
|
||||
return (json_null());
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
xpc_connection_t conn;
|
||||
xpc_object_t msg;
|
||||
json_t *json;
|
||||
json_error_t error;
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Usage: %s <mach service name>\n", argv[0]);
|
||||
return (1);
|
||||
}
|
||||
|
||||
conn = xpc_connection_create_mach_service(argv[1], NULL, 0);
|
||||
if (conn == NULL) {
|
||||
perror("xpc_connection_create_mach_service");
|
||||
return (1);
|
||||
}
|
||||
|
||||
xpc_connection_set_event_handler(conn, ^(xpc_object_t obj) {
|
||||
printf("Received message in generic event handler: %p\n", obj);
|
||||
printf("%s\n", xpc_copy_description(obj));
|
||||
});
|
||||
|
||||
xpc_connection_resume(conn);
|
||||
|
||||
json = json_loadf(stdin, JSON_DECODE_ANY, &error);
|
||||
msg = to_xpc(json);
|
||||
|
||||
xpc_connection_send_message_with_reply(conn, msg, NULL, ^(xpc_object_t resp) {
|
||||
printf("Received message: %p\n", resp);
|
||||
json_t *reply;
|
||||
reply = to_json(resp);
|
||||
json_dumpf(reply, stdout, JSON_INDENT(4));
|
||||
printf("\n");
|
||||
});
|
||||
|
||||
dispatch_main();
|
||||
return (0);
|
||||
}
|
201
mpack-config.h
Normal file
201
mpack-config.h
Normal file
@ -0,0 +1,201 @@
|
||||
|
||||
/**
|
||||
* This is a sample MPack configuration file. Copy it to mpack-config.h somewhere
|
||||
* in your project's include tree and, optionally, edit it to suit your setup.
|
||||
* In most cases you can leave this file with the default config.
|
||||
*/
|
||||
|
||||
#ifndef MPACK_CONFIG_H
|
||||
#define MPACK_CONFIG_H 1
|
||||
|
||||
|
||||
/*
|
||||
* Features
|
||||
*/
|
||||
|
||||
/** Enables compilation of the base Tag Reader. */
|
||||
#define MPACK_READER 1
|
||||
|
||||
/** Enables compilation of the static Expect API. */
|
||||
#define MPACK_EXPECT 1
|
||||
|
||||
/** Enables compilation of the dynamic Node API. */
|
||||
#define MPACK_NODE 1
|
||||
|
||||
/** Enables compilation of the Writer. */
|
||||
#define MPACK_WRITER 1
|
||||
|
||||
|
||||
/*
|
||||
* Dependencies
|
||||
*/
|
||||
|
||||
/**
|
||||
* Enables the use of C stdlib. This allows the library to use malloc
|
||||
* for debugging and in allocation helpers.
|
||||
*/
|
||||
#define MPACK_STDLIB 1
|
||||
|
||||
/**
|
||||
* Enables the use of C stdio. This adds helpers for easily
|
||||
* reading/writing C files and makes debugging easier.
|
||||
*/
|
||||
#define MPACK_STDIO 1
|
||||
|
||||
/**
|
||||
* \def MPACK_MALLOC
|
||||
*
|
||||
* Defines the memory allocation function used by mpack. This is used by
|
||||
* helpers for automatically allocating data the correct size, and for
|
||||
* debugging functions. If this macro is undefined, the allocation helpers
|
||||
* will not be compiled.
|
||||
*
|
||||
* A memory allocator is required for the Node API.
|
||||
*/
|
||||
/**
|
||||
* \def MPACK_REALLOC
|
||||
*
|
||||
* Defines the realloc function used by mpack. It is used by growable buffers
|
||||
* to resize more quickly.
|
||||
*
|
||||
* This is optional, even when MPACK_MALLOC is used. If MPACK_MALLOC is
|
||||
* set and MPACK_REALLOC is not, MPACK_MALLOC is used with a simple copy
|
||||
* to grow buffers.
|
||||
*/
|
||||
#if defined(MPACK_STDLIB) && !defined(MPACK_MALLOC)
|
||||
#define MPACK_MALLOC malloc
|
||||
#define MPACK_REALLOC realloc
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \def MPACK_FREE
|
||||
*
|
||||
* Defines the memory free function used by mpack. This is used by helpers
|
||||
* for automatically allocating data the correct size. If this macro is
|
||||
* undefined, the allocation helpers will not be compiled.
|
||||
*
|
||||
* A memory allocator is required for the Node API.
|
||||
*/
|
||||
#if defined(MPACK_STDLIB) && !defined(MPACK_FREE)
|
||||
#define MPACK_FREE free
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Enables the setjmp()/longjmp() error handling option. MPACK_MALLOC is required.
|
||||
*
|
||||
* Note that you don't have to use it; this just enables the option. It can be
|
||||
* disabled to avoid the dependency on setjmp.h .
|
||||
*/
|
||||
#if defined(MPACK_MALLOC)
|
||||
#define MPACK_SETJMP 1
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Debugging options
|
||||
*/
|
||||
|
||||
/**
|
||||
* \def MPACK_DEBUG
|
||||
*
|
||||
* Enables debug features. You may want to wrap this around your
|
||||
* own debug preprocs. By default, they are enabled if DEBUG or _DEBUG
|
||||
* are defined.
|
||||
*
|
||||
* Note that MPACK_DEBUG cannot be defined differently for different
|
||||
* source files because it affects layout of structs defined in header
|
||||
* files. Your entire project must be compiled with the same value of
|
||||
* MPACK_DEBUG. (This is why NDEBUG is not used.)
|
||||
*/
|
||||
#if defined(DEBUG) || defined(_DEBUG)
|
||||
#define MPACK_DEBUG 1
|
||||
#else
|
||||
#define MPACK_DEBUG 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Set this to 1 to implement a custom mpack_assert_fail() function. This
|
||||
* function must not return, and must have the following signature:
|
||||
*
|
||||
* void mpack_assert_fail(const char* message)
|
||||
*
|
||||
* Asserts are only used when MPACK_DEBUG is enabled, and can be triggered
|
||||
* by bugs in mpack or bugs due to incorrect usage of mpack.
|
||||
*/
|
||||
#define MPACK_CUSTOM_ASSERT 0
|
||||
|
||||
/**
|
||||
* \def MPACK_READ_TRACKING
|
||||
*
|
||||
* Enables compound type size tracking for readers. This ensures that the
|
||||
* correct number of elements or bytes are read from a compound type.
|
||||
*
|
||||
* This is enabled by default in debug builds (provided a malloc() is
|
||||
* available.)
|
||||
*/
|
||||
#if MPACK_DEBUG && MPACK_READER && defined(MPACK_MALLOC)
|
||||
#define MPACK_READ_TRACKING 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \def MPACK_WRITE_TRACKING
|
||||
*
|
||||
* Enables compound type size tracking for writers. This ensures that the
|
||||
* correct number of elements or bytes are written in a compound type.
|
||||
*
|
||||
* Note that without write tracking enabled, it is possible for buggy code
|
||||
* to emit invalid MessagePack without flagging an error by writing the wrong
|
||||
* number of elements or bytes in a compound type. With tracking enabled,
|
||||
* MPACK will catch such errors and break on the offending line of code.
|
||||
*
|
||||
* This is enabled by default in debug builds (provided a malloc() is
|
||||
* available.)
|
||||
*/
|
||||
#if MPACK_DEBUG && MPACK_WRITER && defined(MPACK_MALLOC)
|
||||
#define MPACK_WRITE_TRACKING 1
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Miscellaneous
|
||||
*/
|
||||
|
||||
/**
|
||||
* Stack space to use when initializing a reader or writer with a
|
||||
* stack-allocated buffer.
|
||||
*/
|
||||
#define MPACK_STACK_SIZE 4096
|
||||
|
||||
/**
|
||||
* Buffer size to use for allocated buffers (such as for a file writer.)
|
||||
*/
|
||||
#define MPACK_BUFFER_SIZE 65536
|
||||
|
||||
/**
|
||||
* Number of nodes in each allocated node page.
|
||||
*
|
||||
* Nodes are 16 bytes when compiled for a 32-bit architecture and
|
||||
* 24 bytes when compiled for a 64-bit architecture.
|
||||
*
|
||||
* Using as many nodes fit in one memory page seems to provide the
|
||||
* best performance, and has very little waste when parsing small
|
||||
* messages.
|
||||
*/
|
||||
#define MPACK_NODE_PAGE_SIZE (4096 / sizeof(mpack_node_t))
|
||||
|
||||
/**
|
||||
* The initial depth for the node parser. When MPACK_MALLOC is available,
|
||||
* the node parser has no practical depth limit, and it is not recursive
|
||||
* so there is no risk of overflowing the call stack.
|
||||
*/
|
||||
#define MPACK_NODE_INITIAL_DEPTH 8
|
||||
|
||||
/**
|
||||
* The maximum depth for the node parser if MPACK_MALLOC is not available.
|
||||
* The parsing stack is placed on the call stack.
|
||||
*/
|
||||
#define MPACK_NODE_MAX_DEPTH_WITHOUT_MALLOC 32
|
||||
|
||||
|
||||
#endif
|
||||
|
134
transports/mach.c
Normal file
134
transports/mach.c
Normal file
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright 2014-2015 iXsystems, Inc.
|
||||
* All rights reserved
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted providing that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "../xpc_internal.h"
|
||||
|
||||
#define SOCKET_DIR "/var/run/xpc"
|
||||
|
||||
|
||||
struct unix_pipe
|
||||
{
|
||||
char * up_path;
|
||||
int up_socket;
|
||||
bool up_listener;
|
||||
};
|
||||
|
||||
static int
|
||||
mach_lookup(const char *name, xpc_pipe_t *pipe)
|
||||
{
|
||||
if (flags & XPC_CONNECTION_MACH_SERVICE_LISTENER) {
|
||||
kr = bootstrap_check_in(bootstrap_port, name,
|
||||
&conn->xc_local_port);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
errno = EBUSY;
|
||||
free(conn);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (conn);
|
||||
}
|
||||
|
||||
static int
|
||||
mach_listen(const char *name, xpc_pipe_t *pipe)
|
||||
{
|
||||
kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE,
|
||||
&conn->xc_local_port);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
errno = EPERM;
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
kr = mach_port_insert_right(mach_task_self(), conn->xc_local_port,
|
||||
conn->xc_local_port, MACH_MSG_TYPE_MAKE_SEND);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
errno = EPERM;
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
mach_send(xpc_pipe_t pipe, struct iovec *iov, struct xpc_resource *res, size_t nres)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
mach_recv(xpc_pipe_t pipe, struct iovec *iov, struct xpc_resource **res, size_t *nres)
|
||||
{
|
||||
struct xpc_recv_message message;
|
||||
mach_msg_header_t *request;
|
||||
kern_return_t kr;
|
||||
mig_reply_error_t response;
|
||||
mach_msg_trailer_t *tr;
|
||||
int data_size;
|
||||
struct xpc_object *xo;
|
||||
audit_token_t *auditp;
|
||||
xpc_u val;
|
||||
|
||||
request = &message.header;
|
||||
/* should be size - but what about arbitrary XPC data? */
|
||||
request->msgh_size = MAX_RECV;
|
||||
request->msgh_local_port = local;
|
||||
kr = mach_msg(request, MACH_RCV_MSG |
|
||||
MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) |
|
||||
MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT),
|
||||
0, request->msgh_size, request->msgh_local_port,
|
||||
MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
|
||||
|
||||
if (kr != 0)
|
||||
LOG("mach_msg_receive returned %d\n", kr);
|
||||
*remote = request->msgh_remote_port;
|
||||
*id = message.id;
|
||||
data_size = message.size;
|
||||
|
||||
tr = (mach_msg_trailer_t *)(((char *)&message) + request->msgh_size);
|
||||
auditp = &((mach_msg_audit_trailer_t *)tr)->msgh_audit;
|
||||
|
||||
xo->xo_audit_token = malloc(sizeof(*auditp));
|
||||
memcpy(xo->xo_audit_token, auditp, sizeof(*auditp));
|
||||
|
||||
xpc_dictionary_set_mach_send(xo, XPC_RPORT, request->msgh_remote_port);
|
||||
xpc_dictionary_set_uint64(xo, XPC_SEQID, message.id);
|
||||
*result = xo;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static struct xpc_transport unix_transport = {
|
||||
.listen = mach_listen,
|
||||
.lookup = mach_lookup,
|
||||
.get_credentials = mach_get_credentials,
|
||||
.send = mach_send,
|
||||
.recv = mach_recv
|
||||
};
|
252
transports/unix.c
Normal file
252
transports/unix.c
Normal file
@ -0,0 +1,252 @@
|
||||
/*
|
||||
* Copyright 2014-2015 iXsystems, Inc.
|
||||
* All rights reserved
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted providing that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdbool.h>
|
||||
#include <dispatch/dispatch.h>
|
||||
#include <xpc/xpc.h>
|
||||
|
||||
#include "../xpc_internal.h"
|
||||
|
||||
#define SOCKET_DIR "/var/run/xpc"
|
||||
|
||||
|
||||
struct unix_port
|
||||
{
|
||||
int socket;
|
||||
struct sockaddr_un sun;
|
||||
};
|
||||
|
||||
static int
|
||||
unix_lookup(const char *name, xpc_port_t *port)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
struct unix_port *ret;
|
||||
struct stat st;
|
||||
char *path;
|
||||
|
||||
asprintf(&path, "%s/%s", SOCKET_DIR, name);
|
||||
|
||||
if (stat(path, &st) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (!(st.st_mode & S_IFSOCK)) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
ret = malloc(sizeof(struct unix_port));
|
||||
ret->socket = -1;
|
||||
ret->sun.sun_family = AF_UNIX;
|
||||
ret->sun.sun_len = sizeof(struct sockaddr_un);
|
||||
strncpy(ret->sun.sun_path, path, sizeof(ret->sun.sun_path));
|
||||
|
||||
*port = ret;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
unix_listen(const char *name, xpc_port_t *port)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
struct unix_port *ret;
|
||||
struct stat st;
|
||||
char *path;
|
||||
int nb = 1;
|
||||
|
||||
if (name == NULL) {
|
||||
asprintf(&path, "%s/anonymous.XXXXXXXX", SOCKET_DIR);
|
||||
path = mktemp(path);
|
||||
} else
|
||||
asprintf(&path, "%s/%s", SOCKET_DIR, name);
|
||||
|
||||
unlink(path);
|
||||
|
||||
ret = malloc(sizeof(struct unix_port));
|
||||
ret->sun.sun_family = AF_UNIX;
|
||||
ret->sun.sun_len = sizeof(struct sockaddr_un);
|
||||
strncpy(ret->sun.sun_path, path, sizeof(ret->sun.sun_path));
|
||||
|
||||
ret->socket = socket(AF_UNIX, SOCK_DGRAM, 0);
|
||||
if (ret->socket == -1) {
|
||||
free(ret);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (bind(ret->socket, (struct sockaddr *)&ret->sun, sizeof(struct sockaddr_un)) != 0) {
|
||||
debugf("bind failed: %s", strerror(errno));
|
||||
free(ret);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
//if (setsockopt(ret->socket, 0, LOCAL_CREDS, &nb, sizeof(nb)) == -1) {
|
||||
// debugf("setsockopt failed: %s", strerror(errno));
|
||||
// free(ret);
|
||||
// return (-1);
|
||||
//}
|
||||
|
||||
*port = ret;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
unix_release(xpc_port_t port)
|
||||
{
|
||||
struct unix_port *uport = (struct unix_port *)port;
|
||||
|
||||
if (uport->socket != -1) {
|
||||
close(uport->socket);
|
||||
unlink(uport->sun.sun_path);
|
||||
}
|
||||
|
||||
free(uport);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static char *
|
||||
unix_port_to_string(xpc_port_t port)
|
||||
{
|
||||
struct unix_port *uport = (struct unix_port *)port;
|
||||
char *ret;
|
||||
|
||||
if (uport->socket != -1)
|
||||
asprintf(&ret, "<%s [%d]>", uport->sun.sun_path, uport->socket);
|
||||
else
|
||||
asprintf(&ret, "<%s>", uport->sun.sun_path);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
unix_port_compare(xpc_port_t p1, xpc_port_t p2)
|
||||
{
|
||||
struct unix_port *up1 = (struct unix_port *)p1;
|
||||
struct unix_port *up2 = (struct unix_port *)p2;
|
||||
|
||||
return (strncmp(up1->sun.sun_path, up2->sun.sun_path, sizeof up1->sun.sun_path));
|
||||
}
|
||||
|
||||
static dispatch_source_t
|
||||
unix_create_source(xpc_port_t port, dispatch_queue_t tq)
|
||||
{
|
||||
struct unix_port *uport = (struct unix_port *)port;
|
||||
dispatch_source_t source;
|
||||
|
||||
return (dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, (uintptr_t)uport->socket, 0, tq));
|
||||
}
|
||||
|
||||
static int
|
||||
unix_send(xpc_port_t local, xpc_port_t remote, struct iovec *iov, int niov, struct xpc_resource *res, size_t nres)
|
||||
{
|
||||
struct unix_port *local_port = (struct unix_port *)local;
|
||||
struct unix_port *remote_port = (struct unix_port *)remote;
|
||||
struct msghdr msg;
|
||||
union {
|
||||
struct cmsghdr hdr;
|
||||
struct cmsgcred cred;
|
||||
} cmsg;
|
||||
|
||||
debugf("local=%s, remote=%s, msg=%p, size=%ld",
|
||||
unix_port_to_string(local), unix_port_to_string(remote),
|
||||
iov->iov_base, iov->iov_len);
|
||||
|
||||
msg.msg_name = &remote_port->sun;
|
||||
msg.msg_namelen = remote_port->sun.sun_len;
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = niov;
|
||||
msg.msg_control = (caddr_t) &cmsg;
|
||||
msg.msg_controllen = CMSG_SPACE(sizeof(cmsg));
|
||||
cmsg.hdr.cmsg_type = SCM_CREDS;
|
||||
cmsg.hdr.cmsg_level = SOL_SOCKET;
|
||||
cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(struct cmsgcred));
|
||||
|
||||
if (sendmsg(local_port->socket, &msg, 0) < 0)
|
||||
return (-1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
unix_recv(xpc_port_t local, xpc_port_t *remote, struct iovec *iov, int niov,
|
||||
struct xpc_resource **res, size_t *nres, struct xpc_credentials *creds)
|
||||
{
|
||||
struct unix_port *port = (struct unix_port *)local;
|
||||
struct unix_port *remote_port;
|
||||
struct msghdr msg;
|
||||
struct cmsgcred *recv_creds;
|
||||
ssize_t recvd;
|
||||
union {
|
||||
struct cmsghdr hdr;
|
||||
struct cmsgcred cred;
|
||||
} cmsg;
|
||||
|
||||
remote_port = malloc(sizeof(struct unix_port));
|
||||
remote_port->socket = -1;
|
||||
|
||||
msg.msg_name = &remote_port->sun;
|
||||
msg.msg_namelen = sizeof(struct sockaddr_un);
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = niov;
|
||||
msg.msg_control = (caddr_t) &cmsg;
|
||||
msg.msg_controllen = CMSG_SPACE(sizeof(cmsg));
|
||||
memset(&cmsg, 0, sizeof(cmsg));
|
||||
|
||||
recvd = recvmsg(port->socket, &msg, 0);
|
||||
if (recvd < 0)
|
||||
return (-1);
|
||||
|
||||
recv_creds = (struct cmsgcred *)CMSG_DATA(&cmsg);
|
||||
creds->xc_remote_pid = recv_creds->cmcred_pid;
|
||||
creds->xc_remote_euid = recv_creds->cmcred_euid;
|
||||
creds->xc_remote_guid = recv_creds->cmcred_gid;
|
||||
|
||||
*remote = (xpc_port_t *)remote_port;
|
||||
debugf("local=%s, remote=%s, msg=%p, len=%ld", unix_port_to_string(local), unix_port_to_string(*remote), iov->iov_base, recvd);
|
||||
debugf("remote pid=%d, uid=%d, gid=%d", recv_creds->cmcred_pid, recv_creds->cmcred_uid, recv_creds->cmcred_gid);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
struct xpc_transport unix_transport = {
|
||||
.xt_name = "unix",
|
||||
.xt_listen = unix_listen,
|
||||
.xt_lookup = unix_lookup,
|
||||
.xt_release = unix_release,
|
||||
.xt_port_to_string = unix_port_to_string,
|
||||
.xt_port_compare = unix_port_compare,
|
||||
.xt_create_source = unix_create_source,
|
||||
.xt_send = unix_send,
|
||||
.xt_recv = unix_recv
|
||||
};
|
427
xpc/activity.h
Normal file
427
xpc/activity.h
Normal file
@ -0,0 +1,427 @@
|
||||
#ifndef __XPC_ACTIVITY_H__
|
||||
#define __XPC_ACTIVITY_H__
|
||||
|
||||
#ifndef __XPC_INDIRECT__
|
||||
#error "Please #include <xpc/xpc.h> instead of this file directly."
|
||||
// For HeaderDoc.
|
||||
#include <xpc/base.h>
|
||||
#endif // __XPC_INDIRECT__
|
||||
|
||||
#ifdef __BLOCKS__
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* The following are a collection of keys and values used to set an activity's
|
||||
* execution criteria.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @constant XPC_ACTIVITY_INTERVAL
|
||||
* An integer property indicating the desired time interval (in seconds) of the
|
||||
* activity. The activity will not be run more than once per time interval.
|
||||
* Due to the nature of XPC Activity finding an opportune time to run
|
||||
* the activity, any two occurrences may be more or less than 'interval'
|
||||
* seconds apart, but on average will be 'interval' seconds apart.
|
||||
* The presence of this key implies the following, unless overridden:
|
||||
* - XPC_ACTIVITY_REPEATING with a value of true
|
||||
* - XPC_ACTIVITY_DELAY with a value of half the 'interval'
|
||||
* The delay enforces a minimum distance between any two occurrences.
|
||||
* - XPC_ACTIVITY_GRACE_PERIOD with a value of half the 'interval'.
|
||||
* The grace period is the amount of time allowed to pass after the end of
|
||||
* the interval before more aggressive scheduling occurs. The grace period
|
||||
* does not increase the size of the interval.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0)
|
||||
XPC_EXPORT
|
||||
const char *XPC_ACTIVITY_INTERVAL;
|
||||
|
||||
/*!
|
||||
* @constant XPC_ACTIVITY_REPEATING
|
||||
* A boolean property indicating whether this is a repeating activity.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0)
|
||||
XPC_EXPORT
|
||||
const char *XPC_ACTIVITY_REPEATING;
|
||||
|
||||
/*!
|
||||
* @constant XPC_ACTIVITY_DELAY
|
||||
* An integer property indicating the number of seconds to delay before
|
||||
* beginning the activity.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0)
|
||||
XPC_EXPORT
|
||||
const char *XPC_ACTIVITY_DELAY;
|
||||
|
||||
/*!
|
||||
* @constant XPC_ACTIVITY_GRACE_PERIOD
|
||||
* An integer property indicating the number of seconds to allow as a grace
|
||||
* period before the scheduling of the activity becomes more aggressive.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0)
|
||||
XPC_EXPORT
|
||||
const char *XPC_ACTIVITY_GRACE_PERIOD;
|
||||
|
||||
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0)
|
||||
XPC_EXPORT
|
||||
const int64_t XPC_ACTIVITY_INTERVAL_1_MIN;
|
||||
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0)
|
||||
XPC_EXPORT
|
||||
const int64_t XPC_ACTIVITY_INTERVAL_5_MIN;
|
||||
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0)
|
||||
XPC_EXPORT
|
||||
const int64_t XPC_ACTIVITY_INTERVAL_15_MIN;
|
||||
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0)
|
||||
XPC_EXPORT
|
||||
const int64_t XPC_ACTIVITY_INTERVAL_30_MIN;
|
||||
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0)
|
||||
XPC_EXPORT
|
||||
const int64_t XPC_ACTIVITY_INTERVAL_1_HOUR;
|
||||
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0)
|
||||
XPC_EXPORT
|
||||
const int64_t XPC_ACTIVITY_INTERVAL_4_HOURS;
|
||||
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0)
|
||||
XPC_EXPORT
|
||||
const int64_t XPC_ACTIVITY_INTERVAL_8_HOURS;
|
||||
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0)
|
||||
XPC_EXPORT
|
||||
const int64_t XPC_ACTIVITY_INTERVAL_1_DAY;
|
||||
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0)
|
||||
XPC_EXPORT
|
||||
const int64_t XPC_ACTIVITY_INTERVAL_7_DAYS;
|
||||
|
||||
/*!
|
||||
* @constant XPC_ACTIVITY_PRIORITY
|
||||
* A string property indicating the priority of the activity.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0)
|
||||
XPC_EXPORT
|
||||
const char *XPC_ACTIVITY_PRIORITY;
|
||||
|
||||
/*!
|
||||
* @constant XPC_ACTIVITY_PRIORITY_MAINTENANCE
|
||||
* A string indicating activity is maintenance priority.
|
||||
* Maintenance priority is intended for user-invisible maintenance tasks
|
||||
* such as garbage collection or optimization.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0)
|
||||
XPC_EXPORT
|
||||
const char *XPC_ACTIVITY_PRIORITY_MAINTENANCE;
|
||||
|
||||
/*!
|
||||
* @constant XPC_ACTIVITY_PRIORITY_UTILITY
|
||||
* A string indicating activity is utility priority.
|
||||
* Utility priority is intended for user-visible tasks such as fetching data
|
||||
* from the network, copying files, or importing data.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0)
|
||||
XPC_EXPORT
|
||||
const char *XPC_ACTIVITY_PRIORITY_UTILITY;
|
||||
|
||||
/*!
|
||||
* @constant XPC_ACTIVITY_ALLOW_BATTERY
|
||||
* A Boolean value indicating whether the activity should be allowed to run
|
||||
* while the computer is on battery power. The default value is false for
|
||||
* maintenance priority activity and true for utility priority activity.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0)
|
||||
XPC_EXPORT
|
||||
const char *XPC_ACTIVITY_ALLOW_BATTERY;
|
||||
|
||||
/*!
|
||||
* @constant XPC_ACTIVITY_REQUIRE_SCREEN_SLEEP
|
||||
* A Boolean value indicating whether the activity should only be performed
|
||||
* while the primary screen is in sleep mode. Defaults to false.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0)
|
||||
XPC_EXPORT
|
||||
const char *XPC_ACTIVITY_REQUIRE_SCREEN_SLEEP; // bool
|
||||
|
||||
/*!
|
||||
* @constant XPC_ACTIVITY_REQUIRE_BATTERY_LEVEL
|
||||
* An integer percentage of minimum battery charge required to allow the
|
||||
* activity to run. A default minimum battery level is determined by the
|
||||
* system.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0)
|
||||
XPC_EXPORT
|
||||
const char *XPC_ACTIVITY_REQUIRE_BATTERY_LEVEL; // int (%)
|
||||
|
||||
/*!
|
||||
* @constant XPC_ACTIVITY_REQUIRE_HDD_SPINNING
|
||||
* A Boolean value indicating whether the activity should only be performed
|
||||
* while the hard disk drive (HDD) is spinning. Computers with flash storage
|
||||
* are considered to be equivalent to HDD spinning. Defaults to false.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0)
|
||||
XPC_EXPORT
|
||||
const char *XPC_ACTIVITY_REQUIRE_HDD_SPINNING; // bool
|
||||
|
||||
/*!
|
||||
* @define XPC_TYPE_ACTIVITY
|
||||
* A type representing a connection to a named service. This connection is
|
||||
* bidirectional and can be used to both send and receive messages. A
|
||||
* connection carries the credentials of the remote service provider.
|
||||
*/
|
||||
#define XPC_TYPE_ACTIVITY (&_xpc_type_activity)
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0)
|
||||
XPC_EXPORT
|
||||
XPC_TYPE(_xpc_type_activity);
|
||||
|
||||
/*!
|
||||
* @typedef xpc_activity_t
|
||||
*
|
||||
* @abstract
|
||||
* An XPC activity object.
|
||||
*
|
||||
* @discussion
|
||||
* This object represents a set of execution criteria and a current execution
|
||||
* state for background activity on the system. Once an activity is registered,
|
||||
* the system will evaluate its criteria to determine whether the activity is
|
||||
* eligible to run under current system conditions. When an activity becomes
|
||||
* eligible to run, its execution state will be updated and an invocation of
|
||||
* its handler block will be made.
|
||||
*/
|
||||
XPC_DECL(xpc_activity);
|
||||
|
||||
/*!
|
||||
* @typedef xpc_activity_handler_t
|
||||
*
|
||||
* @abstract
|
||||
* A block that is called when an XPC activity becomes eligible to run.
|
||||
*/
|
||||
typedef void (^xpc_activity_handler_t)(xpc_activity_t activity);
|
||||
|
||||
/*!
|
||||
* @constant XPC_ACTIVITY_CHECK_IN
|
||||
* This constant may be passed to xpc_activity_register() as the criteria
|
||||
* dictionary in order to check in with the system for previously registered
|
||||
* activity using the same identifier (for example, an activity taken from a
|
||||
* launchd property list).
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0)
|
||||
XPC_EXPORT
|
||||
const xpc_object_t XPC_ACTIVITY_CHECK_IN;
|
||||
|
||||
/*!
|
||||
* @function xpc_activity_register
|
||||
*
|
||||
* @abstract
|
||||
* Registers an activity with the system.
|
||||
*
|
||||
* @discussion
|
||||
* Registers a new activity with the system. The criteria of the activity are
|
||||
* described by the dictionary passed to this function. If an activity with the
|
||||
* same identifier already exists, the criteria provided override the existing
|
||||
* criteria unless the special dictionary XPC_ACTIVITY_CHECK_IN is used. The
|
||||
* XPC_ACTIVITY_CHECK_IN dictionary instructs the system to first look up an
|
||||
* existing activity without modifying its criteria. Once the existing activity
|
||||
* is found (or a new one is created with an empty set of criteria) the handler
|
||||
* will be called with an activity object in the XPC_ACTIVITY_STATE_CHECK_IN
|
||||
* state.
|
||||
*
|
||||
* @param identifier
|
||||
* A unique identifier for the activity. Each application has its own namespace.
|
||||
* The identifier should remain constant across registrations, relaunches of
|
||||
* the application, and reboots. It should identify the kind of work being done,
|
||||
* not a particular invocation of the work.
|
||||
*
|
||||
* @param criteria
|
||||
* A dictionary of criteria for the activity.
|
||||
*
|
||||
* @param handler
|
||||
* The handler block to be called when the activity changes state to one of the
|
||||
* following states:
|
||||
* - XPC_ACTIVITY_STATE_CHECK_IN (optional)
|
||||
* - XPC_ACTIVITY_STATE_RUN
|
||||
*
|
||||
* The handler block is never invoked reentrantly. It will be invoked on a
|
||||
* dispatch queue with an appropriate priority to perform the activity.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0)
|
||||
XPC_EXPORT XPC_NONNULL1 XPC_NONNULL2 XPC_NONNULL3
|
||||
void
|
||||
xpc_activity_register(const char *identifier, xpc_object_t criteria,
|
||||
xpc_activity_handler_t handler);
|
||||
|
||||
/*!
|
||||
* @function xpc_activity_copy_criteria
|
||||
*
|
||||
* @abstract
|
||||
* Returns an XPC dictionary describing the execution criteria of an activity.
|
||||
* This will return NULL in cases where the activity has already completed, e.g.
|
||||
* when checking in to an event that finished and was not rescheduled.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0)
|
||||
XPC_EXPORT XPC_WARN_RESULT XPC_RETURNS_RETAINED
|
||||
xpc_object_t
|
||||
xpc_activity_copy_criteria(xpc_activity_t activity);
|
||||
|
||||
/*!
|
||||
* @function xpc_activity_set_criteria
|
||||
*
|
||||
* @abstract
|
||||
* Modifies the execution criteria of an activity.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0)
|
||||
XPC_EXPORT XPC_NONNULL1 XPC_NONNULL2
|
||||
void
|
||||
xpc_activity_set_criteria(xpc_activity_t activity, xpc_object_t criteria);
|
||||
|
||||
/*!
|
||||
* @enum xpc_activity_state_t
|
||||
* An activity is defined to be in one of the following states. Applications
|
||||
* may check the current state of the activity using xpc_activity_get_state()
|
||||
* in the handler block provided to xpc_activity_register().
|
||||
*
|
||||
* The application can modify the state of the activity by calling
|
||||
* xpc_activity_set_state() with one of the following:
|
||||
* - XPC_ACTIVITY_STATE_DEFER
|
||||
* - XPC_ACTIVITY_STATE_CONTINUE
|
||||
* - XPC_ACTIVITY_STATE_DONE
|
||||
*
|
||||
* @constant XPC_ACTIVITY_STATE_CHECK_IN
|
||||
* An activity in this state has just completed a checkin with the system after
|
||||
* XPC_ACTIVITY_CHECK_IN was provided as the criteria dictionary to
|
||||
* xpc_activity_register. The state gives the application an opportunity to
|
||||
* inspect and modify the activity's criteria.
|
||||
*
|
||||
* @constant XPC_ACTIVITY_STATE_WAIT
|
||||
* An activity in this state is waiting for an opportunity to run. This value
|
||||
* is never returned within the activity's handler block, as the block is
|
||||
* invoked in response to XPC_ACTIVITY_STATE_CHECK_IN or XPC_ACTIVITY_STATE_RUN.
|
||||
*
|
||||
* Note:
|
||||
* A launchd job may idle exit while an activity is in the wait state and be
|
||||
* relaunched in response to the activity becoming runnable. The launchd job
|
||||
* simply needs to re-register for the activity on its next launch by passing
|
||||
* XPC_ACTIVITY_STATE_CHECK_IN to xpc_activity_register().
|
||||
*
|
||||
* @constant XPC_ACTIVITY_STATE_RUN
|
||||
* An activity in this state is eligible to run based on its criteria.
|
||||
*
|
||||
* @constant XPC_ACTIVITY_STATE_DEFER
|
||||
* An application may pass this value to xpc_activity_set_state() to indicate
|
||||
* that the activity should be deferred (placed back into the WAIT state) until
|
||||
* a time when its criteria are met again. Deferring an activity does not reset
|
||||
* any of its time-based criteria (in other words, it will remain past due).
|
||||
*
|
||||
* IMPORTANT:
|
||||
* This should be done in response to observing xpc_activity_should_defer().
|
||||
* It should not be done unilaterally. If you determine that conditions are bad
|
||||
* to do your activity's work for reasons you can't express in a criteria
|
||||
* dictionary, you should set the activity's state to XPC_ACTIVITY_STATE_DONE.
|
||||
*
|
||||
*
|
||||
* @constant XPC_ACTIVITY_STATE_CONTINUE
|
||||
* An application may pass this value to xpc_activity_set_state() to indicate
|
||||
* that the activity will continue its operation beyond the return of its
|
||||
* handler block. This can be used to extend an activity to include asynchronous
|
||||
* operations. The activity's handler block will not be invoked again until the
|
||||
* state has been updated to either XPC_ACTIVITY_STATE_DEFER or, in the case
|
||||
* of repeating activity, XPC_ACTIVITY_STATE_DONE.
|
||||
*
|
||||
* @constant XPC_ACTIVITY_STATE_DONE
|
||||
* An application may pass this value to xpc_activity_set_state() to indicate
|
||||
* that the activity has completed. For non-repeating activity, the resources
|
||||
* associated with the activity will be automatically released upon return from
|
||||
* the handler block. For repeating activity, timers present in the activity's
|
||||
* criteria will be reset.
|
||||
*/
|
||||
enum {
|
||||
XPC_ACTIVITY_STATE_CHECK_IN,
|
||||
XPC_ACTIVITY_STATE_WAIT,
|
||||
XPC_ACTIVITY_STATE_RUN,
|
||||
XPC_ACTIVITY_STATE_DEFER,
|
||||
XPC_ACTIVITY_STATE_CONTINUE,
|
||||
XPC_ACTIVITY_STATE_DONE,
|
||||
};
|
||||
typedef long xpc_activity_state_t;
|
||||
|
||||
/*!
|
||||
* @function xpc_activity_get_state
|
||||
*
|
||||
* @abstract
|
||||
* Returns the current state of an activity.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0)
|
||||
XPC_EXPORT XPC_WARN_RESULT XPC_NONNULL1
|
||||
xpc_activity_state_t
|
||||
xpc_activity_get_state(xpc_activity_t activity);
|
||||
|
||||
/*!
|
||||
* @function xpc_activity_set_state
|
||||
*
|
||||
* @abstract
|
||||
* Updates the current state of an activity.
|
||||
*
|
||||
* @return
|
||||
* Returns true if the state was successfully updated; otherwise, returns
|
||||
* false if the requested state transition is not valid.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0)
|
||||
XPC_EXPORT XPC_WARN_RESULT XPC_NONNULL1
|
||||
bool
|
||||
xpc_activity_set_state(xpc_activity_t activity, xpc_activity_state_t state);
|
||||
|
||||
/*!
|
||||
* @function xpc_activity_should_defer
|
||||
*
|
||||
* @abstract
|
||||
* Test whether an activity should be deferred.
|
||||
*
|
||||
* @discussion
|
||||
* This function may be used to test whether the criteria of a long-running
|
||||
* activity are still satisfied. If not, the system indicates that the
|
||||
* application should defer the activity. The application may acknowledge the
|
||||
* deferral by calling xpc_activity_set_state() with XPC_ACTIVITY_STATE_DEFER.
|
||||
* Once deferred, the system will place the activity back into the WAIT state
|
||||
* and re-invoke the handler block at the earliest opportunity when the criteria
|
||||
* are once again satisfied.
|
||||
*
|
||||
* @return
|
||||
* Returns true if the activity should be deferred.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0)
|
||||
XPC_EXPORT
|
||||
bool
|
||||
xpc_activity_should_defer(xpc_activity_t activity);
|
||||
|
||||
/*!
|
||||
* @function xpc_activity_unregister
|
||||
*
|
||||
* @abstract
|
||||
* Unregisters an activity found by its identifier.
|
||||
*
|
||||
* @discussion
|
||||
* A dynamically registered activity will be deleted in response to this call.
|
||||
* Statically registered activity (from a launchd property list) will be
|
||||
* reverted to its original criteria if any modifications were made.
|
||||
*
|
||||
* Unregistering an activity has no effect on any outstanding xpc_activity_t
|
||||
* objects or any currently executing xpc_activity_handler_t blocks; however,
|
||||
* no new handler block invocations will be made after it is unregistered.
|
||||
*
|
||||
* @param identifier
|
||||
* The identifier of the activity to unregister.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0)
|
||||
XPC_EXPORT XPC_NONNULL1
|
||||
void
|
||||
xpc_activity_unregister(const char *identifier);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif // __BLOCKS__
|
||||
|
||||
#endif // __XPC_ACTIVITY_H__
|
||||
|
167
xpc/base.h
Normal file
167
xpc/base.h
Normal file
@ -0,0 +1,167 @@
|
||||
// Copyright (c) 2009-2011 Apple Inc. All rights reserved.
|
||||
|
||||
#ifndef __XPC_BASE_H__
|
||||
#define __XPC_BASE_H__
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#if !defined(__has_include)
|
||||
#define __has_include(x) 0
|
||||
#endif // !defined(__has_include)
|
||||
|
||||
#if !defined(__has_attribute)
|
||||
#define __has_attribute(x) 0
|
||||
#endif // !defined(__has_attribute)
|
||||
|
||||
#if __has_include(<xpc/availability.h>)
|
||||
#include <xpc/availability.h>
|
||||
#else // __has_include(<xpc/availability.h>)
|
||||
#ifdef __APPLE__
|
||||
#include <Availability.h>
|
||||
#endif
|
||||
#define __XPC_IOS_SIMULATOR_AVAILABLE_STARTING(version)
|
||||
#endif // __has_include(<xpc/availability.h>)
|
||||
|
||||
#if XPC_SERVICE_MAIN_IN_LIBXPC
|
||||
#define XPC_HOSTING_OLD_MAIN 1
|
||||
#else // XPC_SERVICE_MAIN_IN_LIBXPC
|
||||
#define XPC_HOSTING_OLD_MAIN 0
|
||||
#endif // XPC_SERVICE_MAIN_IN_LIBXPC
|
||||
|
||||
#ifndef __XPC_INDIRECT__
|
||||
#error "Please #include <xpc/xpc.h> instead of this file directly."
|
||||
#endif // __XPC_INDIRECT__
|
||||
|
||||
#pragma mark Attribute Shims
|
||||
#ifdef __GNUC__
|
||||
#define XPC_CONSTRUCTOR __attribute__((constructor))
|
||||
#define XPC_NORETURN __attribute__((__noreturn__))
|
||||
#define XPC_NOTHROW __attribute__((__nothrow__))
|
||||
#define XPC_NONNULL1 __attribute__((__nonnull__(1)))
|
||||
#define XPC_NONNULL2 __attribute__((__nonnull__(2)))
|
||||
#define XPC_NONNULL3 __attribute__((__nonnull__(3)))
|
||||
#define XPC_NONNULL4 __attribute__((__nonnull__(4)))
|
||||
#define XPC_NONNULL5 __attribute__((__nonnull__(5)))
|
||||
#define XPC_NONNULL6 __attribute__((__nonnull__(6)))
|
||||
#define XPC_NONNULL7 __attribute__((__nonnull__(7)))
|
||||
#define XPC_NONNULL8 __attribute__((__nonnull__(8)))
|
||||
#define XPC_NONNULL9 __attribute__((__nonnull__(9)))
|
||||
#define XPC_NONNULL10 __attribute__((__nonnull__(10)))
|
||||
#define XPC_NONNULL11 __attribute__((__nonnull__(11)))
|
||||
#define XPC_NONNULL_ALL __attribute__((__nonnull__))
|
||||
#define XPC_SENTINEL __attribute__((__sentinel__))
|
||||
#define XPC_PURE __attribute__((__pure__))
|
||||
#define XPC_WARN_RESULT __attribute__((__warn_unused_result__))
|
||||
#define XPC_MALLOC __attribute__((__malloc__))
|
||||
#define XPC_UNUSED __attribute__((__unused__))
|
||||
#define XPC_USED __attribute__((__used__))
|
||||
#define XPC_PACKED __attribute__((__packed__))
|
||||
#define XPC_PRINTF(m, n) __attribute__((format(printf, m, n)))
|
||||
#define XPC_INLINE static __inline__ __attribute__((__always_inline__))
|
||||
#define XPC_NOINLINE __attribute__((noinline))
|
||||
#define XPC_NOIMPL __attribute__((unavailable))
|
||||
|
||||
#if __has_extension(attribute_unavailable_with_message)
|
||||
#define XPC_UNAVAILABLE(m) __attribute__((unavailable(m)))
|
||||
#else // __has_extension(attribute_unavailable_with_message)
|
||||
#define XPC_UNAVAILABLE(m) XPC_NOIMPL
|
||||
#endif // __has_extension(attribute_unavailable_with_message)
|
||||
|
||||
#define XPC_EXPORT extern __attribute__((visibility("default")))
|
||||
#define XPC_NOEXPORT __attribute__((visibility("hidden")))
|
||||
#define XPC_WEAKIMPORT extern __attribute__((weak_import))
|
||||
#define XPC_DEBUGGER_EXCL XPC_NOEXPORT XPC_USED
|
||||
#define XPC_TRANSPARENT_UNION __attribute__((transparent_union))
|
||||
#if __clang__
|
||||
#define XPC_DEPRECATED(m) __attribute__((deprecated(m)))
|
||||
#else // __clang__
|
||||
#define XPC_DEPRECATED(m) __attribute__((deprecated))
|
||||
#endif // __clang
|
||||
|
||||
#if __has_feature(objc_arc)
|
||||
#define XPC_GIVES_REFERENCE __strong
|
||||
#define XPC_UNRETAINED __unsafe_unretained
|
||||
#define XPC_BRIDGE(xo) ((__bridge void *)(xo))
|
||||
#define XPC_BRIDGEREF_BEGIN(xo) ((__bridge_retained void *)(xo))
|
||||
#define XPC_BRIDGEREF_BEGIN_WITH_REF(xo) ((__bridge void *)(xo))
|
||||
#define XPC_BRIDGEREF_MIDDLE(xo) ((__bridge id)(xo))
|
||||
#define XPC_BRIDGEREF_END(xo) ((__bridge_transfer id)(xo))
|
||||
#else // __has_feature(objc_arc)
|
||||
#define XPC_GIVES_REFERENCE
|
||||
#define XPC_UNRETAINED
|
||||
#define XPC_BRIDGE(xo)
|
||||
#define XPC_BRIDGEREF_BEGIN(xo) (xo)
|
||||
#define XPC_BRIDGEREF_BEGIN_WITH_REF(xo) (xo)
|
||||
#define XPC_BRIDGEREF_MIDDLE(xo) (xo)
|
||||
#define XPC_BRIDGEREF_END(xo) (xo)
|
||||
#endif // __has_feature(objc_arc)
|
||||
|
||||
#define _xpc_unreachable() __builtin_unreachable()
|
||||
#else // __GNUC__
|
||||
/*! @parseOnly */
|
||||
#define XPC_CONSTRUCTOR
|
||||
/*! @parseOnly */
|
||||
#define XPC_NORETURN
|
||||
/*! @parseOnly */
|
||||
#define XPC_NOTHROW
|
||||
/*! @parseOnly */
|
||||
#define XPC_NONNULL1
|
||||
/*! @parseOnly */
|
||||
#define XPC_NONNULL2
|
||||
/*! @parseOnly */
|
||||
#define XPC_NONNULL3
|
||||
/*! @parseOnly */
|
||||
#define XPC_NONNULL4
|
||||
/*! @parseOnly */
|
||||
#define XPC_NONNULL5
|
||||
/*! @parseOnly */
|
||||
#define XPC_NONNULL6
|
||||
/*! @parseOnly */
|
||||
#define XPC_NONNULL7
|
||||
/*! @parseOnly */
|
||||
#define XPC_NONNULL8
|
||||
/*! @parseOnly */
|
||||
#define XPC_NONNULL9
|
||||
/*! @parseOnly */
|
||||
#define XPC_NONNULL10
|
||||
/*! @parseOnly */
|
||||
#define XPC_NONNULL11
|
||||
/*! @parseOnly */
|
||||
#define XPC_NONNULL(n)
|
||||
/*! @parseOnly */
|
||||
#define XPC_NONNULL_ALL
|
||||
/*! @parseOnly */
|
||||
#define XPC_SENTINEL
|
||||
/*! @parseOnly */
|
||||
#define XPC_PURE
|
||||
/*! @parseOnly */
|
||||
#define XPC_WARN_RESULT
|
||||
/*! @parseOnly */
|
||||
#define XPC_MALLOC
|
||||
/*! @parseOnly */
|
||||
#define XPC_UNUSED
|
||||
/*! @parseOnly */
|
||||
#define XPC_PACKED
|
||||
/*! @parseOnly */
|
||||
#define XPC_PRINTF(m, n)
|
||||
/*! @parseOnly */
|
||||
#define XPC_INLINE static inline
|
||||
/*! @parseOnly */
|
||||
#define XPC_NOINLINE
|
||||
/*! @parseOnly */
|
||||
#define XPC_NOIMPL
|
||||
/*! @parseOnly */
|
||||
#define XPC_EXPORT extern
|
||||
/*! @parseOnly */
|
||||
#define XPC_WEAKIMPORT
|
||||
/*! @parseOnly */
|
||||
#define XPC_DEPRECATED
|
||||
/*! @parseOnly */
|
||||
#define XPC_UNAVAILABLE(m)
|
||||
#endif // __GNUC__
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif // __XPC_BASE_H__
|
714
xpc/connection.h
Normal file
714
xpc/connection.h
Normal file
@ -0,0 +1,714 @@
|
||||
#ifndef __XPC_CONNECTION_H__
|
||||
#define __XPC_CONNECTION_H__
|
||||
|
||||
#ifndef __XPC_INDIRECT__
|
||||
#error "Please #include <xpc/xpc.h> instead of this file directly."
|
||||
// For HeaderDoc.
|
||||
#include <xpc/base.h>
|
||||
#endif // __XPC_INDIRECT__
|
||||
|
||||
#ifndef __BLOCKS__
|
||||
#error "XPC connections require Blocks support."
|
||||
#endif // __BLOCKS__
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
/*!
|
||||
* @constant XPC_ERROR_CONNECTION_INTERRUPTED
|
||||
* Will be delivered to the connection's event handler if the remote service
|
||||
* exited. The connection is still live even in this case, and resending a
|
||||
* message will cause the service to be launched on-demand. This error serves
|
||||
* as a client's indication that it should resynchronize any state that it had
|
||||
* given the service.
|
||||
*
|
||||
* Any messages in the queue to be sent will be unwound and canceled when this
|
||||
* error occurs. In the case where a message waiting to be sent has a reply
|
||||
* handler, that handler will be invoked with this error. In the context of the
|
||||
* reply handler, this error indicates that a reply to the message will never
|
||||
* arrive.
|
||||
*
|
||||
* Messages that do not have reply handlers associated with them will be
|
||||
* silently disposed of. This error will only be given to peer connections.
|
||||
*/
|
||||
#define XPC_ERROR_CONNECTION_INTERRUPTED \
|
||||
XPC_GLOBAL_OBJECT(_xpc_error_connection_interrupted)
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0)
|
||||
XPC_EXPORT
|
||||
const struct _xpc_dictionary_s _xpc_error_connection_interrupted;
|
||||
|
||||
/*!
|
||||
* @constant XPC_ERROR_CONNECTION_INVALID
|
||||
* Will be delivered to the connection's event handler if the named service
|
||||
* provided to xpc_connection_create() could not be found in the XPC service
|
||||
* namespace. The connection is useless and should be disposed of.
|
||||
*
|
||||
* Any messages in the queue to be sent will be unwound and canceled when this
|
||||
* error occurs, similarly to the behavior when XPC_ERROR_CONNECTION_INTERRUPTED
|
||||
* occurs. The only difference is that the XPC_ERROR_CONNECTION_INVALID will be
|
||||
* given to outstanding reply handlers and the connection's event handler.
|
||||
*
|
||||
* This error may be given to any type of connection.
|
||||
*/
|
||||
#define XPC_ERROR_CONNECTION_INVALID \
|
||||
XPC_GLOBAL_OBJECT(_xpc_error_connection_invalid)
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0)
|
||||
XPC_EXPORT
|
||||
const struct _xpc_dictionary_s _xpc_error_connection_invalid;
|
||||
|
||||
/*!
|
||||
* @constant XPC_ERROR_TERMINATION_IMMINENT
|
||||
* This error will be delivered to a peer connection's event handler when the
|
||||
* XPC runtime has determined that the program should exit and that all
|
||||
* outstanding transactions must be wound down, and no new transactions can be
|
||||
* opened.
|
||||
*
|
||||
* After this error has been delivered to the event handler, no more messages
|
||||
* will be received by the connection. The runtime will still attempt to deliver
|
||||
* outgoing messages, but this error should be treated as an indication that
|
||||
* the program will exit very soon, and any outstanding business over the
|
||||
* connection should be wrapped up as quickly as possible and the connection
|
||||
* canceled shortly thereafter.
|
||||
*
|
||||
* This error will only be delivered to peer connections received through a
|
||||
* listener or the xpc_main() event handler.
|
||||
*/
|
||||
#define XPC_ERROR_TERMINATION_IMMINENT \
|
||||
XPC_GLOBAL_OBJECT(_xpc_error_termination_imminent)
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0)
|
||||
XPC_EXPORT
|
||||
const struct _xpc_dictionary_s _xpc_error_termination_imminent;
|
||||
|
||||
/*!
|
||||
* @constant XPC_CONNECTION_MACH_SERVICE_LISTENER
|
||||
* Passed to xpc_connection_create_mach_service(). This flag indicates that the
|
||||
* caller is the listener for the named service. This flag may only be passed
|
||||
* for services which are advertised in the process' launchd.plist(5). You may
|
||||
* not use this flag to dynamically add services to the Mach bootstrap
|
||||
* namespace.
|
||||
*/
|
||||
#define XPC_CONNECTION_MACH_SERVICE_LISTENER (1 << 0)
|
||||
|
||||
/*!
|
||||
* @constant XPC_CONNECTION_MACH_SERVICE_PRIVILEGED
|
||||
* Passed to xpc_connection_create_mach_service(). This flag indicates that the
|
||||
* job advertising the service name in its launchd.plist(5) should be in the
|
||||
* privileged Mach bootstrap. This is typically accomplished by placing your
|
||||
* launchd.plist(5) in /Library/LaunchDaemons. If specified alongside the
|
||||
* XPC_CONNECTION_MACH_SERVICE_LISTENER flag, this flag is a no-op.
|
||||
*/
|
||||
#define XPC_CONNECTION_MACH_SERVICE_PRIVILEGED (1 << 1)
|
||||
|
||||
/*!
|
||||
* @typedef xpc_finalizer_f
|
||||
* A function that is invoked when a connection is being torn down and its
|
||||
* context needs to be freed. The sole argument is the value that was given to
|
||||
* {@link xpc_connection_set_context} or NULL if no context has been set. It is
|
||||
* not safe to reference the connection from within this function.
|
||||
*
|
||||
* @param value
|
||||
* The context object that is to be disposed of.
|
||||
*/
|
||||
typedef void (*xpc_finalizer_t)(void *value);
|
||||
|
||||
/*!
|
||||
* @function xpc_connection_create
|
||||
* Creates a new connection object.
|
||||
*
|
||||
* @param name
|
||||
* If non-NULL, the name of the service with which to connect. The returned
|
||||
* connection will be a peer.
|
||||
*
|
||||
* If NULL, an anonymous listener connection will be created. You can embed the
|
||||
* ability to create new peer connections in an endpoint, which can be inserted
|
||||
* into a message and sent to another process .
|
||||
*
|
||||
* @param targetq
|
||||
* The GCD queue to which the event handler block will be submitted. This
|
||||
* parameter may be NULL, in which case the connection's target queue will be
|
||||
* libdispatch's default target queue, defined as DISPATCH_TARGET_QUEUE_DEFAULT.
|
||||
* The target queue may be changed later with a call to
|
||||
* xpc_connection_set_target_queue().
|
||||
*
|
||||
* @result
|
||||
* A new connection object. The caller is responsible for disposing of the
|
||||
* returned object with {@link xpc_release} when it is no longer needed.
|
||||
*
|
||||
* @discussion
|
||||
* This method will succeed even if the named service does not exist. This is
|
||||
* because the XPC namespace is not queried for the service name until
|
||||
* the first call to xpc_connection_resume().
|
||||
*
|
||||
* XPC connections, like dispatch sources, are returned in a suspended state, so
|
||||
* you must call {@link xpc_connection_resume()} in order to begin receiving
|
||||
* events from the connection. Also like dispatch sources, connections must be
|
||||
* resumed in order to be safely released. It is a programming error to release
|
||||
* a suspended connection.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0)
|
||||
XPC_EXPORT XPC_MALLOC XPC_RETURNS_RETAINED XPC_WARN_RESULT
|
||||
xpc_connection_t
|
||||
xpc_connection_create(const char *name, dispatch_queue_t targetq);
|
||||
|
||||
/*!
|
||||
* @function xpc_connection_create_mach_service
|
||||
* Creates a new connection object representing a Mach service.
|
||||
*
|
||||
* @param name
|
||||
* The name of the remote service with which to connect. The service name must
|
||||
* exist in a Mach bootstrap that is accessible to the process and be advertised
|
||||
* in a launchd.plist.
|
||||
*
|
||||
* @param targetq
|
||||
* The GCD queue to which the event handler block will be submitted. This
|
||||
* parameter may be NULL, in which case the connection's target queue will be
|
||||
* libdispatch's default target queue, defined as DISPATCH_TARGET_QUEUE_DEFAULT.
|
||||
* The target queue may be changed later with a call to
|
||||
* xpc_connection_set_target_queue().
|
||||
*
|
||||
* @param flags
|
||||
* Additional attributes with which to create the connection.
|
||||
*
|
||||
* @result
|
||||
* A new connection object.
|
||||
*
|
||||
* @discussion
|
||||
* If the XPC_CONNECTION_MACH_SERVICE_LISTENER flag is given to this method,
|
||||
* then the connection returned will be a listener connection. Otherwise, a peer
|
||||
* connection will be returned. See the documentation for
|
||||
* {@link xpc_connection_set_event_handler()} for the semantics of listener
|
||||
* connections versus peer connections.
|
||||
*
|
||||
* This method will succeed even if the named service does not exist. This is
|
||||
* because the Mach namespace is not queried for the service name until the
|
||||
* first call to {@link xpc_connection_resume()}.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0)
|
||||
XPC_EXPORT XPC_MALLOC XPC_RETURNS_RETAINED XPC_WARN_RESULT XPC_NONNULL1
|
||||
xpc_connection_t
|
||||
xpc_connection_create_mach_service(const char *name, dispatch_queue_t targetq,
|
||||
uint64_t flags);
|
||||
|
||||
/*!
|
||||
* @function xpc_connection_create_from_endpoint
|
||||
* Creates a new connection from the given endpoint.
|
||||
*
|
||||
* @param endpoint
|
||||
* The endpoint from which to create the new connection.
|
||||
*
|
||||
* @result
|
||||
* A new peer connection to the listener represented by the given endpoint.
|
||||
*
|
||||
* The same responsibilities of setting an event handler and resuming the
|
||||
* connection after calling xpc_connection_create() apply to the connection
|
||||
* returned by this API. Since the connection yielded by this API is not
|
||||
* associated with a name (and therefore is not rediscoverable), this connection
|
||||
* will receive XPC_ERROR_CONNECTION_INVALID if the listening side crashes,
|
||||
* exits or cancels the listener connection.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0)
|
||||
XPC_EXPORT XPC_MALLOC XPC_RETURNS_RETAINED XPC_WARN_RESULT XPC_NONNULL_ALL
|
||||
xpc_connection_t
|
||||
xpc_connection_create_from_endpoint(xpc_endpoint_t endpoint);
|
||||
|
||||
/*!
|
||||
* @function xpc_connection_set_target_queue
|
||||
* Sets the target queue of the given connection.
|
||||
*
|
||||
* @param connection
|
||||
* The connection object which is to be manipulated.
|
||||
*
|
||||
* @param targetq
|
||||
* The GCD queue to which the event handler block will be submitted. This
|
||||
* parameter may be NULL, in which case the connection's target queue will be
|
||||
* libdispatch's default target queue, defined as DISPATCH_TARGET_QUEUE_DEFAULT.
|
||||
*
|
||||
* @discussion
|
||||
* Setting the target queue is asynchronous and non-preemptive and therefore
|
||||
* this method will not interrupt the execution of an already-running event
|
||||
* handler block. Setting the target queue may be likened to issuing a barrier
|
||||
* to the connection which does the actual work of changing the target queue.
|
||||
*
|
||||
* The XPC runtime guarantees this non-preemptiveness even for concurrent target
|
||||
* queues. If the target queue is a concurrent queue, then XPC still guarantees
|
||||
* that there will never be more than one invocation of the connection's event
|
||||
* handler block executing concurrently. If you wish to process events
|
||||
* concurrently, you can dispatch_async(3) to a concurrent queue from within
|
||||
* the event handler.
|
||||
*
|
||||
* IMPORTANT: When called from within the event handler block,
|
||||
* dispatch_get_current_queue(3) is NOT guaranteed to return a pointer to the
|
||||
* queue set with this method.
|
||||
*
|
||||
* Despite this seeming inconsistency, the XPC runtime guarantees that, when the
|
||||
* target queue is a serial queue, the event handler block will execute
|
||||
* synchonously with respect to other blocks submitted to that same queue. When
|
||||
* the target queue is a concurrent queue, the event handler block may run
|
||||
* concurrently with other blocks submitted to that queue, but it will never run
|
||||
* concurrently with other invocations of itself for the same connection, as
|
||||
* discussed previously.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0)
|
||||
XPC_EXPORT XPC_NONNULL1
|
||||
void
|
||||
xpc_connection_set_target_queue(xpc_connection_t connection,
|
||||
dispatch_queue_t targetq);
|
||||
|
||||
/*!
|
||||
* @function xpc_connection_set_event_handler
|
||||
* Sets the event handler block for the connection.
|
||||
*
|
||||
* @param connection
|
||||
* The connection object which is to be manipulated.
|
||||
*
|
||||
* @param handler
|
||||
* The event handler block.
|
||||
*
|
||||
* @discussion
|
||||
* Setting the event handler is asynchronous and non-preemptive, and therefore
|
||||
* this method will not interrupt the execution of an already-running event
|
||||
* handler block. If the event handler is executing at the time of this call, it
|
||||
* will finish, and then the connection's event handler will be changed before
|
||||
* the next invocation of the event handler. The XPC runtime guarantees this
|
||||
* non-preemptiveness even for concurrent target queues.
|
||||
*
|
||||
* Connection event handlers are non-reentrant, so it is safe to call
|
||||
* xpc_connection_set_event_handler() from within the event handler block.
|
||||
*
|
||||
* The event handler's execution should be treated as a barrier to all
|
||||
* connection activity. When it is executing, the connection will not attempt to
|
||||
* send or receive messages, including reply messages. Thus, it is not safe to
|
||||
* call xpc_connection_send_message_with_reply_sync() on the connection from
|
||||
* within the event handler.
|
||||
*
|
||||
* You do not hold a reference on the object received as the event handler's
|
||||
* only argument. Regardless of the type of object received, it is safe to call
|
||||
* xpc_retain() on the object to obtain a reference to it.
|
||||
*
|
||||
* A connection may receive different events depending upon whether it is a
|
||||
* listener or not. Any connection may receive an error in its event handler.
|
||||
* But while normal connections may receive messages in addition to errors,
|
||||
* listener connections will receive connections and and not messages.
|
||||
*
|
||||
* Connections received by listeners are equivalent to those returned by
|
||||
* xpc_connection_create() with a non-NULL name argument and a NULL targetq
|
||||
* argument with the exception that you do not hold a reference on them.
|
||||
* You must set an event handler and resume the connection. If you do not wish
|
||||
* to accept the connection, you may simply call xpc_connection_cancel() on it
|
||||
* and return. The runtime will dispose of it for you.
|
||||
*
|
||||
* If there is an error in the connection, this handler will be invoked with the
|
||||
* error dictionary as its argument. This dictionary will be one of the well-
|
||||
* known XPC_ERROR_* dictionaries.
|
||||
*
|
||||
* Regardless of the type of event, ownership of the event object is NOT
|
||||
* implicitly transferred. Thus, the object will be released and deallocated at
|
||||
* some point in the future after the event handler returns. If you wish the
|
||||
* event's lifetime to persist, you must retain it with xpc_retain().
|
||||
*
|
||||
* Connections received through the event handler will be released and
|
||||
* deallocated after the connection has gone invalid and delivered that event to
|
||||
* its event handler.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0)
|
||||
XPC_EXPORT XPC_NONNULL_ALL
|
||||
void
|
||||
xpc_connection_set_event_handler(xpc_connection_t connection,
|
||||
xpc_handler_t handler);
|
||||
|
||||
/*!
|
||||
* @function xpc_connection_suspend
|
||||
* Suspends the connection so that the event handler block will not fire and
|
||||
* that the connection will not attempt to send any messages it has in its
|
||||
* queue. All calls to xpc_connection_suspend() must be balanced with calls to
|
||||
* xpc_connection_resume() before releasing the last reference to the
|
||||
* connection.
|
||||
*
|
||||
* @param connection
|
||||
* The connection object which is to be manipulated.
|
||||
*
|
||||
* @discussion
|
||||
* Suspension is asynchronous and non-preemptive, and therefore this method will
|
||||
* not interrupt the execution of an already-running event handler block. If
|
||||
* the event handler is executing at the time of this call, it will finish, and
|
||||
* then the connection will be suspended before the next scheduled invocation
|
||||
* of the event handler. The XPC runtime guarantees this non-preemptiveness even
|
||||
* for concurrent target queues.
|
||||
*
|
||||
* Connection event handlers are non-reentrant, so it is safe to call
|
||||
* xpc_connection_suspend() from within the event handler block.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0)
|
||||
XPC_EXPORT XPC_NONNULL_ALL
|
||||
void
|
||||
xpc_connection_suspend(xpc_connection_t connection);
|
||||
|
||||
/*!
|
||||
* @function xpc_connection_resume
|
||||
* Resumes the connection. Connections start in a suspended state, so you must
|
||||
* call xpc_connection_resume() on a connection before it will send or receive
|
||||
* any messages.
|
||||
*
|
||||
* @param connection
|
||||
* The connection object which is to be manipulated.
|
||||
*
|
||||
* @discussion
|
||||
* In order for a connection to become live, every call to
|
||||
* xpc_connection_suspend() must be balanced with a call to
|
||||
* xpc_connection_resume() after the initial call to xpc_connection_resume().
|
||||
* After the initial resume of the connection, calling xpc_connection_resume()
|
||||
* more times than xpc_connection_suspend() has been called is considered an
|
||||
* error.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0)
|
||||
XPC_EXPORT XPC_NONNULL_ALL
|
||||
void
|
||||
xpc_connection_resume(xpc_connection_t connection);
|
||||
|
||||
/*!
|
||||
* @function xpc_connection_send_message
|
||||
* Sends a message over the connection to the destination service.
|
||||
*
|
||||
* @param connection
|
||||
* The connection over which the message shall be sent.
|
||||
*
|
||||
* @param message
|
||||
* The message to send. This must be a dictionary object. This dictionary is
|
||||
* logically copied by the connection, so it is safe to modify the dictionary
|
||||
* after this call.
|
||||
*
|
||||
* @discussion
|
||||
* Messages are delivered in FIFO order. This API is safe to call from multiple
|
||||
* GCD queues. There is no indication that a message was delivered successfully.
|
||||
* This is because even once the message has been successfully enqueued on the
|
||||
* remote end, there are no guarantees about when the runtime will dequeue the
|
||||
* message and invoke the other connection's event handler block.
|
||||
*
|
||||
* If this API is used to send a message that is in reply to another message,
|
||||
* there is no guarantee of ordering between the invocations of the connection's
|
||||
* event handler and the reply handler for that message, even if they are
|
||||
* targeted to the same queue.
|
||||
*
|
||||
* After extensive study, we have found that clients who are interested in
|
||||
* the state of the message on the server end are typically holding open
|
||||
* transactions related to that message. And the only reliable way to track the
|
||||
* lifetime of that transaction is at the protocol layer. So the server should
|
||||
* send a reply message, which upon receiving, will cause the client to close
|
||||
* its transaction.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0)
|
||||
XPC_EXPORT XPC_NONNULL_ALL
|
||||
void
|
||||
xpc_connection_send_message(xpc_connection_t connection, xpc_object_t message);
|
||||
|
||||
/*!
|
||||
* @function xpc_connection_send_barrier
|
||||
* Issues a barrier against the connection's message-send activity.
|
||||
*
|
||||
* @param connection
|
||||
* The connection against which the barrier is to be issued.
|
||||
*
|
||||
* @param barrier
|
||||
* The barrier block to issue. This barrier prevents concurrent message-send
|
||||
* activity on the connection. No messages will be sent while the barrier block
|
||||
* is executing.
|
||||
*
|
||||
* @discussion
|
||||
* XPC guarantees that, even if the connection's target queue is a concurrent
|
||||
* queue, there are no other messages being sent concurrently while the barrier
|
||||
* block is executing. XPC does not guarantee that the reciept of messages
|
||||
* (either through the connection's event handler or through reply handlers)
|
||||
* will be suspended while the barrier is executing.
|
||||
*
|
||||
* A barrier is issued relative to the message-send queue. Thus, if you call
|
||||
* xpc_connection_send_message() five times and then call
|
||||
* xpc_connection_send_barrier(), the barrier will be invoked after the fifth
|
||||
* message has been sent and its memory disposed of. You may safely cancel a
|
||||
* connection from within a barrier block.
|
||||
*
|
||||
* If a barrier is issued after sending a message which expects a reply, the
|
||||
* behavior is the same as described above. The receipt of a reply message will
|
||||
* not influence when the barrier runs.
|
||||
*
|
||||
* A barrier block can be useful for throttling resource consumption on the
|
||||
* connected side of a connection. For example, if your connection sends many
|
||||
* large messages, you can use a barrier to limit the number of messages that
|
||||
* are inflight at any given time. This can be particularly useful for messages
|
||||
* that contain kernel resources (like file descriptors) which have a system-
|
||||
* wide limit.
|
||||
*
|
||||
* If a barrier is issued on a canceled connection, it will be invoked
|
||||
* immediately. If a connection has been canceled and still has outstanding
|
||||
* barriers, those barriers will be invoked as part of the connection's
|
||||
* unwinding process.
|
||||
*
|
||||
* It is important to note that a barrier block's execution order is not
|
||||
* guaranteed with respect to other blocks that have been scheduled on the
|
||||
* target queue of the connection. Or said differently,
|
||||
* xpc_connection_send_barrier(3) is not equivalent to dispatch_async(3).
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0)
|
||||
XPC_EXPORT XPC_NONNULL_ALL
|
||||
void
|
||||
xpc_connection_send_barrier(xpc_connection_t connection,
|
||||
dispatch_block_t barrier);
|
||||
|
||||
/*!
|
||||
* @function xpc_connection_send_message_with_reply
|
||||
* Sends a message over the connection to the destination service and associates
|
||||
* a handler to be invoked when the remote service sends a reply message.
|
||||
*
|
||||
* @param connection
|
||||
* The connection over which the message shall be sent.
|
||||
*
|
||||
* @param message
|
||||
* The message to send. This must be a dictionary object.
|
||||
*
|
||||
* @param replyq
|
||||
* The GCD queue to which the reply handler will be submitted. This may be a
|
||||
* concurrent queue.
|
||||
*
|
||||
* @param handler
|
||||
* The handler block to invoke when a reply to the message is received from
|
||||
* the connection. If the remote service exits prematurely before the reply was
|
||||
* received, the XPC_ERROR_CONNECTION_INTERRUPTED error will be returned.
|
||||
* If the connection went invalid before the message could be sent, the
|
||||
* XPC_ERROR_CONNECTION_INVALID error will be returned.
|
||||
*
|
||||
* @discussion
|
||||
* If the given GCD queue is a concurrent queue, XPC cannot guarantee that there
|
||||
* will not be multiple reply handlers being invoked concurrently. XPC does not
|
||||
* guarantee any ordering for the invocation of reply handers. So if multiple
|
||||
* messages are waiting for replies and the connection goes invalid, there is no
|
||||
* guarantee that the reply handlers will be invoked in FIFO order. Similarly,
|
||||
* XPC does not guarantee that reply handlers will not run concurrently with
|
||||
* the connection's event handler in the case that the reply queue and the
|
||||
* connection's target queue are the same concurrent queue.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0)
|
||||
XPC_EXPORT XPC_NONNULL1 XPC_NONNULL2 XPC_NONNULL4
|
||||
void
|
||||
xpc_connection_send_message_with_reply(xpc_connection_t connection,
|
||||
xpc_object_t message, dispatch_queue_t replyq, xpc_handler_t handler);
|
||||
|
||||
/*!
|
||||
* @function xpc_connection_send_message_with_reply_sync
|
||||
* Sends a message over the connection and blocks the caller until a reply is
|
||||
* received.
|
||||
*
|
||||
* @param connection
|
||||
* The connection over which the message shall be sent.
|
||||
*
|
||||
* @param message
|
||||
* The message to send. This must be a dictionary object.
|
||||
*
|
||||
* @result
|
||||
* The message that the remote service sent in reply to the original message.
|
||||
* If the remote service exits prematurely before the reply was received, the
|
||||
* XPC_ERROR_CONNECTION_INTERRUPTED error will be returned. If the connection
|
||||
* went invalid before the message could be sent, the
|
||||
* XPC_ERROR_CONNECTION_INVALID error will be returned.
|
||||
*
|
||||
* You are responsible for releasing the returned object.
|
||||
*
|
||||
* @discussion
|
||||
* This API is primarily for transitional purposes. Its implementation is
|
||||
* conceptually equivalent to calling xpc_connection_send_message_with_reply()
|
||||
* and then immediately blocking the calling thread on a semaphore and
|
||||
* signaling the semaphore from the reply block.
|
||||
*
|
||||
* Be judicious about your use of this API. It can block indefinitely, so if you
|
||||
* are using it to implement an API that can be called from the main thread, you
|
||||
* may wish to consider allowing the API to take a queue and callback block so
|
||||
* that results may be delivered asynchronously if possible.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0)
|
||||
XPC_EXPORT XPC_NONNULL_ALL XPC_WARN_RESULT XPC_RETURNS_RETAINED
|
||||
xpc_object_t
|
||||
xpc_connection_send_message_with_reply_sync(xpc_connection_t connection,
|
||||
xpc_object_t message);
|
||||
|
||||
/*!
|
||||
* @function xpc_connection_cancel
|
||||
* Cancels the connection and ensures that its event handler will not fire
|
||||
* again. After this call, any messages that have not yet been sent will be
|
||||
* discarded, and the connection will be unwound. If there are messages that are
|
||||
* awaiting replies, they will have their reply handlers invoked with the
|
||||
* XPC_ERROR_CONNECTION_INVALID error.
|
||||
*
|
||||
* @param connection
|
||||
* The connection object which is to be manipulated.
|
||||
*
|
||||
* @discussion
|
||||
* Cancellation is asynchronous and non-preemptive and therefore this method
|
||||
* will not interrupt the execution of an already-running event handler block.
|
||||
* If the event handler is executing at the time of this call, it will finish,
|
||||
* and then the connection will be canceled, causing a final invocation of the
|
||||
* event handler to be scheduled with the XPC_ERROR_CONNECTION_INVALID error.
|
||||
* After that invocation, there will be no further invocations of the event
|
||||
* handler.
|
||||
*
|
||||
* The XPC runtime guarantees this non-preemptiveness even for concurrent target
|
||||
* queues.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0)
|
||||
XPC_EXPORT XPC_NONNULL_ALL
|
||||
void
|
||||
xpc_connection_cancel(xpc_connection_t connection);
|
||||
|
||||
/*!
|
||||
* @function xpc_connection_get_name
|
||||
* Returns the name of the service with which the connections was created.
|
||||
*
|
||||
* @param connection
|
||||
* The connection object which is to be examined.
|
||||
*
|
||||
* @result
|
||||
* The name of the remote service. If you obtained the connection through an
|
||||
* invocation of another connection's event handler, NULL is returned.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0)
|
||||
XPC_EXPORT XPC_NONNULL_ALL XPC_WARN_RESULT
|
||||
const char *
|
||||
xpc_connection_get_name(xpc_connection_t connection);
|
||||
|
||||
/*!
|
||||
* @function xpc_connection_get_euid
|
||||
* Returns the EUID of the remote peer.
|
||||
*
|
||||
* @param connection
|
||||
* The connection object which is to be examined.
|
||||
*
|
||||
* @result
|
||||
* The EUID of the remote peer at the time the connection was made.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0)
|
||||
XPC_EXPORT XPC_NONNULL_ALL XPC_WARN_RESULT
|
||||
uid_t
|
||||
xpc_connection_get_euid(xpc_connection_t connection);
|
||||
|
||||
/*!
|
||||
* @function xpc_connection_get_egid
|
||||
* Returns the EGID of the remote peer.
|
||||
*
|
||||
* @param connection
|
||||
* The connection object which is to be examined.
|
||||
*
|
||||
* @result
|
||||
* The EGID of the remote peer at the time the connection was made.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0)
|
||||
XPC_EXPORT XPC_NONNULL_ALL XPC_WARN_RESULT
|
||||
gid_t
|
||||
xpc_connection_get_egid(xpc_connection_t connection);
|
||||
|
||||
/*!
|
||||
* @function xpc_connection_get_pid
|
||||
* Returns the PID of the remote peer.
|
||||
*
|
||||
* @param connection
|
||||
* The connection object which is to be examined.
|
||||
*
|
||||
* @result
|
||||
* The PID of the remote peer.
|
||||
*
|
||||
* @discussion
|
||||
* A given PID is not guaranteed to be unique across an entire boot cycle.
|
||||
* Great care should be taken when dealing with this information, as it can go
|
||||
* stale after the connection is established. OS X recycles PIDs, and therefore
|
||||
* another process could spawn and claim the PID before a message is actually
|
||||
* received from the connection.
|
||||
*
|
||||
* XPC will deliver an error to your event handler if the remote process goes
|
||||
* away, but there are no guarantees as to the timing of this notification's
|
||||
* delivery either at the kernel layer or at the XPC layer.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0)
|
||||
XPC_EXPORT XPC_NONNULL_ALL XPC_WARN_RESULT
|
||||
pid_t
|
||||
xpc_connection_get_pid(xpc_connection_t connection);
|
||||
|
||||
/*!
|
||||
* @function xpc_connection_get_asid
|
||||
* Returns the audit session identifier of the remote peer.
|
||||
*
|
||||
* @param connection
|
||||
* The connection object which is to be examined.
|
||||
*
|
||||
* @result
|
||||
* The audit session ID of the remote peer at the time the connection was made.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0)
|
||||
XPC_EXPORT XPC_NONNULL_ALL XPC_WARN_RESULT
|
||||
au_asid_t
|
||||
xpc_connection_get_asid(xpc_connection_t connection);
|
||||
|
||||
/*!
|
||||
* @function xpc_connection_set_context
|
||||
* Sets context on an connection.
|
||||
*
|
||||
* @param connection
|
||||
* The connection which is to be manipulated.
|
||||
*
|
||||
* @param context
|
||||
* The context to associate with the connection.
|
||||
*
|
||||
* @discussion
|
||||
* If you must manage the memory of the context object, you must set a finalizer
|
||||
* to dispose of it. If this method is called on a connection which already has
|
||||
* context associated with it, the finalizer will NOT be invoked. The finalizer
|
||||
* is only invoked when the connection is being deallocated.
|
||||
*
|
||||
* It is recommended that, instead of changing the actual context pointer
|
||||
* associated with the object, you instead change the state of the context
|
||||
* object itself.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0)
|
||||
XPC_EXPORT XPC_NONNULL1
|
||||
void
|
||||
xpc_connection_set_context(xpc_connection_t connection, void *context);
|
||||
|
||||
/*!
|
||||
* @function xpc_connection_get_context
|
||||
* Returns the context associated with the connection.
|
||||
*
|
||||
* @param connection
|
||||
* The connection which is to be examined.
|
||||
*
|
||||
* @result
|
||||
* The context associated with the connection. NULL if there has been no context
|
||||
* associated with the object.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0)
|
||||
XPC_EXPORT XPC_NONNULL_ALL XPC_WARN_RESULT
|
||||
void *
|
||||
xpc_connection_get_context(xpc_connection_t connection);
|
||||
|
||||
/*!
|
||||
* @function xpc_connection_set_finalizer_f
|
||||
* Sets the finalizer for the given connection.
|
||||
*
|
||||
* @param connection
|
||||
* The connection on which to set the finalizer.
|
||||
*
|
||||
* @param finalizer
|
||||
* The function that will be invoked when the connection's retain count has
|
||||
* dropped to zero and is being torn down.
|
||||
*
|
||||
* @discussion
|
||||
* This method disposes of the context value associated with a connection, as
|
||||
* set by {@link xpc_connection_set_context}.
|
||||
*
|
||||
* For many uses of context objects, this API allows for a convenient shorthand
|
||||
* for freeing them. For example, for a context object allocated with malloc(3):
|
||||
*
|
||||
* xpc_connection_set_finalizer_f(object, free);
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0)
|
||||
XPC_EXPORT XPC_NONNULL1
|
||||
void
|
||||
xpc_connection_set_finalizer_f(xpc_connection_t connection,
|
||||
xpc_finalizer_t finalizer);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif // __XPC_CONNECTION_H__
|
23
xpc/debug.h
Normal file
23
xpc/debug.h
Normal file
@ -0,0 +1,23 @@
|
||||
#ifndef __XPC_DEBUG_H__
|
||||
#define __XPC_DEBUG_H__
|
||||
|
||||
/*!
|
||||
* @function xpc_debugger_api_misuse_info
|
||||
* Returns a pointer to a string describing the reason XPC aborted the calling
|
||||
* process. On OS X, this will be the same string present in the "Application
|
||||
* Specific Information" section of the crash report.
|
||||
*
|
||||
* @result
|
||||
* A pointer to the human-readable string describing the reason the caller was
|
||||
* aborted. If XPC was not responsible for the program's termination, NULL will
|
||||
* be returned.
|
||||
*
|
||||
* @discussion
|
||||
* This function is only callable from within a debugger. It is not meant to be
|
||||
* called by the program directly.
|
||||
*/
|
||||
XPC_DEBUGGER_EXCL
|
||||
const char *
|
||||
xpc_debugger_api_misuse_info(void);
|
||||
|
||||
#endif // __XPC_DEBUG_H__
|
22
xpc/endpoint.h
Normal file
22
xpc/endpoint.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef __XPC_ENDPOINT_H__
|
||||
#define __XPC_ENDPOINT_H__
|
||||
|
||||
/*!
|
||||
* @function xpc_endpoint_create
|
||||
* Creates a new endpoint from a connection that is suitable for embedding into
|
||||
* messages.
|
||||
*
|
||||
* @param connection
|
||||
* Only connections obtained through calls to xpc_connection_create*() may be
|
||||
* given to this API. Passing any other type of connection is not supported and
|
||||
* will result in undefined behavior.
|
||||
*
|
||||
* @result
|
||||
* A new endpoint object.
|
||||
*/
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0)
|
||||
XPC_EXPORT XPC_MALLOC XPC_RETURNS_RETAINED XPC_WARN_RESULT XPC_NONNULL1
|
||||
xpc_endpoint_t
|
||||
xpc_endpoint_create(xpc_connection_t connection);
|
||||
|
||||
#endif // __XPC_ENDPOINT_H__
|
24
xpc/launchd.h
Normal file
24
xpc/launchd.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef XPC_LAUNCHD_H_
|
||||
#define XPC_LAUNCHD_H_
|
||||
#include <xpc/xpc.h>
|
||||
|
||||
#define EXNOERROR 0
|
||||
#define EXNOMEM 1
|
||||
#define EXINVAL 2
|
||||
#define EXSRCH 3
|
||||
#define EXMAX EXSRCH
|
||||
|
||||
const char *xpc_strerror(int error);
|
||||
xpc_object_t xpc_copy_entitlement_for_token(const char *, audit_token_t *);
|
||||
int xpc_pipe_routine_reply(xpc_object_t);
|
||||
int xpc_pipe_try_receive(mach_port_t, xpc_object_t *, mach_port_t *,
|
||||
boolean_t (*)(mach_msg_header_t *, mach_msg_header_t *), mach_msg_size_t, int);
|
||||
kern_return_t xpc_call_wakeup(mach_port_t, int);
|
||||
void xpc_dictionary_get_audit_token(xpc_object_t, audit_token_t *);
|
||||
void xpc_dictionary_set_mach_recv(xpc_object_t, const char *, mach_port_t);
|
||||
void xpc_dictionary_set_mach_send(xpc_object_t, const char *, mach_port_t);
|
||||
mach_port_t xpc_dictionary_copy_mach_send(xpc_object_t, const char *);
|
||||
xpc_object_t xpc_copy_entitlements_for_pid(pid_t);
|
||||
xpc_object_t ld2xpc(launch_data_t);
|
||||
|
||||
#endif
|
324
xpc_array.c
Normal file
324
xpc_array.c
Normal file
@ -0,0 +1,324 @@
|
||||
/*
|
||||
* Copyright 2014-2015 iXsystems, Inc.
|
||||
* All rights reserved
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted providing that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <xpc/xpc.h>
|
||||
#include "xpc_internal.h"
|
||||
|
||||
xpc_object_t
|
||||
xpc_array_create(const xpc_object_t *objects, size_t count)
|
||||
{
|
||||
struct xpc_object *xo;
|
||||
size_t i;
|
||||
xpc_u val;
|
||||
|
||||
xo = _xpc_prim_create(_XPC_TYPE_ARRAY, val, 0);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
xpc_array_append_value(xo, objects[i]);
|
||||
|
||||
return (xo);
|
||||
}
|
||||
|
||||
void
|
||||
xpc_array_set_value(xpc_object_t xarray, size_t index, xpc_object_t value)
|
||||
{
|
||||
struct xpc_object *xo, *xotmp, *xotmp2;
|
||||
struct xpc_array_head *arr;
|
||||
size_t i;
|
||||
|
||||
xo = xarray;
|
||||
arr = &xo->xo_array;
|
||||
i = 0;
|
||||
|
||||
if (index == XPC_ARRAY_APPEND)
|
||||
return xpc_array_append_value(xarray, value);
|
||||
|
||||
if (index >= (size_t)xo->xo_size)
|
||||
return;
|
||||
|
||||
TAILQ_FOREACH_SAFE(xotmp, arr, xo_link, xotmp2) {
|
||||
if (i++ == index) {
|
||||
TAILQ_INSERT_AFTER(arr, (struct xpc_object *)value,
|
||||
xotmp, xo_link);
|
||||
TAILQ_REMOVE(arr, xotmp, xo_link);
|
||||
xpc_retain(value);
|
||||
free(xotmp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
xpc_array_append_value(xpc_object_t xarray, xpc_object_t value)
|
||||
{
|
||||
struct xpc_object *xo;
|
||||
struct xpc_array_head *arr;
|
||||
|
||||
xo = xarray;
|
||||
arr = &xo->xo_array;
|
||||
|
||||
TAILQ_INSERT_TAIL(arr, (struct xpc_object *)value, xo_link);
|
||||
xpc_retain(value);
|
||||
}
|
||||
|
||||
|
||||
xpc_object_t
|
||||
xpc_array_get_value(xpc_object_t xarray, size_t index)
|
||||
{
|
||||
struct xpc_object *xo, *xotmp;
|
||||
struct xpc_array_head *arr;
|
||||
size_t i;
|
||||
|
||||
xo = xarray;
|
||||
arr = &xo->xo_array;
|
||||
i = 0;
|
||||
|
||||
if (index > xo->xo_size)
|
||||
return (NULL);
|
||||
|
||||
TAILQ_FOREACH(xotmp, arr, xo_link) {
|
||||
if (i++ == index)
|
||||
return (xotmp);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
size_t
|
||||
xpc_array_get_count(xpc_object_t xarray)
|
||||
{
|
||||
struct xpc_object *xo;
|
||||
|
||||
xo = xarray;
|
||||
return (xo->xo_size);
|
||||
}
|
||||
|
||||
void
|
||||
xpc_array_set_bool(xpc_object_t xarray, size_t index, bool value)
|
||||
{
|
||||
struct xpc_object *xo, *xotmp;
|
||||
|
||||
xo = xarray;
|
||||
xotmp = xpc_bool_create(value);
|
||||
return (xpc_array_set_value(xarray, index, xotmp));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
xpc_array_set_int64(xpc_object_t xarray, size_t index, int64_t value)
|
||||
{
|
||||
struct xpc_object *xo, *xotmp;
|
||||
|
||||
xo = xarray;
|
||||
xotmp = xpc_int64_create(value);
|
||||
return (xpc_array_set_value(xarray, index, xotmp));
|
||||
}
|
||||
|
||||
void
|
||||
xpc_array_set_uint64(xpc_object_t xarray, size_t index, uint64_t value)
|
||||
{
|
||||
struct xpc_object *xo, *xotmp;
|
||||
|
||||
xo = xarray;
|
||||
xotmp = xpc_uint64_create(value);
|
||||
return (xpc_array_set_value(xarray, index, xotmp));
|
||||
}
|
||||
|
||||
void
|
||||
xpc_array_set_double(xpc_object_t xarray, size_t index, double value)
|
||||
{
|
||||
struct xpc_object *xo, *xotmp;
|
||||
|
||||
xo = xarray;
|
||||
xotmp = xpc_double_create(value);
|
||||
return (xpc_array_set_value(xarray, index, xotmp));
|
||||
}
|
||||
|
||||
void
|
||||
xpc_array_set_date(xpc_object_t xarray, size_t index, int64_t value)
|
||||
{
|
||||
struct xpc_object *xo, *xotmp;
|
||||
|
||||
xo = xarray;
|
||||
xotmp = xpc_date_create(value);
|
||||
return (xpc_array_set_value(xarray, index, xotmp));
|
||||
}
|
||||
|
||||
void
|
||||
xpc_array_set_data(xpc_object_t xarray, size_t index, const void *data,
|
||||
size_t length)
|
||||
{
|
||||
struct xpc_object *xo, *xotmp;
|
||||
|
||||
xo = xarray;
|
||||
xotmp = xpc_data_create(data, length);
|
||||
return (xpc_array_set_value(xarray, index, xotmp));
|
||||
}
|
||||
|
||||
void
|
||||
xpc_array_set_string(xpc_object_t xarray, size_t index, const char *string)
|
||||
{
|
||||
struct xpc_object *xo, *xotmp;
|
||||
|
||||
xo = xarray;
|
||||
xotmp = xpc_string_create(string);
|
||||
return (xpc_array_set_value(xarray, index, xotmp));
|
||||
}
|
||||
|
||||
void
|
||||
xpc_array_set_uuid(xpc_object_t xarray, size_t index, const uuid_t value)
|
||||
{
|
||||
struct xpc_object *xo, *xotmp;
|
||||
|
||||
xo = xarray;
|
||||
xotmp = xpc_uuid_create(value);
|
||||
return (xpc_array_set_value(xarray, index, xotmp));
|
||||
}
|
||||
|
||||
void
|
||||
xpc_array_set_fd(xpc_object_t xarray, size_t index, int value)
|
||||
{
|
||||
struct xpc_object *xo, *xotmp;
|
||||
|
||||
xo = xarray;
|
||||
//xotmp = xpc_fd_create(value);
|
||||
return (xpc_array_set_value(xarray, index, xotmp));
|
||||
}
|
||||
|
||||
void
|
||||
xpc_array_set_connection(xpc_object_t xarray, size_t index,
|
||||
xpc_connection_t value)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool
|
||||
xpc_array_get_bool(xpc_object_t xarray, size_t index)
|
||||
{
|
||||
struct xpc_object *xotmp;
|
||||
|
||||
xotmp = xpc_array_get_value(xarray, index);
|
||||
return (xpc_bool_get_value(xotmp));
|
||||
}
|
||||
|
||||
int64_t
|
||||
xpc_array_get_int64(xpc_object_t xarray, size_t index)
|
||||
{
|
||||
struct xpc_object *xotmp;
|
||||
|
||||
xotmp = xpc_array_get_value(xarray, index);
|
||||
return (xpc_int64_get_value(xotmp));
|
||||
}
|
||||
|
||||
uint64_t
|
||||
xpc_array_get_uint64(xpc_object_t xarray, size_t index)
|
||||
{
|
||||
struct xpc_object *xotmp;
|
||||
|
||||
xotmp = xpc_array_get_value(xarray, index);
|
||||
return (xpc_uint64_get_value(xotmp));
|
||||
}
|
||||
|
||||
double
|
||||
xpc_array_get_double(xpc_object_t xarray, size_t index)
|
||||
{
|
||||
struct xpc_object *xotmp;
|
||||
|
||||
xotmp = xpc_array_get_value(xarray, index);
|
||||
return (xpc_double_get_value(xotmp));
|
||||
}
|
||||
|
||||
int64_t
|
||||
xpc_array_get_date(xpc_object_t xarray, size_t index)
|
||||
{
|
||||
struct xpc_object *xotmp;
|
||||
|
||||
xotmp = xpc_array_get_value(xarray, index);
|
||||
return (xpc_date_get_value(xotmp));
|
||||
}
|
||||
|
||||
const void *
|
||||
xpc_array_get_data(xpc_object_t xarray, size_t index, size_t *length)
|
||||
{
|
||||
struct xpc_object *xotmp;
|
||||
|
||||
xotmp = xpc_array_get_value(xarray, index);
|
||||
*length = xpc_data_get_length(xotmp);
|
||||
return (xpc_data_get_bytes_ptr(xotmp));
|
||||
}
|
||||
|
||||
const uint8_t *
|
||||
xpc_array_get_uuid(xpc_object_t xarray, size_t index)
|
||||
{
|
||||
struct xpc_object *xotmp;
|
||||
|
||||
xotmp = xpc_array_get_value(xarray, index);
|
||||
return (xpc_uuid_get_bytes(xotmp));
|
||||
}
|
||||
|
||||
const char *
|
||||
xpc_array_get_string(xpc_object_t xarray, size_t index)
|
||||
{
|
||||
struct xpc_object *xotmp;
|
||||
|
||||
xotmp = xpc_array_get_value(xarray, index);
|
||||
return (xpc_string_get_string_ptr(xotmp));
|
||||
}
|
||||
|
||||
int
|
||||
xpc_array_dup_fd(xpc_object_t array, size_t index)
|
||||
{
|
||||
/* XXX */
|
||||
return (-1);
|
||||
}
|
||||
|
||||
xpc_connection_t
|
||||
xpc_array_get_connection(xpc_object_t array, size_t index)
|
||||
{
|
||||
/* XXX */
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
bool
|
||||
xpc_array_apply(xpc_object_t xarray, xpc_array_applier_t applier)
|
||||
{
|
||||
struct xpc_object *xo, *xotmp;
|
||||
struct xpc_array_head *arr;
|
||||
size_t i;
|
||||
|
||||
i = 0;
|
||||
xo = xarray;
|
||||
arr = &xo->xo_array;
|
||||
|
||||
TAILQ_FOREACH(xotmp, arr, xo_link) {
|
||||
if (!applier(i++, xotmp))
|
||||
return (false);
|
||||
}
|
||||
|
||||
return (true);
|
||||
}
|
448
xpc_connection.c
Normal file
448
xpc_connection.c
Normal file
@ -0,0 +1,448 @@
|
||||
/*
|
||||
* Copyright 2014-2015 iXsystems, Inc.
|
||||
* All rights reserved
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted providing that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <xpc/xpc.h>
|
||||
#include <machine/atomic.h>
|
||||
#include <Block.h>
|
||||
#include "xpc_internal.h"
|
||||
|
||||
#define XPC_CONNECTION_NEXT_ID(conn) (atomic_fetchadd_long(&conn->xc_last_id, 1))
|
||||
|
||||
static void xpc_connection_recv_message();
|
||||
static void xpc_send(xpc_connection_t xconn, xpc_object_t message, uint64_t id);
|
||||
|
||||
xpc_connection_t
|
||||
xpc_connection_create(const char *name, dispatch_queue_t targetq)
|
||||
{
|
||||
char *qname;
|
||||
struct xpc_transport *transport = xpc_get_transport();
|
||||
struct xpc_connection *conn;
|
||||
|
||||
if ((conn = malloc(sizeof(struct xpc_connection))) == NULL) {
|
||||
errno = ENOMEM;
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
memset(conn, 0, sizeof(struct xpc_connection));
|
||||
conn->xc_last_id = 1;
|
||||
TAILQ_INIT(&conn->xc_peers);
|
||||
TAILQ_INIT(&conn->xc_pending);
|
||||
|
||||
/* Create send queue */
|
||||
asprintf(&qname, "com.ixsystems.xpc.connection.sendq.%p", conn);
|
||||
conn->xc_send_queue = dispatch_queue_create(qname, NULL);
|
||||
|
||||
/* Create recv queue */
|
||||
asprintf(&qname, "com.ixsystems.xpc.connection.recvq.%p", conn);
|
||||
conn->xc_recv_queue = dispatch_queue_create(qname, NULL);
|
||||
|
||||
/* Create target queue */
|
||||
conn->xc_target_queue = targetq ? targetq : dispatch_get_main_queue();
|
||||
|
||||
/* Receive queue is initially suspended */
|
||||
dispatch_suspend(conn->xc_recv_queue);
|
||||
|
||||
/* Create local port */
|
||||
if (transport->xt_listen(NULL, &conn->xc_local_port) != 0) {
|
||||
debugf("Cannot create local port: %s", strerror(errno));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return ((xpc_connection_t)conn);
|
||||
}
|
||||
|
||||
xpc_connection_t
|
||||
xpc_connection_create_mach_service(const char *name, dispatch_queue_t targetq,
|
||||
uint64_t flags)
|
||||
{
|
||||
struct xpc_transport *transport = xpc_get_transport();
|
||||
struct xpc_connection *conn;
|
||||
|
||||
conn = (struct xpc_connection *)xpc_connection_create(name, targetq);
|
||||
if (conn == NULL)
|
||||
return (NULL);
|
||||
|
||||
conn->xc_flags = flags;
|
||||
|
||||
if (flags & XPC_CONNECTION_MACH_SERVICE_LISTENER) {
|
||||
transport->xt_release(conn->xc_local_port);
|
||||
|
||||
if (transport->xt_listen(name, &conn->xc_local_port) != 0) {
|
||||
debugf("Cannot create local port: %s", strerror(errno));
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (transport->xt_lookup(name, &conn->xc_remote_port) != 0) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return ((xpc_connection_t)conn);
|
||||
}
|
||||
|
||||
xpc_connection_t
|
||||
xpc_connection_create_from_endpoint(xpc_endpoint_t endpoint)
|
||||
{
|
||||
struct xpc_connection *conn;
|
||||
|
||||
conn = (struct xpc_connection *)xpc_connection_create("anonymous", NULL);
|
||||
if (conn == NULL)
|
||||
return (NULL);
|
||||
|
||||
conn->xc_remote_port = (xpc_port_t)endpoint;
|
||||
return ((xpc_connection_t)conn);
|
||||
}
|
||||
|
||||
void
|
||||
xpc_connection_set_target_queue(xpc_connection_t xconn,
|
||||
dispatch_queue_t targetq)
|
||||
{
|
||||
struct xpc_connection *conn;
|
||||
|
||||
debugf("connection=%p", xconn);
|
||||
conn = (struct xpc_connection *)xconn;
|
||||
conn->xc_target_queue = targetq;
|
||||
}
|
||||
|
||||
void
|
||||
xpc_connection_set_event_handler(xpc_connection_t xconn,
|
||||
xpc_handler_t handler)
|
||||
{
|
||||
struct xpc_connection *conn;
|
||||
|
||||
debugf("connection=%p", xconn);
|
||||
conn = (struct xpc_connection *)xconn;
|
||||
conn->xc_handler = (xpc_handler_t)Block_copy(handler);
|
||||
}
|
||||
|
||||
void
|
||||
xpc_connection_suspend(xpc_connection_t xconn)
|
||||
{
|
||||
struct xpc_connection *conn;
|
||||
|
||||
conn = (struct xpc_connection *)xconn;
|
||||
dispatch_suspend(conn->xc_recv_source);
|
||||
}
|
||||
|
||||
void
|
||||
xpc_connection_resume(xpc_connection_t xconn)
|
||||
{
|
||||
struct xpc_transport *transport = xpc_get_transport();
|
||||
struct xpc_connection *conn;
|
||||
|
||||
debugf("connection=%p", xconn);
|
||||
conn = (struct xpc_connection *)xconn;
|
||||
|
||||
/* Create dispatch source for top-level connection */
|
||||
if (conn->xc_parent == NULL) {
|
||||
conn->xc_recv_source = transport->xt_create_source(
|
||||
conn->xc_local_port, conn->xc_recv_queue);
|
||||
dispatch_set_context(conn->xc_recv_source, conn);
|
||||
dispatch_source_set_event_handler_f(conn->xc_recv_source,
|
||||
xpc_connection_recv_message);
|
||||
dispatch_resume(conn->xc_recv_source);
|
||||
}
|
||||
|
||||
dispatch_resume(conn->xc_recv_queue);
|
||||
}
|
||||
|
||||
void
|
||||
xpc_connection_send_message(xpc_connection_t xconn,
|
||||
xpc_object_t message)
|
||||
{
|
||||
struct xpc_connection *conn;
|
||||
uint64_t id;
|
||||
|
||||
conn = (struct xpc_connection *)xconn;
|
||||
id = xpc_dictionary_get_uint64(message, XPC_SEQID);
|
||||
|
||||
if (id == 0)
|
||||
id = XPC_CONNECTION_NEXT_ID(conn);
|
||||
|
||||
dispatch_async(conn->xc_send_queue, ^{
|
||||
xpc_send(xconn, message, id);
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
xpc_connection_send_message_with_reply(xpc_connection_t xconn,
|
||||
xpc_object_t message, dispatch_queue_t targetq, xpc_handler_t handler)
|
||||
{
|
||||
struct xpc_connection *conn;
|
||||
struct xpc_pending_call *call;
|
||||
|
||||
conn = (struct xpc_connection *)xconn;
|
||||
call = malloc(sizeof(struct xpc_pending_call));
|
||||
call->xp_id = XPC_CONNECTION_NEXT_ID(conn);
|
||||
call->xp_handler = handler;
|
||||
call->xp_queue = targetq;
|
||||
TAILQ_INSERT_TAIL(&conn->xc_pending, call, xp_link);
|
||||
|
||||
dispatch_async(conn->xc_send_queue, ^{
|
||||
xpc_send(xconn, message, call->xp_id);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
xpc_object_t
|
||||
xpc_connection_send_message_with_reply_sync(xpc_connection_t conn,
|
||||
xpc_object_t message)
|
||||
{
|
||||
__block xpc_object_t result;
|
||||
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
|
||||
|
||||
xpc_connection_send_message_with_reply(conn, message, NULL,
|
||||
^(xpc_object_t o) {
|
||||
result = o;
|
||||
dispatch_semaphore_signal(sem);
|
||||
});
|
||||
|
||||
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
|
||||
return (result);
|
||||
}
|
||||
|
||||
void
|
||||
xpc_connection_send_barrier(xpc_connection_t xconn, dispatch_block_t barrier)
|
||||
{
|
||||
struct xpc_connection *conn;
|
||||
|
||||
conn = (struct xpc_connection *)xconn;
|
||||
dispatch_sync(conn->xc_send_queue, barrier);
|
||||
}
|
||||
|
||||
void
|
||||
xpc_connection_cancel(xpc_connection_t connection)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
const char *
|
||||
xpc_connection_get_name(xpc_connection_t connection)
|
||||
{
|
||||
|
||||
return ("unknown"); /* ??? */
|
||||
}
|
||||
|
||||
uid_t
|
||||
xpc_connection_get_euid(xpc_connection_t xconn)
|
||||
{
|
||||
struct xpc_connection *conn;
|
||||
|
||||
conn = (struct xpc_connection *)xconn;
|
||||
return (conn->xc_creds.xc_remote_euid);
|
||||
}
|
||||
|
||||
gid_t
|
||||
xpc_connection_get_guid(xpc_connection_t xconn)
|
||||
{
|
||||
struct xpc_connection *conn;
|
||||
|
||||
conn = (struct xpc_connection *)xconn;
|
||||
return (conn->xc_creds.xc_remote_guid);
|
||||
}
|
||||
|
||||
pid_t
|
||||
xpc_connection_get_pid(xpc_connection_t xconn)
|
||||
{
|
||||
struct xpc_connection *conn;
|
||||
|
||||
conn = (struct xpc_connection *)xconn;
|
||||
return (conn->xc_creds.xc_remote_pid);
|
||||
}
|
||||
|
||||
#ifdef MACH
|
||||
au_asid_t
|
||||
xpc_connection_get_asid(xpc_connection_t xconn)
|
||||
{
|
||||
struct xpc_connection *conn;
|
||||
|
||||
conn = xconn;
|
||||
return (conn->xc_creds.xc_remote_asid);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
xpc_connection_set_context(xpc_connection_t xconn, void *ctx)
|
||||
{
|
||||
struct xpc_connection *conn;
|
||||
|
||||
conn = (struct xpc_connection *)xconn;
|
||||
conn->xc_context = ctx;
|
||||
}
|
||||
|
||||
void *
|
||||
xpc_connection_get_context(xpc_connection_t xconn)
|
||||
{
|
||||
struct xpc_connection *conn;
|
||||
|
||||
conn = (struct xpc_connection *)xconn;
|
||||
return (conn->xc_context);
|
||||
}
|
||||
|
||||
void
|
||||
xpc_connection_set_finalizer_f(xpc_connection_t connection,
|
||||
xpc_finalizer_t finalizer)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
xpc_endpoint_t
|
||||
xpc_endpoint_create(xpc_connection_t connection)
|
||||
{
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
void
|
||||
xpc_main(xpc_connection_handler_t handler)
|
||||
{
|
||||
|
||||
dispatch_main();
|
||||
}
|
||||
|
||||
void
|
||||
xpc_transaction_begin(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
xpc_transaction_end(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
xpc_send(xpc_connection_t xconn, xpc_object_t message, uint64_t id)
|
||||
{
|
||||
struct xpc_connection *conn;
|
||||
int err;
|
||||
|
||||
debugf("connection=%p, message=%p, id=%lu", xconn, message, id);
|
||||
|
||||
conn = (struct xpc_connection *)xconn;
|
||||
if (xpc_pipe_send(message, id, conn->xc_local_port,
|
||||
conn->xc_remote_port) != 0)
|
||||
debugf("send failed: %s", strerror(errno));
|
||||
}
|
||||
|
||||
#ifdef MACH
|
||||
static void
|
||||
xpc_connection_set_credentials(struct xpc_connection *conn, audit_token_t *tok)
|
||||
{
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
pid_t pid;
|
||||
au_asid_t asid;
|
||||
|
||||
if (tok == NULL)
|
||||
return;
|
||||
|
||||
audit_token_to_au32(*tok, NULL, &uid, &gid, NULL, NULL, &pid, &asid,
|
||||
NULL);
|
||||
|
||||
conn->xc_creds.xc_remote_euid = uid;
|
||||
conn->xc_creds.xc_remote_guid = gid;
|
||||
conn->xc_creds.xc_remote_pid = pid;
|
||||
conn->xc_creds.xc_remote_asid = asid;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
xpc_connection_recv_message(void *context)
|
||||
{
|
||||
struct xpc_transport *transport = xpc_get_transport();
|
||||
struct xpc_pending_call *call;
|
||||
struct xpc_connection *conn, *peer;
|
||||
struct xpc_credentials creds;
|
||||
xpc_object_t result;
|
||||
xpc_port_t remote;
|
||||
uint64_t id;
|
||||
int err;
|
||||
|
||||
debugf("connection=%p", context);
|
||||
|
||||
conn = context;
|
||||
if (xpc_pipe_receive(conn->xc_local_port, &remote, &result, &id,
|
||||
&creds) != 0)
|
||||
return;
|
||||
|
||||
debugf("message=%p, id=%lu, remote=%s", result, id,
|
||||
transport->xt_port_to_string(remote));
|
||||
|
||||
if (conn->xc_flags & XPC_CONNECTION_MACH_SERVICE_LISTENER) {
|
||||
TAILQ_FOREACH(peer, &conn->xc_peers, xc_link) {
|
||||
if (transport->xt_port_compare(remote,
|
||||
peer->xc_remote_port) == 0) {
|
||||
dispatch_async(peer->xc_target_queue, ^{
|
||||
peer->xc_handler(result);
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
debugf("new peer on port %s", transport->xt_port_to_string(remote));
|
||||
|
||||
/* New peer */
|
||||
peer = (struct xpc_connection *)xpc_connection_create(NULL, NULL);
|
||||
peer->xc_parent = conn;
|
||||
peer->xc_local_port = conn->xc_local_port;
|
||||
peer->xc_remote_port = remote;
|
||||
peer->xc_creds = creds;
|
||||
|
||||
TAILQ_INSERT_TAIL(&conn->xc_peers, peer, xc_link);
|
||||
|
||||
dispatch_async(conn->xc_target_queue, ^{
|
||||
conn->xc_handler(peer);
|
||||
});
|
||||
|
||||
dispatch_async(peer->xc_target_queue, ^{
|
||||
peer->xc_handler(result);
|
||||
});
|
||||
|
||||
} else {
|
||||
conn->xc_creds = creds;
|
||||
|
||||
TAILQ_FOREACH(call, &conn->xc_pending, xp_link) {
|
||||
if (call->xp_id == id) {
|
||||
dispatch_async(conn->xc_target_queue, ^{
|
||||
call->xp_handler(result);
|
||||
TAILQ_REMOVE(&conn->xc_pending, call,
|
||||
xp_link);
|
||||
free(call);
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (conn->xc_handler) {
|
||||
dispatch_async(conn->xc_target_queue, ^{
|
||||
conn->xc_handler(result);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
378
xpc_dictionary.c
Normal file
378
xpc_dictionary.c
Normal file
@ -0,0 +1,378 @@
|
||||
/*
|
||||
* Copyright 2014-2015 iXsystems, Inc.
|
||||
* All rights reserved
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted providing that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include "xpc/xpc.h"
|
||||
#include "xpc_internal.h"
|
||||
#include "mpack.h"
|
||||
|
||||
#define NVLIST_XPC_TYPE "__XPC_TYPE"
|
||||
|
||||
struct xpc_object *
|
||||
mpack2xpc(const mpack_node_t node)
|
||||
{
|
||||
xpc_object_t xotmp;
|
||||
size_t i;
|
||||
xpc_u val;
|
||||
|
||||
switch (mpack_node_type(node)) {
|
||||
case mpack_type_nil:
|
||||
xotmp = xpc_null_create();
|
||||
break;
|
||||
|
||||
case mpack_type_int:
|
||||
val.i = mpack_node_i64(node);
|
||||
xotmp = xpc_int64_create(val.i);
|
||||
break;
|
||||
|
||||
case mpack_type_uint:
|
||||
val.ui = mpack_node_u64(node);
|
||||
xotmp = xpc_uint64_create(val.ui);
|
||||
break;
|
||||
|
||||
case mpack_type_bool:
|
||||
val.b = mpack_node_bool(node);
|
||||
xotmp = xpc_bool_create(val.b);
|
||||
break;
|
||||
|
||||
case mpack_type_double:
|
||||
val.d = mpack_node_double(node);
|
||||
xotmp = xpc_double_create(val.d);
|
||||
break;
|
||||
|
||||
case mpack_type_str:
|
||||
val.str = mpack_node_cstr_alloc(node, 65536);
|
||||
xotmp = xpc_string_create(val.str);
|
||||
break;
|
||||
|
||||
case mpack_type_bin:
|
||||
break;
|
||||
|
||||
case mpack_type_array:
|
||||
xotmp = xpc_array_create(NULL, 0);
|
||||
for (i = 0; i < mpack_node_array_length(node); i++) {
|
||||
xpc_object_t item = mpack2xpc(
|
||||
mpack_node_array_at(node, i));
|
||||
xpc_array_append_value(item, xotmp);
|
||||
}
|
||||
break;
|
||||
|
||||
case mpack_type_map:
|
||||
xotmp = xpc_dictionary_create(NULL, NULL, 0);
|
||||
for (i = 0; i < mpack_node_map_count(node); i++) {
|
||||
char *key = mpack_node_cstr_alloc(
|
||||
mpack_node_map_key_at(node, i), 1024);
|
||||
xpc_object_t value = mpack2xpc(
|
||||
mpack_node_map_value_at(node, i));
|
||||
xpc_dictionary_set_value(xotmp, key, value);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
xotmp = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
return (xotmp);
|
||||
}
|
||||
|
||||
void
|
||||
xpc2mpack(mpack_writer_t *writer, xpc_object_t obj)
|
||||
{
|
||||
struct xpc_object *xotmp = obj;
|
||||
|
||||
switch (xotmp->xo_xpc_type) {
|
||||
case _XPC_TYPE_DICTIONARY:
|
||||
mpack_start_map(writer, xpc_dictionary_get_count(obj));
|
||||
xpc_dictionary_apply(obj, ^(const char *k, xpc_object_t v) {
|
||||
mpack_write_cstr(writer, k);
|
||||
xpc2mpack(writer, v);
|
||||
return ((bool)true);
|
||||
});
|
||||
mpack_finish_map(writer);
|
||||
break;
|
||||
|
||||
case _XPC_TYPE_ARRAY:
|
||||
mpack_start_array(writer, xpc_array_get_count(obj));
|
||||
xpc_array_apply(obj, ^(size_t index, xpc_object_t v) {
|
||||
xpc2mpack(writer, v);
|
||||
return ((bool)true);
|
||||
});
|
||||
mpack_finish_map(writer);
|
||||
break;
|
||||
|
||||
case _XPC_TYPE_NULL:
|
||||
mpack_write_nil(writer);
|
||||
break;
|
||||
|
||||
case _XPC_TYPE_BOOL:
|
||||
mpack_write_bool(writer, xpc_bool_get_value(obj));
|
||||
break;
|
||||
|
||||
case _XPC_TYPE_INT64:
|
||||
mpack_write_i64(writer, xpc_int64_get_value(obj));
|
||||
break;
|
||||
|
||||
case _XPC_TYPE_DOUBLE:
|
||||
mpack_write_double(writer, xpc_double_get_value(obj));
|
||||
|
||||
case _XPC_TYPE_UINT64:
|
||||
mpack_write_u64(writer, xpc_uint64_get_value(obj));
|
||||
break;
|
||||
|
||||
case _XPC_TYPE_STRING:
|
||||
mpack_write_cstr(writer, xpc_string_get_string_ptr(obj));
|
||||
break;
|
||||
|
||||
case _XPC_TYPE_UUID:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
xpc_object_t
|
||||
xpc_dictionary_create(const char * const *keys, const xpc_object_t *values,
|
||||
size_t count)
|
||||
{
|
||||
struct xpc_object *xo;
|
||||
size_t i;
|
||||
xpc_u val;
|
||||
|
||||
xo = _xpc_prim_create(_XPC_TYPE_DICTIONARY, val, count);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
xpc_dictionary_set_value(xo, keys[i], values[i]);
|
||||
|
||||
return (xo);
|
||||
}
|
||||
|
||||
xpc_object_t
|
||||
xpc_dictionary_create_reply(xpc_object_t original)
|
||||
{
|
||||
struct xpc_object *xo, *xo_orig;
|
||||
xpc_u val;
|
||||
|
||||
xo_orig = original;
|
||||
if ((xo_orig->xo_flags & _XPC_FROM_WIRE) == 0)
|
||||
return (NULL);
|
||||
|
||||
return xpc_dictionary_create(NULL, NULL, 0);
|
||||
}
|
||||
|
||||
#ifdef MACH
|
||||
void
|
||||
xpc_dictionary_get_audit_token(xpc_object_t xdict, audit_token_t *token)
|
||||
{
|
||||
struct xpc_object *xo;
|
||||
|
||||
xo = xdict;
|
||||
if (xo->xo_audit_token != NULL)
|
||||
memcpy(token, xo->xo_audit_token, sizeof(*token));
|
||||
}
|
||||
|
||||
void
|
||||
xpc_dictionary_set_mach_recv(xpc_object_t xdict, const char *key,
|
||||
mach_port_t port)
|
||||
{
|
||||
struct xpc_object *xo = xdict;
|
||||
struct xpc_object *xotmp;
|
||||
xpc_u val;
|
||||
|
||||
val.port = port;
|
||||
xotmp = _xpc_prim_create(_XPC_TYPE_ENDPOINT, val, 0);
|
||||
|
||||
xpc_dictionary_set_value(xdict, key, xotmp);
|
||||
}
|
||||
|
||||
void
|
||||
xpc_dictionary_set_mach_send(xpc_object_t xdict, const char *key,
|
||||
mach_port_t port)
|
||||
{
|
||||
struct xpc_object *xotmp;
|
||||
xpc_u val;
|
||||
|
||||
val.port = port;
|
||||
xotmp = _xpc_prim_create(_XPC_TYPE_ENDPOINT, val, 0);
|
||||
|
||||
xpc_dictionary_set_value(xdict, key, xotmp);
|
||||
}
|
||||
|
||||
mach_port_t
|
||||
xpc_dictionary_copy_mach_send(xpc_object_t xdict, const char *key)
|
||||
{
|
||||
struct xpc_object *xo;
|
||||
const struct xpc_object *xotmp;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
xpc_dictionary_set_value(xpc_object_t xdict, const char *key,
|
||||
xpc_object_t value)
|
||||
{
|
||||
struct xpc_object *xo, *xotmp;
|
||||
struct xpc_dict_head *head;
|
||||
struct xpc_dict_pair *pair;
|
||||
|
||||
xo = xdict;
|
||||
head = &xo->xo_dict;
|
||||
|
||||
TAILQ_FOREACH(pair, head, xo_link) {
|
||||
if (!strcmp(pair->key, key)) {
|
||||
pair->value = value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
xo->xo_size++;
|
||||
pair = malloc(sizeof(struct xpc_dict_pair));
|
||||
pair->key = key;
|
||||
pair->value = value;
|
||||
TAILQ_INSERT_TAIL(&xo->xo_dict, pair, xo_link);
|
||||
xpc_retain(value);
|
||||
}
|
||||
|
||||
xpc_object_t
|
||||
xpc_dictionary_get_value(xpc_object_t xdict, const char *key)
|
||||
{
|
||||
struct xpc_object *xo;
|
||||
struct xpc_dict_head *head;
|
||||
struct xpc_dict_pair *pair;
|
||||
|
||||
xo = xdict;
|
||||
head = &xo->xo_dict;
|
||||
|
||||
TAILQ_FOREACH(pair, head, xo_link) {
|
||||
if (!strcmp(pair->key, key))
|
||||
return (pair->value);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
size_t
|
||||
xpc_dictionary_get_count(xpc_object_t xdict)
|
||||
{
|
||||
struct xpc_object *xo;
|
||||
|
||||
xo = xdict;
|
||||
return (xo->xo_size);
|
||||
}
|
||||
|
||||
void
|
||||
xpc_dictionary_set_bool(xpc_object_t xdict, const char *key, bool value)
|
||||
{;
|
||||
struct xpc_object *xo, *xotmp;
|
||||
|
||||
xo = xdict;
|
||||
xotmp = xpc_bool_create(value);
|
||||
xpc_dictionary_set_value(xdict, key, xotmp);
|
||||
}
|
||||
|
||||
void
|
||||
xpc_dictionary_set_int64(xpc_object_t xdict, const char *key, int64_t value)
|
||||
{
|
||||
struct xpc_object *xo, *xotmp;
|
||||
|
||||
xo = xdict;
|
||||
xotmp = xpc_int64_create(value);
|
||||
xpc_dictionary_set_value(xdict, key, xotmp);
|
||||
}
|
||||
|
||||
void
|
||||
xpc_dictionary_set_uint64(xpc_object_t xdict, const char *key, uint64_t value)
|
||||
{
|
||||
struct xpc_object *xo, *xotmp;
|
||||
|
||||
xo = xdict;
|
||||
xotmp = xpc_uint64_create(value);
|
||||
xpc_dictionary_set_value(xdict, key, xotmp);
|
||||
}
|
||||
|
||||
void
|
||||
xpc_dictionary_set_string(xpc_object_t xdict, const char *key,
|
||||
const char *value)
|
||||
{
|
||||
struct xpc_object *xo, *xotmp;
|
||||
|
||||
xo = xdict;
|
||||
xotmp = xpc_string_create(value);
|
||||
xpc_dictionary_set_value(xdict, key, xotmp);
|
||||
}
|
||||
|
||||
bool
|
||||
xpc_dictionary_get_bool(xpc_object_t xdict, const char *key)
|
||||
{
|
||||
xpc_object_t xo;
|
||||
|
||||
xo = xpc_dictionary_get_value(xdict, key);
|
||||
return (xpc_bool_get_value(xo));
|
||||
}
|
||||
|
||||
int64_t
|
||||
xpc_dictionary_get_int64(xpc_object_t xdict, const char *key)
|
||||
{
|
||||
xpc_object_t xo;
|
||||
|
||||
xo = xpc_dictionary_get_value(xdict, key);
|
||||
return (xpc_int64_get_value(xo));
|
||||
}
|
||||
|
||||
uint64_t
|
||||
xpc_dictionary_get_uint64(xpc_object_t xdict, const char *key)
|
||||
{
|
||||
xpc_object_t xo;
|
||||
|
||||
xo = xpc_dictionary_get_value(xdict, key);
|
||||
return (xpc_uint64_get_value(xo));
|
||||
}
|
||||
|
||||
const char *
|
||||
xpc_dictionary_get_string(xpc_object_t xdict, const char *key)
|
||||
{
|
||||
xpc_object_t xo;
|
||||
|
||||
xo = xpc_dictionary_get_value(xdict, key);
|
||||
return (xpc_string_get_string_ptr(xo));
|
||||
}
|
||||
|
||||
bool
|
||||
xpc_dictionary_apply(xpc_object_t xdict, xpc_dictionary_applier_t applier)
|
||||
{
|
||||
struct xpc_object *xo, *xotmp;
|
||||
struct xpc_dict_head *head;
|
||||
struct xpc_dict_pair *pair;
|
||||
|
||||
xo = xdict;
|
||||
head = &xo->xo_dict;
|
||||
|
||||
TAILQ_FOREACH(pair, head, xo_link) {
|
||||
if (!applier(pair->key, pair->value))
|
||||
return (false);
|
||||
}
|
||||
|
||||
return (true);
|
||||
}
|
210
xpc_internal.h
Normal file
210
xpc_internal.h
Normal file
@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Copyright 2014-2015 iXsystems, Inc.
|
||||
* All rights reserved
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted providing that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LIBXPC_XPC_INTERNAL_H
|
||||
#define _LIBXPC_XPC_INTERNAL_H
|
||||
|
||||
#include <sys/queue.h>
|
||||
#include <sys/uio.h>
|
||||
#include "mpack.h"
|
||||
|
||||
#define debugf(...) \
|
||||
do { \
|
||||
fprintf(stderr, "%s: ", __func__); \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
fprintf(stderr, "\n"); \
|
||||
} while(0);
|
||||
|
||||
#define _XPC_TYPE_INVALID 0
|
||||
#define _XPC_TYPE_DICTIONARY 1
|
||||
#define _XPC_TYPE_ARRAY 2
|
||||
#define _XPC_TYPE_BOOL 3
|
||||
#define _XPC_TYPE_CONNECTION 4
|
||||
#define _XPC_TYPE_ENDPOINT 5
|
||||
#define _XPC_TYPE_NULL 6
|
||||
#define _XPC_TYPE_INT64 8
|
||||
#define _XPC_TYPE_UINT64 9
|
||||
#define _XPC_TYPE_DATE 10
|
||||
#define _XPC_TYPE_DATA 11
|
||||
#define _XPC_TYPE_STRING 12
|
||||
#define _XPC_TYPE_UUID 13
|
||||
#define _XPC_TYPE_FD 14
|
||||
#define _XPC_TYPE_SHMEM 15
|
||||
#define _XPC_TYPE_ERROR 16
|
||||
#define _XPC_TYPE_DOUBLE 17
|
||||
#define _XPC_TYPE_MAX _XPC_TYPE_DOUBLE
|
||||
|
||||
#define XPC_SEQID "XPC sequence number"
|
||||
|
||||
struct xpc_object;
|
||||
struct xpc_dict_pair;
|
||||
struct xpc_resource;
|
||||
struct xpc_credentials;
|
||||
|
||||
TAILQ_HEAD(xpc_dict_head, xpc_dict_pair);
|
||||
TAILQ_HEAD(xpc_array_head, xpc_object);
|
||||
|
||||
typedef void *xpc_port_t;
|
||||
typedef int (*xpc_transport_listen_t)(const char *, xpc_port_t *);
|
||||
typedef int (*xpc_transport_lookup)(const char *, xpc_port_t *);
|
||||
typedef char *(*xpc_transport_port_to_string)(xpc_port_t);
|
||||
typedef int (*xpc_transport_port_compare)(xpc_port_t, xpc_port_t);
|
||||
typedef int (*xpc_transport_release)(xpc_port_t);
|
||||
typedef int (*xpc_transport_send)(xpc_port_t, xpc_port_t, struct iovec *iov,
|
||||
int niov, struct xpc_resource *, size_t);
|
||||
typedef int(*xpc_transport_recv)(xpc_port_t, xpc_port_t*, struct iovec *iov,
|
||||
int niov, struct xpc_resource **, size_t *, struct xpc_credentials *);
|
||||
typedef dispatch_source_t (*xpc_transport_create_source)(xpc_port_t,
|
||||
dispatch_queue_t);
|
||||
|
||||
typedef union {
|
||||
struct xpc_dict_head dict;
|
||||
struct xpc_array_head array;
|
||||
uint64_t ui;
|
||||
int64_t i;
|
||||
char *str;
|
||||
bool b;
|
||||
double d;
|
||||
uintptr_t ptr;
|
||||
int fd;
|
||||
uuid_t uuid;
|
||||
#ifdef MACH
|
||||
mach_port_t port;
|
||||
#endif
|
||||
} xpc_u;
|
||||
|
||||
|
||||
#define _XPC_FROM_WIRE 0x1
|
||||
struct xpc_object {
|
||||
uint8_t xo_xpc_type;
|
||||
uint16_t xo_flags;
|
||||
volatile uint32_t xo_refcnt;
|
||||
size_t xo_size;
|
||||
xpc_u xo_u;
|
||||
#ifdef MACH
|
||||
audit_token_t * xo_audit_token;
|
||||
#endif
|
||||
TAILQ_ENTRY(xpc_object) xo_link;
|
||||
};
|
||||
|
||||
struct xpc_dict_pair {
|
||||
const char * key;
|
||||
struct xpc_object * value;
|
||||
TAILQ_ENTRY(xpc_dict_pair) xo_link;
|
||||
};
|
||||
|
||||
struct xpc_pending_call {
|
||||
uint64_t xp_id;
|
||||
xpc_object_t xp_response;
|
||||
dispatch_queue_t xp_queue;
|
||||
xpc_handler_t xp_handler;
|
||||
TAILQ_ENTRY(xpc_pending_call) xp_link;
|
||||
};
|
||||
|
||||
struct xpc_credentials {
|
||||
uid_t xc_remote_euid;
|
||||
gid_t xc_remote_guid;
|
||||
pid_t xc_remote_pid;
|
||||
#ifdef MACH
|
||||
au_asid_t xc_remote_asid;
|
||||
audit_token_t xc_audit_token;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct xpc_connection {
|
||||
const char * xc_name;
|
||||
xpc_port_t xc_local_port;
|
||||
xpc_port_t xc_remote_port;
|
||||
xpc_handler_t xc_handler;
|
||||
dispatch_source_t xc_recv_source;
|
||||
dispatch_queue_t xc_send_queue;
|
||||
dispatch_queue_t xc_recv_queue;
|
||||
dispatch_queue_t xc_target_queue;
|
||||
int xc_suspend_count;
|
||||
int xc_transaction_count;
|
||||
uint64_t xc_flags;
|
||||
volatile uint64_t xc_last_id;
|
||||
void * xc_context;
|
||||
struct xpc_connection * xc_parent;
|
||||
struct xpc_credentials xc_creds;
|
||||
TAILQ_HEAD(, xpc_pending_call) xc_pending;
|
||||
TAILQ_HEAD(, xpc_connection) xc_peers;
|
||||
TAILQ_ENTRY(xpc_connection) xc_link;
|
||||
};
|
||||
|
||||
struct xpc_resource {
|
||||
int xr_type;
|
||||
union {
|
||||
int xr_fd;
|
||||
};
|
||||
};
|
||||
|
||||
struct xpc_transport {
|
||||
const char * xt_name;
|
||||
xpc_transport_listen_t xt_listen;
|
||||
xpc_transport_lookup xt_lookup;
|
||||
xpc_transport_port_to_string xt_port_to_string;
|
||||
xpc_transport_port_compare xt_port_compare;
|
||||
xpc_transport_release xt_release;
|
||||
xpc_transport_send xt_send;
|
||||
xpc_transport_recv xt_recv;
|
||||
xpc_transport_create_source xt_create_source;
|
||||
};
|
||||
|
||||
struct xpc_service {
|
||||
xpc_port_t xs_pipe;
|
||||
TAILQ_HEAD(, xpc_connection) xs_connections;
|
||||
};
|
||||
|
||||
#define xo_str xo_u.str
|
||||
#define xo_bool xo_u.b
|
||||
#define xo_uint xo_u.ui
|
||||
#define xo_int xo_u.i
|
||||
#define xo_ptr xo_u.ptr
|
||||
#define xo_d xo_u.d
|
||||
#define xo_fd xo_u.fd
|
||||
#define xo_uuid xo_u.uuid
|
||||
#define xo_port xo_u.port
|
||||
#define xo_array xo_u.array
|
||||
#define xo_dict xo_u.dict
|
||||
|
||||
__private_extern__ struct xpc_transport *xpc_get_transport();
|
||||
__private_extern__ void xpc_set_transport(struct xpc_transport *);
|
||||
__private_extern__ struct xpc_object *_xpc_prim_create(int type, xpc_u value,
|
||||
size_t size);
|
||||
__private_extern__ struct xpc_object *_xpc_prim_create_flags(int type,
|
||||
xpc_u value, size_t size, uint16_t flags);
|
||||
__private_extern__ const char *_xpc_get_type_name(xpc_object_t obj);
|
||||
__private_extern__ struct xpc_object *mpack2xpc(mpack_node_t node);
|
||||
__private_extern__ void xpc2mpack(mpack_writer_t *writer, xpc_object_t xo);
|
||||
__private_extern__ void xpc_object_destroy(struct xpc_object *xo);
|
||||
__private_extern__ int xpc_pipe_send(xpc_object_t obj, uint64_t id,
|
||||
xpc_port_t local, xpc_port_t remote);
|
||||
__private_extern__ int xpc_pipe_receive(xpc_port_t local, xpc_port_t *remote,
|
||||
xpc_object_t *result, uint64_t *id, struct xpc_credentials *creds);
|
||||
|
||||
#endif /* _LIBXPC_XPC_INTERNAL_H */
|
388
xpc_misc.c
Normal file
388
xpc_misc.c
Normal file
@ -0,0 +1,388 @@
|
||||
/*
|
||||
* Copyright 2014-2015 iXsystems, Inc.
|
||||
* All rights reserved
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted providing that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/sbuf.h>
|
||||
#include <machine/atomic.h>
|
||||
#include <assert.h>
|
||||
#include <syslog.h>
|
||||
#include <stdarg.h>
|
||||
#include "xpc/xpc.h"
|
||||
#include "xpc_internal.h"
|
||||
|
||||
static void xpc_copy_description_level(xpc_object_t obj, struct sbuf *sbuf,
|
||||
int level);
|
||||
|
||||
extern struct xpc_transport unix_transport;
|
||||
static struct xpc_transport *selected_transport = &unix_transport;
|
||||
|
||||
void
|
||||
fail_log(const char *exp)
|
||||
{
|
||||
syslog(LOG_ERR, "%s", exp);
|
||||
//sleep(1);
|
||||
printf("%s", exp);
|
||||
//abort();
|
||||
}
|
||||
|
||||
struct xpc_transport *
|
||||
xpc_get_transport()
|
||||
{
|
||||
return (selected_transport);
|
||||
}
|
||||
|
||||
static void
|
||||
xpc_dictionary_destroy(struct xpc_object *dict)
|
||||
{
|
||||
struct xpc_dict_head *head;
|
||||
struct xpc_dict_pair *p, *ptmp;
|
||||
|
||||
head = &dict->xo_dict;
|
||||
|
||||
TAILQ_FOREACH_SAFE(p, head, xo_link, ptmp) {
|
||||
TAILQ_REMOVE(head, p, xo_link);
|
||||
xpc_object_destroy(p->value);
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xpc_array_destroy(struct xpc_object *dict)
|
||||
{
|
||||
struct xpc_object *p, *ptmp;
|
||||
struct xpc_array_head *head;
|
||||
|
||||
head = &dict->xo_array;
|
||||
|
||||
TAILQ_FOREACH_SAFE(p, head, xo_link, ptmp) {
|
||||
TAILQ_REMOVE(head, p, xo_link);
|
||||
xpc_object_destroy(p);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
xpc_pack(struct xpc_object *xo, void **buf, size_t *size)
|
||||
{
|
||||
mpack_writer_t writer;
|
||||
|
||||
mpack_writer_init_growable(&writer, (char **)buf, size);
|
||||
xpc2mpack(&writer, xo);
|
||||
|
||||
if (mpack_writer_destroy(&writer) != mpack_ok)
|
||||
return (-1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static struct xpc_object *
|
||||
xpc_unpack(void *buf, size_t size)
|
||||
{
|
||||
mpack_tree_t tree;
|
||||
struct xpc_object *xo;
|
||||
|
||||
mpack_tree_init(&tree, (const char *)buf, size);
|
||||
if (mpack_tree_error(&tree) != mpack_ok) {
|
||||
debugf("unpack failed: %d", mpack_tree_error(&tree))
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
xo = mpack2xpc(mpack_tree_root(&tree));
|
||||
return (xo);
|
||||
}
|
||||
|
||||
void
|
||||
xpc_object_destroy(struct xpc_object *xo)
|
||||
{
|
||||
if (xo->xo_xpc_type == _XPC_TYPE_DICTIONARY)
|
||||
xpc_dictionary_destroy(xo);
|
||||
|
||||
if (xo->xo_xpc_type == _XPC_TYPE_ARRAY)
|
||||
xpc_array_destroy(xo);
|
||||
|
||||
free(xo);
|
||||
}
|
||||
|
||||
xpc_object_t
|
||||
xpc_retain(xpc_object_t obj)
|
||||
{
|
||||
struct xpc_object *xo;
|
||||
|
||||
xo = obj;
|
||||
atomic_add_int(&xo->xo_refcnt, 1);
|
||||
return (obj);
|
||||
}
|
||||
|
||||
void
|
||||
xpc_release(xpc_object_t obj)
|
||||
{
|
||||
struct xpc_object *xo;
|
||||
|
||||
xo = obj;
|
||||
if (atomic_fetchadd_int(&xo->xo_refcnt, -1) > 1)
|
||||
return;
|
||||
|
||||
xpc_object_destroy(xo);
|
||||
}
|
||||
|
||||
static const char *xpc_errors[] = {
|
||||
"No Error Found",
|
||||
"No Memory",
|
||||
"Invalid Argument",
|
||||
"No Such Process"
|
||||
};
|
||||
|
||||
#if 0
|
||||
const char *
|
||||
xpc_strerror(int error)
|
||||
{
|
||||
|
||||
if (error > EXMAX || error < 0)
|
||||
return "BAD ERROR";
|
||||
return (xpc_errors[error]);
|
||||
}
|
||||
#endif
|
||||
|
||||
char *
|
||||
xpc_copy_description(xpc_object_t obj)
|
||||
{
|
||||
char *result;
|
||||
struct sbuf *sbuf;
|
||||
|
||||
sbuf = sbuf_new_auto();
|
||||
xpc_copy_description_level(obj, sbuf, 0);
|
||||
sbuf_finish(sbuf);
|
||||
result = strdup(sbuf_data(sbuf));
|
||||
sbuf_delete(sbuf);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
static void
|
||||
xpc_copy_description_level(xpc_object_t obj, struct sbuf *sbuf, int level)
|
||||
{
|
||||
struct xpc_object *xo = obj;
|
||||
struct uuid *id;
|
||||
char *uuid_str;
|
||||
uint32_t uuid_status;
|
||||
|
||||
if (obj == NULL) {
|
||||
sbuf_printf(sbuf, "<null value>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
sbuf_printf(sbuf, "(%s) ", _xpc_get_type_name(obj));
|
||||
|
||||
switch (xo->xo_xpc_type) {
|
||||
case _XPC_TYPE_DICTIONARY:
|
||||
sbuf_printf(sbuf, "\n");
|
||||
xpc_dictionary_apply(xo, ^(const char *k, xpc_object_t v) {
|
||||
sbuf_printf(sbuf, "%*s\"%s\": ", level * 4, " ", k);
|
||||
xpc_copy_description_level(v, sbuf, level + 1);
|
||||
return ((bool)true);
|
||||
});
|
||||
break;
|
||||
|
||||
case _XPC_TYPE_ARRAY:
|
||||
sbuf_printf(sbuf, "\n");
|
||||
xpc_array_apply(xo, ^(size_t idx, xpc_object_t v) {
|
||||
sbuf_printf(sbuf, "%*s%ld: ", level * 4, " ", idx);
|
||||
xpc_copy_description_level(v, sbuf, level + 1);
|
||||
return ((bool)true);
|
||||
});
|
||||
break;
|
||||
|
||||
case _XPC_TYPE_BOOL:
|
||||
sbuf_printf(sbuf, "%s\n",
|
||||
xpc_bool_get_value(obj) ? "true" : "false");
|
||||
break;
|
||||
|
||||
case _XPC_TYPE_STRING:
|
||||
sbuf_printf(sbuf, "\"%s\"\n",
|
||||
xpc_string_get_string_ptr(obj));
|
||||
break;
|
||||
|
||||
case _XPC_TYPE_INT64:
|
||||
sbuf_printf(sbuf, "%ld\n",
|
||||
xpc_int64_get_value(obj));
|
||||
break;
|
||||
|
||||
case _XPC_TYPE_UINT64:
|
||||
sbuf_printf(sbuf, "%lx\n",
|
||||
xpc_uint64_get_value(obj));
|
||||
break;
|
||||
|
||||
case _XPC_TYPE_DATE:
|
||||
sbuf_printf(sbuf, "%lu\n",
|
||||
xpc_date_get_value(obj));
|
||||
break;
|
||||
|
||||
case _XPC_TYPE_UUID:
|
||||
id = (struct uuid *)xpc_uuid_get_bytes(obj);
|
||||
uuid_to_string(id, &uuid_str, &uuid_status);
|
||||
sbuf_printf(sbuf, "%s\n", uuid_str);
|
||||
free(uuid_str);
|
||||
break;
|
||||
|
||||
case _XPC_TYPE_ENDPOINT:
|
||||
sbuf_printf(sbuf, "<%ld>\n", xo->xo_int);
|
||||
break;
|
||||
|
||||
case _XPC_TYPE_NULL:
|
||||
sbuf_printf(sbuf, "<null>\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MACH
|
||||
struct _launch_data {
|
||||
uint64_t type;
|
||||
union {
|
||||
struct {
|
||||
union {
|
||||
launch_data_t *_array;
|
||||
char *string;
|
||||
void *opaque;
|
||||
int64_t __junk;
|
||||
};
|
||||
union {
|
||||
uint64_t _array_cnt;
|
||||
uint64_t string_len;
|
||||
uint64_t opaque_size;
|
||||
};
|
||||
};
|
||||
int64_t fd;
|
||||
uint64_t mp;
|
||||
uint64_t err;
|
||||
int64_t number;
|
||||
uint64_t boolean; /* We'd use 'bool' but this struct needs to be used under Rosetta, and sizeof(bool) is different between PowerPC and Intel */
|
||||
double float_num;
|
||||
};
|
||||
};
|
||||
|
||||
static uint8_t ld_to_xpc_type[] = {
|
||||
_XPC_TYPE_INVALID,
|
||||
_XPC_TYPE_DICTIONARY,
|
||||
_XPC_TYPE_ARRAY,
|
||||
_XPC_TYPE_FD,
|
||||
_XPC_TYPE_UINT64,
|
||||
_XPC_TYPE_DOUBLE,
|
||||
_XPC_TYPE_BOOL,
|
||||
_XPC_TYPE_STRING,
|
||||
_XPC_TYPE_DATA,
|
||||
_XPC_TYPE_ERROR,
|
||||
_XPC_TYPE_ENDPOINT
|
||||
};
|
||||
|
||||
xpc_object_t
|
||||
ld2xpc(launch_data_t ld)
|
||||
{
|
||||
struct xpc_object *xo;
|
||||
xpc_u val;
|
||||
|
||||
|
||||
if (ld->type > LAUNCH_DATA_MACHPORT)
|
||||
return (NULL);
|
||||
if (ld->type == LAUNCH_DATA_STRING || ld->type == LAUNCH_DATA_OPAQUE) {
|
||||
val.str = malloc(ld->string_len);
|
||||
memcpy(__DECONST(void *, val.str), ld->string, ld->string_len);
|
||||
xo = _xpc_prim_create(ld_to_xpc_type[ld->type], val, ld->string_len);
|
||||
} else if (ld->type == LAUNCH_DATA_BOOL) {
|
||||
val.b = (bool)ld->boolean;
|
||||
xo = _xpc_prim_create(ld_to_xpc_type[ld->type], val, 0);
|
||||
} else if (ld->type == LAUNCH_DATA_ARRAY) {
|
||||
xo = xpc_array_create(NULL, 0);
|
||||
for (uint64_t i = 0; i < ld->_array_cnt; i++)
|
||||
xpc_array_append_value(xo, ld2xpc(ld->_array[i]));
|
||||
} else {
|
||||
val.ui = ld->mp;
|
||||
xo = _xpc_prim_create(ld_to_xpc_type[ld->type], val, ld->string_len);
|
||||
}
|
||||
return (xo);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
xpc_object_t
|
||||
xpc_copy_entitlement_for_token(const char *key __unused, audit_token_t *token __unused)
|
||||
{
|
||||
xpc_u val;
|
||||
|
||||
val.b = true;
|
||||
return (_xpc_prim_create(_XPC_TYPE_BOOL, val,0));
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
xpc_pipe_send(xpc_object_t xobj, uint64_t id, xpc_port_t local, xpc_port_t remote)
|
||||
{
|
||||
struct xpc_transport *transport = xpc_get_transport();
|
||||
struct iovec iov[2];
|
||||
|
||||
assert(xpc_get_type(xobj) == &_xpc_type_dictionary);
|
||||
|
||||
iov[0].iov_base = (void *)&id;
|
||||
iov[0].iov_len = sizeof(uint64_t);
|
||||
|
||||
if (xpc_pack(xobj, &iov[1].iov_base, &iov[1].iov_len) != 0) {
|
||||
debugf("pack failed");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (transport->xt_send(local, remote, (struct iovec *)&iov, 2, NULL, 0) != 0) {
|
||||
debugf("transport send function failed: %s", strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
xpc_pipe_receive(xpc_port_t local, xpc_port_t *remote, xpc_object_t *result,
|
||||
uint64_t *id, struct xpc_credentials *creds)
|
||||
{
|
||||
struct xpc_transport *transport = xpc_get_transport();
|
||||
struct xpc_resource *resources;
|
||||
struct iovec iov;
|
||||
size_t nresources;
|
||||
|
||||
iov.iov_base = malloc(65535);
|
||||
iov.iov_len = 65535;
|
||||
|
||||
if (transport->xt_recv(local, remote, &iov, 1, &resources, &nresources, creds) != 0) {
|
||||
debugf("transport receive function failed: %s", strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
|
||||
*id = *(uint64_t *)iov.iov_base;
|
||||
*result = xpc_unpack(iov.iov_base + sizeof(uint64_t), iov.iov_len - sizeof(uint64_t));
|
||||
|
||||
if (*result == NULL)
|
||||
return (-1);
|
||||
|
||||
return (0);
|
||||
}
|
492
xpc_type.c
Normal file
492
xpc_type.c
Normal file
@ -0,0 +1,492 @@
|
||||
/*
|
||||
* Copyright 2014-2015 iXsystems, Inc.
|
||||
* All rights reserved
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted providing that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include "xpc/xpc.h"
|
||||
#include "xpc_internal.h"
|
||||
|
||||
struct _xpc_type_s {
|
||||
};
|
||||
|
||||
typedef const struct _xpc_type_s xt;
|
||||
xt _xpc_type_array;
|
||||
xt _xpc_type_bool;
|
||||
xt _xpc_type_connection;
|
||||
xt _xpc_type_data;
|
||||
xt _xpc_type_date;
|
||||
xt _xpc_type_dictionary;
|
||||
xt _xpc_type_endpoint;
|
||||
xt _xpc_type_null;
|
||||
xt _xpc_type_error;
|
||||
xt _xpc_type_fd;
|
||||
xt _xpc_type_int64;
|
||||
xt _xpc_type_uint64;
|
||||
xt _xpc_type_shmem;
|
||||
xt _xpc_type_string;
|
||||
xt _xpc_type_uuid;
|
||||
xt _xpc_type_double;
|
||||
|
||||
|
||||
struct _xpc_bool_s {
|
||||
};
|
||||
|
||||
typedef const struct _xpc_bool_s xb;
|
||||
|
||||
xb _xpc_bool_true;
|
||||
xb _xpc_bool_false;
|
||||
|
||||
static size_t xpc_data_hash(const uint8_t *data, size_t length);
|
||||
|
||||
static xpc_type_t xpc_typemap[] = {
|
||||
NULL,
|
||||
XPC_TYPE_DICTIONARY,
|
||||
XPC_TYPE_ARRAY,
|
||||
XPC_TYPE_BOOL,
|
||||
XPC_TYPE_CONNECTION,
|
||||
XPC_TYPE_ENDPOINT,
|
||||
XPC_TYPE_NULL,
|
||||
NULL,
|
||||
XPC_TYPE_INT64,
|
||||
XPC_TYPE_UINT64,
|
||||
XPC_TYPE_DATE,
|
||||
XPC_TYPE_DATA,
|
||||
XPC_TYPE_STRING,
|
||||
XPC_TYPE_UUID,
|
||||
XPC_TYPE_FD,
|
||||
XPC_TYPE_SHMEM,
|
||||
XPC_TYPE_ERROR,
|
||||
XPC_TYPE_DOUBLE
|
||||
};
|
||||
|
||||
static const char *xpc_typestr[] = {
|
||||
"invalid",
|
||||
"dictionary",
|
||||
"array",
|
||||
"bool",
|
||||
"connection",
|
||||
"endpoint",
|
||||
"null",
|
||||
"invalid",
|
||||
"int64",
|
||||
"uint64",
|
||||
"date",
|
||||
"data",
|
||||
"string",
|
||||
"uuid",
|
||||
"fd",
|
||||
"shmem",
|
||||
"error",
|
||||
"double"
|
||||
};
|
||||
|
||||
__private_extern__ struct xpc_object *
|
||||
_xpc_prim_create(int type, xpc_u value, size_t size)
|
||||
{
|
||||
|
||||
return (_xpc_prim_create_flags(type, value, size, 0));
|
||||
}
|
||||
|
||||
__private_extern__ struct xpc_object *
|
||||
_xpc_prim_create_flags(int type, xpc_u value, size_t size, uint16_t flags)
|
||||
{
|
||||
struct xpc_object *xo;
|
||||
|
||||
if ((xo = malloc(sizeof(*xo))) == NULL)
|
||||
return (NULL);
|
||||
|
||||
xo->xo_size = size;
|
||||
xo->xo_xpc_type = type;
|
||||
xo->xo_flags = flags;
|
||||
xo->xo_u = value;
|
||||
xo->xo_refcnt = 1;
|
||||
#if MACH
|
||||
xo->xo_audit_token = NULL;
|
||||
#endif
|
||||
|
||||
if (type == _XPC_TYPE_DICTIONARY)
|
||||
TAILQ_INIT(&xo->xo_dict);
|
||||
|
||||
if (type == _XPC_TYPE_ARRAY)
|
||||
TAILQ_INIT(&xo->xo_array);
|
||||
|
||||
return (xo);
|
||||
}
|
||||
|
||||
xpc_object_t
|
||||
xpc_null_create(void)
|
||||
{
|
||||
xpc_u val;
|
||||
return _xpc_prim_create(_XPC_TYPE_NULL, val, 0);
|
||||
}
|
||||
|
||||
xpc_object_t
|
||||
xpc_bool_create(bool value)
|
||||
{
|
||||
xpc_u val;
|
||||
|
||||
val.b = value;
|
||||
return _xpc_prim_create(_XPC_TYPE_BOOL, val, 1);
|
||||
}
|
||||
|
||||
bool
|
||||
xpc_bool_get_value(xpc_object_t xbool)
|
||||
{
|
||||
struct xpc_object *xo;
|
||||
|
||||
xo = xbool;
|
||||
if (xo == NULL)
|
||||
return (0);
|
||||
|
||||
if (xo->xo_xpc_type == _XPC_TYPE_BOOL)
|
||||
return (xo->xo_bool);
|
||||
|
||||
return (false);
|
||||
}
|
||||
|
||||
xpc_object_t
|
||||
xpc_int64_create(int64_t value)
|
||||
{
|
||||
xpc_u val;
|
||||
|
||||
val.i = value;
|
||||
return _xpc_prim_create(_XPC_TYPE_INT64, val, 1);
|
||||
}
|
||||
|
||||
int64_t
|
||||
xpc_int64_get_value(xpc_object_t xint)
|
||||
{
|
||||
struct xpc_object *xo;
|
||||
|
||||
xo = xint;
|
||||
if (xo == NULL)
|
||||
return (0);
|
||||
|
||||
if (xo->xo_xpc_type == _XPC_TYPE_INT64)
|
||||
return (xo->xo_int);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
xpc_object_t
|
||||
xpc_uint64_create(uint64_t value)
|
||||
{
|
||||
xpc_u val;
|
||||
|
||||
val.ui = value;
|
||||
return _xpc_prim_create(_XPC_TYPE_UINT64, val, 1);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
xpc_uint64_get_value(xpc_object_t xuint)
|
||||
{
|
||||
struct xpc_object *xo;
|
||||
|
||||
xo = xuint;
|
||||
if (xo == NULL)
|
||||
return (0);
|
||||
|
||||
if (xo->xo_xpc_type == _XPC_TYPE_UINT64)
|
||||
return (xo->xo_uint);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
xpc_object_t
|
||||
xpc_double_create(double value)
|
||||
{
|
||||
xpc_u val;
|
||||
|
||||
val.d = value;
|
||||
return _xpc_prim_create(_XPC_TYPE_DOUBLE, val, 1);
|
||||
}
|
||||
|
||||
double
|
||||
xpc_double_get_value(xpc_object_t xdouble)
|
||||
{
|
||||
struct xpc_object *xo = xdouble;
|
||||
|
||||
if (xo->xo_xpc_type == _XPC_TYPE_DOUBLE)
|
||||
return (xo->xo_d);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
xpc_object_t
|
||||
xpc_date_create(int64_t interval)
|
||||
{
|
||||
xpc_u val;
|
||||
|
||||
val.i = interval;
|
||||
return _xpc_prim_create(_XPC_TYPE_DATE, val, 1);
|
||||
}
|
||||
|
||||
xpc_object_t
|
||||
xpc_date_create_from_current(void)
|
||||
{
|
||||
xpc_u val;
|
||||
struct timespec tp;
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, &tp);
|
||||
|
||||
val.ui = *(uint64_t *)&tp;
|
||||
return _xpc_prim_create(_XPC_TYPE_DATE, val, 1);
|
||||
}
|
||||
|
||||
int64_t
|
||||
xpc_date_get_value(xpc_object_t xdate)
|
||||
{
|
||||
struct xpc_object *xo = xdate;
|
||||
|
||||
if (xo == NULL)
|
||||
return (0);
|
||||
|
||||
if (xo->xo_xpc_type == _XPC_TYPE_DATE)
|
||||
return (xo->xo_int);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
xpc_object_t
|
||||
xpc_data_create(const void *bytes, size_t length)
|
||||
{
|
||||
xpc_u val;
|
||||
|
||||
val.ptr = (uintptr_t)bytes;
|
||||
return _xpc_prim_create(_XPC_TYPE_DATA, val, length);
|
||||
}
|
||||
|
||||
#ifdef MACH
|
||||
xpc_object_t
|
||||
xpc_data_create_with_dispatch_data(dispatch_data_t ddata)
|
||||
{
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t
|
||||
xpc_data_get_length(xpc_object_t xdata)
|
||||
{
|
||||
struct xpc_object *xo = xdata;
|
||||
|
||||
if (xo == NULL)
|
||||
return (0);
|
||||
|
||||
if (xo->xo_xpc_type == _XPC_TYPE_DATA)
|
||||
return (xo->xo_size);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
const void *
|
||||
xpc_data_get_bytes_ptr(xpc_object_t xdata)
|
||||
{
|
||||
struct xpc_object *xo = xdata;
|
||||
|
||||
if (xo == NULL)
|
||||
return (NULL);
|
||||
|
||||
if (xo->xo_xpc_type == _XPC_TYPE_DATA)
|
||||
return ((const void *)xo->xo_ptr);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
size_t
|
||||
xpc_data_get_bytes(xpc_object_t xdata, void *buffer, size_t off, size_t length)
|
||||
{
|
||||
|
||||
/* XXX */
|
||||
return (0);
|
||||
}
|
||||
|
||||
xpc_object_t
|
||||
xpc_string_create(const char *string)
|
||||
{
|
||||
xpc_u val;
|
||||
|
||||
val.str = __DECONST(char *, string);
|
||||
return _xpc_prim_create(_XPC_TYPE_STRING, val, strlen(string));
|
||||
}
|
||||
|
||||
xpc_object_t
|
||||
xpc_string_create_with_format(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
xpc_u val;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vasprintf(&val.str, fmt, ap);
|
||||
va_end(ap);
|
||||
return _xpc_prim_create(_XPC_TYPE_STRING, val, strlen(val.str));
|
||||
}
|
||||
|
||||
xpc_object_t
|
||||
xpc_string_create_with_format_and_arguments(const char *fmt, va_list ap)
|
||||
{
|
||||
xpc_u val;
|
||||
|
||||
vasprintf(&val.str, fmt, ap);
|
||||
return _xpc_prim_create(_XPC_TYPE_STRING, val, strlen(val.str));
|
||||
}
|
||||
|
||||
size_t
|
||||
xpc_string_get_length(xpc_object_t xstring)
|
||||
{
|
||||
struct xpc_object *xo = xstring;
|
||||
|
||||
if (xo == NULL)
|
||||
return (0);
|
||||
|
||||
if (xo->xo_xpc_type == _XPC_TYPE_STRING)
|
||||
return (xo->xo_size);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
const char *
|
||||
xpc_string_get_string_ptr(xpc_object_t xstring)
|
||||
{
|
||||
struct xpc_object *xo = xstring;
|
||||
|
||||
if (xo == NULL)
|
||||
return (NULL);
|
||||
|
||||
if (xo->xo_xpc_type == _XPC_TYPE_STRING)
|
||||
return (xo->xo_str);
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
xpc_object_t
|
||||
xpc_uuid_create(const uuid_t uuid)
|
||||
{
|
||||
xpc_u val;
|
||||
|
||||
memcpy(val.uuid, uuid, sizeof(uuid_t));
|
||||
return _xpc_prim_create(_XPC_TYPE_UUID, val, 1);
|
||||
}
|
||||
|
||||
const uint8_t *
|
||||
xpc_uuid_get_bytes(xpc_object_t xuuid)
|
||||
{
|
||||
struct xpc_object *xo;
|
||||
|
||||
xo = xuuid;
|
||||
if (xo == NULL)
|
||||
return (NULL);
|
||||
|
||||
if (xo->xo_xpc_type == _XPC_TYPE_UUID)
|
||||
return ((uint8_t*)&xo->xo_uuid);
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
xpc_type_t
|
||||
xpc_get_type(xpc_object_t obj)
|
||||
{
|
||||
struct xpc_object *xo;
|
||||
|
||||
xo = obj;
|
||||
return (xpc_typemap[xo->xo_xpc_type]);
|
||||
}
|
||||
|
||||
bool
|
||||
xpc_equal(xpc_object_t x1, xpc_object_t x2)
|
||||
{
|
||||
struct xpc_object *xo1, *xo2;
|
||||
|
||||
xo1 = x1;
|
||||
xo2 = x2;
|
||||
|
||||
/* FIXME */
|
||||
return (false);
|
||||
}
|
||||
|
||||
static size_t
|
||||
xpc_data_hash(const uint8_t *data, size_t length)
|
||||
{
|
||||
size_t hash = 5381;
|
||||
|
||||
while (length--)
|
||||
hash = ((hash << 5) + hash) + data[length];
|
||||
|
||||
return (hash);
|
||||
}
|
||||
|
||||
size_t
|
||||
xpc_hash(xpc_object_t obj)
|
||||
{
|
||||
struct xpc_object *xo;
|
||||
__block size_t hash = 0;
|
||||
|
||||
xo = obj;
|
||||
switch (xo->xo_xpc_type) {
|
||||
case _XPC_TYPE_BOOL:
|
||||
case _XPC_TYPE_INT64:
|
||||
case _XPC_TYPE_UINT64:
|
||||
case _XPC_TYPE_DATE:
|
||||
case _XPC_TYPE_ENDPOINT:
|
||||
return ((size_t)xo->xo_u.ui);
|
||||
|
||||
case _XPC_TYPE_STRING:
|
||||
return (xpc_data_hash(
|
||||
(const uint8_t *)xpc_string_get_string_ptr(obj),
|
||||
xpc_string_get_length(obj)));
|
||||
|
||||
case _XPC_TYPE_DATA:
|
||||
return (xpc_data_hash(
|
||||
xpc_data_get_bytes_ptr(obj),
|
||||
xpc_data_get_length(obj)));
|
||||
|
||||
case _XPC_TYPE_DICTIONARY:
|
||||
xpc_dictionary_apply(obj, ^(const char *k, xpc_object_t v) {
|
||||
hash ^= xpc_data_hash((const uint8_t *)k, strlen(k));
|
||||
hash ^= xpc_hash(v);
|
||||
return ((bool)true);
|
||||
});
|
||||
return (hash);
|
||||
|
||||
case _XPC_TYPE_ARRAY:
|
||||
xpc_array_apply(obj, ^(size_t idx, xpc_object_t v) {
|
||||
hash ^= xpc_hash(v);
|
||||
return ((bool)true);
|
||||
});
|
||||
return (hash);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
__private_extern__ const char *
|
||||
_xpc_get_type_name(xpc_object_t obj)
|
||||
{
|
||||
struct xpc_object *xo;
|
||||
|
||||
xo = obj;
|
||||
return (xpc_typestr[xo->xo_xpc_type]);
|
||||
}
|
Loading…
Reference in New Issue
Block a user