blob: 904a3e669ab2058734c1c32c9bf0aec60051f9b7 [file]
/*
* Copyright (c) 2012 The Native Client Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/*
* Test for simple rpc based access to name services.
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <sys/fcntl.h>
#include <string.h>
#include <unistd.h>
#include "native_client/src/public/imc_syscalls.h"
#include "native_client/src/public/name_service.h"
#include "native_client/src/shared/srpc/nacl_srpc.h"
struct StringBuffer {
size_t nbytes;
size_t insert;
char *buffer;
};
NaClSrpcChannel ns_channel;
void StringBufferCtor(struct StringBuffer *sb) {
sb->nbytes = 1024;
sb->insert = 0;
sb->buffer = malloc(sb->nbytes);
if (NULL == sb->buffer) {
perror("StringBufferInit::malloc");
abort();
}
sb->buffer[0] = '\0';
}
void StringBufferDiscardOutput(struct StringBuffer *sb) {
sb->insert = 0;
sb->buffer[0] = '\0';
}
void StringBufferDtor(struct StringBuffer *sb) {
sb->nbytes = 0;
sb->insert = 0;
free(sb->buffer);
sb->buffer = NULL;
}
void StringBufferPrintf(struct StringBuffer *sb,
char const *fmt, ...)
__attribute__((format(printf, 2, 3)));
void StringBufferPrintf(struct StringBuffer *sb,
char const *fmt, ...) {
size_t space;
char *insert_pt;
va_list ap;
int written = 0;
char *new_buffer;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
for (;;) {
space = sb->nbytes - sb->insert;
insert_pt = sb->buffer + sb->insert;
va_start(ap, fmt);
written = vsnprintf(insert_pt, space, fmt, ap);
va_end(ap);
if (written < space) {
sb->insert += written;
break;
}
/* insufficient space -- grow the buffer */
new_buffer = realloc(sb->buffer, 2 * sb->nbytes);
if (NULL == new_buffer) {
/* give up */
fprintf(stderr, "StringBufferPrintf: no memory\n");
break;
}
sb->nbytes *= 2;
sb->buffer = new_buffer;
}
}
int EnumerateNames(struct StringBuffer *sb, NaClSrpcChannel *nschan) {
char buffer[1024];
uint32_t nbytes = sizeof buffer;
char *p;
size_t name_len;
if (NACL_SRPC_RESULT_OK != NaClSrpcInvokeBySignature(nschan,
NACL_NAME_SERVICE_LIST,
&nbytes, buffer)) {
return 0;
}
StringBufferPrintf(sb, "nbytes = %zu\n", (size_t) nbytes);
if (nbytes == sizeof buffer) {
fprintf(stderr, "Insufficent space for namespace enumeration\n");
return 0;
}
for (p = buffer; p - buffer < nbytes; p += name_len) {
name_len = strlen(p) + 1;
StringBufferPrintf(sb, "%s\n", p);
}
return 1;
}
/*
* Return name service output
*/
void NameServiceDump(NaClSrpcRpc *rpc,
NaClSrpcArg **in_args,
NaClSrpcArg **out_args,
NaClSrpcClosure *done) {
struct StringBuffer sb;
StringBufferCtor(&sb);
if (EnumerateNames(&sb, &ns_channel)) {
out_args[0]->arrays.str = strdup(sb.buffer);
rpc->result = NACL_SRPC_RESULT_OK;
} else {
rpc->result = NACL_SRPC_RESULT_APP_ERROR;
}
done->Run(done);
StringBufferDtor(&sb);
}
void ManifestTest(NaClSrpcRpc *rpc,
NaClSrpcArg **in_args,
NaClSrpcArg **out_args,
NaClSrpcClosure *done) {
struct StringBuffer sb;
int status;
int manifest;
char buffer[1024];
uint32_t nbytes = sizeof buffer;
char *p;
size_t name_len;
/* just get the descriptor for now */
StringBufferCtor(&sb);
if (NACL_SRPC_RESULT_OK !=
NaClSrpcInvokeBySignature(&ns_channel, NACL_NAME_SERVICE_LOOKUP,
"ManifestNameService", O_RDWR,
&status, &manifest)) {
fprintf(stderr, "nameservice lookup RPC failed\n");
}
StringBufferPrintf(&sb, "Got manifest descriptor %d\n", manifest);
if (-1 == manifest) {
fprintf(stderr, "nameservice lookup failed: status %d\n", status);
} else {
/* connect to manifest name server */
int manifest_conn;
struct NaClSrpcChannel manifest_channel;
manifest_conn = imc_connect(manifest);
StringBufferPrintf(&sb, "got manifest connection %d\n", manifest_conn);
if (-1 == manifest_conn) {
StringBufferPrintf(&sb, "could not connect\n");
goto done;
}
close(manifest);
if (!NaClSrpcClientCtor(&manifest_channel, manifest_conn)) {
StringBufferPrintf(&sb, "could not build srpc client\n");
goto done;
}
if (NACL_SRPC_RESULT_OK !=
NaClSrpcInvokeBySignature(&manifest_channel, NACL_NAME_SERVICE_LIST,
&nbytes, buffer)) {
StringBufferPrintf(&sb, "manifest list failed\n");
goto done;
}
StringBufferDiscardOutput(&sb);
StringBufferPrintf(&sb, "Manifest Contents:\n");
for (p = buffer; p - buffer < nbytes; p += name_len + 1) {
name_len = strlen(p);
StringBufferPrintf(&sb, "%.*s\n", (int) name_len, p);
}
}
done:
out_args[0]->arrays.str = strdup(sb.buffer);
rpc->result = NACL_SRPC_RESULT_OK;
done->Run(done);
StringBufferDtor(&sb);
}
const struct NaClSrpcHandlerDesc srpc_methods[] = {
/* Export the methods as taking no arguments and returning a string. */
{ "namedump::s", NameServiceDump },
{ "manifest_test::s", ManifestTest },
{ NULL, NULL },
};
int main(void) {
int ns;
int connected_socket;
if (!NaClSrpcModuleInit()) {
return 1;
}
ns = -1;
nacl_nameservice(&ns);
assert(-1 != ns);
connected_socket = imc_connect(ns);
assert(-1 != connected_socket);
if (!NaClSrpcClientCtor(&ns_channel, connected_socket)) {
fprintf(stderr, "Srpc client channel ctor failed\n");
return 1;
}
close(ns);
if (!NaClSrpcAcceptClientConnection(srpc_methods)) {
return 1;
}
NaClSrpcModuleFini();
return 0;
}