├── .gitignore ├── CMakeLists.txt ├── examples ├── CMakeLists.txt ├── credentials │ ├── CMakeLists.txt │ └── xpc-credentials-server.c ├── echo-client │ ├── CMakeLists.txt │ └── xpc-echo-client.c ├── echo-server │ ├── CMakeLists.txt │ └── xpc-echo-server.c └── json-client │ ├── Makefile │ └── xpc-json-client.c ├── mpack-config.h ├── mpack.c ├── mpack.h ├── python ├── setup.py └── src │ ├── blocks_wrapper.c │ ├── blocks_wrapper.h │ ├── xpc.pxd │ └── xpc.pyx ├── transports ├── mach.c └── unix.c ├── xpc ├── activity.h ├── base.h ├── connection.h ├── debug.h ├── endpoint.h ├── launchd.h └── xpc.h ├── xpc_array.c ├── xpc_connection.c ├── xpc_dictionary.c ├── xpc_internal.h ├── xpc_misc.c └── xpc_type.c /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared objects (inc. Windows DLLs) 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | 31 | # Debug files 32 | *.dSYM/ 33 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2015 iXsystems, Inc. 3 | # All rights reserved 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted providing that the following conditions 7 | # are met: 8 | # 1. Redistributions of source code must retain the above copyright 9 | # notice, this list of conditions and the following disclaimer. 10 | # 2. Redistributions in binary form must reproduce the above copyright 11 | # notice, this list of conditions and the following disclaimer in the 12 | # documentation and/or other materials provided with the distribution. 13 | # 14 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | # OR SERVICES LOSS OF USE, DATA, OR PROFITS OR BUSINESS INTERRUPTION) 21 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | # POSSIBILITY OF SUCH DAMAGE. 25 | # 26 | 27 | cmake_minimum_required(VERSION 3.2) 28 | project(libxpc) 29 | 30 | set(BASE_SOURCES 31 | mpack.c 32 | xpc_array.c 33 | xpc_connection.c 34 | xpc_dictionary.c 35 | xpc_misc.c 36 | xpc_type.c 37 | ) 38 | 39 | set(HEADERS 40 | activity.h 41 | base.h 42 | connection.h 43 | debug.h 44 | endpoint.h 45 | launchd.h 46 | xpc.h 47 | ) 48 | 49 | set(UNIX_TRANSPORT_SOURCES 50 | transports/unix.c 51 | ) 52 | 53 | set(MACH_TRANSPORT_SOURCES 54 | transports/mach.c 55 | ) 56 | 57 | set(SOURCES 58 | ${BASE_SOURCES} 59 | ${UNIX_TRANSPORT_SOURCES} 60 | ) 61 | 62 | option(XPC_DEBUG "Adds debugging output" OFF) 63 | option(MACH "Adds Mach transport support" OFF) 64 | 65 | if(XPC_DEBUG) 66 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0") 67 | add_definitions(-DXPC_DEBUG) 68 | endif() 69 | 70 | if(MACH) 71 | set(SOURCES 72 | ${SOURCES} 73 | ${MACH_TRANSPORT_SOURCES} 74 | ) 75 | include_directories(/usr/include/apple) 76 | add_definitions(-DMACH -D__APPLE__) 77 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -lSystem") 78 | endif() 79 | 80 | include_directories(/usr/local/include) 81 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 82 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fblocks -Wall -Wextra") 83 | add_library(xpc SHARED ${SOURCES}) 84 | add_subdirectory(examples) 85 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2015 iXsystems, Inc. 3 | # All rights reserved 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted providing that the following conditions 7 | # are met: 8 | # 1. Redistributions of source code must retain the above copyright 9 | # notice, this list of conditions and the following disclaimer. 10 | # 2. Redistributions in binary form must reproduce the above copyright 11 | # notice, this list of conditions and the following disclaimer in the 12 | # documentation and/or other materials provided with the distribution. 13 | # 14 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | # OR SERVICES LOSS OF USE, DATA, OR PROFITS OR BUSINESS INTERRUPTION) 21 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | # POSSIBILITY OF SUCH DAMAGE. 25 | # 26 | 27 | add_subdirectory(echo-client) 28 | add_subdirectory(echo-server) 29 | add_subdirectory(credentials) 30 | -------------------------------------------------------------------------------- /examples/credentials/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2015 iXsystems, Inc. 3 | # All rights reserved 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted providing that the following conditions 7 | # are met: 8 | # 1. Redistributions of source code must retain the above copyright 9 | # notice, this list of conditions and the following disclaimer. 10 | # 2. Redistributions in binary form must reproduce the above copyright 11 | # notice, this list of conditions and the following disclaimer in the 12 | # documentation and/or other materials provided with the distribution. 13 | # 14 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | # OR SERVICES LOSS OF USE, DATA, OR PROFITS OR BUSINESS INTERRUPTION) 21 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | # POSSIBILITY OF SUCH DAMAGE. 25 | # 26 | 27 | include_directories(../..) 28 | link_directories(/usr/local/lib ../..) 29 | add_executable(xpc-credentials-server xpc-credentials-server.c) 30 | target_link_libraries(xpc-credentials-server BlocksRuntime dispatch sbuf xpc) -------------------------------------------------------------------------------- /examples/credentials/xpc-credentials-server.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2015 iXsystems, Inc. 3 | * All rights reserved 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted providing that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | * 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | int 34 | main(int argc, char *argv[]) 35 | { 36 | xpc_connection_t conn; 37 | 38 | if (argc < 2) { 39 | fprintf(stderr, "Usage: %s \n", argv[0]); 40 | return (1); 41 | } 42 | 43 | conn = xpc_connection_create_mach_service(argv[1], NULL, 44 | XPC_CONNECTION_MACH_SERVICE_LISTENER); 45 | 46 | xpc_connection_set_event_handler(conn, ^(xpc_object_t peer) { 47 | xpc_connection_set_event_handler(peer, ^(xpc_object_t event) { 48 | printf("Message received: %p\n", event); 49 | printf("Client UID: %d\n", xpc_connection_get_euid(peer)); 50 | printf("Client GID: %d\n", xpc_connection_get_egid(peer)); 51 | printf("Client PID: %d\n", xpc_connection_get_pid(peer)); 52 | 53 | xpc_object_t resp = xpc_dictionary_create(NULL, NULL, 0); 54 | xpc_dictionary_set_string(resp, "foo", "bar"); 55 | xpc_connection_send_message(peer, resp); 56 | }); 57 | 58 | xpc_connection_resume(peer); 59 | }); 60 | 61 | xpc_connection_resume(conn); 62 | dispatch_main(); 63 | } 64 | -------------------------------------------------------------------------------- /examples/echo-client/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2015 iXsystems, Inc. 3 | # All rights reserved 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted providing that the following conditions 7 | # are met: 8 | # 1. Redistributions of source code must retain the above copyright 9 | # notice, this list of conditions and the following disclaimer. 10 | # 2. Redistributions in binary form must reproduce the above copyright 11 | # notice, this list of conditions and the following disclaimer in the 12 | # documentation and/or other materials provided with the distribution. 13 | # 14 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | # OR SERVICES LOSS OF USE, DATA, OR PROFITS OR BUSINESS INTERRUPTION) 21 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | # POSSIBILITY OF SUCH DAMAGE. 25 | # 26 | 27 | include_directories(../..) 28 | link_directories(/usr/local/lib ../..) 29 | add_executable(xpc-echo-client xpc-echo-client.c) 30 | target_link_libraries(xpc-echo-client BlocksRuntime dispatch sbuf xpc) -------------------------------------------------------------------------------- /examples/echo-client/xpc-echo-client.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2015 iXsystems, Inc. 3 | * All rights reserved 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted providing that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | * 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | static void 33 | connection_handler(xpc_connection_t peer) 34 | { 35 | xpc_connection_set_event_handler(peer, ^(xpc_object_t event) { 36 | printf("Message received: %p\n", event); 37 | }); 38 | 39 | xpc_connection_resume(peer); 40 | } 41 | 42 | int 43 | main(int argc, char *argv[]) 44 | { 45 | xpc_connection_t conn; 46 | xpc_object_t msg; 47 | 48 | msg = xpc_dictionary_create(NULL, NULL, 0); 49 | xpc_dictionary_set_string(msg, "Hello", "world"); 50 | 51 | if (argc < 2) { 52 | fprintf(stderr, "Usage: %s \n", argv[0]); 53 | return (1); 54 | } 55 | 56 | conn = xpc_connection_create_mach_service(argv[1], NULL, 0); 57 | if (conn == NULL) { 58 | perror("xpc_connection_create_mach_service"); 59 | return (1); 60 | } 61 | 62 | xpc_connection_set_event_handler(conn, ^(xpc_object_t obj) { 63 | printf("Received message in generic event handler: %p\n", obj); 64 | printf("%s\n", xpc_copy_description(obj)); 65 | }); 66 | 67 | xpc_connection_resume(conn); 68 | xpc_connection_send_message(conn, msg); 69 | 70 | xpc_connection_send_message_with_reply(conn, msg, NULL, ^(xpc_object_t resp) { 71 | printf("Received second message: %p\n", resp); 72 | printf("%s\n", xpc_copy_description(resp)); 73 | }); 74 | 75 | xpc_connection_send_message_with_reply(conn, msg, NULL, ^(xpc_object_t resp) { 76 | printf("Received third message: %p\n", resp); 77 | printf("%s\n", xpc_copy_description(resp)); 78 | }); 79 | 80 | dispatch_main(); 81 | } 82 | -------------------------------------------------------------------------------- /examples/echo-server/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2015 iXsystems, Inc. 3 | # All rights reserved 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted providing that the following conditions 7 | # are met: 8 | # 1. Redistributions of source code must retain the above copyright 9 | # notice, this list of conditions and the following disclaimer. 10 | # 2. Redistributions in binary form must reproduce the above copyright 11 | # notice, this list of conditions and the following disclaimer in the 12 | # documentation and/or other materials provided with the distribution. 13 | # 14 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | # OR SERVICES LOSS OF USE, DATA, OR PROFITS OR BUSINESS INTERRUPTION) 21 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | # POSSIBILITY OF SUCH DAMAGE. 25 | # 26 | 27 | include_directories(../..) 28 | link_directories(/usr/local/lib ../..) 29 | add_executable(xpc-echo-server xpc-echo-server.c) 30 | target_link_libraries(xpc-echo-server BlocksRuntime dispatch sbuf xpc) 31 | -------------------------------------------------------------------------------- /examples/echo-server/xpc-echo-server.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2015 iXsystems, Inc. 3 | * All rights reserved 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted providing that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | * 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | int 34 | main(int argc, char *argv[]) 35 | { 36 | xpc_connection_t conn; 37 | 38 | if (argc < 2) { 39 | fprintf(stderr, "Usage: %s \n", argv[0]); 40 | return (1); 41 | } 42 | 43 | conn = xpc_connection_create_mach_service(argv[1], NULL, 44 | XPC_CONNECTION_MACH_SERVICE_LISTENER); 45 | 46 | xpc_connection_set_event_handler(conn, ^(xpc_object_t peer) { 47 | printf("New connection, peer=%p\n", peer); 48 | xpc_connection_set_event_handler(peer, ^(xpc_object_t event) { 49 | if (event == XPC_ERROR_CONNECTION_INVALID) { 50 | printf("Connection closed by remote end\n"); 51 | return; 52 | } 53 | 54 | if (xpc_get_type(event) != XPC_TYPE_DICTIONARY) { 55 | printf("Received something else than a dictionary!\n"); 56 | return; 57 | } 58 | 59 | printf("Message received: %p\n", event); 60 | printf("%s\n", xpc_copy_description(event)); 61 | 62 | xpc_object_t resp = xpc_dictionary_create(NULL, NULL, 0); 63 | xpc_dictionary_set_string(resp, "foo", "bar"); 64 | xpc_connection_send_message(peer, resp); 65 | }); 66 | 67 | xpc_connection_resume(peer); 68 | }); 69 | 70 | xpc_connection_resume(conn); 71 | dispatch_main(); 72 | } 73 | -------------------------------------------------------------------------------- /examples/json-client/Makefile: -------------------------------------------------------------------------------- 1 | .include 2 | PROG= xpc-json-client 3 | SRCS= xpc-json-client.c 4 | BINDIR?= /usr/bin 5 | 6 | NO_WERROR= yes 7 | MK_MAN=no 8 | CFLAGS+= -g -D__APPLE__ -fblocks 9 | CFLAGS+= -I${.CURDIR}/../../../include/apple -I${.CURDIR}/../../../include 10 | CFLAGS+= -I${.CURDIR}/../../../sys 11 | LDADD+= -lmach -lBlocksRuntime -ldispatch -losxsupport -llaunch -lbsm -lnv -lsbuf -lxpc -pthread -ljansson 12 | 13 | .include 14 | -------------------------------------------------------------------------------- /examples/json-client/xpc-json-client.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2015 iXsystems, Inc. 3 | * All rights reserved 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted providing that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | * 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | static xpc_object_t 34 | to_xpc(json_t *json) 35 | { 36 | size_t idx; 37 | xpc_object_t arr, dict; 38 | const char *key; 39 | json_t *val; 40 | 41 | switch (json_typeof(json)) { 42 | case JSON_STRING: 43 | return xpc_string_create(json_string_value(json)); 44 | 45 | case JSON_INTEGER: 46 | return xpc_int64_create(json_integer_value(json)); 47 | 48 | case JSON_TRUE: 49 | return xpc_bool_create(true); 50 | 51 | case JSON_FALSE: 52 | return xpc_bool_create(false); 53 | 54 | case JSON_ARRAY: 55 | arr = xpc_array_create(NULL, 0); 56 | json_array_foreach(json, idx, val) { 57 | xpc_array_append_value(arr, to_xpc(val)); 58 | } 59 | 60 | return arr; 61 | 62 | case JSON_OBJECT: 63 | dict = xpc_dictionary_create(NULL, NULL, 0); 64 | json_object_foreach(json, key, val) { 65 | xpc_dictionary_set_value(dict, key, to_xpc(val)); 66 | } 67 | 68 | return dict; 69 | 70 | default: 71 | return xpc_null_create(); 72 | 73 | } 74 | } 75 | 76 | static json_t * 77 | to_json(xpc_object_t xo) 78 | { 79 | char *txt; 80 | json_t *arr, *obj; 81 | xpc_type_t type; 82 | size_t i; 83 | 84 | type = xpc_get_type(xo); 85 | 86 | printf("to_json: type=%p\n", type); 87 | 88 | if (type == XPC_TYPE_STRING) 89 | return json_string(xpc_string_get_string_ptr(xo)); 90 | 91 | if (type == XPC_TYPE_INT64) 92 | return json_integer(xpc_int64_get_value(xo)); 93 | 94 | if (type == XPC_TYPE_UINT64) 95 | return json_integer(xpc_uint64_get_value(xo)); 96 | 97 | if (type == XPC_TYPE_BOOL) 98 | return json_boolean(xpc_bool_get_value(xo)); 99 | 100 | if (type == XPC_TYPE_ARRAY) { 101 | arr = json_array(); 102 | xpc_array_apply(xo, ^(size_t index, xpc_object_t value) { 103 | json_array_append_new(arr, to_json(value)); 104 | return ((bool)true); 105 | }); 106 | 107 | return (arr); 108 | } 109 | 110 | if (type == XPC_TYPE_DICTIONARY) { 111 | obj = json_object(); 112 | xpc_dictionary_apply(xo, ^(const char *key, xpc_object_t value) { 113 | json_object_set_new(obj, key, to_json(value)); 114 | return ((bool)true); 115 | }); 116 | 117 | return (obj); 118 | } 119 | 120 | return (json_null()); 121 | } 122 | 123 | int 124 | main(int argc, char *argv[]) 125 | { 126 | xpc_connection_t conn; 127 | xpc_object_t msg; 128 | json_t *json; 129 | json_error_t error; 130 | 131 | if (argc < 2) { 132 | fprintf(stderr, "Usage: %s \n", argv[0]); 133 | return (1); 134 | } 135 | 136 | conn = xpc_connection_create_mach_service(argv[1], NULL, 0); 137 | if (conn == NULL) { 138 | perror("xpc_connection_create_mach_service"); 139 | return (1); 140 | } 141 | 142 | xpc_connection_set_event_handler(conn, ^(xpc_object_t obj) { 143 | printf("Received message in generic event handler: %p\n", obj); 144 | printf("%s\n", xpc_copy_description(obj)); 145 | }); 146 | 147 | xpc_connection_resume(conn); 148 | 149 | json = json_loadf(stdin, JSON_DECODE_ANY, &error); 150 | msg = to_xpc(json); 151 | 152 | xpc_connection_send_message_with_reply(conn, msg, NULL, ^(xpc_object_t resp) { 153 | printf("Received message: %p\n", resp); 154 | json_t *reply; 155 | reply = to_json(resp); 156 | json_dumpf(reply, stdout, JSON_INDENT(4)); 157 | printf("\n"); 158 | }); 159 | 160 | dispatch_main(); 161 | return (0); 162 | } 163 | -------------------------------------------------------------------------------- /mpack-config.h: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * This is a sample MPack configuration file. Copy it to mpack-config.h somewhere 4 | * in your project's include tree and, optionally, edit it to suit your setup. 5 | * In most cases you can leave this file with the default config. 6 | */ 7 | 8 | #ifndef MPACK_CONFIG_H 9 | #define MPACK_CONFIG_H 1 10 | 11 | 12 | /* 13 | * Features 14 | */ 15 | 16 | /** Enables compilation of the base Tag Reader. */ 17 | #define MPACK_READER 1 18 | 19 | /** Enables compilation of the static Expect API. */ 20 | #define MPACK_EXPECT 1 21 | 22 | /** Enables compilation of the dynamic Node API. */ 23 | #define MPACK_NODE 1 24 | 25 | /** Enables compilation of the Writer. */ 26 | #define MPACK_WRITER 1 27 | 28 | 29 | /* 30 | * Dependencies 31 | */ 32 | 33 | /** 34 | * Enables the use of C stdlib. This allows the library to use malloc 35 | * for debugging and in allocation helpers. 36 | */ 37 | #define MPACK_STDLIB 1 38 | 39 | /** 40 | * Enables the use of C stdio. This adds helpers for easily 41 | * reading/writing C files and makes debugging easier. 42 | */ 43 | #define MPACK_STDIO 1 44 | 45 | /** 46 | * \def MPACK_MALLOC 47 | * 48 | * Defines the memory allocation function used by mpack. This is used by 49 | * helpers for automatically allocating data the correct size, and for 50 | * debugging functions. If this macro is undefined, the allocation helpers 51 | * will not be compiled. 52 | * 53 | * A memory allocator is required for the Node API. 54 | */ 55 | /** 56 | * \def MPACK_REALLOC 57 | * 58 | * Defines the realloc function used by mpack. It is used by growable buffers 59 | * to resize more quickly. 60 | * 61 | * This is optional, even when MPACK_MALLOC is used. If MPACK_MALLOC is 62 | * set and MPACK_REALLOC is not, MPACK_MALLOC is used with a simple copy 63 | * to grow buffers. 64 | */ 65 | #if defined(MPACK_STDLIB) && !defined(MPACK_MALLOC) 66 | #define MPACK_MALLOC malloc 67 | #define MPACK_REALLOC realloc 68 | #endif 69 | 70 | /** 71 | * \def MPACK_FREE 72 | * 73 | * Defines the memory free function used by mpack. This is used by helpers 74 | * for automatically allocating data the correct size. If this macro is 75 | * undefined, the allocation helpers will not be compiled. 76 | * 77 | * A memory allocator is required for the Node API. 78 | */ 79 | #if defined(MPACK_STDLIB) && !defined(MPACK_FREE) 80 | #define MPACK_FREE free 81 | #endif 82 | 83 | /** 84 | * Enables the setjmp()/longjmp() error handling option. MPACK_MALLOC is required. 85 | * 86 | * Note that you don't have to use it; this just enables the option. It can be 87 | * disabled to avoid the dependency on setjmp.h . 88 | */ 89 | #if defined(MPACK_MALLOC) 90 | #define MPACK_SETJMP 1 91 | #endif 92 | 93 | 94 | /* 95 | * Debugging options 96 | */ 97 | 98 | /** 99 | * \def MPACK_DEBUG 100 | * 101 | * Enables debug features. You may want to wrap this around your 102 | * own debug preprocs. By default, they are enabled if DEBUG or _DEBUG 103 | * are defined. 104 | * 105 | * Note that MPACK_DEBUG cannot be defined differently for different 106 | * source files because it affects layout of structs defined in header 107 | * files. Your entire project must be compiled with the same value of 108 | * MPACK_DEBUG. (This is why NDEBUG is not used.) 109 | */ 110 | #if defined(DEBUG) || defined(_DEBUG) 111 | #define MPACK_DEBUG 1 112 | #else 113 | #define MPACK_DEBUG 0 114 | #endif 115 | 116 | /** 117 | * Set this to 1 to implement a custom mpack_assert_fail() function. This 118 | * function must not return, and must have the following signature: 119 | * 120 | * void mpack_assert_fail(const char* message) 121 | * 122 | * Asserts are only used when MPACK_DEBUG is enabled, and can be triggered 123 | * by bugs in mpack or bugs due to incorrect usage of mpack. 124 | */ 125 | #define MPACK_CUSTOM_ASSERT 0 126 | 127 | /** 128 | * \def MPACK_READ_TRACKING 129 | * 130 | * Enables compound type size tracking for readers. This ensures that the 131 | * correct number of elements or bytes are read from a compound type. 132 | * 133 | * This is enabled by default in debug builds (provided a malloc() is 134 | * available.) 135 | */ 136 | #if MPACK_DEBUG && MPACK_READER && defined(MPACK_MALLOC) 137 | #define MPACK_READ_TRACKING 1 138 | #endif 139 | 140 | /** 141 | * \def MPACK_WRITE_TRACKING 142 | * 143 | * Enables compound type size tracking for writers. This ensures that the 144 | * correct number of elements or bytes are written in a compound type. 145 | * 146 | * Note that without write tracking enabled, it is possible for buggy code 147 | * to emit invalid MessagePack without flagging an error by writing the wrong 148 | * number of elements or bytes in a compound type. With tracking enabled, 149 | * MPACK will catch such errors and break on the offending line of code. 150 | * 151 | * This is enabled by default in debug builds (provided a malloc() is 152 | * available.) 153 | */ 154 | #if MPACK_DEBUG && MPACK_WRITER && defined(MPACK_MALLOC) 155 | #define MPACK_WRITE_TRACKING 1 156 | #endif 157 | 158 | 159 | /* 160 | * Miscellaneous 161 | */ 162 | 163 | /** 164 | * Stack space to use when initializing a reader or writer with a 165 | * stack-allocated buffer. 166 | */ 167 | #define MPACK_STACK_SIZE 4096 168 | 169 | /** 170 | * Buffer size to use for allocated buffers (such as for a file writer.) 171 | */ 172 | #define MPACK_BUFFER_SIZE 65536 173 | 174 | /** 175 | * Number of nodes in each allocated node page. 176 | * 177 | * Nodes are 16 bytes when compiled for a 32-bit architecture and 178 | * 24 bytes when compiled for a 64-bit architecture. 179 | * 180 | * Using as many nodes fit in one memory page seems to provide the 181 | * best performance, and has very little waste when parsing small 182 | * messages. 183 | */ 184 | #define MPACK_NODE_PAGE_SIZE (4096 / sizeof(mpack_node_t)) 185 | 186 | /** 187 | * The initial depth for the node parser. When MPACK_MALLOC is available, 188 | * the node parser has no practical depth limit, and it is not recursive 189 | * so there is no risk of overflowing the call stack. 190 | */ 191 | #define MPACK_NODE_INITIAL_DEPTH 8 192 | 193 | /** 194 | * The maximum depth for the node parser if MPACK_MALLOC is not available. 195 | * The parsing stack is placed on the call stack. 196 | */ 197 | #define MPACK_NODE_MAX_DEPTH_WITHOUT_MALLOC 32 198 | 199 | 200 | #endif 201 | 202 | -------------------------------------------------------------------------------- /python/setup.py: -------------------------------------------------------------------------------- 1 | #- 2 | # Copyright (c) 2014 iXsystems, Inc. 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted provided that the following conditions 7 | # are met: 8 | # 1. Redistributions of source code must retain the above copyright 9 | # notice, this list of conditions and the following disclaimer. 10 | # 2. Redistributions in binary form must reproduce the above copyright 11 | # notice, this list of conditions and the following disclaimer in the 12 | # documentation and/or other materials provided with the distribution. 13 | # 14 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | # SUCH DAMAGE. 25 | # 26 | 27 | from distutils.core import setup 28 | from distutils.extension import Extension 29 | from Cython.Build import cythonize 30 | 31 | 32 | extensions = [ 33 | Extension( 34 | "xpc", 35 | ["src/xpc.pyx", "src/blocks_wrapper.c"], 36 | extra_compile_args=["-g", "-fblocks", "-I/usr/local/include", "-I.."], 37 | extra_link_args=["-L.."], 38 | libraries=["BlocksRuntime", "dispatch", "sbuf", "xpc"] 39 | ) 40 | ] 41 | 42 | 43 | setup( 44 | name='xpc', 45 | version='1.0', 46 | ext_modules=cythonize(extensions) 47 | ) -------------------------------------------------------------------------------- /python/src/blocks_wrapper.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2015 iXsystems, Inc. 3 | * All rights reserved 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted providing that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | * 26 | */ 27 | 28 | #include 29 | #include "blocks_wrapper.h" 30 | 31 | bool xpc_dictionary_apply_f(xpc_object_t obj, 32 | xpc_dictionary_applier_func_t func, void *context) 33 | { 34 | return (xpc_dictionary_apply(obj, ^(const char *key, xpc_object_t val) { 35 | return func(key, val, context); 36 | })); 37 | } 38 | 39 | bool xpc_array_apply_f(xpc_object_t obj, xpc_array_applier_func_t func, 40 | void *context) 41 | { 42 | return (xpc_array_apply(obj, ^(size_t index, xpc_object_t val) { 43 | return func(index, val, context); 44 | })); 45 | } 46 | 47 | void xpc_connection_set_event_handler_f(xpc_connection_t conn, 48 | xpc_handler_func_t func, void *context) 49 | { 50 | xpc_connection_set_event_handler(conn, ^(xpc_object_t obj) { 51 | func(obj, context); 52 | }); 53 | } 54 | -------------------------------------------------------------------------------- /python/src/blocks_wrapper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2015 iXsystems, Inc. 3 | * All rights reserved 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted providing that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | * 26 | */ 27 | 28 | #include 29 | 30 | typedef bool (*xpc_dictionary_applier_func_t)(const char *, xpc_object_t, void *); 31 | typedef bool (*xpc_array_applier_func_t)(size_t, xpc_object_t, void *); 32 | typedef bool (*xpc_handler_func_t)(xpc_object_t, void *); 33 | 34 | bool xpc_dictionary_apply_f(xpc_object_t, xpc_dictionary_applier_func_t, 35 | void *); 36 | bool xpc_array_apply_f(xpc_object_t, xpc_array_applier_func_t, void *); 37 | void xpc_connection_set_event_handler_f(xpc_connection_t, xpc_handler_func_t, 38 | void *); 39 | -------------------------------------------------------------------------------- /python/src/xpc.pxd: -------------------------------------------------------------------------------- 1 | #+ 2 | # Copyright 2015 iXsystems, Inc. 3 | # All rights reserved 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted providing that the following conditions 7 | # are met: 8 | # 1. Redistributions of source code must retain the above copyright 9 | # notice, this list of conditions and the following disclaimer. 10 | # 2. Redistributions in binary form must reproduce the above copyright 11 | # notice, this list of conditions and the following disclaimer in the 12 | # documentation and/or other materials provided with the distribution. 13 | # 14 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | # OR SERVICES LOSS OF USE, DATA, OR PROFITS OR BUSINESS INTERRUPTION) 21 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | # POSSIBILITY OF SUCH DAMAGE. 25 | # 26 | ##################################################################### 27 | 28 | from libc.stdint cimport * 29 | from posix.types cimport gid_t, pid_t, uid_t 30 | 31 | 32 | cdef extern from "uuid/uuid.h": 33 | ctypedef struct uuid_t: 34 | pass 35 | 36 | 37 | cdef extern from "dispatch/dispatch.h": 38 | ctypedef struct dispatch_queue_t: 39 | pass 40 | 41 | ctypedef struct dispatch_data_t: 42 | pass 43 | 44 | ctypedef struct dispatch_block_t: 45 | pass 46 | 47 | 48 | cdef extern from "blocks_wrapper.h" nogil: 49 | ctypedef int (*xpc_dictionary_applier_func_t)(const char *, xpc_object_t, void *) 50 | ctypedef int (*xpc_array_applier_func_t)(size_t, xpc_object_t, void *) 51 | ctypedef void (*xpc_handler_func_t)(xpc_object_t, void *) 52 | 53 | cdef int xpc_dictionary_apply_f(xpc_object_t, xpc_dictionary_applier_func_t, 54 | void *) 55 | cdef int xpc_array_apply_f(xpc_object_t, xpc_array_applier_func_t, void *) 56 | cdef void xpc_connection_set_event_handler_f(xpc_connection_t, xpc_handler_func_t, 57 | void *) 58 | 59 | 60 | cdef extern from "xpc/xpc.h" nogil: 61 | ctypedef struct xpc_connection_t: 62 | pass 63 | 64 | ctypedef struct xpc_endpoint_t: 65 | pass 66 | 67 | ctypedef struct xpc_object_t: 68 | pass 69 | 70 | ctypedef enum xpc_type_t: 71 | XPC_TYPE_CONNECTION 72 | XPC_TYPE_ENDPOINT 73 | XPC_TYPE_NULL 74 | XPC_TYPE_BOOL 75 | XPC_TYPE_INT64 76 | XPC_TYPE_UINT64 77 | XPC_TYPE_DOUBLE 78 | XPC_TYPE_DATE 79 | XPC_TYPE_DATA 80 | XPC_TYPE_STRING 81 | XPC_TYPE_UUID 82 | XPC_TYPE_FD 83 | XPC_TYPE_SHMEM 84 | XPC_TYPE_ARRAY 85 | XPC_TYPE_DICTIONARY 86 | XPC_TYPE_ERROR 87 | 88 | enum: 89 | XPC_CONNECTION_MACH_SERVICE_LISTENER 90 | 91 | cdef void xpc_retain(xpc_object_t object) 92 | cdef void xpc_release(xpc_object_t object) 93 | cdef xpc_object_t xpc_copy(xpc_object_t object) 94 | cdef xpc_type_t xpc_get_type(xpc_object_t object); 95 | cdef int xpc_equal(xpc_object_t object1, xpc_object_t object2) 96 | cdef size_t xpc_hash(xpc_object_t object) 97 | cdef char* xpc_copy_description(xpc_object_t object) 98 | 99 | cdef xpc_object_t xpc_null_create() 100 | cdef xpc_object_t xpc_int_create(int value) 101 | cdef int xpc_int_get_value(xpc_object_t xint) 102 | cdef xpc_object_t xpc_int64_create(int64_t value) 103 | cdef int64_t xpc_int64_get_value(xpc_object_t xint) 104 | cdef xpc_object_t xpc_uint64_create(uint64_t value) 105 | cdef uint64_t xpc_uint64_get_value(xpc_object_t xuint) 106 | cdef xpc_object_t xpc_double_create(double value) 107 | cdef double xpc_double_get_value(xpc_object_t xdouble) 108 | cdef xpc_object_t xpc_date_create(int64_t interval) 109 | cdef xpc_object_t xpc_date_create_from_current() 110 | cdef int64_t xpc_date_get_value(xpc_object_t xdate) 111 | cdef xpc_object_t xpc_data_create(const void *bytes, size_t length) 112 | cdef xpc_object_t xpc_data_create_with_dispatch_data(dispatch_data_t ddata) 113 | cdef size_t xpc_data_get_length(xpc_object_t xdata) 114 | cdef const void * xpc_data_get_bytes_ptr(xpc_object_t xdata) 115 | cdef size_t xpc_data_get_bytes(xpc_object_t xdata, void *buffer, size_t off, size_t length) 116 | cdef xpc_object_t xpc_string_create(const char *string) 117 | cdef size_t xpc_string_get_length(xpc_object_t xstring) 118 | cdef const char * xpc_string_get_string_ptr(xpc_object_t xstring) 119 | cdef xpc_object_t xpc_uuid_create(const uuid_t uuid) 120 | cdef const uint8_t * xpc_uuid_get_bytes(xpc_object_t xuuid) 121 | cdef xpc_object_t xpc_fd_create(int fd) 122 | cdef intxpc_fd_dup(xpc_object_t xfd) 123 | cdef xpc_object_t xpc_shmem_create(void *region, size_t length) 124 | cdef size_t xpc_shmem_map(xpc_object_t xshmem, void **region) 125 | 126 | cdef xpc_object_t xpc_dictionary_create(const char * const *keys, const xpc_object_t *values, size_t count) 127 | cdef xpc_object_t xpc_dictionary_create_reply(xpc_object_t original) 128 | cdef void xpc_dictionary_set_value(xpc_object_t dictionary, const char *key, xpc_object_t value) 129 | cdef xpc_object_t xpc_dictionary_get_value(xpc_object_t dictionary, const char *key) 130 | cdef size_t xpc_dictionary_get_count(xpc_object_t dictionary) 131 | cdef xpc_connection_t xpc_dictionary_get_remote_connection(xpc_object_t dictionary) 132 | cdef void xpc_dictionary_set_int(xpc_object_t dictionary, const char *key, int value) 133 | cdef void xpc_dictionary_set_int64(xpc_object_t dictionary, const char *key, int64_t value) 134 | cdef void xpc_dictionary_set_uint64(xpc_object_t dictionary, const char *key, uint64_t value) 135 | cdef void xpc_dictionary_set_double(xpc_object_t dictionary, const char *key, double value) 136 | cdef void xpc_dictionary_set_date(xpc_object_t dictionary, const char *key, int64_t value) 137 | cdef void xpc_dictionary_set_data(xpc_object_t dictionary, const char *key, const void *value, size_t length) 138 | cdef void xpc_dictionary_set_string(xpc_object_t dictionary, const char *key, const char *value) 139 | cdef void xpc_dictionary_set_uuid(xpc_object_t dictionary, const char *key, const uuid_t value) 140 | cdef void xpc_dictionary_set_fd(xpc_object_t dictionary, const char *key, int value) 141 | cdef void xpc_dictionary_set_connection(xpc_object_t dictionary, const char *key, xpc_connection_t connection) 142 | cdef int xpc_dictionary_get_int(xpc_object_t dictionary, const char *key) 143 | cdef int64_t xpc_dictionary_get_int64(xpc_object_t dictionary, const char *key) 144 | cdef uint64_t xpc_dictionary_get_uint64(xpc_object_t dictionary, const char *key) 145 | cdef double xpc_dictionary_get_double(xpc_object_t dictionary, const char *key) 146 | cdef int64_t xpc_dictionary_get_date(xpc_object_t dictionary, const char *key) 147 | cdef const void *xpc_dictionary_get_data(xpc_object_t dictionary, const char *key, size_t *length) 148 | cdef const uint8_t *xpc_dictionary_get_uuid(xpc_object_t dictionary, const char *key) 149 | cdef const char *xpc_dictionary_get_string(xpc_object_t dictionary, const char *key) 150 | cdef int xpc_dictionary_dup_fd(xpc_object_t dictionary, const char *key) 151 | cdef xpc_connection_t xpc_dictionary_get_connection(xpc_object_t dictionary, const char *key) 152 | 153 | cdef xpc_object_t xpc_array_create(const xpc_object_t *objects, size_t count) 154 | cdef void xpc_array_set_value(xpc_object_t array, size_t index, xpc_object_t value) 155 | cdef void xpc_array_append_value(xpc_object_t array, xpc_object_t value) 156 | cdef xpc_object_t xpc_array_get_value(xpc_object_t array, size_t index) 157 | cdef size_t xpc_array_get_count(xpc_object_t array) 158 | cdef void xpc_array_set_int(xpc_object_t array, size_t index, int value) 159 | cdef void xpc_array_set_int64(xpc_object_t array, size_t index, int64_t value) 160 | cdef void xpc_array_set_uint64(xpc_object_t array, size_t index, uint64_t value) 161 | cdef void xpc_array_set_double(xpc_object_t array, size_t index, double value) 162 | cdef void xpc_array_set_date(xpc_object_t array, size_t index, int64_t value) 163 | cdef void xpc_array_set_data(xpc_object_t array, size_t index, const void *bytes, size_t length) 164 | cdef void xpc_array_set_string(xpc_object_t array, size_t index, const char *value) 165 | cdef void xpc_array_set_uuid(xpc_object_t array, size_t index, const uuid_t value) 166 | cdef void xpc_array_set_fd(xpc_object_t array, size_t index, int value) 167 | cdef void xpc_array_set_connection(xpc_object_t array, size_t index, xpc_connection_t value) 168 | cdef int xpc_array_get_int(xpc_object_t array, size_t index) 169 | cdef int64_t xpc_array_get_int64(xpc_object_t array, size_t index) 170 | cdef uint64_t xpc_array_get_uint64(xpc_object_t array, size_t index) 171 | cdef double xpc_array_get_double(xpc_object_t array, size_t index) 172 | cdef int64_t xpc_array_get_date(xpc_object_t array, size_t index) 173 | cdef const void * xpc_array_get_data(xpc_object_t array, size_t index, size_t *length) 174 | cdef const uint8_t * xpc_array_get_uuid(xpc_object_t array, size_t index) 175 | cdef const char * xpc_array_get_string(xpc_object_t array, size_t index) 176 | cdef int xpc_array_get_fd(xpc_object_t array, size_t index) 177 | cdef xpc_connection_t xpc_array_get_connection(xpc_object_t array, size_t index) 178 | 179 | cdef xpc_connection_t xpc_connection_create(const char *name, dispatch_queue_t targetq) 180 | cdef xpc_connection_t xpc_connection_create_mach_service(const char *name, dispatch_queue_t targetq, uint64_t flags) 181 | cdef xpc_connection_t xpc_connection_create_from_endpoint(xpc_endpoint_t endpoint) 182 | cdef void xpc_connection_set_target_queue(xpc_connection_t connection, dispatch_queue_t targetq) 183 | cdef void xpc_connection_suspend(xpc_connection_t connection) 184 | cdef void xpc_connection_resume(xpc_connection_t connection) 185 | cdef void xpc_connection_send_message(xpc_connection_t connection, xpc_object_t message) 186 | cdef void xpc_connection_send_barrier(xpc_connection_t connection, dispatch_block_t barrier) 187 | cdef xpc_object_t xpc_connection_send_message_with_reply_sync(xpc_connection_t connection, xpc_object_t message) 188 | cdef void xpc_connection_cancel(xpc_connection_t connection) 189 | cdef const char* xpc_connection_get_name(xpc_connection_t connection) 190 | cdef uid_t xpc_connection_get_euid(xpc_connection_t connection) 191 | # cdef gid_t xpc_connection_get_gid(xpc_connection_t connection) 192 | cdef pid_t xpc_connection_get_pid(xpc_connection_t connection) 193 | # cdef au_asid_t xpc_connection_get_asid(xpc_connection_t connection) 194 | cdef void xpc_connection_set_context(xpc_connection_t connection, void *ctx) 195 | cdef void* xpc_connection_get_context(xpc_connection_t connection) 196 | # cdef void xpc_connection_set_finalizer_f(xpc_connection_t connection, xpc_finalizer_t finalizer) 197 | cdef xpc_endpoint_t xpc_endpoint_create(xpc_connection_t connection) 198 | cdef void xpc_main(void *handler) -------------------------------------------------------------------------------- /python/src/xpc.pyx: -------------------------------------------------------------------------------- 1 | #+ 2 | # Copyright 2015 iXsystems, Inc. 3 | # All rights reserved 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted providing that the following conditions 7 | # are met: 8 | # 1. Redistributions of source code must retain the above copyright 9 | # notice, this list of conditions and the following disclaimer. 10 | # 2. Redistributions in binary form must reproduce the above copyright 11 | # notice, this list of conditions and the following disclaimer in the 12 | # documentation and/or other materials provided with the distribution. 13 | # 14 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | # OR SERVICES LOSS OF USE, DATA, OR PROFITS OR BUSINESS INTERRUPTION) 21 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | # POSSIBILITY OF SUCH DAMAGE. 25 | # 26 | ##################################################################### 27 | 28 | import enum 29 | import uuid 30 | cimport xpc 31 | from libc.stdint cimport * 32 | 33 | 34 | class XPCType(enum.IntEnum): 35 | CONNECTION = xpc.XPC_TYPE_CONNECTION 36 | ENDPOINT = xpc.XPC_TYPE_ENDPOINT 37 | NONE = xpc.XPC_TYPE_NULL 38 | BOOL = xpc.XPC_TYPE_BOOL 39 | INT64 = xpc.XPC_TYPE_INT64 40 | UINT64 = xpc.XPC_TYPE_UINT64 41 | DOUBLE = xpc.XPC_TYPE_DOUBLE 42 | DATE = xpc.XPC_TYPE_DATE 43 | DATA = xpc.XPC_TYPE_DATA 44 | STRING = xpc.XPC_TYPE_STRING 45 | UUID = xpc.XPC_TYPE_UUID 46 | FD = xpc.XPC_TYPE_FD 47 | SHMEM = xpc.XPC_TYPE_SHMEM 48 | ARRAY = xpc.XPC_TYPE_ARRAY 49 | DICTIONARY = xpc.XPC_TYPE_DICTIONARY 50 | ERROR = xpc.XPC_TYPE_ERROR 51 | 52 | 53 | class XPCConnectionFlags(enum.IntEnum): 54 | MACH_SERVICE_LISTENER = xpc.XPC_CONNECTION_MACH_SERVICE_LISTENER 55 | 56 | 57 | cdef class XPCObject(object): 58 | cdef xpc.xpc_object_t obj 59 | 60 | def __init__(self, value=None, type=None, ptr=0): 61 | if type: 62 | if type == XPCType.ARRAY: 63 | self.obj = xpc.xpc_array_create(NULL, 0) 64 | 65 | if type == XPCType.DICTIONARY: 66 | self.obj = xpc.xpc_dictionary_create(NULL, NULL, 0) 67 | 68 | if value is not None: 69 | self.value = value 70 | 71 | if ptr: 72 | self.obj = ptr 73 | 74 | def __dealloc__(self): 75 | #if self.obj != NULL: 76 | # xpc.xpc_release(self.obj) 77 | pass 78 | 79 | property ptr: 80 | def __get__(self): 81 | return self.obj 82 | 83 | property type: 84 | def __get__(self): 85 | return XPCType(xpc.xpc_get_type(self.obj)) 86 | 87 | property value: 88 | def __get__(self): 89 | if self.type == XPCType.NONE: 90 | return None 91 | 92 | if self.type == XPCType.BOOL: 93 | return xpc.xpc_bool_get_value(self.obj) 94 | 95 | if self.type == XPCType.DOUBLE: 96 | return xpc.xpc_double_get_value(self.obj) 97 | 98 | if self.type == XPCType.INT64: 99 | return xpc.xpc_int64_get_value(self.obj) 100 | 101 | if self.type == XPCType.UINT64: 102 | return xpc.xpc_uint64_get_value(self.obj) 103 | 104 | if self.type == XPCType.STRING: 105 | return xpc.xpc_string_get_string_ptr(self.obj) 106 | 107 | if self.type == XPCType.UUID: 108 | return uuid.UUID(bytes=xpc.xpc_uuid_get_bytes(self.obj)) 109 | 110 | if self.type == XPCType.CONNECTION: 111 | return XPCConnection(ptr=self.obj) 112 | 113 | def __set__(self, value): 114 | if value is None: 115 | self.obj = xpc.xpc_null_create() 116 | 117 | if isinstance(value, XPCObject): 118 | self.obj = xpc.xpc_copy(value.ptr) 119 | 120 | if isinstance(value, basestring): 121 | self.obj = xpc.xpc_string_create(value) 122 | 123 | if isinstance(value, (int, long)): 124 | self.obj = xpc.xpc_int64_create(value) 125 | 126 | if isinstance(value, bool): 127 | self.obj = xpc.xpc_bool_create(value) 128 | 129 | if isinstance(value, (list, tuple)): 130 | self.obj = xpc.xpc_array_create(NULL, 0) 131 | for i in value: 132 | self.append(i) 133 | 134 | if isinstance(value, dict): 135 | self.obj = xpc.xpc_dictionary_create(NULL, NULL, 0) 136 | for k, v in value.items(): 137 | self[k] = v 138 | 139 | def __repr__(self): 140 | return xpc.xpc_copy_description(self.obj) 141 | 142 | def __getitem__(self, item): 143 | cdef xpc.xpc_object_t obj 144 | 145 | if self.type == XPCType.ARRAY: 146 | obj = xpc.xpc_array_get_value(self.obj, item) 147 | return XPCObject(ptr=obj) 148 | 149 | if self.type in (XPCType.DICTIONARY, XPCType.ERROR): 150 | obj = xpc.xpc_dictionary_get_value(self.obj, item) 151 | return XPCObject(ptr=obj) 152 | 153 | raise NotImplementedError() 154 | 155 | def __setitem__(self, key, value): 156 | if self.type == XPCType.ARRAY: 157 | xpc.xpc_array_set_value(self.obj, key, value.obj) 158 | return 159 | 160 | if self.type == XPCType.DICTIONARY: 161 | xpc.xpc_dictionary_set_value( 162 | self.obj, 163 | key, 164 | XPCObject(value).ptr) 165 | 166 | return 167 | 168 | 169 | raise NotImplementedError() 170 | 171 | def keys(self): 172 | if self.type != XPCType.DICTIONARY: 173 | raise NotImplementedError() 174 | 175 | def values(self): 176 | if self.type != XPCType.DICTIONARY: 177 | raise NotImplementedError() 178 | 179 | def items(self): 180 | if self.type != XPCType.DICTIONARY: 181 | raise NotImplementedError() 182 | 183 | 184 | def append(self, value): 185 | if self.type != XPCType.ARRAY: 186 | raise NotImplementedError() 187 | 188 | xpc.xpc_array_append_value( 189 | self.obj, 190 | XPCObject(value).ptr) 191 | 192 | def update(self, other): 193 | pass 194 | 195 | 196 | cdef class XPCConnection(object): 197 | cdef xpc.xpc_connection_t conn 198 | cdef readonly children 199 | cdef readonly listener 200 | cdef public object on_event 201 | 202 | def __init__(self, name=None, listener=False, ptr=0): 203 | if ptr: 204 | self.conn = ptr 205 | else: 206 | flags = XPCConnectionFlags.MACH_SERVICE_LISTENER if listener else 0 207 | self.conn = xpc.xpc_connection_create_mach_service(name, NULL, flags) 208 | 209 | self.listener = listener 210 | self.on_event = None 211 | self.children = [] 212 | xpc.xpc_connection_set_event_handler_f(self.conn, self.event_handler, self) 213 | 214 | @staticmethod 215 | cdef void event_handler(xpc.xpc_object_t obj, void* context) with gil: 216 | self = context 217 | if self.listener: 218 | conn = XPCConnection(ptr=obj) 219 | self.children.append(conn) 220 | self.on_event(self, conn) 221 | else: 222 | msg = XPCObject(ptr=obj) 223 | self.on_event(self, msg) 224 | 225 | property remote_uid: 226 | def __get__(self): 227 | return xpc.xpc_connection_get_euid(self.conn) 228 | 229 | # property remote_gid: 230 | # def __get__(self): 231 | # return xpc.xpc_connection_get_gid(self.conn) 232 | 233 | property remote_pid: 234 | def __get__(self): 235 | return xpc.xpc_connection_get_pid(self.conn) 236 | 237 | def resume(self): 238 | if not self.on_event: 239 | raise RuntimeError('Set event handler first') 240 | 241 | xpc.xpc_connection_resume(self.conn) 242 | 243 | def send(self, obj): 244 | if not isinstance(obj, XPCObject): 245 | raise ValueError('Only XPCObject instances can be sent') 246 | 247 | if obj.type != XPCType.DICTIONARY: 248 | raise ValueError('Only XPCObjects of type DICTIONARY can be sent') 249 | 250 | xpc.xpc_connection_send_message(self.conn, obj.ptr) 251 | 252 | def send_with_reply(self, obj, callback): 253 | pass 254 | 255 | def send_with_reply_sync(self, obj): 256 | pass 257 | 258 | 259 | def main(): 260 | with nogil: 261 | xpc.xpc_main(NULL); 262 | -------------------------------------------------------------------------------- /transports/mach.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2015 iXsystems, Inc. 3 | * All rights reserved 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted providing that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | * 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #include "../xpc_internal.h" 40 | 41 | #define MAX_RECV 8192 42 | 43 | struct xpc_message { 44 | mach_msg_header_t header; 45 | char body[]; 46 | }; 47 | 48 | static int 49 | mach_lookup(const char *name, xpc_port_t *local, xpc_port_t *remote) 50 | { 51 | mach_port_t mp, rmp; 52 | kern_return_t kr; 53 | 54 | kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, 55 | &mp); 56 | if (kr != KERN_SUCCESS) { 57 | errno = EPERM; 58 | return (-1); 59 | } 60 | 61 | kr = mach_port_insert_right(mach_task_self(), mp, mp, 62 | MACH_MSG_TYPE_MAKE_SEND); 63 | if (kr != KERN_SUCCESS) { 64 | errno = EPERM; 65 | return (-1); 66 | } 67 | 68 | kr = bootstrap_look_up(bootstrap_port, name, &rmp); 69 | if (kr != KERN_SUCCESS) { 70 | debugf("bootstrap_look_up failed kr=%d", kr); 71 | errno = EBUSY; 72 | return (-1); 73 | } 74 | 75 | *local = (xpc_port_t)mp; 76 | *remote = (xpc_port_t)rmp; 77 | return (0); 78 | } 79 | 80 | static int 81 | mach_listen(const char *name, xpc_port_t *port) 82 | { 83 | mach_port_t mp; 84 | kern_return_t kr; 85 | 86 | kr = bootstrap_check_in(bootstrap_port, name, &mp); 87 | if (kr != KERN_SUCCESS) { 88 | debugf("bootstrap_check_in failed kr=%d", kr); 89 | errno = EBUSY; 90 | return (-1); 91 | } 92 | 93 | *port = mp; 94 | return (0); 95 | } 96 | 97 | static char * 98 | mach_port_to_string(xpc_port_t port) 99 | { 100 | mach_port_t p = (mach_port_t)port; 101 | char *ret; 102 | 103 | asprintf(&ret, "<%d>", p); 104 | return (ret); 105 | } 106 | 107 | static int 108 | mach_port_compare(xpc_port_t p1, xpc_port_t p2) 109 | { 110 | return (mach_port_t)p1 == (mach_port_t)p2; 111 | } 112 | 113 | static dispatch_source_t 114 | mach_create_client_source(xpc_port_t port, void *context, dispatch_queue_t tq) 115 | { 116 | mach_port_t mp = (mach_port_t)port; 117 | dispatch_source_t ret; 118 | 119 | ret = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, 120 | (uintptr_t)mp, 0, tq); 121 | 122 | dispatch_set_context(ret, context); 123 | dispatch_source_set_event_handler_f(ret, xpc_connection_recv_message); 124 | dispatch_source_set_cancel_handler(ret, ^{ 125 | xpc_connection_destroy_peer(dispatch_get_context(ret)); 126 | }); 127 | 128 | return (ret); 129 | } 130 | 131 | static dispatch_source_t 132 | mach_create_server_source(xpc_port_t port, void *context, dispatch_queue_t tq) 133 | { 134 | mach_port_t mp = (mach_port_t)port; 135 | void *client_ctx; 136 | dispatch_source_t ret; 137 | 138 | ret = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, 139 | (uintptr_t)mp, 0, tq); 140 | 141 | dispatch_set_context(ret, context); 142 | dispatch_source_set_event_handler_f(ret, 143 | xpc_connection_recv_mach_message); 144 | 145 | return (ret); 146 | } 147 | 148 | static int 149 | mach_send(xpc_port_t local, xpc_port_t remote, void *buf, size_t len, 150 | struct xpc_resource *res, size_t nres) 151 | { 152 | mach_port_t src, dst; 153 | struct xpc_object *xo; 154 | size_t size, msg_size; 155 | struct xpc_message *message; 156 | kern_return_t kr; 157 | int err = 0; 158 | 159 | message = malloc(sizeof(struct xpc_message) + len); 160 | src = (mach_port_t)local; 161 | dst = (mach_port_t)remote; 162 | 163 | debugf("local=%d remote=%d", src, dst); 164 | 165 | msg_size = _ALIGN(len + sizeof(struct xpc_message)); 166 | message->header.msgh_size = msg_size; 167 | message->header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 168 | MACH_MSG_TYPE_MAKE_SEND); 169 | message->header.msgh_remote_port = dst; 170 | message->header.msgh_local_port = src; 171 | memcpy(&message->body, buf, len); 172 | kr = mach_msg_send(&message->header); 173 | 174 | if (kr != KERN_SUCCESS) { 175 | debugf("failed, kr=%d", kr); 176 | err = (kr == KERN_INVALID_TASK) ? EPIPE : EINVAL; 177 | } 178 | 179 | free(message); 180 | return (err); 181 | } 182 | 183 | static int 184 | mach_recv(xpc_port_t local, xpc_port_t *remote, void *buf, size_t len, 185 | struct xpc_resource **res, size_t *nres, struct xpc_credentials *creds) 186 | { 187 | struct xpc_message *message; 188 | mach_port_t src; 189 | mach_msg_header_t *request; 190 | kern_return_t kr; 191 | mig_reply_error_t response; 192 | mach_msg_trailer_t *tr; 193 | int data_size; 194 | audit_token_t *auditp; 195 | 196 | message = malloc(sizeof(struct xpc_message) + sizeof(mach_msg_trailer_t) + len); 197 | src = (mach_port_t)local; 198 | 199 | request = &message->header; 200 | request->msgh_size = MAX_RECV; 201 | request->msgh_local_port = src; 202 | 203 | kr = mach_msg(request, MACH_RCV_MSG | 204 | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) | 205 | MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT), 0, 206 | request->msgh_size, request->msgh_local_port, 207 | MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); 208 | 209 | if (kr != 0) { 210 | debugf("failed, kr=%d", kr); 211 | return (-1); 212 | } 213 | 214 | debugf("msgh_size=%d", message->header.msgh_size); 215 | 216 | *remote = (xpc_port_t)request->msgh_remote_port; 217 | memcpy(buf, &message->body, message->header.msgh_size); 218 | 219 | tr = (mach_msg_trailer_t *)(((char *)&message) + request->msgh_size); 220 | auditp = &((mach_msg_audit_trailer_t *)tr)->msgh_audit; 221 | 222 | return (message->header.msgh_size - sizeof(struct xpc_message)); 223 | } 224 | 225 | struct xpc_transport mach_transport = { 226 | .xt_name = "mach", 227 | .xt_listen = mach_listen, 228 | .xt_lookup = mach_lookup, 229 | .xt_port_to_string = mach_port_to_string, 230 | .xt_port_compare = mach_port_compare, 231 | .xt_create_client_source = mach_create_client_source, 232 | .xt_create_server_source = mach_create_server_source, 233 | .xt_send = mach_send, 234 | .xt_recv = mach_recv 235 | }; 236 | -------------------------------------------------------------------------------- /transports/unix.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2015 iXsystems, Inc. 3 | * All rights reserved 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted providing that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | * 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #include "../xpc_internal.h" 43 | 44 | #define SOCKET_DIR "/var/run/xpc" 45 | 46 | static int unix_lookup(const char *name, xpc_port_t *local, xpc_port_t *remote); 47 | static int unix_listen(const char *name, xpc_port_t *port); 48 | static int unix_release(xpc_port_t port); 49 | static char *unix_port_to_string(xpc_port_t port); 50 | static int unix_port_compare(xpc_port_t p1, xpc_port_t p2); 51 | static dispatch_source_t unix_create_client_source(xpc_port_t port, void *, 52 | dispatch_queue_t tq); 53 | static dispatch_source_t unix_create_server_source(xpc_port_t port, void *, 54 | dispatch_queue_t tq); 55 | static int unix_send(xpc_port_t local, xpc_port_t remote, void *buf, 56 | size_t len, struct xpc_resource *res, size_t nres); 57 | static int unix_recv(xpc_port_t local, xpc_port_t *remote, void *buf, 58 | size_t len, struct xpc_resource **res, size_t *nres, 59 | struct xpc_credentials *creds); 60 | 61 | static int 62 | unix_lookup(const char *name, xpc_port_t *port, xpc_port_t *unused __unused) 63 | { 64 | struct sockaddr_un addr; 65 | int ret; 66 | char *path; 67 | 68 | asprintf(&path, "%s/%s", SOCKET_DIR, name); 69 | 70 | ret = socket(AF_UNIX, SOCK_SEQPACKET, 0); 71 | addr.sun_family = AF_UNIX; 72 | addr.sun_len = sizeof(struct sockaddr_un); 73 | strncpy(addr.sun_path, path, sizeof(addr.sun_path)); 74 | 75 | if (connect(ret, (struct sockaddr *)&addr, 76 | addr.sun_len) != 0) { 77 | debugf("connect failed: %s", strerror(errno)); 78 | return (-1); 79 | } 80 | 81 | *port = (xpc_port_t)(long)ret; 82 | return (0); 83 | } 84 | 85 | static int 86 | unix_listen(const char *name, xpc_port_t *port) 87 | { 88 | struct sockaddr_un addr; 89 | char *path; 90 | int ret; 91 | 92 | asprintf(&path, "%s/%s", SOCKET_DIR, name); 93 | unlink(path); 94 | 95 | addr.sun_family = AF_UNIX; 96 | addr.sun_len = sizeof(struct sockaddr_un); 97 | strncpy(addr.sun_path, path, sizeof(addr.sun_path)); 98 | 99 | ret = socket(AF_UNIX, SOCK_SEQPACKET, 0); 100 | if (ret == -1) 101 | return (-1); 102 | 103 | if (bind(ret, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) != 0) { 104 | debugf("bind failed: %s", strerror(errno)); 105 | return (-1); 106 | } 107 | 108 | if (listen(ret, 5) != 0) { 109 | debugf("listen failed: %s", strerror(errno)); 110 | return (-1); 111 | } 112 | 113 | *port = (xpc_port_t)(long)ret; 114 | return (0); 115 | } 116 | 117 | static int 118 | unix_release(xpc_port_t port) 119 | { 120 | int fd = (int)port; 121 | 122 | if (fd != -1) 123 | close(fd); 124 | 125 | return (0); 126 | } 127 | 128 | static char * 129 | unix_port_to_string(xpc_port_t port) 130 | { 131 | int fd = (int)port; 132 | char *ret; 133 | 134 | if (fd == -1) { 135 | asprintf(&ret, ""); 136 | return (ret); 137 | } 138 | 139 | 140 | asprintf(&ret, "<%d>", fd); 141 | return (ret); 142 | } 143 | 144 | static int 145 | unix_port_compare(xpc_port_t p1, xpc_port_t p2) 146 | { 147 | return (int)p1 == (int)p2; 148 | } 149 | 150 | static dispatch_source_t 151 | unix_create_client_source(xpc_port_t port, void *context, dispatch_queue_t tq) 152 | { 153 | int fd = (int)port; 154 | dispatch_source_t ret; 155 | 156 | ret = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, 157 | (uintptr_t)fd, 0, tq); 158 | 159 | dispatch_set_context(ret, context); 160 | dispatch_source_set_event_handler_f(ret, xpc_connection_recv_message); 161 | dispatch_source_set_cancel_handler(ret, ^{ 162 | shutdown(fd, SHUT_RDWR); 163 | close(fd); 164 | xpc_connection_destroy_peer(dispatch_get_context(ret)); 165 | }); 166 | 167 | return (ret); 168 | } 169 | 170 | static dispatch_source_t 171 | unix_create_server_source(xpc_port_t port, void *context, dispatch_queue_t tq) 172 | { 173 | int fd = (int)port; 174 | void *client_ctx; 175 | dispatch_source_t ret; 176 | 177 | ret = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, 178 | (uintptr_t)fd, 0, tq); 179 | dispatch_source_set_event_handler(ret, ^{ 180 | int sock; 181 | xpc_port_t client_port; 182 | dispatch_source_t client_source; 183 | 184 | sock = accept(fd, NULL, NULL); 185 | client_port = (xpc_port_t)(long)sock; 186 | client_source = unix_create_client_source(client_port, NULL, tq); 187 | xpc_connection_new_peer(context, client_port, -1, client_source); 188 | }); 189 | 190 | return (ret); 191 | } 192 | 193 | static int 194 | unix_send(xpc_port_t local, xpc_port_t remote __unused, void *buf, size_t len, 195 | struct xpc_resource *res, size_t nres) 196 | { 197 | int fd = (int)local; 198 | struct msghdr msg; 199 | struct cmsghdr *cmsg; 200 | struct iovec iov = { .iov_base = buf, .iov_len = len }; 201 | int i, nfds = 0; 202 | 203 | debugf("local=%s, remote=%s, msg=%p, size=%ld", 204 | unix_port_to_string(local), unix_port_to_string(remote), 205 | buf, len); 206 | 207 | memset(&msg, 0, sizeof(struct msghdr)); 208 | msg.msg_iov = &iov; 209 | msg.msg_iovlen = 1; 210 | msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred)); 211 | msg.msg_control = malloc(msg.msg_controllen); 212 | 213 | cmsg = CMSG_FIRSTHDR(&msg); 214 | cmsg->cmsg_type = SCM_CREDS; 215 | cmsg->cmsg_level = SOL_SOCKET; 216 | cmsg->cmsg_len = CMSG_LEN(sizeof(struct cmsgcred)); 217 | 218 | for (i = 0; i < nres; i++) { 219 | if (res[i].xr_type == XPC_RESOURCE_FD) 220 | nfds++; 221 | } 222 | 223 | if (nres > 0) { 224 | int *fds; 225 | 226 | msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred)) + 227 | CMSG_SPACE(nfds * sizeof(int)); 228 | msg.msg_control = realloc(msg.msg_control, msg.msg_controllen); 229 | cmsg = CMSG_NXTHDR(&msg, cmsg); 230 | cmsg->cmsg_type = SCM_RIGHTS; 231 | cmsg->cmsg_level = SOL_SOCKET; 232 | cmsg->cmsg_len = CMSG_LEN(nres * sizeof(int)); 233 | fds = (int *)CMSG_DATA(cmsg); 234 | 235 | for (i = 0; i < nres; i++) { 236 | if (res[i].xr_type == XPC_RESOURCE_FD) 237 | *fds++ = res[i].xr_fd; 238 | } 239 | } 240 | 241 | if (sendmsg(fd, &msg, 0) < 0) 242 | return (-1); 243 | 244 | return (0); 245 | } 246 | 247 | static int 248 | unix_recv(xpc_port_t local, xpc_port_t *remote, void *buf, size_t len, 249 | struct xpc_resource **res, size_t *nres, struct xpc_credentials *creds) 250 | { 251 | int fd = (int)local; 252 | struct msghdr msg; 253 | struct cmsghdr *cmsg; 254 | struct cmsgcred *recv_creds = NULL; 255 | struct iovec iov = { .iov_base = buf, .iov_len = len }; 256 | int *recv_fds = NULL; 257 | size_t recv_fds_count = 0; 258 | ssize_t recvd; 259 | 260 | msg.msg_name = NULL; 261 | msg.msg_namelen = 0; 262 | msg.msg_iov = &iov; 263 | msg.msg_iovlen = 1; 264 | msg.msg_control = malloc(4096); 265 | msg.msg_controllen = 4096; 266 | 267 | recvd = recvmsg(fd, &msg, 0); 268 | if (recvd < 0) 269 | return (-1); 270 | 271 | if (recvd == 0) 272 | return (0); 273 | 274 | for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; 275 | cmsg = CMSG_NXTHDR(&msg, cmsg)) { 276 | if (cmsg->cmsg_type == SCM_CREDS) { 277 | recv_creds = (struct cmsgcred *)CMSG_DATA(cmsg); 278 | continue; 279 | } 280 | 281 | if (cmsg->cmsg_type == SCM_RIGHTS) { 282 | recv_fds = (int *)CMSG_DATA(cmsg); 283 | recv_fds_count = CMSG_SPACE(cmsg); 284 | } 285 | } 286 | 287 | if (recv_creds != NULL) { 288 | creds->xc_remote_pid = recv_creds->cmcred_pid; 289 | creds->xc_remote_euid = recv_creds->cmcred_euid; 290 | creds->xc_remote_guid = recv_creds->cmcred_gid; 291 | debugf("remote pid=%d, uid=%d, gid=%d", recv_creds->cmcred_pid, 292 | recv_creds->cmcred_uid, recv_creds->cmcred_gid); 293 | 294 | } 295 | 296 | if (recv_fds != NULL) { 297 | int i; 298 | *res = malloc(sizeof(struct xpc_resource) * recv_fds_count); 299 | 300 | for (i = 0; i < recv_fds_count; i++) { 301 | (*res)[i].xr_type = XPC_RESOURCE_FD; 302 | (*res)[i].xr_fd = recv_fds[i]; 303 | } 304 | } 305 | 306 | *remote = NULL; 307 | debugf("local=%s, remote=%s, msg=%p, len=%ld", 308 | unix_port_to_string(local), unix_port_to_string(*remote), 309 | buf, recvd); 310 | 311 | return (recvd); 312 | } 313 | 314 | struct xpc_transport unix_transport = { 315 | .xt_name = "unix", 316 | .xt_listen = unix_listen, 317 | .xt_lookup = unix_lookup, 318 | .xt_release = unix_release, 319 | .xt_port_to_string = unix_port_to_string, 320 | .xt_port_compare = unix_port_compare, 321 | .xt_create_server_source = unix_create_server_source, 322 | .xt_create_client_source = unix_create_client_source, 323 | .xt_send = unix_send, 324 | .xt_recv = unix_recv 325 | }; 326 | -------------------------------------------------------------------------------- /xpc/activity.h: -------------------------------------------------------------------------------- 1 | #ifndef __XPC_ACTIVITY_H__ 2 | #define __XPC_ACTIVITY_H__ 3 | 4 | #ifndef __XPC_INDIRECT__ 5 | #error "Please #include instead of this file directly." 6 | // For HeaderDoc. 7 | #include 8 | #endif // __XPC_INDIRECT__ 9 | 10 | #ifdef __BLOCKS__ 11 | 12 | __BEGIN_DECLS 13 | 14 | /* 15 | * The following are a collection of keys and values used to set an activity's 16 | * execution criteria. 17 | */ 18 | 19 | /*! 20 | * @constant XPC_ACTIVITY_INTERVAL 21 | * An integer property indicating the desired time interval (in seconds) of the 22 | * activity. The activity will not be run more than once per time interval. 23 | * Due to the nature of XPC Activity finding an opportune time to run 24 | * the activity, any two occurrences may be more or less than 'interval' 25 | * seconds apart, but on average will be 'interval' seconds apart. 26 | * The presence of this key implies the following, unless overridden: 27 | * - XPC_ACTIVITY_REPEATING with a value of true 28 | * - XPC_ACTIVITY_DELAY with a value of half the 'interval' 29 | * The delay enforces a minimum distance between any two occurrences. 30 | * - XPC_ACTIVITY_GRACE_PERIOD with a value of half the 'interval'. 31 | * The grace period is the amount of time allowed to pass after the end of 32 | * the interval before more aggressive scheduling occurs. The grace period 33 | * does not increase the size of the interval. 34 | */ 35 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0) 36 | XPC_EXPORT 37 | const char *XPC_ACTIVITY_INTERVAL; 38 | 39 | /*! 40 | * @constant XPC_ACTIVITY_REPEATING 41 | * A boolean property indicating whether this is a repeating activity. 42 | */ 43 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0) 44 | XPC_EXPORT 45 | const char *XPC_ACTIVITY_REPEATING; 46 | 47 | /*! 48 | * @constant XPC_ACTIVITY_DELAY 49 | * An integer property indicating the number of seconds to delay before 50 | * beginning the activity. 51 | */ 52 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0) 53 | XPC_EXPORT 54 | const char *XPC_ACTIVITY_DELAY; 55 | 56 | /*! 57 | * @constant XPC_ACTIVITY_GRACE_PERIOD 58 | * An integer property indicating the number of seconds to allow as a grace 59 | * period before the scheduling of the activity becomes more aggressive. 60 | */ 61 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0) 62 | XPC_EXPORT 63 | const char *XPC_ACTIVITY_GRACE_PERIOD; 64 | 65 | 66 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0) 67 | XPC_EXPORT 68 | const int64_t XPC_ACTIVITY_INTERVAL_1_MIN; 69 | 70 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0) 71 | XPC_EXPORT 72 | const int64_t XPC_ACTIVITY_INTERVAL_5_MIN; 73 | 74 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0) 75 | XPC_EXPORT 76 | const int64_t XPC_ACTIVITY_INTERVAL_15_MIN; 77 | 78 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0) 79 | XPC_EXPORT 80 | const int64_t XPC_ACTIVITY_INTERVAL_30_MIN; 81 | 82 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0) 83 | XPC_EXPORT 84 | const int64_t XPC_ACTIVITY_INTERVAL_1_HOUR; 85 | 86 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0) 87 | XPC_EXPORT 88 | const int64_t XPC_ACTIVITY_INTERVAL_4_HOURS; 89 | 90 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0) 91 | XPC_EXPORT 92 | const int64_t XPC_ACTIVITY_INTERVAL_8_HOURS; 93 | 94 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0) 95 | XPC_EXPORT 96 | const int64_t XPC_ACTIVITY_INTERVAL_1_DAY; 97 | 98 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0) 99 | XPC_EXPORT 100 | const int64_t XPC_ACTIVITY_INTERVAL_7_DAYS; 101 | 102 | /*! 103 | * @constant XPC_ACTIVITY_PRIORITY 104 | * A string property indicating the priority of the activity. 105 | */ 106 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0) 107 | XPC_EXPORT 108 | const char *XPC_ACTIVITY_PRIORITY; 109 | 110 | /*! 111 | * @constant XPC_ACTIVITY_PRIORITY_MAINTENANCE 112 | * A string indicating activity is maintenance priority. 113 | * Maintenance priority is intended for user-invisible maintenance tasks 114 | * such as garbage collection or optimization. 115 | */ 116 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0) 117 | XPC_EXPORT 118 | const char *XPC_ACTIVITY_PRIORITY_MAINTENANCE; 119 | 120 | /*! 121 | * @constant XPC_ACTIVITY_PRIORITY_UTILITY 122 | * A string indicating activity is utility priority. 123 | * Utility priority is intended for user-visible tasks such as fetching data 124 | * from the network, copying files, or importing data. 125 | */ 126 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0) 127 | XPC_EXPORT 128 | const char *XPC_ACTIVITY_PRIORITY_UTILITY; 129 | 130 | /*! 131 | * @constant XPC_ACTIVITY_ALLOW_BATTERY 132 | * A Boolean value indicating whether the activity should be allowed to run 133 | * while the computer is on battery power. The default value is false for 134 | * maintenance priority activity and true for utility priority activity. 135 | */ 136 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0) 137 | XPC_EXPORT 138 | const char *XPC_ACTIVITY_ALLOW_BATTERY; 139 | 140 | /*! 141 | * @constant XPC_ACTIVITY_REQUIRE_SCREEN_SLEEP 142 | * A Boolean value indicating whether the activity should only be performed 143 | * while the primary screen is in sleep mode. Defaults to false. 144 | */ 145 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0) 146 | XPC_EXPORT 147 | const char *XPC_ACTIVITY_REQUIRE_SCREEN_SLEEP; // bool 148 | 149 | /*! 150 | * @constant XPC_ACTIVITY_REQUIRE_BATTERY_LEVEL 151 | * An integer percentage of minimum battery charge required to allow the 152 | * activity to run. A default minimum battery level is determined by the 153 | * system. 154 | */ 155 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0) 156 | XPC_EXPORT 157 | const char *XPC_ACTIVITY_REQUIRE_BATTERY_LEVEL; // int (%) 158 | 159 | /*! 160 | * @constant XPC_ACTIVITY_REQUIRE_HDD_SPINNING 161 | * A Boolean value indicating whether the activity should only be performed 162 | * while the hard disk drive (HDD) is spinning. Computers with flash storage 163 | * are considered to be equivalent to HDD spinning. Defaults to false. 164 | */ 165 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0) 166 | XPC_EXPORT 167 | const char *XPC_ACTIVITY_REQUIRE_HDD_SPINNING; // bool 168 | 169 | /*! 170 | * @define XPC_TYPE_ACTIVITY 171 | * A type representing a connection to a named service. This connection is 172 | * bidirectional and can be used to both send and receive messages. A 173 | * connection carries the credentials of the remote service provider. 174 | */ 175 | #define XPC_TYPE_ACTIVITY (&_xpc_type_activity) 176 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0) 177 | XPC_EXPORT 178 | XPC_TYPE(_xpc_type_activity); 179 | 180 | /*! 181 | * @typedef xpc_activity_t 182 | * 183 | * @abstract 184 | * An XPC activity object. 185 | * 186 | * @discussion 187 | * This object represents a set of execution criteria and a current execution 188 | * state for background activity on the system. Once an activity is registered, 189 | * the system will evaluate its criteria to determine whether the activity is 190 | * eligible to run under current system conditions. When an activity becomes 191 | * eligible to run, its execution state will be updated and an invocation of 192 | * its handler block will be made. 193 | */ 194 | XPC_DECL(xpc_activity); 195 | 196 | /*! 197 | * @typedef xpc_activity_handler_t 198 | * 199 | * @abstract 200 | * A block that is called when an XPC activity becomes eligible to run. 201 | */ 202 | typedef void (^xpc_activity_handler_t)(xpc_activity_t activity); 203 | 204 | /*! 205 | * @constant XPC_ACTIVITY_CHECK_IN 206 | * This constant may be passed to xpc_activity_register() as the criteria 207 | * dictionary in order to check in with the system for previously registered 208 | * activity using the same identifier (for example, an activity taken from a 209 | * launchd property list). 210 | */ 211 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0) 212 | XPC_EXPORT 213 | const xpc_object_t XPC_ACTIVITY_CHECK_IN; 214 | 215 | /*! 216 | * @function xpc_activity_register 217 | * 218 | * @abstract 219 | * Registers an activity with the system. 220 | * 221 | * @discussion 222 | * Registers a new activity with the system. The criteria of the activity are 223 | * described by the dictionary passed to this function. If an activity with the 224 | * same identifier already exists, the criteria provided override the existing 225 | * criteria unless the special dictionary XPC_ACTIVITY_CHECK_IN is used. The 226 | * XPC_ACTIVITY_CHECK_IN dictionary instructs the system to first look up an 227 | * existing activity without modifying its criteria. Once the existing activity 228 | * is found (or a new one is created with an empty set of criteria) the handler 229 | * will be called with an activity object in the XPC_ACTIVITY_STATE_CHECK_IN 230 | * state. 231 | * 232 | * @param identifier 233 | * A unique identifier for the activity. Each application has its own namespace. 234 | * The identifier should remain constant across registrations, relaunches of 235 | * the application, and reboots. It should identify the kind of work being done, 236 | * not a particular invocation of the work. 237 | * 238 | * @param criteria 239 | * A dictionary of criteria for the activity. 240 | * 241 | * @param handler 242 | * The handler block to be called when the activity changes state to one of the 243 | * following states: 244 | * - XPC_ACTIVITY_STATE_CHECK_IN (optional) 245 | * - XPC_ACTIVITY_STATE_RUN 246 | * 247 | * The handler block is never invoked reentrantly. It will be invoked on a 248 | * dispatch queue with an appropriate priority to perform the activity. 249 | */ 250 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0) 251 | XPC_EXPORT XPC_NONNULL1 XPC_NONNULL2 XPC_NONNULL3 252 | void 253 | xpc_activity_register(const char *identifier, xpc_object_t criteria, 254 | xpc_activity_handler_t handler); 255 | 256 | /*! 257 | * @function xpc_activity_copy_criteria 258 | * 259 | * @abstract 260 | * Returns an XPC dictionary describing the execution criteria of an activity. 261 | * This will return NULL in cases where the activity has already completed, e.g. 262 | * when checking in to an event that finished and was not rescheduled. 263 | */ 264 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0) 265 | XPC_EXPORT XPC_WARN_RESULT XPC_RETURNS_RETAINED 266 | xpc_object_t 267 | xpc_activity_copy_criteria(xpc_activity_t activity); 268 | 269 | /*! 270 | * @function xpc_activity_set_criteria 271 | * 272 | * @abstract 273 | * Modifies the execution criteria of an activity. 274 | */ 275 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0) 276 | XPC_EXPORT XPC_NONNULL1 XPC_NONNULL2 277 | void 278 | xpc_activity_set_criteria(xpc_activity_t activity, xpc_object_t criteria); 279 | 280 | /*! 281 | * @enum xpc_activity_state_t 282 | * An activity is defined to be in one of the following states. Applications 283 | * may check the current state of the activity using xpc_activity_get_state() 284 | * in the handler block provided to xpc_activity_register(). 285 | * 286 | * The application can modify the state of the activity by calling 287 | * xpc_activity_set_state() with one of the following: 288 | * - XPC_ACTIVITY_STATE_DEFER 289 | * - XPC_ACTIVITY_STATE_CONTINUE 290 | * - XPC_ACTIVITY_STATE_DONE 291 | * 292 | * @constant XPC_ACTIVITY_STATE_CHECK_IN 293 | * An activity in this state has just completed a checkin with the system after 294 | * XPC_ACTIVITY_CHECK_IN was provided as the criteria dictionary to 295 | * xpc_activity_register. The state gives the application an opportunity to 296 | * inspect and modify the activity's criteria. 297 | * 298 | * @constant XPC_ACTIVITY_STATE_WAIT 299 | * An activity in this state is waiting for an opportunity to run. This value 300 | * is never returned within the activity's handler block, as the block is 301 | * invoked in response to XPC_ACTIVITY_STATE_CHECK_IN or XPC_ACTIVITY_STATE_RUN. 302 | * 303 | * Note: 304 | * A launchd job may idle exit while an activity is in the wait state and be 305 | * relaunched in response to the activity becoming runnable. The launchd job 306 | * simply needs to re-register for the activity on its next launch by passing 307 | * XPC_ACTIVITY_STATE_CHECK_IN to xpc_activity_register(). 308 | * 309 | * @constant XPC_ACTIVITY_STATE_RUN 310 | * An activity in this state is eligible to run based on its criteria. 311 | * 312 | * @constant XPC_ACTIVITY_STATE_DEFER 313 | * An application may pass this value to xpc_activity_set_state() to indicate 314 | * that the activity should be deferred (placed back into the WAIT state) until 315 | * a time when its criteria are met again. Deferring an activity does not reset 316 | * any of its time-based criteria (in other words, it will remain past due). 317 | * 318 | * IMPORTANT: 319 | * This should be done in response to observing xpc_activity_should_defer(). 320 | * It should not be done unilaterally. If you determine that conditions are bad 321 | * to do your activity's work for reasons you can't express in a criteria 322 | * dictionary, you should set the activity's state to XPC_ACTIVITY_STATE_DONE. 323 | * 324 | * 325 | * @constant XPC_ACTIVITY_STATE_CONTINUE 326 | * An application may pass this value to xpc_activity_set_state() to indicate 327 | * that the activity will continue its operation beyond the return of its 328 | * handler block. This can be used to extend an activity to include asynchronous 329 | * operations. The activity's handler block will not be invoked again until the 330 | * state has been updated to either XPC_ACTIVITY_STATE_DEFER or, in the case 331 | * of repeating activity, XPC_ACTIVITY_STATE_DONE. 332 | * 333 | * @constant XPC_ACTIVITY_STATE_DONE 334 | * An application may pass this value to xpc_activity_set_state() to indicate 335 | * that the activity has completed. For non-repeating activity, the resources 336 | * associated with the activity will be automatically released upon return from 337 | * the handler block. For repeating activity, timers present in the activity's 338 | * criteria will be reset. 339 | */ 340 | enum { 341 | XPC_ACTIVITY_STATE_CHECK_IN, 342 | XPC_ACTIVITY_STATE_WAIT, 343 | XPC_ACTIVITY_STATE_RUN, 344 | XPC_ACTIVITY_STATE_DEFER, 345 | XPC_ACTIVITY_STATE_CONTINUE, 346 | XPC_ACTIVITY_STATE_DONE, 347 | }; 348 | typedef long xpc_activity_state_t; 349 | 350 | /*! 351 | * @function xpc_activity_get_state 352 | * 353 | * @abstract 354 | * Returns the current state of an activity. 355 | */ 356 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0) 357 | XPC_EXPORT XPC_WARN_RESULT XPC_NONNULL1 358 | xpc_activity_state_t 359 | xpc_activity_get_state(xpc_activity_t activity); 360 | 361 | /*! 362 | * @function xpc_activity_set_state 363 | * 364 | * @abstract 365 | * Updates the current state of an activity. 366 | * 367 | * @return 368 | * Returns true if the state was successfully updated; otherwise, returns 369 | * false if the requested state transition is not valid. 370 | */ 371 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0) 372 | XPC_EXPORT XPC_WARN_RESULT XPC_NONNULL1 373 | bool 374 | xpc_activity_set_state(xpc_activity_t activity, xpc_activity_state_t state); 375 | 376 | /*! 377 | * @function xpc_activity_should_defer 378 | * 379 | * @abstract 380 | * Test whether an activity should be deferred. 381 | * 382 | * @discussion 383 | * This function may be used to test whether the criteria of a long-running 384 | * activity are still satisfied. If not, the system indicates that the 385 | * application should defer the activity. The application may acknowledge the 386 | * deferral by calling xpc_activity_set_state() with XPC_ACTIVITY_STATE_DEFER. 387 | * Once deferred, the system will place the activity back into the WAIT state 388 | * and re-invoke the handler block at the earliest opportunity when the criteria 389 | * are once again satisfied. 390 | * 391 | * @return 392 | * Returns true if the activity should be deferred. 393 | */ 394 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0) 395 | XPC_EXPORT 396 | bool 397 | xpc_activity_should_defer(xpc_activity_t activity); 398 | 399 | /*! 400 | * @function xpc_activity_unregister 401 | * 402 | * @abstract 403 | * Unregisters an activity found by its identifier. 404 | * 405 | * @discussion 406 | * A dynamically registered activity will be deleted in response to this call. 407 | * Statically registered activity (from a launchd property list) will be 408 | * reverted to its original criteria if any modifications were made. 409 | * 410 | * Unregistering an activity has no effect on any outstanding xpc_activity_t 411 | * objects or any currently executing xpc_activity_handler_t blocks; however, 412 | * no new handler block invocations will be made after it is unregistered. 413 | * 414 | * @param identifier 415 | * The identifier of the activity to unregister. 416 | */ 417 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0) 418 | XPC_EXPORT XPC_NONNULL1 419 | void 420 | xpc_activity_unregister(const char *identifier); 421 | 422 | __END_DECLS 423 | 424 | #endif // __BLOCKS__ 425 | 426 | #endif // __XPC_ACTIVITY_H__ 427 | 428 | -------------------------------------------------------------------------------- /xpc/base.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2009-2011 Apple Inc. All rights reserved. 2 | 3 | #ifndef __XPC_BASE_H__ 4 | #define __XPC_BASE_H__ 5 | 6 | #include 7 | 8 | __BEGIN_DECLS 9 | 10 | #if !defined(__has_include) 11 | #define __has_include(x) 0 12 | #endif // !defined(__has_include) 13 | 14 | #if !defined(__has_attribute) 15 | #define __has_attribute(x) 0 16 | #endif // !defined(__has_attribute) 17 | 18 | #if __has_include() 19 | #include 20 | #else // __has_include() 21 | #ifdef __APPLE__ 22 | #include 23 | #endif 24 | #define __XPC_IOS_SIMULATOR_AVAILABLE_STARTING(version) 25 | #endif // __has_include() 26 | 27 | #if XPC_SERVICE_MAIN_IN_LIBXPC 28 | #define XPC_HOSTING_OLD_MAIN 1 29 | #else // XPC_SERVICE_MAIN_IN_LIBXPC 30 | #define XPC_HOSTING_OLD_MAIN 0 31 | #endif // XPC_SERVICE_MAIN_IN_LIBXPC 32 | 33 | #ifndef __XPC_INDIRECT__ 34 | #error "Please #include instead of this file directly." 35 | #endif // __XPC_INDIRECT__ 36 | 37 | #pragma mark Attribute Shims 38 | #ifdef __GNUC__ 39 | #define XPC_CONSTRUCTOR __attribute__((constructor)) 40 | #define XPC_NORETURN __attribute__((__noreturn__)) 41 | #define XPC_NOTHROW __attribute__((__nothrow__)) 42 | #define XPC_NONNULL1 __attribute__((__nonnull__(1))) 43 | #define XPC_NONNULL2 __attribute__((__nonnull__(2))) 44 | #define XPC_NONNULL3 __attribute__((__nonnull__(3))) 45 | #define XPC_NONNULL4 __attribute__((__nonnull__(4))) 46 | #define XPC_NONNULL5 __attribute__((__nonnull__(5))) 47 | #define XPC_NONNULL6 __attribute__((__nonnull__(6))) 48 | #define XPC_NONNULL7 __attribute__((__nonnull__(7))) 49 | #define XPC_NONNULL8 __attribute__((__nonnull__(8))) 50 | #define XPC_NONNULL9 __attribute__((__nonnull__(9))) 51 | #define XPC_NONNULL10 __attribute__((__nonnull__(10))) 52 | #define XPC_NONNULL11 __attribute__((__nonnull__(11))) 53 | #define XPC_NONNULL_ALL __attribute__((__nonnull__)) 54 | #define XPC_SENTINEL __attribute__((__sentinel__)) 55 | #define XPC_PURE __attribute__((__pure__)) 56 | #define XPC_WARN_RESULT __attribute__((__warn_unused_result__)) 57 | #define XPC_MALLOC __attribute__((__malloc__)) 58 | #define XPC_UNUSED __attribute__((__unused__)) 59 | #define XPC_USED __attribute__((__used__)) 60 | #define XPC_PACKED __attribute__((__packed__)) 61 | #define XPC_PRINTF(m, n) __attribute__((format(printf, m, n))) 62 | #define XPC_INLINE static __inline__ __attribute__((__always_inline__)) 63 | #define XPC_NOINLINE __attribute__((noinline)) 64 | #define XPC_NOIMPL __attribute__((unavailable)) 65 | 66 | #if __has_extension(attribute_unavailable_with_message) 67 | #define XPC_UNAVAILABLE(m) __attribute__((unavailable(m))) 68 | #else // __has_extension(attribute_unavailable_with_message) 69 | #define XPC_UNAVAILABLE(m) XPC_NOIMPL 70 | #endif // __has_extension(attribute_unavailable_with_message) 71 | 72 | #define XPC_EXPORT extern __attribute__((visibility("default"))) 73 | #define XPC_NOEXPORT __attribute__((visibility("hidden"))) 74 | #define XPC_WEAKIMPORT extern __attribute__((weak_import)) 75 | #define XPC_DEBUGGER_EXCL XPC_NOEXPORT XPC_USED 76 | #define XPC_TRANSPARENT_UNION __attribute__((transparent_union)) 77 | #if __clang__ 78 | #define XPC_DEPRECATED(m) __attribute__((deprecated(m))) 79 | #else // __clang__ 80 | #define XPC_DEPRECATED(m) __attribute__((deprecated)) 81 | #endif // __clang 82 | 83 | #if __has_feature(objc_arc) 84 | #define XPC_GIVES_REFERENCE __strong 85 | #define XPC_UNRETAINED __unsafe_unretained 86 | #define XPC_BRIDGE(xo) ((__bridge void *)(xo)) 87 | #define XPC_BRIDGEREF_BEGIN(xo) ((__bridge_retained void *)(xo)) 88 | #define XPC_BRIDGEREF_BEGIN_WITH_REF(xo) ((__bridge void *)(xo)) 89 | #define XPC_BRIDGEREF_MIDDLE(xo) ((__bridge id)(xo)) 90 | #define XPC_BRIDGEREF_END(xo) ((__bridge_transfer id)(xo)) 91 | #else // __has_feature(objc_arc) 92 | #define XPC_GIVES_REFERENCE 93 | #define XPC_UNRETAINED 94 | #define XPC_BRIDGE(xo) 95 | #define XPC_BRIDGEREF_BEGIN(xo) (xo) 96 | #define XPC_BRIDGEREF_BEGIN_WITH_REF(xo) (xo) 97 | #define XPC_BRIDGEREF_MIDDLE(xo) (xo) 98 | #define XPC_BRIDGEREF_END(xo) (xo) 99 | #endif // __has_feature(objc_arc) 100 | 101 | #define _xpc_unreachable() __builtin_unreachable() 102 | #else // __GNUC__ 103 | /*! @parseOnly */ 104 | #define XPC_CONSTRUCTOR 105 | /*! @parseOnly */ 106 | #define XPC_NORETURN 107 | /*! @parseOnly */ 108 | #define XPC_NOTHROW 109 | /*! @parseOnly */ 110 | #define XPC_NONNULL1 111 | /*! @parseOnly */ 112 | #define XPC_NONNULL2 113 | /*! @parseOnly */ 114 | #define XPC_NONNULL3 115 | /*! @parseOnly */ 116 | #define XPC_NONNULL4 117 | /*! @parseOnly */ 118 | #define XPC_NONNULL5 119 | /*! @parseOnly */ 120 | #define XPC_NONNULL6 121 | /*! @parseOnly */ 122 | #define XPC_NONNULL7 123 | /*! @parseOnly */ 124 | #define XPC_NONNULL8 125 | /*! @parseOnly */ 126 | #define XPC_NONNULL9 127 | /*! @parseOnly */ 128 | #define XPC_NONNULL10 129 | /*! @parseOnly */ 130 | #define XPC_NONNULL11 131 | /*! @parseOnly */ 132 | #define XPC_NONNULL(n) 133 | /*! @parseOnly */ 134 | #define XPC_NONNULL_ALL 135 | /*! @parseOnly */ 136 | #define XPC_SENTINEL 137 | /*! @parseOnly */ 138 | #define XPC_PURE 139 | /*! @parseOnly */ 140 | #define XPC_WARN_RESULT 141 | /*! @parseOnly */ 142 | #define XPC_MALLOC 143 | /*! @parseOnly */ 144 | #define XPC_UNUSED 145 | /*! @parseOnly */ 146 | #define XPC_PACKED 147 | /*! @parseOnly */ 148 | #define XPC_PRINTF(m, n) 149 | /*! @parseOnly */ 150 | #define XPC_INLINE static inline 151 | /*! @parseOnly */ 152 | #define XPC_NOINLINE 153 | /*! @parseOnly */ 154 | #define XPC_NOIMPL 155 | /*! @parseOnly */ 156 | #define XPC_EXPORT extern 157 | /*! @parseOnly */ 158 | #define XPC_WEAKIMPORT 159 | /*! @parseOnly */ 160 | #define XPC_DEPRECATED 161 | /*! @parseOnly */ 162 | #define XPC_UNAVAILABLE(m) 163 | #endif // __GNUC__ 164 | 165 | __END_DECLS 166 | 167 | #endif // __XPC_BASE_H__ 168 | -------------------------------------------------------------------------------- /xpc/connection.h: -------------------------------------------------------------------------------- 1 | #ifndef __XPC_CONNECTION_H__ 2 | #define __XPC_CONNECTION_H__ 3 | 4 | #ifndef __XPC_INDIRECT__ 5 | #error "Please #include instead of this file directly." 6 | // For HeaderDoc. 7 | #include 8 | #endif // __XPC_INDIRECT__ 9 | 10 | #ifndef __BLOCKS__ 11 | #error "XPC connections require Blocks support." 12 | #endif // __BLOCKS__ 13 | 14 | __BEGIN_DECLS 15 | 16 | /*! 17 | * @constant XPC_ERROR_CONNECTION_INTERRUPTED 18 | * Will be delivered to the connection's event handler if the remote service 19 | * exited. The connection is still live even in this case, and resending a 20 | * message will cause the service to be launched on-demand. This error serves 21 | * as a client's indication that it should resynchronize any state that it had 22 | * given the service. 23 | * 24 | * Any messages in the queue to be sent will be unwound and canceled when this 25 | * error occurs. In the case where a message waiting to be sent has a reply 26 | * handler, that handler will be invoked with this error. In the context of the 27 | * reply handler, this error indicates that a reply to the message will never 28 | * arrive. 29 | * 30 | * Messages that do not have reply handlers associated with them will be 31 | * silently disposed of. This error will only be given to peer connections. 32 | */ 33 | #define XPC_ERROR_CONNECTION_INTERRUPTED \ 34 | XPC_GLOBAL_OBJECT(_xpc_error_connection_interrupted) 35 | __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0) 36 | XPC_EXPORT 37 | const struct _xpc_dictionary_s _xpc_error_connection_interrupted; 38 | 39 | /*! 40 | * @constant XPC_ERROR_CONNECTION_INVALID 41 | * Will be delivered to the connection's event handler if the named service 42 | * provided to xpc_connection_create() could not be found in the XPC service 43 | * namespace. The connection is useless and should be disposed of. 44 | * 45 | * Any messages in the queue to be sent will be unwound and canceled when this 46 | * error occurs, similarly to the behavior when XPC_ERROR_CONNECTION_INTERRUPTED 47 | * occurs. The only difference is that the XPC_ERROR_CONNECTION_INVALID will be 48 | * given to outstanding reply handlers and the connection's event handler. 49 | * 50 | * This error may be given to any type of connection. 51 | */ 52 | #define XPC_ERROR_CONNECTION_INVALID \ 53 | XPC_GLOBAL_OBJECT(_xpc_error_connection_invalid) 54 | __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0) 55 | XPC_EXPORT 56 | const struct _xpc_dictionary_s _xpc_error_connection_invalid; 57 | 58 | /*! 59 | * @constant XPC_ERROR_TERMINATION_IMMINENT 60 | * This error will be delivered to a peer connection's event handler when the 61 | * XPC runtime has determined that the program should exit and that all 62 | * outstanding transactions must be wound down, and no new transactions can be 63 | * opened. 64 | * 65 | * After this error has been delivered to the event handler, no more messages 66 | * will be received by the connection. The runtime will still attempt to deliver 67 | * outgoing messages, but this error should be treated as an indication that 68 | * the program will exit very soon, and any outstanding business over the 69 | * connection should be wrapped up as quickly as possible and the connection 70 | * canceled shortly thereafter. 71 | * 72 | * This error will only be delivered to peer connections received through a 73 | * listener or the xpc_main() event handler. 74 | */ 75 | #define XPC_ERROR_TERMINATION_IMMINENT \ 76 | XPC_GLOBAL_OBJECT(_xpc_error_termination_imminent) 77 | __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0) 78 | XPC_EXPORT 79 | const struct _xpc_dictionary_s _xpc_error_termination_imminent; 80 | 81 | /*! 82 | * @constant XPC_CONNECTION_MACH_SERVICE_LISTENER 83 | * Passed to xpc_connection_create_mach_service(). This flag indicates that the 84 | * caller is the listener for the named service. This flag may only be passed 85 | * for services which are advertised in the process' launchd.plist(5). You may 86 | * not use this flag to dynamically add services to the Mach bootstrap 87 | * namespace. 88 | */ 89 | #define XPC_CONNECTION_MACH_SERVICE_LISTENER (1 << 0) 90 | 91 | /*! 92 | * @constant XPC_CONNECTION_MACH_SERVICE_PRIVILEGED 93 | * Passed to xpc_connection_create_mach_service(). This flag indicates that the 94 | * job advertising the service name in its launchd.plist(5) should be in the 95 | * privileged Mach bootstrap. This is typically accomplished by placing your 96 | * launchd.plist(5) in /Library/LaunchDaemons. If specified alongside the 97 | * XPC_CONNECTION_MACH_SERVICE_LISTENER flag, this flag is a no-op. 98 | */ 99 | #define XPC_CONNECTION_MACH_SERVICE_PRIVILEGED (1 << 1) 100 | 101 | /*! 102 | * @typedef xpc_finalizer_f 103 | * A function that is invoked when a connection is being torn down and its 104 | * context needs to be freed. The sole argument is the value that was given to 105 | * {@link xpc_connection_set_context} or NULL if no context has been set. It is 106 | * not safe to reference the connection from within this function. 107 | * 108 | * @param value 109 | * The context object that is to be disposed of. 110 | */ 111 | typedef void (*xpc_finalizer_t)(void *value); 112 | 113 | /*! 114 | * @function xpc_connection_create 115 | * Creates a new connection object. 116 | * 117 | * @param name 118 | * If non-NULL, the name of the service with which to connect. The returned 119 | * connection will be a peer. 120 | * 121 | * If NULL, an anonymous listener connection will be created. You can embed the 122 | * ability to create new peer connections in an endpoint, which can be inserted 123 | * into a message and sent to another process . 124 | * 125 | * @param targetq 126 | * The GCD queue to which the event handler block will be submitted. This 127 | * parameter may be NULL, in which case the connection's target queue will be 128 | * libdispatch's default target queue, defined as DISPATCH_TARGET_QUEUE_DEFAULT. 129 | * The target queue may be changed later with a call to 130 | * xpc_connection_set_target_queue(). 131 | * 132 | * @result 133 | * A new connection object. The caller is responsible for disposing of the 134 | * returned object with {@link xpc_release} when it is no longer needed. 135 | * 136 | * @discussion 137 | * This method will succeed even if the named service does not exist. This is 138 | * because the XPC namespace is not queried for the service name until 139 | * the first call to xpc_connection_resume(). 140 | * 141 | * XPC connections, like dispatch sources, are returned in a suspended state, so 142 | * you must call {@link xpc_connection_resume()} in order to begin receiving 143 | * events from the connection. Also like dispatch sources, connections must be 144 | * resumed in order to be safely released. It is a programming error to release 145 | * a suspended connection. 146 | */ 147 | __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0) 148 | XPC_EXPORT XPC_MALLOC XPC_RETURNS_RETAINED XPC_WARN_RESULT 149 | xpc_connection_t 150 | xpc_connection_create(const char *name, dispatch_queue_t targetq); 151 | 152 | /*! 153 | * @function xpc_connection_create_mach_service 154 | * Creates a new connection object representing a Mach service. 155 | * 156 | * @param name 157 | * The name of the remote service with which to connect. The service name must 158 | * exist in a Mach bootstrap that is accessible to the process and be advertised 159 | * in a launchd.plist. 160 | * 161 | * @param targetq 162 | * The GCD queue to which the event handler block will be submitted. This 163 | * parameter may be NULL, in which case the connection's target queue will be 164 | * libdispatch's default target queue, defined as DISPATCH_TARGET_QUEUE_DEFAULT. 165 | * The target queue may be changed later with a call to 166 | * xpc_connection_set_target_queue(). 167 | * 168 | * @param flags 169 | * Additional attributes with which to create the connection. 170 | * 171 | * @result 172 | * A new connection object. 173 | * 174 | * @discussion 175 | * If the XPC_CONNECTION_MACH_SERVICE_LISTENER flag is given to this method, 176 | * then the connection returned will be a listener connection. Otherwise, a peer 177 | * connection will be returned. See the documentation for 178 | * {@link xpc_connection_set_event_handler()} for the semantics of listener 179 | * connections versus peer connections. 180 | * 181 | * This method will succeed even if the named service does not exist. This is 182 | * because the Mach namespace is not queried for the service name until the 183 | * first call to {@link xpc_connection_resume()}. 184 | */ 185 | __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0) 186 | XPC_EXPORT XPC_MALLOC XPC_RETURNS_RETAINED XPC_WARN_RESULT XPC_NONNULL1 187 | xpc_connection_t 188 | xpc_connection_create_mach_service(const char *name, dispatch_queue_t targetq, 189 | uint64_t flags); 190 | 191 | /*! 192 | * @function xpc_connection_create_from_endpoint 193 | * Creates a new connection from the given endpoint. 194 | * 195 | * @param endpoint 196 | * The endpoint from which to create the new connection. 197 | * 198 | * @result 199 | * A new peer connection to the listener represented by the given endpoint. 200 | * 201 | * The same responsibilities of setting an event handler and resuming the 202 | * connection after calling xpc_connection_create() apply to the connection 203 | * returned by this API. Since the connection yielded by this API is not 204 | * associated with a name (and therefore is not rediscoverable), this connection 205 | * will receive XPC_ERROR_CONNECTION_INVALID if the listening side crashes, 206 | * exits or cancels the listener connection. 207 | */ 208 | __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0) 209 | XPC_EXPORT XPC_MALLOC XPC_RETURNS_RETAINED XPC_WARN_RESULT XPC_NONNULL_ALL 210 | xpc_connection_t 211 | xpc_connection_create_from_endpoint(xpc_endpoint_t endpoint); 212 | 213 | /*! 214 | * @function xpc_connection_set_target_queue 215 | * Sets the target queue of the given connection. 216 | * 217 | * @param connection 218 | * The connection object which is to be manipulated. 219 | * 220 | * @param targetq 221 | * The GCD queue to which the event handler block will be submitted. This 222 | * parameter may be NULL, in which case the connection's target queue will be 223 | * libdispatch's default target queue, defined as DISPATCH_TARGET_QUEUE_DEFAULT. 224 | * 225 | * @discussion 226 | * Setting the target queue is asynchronous and non-preemptive and therefore 227 | * this method will not interrupt the execution of an already-running event 228 | * handler block. Setting the target queue may be likened to issuing a barrier 229 | * to the connection which does the actual work of changing the target queue. 230 | * 231 | * The XPC runtime guarantees this non-preemptiveness even for concurrent target 232 | * queues. If the target queue is a concurrent queue, then XPC still guarantees 233 | * that there will never be more than one invocation of the connection's event 234 | * handler block executing concurrently. If you wish to process events 235 | * concurrently, you can dispatch_async(3) to a concurrent queue from within 236 | * the event handler. 237 | * 238 | * IMPORTANT: When called from within the event handler block, 239 | * dispatch_get_current_queue(3) is NOT guaranteed to return a pointer to the 240 | * queue set with this method. 241 | * 242 | * Despite this seeming inconsistency, the XPC runtime guarantees that, when the 243 | * target queue is a serial queue, the event handler block will execute 244 | * synchonously with respect to other blocks submitted to that same queue. When 245 | * the target queue is a concurrent queue, the event handler block may run 246 | * concurrently with other blocks submitted to that queue, but it will never run 247 | * concurrently with other invocations of itself for the same connection, as 248 | * discussed previously. 249 | */ 250 | __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0) 251 | XPC_EXPORT XPC_NONNULL1 252 | void 253 | xpc_connection_set_target_queue(xpc_connection_t connection, 254 | dispatch_queue_t targetq); 255 | 256 | /*! 257 | * @function xpc_connection_set_event_handler 258 | * Sets the event handler block for the connection. 259 | * 260 | * @param connection 261 | * The connection object which is to be manipulated. 262 | * 263 | * @param handler 264 | * The event handler block. 265 | * 266 | * @discussion 267 | * Setting the event handler is asynchronous and non-preemptive, and therefore 268 | * this method will not interrupt the execution of an already-running event 269 | * handler block. If the event handler is executing at the time of this call, it 270 | * will finish, and then the connection's event handler will be changed before 271 | * the next invocation of the event handler. The XPC runtime guarantees this 272 | * non-preemptiveness even for concurrent target queues. 273 | * 274 | * Connection event handlers are non-reentrant, so it is safe to call 275 | * xpc_connection_set_event_handler() from within the event handler block. 276 | * 277 | * The event handler's execution should be treated as a barrier to all 278 | * connection activity. When it is executing, the connection will not attempt to 279 | * send or receive messages, including reply messages. Thus, it is not safe to 280 | * call xpc_connection_send_message_with_reply_sync() on the connection from 281 | * within the event handler. 282 | * 283 | * You do not hold a reference on the object received as the event handler's 284 | * only argument. Regardless of the type of object received, it is safe to call 285 | * xpc_retain() on the object to obtain a reference to it. 286 | * 287 | * A connection may receive different events depending upon whether it is a 288 | * listener or not. Any connection may receive an error in its event handler. 289 | * But while normal connections may receive messages in addition to errors, 290 | * listener connections will receive connections and and not messages. 291 | * 292 | * Connections received by listeners are equivalent to those returned by 293 | * xpc_connection_create() with a non-NULL name argument and a NULL targetq 294 | * argument with the exception that you do not hold a reference on them. 295 | * You must set an event handler and resume the connection. If you do not wish 296 | * to accept the connection, you may simply call xpc_connection_cancel() on it 297 | * and return. The runtime will dispose of it for you. 298 | * 299 | * If there is an error in the connection, this handler will be invoked with the 300 | * error dictionary as its argument. This dictionary will be one of the well- 301 | * known XPC_ERROR_* dictionaries. 302 | * 303 | * Regardless of the type of event, ownership of the event object is NOT 304 | * implicitly transferred. Thus, the object will be released and deallocated at 305 | * some point in the future after the event handler returns. If you wish the 306 | * event's lifetime to persist, you must retain it with xpc_retain(). 307 | * 308 | * Connections received through the event handler will be released and 309 | * deallocated after the connection has gone invalid and delivered that event to 310 | * its event handler. 311 | */ 312 | __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0) 313 | XPC_EXPORT XPC_NONNULL_ALL 314 | void 315 | xpc_connection_set_event_handler(xpc_connection_t connection, 316 | xpc_handler_t handler); 317 | 318 | /*! 319 | * @function xpc_connection_suspend 320 | * Suspends the connection so that the event handler block will not fire and 321 | * that the connection will not attempt to send any messages it has in its 322 | * queue. All calls to xpc_connection_suspend() must be balanced with calls to 323 | * xpc_connection_resume() before releasing the last reference to the 324 | * connection. 325 | * 326 | * @param connection 327 | * The connection object which is to be manipulated. 328 | * 329 | * @discussion 330 | * Suspension is asynchronous and non-preemptive, and therefore this method will 331 | * not interrupt the execution of an already-running event handler block. If 332 | * the event handler is executing at the time of this call, it will finish, and 333 | * then the connection will be suspended before the next scheduled invocation 334 | * of the event handler. The XPC runtime guarantees this non-preemptiveness even 335 | * for concurrent target queues. 336 | * 337 | * Connection event handlers are non-reentrant, so it is safe to call 338 | * xpc_connection_suspend() from within the event handler block. 339 | */ 340 | __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0) 341 | XPC_EXPORT XPC_NONNULL_ALL 342 | void 343 | xpc_connection_suspend(xpc_connection_t connection); 344 | 345 | /*! 346 | * @function xpc_connection_resume 347 | * Resumes the connection. Connections start in a suspended state, so you must 348 | * call xpc_connection_resume() on a connection before it will send or receive 349 | * any messages. 350 | * 351 | * @param connection 352 | * The connection object which is to be manipulated. 353 | * 354 | * @discussion 355 | * In order for a connection to become live, every call to 356 | * xpc_connection_suspend() must be balanced with a call to 357 | * xpc_connection_resume() after the initial call to xpc_connection_resume(). 358 | * After the initial resume of the connection, calling xpc_connection_resume() 359 | * more times than xpc_connection_suspend() has been called is considered an 360 | * error. 361 | */ 362 | __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0) 363 | XPC_EXPORT XPC_NONNULL_ALL 364 | void 365 | xpc_connection_resume(xpc_connection_t connection); 366 | 367 | /*! 368 | * @function xpc_connection_send_message 369 | * Sends a message over the connection to the destination service. 370 | * 371 | * @param connection 372 | * The connection over which the message shall be sent. 373 | * 374 | * @param message 375 | * The message to send. This must be a dictionary object. This dictionary is 376 | * logically copied by the connection, so it is safe to modify the dictionary 377 | * after this call. 378 | * 379 | * @discussion 380 | * Messages are delivered in FIFO order. This API is safe to call from multiple 381 | * GCD queues. There is no indication that a message was delivered successfully. 382 | * This is because even once the message has been successfully enqueued on the 383 | * remote end, there are no guarantees about when the runtime will dequeue the 384 | * message and invoke the other connection's event handler block. 385 | * 386 | * If this API is used to send a message that is in reply to another message, 387 | * there is no guarantee of ordering between the invocations of the connection's 388 | * event handler and the reply handler for that message, even if they are 389 | * targeted to the same queue. 390 | * 391 | * After extensive study, we have found that clients who are interested in 392 | * the state of the message on the server end are typically holding open 393 | * transactions related to that message. And the only reliable way to track the 394 | * lifetime of that transaction is at the protocol layer. So the server should 395 | * send a reply message, which upon receiving, will cause the client to close 396 | * its transaction. 397 | */ 398 | __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0) 399 | XPC_EXPORT XPC_NONNULL_ALL 400 | void 401 | xpc_connection_send_message(xpc_connection_t connection, xpc_object_t message); 402 | 403 | /*! 404 | * @function xpc_connection_send_barrier 405 | * Issues a barrier against the connection's message-send activity. 406 | * 407 | * @param connection 408 | * The connection against which the barrier is to be issued. 409 | * 410 | * @param barrier 411 | * The barrier block to issue. This barrier prevents concurrent message-send 412 | * activity on the connection. No messages will be sent while the barrier block 413 | * is executing. 414 | * 415 | * @discussion 416 | * XPC guarantees that, even if the connection's target queue is a concurrent 417 | * queue, there are no other messages being sent concurrently while the barrier 418 | * block is executing. XPC does not guarantee that the reciept of messages 419 | * (either through the connection's event handler or through reply handlers) 420 | * will be suspended while the barrier is executing. 421 | * 422 | * A barrier is issued relative to the message-send queue. Thus, if you call 423 | * xpc_connection_send_message() five times and then call 424 | * xpc_connection_send_barrier(), the barrier will be invoked after the fifth 425 | * message has been sent and its memory disposed of. You may safely cancel a 426 | * connection from within a barrier block. 427 | * 428 | * If a barrier is issued after sending a message which expects a reply, the 429 | * behavior is the same as described above. The receipt of a reply message will 430 | * not influence when the barrier runs. 431 | * 432 | * A barrier block can be useful for throttling resource consumption on the 433 | * connected side of a connection. For example, if your connection sends many 434 | * large messages, you can use a barrier to limit the number of messages that 435 | * are inflight at any given time. This can be particularly useful for messages 436 | * that contain kernel resources (like file descriptors) which have a system- 437 | * wide limit. 438 | * 439 | * If a barrier is issued on a canceled connection, it will be invoked 440 | * immediately. If a connection has been canceled and still has outstanding 441 | * barriers, those barriers will be invoked as part of the connection's 442 | * unwinding process. 443 | * 444 | * It is important to note that a barrier block's execution order is not 445 | * guaranteed with respect to other blocks that have been scheduled on the 446 | * target queue of the connection. Or said differently, 447 | * xpc_connection_send_barrier(3) is not equivalent to dispatch_async(3). 448 | */ 449 | __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0) 450 | XPC_EXPORT XPC_NONNULL_ALL 451 | void 452 | xpc_connection_send_barrier(xpc_connection_t connection, 453 | dispatch_block_t barrier); 454 | 455 | /*! 456 | * @function xpc_connection_send_message_with_reply 457 | * Sends a message over the connection to the destination service and associates 458 | * a handler to be invoked when the remote service sends a reply message. 459 | * 460 | * @param connection 461 | * The connection over which the message shall be sent. 462 | * 463 | * @param message 464 | * The message to send. This must be a dictionary object. 465 | * 466 | * @param replyq 467 | * The GCD queue to which the reply handler will be submitted. This may be a 468 | * concurrent queue. 469 | * 470 | * @param handler 471 | * The handler block to invoke when a reply to the message is received from 472 | * the connection. If the remote service exits prematurely before the reply was 473 | * received, the XPC_ERROR_CONNECTION_INTERRUPTED error will be returned. 474 | * If the connection went invalid before the message could be sent, the 475 | * XPC_ERROR_CONNECTION_INVALID error will be returned. 476 | * 477 | * @discussion 478 | * If the given GCD queue is a concurrent queue, XPC cannot guarantee that there 479 | * will not be multiple reply handlers being invoked concurrently. XPC does not 480 | * guarantee any ordering for the invocation of reply handers. So if multiple 481 | * messages are waiting for replies and the connection goes invalid, there is no 482 | * guarantee that the reply handlers will be invoked in FIFO order. Similarly, 483 | * XPC does not guarantee that reply handlers will not run concurrently with 484 | * the connection's event handler in the case that the reply queue and the 485 | * connection's target queue are the same concurrent queue. 486 | */ 487 | __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0) 488 | XPC_EXPORT XPC_NONNULL1 XPC_NONNULL2 XPC_NONNULL4 489 | void 490 | xpc_connection_send_message_with_reply(xpc_connection_t connection, 491 | xpc_object_t message, dispatch_queue_t replyq, xpc_handler_t handler); 492 | 493 | /*! 494 | * @function xpc_connection_send_message_with_reply_sync 495 | * Sends a message over the connection and blocks the caller until a reply is 496 | * received. 497 | * 498 | * @param connection 499 | * The connection over which the message shall be sent. 500 | * 501 | * @param message 502 | * The message to send. This must be a dictionary object. 503 | * 504 | * @result 505 | * The message that the remote service sent in reply to the original message. 506 | * If the remote service exits prematurely before the reply was received, the 507 | * XPC_ERROR_CONNECTION_INTERRUPTED error will be returned. If the connection 508 | * went invalid before the message could be sent, the 509 | * XPC_ERROR_CONNECTION_INVALID error will be returned. 510 | * 511 | * You are responsible for releasing the returned object. 512 | * 513 | * @discussion 514 | * This API is primarily for transitional purposes. Its implementation is 515 | * conceptually equivalent to calling xpc_connection_send_message_with_reply() 516 | * and then immediately blocking the calling thread on a semaphore and 517 | * signaling the semaphore from the reply block. 518 | * 519 | * Be judicious about your use of this API. It can block indefinitely, so if you 520 | * are using it to implement an API that can be called from the main thread, you 521 | * may wish to consider allowing the API to take a queue and callback block so 522 | * that results may be delivered asynchronously if possible. 523 | */ 524 | __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0) 525 | XPC_EXPORT XPC_NONNULL_ALL XPC_WARN_RESULT XPC_RETURNS_RETAINED 526 | xpc_object_t 527 | xpc_connection_send_message_with_reply_sync(xpc_connection_t connection, 528 | xpc_object_t message); 529 | 530 | /*! 531 | * @function xpc_connection_cancel 532 | * Cancels the connection and ensures that its event handler will not fire 533 | * again. After this call, any messages that have not yet been sent will be 534 | * discarded, and the connection will be unwound. If there are messages that are 535 | * awaiting replies, they will have their reply handlers invoked with the 536 | * XPC_ERROR_CONNECTION_INVALID error. 537 | * 538 | * @param connection 539 | * The connection object which is to be manipulated. 540 | * 541 | * @discussion 542 | * Cancellation is asynchronous and non-preemptive and therefore this method 543 | * will not interrupt the execution of an already-running event handler block. 544 | * If the event handler is executing at the time of this call, it will finish, 545 | * and then the connection will be canceled, causing a final invocation of the 546 | * event handler to be scheduled with the XPC_ERROR_CONNECTION_INVALID error. 547 | * After that invocation, there will be no further invocations of the event 548 | * handler. 549 | * 550 | * The XPC runtime guarantees this non-preemptiveness even for concurrent target 551 | * queues. 552 | */ 553 | __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0) 554 | XPC_EXPORT XPC_NONNULL_ALL 555 | void 556 | xpc_connection_cancel(xpc_connection_t connection); 557 | 558 | /*! 559 | * @function xpc_connection_get_name 560 | * Returns the name of the service with which the connections was created. 561 | * 562 | * @param connection 563 | * The connection object which is to be examined. 564 | * 565 | * @result 566 | * The name of the remote service. If you obtained the connection through an 567 | * invocation of another connection's event handler, NULL is returned. 568 | */ 569 | __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0) 570 | XPC_EXPORT XPC_NONNULL_ALL XPC_WARN_RESULT 571 | const char * 572 | xpc_connection_get_name(xpc_connection_t connection); 573 | 574 | /*! 575 | * @function xpc_connection_get_euid 576 | * Returns the EUID of the remote peer. 577 | * 578 | * @param connection 579 | * The connection object which is to be examined. 580 | * 581 | * @result 582 | * The EUID of the remote peer at the time the connection was made. 583 | */ 584 | __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0) 585 | XPC_EXPORT XPC_NONNULL_ALL XPC_WARN_RESULT 586 | uid_t 587 | xpc_connection_get_euid(xpc_connection_t connection); 588 | 589 | /*! 590 | * @function xpc_connection_get_egid 591 | * Returns the EGID of the remote peer. 592 | * 593 | * @param connection 594 | * The connection object which is to be examined. 595 | * 596 | * @result 597 | * The EGID of the remote peer at the time the connection was made. 598 | */ 599 | __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0) 600 | XPC_EXPORT XPC_NONNULL_ALL XPC_WARN_RESULT 601 | gid_t 602 | xpc_connection_get_egid(xpc_connection_t connection); 603 | 604 | /*! 605 | * @function xpc_connection_get_pid 606 | * Returns the PID of the remote peer. 607 | * 608 | * @param connection 609 | * The connection object which is to be examined. 610 | * 611 | * @result 612 | * The PID of the remote peer. 613 | * 614 | * @discussion 615 | * A given PID is not guaranteed to be unique across an entire boot cycle. 616 | * Great care should be taken when dealing with this information, as it can go 617 | * stale after the connection is established. OS X recycles PIDs, and therefore 618 | * another process could spawn and claim the PID before a message is actually 619 | * received from the connection. 620 | * 621 | * XPC will deliver an error to your event handler if the remote process goes 622 | * away, but there are no guarantees as to the timing of this notification's 623 | * delivery either at the kernel layer or at the XPC layer. 624 | */ 625 | __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0) 626 | XPC_EXPORT XPC_NONNULL_ALL XPC_WARN_RESULT 627 | pid_t 628 | xpc_connection_get_pid(xpc_connection_t connection); 629 | 630 | /*! 631 | * @function xpc_connection_get_asid 632 | * Returns the audit session identifier of the remote peer. 633 | * 634 | * @param connection 635 | * The connection object which is to be examined. 636 | * 637 | * @result 638 | * The audit session ID of the remote peer at the time the connection was made. 639 | */ 640 | __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0) 641 | XPC_EXPORT XPC_NONNULL_ALL XPC_WARN_RESULT 642 | au_asid_t 643 | xpc_connection_get_asid(xpc_connection_t connection); 644 | 645 | /*! 646 | * @function xpc_connection_set_context 647 | * Sets context on an connection. 648 | * 649 | * @param connection 650 | * The connection which is to be manipulated. 651 | * 652 | * @param context 653 | * The context to associate with the connection. 654 | * 655 | * @discussion 656 | * If you must manage the memory of the context object, you must set a finalizer 657 | * to dispose of it. If this method is called on a connection which already has 658 | * context associated with it, the finalizer will NOT be invoked. The finalizer 659 | * is only invoked when the connection is being deallocated. 660 | * 661 | * It is recommended that, instead of changing the actual context pointer 662 | * associated with the object, you instead change the state of the context 663 | * object itself. 664 | */ 665 | __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0) 666 | XPC_EXPORT XPC_NONNULL1 667 | void 668 | xpc_connection_set_context(xpc_connection_t connection, void *context); 669 | 670 | /*! 671 | * @function xpc_connection_get_context 672 | * Returns the context associated with the connection. 673 | * 674 | * @param connection 675 | * The connection which is to be examined. 676 | * 677 | * @result 678 | * The context associated with the connection. NULL if there has been no context 679 | * associated with the object. 680 | */ 681 | __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0) 682 | XPC_EXPORT XPC_NONNULL_ALL XPC_WARN_RESULT 683 | void * 684 | xpc_connection_get_context(xpc_connection_t connection); 685 | 686 | /*! 687 | * @function xpc_connection_set_finalizer_f 688 | * Sets the finalizer for the given connection. 689 | * 690 | * @param connection 691 | * The connection on which to set the finalizer. 692 | * 693 | * @param finalizer 694 | * The function that will be invoked when the connection's retain count has 695 | * dropped to zero and is being torn down. 696 | * 697 | * @discussion 698 | * This method disposes of the context value associated with a connection, as 699 | * set by {@link xpc_connection_set_context}. 700 | * 701 | * For many uses of context objects, this API allows for a convenient shorthand 702 | * for freeing them. For example, for a context object allocated with malloc(3): 703 | * 704 | * xpc_connection_set_finalizer_f(object, free); 705 | */ 706 | __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0) 707 | XPC_EXPORT XPC_NONNULL1 708 | void 709 | xpc_connection_set_finalizer_f(xpc_connection_t connection, 710 | xpc_finalizer_t finalizer); 711 | 712 | __END_DECLS 713 | 714 | #endif // __XPC_CONNECTION_H__ 715 | -------------------------------------------------------------------------------- /xpc/debug.h: -------------------------------------------------------------------------------- 1 | #ifndef __XPC_DEBUG_H__ 2 | #define __XPC_DEBUG_H__ 3 | 4 | /*! 5 | * @function xpc_debugger_api_misuse_info 6 | * Returns a pointer to a string describing the reason XPC aborted the calling 7 | * process. On OS X, this will be the same string present in the "Application 8 | * Specific Information" section of the crash report. 9 | * 10 | * @result 11 | * A pointer to the human-readable string describing the reason the caller was 12 | * aborted. If XPC was not responsible for the program's termination, NULL will 13 | * be returned. 14 | * 15 | * @discussion 16 | * This function is only callable from within a debugger. It is not meant to be 17 | * called by the program directly. 18 | */ 19 | XPC_DEBUGGER_EXCL 20 | const char * 21 | xpc_debugger_api_misuse_info(void); 22 | 23 | #endif // __XPC_DEBUG_H__ 24 | -------------------------------------------------------------------------------- /xpc/endpoint.h: -------------------------------------------------------------------------------- 1 | #ifndef __XPC_ENDPOINT_H__ 2 | #define __XPC_ENDPOINT_H__ 3 | 4 | /*! 5 | * @function xpc_endpoint_create 6 | * Creates a new endpoint from a connection that is suitable for embedding into 7 | * messages. 8 | * 9 | * @param connection 10 | * Only connections obtained through calls to xpc_connection_create*() may be 11 | * given to this API. Passing any other type of connection is not supported and 12 | * will result in undefined behavior. 13 | * 14 | * @result 15 | * A new endpoint object. 16 | */ 17 | __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0) 18 | XPC_EXPORT XPC_MALLOC XPC_RETURNS_RETAINED XPC_WARN_RESULT XPC_NONNULL1 19 | xpc_endpoint_t 20 | xpc_endpoint_create(xpc_connection_t connection); 21 | 22 | #endif // __XPC_ENDPOINT_H__ 23 | -------------------------------------------------------------------------------- /xpc/launchd.h: -------------------------------------------------------------------------------- 1 | #ifndef XPC_LAUNCHD_H_ 2 | #define XPC_LAUNCHD_H_ 3 | #include 4 | 5 | #define EXNOERROR 0 6 | #define EXNOMEM 1 7 | #define EXINVAL 2 8 | #define EXSRCH 3 9 | #define EXMAX EXSRCH 10 | 11 | const char *xpc_strerror(int error); 12 | xpc_object_t xpc_copy_entitlement_for_token(const char *, audit_token_t *); 13 | int xpc_pipe_routine_reply(xpc_object_t); 14 | int xpc_pipe_try_receive(mach_port_t, xpc_object_t *, mach_port_t *, 15 | boolean_t (*)(mach_msg_header_t *, mach_msg_header_t *), mach_msg_size_t, int); 16 | kern_return_t xpc_call_wakeup(mach_port_t, int); 17 | void xpc_dictionary_get_audit_token(xpc_object_t, audit_token_t *); 18 | void xpc_dictionary_set_mach_recv(xpc_object_t, const char *, mach_port_t); 19 | void xpc_dictionary_set_mach_send(xpc_object_t, const char *, mach_port_t); 20 | mach_port_t xpc_dictionary_copy_mach_send(xpc_object_t, const char *); 21 | xpc_object_t xpc_copy_entitlements_for_pid(pid_t); 22 | xpc_object_t ld2xpc(launch_data_t); 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /xpc_array.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2015 iXsystems, Inc. 3 | * All rights reserved 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted providing that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | * 26 | */ 27 | 28 | #include 29 | #include 30 | #include "xpc_internal.h" 31 | 32 | xpc_object_t 33 | xpc_array_create(const xpc_object_t *objects, size_t count) 34 | { 35 | struct xpc_object *xo; 36 | size_t i; 37 | xpc_u val; 38 | 39 | xo = _xpc_prim_create(_XPC_TYPE_ARRAY, val, 0); 40 | 41 | for (i = 0; i < count; i++) 42 | xpc_array_append_value(xo, objects[i]); 43 | 44 | return (xo); 45 | } 46 | 47 | void 48 | xpc_array_set_value(xpc_object_t xarray, size_t index, xpc_object_t value) 49 | { 50 | struct xpc_object *xo, *xotmp, *xotmp2; 51 | struct xpc_array_head *arr; 52 | size_t i; 53 | 54 | xo = xarray; 55 | arr = &xo->xo_array; 56 | i = 0; 57 | 58 | if (index == XPC_ARRAY_APPEND) 59 | return xpc_array_append_value(xarray, value); 60 | 61 | if (index >= (size_t)xo->xo_size) 62 | return; 63 | 64 | TAILQ_FOREACH_SAFE(xotmp, arr, xo_link, xotmp2) { 65 | if (i++ == index) { 66 | TAILQ_INSERT_AFTER(arr, (struct xpc_object *)value, 67 | xotmp, xo_link); 68 | TAILQ_REMOVE(arr, xotmp, xo_link); 69 | xpc_retain(value); 70 | free(xotmp); 71 | break; 72 | } 73 | } 74 | } 75 | 76 | void 77 | xpc_array_append_value(xpc_object_t xarray, xpc_object_t value) 78 | { 79 | struct xpc_object *xo; 80 | struct xpc_array_head *arr; 81 | 82 | xo = xarray; 83 | arr = &xo->xo_array; 84 | 85 | TAILQ_INSERT_TAIL(arr, (struct xpc_object *)value, xo_link); 86 | xpc_retain(value); 87 | } 88 | 89 | 90 | xpc_object_t 91 | xpc_array_get_value(xpc_object_t xarray, size_t index) 92 | { 93 | struct xpc_object *xo, *xotmp; 94 | struct xpc_array_head *arr; 95 | size_t i; 96 | 97 | xo = xarray; 98 | arr = &xo->xo_array; 99 | i = 0; 100 | 101 | if (index > xo->xo_size) 102 | return (NULL); 103 | 104 | TAILQ_FOREACH(xotmp, arr, xo_link) { 105 | if (i++ == index) 106 | return (xotmp); 107 | } 108 | 109 | return (NULL); 110 | } 111 | 112 | size_t 113 | xpc_array_get_count(xpc_object_t xarray) 114 | { 115 | struct xpc_object *xo; 116 | 117 | xo = xarray; 118 | return (xo->xo_size); 119 | } 120 | 121 | void 122 | xpc_array_set_bool(xpc_object_t xarray, size_t index, bool value) 123 | { 124 | struct xpc_object *xo, *xotmp; 125 | 126 | xo = xarray; 127 | xotmp = xpc_bool_create(value); 128 | return (xpc_array_set_value(xarray, index, xotmp)); 129 | } 130 | 131 | 132 | void 133 | xpc_array_set_int64(xpc_object_t xarray, size_t index, int64_t value) 134 | { 135 | struct xpc_object *xo, *xotmp; 136 | 137 | xo = xarray; 138 | xotmp = xpc_int64_create(value); 139 | return (xpc_array_set_value(xarray, index, xotmp)); 140 | } 141 | 142 | void 143 | xpc_array_set_uint64(xpc_object_t xarray, size_t index, uint64_t value) 144 | { 145 | struct xpc_object *xo, *xotmp; 146 | 147 | xo = xarray; 148 | xotmp = xpc_uint64_create(value); 149 | return (xpc_array_set_value(xarray, index, xotmp)); 150 | } 151 | 152 | void 153 | xpc_array_set_double(xpc_object_t xarray, size_t index, double value) 154 | { 155 | struct xpc_object *xo, *xotmp; 156 | 157 | xo = xarray; 158 | xotmp = xpc_double_create(value); 159 | return (xpc_array_set_value(xarray, index, xotmp)); 160 | } 161 | 162 | void 163 | xpc_array_set_date(xpc_object_t xarray, size_t index, int64_t value) 164 | { 165 | struct xpc_object *xo, *xotmp; 166 | 167 | xo = xarray; 168 | xotmp = xpc_date_create(value); 169 | return (xpc_array_set_value(xarray, index, xotmp)); 170 | } 171 | 172 | void 173 | xpc_array_set_data(xpc_object_t xarray, size_t index, const void *data, 174 | size_t length) 175 | { 176 | struct xpc_object *xo, *xotmp; 177 | 178 | xo = xarray; 179 | xotmp = xpc_data_create(data, length); 180 | return (xpc_array_set_value(xarray, index, xotmp)); 181 | } 182 | 183 | void 184 | xpc_array_set_string(xpc_object_t xarray, size_t index, const char *string) 185 | { 186 | struct xpc_object *xo, *xotmp; 187 | 188 | xo = xarray; 189 | xotmp = xpc_string_create(string); 190 | return (xpc_array_set_value(xarray, index, xotmp)); 191 | } 192 | 193 | void 194 | xpc_array_set_uuid(xpc_object_t xarray, size_t index, const uuid_t value) 195 | { 196 | struct xpc_object *xo, *xotmp; 197 | 198 | xo = xarray; 199 | xotmp = xpc_uuid_create(value); 200 | return (xpc_array_set_value(xarray, index, xotmp)); 201 | } 202 | 203 | void 204 | xpc_array_set_fd(xpc_object_t xarray, size_t index, int value) 205 | { 206 | struct xpc_object *xo, *xotmp; 207 | 208 | xo = xarray; 209 | //xotmp = xpc_fd_create(value); 210 | return (xpc_array_set_value(xarray, index, xotmp)); 211 | } 212 | 213 | void 214 | xpc_array_set_connection(xpc_object_t xarray, size_t index, 215 | xpc_connection_t value) 216 | { 217 | 218 | } 219 | 220 | bool 221 | xpc_array_get_bool(xpc_object_t xarray, size_t index) 222 | { 223 | struct xpc_object *xotmp; 224 | 225 | xotmp = xpc_array_get_value(xarray, index); 226 | return (xpc_bool_get_value(xotmp)); 227 | } 228 | 229 | int64_t 230 | xpc_array_get_int64(xpc_object_t xarray, size_t index) 231 | { 232 | struct xpc_object *xotmp; 233 | 234 | xotmp = xpc_array_get_value(xarray, index); 235 | return (xpc_int64_get_value(xotmp)); 236 | } 237 | 238 | uint64_t 239 | xpc_array_get_uint64(xpc_object_t xarray, size_t index) 240 | { 241 | struct xpc_object *xotmp; 242 | 243 | xotmp = xpc_array_get_value(xarray, index); 244 | return (xpc_uint64_get_value(xotmp)); 245 | } 246 | 247 | double 248 | xpc_array_get_double(xpc_object_t xarray, size_t index) 249 | { 250 | struct xpc_object *xotmp; 251 | 252 | xotmp = xpc_array_get_value(xarray, index); 253 | return (xpc_double_get_value(xotmp)); 254 | } 255 | 256 | int64_t 257 | xpc_array_get_date(xpc_object_t xarray, size_t index) 258 | { 259 | struct xpc_object *xotmp; 260 | 261 | xotmp = xpc_array_get_value(xarray, index); 262 | return (xpc_date_get_value(xotmp)); 263 | } 264 | 265 | const void * 266 | xpc_array_get_data(xpc_object_t xarray, size_t index, size_t *length) 267 | { 268 | struct xpc_object *xotmp; 269 | 270 | xotmp = xpc_array_get_value(xarray, index); 271 | *length = xpc_data_get_length(xotmp); 272 | return (xpc_data_get_bytes_ptr(xotmp)); 273 | } 274 | 275 | const uint8_t * 276 | xpc_array_get_uuid(xpc_object_t xarray, size_t index) 277 | { 278 | struct xpc_object *xotmp; 279 | 280 | xotmp = xpc_array_get_value(xarray, index); 281 | return (xpc_uuid_get_bytes(xotmp)); 282 | } 283 | 284 | const char * 285 | xpc_array_get_string(xpc_object_t xarray, size_t index) 286 | { 287 | struct xpc_object *xotmp; 288 | 289 | xotmp = xpc_array_get_value(xarray, index); 290 | return (xpc_string_get_string_ptr(xotmp)); 291 | } 292 | 293 | int 294 | xpc_array_dup_fd(xpc_object_t array, size_t index) 295 | { 296 | /* XXX */ 297 | return (-1); 298 | } 299 | 300 | xpc_connection_t 301 | xpc_array_get_connection(xpc_object_t array, size_t index) 302 | { 303 | /* XXX */ 304 | return (NULL); 305 | } 306 | 307 | bool 308 | xpc_array_apply(xpc_object_t xarray, xpc_array_applier_t applier) 309 | { 310 | struct xpc_object *xo, *xotmp; 311 | struct xpc_array_head *arr; 312 | size_t i; 313 | 314 | i = 0; 315 | xo = xarray; 316 | arr = &xo->xo_array; 317 | 318 | TAILQ_FOREACH(xotmp, arr, xo_link) { 319 | if (!applier(i++, xotmp)) 320 | return (false); 321 | } 322 | 323 | return (true); 324 | } 325 | -------------------------------------------------------------------------------- /xpc_connection.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2015 iXsystems, Inc. 3 | * All rights reserved 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted providing that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | * 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include "xpc_internal.h" 33 | 34 | #define XPC_CONNECTION_NEXT_ID(conn) (atomic_fetchadd_long(&conn->xc_last_id, 1)) 35 | 36 | static void xpc_send(xpc_connection_t xconn, xpc_object_t message, uint64_t id); 37 | 38 | xpc_connection_t 39 | xpc_connection_create(const char *name, dispatch_queue_t targetq) 40 | { 41 | char *qname; 42 | struct xpc_transport *transport = xpc_get_transport(); 43 | struct xpc_connection *conn; 44 | 45 | if ((conn = malloc(sizeof(struct xpc_connection))) == NULL) { 46 | errno = ENOMEM; 47 | return (NULL); 48 | } 49 | 50 | memset(conn, 0, sizeof(struct xpc_connection)); 51 | conn->xc_last_id = 1; 52 | TAILQ_INIT(&conn->xc_peers); 53 | TAILQ_INIT(&conn->xc_pending); 54 | 55 | /* Create send queue */ 56 | asprintf(&qname, "com.ixsystems.xpc.connection.sendq.%p", conn); 57 | conn->xc_send_queue = dispatch_queue_create(qname, NULL); 58 | 59 | /* Create recv queue */ 60 | asprintf(&qname, "com.ixsystems.xpc.connection.recvq.%p", conn); 61 | conn->xc_recv_queue = dispatch_queue_create(qname, NULL); 62 | 63 | /* Create target queue */ 64 | conn->xc_target_queue = targetq ? targetq : dispatch_get_main_queue(); 65 | 66 | /* Receive queue is initially suspended */ 67 | dispatch_suspend(conn->xc_recv_queue); 68 | 69 | return ((xpc_connection_t)conn); 70 | } 71 | 72 | xpc_connection_t 73 | xpc_connection_create_mach_service(const char *name, dispatch_queue_t targetq, 74 | uint64_t flags) 75 | { 76 | struct xpc_transport *transport = xpc_get_transport(); 77 | struct xpc_connection *conn; 78 | 79 | conn = (struct xpc_connection *)xpc_connection_create(name, targetq); 80 | if (conn == NULL) 81 | return (NULL); 82 | 83 | conn->xc_flags = flags; 84 | 85 | if (flags & XPC_CONNECTION_MACH_SERVICE_LISTENER) { 86 | if (transport->xt_listen(name, &conn->xc_local_port) != 0) { 87 | debugf("Cannot create local port: %s", strerror(errno)); 88 | return (NULL); 89 | } 90 | 91 | return ((xpc_connection_t)conn); 92 | } 93 | 94 | if (transport->xt_lookup(name, &conn->xc_local_port, &conn->xc_remote_port) != 0) { 95 | return (NULL); 96 | } 97 | 98 | return ((xpc_connection_t)conn); 99 | } 100 | 101 | xpc_connection_t 102 | xpc_connection_create_from_endpoint(xpc_endpoint_t endpoint) 103 | { 104 | struct xpc_connection *conn; 105 | 106 | conn = (struct xpc_connection *)xpc_connection_create("anonymous", NULL); 107 | if (conn == NULL) 108 | return (NULL); 109 | 110 | conn->xc_remote_port = (xpc_port_t)endpoint; 111 | return ((xpc_connection_t)conn); 112 | } 113 | 114 | void 115 | xpc_connection_set_target_queue(xpc_connection_t xconn, 116 | dispatch_queue_t targetq) 117 | { 118 | struct xpc_connection *conn; 119 | 120 | debugf("connection=%p", xconn); 121 | conn = (struct xpc_connection *)xconn; 122 | conn->xc_target_queue = targetq; 123 | } 124 | 125 | void 126 | xpc_connection_set_event_handler(xpc_connection_t xconn, 127 | xpc_handler_t handler) 128 | { 129 | struct xpc_connection *conn; 130 | 131 | debugf("connection=%p", xconn); 132 | conn = (struct xpc_connection *)xconn; 133 | conn->xc_handler = (xpc_handler_t)Block_copy(handler); 134 | } 135 | 136 | void 137 | xpc_connection_suspend(xpc_connection_t xconn) 138 | { 139 | struct xpc_connection *conn; 140 | 141 | conn = (struct xpc_connection *)xconn; 142 | dispatch_suspend(conn->xc_recv_source); 143 | } 144 | 145 | void 146 | xpc_connection_resume(xpc_connection_t xconn) 147 | { 148 | struct xpc_transport *transport = xpc_get_transport(); 149 | struct xpc_connection *conn; 150 | 151 | debugf("connection=%p", xconn); 152 | conn = (struct xpc_connection *)xconn; 153 | 154 | /* Create dispatch source for top-level connection */ 155 | if (conn->xc_flags & XPC_CONNECTION_MACH_SERVICE_LISTENER) { 156 | conn->xc_recv_source = transport->xt_create_server_source( 157 | conn->xc_local_port, conn, conn->xc_recv_queue); 158 | dispatch_resume(conn->xc_recv_source); 159 | } else { 160 | if (conn->xc_parent == NULL) { 161 | conn->xc_recv_source = transport->xt_create_client_source( 162 | conn->xc_local_port, conn, conn->xc_recv_queue); 163 | dispatch_resume(conn->xc_recv_source); 164 | } 165 | } 166 | 167 | dispatch_resume(conn->xc_recv_queue); 168 | } 169 | 170 | void 171 | xpc_connection_send_message(xpc_connection_t xconn, 172 | xpc_object_t message) 173 | { 174 | struct xpc_connection *conn; 175 | uint64_t id; 176 | 177 | conn = (struct xpc_connection *)xconn; 178 | id = xpc_dictionary_get_uint64(message, XPC_SEQID); 179 | 180 | if (id == 0) 181 | id = XPC_CONNECTION_NEXT_ID(conn); 182 | 183 | dispatch_async(conn->xc_send_queue, ^{ 184 | xpc_send(xconn, message, id); 185 | }); 186 | } 187 | 188 | void 189 | xpc_connection_send_message_with_reply(xpc_connection_t xconn, 190 | xpc_object_t message, dispatch_queue_t targetq, xpc_handler_t handler) 191 | { 192 | struct xpc_connection *conn; 193 | struct xpc_pending_call *call; 194 | 195 | conn = (struct xpc_connection *)xconn; 196 | call = malloc(sizeof(struct xpc_pending_call)); 197 | call->xp_id = XPC_CONNECTION_NEXT_ID(conn); 198 | call->xp_handler = handler; 199 | call->xp_queue = targetq; 200 | TAILQ_INSERT_TAIL(&conn->xc_pending, call, xp_link); 201 | 202 | dispatch_async(conn->xc_send_queue, ^{ 203 | xpc_send(xconn, message, call->xp_id); 204 | }); 205 | 206 | } 207 | 208 | xpc_object_t 209 | xpc_connection_send_message_with_reply_sync(xpc_connection_t conn, 210 | xpc_object_t message) 211 | { 212 | __block xpc_object_t result; 213 | dispatch_semaphore_t sem = dispatch_semaphore_create(0); 214 | 215 | xpc_connection_send_message_with_reply(conn, message, NULL, 216 | ^(xpc_object_t o) { 217 | result = o; 218 | dispatch_semaphore_signal(sem); 219 | }); 220 | 221 | dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); 222 | return (result); 223 | } 224 | 225 | void 226 | xpc_connection_send_barrier(xpc_connection_t xconn, dispatch_block_t barrier) 227 | { 228 | struct xpc_connection *conn; 229 | 230 | conn = (struct xpc_connection *)xconn; 231 | dispatch_sync(conn->xc_send_queue, barrier); 232 | } 233 | 234 | void 235 | xpc_connection_cancel(xpc_connection_t connection) 236 | { 237 | 238 | } 239 | 240 | const char * 241 | xpc_connection_get_name(xpc_connection_t connection) 242 | { 243 | 244 | return ("unknown"); /* ??? */ 245 | } 246 | 247 | uid_t 248 | xpc_connection_get_euid(xpc_connection_t xconn) 249 | { 250 | struct xpc_connection *conn; 251 | 252 | conn = (struct xpc_connection *)xconn; 253 | return (conn->xc_creds.xc_remote_euid); 254 | } 255 | 256 | gid_t 257 | xpc_connection_get_egid(xpc_connection_t xconn) 258 | { 259 | struct xpc_connection *conn; 260 | 261 | conn = (struct xpc_connection *)xconn; 262 | return (conn->xc_creds.xc_remote_guid); 263 | } 264 | 265 | pid_t 266 | xpc_connection_get_pid(xpc_connection_t xconn) 267 | { 268 | struct xpc_connection *conn; 269 | 270 | conn = (struct xpc_connection *)xconn; 271 | return (conn->xc_creds.xc_remote_pid); 272 | } 273 | 274 | #ifdef MACH 275 | au_asid_t 276 | xpc_connection_get_asid(xpc_connection_t xconn) 277 | { 278 | struct xpc_connection *conn; 279 | 280 | conn = xconn; 281 | return (conn->xc_creds.xc_remote_asid); 282 | } 283 | #endif 284 | 285 | void 286 | xpc_connection_set_context(xpc_connection_t xconn, void *ctx) 287 | { 288 | struct xpc_connection *conn; 289 | 290 | conn = (struct xpc_connection *)xconn; 291 | conn->xc_context = ctx; 292 | } 293 | 294 | void * 295 | xpc_connection_get_context(xpc_connection_t xconn) 296 | { 297 | struct xpc_connection *conn; 298 | 299 | conn = (struct xpc_connection *)xconn; 300 | return (conn->xc_context); 301 | } 302 | 303 | void 304 | xpc_connection_set_finalizer_f(xpc_connection_t connection, 305 | xpc_finalizer_t finalizer) 306 | { 307 | 308 | } 309 | 310 | xpc_endpoint_t 311 | xpc_endpoint_create(xpc_connection_t connection) 312 | { 313 | return (NULL); 314 | } 315 | 316 | void 317 | xpc_main(xpc_connection_handler_t handler) 318 | { 319 | 320 | dispatch_main(); 321 | } 322 | 323 | void 324 | xpc_transaction_begin(void) 325 | { 326 | 327 | } 328 | 329 | void 330 | xpc_transaction_end(void) 331 | { 332 | 333 | } 334 | 335 | static void 336 | xpc_send(xpc_connection_t xconn, xpc_object_t message, uint64_t id) 337 | { 338 | struct xpc_connection *conn; 339 | int err; 340 | 341 | debugf("connection=%p, message=%p, id=%lu", xconn, message, id); 342 | 343 | conn = (struct xpc_connection *)xconn; 344 | if (xpc_pipe_send(message, id, conn->xc_local_port, 345 | conn->xc_remote_port) != 0) 346 | debugf("send failed: %s", strerror(errno)); 347 | } 348 | 349 | #ifdef MACH 350 | static void 351 | xpc_connection_set_credentials(struct xpc_connection *conn, audit_token_t *tok) 352 | { 353 | uid_t uid; 354 | gid_t gid; 355 | pid_t pid; 356 | au_asid_t asid; 357 | 358 | if (tok == NULL) 359 | return; 360 | 361 | audit_token_to_au32(*tok, NULL, &uid, &gid, NULL, NULL, &pid, &asid, 362 | NULL); 363 | 364 | conn->xc_creds.xc_remote_euid = uid; 365 | conn->xc_creds.xc_remote_guid = gid; 366 | conn->xc_creds.xc_remote_pid = pid; 367 | conn->xc_creds.xc_remote_asid = asid; 368 | } 369 | #endif 370 | 371 | struct xpc_connection * 372 | xpc_connection_get_peer(void *context, xpc_port_t port) 373 | { 374 | struct xpc_transport *transport = xpc_get_transport(); 375 | struct xpc_connection *conn, *peer; 376 | 377 | conn = context; 378 | TAILQ_FOREACH(peer, &conn->xc_peers, xc_link) { 379 | if (transport->xt_port_compare(port, 380 | peer->xc_remote_port)) { 381 | return (peer); 382 | } 383 | } 384 | 385 | return (NULL); 386 | } 387 | 388 | void * 389 | xpc_connection_new_peer(void *context, xpc_port_t local, xpc_port_t remote, dispatch_source_t src) 390 | { 391 | struct xpc_transport *transport = xpc_get_transport(); 392 | struct xpc_connection *conn, *peer; 393 | 394 | conn = context; 395 | peer = (struct xpc_connection *)xpc_connection_create(NULL, NULL); 396 | peer->xc_parent = conn; 397 | peer->xc_local_port = local; 398 | peer->xc_remote_port = remote; 399 | peer->xc_recv_source = src; 400 | 401 | TAILQ_INSERT_TAIL(&conn->xc_peers, peer, xc_link); 402 | 403 | if (src) { 404 | dispatch_set_context(src, peer); 405 | dispatch_resume(src); 406 | dispatch_async(conn->xc_target_queue, ^{ 407 | conn->xc_handler(peer); 408 | }); 409 | } 410 | 411 | return (peer); 412 | } 413 | 414 | void 415 | xpc_connection_destroy_peer(void *context) 416 | { 417 | struct xpc_connection *conn, *parent; 418 | 419 | conn = context; 420 | parent = conn->xc_parent; 421 | 422 | if (conn->xc_parent != NULL) { 423 | dispatch_async(parent->xc_target_queue, ^{ 424 | conn->xc_handler((xpc_object_t)XPC_ERROR_CONNECTION_INVALID); 425 | }); 426 | 427 | TAILQ_REMOVE(&parent->xc_peers, conn, xc_link); 428 | } 429 | 430 | dispatch_release(conn->xc_recv_source); 431 | } 432 | 433 | static void 434 | xpc_connection_dispatch_callback(struct xpc_connection *conn, 435 | xpc_object_t result, uint64_t id) 436 | { 437 | struct xpc_pending_call *call; 438 | 439 | TAILQ_FOREACH(call, &conn->xc_pending, xp_link) { 440 | if (call->xp_id == id) { 441 | dispatch_async(conn->xc_target_queue, ^{ 442 | call->xp_handler(result); 443 | TAILQ_REMOVE(&conn->xc_pending, call, 444 | xp_link); 445 | free(call); 446 | }); 447 | return; 448 | } 449 | } 450 | 451 | if (conn->xc_handler) { 452 | debugf("yes"); 453 | dispatch_async(conn->xc_target_queue, ^{ 454 | debugf("calling handler=%p", conn->xc_handler); 455 | conn->xc_handler(result); 456 | }); 457 | } 458 | } 459 | 460 | void 461 | xpc_connection_recv_message(void *context) 462 | { 463 | struct xpc_pending_call *call; 464 | struct xpc_connection *conn; 465 | struct xpc_credentials creds; 466 | xpc_object_t result; 467 | xpc_port_t remote; 468 | uint64_t id; 469 | int err; 470 | 471 | debugf("connection=%p", context); 472 | 473 | conn = context; 474 | err = xpc_pipe_receive(conn->xc_local_port, &remote, &result, &id, 475 | &creds); 476 | 477 | if (err < 0) 478 | return; 479 | 480 | if (err == 0) { 481 | dispatch_source_cancel(conn->xc_recv_source); 482 | return; 483 | } 484 | 485 | debugf("msg=%p, id=%lu", result, id); 486 | 487 | conn->xc_creds = creds; 488 | 489 | xpc_connection_dispatch_callback(conn, result, id); 490 | } 491 | 492 | void 493 | xpc_connection_recv_mach_message(void *context) 494 | { 495 | struct xpc_transport *transport = xpc_get_transport(); 496 | 497 | struct xpc_connection *conn, *peer; 498 | struct xpc_credentials creds; 499 | xpc_object_t result; 500 | xpc_port_t remote; 501 | uint64_t id; 502 | int err; 503 | 504 | debugf("connection=%p", context); 505 | 506 | conn = context; 507 | if (xpc_pipe_receive(conn->xc_local_port, &remote, &result, &id, 508 | &creds) < 0) 509 | return; 510 | 511 | debugf("message=%p, id=%lu, remote=%s", result, id, 512 | transport->xt_port_to_string(remote)); 513 | 514 | peer = xpc_connection_get_peer(context, remote); 515 | if (!peer) { 516 | debugf("new peer on port %s", 517 | transport->xt_port_to_string(remote)); 518 | peer = xpc_connection_new_peer(context, conn->xc_local_port, remote, NULL); 519 | 520 | dispatch_async(conn->xc_target_queue, ^{ 521 | conn->xc_handler(peer); 522 | xpc_connection_dispatch_callback(peer, result, id); 523 | }); 524 | } else 525 | xpc_connection_dispatch_callback(peer, result, id); 526 | } -------------------------------------------------------------------------------- /xpc_dictionary.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2015 iXsystems, Inc. 3 | * All rights reserved 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted providing that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | * 26 | */ 27 | 28 | #include 29 | #include "xpc/xpc.h" 30 | #include "xpc_internal.h" 31 | #include "mpack.h" 32 | 33 | static struct xpc_object * 34 | mpack2xpc_extension(int8_t type, const char *data) 35 | { 36 | 37 | } 38 | 39 | struct xpc_object * 40 | mpack2xpc(const mpack_node_t node) 41 | { 42 | xpc_object_t xotmp; 43 | size_t i; 44 | xpc_u val; 45 | 46 | switch (mpack_node_type(node)) { 47 | case mpack_type_nil: 48 | xotmp = xpc_null_create(); 49 | break; 50 | 51 | case mpack_type_int: 52 | val.i = mpack_node_i64(node); 53 | xotmp = xpc_int64_create(val.i); 54 | break; 55 | 56 | case mpack_type_uint: 57 | val.ui = mpack_node_u64(node); 58 | xotmp = xpc_uint64_create(val.ui); 59 | break; 60 | 61 | case mpack_type_bool: 62 | val.b = mpack_node_bool(node); 63 | xotmp = xpc_bool_create(val.b); 64 | break; 65 | 66 | case mpack_type_double: 67 | val.d = mpack_node_double(node); 68 | xotmp = xpc_double_create(val.d); 69 | break; 70 | 71 | case mpack_type_str: 72 | val.str = mpack_node_cstr_alloc(node, 65536); 73 | xotmp = xpc_string_create(val.str); 74 | break; 75 | 76 | case mpack_type_bin: 77 | break; 78 | 79 | case mpack_type_array: 80 | xotmp = xpc_array_create(NULL, 0); 81 | for (i = 0; i < mpack_node_array_length(node); i++) { 82 | xpc_object_t item = mpack2xpc( 83 | mpack_node_array_at(node, i)); 84 | xpc_array_append_value(item, xotmp); 85 | } 86 | break; 87 | 88 | case mpack_type_map: 89 | xotmp = xpc_dictionary_create(NULL, NULL, 0); 90 | for (i = 0; i < mpack_node_map_count(node); i++) { 91 | char *key = mpack_node_cstr_alloc( 92 | mpack_node_map_key_at(node, i), 1024); 93 | xpc_object_t value = mpack2xpc( 94 | mpack_node_map_value_at(node, i)); 95 | xpc_dictionary_set_value(xotmp, key, value); 96 | } 97 | break; 98 | 99 | case mpack_type_ext: 100 | xotmp = mpack2xpc_extension(mpack_node_exttype(node), 101 | mpack_node_data(node)); 102 | break; 103 | 104 | default: 105 | xotmp = NULL; 106 | break; 107 | } 108 | 109 | return (xotmp); 110 | } 111 | 112 | void 113 | xpc2mpack(mpack_writer_t *writer, xpc_object_t obj) 114 | { 115 | struct xpc_object *xotmp = obj; 116 | 117 | switch (xotmp->xo_xpc_type) { 118 | case _XPC_TYPE_DICTIONARY: 119 | mpack_start_map(writer, xpc_dictionary_get_count(obj)); 120 | xpc_dictionary_apply(obj, ^(const char *k, xpc_object_t v) { 121 | mpack_write_cstr(writer, k); 122 | xpc2mpack(writer, v); 123 | return ((bool)true); 124 | }); 125 | mpack_finish_map(writer); 126 | break; 127 | 128 | case _XPC_TYPE_ARRAY: 129 | mpack_start_array(writer, xpc_array_get_count(obj)); 130 | xpc_array_apply(obj, ^(size_t index __unused, xpc_object_t v) { 131 | xpc2mpack(writer, v); 132 | return ((bool)true); 133 | }); 134 | mpack_finish_map(writer); 135 | break; 136 | 137 | case _XPC_TYPE_NULL: 138 | mpack_write_nil(writer); 139 | break; 140 | 141 | case _XPC_TYPE_BOOL: 142 | mpack_write_bool(writer, xpc_bool_get_value(obj)); 143 | break; 144 | 145 | case _XPC_TYPE_INT64: 146 | mpack_write_i64(writer, xpc_int64_get_value(obj)); 147 | break; 148 | 149 | case _XPC_TYPE_DOUBLE: 150 | mpack_write_double(writer, xpc_double_get_value(obj)); 151 | 152 | case _XPC_TYPE_UINT64: 153 | mpack_write_u64(writer, xpc_uint64_get_value(obj)); 154 | break; 155 | 156 | case _XPC_TYPE_STRING: 157 | mpack_write_cstr(writer, xpc_string_get_string_ptr(obj)); 158 | break; 159 | 160 | case _XPC_TYPE_UUID: 161 | break; 162 | } 163 | } 164 | 165 | xpc_object_t 166 | xpc_dictionary_create(const char * const *keys, const xpc_object_t *values, 167 | size_t count) 168 | { 169 | struct xpc_object *xo; 170 | size_t i; 171 | xpc_u val; 172 | 173 | xo = _xpc_prim_create(_XPC_TYPE_DICTIONARY, val, count); 174 | 175 | for (i = 0; i < count; i++) 176 | xpc_dictionary_set_value(xo, keys[i], values[i]); 177 | 178 | return (xo); 179 | } 180 | 181 | xpc_object_t 182 | xpc_dictionary_create_reply(xpc_object_t original) 183 | { 184 | struct xpc_object *xo_orig; 185 | 186 | xo_orig = original; 187 | if ((xo_orig->xo_flags & _XPC_FROM_WIRE) == 0) 188 | return (NULL); 189 | 190 | return xpc_dictionary_create(NULL, NULL, 0); 191 | } 192 | 193 | #ifdef MACH 194 | void 195 | xpc_dictionary_get_audit_token(xpc_object_t xdict, audit_token_t *token) 196 | { 197 | struct xpc_object *xo; 198 | 199 | xo = xdict; 200 | if (xo->xo_audit_token != NULL) 201 | memcpy(token, xo->xo_audit_token, sizeof(*token)); 202 | } 203 | 204 | void 205 | xpc_dictionary_set_mach_recv(xpc_object_t xdict, const char *key, 206 | mach_port_t port) 207 | { 208 | struct xpc_object *xo = xdict; 209 | struct xpc_object *xotmp; 210 | xpc_u val; 211 | 212 | val.port = port; 213 | xotmp = _xpc_prim_create(_XPC_TYPE_ENDPOINT, val, 0); 214 | 215 | xpc_dictionary_set_value(xdict, key, xotmp); 216 | } 217 | 218 | void 219 | xpc_dictionary_set_mach_send(xpc_object_t xdict, const char *key, 220 | mach_port_t port) 221 | { 222 | struct xpc_object *xotmp; 223 | xpc_u val; 224 | 225 | val.port = port; 226 | xotmp = _xpc_prim_create(_XPC_TYPE_ENDPOINT, val, 0); 227 | 228 | xpc_dictionary_set_value(xdict, key, xotmp); 229 | } 230 | 231 | mach_port_t 232 | xpc_dictionary_copy_mach_send(xpc_object_t xdict, const char *key) 233 | { 234 | struct xpc_object *xo; 235 | const struct xpc_object *xotmp; 236 | 237 | } 238 | #endif 239 | 240 | void 241 | xpc_dictionary_set_value(xpc_object_t xdict, const char *key, 242 | xpc_object_t value) 243 | { 244 | struct xpc_object *xo; 245 | struct xpc_dict_head *head; 246 | struct xpc_dict_pair *pair; 247 | 248 | xo = xdict; 249 | head = &xo->xo_dict; 250 | 251 | TAILQ_FOREACH(pair, head, xo_link) { 252 | if (!strcmp(pair->key, key)) { 253 | pair->value = value; 254 | return; 255 | } 256 | } 257 | 258 | xo->xo_size++; 259 | pair = malloc(sizeof(struct xpc_dict_pair)); 260 | pair->key = key; 261 | pair->value = value; 262 | TAILQ_INSERT_TAIL(&xo->xo_dict, pair, xo_link); 263 | xpc_retain(value); 264 | } 265 | 266 | xpc_object_t 267 | xpc_dictionary_get_value(xpc_object_t xdict, const char *key) 268 | { 269 | struct xpc_object *xo; 270 | struct xpc_dict_head *head; 271 | struct xpc_dict_pair *pair; 272 | 273 | xo = xdict; 274 | head = &xo->xo_dict; 275 | 276 | TAILQ_FOREACH(pair, head, xo_link) { 277 | if (!strcmp(pair->key, key)) 278 | return (pair->value); 279 | } 280 | 281 | return (NULL); 282 | } 283 | 284 | size_t 285 | xpc_dictionary_get_count(xpc_object_t xdict) 286 | { 287 | struct xpc_object *xo; 288 | 289 | xo = xdict; 290 | return (xo->xo_size); 291 | } 292 | 293 | void 294 | xpc_dictionary_set_bool(xpc_object_t xdict, const char *key, bool value) 295 | {; 296 | struct xpc_object *xo, *xotmp; 297 | 298 | xo = xdict; 299 | xotmp = xpc_bool_create(value); 300 | xpc_dictionary_set_value(xdict, key, xotmp); 301 | } 302 | 303 | void 304 | xpc_dictionary_set_int64(xpc_object_t xdict, const char *key, int64_t value) 305 | { 306 | struct xpc_object *xo, *xotmp; 307 | 308 | xo = xdict; 309 | xotmp = xpc_int64_create(value); 310 | xpc_dictionary_set_value(xdict, key, xotmp); 311 | } 312 | 313 | void 314 | xpc_dictionary_set_uint64(xpc_object_t xdict, const char *key, uint64_t value) 315 | { 316 | struct xpc_object *xo, *xotmp; 317 | 318 | xo = xdict; 319 | xotmp = xpc_uint64_create(value); 320 | xpc_dictionary_set_value(xdict, key, xotmp); 321 | } 322 | 323 | void 324 | xpc_dictionary_set_string(xpc_object_t xdict, const char *key, 325 | const char *value) 326 | { 327 | struct xpc_object *xo, *xotmp; 328 | 329 | xo = xdict; 330 | xotmp = xpc_string_create(value); 331 | xpc_dictionary_set_value(xdict, key, xotmp); 332 | } 333 | 334 | bool 335 | xpc_dictionary_get_bool(xpc_object_t xdict, const char *key) 336 | { 337 | xpc_object_t xo; 338 | 339 | xo = xpc_dictionary_get_value(xdict, key); 340 | return (xpc_bool_get_value(xo)); 341 | } 342 | 343 | int64_t 344 | xpc_dictionary_get_int64(xpc_object_t xdict, const char *key) 345 | { 346 | xpc_object_t xo; 347 | 348 | xo = xpc_dictionary_get_value(xdict, key); 349 | return (xpc_int64_get_value(xo)); 350 | } 351 | 352 | uint64_t 353 | xpc_dictionary_get_uint64(xpc_object_t xdict, const char *key) 354 | { 355 | xpc_object_t xo; 356 | 357 | xo = xpc_dictionary_get_value(xdict, key); 358 | return (xpc_uint64_get_value(xo)); 359 | } 360 | 361 | const char * 362 | xpc_dictionary_get_string(xpc_object_t xdict, const char *key) 363 | { 364 | xpc_object_t xo; 365 | 366 | xo = xpc_dictionary_get_value(xdict, key); 367 | return (xpc_string_get_string_ptr(xo)); 368 | } 369 | 370 | bool 371 | xpc_dictionary_apply(xpc_object_t xdict, xpc_dictionary_applier_t applier) 372 | { 373 | struct xpc_object *xo, *xotmp; 374 | struct xpc_dict_head *head; 375 | struct xpc_dict_pair *pair; 376 | 377 | xo = xdict; 378 | head = &xo->xo_dict; 379 | 380 | TAILQ_FOREACH(pair, head, xo_link) { 381 | if (!applier(pair->key, pair->value)) 382 | return (false); 383 | } 384 | 385 | return (true); 386 | } 387 | -------------------------------------------------------------------------------- /xpc_internal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2015 iXsystems, Inc. 3 | * All rights reserved 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted providing that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | * 26 | */ 27 | 28 | #ifndef _LIBXPC_XPC_INTERNAL_H 29 | #define _LIBXPC_XPC_INTERNAL_H 30 | 31 | #include 32 | #include 33 | #include 34 | #include "mpack.h" 35 | 36 | #ifdef XPC_DEBUG 37 | #define debugf(...) \ 38 | do { \ 39 | fprintf(stderr, "%s: ", __func__); \ 40 | fprintf(stderr, __VA_ARGS__); \ 41 | fprintf(stderr, "\n"); \ 42 | } while(0); 43 | #else 44 | #define debugf(...) 45 | #endif 46 | 47 | #define _XPC_TYPE_INVALID 0 48 | #define _XPC_TYPE_DICTIONARY 1 49 | #define _XPC_TYPE_ARRAY 2 50 | #define _XPC_TYPE_BOOL 3 51 | #define _XPC_TYPE_CONNECTION 4 52 | #define _XPC_TYPE_ENDPOINT 5 53 | #define _XPC_TYPE_NULL 6 54 | #define _XPC_TYPE_INT64 8 55 | #define _XPC_TYPE_UINT64 9 56 | #define _XPC_TYPE_DATE 10 57 | #define _XPC_TYPE_DATA 11 58 | #define _XPC_TYPE_STRING 12 59 | #define _XPC_TYPE_UUID 13 60 | #define _XPC_TYPE_FD 14 61 | #define _XPC_TYPE_SHMEM 15 62 | #define _XPC_TYPE_ERROR 16 63 | #define _XPC_TYPE_DOUBLE 17 64 | #define _XPC_TYPE_MAX _XPC_TYPE_DOUBLE 65 | 66 | #define XPC_SEQID "XPC sequence number" 67 | #define XPC_PROTOCOL_VERSION 1 68 | 69 | struct xpc_object; 70 | struct xpc_dict_pair; 71 | struct xpc_resource; 72 | struct xpc_credentials; 73 | 74 | TAILQ_HEAD(xpc_dict_head, xpc_dict_pair); 75 | TAILQ_HEAD(xpc_array_head, xpc_object); 76 | 77 | typedef void *xpc_port_t; 78 | typedef void (*xpc_transport_init_t)(); 79 | typedef int (*xpc_transport_listen_t)(const char *, xpc_port_t *); 80 | typedef int (*xpc_transport_lookup)(const char *, xpc_port_t *, xpc_port_t *); 81 | typedef char *(*xpc_transport_port_to_string)(xpc_port_t); 82 | typedef int (*xpc_transport_port_compare)(xpc_port_t, xpc_port_t); 83 | typedef int (*xpc_transport_release)(xpc_port_t); 84 | typedef int (*xpc_transport_send)(xpc_port_t, xpc_port_t, void *buf, 85 | size_t len, struct xpc_resource *, size_t); 86 | typedef int(*xpc_transport_recv)(xpc_port_t, xpc_port_t*, void *buf, 87 | size_t len, struct xpc_resource **, size_t *, struct xpc_credentials *); 88 | typedef dispatch_source_t (*xpc_transport_create_source)(xpc_port_t, 89 | void *, dispatch_queue_t); 90 | 91 | typedef union { 92 | struct xpc_dict_head dict; 93 | struct xpc_array_head array; 94 | uint64_t ui; 95 | int64_t i; 96 | char *str; 97 | bool b; 98 | double d; 99 | uintptr_t ptr; 100 | int fd; 101 | uuid_t uuid; 102 | #ifdef MACH 103 | mach_port_t port; 104 | #endif 105 | } xpc_u; 106 | 107 | struct xpc_frame_header { 108 | uint64_t version; 109 | uint64_t id; 110 | uint64_t length; 111 | uint64_t spare[4]; 112 | }; 113 | 114 | #define _XPC_FROM_WIRE 0x1 115 | struct xpc_object { 116 | uint8_t xo_xpc_type; 117 | uint16_t xo_flags; 118 | volatile uint32_t xo_refcnt; 119 | size_t xo_size; 120 | xpc_u xo_u; 121 | #ifdef MACH 122 | audit_token_t * xo_audit_token; 123 | #endif 124 | TAILQ_ENTRY(xpc_object) xo_link; 125 | }; 126 | 127 | struct xpc_dict_pair { 128 | const char * key; 129 | struct xpc_object * value; 130 | TAILQ_ENTRY(xpc_dict_pair) xo_link; 131 | }; 132 | 133 | struct xpc_pending_call { 134 | uint64_t xp_id; 135 | xpc_object_t xp_response; 136 | dispatch_queue_t xp_queue; 137 | xpc_handler_t xp_handler; 138 | TAILQ_ENTRY(xpc_pending_call) xp_link; 139 | }; 140 | 141 | struct xpc_credentials { 142 | uid_t xc_remote_euid; 143 | gid_t xc_remote_guid; 144 | pid_t xc_remote_pid; 145 | #ifdef MACH 146 | au_asid_t xc_remote_asid; 147 | audit_token_t xc_audit_token; 148 | #endif 149 | }; 150 | 151 | struct xpc_connection { 152 | const char * xc_name; 153 | xpc_port_t xc_local_port; 154 | xpc_port_t xc_remote_port; 155 | xpc_handler_t xc_handler; 156 | dispatch_source_t xc_recv_source; 157 | dispatch_queue_t xc_send_queue; 158 | dispatch_queue_t xc_recv_queue; 159 | dispatch_queue_t xc_target_queue; 160 | int xc_suspend_count; 161 | int xc_transaction_count; 162 | uint64_t xc_flags; 163 | volatile uint64_t xc_last_id; 164 | void * xc_context; 165 | struct xpc_connection * xc_parent; 166 | struct xpc_credentials xc_creds; 167 | TAILQ_HEAD(, xpc_pending_call) xc_pending; 168 | TAILQ_HEAD(, xpc_connection) xc_peers; 169 | TAILQ_ENTRY(xpc_connection) xc_link; 170 | }; 171 | 172 | struct xpc_resource { 173 | int xr_type; 174 | #define XPC_RESOURCE_FD 0x01 175 | #define XPC_RESOURCE_SHMEM 0x02 176 | union { 177 | int xr_fd; 178 | }; 179 | }; 180 | 181 | struct xpc_transport { 182 | const char * xt_name; 183 | pthread_once_t xt_initialized; 184 | xpc_transport_init_t xt_init; 185 | xpc_transport_listen_t xt_listen; 186 | xpc_transport_lookup xt_lookup; 187 | xpc_transport_port_to_string xt_port_to_string; 188 | xpc_transport_port_compare xt_port_compare; 189 | xpc_transport_release xt_release; 190 | xpc_transport_send xt_send; 191 | xpc_transport_recv xt_recv; 192 | xpc_transport_create_source xt_create_server_source; 193 | xpc_transport_create_source xt_create_client_source; 194 | }; 195 | 196 | struct xpc_service { 197 | xpc_port_t xs_pipe; 198 | TAILQ_HEAD(, xpc_connection) xs_connections; 199 | }; 200 | 201 | #define xo_str xo_u.str 202 | #define xo_bool xo_u.b 203 | #define xo_uint xo_u.ui 204 | #define xo_int xo_u.i 205 | #define xo_ptr xo_u.ptr 206 | #define xo_d xo_u.d 207 | #define xo_fd xo_u.fd 208 | #define xo_uuid xo_u.uuid 209 | #define xo_port xo_u.port 210 | #define xo_array xo_u.array 211 | #define xo_dict xo_u.dict 212 | 213 | __private_extern__ struct xpc_transport *xpc_get_transport(); 214 | __private_extern__ void xpc_set_transport(struct xpc_transport *); 215 | __private_extern__ struct xpc_object *_xpc_prim_create(int type, xpc_u value, 216 | size_t size); 217 | __private_extern__ struct xpc_object *_xpc_prim_create_flags(int type, 218 | xpc_u value, size_t size, uint16_t flags); 219 | __private_extern__ const char *_xpc_get_type_name(xpc_object_t obj); 220 | __private_extern__ struct xpc_object *mpack2xpc(mpack_node_t node); 221 | __private_extern__ void xpc2mpack(mpack_writer_t *writer, xpc_object_t xo); 222 | __private_extern__ void xpc_object_destroy(struct xpc_object *xo); 223 | __private_extern__ void xpc_connection_recv_message(void *); 224 | __private_extern__ void xpc_connection_recv_mach_message(void *); 225 | __private_extern__ void *xpc_connection_new_peer(void *context, 226 | xpc_port_t local, xpc_port_t remote, dispatch_source_t src); 227 | __private_extern__ void xpc_connection_destroy_peer(void *context); 228 | __private_extern__ int xpc_pipe_send(xpc_object_t obj, uint64_t id, 229 | xpc_port_t local, xpc_port_t remote); 230 | __private_extern__ int xpc_pipe_receive(xpc_port_t local, xpc_port_t *remote, 231 | xpc_object_t *result, uint64_t *id, struct xpc_credentials *creds); 232 | 233 | #endif /* _LIBXPC_XPC_INTERNAL_H */ -------------------------------------------------------------------------------- /xpc_misc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2015 iXsystems, Inc. 3 | * All rights reserved 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted providing that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | * 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include "xpc/xpc.h" 36 | #include "xpc_internal.h" 37 | 38 | #define RECV_BUFFER_SIZE 65536 39 | 40 | static void xpc_copy_description_level(xpc_object_t obj, struct sbuf *sbuf, 41 | int level); 42 | 43 | extern struct xpc_transport unix_transport __attribute__((weak)); 44 | extern struct xpc_transport mach_transport __attribute__((weak)); 45 | static struct xpc_transport *selected_transport = NULL; 46 | 47 | struct xpc_transport * 48 | xpc_get_transport() 49 | { 50 | if (!selected_transport) { 51 | char *env = getenv("XPC_TRANSPORT"); 52 | if (env) { 53 | if (!strcmp(env, "unix")) 54 | selected_transport = &unix_transport; 55 | 56 | if (!strcmp(env, "mach")) 57 | selected_transport = &mach_transport; 58 | } else { 59 | #ifdef MACH 60 | selected_transport = &mach_transport; 61 | #else 62 | selected_transport = &unix_transport; 63 | #endif 64 | } 65 | } 66 | 67 | return (selected_transport); 68 | } 69 | 70 | static void 71 | xpc_dictionary_destroy(struct xpc_object *dict) 72 | { 73 | struct xpc_dict_head *head; 74 | struct xpc_dict_pair *p, *ptmp; 75 | 76 | head = &dict->xo_dict; 77 | 78 | TAILQ_FOREACH_SAFE(p, head, xo_link, ptmp) { 79 | TAILQ_REMOVE(head, p, xo_link); 80 | xpc_object_destroy(p->value); 81 | free(p); 82 | } 83 | } 84 | 85 | static void 86 | xpc_array_destroy(struct xpc_object *dict) 87 | { 88 | struct xpc_object *p, *ptmp; 89 | struct xpc_array_head *head; 90 | 91 | head = &dict->xo_array; 92 | 93 | TAILQ_FOREACH_SAFE(p, head, xo_link, ptmp) { 94 | TAILQ_REMOVE(head, p, xo_link); 95 | xpc_object_destroy(p); 96 | } 97 | } 98 | 99 | static int 100 | xpc_pack(struct xpc_object *xo, void **buf, uint64_t id, size_t *size) 101 | { 102 | struct xpc_frame_header *header; 103 | mpack_writer_t writer; 104 | char *packed, *ret; 105 | size_t packed_size; 106 | 107 | mpack_writer_init_growable(&writer, &packed, &packed_size); 108 | xpc2mpack(&writer, xo); 109 | 110 | if (mpack_writer_destroy(&writer) != mpack_ok) 111 | return (-1); 112 | 113 | ret = malloc(packed_size + sizeof(*header)); 114 | memset(ret, 0, packed_size + sizeof(*header)); 115 | 116 | header = (struct xpc_frame_header *)ret; 117 | header->length = packed_size; 118 | header->id = id; 119 | header->version = XPC_PROTOCOL_VERSION; 120 | 121 | memcpy(ret + sizeof(*header), packed, packed_size); 122 | *buf = ret; 123 | *size = packed_size + sizeof(*header); 124 | 125 | free(packed); 126 | return (0); 127 | } 128 | 129 | static struct xpc_object * 130 | xpc_unpack(void *buf, size_t size) 131 | { 132 | mpack_tree_t tree; 133 | struct xpc_object *xo; 134 | 135 | mpack_tree_init(&tree, (const char *)buf, size); 136 | if (mpack_tree_error(&tree) != mpack_ok) { 137 | debugf("unpack failed: %d", mpack_tree_error(&tree)) 138 | return (NULL); 139 | } 140 | 141 | xo = mpack2xpc(mpack_tree_root(&tree)); 142 | return (xo); 143 | } 144 | 145 | void 146 | xpc_object_destroy(struct xpc_object *xo) 147 | { 148 | if (xo->xo_xpc_type == _XPC_TYPE_DICTIONARY) 149 | xpc_dictionary_destroy(xo); 150 | 151 | if (xo->xo_xpc_type == _XPC_TYPE_ARRAY) 152 | xpc_array_destroy(xo); 153 | 154 | free(xo); 155 | } 156 | 157 | xpc_object_t 158 | xpc_retain(xpc_object_t obj) 159 | { 160 | struct xpc_object *xo; 161 | 162 | xo = obj; 163 | atomic_add_int(&xo->xo_refcnt, 1); 164 | return (obj); 165 | } 166 | 167 | void 168 | xpc_release(xpc_object_t obj) 169 | { 170 | struct xpc_object *xo; 171 | 172 | xo = obj; 173 | if (atomic_fetchadd_int(&xo->xo_refcnt, -1) > 1) 174 | return; 175 | 176 | xpc_object_destroy(xo); 177 | } 178 | 179 | static const char *xpc_errors[] = { 180 | "No Error Found", 181 | "No Memory", 182 | "Invalid Argument", 183 | "No Such Process" 184 | }; 185 | 186 | #if 0 187 | const char * 188 | xpc_strerror(int error) 189 | { 190 | 191 | if (error > EXMAX || error < 0) 192 | return "BAD ERROR"; 193 | return (xpc_errors[error]); 194 | } 195 | #endif 196 | 197 | char * 198 | xpc_copy_description(xpc_object_t obj) 199 | { 200 | char *result; 201 | struct sbuf *sbuf; 202 | 203 | sbuf = sbuf_new_auto(); 204 | xpc_copy_description_level(obj, sbuf, 0); 205 | sbuf_finish(sbuf); 206 | result = strdup(sbuf_data(sbuf)); 207 | sbuf_delete(sbuf); 208 | 209 | return (result); 210 | } 211 | 212 | static void 213 | xpc_copy_description_level(xpc_object_t obj, struct sbuf *sbuf, int level) 214 | { 215 | struct xpc_object *xo = obj; 216 | struct uuid *id; 217 | char *uuid_str; 218 | uint32_t uuid_status; 219 | 220 | if (obj == NULL) { 221 | sbuf_printf(sbuf, "\n"); 222 | return; 223 | } 224 | 225 | sbuf_printf(sbuf, "(%s) ", _xpc_get_type_name(obj)); 226 | 227 | switch (xo->xo_xpc_type) { 228 | case _XPC_TYPE_DICTIONARY: 229 | sbuf_printf(sbuf, "\n"); 230 | xpc_dictionary_apply(xo, ^(const char *k, xpc_object_t v) { 231 | sbuf_printf(sbuf, "%*s\"%s\": ", level * 4, " ", k); 232 | xpc_copy_description_level(v, sbuf, level + 1); 233 | return ((bool)true); 234 | }); 235 | break; 236 | 237 | case _XPC_TYPE_ARRAY: 238 | sbuf_printf(sbuf, "\n"); 239 | xpc_array_apply(xo, ^(size_t idx, xpc_object_t v) { 240 | sbuf_printf(sbuf, "%*s%ld: ", level * 4, " ", idx); 241 | xpc_copy_description_level(v, sbuf, level + 1); 242 | return ((bool)true); 243 | }); 244 | break; 245 | 246 | case _XPC_TYPE_BOOL: 247 | sbuf_printf(sbuf, "%s\n", 248 | xpc_bool_get_value(obj) ? "true" : "false"); 249 | break; 250 | 251 | case _XPC_TYPE_STRING: 252 | sbuf_printf(sbuf, "\"%s\"\n", 253 | xpc_string_get_string_ptr(obj)); 254 | break; 255 | 256 | case _XPC_TYPE_INT64: 257 | sbuf_printf(sbuf, "%ld\n", 258 | xpc_int64_get_value(obj)); 259 | break; 260 | 261 | case _XPC_TYPE_UINT64: 262 | sbuf_printf(sbuf, "%lx\n", 263 | xpc_uint64_get_value(obj)); 264 | break; 265 | 266 | case _XPC_TYPE_DATE: 267 | sbuf_printf(sbuf, "%lu\n", 268 | xpc_date_get_value(obj)); 269 | break; 270 | 271 | case _XPC_TYPE_UUID: 272 | id = (struct uuid *)xpc_uuid_get_bytes(obj); 273 | uuid_to_string(id, &uuid_str, &uuid_status); 274 | sbuf_printf(sbuf, "%s\n", uuid_str); 275 | free(uuid_str); 276 | break; 277 | 278 | case _XPC_TYPE_ENDPOINT: 279 | sbuf_printf(sbuf, "<%ld>\n", xo->xo_int); 280 | break; 281 | 282 | case _XPC_TYPE_NULL: 283 | sbuf_printf(sbuf, "\n"); 284 | break; 285 | } 286 | } 287 | 288 | #ifdef MACH 289 | struct _launch_data { 290 | uint64_t type; 291 | union { 292 | struct { 293 | union { 294 | launch_data_t *_array; 295 | char *string; 296 | void *opaque; 297 | int64_t __junk; 298 | }; 299 | union { 300 | uint64_t _array_cnt; 301 | uint64_t string_len; 302 | uint64_t opaque_size; 303 | }; 304 | }; 305 | int64_t fd; 306 | uint64_t mp; 307 | uint64_t err; 308 | int64_t number; 309 | 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 */ 310 | double float_num; 311 | }; 312 | }; 313 | 314 | static uint8_t ld_to_xpc_type[] = { 315 | _XPC_TYPE_INVALID, 316 | _XPC_TYPE_DICTIONARY, 317 | _XPC_TYPE_ARRAY, 318 | _XPC_TYPE_FD, 319 | _XPC_TYPE_UINT64, 320 | _XPC_TYPE_DOUBLE, 321 | _XPC_TYPE_BOOL, 322 | _XPC_TYPE_STRING, 323 | _XPC_TYPE_DATA, 324 | _XPC_TYPE_ERROR, 325 | _XPC_TYPE_ENDPOINT 326 | }; 327 | 328 | xpc_object_t 329 | ld2xpc(launch_data_t ld) 330 | { 331 | struct xpc_object *xo; 332 | xpc_u val; 333 | 334 | 335 | if (ld->type > LAUNCH_DATA_MACHPORT) 336 | return (NULL); 337 | if (ld->type == LAUNCH_DATA_STRING || ld->type == LAUNCH_DATA_OPAQUE) { 338 | val.str = malloc(ld->string_len); 339 | memcpy(__DECONST(void *, val.str), ld->string, ld->string_len); 340 | xo = _xpc_prim_create(ld_to_xpc_type[ld->type], val, ld->string_len); 341 | } else if (ld->type == LAUNCH_DATA_BOOL) { 342 | val.b = (bool)ld->boolean; 343 | xo = _xpc_prim_create(ld_to_xpc_type[ld->type], val, 0); 344 | } else if (ld->type == LAUNCH_DATA_ARRAY) { 345 | xo = xpc_array_create(NULL, 0); 346 | for (uint64_t i = 0; i < ld->_array_cnt; i++) 347 | xpc_array_append_value(xo, ld2xpc(ld->_array[i])); 348 | } else { 349 | val.ui = ld->mp; 350 | xo = _xpc_prim_create(ld_to_xpc_type[ld->type], val, ld->string_len); 351 | } 352 | return (xo); 353 | } 354 | #endif 355 | 356 | #if 0 357 | xpc_object_t 358 | xpc_copy_entitlement_for_token(const char *key __unused, audit_token_t *token __unused) 359 | { 360 | xpc_u val; 361 | 362 | val.b = true; 363 | return (_xpc_prim_create(_XPC_TYPE_BOOL, val,0)); 364 | } 365 | #endif 366 | 367 | int 368 | xpc_pipe_send(xpc_object_t xobj, uint64_t id, xpc_port_t local, xpc_port_t remote) 369 | { 370 | struct xpc_transport *transport = xpc_get_transport(); 371 | void *buf; 372 | size_t size; 373 | 374 | assert(xpc_get_type(xobj) == &_xpc_type_dictionary); 375 | 376 | if (xpc_pack(xobj, &buf, id, &size) != 0) { 377 | debugf("pack failed"); 378 | return (-1); 379 | } 380 | 381 | if (transport->xt_send(local, remote, buf, size, NULL, 0) != 0) { 382 | debugf("transport send function failed: %s", strerror(errno)); 383 | return (-1); 384 | } 385 | 386 | return (0); 387 | } 388 | 389 | int 390 | xpc_pipe_receive(xpc_port_t local, xpc_port_t *remote, xpc_object_t *result, 391 | uint64_t *id, struct xpc_credentials *creds) 392 | { 393 | struct xpc_transport *transport = xpc_get_transport(); 394 | struct xpc_resource *resources; 395 | struct xpc_frame_header *header; 396 | void *buffer; 397 | size_t nresources; 398 | int ret; 399 | 400 | buffer = malloc(RECV_BUFFER_SIZE); 401 | 402 | ret = transport->xt_recv(local, remote, buffer, RECV_BUFFER_SIZE, 403 | &resources, &nresources, creds); 404 | if (ret < 0) { 405 | debugf("transport receive function failed: %s", strerror(errno)); 406 | return (-1); 407 | } 408 | 409 | if (ret == 0) { 410 | debugf("remote side closed connection, port=%s", transport->xt_port_to_string(local)); 411 | return (ret); 412 | } 413 | 414 | header = (struct xpc_frame_header *)buffer; 415 | if (header->length > (ret - sizeof(*header))) { 416 | debugf("invalid message length"); 417 | return (-1); 418 | } 419 | 420 | if (header->version != XPC_PROTOCOL_VERSION) { 421 | debugf("invalid protocol version") 422 | return (-1); 423 | } 424 | 425 | *id = header->id; 426 | 427 | debugf("length=%ld", header->length); 428 | 429 | *result = xpc_unpack(buffer + sizeof(*header), header->length); 430 | 431 | if (*result == NULL) 432 | return (-1); 433 | 434 | free(buffer); 435 | return (ret); 436 | } 437 | -------------------------------------------------------------------------------- /xpc_type.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2015 iXsystems, Inc. 3 | * All rights reserved 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted providing that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 18 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | * 26 | */ 27 | 28 | #include 29 | #include 30 | #include "xpc/xpc.h" 31 | #include "xpc_internal.h" 32 | 33 | struct _xpc_type_s { 34 | }; 35 | 36 | typedef const struct _xpc_type_s xt; 37 | xt _xpc_type_array; 38 | xt _xpc_type_bool; 39 | xt _xpc_type_connection; 40 | xt _xpc_type_data; 41 | xt _xpc_type_date; 42 | xt _xpc_type_dictionary; 43 | xt _xpc_type_endpoint; 44 | xt _xpc_type_null; 45 | xt _xpc_type_error; 46 | xt _xpc_type_fd; 47 | xt _xpc_type_int64; 48 | xt _xpc_type_uint64; 49 | xt _xpc_type_shmem; 50 | xt _xpc_type_string; 51 | xt _xpc_type_uuid; 52 | xt _xpc_type_double; 53 | 54 | 55 | struct _xpc_bool_s { 56 | }; 57 | 58 | typedef const struct _xpc_bool_s xb; 59 | 60 | xb _xpc_bool_true; 61 | xb _xpc_bool_false; 62 | 63 | struct _xpc_dictionary_s { 64 | }; 65 | 66 | typedef const struct _xpc_dictionary_s xs; 67 | 68 | xs _xpc_error_connection_interrupted; 69 | xs _xpc_error_connection_invalid; 70 | xs _xpc_error_connection_imminent; 71 | 72 | static size_t xpc_data_hash(const uint8_t *data, size_t length); 73 | 74 | static xpc_type_t xpc_typemap[] = { 75 | NULL, 76 | XPC_TYPE_DICTIONARY, 77 | XPC_TYPE_ARRAY, 78 | XPC_TYPE_BOOL, 79 | XPC_TYPE_CONNECTION, 80 | XPC_TYPE_ENDPOINT, 81 | XPC_TYPE_NULL, 82 | NULL, 83 | XPC_TYPE_INT64, 84 | XPC_TYPE_UINT64, 85 | XPC_TYPE_DATE, 86 | XPC_TYPE_DATA, 87 | XPC_TYPE_STRING, 88 | XPC_TYPE_UUID, 89 | XPC_TYPE_FD, 90 | XPC_TYPE_SHMEM, 91 | XPC_TYPE_ERROR, 92 | XPC_TYPE_DOUBLE 93 | }; 94 | 95 | static const char *xpc_typestr[] = { 96 | "invalid", 97 | "dictionary", 98 | "array", 99 | "bool", 100 | "connection", 101 | "endpoint", 102 | "null", 103 | "invalid", 104 | "int64", 105 | "uint64", 106 | "date", 107 | "data", 108 | "string", 109 | "uuid", 110 | "fd", 111 | "shmem", 112 | "error", 113 | "double" 114 | }; 115 | 116 | __private_extern__ struct xpc_object * 117 | _xpc_prim_create(int type, xpc_u value, size_t size) 118 | { 119 | 120 | return (_xpc_prim_create_flags(type, value, size, 0)); 121 | } 122 | 123 | __private_extern__ struct xpc_object * 124 | _xpc_prim_create_flags(int type, xpc_u value, size_t size, uint16_t flags) 125 | { 126 | struct xpc_object *xo; 127 | 128 | if ((xo = malloc(sizeof(*xo))) == NULL) 129 | return (NULL); 130 | 131 | xo->xo_size = size; 132 | xo->xo_xpc_type = type; 133 | xo->xo_flags = flags; 134 | xo->xo_u = value; 135 | xo->xo_refcnt = 1; 136 | #if MACH 137 | xo->xo_audit_token = NULL; 138 | #endif 139 | 140 | if (type == _XPC_TYPE_DICTIONARY) 141 | TAILQ_INIT(&xo->xo_dict); 142 | 143 | if (type == _XPC_TYPE_ARRAY) 144 | TAILQ_INIT(&xo->xo_array); 145 | 146 | return (xo); 147 | } 148 | 149 | xpc_object_t 150 | xpc_null_create(void) 151 | { 152 | xpc_u val; 153 | return _xpc_prim_create(_XPC_TYPE_NULL, val, 0); 154 | } 155 | 156 | xpc_object_t 157 | xpc_bool_create(bool value) 158 | { 159 | xpc_u val; 160 | 161 | val.b = value; 162 | return _xpc_prim_create(_XPC_TYPE_BOOL, val, 1); 163 | } 164 | 165 | bool 166 | xpc_bool_get_value(xpc_object_t xbool) 167 | { 168 | struct xpc_object *xo; 169 | 170 | xo = xbool; 171 | if (xo == NULL) 172 | return (0); 173 | 174 | if (xo->xo_xpc_type == _XPC_TYPE_BOOL) 175 | return (xo->xo_bool); 176 | 177 | return (false); 178 | } 179 | 180 | xpc_object_t 181 | xpc_int64_create(int64_t value) 182 | { 183 | xpc_u val; 184 | 185 | val.i = value; 186 | return _xpc_prim_create(_XPC_TYPE_INT64, val, 1); 187 | } 188 | 189 | int64_t 190 | xpc_int64_get_value(xpc_object_t xint) 191 | { 192 | struct xpc_object *xo; 193 | 194 | xo = xint; 195 | if (xo == NULL) 196 | return (0); 197 | 198 | if (xo->xo_xpc_type == _XPC_TYPE_INT64) 199 | return (xo->xo_int); 200 | 201 | return (0); 202 | } 203 | 204 | xpc_object_t 205 | xpc_uint64_create(uint64_t value) 206 | { 207 | xpc_u val; 208 | 209 | val.ui = value; 210 | return _xpc_prim_create(_XPC_TYPE_UINT64, val, 1); 211 | } 212 | 213 | uint64_t 214 | xpc_uint64_get_value(xpc_object_t xuint) 215 | { 216 | struct xpc_object *xo; 217 | 218 | xo = xuint; 219 | if (xo == NULL) 220 | return (0); 221 | 222 | if (xo->xo_xpc_type == _XPC_TYPE_UINT64) 223 | return (xo->xo_uint); 224 | 225 | return (0); 226 | } 227 | 228 | xpc_object_t 229 | xpc_double_create(double value) 230 | { 231 | xpc_u val; 232 | 233 | val.d = value; 234 | return _xpc_prim_create(_XPC_TYPE_DOUBLE, val, 1); 235 | } 236 | 237 | double 238 | xpc_double_get_value(xpc_object_t xdouble) 239 | { 240 | struct xpc_object *xo = xdouble; 241 | 242 | if (xo->xo_xpc_type == _XPC_TYPE_DOUBLE) 243 | return (xo->xo_d); 244 | 245 | return (0); 246 | } 247 | 248 | xpc_object_t 249 | xpc_date_create(int64_t interval) 250 | { 251 | xpc_u val; 252 | 253 | val.i = interval; 254 | return _xpc_prim_create(_XPC_TYPE_DATE, val, 1); 255 | } 256 | 257 | xpc_object_t 258 | xpc_date_create_from_current(void) 259 | { 260 | xpc_u val; 261 | struct timespec tp; 262 | 263 | clock_gettime(CLOCK_REALTIME, &tp); 264 | 265 | val.ui = *(uint64_t *)&tp; 266 | return _xpc_prim_create(_XPC_TYPE_DATE, val, 1); 267 | } 268 | 269 | int64_t 270 | xpc_date_get_value(xpc_object_t xdate) 271 | { 272 | struct xpc_object *xo = xdate; 273 | 274 | if (xo == NULL) 275 | return (0); 276 | 277 | if (xo->xo_xpc_type == _XPC_TYPE_DATE) 278 | return (xo->xo_int); 279 | 280 | return (0); 281 | } 282 | 283 | xpc_object_t 284 | xpc_data_create(const void *bytes, size_t length) 285 | { 286 | xpc_u val; 287 | 288 | val.ptr = (uintptr_t)bytes; 289 | return _xpc_prim_create(_XPC_TYPE_DATA, val, length); 290 | } 291 | 292 | #ifdef MACH 293 | xpc_object_t 294 | xpc_data_create_with_dispatch_data(dispatch_data_t ddata) 295 | { 296 | 297 | } 298 | #endif 299 | 300 | size_t 301 | xpc_data_get_length(xpc_object_t xdata) 302 | { 303 | struct xpc_object *xo = xdata; 304 | 305 | if (xo == NULL) 306 | return (0); 307 | 308 | if (xo->xo_xpc_type == _XPC_TYPE_DATA) 309 | return (xo->xo_size); 310 | 311 | return (0); 312 | } 313 | 314 | const void * 315 | xpc_data_get_bytes_ptr(xpc_object_t xdata) 316 | { 317 | struct xpc_object *xo = xdata; 318 | 319 | if (xo == NULL) 320 | return (NULL); 321 | 322 | if (xo->xo_xpc_type == _XPC_TYPE_DATA) 323 | return ((const void *)xo->xo_ptr); 324 | 325 | return (0); 326 | } 327 | 328 | size_t 329 | xpc_data_get_bytes(xpc_object_t xdata, void *buffer, size_t off, size_t length) 330 | { 331 | 332 | /* XXX */ 333 | return (0); 334 | } 335 | 336 | xpc_object_t 337 | xpc_string_create(const char *string) 338 | { 339 | xpc_u val; 340 | 341 | val.str = __DECONST(char *, string); 342 | return _xpc_prim_create(_XPC_TYPE_STRING, val, strlen(string)); 343 | } 344 | 345 | xpc_object_t 346 | xpc_string_create_with_format(const char *fmt, ...) 347 | { 348 | va_list ap; 349 | xpc_u val; 350 | 351 | va_start(ap, fmt); 352 | vasprintf(&val.str, fmt, ap); 353 | va_end(ap); 354 | return _xpc_prim_create(_XPC_TYPE_STRING, val, strlen(val.str)); 355 | } 356 | 357 | xpc_object_t 358 | xpc_string_create_with_format_and_arguments(const char *fmt, va_list ap) 359 | { 360 | xpc_u val; 361 | 362 | vasprintf(&val.str, fmt, ap); 363 | return _xpc_prim_create(_XPC_TYPE_STRING, val, strlen(val.str)); 364 | } 365 | 366 | size_t 367 | xpc_string_get_length(xpc_object_t xstring) 368 | { 369 | struct xpc_object *xo = xstring; 370 | 371 | if (xo == NULL) 372 | return (0); 373 | 374 | if (xo->xo_xpc_type == _XPC_TYPE_STRING) 375 | return (xo->xo_size); 376 | 377 | return (0); 378 | } 379 | 380 | const char * 381 | xpc_string_get_string_ptr(xpc_object_t xstring) 382 | { 383 | struct xpc_object *xo = xstring; 384 | 385 | if (xo == NULL) 386 | return (NULL); 387 | 388 | if (xo->xo_xpc_type == _XPC_TYPE_STRING) 389 | return (xo->xo_str); 390 | 391 | return (NULL); 392 | } 393 | 394 | xpc_object_t 395 | xpc_uuid_create(const uuid_t uuid) 396 | { 397 | xpc_u val; 398 | 399 | memcpy(val.uuid, uuid, sizeof(uuid_t)); 400 | return _xpc_prim_create(_XPC_TYPE_UUID, val, 1); 401 | } 402 | 403 | const uint8_t * 404 | xpc_uuid_get_bytes(xpc_object_t xuuid) 405 | { 406 | struct xpc_object *xo; 407 | 408 | xo = xuuid; 409 | if (xo == NULL) 410 | return (NULL); 411 | 412 | if (xo->xo_xpc_type == _XPC_TYPE_UUID) 413 | return ((uint8_t*)&xo->xo_uuid); 414 | 415 | return (NULL); 416 | } 417 | 418 | xpc_type_t 419 | xpc_get_type(xpc_object_t obj) 420 | { 421 | struct xpc_object *xo; 422 | 423 | xo = obj; 424 | return (xpc_typemap[xo->xo_xpc_type]); 425 | } 426 | 427 | bool 428 | xpc_equal(xpc_object_t x1, xpc_object_t x2) 429 | { 430 | struct xpc_object *xo1, *xo2; 431 | 432 | xo1 = x1; 433 | xo2 = x2; 434 | 435 | /* FIXME */ 436 | return (false); 437 | } 438 | 439 | xpc_object_t 440 | xpc_copy(xpc_object_t obj) 441 | { 442 | struct xpc_object *xo, *xotmp; 443 | const void *newdata; 444 | 445 | xo = obj; 446 | switch (xo->xo_xpc_type) { 447 | case _XPC_TYPE_BOOL: 448 | case _XPC_TYPE_INT64: 449 | case _XPC_TYPE_UINT64: 450 | case _XPC_TYPE_DATE: 451 | case _XPC_TYPE_ENDPOINT: 452 | return _xpc_prim_create(xo->xo_xpc_type, xo->xo_u, 1); 453 | 454 | case _XPC_TYPE_STRING: 455 | return xpc_string_create(strdup( 456 | xpc_string_get_string_ptr(xo))); 457 | 458 | case _XPC_TYPE_DATA: 459 | newdata = xpc_data_get_bytes_ptr(obj); 460 | return (xpc_data_create(newdata, 461 | xpc_data_get_length(obj))); 462 | 463 | case _XPC_TYPE_DICTIONARY: 464 | xotmp = xpc_dictionary_create(NULL, NULL, 0); 465 | xpc_dictionary_apply(obj, ^(const char *k, xpc_object_t v) { 466 | xpc_dictionary_set_value(xotmp, k, xpc_copy(v)); 467 | return (bool)true; 468 | }); 469 | return (xotmp); 470 | 471 | case _XPC_TYPE_ARRAY: 472 | xotmp = xpc_array_create(NULL, 0); 473 | xpc_array_apply(obj, ^(size_t idx, xpc_object_t v) { 474 | xpc_array_set_value(xotmp, idx, xpc_copy(v)); 475 | return ((bool)true); 476 | }); 477 | return (xotmp); 478 | } 479 | 480 | return (0); 481 | } 482 | 483 | static size_t 484 | xpc_data_hash(const uint8_t *data, size_t length) 485 | { 486 | size_t hash = 5381; 487 | 488 | while (length--) 489 | hash = ((hash << 5) + hash) + data[length]; 490 | 491 | return (hash); 492 | } 493 | 494 | size_t 495 | xpc_hash(xpc_object_t obj) 496 | { 497 | struct xpc_object *xo; 498 | __block size_t hash = 0; 499 | 500 | xo = obj; 501 | switch (xo->xo_xpc_type) { 502 | case _XPC_TYPE_BOOL: 503 | case _XPC_TYPE_INT64: 504 | case _XPC_TYPE_UINT64: 505 | case _XPC_TYPE_DATE: 506 | case _XPC_TYPE_ENDPOINT: 507 | return ((size_t)xo->xo_u.ui); 508 | 509 | case _XPC_TYPE_STRING: 510 | return (xpc_data_hash( 511 | (const uint8_t *)xpc_string_get_string_ptr(obj), 512 | xpc_string_get_length(obj))); 513 | 514 | case _XPC_TYPE_DATA: 515 | return (xpc_data_hash( 516 | xpc_data_get_bytes_ptr(obj), 517 | xpc_data_get_length(obj))); 518 | 519 | case _XPC_TYPE_DICTIONARY: 520 | xpc_dictionary_apply(obj, ^(const char *k, xpc_object_t v) { 521 | hash ^= xpc_data_hash((const uint8_t *)k, strlen(k)); 522 | hash ^= xpc_hash(v); 523 | return ((bool)true); 524 | }); 525 | return (hash); 526 | 527 | case _XPC_TYPE_ARRAY: 528 | xpc_array_apply(obj, ^(size_t idx, xpc_object_t v) { 529 | hash ^= xpc_hash(v); 530 | return ((bool)true); 531 | }); 532 | return (hash); 533 | } 534 | 535 | return (0); 536 | } 537 | 538 | __private_extern__ const char * 539 | _xpc_get_type_name(xpc_object_t obj) 540 | { 541 | struct xpc_object *xo; 542 | 543 | xo = obj; 544 | return (xpc_typestr[xo->xo_xpc_type]); 545 | } --------------------------------------------------------------------------------