Home | History | Annotate | Download | only in nameservice
      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