2 * Copyright 2008, Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
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
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.
35 * Tests the Nrd Xfer protocol implementation.
42 #include <sys/types.h>
47 #include <sys/nacl_imc_api.h>
48 #include <sys/nacl_syscalls.h>
52 void thread_sleep(unsigned int num_seconds
) {
58 if (0 == num_seconds
) {
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
;
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
,
82 struct NaClImcMsgHdr msg_hdr
;
83 struct NaClImcMsgIoVec 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
);
100 int recv_imc_msg(int channel
,
104 struct NaClImcMsgHdr msg_hdr
;
105 struct NaClImcMsgIoVec iov
;
109 msg_hdr
.iov_length
= 1;
110 msg_hdr
.descv
= descp
;
111 msg_hdr
.desc_length
= NULL
!= descp
;
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
);
120 if (0 != (msg_hdr
.flags
& (RECVMSG_DATA_TRUNCATED
121 | RECVMSG_DESC_TRUNCATED
))) {
122 fprintf(stderr
, "imc_recvmsg truncated: %d\n", msg_hdr
.flags
);
125 if (msg_hdr
.desc_length
!= (NULL
!= descp
)) {
126 fprintf(stderr
, "icm_recvmsg: got wrong descriptor count\n");
133 * worker thread only processes one fake RPC.
135 void *worker_thread(void *state
) {
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
];
155 send_imc_msg(ch
, buf
, -1);
161 int main(int ac
, char **av
) {
163 char const *message
= NULL
;
164 char const *message2
= NULL
;
166 int client_desc
= -1;
168 int sockaddrd
; /* socket address descriptor */
171 char data_buffer
[4096];
172 int desc_buffer
[IMC_USER_DESC_MAX
];
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"))) {
180 client_desc
= strtol(optarg
, (char **) 0, 0);
181 /* descriptor holds a connection capability for the server */
184 loop_iter
= strtoul(optarg
, (char **) 0, 0);
196 sleep_seconds
= strtoul(optarg
, (char **) 0, 0);
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"
204 "Typically, server is run using a command such as\n"
206 " sel_ldr -X -1 -D 1 -f nrd_xfer_test2.nexe -- -s\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"
211 " sel_ldr -X -1 -a 6:<addr-from-server> " /* no \n */
212 "-- nrd_xfer_test_nacl.nexe -c 6\n"
214 "to have descriptor 6 be used to represent the socket\n"
215 "address for connecting to the server\n"));
220 for (i
= 0; i
< sizeof desc_buffer
/ sizeof desc_buffer
[0]; ++i
) {
225 message
= (NULL
!= message
) ? message
226 : "\"Hello world!\", from server\n";
227 message2
= (NULL
!= message2
) ? message2
230 message
= (NULL
!= message
) ? message
231 : "Client connect request\n";
232 message2
= (NULL
!= message2
) ? message2
233 :"\"Goodbye cruel world!\", from client\n";
241 printf("Accepting a client connection...\n");
242 channel
= imc_accept(3);
243 printf("...got channel descriptor %d\n", channel
);
246 rv
= recv_imc_msg(channel
, data_buffer
, sizeof data_buffer
, NULL
);
247 printf("Receive returned %d\n", rv
);
250 fprintf(stderr
, "imc_recvmsg failed\n");
253 printf("Data bytes: %.*s\n", rv
, data_buffer
);
256 if (-1 == imc_makeboundsock(pair
)) {
257 fprintf(stderr
, "imc_socketpair failed, errno %d\n", errno
);
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]);
266 fprintf(stderr
, "pthread_create failed, returned %d\n", err
);
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
);
286 if (-1 == client_desc
) {
288 "Client needs server socket address to which to connect\n");
292 channel
= imc_connect(client_desc
);
294 printf("Connect returned %d\n", channel
);
297 fprintf(stderr
, "Client could not connect, errno %d\n", errno
);
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
);
311 subchannel
= imc_connect(sockaddrd
);
313 if (-1 == subchannel
) {
314 printf("Connect for client-specific socket failed: errno %d\n", errno
);
318 if (-1 == close(sockaddrd
)) {
319 fprintf(stderr
, "close of %d sockaddr failed, errno %d\n",
323 send_imc_msg(subchannel
, message2
, -1);
324 if (-1 == (rv
= recv_imc_msg(subchannel
, data_buffer
, sizeof data_buffer
,
326 fprintf(stderr
, "receive from worker thread failed, errno %d\n",
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
);