1 /* 2 * Copyright (c) 2012 The Chromium Authors. All rights reserved. 3 * Use of this source code is governed by a BSD-style license that can be 4 * found in the LICENSE file. 5 */ 6 7 /* 8 * Post-message based test for simple rpc based access to name services. 9 * 10 * Converted from srpc_nameservice_test (deprecated), i.e., C -> C++, 11 * srpc -> post message. 12 */ 13 #include <string> 14 15 #include <assert.h> 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <inttypes.h> 19 #include <sys/fcntl.h> 20 #include <string.h> 21 #include <unistd.h> 22 23 #include "native_client/src/include/nacl_scoped_ptr.h" 24 #include "native_client/src/public/imc_syscalls.h" 25 #include "native_client/src/public/name_service.h" 26 #include "native_client/src/shared/srpc/nacl_srpc.h" 27 28 #include "ppapi/cpp/instance.h" 29 #include "ppapi/cpp/module.h" 30 #include "ppapi/cpp/var.h" 31 32 #include "ppapi/native_client/src/untrusted/nacl_ppapi_util/nacl_ppapi_util.h" 33 #include "ppapi/native_client/src/untrusted/nacl_ppapi_util/string_buffer.h" 34 35 #define RNG_OUTPUT_BYTES 1024 36 37 #define BYTES_PER_LINE 32 38 #define BYTE_SPACING 4 39 40 bool g_ns_channel_initialized = false; 41 NaClSrpcChannel g_ns_channel; 42 43 void dump_output(nacl::StringBuffer *sb, int d, size_t nbytes) { 44 nacl::scoped_array<uint8_t> bytes; 45 size_t got; 46 int copied; 47 48 bytes.reset(new uint8_t[nbytes]); 49 if (NULL == bytes.get()) { 50 perror("dump_output"); 51 fprintf(stderr, "No memory\n"); 52 return; 53 } 54 // Read the RNG output. 55 for (got = 0; got < nbytes; got += copied) { 56 copied = read(d, bytes.get() + got, nbytes - got); 57 if (-1 == copied) { 58 perror("dump_output:read"); 59 fprintf(stderr, "read failure\n"); 60 break; 61 } 62 printf("read(%d, ..., %u) -> %d\n", d, nbytes - got, copied); 63 } 64 // Hex dump it so we can eyeball it for randomness. Ideally we 65 // would have a chi-square test here to test randomness. 66 for (size_t ix = 0; ix < got; ++ix) { 67 if (0 == (ix & (BYTES_PER_LINE - 1))) { 68 sb->Printf("\n%04x:", ix); 69 } else if (0 == (ix & (BYTE_SPACING - 1))) { 70 sb->Printf(" "); 71 } 72 sb->Printf("%02x", bytes[ix]); 73 } 74 sb->Printf("\n"); 75 } 76 77 void EnumerateNames(NaClSrpcChannel *nschan, nacl::StringBuffer *sb) { 78 char buffer[1024]; 79 uint32_t nbytes = sizeof buffer; 80 81 if (NACL_SRPC_RESULT_OK != NaClSrpcInvokeBySignature(nschan, 82 NACL_NAME_SERVICE_LIST, 83 &nbytes, buffer)) { 84 sb->Printf("NaClSrpcInvokeBySignature failed\n"); 85 return; 86 } 87 sb->Printf("nbytes = %u\n", (size_t) nbytes); 88 if (nbytes == sizeof buffer) { 89 sb->Printf("Insufficent space for namespace enumeration\n"); 90 return; 91 } 92 93 size_t name_len; 94 for (char *p = buffer; 95 static_cast<size_t>(p - buffer) < nbytes; 96 p += name_len) { 97 name_len = strlen(p) + 1; 98 sb->Printf("%s\n", p); 99 } 100 } 101 102 void Initialize(const pp::Var& message_data, nacl::StringBuffer* sb) { 103 if (g_ns_channel_initialized) { 104 return; 105 } 106 int ns = -1; 107 nacl_nameservice(&ns); 108 printf("ns = %d\n", ns); 109 assert(-1 != ns); 110 int connected_socket = imc_connect(ns); 111 assert(-1 != connected_socket); 112 if (!NaClSrpcClientCtor(&g_ns_channel, connected_socket)) { 113 sb->Printf("Srpc client channel ctor failed\n"); 114 close(ns); 115 } 116 sb->Printf("NaClSrpcClientCtor succeeded\n"); 117 close(ns); 118 g_ns_channel_initialized = 1; 119 } 120 121 // 122 // Return name service output 123 // 124 void NameServiceDump(const pp::Var& message_data, nacl::StringBuffer* sb) { 125 Initialize(message_data, sb); 126 EnumerateNames(&g_ns_channel, sb); 127 } 128 129 // 130 // Dump RNG output into a string. 131 // 132 void RngDump(const pp::Var& message_data, nacl::StringBuffer* sb) { 133 NaClSrpcError rpc_result; 134 int status; 135 int rng; 136 137 Initialize(message_data, sb); 138 139 rpc_result = NaClSrpcInvokeBySignature(&g_ns_channel, 140 NACL_NAME_SERVICE_LOOKUP, 141 "SecureRandom", O_RDONLY, 142 &status, &rng); 143 assert(NACL_SRPC_RESULT_OK == rpc_result); 144 printf("rpc status %d\n", status); 145 assert(NACL_NAME_SERVICE_SUCCESS == status); 146 printf("rng descriptor %d\n", rng); 147 148 dump_output(sb, rng, RNG_OUTPUT_BYTES); 149 close(rng); 150 } 151 152 void ManifestTest(const pp::Var& message_data, nacl::StringBuffer* sb) { 153 int status = -1; 154 int manifest; 155 156 Initialize(message_data, sb); 157 158 // Make the name service lookup for the manifest service descriptor. 159 if (NACL_SRPC_RESULT_OK != 160 NaClSrpcInvokeBySignature(&g_ns_channel, NACL_NAME_SERVICE_LOOKUP, 161 "ManifestNameService", O_RDWR, 162 &status, &manifest) || 163 NACL_NAME_SERVICE_SUCCESS != status) { 164 fprintf(stderr, "nameservice lookup failed, status %d\n", status); 165 return; 166 } 167 sb->Printf("Got manifest descriptor %d\n", manifest); 168 if (-1 == manifest) { 169 return; 170 } 171 172 // Connect to manifest name server. 173 int manifest_conn = imc_connect(manifest); 174 close(manifest); 175 sb->Printf("got manifest connection %d\n", manifest_conn); 176 if (-1 == manifest_conn) { 177 sb->Printf("could not connect\n"); 178 return; 179 } 180 sb->DiscardOutput(); 181 sb->Printf("ManifestTest: basic connectivity ok\n"); 182 183 close(manifest_conn); 184 } 185 186 struct PostMessageHandlerDesc { 187 char const *request; 188 void (*handler)(const pp::Var& message_data, nacl::StringBuffer* out); 189 }; 190 191 // This object represents one time the page says <embed>. 192 class MyInstance : public pp::Instance { 193 public: 194 explicit MyInstance(PP_Instance instance) : pp::Instance(instance) {} 195 virtual ~MyInstance() {} 196 virtual void HandleMessage(const pp::Var& message_data); 197 }; 198 199 // HandleMessage gets invoked when postMessage is called on the DOM 200 // element associated with this plugin instance. In this case, if we 201 // are given a string, we'll post a message back to JavaScript with a 202 // reply string -- essentially treating this as a string-based RPC. 203 void MyInstance::HandleMessage(const pp::Var& message_data) { 204 static struct PostMessageHandlerDesc kMsgHandlers[] = { 205 { "init", Initialize }, 206 { "nameservice", NameServiceDump }, 207 { "rng", RngDump }, 208 { "manifest_test", ManifestTest }, 209 { reinterpret_cast<char const *>(NULL), 210 reinterpret_cast<void (*)(const pp::Var&, nacl::StringBuffer*)>(NULL) } 211 }; 212 nacl::StringBuffer sb; 213 214 if (message_data.is_string()) { 215 std::string op_name(message_data.AsString()); 216 std::string reply; 217 size_t len; 218 219 fprintf(stderr, "Searching for handler for request \"%s\".\n", 220 op_name.c_str()); 221 222 for (size_t ix = 0; kMsgHandlers[ix].request != NULL; ++ix) { 223 if (op_name == kMsgHandlers[ix].request) { 224 fprintf(stderr, "found at index %u\n", ix); 225 kMsgHandlers[ix].handler(message_data, &sb); 226 break; 227 } 228 } 229 230 reply = sb.ToString(); 231 len = strlen(reply.c_str()); 232 fprintf(stderr, "posting reply len %d\n", len); 233 // fprintf(stderr, "posting reply \"%s\".\n", sb.ToString().c_str()); 234 fprintf(stderr, "posting reply \""); 235 fflush(stderr); 236 write(2, reply.c_str(), len); 237 fprintf(stderr, "\".\n"); 238 fflush(stderr); 239 240 PostMessage(pp::Var(sb.ToString())); 241 fprintf(stderr, "returning\n"); 242 fflush(stderr); 243 } 244 } 245 246 // This object is the global object representing this plugin library as long 247 // as it is loaded. 248 class MyModule : public pp::Module { 249 public: 250 MyModule() : pp::Module() {} 251 virtual ~MyModule() {} 252 253 // Override CreateInstance to create your customized Instance object. 254 virtual pp::Instance* CreateInstance(PP_Instance instance) { 255 return new MyInstance(instance); 256 } 257 }; 258 259 namespace pp { 260 261 // Factory function for your specialization of the Module object. 262 Module* CreateModule() { 263 return new MyModule(); 264 } 265 266 } // namespace pp 267