1// Copyright 2018 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <fuchsia/ldsvc/c/fidl.h> 6#include <string.h> 7#include <threads.h> 8#include <zircon/fidl.h> 9#include <zircon/syscalls.h> 10 11#include <unittest/unittest.h> 12 13static bool g_server_done = false; 14 15static zx_status_t ldsvc_Done(void* ctx) { 16 g_server_done = true; 17 return ZX_OK; 18} 19 20static zx_status_t ldsvc_LoadObject(void* ctx, const char* object_name_data, size_t object_name_size, fidl_txn_t* txn) { 21 size_t len = strlen("object name"); 22 ASSERT_EQ(len, object_name_size, ""); 23 EXPECT_EQ(0, memcmp(object_name_data, "object name", len), ""); 24 zx_handle_t event = ZX_HANDLE_INVALID; 25 EXPECT_EQ(ZX_OK, zx_event_create(0, &event), ""); 26 return fuchsia_ldsvc_LoaderLoadObject_reply(txn, 42, event); 27} 28 29static zx_status_t ldsvc_LoadScriptInterpreter(void* ctx, const char* interpreter_name_data, size_t interpreter_name_size, fidl_txn_t* txn) { 30 size_t len = strlen("script interpreter"); 31 ASSERT_EQ(len, interpreter_name_size, ""); 32 EXPECT_EQ(0, memcmp(interpreter_name_data, "script interpreter", len), ""); 33 zx_handle_t event = ZX_HANDLE_INVALID; 34 EXPECT_EQ(ZX_OK, zx_event_create(0, &event), ""); 35 return fuchsia_ldsvc_LoaderLoadScriptInterpreter_reply(txn, 43, event); 36} 37 38static zx_status_t ldsvc_Config(void* ctx, const char* config_data, size_t config_size, fidl_txn_t* txn) { 39 size_t len = strlen("my config"); 40 ASSERT_EQ(len, config_size, ""); 41 EXPECT_EQ(0, memcmp(config_data, "my config", len), ""); 42 return fuchsia_ldsvc_LoaderConfig_reply(txn, 44); 43} 44 45static zx_status_t ldsvc_Clone(void* ctx, zx_handle_t loader, fidl_txn_t* txn) { 46 EXPECT_EQ(ZX_OK, zx_handle_close(loader), ""); 47 return fuchsia_ldsvc_LoaderClone_reply(txn, 45); 48} 49 50static zx_status_t ldsvc_DebugPublishDataSink(void* ctx, const char* data_sink_data, size_t data_sink_size, zx_handle_t data, fidl_txn_t* txn) { 51 size_t len = strlen("my data sink"); 52 ASSERT_EQ(len, data_sink_size, ""); 53 EXPECT_EQ(0, memcmp(data_sink_data, "my data sink", len), ""); 54 EXPECT_EQ(ZX_OK, zx_handle_close(data), ""); 55 return fuchsia_ldsvc_LoaderDebugPublishDataSink_reply(txn, 46); 56} 57 58static zx_status_t ldsvc_DebugLoadConfig(void* ctx, const char* config_name_data, size_t config_name_size, fidl_txn_t* txn) { 59 size_t len = strlen("my debug config"); 60 ASSERT_EQ(len, config_name_size, ""); 61 EXPECT_EQ(0, memcmp(config_name_data, "my debug config", len), ""); 62 zx_handle_t event = ZX_HANDLE_INVALID; 63 EXPECT_EQ(ZX_OK, zx_event_create(0, &event), ""); 64 return fuchsia_ldsvc_LoaderDebugLoadConfig_reply(txn, 47, event); 65} 66 67static const fuchsia_ldsvc_Loader_ops_t kOps = { 68 .Done = ldsvc_Done, 69 .LoadObject = ldsvc_LoadObject, 70 .LoadScriptInterpreter = ldsvc_LoadScriptInterpreter, 71 .Config = ldsvc_Config, 72 .Clone = ldsvc_Clone, 73 .DebugPublishDataSink = ldsvc_DebugPublishDataSink, 74 .DebugLoadConfig = ldsvc_DebugLoadConfig, 75}; 76 77typedef struct ldsvc_connection { 78 fidl_txn_t txn; 79 zx_handle_t channel; 80 zx_txid_t txid; 81 uint32_t reply_count; 82} ldsvc_connection_t; 83 84static zx_status_t ldsvc_server_reply(fidl_txn_t* txn, const fidl_msg_t* msg) { 85 ldsvc_connection_t* conn = (ldsvc_connection_t*)txn; 86 if (msg->num_bytes < sizeof(fidl_message_header_t)) 87 return ZX_ERR_INVALID_ARGS; 88 fidl_message_header_t* hdr = (fidl_message_header_t*)msg->bytes; 89 hdr->txid = conn->txid; 90 conn->txid = 0; 91 ++conn->reply_count; 92 return zx_channel_write(conn->channel, 0, msg->bytes, msg->num_bytes, 93 msg->handles, msg->num_handles); 94} 95 96static int ldsvc_server(void* ctx) { 97 ldsvc_connection_t conn = { 98 .txn.reply = ldsvc_server_reply, 99 .channel = *(zx_handle_t*)ctx, 100 .reply_count = 0u, 101 }; 102 zx_status_t status = ZX_OK; 103 g_server_done = false; 104 105 while (status == ZX_OK && !g_server_done) { 106 zx_signals_t observed; 107 status = zx_object_wait_one( 108 conn.channel, ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED, 109 ZX_TIME_INFINITE, &observed); 110 if ((observed & ZX_CHANNEL_READABLE) != 0) { 111 ASSERT_EQ(ZX_OK, status, ""); 112 char bytes[ZX_CHANNEL_MAX_MSG_BYTES]; 113 zx_handle_t handles[ZX_CHANNEL_MAX_MSG_HANDLES]; 114 fidl_msg_t msg = { 115 .bytes = bytes, 116 .handles = handles, 117 .num_bytes = 0u, 118 .num_handles = 0u, 119 }; 120 status = zx_channel_read(conn.channel, 0, bytes, handles, 121 ZX_CHANNEL_MAX_MSG_BYTES, 122 ZX_CHANNEL_MAX_MSG_HANDLES, 123 &msg.num_bytes, &msg.num_handles); 124 ASSERT_EQ(ZX_OK, status, ""); 125 ASSERT_GE(msg.num_bytes, sizeof(fidl_message_header_t), ""); 126 fidl_message_header_t* hdr = (fidl_message_header_t*)msg.bytes; 127 conn.txid = hdr->txid; 128 conn.reply_count = 0u; 129 status = fuchsia_ldsvc_Loader_dispatch(NULL, &conn.txn, &msg, &kOps); 130 ASSERT_EQ(ZX_OK, status, ""); 131 if (!g_server_done) 132 ASSERT_EQ(1u, conn.reply_count, ""); 133 } else { 134 break; 135 } 136 } 137 138 zx_handle_close(conn.channel); 139 return 0; 140} 141 142static bool loader_test(void) { 143 BEGIN_TEST; 144 145 zx_handle_t client, server; 146 zx_status_t status = zx_channel_create(0, &client, &server); 147 ASSERT_EQ(ZX_OK, status, ""); 148 149 thrd_t thread; 150 int rv = thrd_create(&thread, ldsvc_server, &server); 151 ASSERT_EQ(thrd_success, rv, ""); 152 153 { 154 const char* object_name = "object name"; 155 zx_status_t rv = ZX_OK; 156 zx_handle_t object = ZX_HANDLE_INVALID; 157 ASSERT_EQ(ZX_OK, fuchsia_ldsvc_LoaderLoadObject(client, object_name, strlen(object_name), &rv, &object), ""); 158 ASSERT_EQ(42, rv, ""); 159 ASSERT_EQ(ZX_OK, zx_handle_close(object), ""); 160 } 161 162 { 163 const char* interpreter_name = "script interpreter"; 164 zx_status_t rv = ZX_OK; 165 zx_handle_t object = ZX_HANDLE_INVALID; 166 ASSERT_EQ(ZX_OK, fuchsia_ldsvc_LoaderLoadScriptInterpreter(client, interpreter_name, strlen(interpreter_name), &rv, &object), ""); 167 ASSERT_EQ(43, rv, ""); 168 ASSERT_EQ(ZX_OK, zx_handle_close(object), ""); 169 } 170 171 { 172 const char* config = "my config"; 173 zx_status_t rv = ZX_OK; 174 ASSERT_EQ(ZX_OK, fuchsia_ldsvc_LoaderConfig(client, config, strlen(config), &rv), ""); 175 ASSERT_EQ(44, rv, ""); 176 } 177 178 { 179 zx_status_t rv = ZX_OK; 180 zx_handle_t h1, h2; 181 ASSERT_EQ(ZX_OK, zx_eventpair_create(0, &h1, &h2), ""); 182 ASSERT_EQ(ZX_OK, fuchsia_ldsvc_LoaderClone(client, h1, &rv), ""); 183 ASSERT_EQ(45, rv, ""); 184 ASSERT_EQ(ZX_ERR_PEER_CLOSED, zx_object_signal_peer(h2, 0, 0), ""); 185 ASSERT_EQ(ZX_OK, zx_handle_close(h2), ""); 186 } 187 188 { 189 const char* sink = "my data sink"; 190 zx_status_t rv = ZX_OK; 191 zx_handle_t h1, h2; 192 ASSERT_EQ(ZX_OK, zx_eventpair_create(0, &h1, &h2), ""); 193 ASSERT_EQ(ZX_OK, fuchsia_ldsvc_LoaderDebugPublishDataSink(client, sink, strlen(sink), h1, &rv), ""); 194 ASSERT_EQ(46, rv, ""); 195 ASSERT_EQ(ZX_ERR_PEER_CLOSED, zx_object_signal_peer(h2, 0, 0), ""); 196 ASSERT_EQ(ZX_OK, zx_handle_close(h2), ""); 197 } 198 199 { 200 const char* config_name = "my debug config"; 201 zx_status_t rv = ZX_OK; 202 zx_handle_t object = ZX_HANDLE_INVALID; 203 ASSERT_EQ(ZX_OK, fuchsia_ldsvc_LoaderDebugLoadConfig(client, config_name, strlen(config_name), &rv, &object), ""); 204 ASSERT_EQ(47, rv, ""); 205 ASSERT_EQ(ZX_OK, zx_handle_close(object), ""); 206 } 207 208 ASSERT_EQ(ZX_OK, fuchsia_ldsvc_LoaderDone(client), ""); 209 ASSERT_EQ(ZX_OK, zx_handle_close(client), ""); 210 211 int result = 0; 212 rv = thrd_join(thread, &result); 213 ASSERT_EQ(thrd_success, rv, ""); 214 215 END_TEST; 216} 217 218BEGIN_TEST_CASE(ldsvc_tests) 219RUN_NAMED_TEST("fuchsia.ldsvc.Loader test", loader_test) 220END_TEST_CASE(ldsvc_tests); 221