diff options
author | sumedh <sumedh@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 1997-02-17 00:09:24 +0000 |
---|---|---|
committer | sumedh <sumedh@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 1997-02-17 00:09:24 +0000 |
commit | c685695d30d92cc376ab180641e5faf73cd2b8c1 (patch) | |
tree | a98ed952c2f465e5bdf9df6d02da29ba7899ad59 /TAO/IIOP/test | |
parent | c80c06ac96191632bddc35badae5886a7171ec4e (diff) | |
download | ATCD-c685695d30d92cc376ab180641e5faf73cd2b8c1.tar.gz |
Added IIOP files
Diffstat (limited to 'TAO/IIOP/test')
-rw-r--r-- | TAO/IIOP/test/Makefile | 80 | ||||
-rw-r--r-- | TAO/IIOP/test/clnt.cpp | 491 | ||||
-rw-r--r-- | TAO/IIOP/test/cubit.cpp | 590 | ||||
-rw-r--r-- | TAO/IIOP/test/cubit.hh | 106 | ||||
-rw-r--r-- | TAO/IIOP/test/cubit.idl | 40 | ||||
-rw-r--r-- | TAO/IIOP/test/svr.cpp | 423 | ||||
-rw-r--r-- | TAO/IIOP/test/test1.cpp | 383 | ||||
-rw-r--r-- | TAO/IIOP/test/test1.hh | 124 | ||||
-rw-r--r-- | TAO/IIOP/test/test1.idl | 78 | ||||
-rw-r--r-- | TAO/IIOP/test/test1_clnt.cpp | 636 | ||||
-rw-r--r-- | TAO/IIOP/test/test1_svr.cpp | 644 |
11 files changed, 3595 insertions, 0 deletions
diff --git a/TAO/IIOP/test/Makefile b/TAO/IIOP/test/Makefile new file mode 100644 index 00000000000..3dfca9eab2e --- /dev/null +++ b/TAO/IIOP/test/Makefile @@ -0,0 +1,80 @@ +# @(#)Makefile 1.12 95/09/30 +# Makefile for sanity checks + +ROOT = .. + +include $(ROOT)/Makefile.conf + +CPPFLAGS += -I$(ROOT)/proto/include + +LDLIBS = -Qoption ld -R$(ROOT)/proto/lib -L$(ROOT)/proto/lib -lcorba + +PROG_SRCS = svr.cpp clnt.cpp cubit.cpp \ + test1.cpp test1_clnt.cpp test1_svr.cpp \ + echo_clnt.cpp echo_svr.cpp + +TESTS = svr clnt test1_svr test1_clnt +# TESTS = svr clnt test1_svr test1_clnt echo_svr echo_clnt + + +######## +default: $(TESTS) +all: default + + +######## +# Sanity check builds by running basic functionality tests. +# +# "sleep 5" in the server startup is usually enough to get the +# objref into the file so the client can read it. +# +check: $(TESTS) + @echo "testing with 'cube' calls, stub + DII, IOR strings" + @./svr -i30 -o non-internet > obj.1 & sleep 5 + @./clnt -n250 -O `cat obj.1` -x + @echo '' + @echo "testing request forwarding with 'cube' calls, stub + DII" + @./svr -f -i30 > obj.2 & sleep 5 + @./clnt -n250 -O `cat obj.2` -x + @echo '' + @echo "testing transmission of primitive data types" + @./test1_svr -i30 > obj.3 & sleep 5 + @./test1_clnt -n50 -O `cat obj.3` -x + @echo '' +# @echo "testing echo of primitive data values" +# @./echo_svr -i30 > obj.4 & sleep 5 +# @./echo_clnt -O `cat obj.4` -x +# @echo '' + @echo "testing with 'cube' calls, MT-ized (no forwarding)" + @./svr -t -i30 -o non-internet > obj.5 & sleep 5 + @./clnt -n250 -O `cat obj.5` -x + @echo '' + +######## +# CUBIT test +svr: svr.o cubit.o + $(LINK.cc) -o svr svr.o cubit.o $(LDLIBS) +clnt: cubit.o clnt.o + $(LINK.cc) -o clnt clnt.o cubit.o $(LDLIBS) + +######## +# BASIC DATATYPES test +test1_clnt: test1.o test1_clnt.o + $(LINK.cc) -o test1_clnt test1_clnt.o test1.o $(LDLIBS) +test1_svr: test1.o test1_svr.o + $(LINK.cc) -o test1_svr test1_svr.o test1.o $(LDLIBS) + +######## +# ECHO test ... "test1" where the operation semantics are violated; +# this aids some porting work, but is a less rigorous test +echo_clnt: test1.o echo_clnt.o + $(LINK.cc) -o echo_clnt echo_clnt.o test1.o $(LDLIBS) +echo_svr: test1.o echo_svr.o + $(LINK.cc) -o echo_svr echo_svr.o test1.o $(LDLIBS) + +clean: + -rm -rf *.o Log $(TESTS) obj.* core Templates.DB .make.state + +install: + -@echo "Nothing to install, these are tests!" + diff --git a/TAO/IIOP/test/clnt.cpp b/TAO/IIOP/test/clnt.cpp new file mode 100644 index 00000000000..28a6739f01e --- /dev/null +++ b/TAO/IIOP/test/clnt.cpp @@ -0,0 +1,491 @@ +// @(#)clnt.cpp 1.2 95/09/12 +// Copyright 1994-1995 by Sun Microsystems Inc. +// All Rights Reserved +// +// TEST: Simple "cube" client, calling hand-crafted stubs. +// + +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> + +#if unix +# include <unistd.h> +# include <sys/time.h> + +#else // windows +# include "getopt.h" // e.g. GNU's version + +#endif // unix + +#include "cubit.hh" + +#include "../lib/runtime/debug.hh" + + +#if !defined (DECLARED_GETTIMEOFDAY) +extern "C" int gettimeofday (struct timeval *, struct timezone *); +#endif + +extern char *optarg; // missing on some platforms + +inline int func (unsigned i) { return i - 117; } + +extern void +print_exception (const CORBA_Exception *, const char *, FILE *f=stdout); + + +// +// forward declarations +// +static void cube_union_stub(unsigned, unsigned&, unsigned&, + CORBA_Object_ptr, CORBA_Environment &); + +static void cube_union_dii(unsigned &, unsigned &, + CORBA_Object_ptr, CORBA_Environment &); + + +int +main (int argc, char *const *argv) +{ + CORBA_ORB_ptr orb_ptr; + CORBA_Environment env; + CORBA_Object_ptr objref = CORBA_Object::_nil(); + unsigned loop_count = 1; + int exit_later = 0; + + orb_ptr = CORBA_ORB_init (argc, argv, "internet", env); + if (env.exception () != 0) { + print_exception (env.exception (), "ORB initialisation"); + return 1; + } + + // + // Parse command line and verify parameters. + // + int c; + + while ((c = getopt (argc, argv, "dn:O:x")) != EOF) + switch (c) { + case 'd': // debug flag + debug_level++; + continue; + + case 'n': // loop count + loop_count = (unsigned) atoi (optarg); + continue; + + case 'O': // stringified objref + { + objref = orb_ptr->string_to_object ( + (CORBA_String)optarg, env); + if (env.exception () != 0) { + print_exception (env.exception (), "string2object"); + return 1; + } + } + continue; + + case 'x': + exit_later++; + continue; + + case '?': + default: + fprintf (stderr, "usage: %s" + " [-d]" + " [-n loopcount]" + " [-O objref]" + " [-x]" + "\n", argv [0] + ); + return 1; + } + + if (CORBA_is_nil (objref) == CORBA_B_TRUE) { + fprintf (stderr, "%s: must identify non-null target objref\n", + argv [0]); + return 1; + } + + // + // See if the type of the objref is correct ... and while we're + // at it, incur connection setup costs outside of the timing loop. + // (Should probably report setup costs.) + // + CORBA_Boolean type_ok; + + type_ok = objref->_is_a (Cubit__id, env); + if (env.exception () != 0) { + print_exception (env.exception (), "check type of target"); + return -1; + } else if (type_ok != CORBA_B_TRUE) { + fprintf (stderr, "%s: target objref is of wrong type\n", + argv [0]); + printf ("type_ok = %d\n", type_ok); + return 1; + } + + // + // Make the calls in a loop. + // + // XXX should do two things: (a) put all the calls into a + // separate routine, and (b) set it up so a utility routine + // loops/times the calls ... these will allow (c) adding + // more categories of calls + // + unsigned i; + unsigned call_count, error_count; + + call_count = 0; + error_count = 0; + +#if defined (HAVE_GETTIMEOFDAY) + timeval before, after; + + if (gettimeofday (&before, 0) < 0) + dperror ("gettimeofday before"); +#endif // defined (HAVE_GETTIMEOFDAY) + + for (i = 0; i < loop_count; i++) { + // + // Cube an octet. + // + CORBA_Octet arg_octet, ret_octet; + + call_count++; + ret_octet = Cubit_cube_octet (objref, arg_octet = func (i), env); + if (env.exception () != 0) { + print_exception (env.exception (), "from cube_octet"); + error_count++; + } else { + dmsg2 ("cube octet: %d --> %d\n", arg_octet, ret_octet); + arg_octet = arg_octet * arg_octet * arg_octet; + if (arg_octet != ret_octet) { + printf ("** cube_octet(%d) ERROR (--> %d)\n", + (CORBA_Octet) func (i), ret_octet); + error_count++; + } + } + + // + // Cube a short. + // + CORBA_Short arg_short, ret_short; + + call_count++; + ret_short = Cubit_cube_short (objref, arg_short = func (i), env); + if (env.exception () != 0) { + print_exception (env.exception (), "from cube_short"); + error_count++; + } else { + dmsg2 ("cube short: %d --> %d\n", arg_short, ret_short); + arg_short = arg_short * arg_short * arg_short; + if (arg_short != ret_short) { + printf ("** cube_short(%d) ERROR (--> %d)\n", + (CORBA_Short) func (i), ret_short); + error_count++; + } + } + + // + // Cube a long. + // + CORBA_Long arg_long, ret_long; + + call_count++; + ret_long = Cubit_cube_long (objref, arg_long = func (i), env); + if (env.exception () != 0) { + print_exception (env.exception (), "from cube_long"); + error_count++; + } else { + dmsg2 ("cube long: %d --> %d\n", arg_long, ret_long); + arg_long = arg_long * arg_long * arg_long; + if (arg_long != ret_long) { + printf ("** cube_long(%ld) ERROR (--> %ld)\n", + (CORBA_Long) func (i), ret_long); + error_count++; + } + } + + // + // Cube a "struct" ... + // + Cubit_Many arg_struct, *ret_struct; + + call_count++; + + arg_struct.l = func (i); + arg_struct.s = func (i); + arg_struct.o = func (i); + + ret_struct = Cubit_cube_struct (objref, arg_struct, env); + if (env.exception () != 0) { + print_exception (env.exception (), "from cube_struct"); + error_count++; + } else { + dmsg ("cube struct ..."); + arg_struct.l = arg_struct.l * arg_struct.l * arg_struct.l; + arg_struct.s = arg_struct.s * arg_struct.s * arg_struct.s; + arg_struct.o = arg_struct.o * arg_struct.o * arg_struct.o; + + if (arg_struct.l != ret_struct->l + || arg_struct.s != ret_struct->s + || arg_struct.o != ret_struct->o) { + printf ("** cube_struct ERROR\n"); + error_count++; + } + delete ret_struct; + } + + } + +#if defined (HAVE_GETTIMEOFDAY) + if (gettimeofday (&after, 0) < 0) + dperror ("gettimeofday after"); + + if (call_count > 0) { + if (error_count == 0) { + unsigned long us; + + us = after.tv_sec - before.tv_sec; + us *= 1000 * 1000; + us += after.tv_usec - before.tv_usec; + us /= call_count; + + printf ("cube average call time\t= %ld.%.03ldms, \t" + "%ld calls/second\n", + us / 1000, us % 1000, + 1000000L / us); + } + + printf ("%d calls, %d errors\n", call_count, error_count); + } +#endif // defined (HAVE_GETTIMEOFDAY) + + // + // Simple test for DII: call "cube_struct". (It's not timed + // since the copious mallocation of DII would bias numbers against + // typical stub-based calls.) + // + do { + // + // Create the request ... + // + CORBA_Request_ptr req; + + req = objref->_request ((const CORBA_String) "cube_struct", env); + if (env.exception () != 0) { + print_exception (env.exception (), "DII request create"); + break; + } + + // + // ... initialise the argument list and result ... + // + Cubit_Many arg, *result; + + arg.o = 3; arg.l = 5; arg.s = -7; + + CORBA_Any tmp_arg (TC_Cubit_Many, &arg, CORBA_B_FALSE); + + req->arguments ()->add_value (0, tmp_arg, CORBA_ARG_IN, env); + if (env.exception () != 0) { + print_exception (env.exception (), "DII request arg add"); + CORBA_release (req); + break; + } + + req->result ()->value () + ->replace (TC_Cubit_Many, 0, CORBA_B_TRUE, env); + if (env.exception () != 0) { + print_exception (env.exception (), "DII request result type"); + CORBA_release (req); + break; + } + + // + // Make the invocation, verify the result + // + req->invoke (); + if (req->env ()->exception () != 0) { + print_exception (req->env ()->exception (), "DII invoke"); + CORBA_release (req); + break; + } + + result = (Cubit_Many *) req->result ()->value ()->value (); + + if (result->o != 27 || result->l != 125 || result->s != -343) + fprintf (stderr, "DII cube_struct -- bad results\n"); + else + dmsg ("DII cube_struct ... success!!"); + + CORBA_release (req); + + } while (0); + + // + // Two more tests, using the "cube_union" function + // + cube_union_dii(call_count, error_count, objref, env); + if (env.exception () != 0) + error_count++; + + cube_union_stub(i, call_count, error_count, objref, env); + if (env.exception () != 0) + error_count++; + + if (exit_later) { + Cubit_please_exit (objref, env); + dexc (env, "server, please exit"); + } + + CORBA_release (objref); + + return (error_count == 0) ? 0 : 1; +} + + +static void +cube_union_stub( + unsigned i, + unsigned &call_count, + unsigned &error_count, + CORBA_Object_ptr objref, + CORBA_Environment &env) +{ + // + // Cube a "union" ... + // + Cubit_oneof u, *r; + + call_count++; + + u._disc = e_2nd; + u.l = 3; + + r = Cubit_cube_union (objref, u, env); + if (env.exception () != 0) { + print_exception (env.exception (), "from cube_union"); + error_count++; + } else { + dmsg ("cube union ..."); + u.l = u.l * u.l * u.l ; + + if (u.l != r->l) { + printf ("** cube_union ERROR\n"); + error_count++; + } + + delete r; + } + + // + // Cube another "union" which uses the default arm ... + // + call_count++; + + u._disc = e_5th; + u.cm.l = func (i); + u.cm.s = func (i); + u.cm.o = func (i); + + u.cm.l = 7; + u.cm.s = 5; + u.cm.o = 3; + + r = Cubit_cube_union (objref, u, env); + if (env.exception () != 0) { + print_exception (env.exception (), "from cube_union"); + error_count++; + } else { + dmsg ("cube union ..."); + u.cm.l = u.cm.l * u.cm.l * u.cm.l; + u.cm.s = u.cm.s * u.cm.s * u.cm.s; + u.cm.o = u.cm.o * u.cm.o * u.cm.o; + + if (u.cm.l != r->cm.l + || u.cm.s != r->cm.s + || u.cm.o != r->cm.o) { + printf ("** cube_union ERROR\n"); + error_count++; + } + + delete r; + } +} + + +static void +cube_union_dii ( + unsigned &call_count, + unsigned &error_count, + CORBA_Object_ptr objref, + CORBA_Environment &env) +{ + // + // Create the request ... + // + CORBA_Request_ptr req; + + call_count++; + + req = objref->_request ((const CORBA_String) "cube_union", env); + if (env.exception () != 0) { + error_count++; + + print_exception (env.exception (), "cube_union_dii request create"); + return; + } + + // + // ... initialise the argument list and result ... + // + Cubit_oneof u, *r; + + u._disc = e_3rd; + u.cm.l = 5; + u.cm.s = -7; + u.cm.o = 3; + + CORBA_Any tmp_arg (TC_Cubit_oneof, &u, CORBA_B_FALSE); + + req->arguments ()->add_value (0, tmp_arg, CORBA_ARG_IN, env); + if (env.exception () != 0) { + error_count++; + print_exception (env.exception (), "cube_union_dii request arg add"); + CORBA_release (req); + return; + } + + req->result ()->value ()->replace (TC_Cubit_oneof, 0, CORBA_B_TRUE, env); + if (env.exception () != 0) { + error_count++; + print_exception (env.exception (), "cube_union_dii result type"); + CORBA_release (req); + return; + } + + // + // Make the invocation, verify the result + // + req->invoke (); + if (req->env ()->exception () != 0) { + error_count++; + print_exception (req->env ()->exception (),"cube_union_dii invoke"); + CORBA_release (req); + return; + } + + r = (Cubit_oneof *) req->result ()->value ()->value (); + + if (r->cm.o != 27 || r->cm.l != 125 || r->cm.s != -343) { + error_count++; + fprintf (stderr, "cube_union_dii -- bad results\n"); + } + else + dmsg ("cube_union_dii ... success!!"); + + CORBA_release (req); +} diff --git a/TAO/IIOP/test/cubit.cpp b/TAO/IIOP/test/cubit.cpp new file mode 100644 index 00000000000..077ba286522 --- /dev/null +++ b/TAO/IIOP/test/cubit.cpp @@ -0,0 +1,590 @@ +// @(#)cubit.cpp 1.2 95/09/29 +// Copyright 1994-1995 by Sun Microsystems Inc. +// All Rights Reserved +// +// TEST: hand-written C-style "Cubit" stubs and "skeletons" +// +// NOTE: these "skeletons" are really the methods, using DSI. No real +// ORB would be implemented in this particular way. Several things would +// be more typical of real (static) skeletons: +// +// * Most of the "in" (and much of the "out") parameter data would +// be preallocated on the stack, not heap allocated. (Static +// preallocation doesnt' really work in a multithreaded system, +// and moreover can waste a lot of space.) +// +// * The ORB core wouldn't be told about parameters using heap +// allocated data structures (e.g. NVList). +// +// * Skeletons would need to some kind of "marshal the response NOW" +// API so that stack-allocated "out" values wouldn't become invalid +// up until they were safely marshaled. +// +// * They'd handle exceptions rather than just generating debugging +// messages when they happen. +// +// * Method code would be called by the skeletons, not written as +// part of the "skeleton" itself! +// +// A key part of turning this code into a complete ORB would be to ensure +// that skeletons were always efficient and correct. They might not need +// to be sharable between different implementations of the same OMG-IDL +// object interface, but many ORBs choose to be structured that way. +// + +#include "cubit.hh" // for stubs ... +#include <corba/toa.hh> // ... and skeletons + +#include "../lib/runtime/debug.hh" // ... and debugging + + +// +// CUBE OCTET +// + +static const paramdata Cubit_cube_octet_params [] = { + { _tc_CORBA_Octet, PARAM_RETURN, 0 }, + { _tc_CORBA_Octet, PARAM_IN, 0 } +}; + +static const calldata Cubit_cube_octet_calldata = { + "cube_octet", CORBA_B_TRUE, + 2, &Cubit_cube_octet_params [0], + 0, 0 +}; + + +CORBA_Octet +Cubit_cube_octet ( + Cubit_ptr target, + CORBA_Octet o, + CORBA_Environment &env +) +{ + CORBA_Octet retval; + STUB_Object *data; + + if (target->QueryInterface (IID_STUB_Object, (void **)&data) + != NOERROR) + env.exception (new CORBA_INV_OBJREF (COMPLETED_NO)); + else { + data->do_call (env, &Cubit_cube_octet_calldata, + &retval, &o); + data->Release (); + } + return retval; +} + +static void +_cube_octet_skel ( + CORBA_ServerRequest &req, + CORBA_Environment &env +) +{ + CORBA_NVList_ptr nvlist; + CORBA_NamedValue_ptr nv; + CORBA_Any temp_value (_tc_CORBA_Octet); + + req.orb()->create_list (0, nvlist); + nv = nvlist->add_value (0, temp_value, CORBA_ARG_IN, env); + dexc (env, "cube_octet, add value"); + + req.params (nvlist, env); + dexc (env, "cube_octet, get params"); + + CORBA_Octet *value = new CORBA_Octet; + + *value = *(CORBA_Octet *)nv->value ()->value (); + // dmsg1 ("cube octet, parameter '%d'", *value); + *value = (CORBA_Octet) ((*value) * (*value) * (*value)); + // dmsg1 ("cube octet, result '%d'", *value); + + CORBA_Any *any = + new CORBA_Any (_tc_CORBA_Octet, value, CORBA_B_TRUE); + + req.result (any, env); + dexc (env, "cube_octet, result"); +} + + +// +// CUBE SHORT +// + +static const paramdata Cubit_cube_short_params [] = { + { _tc_CORBA_Short, PARAM_RETURN, 0 }, + { _tc_CORBA_Short, PARAM_IN, 0 } +}; + +static const calldata Cubit_cube_short_calldata = { + "cube_short", CORBA_B_TRUE, + 2, &Cubit_cube_short_params [0], + 0, 0 +}; + + +CORBA_Short +Cubit_cube_short ( + Cubit_ptr target, + CORBA_Short s, + CORBA_Environment &env +) +{ + CORBA_Short retval; + STUB_Object *data; + + if (target->QueryInterface (IID_STUB_Object, (void **)&data) + != NOERROR) + env.exception (new CORBA_INV_OBJREF (COMPLETED_NO)); + else { + data->do_call (env, &Cubit_cube_short_calldata, + &retval, &s); + data->Release (); + } + return retval; +} + +static void +_cube_short_skel ( + CORBA_ServerRequest &req, + CORBA_Environment &env +) +{ + CORBA_NVList_ptr nvlist; + CORBA_NamedValue_ptr nv; + CORBA_Any temp_value (_tc_CORBA_Short); + + req.orb()->create_list (0, nvlist); + nv = nvlist->add_value (0, temp_value, CORBA_ARG_IN, env); + dexc (env, "cube_short, add_value"); + + req.params (nvlist, env); + dexc (env, "cube_short, get params"); + + CORBA_Short *value = new CORBA_Short; + + *value = *(CORBA_Short *)nv->value ()->value (); + // dmsg1 ("cube short, parameter '%d'", *value); + *value =(CORBA_Short) ((*value) * (*value) * (*value)); + // dmsg1 ("cube short, result '%d'", *value); + + CORBA_Any *any = + new CORBA_Any (_tc_CORBA_Short, value, CORBA_B_TRUE); + + req.result (any, env); + dexc (env, "cube_short, result"); +} + + +// +// CUBE LONG +// + +static const paramdata Cubit_cube_long_params [] = { + { _tc_CORBA_Long, PARAM_RETURN, 0 }, + { _tc_CORBA_Long, PARAM_IN, 0 } +}; + +static const calldata Cubit_cube_long_calldata = { + "cube_long", CORBA_B_TRUE, + 2, &Cubit_cube_long_params [0], + 0, 0 +}; + + +CORBA_Long +Cubit_cube_long ( + Cubit_ptr target, + CORBA_Long l, + CORBA_Environment &env +) +{ + CORBA_Long retval; + STUB_Object *data; + + if (target->QueryInterface (IID_STUB_Object, (void **)&data) + != NOERROR) + env.exception (new CORBA_INV_OBJREF (COMPLETED_NO)); + else { + data->do_call (env, &Cubit_cube_long_calldata, + &retval, &l); + data->Release (); + } + return retval; +} + + +static void +_cube_long_skel ( + CORBA_ServerRequest &req, + CORBA_Environment &env +) +{ + CORBA_NVList_ptr nvlist; + CORBA_NamedValue_ptr nv; + CORBA_Any temp_value (_tc_CORBA_Long); + + req.orb()->create_list (0, nvlist); + nv = nvlist->add_value (0, temp_value, CORBA_ARG_IN, env); + dexc (env, "cube_long, add_value"); + + req.params (nvlist, env); + dexc (env, "cube_long, get params"); + + CORBA_Long *value = new CORBA_Long; + + *value = *(CORBA_Long *)nv->value ()->value (); + // dmsg1 ("cube long, parameter '%d'", *value); + *value = (*value) * (*value) * (*value); + // dmsg1 ("cube long, result '%d'", *value); + + CORBA_Any *any = + new CORBA_Any (_tc_CORBA_Long, value, CORBA_B_TRUE); + + req.result (any, env); + dexc (env, "cube_long, result"); +} + +// +// Encapsulated parameters for struct "Cubit_Many" typecode. +// None of these parameters is complicated, so this is just +// a linear sequence of element encodings +// +// NOTE: it's important that this be longword aligned!! +// +static const CORBA_Long _oc_Cubit_Many [] = { + 1, // byte order flag (TRICKY!) + + 1, 0, // empty string: repository/type ID + 1, 0, // empty string: struct name + + 3, // three struct elements + + // First structure element: name, typecode for Octet + 1, 0, // empty string: name "o" + tk_octet, + + // Second structure element: name, typecode for Long + 1, 0, // empty string: name "l" + tk_long, + + // Third structure element: name, typecode for Short + 1, 0, // empty string: name "s" + tk_short, +}; + +static CORBA_TypeCode _tc_Cubit_Many (tk_struct, + sizeof _oc_Cubit_Many, (unsigned char *) &_oc_Cubit_Many, + CORBA_B_FALSE); +CORBA_TypeCode_ptr TC_Cubit_Many = &_tc_Cubit_Many; + + +// +// CUBE STRUCT +// + +static const paramdata Cubit_cube_struct_params [] = { + { &_tc_Cubit_Many, PARAM_RETURN, sizeof (Cubit_Many) }, + { &_tc_Cubit_Many, PARAM_IN, 0 } +}; + +static const calldata Cubit_cube_struct_calldata = { + "cube_struct", CORBA_B_TRUE, + 2, &Cubit_cube_struct_params [0], + 0, 0 +}; + +Cubit_Many * +Cubit_cube_struct ( + Cubit_ptr target, + Cubit_Many &values, + CORBA_Environment &env +) +{ + Cubit_Many *retval; + STUB_Object *data; + + if (target->QueryInterface (IID_STUB_Object, (void **)&data) + != NOERROR) + env.exception (new CORBA_INV_OBJREF (COMPLETED_NO)); + else { + data->do_call (env, &Cubit_cube_struct_calldata, + &retval, &values); + data->Release (); + } + return retval; +} + + +static void +_cube_struct_skel ( + CORBA_ServerRequest &req, + CORBA_Environment &env +) +{ + CORBA_NVList_ptr nvlist; + CORBA_NamedValue_ptr nv; + CORBA_Any temp_value (TC_Cubit_Many); + + req.orb()->create_list (0, nvlist); + nv = nvlist->add_value (0, temp_value, CORBA_ARG_IN, env); + dexc (env, "cube_struct, add_value"); + + req.params (nvlist, env); + dexc (env, "cube_struct, get params"); + + Cubit_Many *value; + Cubit_Many *retval = new Cubit_Many; + + value = (Cubit_Many *)nv->value ()->value (); + + retval->o = (CORBA_Octet) (value->o * value->o * value->o); + retval->s = (CORBA_Short) (value->s * value->s * value->s); + retval->l = value->l * value->l * value->l; + + // dmsg2 ("cube struct.o, %d -> %d", value->o, retval->o); + // dmsg2 ("cube struct.s, %d -> %d", value->s, retval->s); + // dmsg2 ("cube struct.l, %d -> %d", value->l, retval->l); + + CORBA_Any *any = + new CORBA_Any (TC_Cubit_Many, retval, CORBA_B_TRUE); + + req.result (any, env); + dexc (env, "cube_struct, result"); +} + +// +// CUBE UNION +// + +// +// NOTE: not all union typecodes can be encoded as an array +// of "long "values, but this one can. Ones with discriminants +// that are one or two bytes long can't easily be coded portably. +// +// The benefit of doing it as an array of "long" values is +// twofold: (a) easier to read; (b) on most systems it's then +// adequately aligned for the typecode interpreter to use, so +// no additional runtime copy needs to be made. +// +static const CORBA_Long _oc_Cubit_oneof [] = { + 1, // byte order flag (TRICKY) + 1, 0, // omitted repository/type ID + 1, 0, // omitted struct name, "oneof" + + // + // discriminant typecode: + // + tk_enum, // tk_enum + 72, // encapsulation length + + 1, // byte order flag (TRICKY) + 1, 0, // omitted repository/type ID + 1, 0, // omitted enum name, "discrim" + 6, // 5 elements in the enum + + 1, 0, // omitted member name, "e_0th" + 1, 0, // omitted member name, "e_1st" + 1, 0, // omitted member name, "e_2nd" + 1, 0, // omitted member name, "e_3rd" + 1, 0, // omitted member name, "e_4th" + 1, 0, // omitted member name, "e_5th" + + 4, // default member index (zero based) + 5, // number of union members + + // the 1st union branch arm + e_0th, // member label value + 1, 0, // omitted member name, "o" + tk_octet, // member typecode + + // the 2nd union branch arm + e_1st, // member label value + 1, 0, // omitted member name, "s" + tk_short, // member typecode + + // the 3rd union branch arm + e_2nd, // member label value + 1, 0, // omitted member name, "l" + tk_long, // member typecode + + // the 4th union branch arm + e_3rd, // member label value + 1, 0, // omitted member name, "cm" + + // the 4th union member typecode + tk_struct, // tk_struct + 60, // encap length + + 1, // byte order flag (TRICKY) + 1, 0, // omitted repository/type ID + 1, 0, // omitted struct name, "Many" + 3, // three struct members + + // First structure element + 1, 0, // omitted member name, "o" + tk_octet, // member type, tk_octet + + // Second structure element + 1, 0, // omitted member name, "l" + tk_long, // member type, tk_long + + // Third structure element + 1, 0, // omitted member name, "s" + tk_short, // member type, tk_short + + // the 5th union branch arm + 4, // the 5th member label value + 1, 0, // omitted member name, "cm" + ~0, // indirected typecode (~0) + -84 // offset to struct "Many" typecode +}; + +static CORBA_TypeCode _tc_Cubit_oneof (tk_union, + (sizeof _oc_Cubit_oneof), (unsigned char *) &_oc_Cubit_oneof, + CORBA_B_FALSE); +CORBA_TypeCode_ptr TC_Cubit_oneof = &_tc_Cubit_oneof; + +static const paramdata Cubit_cube_union_params [] = { + { &_tc_Cubit_oneof, PARAM_RETURN, sizeof (Cubit_oneof) }, + { &_tc_Cubit_oneof, PARAM_IN, 0 } +}; + +static const calldata Cubit_cube_union_calldata = { + "cube_union", CORBA_B_TRUE, + 2, &Cubit_cube_union_params [0], + 0, 0 +}; + +Cubit_oneof * +Cubit_cube_union ( + Cubit_ptr target, + Cubit_oneof &values, + CORBA_Environment &env +) +{ + Cubit_oneof *retval; + STUB_Object *data; + + if (target->QueryInterface (IID_STUB_Object, (void **)&data) + != NOERROR) + env.exception (new CORBA_INV_OBJREF (COMPLETED_NO)); + else { + data->do_call (env, &Cubit_cube_union_calldata, + &retval, &values); + data->Release (); + } + return retval; +} + + +static void +_cube_union_skel ( + CORBA_ServerRequest &req, + CORBA_Environment &env +) +{ + CORBA_NVList_ptr nvlist; + CORBA_NamedValue_ptr nv; + CORBA_Any temp_value (TC_Cubit_oneof); + + req.orb()->create_list (0, nvlist); + nv = nvlist->add_value (0, temp_value, CORBA_ARG_IN, env); + dexc (env, "cube_union_3rd, add_value"); + + req.params (nvlist, env); + dexc (env, "cube_union_3rd, get params"); + + Cubit_oneof *v; + Cubit_oneof *r = new Cubit_oneof; + + v = (Cubit_oneof *)nv->value ()->value (); + r->_disc = v->_disc; + + switch (v->_disc) { + case e_0th: + r->o = (CORBA_Octet) (v->o * v->o * v->o); + break; + + case e_1st: + r->s = (CORBA_Short) (v->s * v->s * v->s); + break; + + case e_2nd: + r->l = v->l * v->l * v->l; + break; + + case e_3rd: + default: + r->cm.o = (CORBA_Octet) (v->cm.o * v->cm.o * v->cm.o); + r->cm.s = (CORBA_Short) (v->cm.s * v->cm.s * v->cm.s); + r->cm.l = v->cm.l * v->cm.l * v->cm.l; + break; + } + + CORBA_Any *any = new CORBA_Any (TC_Cubit_oneof, r, CORBA_B_TRUE); + + req.result (any, env); + dexc (env, "cube_struct, result"); +} + + +// +// PLEASE EXIT +// + +static const calldata Cubit_please_exit_calldata = { + "please_exit", CORBA_B_FALSE, + 0, 0, + 0, 0 +}; + +void +Cubit_please_exit ( + Cubit_ptr target, + CORBA_Environment &env +) +{ + STUB_Object *data; + + if (target->QueryInterface (IID_STUB_Object, (void **)&data) + != NOERROR) + env.exception (new CORBA_INV_OBJREF (COMPLETED_NO)); + else { + data->do_call (env, &Cubit_please_exit_calldata + ); + data->Release (); + } +} + +static void +_please_exit_skel ( + CORBA_ServerRequest &req, + CORBA_Environment &env +) +{ + dmsg ("I've been asked to shut down..."); + req.oa ()->please_shutdown (env); + dexc (env, "please_exit, please_shutdown"); +} + + +const CORBA_Char *Cubit__id = (CORBA_Char *) + "IDL:Eng.SUN.COM/Cubit:1.1"; + + +// +// table of all operations, used by operation dispatch to get to the +// right skeleton ... could be sorted by the IDL compiler so bsearch +// is effective, perhaps with help from opname hashes and a small cache +// (e.g. like Obj-C?). for now, just lsearch. +// +const skel_entry Cubit_operations [] = { + { &Cubit_cube_octet_calldata, _cube_octet_skel }, + { &Cubit_cube_short_calldata, _cube_short_skel }, + { &Cubit_cube_long_calldata, _cube_long_skel }, + { &Cubit_cube_struct_calldata, _cube_struct_skel }, + { &Cubit_cube_union_calldata, _cube_union_skel }, + { &Cubit_please_exit_calldata, _please_exit_skel }, + { 0, 0 } // last entry +}; diff --git a/TAO/IIOP/test/cubit.hh b/TAO/IIOP/test/cubit.hh new file mode 100644 index 00000000000..aae2c06bd31 --- /dev/null +++ b/TAO/IIOP/test/cubit.hh @@ -0,0 +1,106 @@ +// @(#)cubit.hh 1.1 95/09/10 +// Copyright 1994-1995 by Sun Microsystems Inc. +// All Rights Reserved +// +// Hand-crafted C language binding glue ... +// +// This doesn't use C++ since doing the obvious derivation +// (all parent interfaces are virtual public parents) makes +// object references have different "views". That is, a +// pointer to a Cubit (i.e. a Cubit_ptr) would not have +// the same binary value as a pointer to a CORBA_Object +// (i.e. a CORBA_Object_ptr, generic objref). That'd +// mean lots of narrowing/widening/RTTI infrastructure. +// + +#ifndef _CUBIT_HH +#define _CUBIT_HH + +#ifdef _MSC_VER +#pragma pack (push, 1) // VC++, known padding rules +#endif // VC++ + +#include <corba/orb.hh> +#include <corba/stub.hh> + + +// +// C style binding +// + +typedef CORBA_Object Cubit; +typedef Cubit *Cubit_ptr, *CubitRef; + +extern CORBA_TypeCode_ptr TC_Cubit_Many; +extern CORBA_TypeCode_ptr TC_Cubit_oneof; + +struct Cubit_Many { + CORBA_Octet o; + CORBA_Long l; + CORBA_Short s; +}; + +enum Cubit_discrim {e_0th = 0, e_1st = 1, e_2nd = 2, + e_3rd = 3, e_4th = 4, e_5th = 5}; + +struct Cubit_oneof { + Cubit_discrim _disc; + + union { + CORBA_Octet o; + CORBA_Short s; + CORBA_Long l; + Cubit_Many cm; + }; +}; + +CORBA_Octet +Cubit_cube_octet ( + Cubit_ptr target, + CORBA_Octet o, + CORBA_Environment &env +); + +CORBA_Short +Cubit_cube_short ( + Cubit_ptr target, + CORBA_Short s, + CORBA_Environment &env +); + +CORBA_Long +Cubit_cube_long ( + Cubit_ptr target, + CORBA_Long l, + CORBA_Environment &env +); + +Cubit_Many * +Cubit_cube_struct ( + Cubit_ptr target, + Cubit_Many &values, + CORBA_Environment &env +); + +Cubit_oneof * +Cubit_cube_union ( + Cubit_ptr target, + Cubit_oneof &values, + CORBA_Environment &env +); + +void +Cubit_please_exit ( + Cubit_ptr target, + CORBA_Environment &env +); + +extern const CORBA_Char *Cubit__id; // type ID + +extern const skel_entry Cubit_operations []; + +#ifdef _MSC_VER +#pragma pack (pop) // VC++, go back to other padding rules +#endif // VC++ + +#endif // _CUBIT_HH diff --git a/TAO/IIOP/test/cubit.idl b/TAO/IIOP/test/cubit.idl new file mode 100644 index 00000000000..d9b38c34a2a --- /dev/null +++ b/TAO/IIOP/test/cubit.idl @@ -0,0 +1,40 @@ +// @(#)cubit.idl 1.1 95/09/10 +// Copyright 1994-1995 by Sun Microsystems, Inc. + +#pragma prefix "Eng.SUN.COM" +#pragma version Cubit 1.1 + +interface Cubit { + octet cube_octet (in octet o); + short cube_short (in short s); + long cube_long (in long l); + + struct Many { + octet o; // + 3 bytes padding (normally) ... + long l; + short s; // + 2 bytes padding (normally) ... + }; + + Many cube_struct (in Many values); + + enum discrim {e_0th, e_1st, e_2nd, e_3rd, e_4th, e_5th}; + + union oneof + switch (discrim) { + // this is an easy union to interpret; no padding + // is needed between discriminant and value. + case e_0th: + octet o; + case e_1st: + short s; + case e_2nd: + long l; + case e_3rd: + default: + Many cm; + }; + + oneof cube_union (in oneof values); + + oneway void please_exit (); +}; diff --git a/TAO/IIOP/test/svr.cpp b/TAO/IIOP/test/svr.cpp new file mode 100644 index 00000000000..cb34263c82c --- /dev/null +++ b/TAO/IIOP/test/svr.cpp @@ -0,0 +1,423 @@ +// @(#)svr.cpp 1.6 95/10/02 +// Copyright 1994-1995 by Sun Microsystems Inc. +// All Rights Reserved +// +// TEST: simple IIOP server for "cubit.idl" interface. +// +// Starts up, builds an objref, prints its string, listens for +// messages, responds to them. +// + +#include <stdio.h> +#include <string.h> + +#if unix +# include <unistd.h> // for getopt on some systems + +#else // windows +# include "getopt.h" // e.g. GNU's version + +#endif + +#include "cubit.hh" +#include <corba/toa.hh> + + +// +// XXX a general debug/trace facility would be handy +// +#include "../lib/runtime/debug.hh" + +// +// XXX this stuff is ugly but needed, since this exposes features +// (IIOP forwarding) that TOA doesn't provide. +// +#include "../lib/bridge/connmgr.hh" +#include "../lib/bridge/tcpoa.hh" + + +extern char *optarg; // missing on some platforms + +extern void +print_exception (const CORBA_Exception *, const char *, FILE *f=stdout); + + +static void +is_a_skel ( + CORBA_ServerRequest &req, + CORBA_Environment &env +) +{ + CORBA_NVList_ptr nvlist; + CORBA_NamedValue_ptr nv; + CORBA_Any temp_value (_tc_CORBA_String); + + req.orb()->create_list (0, nvlist); + nv = nvlist->add_value (0, temp_value, CORBA_ARG_IN, env); + + req.params (nvlist, env); + if (env.exception () != 0) { + dexc (env, "is_a_skel, get params"); + return; + } + + CORBA_Boolean *retval; + CORBA_String value = *(CORBA_String *) + nv->value ()->value (); + + // + // This object's type "is_a" conformant subtype of the type whose + // ID ("Repository ID") is passed if it's (a) either the same type + // as indicated by the ID, or (b) one of the classes from which it + // inherits is_a subtype, or (c) the ID is for the generic CORBA + // object. + // + // XXX IDs should be compared recognizing that the "IDL" and "DCE" + // ID types have a minor version code, and that if the minor code + // (a 16 bit unsigned integer, in ASCII form) of the ID passed is + // not greater than one of the IDs we know, it's still compatible. + // + // XXX "env" should be checked to see if TypeCode::id() reported + // an exception ... + // + if (strcmp ((char *)value, (char *)Cubit__id) == 0 + || strcmp ((char *)value, _tc_CORBA_Object->id (env)) == 0) + retval = new CORBA_Boolean (CORBA_B_TRUE); + else + retval = new CORBA_Boolean (CORBA_B_FALSE); + + CORBA_Any *any = + new CORBA_Any (_tc_CORBA_Boolean, retval, CORBA_B_TRUE); + + req.result (any, env); + dexc (env, "_is_a, result"); +} + + +// +// Dispatch to Skeletons +// +// XXX explore packaging most of this as part of the TCP_OA !! +// +static void +tcpoa_dispatch ( + CORBA_OctetSeq &key, + CORBA_ServerRequest &req, + void *context, + CORBA_Environment &env +) +{ + // + // Verify that the target object and "this" object have the + // same key. Normally, this would be used to figure out + // which object was the target, and hence which operations + // vector to dispatch the request. + // + CORBA_OctetSeq *obj_key; + + obj_key = (CORBA_OctetSeq *) context; + + if (obj_key->length != key.length + || memcmp (obj_key->buffer, key.buffer, + obj_key->length) != 0) { + env.exception (new CORBA_OBJECT_NOT_EXIST (COMPLETED_NO)); +#ifdef DEBUG + if (debug_level) + dmsg_opaque ("request to nonexistent object, key = ", + key.buffer, key.length); +#endif + return; + } + + // + // Find a "skeleton" (nyet :-) entry for this operation, + // then call it with the right per-object state. (Someday this + // search will be sped up, e.g. by hashing or binary search.) + // + const skel_entry *entry; + CORBA_String opname; + + opname = req.op_name (); + + for (entry = &Cubit_operations [0]; entry->op_descriptor; entry++) { + if (strcmp ((char *)opname, entry->op_descriptor->opname) == 0) { + entry->impl_skeleton (req, env); + return; + } + } + + // + // Try one of the ORB's built-in operations. + // + // XXX the rest too: _non_existent (just return false), + // _get_interface (needs an interface repository reference for this + // objref's type), and _get_implementation (needs an implementation + // repository). + // + if (strcmp ((char *)opname, "_is_a") == 0) { + is_a_skel (req, env); + return; + } + + // + // No match. Operation not implemented; say so. + // + dmsg1 ("unknown operation, %s", opname); + env.exception (new CORBA_BAD_OPERATION (COMPLETED_NO)); +} + +// +// forwarding support +// +static CORBA_Object_ptr fwd_ref; + +static void +tcpoa_forwarder ( + CORBA_OctetSeq &key, + CORBA_Object_ptr &the_ref, + void *context, + CORBA_Environment &env +) +{ + CORBA_OctetSeq *obj_key; + + obj_key = (CORBA_OctetSeq *) context; + + if (obj_key->length == key.length + && memcmp (obj_key->buffer, key.buffer, key.length) == 0) { + the_ref = fwd_ref->_duplicate (fwd_ref); + } else + env.exception (new CORBA_OBJECT_NOT_EXIST (COMPLETED_NO)); +} + + +// +// Socket-based passive OA entry point +// +int +OA_listen ( + CORBA_ORB_ptr orb_ptr, + TCP_OA_ptr oa_ptr, + CORBA_String key, + int idle, + CORBA_Boolean do_fork, + CORBA_Boolean do_threads +) +{ + // + // Create the object we'll be implementing. + // + CORBA_OctetSeq obj_key; + CORBA_Object_ptr obj; + CORBA_Environment env; + + obj_key.buffer = (CORBA_Octet *) key; + obj_key.length = obj_key.maximum = strlen ((char *)key); + + obj = oa_ptr->create (obj_key, (CORBA_String) "", env); + if (env.exception () != 0) { + print_exception (env.exception (), "TCP_OA::create"); + return 1; + } + + // + // Stringify the objref we'll be implementing, and + // print it to stdout. Someone will take that string + // and give it to some client. Then release the object. + // + CORBA_String str; + + str = orb_ptr->object_to_string (obj, env); + if (env.exception () != 0) { + print_exception (env.exception (), "object2string"); + return 1; + } + puts ((char *)str); + fflush (stdout); + dmsg1 ("listening as object '%s'", str); + CORBA_release (obj); + obj = 0; + + // + // If we're forking a child server, do so -- read the objref + // it'll use, and prepare to forward all requests to it. That + // objref has a dynamically assigned port. + // + if (do_fork) { +#if defined (HAVE_POPEN) + FILE *f = popen ("exec ./svr -i120 -kbaskerville", "r"); + char buffer [BUFSIZ]; + + if (fgets (buffer, sizeof buffer, f) != buffer) { + fprintf (stderr, "error: can't read from child\n"); + return 1; + } + fwd_ref = orb_ptr->string_to_object ((CORBA_String) buffer, env); + if (env.exception () != 0) { + print_exception (env.exception (), "string2object"); + return 1; + } + + // + // NOTE: don't fclose("f") since some systems make that the + // same as pclose("f"). Pclose waits for the child to exit, + // causing a deadlock since the child won't exit until it's + // told to do so by a client, but no client can be redirected + // to the child until the pclose returns ... + // +#else + fprintf (stderr, "error: no popen(), can't create child\n"); + env.exception (new CORBA_IMP_LIMIT); + return 1; +#endif // !defined (HAVE_POPEN) + } + + // + // Handle requests for this object until we're killed, or one of + // the methods asks us to exit. + // + // NOTE: for multithreaded environments (e.g. POSIX threads) also + // want to use threads. The current notion is to dedicate a thread + // to a "read" on each client file descriptor, and then when that + // successfully gets a Request message, to start another thread + // reading that descriptor while the first one creates the Reply. + // + // This will accentuate the need for server-side policies to address + // resource management, such as shutting down connections that have + // no requests in progress after they've been idle for some time + // period (e.g. 10 minutes), and reclaiming the thread used by that + // connection. + // + while (oa_ptr->shutting_down () != CORBA_B_TRUE) { + if (idle == -1) + oa_ptr->get_request (tcpoa_dispatch, + fwd_ref ? tcpoa_forwarder : 0, + do_threads, &obj_key, 0, env); + else { + timeval tv; + + tv.tv_sec = idle; + tv.tv_usec = 0; + oa_ptr->get_request (tcpoa_dispatch, + fwd_ref ? tcpoa_forwarder : 0, + do_threads, &obj_key, &tv, env); + } + + // + // XXX "env2" should be checked to see if TypeCode::id() reported + // an exception ... + // + CORBA_Environment env2; + + if (env.exception () != 0 + && strcmp ((char *)env.exception ()->id (), + _tc_CORBA_INITIALIZE->id (env2)) == 0) { + print_exception (env.exception (), "TCP_OA::get_request"); + return 1; + } + env.clear (); + } + + // + // Shut down the OA -- recycles all underlying resources (e.g. file + // descriptors, etc). + // + oa_ptr->clean_shutdown (env); + return 0; +} + + +// +// Standard command line parsing utilities used. +// +int +main ( + int argc, + char *const *argv +) +{ + CORBA_Environment env; + CORBA_ORB_ptr orb_ptr; + TCP_OA_ptr oa_ptr; + CORBA_Boolean do_fork = CORBA_B_FALSE; + CORBA_Boolean do_threads = CORBA_B_FALSE; + CORBA_String key = (CORBA_String) "key0"; + char *oa_name = 0; + char *orb_name = "internet"; + int idle = -1; + + // + // Parse the command line, get options + // + int c; + + while ((c = getopt (argc, argv, "di:fk:o:p:t")) != EOF) + switch (c) { + case 'd': // more debug noise + debug_level++; + continue; + + case 'i': // idle seconds b4 exit + idle = atoi (optarg); + continue; + + case 'f': // fork child server + do_fork = CORBA_B_TRUE; + continue; + + case 'k': // key (str) + key = (CORBA_String) optarg; + continue; + + case 'o': // orb name + orb_name = optarg; + continue; + + case 'p': // portnum + oa_name = optarg; + continue; + + case 't': // create thread-per-request + do_threads = CORBA_B_TRUE; + continue; + + // XXX set debug filters ... + + // + // XXX ignore OMG-specified options ... hope nobody ever tries + // to use that "-ORB* param" and "-OA* param" syntax, it flies + // in the face of standard command parsing algorithms which + // require single-character option specifiers. + // + + case '?': + default: + fprintf (stderr, "usage: %s" + " [-d]" + " [-f]" + " [-i idle_seconds]" + " [-k]" + " [-k object_key=key0]" + " [-o orb_name=internet]" + " [-p portnum=5555]" + " [-t]" + "\n", argv [0] + ); + return 1; + } + + orb_ptr = CORBA_ORB_init (argc, argv, orb_name, env); + if (env.exception () != 0) { + print_exception (env.exception (), "ORB init"); + return 1; + } + + oa_ptr = TCP_OA::init (orb_ptr, oa_name, env); + if (env.exception () != 0) { + print_exception (env.exception (), "OA init"); + return 1; + } + + return OA_listen (orb_ptr, oa_ptr, key, idle, do_fork, do_threads); +} + diff --git a/TAO/IIOP/test/test1.cpp b/TAO/IIOP/test/test1.cpp new file mode 100644 index 00000000000..78506e07e24 --- /dev/null +++ b/TAO/IIOP/test/test1.cpp @@ -0,0 +1,383 @@ +// @(#)test1.cpp 1.4 95/09/28 +// Copyright 1995 by Sun Microsystems, Inc. +// All Rights Reserved +// +// TEST stubs for "test1" +// + +#include <stdio.h> + +#include "test1.hh" + + +// +// Define all the stubs ... it's a lot less error prone to do it with +// macros than by hand! +// +// NOTE: the "calldata" is exported for use by the skeletons. At some +// point skeletons will probably be fully abstracted; for now they aren't. +// +// Also, for some reason, name mangling is changed by the explicit +// declaration as "extern" -- if it's not done, linking fails. +// +#define DEFINE_TEST3(typename, truetype, truetypename) \ + static const paramdata test1_ ## typename ## _paramdata [4] = { \ + { _tc_CORBA_ ## truetypename, PARAM_RETURN, 0 }, \ + { _tc_CORBA_ ## truetypename, PARAM_IN, 0 }, \ + { _tc_CORBA_ ## truetypename, PARAM_OUT, 0 }, \ + { _tc_CORBA_ ## truetypename, PARAM_INOUT, 0 }, \ + }; \ + \ + extern const calldata test1_ ## typename ## _calldata; \ + \ + const calldata test1_ ## typename ## _calldata = { \ + "test_" #typename, CORBA_B_TRUE, \ + 4, &test1_ ## typename ## _paramdata [0], \ + 0, 0, \ + }; \ + \ + CORBA_ ## truetype \ + test1_test_ ## typename (test1_ptr target, \ + CORBA_ ## truetype in_a1, \ + CORBA_ ## truetype &out_a2, \ + CORBA_ ## truetype &inout_a3, \ + CORBA_Environment &env) { \ + CORBA_ ## truetype _retval = 0; \ + STUB_Object *_obj; \ + if (target->QueryInterface (IID_STUB_Object, (void **)&_obj) \ + != NOERROR) \ + env.exception (new CORBA_INV_OBJREF (COMPLETED_NO)); \ + else { \ + _obj->do_call (env, &test1_ ## typename ## _calldata, \ + &_retval, &in_a1, &out_a2, &inout_a3); \ + _obj->Release (); \ + } \ + return _retval; \ + } + +#define DEFINE_TEST(typename, truetype) \ + DEFINE_TEST3(typename, truetype, truetype) + + +// +// Generate a system exception, passing an operation ID that's +// not allowed by IIOP (much less this interface) and verifying +// that the server returns some kind of system exception. +// +static const calldata illegal_calldata = { + "+_illegal", CORBA_B_TRUE, + 0, 0, + 0, 0 +}; + +void +test_illegal (test1_ptr target, CORBA_Environment &env) +{ + STUB_Object *data; + + if (target->QueryInterface (IID_STUB_Object, (void **)&data) + != NOERROR) + env.exception (new CORBA_INV_OBJREF (COMPLETED_NO)); + else { + data->do_call (env, &illegal_calldata + ); + data->Release (); + } +} + + +extern const calldata test1_void_calldata; +const calldata test1_void_calldata = { + "test_void", CORBA_B_TRUE, + 0, 0, + 0, 0 +}; + +void +test1_test_void (test1_ptr target, CORBA_Environment &env) +{ + STUB_Object *data; + + if (target->QueryInterface (IID_STUB_Object, (void **)&data) + != NOERROR) + env.exception (new CORBA_INV_OBJREF (COMPLETED_NO)); + else { + data->do_call (env, &test1_void_calldata + ); + data->Release (); + } +} + +DEFINE_TEST (short, Short); +DEFINE_TEST (long, Long); +DEFINE_TEST (ushort, UShort); +DEFINE_TEST (ulong, ULong); + +#if defined(MIPS) +// +// NOTE: C/C++ compilers as a rule pass a "float" in the space that +// a "double" takes up. Conversions are evidently optional; portability +// forces the following "explicit temporary" hack to work on at least +// one MIPS platform, which converts the parameter to "double" and +// hence changes the binary representation. (Even if that is a compiler +// bug, it's probably required by now for binary compatibility!) +// +// A "-k ansi" compiler flag may be needed to get correct behaviour; +// passing the "in" parameters by reference apparently works too. At +// this time, none of these solutions is used by default. +// +// This stub-level hackery seems like it could be replaced inside of the +// stub interpreter, which could just manually convert "float" parameters +// (all of them) as special cases. But of course, that would slow the +// interpreter down on _every_ call, not just the ones that require it +// (such as this one). Tradeoffs! +// +static const paramdata test1_float_paramdata [4] = { + { _tc_CORBA_Float , PARAM_RETURN , 0 }, + { _tc_CORBA_Float , PARAM_IN , 0 }, + { _tc_CORBA_Float , PARAM_OUT , 0 }, + { _tc_CORBA_Float , PARAM_INOUT , 0 } +}; + +extern const calldata test1_float_calldata; + +const calldata test1_float_calldata = { + "test_float", CORBA_B_TRUE, + 4 , &test1_float_paramdata [0], + 0 , 0 +}; + +CORBA_Float +test1_test_float ( + test1_ptr target, + CORBA_Float in_a1, + CORBA_Float &out_a2, + CORBA_Float &inout_a3, + CORBA_Environment &env +) +{ + CORBA_Float _retval; + + // These three temporaries required due to MIPS compiler bug + CORBA_Float _in_a1 = in_a1; + CORBA_Float _out_a2 = out_a2; + CORBA_Float _inout_a3 = inout_a3; + + target -> data -> do_call (env, + &test1_float_calldata, + &_retval, + &_in_a1, + &_out_a2, + &_inout_a3); + return _retval; +} + +#else +DEFINE_TEST (float, Float); +#endif // MIPS + + +DEFINE_TEST (double, Double); +DEFINE_TEST (boolean, Boolean); +DEFINE_TEST (char, Char); +DEFINE_TEST (octet, Octet); + +/* +CORBA_Any * +test1_test_any (test1_ptr target, + const CORBA_Any &in_a1, + CORBA_Any *&out_a2, + CORBA_Any &inout_a3, + CORBA_Environment &env) +{ + // XXX implement this stub! ... annoying that C++ mapping + // calls for so much special casing +} +*/ + + +DEFINE_TEST3 (TypeCode, TypeCode_ptr, TypeCode); +DEFINE_TEST3 (Principal, Principal_ptr, Principal); +DEFINE_TEST3 (Object, Object_ptr, Object); + +// NOTE: C++ mapping has "in" strings as "const", which doesn't +// show up in this macro ... +DEFINE_TEST3 (string, Char *, String); + +DEFINE_TEST (longlong, LongLong); +DEFINE_TEST (ulonglong, ULongLong); +DEFINE_TEST (wchar, WChar); + +// NOTE: C++ mapping has "in" strings as "const", which doesn't +// show up in this macro ... +DEFINE_TEST3 (wstring, WChar *, WString); + +DEFINE_TEST (longdouble, LongDouble); + +#undef DEFINE_TEST + + +// +// Utility macros used to construct octet codes that are aligned +// on longword boundaries, and with a known byte order. This +// happens to use big endian encoding since it was convenient. +// (Longword alignment is a happy accident of the specification +// of OMG-IDL ... it could have been much worse!) +// +// It'd be much simpler to lay out such data in assembler! +// + +#if defined (WORDS_BIGENDIAN) +# define MAKE_BIG_LONG(a,b,c,d) \ + ((((a) & 0xff) << 24) | (((b) & 0xff) << 16) \ + | (((c) & 0xff) << 8) | ((d) & 0xff)) +# define BIG_ENDIAN_LONG(x) (x) + +#else // LITTLE_ENDIAN +# define MAKE_BIG_LONG(a,b,c,d) \ + ((((d) & 0xff) << 24) | (((c) & 0xff) << 16) \ + | (((b) & 0xff) << 8) | ((a) & 0xff)) +# define BYTE_FROM(n,integer) (((integer)>>(8*(n)))&0xff) +# define BIG_ENDIAN_LONG(integer) \ + MAKE_BIG_LONG (BYTE_FROM(3,integer), BYTE_FROM(2,integer),\ + BYTE_FROM(1,integer), BYTE_FROM(0,integer)) +#endif + + + +// +// "x1" exception typecode ... must be longword aligned +// +static CORBA_Long oc_x1 [] = { + 0, // big endian flag + padding + BIG_ENDIAN_LONG (29), // length of ID string + NUL + MAKE_BIG_LONG ('I', 'D', 'L', ':'), // bytes of ID string + MAKE_BIG_LONG ('E', 'n', 'g', '.'), + MAKE_BIG_LONG ('S', 'U', 'N', '.'), + MAKE_BIG_LONG ('C', 'O', 'M', '/'), + MAKE_BIG_LONG ('t', 'e', 's', 't'), + MAKE_BIG_LONG ('1', '/', 'x', '1'), + MAKE_BIG_LONG (':', '1', '.', '0'), + 0, + BIG_ENDIAN_LONG (1), // (empty) namelen + NUL + 0, + BIG_ENDIAN_LONG (1), // only one struct member + BIG_ENDIAN_LONG (1), // (empty) member name + NUL + 0, + BIG_ENDIAN_LONG (tk_long) +}; +static CORBA_TypeCode tc_x1 (tk_except, sizeof oc_x1, + (unsigned char *)&oc_x1, CORBA_B_FALSE); +CORBA_TypeCode_ptr _tc_test1_x1 = &tc_x1; + + + +// +// "x2" exception typecode ... must be longword aligned +// +static CORBA_Long oc_x2 [] = { + 0, // big endian flag + padding + BIG_ENDIAN_LONG (29), // length of ID string + NUL + MAKE_BIG_LONG ('I', 'D', 'L', ':'), // bytes of ID string + MAKE_BIG_LONG ('E', 'n', 'g', '.'), + MAKE_BIG_LONG ('S', 'U', 'N', '.'), + MAKE_BIG_LONG ('C', 'O', 'M', '/'), + MAKE_BIG_LONG ('t', 'e', 's', 't'), + MAKE_BIG_LONG ('1', '/', 'x', '2'), + MAKE_BIG_LONG (':', '1', '.', '0'), + 0, + BIG_ENDIAN_LONG (1), // (empty) namelen + NUL + 0, + BIG_ENDIAN_LONG (2), // two struct members + + BIG_ENDIAN_LONG (1), // (empty) member name + NUL + 0, + BIG_ENDIAN_LONG (tk_objref), + BIG_ENDIAN_LONG (29), // type ID + NUL + MAKE_BIG_LONG ('I', 'D', 'L', ':'), // bytes of ID string + MAKE_BIG_LONG ('o', 'm', 'g', '.'), + MAKE_BIG_LONG ('o', 'r', 'g', '/'), + MAKE_BIG_LONG ('C', 'O', 'R', 'B'), + MAKE_BIG_LONG ('A', '/', 'O', 'b'), + MAKE_BIG_LONG ('j', 'e', 'c', 't'), + MAKE_BIG_LONG (':', '1', '.', '0'), + 0, + + BIG_ENDIAN_LONG (1), // (empty) member name + NUL + 0, + BIG_ENDIAN_LONG (tk_long) +}; +static CORBA_TypeCode tc_x2 (tk_except, sizeof oc_x2, + (unsigned char *)&oc_x2, CORBA_B_FALSE); +CORBA_TypeCode_ptr _tc_test1_x2 = &tc_x2; + + +// +// parameter, exception, and call descriptions for "test_throw" +// +static const paramdata test1_test_throw_paramdata [1] = { + { _tc_CORBA_Long, PARAM_IN, 0 } +}; + +static CORBA_TypeCode_ptr test1_test_throw_excepts [2] = { + &tc_x1, &tc_x2 +}; + +extern const calldata test1_test_throw_calldata; + +const calldata test1_test_throw_calldata = { + "test_throw", CORBA_B_TRUE, + 1, &test1_test_throw_paramdata [0], + 2, &test1_test_throw_excepts [0] +}; + +// +// "test_throw" stub +// +void +test1_test_throw ( + test1_ptr target, + CORBA_Long case_num, + CORBA_Environment &env // throw (x1, x2) +) +{ + STUB_Object *data; + + if (target->QueryInterface (IID_STUB_Object, (void **)&data) + != NOERROR) + env.exception (new CORBA_INV_OBJREF (COMPLETED_NO)); + else { + data->do_call (env, &test1_test_throw_calldata, + &case_num); + data->Release (); + } +} + +// +// PLEASE EXIT +// + +static const calldata test1_please_exit_calldata = { + "please_exit", CORBA_B_FALSE, + 0, 0, + 0, 0 +}; + +void +test1_please_exit ( + test1_ptr target, + CORBA_Environment &env +) +{ + STUB_Object *data; + + if (target->QueryInterface (IID_STUB_Object, (void **)&data) + != NOERROR) + env.exception (new CORBA_INV_OBJREF (COMPLETED_NO)); + else { + data->do_call (env, &test1_please_exit_calldata + ); + data->Release (); + } +} + diff --git a/TAO/IIOP/test/test1.hh b/TAO/IIOP/test/test1.hh new file mode 100644 index 00000000000..3d5f2fed7bb --- /dev/null +++ b/TAO/IIOP/test/test1.hh @@ -0,0 +1,124 @@ +// @(#)test1.hh 1.2 95/09/12 +// Copyright 1995 by Sun Microsystems, Inc. +// All Rights Reserved +// +// TEST interface for "test1" +// + +#ifndef _TEST1_HH +#define _TEST1_HH + +#include <corba/orb.hh> +#include <corba/stub.hh> + + +#ifdef _MSC_VER +#pragma pack (push, 1) // VC++, known padding rules +#endif // VC++ + +typedef CORBA_UShort test1_ushort; +typedef CORBA_ULong test1_ulong; + +typedef CORBA_LongLong test1_longlong; +typedef CORBA_ULongLong test1_ulonglong; +typedef CORBA_LongDouble test1_longdouble; + +typedef CORBA_Object test1; +typedef test1 *test1_ptr; + +#define DECL_TEST(typename, truetype) \ + truetype \ + test1_test_ ## typename ( \ + test1_ptr target, \ + truetype in_a1, \ + truetype &out_a2, \ + truetype &inout_a3, \ + CORBA_Environment &env \ + ) + +void test_illegal (test1_ptr target, CORBA_Environment &env); +void test1_test_void (test1_ptr target, CORBA_Environment &env); + +DECL_TEST (short, CORBA_Short); +DECL_TEST (long, CORBA_Long); +DECL_TEST (ushort, CORBA_UShort); +DECL_TEST (ulong, CORBA_ULong); +DECL_TEST (float, CORBA_Float); +DECL_TEST (double, CORBA_Double); +DECL_TEST (boolean, CORBA_Boolean); +DECL_TEST (char, CORBA_Char); +DECL_TEST (octet, CORBA_Octet); + +CORBA_Any * +test1_test_any ( + test1_ptr target, + const CORBA_Any &in_a1, + CORBA_Any *&out_a2, + CORBA_Any &inout_a3, + CORBA_Environment &env +); + +DECL_TEST (TypeCode, CORBA_TypeCode_ptr); +DECL_TEST (Principal, CORBA_Principal_ptr); +DECL_TEST (Object, CORBA_Object_ptr); + +// NOTE: CORBA C++ mapping says the "in" string is const +DECL_TEST (string, CORBA_String); + +DECL_TEST (longlong, CORBA_LongLong); +DECL_TEST (ulonglong, CORBA_ULongLong); +DECL_TEST (wchar, CORBA_WChar); + +// NOTE: CORBA C++ mapping says the "in" string is const +DECL_TEST (wstring, CORBA_WString); + +DECL_TEST (longdouble, CORBA_LongDouble); + +#undef DECL_TEST + +extern CORBA_TypeCode_ptr _tc_test1_x1; + +class test1_x1 : public CORBA_UserException { + public: + CORBA_Long case_num; + + test1_x1 (CORBA_Long n) + : CORBA_UserException (_tc_test1_x1), case_num (n) + { } +}; + +extern CORBA_TypeCode_ptr _tc_test1_x2; + +class test1_x2 : public CORBA_UserException { + public: + CORBA_Object_ptr obj; + CORBA_Long case_num; + + test1_x2 (CORBA_Object_ptr obj1, + CORBA_Long n) + : CORBA_UserException (_tc_test1_x2), + obj (obj1), case_num (n) { } + + ~test1_x2 () + { CORBA_release (obj); } +}; + +void +test1_test_throw ( + test1_ptr target, + CORBA_Long case_num, + CORBA_Environment &env // throw (x1, x2) +); + +void +test1_please_exit ( + test1_ptr target, + CORBA_Environment &env +); + +#ifdef _MSC_VER +#pragma pack (pop) // VC++, go back to other padding rules +#endif // VC++ + +#endif // _TEST1_HH + diff --git a/TAO/IIOP/test/test1.idl b/TAO/IIOP/test/test1.idl new file mode 100644 index 00000000000..e6cf20cd2de --- /dev/null +++ b/TAO/IIOP/test/test1.idl @@ -0,0 +1,78 @@ +// @(#)test1.idl 1.1 95/09/11 +// Copyright 1994-1995 by Sun Microsystems, Inc. +// +// TEST basic marshaling tests for all IDL primitive types, modes +// +// This test omits constructed types (struct, union, enum, sequence, and +// array types), and only tests very simple user defined exceptions. +// +// Values returned are well defined functions of the input values: +// +// * For numeric types (octet, short, long, longlong, float, double, +// longdouble, and unsigned variants) the value is cubed. +// * For Boolean, it's the negation. +// * For Any, TypeCode, Principal, Object, char and wchar, +// string and wstring, it's the input value. +// +// The "return" and "out" parameter is the function of the "in" parameter; +// the "inout" parameter is the function of its original value. +// +// The "echo" test has all output values be the input values, with no +// changes to the bit patterns originally transmitted. While easier to +// use to identify some kinds of problem, it is not as complete a test. +// + +#define DECL_TEST(type) \ + type test_ ## type ( in type a1, out type a2, inout type a3) + +#pragma prefix "Eng.SUN.COM" // only for Sun-defined interfaces + +interface test1 { + void test_void (); + + typedef unsigned short ushort; + typedef unsigned long ulong; + + typedef long long longlong; + typedef unsigned long long ulonglong; + typedef long double longdouble; + + DECL_TEST (short); + DECL_TEST (long); + DECL_TEST (ushort); + DECL_TEST (ulong); + DECL_TEST (float); + DECL_TEST (double); + DECL_TEST (boolean); + DECL_TEST (char); + DECL_TEST (octet); + DECL_TEST (any); + DECL_TEST (TypeCode); + DECL_TEST (Principal); + DECL_TEST (Object); // CORBA::Object + DECL_TEST (string); // unbounded string + + DECL_TEST (longlong); + DECL_TEST (ulonglong); + DECL_TEST (wchar); + DECL_TEST (wstring); // unbounded wstring + DECL_TEST (longdouble); + + // + // All cases, "case_num" in the exception is the same as the 'in' param + // * negative or zero, throws x1 + // * positive even cases, throws x2 with obj = null objref + // * positive odd cases, throws x2 with obj = target objref + // + exception x1 { long case_num; }; + exception x2 { Object obj; long case_num; }; + + void test_throw (in long case_num) raises (x1, x2); + + // + // Aid for test cleanup in case server's not told to quit after + // being idle for some time period + // + oneway void please_exit (); +}; + diff --git a/TAO/IIOP/test/test1_clnt.cpp b/TAO/IIOP/test/test1_clnt.cpp new file mode 100644 index 00000000000..53a0c504580 --- /dev/null +++ b/TAO/IIOP/test/test1_clnt.cpp @@ -0,0 +1,636 @@ +// @(#)test1_clnt.cpp 1.5 95/09/24 +// Copyright 1995 by Sun Microsystems, Inc. +// All Rights Reserved +// +// TEST client driver for "test1" +// + +#ifdef USE_IOSTREAM +#include <iostream.h> +#endif + +#include <stdio.h> +#include <string.h> + +#if unix +# include <unistd.h> + +#else // windows +# include "getopt.h" // e.g. GNU's version + +#endif // unix + +#include "test1.hh" +#include "../lib/runtime/debug.hh" + + +extern char *optarg; // missing on some platforms + +extern void +print_exception (const CORBA_Exception *, const char *, FILE *f=stdout); + + +// +// All tests are specified so that the return value and "out" (second) +// parameters are easily tested functions of the "in" (first) parameter, +// and the "inout" (third) parameter is the same function the its +// initial value. Caller is expected to specify two different "in" +// values. This helps make the marshaled bits vary, and turn up a class +// of potential problems that'd be hidden if parameter order had no +// effect on the test. +// +// PERFORM_TEST calls a test for a given type, reporting in cases where +// the ORB or operation failed. The COMPARE symbol can be redefined +// to achieve different functions -- e.g. cubing numbers, identity, +// negation, etc. It should return true iff the correct result was +// returned. +// +// BAD_COMPARE_VALUES is to produce diagnostics when a test fails, +// showing the actual and expected values of returned parameters. +// This helps diagnose specific porting problems. +// +// The RELEASE symbol may be defined to free memory, eliminating client +// side memory leaks in the test. +// +#define RELEASE(X) // NOP by default +#define PERFORM_TEST(name,type,value1,value2) \ + { \ + CORBA_ ## type v1, v2, v3; \ + \ + v1 = (CORBA_ ## type)(value1); \ + v2 = 0; \ + v3 = (CORBA_ ## type)(value2); \ + \ + test_count++; \ + v1 = test1_test_ ## name (target, v1, v2, v3, env); \ + if (env.exception () != 0) { \ + print_exception (env.exception (), "perform test_" #name); \ + error_count++; \ + } else if (!COMPARE (CORBA_ ## type, v1, value1) \ + || !COMPARE (CORBA_ ## type, v2, value1) \ + || !COMPARE (CORBA_ ## type, v3, value2) ) { \ + fprintf (stderr, "bad comparison, test_" #name "\n"); \ + BAD_COMPARE_VALUES(type,v1,v2,v3,value1,value2) \ + error_count++; \ + } \ + RELEASE (v1); RELEASE (v2); RELEASE (v3); \ + } + +// +// This messing about is because the ostream op << cannot always +// be used with all kinds of data ... e.g. LongDouble, TypeCode. +// +#ifdef USE_IOSTREAM +# define DO_IO(x) x +#else +# define DO_IO(x) +#endif +#define BAD_COMPARE_VALUE_OUT(type,v1,v2,v3,value1,value2) \ + DO_IO( cerr << " v1=" << v1; \ + cerr << " expecting " << EXPVAL(CORBA_ ## type, value1) << "\n"; \ + cerr << " v2=" << v2; \ + cerr << " expecting " << EXPVAL(CORBA_ ## type, value1) << "\n"; \ + cerr << " v3=" << v3; \ + cerr << " expecting " << EXPVAL(CORBA_ ## type, value2) << "\n"); +#define BAD_COMPARE_VALUES(type,v1,v2,v3,value1,value2) \ + BAD_COMPARE_VALUE_OUT(type,v1,v2,v3,value1,value2) + + +// +// test utility -- should be able to just use is_equivalent() directly +// but this implementation uses null pointers for nil, so this must +// check for nulls first. (May be noncompliant with C++ mapping!) +// +static CORBA_Boolean +compare_objrefs ( + CORBA_Object_ptr v1, + CORBA_Object_ptr v2 +) +{ + CORBA_Boolean temp; + CORBA_Environment env; + + if (v1 == v2) + return CORBA_B_TRUE; + + if (CORBA_is_nil (v1)) + return CORBA_is_nil (v2); + + temp = v1->_is_equivalent (v2, env); + if (env.exception () != 0) { + print_exception (env.exception (), "compare objref"); + return CORBA_B_FALSE; + } + return temp; +} + + +// +// Helper routine to help sure math (especially for floating point) +// gets done correctly. +// +template <class Type> +Type cube (Type arg) +{ + Type temp = arg; + + temp = temp * arg; + temp = temp * arg; + return temp; +} + + +static int skip_longdouble = 0; + +// +// This just performs the tests ... +// +void +do_tests ( + test1_ptr target, + unsigned loop_count, + unsigned &test_count, + unsigned &error_count +) +{ + int count; + + for (count = 0; count < loop_count; count++) { + CORBA_Environment env; + CORBA_Environment env2; // XXX + + // + // test_void + // + test_count++; + test1_test_void (target, env); + if (env.exception () != 0) { + print_exception (env.exception (), "perform test_void"); + error_count++; + } + + // + // Numeric tests ... try some variety in computation, no real + // rationale in the choice of initial parameter values except + // not to use the same values all the time. + // +#define EXPVAL(type,original_value) ((type) cube((type)(original_value))) +#define COMPARE(type,retval,original_value) \ + ((retval) == EXPVAL(type, original_value)) + + PERFORM_TEST (octet, Octet, count + 29, count - 22); + + PERFORM_TEST (short, Short, count - 23, count + 19); + PERFORM_TEST (ushort, UShort, count + 23, count - 19); + + PERFORM_TEST (long, Long, count - 17, count + 20); + PERFORM_TEST (ulong, ULong, count + 17, count - 20); + +#if !defined (NONNATIVE_LONGLONG) + // don't try this on platforms that don't support + // math on longlongs ... + PERFORM_TEST (longlong, LongLong, count - 177, count + 3); + PERFORM_TEST (ulonglong, ULongLong, count + 177, count - 3); +#endif // !NONNATIVE_LONGLONG + +#if !defined (i386) + // + // XXX not sure what's wrong with the COMPARE macro with respect to + // floating point on x86, since fprintf shows the values basically + // look correct ... but these float/double tests fail. + // + PERFORM_TEST (float, Float, count - 0.29, count + 3.14159); + PERFORM_TEST (double, Double, count * 1.77, count * 2.71); +#endif // !defined (i386) + + +#ifndef NONNATIVE_LONGDOUBLE +#undef BAD_COMPARE_VALUES +#define BAD_COMPARE_VALUES(type,v1,v2,v3,value1,value2) // NOP + + // + // don't try this between two platforms that don't provide + // arithmetic support for LongDouble values ... + // + if (!skip_longdouble) { + PERFORM_TEST (longdouble, LongDouble, + count - 2.33, count * 3.14159); + } + +# undef BAD_COMPARE_VALUES +# define BAD_COMPARE_VALUES(type,v1,v2,v3,value1,value2) \ + BAD_COMPARE_VALUE_OUT(type,v1,v2,v3,value1,value2) +#endif // !NONNATIVE_LONGDOUBLE + +#undef COMPARE +#undef EXPVAL + + + // + // Boolean -- negation + // +#define EXPVAL(type,original_value) (!(type)(original_value)) +#define COMPARE(type,retval,original_value) \ + (((type)(retval)) == EXPVAL(type,original_value)) + + PERFORM_TEST (boolean, Boolean, + (count & 0x01) != 0, (count & 0x01) == 0); +#undef COMPARE +#undef EXPVAL + + // + // Char, WChar -- identity + // +#define EXPVAL(type,original_value) ((type)(original_value)) +#define COMPARE(type,retval,original_value) \ + (((type)(retval)) == EXPVAL(type,original_value)) + + PERFORM_TEST (char, Char, count + 26, count - 5); + PERFORM_TEST (wchar, WChar, count, count + 25); +#undef COMPARE +#undef EXPVAL + + // + // Object_ptr -- identity (special comparision) + // +#define EXPVAL(type,original_value) ((type)(original_value)) +#define COMPARE(type,retval,original_value) \ + (compare_objrefs (retval, original_value) == CORBA_B_TRUE) +#undef RELEASE +#define RELEASE(obj) \ + { CORBA_release (obj); } + + PERFORM_TEST (Object, Object_ptr, target, CORBA_Object::_nil ()); +#undef COMPARE +#undef EXPVAL + + // + // TypeCode_ptr -- identity (special comparision), and verifies + // that most of the built-in typecode constants exist. + // + // XXX should try this on all standard and system exceptions! + // + // XXX this currently tests only marshaling/unmarshaling of + // "no parameter" TypeCodes ... complex ones (objref, struct, + // union, enum, sequence, array, alias, exception) are _NOT_ + // currently attempted. + // + // XXX for the simple typecodes (string, wstring), the single + // "bound" parameter isn't exercised/verified as it should be. + // +#define EXPVAL(type,original_value) ((type)(original_value)) +#define COMPARE(type,retval,original) \ + (((retval) == (original)) || \ + ((retval)->_kind == (original)->_kind)) + +#undef RELEASE +#define RELEASE(tc) \ + { CORBA_release (tc); } + +#undef BAD_COMPARE_VALUES +#define BAD_COMPARE_VALUES(type,v1,v2,v3,value1,value2) // NOP + + { + PERFORM_TEST (TypeCode, TypeCode_ptr, + _tc_CORBA_Null, _tc_CORBA_Void); + + PERFORM_TEST (TypeCode, TypeCode_ptr, + _tc_CORBA_Short, _tc_CORBA_UShort); + PERFORM_TEST (TypeCode, TypeCode_ptr, + _tc_CORBA_Long, _tc_CORBA_ULong); + PERFORM_TEST (TypeCode, TypeCode_ptr, + _tc_CORBA_LongLong, _tc_CORBA_ULongLong); + + PERFORM_TEST (TypeCode, TypeCode_ptr, + _tc_CORBA_Float, _tc_CORBA_Double); + + PERFORM_TEST (TypeCode, TypeCode_ptr, + _tc_CORBA_Boolean, _tc_CORBA_Octet); + + PERFORM_TEST (TypeCode, TypeCode_ptr, + _tc_CORBA_Any, _tc_CORBA_TypeCode); + + PERFORM_TEST (TypeCode, TypeCode_ptr, + _tc_CORBA_LongDouble, _tc_CORBA_Principal); + + PERFORM_TEST (TypeCode, TypeCode_ptr, + _tc_CORBA_Char, _tc_CORBA_String); + PERFORM_TEST (TypeCode, TypeCode_ptr, + _tc_CORBA_WChar, _tc_CORBA_WString); + + PERFORM_TEST (TypeCode, TypeCode_ptr, + _tc_CORBA_LongDouble, _tc_CORBA_Octet); + + // + // Try all of the standard exception typecodes. + // + PERFORM_TEST (TypeCode, TypeCode_ptr, + _tc_CORBA_UNKNOWN, _tc_CORBA_BAD_PARAM); + PERFORM_TEST (TypeCode, TypeCode_ptr, + _tc_CORBA_NO_MEMORY, _tc_CORBA_IMP_LIMIT); + PERFORM_TEST (TypeCode, TypeCode_ptr, + _tc_CORBA_COMM_FAILURE, _tc_CORBA_INV_OBJREF); + PERFORM_TEST (TypeCode, TypeCode_ptr, + _tc_CORBA_OBJECT_NOT_EXIST, _tc_CORBA_NO_PERMISSION); + PERFORM_TEST (TypeCode, TypeCode_ptr, + _tc_CORBA_INTERNAL, _tc_CORBA_MARSHAL); + PERFORM_TEST (TypeCode, TypeCode_ptr, + _tc_CORBA_INITIALIZE, _tc_CORBA_NO_IMPLEMENT); + PERFORM_TEST (TypeCode, TypeCode_ptr, + _tc_CORBA_BAD_TYPECODE, _tc_CORBA_BAD_OPERATION); + PERFORM_TEST (TypeCode, TypeCode_ptr, + _tc_CORBA_NO_RESOURCES, _tc_CORBA_NO_RESPONSE); + PERFORM_TEST (TypeCode, TypeCode_ptr, + _tc_CORBA_PERSIST_STORE, _tc_CORBA_BAD_INV_ORDER); + PERFORM_TEST (TypeCode, TypeCode_ptr, + _tc_CORBA_TRANSIENT, _tc_CORBA_FREE_MEM); + PERFORM_TEST (TypeCode, TypeCode_ptr, + _tc_CORBA_INV_IDENT, _tc_CORBA_INV_FLAG); + PERFORM_TEST (TypeCode, TypeCode_ptr, + _tc_CORBA_INTF_REPOS, _tc_CORBA_BAD_CONTEXT); + PERFORM_TEST (TypeCode, TypeCode_ptr, + _tc_CORBA_OBJ_ADAPTER, _tc_CORBA_DATA_CONVERSION); + + // + // All the built-in "user defined" system exceptions. + // + PERFORM_TEST (TypeCode, TypeCode_ptr, + _tc_CORBA_BadKind, _tc_CORBA_Bounds); + } +#undef COMPARE +#undef RELEASE + + // + // string (unbounded)-- identity (special comparision) + // +#define COMPARE(type,retval,original_value) \ + (strcmp ((char *)(retval), (char*)(original_value)) == 0) +#undef RELEASE +#define RELEASE(obj) CORBA_string_free(obj) + static const CORBA_Char str1 [] = "small"; + static const CORBA_Char str2 [] = + "relatively long string, constructed" + " with the aid of C++ implicit string" + " catenation, which simplifies much stuff"; + PERFORM_TEST (string, String, str1, str2); +#undef COMPARE +#undef RELEASE + + + // XXX any, principal, wstring ... output _is_ input + + + // + // Three test cases involve throwing user-defined exceptions. + // + { + CORBA_Exception *xp; + + // + // Case one: with parameter <= zero, must throw + // an "x1" exception whose "case_num" is that parameter + // + test_count++; + + test1_test_throw (target, -5, env); + if (env.exception () != 0) { + xp = env.exception (); + + if (strcmp ((char *)xp->id (), + (char *) _tc_test1_x1->id (env2)) != 0) { + error_count++; + fprintf (stderr, "test_throw case 1, " + "wrong exception thrown (id = '%s')\n", + xp->id ()); + } else { + test1_x1 *xp2 = (test1_x1 *) xp; + + if (xp2->case_num != -5) { + error_count++; + fprintf (stderr, "test_throw case 1, " + "wrong value (case_num = '%ld')\n", + xp2->case_num); + } + + // else, right exception was thrown + } + } else { + error_count++; + fprintf (stderr, "test_throw case 1, " + "no exception thrown !!\n"); + } + + + // + // Case two: with positive odd parameter, must throw + // an "x2" exception whose obj is null, and whose case_num + // is that parameter + // + test_count++; + + test1_test_throw (target, 101, env); + if (env.exception () != 0) { + xp = env.exception (); + + if (strcmp ((char *)xp->id (), + (char *) _tc_test1_x2->id (env2)) != 0) { + error_count++; + fprintf (stderr, "test_throw case 2, " + "wrong exception thrown (id = '%s')\n", + xp->id ()); + } else { + test1_x2 *xp2 = (test1_x2 *) xp; + + if (xp2->case_num != 101) { + error_count++; + fprintf (stderr, "test_throw case 2, " + "wrong value (case_num = '%ld')\n", + xp2->case_num); + } + + if (!CORBA_is_nil (xp2->obj)) { + error_count++; + fprintf (stderr, "test_throw case 2, " + "non-null objref thrown\n"); + } + + // else, right exception was thrown + } + } else { + error_count++; + fprintf (stderr, "test_throw case 2, " + "no exception thrown !!\n"); + } + + +#if 0 +// 18-sept-95: commented this out. Work remains to be done in +// this area: (a) ServerRequest::target operation unimplemented, +// so for the servers of current interest this test is no help; +// (b) probable pointer leak in exceptions holding data. + + // + // Case three: with positive even parameter, must throw + // an "x2" exception whose obj is the target, and whose + // case_num is that parameter + // + test_count++; + + test1_test_throw (target, 42, env); + if (env.exception () != 0) { + xp = env.exception (); + + if (strcmp ((char *)xp->id (), + (char *) _tc_test1_x2->id (env2)) != 0) { + error_count++; + fprintf (stderr, "test_throw case 3, " + "wrong exception thrown (id = '%s')\n", + xp->id ()); + } else { + test1_x2 *xp2 = (test1_x2 *) xp; + + if (xp2->case_num != 42) { + error_count++; + fprintf (stderr, "test_throw case 3, " + "wrong value (case_num = '%ld')\n", + xp2->case_num); + } + + CORBA_Boolean status; + + status = target->_is_equivalent (xp2->obj, env); + + if (env.exception () != 0) { + error_count++; + print_exception (env.exception (), + "test_throw/3 call to is_equivalent"); + } else if (status != CORBA_B_TRUE) { + error_count++; + fprintf (stderr, "test_throw case 3, " + "non-equivalent objref thrown\n"); + } + + // else, right exception was thrown + } + } else { + error_count++; + fprintf (stderr, "test_throw case 3, " + "no exception thrown !!\n"); + } + + env.clear (); +#endif // 0 + + } + + // + // test_illegal -- generate a BAD_OPERATION system exception + // from the remote process + // + test_count++; + test_illegal (target, env); + if (env.exception () == 0 + || strcmp ((char *) env.exception()->id(), + (char *) _tc_CORBA_BAD_OPERATION->id (env2)) != 0) { + fprintf (stderr, "couldn't generate BAD_OPERATION exception\n"); + error_count++; + } + } +} + + +int +main ( + int argc, + char *const *argv +) +{ + CORBA_ORB_ptr orb_ptr; + CORBA_Environment env; + CORBA_Object_ptr objref = CORBA_Object::_nil(); + unsigned loop_count = 1; + unsigned tests = 0, errors = 0; + int exit_later = 0; + + orb_ptr = CORBA_ORB_init (argc, argv, "internet", env); + if (env.exception () != 0) { + dexc (env, "ORB initialisation"); + return 1; + } + + // + // Parse and verify parameters. + // + int c; + + while ((c = getopt (argc, argv, "dln:O:x")) != EOF) + switch (c) { + case 'd': // debug flag + debug_level++; + continue; + + case 'l': // skip "long double" test + skip_longdouble++; + continue; + + case 'n': // loop count + loop_count = (unsigned) atoi (optarg); + continue; + + case 'O': // stringified objref + { + objref = orb_ptr->string_to_object ( + (CORBA_String)optarg, env); + if (env.exception () != 0) { + dexc (env, "string2object"); + return 1; + } + } + continue; + + case 'x': + exit_later++; + continue; + + case '?': + default: + fprintf (stderr, "usage: %s" + " [-d]" + " [-l]" + " [-n loopcount]" + " [-O objref]" + " [-x]" + "\n", argv [0] + ); + return 1; + } + + if (CORBA_is_nil (objref) == CORBA_B_TRUE) { + fprintf (stderr, "%s: must identify non-null target objref\n", + argv [0]); + return 1; + } + + + do_tests (objref, loop_count, tests, errors); + + char *progname = strrchr (argv [0], '/'); + + if (progname != 0) + progname += 1; + else + progname = argv [0]; + + fprintf (stderr, "%s: %d loops, %d tests (%d errors)\n", + progname, loop_count, tests, errors); + + if (exit_later) { + test1_please_exit (objref, env); + if (env.exception () != 0) + print_exception (env.exception (), "test1_please_exit"); + } + + CORBA_release (objref); + + return errors != 0; +} diff --git a/TAO/IIOP/test/test1_svr.cpp b/TAO/IIOP/test/test1_svr.cpp new file mode 100644 index 00000000000..668fbae2afc --- /dev/null +++ b/TAO/IIOP/test/test1_svr.cpp @@ -0,0 +1,644 @@ +// @(#)test1_svr.cpp 1.7 95/09/25 +// Copyright 1995 by Sun Microsystems Inc. +// All Rights Reserved +// +// TEST: simple IIOP server for "test1.idl" interface. +// +// Starts up, builds an objref, prints its string, listens for +// messages, responds to them. +// + +#include <stdio.h> +#include <string.h> + +#if unix +# include <unistd.h> // for getopt on some systems + +#else // windows +# include "getopt.h" // e.g. GNU's version + +#endif + +#include "test1.hh" +#include <corba/toa.hh> + +#include "../lib/runtime/debug.hh" + + + +extern char *optarg; // missing on some platforms + +// +// Skeleton code ... just a macro for a bunch of DSI-based method code, +// in lieu of having an IDL compmiler generate static skeletons. Static +// skeletons would be more efficient; most mallocation could go away. +// +// Use by: defining OPERATION macro, call DEFINE_SKEL3 as needed, then +// undef OPERATION. +// +// NOTE: "v1_copy" below is needed to work around a bug with the +// HP9000 G++ 2.6.3 compiler, with "LongLong". +// +// XXX this could probably be a template ... or could even be merged +// directly into the Dynamic Implementation Routine below. +// +// XXX we must currently use IN_COPY_VALUE since the memory consumed +// by the parameters must be deallocated by the ORB. When we get an +// updated version of DSI which provides "send it now" semantics, +// these should preallocate the values and not use IN_COPY_VALUE. A +// net decrease in malloc overhead can be had that way. (NVList should +// also get a public constructor, and a way to provide the buffer.) +// +#define DEFINE_SKEL3(name,truetype,truetypename) \ + static void \ + _test1_test_ ## name ( \ + CORBA_ServerRequest &req, \ + CORBA_Environment &env \ + ) \ + { \ + CORBA_NVList_ptr nvlist; \ + CORBA_ ## truetype scratch = 0; \ + CORBA_Any temp_value (_tc_CORBA_ ## truetypename, \ + &scratch, CORBA_B_FALSE); \ + \ + req.orb ()->create_list (3, nvlist); \ + (void) nvlist->add_value (0, temp_value, \ + CORBA_IN_COPY_VALUE|CORBA_ARG_IN, env); \ + (void) nvlist->add_value (0, temp_value, \ + CORBA_IN_COPY_VALUE|CORBA_ARG_OUT, env); \ + (void) nvlist->add_value (0, temp_value, \ + CORBA_IN_COPY_VALUE|CORBA_ARG_INOUT, env); \ + \ + req.params (nvlist, env); \ + if (env.exception () != 0) { \ + dexc (env, "test1_test_" # name "skeleton, req.params"); \ + return; \ + } \ + \ + CORBA_ ## truetype *v1, *v2, *retval; \ + \ + v1 = (CORBA_ ## truetype *) nvlist->item (0)->value ()->value (); \ + v2 = new CORBA_ ## truetype; \ + *v2 = (CORBA_ ## truetype) OPERATION (*v1); \ + retval = new CORBA_ ## truetype; \ + *retval = (CORBA_ ## truetype) OPERATION (*v1); \ + \ + CORBA_Any_ptr any_val; \ + \ + any_val = nvlist->item (1)->value (); \ + any_val->replace (any_val->type (), v2, CORBA_B_TRUE, env); \ + if (env.exception () != 0) { \ + dexc (env, "test1_test_" # name "skeleton, val2 replace"); \ + return; \ + } \ + \ + v1 = (CORBA_ ## truetype *) nvlist->item (2)->value ()->value (); \ + CORBA_ ## truetype v1copy = *v1; \ + *v1 = (CORBA_ ## truetype) OPERATION (v1copy); \ + \ + any_val = new CORBA_Any (_tc_CORBA_ ## truetypename, \ + retval, CORBA_B_TRUE); \ + req.result (any_val, env); \ + if (env.exception () != 0) { \ + dexc (env, "test1_test_" # name "skeleton, result"); \ + return; \ + } \ + } \ + extern calldata test1_ ## name ## _calldata; + + +extern const calldata test1_void_calldata; + +static void +_test1_test_void ( + CORBA_ServerRequest &req, + CORBA_Environment &env +) +{ + CORBA_NVList_ptr nvlist; + + req.orb ()->create_list (0, nvlist); + req.params (nvlist, env); + + if (env.exception () != 0) + dexc (env, "test_throw, get params"); +} + + +// +// Dynamic Skeleton methods for numeric types ... these all just +// cube their parameters in various permutations +// +template <class Type> +Type cube (Type arg) +{ + Type temp = arg; + + temp = temp * arg; + temp = temp * arg; + return temp; +} + +#define OPERATION(n) cube(n) + +DEFINE_SKEL3 (octet, Octet, Octet) + +DEFINE_SKEL3 (short, Short, Short) +DEFINE_SKEL3 (ushort, UShort, UShort) + +DEFINE_SKEL3 (long, Long, Long) +DEFINE_SKEL3 (ulong, ULong, ULong) + +#if !defined (NONNATIVE_LONGLONG) + // don't try this on platforms that don't support + // math on longlongs ... +DEFINE_SKEL3 (longlong, LongLong, LongLong) +DEFINE_SKEL3 (ulonglong, ULongLong, ULongLong) +#endif // !NONNATIVE_LONGLONG + +DEFINE_SKEL3 (float, Float, Float) +DEFINE_SKEL3 (double, Double, Double) + +#if !defined (NONNATIVE_LONGDOUBLE) + // don't try this on platforms that don't support + // math on long doubles ... +DEFINE_SKEL3 (longdouble, LongDouble, LongDouble) +#endif // !NONNATIVE_LONGDOUBLE + +#undef OPERATION + +// +// Dynamic Skeleton methods for Boolean type ... just negates its +// parameters +// +#define OPERATION(x) (!(x)) +DEFINE_SKEL3 (boolean, Boolean, Boolean) +#undef OPERATION + +// +// For character types, output is same as input, no magic needed. +// +#define OPERATION(x) (x) +DEFINE_SKEL3 (char, Char, Char) +DEFINE_SKEL3 (wchar, WChar, WChar) +#undef OPERATION + +// +// For objref, typecode, output is same as input but duplication +// is needed +// +#define OPERATION(x) ((x) ? (x)->AddRef() : 0, x) +DEFINE_SKEL3 (Object, Object_ptr, Object) +DEFINE_SKEL3 (TypeCode, TypeCode_ptr, TypeCode) +#undef OPERATION + +// +// For string, output is copy of input +// +#define OPERATION(x) (CORBA_string_copy(x)) +DEFINE_SKEL3 (string, String, String) +#undef OPERATION + +// +// For wstring, output is copy of input +// +#define OPERATION(x) (CORBA_wstring_copy(x)) +DEFINE_SKEL3 (wstring, WString, WString) +#undef OPERATION + +// +// XXX IMPLEMENT THE REST OF THE DATA TYPES +// +// any, principal -- out is in +// + + +// +// All cases, "case_num" in the exception is the same as the 'in' param +// * negative or zero, throws x1 +// * positive even cases, throws x2 with obj = null objref +// * positive odd cases, throws x2 with obj = target objref +// +// exception x1 { long case_num; }; +// exception x2 { Object obj; long case_num; }; +// +// void test_throw (in long case_num) raises (x1, x2); +// + +extern const calldata test1_test_throw_calldata; + +static void +_test1_test_throw ( + CORBA_ServerRequest &req, + CORBA_Environment &env +) +{ + CORBA_NVList_ptr nvlist; + CORBA_NamedValue_ptr nv; + CORBA_Any temp_value (_tc_CORBA_Long); + CORBA_Long value; + + req.orb ()->create_list (0, nvlist); + nv = nvlist->add_value (0, temp_value, CORBA_ARG_IN, env); + + req.params (nvlist, env); + if (env.exception () != 0) { + dexc (env, "test_throw, get params"); + return; + } + + value = *(CORBA_Long *)nv->value ()->value (); + if (env.exception () != 0) { + dexc (env, "test_throw, param value"); + return; + } + + CORBA_Any_ptr any; + + if (value <= 0) { + test1_x1 *x; + + x = new test1_x1 (value); + any = new CORBA_Any (_tc_test1_x1, x, CORBA_B_TRUE); + + } else if (value & 0x01) { + test1_x2 *x; + + x = new test1_x2 (CORBA_Object::_nil (), value); + any = new CORBA_Any (_tc_test1_x2, x, CORBA_B_TRUE); + + } else { +#if 0 + test1_x2 *x; + + x = new test1_x2 (req.oa()->target (), value); + any = new CORBA_Any (_tc_test1_x2, x, CORBA_B_TRUE); +#else + // + // XXX right now, we don't have a target() operation on the + // TOA ... needs to be added. Verify the client side memory + // leak of pointers embedded in user exceptions is fixed, too. + // + env.exception (new CORBA_IMP_LIMIT (COMPLETED_NO)); + return; +#endif + } + + req.exception (USER_EXCEPTION, any, env); +} + + +// +// This table is used to associate operation names with the Dynamic +// Skeleton method ... someday it could return static skeletons. +// +#define DECL_SKEL(name) \ + { & test1_ ## name ## _calldata, _test1_test_ ## name } + +static const skel_entry test1_operations [] = { + DECL_SKEL (void), + + DECL_SKEL (octet), + DECL_SKEL (char), + + DECL_SKEL (wchar), + + DECL_SKEL (short), + DECL_SKEL (ushort), + DECL_SKEL (long), + DECL_SKEL (ulong), + +#if !defined (NONNATIVE_LONGLONG) + // don't try this on platforms that don't support + // math on longlongs ... + DECL_SKEL (longlong), + DECL_SKEL (ulonglong), +#endif + + DECL_SKEL (float), + DECL_SKEL (double), + +#if !defined (NONNATIVE_LONGDOUBLE) + // don't try this on platforms that don't support + // math on long doubles ... + DECL_SKEL (longdouble), +#endif // !NONNATIVE_LONGDOUBLE + + DECL_SKEL (boolean), + + DECL_SKEL (Object), + DECL_SKEL (TypeCode), + + DECL_SKEL (string), + DECL_SKEL (wstring), + + { & test1_test_throw_calldata, _test1_test_throw }, + + { 0, 0 } +}; + + +// +// Dispatch to method code ... +// +// Knows how to interpret "context" to get target objref, and where to +// get second level skeletons for that target. Both of those operations +// will generally be abstracted (into library and stub code) so the main +// body of this routine would be invisible to most applications. +// +// However, there are applications that need to do this stuff themselves +// (like bridging between environments, e.g. different ORBs, languages, or +// other object systems). Everything needed to work without using an IDL +// compiler is a public, supported API. +// +static void +level1_skeleton ( + CORBA_OctetSeq &key, + CORBA_ServerRequest &req, + void *context, + CORBA_Environment &env +) +{ + // + // Verify that the target object and "this" object have the + // same key. Normally, this would be used to figure out + // which object was the target, and hence which operations + // vector to dispatch the request. + // + CORBA_OctetSeq *obj_key; + + obj_key = (CORBA_OctetSeq *) context; + if (obj_key->length != key.length + || memcmp (obj_key->buffer, key.buffer, + obj_key->length) != 0) { + env.exception (new CORBA_OBJECT_NOT_EXIST (COMPLETED_NO)); +#ifdef DEBUG + if (debug_level) + dmsg_opaque ("request to nonexistent object, key = ", + key.buffer, key.length); +#endif + return; + } + + // + // Find a "level 2 skeleton" for this operation, then + // call it with the right per-object state. + // + const skel_entry *entry; + CORBA_String opname; + + opname = req.op_name (); + for (entry = &test1_operations [0]; entry->op_descriptor; entry++) { + if (strcmp ((char *)opname, entry->op_descriptor->opname) == 0) { + entry->impl_skeleton (req, env); + return; + } + } + + // + // XXX True top-level skeleton code would also have to understand + // the built-in operations: + // + // * _is_a (for narrowing tests) ... can be derived by searching an + // appropriately structured graph of level2 skeletons. + // + // * _non_existent ... if the level1 skeleton consults a module + // which understands object lifespans, this should be simple. + // + // * _get_interface ... could either (a) fail; (b) return the ref + // from some IFR; or most interestingly (c) return a ref to some + // code in this process that can answer all IFR queries from the + // skeleton data structures. + // + // * _get_implementation ... return some administrative hook to + // the object implementation: + // + // No other legal operations start with a character that's not an + // ASCII alphanumeric, for what it's worth. + // + // The skeleton might want to use data in the object key to find + // the objref's type; if it's integrated with object creation, and + // an per-process implementation repository, this should be easy. + // + + // + // bypass level 2 skeletons for this one ... + // + if (strcmp ((char *) opname, "please_exit") == 0) { + dmsg ("I've been asked to shut down..."); + req.oa ()->please_shutdown (env); + dexc (env, "please_exit, please_shutdown"); + return; + } + + // + // No match. Operation not implemented; say so. + // + dmsg1 ("unknown operation, %s", opname); + env.exception (new CORBA_BAD_OPERATION (COMPLETED_NO)); +} + + +// +// Create and print the objref, listen for calls on it until done. +// +extern void +print_exception (const CORBA_Exception *, const char *, FILE *f=stdout); + +int +OA_listen ( + CORBA_ORB_ptr orb_ptr, + TOA_ptr oa_ptr, + CORBA_String key, + int idle +) +{ + // + // Create the object we'll be implementing. + // + CORBA_OctetSeq obj_key; + CORBA_Object_ptr obj; + CORBA_Environment env; + + obj_key.buffer = (CORBA_Octet *) key; + obj_key.length = obj_key.maximum = strlen (key); + + obj = oa_ptr->create (obj_key, (CORBA_String) "", env); + if (env.exception () != 0) { + print_exception (env.exception (), "TOA::create"); + return 1; + } + + // + // Stringify the objref we'll be implementing, and + // print it to stdout. Someone will take that string + // and give it to some client. + // + CORBA_String str; + + str = orb_ptr->object_to_string (obj, env); + if (env.exception () != 0) { + print_exception (env.exception (), "object2string"); + return 1; + } + puts ((char *)str); + fflush (stdout); + dmsg1 ("listening as object '%s'", str); + + // + // Clean up -- "key" is sufficient to dispatch all requests. + // + CORBA_release (obj); + CORBA_string_free (str); + env.clear (); + + // + // Handle requests for this object until we're killed, or one of + // the methods makes us exit. + // + // NOTE: apart from registering the top level skeleton, the rest + // of this loop is exactly what TOA::run() does. It's here to + // show there's no magic. + // + oa_ptr->register_dir (level1_skeleton, &obj_key, env); + if (env.exception () != 0) { + print_exception (env.exception (), "register_dir"); + return 1; + } + + for (;;) { + if (idle == -1) + oa_ptr->get_request (CORBA_B_FALSE, 0, env); + else { + timeval tv; + + tv.tv_sec = idle; + tv.tv_usec = 0; + oa_ptr->get_request (CORBA_B_FALSE, &tv, env); + } + + CORBA_Exception_ptr xp; + + if ((xp = env.exception ()) != 0) { + CORBA_Environment env2; // XXX + char *id; + + id = env.exception ()->id (); + + // + // We get BAD_INV_ORDER if we call get_request() after + // shutdown was initiated. Simpler to rely on that + // than to arrange any handshaking in this simple app. + // + if (strcmp (id, _tc_CORBA_BAD_INV_ORDER->id (env2)) == 0) { + break; + + // + // Other exceptions are errors. + // + } else { + print_exception (env.exception (), "TOA::get_request"); + return 1; + } + } + env.clear (); + } + + // + // Shut down the OA -- recycles all underlying resources (e.g. file + // descriptors, etc). + // + // XXX shutdown is not quite the same as release, unless we want mem + // leaks to cause some rude failure modes. TOA just hasn't been + // updated yet to have any handshake about this though. + // + oa_ptr->Release (); + return 0; +} + + +// +// Standard command line parsing utilities used. +// +int +main ( + int argc, + char *const *argv +) +{ + CORBA_Environment env; + CORBA_ORB_ptr orb_ptr; + TOA_ptr oa_ptr; + CORBA_String key = (CORBA_String) "elvis"; + char *oa_name = 0; + char *orb_name = "internet"; + int idle = -1; + + // + // Parse the command line, get options + // + int c; + + while ((c = getopt (argc, argv, "di:k:o:p:")) != EOF) + switch (c) { + case 'd': // more debug noise + debug_level++; + continue; + + case 'i': // idle seconds b4 exit + idle = atoi (optarg); + continue; + + case 'k': // key (str) + key = (CORBA_String) optarg; + continue; + + case 'o': // orb name + orb_name = optarg; + continue; + + case 'p': // portnum + oa_name = optarg; + continue; + + // XXX set debug filters ... + + // + // XXX ignore OMG-specified options ... hope nobody ever tries + // to use that "-ORB* param" and "-OA* param" syntax, it flies + // in the face of standard command parsing algorithms which + // require single-character option specifiers. + // + + + case '?': + default: + fprintf (stderr, "usage: %s" + " [-d]" + " [-i idle_seconds]" + " [-k object_key=elvis]" + " [-o orbname=internet]" + " [-p oa_name]" + "\n", argv [0] + ); + return 1; + } + + orb_ptr = CORBA_ORB_init (argc, argv, orb_name, env); + if (env.exception () != 0) { + print_exception (env.exception (), "ORB init"); + return 1; + } + + // + // The TOA may or may not actually be named ... + // + oa_ptr = TOA::get_named_toa (orb_ptr, oa_name, env); + if (env.exception () != 0) { + print_exception (env.exception (), "OA init"); + return 1; + } + + return OA_listen (orb_ptr, oa_ptr, key, idle); +} + |