imcplugin demo: Extend to support stat() call
[nativeclient.git] / tests / nrd_xfer / nrd_xfer_test2.c
blob945d164823a3d8b9f8e846215c3c8a7436f3fee2
1 /*
2 * Copyright 2008, Google Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 /** @file
35 * Tests the Nrd Xfer protocol implementation.
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <fcntl.h>
45 #include <errno.h>
47 #include <sys/nacl_imc_api.h>
48 #include <sys/nacl_syscalls.h>
50 #include <pthread.h>
52 void thread_sleep(unsigned int num_seconds) {
53 pthread_mutex_t mu;
54 pthread_cond_t cv;
55 struct timeval tv;
56 struct timespec ts;
58 if (0 == num_seconds) {
59 return;
61 pthread_mutex_init(&mu, NULL);
62 pthread_cond_init(&cv, NULL);
64 gettimeofday(&tv, NULL);
65 ts.tv_sec = tv.tv_sec + num_seconds;
66 ts.tv_nsec = 0;
68 pthread_mutex_lock(&mu);
69 pthread_cond_timedwait(&cv, &mu, &ts); /* just for the timeout */
70 pthread_mutex_unlock(&mu);
72 pthread_cond_destroy(&cv);
73 pthread_mutex_destroy(&mu);
77 * sends a string w/ at most one descriptor.
79 void send_imc_msg(int channel,
80 char const *msg,
81 int desc) {
82 struct NaClImcMsgHdr msg_hdr;
83 struct NaClImcMsgIoVec iov;
84 int nbytes;
85 int rv;
87 msg_hdr.iov = &iov;
88 msg_hdr.iov_length = 1;
89 msg_hdr.descv = &desc;
90 msg_hdr.desc_length = -1 != desc;
91 iov.base = (char *) msg;
92 iov.length = nbytes = strlen(msg);
93 if (nbytes != (rv = imc_sendmsg(channel, &msg_hdr, 0))) {
94 fprintf(stderr, "imc_sendmsg returned %d, expected %d\n", rv, nbytes);
95 fprintf(stderr, "errno %d\n", errno);
96 exit(1);
100 int recv_imc_msg(int channel,
101 char *recvbuf,
102 int bufsize,
103 int *descp) {
104 struct NaClImcMsgHdr msg_hdr;
105 struct NaClImcMsgIoVec iov;
106 int rv;
108 msg_hdr.iov = &iov;
109 msg_hdr.iov_length = 1;
110 msg_hdr.descv = descp;
111 msg_hdr.desc_length = NULL != descp;
112 msg_hdr.flags = 0;
113 iov.base = recvbuf;
114 iov.length = bufsize;
115 if (-1 == (rv = imc_recvmsg(channel, &msg_hdr, 0))) {
116 fprintf(stderr, "imc_recvmsg returned %d\n", rv);
117 fprintf(stderr, "errno %d\n", errno);
118 exit(1);
120 if (0 != (msg_hdr.flags & (RECVMSG_DATA_TRUNCATED
121 | RECVMSG_DESC_TRUNCATED))) {
122 fprintf(stderr, "imc_recvmsg truncated: %d\n", msg_hdr.flags);
123 exit(1);
125 if (msg_hdr.desc_length != (NULL != descp)) {
126 fprintf(stderr, "icm_recvmsg: got wrong descriptor count\n");
127 exit(1);
129 return rv;
133 * worker thread only processes one fake RPC.
135 void *worker_thread(void *state) {
136 int d = (int) state;
137 char buf[4096];
138 int rv;
139 int i;
140 int ch;
142 ch = imc_accept(d);
143 write(2, "accepted\n", 9);
145 rv = recv_imc_msg(ch, buf, sizeof buf, NULL);
146 /* in case newlib version of stdio has thread safety issues */
147 write(2, "Got: ", 5); write(2, buf, rv); write(2, "\n", 1);
149 /* echo it ... sdrawkcab! */
150 for (i = rv/2; --i >= 0; ) {
151 char t = buf[rv - 1 - i];
152 buf[rv - 1 - i] = buf[i];
153 buf[i] = t;
155 send_imc_msg(ch, buf, -1);
156 close(ch);
157 close(d);
158 return 0;
161 int main(int ac, char **av) {
162 int opt;
163 char const *message = NULL;
164 char const *message2 = NULL;
165 int server = 0;
166 int client_desc = -1;
167 int channel;
168 int sockaddrd; /* socket address descriptor */
169 int subchannel;
170 int rv;
171 char data_buffer[4096];
172 int desc_buffer[IMC_USER_DESC_MAX];
173 size_t i;
174 unsigned long loop_iter = 1;
175 unsigned int sleep_seconds = 0;
177 while (EOF != (opt = getopt(ac, av, "c:l:m:M:sS:t:v"))) {
178 switch (opt) {
179 case 'c':
180 client_desc = strtol(optarg, (char **) 0, 0);
181 /* descriptor holds a connection capability for the server */
182 break;
183 case 'l':
184 loop_iter = strtoul(optarg, (char **) 0, 0);
185 break;
186 case 'm':
187 message = optarg;
188 break;
189 case 'M':
190 message2 = optarg;
191 break;
192 case 's':
193 server = 1;
194 break;
195 case 'S':
196 sleep_seconds = strtoul(optarg, (char **) 0, 0);
197 break;
198 default:
199 fprintf(stderr,
200 ("Usage: sel_ldr [sel_ldr_args] -- " /* no newline */
201 "nrd_xfer_test2.nexe [-c server-addr-desc] [-s]\n"
202 " [-l loop_count] [-S server-sleep-sec]\n"
203 "\n"
204 "Typically, server is run using a command such as\n"
205 "\n"
206 " sel_ldr -X -1 -D 1 -f nrd_xfer_test2.nexe -- -s\n"
207 "\n"
208 "so the socket address is printed to standard output,\n"
209 "and then the client is run with a command such as\n"
210 "\n"
211 " sel_ldr -X -1 -a 6:<addr-from-server> " /* no \n */
212 "-- nrd_xfer_test_nacl.nexe -c 6\n"
213 "\n"
214 "to have descriptor 6 be used to represent the socket\n"
215 "address for connecting to the server\n"));
216 return 1;
220 for (i = 0; i < sizeof desc_buffer / sizeof desc_buffer[0]; ++i) {
221 desc_buffer[i] = -1;
224 if (server) {
225 message = (NULL != message) ? message
226 : "\"Hello world!\", from server\n";
227 message2 = (NULL != message2) ? message2
228 : "SERVER MSG2";
229 } else {
230 message = (NULL != message) ? message
231 : "Client connect request\n";
232 message2 = (NULL != message2) ? message2
233 :"\"Goodbye cruel world!\", from client\n";
236 if (server) {
237 int pair[2];
238 pthread_t thr;
239 int err;
241 printf("Accepting a client connection...\n");
242 channel = imc_accept(3);
243 printf("...got channel descriptor %d\n", channel);
244 do {
246 rv = recv_imc_msg(channel, data_buffer, sizeof data_buffer, NULL);
247 printf("Receive returned %d\n", rv);
249 if (-1 == rv) {
250 fprintf(stderr, "imc_recvmsg failed\n");
251 return 1;
253 printf("Data bytes: %.*s\n", rv, data_buffer);
255 /* send a reply */
256 if (-1 == imc_makeboundsock(pair)) {
257 fprintf(stderr, "imc_socketpair failed, errno %d\n", errno);
258 return 2;
261 * send pair[1], the addr, to peer as reply.
263 send_imc_msg(channel, "sockaddr", pair[1]);
264 err = pthread_create(&thr, NULL, worker_thread, (void *) pair[0]);
265 if (0 != err) {
266 fprintf(stderr, "pthread_create failed, returned %d\n", err);
267 return 4;
270 pthread_detach(thr);
272 if (-1 == close(pair[1])) {
273 fprintf(stderr, "close of socketpair half failed\n");
276 if (0 != sleep_seconds) {
277 printf("sleeping for %d seconds...\n", sleep_seconds);
278 thread_sleep(sleep_seconds);
280 } while (--loop_iter > 0);
282 if (-1 == close(channel)) {
283 fprintf(stderr, "close of channel %d failed\n", channel);
285 } else {
286 if (-1 == client_desc) {
287 fprintf(stderr,
288 "Client needs server socket address to which to connect\n");
289 return 100;
292 channel = imc_connect(client_desc);
294 printf("Connect returned %d\n", channel);
296 if (-1 == channel) {
297 fprintf(stderr, "Client could not connect, errno %d\n", errno);
298 return 101;
301 do {
302 send_imc_msg(channel, message, -1);
303 rv = recv_imc_msg(channel, data_buffer, sizeof data_buffer, &sockaddrd);
305 printf("start RPC reply returned socket addr desc %d\n", sockaddrd);
306 if (-1 == sockaddrd) {
307 fprintf(stderr, "connect failed, errno %d\n", errno);
308 return 106;
311 subchannel = imc_connect(sockaddrd);
313 if (-1 == subchannel) {
314 printf("Connect for client-specific socket failed: errno %d\n", errno);
315 return 107;
318 if (-1 == close(sockaddrd)) {
319 fprintf(stderr, "close of %d sockaddr failed, errno %d\n",
320 sockaddrd, errno);
323 send_imc_msg(subchannel, message2, -1);
324 if (-1 == (rv = recv_imc_msg(subchannel, data_buffer, sizeof data_buffer,
325 NULL))) {
326 fprintf(stderr, "receive from worker thread failed, errno %d\n",
327 errno);
328 return 108;
330 /* let's not trust server to NUL terminate */
331 data_buffer[sizeof data_buffer - 1] = '\0';
332 printf("reply: %s\n", data_buffer);
334 if (-1 == close(subchannel)) {
335 fprintf(stderr, "close of subchannel %d failed\n", subchannel);
337 } while (--loop_iter > 0);
339 if (-1 == close(channel)) {
340 fprintf(stderr, "close of %d (channel) failed\n", channel);
343 return 0;