1/*
2 * Copyright (c) 2010 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1.  Redistributions of source code must retain the above copyright
11 *     notice, this list of conditions and the following disclaimer.
12 * 2.  Redistributions in binary form must reproduce the above copyright
13 *     notice, this list of conditions and the following disclaimer in the
14 *     documentation and/or other materials provided with the distribution.
15 * 3.  Neither the name of Apple Inc. ("Apple") 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.
18 *
19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * Portions of this software have been released under the following terms:
31 *
32 * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC.
33 * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY
34 * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION
35 *
36 * To anyone who acknowledges that this file is provided "AS IS"
37 * without any express or implied warranty:
38 * permission to use, copy, modify, and distribute this file for any
39 * purpose is hereby granted without fee, provided that the above
40 * copyright notices and this notice appears in all source code copies,
41 * and that none of the names of Open Software Foundation, Inc., Hewlett-
42 * Packard Company or Digital Equipment Corporation be used
43 * in advertising or publicity pertaining to distribution of the software
44 * without specific, written prior permission.  Neither Open Software
45 * Foundation, Inc., Hewlett-Packard Company nor Digital
46 * Equipment Corporation makes any representations about the suitability
47 * of this software for any purpose.
48 *
49 * Copyright (c) 2007, Novell, Inc. All rights reserved.
50 * Redistribution and use in source and binary forms, with or without
51 * modification, are permitted provided that the following conditions
52 * are met:
53 *
54 * 1.  Redistributions of source code must retain the above copyright
55 *     notice, this list of conditions and the following disclaimer.
56 * 2.  Redistributions in binary form must reproduce the above copyright
57 *     notice, this list of conditions and the following disclaimer in the
58 *     documentation and/or other materials provided with the distribution.
59 * 3.  Neither the name of Novell Inc. nor the names of its contributors
60 *     may be used to endorse or promote products derived from this
61 *     this software without specific prior written permission.
62 *
63 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
64 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
65 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
66 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
67 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
68 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
69 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
70 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
71 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
72 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
73 *
74 * @APPLE_LICENSE_HEADER_END@
75 */
76
77/*
78**  NAME
79**
80**      client.c
81**
82**  FACILITY:
83**
84**      Remote Procedure Call (RPC)
85**
86**  ABSTRACT:
87**
88**  Client application code for performance and system exerciser.
89**
90**
91*/
92
93#include <perf_c.h>
94#include <string.h>
95#include <malloc.h>
96#include <sys/time.h>
97#ifndef NO_TIMES
98#include <sys/times.h>
99#include <unistd.h>
100#endif  /* NO_TIMES */
101#include <stdlib.h>
102#include <sys/wait.h>
103
104
105typedef struct
106{
107    unsigned short              ifspec_vers;
108    unsigned short              opcnt;
109    unsigned long               vers;
110    idl_uuid_t                      id;
111    unsigned short              stub_rtl_if_vers;
112} rpc_if_rep_t, *rpc_if_rep_p_t;
113
114static void looping_test();
115static void brd_test();
116static void unreg_test();
117static void forwarding_test();
118static void exception_test();
119static void shutdown_test();
120static void callback_test();
121static void generic_test();
122static void context_test();
123static void static_cancel_test();
124static void stats_test();
125static void inq_if_ids_test();
126static void one_shot_test();
127
128#define SHUTMODE_MGR    1
129#define SHUTMODE_NO_MGR 2
130#define SHUTMODE_MGMT   3
131
132struct tinfo_t
133{
134    void (*proc)();
135    char *name;
136    char *usage;
137} tinfo[] =
138    {
139        /*  0 */     {looping_test,    "Null call",
140                "host passes calls/pass verify? idempotent?"},
141        /*  1 */     {looping_test,    "Variable length input arg",
142                "host passes calls/pass verify? idempotent? nbytes"},
143        /*  2 */     {looping_test,    "Variable length output arg",
144                "host passes calls/pass verify? idempotent? nbytes"},
145        /*  3 */     {brd_test,        "Broadcast",
146                "family"},
147        /*  4 */     {looping_test,    "Maybe",
148                "host passes calls/pass"},
149        /*  5 */     {brd_test,        "Broadcast/maybe",
150                "family"},
151        /*  6 */     {looping_test,    "Floating point",
152                "host passes calls/pass verify? idempotent?"},
153        /*  7 */     {unreg_test,      "Unregistered interface",
154                "host"},
155        /*  8 */     {forwarding_test, "Forwarding",
156                "host global?"},
157        /*  9 */     {exception_test,  "Exception",
158                "host"},
159        /* 10 */     {looping_test,    "Slow call",
160                "host passes calls/pass verify? idempotent? seconds [mode]"},
161        /* 11 */     {shutdown_test,   "Shutdown",
162                "host[+ep] [mode [secs]] (1=manager, 2=no manager, 3=management)"},
163        /* 12 */     {callback_test,   "Callback (UNSUPPORTED!)",
164                "host passes callbacks/pass idempotent?"},
165        /* 13 */     {generic_test,    "Generic interface",
166                "host"},
167        /* 14 */     {context_test,    "Context test",
168                "host passes die? seconds"},
169        /* 15 */     {static_cancel_test,    "Static Cancel",
170                "host passes idempotent? [seconds [cancel-timeout-seconds]]"},
171        /* 16 */     {stats_test,      "Statistics",
172                "[host+ep]"},
173        /* 17 */     {inq_if_ids_test, "Interface identifiers",
174                "[host+ep]"},
175        /* 18 */     {one_shot_test, "One shot",
176                "host[+ep] forward? idempotent?"},
177    };
178
179#define N_TESTS (int)(sizeof tinfo / sizeof (struct tinfo_t))
180
181
182#ifdef _POSIX_THREADS
183
184#define MAX_TASKS 40
185
186idl_boolean multithread = false;
187idl_boolean use_shared_handle = false;
188int n_tasks;
189pthread_mutex_t global_mutex;
190
191#endif
192
193idl_boolean authenticate;
194unsigned32  authn_level;
195idl_char    *auth_principal;
196unsigned32  authn_protocol;
197unsigned32  authz_protocol;
198
199idl_boolean debug = false;
200idl_boolean stats = false;
201idl_boolean use_obj = false;
202idl_boolean compat_mode = false;
203signed32 timeout = -1;
204signed32 cancel_timeout = -1;
205
206int recreate_binding_freq = 0;  /* "infinity" */
207int reset_binding_freq = 0;     /* "infinity" */
208
209int wait_point = -1;
210int wait_time;
211
212unsigned32 socket_buf_size = 0;	/* os default */
213
214int verbose = 1;
215
216#ifdef NO_TIMES
217struct msec_time
218{
219    unsigned long msec;
220    unsigned short usec;
221};
222#else
223struct msec_time
224{
225    struct tms ptime;
226    struct timeval elapsed;
227    unsigned long r_msec;
228    unsigned long r_usec;
229    unsigned long u_msec;
230    unsigned long s_msec;
231};
232
233static long clock_ticks;
234#endif  /* NO_TIMES */
235
236#ifndef NO_GETTIMEOFDAY
237
238#define GETTIMEOFDAY(t) \
239{ \
240    struct timezone tz; \
241 \
242    gettimeofday(t, &tz); \
243}
244
245#else
246
247struct timeval
248{
249    unsigned long tv_sec;
250    unsigned long tv_usec;
251};
252
253#define GETTIMEOFDAY(t) \
254{ \
255    (t)->tv_sec  = time(NULL); \
256    (t)->tv_usec = 0; \
257}
258
259#endif
260
261
262/*
263 * Print how to use this program
264 */
265void usage (test)
266
267int             test;
268
269{
270    int             i;
271
272    if (test != -1)
273    {
274        fprintf (stderr, "usage: client <flags> %d %s\n",
275            test, tinfo[test].usage);
276    }
277    else
278    {
279        fprintf (stderr, "usage: client [-Dis] [-d <debug switches>] [(-m|M) <nthreads>]\n");
280        fprintf (stderr, "              [-t <timeout>] [-c <timeout>] [-w <wait point>,<wait secs>]\n");
281        fprintf (stderr, "              [-p <authn proto>,<authz proto>[,<level>[,<principal>]]]\n");
282        fprintf (stderr, "              [-r <frequency>] [-R <frequency>] [-v <verbose level>]\n");
283        fprintf (stderr, "              [-f <opt>] [-B <bufsize>]\n");
284        fprintf (stderr, "              test# ...\n");
285        fprintf (stderr, "  -d: Turns on NCK runtime debug output\n");
286        fprintf (stderr, "  -D: Turns on default NCK runtime debug output\n");
287        fprintf (stderr, "  -t: Set communications timeout (0-10)\n");
288        fprintf (stderr, "  -c: Set cancel timeout (seconds)\n");
289        fprintf (stderr, "  -B: Set CN TCP socket buffer (bytes)\n");
290        fprintf (stderr, "  -f: Repeat test after fork, <opt> can be:\n");
291        fprintf (stderr, "      1: Repeat test in the original and child processes\n");
292        fprintf (stderr, "      2: Repeat test in the original process only\n");
293        fprintf (stderr, "      3: Repeat test in the child process only\n");
294        fprintf (stderr, "      4: Repeat test in the child and grandchild processes\n");
295        fprintf (stderr, "      5: Repeat test in the grandchild process only\n");
296        fprintf (stderr, "      6: Run test in the child process only\n");
297        fprintf (stderr, "  -s: Prints statistics at end of test\n");
298        fprintf (stderr, "  -w: Causes client to wait at specified point for specified time\n");
299        fprintf (stderr, "  -o: Use perf object in bindings (default is no object)\n");
300        fprintf (stderr, "  -1: Avoid doing certain things that NCS 1.5 can't do\n");
301        fprintf (stderr, "  -r: Reset bindings every <frequency> calls in a single pass\n");
302        fprintf (stderr, "  -R: Recreate bindings every <frequency> calls in a single pass\n");
303#ifdef _POSIX_THREADS
304        fprintf (stderr,
305            "  -m: Causes nthreads tasks to run at same time (tasking systems only)\n");
306        fprintf (stderr,
307            "  -M: Same as -m but use a shared binding handle (tasking systems only)\n");
308#endif
309        fprintf (stderr,
310            "  -i: Causes statistics to be dumped at end of run\n");
311        fprintf (stderr,
312            "  -p: Authenticate using <authn proto>/<authz proto> at <level> to <principal>\n");
313        fprintf (stderr,
314            "      <level> and <principal> may be omitted\n");
315#ifndef NO_TIMES
316        fprintf (stderr, "CLK_TCK: %ld ticks/sec\n", clock_ticks);
317#endif  /* NO_TIMES */
318        fprintf (stderr, "\n");
319
320        for (i = 0; i < N_TESTS; i++)
321        {
322            fprintf(stderr, "  test #%d: %s test\n    usage: client %d %s\n",
323                    i, tinfo[i].name, i, tinfo[i].usage);
324        }
325    }
326
327    exit(1);
328}
329
330/*
331 * If the specified point is a wait point, then sleep for the specified amount
332 * of time.
333 */
334
335static void check_wait_point(point)
336
337int point;
338
339{
340    if (wait_point == point)
341    {
342        printf("...wait point %d: sleeping for %d seconds\n", point, wait_time);
343        SLEEP(wait_time);
344    }
345}
346
347#ifdef NO_TIMES
348/*
349 * Take a starting time and an iteration count, and produce an average
350 * time per iteration based on the current time.
351 */
352
353static void end_timing(start_time, iterations, avg_time)
354
355struct timeval *start_time;
356unsigned long iterations;
357struct msec_time *avg_time;
358
359{
360    struct timeval elapsed_time;
361    unsigned long elapsed_usec;
362
363    GETTIMEOFDAY(&elapsed_time);
364
365    if (elapsed_time.tv_usec < start_time->tv_usec)
366    {
367        elapsed_time.tv_sec--;
368        elapsed_time.tv_usec += 1000000;
369    }
370
371    elapsed_time.tv_usec -= start_time->tv_usec;
372    elapsed_time.tv_sec  -= start_time->tv_sec;
373
374    elapsed_usec = (elapsed_time.tv_sec * 1000000) + elapsed_time.tv_usec;
375
376    avg_time->msec = (elapsed_usec / iterations) / 1000;
377    avg_time->usec = (elapsed_usec / iterations) % 1000;
378}
379#else
380static void start_timing(start_time)
381struct msec_time *start_time;
382{
383    GETTIMEOFDAY(&start_time->elapsed);
384
385    if (times(&start_time->ptime) == -1)
386        memset(&start_time->ptime, 0, sizeof(start_time->ptime));
387}
388
389/*
390 * Take a starting time and an iteration count, and produce an average
391 * time per iteration based on the current time.
392 */
393
394static void end_timing(start_time, iterations, avg_time)
395
396struct msec_time *start_time;
397unsigned long iterations;
398struct msec_time *avg_time;
399
400{
401    struct tms ptime;
402    unsigned long elapsed_usec;
403
404    GETTIMEOFDAY(&avg_time->elapsed);
405
406    if (times(&ptime) != -1)
407    {
408        avg_time->ptime.tms_utime = ptime.tms_utime
409            - start_time->ptime.tms_utime;
410        avg_time->ptime.tms_stime = ptime.tms_stime
411            - start_time->ptime.tms_stime;
412
413        avg_time->u_msec = (avg_time->ptime.tms_utime / iterations)
414            * 1000 / clock_ticks;
415        avg_time->s_msec = (avg_time->ptime.tms_stime / iterations)
416            * 1000 / clock_ticks;
417    }
418    else
419    {
420        avg_time->u_msec = 0;
421        avg_time->s_msec = 0;
422    }
423
424    if (avg_time->elapsed.tv_usec < start_time->elapsed.tv_usec)
425    {
426        avg_time->elapsed.tv_sec--;
427        avg_time->elapsed.tv_usec += 1000000;
428    }
429
430    avg_time->elapsed.tv_usec -= start_time->elapsed.tv_usec;
431    avg_time->elapsed.tv_sec  -= start_time->elapsed.tv_sec;
432
433    elapsed_usec = (avg_time->elapsed.tv_sec * 1000000)
434        + avg_time->elapsed.tv_usec;
435
436    avg_time->r_msec = (elapsed_usec / iterations) / 1000;
437    avg_time->r_usec = (elapsed_usec / iterations) % 1000;
438}
439#endif  /* NO_TIMES */
440
441/*
442 * Get an RPC handle for a name
443 */
444
445static handle_t binding_from_string_binding (object, name)
446
447idl_uuid_t              *object;
448char                *name;
449
450{
451    unsigned32          st;
452    handle_t            h;
453
454    rpc_binding_from_string_binding
455        ((idl_char *) name, (rpc_binding_handle_t *) &h, &st);
456
457    if (st != rpc_s_ok)
458    {
459        fprintf (stderr, "*** Can't convert name \"%s\" to binding - %s\n",
460            name, error_text (st));
461        exit(1);
462    }
463
464    rpc_binding_set_object (h,
465                            object != NULL ?
466                                object :
467                                use_obj ? &NilTypeObj : NULL,
468                            &st);
469
470    if (st != rpc_s_ok)
471    {
472        fprintf (stderr, "*** Can't set binding's object - %s\n",
473            error_text (st));
474        exit(1);
475    }
476
477    if (timeout != -1)
478    {
479        rpc_mgmt_set_com_timeout (h, (unsigned32) timeout, &st);
480
481        if (st != rpc_s_ok)
482        {
483            fprintf (stderr, "*** Can't set timeout for binding - %s\n",
484                 error_text (st));
485            exit(1);
486        }
487    }
488
489    if (authenticate)
490    {
491        unsigned32 authn_level_local, authn_protocol_local, authz_protocol_local;
492        unsigned_char_p_t auth_principal_local;
493
494        /*
495         * If no server principal name was supplied, we must go get one from
496         * the server.
497         */
498        if (auth_principal == NULL)
499        {
500            rpc_mgmt_inq_server_princ_name (h, authn_protocol, &auth_principal, &st);
501            if (st != rpc_s_ok)
502            {
503                fprintf (stderr, "*** Can't get server principal name - %s\n",
504                     error_text (st));
505                exit(1);
506            }
507            VRprintf(2, ("  Server principal name found to be: \"%s\"\n",
508                    auth_principal));
509        }
510
511        /*
512         * Leave a backdoor for testing the unsupported "null server
513         * principal name" feature of rpc_binding_set_auth_info().
514         */
515        if (strcmp ((char *) auth_principal, "NULL") == 0)
516        {
517            auth_principal = NULL;
518        }
519
520        rpc_binding_set_auth_info
521            (h, auth_principal, authn_level, authn_protocol, NULL, authz_protocol, &st);
522        if (st != rpc_s_ok)
523        {
524            fprintf (stderr, "*** Can't set authentication for binding - %s\n",
525                 error_text (st));
526            exit(1);
527        }
528        rpc_binding_inq_auth_info
529            (h, &auth_principal_local, &authn_level_local, &authn_protocol_local, NULL,
530                &authz_protocol_local, &st);
531        if (st != rpc_s_ok)
532        {
533            fprintf (stderr, "*** Can't get authentication back from binding - %s\n",
534                error_text (st));
535            exit(1);
536        }
537        VRprintf(2, ("  Authentication info from binding:\n    authn protocol: %s\n    authz protocol: %s\n    level: %s\n    server princ: \"%s\"\n  -----------------\n",
538                authn_names[authn_protocol_local],
539                authz_names[authz_protocol_local],
540                authn_level_names[authn_level_local],
541                auth_principal_local));
542        if (auth_principal_local != NULL)
543        {
544            rpc_string_free (&auth_principal_local, &st);
545        }
546    }
547
548    return h;
549}
550
551/*
552 * Convert a binding to a string binding.
553 */
554
555static void binding_to_string_binding (rh, name)
556
557handle_t            rh;
558unsigned_char_p_t   *name;
559
560{
561    unsigned32      st;
562
563    rpc_binding_to_string_binding (rh, name, &st);
564    if (st != rpc_s_ok)
565    {
566        fprintf (stderr, "*** Can't convert binding to string binding - %s\n",
567            error_text (st));
568        exit(1);
569    }
570}
571
572/*
573 * Reset a binding.
574 */
575
576static void binding_reset (rh)
577
578handle_t    rh;
579
580{
581    unsigned32      st;
582
583    rpc_binding_reset((rpc_binding_handle_t) rh, &st);
584    if (st != rpc_s_ok)
585    {
586        fprintf(stderr, "*** Can't reset binding - %s\n", error_text(st));
587        exit(1);
588    }
589}
590
591
592/*
593 * Broadcast test
594 */
595
596static void brd_test (test, argc, argv)
597
598int                 test;
599int                 argc;
600char                *argv[];
601
602{
603    handle_t            rh;
604    unsigned32          st;
605    unsigned_char_p_t   name, name2;
606    idl_char            result[256];
607
608    if (argc < 3)
609    {
610        usage (test);
611    }
612
613    rpc_string_binding_compose (NULL, (unsigned_char_p_t) argv[2],
614            NULL, NULL, NULL, &name, &st);
615    if (st != rpc_s_ok)
616    {
617        fprintf(stderr, "*** Can't form string binding from \"%s\"\n", argv[2]);
618        exit(1);
619    }
620
621    rh = binding_from_string_binding (NULL, name);
622
623    /*
624     * Broadcast/maybe test; just make the call and return.
625     */
626
627    if (test == 5)
628    {
629        perf_brd_maybe(rh);
630        return;
631    }
632
633    /*
634     * Normal broadcast.
635     */
636
637    printf ("  Broadcast call that should succeed...\n");
638
639    perf_brd(rh, result);
640    binding_to_string_binding (rh, &name2);
641    printf("    bound to \"%s\", result=\"%s\"\n", name2, result);
642
643    rpc_string_free (&name2, &st);
644    rpc_binding_free (&rh, &st);
645
646    /*
647     * Call a broadcast routine that raises an exception; should see comm failure,
648     * NOT exception.
649     */
650
651    printf ("  Broadcast call that should get communications failure (exception case)...\n");
652
653    rh = binding_from_string_binding (NULL, name);
654
655    TRY
656    {
657        perf_brd_fault(rh);
658        binding_to_string_binding (rh, &name2);
659        fprintf (stderr, "*** Call succeeded (shouldn't have); bound to \"%s\", result=\"%s\"\n", name2, result);
660        rpc_string_free (&name2, &st);
661        exit(1);
662    }
663    CATCH (rpc_x_comm_failure)
664    {
665        printf ("    call failed as expected\n");
666    }
667    CATCH_ALL
668    {
669        exc_report(THIS_CATCH);
670        printf ("    call failed, but with something other than \"communications failure\"\n");
671    }
672    ENDTRY
673
674    rpc_binding_free (&rh, &st);
675
676    /*
677     * Call a broadcast routine that should not be registered; should see comm
678     * failure, NOT exception.
679     */
680
681    printf ("  Broadcast call that should get communications failure (unknown i/f case)...\n");
682
683    rh = binding_from_string_binding (NULL, name);
684
685    TRY
686    {
687        perfb_brd(rh, result);
688        binding_to_string_binding (rh, &name2);
689        fprintf (stderr, "*** Call succeeded (shouldn't have); bound to \"%s\", result=\"%s\"\n", name2, result);
690        exit(1);
691    }
692    CATCH (rpc_x_comm_failure)
693    {
694        printf ("    call failed as expected\n");
695    }
696    CATCH_ALL
697    {
698        printf ("    call failed, but with something other than \"communications failure\"\n");
699    }
700    ENDTRY
701}
702
703/*
704 * Shutdown test
705 */
706
707static void shutdown_test (test, argc, argv)
708
709int                 test;
710int                 argc;
711char                *argv[];
712
713{
714    handle_t            rh;
715    int                 mode;
716    unsigned32          secs;
717    unsigned32          st;
718
719    if (argc < 3)
720    {
721        usage(test);
722    }
723
724    rh = binding_from_string_binding(NULL, argv[2]);
725
726    mode = (argc < 4) ? SHUTMODE_MGR : atoi(argv[3]);
727
728    switch (mode)
729    {
730        case SHUTMODE_MGR:
731            printf("  Shutdown via manager thread calling shutdown\n");
732            perf_shutdown(rh);
733            break;
734
735        case SHUTMODE_NO_MGR:
736            printf("  Shutdown via non-manager calling shutdown\n");
737            secs = (argc < 5) ? 0 : atoi(argv[4]);
738            perf_shutdown2(rh, secs);
739            break;
740
741        case SHUTMODE_MGMT:
742            printf("  Shutdown via local call to management function\n");
743            rpc_mgmt_stop_server_listening(rh, &st);
744            if (st != rpc_s_ok)
745            {
746                fprintf(stderr, "*** Error from management function - %s\n",
747                    error_text (st));
748            }
749            break;
750    }
751
752}
753
754/*
755 * Unregistered interface test.
756 */
757
758static void unreg_test (test, argc, argv)
759
760int                 test;
761int                 argc;
762char                *argv[];
763
764{
765    char                name[256];
766    handle_t            rh;
767    unsigned32          st;
768    unsigned_char_t     *endpoint;
769
770    rpc_if_rep_p_t      if_rep = (rpc_if_rep_p_t)perfb_v1_0_c_ifspec;
771    idl_uuid_t              if_uuid;
772
773    if (argc < 3)
774    {
775        usage(test);
776    }
777
778    memcpy(&if_uuid, &(if_rep->id), sizeof(idl_uuid_t));
779
780    rh = binding_from_string_binding(NULL, argv[2]);
781
782    rpc_string_binding_parse((unsigned_char_t *)argv[2], NULL, NULL, NULL,
783                             &endpoint, NULL, &st);
784    if (st != rpc_s_ok)
785    {
786        fprintf(stderr, "*** Can't parse string binding from \"%s\"\n", argv[2]);
787        exit(1);
788    }
789
790    if (endpoint == NULL)
791    {
792        /*
793         * Do a RPC to a supported interface so that we can get a complete
794         * binding to the server.
795         */
796        perf_init(rh);
797    }
798
799    uuid_create(&(if_rep->id), &st);
800    if (st != rpc_s_ok)
801    {
802        fprintf(stderr, "*** Can't create uuid\n");
803        exit(1);
804    }
805
806    /*
807     * Now try a RPC to an interface that the server doesn't
808     * have registered.
809     */
810    TRY
811    {
812        perfb_init(rh, (idl_char *) name);
813        fprintf(stderr, "*** Call that should have failed succeeded!\n");
814    }
815    CATCH (rpc_x_unknown_if)
816    {
817        printf("  \"Unknown interface\" exception correctly raised\n");
818    }
819    ENDTRY
820
821#ifdef _POSIX_THREADS
822    if (! multithread)
823#endif
824    memcpy(&(if_rep->id), &if_uuid, sizeof(idl_uuid_t));
825}
826
827/*
828 * Inquire Interface ids test
829 */
830
831static void do_inq_if_ids (name)
832char *name;
833{
834    handle_t                rh;
835    rpc_if_id_vector_p_t    if_ids;
836    unsigned32              st;
837    char                    *pstring;
838    unsigned_char_p_t       uuid_string;
839    unsigned32              i;
840    unsigned32              temp_status;
841
842    if (name == NULL)
843    {
844        pstring = "local process";
845        rh = NULL;
846    }
847    else
848    {
849        pstring = name;
850        rh = binding_from_string_binding(NULL, name);
851    }
852
853    rpc_mgmt_inq_if_ids (rh, &if_ids, &st);
854    if (st != rpc_s_ok)
855    {
856        fprintf(stderr, "*** Can't inquire interface ids for %s - %s\n",
857                pstring, error_text(st));
858        exit(1);
859    }
860
861    printf ("%ld interface ids returned for %s.\n", if_ids->count, pstring);
862    for (i = 0; i < if_ids->count; i++)
863    {
864        uuid_to_string (&if_ids->if_id[i]->uuid, &uuid_string, &st);
865        printf ("%ld:\tuuid:\t%s\n\tvers_major:\t%d\tvers_minor\t%d\n",
866            (i+1), uuid_string, if_ids->if_id[i]->vers_major,
867            if_ids->if_id[i]->vers_minor );
868        rpc_string_free (&uuid_string, &temp_status);
869    }
870
871    rpc_if_id_vector_free (&if_ids, &st);
872    if (st != rpc_s_ok)
873    {
874        fprintf(stderr, "*** Can't free interface ids - %s\n", error_text(st));
875        exit(1);
876    }
877}
878
879static void inq_if_ids_test (test, argc, argv)
880
881int                 test;
882int                 argc;
883char                *argv[];
884
885{
886    if (argc < 2)
887    {
888        usage(test);
889    }
890
891    do_inq_if_ids (argc == 2 ? NULL : argv[2]);
892}
893
894
895/*
896 * Statistics test
897 */
898
899static void do_stats (name)
900char *name;
901{
902    handle_t                rh;
903    rpc_stats_vector_p_t    stats;
904    unsigned32              st;
905    unsigned char           *pstring;
906
907    if (name == NULL)
908    {
909        pstring = (unsigned char *)"local process";
910        rh = NULL;
911    }
912    else
913    {
914        pstring = (unsigned char *)name;
915        rh = binding_from_string_binding(NULL, name);
916    }
917
918    rpc_mgmt_inq_stats (rh, &stats, &st);
919    if (st != rpc_s_ok)
920    {
921        fprintf(stderr, "*** Can't inquire statistics for %s - %s\n",
922                pstring, error_text(st));
923        exit(1);
924    }
925
926    if (name != NULL)
927    {
928        binding_to_string_binding(rh, &pstring, &st);
929    }
930
931    printf("  Stats for %s\n", pstring);
932
933    if (name != NULL)
934        rpc_string_free(&pstring, &st);
935
936    printf("    Calls sent:   %9lu\n", stats->stats[rpc_c_stats_calls_out]);
937    printf("    Calls rcvd:   %9lu\n", stats->stats[rpc_c_stats_calls_in]);
938    printf("    Packets sent: %9lu\n", stats->stats[rpc_c_stats_pkts_out]);
939    printf("    Packets rcvd: %9lu\n", stats->stats[rpc_c_stats_pkts_in]);
940
941    rpc_mgmt_stats_vector_free (&stats, &st);
942    if (st != rpc_s_ok)
943    {
944        fprintf(stderr, "*** Can't free statistics - %s\n", error_text(st));
945        exit(1);
946    }
947}
948
949static void stats_test (test, argc, argv)
950
951int                 test;
952int                 argc;
953char                *argv[];
954
955{
956    if (argc < 2)
957    {
958        usage(test);
959    }
960
961    do_stats (argc == 2 ? NULL : argv[2]);
962}
963
964
965/*
966 * Auxiliary routine for forwarding test.
967 */
968
969static void forwarding_mgmt_test (rh, obj, msg)
970
971handle_t            rh;
972uuid_p_t            obj;
973char                *msg;
974
975{
976    unsigned int                 i;
977    rpc_if_id_vector_p_t if_ids;
978    rpc_if_id_t         perfb_if_id;
979    unsigned32          st;
980
981    /*
982     * Clear binding again and make a management call to test that
983     * management calls on partial bindings work.  We do a
984     * mgmt_inq_if_ids and make sure that "perfb" is one of the i/f's
985     * we get back.
986     */
987    binding_reset(rh);
988
989    rpc_binding_set_object(rh, obj, &st);
990    if (st != 0)
991    {
992        fprintf(stderr, "*** Can't set object in binding (%s) - %s\n",
993            msg, error_text(st));
994        exit(1);
995    }
996
997    rpc_if_inq_id(perfb_v1_0_c_ifspec, &perfb_if_id, &st);
998    if (st != rpc_s_ok)
999    {
1000        fprintf(stderr, "*** Can't get interface id for perfb interface (%s) - %s\n",
1001                msg, error_text(st));
1002        exit(1);
1003    }
1004
1005    rpc_mgmt_inq_if_ids (rh, &if_ids, &st);
1006    if (st != 0)
1007    {
1008        fprintf(stderr, "*** Can't get interface ids through partial binding (%s) - %s\n",
1009            msg, error_text(st));
1010        exit(1);
1011    }
1012
1013    for (i = 0; i < if_ids->count; i++)
1014    {
1015        if (uuid_equal(&if_ids->if_id[i]->uuid, &perfb_if_id.uuid, &st))
1016            break;
1017    }
1018
1019    if (i == if_ids->count)
1020    {
1021        fprintf(stderr, "*** Request for interface ids through partial binding completed OK,\n");
1022        fprintf(stderr, "***    but perfb i/f not found; probably forwarded to wrong server (%s).\n",
1023            msg);
1024        exit(1);
1025    }
1026
1027    printf("  request for interface ids through partial binding completed OK (%s)\n",
1028                msg);
1029
1030    rpc_if_id_vector_free (&if_ids, &st);
1031    if (st != rpc_s_ok)
1032    {
1033        fprintf(stderr, "*** Can't free interface ids (%s) - %s\n",
1034            msg, error_text(st));
1035        exit(1);
1036    }
1037}
1038
1039/*
1040 * Forwarding test.
1041 */
1042
1043static void forwarding_test (test, argc, argv)
1044
1045int                 test;
1046int                 argc;
1047char                *argv[];
1048
1049{
1050    handle_t            rh;
1051    char                name[256];
1052    unsigned_char_p_t   name2;
1053    unsigned32          st;
1054    idl_boolean         global;
1055#define FSIZE 4000
1056    unsigned32       d[FSIZE];
1057    int                 i;
1058    unsigned32          sum, rsum;
1059    idl_char            result[256];
1060    unsigned_char_p_t   pstring;
1061
1062	DO_NOT_CLOBBER(rh);
1063	DO_NOT_CLOBBER(rsum);
1064
1065    if (argc < 4)
1066    {
1067        usage(test);
1068    }
1069
1070    global = argv[3][0] == 'y';
1071    rh = binding_from_string_binding(NULL, argv[2]);
1072
1073    /*
1074     * Tell server to register the "perfb" interface.
1075     */
1076    perf_register_b(rh, global, &st);
1077
1078    if (st != 0)
1079    {
1080        fprintf(stderr, "*** Can't register \"perfb\" interface - %s\n",
1081            error_text(st));
1082        exit(1);
1083    }
1084
1085    TRY
1086    {
1087        if (! compat_mode)
1088        {
1089            /*
1090             * Clear the binding to the server and call resolve_binding.
1091             */
1092            binding_reset(rh);
1093
1094            rpc_ep_resolve_binding(rh, perfb_v1_0_c_ifspec, &st);
1095            if (st != rpc_s_ok)
1096            {
1097                fprintf(stderr, "*** Can't resolve \"perfb\" interface - %s\n",
1098                        error_text(st));
1099                exit(1);
1100            }
1101
1102            binding_to_string_binding(rh, &pstring, &st);
1103            printf("  binding resolved to: %s\n", pstring);
1104            rpc_string_free(&pstring, &st);
1105        }
1106
1107        /*
1108         * Clear binding to server and make a simple call to the "perfb" interface.
1109         */
1110        binding_reset(rh);
1111
1112        perfb_init(rh, (idl_char *) name);
1113        printf("  result of forwarded call = \"%s\"\n", name);
1114
1115        /*
1116         * Clear binding again and make a call that's too big to fit in a
1117         * single pkt to make sure multi-pkt forwarding works.  Note that old
1118         * perf servers don't handle this call so catch that sort of error.
1119         */
1120        binding_reset(rh);
1121
1122        for (i = 0, rsum = 0; i < FSIZE; i++)
1123        {
1124            d[i] = i;
1125            rsum += d[i];
1126        }
1127
1128        TRY
1129        {
1130            perfb_in(rh, d, FSIZE, true, &sum);
1131            if (sum != rsum)
1132            {
1133                fprintf(stderr, "*** Sum mismatch in large forwarded call (%lu, %lu)\n",
1134                    sum, rsum);
1135            }
1136            else
1137            {
1138                printf("  large forwarded call completed OK\n");
1139            }
1140        }
1141        CATCH (rpc_x_op_rng_error)
1142        {
1143            printf ("  warning: server doesn't implement \"perfb_in\" procedure ");
1144            printf ("(probably an old server)\n");
1145            printf ("           large forwarded call test skipped\n");
1146        }
1147        ENDTRY
1148
1149        if (! compat_mode)
1150        {
1151            /*
1152             * Test forwarded mgmt calls.
1153             */
1154            forwarding_mgmt_test (rh, &NilTypeObj, "nil type object");
1155            forwarding_mgmt_test (rh, &FooObj1, "non-nil type object");
1156        }
1157
1158        /*
1159         * Clear binding again and make a broadcast call.
1160         */
1161        binding_reset(rh);
1162
1163        rpc_binding_set_object(rh, NULL, &st);
1164        if (st != 0)
1165        {
1166            fprintf(stderr, "*** Can't reset object in binding to nil - %s\n",
1167                error_text(st));
1168            exit(1);
1169        }
1170
1171        TRY
1172        {
1173            perfb_brd(rh, result);
1174            binding_to_string_binding (rh, &name2);
1175            printf("  broadcast forwarded call completed OK\n");
1176            printf("    bound to \"%s\", result=\"%s\"\n", name2, result);
1177        }
1178        CATCH (rpc_x_invalid_call_opt)
1179        {
1180            printf ("  warning: can't do broadcast\n");
1181        }
1182        CATCH (rpc_x_op_rng_error)
1183        {
1184            printf ("  warning: server doesn't implement \"perfb_brd\" procedure ");
1185            printf ("(probably an old server)\n");
1186            printf ("           broadcast call test skipped\n");
1187        }
1188        CATCH (rpc_x_comm_failure)
1189        {
1190            printf ("  warning: communications failure (may be an old server)\n");
1191            printf ("           broadcast call test skipped\n");
1192        }
1193        CATCH_ALL
1194        {
1195            exc_report(THIS_CATCH);
1196            fprintf (stderr, "*** Unknown exception raised in during broadcast forwarded call\n");
1197            RERAISE;
1198        }
1199        ENDTRY
1200    }
1201    FINALLY
1202    {
1203        /*
1204         * Tell server to unregister the "perfb" interface.
1205         */
1206        rh = binding_from_string_binding(NULL, argv[2]);
1207
1208        perf_unregister_b(rh, &st);
1209        if (st != 0)
1210        {
1211            fprintf(stderr, "*** Can't unregister \"perfb\" interface - %s\n",
1212                error_text(st));
1213            exit(1);
1214        }
1215    }
1216    ENDTRY
1217}
1218
1219/*
1220 * Exception test.
1221 */
1222
1223static void exception_test (test, argc, argv)
1224
1225int                 test;
1226int                 argc;
1227char                *argv[];
1228
1229{
1230    handle_t            rh;
1231
1232    if (argc < 3)
1233    {
1234        usage(test);
1235    }
1236
1237    rh = binding_from_string_binding(NULL, argv[2]);
1238
1239    TRY
1240    {
1241        perf_exception(rh);
1242        fprintf(stderr, "*** NO exception raised\n");
1243        exit (1);
1244    }
1245#ifndef PD_BUILD
1246    CATCH (exc_intdiv_e)
1247#else
1248    CATCH (exc_e_intdiv)
1249#endif
1250    {
1251        printf("  Integer div-by-zero exception correctly raised\n");
1252    }
1253#ifndef PD_BUILD
1254    CATCH (exc_fltdiv_e)
1255#else
1256    CATCH (exc_e_fltdiv)
1257#endif
1258    {
1259        printf("  Floating div-by-zero exception correctly raised\n");
1260    }
1261    CATCH (exc_e_aritherr)
1262    {
1263        printf("  Arithmetic error exception correctly raised\n");
1264    }
1265    CATCH_ALL
1266    {
1267        exc_report(THIS_CATCH);
1268        fprintf(stderr, "*** WRONG exception raised\n");
1269        exit(1);
1270    }
1271    ENDTRY
1272}
1273
1274/*
1275 * Callback routines for callback test.
1276 */
1277
1278static unsigned long callback_passes, callback_count;
1279
1280void perfc_init (h, p)
1281
1282handle_t            h __attribute__(unused);
1283unsigned32       *p;
1284
1285{
1286    callback_count = 0;
1287    *p = callback_passes;
1288}
1289
1290void perfc_cb (h, c)
1291
1292handle_t            h __attribute__(unused);
1293unsigned32       *c;
1294
1295{
1296    *c = ++callback_count;
1297    printf("    ...in callback %lu\n", *c);
1298}
1299
1300void perfc_cb_idem (h, c)
1301
1302handle_t            h __attribute__(unused);
1303unsigned32       *c;
1304
1305{
1306    *c = ++callback_count;
1307    printf("    ...in idempotent callback %lu\n", *c);
1308}
1309
1310perfc_v2_0_epv_t perfc_v2_mgr_epv =
1311{
1312    perfc_init,
1313    perfc_cb,
1314    perfc_cb_idem
1315};
1316
1317/*
1318 * Callback test
1319 */
1320static void callback_test (test, argc, argv)
1321
1322int                 test;
1323int                 argc;
1324char                *argv[];
1325
1326{
1327    handle_t            rh;
1328    unsigned32          st;
1329    unsigned long       idem;
1330    unsigned short      passes, i;
1331
1332    if (argc < 6)
1333    {
1334        usage(test);
1335    }
1336
1337    passes = atoi(argv[3]);
1338    callback_passes = atoi(argv[4]);
1339    idem = argv[5][0] == 'y';
1340
1341    rh = binding_from_string_binding(NULL, argv[2]);
1342
1343    rpc_server_register_if (perfc_v2_0_s_ifspec, NULL,
1344        (rpc_mgr_epv_t) &perfc_v2_mgr_epv, &st);
1345    if (st != rpc_s_ok)
1346    {
1347        fprintf(stderr, "*** Can't register interface - %s\n", error_text(st));
1348        exit(1);
1349    }
1350
1351    for (i = 1; i <= passes; i++)
1352    {
1353        perf_call_callback(rh, idem);
1354        printf("  pass %2d...OK\n", i);
1355    }
1356
1357    rpc_server_unregister_if (perfc_v2_0_s_ifspec, NULL, &st);
1358    if (st != rpc_s_ok)
1359    {
1360        fprintf(stderr, "*** Can't unregister interface - %s\n", error_text(st));
1361        exit(1);
1362    }
1363}
1364
1365/*
1366 * Returns T if two double floats are "pretty close" to each other.
1367 */
1368
1369static idl_boolean approx_eq (d1, d2)
1370
1371double              d1, d2;
1372
1373{
1374    double ratio = d1 / d2;
1375    return (ratio > .9999 && ratio < 1.00001);
1376}
1377
1378/*
1379 * Generic interface test
1380 */
1381
1382static void generic_test (test, argc, argv)
1383
1384int                 test;
1385int                 argc;
1386char                *argv[];
1387
1388{
1389    handle_t            rh;
1390    unsigned32       x;
1391
1392    if (argc < 3)
1393    {
1394        usage(test);
1395    }
1396
1397    rh = binding_from_string_binding((uuid_p_t) &FooObj1, argv[2]);
1398    perfg_op1(rh, 17l, &x);
1399
1400    if (x != 34)
1401    {
1402        fprintf(stderr, "*** op1 on Foo1 returned %lu instead of 34\n", x);
1403    }
1404
1405    rh = binding_from_string_binding((uuid_p_t) &BarObj2, argv[2]);
1406    perfg_op2(rh, 3l, &x);
1407
1408    if (x != 15)
1409    {
1410        fprintf(stderr, "*** op2 on Bar2 returned %lu instead of 15\n", x);
1411    }
1412
1413    rh = binding_from_string_binding((uuid_p_t) &FooObj2, argv[2]);
1414    perfg_op1(rh, 111l, &x);
1415
1416    if (x != 222)
1417    {
1418        fprintf(stderr, "*** op1 on Foo2 returned %lu instead of 222\n", x);
1419    }
1420
1421    rh = binding_from_string_binding((uuid_p_t) &BarObj1, argv[2]);
1422    perfg_op2(rh, 13l, &x);
1423
1424    if (x != 65)
1425    {
1426        fprintf(stderr, "*** op2 on Bar1 returned %lu instead of 65\n", x);
1427    }
1428
1429    TRY {
1430        idl_uuid_t  random_uuid;
1431        unsigned32 st;
1432
1433        uuid_create(&random_uuid, &st);
1434        rh = binding_from_string_binding(&random_uuid, argv[2]);
1435        perfg_op1(rh, 17, &x);
1436        fprintf(stderr,
1437            "*** op1 on random uuid: \"Unsupported type\" exception expected\n");
1438        exit(1);
1439    }
1440    CATCH (rpc_x_unsupported_type)
1441    {
1442        printf("    op1 on random uuid: \"Unsupported type\" exception correctly raised\n");
1443    }
1444    CATCH (rpc_x_comm_failure)
1445    {
1446        fprintf(stderr, "*** op1 on random uuid: comm failure\n");
1447        exit(1);
1448    }
1449    CATCH_ALL
1450    {
1451        exc_report(THIS_CATCH);
1452        fprintf(stderr, "*** op1 on random uuid: incorrect exception\n");
1453        exit(1);
1454    }
1455    ENDTRY
1456
1457    TRY {
1458        rh = binding_from_string_binding(&ZotObj, argv[2]);
1459        perfg_op1(rh, 17, &x);
1460        fprintf(stderr,
1461            "*** op1 on unsupported type: \"Unsupported type\" exception expected\n");
1462        exit(1);
1463    }
1464    CATCH (rpc_x_unsupported_type)
1465    {
1466        printf("    op1 on unsupported uuid: \"Unsupported type\" exception correctly raised\n");
1467    }
1468    CATCH (rpc_x_comm_failure)
1469    {
1470        fprintf(stderr, "*** op1 on random uuid: comm failure\n");
1471        exit(1);
1472    }
1473    CATCH_ALL
1474    {
1475        exc_report(THIS_CATCH);
1476        fprintf(stderr, "*** op1 on random uuid: incorrect exception\n");
1477        exit(1);
1478    }
1479    ENDTRY
1480
1481    printf("  ...OK\n");
1482}
1483
1484/*
1485 * Static Cancel test
1486 *
1487 * (static in the sense that a cancel is posted to the thread before
1488 * the RPC is performed and we perform limited tests).
1489 *
1490 * Note: since this test is using existing perf RPCs, there is the
1491 * possibility that things may appear to work on the client side
1492 * without the server side actually having performed correctly
1493 * (because we don't actually check that the server side did or
1494 * did not detect the cancel as expected_; you should be able to
1495 * follow the test printout and verify this visually.
1496 */
1497
1498/*
1499 * Determine if a cancel is pending (and clear it).
1500 */
1501
1502static boolean32 cancel_was_pending()
1503{
1504    volatile boolean32 pending = false;
1505
1506    TRY
1507    {
1508        pthread_testcancel();
1509    }
1510    CATCH (pthread_cancel_e)
1511    {
1512        printf("pending is set to TRUE\n"); fflush(stdout);
1513        pending = true;
1514    }
1515    CATCH_ALL
1516    {
1517        exc_report(THIS_CATCH);
1518        fprintf(stderr, "*** Unknown exception raised\n");
1519    }
1520    ENDTRY
1521
1522    return pending;
1523}
1524
1525/*
1526 * static_cancel_test1
1527 *
1528 * Perform a RPC that doesn't call a cancellable operation
1529 * and verify that a cancel is pending upon completion.
1530 */
1531void static_cancel_test1(rh, idem, slow_secs)
1532
1533rpc_binding_handle_t    rh;
1534unsigned32              idem;
1535unsigned long           slow_secs;
1536
1537{
1538
1539  boolean32 pending;
1540
1541  printf("    Static Cancel Test 1 (server should NOT detect cancel):\n");
1542
1543  /* make sure general cancellability is on */
1544  pthread_setcancel(CANCEL_ON);
1545
1546    TRY
1547    {
1548
1549      /*
1550       * post a cancel to this thread and make a server RPC call
1551       */
1552
1553        pthread_cancel(pthread_self());
1554        if (idem)
1555        {
1556            perf_null_slow_idem(rh, 2 /* CPU LOOP */, slow_secs);
1557        }
1558        else
1559        {
1560            perf_null_slow(rh, 2 /* CPU LOOP */, slow_secs);
1561        }
1562        pending =  cancel_was_pending();
1563
1564	if (pending)
1565            printf("        Correct RPC cancel pending operation\n");
1566        else
1567            fprintf(stderr, "    *** lost cancel (not pending)!\n");
1568    }
1569    CATCH (pthread_cancel_e)
1570    {
1571        fprintf(stderr, "    *** unexpected cancel exception raised!\n");
1572        if (cancel_was_pending())
1573            fprintf(stderr, "    *** and cancel still pending!\n");
1574    }
1575    CATCH (rpc_x_cancel_timeout)
1576    {
1577        fprintf(stderr, "    *** unexpected cancel timeout exception raised!\n");
1578        if (! cancel_was_pending())
1579            fprintf(stderr, "    *** and lost cancel (not pending)!\n");
1580	    RERAISE;
1581    }
1582    CATCH_ALL
1583    {
1584        exc_report(THIS_CATCH);
1585        fprintf(stderr, "    *** unexpected exception raised!\n");
1586        fprintf(stderr, "    *** cancel %s pending\n",
1587                cancel_was_pending() ? "still" : "not");
1588	RERAISE;
1589    }
1590    ENDTRY
1591}
1592
1593/*
1594 * static_cancel_test2
1595 *
1596 * Perform a RPC that does call a cancellable operation
1597 * and verify that a cancel is detected.
1598 */
1599void static_cancel_test2(rh, idem, slow_secs)
1600
1601rpc_binding_handle_t    rh;
1602unsigned32              idem;
1603unsigned long           slow_secs;
1604
1605{
1606    int oc;
1607    boolean32 pending;
1608
1609    printf("    Static Cancel Test 2 (server SHOULD detect cancel):\n");
1610
1611    TRY
1612    {
1613        pthread_cancel(pthread_self());
1614        if (idem)
1615        {
1616            perf_null_slow_idem(rh, 0 /* SLEEP LOOP */, slow_secs);
1617        }
1618        else
1619        {
1620            perf_null_slow(rh, 0 /* SLEEP LOOP */, slow_secs);
1621        }
1622        fprintf(stderr, "    *** cancel exception NOT raised!\n");
1623
1624	pending = cancel_was_pending();
1625	oc = pthread_setcancel(CANCEL_OFF);
1626
1627        if (pending)
1628            printf("    ... but cancel not lost (was pending)\n");
1629        else
1630            fprintf(stderr, "    *** and lost cancel (not pending)!\n");
1631    }
1632    CATCH (pthread_cancel_e)
1633    {
1634        fprintf(stderr, "        Correct cancel exception operation\n");
1635        if (cancel_was_pending())
1636            fprintf(stderr, "    *** but ERROR: cancel still pending!\n");
1637    }
1638    CATCH (rpc_x_cancel_timeout)
1639    {
1640        fprintf(stderr, "    *** unexpected cancel timeout exception raised!\n");
1641        if (! cancel_was_pending())
1642            fprintf(stderr, "    *** and lost cancel (not pending)!\n");
1643	RERAISE;
1644    }
1645    CATCH_ALL
1646    {
1647        exc_report(THIS_CATCH);
1648        fprintf(stderr, "    *** unexpected exception raised!\n");
1649        fprintf(stderr, "    *** cancel %s pending\n",
1650                cancel_was_pending() ? "still" : "not");
1651	RERAISE;
1652    }
1653    ENDTRY
1654}
1655
1656/*
1657 * static_cancel_test3
1658 *
1659 * Perform a RPC that doesn't call a cancellable operation followed
1660 * by one that does and verify that a cancel is detected.
1661 */
1662void static_cancel_test3(rh, idem, slow_secs)
1663
1664rpc_binding_handle_t    rh;
1665unsigned32              idem;
1666unsigned long           slow_secs;
1667
1668{
1669    int oc;
1670    boolean32 pending;
1671    volatile idl_boolean first_done = false;
1672
1673    printf("    Static Cancel Test 3 (server SHOULD detect cancel on 2nd RPC):\n");
1674
1675    TRY
1676    {
1677        pthread_cancel(pthread_self());
1678
1679        if (idem)
1680        {
1681            perf_null_slow_idem(rh, 2 /* CPU LOOP */, slow_secs);
1682            first_done = true;
1683            perf_null_slow_idem(rh, 0 /* SLEEP LOOP */, slow_secs);
1684        }
1685        else
1686        {
1687            perf_null_slow(rh, 2 /* CPU LOOP */, slow_secs);
1688            first_done = true;
1689            perf_null_slow(rh, 0 /* SLEEP LOOP */, slow_secs);
1690        }
1691
1692	pending = cancel_was_pending();
1693	oc = pthread_setcancel(CANCEL_OFF);
1694
1695        fprintf(stderr, "    *** cancel exception NOT raised!\n");
1696        if (pending)
1697        {
1698            printf("    ... but cancel not lost (was pending)\n");
1699        }
1700        else
1701        {
1702            fprintf(stderr, "    *** and lost cancel (not pending)!\n");
1703        }
1704    }
1705    CATCH (pthread_cancel_e)
1706    {
1707        if (! first_done)
1708        {
1709            fprintf(stderr, "    *** unexpected cancel raised (1st call)!\n");
1710            fprintf(stderr, "    *** cancel %s pending\n",
1711                cancel_was_pending() ? "still" : "not");
1712        }
1713        else
1714        {
1715            fprintf(stderr, "        Correct cancel exception operation\n");
1716            if (cancel_was_pending())
1717                fprintf(stderr, "    *** but ERROR: cancel still pending!\n");
1718        }
1719    }
1720    CATCH (rpc_x_cancel_timeout)
1721    {
1722        fprintf(stderr, "    *** unexpected cancel timeout raised (%s call)!\n",
1723                                    first_done ? "2nd" : "1st");
1724        if (! cancel_was_pending())
1725            fprintf(stderr, "    *** and lost cancel (not pending)!\n");
1726	RERAISE;
1727    }
1728    CATCH_ALL
1729    {
1730        exc_report(THIS_CATCH);
1731        fprintf(stderr, "    *** unexpected exception raised (%s call)!\n",
1732            first_done ? "2nd" : "1st");
1733        fprintf(stderr, "    *** cancel %s pending\n",
1734                cancel_was_pending() ? "still" : "not");
1735    }
1736    ENDTRY
1737}
1738
1739/*
1740 * Static Cancel test
1741 */
1742
1743static void static_cancel_test (test, argc, argv)
1744
1745int                 test;
1746int                 argc;
1747char                *argv[];
1748
1749{
1750    handle_t            rh;
1751    int                 idem;
1752    int                 has_ctmo = false;
1753    signed32            ctmo = 0;
1754    unsigned short      i, passes;
1755    unsigned long       slow_secs = 5;
1756    unsigned32          st;
1757
1758    if (argc < 5)
1759    {
1760        usage(test);
1761    }
1762
1763    rh = binding_from_string_binding(NULL, argv[2]);
1764    passes = atoi(argv[3]);
1765    idem = argv[4][0] == 'y';
1766
1767    if (argc > 5)
1768        slow_secs = atoi(argv[5]);
1769
1770    if (argc > 6)
1771    {
1772        has_ctmo = true;
1773        ctmo = atoi(argv[6]);
1774    }
1775
1776    printf("    passes: %d; idem: %s; slow secs: %ld; cancel timeout secs: %s\n",
1777            passes, idem ? "yes" : "no", slow_secs,
1778            has_ctmo ? argv[6] : "<default>");
1779
1780    if (has_ctmo)
1781    {
1782        rpc_mgmt_set_cancel_timeout(ctmo, &st);
1783        if (st != rpc_s_ok)
1784        {
1785            fprintf(stderr, "*** Error setting cancel timeout - '%s'\n",
1786                error_text(st));
1787            exit(1);
1788        }
1789    }
1790
1791    for (i = 0; i < passes; i++)
1792    {
1793        static_cancel_test1(rh, idem, slow_secs);
1794        static_cancel_test2(rh, idem, slow_secs);
1795        static_cancel_test3(rh, idem, slow_secs);
1796
1797        printf("    pass %2d...OK\n", i);
1798    }
1799}
1800
1801
1802/*
1803 * Context test
1804 */
1805
1806static void context_test (test, argc, argv)
1807
1808int                 test;
1809int                 argc;
1810char                *argv[];
1811
1812{
1813    handle_t            rh;
1814    unsigned32          data, rdata;
1815    int                 die;
1816    struct timespec     delay;
1817    idl_void_p_t        context;
1818    unsigned short      i, passes;
1819
1820    if (argc < 6)
1821    {
1822        usage(test);
1823    }
1824
1825    rh = binding_from_string_binding(NULL, argv[2]);
1826    passes = atoi(argv[3]);
1827    die = argv[4][0] == 'y';
1828
1829    delay.tv_sec = atoi(argv[5]);
1830    delay.tv_nsec = 0;
1831
1832    printf("    passes: %d; die: %s; sleep secs: %ld\n",
1833            passes, die ? "yes" : "no", delay.tv_sec);
1834
1835    for (i = 0; i < passes; i++)
1836    {
1837        data = time (NULL);
1838
1839        perf_get_context (rh, data, &context);
1840
1841        if (! perf_test_context (context, &rdata))
1842        {
1843            fprintf (stderr, "*** perf_get_context returned false\n");
1844        }
1845
1846        if (rdata != data)
1847        {
1848            fprintf (stderr, "*** data mismatch on data returned by perf_get_context; %lu != %lu\n",
1849                rdata, data);
1850        }
1851
1852        if (delay.tv_sec > 0)
1853        {
1854            printf ("        Sleeping for %ld seconds...\n", delay.tv_sec);
1855            pthread_delay_np(&delay);
1856            printf ("        ...awake\n");
1857        }
1858
1859        if (! die)
1860        {
1861            if (! perf_free_context (&context, &rdata))
1862            {
1863                fprintf (stderr, "*** perf_free_context returned false\n");
1864            }
1865
1866            if (rdata != data)
1867            {
1868                fprintf (stderr, "*** data mismatch on data returned by perf_free_context; %lu != %lu\n",
1869                    rdata, data);
1870            }
1871        }
1872
1873        printf("    pass %2d...OK\n", i);
1874    }
1875}
1876
1877
1878/*
1879 * Looping test
1880 */
1881
1882static void looping_test (test, argc, argv)
1883
1884int                 test;
1885int                 argc;
1886char                *argv[];
1887
1888{
1889#define MSIZE (1024 * 1024)
1890    unsigned32          i;
1891    unsigned short      passes;
1892    handle_t            rh;
1893    unsigned32          st;
1894#ifdef NO_TIMES
1895    struct timeval      start_time;
1896#else
1897    struct msec_time    start_time;
1898#endif  /* NO_TIMES */
1899    struct msec_time    avg_time;
1900    unsigned short      cpp;
1901    unsigned32          *d;
1902    unsigned32          len;
1903    unsigned32          sum=0, rsum=0;
1904    unsigned32          n_calls, n_brd, n_maybe, n_brd_maybe;
1905    idl_boolean         idem;
1906    idl_boolean         verify;
1907    unsigned short      pass, calln;
1908    unsigned32          slow_secs=0;
1909    perf_slow_mode_t    slow_mode=0;
1910    static char         *slow_mode_names[4] = {"sleep", "I/O", "CPU", "Fork sleep"};
1911#ifdef _POSIX_THREADS
1912    static handle_t     first_handle = NULL;
1913#endif
1914
1915    d = (unsigned32 *)malloc(MSIZE);
1916
1917    switch (test)
1918    {
1919    case 4:
1920        if (argc < 5)
1921            usage(test);
1922        break;
1923    default:
1924        if (argc < 7)
1925            usage(test);
1926        break;
1927    }
1928
1929    passes = atoi(argv[3]);
1930    cpp    = atoi(argv[4]);
1931    if (test == 4)
1932    {
1933        verify = false;
1934        idem   = true;
1935    }
1936    else
1937    {
1938        verify = argv[5][0] == 'y';
1939        idem   = argv[6][0] == 'y';
1940    }
1941    len    = 0;
1942
1943    /*
1944     * Sanity check calls/pass.
1945     */
1946
1947    if (cpp <= 0)
1948    {
1949        fprintf (stderr, "\nERROR: calls/pass must be > 0.\n\n");
1950        exit (1);
1951    }
1952
1953#ifdef _POSIX_THREADS
1954    if (multithread)
1955    {
1956        pthread_mutex_lock(&global_mutex);
1957        if (first_handle == NULL)
1958        {
1959            rh = first_handle = binding_from_string_binding(NULL, argv[2]);
1960        }
1961        else
1962        {
1963            if (use_shared_handle)
1964            {
1965                rpc_binding_handle_copy(first_handle, &rh, &st);
1966            }
1967            else
1968            {
1969                rpc_binding_copy(first_handle, &rh, &st);
1970            }
1971
1972            if (st != rpc_s_ok)
1973            {
1974                fprintf(stderr, "*** Can't copy binding - %s\n", error_text(st));
1975                exit(1);
1976            }
1977        }
1978        pthread_mutex_unlock(&global_mutex);
1979    }
1980    else
1981#endif
1982    {
1983        rh = binding_from_string_binding(NULL, argv[2]);
1984    }
1985
1986    printf("    passes: %d; calls/pass: %d; verification: %s; idempotent: %s",
1987        passes, cpp, verify ? "on" : "off", idem ? "yes" : "no");
1988
1989    switch (test)
1990    {
1991        case 1:
1992        case 2:
1993            if (argc < 8)
1994            {
1995                printf("\n");
1996                usage(test);
1997            }
1998            len = atoi(argv[7]) / 4;
1999            printf("; bytes/call: %ld", len * 4);
2000            break;
2001        case 10:
2002            if (argc < 8)
2003            {
2004                printf("\n");
2005                usage(test);
2006            }
2007            slow_secs = atoi(argv[7]);
2008            if (argc < 9)
2009            {
2010                slow_mode = perf_slow_sleep;
2011            }
2012            else
2013            {
2014                slow_mode = atoi(argv[8]);
2015                if (slow_mode > 3)
2016                {
2017                    printf("\n");
2018                    usage(test);
2019                }
2020            }
2021            printf("; sleep secs: %ld; mode: %s",
2022                   slow_secs, slow_mode_names[slow_mode]);
2023            break;
2024    }
2025
2026    printf("\n");
2027
2028    for (pass = 1; pass <= passes; pass++)
2029    {
2030        if (verify && ! idem)
2031        {
2032            perf_init(rh);
2033        }
2034
2035#ifdef NO_TIMES
2036        GETTIMEOFDAY(&start_time);
2037#else
2038        start_timing(&start_time);
2039#endif  /* NO_TIMES */
2040
2041        for (calln = 1; calln <= cpp; calln++)
2042        {
2043            if (verify)
2044            {
2045                for (i = 0, rsum = 0; i < len; i++)
2046                {
2047                    d[i] = i * perf_magic * pass * calln;
2048                    rsum += d[i];
2049                }
2050            }
2051
2052            /*
2053             * for non-32 bit machines
2054             */
2055            rsum &= (unsigned long) 0xffffffff;
2056
2057            switch (test)
2058            {
2059                case 0:
2060                    if (idem)
2061                    {
2062                        perf_null_idem(rh);
2063                    }
2064                    else
2065                    {
2066                        perf_null(rh);
2067                    }
2068                    break;
2069
2070                case 4:
2071                    perf_maybe(rh);
2072                    break;
2073
2074                case 10:
2075                    if (idem)
2076                    {
2077                        perf_null_slow_idem(rh, slow_mode, slow_secs);
2078                    }
2079                    else
2080                    {
2081                        perf_null_slow(rh, slow_mode, slow_secs);
2082                    }
2083                    break;
2084
2085                case 1:
2086                    if (idem)
2087                    {
2088                        perf_in_idem(rh, d, len, verify, &sum);
2089                    }
2090                    else
2091                    {
2092                        perf_in(rh, d, len, verify, &sum);
2093                    }
2094                    if (verify)
2095                    {
2096                        if (sum != rsum)
2097                        {
2098                            fprintf(stderr, "*** Sum mismatch (%lu, %lu)\n",
2099                                sum, rsum);
2100                        }
2101                    }
2102                    break;
2103
2104                case 2:
2105                {
2106                    unsigned32 tlen = len;
2107
2108                    if (idem)
2109                    {
2110                        perf_out_idem (rh, d, &tlen, len,
2111				       pass * calln, verify);
2112                    }
2113                    else
2114                    {
2115                        perf_out (rh, d, &tlen, len,
2116				  pass * calln, verify);
2117                    }
2118                    if (len != tlen)
2119                    {
2120                        fprintf(stderr,
2121"*** Output length (%lu) is not equal to input length (%lu)\n", tlen, len);
2122                        exit(1);
2123                    }
2124
2125                    if (verify)
2126                    {
2127                        for (i = 0, sum = 0; i < len; i++)
2128                        {
2129                            sum += d[i];
2130                        }
2131
2132                        /*
2133                         * for non-32 bit machines
2134                         */
2135                        sum &= (unsigned long) 0xffffffff;
2136                        if (sum != rsum)
2137                        {
2138                            fprintf(stderr, "*** Sum mismatch (%lu, %lu)\n",
2139                                sum, rsum);
2140                        }
2141                    }
2142                    break;
2143                }
2144
2145                case 6:
2146                {
2147                    float f1 = (float) (rand()+1);
2148                    float f2 = (calln & 1 ? 1.0 : -1.0) * (rand()+1);
2149                    double d1 = 1.0 / (rand()+1);
2150                    double d2;
2151                    float o1, o1_l;
2152                    double o2, o2_l;
2153
2154                    d2 = sqrt(pow((double) (7 + (rand()+1) % 10),
2155                        (double) ((rand()+1) % 40)));
2156                    o1_l = (f1 / f2) * (d1 / d2);
2157                    o2_l = (f2 / f1) * (d2 / d1);
2158
2159                    MARSHALL_DOUBLE(d1);
2160                    MARSHALL_DOUBLE(d2);
2161
2162                    perf_fp_test(rh, &f1, &f2, d1, d2, &o1, &o2);
2163
2164                    UNMARSHALL_DOUBLE(o2);
2165
2166                    if (verify)
2167                    {
2168                        if (! approx_eq(o1, o1_l))
2169                        {
2170                            fprintf(stderr,
2171                "*** Floating error #1 (%g != %g -- (%g / %g) * (%g / %g))\n",
2172                                o1, o1_l, f1, f2, d1, d2);
2173                        }
2174
2175                        if (! approx_eq(o2, o2_l))
2176                        {
2177                            fprintf(stderr,
2178                "*** Floating error #2 (%g != %g -- (%g / %g) * (%g / %g))\n",
2179                                o2, o2_l, f2, f1, d2, d1);
2180                        }
2181                    }
2182                    break;
2183                }
2184            }
2185#ifdef _POSIX_THREADS
2186            if (! multithread)
2187#endif
2188            {
2189                if (reset_binding_freq > 0 && calln % reset_binding_freq == 0)
2190                {
2191                    binding_reset(rh);
2192                    printf("          [binding has been reset]\n");
2193                }
2194                if (recreate_binding_freq > 0 && calln % recreate_binding_freq == 0)
2195                {
2196                    rpc_binding_free(&rh, &st);
2197                    rh = binding_from_string_binding(NULL, argv[2]);
2198                    printf("          [binding has been recreated]\n");
2199                }
2200            }
2201        }
2202
2203        end_timing(&start_time, cpp, &avg_time);
2204
2205        if (verify && (! idem)
2206#ifdef _POSIX_THREADS
2207            && (! multithread)
2208#endif
2209            )
2210        {
2211            perf_info(rh, &n_calls, &n_brd, &n_maybe, &n_brd_maybe);
2212            if (n_calls != cpp)
2213            {
2214                fprintf(stderr, "*** Call count mismatch (%lu, %d)\n",
2215                    n_calls, cpp);
2216            }
2217        }
2218
2219#ifdef NO_TIMES
2220        printf("        pass %3d; ms/call: %lu.%03u",
2221                pass, avg_time.msec, avg_time.usec);
2222
2223        if (len > 0 && avg_time.msec > 0)
2224        {
2225            printf("; kbytes/sec: %3lu", (len * 4) / avg_time.msec);
2226        }
2227#else
2228        if (avg_time.u_msec == 0 || avg_time.s_msec == 0)
2229            printf("        pass %3d; ms/call: %lu.%03lu (ms/pass: %lu/%lu)",
2230                   pass, avg_time.r_msec, avg_time.r_usec,
2231                   avg_time.ptime.tms_utime*(1000/clock_ticks),
2232                   avg_time.ptime.tms_stime*(1000/clock_ticks));
2233        else
2234            printf("        pass %3d; ms/call: %lu.%03lu (%lu/%lu)",
2235                   pass, avg_time.r_msec, avg_time.r_usec,
2236                   avg_time.u_msec, avg_time.s_msec);
2237
2238        if (len > 0 && avg_time.r_msec > 0)
2239        {
2240            printf("; kbytes/sec: %3lu", (len * 4) / avg_time.r_msec);
2241        }
2242#endif  /* NO_TIMES */
2243
2244        printf("\n");
2245
2246    }
2247}
2248
2249/*
2250 * One shot test
2251 */
2252
2253static void one_shot_test (test, argc, argv)
2254
2255int                 test;
2256int                 argc;
2257char                *argv[];
2258
2259{
2260    handle_t            rh;
2261#ifdef NO_TIMES
2262    struct timeval      start_time;
2263#else
2264    struct msec_time    start_time;
2265#endif  /* NO_TIMES */
2266    struct msec_time    avg_time;
2267    idl_boolean         fwd;
2268    idl_boolean         idem;
2269
2270    if (argc < 5)
2271    {
2272        usage(test);
2273    }
2274
2275    fwd  = argv[3][0] == 'y';
2276    idem = argv[4][0] == 'y';
2277
2278    rh = binding_from_string_binding(NULL, argv[2]);
2279
2280    printf("    forward: %s; idempotent: %s\n",
2281            fwd ? "yes" : "no", idem ? "yes" : "no");
2282
2283#ifdef NO_TIMES
2284    GETTIMEOFDAY(&start_time);
2285#else
2286    start_timing(&start_time);
2287#endif  /* NO_TIMES */
2288
2289    if (fwd)
2290        if (idem)
2291            perfb_null_idem(rh);
2292        else
2293            perfb_null(rh);
2294    else
2295        if (idem)
2296            perf_null_idem(rh);
2297        else
2298            perf_null(rh);
2299
2300    end_timing(&start_time, 1, &avg_time);
2301
2302#ifdef NO_TIMES
2303    printf("        ms: %lu.%03u\n", avg_time.msec, avg_time.usec);
2304#else
2305    printf("        ms: %lu.%03lu (%lu/%lu)\n",
2306           avg_time.r_msec, avg_time.r_usec,
2307           avg_time.u_msec, avg_time.s_msec);
2308#endif  /* NO_TIMES */
2309}
2310
2311/*
2312 * Start test.  Catch and print any exceptions that are raised.
2313 */
2314
2315void rpc__cn_set_sock_buffsize (
2316        unsigned32	  /* rsize */,
2317        unsigned32	  /* ssize */,
2318        unsigned32	* /* st */);
2319void rpc__cn_inq_sock_buffsize (
2320        unsigned32	* /* rsize */,
2321        unsigned32	* /* ssize */,
2322        unsigned32  * /* st */);
2323
2324static void start_test(test, argc, argv)
2325
2326int test;
2327int argc;
2328char *argv[];
2329{
2330    unsigned32 rsize, ssize;
2331    error_status_t status;
2332
2333    rpc__cn_set_sock_buffsize(socket_buf_size, socket_buf_size, &status);
2334    if (status != rpc_s_ok)
2335    {
2336	fprintf(stderr,"*** rpc__cn_set_sock_buffsize failed (0x%lx)\n", status);
2337        exit(1);
2338    }
2339
2340    rpc__cn_inq_sock_buffsize(&rsize, &ssize, &status);
2341    if (status != rpc_s_ok)
2342    {
2343	fprintf(stderr,"*** rpc__cn_inq_sock_buffsize failed (0x%lx)\n", status);
2344        exit(1);
2345    }
2346    if (socket_buf_size != rsize || socket_buf_size != ssize)
2347    {
2348        fprintf(stderr, "*** CN socket buffer sizes dont match:\n");
2349        fprintf(stderr, "*** READ desired: %lu   actual: %lu\n", socket_buf_size, rsize);
2350        fprintf(stderr, "*** WRITE desired: %lu  actual: %lu\n", socket_buf_size, ssize);
2351        exit(1);
2352    }
2353
2354    TRY
2355    {
2356        (*tinfo[test].proc)(test, argc, argv);
2357    }
2358    CATCH (rpc_x_comm_failure)
2359    {
2360        fprintf(stderr, "*** \"Communications failure\" exception raised\n");
2361    }
2362    CATCH (rpc_x_op_rng_error)
2363    {
2364        fprintf(stderr, "*** \"Operation out of range\" exception raised\n");
2365    }
2366    CATCH (rpc_x_unknown_if)
2367    {
2368        fprintf(stderr, "*** \"Unknown interface\" exception raised\n");
2369    }
2370    CATCH (rpc_x_unknown_error)
2371    {
2372        fprintf(stderr, "*** \"Unknown error\" exception raised\n");
2373    }
2374    CATCH (rpc_x_unknown_remote_fault)
2375    {
2376        fprintf(stderr, "*** \"Unknown remote fault\" exception raised\n");
2377    }
2378    CATCH_ALL
2379    {
2380        exc_report(THIS_CATCH);
2381        fprintf(stderr, "*** Unknown exception raised\n");
2382    }
2383    FINALLY
2384    {
2385        check_wait_point(0);
2386    }
2387    ENDTRY
2388}
2389
2390
2391#ifdef _POSIX_THREADS
2392
2393struct task_info_t
2394{
2395    int     thread;
2396    int     test;
2397    int     argc;
2398    char    **argv;
2399};
2400
2401/*
2402 * Base procedure for multithreading test
2403 */
2404
2405static void multi_task (info, len)
2406
2407struct task_info_t  *info;
2408int                 len __attribute__(unused);
2409
2410{
2411    unsigned32  st;
2412
2413    if (cancel_timeout != -1)
2414    {
2415        rpc_mgmt_set_cancel_timeout(cancel_timeout, &st);
2416        if (st != rpc_s_ok)
2417        {
2418            fprintf(stderr,
2419                "*** Error setting cancel timeout (thread %d) - '%s'\n",
2420                info->thread, error_text(st));
2421            return;
2422        }
2423    }
2424
2425    TRY
2426    {
2427        start_test(info->test, info->argc, info->argv);
2428    }
2429    CATCH_ALL
2430    {
2431        exc_report(THIS_CATCH);
2432        fprintf(stderr, "*** Multi-thread base: exception raised (thread %d)\n", info->thread);
2433        RERAISE;
2434    }
2435    ENDTRY
2436}
2437
2438#endif
2439
2440
2441#ifdef _POSIX_THREADS
2442
2443/*
2444 * Start up multiple tasks, each running a test.
2445 */
2446
2447#define TASK_STACK_SIZE (64 * 1024)
2448#define TASK_PRIORITY 3
2449
2450static void multi_test (test, argc, argv)
2451
2452int                 test;
2453int                 argc;
2454char                *argv[];
2455{
2456    int                 i;
2457    volatile idl_boolean  done;
2458    pthread_t           tasks[MAX_TASKS];
2459
2460	DO_NOT_CLOBBER(i);
2461
2462    if (n_tasks > MAX_TASKS)
2463    {
2464        fprintf(stderr, "%d is too many tasks (max is %d)\n", n_tasks, MAX_TASKS);
2465        exit(1);
2466    }
2467
2468    setbuf(stdout, NULL);       /* Buffered output and tasking don't mix */
2469
2470    printf("  Multithreading: # tasks = %d\n", n_tasks);
2471
2472    for (i = 0; i < n_tasks; i++)
2473    {
2474        struct task_info_t *info = (struct task_info_t *) malloc(sizeof(struct task_info_t));
2475
2476        info->thread = i;
2477        info->test   = test;
2478        info->argc   = argc;
2479        info->argv   = argv;
2480
2481        TRY {
2482            pthread_create(&tasks[i], pthread_attr_default,
2483                (pthread_startroutine_t) multi_task, (pthread_addr_t) info);
2484        } CATCH_ALL {
2485            exc_report(THIS_CATCH);
2486            printf("*** pthread_create failed\n");
2487            exit(1);
2488        } ENDTRY
2489    }
2490
2491    done = false;
2492    while (!done)
2493    {
2494        TRY {
2495            for (i = 0; i < n_tasks; i++)
2496            {
2497                void *junk;
2498                pthread_join(tasks[i], &junk);
2499            }
2500            done = true;
2501        } CATCH_ALL {
2502            exc_report(THIS_CATCH);
2503            printf("*** Cancelling threads\n");
2504            for (i = 0; i < n_tasks; i++)
2505            {
2506                pthread_cancel(tasks[i]);
2507            }
2508        } ENDTRY
2509    }
2510
2511    if (stats)
2512    {
2513        do_stats (NULL);
2514    }
2515}
2516
2517#endif
2518
2519
2520/*
2521 * Parse authentication (-p) option.
2522 */
2523extern int lookup_name(char *table[], char *s);
2524
2525static void parse_auth_option()
2526{
2527    extern char         *optarg;
2528    char                *s;
2529
2530    char                *tmp;
2531
2532    if ((tmp = (char *)malloc(strlen(optarg)+1)) == NULL)
2533    {
2534        fprintf(stderr, "*** No more memery\n");
2535        exit(1);
2536    }
2537
2538    strlcpy(tmp, optarg, strlen(optarg)+1));
2539
2540    /*
2541     * We can't free tmp, so we will loose some memory after each fork.
2542     */
2543
2544    if ((s = (char *) strtok(tmp, ",")) == NULL)
2545        usage(-1);
2546    authn_protocol = strcmp(s, "default") == 0 ?
2547                        rpc_c_authn_default : lookup_name(authn_names, s);
2548
2549    if ((s = (char *) strtok(NULL, ",")) == NULL)
2550        usage(-1);
2551    authz_protocol = lookup_name(authz_names, s);
2552
2553    if ((s = (char *) strtok(NULL, ",")) == NULL)
2554    {
2555        authn_level = rpc_c_authn_level_default;
2556    }
2557    else
2558    {
2559        authn_level = lookup_name(authn_level_names, s);
2560
2561        if ((auth_principal = (idl_char *) strtok(NULL, " ")) == NULL)
2562        {
2563            auth_principal = NULL;
2564        }
2565    }
2566}
2567
2568
2569/*
2570 * Main program
2571 */
2572extern void rpc__dbg_set_switches    (
2573        char            * /*s*/,
2574        unsigned32      * /*st*/
2575    );
2576extern void dump_stg_info(void);
2577
2578int main (argc, argv)
2579
2580int                 argc;
2581char                *argv[];
2582
2583{
2584    int                 test, save_argc=0;
2585    unsigned32          st;
2586    int                 c;
2587    idl_boolean         stats = false;
2588    extern int          optind;
2589    extern char         *optarg;
2590    char                *s, **save_argv=NULL;
2591    int                 do_fork = 0;
2592    int                 fork_count = 0;
2593    pid_t               cpid = 0;
2594    pid_t               opid = getpid();
2595
2596    if ((clock_ticks = sysconf(_SC_CLK_TCK)) == -1)
2597        clock_ticks = 1;
2598
2599fork_test_replay:
2600
2601    while ((c = getopt(argc, argv, "oslDi1B:d:p:m:M:t:c:f:w:v:r:R:")) != EOF)
2602    {
2603        switch (c)
2604        {
2605        case 'd':
2606        case 'D':
2607            rpc__dbg_set_switches(c == 'd' ? optarg : DEBUG_LEVEL, &st);
2608            if (st != rpc_s_ok)
2609            {
2610                fprintf(stderr, "*** Error setting debug level - %s\n",
2611                    error_text(st));
2612                usage(-1);
2613            }
2614
2615            debug = true;
2616            break;
2617
2618        case 'p':
2619            parse_auth_option();
2620            authenticate = true;
2621            break;
2622
2623        case 'i':
2624            stats = true;
2625            break;
2626
2627        case 't':
2628            timeout = atoi(optarg);
2629            break;
2630
2631        case 'v':
2632            verbose = atoi(optarg);
2633            break;
2634
2635        case 'c':
2636            cancel_timeout = atoi(optarg);
2637            if (cancel_timeout != -1)
2638            {
2639                rpc_mgmt_set_cancel_timeout(cancel_timeout, &st);
2640                if (st != rpc_s_ok)
2641                {
2642                    fprintf(stderr, "*** Error setting cancel timeout - '%s'\n",
2643                        error_text(st));
2644                    exit(1);
2645                }
2646            }
2647            break;
2648
2649        case 's':
2650            stats = true;
2651            break;
2652
2653        case 'f':
2654            /*
2655             * If we've already forked, don't do it again.
2656             */
2657            if (do_fork == 0)
2658            {
2659                do_fork = atoi(optarg);
2660                save_argc = argc;
2661                save_argv = argv;
2662            }
2663            break;
2664
2665        case 'w':
2666            {
2667                char *tmp;
2668
2669                if ((tmp = (char *)malloc(strlen(optarg)+1)) == NULL)
2670                {
2671                    fprintf(stderr, "*** No more memory\n");
2672                    exit(1);
2673                }
2674
2675                strlcpy(tmp, optarg, strlen(optarg)+1));
2676
2677                /*
2678                 * We can't free tmp, so we will loose some memory after each fork.
2679                 */
2680
2681                if ((s = (char *) strtok(tmp, ",")) == NULL)
2682                    usage(-1);
2683                wait_point = atoi(s);
2684
2685                if ((s = (char *) strtok(NULL, " ")) == NULL)
2686                    usage(-1);
2687                wait_time = atoi(s);
2688            }
2689            break;
2690
2691        case 'o':
2692            use_obj = true;
2693            break;
2694
2695        case '1':
2696            compat_mode = true;
2697            break;
2698
2699        case 'r':
2700            reset_binding_freq = atoi(optarg);
2701            break;
2702
2703        case 'R':
2704            recreate_binding_freq = atoi(optarg);
2705            break;
2706
2707#ifdef _POSIX_THREADS
2708        case 'm':
2709        case 'M':
2710            multithread = true;
2711            n_tasks = atoi(optarg);
2712            use_shared_handle = (c == 'M');
2713            break;
2714#endif
2715
2716	case 'B':
2717	    socket_buf_size = atoi(optarg);
2718	    break;
2719
2720        default:
2721            usage(-1);
2722        }
2723    }
2724
2725    argc -= optind - 1;
2726    argv = &argv[optind - 1];
2727
2728    if (argc < 2)
2729    {
2730        usage(-1);
2731    }
2732
2733    test = atoi(argv[1]);
2734
2735    if (test < 0 || test > N_TESTS - 1)
2736    {
2737        usage(-1);
2738    }
2739
2740    printf("%s test [%d]", tinfo[test].name, test);
2741
2742    if (debug)
2743    {
2744        printf(" (debug on)");
2745    }
2746
2747    printf("\n");
2748
2749    if (authenticate)
2750    {
2751        VRprintf(2, ("  -----------------\n  Authentication params:\n    authn protocol: %s\n    authz protocol: %s\n    level: %s\n    server princ: \"%s\"\n  -----------------\n",
2752                authn_protocol == (unsigned32)rpc_c_authn_default ?
2753                    "default" : authn_names[authn_protocol],
2754                authz_names[authz_protocol],
2755                authn_level_names[authn_level],
2756                (auth_principal == NULL) ? "<none given>" : (char *) auth_principal));
2757    }
2758
2759    if (debug)
2760    {
2761        dump_stg_info();
2762    }
2763
2764    check_wait_point(1);
2765
2766    if (fork_count != 0 || do_fork != 6)
2767    {
2768#ifdef _POSIX_THREADS
2769        pthread_mutex_init(&global_mutex, pthread_mutexattr_default);
2770
2771        if (multithread)
2772        {
2773            multi_test(test, argc, argv);
2774            exit(0);
2775        }
2776#endif
2777
2778        start_test(test, argc, argv);
2779
2780        if (stats)
2781        {
2782            do_stats (NULL);
2783        }
2784    }
2785
2786    switch (do_fork)
2787    {
2788    case 1:
2789        if (opid != getpid())        /* child */
2790            break;
2791        if (fork_count != 0)    /* original */
2792        {
2793            waitpid(cpid, NULL, 0);
2794            break;
2795        }
2796        /*
2797         * Do the fork.  Both parent and child need to jump back and
2798         * start over again.
2799         */
2800        cpid = fork();
2801        fork_count++;
2802        argc = save_argc;
2803        argv = save_argv;
2804        optind = 1;
2805        goto fork_test_replay;
2806        break;
2807    case 2:
2808        if (fork_count != 0)    /* original */
2809        {
2810            waitpid(cpid, NULL, 0);
2811            break;
2812        }
2813        /*
2814         * Do the fork.  Only parent need to jump back and
2815         * start over again.
2816         */
2817        cpid = fork();
2818        fork_count++;
2819
2820        if (cpid == 0)  /* child */
2821            break;
2822
2823        argc = save_argc;
2824        argv = save_argv;
2825        optind = 1;
2826        goto fork_test_replay;
2827        break;
2828    case 3:
2829        if (opid != getpid())        /* child */
2830            break;
2831        /*
2832         * Do the fork.  Only child need to jump back and
2833         * start over again.
2834         */
2835        cpid = fork();
2836        fork_count++;
2837
2838        if (cpid != 0)    /* original */
2839        {
2840            waitpid(cpid, NULL, 0);
2841            break;
2842        }
2843
2844        argc = save_argc;
2845        argv = save_argv;
2846        optind = 1;
2847        goto fork_test_replay;
2848        break;
2849    case 4:
2850        if (fork_count == 1)    /* child */
2851        {
2852            waitpid(cpid, NULL, 0);
2853            break;
2854        }
2855        if (opid != getpid())        /* grandchild */
2856            break;
2857        /*
2858         * Do the fork twice.  Both child and grandchild need to jump back and
2859         * start over again.
2860         */
2861        cpid = fork();
2862        fork_count++;
2863
2864        if (cpid != 0)    /* original */
2865        {
2866            waitpid(cpid, NULL, 0);
2867            break;
2868        }
2869
2870        cpid = fork();
2871        if (cpid == 0)  /* grandchild */
2872            fork_count++;
2873
2874        argc = save_argc;
2875        argv = save_argv;
2876        optind = 1;
2877        goto fork_test_replay;
2878        break;
2879    case 5:
2880        if (opid != getpid())        /* grandchild */
2881            break;
2882        /*
2883         * Do the fork twice.  Only grandchild need to jump back and
2884         * start over again.
2885         */
2886        cpid = fork();
2887        fork_count++;
2888
2889        if (cpid != 0)    /* original */
2890        {
2891            waitpid(cpid, NULL, 0);
2892            break;
2893        }
2894
2895        cpid = fork();
2896        fork_count++;
2897
2898        if (cpid != 0)    /* child */
2899        {
2900            waitpid(cpid, NULL, 0);
2901            break;
2902        }
2903
2904        argc = save_argc;
2905        argv = save_argv;
2906        optind = 1;
2907        goto fork_test_replay;
2908        break;
2909    case 6:
2910        if (opid != getpid())        /* child */
2911            break;
2912        /*
2913         * Do the fork.  Only child need to jump back and
2914         * start over again.
2915         */
2916        cpid = fork();
2917        fork_count++;
2918
2919        if (cpid != 0)    /* original */
2920        {
2921            waitpid(cpid, NULL, 0);
2922            break;
2923        }
2924
2925        argc = save_argc;
2926        argv = save_argv;
2927        optind = 1;
2928        goto fork_test_replay;
2929        break;
2930    default:
2931        break;
2932    }
2933
2934    exit(0);
2935}
2936