blob: d76e0a66868d47d89b53f24046f73ae5d2856625 [file] [log] [blame]
/*
* Copyright (c) 2008 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.
*/
/** @file
*
* Tests the Nrd Xfer protocol implementation.
*/
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include "native_client/src/public/imc_syscalls.h"
#include "native_client/src/public/imc_types.h"
/*
* sends a string w/ at most one descriptor.
*/
void send_imc_msg(int channel,
char const *msg,
int desc) {
struct NaClAbiNaClImcMsgHdr msg_hdr;
struct NaClAbiNaClImcMsgIoVec iov;
int nbytes;
int rv;
msg_hdr.iov = &iov;
msg_hdr.iov_length = 1;
msg_hdr.descv = &desc;
msg_hdr.desc_length = -1 != desc;
iov.base = (char *) msg;
iov.length = nbytes = strlen(msg);
if (nbytes != (rv = imc_sendmsg(channel, &msg_hdr, 0))) {
fprintf(stderr, "imc_sendmsg returned %d, expected %d\n", rv, nbytes);
fprintf(stderr, "errno %d\n", errno);
exit(1);
}
}
int recv_imc_msg(int channel,
char *recvbuf,
int bufsize,
int *descp) {
struct NaClAbiNaClImcMsgHdr msg_hdr;
struct NaClAbiNaClImcMsgIoVec iov;
int rv;
msg_hdr.iov = &iov;
msg_hdr.iov_length = 1;
msg_hdr.descv = descp;
msg_hdr.desc_length = NULL != descp;
msg_hdr.flags = 0;
iov.base = recvbuf;
iov.length = bufsize;
if (-1 == (rv = imc_recvmsg(channel, &msg_hdr, 0))) {
fprintf(stderr, "imc_recvmsg returned %d\n", rv);
fprintf(stderr, "errno %d\n", errno);
exit(1);
}
if (0 != (msg_hdr.flags & (NACL_ABI_RECVMSG_DATA_TRUNCATED
| NACL_ABI_RECVMSG_DESC_TRUNCATED))) {
fprintf(stderr, "imc_recvmsg truncated: %d\n", msg_hdr.flags);
exit(1);
}
if (msg_hdr.desc_length != (NULL != descp)) {
fprintf(stderr, "icm_recvmsg: got wrong descriptor count\n");
exit(1);
}
return rv;
}
/*
* worker thread only processes one fake RPC.
*/
void *worker_thread(void *state) {
int d = (int) state;
char buf[4096];
int rv;
int i;
int ch;
ch = imc_accept(d);
write(2, "accepted\n", 9);
rv = recv_imc_msg(ch, buf, sizeof buf, NULL);
/* in case newlib version of stdio has thread safety issues */
write(2, "Got: ", 5); write(2, buf, rv); write(2, "\n", 1);
/* echo it ... sdrawkcab! */
for (i = rv/2; --i >= 0; ) {
char t = buf[rv - 1 - i];
buf[rv - 1 - i] = buf[i];
buf[i] = t;
}
send_imc_msg(ch, buf, -1);
close(ch);
close(d);
return 0;
}
int main(int ac, char **av) {
int opt;
char const *message = NULL;
char const *message2 = NULL;
int server = 0;
int client_desc = -1;
int channel;
int sockaddrd; /* socket address descriptor */
int subchannel;
int rv;
char data_buffer[4096];
int desc_buffer[NACL_ABI_IMC_USER_DESC_MAX];
size_t i;
unsigned long loop_iter = 1;
unsigned int sleep_seconds = 0;
while (EOF != (opt = getopt(ac, av, "c:l:m:M:sS:t:v"))) {
switch (opt) {
case 'c':
client_desc = strtol(optarg, (char **) 0, 0);
/* descriptor holds a connection capability for the server */
break;
case 'l':
loop_iter = strtoul(optarg, (char **) 0, 0);
break;
case 'm':
message = optarg;
break;
case 'M':
message2 = optarg;
break;
case 's':
server = 1;
break;
case 'S':
sleep_seconds = strtoul(optarg, (char **) 0, 0);
break;
default:
fprintf(stderr,
("Usage: sel_ldr [sel_ldr_args] -- " /* no newline */
"nrd_xfer_test2.nexe [-c server-addr-desc] [-s]\n"
" [-l loop_count] [-S server-sleep-sec]\n"
"\n"
"Typically, server is run using a command such as\n"
"\n"
" sel_ldr -X -1 -D 1 -f nrd_xfer_test2.nexe -- -s\n"
"\n"
"so the socket address is printed to standard output,\n"
"and then the client is run with a command such as\n"
"\n"
" sel_ldr -X -1 -a 6:<addr-from-server> " /* no \n */
"-- nrd_xfer_test_nacl.nexe -c 6\n"
"\n"
"to have descriptor 6 be used to represent the socket\n"
"address for connecting to the server\n"));
return 1;
}
}
for (i = 0; i < sizeof desc_buffer / sizeof desc_buffer[0]; ++i) {
desc_buffer[i] = -1;
}
if (server) {
message = (NULL != message) ? message
: "\"Hello world!\", from server\n";
message2 = (NULL != message2) ? message2
: "SERVER MSG2";
} else {
message = (NULL != message) ? message
: "Client connect request\n";
message2 = (NULL != message2) ? message2
:"\"Goodbye cruel world!\", from client\n";
}
if (server) {
int pair[2];
pthread_t thr;
int err;
printf("Accepting a client connection...\n");
channel = imc_accept(3);
printf("...got channel descriptor %d\n", channel);
do {
rv = recv_imc_msg(channel, data_buffer, sizeof data_buffer, NULL);
printf("Receive returned %d\n", rv);
if (-1 == rv) {
fprintf(stderr, "imc_recvmsg failed\n");
return 1;
}
printf("Data bytes: %.*s\n", rv, data_buffer);
/* send a reply */
if (-1 == imc_makeboundsock(pair)) {
fprintf(stderr, "imc_socketpair failed, errno %d\n", errno);
return 2;
}
/*
* send pair[1], the addr, to peer as reply.
*/
send_imc_msg(channel, "sockaddr", pair[1]);
err = pthread_create(&thr, NULL, worker_thread, (void *) pair[0]);
if (0 != err) {
fprintf(stderr, "pthread_create failed, returned %d\n", err);
return 4;
}
pthread_detach(thr);
if (-1 == close(pair[1])) {
fprintf(stderr, "close of socketpair half failed\n");
}
if (0 != sleep_seconds) {
printf("sleeping for %d seconds...\n", sleep_seconds);
sleep(sleep_seconds);
}
} while (--loop_iter > 0);
if (-1 == close(channel)) {
fprintf(stderr, "close of channel %d failed\n", channel);
}
} else {
if (-1 == client_desc) {
fprintf(stderr,
"Client needs server socket address to which to connect\n");
return 100;
}
channel = imc_connect(client_desc);
printf("Connect returned %d\n", channel);
if (-1 == channel) {
fprintf(stderr, "Client could not connect, errno %d\n", errno);
return 101;
}
do {
send_imc_msg(channel, message, -1);
rv = recv_imc_msg(channel, data_buffer, sizeof data_buffer, &sockaddrd);
printf("start RPC reply returned socket addr desc %d\n", sockaddrd);
if (-1 == sockaddrd) {
fprintf(stderr, "connect failed, errno %d\n", errno);
return 106;
}
subchannel = imc_connect(sockaddrd);
if (-1 == subchannel) {
printf("Connect for client-specific socket failed: errno %d\n", errno);
return 107;
}
if (-1 == close(sockaddrd)) {
fprintf(stderr, "close of %d sockaddr failed, errno %d\n",
sockaddrd, errno);
}
send_imc_msg(subchannel, message2, -1);
if (-1 == (rv = recv_imc_msg(subchannel, data_buffer, sizeof data_buffer,
NULL))) {
fprintf(stderr, "receive from worker thread failed, errno %d\n",
errno);
return 108;
}
/* let's not trust server to NUL terminate */
data_buffer[sizeof data_buffer - 1] = '\0';
printf("reply: %s\n", data_buffer);
if (-1 == close(subchannel)) {
fprintf(stderr, "close of subchannel %d failed\n", subchannel);
}
} while (--loop_iter > 0);
if (-1 == close(channel)) {
fprintf(stderr, "close of %d (channel) failed\n", channel);
}
}
return 0;
}