summaryrefslogtreecommitdiff
path: root/TAO/IIOP
diff options
context:
space:
mode:
authorsumedh <sumedh@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1997-02-17 00:09:24 +0000
committersumedh <sumedh@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1997-02-17 00:09:24 +0000
commitc685695d30d92cc376ab180641e5faf73cd2b8c1 (patch)
treea98ed952c2f465e5bdf9df6d02da29ba7899ad59 /TAO/IIOP
parentc80c06ac96191632bddc35badae5886a7171ec4e (diff)
downloadATCD-c685695d30d92cc376ab180641e5faf73cd2b8c1.tar.gz
Added IIOP files
Diffstat (limited to 'TAO/IIOP')
-rw-r--r--TAO/IIOP/lib/bridge/Makefile9
-rw-r--r--TAO/IIOP/lib/bridge/connmgr.cpp807
-rw-r--r--TAO/IIOP/lib/bridge/connmgr.hh141
-rw-r--r--TAO/IIOP/lib/bridge/giop.cpp1355
-rw-r--r--TAO/IIOP/lib/bridge/giop.hh317
-rw-r--r--TAO/IIOP/lib/bridge/iiopobj.cpp198
-rw-r--r--TAO/IIOP/lib/bridge/iiopobj.hh154
-rw-r--r--TAO/IIOP/lib/bridge/iioporb.cpp408
-rw-r--r--TAO/IIOP/lib/bridge/iioporb.hh49
-rw-r--r--TAO/IIOP/lib/bridge/invoke.cpp346
-rw-r--r--TAO/IIOP/lib/bridge/svrrqst.cpp261
-rw-r--r--TAO/IIOP/lib/bridge/svrrqst.hh96
-rw-r--r--TAO/IIOP/lib/bridge/tcpoa.cpp1026
-rw-r--r--TAO/IIOP/lib/bridge/tcpoa.hh276
-rw-r--r--TAO/IIOP/lib/corba/any.hh87
-rw-r--r--TAO/IIOP/lib/corba/corbacom.hh108
-rw-r--r--TAO/IIOP/lib/corba/except.hh186
-rw-r--r--TAO/IIOP/lib/corba/nvlist.hh119
-rw-r--r--TAO/IIOP/lib/corba/object.hh111
-rw-r--r--TAO/IIOP/lib/corba/orb.hh159
-rw-r--r--TAO/IIOP/lib/corba/orbconf.hh203
-rw-r--r--TAO/IIOP/lib/corba/orbconf.hh.in202
-rw-r--r--TAO/IIOP/lib/corba/orbobj.hh72
-rw-r--r--TAO/IIOP/lib/corba/principa.hh52
-rw-r--r--TAO/IIOP/lib/corba/request.hh69
-rw-r--r--TAO/IIOP/lib/corba/sequence.hh23
-rw-r--r--TAO/IIOP/lib/corba/stub.hh226
-rw-r--r--TAO/IIOP/lib/corba/svrrqst.hh73
-rw-r--r--TAO/IIOP/lib/corba/toa.hh182
-rw-r--r--TAO/IIOP/lib/corba/typecode.hh299
-rw-r--r--TAO/IIOP/lib/onc/Makefile8
-rw-r--r--TAO/IIOP/lib/onc/xdr.cpp812
-rw-r--r--TAO/IIOP/lib/onc/xdr.hh281
-rw-r--r--TAO/IIOP/lib/runtime/Makefile13
-rw-r--r--TAO/IIOP/lib/runtime/align.hh63
-rw-r--r--TAO/IIOP/lib/runtime/any.cpp670
-rw-r--r--TAO/IIOP/lib/runtime/cdr.cpp460
-rw-r--r--TAO/IIOP/lib/runtime/cdr.hh360
-rw-r--r--TAO/IIOP/lib/runtime/corbacom.cpp99
-rw-r--r--TAO/IIOP/lib/runtime/debug.cpp337
-rw-r--r--TAO/IIOP/lib/runtime/debug.hh104
-rw-r--r--TAO/IIOP/lib/runtime/except.cpp535
-rw-r--r--TAO/IIOP/lib/runtime/interp.cpp1515
-rw-r--r--TAO/IIOP/lib/runtime/marshal.cpp1101
-rw-r--r--TAO/IIOP/lib/runtime/nvlist.cpp262
-rw-r--r--TAO/IIOP/lib/runtime/object.cpp405
-rw-r--r--TAO/IIOP/lib/runtime/orbobj.cpp317
-rw-r--r--TAO/IIOP/lib/runtime/principa.cpp107
-rw-r--r--TAO/IIOP/lib/runtime/request.cpp168
-rw-r--r--TAO/IIOP/lib/runtime/t-xdr.cpp268
-rw-r--r--TAO/IIOP/lib/runtime/tc_const.cpp133
-rw-r--r--TAO/IIOP/lib/runtime/thread.hh185
-rw-r--r--TAO/IIOP/lib/runtime/toa.cpp146
-rw-r--r--TAO/IIOP/lib/runtime/typecode.cpp712
-rw-r--r--TAO/IIOP/test/Makefile80
-rw-r--r--TAO/IIOP/test/clnt.cpp491
-rw-r--r--TAO/IIOP/test/cubit.cpp590
-rw-r--r--TAO/IIOP/test/cubit.hh106
-rw-r--r--TAO/IIOP/test/cubit.idl40
-rw-r--r--TAO/IIOP/test/svr.cpp423
-rw-r--r--TAO/IIOP/test/test1.cpp383
-rw-r--r--TAO/IIOP/test/test1.hh124
-rw-r--r--TAO/IIOP/test/test1.idl78
-rw-r--r--TAO/IIOP/test/test1_clnt.cpp636
-rw-r--r--TAO/IIOP/test/test1_svr.cpp644
65 files changed, 20270 insertions, 0 deletions
diff --git a/TAO/IIOP/lib/bridge/Makefile b/TAO/IIOP/lib/bridge/Makefile
new file mode 100644
index 00000000000..c1f7a3ac3ba
--- /dev/null
+++ b/TAO/IIOP/lib/bridge/Makefile
@@ -0,0 +1,9 @@
+# @(#)Makefile 1.4 95/09/25
+
+FILES = \
+ iioporb.cpp iiopobj.cpp connmgr.cpp giop.cpp \
+ invoke.cpp svrrqst.cpp tcpoa.cpp
+
+ROOT = ../..
+
+include ../Makefile.gen
diff --git a/TAO/IIOP/lib/bridge/connmgr.cpp b/TAO/IIOP/lib/bridge/connmgr.cpp
new file mode 100644
index 00000000000..3cdde3c1d76
--- /dev/null
+++ b/TAO/IIOP/lib/bridge/connmgr.cpp
@@ -0,0 +1,807 @@
+// @(#)connmgr.cpp 1.4 95/09/29
+// Copyright 1994-1995 by Sun Microsystems Inc.
+// All Rights Reserved
+//
+// IIOP: Simple asymmetric TCP connection manager
+//
+// This has been multithreaded with a very simple strategy, optimizing
+// for "lightly threaded" clients rather than maximal sharing of system
+// resources (connections, time) in concurrent environments. Two locks
+// are used, one each for client and server sides.
+//
+// The expectation is: threads have a refcount on an endpoint only while
+// a call's active. Between calls, they release the endpoint record. If
+// need be, the file descriptor in the record may be set to a negative
+// number, and the descriptor closed (e.g. on unrecoverable error).
+//
+// The tricky issues have been strongly avoided. Particularly, on any
+// given connection no multiplexing is done; that simplifies this code
+// substantially, as well as the protocol code that'd otherwise need to
+// dispatch IIOP replies to arbitrary client threads. This costs most if
+// several "long" (time-wise) calls are made concurrently.
+//
+// Similarly, condition variables aren't used to allow concurrent access
+// to connection tables during "long" operations: name service lookups,
+// connection establishment, or both. Initial connection establishment,
+// including use of hostname aliases, pays this cost.
+//
+
+#include <assert.h>
+#include <memory.h>
+#include <string.h>
+
+#if unix
+# include <netdb.h>
+# include <unistd.h>
+
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <sys/time.h>
+
+# include <netinet/in.h>
+
+#else // unix
+# include <winsock.h>
+
+#endif // unix
+
+#include <corba/orb.hh>
+#include <corba/stub.hh>
+
+#include "bridge/connmgr.hh"
+#include "runtime/thread.hh"
+#include "runtime/debug.hh"
+
+
+//
+// It's mostly older platforms, but sometimes it's hard to get declarations
+// for socket calls, variables, utilities ... C++ requires them.
+//
+#if !defined (DECLARED_H_ERRNO)
+extern int h_errno;
+#endif
+
+#if !defined (DECLARED_ACCEPT)
+extern "C" int accept(int, void *, int *);
+#endif
+
+#if !defined (DECLARED_BIND)
+extern "C" int bind(int, const void *, int);
+#endif
+
+#if !defined (DECLARED_CONNECT)
+extern "C" int connect(int, const void *, int);
+#endif
+
+#if !defined (DECLARED_LISTEN)
+extern "C" int listen(int, int);
+#endif
+
+#if !defined (DECLARED_SELECT) && !defined (SELECT_INT_STAR)
+extern "C" int select (int, fd_set *, fd_set *, fd_set *, struct timeval *);
+#endif
+
+#if !defined (DECLARED_SETSOCKOPT)
+extern "C" int setsockopt (int, int, int, const char *, int);
+#endif
+
+#if !defined (DECLARED_SOCKET)
+extern "C" int socket (int, int, int);
+#endif
+
+#if !defined (DECLARED_BZERO) && !defined (bzero)
+ // in case FD_ZERO needs it
+#define bzero(addr, cnt) memset(addr, 0, cnt)
+#endif
+
+
+#if defined (SELECT_INT_STAR)
+# define SELECT_ARG_CAST (int *)
+#else
+# define SELECT_ARG_CAST
+#endif
+
+
+//
+// We tell the kernel to queue no more than LISTEN_LIMIT connection
+// requests ... traditionally, BSD implementations max out at 5, but
+// more recent implementations have no OS limit.
+//
+#define LISTEN_LIMIT 5 // traditional maximum
+
+//
+// Lists holding the connections managed in this module: one for outgoing
+// connections (client list), the other for incoming ones (server list).
+//
+// NOTE: with multiple OAs, it'll be desirable to let each OA have its own
+// server endpoint list so OAs can manage requests (and their threading)
+// separately.
+//
+static client_endpoint *client_list;
+static server_endpoint *server_list;
+
+
+#ifdef _POSIX_THREADS
+//
+// If POSIX threads are available, set up locks covering access to
+// both client and server side connection lists. They're separate
+// to avoid deadlocking, e.g. self-deadlock when a process calls to
+// an object it implements.
+//
+static pthread_mutex_t client_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t server_lock = PTHREAD_MUTEX_INITIALIZER;
+
+//
+// We need to cleanly indicate to select()ing server threads that a
+// a connection has been returned to their purview. The simplest way
+// is for them to wake up normally ... e.g. by data arriving. We use
+// writes on a private pipe: that's what signal_fd is for.
+//
+static int signal_fd;
+
+//
+// Conceptually, each TCP OA listens to a single "in" signal FD. But
+// we only support one of them for now.
+//
+static int signal_in_fd;
+
+#endif // _POSIX_THREADS
+
+
+//
+// Release ... must be reentrant in threaded systems.
+//
+void
+client_endpoint::release ()
+{
+#ifdef _POSIX_THREADS
+ Critical region (&client_lock);
+#endif // _POSIX_THREADS
+
+ assert (refcount == 1);
+ refcount--;
+}
+
+
+//
+// Gets or makes a connection to the indicated host@port, or reports an
+// exception explaining why it couldn't.
+//
+client_endpoint *
+client_endpoint::lookup (
+ char *host,
+ unsigned short port,
+ CORBA_Environment &env
+)
+{
+ client_endpoint *list;
+ hostent *hp = 0;
+
+#ifdef _POSIX_THREADS
+ Critical region (&client_lock);
+#endif // _POSIX_THREADS
+
+ //
+ // see if it's already in the list. if we find it here, we've
+ // saved a costly/remote name service lookup.
+ //
+ // THREADING NOTE: a policy decision is made here to use a different
+ // connection when an existing one is in use. As with all policies,
+ // there are cases where different decisions would be in some sense
+ // more optimal. The rationale is primarily that simpler MT code is
+ // preferable; blocking until the connection is idle again can easily
+ // deadlock mutually recursive invocations, and performance tradeoffs
+ // don't argue universally for multiplexing connections.
+ //
+ for (list = client_list; list != 0; list = list->next) {
+ if (list->port == port) {
+ if (list->fd == -1) {
+ dmsg ("client, dead FD in endpoint table");
+ continue;
+ }
+ if (strcmp (list->hostname, host) == 0) {
+ if (list->refcount == 0) {
+ list->refcount++;
+ return list;
+ } else {
+ //
+ // find/make a different connection, this one
+ // is busy for the moment
+ //
+ continue;
+ }
+ }
+
+ // else maybe one's an address, one's a name
+ // or one's a FQDN, one's not fully qualified
+ // ...
+ }
+ }
+
+ //
+ // See if we can find the host's address. This handles two styles
+ // of hostname: domain names (including partially qualified names,
+ // which rely on some implicit location in the DNS hierarchy), and
+ // "dotted-decimal" notation (e.g. "192.9.200.1"). Both forms are
+ // required by Internet standards (and hence IIOP).
+ //
+ // THREADING NOTE: gethostbyname is a "long" call, it'd often be worth
+ // dropping the lock during this call. It'd complicate control flow
+ // though, so until heavily threaded clients are common it's left
+ // to work in this simple way.
+ //
+ // XXX note that some platforms, particularly older ones no longer
+ // being actively maintained, violate Internet standards and don't
+ // accept dotted-decimal hostnames.
+ //
+ if (hp == 0) {
+ while ((hp = gethostbyname (host)) == 0) {
+ switch (h_errno) {
+ case TRY_AGAIN: // soft error
+ // sleep (1);
+ continue;
+
+ case HOST_NOT_FOUND: // hard NAK (not-exist)
+ dmsg1 ("gethostbyname '%s' --> No such host", host);
+ env.exception (new CORBA_OBJECT_NOT_EXIST (COMPLETED_NO));
+ return 0;
+
+ case NO_RECOVERY: // hard error
+ case NO_DATA: // maybe found an MX record?
+ default: // nonstandard error code
+ dmsg2 ("gethostbyname '%s' --> h_errno %d", host, h_errno);
+ env.exception (new CORBA_COMM_FAILURE (COMPLETED_NO));
+ return 0;
+ }
+ }
+ //
+ // Here we found the address associated with the hostname.
+ //
+ // NOTE: if we save addresses in the connection table, we might
+ // rescan it on the grounds that maybe we got a hostname alias
+ // (e.g. not the DNS CNAME). No functionality lost if we don't,
+ // but in some cases we'd save a connection.
+ //
+ }
+
+ //
+ // Here we've decided to grow the set of connections to satisfy
+ // this request. We get the record and then fill it out.
+ //
+ // NOTE: Should first shrink the list if it's very large! We could
+ // track time of last use to support LRU purging of connection cache,
+ // with potential removing of duplicates.
+ //
+ list = new client_endpoint;
+
+ if ((list->fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
+ dsockerr ("client socket");
+ delete list;
+
+ env.exception (new CORBA_UNKNOWN (COMPLETED_NO));
+ return 0;
+ }
+
+ //
+ // SECURITY NOTE: Some networks routinely configure bridges based on
+ // source and destination port. So it may be important to bind this
+ // socket to some preestablished port before connecting, since without
+ // doing so the traffic may not be passed through a firewall or bridge.
+ //
+
+
+ //
+ // Connect to the desired server address.
+ //
+ // THREADING NOTE: this is again a "long" call, during which it'll be
+ // worth dropping the lock on the connection list some day when many
+ // client threads contend on that lock.
+ //
+ sockaddr_in addr;
+
+ memset (&addr, 0, sizeof addr);
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = *(long *)hp->h_addr;
+ addr.sin_port = htons (port);
+
+ if (connect (list->fd, (sockaddr *) &addr, sizeof addr) < 0) {
+ dsockerr ("client connect");
+ dmsg2 ("... connect failure was to '%s:%d'", host, port);
+ delete list;
+
+ env.exception (new CORBA_COMM_FAILURE (COMPLETED_NO));
+ return 0;
+ }
+
+ list->hostname = strdup (host);
+ list->port = port;
+ list->refcount = 1;
+ list->next = client_list;
+
+ client_list = list;
+
+ return list;
+}
+
+
+#ifdef DEBUG
+
+void
+client_endpoint::dump (FILE *file)
+{
+ client_endpoint *list;
+
+#ifdef _POSIX_THREADS
+ //
+ // NOTE that although this lock is held for a _very_ long time
+ // (terminal/stderr I/O is much slower than network I/O and this
+ // does "lots" of it) we don't have much of an option because we
+ // need to present a single, consistent view of this table.
+ //
+ Critical region (&client_lock);
+#endif // _POSIX_THREADS
+
+ fprintf (file, "List of client-side connections:\n");
+
+ for (list = client_list; list != 0; list = list->next) {
+ fprintf (file, " %s @ %d\tfd %d\trefcnt %d\n",
+ list->hostname, list->port, list->fd,
+ list->refcount);
+ }
+ fprintf (file, "\n");
+}
+
+#endif
+
+
+
+//
+// Release ... must be reentrant in threaded systems.
+//
+// NOTE: this version actually does two things, which could be split
+// into two separate routines with some TBD effect on performance. It
+// decrements the use count of this connection; and it informs other
+// potential reading threads that it's OK to read incoming messages.
+//
+// Splitting these two apart could let the server issue Reply messages
+// in arbitrary orders, at the potential cost of putting extra context
+// switching into the critical path for request handling.
+//
+void
+server_endpoint::release ()
+{
+#ifdef _POSIX_THREADS
+ Critical region (&server_lock);
+#endif // _POSIX_THREADS
+
+ assert (refcount == 1);
+ refcount--;
+
+#ifdef _POSIX_THREADS
+ //
+ // Tell whoever's in block_for_input() that they can look again
+ // at this connection, reading messages off of it and replying
+ // to them as appropriate.
+ //
+ (void) write (signal_fd, "b", 1);
+#endif // _POSIX_THREADS
+}
+
+
+//
+// Initialize a server endpoint, at the specified port or, if that port
+// number is zero, then at any available port.
+//
+// XXX at some point this will include an interface name, to facilitate
+// its use on multihomed hosts such as firewalls.
+//
+server_endpoint *
+server_endpoint::initialize (
+ unsigned short &port,
+ // XXX char *ifname
+ CORBA_Environment &env
+)
+{
+#ifdef _POSIX_THREADS
+ Critical region (&server_lock);
+#endif // _POSIX_THREADS
+
+ //
+ // XXX at this time, we only support one port/listener per process.
+ // This restriction should be lifted sometime.
+ //
+ if (server_list != 0) {
+ env.exception (new CORBA_INITIALIZE (COMPLETED_NO));
+ return 0;
+ }
+
+ //
+ // Initial "connection" record.
+ //
+ server_endpoint *list;
+
+ list = new server_endpoint;
+ list->is_passive = CORBA_B_TRUE;
+ list->port = port;
+ list->next = 0;
+ list->refcount = 0;
+
+ //
+ // Create the socket
+ //
+ if ((list->fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
+ dsockerr ("server socket");
+ delete list;
+
+ env.exception (new CORBA_INITIALIZE (COMPLETED_NO));
+ return 0;
+ }
+
+ //
+ // Bind it to the requested port, if one was requested.
+ //
+ sockaddr_in addr;
+
+ if (port != 0) {
+#ifdef SO_REUSEADDR
+ //
+ // In cases where servers abort and must be restarted, we
+ // want to avoid TCP's mandatory 4 minute close-wait timeout.
+ // So we set SO_REUSEADDR only on the "listening" socket,
+ // which never actually gets a connection; it's safe to be
+ // "reusing" the address since the OS never reuses TCP ports
+ // which are in the BOUND or LISTEN states.
+ //
+ // If we can't do this, it's not an error -- this is just an
+ // optimization applicable to some failure cases, we can live
+ // without it in all cases. Applications might care; if so,
+ // they should run on platforms supporting SO_REUSEADDR.
+ //
+ int flag = 1;
+
+ if (setsockopt (list->fd, SOL_SOCKET, SO_REUSEADDR,
+ (char *) &flag, sizeof (flag)) < 0) {
+ dsockerr ("server setsockopt SO_REUSEADDR");
+ }
+#endif // SO_REUSEADDR
+
+ memset (&addr, 0, sizeof addr);
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons (port);
+
+ //
+ // XXX someday, this is where we'll bind to specific interfaces
+ // on multihomed hosts (e.g. firewalls) which do no routing.
+ //
+ addr.sin_addr.s_addr = htonl (INADDR_ANY);
+
+ if (bind (list->fd, (sockaddr *)&addr, sizeof addr) < 0) {
+ dsockerr ("server bind");
+ closesocket (list->fd);
+ delete list;
+
+ env.exception (new CORBA_INITIALIZE (COMPLETED_NO));
+ return 0;
+ }
+ }
+
+ //
+ // Make it a listening (passive) socket
+ //
+ if (listen (list->fd, LISTEN_LIMIT) < 0) {
+ dsockerr ("server listen");
+ closesocket (list->fd);
+ delete list;
+
+ env.exception (new CORBA_INITIALIZE (COMPLETED_NO));
+ return 0;
+ }
+
+ //
+ // If we bound to a system-assigned port, find out which port
+ // address the system assigned us.
+ //
+ if (port == 0) {
+ int size = sizeof (addr);
+
+ if (getsockname (list->fd, (sockaddr *) &addr, &size) < 0) {
+ dsockerr ("server getsockname");
+ closesocket (list->fd);
+ delete list;
+
+ env.exception (new CORBA_INITIALIZE (COMPLETED_NO));
+ return 0;
+ }
+ port = list->port = ntohs (addr.sin_port);
+ }
+
+#ifdef _POSIX_THREADS
+ //
+ // We need a clean way to have other threads signal ones that
+ // are select()ing that there's another connection they need to
+ // pay attention to. So we set up a pipe for them to use.
+ //
+ int pipefd [2];
+
+ if (pipe (pipefd) != 0) {
+ dperror ("pipe for connection manager");
+ closesocket (list->fd);
+ delete list;
+
+ env.exception (new CORBA_INITIALIZE (COMPLETED_NO));
+ return 0;
+ }
+ signal_in_fd = pipefd [0];
+ signal_fd = pipefd [1];
+#endif // _POSIX_THREADS
+
+ server_list = list;
+
+ return list;
+}
+
+
+//
+// Get a connection. Unless "eager" is set, the connection returned
+// will actually have data ready for input. Normally, unthreaded
+// environments can't be "eager", and threaded environments prefer to
+// use that model to achieve better performance. Threaded environments
+// can of course not be "eager".
+//
+// THREADING NOTE: It's undesirable to have more than one thread call this
+// at the same time; the semantics of two threads that select() on the same
+// file descriptor are undefined. Hence the static flag that's tested.
+//
+server_endpoint *
+server_endpoint::block_for_connection (
+ CORBA_Boolean eager,
+ timeval *timeout,
+ CORBA_Environment &env
+)
+{
+#ifdef _POSIX_THREADS
+ Critical region (&server_lock);
+#endif // _POSIX_THREADS
+
+ //
+ // Head of the list is a passive file descriptor. The rest is a list
+ // of ones used for I/O to clients. Only call block_for_input() on
+ // endpoints returned by initialize().
+ //
+ assert (is_passive);
+
+ //
+ // Scan the list of server-side connections and generate the fd_set
+ // we'd use in a select() call (or eagerly return a file descriptor,
+ // without selecting first). Make the call, examine the results;
+ // maybe we return soon to the caller, maybe we don't.
+ //
+ // XXX if there are lots of connections here we should contemplate
+ // shutting down several of them in order to gracefully reclaim the
+ // OS resources associated with the connections.
+ //
+ for (;;) {
+ fd_set read_fdset;
+ server_endpoint *list, *previous;
+ int max_fd = 0;
+
+ FD_ZERO (&read_fdset);
+ for (list = this, previous = 0;
+ list;
+ previous = list, list = list->next) {
+
+ //
+ // Delete records for connections that were closed and
+ // which nobody is using.
+ //
+ if (list->fd < 0) {
+ if (list->refcount != 0)
+ continue;
+
+ assert (previous != 0); // passive must exist!
+
+ previous->next = list->next;
+ delete list;
+ list = previous;
+ continue;
+ }
+
+ //
+ // If nobody else is reading from this connection, we work with
+ // it ... if the caller is "eager" we return it immediately
+ // (even with no data). Else we prepare to select on it.
+ //
+ // Refcount is currently used to track if someone's reading,
+ // though it'd be easy to further distinguish "someone reading"
+ // from "someone needs". A "needed" connection without someone
+ // currently reading could be assigned a thread to read it;
+ // that would enable out-of-order processing (a lock would be
+ // needed to ensure no interleaving of GIOP 1.1 fragments).
+ //
+ if (list->refcount == 0) {
+ if (eager && !list->is_passive) {
+ list->refcount++;
+ return list;
+ }
+ FD_SET (list->fd, &read_fdset);
+ if (list->fd > max_fd)
+ max_fd = list->fd;
+ }
+ }
+
+ //
+ // Select until something interesting happens.
+ //
+ // THREADING NOTE: We leave the critical section for the duration
+ // of this select() since we'll normally be there a long time, and
+ // other threads must grab server_lock while we block. But we must
+ // reenter it later to compare the select() output with the set of
+ // legal server side connections.
+ //
+ // Also, since the semantics of multiple threads calling select()
+ // on the same file descriptor(s) is undefined, we prevent that.
+ //
+ // We add the pipe file descriptor to the list so that when other
+ // threads release connections, we can learn about this.
+ //
+#ifdef _POSIX_THREADS
+ static int doing_select; // = 0
+
+ if (doing_select) {
+ dmsg ("concurrent block_for_input() calls");
+ env.exception (new CORBA_IMP_LIMIT (COMPLETED_NO));
+ return 0;
+ } else
+ doing_select = 1;
+
+ region.leave ();
+
+ FD_SET (signal_in_fd, &read_fdset);
+ if (signal_in_fd > max_fd)
+ max_fd = signal_in_fd;
+#endif // _POSIX_THREADS
+
+ int value = select (max_fd + 1, SELECT_ARG_CAST &read_fdset,
+ 0, 0, timeout);
+
+#ifdef _POSIX_THREADS
+ region.enter ();
+ doing_select = 0;
+#endif // _POSIX_THREADS
+
+ if (value < 0) {
+ dsockerr ("server select");
+ env.exception (new CORBA_COMM_FAILURE (COMPLETED_NO));
+ return 0;
+ } else if (value == 0) {
+ dmsg ("server select timed out");
+ return 0;
+ }
+
+ //
+ // Check out the set of FDs we found out about in select() above.
+ // If accept() is needed, do so and rescan. Else return an entry
+ // from the list.
+ //
+ // THREADING NOTE: we read any byte written by another thread
+ // to wake us up. Rare to have more than one such byte!
+ //
+#ifdef _POSIX_THREADS
+ if (FD_ISSET (signal_in_fd, &read_fdset)) {
+ char b;
+ (void) read (signal_in_fd, &b, 1);
+ if (debug_level >= 5)
+ dmsg ("block_for_input() woken up");
+ }
+#endif // _POSIX_THREADS
+
+ for (list = this; list; list = list->next) {
+ if (list->fd == -1 || !FD_ISSET (list->fd, &read_fdset))
+ continue;
+
+ //
+ // If we've got one with incoming data, return it.
+ //
+ if (!list->is_passive) {
+ list->refcount++;
+ return list;
+ }
+
+ //
+ // Nyet ... incoming connection. Accept it.
+ //
+ sockaddr_in saddr;
+ int saddr_siz = sizeof saddr;
+ int new_fd;
+
+ if ((new_fd = accept (list->fd,
+ (sockaddr *) &saddr, &saddr_siz)) < 0) {
+ dsockerr ("server accept");
+ continue; // what else?
+ }
+
+ server_endpoint *new_clnt;
+
+ new_clnt = new server_endpoint;
+ new_clnt->fd = new_fd;
+ new_clnt->port = saddr.sin_port;
+ new_clnt->is_passive = CORBA_B_FALSE;
+ new_clnt->refcount = 0;
+
+ dmsg1 ("accepted new FD %d", fd);
+
+ //
+ // Splice it into list betwen here and next. Since most
+ // systems can't piggyback data with the connection setup
+ // packet, there's probably no data here yet. We can't
+ // find out when it arrives without blocking or polling.
+ //
+ new_clnt->next = list->next;
+ list->next = new_clnt;
+ list = new_clnt;
+
+ //
+ // One ramification of an "eager" model: we treat the
+ // connection as having data immediately on connection
+ // establishment. Lacking transactional TCP this will not
+ // often be the case ... but the basic "eager" model is
+ // that we spend LWPs (threads) to improve latencies.
+ //
+ if (eager) {
+ new_clnt->refcount++;
+ return new_clnt;
+ }
+ }
+ }
+}
+
+void
+server_endpoint::shutdown_connections (
+ void (*close_conn) (int &, void *),
+ void *info
+)
+{
+ server_endpoint *list, *successor;
+
+#ifdef _POSIX_THREADS
+ Critical region (&server_lock);
+#endif // _POSIX_THREADS
+
+ for (list = this; list != 0; list = successor) {
+ if (list->is_passive)
+ (void) closesocket (list->fd);
+ else
+ close_conn (list->fd, info);
+
+ successor = list->next;
+ delete list;
+ }
+}
+
+
+#ifdef DEBUG
+
+void
+server_endpoint::dump (FILE *file)
+{
+ server_endpoint *list;
+
+#ifdef _POSIX_THREADS
+ //
+ // NOTE the comment in client_endpoint::dump() re long lock times.
+ //
+ Critical region (&client_lock);
+#endif // _POSIX_THREADS
+
+ fprintf (file, "List of server-side connections:\n");
+
+ for (list = server_list; list != 0; list = list->next) {
+ fprintf (file, " port %d%s\tfd %d\trefcnt %d\n",
+ list->port, list->is_passive ? " (passive)" : "",
+ list->fd, list->refcount);
+ }
+ fprintf (file, "\n");
+}
+
+#endif
+
diff --git a/TAO/IIOP/lib/bridge/connmgr.hh b/TAO/IIOP/lib/bridge/connmgr.hh
new file mode 100644
index 00000000000..2a2a55fb6ab
--- /dev/null
+++ b/TAO/IIOP/lib/bridge/connmgr.hh
@@ -0,0 +1,141 @@
+// @(#)connmgr.hh 1.2 95/09/24
+// Copyright 1994-1995 by Sun Microsystems Inc.
+// All Rights Reserved
+//
+// Simple threaded asymmetric TCP connection manager.
+//
+
+#ifndef _CONNMGR_HH
+#define _CONNMGR_HH
+
+#if unix
+# include <sys/time.h>
+#else // __WIN32__
+# include <winsock.h>
+#endif
+
+#ifdef DEBUG
+#include <stdio.h>
+#endif
+
+//
+// Utility class that may not really belong here; it's currently used only
+// with connection endpoints though.
+//
+// THREADING NOTE: note that the pointer doesn't change, so two threads
+// could share an "autorelease<T>" value if they collaborated about safe
+// refcounting and destruction.
+//
+template <class T>
+class autorelease {
+ public:
+ autorelease &operator = (T *ptr)
+ {
+ if (_state) _state->release();
+ _state = ptr; return *this;
+ }
+ operator int () { return _state ? 1 : 0; }
+ T *operator -> () { return _state; }
+ autorelease () { _state = 0; }
+ ~autorelease ()
+ { if (_state) _state->release (); }
+
+ private:
+ T *_state;
+};
+
+
+//
+// Client endpoints are acquired just by looking them up; they're created
+// if needed, and may be closed when they're not in use.
+//
+// NOTE: timeout on lookup/create would be a nice quality-of-service
+// knob to be able to tweak...
+//
+struct client_endpoint {
+ int fd;
+
+ static client_endpoint *lookup (
+ char *host,
+ unsigned short port,
+ CORBA_Environment &env
+ );
+
+ void release ();
+
+#ifdef DEBUG
+ static void dump (FILE *);
+#endif
+
+ private:
+ char *hostname;
+ unsigned short port;
+ unsigned refcount;
+ client_endpoint *next;
+
+#ifdef __GNUG__
+ //
+ // G++ (even 2.6.3) stupidly thinks instances can't be
+ // created This de-warns.
+ //
+ friend class everyone_needs_a_friend;
+#endif
+};
+
+
+//
+// Server endpoints start out by waiting passively for input on a port.
+// New connections may be created. Old ones may be disconnected.
+//
+// NOTE: this version doesn't bind to specific host addresses on
+// multihomed hosts, so it's not yet suitable for use on firewalls.
+//
+// NOTE: this version also doesn't listen on more than one port at a time.
+//
+class server_endpoint {
+ public:
+ int fd;
+
+ static server_endpoint *initialize (
+ unsigned short &port,
+ // XXX char *ifname,
+ CORBA_Environment &env
+ );
+
+ server_endpoint *block_for_connection (
+ CORBA_Boolean eager,
+ timeval *timeout,
+ CORBA_Environment &env
+ );
+
+ void shutdown_connections (
+ // add a flag saying some, all?
+ void (*close_conn)(
+ int &fd,
+ void *info
+ ),
+ void *info
+ );
+
+ void release ();
+
+#ifdef DEBUG
+ static void dump (FILE *);
+#endif
+
+ private:
+ unsigned short port;
+ CORBA_Boolean is_passive;
+ unsigned refcount;
+ server_endpoint *next;
+
+#if defined (__GNUG__)
+ //
+ // G++ (even 2.6.3) stupidly thinks instances can't be
+ // created. This de-warns.
+ //
+ friend class everyone_needs_a_friend;
+#endif
+};
+
+#endif // _CONNMGR_HH
diff --git a/TAO/IIOP/lib/bridge/giop.cpp b/TAO/IIOP/lib/bridge/giop.cpp
new file mode 100644
index 00000000000..a95aede47fb
--- /dev/null
+++ b/TAO/IIOP/lib/bridge/giop.cpp
@@ -0,0 +1,1355 @@
+// @(#)giop.cpp 1.10 95/09/21
+// Copyright 1994-1995 by Sun Microsystems Inc.
+// All Rights Reserved
+//
+// GIOP: Utility routines for sending, receiving GIOP messages
+//
+// Note that the Internet IOP is just the TCP-specific mapping of
+// the General IOP. Areas where other protocols may map differently
+// include use of record streams (TCP has none), orderly disconnect
+// (TCP has it), endpoint addressing (TCP uses host + port), security
+// (Internet security should be leveraged by IIOP) and more.
+//
+// NOTE: There are a few places where this code knows that it's really
+// talking IIOP instead of GIOP. No rush to fix this so long as we are
+// really not running atop multiple connection protocols.
+//
+// THREADING NOTE: currently, the connection manager eliminates tricky
+// threading issues by providing this code with the same programming model
+// both in threaded and unthreaded environments. Since the GIOP APIs were
+// all designed to be reentrant, this makes threading rather simple!
+//
+// That threading model is that the thread making (or handling) a call is
+// given exclusive access to a connection for the duration of a call, so
+// that no multiplexing or demultiplexing is needed. That is, locking is
+// at the "connection level" rather than "message level".
+//
+// The down side of this simple threading model is that utilization of
+// system resources (mostly connections, but to some extent network I/O)
+// in some kinds of environments can be inefficient. However, simpler
+// threading models are much easier to get properly debugged, and often
+// perform better. Also, such environments haven't been seen to be any
+// kind of problem; the model can be changed later if needed, it's just an
+// internal implementation detail. Any portable ORB client is not allowed
+// to rely on semantic implications of such a model.
+//
+// XXX there is lots of unverified I/O here. In all cases, if an error
+// is detected when marshaling or unmarshaling, it should be reported.
+//
+
+#include <assert.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if unix
+# include <sys/types.h>
+# include <sys/socket.h>
+
+ // Use normal file I/O where possible, it's better tuned.
+# define send(s,buf,len,zero) write(s,buf,len)
+# define recv(s,buf,len,zero) read(s,buf,len)
+
+#else
+# include <winsock.h>
+
+#endif
+
+#include <corba/orb.hh>
+
+#include "runtime/cdr.hh"
+#include "runtime/debug.hh"
+#include "runtime/thread.hh"
+#include "bridge/giop.hh"
+
+
+#if !defined (DECLARED_SHUTDOWN)
+extern "C" int shutdown (int fd, int how);
+#endif
+
+
+#define GIOP_HDR_LEN 12 // defined by GIOP 1.0 protocol
+
+
+#ifdef _POSIX_THREADS
+//
+// This lock covers the mutable info in all IIOP objref data,
+// namely the forwarded-to objref. It must be held when a client
+// thread is reading or modifying that data, to prevent one from
+// overwriting data the other's reading or writing.
+//
+static pthread_mutex_t fwd_info_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif // _POSIX_THREADS
+
+
+//
+// Apart from the length word, headers are specified to be arrays of
+// bytes. They're dealt with as such, rather than using CDR routines,
+// to speed up the critical paths for message read and write.
+//
+static inline CORBA_Boolean
+start_message (
+ GIOP::MsgType type,
+ CDR &msg
+)
+{
+ msg.next = msg.buffer; // for reused streams
+ msg.remaining = msg.length;
+
+ if (msg.bytes_remaining () < GIOP_HDR_LEN)
+ return CORBA_B_FALSE;
+
+ msg.next [0] = 'G';
+ msg.next [1] = 'I';
+ msg.next [2] = 'O';
+ msg.next [3] = 'P';
+
+ msg.next [4] = GIOP::MY_MAJOR;
+ msg.next [5] = GIOP::MY_MINOR;
+ msg.next [6] = MY_BYTE_SEX;
+ msg.next [7] = (unsigned char) type;
+
+ msg.skip_bytes (GIOP_HDR_LEN);
+ return CORBA_B_TRUE;
+}
+
+#ifdef DEBUG
+static const char digits [] = "0123456789ABCD";
+static const char *names [] = {
+ "Request", "Reply", "CancelRequest",
+ "LocateRequest", "LocateReply",
+ "CloseConnection", "MessageError"
+};
+
+static void
+dump_msg (const char *label, const unsigned char *ptr, size_t len)
+{
+ if (debug_level >= 2) {
+ dmsg_v ("%s GIOP v%c.%c msg, %d data bytes, %s endian, %s\n",
+ label, digits [ptr [4]], digits [ptr [5]],
+ len - GIOP_HDR_LEN,
+ (ptr [6] == MY_BYTE_SEX) ? "my" : "other",
+ (ptr [7] <= GIOP::MessageError)
+ ? names [ptr [7]] : "UNKNOWN TYPE");
+
+ if (debug_level >= 4)
+ dmsg_opaque_full("data bytes", ptr, len);
+ }
+}
+
+#else // !DEBUG
+#define dump_msg(label,ptr,len)
+#endif // !DEBUG
+
+CORBA_Boolean
+GIOP::send_message (
+ CDR &stream,
+ int &connection
+)
+{
+ char *buf = (char *) stream.buffer;
+ size_t buflen = stream.next - stream.buffer;
+ int writelen;
+
+ assert (buflen == (stream.length - stream.remaining));
+
+ //
+ // Patch the message length in the GIOP header; it's always at the
+ // same eight byte offset into the message.
+ //
+ // NOTE: Here would also be a fine place to calculate a digital
+ // signature for the message and place it into a preallocated
+ // slot in the "ServiceContext". Similarly, this is a good spot
+ // to encrypt messages (or just the message bodies) if that's
+ // needed in this particular environment and that isn't handled
+ // by the networking infrastructure (e.g. IPSEC).
+ //
+ *(CORBA_Long *)(stream.buffer + 8) =
+ (CORBA_Long) (buflen - GIOP_HDR_LEN);
+
+ //
+ // Strictly speaking, should not need to loop here because the
+ // socket never gets set to a nonblocking mode ... some Linux
+ // versions seem to need it though. Leaving it costs little.
+ //
+ dump_msg ("send", stream.buffer, buflen);
+ while (buflen > 0) {
+ if (buflen > stream.length) {
+ dmsg2 ("?? writebuf, buflen %u > length %u\n",
+ buflen, stream.length);
+ return CORBA_B_FALSE;
+ }
+ writelen = send (connection, (char _FAR *) buf, buflen, 0);
+
+#ifdef DEBUG
+ dmsg_filter (6, "wrote %d bytes to connection %d",
+ writelen, connection);
+#endif // DEBUG
+
+ assert ((writelen >= 0 &&
+ ((size_t)writelen) <= buflen) || writelen == -1);
+
+ //
+ // On error or EOF, report the fault, close the connection, and
+ // mark it as unusable/defunct.
+ //
+ // XXX on client side write errors, we may hit the case that
+ // the server did a clean shutdown but we've not yet read the
+ // GIOP::CloseConnection message. If we get an error, we need
+ // to see if there is such a message waiting for us, and if so
+ // we should cause (full) rebinding to take place.
+ //
+ if (writelen == -1) {
+ dsockerr ("OutgoingMessage::writebuf()");
+ dmsg1 ("closing conn %d after fault", connection);
+ closesocket (connection);
+ connection = -1;
+ return CORBA_B_FALSE;
+ } else if (writelen == 0) {
+ dmsg1 ("OutgoingMessage::writebuf() ... EOF, closing conn %d",
+ connection);
+ closesocket (connection);
+ connection = -1;
+ return CORBA_B_FALSE;
+ }
+ if ((buflen -= writelen) != 0)
+ buf += writelen;
+
+#ifdef DEBUG
+ //
+ // NOTE: this should never be seen. However, on Linux
+ // it's been seen with UNIX domain sockets.
+ //
+ if (buflen)
+ dmsg_filter (8, "%u more bytes to write...\n", buflen);
+#endif
+ }
+ return CORBA_B_TRUE;
+}
+
+
+//
+// Server sends an "I'm shutting down now, any requests you've sent me
+// can be retried" message to the server. The message is prefab, for
+// simplicity.
+//
+// NOTE: this is IIOP-specific though it doesn't look like it is. It
+// relies on a TCP-ism: orderly disconnect, which doesn't exist in all
+// transport protocols. Versions of GIOP atop some transport that's
+// lacking orderly disconnect must define some transport-specific
+// handshaking (e.g. the XNS/SPP handshake convention) in order to know
+// that the same transport semantics are provided when shutdown is begun
+// with messages "in flight". (IIOP doesn't report false errors in the
+// case of "clean shutdown", because it relies on orderly disconnect as
+// provided by TCP. This quality of service is required to write robust
+// distributed systems.)
+//
+static const char
+close_message [GIOP_HDR_LEN] = {
+ 'G', 'I', 'O', 'P',
+ GIOP::MY_MAJOR, GIOP::MY_MINOR, MY_BYTE_SEX, GIOP::CloseConnection,
+ 0, 0, 0, 0
+};
+
+
+void
+GIOP::close_connection (
+ int &fd,
+ void * // currently unused
+)
+{
+ //
+ // It's important that we use a reliable shutdown after we send
+ // this message, so we know it's received.
+ //
+ // XXX should recv and discard queued data for portability; note
+ // that this won't block (long) since we never set SO_LINGER
+ //
+ dump_msg ("send", (const unsigned char *) close_message, GIOP_HDR_LEN);
+ (void) send (fd, close_message, GIOP_HDR_LEN, 0);
+ (void) shutdown (fd, 2);
+ (void) closesocket (fd);
+ dmsg1 ("shut down socket %d", fd);
+ fd = -1;
+}
+
+//
+// Send an "I can't understand you" message -- again, the message is
+// prefabricated for simplicity. This implies abortive disconnect
+// (at the application level, if not at the level of TCP).
+//
+// NOTE that IIOP will still benefit from TCP's orderly disconnect.
+//
+static const char
+error_message [GIOP_HDR_LEN] = {
+ 'G', 'I', 'O', 'P',
+ GIOP::MY_MAJOR, GIOP::MY_MINOR, MY_BYTE_SEX, GIOP::MessageError,
+ 0, 0, 0, 0
+};
+
+static inline void
+send_error (int &fd)
+{
+ dump_msg ("send", (const unsigned char *) error_message, GIOP_HDR_LEN);
+ (void) send (fd, error_message, GIOP_HDR_LEN, 0);
+ (void) shutdown (fd, 2);
+ (void) closesocket (fd);
+ dmsg1 ("aborted socket %d", fd);
+ fd = -1;
+}
+
+
+//
+// Loop on data read ... this is required with some implementations of
+// sockets (e.g. winsock, HP/UX) since even when async mode is not set,
+// recv() won't block until the requested amount of data is available.
+//
+static int
+read_buffer (
+ int fd,
+ char *buf,
+ size_t len
+)
+{
+ int bytes_read = 0;
+
+ while (len != 0) {
+ int retval;
+
+ retval = recv (fd, buf, len, 0);
+
+#ifdef DEBUG
+ dmsg_filter (6, "read %d bytes from connection: %d", retval, fd);
+#endif
+ if (retval <= 0) // EOF or error
+ return retval;
+
+ len -= retval;
+ buf += retval;
+ bytes_read += retval;
+ }
+
+ return bytes_read;
+}
+
+
+//
+// Read the message header, plus any data part of the message, setting
+// stuff up so that CDR byteswaps data as appropriate. Errors are reported
+// to be MessageError messages.
+//
+// NOTE: this code is structured to issue two read() calls for each
+// incoming message. Alternative structures (e.g. with a user-space buffer
+// per connection, or networking code handing off entire GIOP messages) can
+// reduce the overhead of these calls to the networking code; correctness
+// and simplicity drove this implementation more than efficiency.
+//
+// NOTE: as always, counting system calls associated with I/O gives you
+// a good basic understanding of the tuning issues. On the server side,
+// there is normally select/read/read/write per invocation. The call to
+// select() can be omitted by allocating a thread to each connection; in
+// some cases, that alone has almost doubled performance. The two read()
+// calls can be made into one by fancy buffering. How fast could it be
+// with both optimizations applied?
+//
+GIOP::MsgType
+GIOP::read_message (
+ int &connection,
+ CDR &msg,
+ CORBA_Environment &env
+)
+{
+ GIOP::MsgType retval;
+ CORBA_ULong message_size;
+
+ //
+ // Read the message header off the wire.
+ //
+ // THREADING NOTE: the connection manager handed us this connection
+ // for exclusive use, so we need not worry about having two threads
+ // interleave reads of partial messages. This model is excellent
+ // for "lightly threaded" systems (as will be the majority in the
+ // near future) but makes less effective use of connection resources
+ // as the "duty factor" goes down because of either long calls or
+ // bursty contention during numerous short calls to the same server.
+ //
+ assert (msg.length > GIOP_HDR_LEN);
+
+ msg.next = msg.buffer;
+ msg.remaining = GIOP_HDR_LEN;
+
+ char *bufptr = (char _FAR *) msg.buffer;
+ int len;
+
+ //
+ // Read the header into the buffer.
+ //
+ if ((len = read_buffer (connection, bufptr, GIOP_HDR_LEN))
+ != GIOP_HDR_LEN) {
+ if (len == 0) { // EOF
+ dmsg1 ("Header EOF ... peer probably aborted connection %d",
+ connection);
+
+ //
+ // XXX should probably find some way to report this without
+ // an exception, since for most servers it's not an error.
+ // Is it _never_ an error? Not sure ...
+ //
+ } else if (len < 0) { // error
+ dsockerr ("GIOP::read_message header");
+ } else { // short read ...
+ dmsg ("read message header failed (short)");
+ }
+ env.exception (new CORBA_COMM_FAILURE (COMPLETED_MAYBE));
+ return MessageError;
+ }
+
+ //
+ // NOTE: if message headers, or whome messages, get encrypted in
+ // application software (rather than by the network infrastructure)
+ // they should be decrypted here ...
+ //
+
+ //
+ // First make sure it's a GIOP message of any version.
+ //
+ if (!(msg.buffer [0] == 'G' && msg.buffer [1] == 'I'
+ && msg.buffer [2] == 'O' && msg.buffer [3] == 'P')) {
+ env.exception (new CORBA_MARSHAL (COMPLETED_MAYBE)); // header
+ dmsg ("bad header, magic word");
+ return MessageError;
+ }
+
+ //
+ // Then make sure the major version is ours, and the minor version is
+ // one that we understand.
+ //
+ if (!(msg.buffer [4] == MY_MAJOR && msg.buffer [5] <= MY_MINOR)) {
+ env.exception (new CORBA_MARSHAL (COMPLETED_MAYBE)); // header
+ dmsg ("bad header, version");
+ return MessageError;
+ }
+
+ //
+ // Get the message type out and adjust the buffer's records to record
+ // that we've read everything except the length.
+ //
+ retval = (GIOP::MsgType) msg.buffer [7];
+ msg.skip_bytes (8);
+
+ //
+ // Make sure byteswapping is done if needed, and then read the message
+ // size (appropriately byteswapped).
+ //
+ msg.do_byteswap = (msg.buffer [6] != MY_BYTE_SEX);
+ msg.get_ulong (message_size);
+
+ //
+ // Make sure we have the full length in memory, growing the
+ // buffer if needed.
+ //
+ // NOTE: We could overwrite these few bytes of header... they're
+ // left around for now as a debugging aid.
+ //
+ assert (message_size <= UINT_MAX);
+
+ if ((GIOP_HDR_LEN + message_size) > msg.length)
+ msg.grow ((size_t) (GIOP_HDR_LEN + message_size));
+
+ msg.remaining = (size_t) message_size;
+ bufptr = (char *) & msg.buffer [GIOP_HDR_LEN];
+
+ //
+ // Read the rest of this message into the buffer.
+ //
+ if ((len = read_buffer (connection, bufptr, (size_t) message_size))
+ != (int) message_size) {
+ if (len == 0) {
+ dmsg1 ("read message body, EOF on fd %d", connection);
+ } else if (len < 0) {
+ dperror ("GIOP::read_message() body");
+ } else {
+ dmsg2 ("short read, only %d of %d bytes", len, message_size);
+ }
+
+ // clean up, and ...
+ env.exception (new CORBA_COMM_FAILURE (COMPLETED_MAYBE)); // body
+ dmsg ("couldn't read rest of message");
+ return MessageError;
+ }
+
+ dump_msg ("recv", msg.buffer, (size_t)(message_size + GIOP_HDR_LEN));
+ return retval;
+}
+
+
+//
+// Normal invocations don't involve any heap allocation; messages are
+// constructed into stack-based buffers and are read into those buffers
+// too. Larger buffers are heap-allocated as needed.
+//
+// The constraint on request IDs is that no two requests from the same
+// client with the same ID are outstanding at the same time. In single
+// threaded environments, this is met by any number whatever. When
+// multiple threads are used, we eliminate the need for any locked state
+// by using the thread ID as the request ID, since any given thread
+// has at most one request outstanding at a time.
+//
+// NOTE: this means that if "deferred synchronous" calls get supported,
+// it's done by creating a thread internally to make the call. That is
+// less disruptive (and error prone) in general than restructuring an ORB
+// core in terms of asynchrony.
+//
+
+GIOP::Invocation::Invocation (
+ IIOP_Object *data,
+ const char *operation,
+ CORBA_Boolean is_roundtrip
+) :
+ _data (data),
+ opname (operation),
+ do_rsvp (is_roundtrip),
+ stream (&buffer [0], sizeof buffer)
+{
+#ifdef _POSIX_THREADS
+ //
+ // POSIX does not require this to be true, it's an implementation
+ // assumption that will at some point be removed but is true on
+ // many current POSIX.1c implementations.
+ //
+ assert (sizeof (CORBA_ULong) == sizeof (pthread_t));
+
+ my_request_id = (CORBA_ULong) pthread_self ();
+#else
+ my_request_id = 0;
+#endif // _POSIX_THREADS
+}
+
+GIOP::Invocation::~Invocation ()
+{
+}
+
+//
+// Octet codes for the parameters of the "Opaque" (sequence of octet) data
+// type used various places internally ... a CDR encapsulation holding two
+// parameters (like all sequence TypeCodes).
+//
+// NOTE: this **MUST** be longword aligned, which is why it's coded as a
+// longword array not an octet array. Just sticking a long in for padding
+// won't work with compilers that optimize unused data out of existence.
+//
+static const CORBA_Long _oc_opaque [] = { // CDR typecode octets
+ 1, // native endian + padding; "tricky"
+ 10, // ... (sequence of) octets
+ 0 // ... unbounded
+};
+CORBA_TypeCode TC_opaque (tk_sequence,
+ sizeof _oc_opaque, (unsigned char *) &_oc_opaque,
+ CORBA_B_FALSE);
+
+
+//
+// Octet codes for the parameters of the ServiceContextList TypeCode ...
+// this is a CDR encapsulation holding two parameters (like all sequences):
+// a TypeCode, and the bounds of the sequence (zero in this case).
+//
+// This is complicated since the Typecode for the data type for the sequence
+// members is complex, a structure that nests two further typecodes (one is
+// a sequence).
+//
+// NOTE: this must be longword aligned!
+//
+static const CORBA_Long _oc_svc_ctx_list [] = {
+ // START bytes of encapsulation 0
+ 1, // native endian + padding; "tricky"
+
+ //
+ // FIRST sequence param: typecode for struct is complex,
+ // and so uses a nested encapsulation.
+ //
+ tk_struct,
+ 72, // length of encapsulation 1
+
+ // START bytes of encapsulation 1 (struct params)
+ 1, // native endian + padding; "tricky"
+ 1, 0, // type ID omitted: null string
+ 1, 0, // name omitted "ServiceContext"
+
+ 2, // two struct elements
+
+ //
+ // First structure element: name, typecode for ULong
+ //
+ // NOTE: to be more strictly correct this could be a tk_alias
+ // typecode ...
+ //
+ 1, 0, // name omitted: "context_id"
+ tk_long,
+
+ //
+ // Second structure element: name, typecode for sequence of octet;
+ // the typecode for sequence of octet is complex, there's a second
+ // level of nested encapuslation here.
+ //
+ 1, 0, // name omitted: "context_data"
+ tk_sequence, // sequence typecode
+ 16, // length of encapsulation 2
+
+ // START bytes of encapsulation 2 (sequence params)
+ 1, // native endian + padding; "tricky"
+ 1, 0, // type ID omitted: null string
+ tk_octet, // (sequence of) octet
+ 0, // ... unbounded length
+ // END bytes of encapsulation 2 (sequence params)
+
+ // END bytes of encapsulation 1 (struct params)
+
+ //
+ // SECOND sequence param: bound of sequence (none)
+ //
+ 0 // unbounded seq of ServiceContext
+ // END bytes of encapsulation 0 (sequence params)
+};
+static CORBA_TypeCode TC_ServiceContextList (tk_sequence,
+ sizeof _oc_svc_ctx_list, (unsigned char *) &_oc_svc_ctx_list,
+ CORBA_B_FALSE);
+
+
+//
+// The public API involves creating an invocation, starting it, filling
+// in request parameters, actually performing the invocation, getting
+// response parameters, and then cleaning up. Sometimes they must be
+// restarted (e.g. request forwarding). This is the start/restart entry.
+//
+void
+GIOP::Invocation::start (
+ CORBA_Environment &env
+)
+{
+ const opaque *key;
+
+ //
+ // First try to bind to the appropriate address. We do that here since
+ // we may get forwarded to a different objref in the course of any
+ // given call, with new start() call each time. It's not cached in
+ // the objref data since the connections change asynchronously from
+ // objref invocations and this simplifies connection management.
+ //
+ // THREADING NOTE: this connection is reserved to this call. Also,
+ // starting at this point in the call, new forwarding information will
+ // not be used until/unless the call is reissued. Correctness is not
+ // affected, the call will just be forwarded later than it might be
+ // in a more complex implementation.
+ //
+ assert (endpoint == 0);
+ assert (_data != 0);
+
+#ifdef _POSIX_THREADS
+ Critical section (&fwd_info_lock);
+#endif // _POSIX_THREADS
+
+ if (_data->fwd_profile != 0) {
+ key = &_data->fwd_profile->object_key;
+ endpoint = client_endpoint::lookup (
+ (char *)_data->fwd_profile->host,
+ _data->fwd_profile->port, env);
+ } else {
+ key = &_data->profile.object_key;
+ endpoint = client_endpoint::lookup (
+ (char *)_data->profile.host,
+ _data->profile.port, env);
+ }
+ if (env.exception () != 0) {
+ dexc (env, "invoke, lookup client endpoint");
+ return;
+ }
+
+ //
+ // POLICY DECISION: If the client expects most agents to forward, then
+ // it could try to make sure that it's been forwarded at least once by
+ // eliciting it with a LocateRequest message. (Further hinting in the
+ // IIOP::ProfileData could help!)
+ //
+ // That scenario does not match an "Inter" ORB Protocol well, since
+ // bridges chain calls rather than forwarding them. It does match
+ // some kinds of "Intra" ORB scenarios well, with many agents that
+ // spawn new processes talking to their clients across the net.
+ //
+ // At this time, the policy noted above is followed in the sense
+ // that this software does NOT expect most agents to forward, so it
+ // doesn't bother to probe. Correctness is not affected; this is
+ // only a quality-of-service policy. It affects mostly performance,
+ // but the "best efforts" semantics for "oneway" messages would also
+ // be impacted in that some (by definition, buggy!) code which used
+ // only "oneway" messages might not work at all.
+ //
+
+ //
+ // Build the outgoing message, starting with generic GIOP header.
+ //
+ if (start_message (Request, stream) != CORBA_B_TRUE) {
+ env.exception (new CORBA_MARSHAL (COMPLETED_NO));
+ return;
+ }
+
+ //
+ // Then fill in the rest of the RequestHeader
+ //
+ // The first element of header is service context list; transactional
+ // context would be acquired here using the transaction service APIs.
+ // Other kinds of context are as yet undefined.
+ //
+ // Last element of request header is the principal; no portable way
+ // to get it, we just pass empty principal (convention: indicates
+ // "anybody"). Steps upward in security include passing an unverified
+ // user ID, and then verifying the message (i.e. a dummy service context
+ // entry is set up to hold a digital signature for this message, then
+ // patched shortly before it's sent).
+ //
+ static CORBA_Principal_ptr anybody = 0;
+ static ServiceContextList svc_ctx; // all zeroes
+
+ if (CDR::encoder (&TC_ServiceContextList, 0, &svc_ctx, &stream, env)
+ != CORBA_TypeCode::TRAVERSE_CONTINUE)
+ return;
+
+ if (!stream.put_ulong (my_request_id) || !stream.put_boolean (do_rsvp)) {
+ env.exception (new CORBA_MARSHAL (COMPLETED_NO));
+ return;
+ }
+
+ if (CDR::encoder (&TC_opaque, key, 0, &stream, env)
+ != CORBA_TypeCode::TRAVERSE_CONTINUE
+ || CDR::encoder (_tc_CORBA_String, &opname, 0, &stream, env)
+ != CORBA_TypeCode::TRAVERSE_CONTINUE
+ || CDR::encoder (_tc_CORBA_Principal, &anybody, 0, &stream, env)
+ != CORBA_TypeCode::TRAVERSE_CONTINUE)
+ return; // right after fault
+ else
+ return; // no fault reported
+}
+
+extern CORBA_ExceptionList __system_exceptions;
+
+//
+// Send request, block until any reply comes back, and unmarshal
+// reply parameters as appropriate.
+//
+GIOP::ReplyStatusType
+GIOP::Invocation::invoke (
+ CORBA_ExceptionList &exceptions,
+ CORBA_Environment &env
+)
+{
+ //
+ // Send Request, return on error or if we're done
+ //
+ if (!send_message (stream, endpoint->fd)) {
+ //
+ // send_message() closed the connection; we just release it here.
+ //
+ // XXX highly desirable to know whether we wrote _any_ data; if
+ // we wrote none, then there's no chance the call completed and
+ // applications don't have to deal with those nasty indeterminate
+ // states where they can't immediatly tell if what's safe to do.
+ //
+ // XXX also, there might have been a GIOP::CloseConnection message
+ // in the input queue. If so, this request should be treated as
+ // a (full) "rebind" case. Can't do that from this point in the
+ // code however! Some minor restructuring needs to happen.
+ //
+ endpoint = 0;
+ env.exception (new CORBA_COMM_FAILURE (COMPLETED_MAYBE));
+ return SYSTEM_EXCEPTION;
+ }
+ if (!do_rsvp)
+ return NO_EXCEPTION;
+
+ //
+ // This blocks until the response is read. In the current version,
+ // there is only one client thread that ever uses this connection, so
+ // most response messages are illegal.
+ //
+ // THREADING NOTE: to make more efficient use of connection resources,
+ // we'd multiplex I/O on connections. For example, one thread would write
+ // its GIOP::Request (or GIOP::LocateRequest etc) message and block for
+ // the response, then another would do the same thing. When a response
+ // came back, it would be handed to the thread which requested it.
+ //
+ // Currently the connection manager doesn't support such fine grained
+ // connection locking, and also this server implementation wouldn't
+ // take advantage of that potential concurrency in requests either.
+ // There are often performance losses coming from fine-grained locks
+ // being used inappropriately; there's some evidence that locking at
+ // the level of requests loses on at least some platforms.
+ //
+ // XXX In all MT environments, there's a cancellation point lurking
+ // here; need to investigate. Client threads would frequently be
+ // canceled sometime during read_message ... the correct action to
+ // take on being canceled is to issue a CancelRequest message to
+ // the server and then imediately let other client-side cancellation
+ // handlers do their jobs.
+ //
+ // In C++, that basically means to unwind the stack using almost normal
+ // procedures: all destructors should fire, and some "catch" blocks
+ // should probably be able to handle things like releasing pointers.
+ // (Without unwinding the C++ stack, resources that must be freed by
+ // thread cancellation won't be freed, and the process won't continue
+ // to function correctly.) The tricky part is that according to POSIX,
+ // all C stack frames must also have their (explicitly coded) handlers
+ // called. We assume a POSIX.1c/C/C++ environment.
+ //
+ switch (read_message (endpoint->fd, stream, env)) {
+ case Reply:
+ // handle reply ... must be right one etc
+ break;
+
+ case CloseConnection:
+ //
+ // Special case of forwarding -- server was closing the connection,
+ // which just indicates resource constraints, not an error. The
+ // client is effectively "forwarded" to the same server!
+ //
+ // However, we must reinitialize the forwarding chain, since the
+ // resource being reclaimed might also have been the process, not
+ // just the connection. Without reinitializing, we'd give false
+ // error reports to applications.
+ //
+ {
+#ifdef _POSIX_THREADS
+ Critical section (&fwd_info_lock);
+#endif // _POSIX_THREADS
+
+ delete _data->fwd_profile;
+ _data->fwd_profile = 0;
+
+ (void) closesocket (endpoint->fd);
+ endpoint->fd = -1;
+ endpoint = 0;
+ return LOCATION_FORWARD;
+ }
+
+ case Request:
+ case CancelRequest:
+ case LocateRequest:
+ case LocateReply:
+ default:
+ //
+ // These are all illegal messages to find. If found, they could be
+ // indicative of client bugs (lost track of input stream) or server
+ // bugs; maybe the request was acted on, maybe not, we can't tell.
+ //
+ dmsg ("illegal message in response to my Request!");
+ env.exception (new CORBA_COMM_FAILURE (COMPLETED_MAYBE));
+ // FALLTHROUGH ...
+
+ case MessageError:
+ //
+ // Couldn't read it for some reason ... exception's set already,
+ // so just tell the other end about the trouble (closing the
+ // connection) and return.
+ //
+ send_error (endpoint->fd);
+ return SYSTEM_EXCEPTION;
+ }
+
+ //
+ // Process reply message. Again, due to the single threading in this
+ // code, only the reply to this request is allowed to be coming back.
+ //
+ // NOTE: if the response really _isn't_ for this thread, it's now
+ // treated as an error in which synchronization can't be recovered.
+ // There might be cases where it _could_ be recovered ... e.g. maybe
+ // for some reason the previous call couldn't pick up its response.
+ // It'd be worth investigating (and handling) any such cases.
+ //
+ // NOTE: since this implementation supports no ORB services (notably,
+ // the transaction service, which is the only one that's currently
+ // defined), the reply context is discarded. Normally it'd be fed,
+ // component at a time, to the relevant services.
+ //
+ // NOTE: As security support kicks in, this is the right place to
+ // verify a digital signature, if that is required in this particular
+ // runtime security environment. How to know if that's the case?
+ // It's likely that standard Internet IPSEC infrastructure (RFC 1825
+ // through 1827, and successors) will be used to enforce many security
+ // policies; integrity and privacy guarantees may be provided by the
+ // network, and need no support here.
+ //
+ ServiceContextList reply_ctx;
+ CORBA_ULong request_id;
+ CORBA_ULong reply_status; // GIOP::ReplyStatusType
+
+ if (CDR::decoder (&TC_ServiceContextList, &reply_ctx, 0, &stream, env)
+ != CORBA_TypeCode::TRAVERSE_CONTINUE) {
+ send_error (endpoint->fd);
+ return SYSTEM_EXCEPTION;
+ }
+ delete reply_ctx.buffer;
+
+ if (!stream.get_ulong (request_id)
+ || request_id != my_request_id
+ || !stream.get_ulong (reply_status)
+ || reply_status > LOCATION_FORWARD) {
+ send_error (endpoint->fd);
+ env.exception (new CORBA_COMM_FAILURE (COMPLETED_MAYBE));
+ dmsg ("bad Response header");
+ return SYSTEM_EXCEPTION;
+ }
+
+ //
+ // If there was no exception, let the caller parse the normal response.
+ // Otherwise parse and handle the response; we always know how to deal
+ // with the standard exceptions, and the caller provides a list of
+ // allowed user-defined exceptions so that we know how to unmarshal
+ // those too (without IFR consultation).
+ //
+ // When requests are forwarded, we just store the revised profile data
+ // in this objref structure. The expectation is that the call will
+ // be reissued until someone gives up on a forwarding chain, and that
+ // other calls will reap the benefit of the forwarding work by this
+ // thread.
+ //
+ // NOTE: should ensure that from here on, all system exceptions
+ // return COMPLETED_YES status ... even ones reported by code which
+ // we call.
+ //
+ switch (reply_status) {
+ case NO_EXCEPTION:
+ break;
+
+ case USER_EXCEPTION:
+ case SYSTEM_EXCEPTION:
+ {
+ CORBA_String exception_id;
+
+ //
+ // Pull the exception ID out of the marshaling buffer.
+ //
+ {
+ CORBA_ULong len;
+
+ //
+ // Read "length" field of string, so "next" points
+ // right at the null-terminated ID. Then get the ID.
+ //
+ if (stream.get_ulong (len) != CORBA_B_TRUE
+ || len > stream.remaining) {
+ send_error (endpoint->fd);
+ env.exception (new CORBA_MARSHAL (COMPLETED_YES));
+ return SYSTEM_EXCEPTION;
+ }
+ exception_id = (CORBA_String) stream.next;
+ stream.skip_bytes (len);
+ }
+
+ //
+ // User and system exceptions differ only in what table of
+ // exception typecodes is searched.
+ //
+ CORBA_ExceptionList *xlist;
+
+ if (reply_status == USER_EXCEPTION)
+ xlist = &exceptions;
+ else
+ xlist = &__system_exceptions;
+
+ //
+ // Find it in the operation description and then use that to get
+ // the typecode. Use it to unmarshal the exception's value; if
+ // that exception is not allowed by this operation, fail (next).
+ //
+ unsigned i;
+ CORBA_TypeCode_ptr *tcp;
+
+ for (i = 0, tcp = xlist->buffer;
+ i < xlist->length;
+ i++, tcp++) {
+ CORBA_String xid;
+
+ xid = (*tcp)->id (env);
+ if (env.exception () != 0) {
+ dexc (env, "invoke(), get exception ID");
+ send_error (endpoint->fd);
+ return SYSTEM_EXCEPTION;
+ }
+
+ if (strcmp ((char *)exception_id, (char *)xid) == 0) {
+ size_t size;
+ CORBA_Exception *exception;
+
+ size = (*tcp)->size (env);
+ if (env.exception () != 0) {
+ dexc (env, "invoke(), get exception size");
+ send_error (endpoint->fd);
+ return SYSTEM_EXCEPTION;
+ }
+
+ //
+ // Create the exception, fill in the generic parts
+ // such as vtable, typecode ptr, refcount ... we
+ // need to clean them all up together, in case of
+ // errors unmarshaling.
+ //
+ exception = new (new char [size]) CORBA_Exception (*tcp);
+
+ if (CDR::decoder (*tcp, exception, 0, &stream, env)
+ != CORBA_TypeCode::TRAVERSE_CONTINUE) {
+ delete exception;
+ dmsg2 ("invoke, unmarshal %s exception %s",
+ (reply_status == USER_EXCEPTION)
+ ? "user" : "system",
+ exception_id);
+ send_error (endpoint->fd);
+ return SYSTEM_EXCEPTION;
+ }
+ env.exception (exception);
+ return (GIOP::ReplyStatusType) reply_status;
+ }
+ }
+
+ //
+ // If we couldn't find this exception's typecode, report it as
+ // an OA error since the skeleton passed an exception that was
+ // not allowed by the operation's IDL definition. In the case
+ // of a dynamic skeleton it's actually an implementation bug.
+ //
+ // It's known to be _very_ misleading to try reporting this as
+ // any kind of marshaling error (unless minor codes are made
+ // to be _very_ useful) ... folk try to find/fix ORB bugs that
+ // don't exist, not bugs in/near the implementation code.
+ //
+ if (reply_status == USER_EXCEPTION)
+ env.exception (new CORBA_OBJ_ADAPTER (COMPLETED_YES));
+ else
+ env.exception (new CORBA_INTERNAL (COMPLETED_MAYBE));
+ return SYSTEM_EXCEPTION;
+ }
+ // NOTREACHED
+
+ case LOCATION_FORWARD:
+ {
+ CORBA_Object_ptr obj;
+ IIOP_Object *obj2;
+
+ //
+ // Unmarshal the object we _should_ be calling. We know
+ // that one of the facets of this object will be an IIOP
+ // invocation profile.
+ //
+ if (CDR::decoder (_tc_CORBA_Object, &obj, 0, &stream, env)
+ != CORBA_TypeCode::TRAVERSE_CONTINUE
+ || obj->QueryInterface (IID_IIOP_Object, (void **)&obj2)
+ != NOERROR
+ ) {
+ dexc (env, "invoke, location forward");
+ send_error (endpoint->fd);
+ return SYSTEM_EXCEPTION;
+ }
+ CORBA_release (obj);
+
+ //
+ // Make a copy of the IIOP profile in the forwarded objref,
+ // reusing memory where practical. Then delete the forwarded
+ // objref, retaining only its profile.
+ //
+ // XXX add and use a "forward count", to prevent loss of data
+ // in forwarding chains during concurrent calls -- only a
+ // forward that's a response to the current fwd_profile should
+ // be recorded here. (This is just an optimization, and is
+ // not related to correctness.)
+ //
+#ifdef _POSIX_THREADS
+ Critical section (&fwd_info_lock);
+#endif // _POSIX_THREADS
+
+ delete _data->fwd_profile;
+ _data->fwd_profile = new IIOP::ProfileBody (obj2->profile);
+
+ obj2->Release ();
+
+ env.clear ();
+
+ //
+ // Make sure a new connection is used next time.
+ //
+ endpoint = 0;
+ }
+ break;
+ }
+
+ //
+ // All standard exceptions from here on in the call path know for certain
+ // that the call "completed" ... except in the case of system exceptions
+ // which say otherwise, and for LOCATION_FORWARD responses.
+ //
+ return (GIOP::ReplyStatusType) reply_status;
+}
+
+
+//
+// Generic server side read + dispatch one message; returns when that
+// bit of work is complete.
+//
+// In the typical case, the request and response buffers live on the
+// stack so that the heap never gets used. These grow if needed.
+//
+void
+GIOP::incoming_message (
+ int &fd,
+ LocateStatusType check_forward (
+ opaque &key,
+ CORBA_Object_ptr &objref,
+ void *context
+ ),
+ void handle_request (
+ RequestHeader &req,
+ CDR &req_body,
+ CDR *reply,
+ void *context,
+ CORBA_Environment &env
+ ),
+ void *context,
+ CORBA_Environment &env
+)
+{
+ unsigned char buffer [CDR::DEFAULT_BUFSIZE];
+ CDR msg (&buffer [0], sizeof buffer);
+
+ switch (read_message (fd, msg, env)) {
+ case Request:
+ {
+ RequestHeader req;
+ CORBA_Boolean hdr_status;
+
+ //
+ // Tear out the service context ... we currently ignore it,
+ // but it should probably be passed to each ORB service as
+ // appropriate (e.g. transactions, security).
+ //
+ // NOTE: As security support kicks in, this is a good place
+ // to verify a digital signature, if that is required in this
+ // security environment. It may be required even when using
+ // IPSEC security infrastructure.
+ //
+ hdr_status = CDR::decoder (&TC_ServiceContextList,
+ &req.service_info, 0, &msg, env);
+
+ //
+ // Get the rest of the request header ...
+ //
+ hdr_status = hdr_status && msg.get_ulong (req.request_id);
+ hdr_status = hdr_status && msg.get_boolean (req.response_expected);
+ hdr_status = hdr_status && CDR::decoder (&TC_opaque, &req.object_key,
+ 0, &msg, env);
+ hdr_status = hdr_status && CDR::decoder (_tc_CORBA_String, &req.operation,
+ 0, &msg, env);
+ hdr_status = hdr_status && CDR::decoder (_tc_CORBA_Principal,
+ &req.requesting_principal, 0, &msg, env);
+
+
+ // XXX check whether hdr_status identifies a header
+ // unmarshaling error, and handle appropriately
+
+#ifdef DEBUG
+ if (debug_level >= 3) {
+ dmsg_v ("%sRequest ID %#lx from FD %d",
+ req.response_expected ? "" : "Oneway ",
+ req.request_id, fd);
+ if (debug_level >= 4) {
+ dmsg_opaque ("object key", req.object_key.buffer,
+ req.object_key.length);
+ dmsg_v (" opname '%s'", req.operation);
+ if (req.requesting_principal)
+ dmsg_opaque ("client principal",
+ req.requesting_principal->id.buffer,
+ req.requesting_principal->id.length);
+ else
+ dmsg (" client principal (EMPTY)");
+ }
+
+ // NOTE: describe any service context, and how
+ // many bytes of non-header data were sent.
+ }
+#endif // DEBUG
+
+ //
+ // Verify that we're to dispatch the request within this
+ // particular process.
+ //
+ if (check_forward != 0) {
+ LocateStatusType status;
+ CORBA_Object_ptr fwd_ref = 0;
+
+ status = check_forward (req.object_key, fwd_ref, context);
+ if (status != OBJECT_HERE) {
+ ServiceContextList resp_ctx;
+ unsigned char buf2 [CDR::DEFAULT_BUFSIZE];
+ CDR response (&buf2 [0],
+ sizeof buf2);
+
+ start_message (Reply, response);
+ resp_ctx.length = 0;
+ CDR::encoder (&TC_ServiceContextList, &resp_ctx,
+ 0, &response, env);
+ response.put_ulong (req.request_id);
+
+ //
+ // If we're not sending a response, just clean up.
+ //
+ if (!req.response_expected) {
+ if (status == OBJECT_FORWARD)
+ CORBA_release (fwd_ref);
+
+ //
+ // Else either forward the request ...
+ //
+ } else if (status == OBJECT_FORWARD) {
+ dmsg ("forwarding Request message");
+ response.put_ulong (LOCATION_FORWARD);
+ CDR::encoder (_tc_CORBA_Object, &fwd_ref,
+ 0, &response, env);
+ CORBA_release (fwd_ref);
+ (void) send_message (response, fd);
+
+ //
+ // ... or report exception that the object doesn't exist.
+ //
+ } else {
+ CORBA_OBJECT_NOT_EXIST exc (COMPLETED_YES);
+
+ response.put_ulong (SYSTEM_EXCEPTION);
+ (void) CDR::encoder (_tc_CORBA_OBJECT_NOT_EXIST,
+ &exc, 0, &response, env);
+
+ (void) send_message (response, fd);
+ }
+
+ delete req.object_key.buffer;
+ CORBA_string_free (req.operation);
+ return;
+ }
+ }
+
+
+ //
+ // So, we read a request, now dispatch it using something more
+ // primitive than a CORBA2 ServerRequest pseudo-object.
+ //
+ if (req.response_expected) {
+ ServiceContextList resp_ctx;
+ unsigned char buf2 [CDR::DEFAULT_BUFSIZE];
+ CDR response (&buf2 [0], sizeof buf2);
+
+ start_message (Reply, response);
+ resp_ctx.length = 0;
+ CDR::encoder (&TC_ServiceContextList, &resp_ctx,
+ 0, &response, env);
+ response.put_ulong (req.request_id);
+
+ handle_request (req, msg, &response, context, env);
+
+ //
+ // "handle_request" routine puts ReplyStatusType then
+ // parameters.
+ //
+ (void) send_message (response, fd);
+ } else
+ handle_request (req, msg, 0, context, env);
+
+ delete req.object_key.buffer;
+ CORBA_string_free (req.operation);
+ }
+ break;
+
+ //
+ // Forward requests as needed; if caller hasn't provided code to
+ // support forwarding, we default to doing no forwarding.
+ //
+ case LocateRequest:
+ {
+ CORBA_ULong request_id;
+ opaque key;
+
+ msg.get_ulong (request_id);
+ CDR::decoder (&TC_opaque, &key, 0, &msg, env);
+
+ //
+ // we've read the request header; send a LocateReply
+ //
+ unsigned char resp [CDR::DEFAULT_BUFSIZE];
+ CDR response (resp, sizeof resp);
+ CORBA_Object_ptr fwd_ref = 0;
+
+ start_message (LocateReply, response);
+ response.put_ulong (request_id);
+ if (check_forward == 0) {
+ response.put_ulong (OBJECT_HERE);
+ dmsg ("LocateRequest response: object is (always) here!");
+ } else {
+ LocateStatusType status;
+
+ status = check_forward (key, fwd_ref, context);
+ response.put_ulong ((CORBA_ULong) status);
+ if (status == OBJECT_FORWARD) {
+ dmsg ("LocateRequest response: forward requests");
+ CDR::encoder (_tc_CORBA_Object, &fwd_ref, 0,
+ &response, env);
+ } else if (status == OBJECT_HERE) {
+ dmsg ("LocateRequest response: object is here!");
+ } else {
+ dmsg ("LocateRequest response: no such object");
+ }
+ }
+ (void) send_message (response, fd);
+ }
+ break;
+
+ //
+ // Cancel request -- ignored this implementation.
+ //
+ // THREADING NOTE: Handling it would require (a) some thread to read
+ // the CancelRequest while one was working on handling the Request,
+ // (b) a way to find the thread working on that request, (c) using
+ // thread cancellation to alert that thread that the work it's
+ // been doing can safely be discarded. Also of course (d) making
+ // the various worker threads cleanly handle cancellation, and
+ // (e) modifying client code to send a CancelRequest when it's
+ // been canceled.
+ //
+ case CancelRequest:
+ {
+ CORBA_ULong request_id;
+
+ msg.get_ulong (request_id);
+ }
+ break;
+
+ //
+ // These messages should never be sent to the server; it's an error
+ // if the peer tries. Set the environment accordingly, as it's not
+ // yet been reported as an error.
+ //
+ case Reply:
+ case LocateReply:
+ case CloseConnection:
+ default: // Unknown message
+ dmsg ("Illegal message received by server");
+ env.exception (new CORBA_COMM_FAILURE (COMPLETED_NO));
+ // FALLTHROUGH
+
+ //
+ // read_message() has already set some error in the environment for
+ // all "MessageError" cases, so don't clobber it.
+ //
+ // General error recovery is to send MessageError to the peer just
+ // in case (it'll fail on EOF) and then close the connection.
+ //
+ case MessageError:
+ send_error (fd);
+ break;
+ }
+
+ // ... error if unconsumed data remains; is this the spot to test that?
+}
diff --git a/TAO/IIOP/lib/bridge/giop.hh b/TAO/IIOP/lib/bridge/giop.hh
new file mode 100644
index 00000000000..daf952ef0e0
--- /dev/null
+++ b/TAO/IIOP/lib/bridge/giop.hh
@@ -0,0 +1,317 @@
+// @(#)giop.hh 1.2 95/09/06
+// Copyright 1994-1995 by Sun Microsystems Inc.
+// All Rights Reserved
+//
+// GIOP data structures and support routines
+//
+// Note that some symbols in this module are part of the "Internet"
+// Inter-ORB Protocol (IIOP), not the General IOP. Only addressing
+// information and certain details of connection usage are specific
+// to IIOP; all other protocol details can be reused by ORB protocols
+// that are built atop connection protocols other than TCP.
+//
+// THREADING NOTE: Threads should never manipulate another thread's
+// invocations. In this implementation, all data structures used to
+// represent invocations (and parts of them) are owned by the thread
+// which created them. Multiple threads may make of course concurrent
+// invocations safely, since the GIOP code is reentrant.
+//
+
+#ifndef _GIOP_HH
+#define _GIOP_HH
+
+#include <corba/orb.hh>
+#include <corba/stub.hh>
+
+#include "bridge/connmgr.hh"
+#include "bridge/iiopobj.hh" // XXX -- not generic!
+
+
+// XXX this same typedef is used in other places, e.g. iiopobj.hh
+typedef CORBA_SEQUENCE <CORBA_Octet> opaque;
+
+class IOP { // namespace
+ public:
+ //
+ // Assigned Protocol/Profile tag values. ORB protcols may be
+ // uniquely identified by tags such as these. This allows each
+ // ORB's own objref profiles to be interchanged using IORs.
+ //
+ // Email to tag-request@omg.org to allocate tags
+ //
+ typedef CORBA_ULong ProfileId;
+ enum {
+ TAG_INTERNET_IOP = 0, // IIOP
+ TAG_MULTIPLE_COMPONENTS = 1, // DCE-CIOP
+
+ //
+ // This is a subset of the list of other profile tags
+ //
+ TAG_ONC_IOP = 0x4f4e4300 // ONC IOP
+ };
+
+ struct TaggedProfile { // one per protocol
+ ProfileId tag;
+ opaque profile_data;
+ };
+ typedef CORBA_SEQUENCE <TaggedProfile> TaggedProfileSeq;
+
+ //
+ // InteroperableObjectReference ... a set of protocol-specific
+ // protocol profiles, plus a type ID. Only one object is denoted
+ // by all of this information. It's OK to delete all profiles
+ // except the one for the single protocol actually being used.
+ //
+ struct IOR {
+ char *type_id;
+ TaggedProfileSeq profiles;
+ };
+
+ //
+ // Some protocols can be factored into a set of optional components.
+ // Use of such components is defined by the protocol's specification.
+ //
+ // Email to tag-request@omg.org to allocate tags
+ //
+ typedef CORBA_ULong ComponentId;
+ enum {
+ //
+ // these are all defined by DCE-CIOP in OMG TC document 95-3-10
+ //
+ TAG_DCE_STRING_BINDING = 100, // string binding handle
+ TAG_DCE_BINDING_NAME = 101, // CDS/GDS/... name
+ TAG_DCE_NO_PIPES = 102, // no component data
+ TAG_OBJECT_KEY = 10, // opaque
+ TAG_ENDPOINT_ID = 11, // uuid
+ TAG_LOCATION_POLICY = 12 // octet/enum
+ };
+
+ //
+ // One way to represent multicomponent profiles, e.g. as done by
+ // the DCE-CIOP protocol. One of these gets encapsulated in
+ // TaggedProfile::profile_data. TAG_MULTIPLE_COMPONENTS may be
+ // used to represent protocol profiles structured in that way,
+ // but protocol-specific tags facilitate simpler scanning of IORs
+ // since you can be assured that each profile only has data used
+ // within a single ORB protocol.
+ //
+ struct TaggedComponent {
+ ComponentId tag;
+ opaque component_data;
+ };
+ typedef CORBA_SEQUENCE <TaggedComponent> MultipleComponentProfile;
+};
+
+
+class GIOP { // namespace
+
+ public:
+ struct Version { CORBA_Octet major, minor; };
+
+ //
+ // GIOP protocol version information
+ //
+ enum { MY_MAJOR = 1, MY_MINOR = 0 }; // 1.0
+
+ //
+ // All GIOP messages include a header and message type.
+ //
+ enum MsgType {
+ Request = 0, // sent by client
+ Reply = 1, // by server
+ CancelRequest = 2, // by client
+ LocateRequest = 3, // by client
+ LocateReply = 4, // by server
+ CloseConnection = 5, // by server
+ MessageError = 6 // by both
+ };
+
+ struct MessageHeader {
+ CORBA_Char magic [4]; // "GIOP"
+ Version giop_version;
+ CORBA_Octet byte_order; // 0 = big, 1 = little
+ CORBA_Octet message_type; // MsgType above
+ CORBA_ULong message_size; // in byte_order!
+ };
+
+ //
+ // Support for Implicit ORB Service Context
+ //
+ typedef CORBA_ULong ServiceID;
+ enum {
+ TransactionService = 0
+ //
+ // more service IDs may be defined by OMG
+ //
+ };
+ struct ServiceContext {
+ ServiceID context_id;
+ opaque context_data;
+ };
+ typedef CORBA_SEQUENCE <ServiceContext> ServiceContextList;
+
+ //
+ // Request, Reply headers
+ //
+ struct RequestHeader {
+ ServiceContextList service_info;
+ CORBA_ULong request_id;
+ CORBA_Boolean response_expected;
+ opaque object_key;
+ CORBA_String operation;
+ CORBA_Principal_ptr requesting_principal;
+ };
+
+ enum ReplyStatusType {
+ NO_EXCEPTION,
+ USER_EXCEPTION,
+ SYSTEM_EXCEPTION,
+ LOCATION_FORWARD
+ };
+
+ struct ReplyHeader {
+ ServiceContextList service_info;
+ CORBA_ULong request_id;
+ ReplyStatusType reply_status;
+ };
+
+ //
+ // Cancellation -- applies both to Requests and LocateRequests.
+ //
+ struct CancelRequestHeader {
+ CORBA_ULong request_id;
+ };
+
+ //
+ // Location service support
+ //
+ struct LocateRequestHeader {
+ CORBA_ULong request_id;
+ opaque object_key;
+ };
+
+ enum LocateStatusType {
+ UNKNOWN_OBJECT,
+ OBJECT_HERE,
+ OBJECT_FORWARD
+ };
+
+ struct LocateReplyHeader {
+ CORBA_ULong request_id;
+ LocateStatusType locate_status;
+ };
+
+
+ //
+ // Invocation: Sends a Request, optionally reads associated Reply.
+ // Uses transport info passed in, doesn't locate anything.
+ //
+ class Invocation {
+ public:
+ Invocation (
+ IIOP_Object *data,
+ const char *operation,
+ CORBA_Boolean is_roundtrip
+ );
+ ~Invocation ();
+
+ //
+ // "start" goes beyond initialising data structures, and
+ // makes calls that may fail -- and thus throw exceptions.
+ //
+ void start (
+ CORBA_Environment &env
+ );
+
+ void put_param (
+ CORBA_TypeCode_ptr tc,
+ void *value,
+ CORBA_Environment &env
+ )
+ {
+ (void) CDR::encoder (tc, value, 0, &stream, env);
+ }
+
+ ReplyStatusType invoke (
+ CORBA_ExceptionList &exceptions,
+ CORBA_Environment &env
+ );
+
+ void get_value (
+ CORBA_TypeCode_ptr tc,
+ void *value,
+ CORBA_Environment &env
+ )
+ {
+ (void) CDR::decoder (tc, value, 0, &stream, env);
+ }
+
+ // no CORBA_Context support (deprecated)
+
+ private:
+ IIOP_Object *_data;
+ const char *opname;
+ CORBA_Boolean do_rsvp;
+ CORBA_ULong my_request_id;
+
+ unsigned char buffer [CDR::DEFAULT_BUFSIZE];
+ CDR stream;
+
+ autorelease <client_endpoint> endpoint;
+ };
+
+ //
+ // Close a connection, first sending GIOP::CloseConnection
+ //
+ static void close_connection (int &fd, void *ctx);
+
+ //
+ // Generic server side data dispatch -- called for all file descriptors
+ // on which incoming messages are expected.
+ //
+ // The handle_request() routine is used to handle request messages; its
+ // 'reply' parameter is null if the request is "oneway" (or the client
+ // isn't waiting for the response that this request normally creates).
+ //
+ // The optional check_forward() routine is used to verify that the
+ // request is to be delivered within this process by handle_request().
+ // Each call to handle_request() is preceded by a call to this routine
+ // if it's provided. It's used when handling GIOP "Request" messages
+ // as well as GIOP "LocateRequest" messages, and returns an enum to
+ // indicate overal status (LocateStatusType) as well as an objref
+ // in the case of OBJECT_FORWARD. That objref is released.
+ //
+ static void incoming_message (
+ int &fd,
+ LocateStatusType check_forward (
+ opaque &key,
+ CORBA_Object_ptr &objref,
+ void *context
+ ),
+ void handle_request (
+ RequestHeader &req,
+ CDR &request_body,
+ CDR *reply,
+ void *context,
+ CORBA_Environment &env
+ ),
+ void *context,
+ CORBA_Environment &env
+ );
+
+ static CORBA_Boolean send_message (
+ CDR &stream,
+ int &connection
+ );
+
+ //
+ // Reads message, returns message type from header
+ //
+ static MsgType read_message (
+ int &connection,
+ CDR &msg,
+ CORBA_Environment &env
+ );
+};
+
+#endif // _GIOP_HH
diff --git a/TAO/IIOP/lib/bridge/iiopobj.cpp b/TAO/IIOP/lib/bridge/iiopobj.cpp
new file mode 100644
index 00000000000..ba108478c72
--- /dev/null
+++ b/TAO/IIOP/lib/bridge/iiopobj.cpp
@@ -0,0 +1,198 @@
+// @(#)iiopobj.cpp 1.9 95/11/04
+// Copyright 1995 by Sun Microsystems Inc.
+// All Rights Reserved
+//
+// IIOP Bridge: CORBA::Object operations
+//
+// Some CORBA::Object and other operations are specific to this IIOP
+// based implementation, and can neither be used by other kinds of objref
+// nor have a default implementation.
+//
+
+#include <assert.h>
+#include <limits.h>
+#include <corba/orb.hh>
+
+#include <initguid.h>
+#include <string.h>
+
+#include <corba/stub.hh>
+
+#include "runtime/thread.hh"
+
+#include "bridge/iiopobj.hh"
+
+
+#ifdef _POSIX_THREADS
+//
+// If POSIX threads are available, set up lock covering refcounts.
+//
+static pthread_mutex_t iiopobj_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif // _POSIX_THREADS
+
+
+
+IIOP::ProfileBody::ProfileBody (
+ const IIOP::ProfileBody &src
+) :
+ iiop_version (src.iiop_version),
+ port (src.port)
+{
+ assert (src.iiop_version.major == MY_MAJOR);
+ assert (src.iiop_version.minor == MY_MINOR);
+
+ host = strdup (src.host);
+
+ object_key.length = object_key.maximum = src.object_key.length;
+ object_key.buffer = (CORBA_Octet *) malloc (object_key.maximum);
+ (void) memcpy (object_key.buffer, src.object_key.buffer,
+ object_key.length);
+}
+
+
+//
+// Quick'n'dirty hash of objref data, for partitioning objrefs into sets
+//
+// NOTE that this must NOT go across the network!
+//
+CORBA_ULong
+IIOP_Object::hash (
+ CORBA_ULong max,
+ CORBA_Environment &env
+)
+{
+ CORBA_ULong hashval;
+
+ env.clear ();
+
+ //
+ // Just grab a bunch of convenient bytes and hash them; could do
+ // more (hostname, full key, exponential hashing) but no real need
+ // to do so except if performance requires a more costly hash.
+ //
+ hashval = profile.object_key.length * profile.port;
+ hashval += profile.iiop_version.minor;
+ if (profile.object_key.length >= 4) {
+ hashval += profile.object_key.buffer [1];
+ hashval += profile.object_key.buffer [3];
+ }
+
+ return hashval % max;
+}
+
+
+//
+// Expensive comparison of objref data, to see if two objrefs certainly
+// point at the same object. (It's quite OK for this to return FALSE,
+// and yet have the two objrefs really point to the same object.)
+//
+// NOTE that this must NOT go across the network!
+//
+CORBA_Boolean
+IIOP_Object::is_equivalent (
+ CORBA_Object_ptr other_obj,
+ CORBA_Environment &env
+)
+{
+ IIOP::ProfileBody *body, *body2;
+ IIOP_Object *other_iiop_obj;
+
+ env.clear ();
+
+ if (CORBA_is_nil (other_obj) == CORBA_B_TRUE
+ || other_obj->QueryInterface (IID_IIOP_Object,
+ (void **)&other_iiop_obj) != NOERROR)
+ return CORBA_B_FALSE;
+ CORBA_release (other_obj);
+
+ //
+ // Compare all the bytes of the object address -- must be the same
+ //
+ body = &profile;
+ body2 = &other_iiop_obj->profile;
+
+ assert (body->object_key.length < UINT_MAX);
+
+ return body->object_key.length == body2->object_key.length
+ && memcmp (body->object_key.buffer, body2->object_key.buffer,
+ (size_t) body->object_key.length) == 0
+ && body->port == body2->port
+ && strcmp ((char *)body->host, (char *)body2->host) == 0
+ && body->iiop_version.minor == body2->iiop_version.minor
+ && body->iiop_version.major == body2->iiop_version.major;
+}
+
+
+//
+// For COM -- IUnknown operations
+//
+
+// {A201E4C3-F258-11ce-9598-0000C07CA898}
+DEFINE_GUID (IID_IIOP_Object,
+0xa201e4c3, 0xf258, 0x11ce, 0x95, 0x98, 0x0, 0x0, 0xc0, 0x7c, 0xa8, 0x98);
+
+
+ULONG
+__stdcall
+IIOP_Object::AddRef ()
+{
+#ifdef _POSIX_THREADS
+ Critical region (&iiopobj_lock);
+#endif
+
+ return ++_refcount;
+}
+
+ULONG
+__stdcall
+IIOP_Object::Release ()
+{
+#ifdef _POSIX_THREADS
+ Critical region (&iiopobj_lock);
+#endif
+
+ if (--_refcount != 0)
+ return _refcount;
+
+#ifdef _POSIX_THREADS
+ region.leave ();
+#endif
+
+ delete this;
+ return 0;
+}
+
+
+//
+// Note that (as of this writing) this is the only place all
+// the interfaces to an "objref" come together:
+//
+// IUnknown ... this one
+// STUB_OBJECT ... inherited by this one
+// IIOP_OBJECT ... this one
+//
+// CORBA_Object ... contained within this; it delegates back
+// to this one as its "parent"
+//
+HRESULT
+__stdcall
+IIOP_Object::QueryInterface (
+ REFIID riid,
+ void **ppv
+)
+{
+ *ppv = 0;
+
+ if (IID_IIOP_Object == riid
+ || IID_STUB_Object == riid
+ || IID_IUnknown == riid)
+ *ppv = this;
+ else if (IID_CORBA_Object == riid)
+ *ppv = &base;
+
+ if (*ppv == 0)
+ return ResultFromScode (E_NOINTERFACE);
+
+ (void) AddRef ();
+ return NOERROR;
+}
diff --git a/TAO/IIOP/lib/bridge/iiopobj.hh b/TAO/IIOP/lib/bridge/iiopobj.hh
new file mode 100644
index 00000000000..1ca702b23b3
--- /dev/null
+++ b/TAO/IIOP/lib/bridge/iiopobj.hh
@@ -0,0 +1,154 @@
+// @(#)iiopobj.hh 1.9 95/11/04
+// Copyright 1994-1995 by Sun Microsystems Inc.
+// All Rights Reserved
+//
+// IIOP objref representation
+//
+// This allows stubs which support multiple protocols, since the
+// stub (and DII) code only work with the parent "STUB_Objref"
+// class when making calls.
+//
+
+#ifndef _iiopobj_hh
+#define _iiopobj_hh
+
+typedef CORBA_SEQUENCE <CORBA_Octet> opaque;
+
+class _EXPCLASS IIOP
+{ // namespace
+ public:
+
+ struct Version { CORBA_Octet major, minor; };
+
+ //
+ // IIOP Protocol version is distinct from GIOP version.
+ //
+ enum { MY_MAJOR = 1, MY_MINOR = 0 };
+
+ //
+ // IOR support ... ProfileBody is encapsulated in an IIOP
+ // profile entry within an IOR.
+ //
+ struct ProfileBody {
+ Version iiop_version;
+ CORBA_String host;
+ CORBA_UShort port;
+ opaque object_key;
+
+ ProfileBody ()
+ : host (0) { }
+
+ ProfileBody (const ProfileBody &src);
+
+ ~ProfileBody ()
+ { delete host; delete object_key.buffer; }
+ private:
+ ProfileBody &operator = (const ProfileBody &src);
+ };
+};
+
+
+//
+// Representation of an IIOP objref: the profile body, and any
+// forwarded pointer. Implementations of basic invocation code;
+// how to marshal an objref. Contains a CORBA::Object interface.
+//
+// NOTE that this uses (single) implementation inheritance to share
+// most of the basic code for an object reference.
+//
+extern "C" const IID IID_IIOP_Object;
+
+class _EXPCLASS IIOP_Object : public STUB_Object
+{
+ public:
+ //
+ // stub-based invocation
+ //
+ void do_call (
+ CORBA_Environment &env,
+ const calldata *info,
+ ...
+ );
+
+ //
+ // DII based invocation
+ //
+ void do_dynamic_call (
+ const char *opname,
+ CORBA_Boolean is_roundtrip,
+ CORBA_NVList_ptr args,
+ CORBA_NamedValue_ptr result,
+ CORBA_Flags flags,
+ CORBA_ExceptionList &exceptions,
+ CORBA_Environment &env
+ );
+
+ //
+ // Support for tables keyed by objrefs.
+ //
+ CORBA_ULong hash (
+ CORBA_ULong maximum,
+ CORBA_Environment &env
+ );
+ CORBA_Boolean is_equivalent (
+ CORBA_Object_ptr other_obj,
+ CORBA_Environment &env
+ );
+
+ //
+ // XXX All objref representations should know how to marshal themselves.
+ // That will involve ensuring that the IOR that gets marshaled talks a
+ // specific protocol, otherwise the target of a message would not be
+ // invoke using the objref it receives (compromising functionality in
+ // a very basic and mysterious mannter). So for example an objref might
+ // need to create a proxy for itself rather than marshaling its own
+ // representation. [ The IIOP engine does not need to worry about such
+ // issues since it only supports one protocol -- the problem won't show
+ // up. "Multiprotocol ORBs" will need to solve that problem though. ]
+ //
+
+ IIOP::ProfileBody profile;
+ IIOP::ProfileBody *fwd_profile;
+
+ IIOP_Object (char *repository_id)
+ : fwd_profile (0), base (this),
+ STUB_Object (repository_id),
+ _refcount (1)
+ { }
+
+ //
+ // COM stuff
+ //
+ ULONG __stdcall AddRef ();
+ ULONG __stdcall Release ();
+ HRESULT __stdcall QueryInterface (
+ REFIID type_id,
+ void **ppv
+ );
+
+ private:
+ CORBA_Object base;
+ unsigned _refcount;
+
+ //
+ // Destructor is to be called only through Release()
+ //
+ ~IIOP_Object ()
+ { assert (_refcount == 0);
+ delete fwd_profile; }
+
+ //
+ // Disallow copy constructor and assignment operator
+ //
+ IIOP_Object (const IIOP_Object &);
+ operator = (const IIOP_Object &);
+#if defined (__GNUG__)
+ //
+ // G++ (even 2.6.3) stupidly thinks instances can't be
+ // created. This de-warns.
+ //
+ friend class everyone_needs_a_friend;
+#endif
+};
+
+#endif // _iiopobj_hh
diff --git a/TAO/IIOP/lib/bridge/iioporb.cpp b/TAO/IIOP/lib/bridge/iioporb.cpp
new file mode 100644
index 00000000000..719c3ccc943
--- /dev/null
+++ b/TAO/IIOP/lib/bridge/iioporb.cpp
@@ -0,0 +1,408 @@
+// @(#)iioporb.cpp 1.8 95/09/19
+// Copyright 1994-1995 by Sun Microsystems Inc.
+// All Rights Reserved
+//
+// IIOP: ORB pseudo-object
+//
+// This includes objref stringification/destringification for IIOP object
+// references.
+//
+
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+#include <corba/orb.hh>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <initguid.h>
+#include <corba/stub.hh>
+
+#include "runtime/cdr.hh"
+#include "bridge/iioporb.hh"
+#include "bridge/iiopobj.hh"
+
+
+static const char ior_prefix [] = "IOR:";
+static const char iiop_prefix [] = "iiop:";
+static const char xchars [] = "0123456789abcdef";
+
+
+//
+// hex conversion utilities
+//
+static inline char
+nibble2hex (unsigned n)
+{
+ return xchars [n & 0x0f];
+}
+
+static inline
+unsigned char
+hex2byte (char c)
+{
+ if (isdigit (c))
+ return (unsigned char) (c - '0');
+ else if (islower (c))
+ return (unsigned char) (10 + c - 'a');
+ else
+ return (unsigned char) (10 + c - 'A');
+}
+
+
+//
+// Objref stringification
+//
+CORBA_String
+IIOP_ORB::object_to_string (
+ CORBA_Object_ptr obj,
+ CORBA_Environment &env
+)
+{
+ env.clear ();
+
+ //
+ // Application writer controls what kind of objref strings they get,
+ // maybe along with other things, by how they initialize the ORB.
+ //
+ if (use_omg_ior_format) {
+
+ //
+ // By default, orbs use IOR strings; these are ugly (and error
+ // prone) but specified by CORBA.
+ //
+ // XXX there should be a simple way to reuse this code in other
+ // ORB implementations ...
+ //
+ unsigned char *bytes, buf [BUFSIZ];
+ CDR cdr (buf, sizeof buf, MY_BYTE_SEX);
+
+ bytes = buf;
+ (void) memset (bytes, 0, BUFSIZ); // support limited oref strcmp
+
+ //
+ // Marshal the objref into an encapsulation bytestream.
+ //
+ (void) cdr.put_char (MY_BYTE_SEX);
+ if (CDR::encoder (_tc_CORBA_Object, &obj, 0, &cdr, env)
+ != CORBA_TypeCode::TRAVERSE_CONTINUE)
+ return 0;
+
+ //
+ // Now hexify the encapsulated CDR data into a string,
+ // and return that string.
+ //
+ CORBA_String string, cp;
+ size_t len = cdr.length - cdr.remaining;
+
+ string = CORBA_string_alloc (sizeof ior_prefix + 2 * len);
+ strcpy ((char *)string, ior_prefix);
+
+ for (cp = (CORBA_String) strchr ((char *)string, ':') + 1,
+ bytes = cdr.buffer;
+ len--; bytes++) {
+ *cp++ = nibble2hex ((*bytes) >> 4);
+ *cp++ = nibble2hex (*bytes);
+ }
+ *cp = 0;
+ return string;
+ } else {
+ //
+ // The "internet" ORB uses readable URL style objrefs, as
+ // used in the World Wide Web.
+ //
+ // NOTE: the version ID in the string is ugly but we can't
+ // realistically eliminate it by any "assume 1.0" strategy...
+ // Similarly with the port, because there's no single IIOP
+ // port to which we could default.
+ //
+ static const char digits [] = "0123456789";
+
+ //
+ // This only works for IIOP objrefs. If we're handed an objref
+ // that's not an IIOP objref, fail -- application must use an
+ // ORB that's configured differently.
+ //
+ IIOP_Object *obj2;
+
+ if (obj->QueryInterface (IID_IIOP_Object, (void **)&obj2)
+ != NOERROR) {
+ env.exception (new CORBA_DATA_CONVERSION (COMPLETED_NO));
+ return 0;
+ }
+
+ if (!obj2) // null?
+ return CORBA_string_copy ((CORBA_String) iiop_prefix);
+
+ char buf [BUFSIZ + 2];
+
+ sprintf (buf, "%s%c.%c//%s:%d/", iiop_prefix,
+ digits [obj2->profile.iiop_version.major],
+ digits [obj2->profile.iiop_version.minor],
+ obj2->profile.host, obj2->profile.port);
+
+ char *cp = strchr (buf, 0);
+ unsigned len;
+ unsigned char *byte;
+
+ for (len = (unsigned) obj2->profile.object_key.length,
+ byte = obj2->profile.object_key.buffer;
+ cp < &buf [BUFSIZ] && len != 0;
+ len--, byte++) {
+ if (isascii (*byte) && isprint (*byte) && *byte != '\\') {
+ *cp++ = (char) *byte;
+ continue;
+ }
+
+ //
+ // NOTE: this could run two characters past &buf[BUFSIZ],
+ // which is why buf is exactly two characters bigger than
+ // that ... saves coding a test here.
+ //
+ *cp++ = '\\';
+ *cp++ = nibble2hex (*byte & 0x0f);
+ *cp++ = nibble2hex ((*byte >> 4) & 0x0f);
+ }
+ if (cp >= &buf [BUFSIZ]) {
+ env.exception (new CORBA_IMP_LIMIT (COMPLETED_NO));
+ return 0;
+ }
+ *cp = 0;
+ return CORBA_string_copy ((CORBA_String) &buf[0]);
+ }
+}
+
+
+//
+// Destringify OMG-specified "IOR" string.
+//
+// XXX there should be a simple way to reuse this code in other
+// ORB implementations ...
+//
+static CORBA_Object_ptr
+ior_string_to_object (
+ CORBA_String str,
+ CORBA_Environment &env
+)
+{
+ //
+ // Unhex the bytes, and make a CDR deencapsulation stream
+ // from the resulting data.
+ //
+ unsigned char *buffer = new
+ unsigned char [1 + strlen ((char *) str) / 2];
+ char *tmp = (char *)str;
+ size_t len = 0;
+
+ while (tmp [0] && tmp [1]) {
+ unsigned char byte;
+
+ if (!(isxdigit (tmp [0]) && isxdigit (tmp [1])))
+ break;
+
+ byte = (unsigned char) (hex2byte (tmp [0]) << 4);
+ byte |= hex2byte (tmp [1]);
+
+ buffer [len++] = byte;
+ tmp += 2;
+ }
+ if (tmp [0] && !isspace (tmp [0])) {
+ delete buffer;
+ env.exception (new CORBA_BAD_PARAM (COMPLETED_NO));
+ return 0;
+ }
+
+ //
+ // Create deencapsulation stream ... then unmarshal objref
+ // from that stream.
+ //
+ CDR stream;
+ CORBA_Object_ptr objref;
+
+ stream.setup_encapsulation (buffer, len);
+ if (CDR::decoder (_tc_CORBA_Object, &objref, 0, &stream, env)
+ != CORBA_TypeCode::TRAVERSE_CONTINUE) {
+ objref = 0;
+ }
+
+ delete buffer;
+ return objref;
+}
+
+
+//
+// Destringify URL style IIOP objref.
+//
+static CORBA_Object_ptr
+iiop_string_to_object (
+ CORBA_String string,
+ CORBA_Environment &env
+)
+{
+ //
+ // NIL objref encodes as just "iiop:" ... which has already been
+ // removed, so we see it as an empty string.
+ //
+ if (!string || !*string)
+ return 0;
+
+ //
+ // type ID not encoded in this string ... makes narrowing rather
+ // expensive, though it does ensure that type-safe narrowing code
+ // gets thoroughly excercised/debugged!
+ //
+ IIOP_Object *data = new IIOP_Object (0); // null type ID
+
+ //
+ // Remove the "N.N//" prefix, and verify the version's one
+ // that we accept
+ //
+ if (isdigit (string [0]) && isdigit (string [2]) && string [1] == '.'
+ && string [3] == '/' && string [4] == '/') {
+ data->profile.iiop_version.major = (char) (string [0] - '0');
+ data->profile.iiop_version.minor = (char) (string [2] - '0');
+ string += 5;
+ } else {
+ env.exception (new CORBA_DATA_CONVERSION (COMPLETED_NO));
+ data->Release ();
+ return 0;
+ }
+ if (data->profile.iiop_version.major != IIOP::MY_MAJOR
+ || data->profile.iiop_version.minor > IIOP::MY_MINOR) {
+ env.exception (new CORBA_DATA_CONVERSION (COMPLETED_NO));
+ data->Release ();
+ return 0;
+ }
+
+ //
+ // Pull off the "hostname:port/" part of the objref
+ //
+ char *cp;
+
+ if ((cp = strchr (string, ':'))== 0) {
+ env.exception (new CORBA_DATA_CONVERSION (COMPLETED_NO));
+ data->Release ();
+ return 0;
+ }
+
+ data->profile.host = CORBA_string_alloc (1 + cp - string);
+ for (cp = data->profile.host; *string != ':'; *cp++ = *string++)
+ continue;
+ *cp = 0;
+ string++;
+
+ if ((cp = strchr ((char *)string, '/')) == 0) {
+ env.exception (new CORBA_DATA_CONVERSION (COMPLETED_NO));
+ CORBA_string_free (data->profile.host);
+ data->Release ();
+ return 0;
+ }
+
+ data->profile.port = (short) atoi ((char *)string);
+ string = ++cp;
+
+ //
+ // Parse the key ... it's ASCII plus hex escapes for everything
+ // nonprintable. This assumes that printable ASCII is the common
+ // case ... but since stringification is uncommon, no big deal.
+ //
+ data->profile.object_key.buffer
+ = (unsigned char *) CORBA_string_copy (string);
+
+ //
+ // Strip out whitespace and adjust length accordingly.
+ //
+ for (cp = (char *) data->profile.object_key.buffer; *cp; cp++) {
+ if (!isprint (*cp)) {
+ *cp = '\0';
+ break;
+ }
+ }
+ string = (char *) data->profile.object_key.buffer;
+ data->profile.object_key.length = strlen (string);
+ data->profile.object_key.maximum = data->profile.object_key.length;
+
+ //
+ // Strip out hex escapes and adjust the key's length appropriately.
+ //
+ while ((cp =
+ strchr ((char *)data->profile.object_key.buffer, '\\')) != 0) {
+ *cp = (CORBA_Char) (hex2byte ((char) cp [1]) << 4);
+ *cp |= (CORBA_Char) hex2byte ((char) cp [2]);
+ cp++;
+
+ size_t len = strlen (cp);
+
+ memcpy (cp, cp+2, len - 2);
+ data->profile.object_key.length -= 2;
+ }
+
+ //
+ // Return the objref.
+ //
+ CORBA_Object_ptr obj;
+
+ (void) data->QueryInterface (IID_CORBA_Object, (void **)&obj);
+ data->Release ();
+ return obj;
+}
+
+
+//
+// Destringify arbitrary objrefs.
+//
+CORBA_Object_ptr
+IIOP_ORB::string_to_object (
+ CORBA_String str,
+ CORBA_Environment &env
+)
+{
+ env.clear ();
+
+ //
+ // Use the prefix code to choose which destringify algorithm to use.
+ //
+ if (strncmp ((char *)str, iiop_prefix, sizeof iiop_prefix - 1) == 0)
+ return iiop_string_to_object (str + sizeof iiop_prefix - 1, env);
+
+ if (strncmp ((char *)str, ior_prefix, sizeof ior_prefix - 1) == 0)
+ return ior_string_to_object (str + sizeof ior_prefix - 1, env);
+
+ env.exception (new CORBA_BAD_PARAM (COMPLETED_NO));
+ return 0;
+}
+
+//
+// COM IUnknown support
+//
+
+// {A201E4C4-F258-11ce-9598-0000C07CA898}
+DEFINE_GUID (IID_IIOP_ORB,
+0xa201e4c4, 0xf258, 0x11ce, 0x95, 0x98, 0x0, 0x0, 0xc0, 0x7c, 0xa8, 0x98);
+
+
+HRESULT
+__stdcall
+IIOP_ORB::QueryInterface (
+ REFIID riid,
+ void **ppv
+)
+{
+ *ppv = 0;
+
+ if (IID_CORBA_ORB == riid
+ || IID_IIOP_ORB == riid
+ || IID_IUnknown == riid)
+ *ppv = this;
+
+ //
+ // XXX gotta aggregate ...
+ //
+
+ if (*ppv == 0)
+ return ResultFromScode (E_NOINTERFACE);
+
+ (void) AddRef ();
+ return NOERROR;
+}
diff --git a/TAO/IIOP/lib/bridge/iioporb.hh b/TAO/IIOP/lib/bridge/iioporb.hh
new file mode 100644
index 00000000000..87130929c28
--- /dev/null
+++ b/TAO/IIOP/lib/bridge/iioporb.hh
@@ -0,0 +1,49 @@
+// @(#)iioporb.hh 1.2 95/11/04
+// Copyright 1995 by Sun Microsystems, Inc.
+// All Rights Reserved
+//
+// IIOP: bridge implementation of IIOP_ORB
+//
+// This is one of the two main hooks into IIOP in this Win32 C/C++/COM
+// based implementation; the other being IIOP_Object.
+//
+
+#ifndef _iioporb_hh
+#define _iioporb_hh
+typedef class IIOP_ORB *IIOP_ORB_ptr;
+
+extern const IID IID_IIOP_ORB;
+
+//
+// ORB pseudo-objref
+//
+class _EXPCLASS IIOP_ORB : public CORBA_ORB
+{
+ public:
+ IIOP_ORB (CORBA_Boolean flag)
+ { use_omg_ior_format = flag; }
+
+ ~IIOP_ORB () { }
+
+ CORBA_Object_ptr string_to_object (
+ CORBA_String str,
+ CORBA_Environment &env
+ );
+ CORBA_String object_to_string (
+ CORBA_Object_ptr obj,
+ CORBA_Environment &env
+ );
+
+ HRESULT __stdcall QueryInterface (
+ REFIID riid,
+ void **ppv
+ );
+ private:
+ CORBA_Boolean use_omg_ior_format;
+
+ // these are not provided
+ IIOP_ORB (const IIOP_ORB &);
+ IIOP_ORB &operator = (const IIOP_ORB &);
+};
+
+#endif // _iioporb_hh
diff --git a/TAO/IIOP/lib/bridge/invoke.cpp b/TAO/IIOP/lib/bridge/invoke.cpp
new file mode 100644
index 00000000000..fd287d1888d
--- /dev/null
+++ b/TAO/IIOP/lib/bridge/invoke.cpp
@@ -0,0 +1,346 @@
+// @(#)invoke.cpp 1.3 95/09/24
+// Copyright 1994-1995 by Sun Microsystems Inc.
+// All Rights Reserved
+//
+// IIOP stub support for static and dynamic invocation
+//
+// This file holds DII support, and an analagous interpreter that let static
+// stubs be very small. It's specific to objrefs with IIOP::ProfileBody.
+//
+// NOTE: this may someday be moved within an IIOP class so that the public
+// stub interface is completely independent of ORB/protocol internals.
+//
+// THREADING NOTE: Code below this point is of course thread-safe (at least
+// on supported threaded platforms), so the caller of these routines need
+// only ensure that the data being passed in is not being modified by any
+// other thread.
+//
+// As an _experiment_ (to estimate the performance cost) remote calls are
+// currently deemed "cancel-safe". That means that they can be called
+// by threads when they're in asynchronous cancellation mode. The only
+// effective way to do this is to disable async cancellation for the
+// duration of the call. There are numerous rude interactions with code
+// generators for C++ ... cancellation handlers just do normal stack
+// unwinding like exceptions, but exceptions are purely synchronous and
+// sophisticated code generators rely on that to generate better code,
+// which in some cases may be very hard to unwind.
+//
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <corba/orb.hh>
+
+#include "runtime/cdr.hh"
+#include "runtime/thread.hh"
+#include "runtime/debug.hh"
+#include "bridge/giop.hh"
+#include "bridge/connmgr.hh"
+
+
+//
+// "stub interpreter" for static stubs. IDL compiler (or human equivalent
+// thereof :-) should just dump a read-only description of the call into
+// "calldata" and do varargs calls to this routine, which does all the work.
+//
+// NOTE: This routine includes stub interpreter code, upon which a patent
+// application is pending.
+//
+void
+IIOP_Object::do_call (
+ CORBA_Environment &env, // exception reporting
+ const calldata *info, // call description
+ ... // ... any parameters
+)
+{
+#ifdef _POSIX_THREADS
+ ForceSynchronousCancel temp; // side effect driven
+#endif // _POSIX_THREADS
+
+ GIOP::Invocation call (this, info->opname,
+ info->is_roundtrip);
+
+ //
+ // We may need to loop through here more than once if we're forwarded
+ // to some other object reference.
+ //
+ // NOTE: A quality-of-service policy may be useful to establish here,
+ // specifically one controlling how many times the call is reissued
+ // before failing the call on the assumption that something is broken.
+ //
+ // NOTE: something missing is a dynamic way to change the policy of
+ // whether to issue LocateRequest messages or not. This code uses a
+ // simple, fixed policy: never use LocateRequest messages.
+ //
+ for (;;) {
+ //
+ // Start the call by constructing the request message header.
+ //
+ env.clear ();
+ call.start (env);
+ if (env.exception ()) {
+ dexc (env, "do_call, start request message");
+ return;
+ }
+
+ //
+ // Now, put all "in" and "inout" parameters into the request
+ // message body.
+ //
+ // Some "inout" data have an extra level of indirection, specified
+ // by the language mapping's memory allocation policies ... the
+ // indirection only shows up here when it's needed later for
+ // allocating "out" memory, otherwise there's just one indirection.
+ //
+ unsigned i;
+ const paramdata *pdp;
+ va_list param_vector;
+
+ va_start (param_vector, info);
+ for (i = 0, pdp = info->params;
+ i < info->param_count;
+ i++, pdp++) {
+ void *ptr = va_arg (param_vector, void *);
+
+ if (pdp->mode == PARAM_IN)
+ call.put_param (pdp->tc, ptr, env);
+ else if (pdp->mode == PARAM_INOUT) {
+ if (pdp->value_size == 0)
+ call.put_param (pdp->tc, ptr, env);
+ else
+ call.put_param (pdp->tc, *(void **)ptr, env);
+ }
+
+ if (env.exception ()) {
+ dexc (env, "do_call, put request parameter");
+ return;
+ }
+ }
+ va_end (param_vector);
+
+ //
+ // Make the call ... blocking for response if needed. Note that
+ // "oneway" calls can't return any exceptions except system ones.
+ //
+ GIOP::ReplyStatusType status;
+ CORBA_ExceptionList exceptions;
+
+ exceptions.length = exceptions.maximum = info->except_count;
+ exceptions.buffer = (CORBA_TypeCode_ptr *) info->excepts;
+
+ status = call.invoke (exceptions, env);
+
+ exceptions.buffer = 0; // don't free it
+
+ if (env.exception ()) {
+ dexc (env, "do_call, invoke");
+ return;
+ }
+ if (!info->is_roundtrip
+ || status == GIOP::SYSTEM_EXCEPTION
+ || status == GIOP::USER_EXCEPTION)
+ return;
+
+ //
+ // Now, get all the "return", "out", and "inout" parameters from
+ // the response message body.
+ //
+ if (status == GIOP::NO_EXCEPTION) {
+ va_start (param_vector, info);
+ for (i = 0, pdp = info->params;
+ i < info->param_count;
+ i++, pdp++) {
+ void *ptr = va_arg (param_vector, void *);
+
+ if (pdp->mode == PARAM_RETURN
+ || pdp->mode == PARAM_OUT
+ || pdp->mode == PARAM_INOUT) {
+ //
+ // The language mapping's memory allocation policy says
+ // that some data is heap-allocated. This interpreter
+ // is told about the relevant policy by whoever built
+ // the operation description (e.g. the IDL compiler) so
+ // it doesn't have to know the policy associated with a
+ // particular language binding (e.g. C/C++ differ, and
+ // C++ even has different policies for different kinds
+ // of structures).
+ //
+ if (pdp->value_size == 0) {
+ call.get_value (pdp->tc, ptr, env);
+ } else {
+ // assert (value_size == tc->size());
+ *(void **)ptr = new CORBA_Octet [pdp->value_size];
+ call.get_value (pdp->tc, *(void **)ptr, env);
+ }
+
+ if (env.exception ()) {
+ dexc (env, "do_call, get reply parameter");
+ return;
+ }
+ }
+ }
+ va_end (param_vector);
+ return;
+ }
+
+ //
+ // ... or maybe this request got forwarded to someplace else; send
+ // the request there instead.
+ //
+ assert (status == GIOP::LOCATION_FORWARD);
+ }
+}
+
+
+//
+// DII analogue of the above. Differs in how the vararg calling convention
+// is implemented -- DII doesn't use the normal call stack with its implicit
+// typing, but iinstead uses heap-based arguments with explicit typing.
+//
+void
+IIOP_Object::do_dynamic_call (
+ const char *opname, // operation name
+ CORBA_Boolean is_roundtrip, // results required?
+ CORBA_NVList_ptr args, // parameters
+ CORBA_NamedValue_ptr result, // result
+ CORBA_Flags flags, // per-call flag (one!)
+ CORBA_ExceptionList &exceptions, // possible user exceptions
+ CORBA_Environment &env // exception reporting
+)
+{
+#ifdef _POSIX_THREADS
+ ForceSynchronousCancel temp; // side effect driven
+#endif // _POSIX_THREADS
+
+ GIOP::Invocation call (this, opname, is_roundtrip);
+
+ //
+ // Loop as needed for forwarding; see above.
+ //
+ for (;;) {
+ //
+ // Start the call by constructing the request message header.
+ //
+ env.clear ();
+ call.start (env);
+ if (env.exception ()) {
+ dexc (env, "do_call, start request message");
+ return;
+ }
+
+ //
+ // Now, put all "in" and "inout" parameters into the request
+ // message body.
+ //
+ unsigned i;
+
+ for (i = 0; i < args->count (); i++) {
+ CORBA_NamedValue_ptr value = args->item (i);
+
+ if (value->flags () == CORBA_ARG_IN
+ || value->flags () == CORBA_ARG_INOUT) {
+ call.put_param (value->value ()->type (),
+ value->value ()->value (), env);
+ if (env.exception ()) {
+ dexc (env, "do_dynamic_call, put request parameter");
+ return;
+ }
+ }
+ }
+
+ //
+ // Make the call ... blocking for response if needed. Note that
+ // "oneway" calls can't return any exceptions except system ones.
+ //
+ GIOP::ReplyStatusType status;
+
+ status = call.invoke (exceptions, env);
+ if (env.exception ()) {
+ dexc (env, "do_dynamic_call, invoke");
+ return;
+ }
+ if (!is_roundtrip
+ || status == GIOP::SYSTEM_EXCEPTION
+ || status == GIOP::USER_EXCEPTION)
+ return;
+
+ //
+ // Now, get all the "return", "out", and "inout" parameters from the
+ // response message body ... return parameter is first, the rest are
+ // in the order defined in the IDL spec (which is also the order that
+ // DII users are required to use).
+ //
+ if (status == GIOP::NO_EXCEPTION) {
+ if (result != 0) {
+
+ //
+ // If caller didn't set OUT_LIST_MEMORY flag, allocate
+ // memory for return value ...
+ //
+ if (!(flags & CORBA_OUT_LIST_MEMORY)) {
+ CORBA_TypeCode_ptr tcp;
+ size_t size;
+
+ tcp = result->value ()->type ();
+ size = tcp->size (env);
+ dexc (env, "do_dynamic_call, get result size");
+
+ if (size != 0) {
+ void *ptr = new CORBA_Octet [size];
+
+ tcp->AddRef ();
+ result->value ()->replace (tcp, ptr,
+ CORBA_B_TRUE, env);
+ dexc (env, "do_dynamic_call, set result mem");
+ }
+ }
+
+ call.get_value (result->value ()->type (),
+ result->value ()->value (), env);
+ }
+
+ for (i = 0; i < args->count (); i++) {
+ CORBA_NamedValue_ptr value = args->item (i);
+
+ if (value->flags () == CORBA_ARG_OUT
+ || value->flags () == CORBA_ARG_INOUT) {
+ //
+ // If caller didn't set OUT_LIST_MEMORY flag, allocate
+ // memory for this parameter ...
+ //
+ if (!(flags & CORBA_OUT_LIST_MEMORY)) {
+ CORBA_TypeCode_ptr tcp;
+ size_t size;
+
+ tcp = value->value ()->type ();
+ size = tcp->size (env);
+ dexc (env, "do_dynamic_call, get param size");
+
+ if (size != 0) {
+ void *ptr = new CORBA_Octet [size];
+
+ tcp->AddRef ();
+ value->value ()->replace (tcp, ptr,
+ CORBA_B_TRUE, env);
+ dexc (env, "do_dynamic_call, set result mem");
+ }
+ }
+
+ call.get_value (value->value ()->type (),
+ value->value ()->value (), env);
+ if (env.exception ()) {
+ dexc (env, "do_dynamic_call, get response parameter");
+ return;
+ }
+ }
+ }
+ return;
+ }
+
+ //
+ // ... or maybe this request got forwarded to someplace else.
+ //
+ assert (status == GIOP::LOCATION_FORWARD);
+ }
+}
diff --git a/TAO/IIOP/lib/bridge/svrrqst.cpp b/TAO/IIOP/lib/bridge/svrrqst.cpp
new file mode 100644
index 00000000000..3e895155404
--- /dev/null
+++ b/TAO/IIOP/lib/bridge/svrrqst.cpp
@@ -0,0 +1,261 @@
+// @(#)svrrqst.cpp 1.9 95/11/04
+// Copyright 1994-1995 by Sun Microsystems Inc.
+// All Rights Reserved
+//
+// Implementation of the Dynamic Server Skeleton Interface
+//
+#include <corba/orb.hh>
+
+#include <initguid.h>
+
+#include "runtime/debug.hh"
+#include "runtime/thread.hh"
+#include "runtime/cdr.hh"
+
+#include "bridge/svrrqst.hh"
+
+
+// {77420086-F276-11ce-9598-0000C07CA898}
+DEFINE_GUID (IID_IIOP_ServerRequest,
+0x77420086, 0xf276, 0x11ce, 0x95, 0x98, 0x0, 0x0, 0xc0, 0x7c, 0xa8, 0x98);
+
+// {4B48D881-F7F0-11ce-9598-0000C07CA898}
+DEFINE_GUID(IID_CORBA_ServerRequest,
+0x4b48d881, 0xf7f0, 0x11ce, 0x95, 0x98, 0x0, 0x0, 0xc0, 0x7c, 0xa8, 0x98);
+
+
+
+#ifdef _POSIX_THREADS
+static pthread_mutex_t svrqst_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif // _POSIX_THREADS
+
+
+IIOP_ServerRequest::~IIOP_ServerRequest ()
+{
+ assert (_refcount == 0);
+ if (_params)
+ CORBA_release (_params);
+ if (_retval)
+ delete _retval;
+ if (_exception)
+ delete _exception;
+}
+
+
+ULONG
+__stdcall
+IIOP_ServerRequest::AddRef ()
+{
+#ifdef _POSIX_THREADS
+ Critical region (&svrqst_lock);
+#endif
+
+ assert (_refcount > 0);
+ return _refcount++;
+}
+
+ULONG
+__stdcall
+IIOP_ServerRequest::Release ()
+{
+#ifdef _POSIX_THREADS
+ Critical region (&svrqst_lock);
+#endif
+
+ assert (this != 0);
+ assert (_refcount > 0);
+
+ if (--_refcount != 0)
+ return _refcount;
+
+ delete this;
+ return 0;
+}
+
+HRESULT
+__stdcall
+IIOP_ServerRequest::QueryInterface (
+ REFIID riid,
+ void **ppv
+)
+{
+ assert (_refcount > 0);
+ *ppv = 0;
+
+ if (IID_IIOP_ServerRequest == riid
+ || IID_CORBA_ServerRequest == riid
+ || IID_IUnknown == riid)
+ *ppv = this;
+
+ if (*ppv == 0)
+ return ResultFromScode (E_NOINTERFACE);
+
+ (void) AddRef ();
+ return NOERROR;
+}
+
+
+//
+// Unmarshal in/inout params, and set up to marshal the appropriate
+// inout/out/return values later on.
+//
+void
+__stdcall
+IIOP_ServerRequest::params (
+ CORBA_NVList_ptr list,
+ CORBA_Environment &env
+)
+{
+ unsigned i;
+
+ env.clear ();
+
+ //
+ // Save params for later use when marshaling reply
+ //
+ _params = list;
+
+ //
+ // Then unmarshal each "in" and "inout" parameter
+ //
+ for (i = 0; i < list->count (); i++) {
+ CORBA_NamedValue_ptr nv;
+ CORBA_Any_ptr any;
+ CORBA_TypeCode_ptr tc;
+ void *value;
+
+ nv = list->item (i);
+ if (!(nv->flags () & (CORBA_ARG_IN | CORBA_ARG_INOUT)))
+ continue;
+
+ //
+ // First, make sure the memory into which we'll be unmarshaling
+ // exists, and is the right size.
+ //
+ // NOTE: desirable to have a way to let the dynamic implementation
+ // routine preallocate this data, for environments where DSI is
+ // just being used in lieu of a language mapped server side API
+ // and the size is really knowable in advance.
+ //
+ any = nv->value ();
+ tc = any->type ();
+ tc->AddRef ();
+ value = new char [tc->size (env)];
+ any->replace (tc, value, CORBA_B_TRUE, env);
+
+ //
+ // Decrement the refcount of "tc".
+ //
+ // The earlier AddRef is needed since Any::replace() releases
+ // the typecode inside the Any. Without the dup, the reference
+ // count can go to zero, and the typecode would then be deleted.
+ //
+ // This Release ensures that the reference count is correct so
+ // the typecode can be deleted some other time.
+ //
+ tc->Release ();
+
+ //
+ // Then just unmarshal the value.
+ //
+ (void) CDR::decoder (tc, value, 0, _incoming, env);
+ }
+
+ //
+ // If any data is left over, it'd be context values ... else error.
+ // We don't support context values, so it's always an error.
+ //
+ if (_incoming->bytes_remaining () != 0) {
+ dmsg1 ("params(), %d bytes remaining (error)",
+ _incoming->bytes_remaining ());
+ env.exception (new CORBA_BAD_PARAM (COMPLETED_NO));
+ }
+}
+
+
+//
+// Store the result value. There's either an exception, or a result,
+// but not both of them. Results (and exceptions) can be reported
+// only after the parameter list has been provided (maybe empty).
+//
+void
+__stdcall
+IIOP_ServerRequest::result (
+ CORBA_Any_ptr value,
+ CORBA_Environment &env
+)
+{
+ env.clear ();
+
+ if (!_params || _retval || _exception)
+ env.exception (new CORBA_BAD_INV_ORDER (COMPLETED_NO));
+ else
+ _retval = value;
+
+ // XXX send the message now!
+}
+
+
+//
+// Store the exception value.
+//
+void
+__stdcall
+IIOP_ServerRequest::exception (
+ CORBA_ExceptionType type,
+ CORBA_Any_ptr value,
+ CORBA_Environment &env
+)
+{
+ if (!_params || _retval || _exception)
+ env.exception (new CORBA_BAD_INV_ORDER (COMPLETED_NO));
+ else {
+ env.clear ();
+ _exception = value;
+ _ex_type = type;
+ }
+
+ // XXX send the message now!
+}
+
+
+//
+// Invocation attributes.
+//
+CORBA_String
+__stdcall
+IIOP_ServerRequest::op_name ()
+{
+ return _opname;
+}
+
+CORBA_Object_ptr
+__stdcall
+IIOP_ServerRequest::target ()
+{
+ // XXX implement me!! Code from TCP_OA exists ...
+ return 0;
+}
+
+CORBA_Principal_ptr
+__stdcall
+IIOP_ServerRequest::caller ()
+{
+ // XXX ... return client's principal
+ return 0;
+}
+
+CORBA_ORB_ptr
+__stdcall
+IIOP_ServerRequest::orb ()
+{
+ return _orb;
+}
+
+TOA_ptr
+__stdcall
+IIOP_ServerRequest::oa ()
+{
+ return _toa;
+}
+
diff --git a/TAO/IIOP/lib/bridge/svrrqst.hh b/TAO/IIOP/lib/bridge/svrrqst.hh
new file mode 100644
index 00000000000..f969971bfb1
--- /dev/null
+++ b/TAO/IIOP/lib/bridge/svrrqst.hh
@@ -0,0 +1,96 @@
+// @(#)svrrqst.hh 1.3 95/11/04
+// Copyright 1994-1995 by Sun Microsystems, Inc.
+// All Rights Reserved
+//
+// Header file for Win32 C/C++/COM interface to CORBA's Dynamic
+// Server Skeleton Interface's "Server Request" type.
+//
+
+#ifndef _svrrqst_hh
+#define _svrrqst_hh
+
+#include "runtime/cdr.hh"
+
+extern const IID IID_IIOP_ServerRequest;
+
+class _EXPCLASS IIOP_ServerRequest : public CORBA_ServerRequest
+{
+ public:
+ //
+ // Constructor, destructor
+ //
+ IIOP_ServerRequest (
+ CDR *msg,
+ CORBA_ORB_ptr the_orb,
+ TOA_ptr the_toa
+ )
+ : _incoming (msg), _params (0), _retval (0),
+ _exception (0),
+ _ex_type (NO_EXCEPTION),
+ _refcount (1),
+ _orb (the_orb),
+ _toa (the_toa)
+ { }
+
+ virtual ~IIOP_ServerRequest ();
+
+ //
+ // General ServerRequest operations
+ //
+ void __stdcall params (
+ CORBA_NVList_ptr list,
+ CORBA_Environment &env
+ );
+
+ void __stdcall result (
+ CORBA_Any_ptr value,
+ CORBA_Environment &env
+ );
+
+ void __stdcall exception (
+ CORBA_ExceptionType type,
+ CORBA_Any_ptr value,
+ CORBA_Environment &env
+ );
+
+ //
+ // Request attributes
+ //
+ CORBA_String __stdcall op_name ();
+ CORBA_Principal_ptr __stdcall caller ();
+ CORBA_Object_ptr __stdcall target ();
+ CORBA_ORB_ptr __stdcall orb ();
+ TOA_ptr __stdcall oa ();
+
+ //
+ // Stuff required for COM IUnknown support
+ //
+ ULONG __stdcall AddRef ();
+ ULONG __stdcall Release ();
+ HRESULT __stdcall QueryInterface (
+ REFIID riid,
+ void **ppv
+ );
+
+ // private:
+ CORBA_String _opname;
+ CDR *_incoming;
+ CORBA_NVList_ptr _params;
+ CORBA_Any_ptr _retval;
+ CORBA_Any_ptr _exception;
+ CORBA_ExceptionType _ex_type;
+
+ //
+ // Just drop the refcount, don't destroy the object; most
+ // of these are stack-allocated.
+ //
+ void release () { _refcount--; }
+
+ private:
+ unsigned _refcount;
+ CORBA_ORB_ptr _orb;
+ TOA_ptr _toa;
+};
+
+#endif // _svrrqst_hh
+
diff --git a/TAO/IIOP/lib/bridge/tcpoa.cpp b/TAO/IIOP/lib/bridge/tcpoa.cpp
new file mode 100644
index 00000000000..5e98c21e82c
--- /dev/null
+++ b/TAO/IIOP/lib/bridge/tcpoa.cpp
@@ -0,0 +1,1026 @@
+// @(#)tcpoa.cpp 1.16 95/11/04
+// Copyright 1994-1995 by Sun Microsystems Inc.
+// All Rights Reserved
+//
+// IIOP: Small "TCP OA", thinly layered atop IIOP.
+//
+// Like all OAs, this provides an object creation facility and a simple
+// DSI-based operation dispatch facility. However, it's so simple it
+// doesn't do any more than that! In particular, it maintains no per-object
+// state either on disk or in memory.
+//
+// NOTE: It's undesirable in firewall and threaded environments to continue
+// with the current restriction of only one OA per process.
+//
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#if unix
+#include <unistd.h>
+#include <netdb.h>
+
+#else
+#include <winsock.h>
+
+#endif
+
+#include <corba/orb.hh>
+#include <corba/toa.hh>
+
+#include "runtime/thread.hh"
+#include "runtime/cdr.hh"
+#include "runtime/debug.hh"
+
+#include "bridge/connmgr.hh"
+#include "bridge/tcpoa.hh"
+#include "bridge/giop.hh"
+#include "bridge/svrrqst.hh"
+
+#include <initguid.h>
+
+
+#ifdef NO_HOSTNAMES
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif // NO_HOSTNAMES
+
+
+#if !defined (DECLARED_GETHOSTNAME)
+extern "C" int gethostname (char *, int);
+#endif
+
+
+
+static TCP_OA *the_oa;
+static short tcp_port;
+static char namebuf [65];
+
+
+#ifdef _POSIX_THREADS
+static pthread_key_t request_key;
+static pthread_mutex_t tcpoa_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t tcpoa_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_attr_t thread_attr;
+#endif // _POSIX_THREADS
+
+
+TCP_OA::TCP_OA (
+ CORBA_ORB_ptr owning_orb,
+ CORBA_UShort _port,
+ CORBA_Environment &env
+)
+{
+ assert (the_oa == 0);
+
+ port = _port;
+ do_exit = CORBA_B_FALSE;
+ _orb = owning_orb;
+ call_count = 0;
+ skeleton = 0;
+
+ if (gethostname (namebuf, sizeof namebuf) < 0) {
+ dsockerr ("gethostname");
+ return;
+ }
+
+#ifdef NO_HOSTNAMES
+ //
+ // In some highly static environments, or where even the most basic
+ // Internet services are unavailable, it's desirable to use IP addresses
+ // rather than host names in object references. IP addresses are
+ // normally bad to use since they need to change.
+ //
+ // In general, TCP OA initialization options are needed to control at
+ // least three kinds of host identifiers to embed in objrefs:
+ //
+ // (a) unqualified host names, which is what gethostname() returns
+ // at most sites;
+ //
+ // (b) qualified host names (including fully qualified ones, also
+ // ones with just subdomain qualification) which are hard to
+ // discover in a portable way;
+ //
+ // (c) "Dot notation" IP addresses, which can get stale after a short
+ // while ... hosts move between networks, network numbers change,
+ // and so on. These will also cause problems in the upcoming
+ // evolution of the Internet to IPv6.
+ //
+ // At this time, no general framework is available to control the choice
+ // of these kinds of identifiers. A remotely administerable framework
+ // (e.g. Win32 registry) seems like it'd be most appropriate.
+ //
+ // NOTE: gethostbyname() is MT-unsafe, call only in one thread!!
+ //
+ hostent *hp;
+ char *dot_notation;
+
+ hp = gethostbyname (namebuf);
+ assert (hp != 0);
+
+ dot_notation = inet_ntoa (*(in_addr *)hp->h_addr);
+ assert (dot_notation != 0);
+
+ (void) strcpy (namebuf, dot_notation);
+#endif // NO_HOSTNAMES
+
+ //
+ // Initialize the endpoint ... or try!
+ //
+ // NOTE that this sets "port" if it was originally zero. An
+ // original value of zero indicates that the OS should select
+ // a port on which this OA will listen.
+ //
+ endpoint = server_endpoint::initialize (port, env);
+ tcp_port = port;
+
+ if (env.exception () != 0) {
+ dmsg2 ("TCP OA: '%s', port %u", namebuf, port);
+ the_oa = this;
+ }
+}
+
+TCP_OA::~TCP_OA ()
+{
+ if (endpoint) {
+ endpoint->shutdown_connections (GIOP::close_connection, 0);
+ endpoint = 0;
+ }
+}
+
+
+//
+// Public initialisation routine for this OA.
+//
+TCP_OA_ptr
+TCP_OA::init (
+ CORBA_ORB_ptr parent,
+ char *oa_name,
+ CORBA_Environment &env
+)
+{
+ env.clear ();
+
+#ifdef _POSIX_THREADS
+ Critical region (&tcpoa_mutex);
+#endif // _POSIX_THREADS
+
+ if (the_oa) {
+ env.exception (new CORBA_INITIALIZE (COMPLETED_NO));
+ return 0;
+ }
+
+#ifdef _POSIX_THREADS
+
+ //
+ // Initialize POSIX thread stuff: TSD key for request data, and
+ // attributes for threads that can be dynamically created.
+ //
+ // XXX this stuff should be guarded by "pthread_once", it's not
+ // at all OA-specific.
+ //
+ (void) pthread_key_create (&request_key, 0);
+
+ (void) pthread_attr_init (&thread_attr);
+ (void) pthread_attr_setdetachstate (&thread_attr, PTHREAD_CREATE_DETACHED);
+
+#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
+ (void) pthread_attr_setscope (&thread_attr, PTHREAD_SCOPE_PROCESS);
+#endif // _POSIX_THREAD_PRIORITY_SCHEDULING
+
+#endif // _POSIX_THREADS
+
+
+ //
+ // The "OA Name" is either the service name (normally listed in the
+ // /etc/services file) or is the string form of the port number.
+ // These are both controlled by local administration, though in some
+ // cases the IETF will register port numbers. If the OA name is
+ // unspecified (null pointer) or zero, the OS assigns some port
+ // which is currently unused.
+ //
+ // XXX getservent() is MT-unsafe; use getservent_r() where it exists
+ // on the target platform
+ //
+ unsigned short port;
+ struct servent *sp;
+
+ if (oa_name && (sp = getservbyname (oa_name, "tcp")) != 0)
+ port = (unsigned short) sp->s_port;
+ else if (oa_name != 0 && atoi (oa_name) != -1)
+ port = (unsigned short) atoi (oa_name);
+ else
+ port = 0;
+
+ the_oa = new TCP_OA (parent, port, env);
+
+ return the_oa;
+}
+
+
+//
+// Create an objref
+//
+CORBA_Object_ptr
+__stdcall
+TCP_OA::create (
+ CORBA_OctetSeq _FAR &key,
+ CORBA_String _FAR type_id,
+ CORBA_Environment _FAR &env
+)
+{
+ CORBA_String id;
+ IIOP_Object *data;
+
+ if (type_id)
+ id = CORBA_string_copy (type_id);
+ else
+ id = 0;
+ data = new IIOP_Object (id);
+
+ if (data != 0)
+ env.clear ();
+ else {
+ env.exception (new CORBA_NO_MEMORY (COMPLETED_NO));
+ return 0;
+ }
+
+ data->profile.iiop_version.major = IIOP::MY_MAJOR;
+ data->profile.iiop_version.minor = IIOP::MY_MINOR;
+ data->profile.host = strdup (namebuf);
+ data->profile.port = port;
+ data->profile.object_key.length = key.length;
+ data->profile.object_key.maximum = key.length;
+ data->profile.object_key.buffer = new CORBA_Octet [(size_t) key.length];
+
+ //
+ // Verify the memory allocations we just did ...
+ //
+ if (data->profile.host == 0 || data->profile.object_key.buffer == 0) {
+ env.exception (new CORBA_NO_MEMORY (COMPLETED_NO));
+ data->Release ();
+ return 0;
+ }
+
+ memcpy (data->profile.object_key.buffer, key.buffer, (size_t) key.length);
+
+ //
+ // Return the CORBA_Object_ptr interface to this objref.
+ //
+ CORBA_Object_ptr new_obj;
+
+ if (data->QueryInterface (IID_CORBA_Object, (void **)&new_obj)
+ != NOERROR) {
+ env.exception (new CORBA_INTERNAL (COMPLETED_NO));
+ }
+ data->Release ();
+ return new_obj;
+}
+
+
+//
+// Return the key fed into an object at creation time.
+//
+CORBA_OctetSeq *
+__stdcall
+TCP_OA::get_key (
+ CORBA_Object_ptr ,
+ CORBA_Environment &env
+)
+{
+ // XXX implement me ! ... must have been created by this OA.
+ env.exception (new CORBA_IMP_LIMIT (COMPLETED_NO));
+ return 0;
+}
+
+
+#ifdef _POSIX_THREADS
+//
+// Use the TSD key set up as part of OA initialization to get the
+// thread-specific data describing this invocation
+//
+#define request_tsd \
+ ((GIOP::RequestHeader *) pthread_getspecific (request_key))
+
+#else
+
+//
+// This emulates "thread specific data" to hold data about the request
+// that the thread is processing. It needs to be accessed for a variety
+// of purposes in the course of request processing.
+//
+static GIOP::RequestHeader *request_tsd;
+#endif // _POSIX_THREADS
+
+
+//
+// Return the objref which is target of the call. This must be freed
+// by whoever calls the routine.
+//
+// XXX should be consistent with other explicit/implicit request data
+// and have the ORB free it when the call returns; that'll let the cost
+// of the four mallocs (yeech!) be amortized over more work.
+//
+// XXX there's no way to report exceptions here ...
+//
+CORBA_Object_ptr
+__stdcall
+_this ()
+{
+ IIOP_Object *data;
+ opaque *key = &request_tsd->object_key;
+
+ //
+ // NOTE: The "TCP_OA" can't return the type ID of this object
+ // since it has no persistent storage. The expectation is that
+ // code layered on top of this OA, providing whatever storage is
+ // needed and defining their own policies for object keys, will be
+ // built on top of this interface; their implementations of the
+ // "_this()" routine will return a full objref (and also be able
+ // to answer questions like whether it _is_a given type).
+ //
+ if ((data = new IIOP_Object (0)) == 0) { // null type ID
+ return 0;
+ }
+
+ data->profile.iiop_version.major = IIOP::MY_MAJOR;
+ data->profile.iiop_version.minor = IIOP::MY_MINOR;
+ data->profile.host = strdup (namebuf);
+ data->profile.port = tcp_port;
+ data->profile.object_key.length = key->length;
+ data->profile.object_key.maximum = key->length;
+ data->profile.object_key.buffer = new CORBA_Octet [(size_t) key->length];
+ memcpy (data->profile.object_key.buffer, key->buffer, (size_t) key->length);
+
+ if (data->profile.host == 0 || data->profile.object_key.buffer == 0) {
+ data->Release ();
+ return 0;
+ }
+
+ //
+ // Return the CORBA_Object_ptr interface to this objref.
+ //
+ CORBA_Object_ptr new_obj;
+
+ (void) data->QueryInterface (IID_CORBA_Object, (void **)&new_obj);
+ data->Release ();
+ return new_obj;
+}
+
+
+//
+// return the target's key
+//
+// NOTE: as with all "in" parameters to a call, this memory is freed
+// by the ORB not by the object implementation.
+//
+CORBA_OctetSeq *
+__stdcall
+TCP_OA::get_target_key (
+ CORBA_Environment &env
+)
+{
+ env.clear ();
+
+ return &request_tsd->object_key;
+}
+
+
+//
+// return the caller's principal
+//
+// NOTE: as with all "in" parameters to a call, this memory is freed
+// by the ORB not by the object implementation.
+//
+CORBA_Principal_ptr
+__stdcall
+TCP_OA::get_client_principal (
+ CORBA_Environment &env
+)
+{
+ env.clear ();
+
+ return request_tsd->requesting_principal;
+}
+
+
+//
+// Dispatch routine that provides most of the IIOP glue ... constructs
+// a dynamic ServerRequest and any reply message that's needed.
+//
+static void
+tcp_oa_dispatcher (
+ GIOP::RequestHeader &req,
+ CDR &request_body,
+ CDR *reply,
+ void *context,
+ CORBA_Environment &env
+)
+{
+ IIOP_ServerRequest svr_req (
+ &request_body,
+ the_oa->orb (),
+ the_oa
+ );
+
+ //
+ // ServerRequest is what does the unmarshaling, driven by typecodes
+ // that the DSI user provides. Create the ServerRequest, store away
+ // information that'll be needed by some methods, and call the dispatch
+ // routine that the user supplied. Then release the reference so it
+ // can be safely destroyed sometime later.
+ //
+ svr_req._opname = req.operation;
+
+#ifdef _POSIX_THREADS
+ (void) pthread_setspecific (request_key, &req);
+#else
+ request_tsd = &req;
+#endif // _POSIX_THREADS
+
+ TCP_OA::dispatch_context *helper;
+
+ helper = (TCP_OA::dispatch_context *) context;
+ helper->skeleton (req.object_key, svr_req, helper->context, env);
+
+ svr_req.release ();
+
+ //
+ // If reply is null, this was a oneway request ... return!
+ //
+ if (reply == 0)
+ return;
+
+ //
+ // Otherwise check for correct parameter handling, and reply as
+ // appropriate.
+ //
+ // NOTE: if "env" is set, it takes precedence over exceptions
+ // reported using the mechanism of the ServerRequest. Only system
+ // exceptions are reported that way ...
+ //
+ // XXX Exception reporting is ambiguous; it can be cleaner than
+ // this. With both language-mapped and dynamic/explicit reporting
+ // mechanisms, one of must be tested "first" ... so an exception
+ // reported using the other mechanism could be "lost". Perhaps only
+ // the language mapped one should be used for system exceptions.
+ //
+ CORBA_TypeCode_ptr tc;
+ const void *value;
+
+ if (!svr_req._params && env.exception () == 0) {
+ dmsg ("DSI user error, didn't supply params");
+ env.exception (new CORBA_BAD_INV_ORDER (COMPLETED_NO));
+ }
+
+ if (env.exception () != 0) { // standard exceptions only
+ CORBA_Environment env2;
+ CORBA_Exception *x = env.exception ();
+ CORBA_TypeCode_ptr except_tc = x->type ();
+
+ reply->put_ulong (GIOP::SYSTEM_EXCEPTION);
+ (void) CDR::encoder (except_tc, x, 0, reply, env2);
+
+ } else if (svr_req._exception) { // any exception at all
+ CORBA_Exception *x;
+ CORBA_TypeCode_ptr except_tc;
+
+ x = (CORBA_Exception *) svr_req._exception->value ();
+ except_tc = svr_req._exception->type ();
+
+ //
+ // Finish the GIOP Reply header, then marshal the exception.
+ //
+ // XXX x->type() someday ...
+ //
+ if (svr_req._ex_type == SYSTEM_EXCEPTION)
+ reply->put_ulong (GIOP::SYSTEM_EXCEPTION);
+ else
+ reply->put_ulong (GIOP::USER_EXCEPTION);
+
+ (void) CDR::encoder (except_tc, x, 0, reply, env);
+
+ } else { // normal reply
+ //
+ // First finish the GIOP header ...
+ //
+ reply->put_ulong (GIOP::NO_EXCEPTION);
+
+ //
+ // ... then send any return value ...
+ //
+ if (svr_req._retval) {
+ tc = svr_req._retval->type ();
+ value = svr_req._retval->value ();
+ (void) CDR::encoder (tc, value, 0, reply, env);
+ }
+
+ //
+ // ... followed by "inout" and "out" parameters, left to right
+ //
+ unsigned i;
+
+ for (i = 0; i < svr_req._params->count (); i++) {
+ CORBA_NamedValue_ptr nv = svr_req._params->item (i);
+ CORBA_Any_ptr any;
+
+ if (!(nv->flags () & (CORBA_ARG_INOUT|CORBA_ARG_OUT)))
+ continue;
+
+ any = nv->value ();
+ tc = any->type ();
+ value = any->value ();
+ (void) CDR::encoder (tc, value, 0, reply, env);
+ }
+ }
+}
+
+
+//
+// Helper routine that provides IIOP glue for forwarding requests
+// to specific objects from one process to another.
+//
+static GIOP::LocateStatusType
+tcp_oa_forwarder (
+ opaque &target_key,
+ CORBA_Object_ptr &forward_reference,
+ void *ctx
+)
+{
+ TCP_OA::dispatch_context *helper;
+ CORBA_Environment env;
+
+ helper = (TCP_OA::dispatch_context *) ctx;
+ assert (helper->check_forward != 0);
+ helper->check_forward (target_key, forward_reference, helper->context, env);
+
+ if (env.exception () != 0)
+ return GIOP::UNKNOWN_OBJECT;
+ else if (forward_reference == 0)
+ return GIOP::OBJECT_HERE;
+ else
+ return GIOP::OBJECT_FORWARD;
+}
+
+
+//
+// Generic routine to handle a message.
+//
+void
+TCP_OA::handle_message (
+ dispatch_context &ctx,
+ CORBA_Environment &env
+)
+{
+ GIOP::incoming_message (ctx.endpoint->fd,
+ ctx.check_forward ? tcp_oa_forwarder : 0,
+ tcp_oa_dispatcher, &ctx, env);
+
+#ifdef _POSIX_THREADS
+ Critical region (&tcpoa_mutex);
+#endif // _POSIX_THREADS
+
+ call_count--;
+}
+
+
+#ifdef _POSIX_THREADS
+//
+// For cases where the OA creates new threads to handle messages (which
+// are typically, but not always, GIOP::Request messages) we need to have
+// a routine for that new thread to execute. This is that routine: its
+// role is only to set up to call the common "handle_message" routine,
+// knowing that it's not the thread which was initially handed the message.
+//
+// In "aggressive" threading mode, it continues reading from the connection
+// until the connection goes away (e.g. client goes away, or server does
+// its shutdown work). This is a big win.
+//
+// XXX this needs to set up so it goes away with pthread_cancel(). We
+// lack any kind of "timed read" primitive so the best we could otherwise
+// do is to select (with timeout) before issuing the read, possibly with
+// a switch to another thread in between.
+//
+void *
+TCP_OA::worker (void *arg)
+{
+ CORBA_Environment env;
+ dispatch_context *context = (dispatch_context *)arg;
+
+ do {
+ dmsg1 ("worker starting on FD %d", context->endpoint->fd);
+ context->oa->handle_message (*context, env);
+
+ if (env.exception () != 0) {
+ dexc (env, "TCP_OA, worker");
+ env.clear ();
+ }
+ } while (context->aggressive && context->endpoint->fd != -1);
+
+ delete context;
+ return 0;
+}
+#endif // _POSIX_THREADS
+
+
+//
+// Block till some request comes in, and call "skeleton" when it does.
+// Uses helper routines above to do most of the work.
+//
+// THREADING NOTE: Only one thread may call this at a time, due to some
+// underlying issues with select(). If you want a model wherein a finite
+// pool of threads handles your requests, this doesn't do that. (This is
+// probably a good thing: it's all but impossible to accurately bound the
+// number of concurrent requests any given server will need to handle.)
+//
+void
+__stdcall
+TCP_OA::get_request (
+ TOA::dsi_handler handler,
+ void check_forward (
+ CORBA_OctetSeq &key,
+ CORBA_Object_ptr &fwd_ref,
+ void *ctx,
+ CORBA_Environment &env
+ ),
+ CORBA_Boolean do_thr_create,
+ void *app_state,
+ timeval *timeout,
+ CORBA_Environment &env
+)
+{
+ server_endpoint *fd;
+
+ env.clear ();
+
+ //
+ // Two bits of OA-private state need to be guarded by a critical
+ // region: the "do_exit" flag, and the "call_count" flag. These
+ // are used in clean shutdown, and can be modified here.
+ //
+ {
+#ifdef _POSIX_THREADS
+ Critical region (&tcpoa_mutex);
+#endif // _POSIX_THREADS
+
+ //
+ // Applications sometimes make mistakes: here, it'd be
+ // polling for a new request after initiating shutdown.
+ //
+ if (do_exit) {
+ dmsg ("called get_request during OA shutdown");
+ env.exception (new CORBA_BAD_INV_ORDER (COMPLETED_NO));
+ return;
+ }
+
+#ifndef _POSIX_THREADS
+ //
+ // Here, some unthreaded app asked for thread support. Ooops!
+ //
+ if (do_thr_create) {
+ env.exception (new CORBA_IMP_LIMIT (COMPLETED_NO));
+ dexc (env, "TCP_OA, unthreaded: can't create worker threads");
+ return;
+ }
+#endif // _POSIX_THREADS
+
+ //
+ // Get a request/message ... if no file descriptor is returned,
+ // the application-specified timeout was reached, leading to a
+ // clean shutdown. Otherwise we flag an incoming message (so
+ // shutdown will know it can't start yet), and leave the critical
+ // section. Some other thread could now get a request on some
+ // other connection, if one's ready.
+ //
+ // THREADING NOTE: what block_for_connection() returns will not
+ // be read or written by any other thread until it's released ...
+ // that is, until "fd" goes out of scope. At least, in the
+ // current implementation, which doesn't let threads share a
+ // connection.
+ //
+ // Also, note that the underlying constraint of only allowing a
+ // single thread to block_for_connection() call bubbles up here too.
+ //
+#ifdef _POSIX_THREADS
+ static int blocking; // = 0
+
+ if (blocking) {
+ dmsg ("concurrent TCP_OA::get_request() calls");
+ env.exception (new CORBA_IMP_LIMIT (COMPLETED_NO));
+ return;
+ } else
+ blocking = 1;
+
+ region.leave ();
+#endif // _POSIX_THREADS
+
+ //
+ // Get a connection and hand it to method code.
+ //
+ // There are four "threading modes" currently possible with
+ // this software, though only two are exposed in the OA API.
+ //
+ // - Single-Threaded ... where either no threads are
+ // used, or method code only sees one thread.
+ //
+ // - Simple MT ... like single threaded, except that
+ // (a) method code can see multiple threads, (b) a thread
+ // context switch happens before incoming methods get
+ // processed, and (c) there's expensive handshaking re
+ // connections when they're released.
+ //
+ // - "Eager" MT ... like simple MT, except that the context
+ // switch (b) is gone, and incoming data is handled right
+ // away by a thread that's always blocked in a read. The
+ // initial request latency is lower than "Simple MT".
+ //
+ // - "Aggressive" MT ... like "eager" MT except that the
+ // costly handshaking (c) is removed along with thread
+ // creation costs. Throughput is higher than with any
+ // of the other models, since it's not just initial
+ // requests which benefit from reduced latency and
+ // since overall MT-related costs are minimized.
+ //
+ // To the application, only "single threaded" and "MT" policies
+ // are exposed ... the rest is implementation details, all they
+ // really care about is whether method code seems multiple threads
+ // and the quality of the implementation (size, speed, etc).
+ //
+ // XXX Right now we equate "MT" to "Aggressive", despite problems.
+ // If clients behave well, they're not an issue; in real systems,
+ // we know clients don't always behave.
+ //
+ // One forward-looking way is to use pthread_cancel to kill idle
+ // workers ... that looks forward to a later implementation which
+ // always has a read outstanding on a connection, and so can also
+ // handle GIOP::CancelRequest messages.
+ //
+
+ fd = endpoint->block_for_connection (do_thr_create, timeout, env);
+
+#ifdef _POSIX_THREADS
+ region.enter ();
+ blocking = 0;
+#endif // _POSIX_THREADS
+
+ if (env.exception () != 0) {
+ dexc (env, "TCP_OA, block for connection");
+ return;
+ }
+ if (fd == 0) {
+ do_exit = CORBA_B_TRUE;
+ return;
+ }
+
+ //
+ // THREADING NOTE: This is the last of the need to have the OA
+ // locked ... next, let other threads in to access its state.
+ //
+ call_count++;
+ }
+
+ //
+ // OK, now we've got a connection with a "live" IIOP message ready.
+ //
+ // If we're "eager", there's not actually any data on that connection
+ // yet ... but we still hand it to some other thread as if it were
+ // all there. This gets all the setup out of the critical path so that
+ // when data does arrive, its latency is minimal: straight into the
+ // IIOP data buffer, in the best (zero copy) case, with no lingering in
+ // kernel read queues.
+ //
+ if (do_thr_create) {
+#ifdef _POSIX_THREADS
+ //
+ // Want to handle it in another thread. That means handing off a
+ // bunch of information to that thread and then having it do the
+ // work ... the simplest alternative is to heap-allocate the data
+ // and hand it over. That involves no handshaking with the thread
+ // we're about to create. Note that we're also handing off the
+ // connection resource too -- when this dispatch context gets
+ // destroyed, only then is the connection released.
+ //
+ dispatch_context *ctx;
+
+ ctx = new dispatch_context;
+ ctx->skeleton = handler;
+ ctx->check_forward = check_forward;
+ ctx->context = app_state;
+ ctx->oa = this;
+ ctx->endpoint = fd;
+ ctx->aggressive = do_thr_create;
+
+ //
+ // Actually create the thread.
+ //
+ int errcode;
+ pthread_t tid;
+
+ // XXX Devpro bug at "-O3"
+ void *(*func)(void *) = worker;
+
+ errcode = pthread_create (&tid, &thread_attr, func, ctx);
+
+ if (errcode == 0)
+ return;
+
+ //
+ // Can't create a thread as requested. Rather than handling it
+ // in another thread, we must then handle it ourselves. It's bad
+ // news to drop requests, as would happen if we were to just
+ // report an exception.
+ //
+ // XXX this should be logged as some kind of system fault;
+ // an administrator would need to deal with these failures
+ // if they happen repatedly.
+ //
+ dmsg2 ("pthread_create error: %d (%s)", errcode,
+ strerror (errcode));
+ delete context;
+
+#endif // _POSIX_THREADS
+ }
+
+ //
+ // Handle it in this thread. We can do it without any need
+ // to dynamically allocate memory.
+ //
+ dispatch_context ctx;
+
+ ctx.skeleton = handler;
+ ctx.check_forward = check_forward;
+ ctx.context = app_state;
+ ctx.oa = this;
+ ctx.endpoint = fd;
+
+#ifdef _POSIX_THREADS
+ ctx.aggressive = CORBA_B_FALSE;
+#endif
+
+ handle_message (ctx, env);
+
+ //
+ // Don't report any errors from the application/skeleton back to the
+ // top level ... the application already has a variety of means to
+ // pass whatever data needs passing, and we don't need to confuse
+ // things by mixing ORB and application errors here.
+ //
+ if (env.exception () != 0) {
+ dexc (env, "TCP_OA, handle incoming message");
+ env.clear ();
+ }
+}
+
+
+//
+// Used by method code to ask the OA to shut down.
+//
+void
+__stdcall
+TCP_OA::please_shutdown (
+ CORBA_Environment &env
+)
+{
+#ifdef _POSIX_THREADS
+ Critical region (&tcpoa_mutex);
+#endif // _POSIX_THREADS
+
+ env.clear ();
+ do_exit = CORBA_B_TRUE;
+}
+
+//
+// Used by non-method code to tell the OA to shut down.
+//
+void
+__stdcall
+TCP_OA::clean_shutdown (
+ CORBA_Environment &env
+)
+{
+#ifdef _POSIX_THREADS
+ Critical region (&tcpoa_mutex);
+#endif // _POSIX_THREADS
+
+ env.clear ();
+
+ if (call_count != 0) {
+ dmsg ("called clean_shutdown with requests outstanding");
+ env.exception (new CORBA_BAD_INV_ORDER (COMPLETED_NO));
+ return;
+ }
+
+ endpoint->shutdown_connections (GIOP::close_connection, 0);
+ endpoint = 0;
+}
+
+
+//
+// For TOA -- TOA operations for which we provide the vtable entry
+//
+
+void
+__stdcall
+TCP_OA::register_dir (
+ TOA::dsi_handler handler,
+ void *ctx,
+ CORBA_Environment &env
+)
+{
+ if (handler == 0) {
+ env.exception (new CORBA_BAD_PARAM (COMPLETED_NO));
+ return;
+ }
+
+ skeleton = handler;
+ context = ctx;
+
+ env.clear ();
+}
+
+void
+__stdcall
+TCP_OA::get_request (
+ CORBA_Boolean use_threads,
+ struct timeval *tvp,
+ CORBA_Environment &env
+)
+{
+ //
+ // API spec calls for the DIR to be registered and for this to
+ // report an invocation order problem if this is called after
+ // shutdown was started (app can always avoid the latter).
+ //
+ if (skeleton == 0) {
+ env.exception (new CORBA_INITIALIZE (COMPLETED_NO));
+ return;
+ }
+
+ //
+ // Just call the IIOP level dispatch code without allowing it to
+ // ever forward requests to another TCP_OA.
+ //
+ get_request (skeleton, 0, use_threads, context, tvp, env);
+}
+
+
+//
+// For COM -- IUnknown operations, we provide the vtable entry
+//
+
+// {A201E4C4-F258-11ce-9598-0000C07CA898}
+DEFINE_GUID (IID_TCP_OA,
+0xa201e4c4, 0xf258, 0x11ce, 0x95, 0x98, 0x0, 0x0, 0xc0, 0x7c, 0xa8, 0x98);
+
+
+ULONG
+__stdcall
+TCP_OA::AddRef ()
+{
+#ifdef _POSIX_THREADS
+ Critical region (&tcpoa_lock);
+#endif
+
+ return ++refcount;
+}
+
+ULONG
+__stdcall
+TCP_OA::Release ()
+{
+#ifdef _POSIX_THREADS
+ Critical region (&tcpoa_lock);
+#endif
+
+ if (--refcount != 0)
+ return refcount;
+
+#ifdef _POSIX_THREADS
+ region.leave ();
+#endif
+
+ delete this;
+ return 0;
+}
+
+HRESULT
+__stdcall
+TCP_OA::QueryInterface (
+ REFIID riid,
+ void **ppv
+)
+{
+ *ppv = 0;
+
+ if (IID_TCP_OA == riid
+ || IID_TOA == riid
+ || IID_IUnknown == riid)
+ *ppv = this;
+
+ if (*ppv == 0)
+ return ResultFromScode (E_NOINTERFACE);
+
+ (void) AddRef ();
+ return NOERROR;
+}
diff --git a/TAO/IIOP/lib/bridge/tcpoa.hh b/TAO/IIOP/lib/bridge/tcpoa.hh
new file mode 100644
index 00000000000..47212d4f22b
--- /dev/null
+++ b/TAO/IIOP/lib/bridge/tcpoa.hh
@@ -0,0 +1,276 @@
+// @(#)tcpoa.hh 1.6 95/10/02
+// Copyright 1994-1995 by Sun Microsystems Inc.
+// All Rights Reserved
+//
+// Simple "TCP" OA ... lets one create objrefs very thinly layered atop
+// TCP addressing. This OA holds no state whatsoever (!!!!), and only
+// supports transient objects.
+//
+// You may well want to build more "advanced" OAs on top of this one,
+// providing features such as activation of persistent objects. (The
+// BOA, for example, provides a persistent object activation facility.)
+//
+// In particular: you will probably want to build atop this to plug in
+// skeletons for any language binding, mapping individual objrefs to type
+// and implementation information so support for CORBA::Object operations
+// such as get_interface(), is_a(), get_implementation(), and the test for
+// non-existence can all be handled by an Object Adapter, not by any
+// application code.
+//
+// This might also be the appropriate level to define interfaces that'd
+// let MT-unsafe window system toolkits hardwire their event dispatch
+// frameworks into the one used by this ORB. For MT-safe window system
+// toolkits, such integration is not needed because everything works
+// fine if the application just allocates one thread to handle dispatch
+// of each subsystem's events (e.g. ORB, GUI, etc).
+//
+
+#ifndef _TCPOA_HH
+#define _TCPOA_HH
+
+class _EXPCLASS TCP_OA;
+typedef TCP_OA *TCP_OA_ptr;
+
+extern const IID IID_TCP_OA;
+
+class _EXPCLASS TCP_OA : public TOA {
+ public:
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // TOA support ... TOA is intended to be a public API that anyone can
+ // use, including skeletons.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ CORBA_Object_ptr __stdcall create (
+ CORBA_OctetSeq &obj_id,
+ CORBA_String type_id,
+ CORBA_Environment &env
+ );
+
+ void __stdcall register_dir (
+ TOA::dsi_handler handler,
+ void *context,
+ CORBA_Environment &env
+ );
+
+ void __stdcall get_request (
+ CORBA_Boolean use_threads,
+ struct timeval *tvp,
+ CORBA_Environment &env
+ );
+
+ void __stdcall please_shutdown (
+ CORBA_Environment &env
+ );
+
+ //
+ // Stuff required for COM IUnknown support
+ //
+ ULONG __stdcall AddRef ();
+ ULONG __stdcall Release ();
+ HRESULT __stdcall QueryInterface (
+ REFIID riid,
+ void **ppv
+ );
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // TCP_OA SPECIFIC from here on down ... all of this is subject to
+ // change and simplification. It's intended to be an internal API
+ // providing efficient access to all basic IIOP functionality.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ //
+ // OA initialisation, per the template in OMG TC doc 94-9-46
+ //
+ // NOTE that since this OA is not defined by OMG, it doesn't
+ // go into the CORBA (and hence ORB) scope and acquiring this
+ // OA is not an operation on any particular ORB.
+ //
+ // Also, this needs no configuration beyond which OA is used;
+ // there's no need for argc/argv to control any initialization
+ // options.
+ //
+ static TCP_OA_ptr init (
+ CORBA_ORB_ptr which_orb,
+ char *oa_name,
+ CORBA_Environment &env
+ );
+
+ //
+ // Block till some request comes in, or "timeout" passes. Handle any
+ // requests with "handle_request", passing it "context" for access to
+ // non-global application state.
+ //
+ // If the "do_thr_create" flag is set, "handle_request" is invoked in
+ // a new thread rather than by the calling thread.
+ //
+ // If "check_forward" is null, all incoming requests are passed to
+ // handle_request() and requests for objects can't be forwarded so
+ // they arrive at any other process.
+ //
+ // If "check_forward" is non-null, the function is called when the OA
+ // needs to establish whether a request for a particular object (as
+ // identified by "key") are handled in this process. If it returns an
+ // exception, the object is deemed not to exist (this is authoritative).
+ // If the "fwd_ref" returned is non-null, the request is forwarded to
+ // that object reference. Otherwise (no exception, null "fwd_ref")
+ // requests for that object may arrive via handle_request().
+ //
+ // This routine returns after a request arrives, regardless of whether
+ // a thread started processing.
+ //
+ void __stdcall get_request (
+ TOA::dsi_handler handle_request,
+ void check_forward (
+ CORBA_OctetSeq &key,
+ CORBA_Object_ptr &fwd_ref,
+ void *context,
+ CORBA_Environment &env
+ ),
+ CORBA_Boolean do_thr_create,
+ void *context,
+ timeval *timeout,
+ CORBA_Environment &env
+ );
+
+ //
+ // OA user asks for a clean shutdown of the OA after currently
+ // active calls complete. OA "requester" (calls get_request)
+ // asks if we're shutting down, and if so closes down transport
+ // cleanly.
+ //
+ CORBA_Boolean shutting_down ()
+ { return do_exit; }
+
+ void clean_shutdown (
+ CORBA_Environment &env
+ );
+
+ //
+ // When dispatching a request to an object, you need to be able to get
+ // the object key you used to create the reference. It's the main way
+ // servers distinguish two object references from each other.
+ //
+ CORBA_OctetSeq *__stdcall get_key (
+ CORBA_Object_ptr obj,
+ CORBA_Environment &env
+ );
+
+ //
+ // OA-specific state
+ //
+ CORBA_ORB_ptr orb () const { return _orb; }
+
+ //
+ // Various request-specific state.
+ //
+ CORBA_OctetSeq *__stdcall get_target_key (
+ CORBA_Environment &env
+ );
+ CORBA_Principal_ptr __stdcall get_client_principal (
+ CORBA_Environment &env
+ );
+
+ // PRIVATE:
+
+ //
+ // Data structure passed as "context" to the GIOP code, which then
+ // calls back one of the two helper routines as part of handling any
+ // particular incoming request.
+ //
+ struct dispatch_context {
+ TOA::dsi_handler skeleton;
+ void (*check_forward) (
+ CORBA_OctetSeq &key,
+ CORBA_Object_ptr &fwd_ref,
+ void *context,
+ CORBA_Environment &env
+ );
+ void *context;
+ TCP_OA *oa;
+ autorelease <server_endpoint>
+ endpoint;
+#ifdef _POSIX_THREADS
+ CORBA_Boolean aggressive;
+#endif // _POSIX_THREADS
+ };
+
+ private:
+ CORBA_UShort port;
+ CORBA_Boolean do_exit;
+ CORBA_ORB_ptr _orb;
+ unsigned call_count;
+ unsigned refcount;
+ server_endpoint *endpoint;
+
+ TOA::dsi_handler skeleton;
+ void *context;
+
+ //
+ // Used internally by threaded (and unthreaded) code to
+ // dispatch incoming GIOP messages
+ //
+ void handle_message (
+ dispatch_context &context,
+ CORBA_Environment &env
+ );
+
+#ifdef _POSIX_THREADS
+ //
+ // Used internally by threaded code to process incoming messages.
+ //
+ static void *worker (void *arg);
+#endif // _POSIX_THREADS
+
+ //
+ // Constructor -- build it with a port number to listen to
+ //
+ TCP_OA (
+ CORBA_ORB_ptr orb_arg,
+ CORBA_UShort port,
+ CORBA_Environment &env
+ );
+ virtual ~TCP_OA ();
+
+ //
+ // Copy and assignment: just say no
+ //
+ TCP_OA (const TCP_OA &src);
+ TCP_OA &operator = (const TCP_OA &src);
+
+#if defined (__GNUG__)
+ //
+ // G++ (even 2.6.3) stupidly thinks instances can't be
+ // created. This de-warns.
+ //
+ friend class everyone_needs_a_friend;
+#endif
+};
+
+typedef TCP_OA *TCP_OA_ptr;
+
+
+//
+// Method code (only!) is defined to have access to three functions, for
+// the orb, object, and OA involved in a call.
+//
+// In this version we implement these by access through routines that
+// use thread-specific data in multithreaded environments; the routines
+// themselves (implementation of the symbol) are not public, but the
+// symbol is usable in any method code.
+//
+// NOTE: it'd be preferable to define the "orb" and "tcp_oa" symbols
+// only within method code (e.g. protected member functions on some
+// servant base class), but as we don't yet implement much server
+// side mapping that's impractical.
+//
+// XXX many of these are now methods on CORBA_ServerRequest...
+//
+extern CORBA_Object_ptr __stdcall _this (void);
+
+#endif // _TCPOA_HH
+
diff --git a/TAO/IIOP/lib/corba/any.hh b/TAO/IIOP/lib/corba/any.hh
new file mode 100644
index 00000000000..4b0a6590e5b
--- /dev/null
+++ b/TAO/IIOP/lib/corba/any.hh
@@ -0,0 +1,87 @@
+//
+// Header file for Win32 C/C++/COM interface to CORBA's "Any" type.
+//
+// Class "Any" can wrap values of any type, with the assistance
+// of a TypeCode to describe that type.
+//
+// XXX should find a way to make its memory allocation always go
+// within the appropriate OLE heap...
+//
+typedef CORBA_Any *CORBA_Any_ptr;
+
+extern const IID IID_CORBA_Any;
+
+class CORBA_Any : public IUnknown
+{
+ public:
+ // minor codes for exceptional returns
+ enum {
+ uninitialised_type = 0xf000,
+ value_without_type,
+ unsupported_operation
+ };
+
+ CORBA_Any ();
+ CORBA_Any (
+ CORBA_TypeCode_ptr type,
+ void *value = 0,
+ CORBA_Boolean orb_owns_data
+ = CORBA_B_FALSE
+ );
+ CORBA_Any (const CORBA_Any &a);
+ virtual ~CORBA_Any ();
+
+ void *operator new (size_t, const void *p)
+ { return (void *) p; }
+ void *operator new (size_t s)
+ { return ::operator new (s); }
+ void operator delete (void *p)
+ { ::operator delete (p); }
+
+ //
+ // NOTE: 94-9-14 has assignment operator plus many insertion,
+ // extraction operators, various from_xx and to_xx helper classes.
+ //
+
+ void replace (
+ CORBA_TypeCode_ptr type,
+ const void *value,
+ CORBA_Boolean orb_owns_data,
+ CORBA_Environment &env
+ );
+
+ CORBA_TypeCode_ptr type () const;
+ void *value () const;
+
+ //
+ // Stuff required for COM IUnknown support
+ //
+ ULONG __stdcall AddRef ();
+ ULONG __stdcall Release ();
+ HRESULT __stdcall QueryInterface (
+ REFIID riid,
+ void **ppv
+ );
+
+ //
+ // Conversion to/from COM Variant types: copy constructor,
+ // assignment operator, cast.
+ //
+ CORBA_Any (const VARIANT &src);
+ CORBA_Any &operator = (const VARIANT &src);
+ operator VARIANT ();
+
+ private:
+ CORBA_TypeCode_ptr _type;
+ void *_value;
+ CORBA_Boolean _orb_owns_data;
+
+ unsigned _refcnt;
+
+ // NOT PROVIDED
+ CORBA_Any &operator = (const CORBA_Any &a);
+
+ //
+ // 94-9-14 hides unsigned char insert/extract
+ //
+};
diff --git a/TAO/IIOP/lib/corba/corbacom.hh b/TAO/IIOP/lib/corba/corbacom.hh
new file mode 100644
index 00000000000..2a8ea5e23c2
--- /dev/null
+++ b/TAO/IIOP/lib/corba/corbacom.hh
@@ -0,0 +1,108 @@
+// @(#)corbacom.hh 1.2 95/10/02
+// Copyright 1995 by Sun Microsystems, Inc.
+// All Rights Reserved
+//
+// CORBA C/C++/COM mapping for Win32
+//
+
+#include <objbase.h> // Win32 name for "compobj.h"
+
+#if SIZEOF_BOOL != 0
+typedef bool CORBA_Boolean;
+#define CORBA_B_FALSE false
+#define CORBA_B_TRUE true
+
+#else // "bool" not builtin to this compiler
+typedef int CORBA_Boolean;
+enum { CORBA_B_FALSE = 0, CORBA_B_TRUE = 1 };
+#endif // "bool" not builtin
+
+typedef unsigned char CORBA_Octet;
+
+typedef short CORBA_Short;
+typedef unsigned short CORBA_UShort;
+
+//
+// CORBA "Long" (and its unsigned cousin) are 32 bits, just like
+// on almost all C/C++ compilers.
+//
+#if SIZEOF_LONG == 4
+typedef long CORBA_Long;
+typedef unsigned long CORBA_ULong;
+#else
+// just assume "int" is 4 bytes long ...
+typedef int CORBA_Long;
+typedef unsigned CORBA_ULong;
+#endif // SIZEOF_LONG != 4
+
+//
+// 94-9-32 Appendix A, also the OMG C++ mapping, stipulate that
+// 64 bit integers are "LongLong".
+//
+// NOTE: those are IDL extensions, not yet standard.
+//
+#if SIZEOF_LONG_LONG == 8
+typedef long long CORBA_LongLong;
+typedef unsigned long long CORBA_ULongLong;
+#elif SIZEOF_LONG == 8
+typedef long CORBA_LongLong;
+typedef unsigned long CORBA_ULongLong;
+#elif defined (_MSC_VER) && _MSC_VER >= 900
+typedef __int64 CORBA_LongLong;
+typedef unsigned __int64 CORBA_ULongLong;
+#else
+//
+// If "long long" isn't native, programs can't use these
+// data types in normal arithmetic expressions. If any
+// particular application can cope with the loss of range
+// it can define conversion operators itself.
+//
+# define NONNATIVE_LONGLONG
+#if defined (WORDS_BIGENDIAN)
+struct CORBA_LongLong { CORBA_Long h, l; };
+struct CORBA_ULongLong { UCORBA_Long h, l; };
+#else
+struct CORBA_LongLong { CORBA_Long l, h; };
+struct CORBA_ULongLong { CORBA_ULong l, h; };
+#endif // !WORDS_BIGENDIAN
+#endif // no native 64 bit integer type
+
+typedef float CORBA_Float;
+typedef double CORBA_Double;
+
+//
+// 94-9-32 Appendix A defines a 128 bit floating point "long
+// double" data type, with greatly extended precision and
+// four more bits of exponent (compared to "double").
+//
+// NOTE: that is an IDL extension, not yet standard.
+//
+#if SIZEOF_LONG_DOUBLE == 16
+typedef long double CORBA_LongDouble;
+#else
+#define NONNATIVE_LONGDOUBLE
+struct CORBA_LongDouble {
+ char ld [16];
+};
+#endif // SIZEOF_LONG_DOUBLE != 16
+
+typedef char CORBA_Char;
+typedef CORBA_Char *CORBA_String;
+
+CORBA_String CORBA_string_alloc (CORBA_ULong len);
+CORBA_String CORBA_string_copy (const CORBA_Char *const);
+void CORBA_string_free (CORBA_Char *const);
+
+//
+// 94-9-32 Appendix A defines 16-bit UNICODE characters as
+// "WChar", and null-terminated strings of them as "WString".
+//
+// NOTE: those are IDL extensions, not yet standard.
+//
+typedef wchar_t CORBA_WChar;
+typedef CORBA_WChar *CORBA_WString;
+
+CORBA_WString CORBA_wstring_alloc (CORBA_ULong len);
+CORBA_WString CORBA_wstring_copy (const CORBA_WChar *const);
+void CORBA_wstring_free (CORBA_WChar *const);
+
diff --git a/TAO/IIOP/lib/corba/except.hh b/TAO/IIOP/lib/corba/except.hh
new file mode 100644
index 00000000000..0dacdfb0900
--- /dev/null
+++ b/TAO/IIOP/lib/corba/except.hh
@@ -0,0 +1,186 @@
+//
+// Header file for Win32 C/C++/COM interface to a CORBA ORB.
+//
+// This file defines way in which CORBA exceptions are reported.
+//
+
+//
+// CORBA2-specified exception hierarchy.
+//
+// All exceptions have a type (represented by a TypeCode) and a widely
+// scoped type ID (in the TypeCode) that generated by any OMG-IDL compiler
+// and available through the Interface Repositories. Think of it as a
+// "globally scoped" name distinguishing each exception.
+//
+extern const IID IID_CORBA_Exception;
+extern const IID IID_CORBA_UserException;
+extern const IID IID_CORBA_SystemException;
+
+class _EXPCLASS CORBA_Exception : public IUnknown {
+ public:
+ CORBA_Exception (const CORBA_Exception &src);
+ CORBA_Exception &operator = (const CORBA_Exception &src);
+
+ void *operator new (size_t, const void *p)
+ { return (void *) p; }
+ void *operator new (size_t s)
+ { return ::operator new (s); }
+ void operator delete (void *p)
+ { ::operator delete (p); }
+
+
+ const CORBA_String id () const;
+ const CORBA_TypeCode_ptr type () const;
+
+ //
+ // Stuff required for COM IUnknown support
+ //
+ ULONG __stdcall AddRef ();
+ ULONG __stdcall Release ();
+ HRESULT __stdcall QueryInterface (
+ REFIID riid,
+ void **ppv
+ );
+
+ CORBA_Exception (
+ CORBA_TypeCode_ptr type
+ );
+ virtual ~CORBA_Exception ();
+ private:
+ CORBA_TypeCode_ptr _type;
+ unsigned _refcnt;
+};
+typedef CORBA_Exception *CORBA_Exception_ptr;
+
+//
+// User exceptions are those defined by application developers
+// using OMG-IDL.
+//
+class _EXPCLASS CORBA_UserException : public CORBA_Exception {
+ public:
+ CORBA_UserException (CORBA_TypeCode_ptr tc);
+ ~CORBA_UserException ();
+ protected:
+ // copy and assignment operators
+};
+
+//
+// System exceptions are those defined in the CORBA spec; OMG-IDL
+// defines these.
+//
+enum CORBA_CompletionStatus {
+ COMPLETED_YES, // successful or exceptional completion
+ COMPLETED_NO, // didn't change any state; retry is OK
+ COMPLETED_MAYBE // can't say what happened; retry unsafe
+};
+
+class _EXPCLASS CORBA_SystemException : public CORBA_Exception {
+ public:
+ // 94-9-14 also sez: public copy constructor
+ // and assignment operator.
+
+ CORBA_SystemException (
+ CORBA_TypeCode_ptr tc,
+ CORBA_ULong code,
+ CORBA_CompletionStatus completed
+ );
+ ~CORBA_SystemException ();
+
+ CORBA_ULong minor () const { return _minor; }
+ void minor (CORBA_ULong m) { _minor = m; }
+
+ CORBA_CompletionStatus completion () const { return _completed; }
+ void completion (CORBA_CompletionStatus c)
+ { _completed = c; }
+
+ private:
+ CORBA_ULong _minor;
+ CORBA_CompletionStatus _completed;
+};
+
+
+//
+// Declarations for all of the CORBA standard exceptions.
+//
+// XXX shouldn't have a default minor code, at least for code that's
+// inside the ORB. All minor codes should be symbolically catalogued.
+//
+#define SYSEX(name) \
+extern CORBA_TypeCode_ptr _tc_CORBA_ ## name ; \
+class _EXPCLASS CORBA_ ## name : public CORBA_SystemException { \
+ public: \
+ CORBA_ ## name ( \
+ CORBA_CompletionStatus completed, \
+ CORBA_ULong code = 0xffff0000L \
+ ) : CORBA_SystemException ( \
+ _tc_CORBA_ ## name, \
+ code, completed) { } }
+
+SYSEX (UNKNOWN);
+SYSEX (BAD_PARAM);
+SYSEX (NO_MEMORY);
+SYSEX (IMP_LIMIT);
+SYSEX (COMM_FAILURE);
+SYSEX (INV_OBJREF);
+SYSEX (OBJECT_NOT_EXIST);
+SYSEX (NO_PERMISSION);
+SYSEX (INTERNAL);
+SYSEX (MARSHAL);
+SYSEX (INITIALIZE);
+SYSEX (NO_IMPLEMENT);
+SYSEX (BAD_TYPECODE);
+SYSEX (BAD_OPERATION);
+SYSEX (NO_RESOURCES);
+SYSEX (NO_RESPONSE);
+SYSEX (PERSIST_STORE);
+SYSEX (BAD_INV_ORDER);
+SYSEX (TRANSIENT);
+SYSEX (FREE_MEM);
+SYSEX (INV_IDENT);
+SYSEX (INV_FLAG);
+SYSEX (INTF_REPOS);
+SYSEX (BAD_CONTEXT);
+SYSEX (OBJ_ADAPTER);
+SYSEX (DATA_CONVERSION);
+
+#undef SYSEX
+
+//
+// A CORBA_Environment is a way to automagically ensure that exception
+// data is freed -- the "var" class for Exceptions. It adds just a bit
+// of convenience function support, helping classify exceptions as well
+// as reducing memory leakage.
+//
+enum CORBA_ExceptionType {
+ NO_EXCEPTION,
+ SYSTEM_EXCEPTION,
+ USER_EXCEPTION
+};
+
+class CORBA_Environment {
+ public:
+ CORBA_Environment () : _exception (0) { }
+ ~CORBA_Environment () { clear (); }
+
+ CORBA_Exception_ptr exception () const { return _exception; }
+ void exception (CORBA_Exception *ex)
+ { clear (); _exception = ex; }
+
+ CORBA_ExceptionType exception_type () const;
+ const CORBA_String exception_id () const;
+
+ void clear ()
+ {
+ if (_exception) {
+ _exception->Release ();
+ _exception = 0; // XXX
+ }
+ }
+
+ private:
+ CORBA_Exception_ptr _exception;
+
+ // these are not provided
+ CORBA_Environment (const CORBA_Environment &src);
+ CORBA_Environment &operator = (const CORBA_Environment &src);
+};
diff --git a/TAO/IIOP/lib/corba/nvlist.hh b/TAO/IIOP/lib/corba/nvlist.hh
new file mode 100644
index 00000000000..e7b8b8e20dd
--- /dev/null
+++ b/TAO/IIOP/lib/corba/nvlist.hh
@@ -0,0 +1,119 @@
+// @(#)nvlist.hh 1.5 95/09/12
+// Copyright 1995 by Sun Microsystems, Inc.
+//
+// NamedValue ... these occur only in "NVList" (named value list)
+// data structures. The binary form of the data structure is frozen
+// and visible to programs using it (e.g. from C). The C++ class
+// supports some programming discipline, e.g. to avoid memory leaks.
+//
+// They just represent parameters to calls. The name is optional,
+// and the value is packaged as an Any. The flags indicate parameter
+// mode, and some ownership rules for "top level" memory.
+//
+class _EXPCLASS CORBA_NamedValue;
+
+void CORBA_release (CORBA_NamedValue_ptr x);
+CORBA_Boolean CORBA_is_nil (CORBA_NamedValue_ptr x);
+
+// No IID required
+enum {
+ CORBA_ARG_IN = 0x01,
+ CORBA_ARG_OUT = 0x02,
+ CORBA_ARG_INOUT = 0x04,
+ CORBA_IN_COPY_VALUE = 0x08,
+ CORBA_OUT_LIST_MEMORY = 0x10
+};
+
+class _EXPCLASS CORBA_NamedValue
+{
+ public:
+ const CORBA_String _FAR name () { return (const CORBA_String) _name; }
+ CORBA_Any_ptr _FAR value () { return &_any; }
+ CORBA_Flags flags () const { return _flags; }
+
+ ~CORBA_NamedValue ();
+
+ //
+ // Stuff required for COM IUnknown support
+ //
+ ULONG __stdcall AddRef ();
+ ULONG __stdcall Release ();
+ HRESULT __stdcall QueryInterface (
+ REFIID riid,
+ void **ppv
+ );
+
+ private:
+ unsigned _refcount;
+
+ CORBA_Any _any;
+ CORBA_Flags _flags;
+ const CORBA_Char *_FAR _name;
+
+ CORBA_NamedValue () : _flags (0), _name (0) { }
+
+ friend class CORBA_NVList;
+ friend class CORBA_Request;
+};
+
+
+//
+// NVList ... this is used in the (client side) DII (Dynamic Invocation
+// Interface) to hold parameters, except for the return parameter. It's
+// used in the same role in the (server side) DSI (Dynamic Skeleton
+// Interface).
+//
+// Each user (client, server) provides the typecode and memory for each
+// parameter using an NVList, then talks to the ORB using a Request or
+// ServerRequest pseudo-object. The ORB copies data to/from the IPC
+// messages (e.g. IIOP::Request, IIOP::Response) as appropriate.
+//
+class _EXPCLASS CORBA_NVList;
+
+void CORBA_release (CORBA_NVList_ptr x);
+CORBA_Boolean CORBA_is_nil (CORBA_NVList_ptr x);
+
+extern "C" const IID IID_CORBA_NVList;
+
+class _EXPCLASS CORBA_NVList
+{
+ public:
+ CORBA_ULong count () const
+ { return _len; }
+
+ CORBA_NamedValue_ptr add_value (
+ const CORBA_Char *_FAR ,
+ const CORBA_Any _FAR &,
+ CORBA_Flags,
+ CORBA_Environment _FAR &
+ );
+
+ CORBA_NamedValue_ptr item (CORBA_Long n) const
+ { return &_values [(unsigned) n]; }
+
+ ~CORBA_NVList ();
+
+ //
+ // Stuff required for COM IUnknown support
+ //
+ ULONG __stdcall AddRef ();
+ ULONG __stdcall Release ();
+ HRESULT __stdcall QueryInterface (
+ REFIID riid,
+ void **ppv
+ );
+
+ private:
+ CORBA_NamedValue *_FAR _values;
+ unsigned _max;
+ unsigned _len;
+ unsigned _refcount;
+
+ CORBA_NVList ()
+ : _values (0), _max (0),
+ _len (0), _refcount (1)
+ { }
+
+ friend class CORBA_ORB;
+ friend class CORBA_Request;
+};
diff --git a/TAO/IIOP/lib/corba/object.hh b/TAO/IIOP/lib/corba/object.hh
new file mode 100644
index 00000000000..6296fa7682a
--- /dev/null
+++ b/TAO/IIOP/lib/corba/object.hh
@@ -0,0 +1,111 @@
+// @(#)object.hh 1.7 95/11/30
+// Copyright 1995 by Sun Microsystems, Inc.
+// All Rights Reserved
+//
+// Header file for Win32 interface to CORBA's base "Object" type.
+//
+// A "Object" is an entity that can be the target of an invocation
+// using an ORB. All CORBA objects provide this functionality.
+// See the CORBA 2.0 specification for details.
+//
+typedef class CORBA_Object *CORBA_Object_ptr;
+void CORBA_release (CORBA_Object_ptr obj);
+CORBA_Boolean CORBA_is_nil (CORBA_Object_ptr obj);
+
+extern const IID IID_CORBA_Object;
+
+class _EXPCLASS CORBA_Object : public IUnknown
+{
+ public:
+ static CORBA_Object_ptr _duplicate (CORBA_Object_ptr obj);
+ static CORBA_Object_ptr _nil ();
+
+ //
+ // These calls correspond to over-the-wire operations, or at
+ // least do so in many common cases. The normal implementation
+ // assumes a particular simple, efficient, protocol-neutral
+ // interface for making such calls, but may be overridden when
+ // it appears appropriate.
+ //
+ virtual CORBA_InterfaceDef_ptr __stdcall
+ _get_interface (
+ CORBA_Environment &env
+ );
+ virtual CORBA_Boolean __stdcall
+ _is_a (
+ const CORBA_Char *logical_type_id,
+ CORBA_Environment &env
+ );
+ virtual CORBA_ImplementationDef_ptr __stdcall
+ _get_implementation (
+ CORBA_Environment &env
+ );
+ virtual CORBA_Boolean __stdcall
+ _non_existent (
+ CORBA_Environment &env
+ );
+
+ //
+ // The mapping for create_request is split into two forms, corresponding to
+ // the two usage styles described in CORBA section 6.2.1.
+ //
+ // The default implementation of this method uses the same simple,
+ // multi-protocol remote invocation interface as is assumed by the
+ // calls above ... that's how it can have a default implementation.
+ //
+ virtual void __stdcall
+ _create_request(
+ const CORBA_Char *operation,
+ CORBA_NVList_ptr arg_list,
+ CORBA_NamedValue_ptr result,
+ CORBA_Request_ptr &request,
+ CORBA_Flags req_flags,
+ CORBA_Environment &env
+ );
+ virtual CORBA_Request_ptr __stdcall
+ _request (
+ const CORBA_Char *operation,
+ CORBA_Environment &env
+ );
+
+ //
+ // These two rely on the representation of the object reference's
+ // private state. Since that changes easily (when different
+ // ORB protocols are in use) there is no default implementation.
+ //
+ virtual CORBA_ULong __stdcall
+ _hash (
+ CORBA_ULong maximum,
+ CORBA_Environment &env
+ );
+ virtual CORBA_Boolean __stdcall
+ _is_equivalent (
+ CORBA_Object_ptr other_obj,
+ CORBA_Environment &env
+ );
+ //
+ // Stuff required for COM IUnknown support ... this class is
+ // intended to aggregate or be contained with others, which
+ // in combination provide all requisite CORBA/COM support.
+ //
+ ULONG __stdcall AddRef ();
+ ULONG __stdcall Release ();
+ HRESULT __stdcall QueryInterface (
+ REFIID riid,
+ void **ppv
+ );
+
+ CORBA_Object (IUnknown *p);
+ virtual ~CORBA_Object ();
+
+ private:
+ IUnknown *const parent;
+
+ //
+ // these two are not provided!
+ //
+ CORBA_Object (const CORBA_Object &);
+ CORBA_Object &operator = (const CORBA_Object &);
+};
+
+// XXX need CORBA_Object_var class typedef
diff --git a/TAO/IIOP/lib/corba/orb.hh b/TAO/IIOP/lib/corba/orb.hh
new file mode 100644
index 00000000000..ccb5ea69c29
--- /dev/null
+++ b/TAO/IIOP/lib/corba/orb.hh
@@ -0,0 +1,159 @@
+// @(#)orb.hh 1.3 95/09/13
+
+/*
+
+COPYRIGHT AND LICENSING
+-----------------------
+This notice applies to all files in this software distribution.
+Please read it!
+
+
+Copyright 1995 Sun Microsystems, Inc.
+Printed in the United States of America.
+All Rights Reserved.
+
+This software product (LICENSED PRODUCT), implementing the Object Management
+Group's "Internet Inter-ORB Protocol", is protected by copyright and is
+distributed under the following license restricting its use. Portions of
+LICENSED PRODUCT may be protected by one or more U.S. or foreign patents, or
+pending applications.
+
+LICENSED PRODUCT is made available for your use provided that you include
+this license and copyright notice on all media and documentation and the
+software program in which this product is incorporated in whole or part.
+
+You may copy, modify, distribute, or sublicense the LICENCED PRODUCT without
+charge as part of a product or software program developed by you, so long as
+you preserve the functionality of interoperating with the Object Management
+Group's "Internet Inter-ORB Protocol" version one. However, any uses other
+than the foregoing uses shall require the express written consent of Sun
+Microsystems, Inc.
+
+The names of Sun Microsystems, Inc. and any of its subsidiaries or
+affiliates may not be used in advertising or publicity pertaining to
+distribution of the LICENSED PRODUCT as permitted herein.
+
+This license is effective until terminated by Sun for failure to comply with
+this license. Upon termination, you shall destroy or return all code and
+documentation for the LICENSED PRODUCT.
+
+LICENSED PRODUCT IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
+THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+PURPOSE, NONINFRINGEMENT, OR ARISING FROM A COURSE OF DEALING, USAGE OR
+TRADE PRACTICE.
+
+LICENSED PRODUCT IS PROVIDED WITH NO SUPPORT AND WITHOUT ANY OBLIGATION ON
+THE PART OF SUN OR ANY OF ITS SUBSIDIARIES OR AFFILIATES TO ASSIST IN ITS
+USE, CORRECTION, MODIFICATION OR ENHANCEMENT.
+
+SUN OR ANY OF ITS SUBSIDIARIES OR AFFILIATES SHALL HAVE NO LIABILITY WITH
+RESPECT TO THE INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY
+LICENSED PRODUCT OR ANY PART THEREOF.
+
+IN NO EVENT WILL SUN OR ANY OF ITS SUBSIDIARIES OR AFFILIATES BE LIABLE FOR
+ANY LOST REVENUE OR PROFITS OR OTHER SPECIAL, INDIRECT AND CONSEQUENTIAL
+DAMAGES, EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+Use, duplication, or disclosure by the government is subject to restrictions
+as set forth in subparagraph (c)(1)(ii) of the Rights in Technical Data and
+Computer Software clause at DFARS 252.227-7013 and FAR 52.227-19.
+
+SunOS, SunSoft, Sun, Solaris, Sun Microsystems and the Sun logo are
+trademarks or registered trademarks of Sun Microsystems, Inc.
+
+SunSoft, Inc.
+2550 Garcia Avenue
+Mountain View, California 94043
+
+*/
+
+//
+// MASTER HEADER file for C/C++ Win32 interface to a CORBA 2.0 ORB.
+// Include only this file, to see all ORB interfaces declared.
+//
+// This interface uses COM as the basis for its binary standard, and
+// follows the OMG C++ mapping for compilers which don't support C++
+// exceptions (COM doesn't use them) or namespaces. Objects which
+// are implemented using this source base support OLE Automation.
+//
+// XXX Note re status of this as reference, cosubmitted with RFP?
+//
+#ifndef _CORBA_orb_hh
+#define _CORBA_orb_hh
+
+#include <stdlib.h>
+
+//
+// For some reason, PC compilers don't implement "natural" alignment, but
+// only use fixed alignment policies. The following #pragmas configure
+// fixed one-byte alignment policy, since some fixed policy needs to apply
+// throughout an ORB.
+//
+#if defined (_MSC_VER)
+# pragma pack (push, 1) // VC++, stack 1-byte alignment policy
+
+# ifdef _DEBUG // convert from VC++ convention ...
+# define DEBUG // ... to normal convention
+# endif
+
+#elif defined (__BORLANDC__)
+# pragma option -a // BC++, use 1 byte alignment
+
+#endif
+
+//
+// Get various definitions facilitating portability.
+//
+#include <corba/orbconf.hh>
+
+//
+// Forward declarations of some data types are needed.
+//
+typedef class CORBA_TypeCode *CORBA_TypeCode_ptr;
+typedef class CORBA_Any *CORBA_Any_ptr;
+
+typedef class CORBA_ImplementationDef *CORBA_ImplementationDef_ptr;
+
+typedef class CORBA_InterfaceDef *CORBA_InterfaceDef_ptr;
+
+typedef class CORBA_Request *CORBA_Request_ptr;
+
+typedef class CORBA_NamedValue *CORBA_NamedValue_ptr;
+
+typedef class CORBA_NVList *CORBA_NVList_ptr;
+
+typedef unsigned CORBA_Flags; // enum values defined in nvlist.hh,
+ // bitwise ORed
+
+//
+// Basic types used in the CORBA 2.0 runtime
+//
+#include <corba/corbacom.hh>
+#include <corba/except.hh>
+#include <corba/object.hh>
+#include <corba/sequence.hh>
+#include <corba/principa.hh>
+#include <corba/typecode.hh>
+#include <corba/any.hh>
+#include <corba/nvlist.hh>
+#include <corba/request.hh>
+#include <corba/svrrqst.hh>
+
+//
+// Bootstrapping, etc
+//
+#include <corba/orbobj.hh>
+
+
+// NOTE: stub APIs are nonportable, and must be explicitly #included
+// by code emitted from an IDL compiler.
+
+
+#if defined (_MSC_VER)
+# pragma pack (pop) // VC++, goes back to other padding rules
+#endif // VC++
+
+ // BC++ we leave with 1-byte padding rules...
+
+#endif // _CORBA_orb_hh
+
diff --git a/TAO/IIOP/lib/corba/orbconf.hh b/TAO/IIOP/lib/corba/orbconf.hh
new file mode 100644
index 00000000000..7c6906aa7ad
--- /dev/null
+++ b/TAO/IIOP/lib/corba/orbconf.hh
@@ -0,0 +1,203 @@
+/* orbconf.hh. Generated automatically by configure. */
+// @(#)orbconf.hh 1.2 95/10/02
+// Copyright 1995 by Sun Microsystems, Inc
+//
+// Build configuration file for the Inter-ORB Engine, and application
+// level code using it via <corba.hh>
+//
+// !! Modify "orbconf.hh", not the file generated by "configure" !!
+//
+// Keep the tests in the order they're found in "configure.in". Also, keep
+// in mind that all "#undef" preprocessor directives are deemed to be the
+// property of "autoconf"; if those are needed in their own right, they must
+// be in some other file.
+//
+// This file builds on work originally contributed by a team at apm.co.uk:
+// Owen Rees (rtor), Guangxing Li (gxl) and Mike Beasley (mdrb).
+//
+
+#ifndef _ORB_CONFIG_HH
+#define _ORB_CONFIG_HH
+
+/* Define if you have the <widec.h> header file. */
+#define HAVE_WIDEC_H 1
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef pid_t */
+
+/* Define if your processor stores words with the most significant
+ byte first (like Motorola and SPARC, unlike Intel and VAX). */
+#define WORDS_BIGENDIAN 1
+
+/* The number of bytes in an int. */
+#define SIZEOF_INT 4
+
+/* The number of bytes in a long. */
+#define SIZEOF_LONG 4
+
+/* The number of bytes in a void *. */
+#define SIZEOF_VOID_P 4
+
+/* The number of bytes in a long long. */
+#define SIZEOF_LONG_LONG 8
+
+/* The number of bytes in a long double. */
+#define SIZEOF_LONG_DOUBLE 16
+
+/* The number of bytes in a bool. */
+#define SIZEOF_BOOL 0
+
+/* Define as the return type of signal handlers (int or void). */
+#define RETSIGTYPE void
+
+/* Define if you don't have vprintf but do have _doprnt. */
+/* #undef HAVE_DOPRNT */
+
+/* Define if you have the vprintf function. */
+#define HAVE_VPRINTF 1
+
+/* Define if you have the gettimeofday function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define if you have the strdup function. */
+#define HAVE_STRDUP 1
+
+/* Define if you have the popen function. */
+#define HAVE_POPEN 1
+
+/* Define if SIG_IGN is broken. */
+/* #undef SIG_IGN_BROKEN */
+
+/* Define if you have h_errno declared. */
+#define DECLARED_H_ERRNO 1
+
+/* Define if you have accept declared. */
+#define DECLARED_ACCEPT 1
+
+/* Define if you have bind declared. */
+#define DECLARED_BIND 1
+
+/* Define if you have connect declared. */
+#define DECLARED_CONNECT 1
+
+/* Define if you have listen declared. */
+#define DECLARED_LISTEN 1
+
+/* Define if you have select declared. */
+#define DECLARED_SELECT 1
+
+/* Define if you have setsockopt declared. */
+#define DECLARED_SETSOCKOPT 1
+
+/* Define if you have shutdown declared. */
+#define DECLARED_SHUTDOWN 1
+
+/* Define if you have socket declared. */
+#define DECLARED_SOCKET 1
+
+/* Define if you have gettimeofday declared. */
+#define DECLARED_GETTIMEOFDAY 1
+
+/* Define if you have kill declared. */
+#define DECLARED_KILL 1
+
+/* Define if you have gethostname declared. */
+/* #undef DECLARED_GETHOSTNAME */
+
+/* Define if you have bzero declared. */
+/* #undef DECLARED_BZERO */
+
+/* Define if you have strerror declared. */
+#define DECLARED_STRERROR 1
+
+
+
+//
+// Various issues not dealt with via autoconf/configure.
+//
+#if !defined (_WINSOCKAPI_)
+ // Winsock added nonstandard APIs
+# define closesocket(s) close(s)
+#endif // _WINSOCKAPI_
+
+#ifdef minor
+ // namespace pollution that's common on older UNIXes,
+ // XXX this can't go here, "autoconf" wants to own #undef
+/* # undef minor */
+#endif // minor
+
+
+//
+// BC++ seems to have a different convention for detecting Win32 than VC++.
+//
+#if defined (__WIN32__)
+# define _WIN32
+#endif // BC++ convention
+
+//
+// For Win16, near/far pointers reflect same/other segment addressing.
+//
+#if defined (unix) || defined (_WIN32)
+# define _FAR
+#endif
+
+//
+// Assume DOS/Windows if "configure" didn't get run.
+//
+#ifndef SIZEOF_LONG
+# define SIZEOF_BOOL 0
+# ifdef _WIN32
+# define SIZEOF_INT 4
+# else // Win16
+# define SIZEOF_INT 2
+# endif // Win32/Win16
+# define SIZEOF_LONG 4
+# define SIZEOF_VOID_P 4 // "large model" or Win32
+# define SIZEOF_LONG_LONG 8
+# define SIZEOF_LONGDOUBLE 12
+
+# define DECLARED_ACCEPT
+# define DECLARED_BIND
+# define DECLARED_CONNECT
+# define DECLARED_GETHOSTNAME
+# define DECLARED_H_ERRNO
+# define DECLARED_LISTEN
+# define DECLARED_LISTEN
+# define DECLARED_SELECT
+# define DECLARED_SETSOCKOPT
+# define DECLARED_SHUTDOWN
+# define DECLARED_SOCKET
+# define DECLARED_STRERROR
+
+# define HAVE_STRDUP
+# define HAVE_VPRINTF
+
+typedef unsigned long pid_t;
+
+#endif
+
+//
+// For both Win16 and Win32, DLLs (shared libraries) need to know what
+// classes, functions, and data are exported. DLLs aren't quite dealt
+// with here yet, it's tough to do it portably (viz. the different
+// answers now used by BC++/VC++).
+//
+// (Wouldn't it be nice if more C++ compilers and linkers took advantage
+// of syntax to help get ensure that only public interfaces get exported
+// from shared libraries? Hmmm...)
+//
+#if defined (unix) || !defined (__BORLANDC__)
+# define _EXPCLASS
+# define _EXPFUNC
+# define _EXPDATA
+#endif
+
+#if defined (hpux)
+# define SELECT_INT_STAR
+#endif
+
+#ifndef HAVE_STRDUP
+#define strdup(s) strcpy ((char *)malloc (strlen (s) + 1), s)
+#endif
+
+#endif // _ORB_CONFIG_HH
diff --git a/TAO/IIOP/lib/corba/orbconf.hh.in b/TAO/IIOP/lib/corba/orbconf.hh.in
new file mode 100644
index 00000000000..62b9c0949a8
--- /dev/null
+++ b/TAO/IIOP/lib/corba/orbconf.hh.in
@@ -0,0 +1,202 @@
+// @(#)orbconf.hh.in 1.2 95/09/06
+// Copyright 1995 by Sun Microsystems, Inc
+//
+// Build configuration file for the Inter-ORB Engine, and application
+// level code using it via <corba.hh>
+//
+// !! Modify "orbconf.hh.in", not the file generated by "configure" !!
+//
+// Keep the tests in the order they're found in "configure.in". Also, keep
+// in mind that all "#undef" preprocessor directives are deemed to be the
+// property of "autoconf"; if those are needed in their own right, they must
+// be in some other file. (For example, "#undef minor".)
+//
+// This file builds on work originally contributed by a team at apm.co.uk:
+// Owen Rees (rtor), Guangxing Li (gxl) and Mike Beasley (mdrb).
+//
+
+#ifndef _ORB_CONFIG_HH
+#define _ORB_CONFIG_HH
+
+/* Define if you have the <widec.h> header file. */
+#undef HAVE_WIDEC_H
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef pid_t
+
+/* Define if your processor stores words with the most significant
+ byte first (like Motorola and SPARC, unlike Intel and VAX). */
+#undef WORDS_BIGENDIAN
+
+/* The number of bytes in an int. */
+#undef SIZEOF_INT
+
+/* The number of bytes in a long. */
+#undef SIZEOF_LONG
+
+/* The number of bytes in a void *. */
+#undef SIZEOF_VOID_P
+
+/* The number of bytes in a long long. */
+#undef SIZEOF_LONG_LONG
+
+/* The number of bytes in a long double. */
+#undef SIZEOF_LONG_DOUBLE
+
+/* The number of bytes in a bool. */
+#undef SIZEOF_BOOL
+
+/* Define as the return type of signal handlers (int or void). */
+#undef RETSIGTYPE
+
+/* Define if you don't have vprintf but do have _doprnt. */
+#undef HAVE_DOPRNT
+
+/* Define if you have the vprintf function. */
+#undef HAVE_VPRINTF
+
+/* Define if you have the gettimeofday function. */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define if you have the strdup function. */
+#undef HAVE_STRDUP
+
+/* Define if you have the popen function. */
+#undef HAVE_POPEN
+
+/* Define if SIG_IGN is broken. */
+#undef SIG_IGN_BROKEN
+
+/* Define if you have h_errno declared. */
+#undef DECLARED_H_ERRNO
+
+/* Define if you have accept declared. */
+#undef DECLARED_ACCEPT
+
+/* Define if you have bind declared. */
+#undef DECLARED_BIND
+
+/* Define if you have connect declared. */
+#undef DECLARED_CONNECT
+
+/* Define if you have listen declared. */
+#undef DECLARED_LISTEN
+
+/* Define if you have select declared. */
+#undef DECLARED_SELECT
+
+/* Define if you have setsockopt declared. */
+#undef DECLARED_SETSOCKOPT
+
+/* Define if you have shutdown declared. */
+#undef DECLARED_SHUTDOWN
+
+/* Define if you have socket declared. */
+#undef DECLARED_SOCKET
+
+/* Define if you have gettimeofday declared. */
+#undef DECLARED_GETTIMEOFDAY
+
+/* Define if you have kill declared. */
+#undef DECLARED_KILL
+
+/* Define if you have gethostname declared. */
+#undef DECLARED_GETHOSTNAME
+
+/* Define if you have bzero declared. */
+#undef DECLARED_BZERO
+
+/* Define if you have strerror declared. */
+#undef DECLARED_STRERROR
+
+
+
+//
+// Various issues not dealt with via autoconf/configure.
+//
+
+#if !defined (_WINSOCKAPI_)
+ // Winsock added nonstandard APIs
+# define closesocket(s) close(s)
+#endif // _WINSOCKAPI_
+#ifdef minor
+ // some older UNIXes have namespace pollution
+# undef minor
+#endif // minor
+
+
+//
+// BC++ seems to have a different convention for detecting Win32 than VC++.
+//
+#if defined (__WIN32__)
+# define _WIN32
+#endif // BC++ convention
+
+//
+// For Win16, near/far pointers reflect same/other segment addressing.
+//
+#if defined (unix) || defined (_WIN32)
+# define _FAR
+#endif
+
+//
+// Assume DOS/Windows if "configure" didn't get run.
+//
+#ifndef SIZEOF_LONG
+# define SIZEOF_BOOL 0
+# ifdef _WIN32
+# define SIZEOF_INT 4
+# else // Win16
+# define SIZEOF_INT 2
+# endif // Win32/Win16
+# define SIZEOF_LONG 4
+# define SIZEOF_VOID_P 4 // "large model" or Win32
+# define SIZEOF_LONG_LONG 0
+# define SIZEOF_LONGDOUBLE 12
+
+# define DECLARED_ACCEPT
+# define DECLARED_BIND
+# define DECLARED_CONNECT
+# define DECLARED_GETHOSTNAME
+# define DECLARED_H_ERRNO
+# define DECLARED_LISTEN
+# define DECLARED_LISTEN
+# define DECLARED_SELECT
+# define DECLARED_SETSOCKOPT
+# define DECLARED_SHUTDOWN
+# define DECLARED_SOCKET
+# define DECLARED_STRERROR
+
+# define HAVE_STRDUP
+# define HAVE_VPRINTF
+
+// XXX sometimes compiler gets confused about this one ...
+typedef unsigned long pid_t;
+
+#endif // DOS/Windows
+
+//
+// For both Win16 and Win32, DLLs (shared libraries) need to know what
+// classes, functions, and data are exported. DLLs aren't quite dealt
+// with here yet, it's tough to do it portably (viz. the different
+// answers now used by BC++/VC++).
+//
+// (Wouldn't it be nice if more C++ compilers and linkers took advantage
+// of syntax to help get ensure that only public interfaces get exported
+// from shared libraries? Hmmm...)
+//
+#if defined (unix) || !defined (__BORLANDC__)
+# define _EXPCLASS
+# define _EXPFUNC
+# define _EXPDATA
+#endif
+
+#if defined (hpux)
+# define SELECT_INT_STAR
+#endif
+
+#ifndef HAVE_STRDUP
+#define strdup(s) strcpy ((char *)malloc (strlen (s) + 1), s)
+#endif
+
+#endif // _ORB_CONFIG_HH
diff --git a/TAO/IIOP/lib/corba/orbobj.hh b/TAO/IIOP/lib/corba/orbobj.hh
new file mode 100644
index 00000000000..960fcac5b8e
--- /dev/null
+++ b/TAO/IIOP/lib/corba/orbobj.hh
@@ -0,0 +1,72 @@
+//
+// Header file for Win32 interface to CORBA's "ORB" type.
+//
+// The "ORB" pseudo-object is used in bootstrapping, such as to
+// create object references from strings. It's also used to
+// create strings from object references.
+//
+typedef class CORBA_ORB *CORBA_ORB_ptr;
+void CORBA_release (CORBA_ORB_ptr orb);
+CORBA_Boolean CORBA_is_nil (CORBA_ORB_ptr orb);
+
+extern const IID IID_CORBA_ORB;
+
+//
+// ORB initialisation, per OMG document 94-9-46.
+//
+CORBA_ORB_ptr
+CORBA_ORB_init (
+ int &argc,
+ char *const *argv,
+ char *orb_name,
+ CORBA_Environment &env
+);
+
+//
+// ORB pseudo-objref
+//
+class _EXPCLASS CORBA_ORB : public IUnknown
+{
+ public:
+ static CORBA_ORB_ptr _duplicate (CORBA_ORB_ptr orb);
+ static CORBA_ORB_ptr _nil ();
+
+ virtual CORBA_Object_ptr string_to_object (
+ CORBA_String str,
+ CORBA_Environment &env
+ ) = 0;
+ virtual CORBA_String object_to_string (
+ CORBA_Object_ptr obj,
+ CORBA_Environment &env
+ ) = 0;
+
+ // similar for TypeCodes and Anys ... to/from octet sequences
+
+ void create_list (
+ CORBA_Long count,
+ CORBA_NVList_ptr &retval
+ );
+
+ //
+ // Stuff required for COM IUnknown support ... this class is intended
+ // to be inherited by others, which will provide some more of the
+ // CORBA/COM support. Implementations of this "CORBA_ORB" class must
+ // know how to create stringify/destringify their objrefs, as well as
+ // how to marshal and unmarshal them ... as well as provide their
+ // own QueryInterface.
+ //
+ ULONG __stdcall AddRef ();
+ ULONG __stdcall Release ();
+
+ protected:
+ CORBA_ORB ();
+ virtual ~CORBA_ORB ();
+
+ private:
+ unsigned _refcount;
+
+ // these are not provided
+ CORBA_ORB (const CORBA_ORB &);
+ CORBA_ORB &operator = (const CORBA_ORB &);
+};
+
diff --git a/TAO/IIOP/lib/corba/principa.hh b/TAO/IIOP/lib/corba/principa.hh
new file mode 100644
index 00000000000..3cb5b0a8880
--- /dev/null
+++ b/TAO/IIOP/lib/corba/principa.hh
@@ -0,0 +1,52 @@
+//
+// Header file for Win32 interface to CORBA's "Principal" type.
+//
+// A "Principal" identifies an authenticated entity in the network
+// administration framework. Identities are used to control acccess
+// (authorization) as well as in audit trails (accountability).
+//
+typedef class CORBA_Principal *CORBA_Principal_ptr;
+
+void CORBA_release (CORBA_Principal_ptr principal);
+CORBA_Boolean CORBA_is_nil (CORBA_Principal_ptr principal);
+
+extern const IID IID_CORBA_Principal;
+
+class _EXPCLASS CORBA_Principal : public IUnknown
+{
+ public:
+ //
+ // To applications, the identifier is an opaque ID.
+ //
+ CORBA_SEQUENCE <CORBA_Octet> id;
+
+ // XXX add "==", "<", ">" operators
+
+ //
+ // Stuff required for COM IUnknown support
+ //
+ ULONG __stdcall AddRef ();
+ ULONG __stdcall Release ();
+ HRESULT __stdcall QueryInterface (
+ REFIID riid,
+ void **ppv
+ );
+
+ CORBA_Principal ();
+ private:
+ unsigned _refcount;
+
+ virtual ~CORBA_Principal ();
+
+ // these are not provided
+ CORBA_Principal &operator = (const CORBA_Principal_ptr &);
+ CORBA_Principal (const CORBA_Principal_ptr &);
+
+#if defined (__GNUG__)
+ //
+ // G++ (even 2.6.3) stupidly thinks instances can't be
+ // created. This de-warns.
+ //
+ friend class everyone_needs_a_friend;
+#endif
+};
diff --git a/TAO/IIOP/lib/corba/request.hh b/TAO/IIOP/lib/corba/request.hh
new file mode 100644
index 00000000000..74e6e31afba
--- /dev/null
+++ b/TAO/IIOP/lib/corba/request.hh
@@ -0,0 +1,69 @@
+// @(#)request.hh 1.2 95/10/02
+// Copyright 1994-1995 by Sun Microsystems, Inc.
+//
+// Header file for Win32 C/C++/COM interface to CORBA's Dynamic
+// Invocation Interface "Request" type.
+//
+
+void CORBA_release (CORBA_Request_ptr req);
+CORBA_Boolean CORBA_is_nil (CORBA_Request_ptr req);
+
+typedef CORBA_SEQUENCE <CORBA_TypeCode_ptr> CORBA_ExceptionList;
+typedef CORBA_ExceptionList *CORBA_ExceptionList_ptr;
+
+extern const IID IID_CORBA_Request;
+
+class _EXPCLASS CORBA_Request : public IUnknown
+{
+ public:
+ //
+ // XXX these should not be inlined
+ //
+ CORBA_Object_ptr target () const { return _target; }
+ const CORBA_Char *operation () const { return _opname; }
+ CORBA_NVList_ptr arguments () { return _args; }
+ CORBA_NamedValue_ptr result () { return _result; }
+ CORBA_ExceptionList_ptr exceptions () { return &_exceptions; }
+ CORBA_Environment *env () { return &_env; }
+
+ void invoke ();
+ void send_oneway ();
+
+ //
+ // Stuff required for COM IUnknown support
+ //
+ ULONG __stdcall AddRef ();
+ ULONG __stdcall Release ();
+ HRESULT __stdcall QueryInterface (
+ REFIID riid,
+ void **ppv
+ );
+
+ private:
+ friend class CORBA_Object;
+
+ CORBA_Request (
+ CORBA_Object_ptr obj,
+ const CORBA_Char *op,
+ CORBA_NVList_ptr args,
+ CORBA_NamedValue_ptr result,
+ CORBA_Flags flags
+ );
+
+ CORBA_Request (
+ CORBA_Object_ptr obj,
+ const CORBA_Char *op
+ );
+
+ virtual ~CORBA_Request ();
+
+ CORBA_Object_ptr _target;
+ const CORBA_Char *_opname;
+ CORBA_NVList_ptr _args;
+ CORBA_NamedValue_ptr _result;
+ CORBA_Flags _flags;
+ CORBA_Environment _env;
+ CORBA_ExceptionList _exceptions;
+
+ unsigned _refcount;
+};
diff --git a/TAO/IIOP/lib/corba/sequence.hh b/TAO/IIOP/lib/corba/sequence.hh
new file mode 100644
index 00000000000..533bdf2b617
--- /dev/null
+++ b/TAO/IIOP/lib/corba/sequence.hh
@@ -0,0 +1,23 @@
+//
+// utility template class
+//
+template <class T>
+struct CORBA_SEQUENCE {
+#if SIZEOF_LONG == 4
+ unsigned long maximum;
+ unsigned long length;
+#else
+ // just assume "int" is four bytes long ...
+ unsigned maximum;
+ unsigned length;
+#endif
+ T *buffer;
+
+ CORBA_SEQUENCE ()
+ : maximum (0), length (0), buffer (0) { }
+
+ // XXX destructor should free buffer, elements!!
+ ~CORBA_SEQUENCE () { }
+};
+
+typedef CORBA_SEQUENCE <CORBA_Octet> CORBA_OctetSeq;
diff --git a/TAO/IIOP/lib/corba/stub.hh b/TAO/IIOP/lib/corba/stub.hh
new file mode 100644
index 00000000000..ee6bf803109
--- /dev/null
+++ b/TAO/IIOP/lib/corba/stub.hh
@@ -0,0 +1,226 @@
+// @(#)stub.hh 1.7 95/09/12
+// Copyright 1994-1995 by Sun Microsystems Inc.
+// All Rights Reserved
+//
+// ORB data structures used by static and dynamic stubs,
+// and to a lesser degree by skeletons
+//
+// Header file for Win32 C/C++/COM interface to one kind of CORBA remote
+// invocation framework. This is for use by compiler-generated code, not
+// by portable applications!
+//
+// These constitute the stub API to this "ORB Core". Such interfaces are
+// not specified by OMG, and may differ between different ORBs. This
+// one has the particular advantage that stubs can be quite small.
+//
+#ifndef _STUB_HH
+#define _STUB_HH
+
+//
+// Descriptions of parameters.
+//
+enum param_type { // parameter mode of a given parameter
+ PARAM_IN,
+ PARAM_OUT,
+ PARAM_INOUT,
+ PARAM_RETURN // = PARAM_OUT
+};
+
+struct paramdata { // description of a single parameter
+ CORBA_TypeCode_ptr tc; // type of param
+ param_type mode; // its mode
+
+ //
+ // If value_size is nonzero for OUT, INOUT, or RETURN parameters, it's
+ // (a) an indicator that the ORB returns a pointer-to-value for this
+ // parameter, and also (b) is the size of the top-level of the value
+ // that's returned (e.g. ignoring nested sequence buffers). That is,
+ // it moves CPU cycles from runtime -- some calls to tc->size() -- to
+ // compile time where they're cheap/free.
+ //
+ // It _must_ only be set for cases where the ORB allocates the return
+ // value, which must then be ORB::free()d ... e.g. where the value
+ // is a pointer to data such as a struct, sequence, or union. (The
+ // CORBA C++ mapping doesn't require that for all "out" structs; only
+ // those of "variable size".) If this value is nonzero, the value
+ // passed to do_call() must be the address of a pointer.
+ //
+ size_t value_size; // zero or tc->size ()
+};
+
+
+//
+// Descriptions of operations, as used by the stub interpreter. Only
+// interpretive marshaling/unmarshaling is used, and the stubs don't
+// know what particular on-the-wire protocol is being used.
+//
+// NOTE: when using C++ exceptions, many C++ compilers will require
+// the use of compiled code throw the exception. As binary standards
+// for exception throwing evolve, it may become practical to interpretively
+// throw exceptions.
+//
+struct calldata {
+ const char *opname; // operation name
+ CORBA_Boolean is_roundtrip; // !oneway
+
+ //
+ // When constructing tables of parameters, put them in the same order
+ // they appear in the IDL spec: return value, then parameters left
+ // to right. Other orders may produce illegal IIOP protocol messages.
+ //
+ unsigned param_count; // # parameters
+ const paramdata *params; // their descriptions
+
+ //
+ // The exceptions allowed by this operation can be listed in any
+ // order, and need not include the system exceptions which may be
+ // returned by OMG-IDL operations. If an operation tries to return
+ // any exception not allowed by its type signature, this causes a
+ // a system exception to be reported.
+ //
+ unsigned except_count; // # exceptions
+ const CORBA_TypeCode_ptr *excepts; // their descriptions
+};
+
+
+//
+// Skeletons map "ServerRequest" generic signatures to the static call
+// signature required by the implementation's methods.
+//
+// NOTE: there are several optimizations that'd be desirable for use by
+// "static skeletons", notably (a) passing of per-object data held by the
+// OA so that the method doesn't need to look it up itself, (b) removing
+// all mandatory heap allocation of data, and of course (c) handling all
+// the built-in ORB calls like "is_a" and "get_implementation". This code
+// is currently set up only for Dynamic Skeletons and bridging, for which
+// none of those are real issues.
+//
+typedef void (*skeleton)(CORBA_ServerRequest &, CORBA_Environment &);
+
+struct skel_entry { // table of these per implementation
+ const calldata *op_descriptor;
+ skeleton impl_skeleton;
+};
+
+
+
+//
+// Per-objref data includes the (protocol-specific) ProfileBody, which
+// is handled by placing it into a subclass of this type along with
+// data that may be used in protocol-specific caching schemes.
+//
+// The type ID (the data specified by CORBA 2.0 that gets exposed "on
+// the wire", and in stringified objrefs) is held by this module.
+//
+// The stub and DII interpreter APIs are member functions of this type.
+//
+extern const IID IID_STUB_Object;
+
+class _EXPCLASS STUB_Object : public IUnknown
+{
+ public:
+ //
+ // The "stub interpreter" method parameters are:
+ //
+ // - env ... used for exception reporting
+ // - info ... describes the call
+ // - varargs parameters follow
+ //
+ // The varargs parameters are pointers to data instances as described
+ // by info->params. (If the value_size is nonzero, the data instance
+ // is itself a pointer.) The order on the call stack must be exactly
+ // the order they're listed in info->params; normally this is the order
+ // the values are listed in the OMG-IDL operation specification.
+ //
+ // NOTE: This can be sped up by eliminating some parameter shuffling.
+ // The stub and "do_call" parameters are all but the same, except that
+ // their order is different.
+ //
+ virtual void do_call (
+ CORBA_Environment &env,
+ const calldata *info,
+ ...
+ ) = 0;
+
+ //
+ // Dynamic invocations use a more costly "varargs" calling convention;
+ // it's got the same input data as the (static) stub-oriented one, but
+ // the data is represented somewhat differently.
+ //
+ // Operation-specific data isn't collected in a stack frame and into a
+ // static/readonly "calldata" structure, but instead is collected into
+ // these parameters, the majority of which are heap-allocated:
+ //
+ // - opname ... the name of the operation
+ // - is_roundtrip ... true except for oneway operations, or ones where
+ // the client doesn't care about responses
+ // - args ... call parameters and their descriptions
+ // - result ... result and its description
+ // - flags ... only one DII flag is legal
+ // - exceptions ... list of legal user-defined exceptions
+ // - env ... used for exception reporting.
+ //
+ virtual void do_dynamic_call (
+ const char *opname,
+ CORBA_Boolean is_roundtrip,
+ CORBA_NVList_ptr args,
+ CORBA_NamedValue_ptr result,
+ CORBA_Flags flags,
+ CORBA_ExceptionList &exceptions,
+ CORBA_Environment &env
+ ) = 0;
+
+ //
+ // All objref representations carry around a type ID.
+ //
+ CORBA_String type_id;
+
+ //
+ // All objref representations know how to hash themselves and compare
+ // themselves for equivalence to others. It's easily possible to have
+ // two objrefs that are distinct copies of data that refers/points to
+ // the same remote object (i.e. are equivalent).
+ //
+ virtual CORBA_ULong hash (
+ CORBA_ULong maximum,
+ CORBA_Environment &env
+ ) = 0;
+ virtual CORBA_Boolean is_equivalent (
+ CORBA_Object_ptr other_obj,
+ CORBA_Environment &env
+ ) = 0;
+
+ //
+ // XXX All objref representations should know how to marshal themselves.
+ // That will involve ensuring that the IOR that gets marshaled talks a
+ // specific protocol, otherwise the target of a message would not be
+ // invoke using the objref it receives (compromising functionality in
+ // a very basic and mysterious manner). So for example an objref might
+ // need to create a proxy for itself rather than marshaling its own
+ // representation. [ The IIOP engine does not need to worry about such
+ // issues since it only supports one protocol -- the problem won't show
+ // up. "Multiprotocol ORBs" will need to solve that problem though. ]
+ //
+
+ STUB_Object (char *p = 0)
+ : type_id (p) { }
+
+ protected:
+ // XXX virtual inlines are evil
+ virtual ~STUB_Object ()
+ { CORBA_string_free (type_id); }
+
+ //
+ // COM operations ... provided by an implementation class which
+ // inherits from this one.
+ //
+
+ private:
+ //
+ // Disallow copy constructor and assignment operator
+ //
+ STUB_Object (const STUB_Object &);
+ operator = (const STUB_Object &);
+};
+
+#endif //_STUB_HH
diff --git a/TAO/IIOP/lib/corba/svrrqst.hh b/TAO/IIOP/lib/corba/svrrqst.hh
new file mode 100644
index 00000000000..784b1b7c4de
--- /dev/null
+++ b/TAO/IIOP/lib/corba/svrrqst.hh
@@ -0,0 +1,73 @@
+// @(#)svrrqst.hh 1.5 95/09/25
+//
+// Header file for Win32 C/C++/COM interface to CORBA's Dynamic
+// Server Skeleton Interface's "Server Request" type.
+//
+// XXX this is currently in an intermediate state; this is not
+// supposed to be IIOP-specific, or to expose quite so many
+// implementation details, but right now it is.
+//
+
+typedef class CORBA_ServerRequest *CORBA_ServerRequest_ptr;
+typedef class CORBA_ORB *CORBA_ORB_ptr;
+typedef class TOA *TOA_ptr;
+
+void CORBA_release (CORBA_ServerRequest_ptr req);
+CORBA_Boolean CORBA_is_nil (CORBA_ServerRequest_ptr req);
+
+extern const IID IID_CORBA_ServerRequest;
+
+class _EXPCLASS CORBA_ServerRequest : public IUnknown
+{
+ public:
+ //
+ // Implementation uses this to provide the ORB with the operation's
+ // parameter list ... on return, their values are available; the list
+ // fed in has typecodes and (perhap) memory assigned.
+ //
+ virtual void __stdcall params (
+ CORBA_NVList_ptr list,
+ CORBA_Environment &env
+ ) = 0;
+
+ //
+ // Implementation uses this to provide the operation result ... illegal
+ // if exception() was called or params() was not called.
+ //
+ // XXX Implementation should be able to assume response has been sent
+ // when this returns, and reclaim memory it allocated.
+ //
+ virtual void __stdcall result (
+ CORBA_Any_ptr value,
+ CORBA_Environment &env
+ ) = 0;
+
+ //
+ // Implementation uses this to provide the exception value which is the
+ // only result of this particular invocation.
+ //
+ // XXX Implementation should be able to assume response has been sent
+ // when this returns, and reclaim memory it allocated.
+ //
+ virtual void __stdcall exception (
+ CORBA_ExceptionType type,
+ CORBA_Any_ptr value,
+ CORBA_Environment &env
+ ) = 0;
+
+ //
+ // Get various universal call attributes: who made the call, the
+ // target of the call, what ORB and OA that target object uses.
+ //
+ // NOTE: none of these report exceptions; unavailability of any of
+ // this stuff is a catastrophic error since this is all part of
+ // the basic CORBA Object Model.
+ //
+ // XXX should not be not assuming all OAs implement the TOA API !!
+ //
+ virtual CORBA_Principal_ptr __stdcall caller () = 0;
+ virtual CORBA_Object_ptr __stdcall target () = 0;
+ virtual CORBA_String __stdcall op_name () = 0;
+ virtual TOA_ptr __stdcall oa () = 0;
+ virtual CORBA_ORB_ptr __stdcall orb () = 0;
+};
diff --git a/TAO/IIOP/lib/corba/toa.hh b/TAO/IIOP/lib/corba/toa.hh
new file mode 100644
index 00000000000..23229870da2
--- /dev/null
+++ b/TAO/IIOP/lib/corba/toa.hh
@@ -0,0 +1,182 @@
+// @(#)toa.hh 1.6 95/10/02
+// Copyright 1995 by Sun Microsystems, Inc.
+//
+// (Early) TOA
+//
+// TOA is a stripped down, lean, mean, portable OA. The work involved
+// in managing objects is all handled by "higher level" code, including
+// skeletons, generated either by an IDL compiler by hand. TOA itself
+// maintains no object-level state.
+//
+
+#ifndef _TOA_HH
+#define _TOA_HH
+
+typedef class TOA *TOA_ptr;
+
+CORBA_Boolean is_nil (TOA_ptr obj);
+void release (TOA_ptr obj);
+
+extern const IID IID_TOA;
+
+class TOA : public IUnknown
+{
+ public:
+ //
+ // Create a reference to an object, using identifying information that
+ // is fully exposed to applications. (An ORB may use additional data
+ // internally, of course.)
+ //
+ // Object IDs are assigned and used by servers to identify objects.
+ //
+ // Type IDs are repository IDs, assigned as part of OMG-IDL interface
+ // definition to identify specific interfaces and their relationships
+ // to other OMG-IDL interfaces. It's OK to provide a null type ID.
+ //
+ // Clients which invoke operations using one of these references when
+ // the server is not active (or after the last reference to the TOA is
+ // released) will normally see an OBJECT_NOT_EXIST exception reported
+ // by the ORB. If the TOA is a "Named TOA" the client's ORB will not
+ // normally return OBJECT_NOT_EXIST unless the TOA reports that fault.
+ //
+ // NOTE: Since any given TOA may have been used in the past, servers
+ // may need to place some data (such as a timestamp) into the object ID
+ // to help distinguish different incarnations of the TOA. "Named TOA"
+ // objects won't want those semantics as much as "Anonymous" ones.
+ //
+ virtual CORBA_Object_ptr __stdcall
+ create (
+ CORBA_OctetSeq &obj_id,
+ CORBA_String type_id,
+ CORBA_Environment &env
+ ) = 0;
+
+ //
+ // All invocations are handled using DSI ... slightly enhanced from
+ // the original CORBA 2.0 specs, to improve performance by getting
+ // rid of all mallocation for calls with fixed-size parameter lists.
+ //
+ // A single skeleton, also called "Dynamic Implementation Routine",
+ // is provided to the ORB; it is called on all requests, along with a
+ // pointer to context that was provided by the server.
+ //
+ // One could imagine that the DIR would recognize that the context
+ // is a hashtable for per-object state, keyed by the object ID.
+ //
+ // Note that in addition to the operations defined by an object's
+ // IDL interface specification, four operations must be supported
+ // by code layered above the TOA. There are many ways in which
+ // these operations can be hidden from "application" programs, and
+ // some solutions are noted below.
+ //
+ // * "_is_a" is readily handled by skeletons,
+ //
+ // * "_get_interface" similarly, though with more work to allow the
+ // IFR data structures to be extracted from skeletons.
+ //
+ // * "_get_implementation" is implementation-specific, a facility
+ // through which administrative and other information may be
+ // acquired. Not all systems provide consistent ways to utilize
+ // this facility.
+ //
+ // * "_non_existent" asks if the referred-to object still exists.
+ // This enables solving many "distributed garbage" problems,
+ // such as maintaining persistent tables keyed by references to
+ // objects that may no longer exist.
+ //
+ typedef void __stdcall (*dsi_handler) ( // DIR
+ CORBA_OctetSeq &obj_id,
+ CORBA_ServerRequest &request,
+ void *context,
+ CORBA_Environment &env
+ );
+
+ virtual void __stdcall register_dir (
+ dsi_handler skeleton,
+ void *context,
+ CORBA_Environment &env
+ ) = 0;
+
+ //
+ // Get/handle requests ... this starts processing a request, or
+ // times out.
+ //
+ // If the "use threads" flag is FALSE, then any request processing
+ // will have completed when the call returns.
+ //
+ // If the "use threads" flag is TRUE, then applications may see
+ // concurrent execution of method code (and processing may not be
+ // complete when this call returns). This value is only legal in
+ // environments which support threads.
+ //
+ // Normal timeout semantics apply: if the timeval pointer is NULL
+ // the call will not time out. Otherwise the value pointed to
+ // is the minimum amount of time that will elapse before this
+ // call returns.
+ //
+ // Reports INITIALIZE exception if no DIR was registered.
+ // Reports BAD_INV_ORDER if this is shutting down.
+ //
+ virtual void __stdcall get_request (
+ CORBA_Boolean use_threads,
+ struct timeval *tvp,
+ CORBA_Environment &env
+ ) = 0;
+
+ //
+ // Please Shutdown -- reject all further incoming requests, and allow
+ // all currently active calls (e.g. "this one") to complete. This
+ // ensures that OS resources associated with this OA can be reclaimed
+ // even if some buggy applications code mismanages refcounting on
+ // this TOA.
+ //
+ virtual void __stdcall please_shutdown (
+ CORBA_Environment &env
+ ) = 0;
+
+ //
+ // Run -- call get_request() in a loop until shutdown completes.
+ // Uses as much concurrency as is provided in this environment.
+ // Initiate shutdown if we've been idle for the specified time.
+ //
+ // This uses only the public APIs defined above; the function is
+ // defined here purely for convenience, to help some applications
+ // avoid writing that loop.
+ //
+ void __stdcall run (
+ struct timeval *tvp,
+ CORBA_Environment &env
+ ); // NOT PURE VIRTUAL !!
+
+ //
+ // Get an "anonymous" TOA pseudo-objref ... this is the API that
+ // most applications will use. It returns a TOA which is not
+ // otherwise in use (though it may have been used in the past).
+ //
+ // Any given TOA (named or otherwise) will create equivalent object
+ // references when TOA::create() is called with the same object and
+ // type IDs. This is not true for two different TOAs.
+ //
+ static TOA_ptr get_toa (
+ CORBA_ORB_ptr orb,
+ CORBA_Environment &env
+ ); // NOT PURE VIRTUAL !!
+
+ //
+ // Get a "named" TOA ... most applications don't use/need this API.
+ //
+ // TOA names are for ORB/system bootstrapping purposes, and need not
+ // be shared between different systems. The scope of the name isn't
+ // guaranteed to include more than one system. The names themselves
+ // are administered using system-specific mechanisms and policies.
+ //
+ static TOA_ptr get_named_toa (
+ CORBA_ORB_ptr orb,
+ CORBA_String name,
+ CORBA_Environment &env
+ ); // NOT PURE VIRTUAL !!
+
+ private:
+};
+
+#endif // _TOA_HH
diff --git a/TAO/IIOP/lib/corba/typecode.hh b/TAO/IIOP/lib/corba/typecode.hh
new file mode 100644
index 00000000000..17c4bb72cc5
--- /dev/null
+++ b/TAO/IIOP/lib/corba/typecode.hh
@@ -0,0 +1,299 @@
+//
+// Header file for Win32 C/C++/COM interface to CORBA's "TypeCode" type.
+//
+
+//
+// Kinds of typecodes. Do not change these enum values, or duplicate
+// them if you need to add values. They are used to index tables, and
+// if you change the values you'll need to find and update all of those
+// tables. The values are also part of the Common Data Representation,
+// and hence are part of IIOP and other ORB protocols.
+//
+enum CORBA_TCKind {
+ tk_null = 0,
+ tk_void = 1,
+ tk_short = 2,
+ tk_long = 3,
+ tk_ushort = 4,
+ tk_ulong = 5,
+ tk_float = 6,
+ tk_double = 7,
+ tk_boolean = 8,
+ tk_char = 9,
+ tk_octet = 10,
+ tk_any = 11,
+ tk_TypeCode = 12,
+ tk_Principal = 13,
+ tk_objref = 14,
+ tk_struct = 15,
+ tk_union = 16,
+ tk_enum = 17,
+ tk_string = 18,
+ tk_sequence = 19,
+ tk_array = 20,
+ tk_alias = 21, // 94-11-7
+ tk_except = 22, // 94-11-7
+
+ // these five are OMG-IDL data type extensions
+ tk_longlong = 23, // 94-9-32 Appendix A (+ 2)
+ tk_ulonglong = 24, // 94-9-32 Appendix A (+ 2)
+ tk_longdouble = 25, // 94-9-32 Appendix A (+ 2)
+ tk_wchar = 26, // 94-9-32 Appendix A (+ 2)
+ tk_wstring = 27, // 94-9-32 Appendix A (+ 2)
+
+ //
+ // This symbol is not defined by CORBA 2.0. It's used to speed up
+ // dispatch based on TCKind values, and lets many important ones
+ // just be table lookups. It must always be the last enum value!!
+ //
+ TC_KIND_COUNT
+};
+
+
+//
+// Two "user exceptions" are defined for manipulating TypeCodes.
+//
+extern CORBA_TypeCode_ptr _tc_CORBA_Bounds;
+class CORBA_Bounds : public CORBA_UserException {
+ public:
+ CORBA_Bounds (
+ ) : CORBA_UserException (_tc_CORBA_Bounds)
+ {}
+};
+
+extern CORBA_TypeCode_ptr _tc_CORBA_BadKind;
+class CORBA_BadKind : public CORBA_UserException {
+ public:
+ CORBA_BadKind (
+ ) : CORBA_UserException (_tc_CORBA_BadKind)
+ {}
+};
+
+
+//
+// A TypeCode describes data. This one's as thin a wrapper around CDR
+// octet sequences as is practical. There are guesses here about how
+// the OMG C++ mapping and CORBA 2.0 IFR specification will interact.
+//
+// NOTE: Use TypeCode_ptr, except in code (e.g. output of and OMG-IDL
+// compiler) that needs to create typecodes from their octet-sequence
+// encodings.
+//
+typedef class CORBA_TypeCode *CORBA_TypeCode_ptr;
+void CORBA_release (CORBA_TypeCode_ptr);
+CORBA_Boolean CORBA_is_nil (CORBA_TypeCode_ptr obj);
+
+extern const IID IID_CORBA_TypeCode;
+
+class _EXPCLASS CORBA_TypeCode : public IUnknown
+{
+ public:
+ //
+ // For all TypeCode kinds
+ //
+ CORBA_TCKind kind (CORBA_Environment &) const;
+
+ //
+ // Deprecated, CORBA 1.2, not fully usable
+ //
+ CORBA_ULong param_count (CORBA_Environment &) const;
+
+ //
+ // For tk_{objref,struct,union,enum,alias,except}
+ //
+ CORBA_String id (CORBA_Environment &) const;
+
+ //
+ // Other CORBA 2.0 IFR updates -- not yet implemented/needed
+ //
+ // String name () raises (BadKind);
+ // ULong member_count () raises (BadKind);
+ // String member_name (...) raises (BadKind, Bounds);
+ // TypeCode_ptr member_type (...) raises (BadKind, Bounds);
+
+ CORBA_Any_ptr member_label (CORBA_ULong n, CORBA_Environment&) const;
+
+ // TypeCode_ptr discriminator_type () raises (BadKind);
+ // Long default_index () raises (BadKind);
+
+ // Long length () raises (BadKind);
+ // TypeCode_ptr content_type () raises (BadKind);
+
+ //
+ // Internal utilities, pending CORBA 2.0 IFR APIs; just enough
+ // to make array and sequence typecode interpretation cheap
+ //
+ CORBA_ULong ulong_param (CORBA_ULong n, CORBA_Environment &) const;
+ CORBA_TypeCode_ptr typecode_param (CORBA_ULong n,
+ CORBA_Environment &) const;
+
+ //
+ // Creation/refcounting ... these aren't really public APIs,
+ // but an IDL compiler will need to be able to create TypeCodes
+ // as part of creating stubs.
+ //
+ //
+ // This constructor is used only for built-in
+ // TypeCode constants, with no parameters.
+ //
+ CORBA_TypeCode (
+ CORBA_TCKind kind // EMPTY paramlists!
+ );
+
+ //
+ // This constructor is used both for typecode
+ // constants and for heap-allocated TypeCodes.
+ // The two are distinguished by the orb_owns_tc
+ // flag passed in by the creator.
+ //
+ // For simple param lists with a single
+ // numeric parameter, only 'length' matters.
+ //
+ // For complex param lists, or simple param
+ // lists for which the parameter is a string
+ // or typecode, length _and_ buffer matter.
+ //
+ CORBA_TypeCode (
+ CORBA_TCKind kind,
+ CORBA_ULong length,
+ CORBA_Octet *buffer,
+ CORBA_Boolean orb_owns_tc
+ );
+ void *operator new (size_t, void *p)
+ { return p; }
+ void *operator new (size_t s)
+ { return ::operator new(s); }
+
+ virtual ~CORBA_TypeCode ();
+
+ //
+ // "orb owns" is always set, except for TypeCode constants.
+ //
+
+ //
+ // This routine calls visit() on each component of one (or two)
+ // structurally equivalent data values. "Components" are either
+ // primitive (long, string, ...) or constructed (struct, ...)
+ // data elements.
+ //
+ // It will NOT descend into those nodes if they're constructed;
+ // it's the job of the visit() routine to do that as needed.
+ //
+ // "Context" can be used to hold state used by the visit() routine.
+ // To terminate traversal "early", visit() returns TRAVERSE_STOP.
+ //
+ // The "value1" and "value2" parameters are pointers to data
+ // values of the structure described by the TypeCode. Using
+ // the normal size, alignment, and padding rules used by the
+ // compilers on a given platform, the visit() routine is called
+ // with pointers to subsidiary elements.
+ //
+ // As all this routine does is appropriate pointer adjustments,
+ // it any value at all can be passed in as "value1" or "value2".
+ // You could ignore one value and examine a data structure; copy
+ // from one to the other; compare one to the other; and more.
+ //
+ // Normal usage is to have application code call its visit()
+ // routine directly, and have that decide whether to use the
+ // typecode interpereter's knowledge of data structure layout
+ // through mutual recursion.
+ //
+ enum traverse_status { TRAVERSE_STOP, TRAVERSE_CONTINUE };
+
+ typedef traverse_status (_FAR * VisitRoutine) (
+ CORBA_TypeCode_ptr tc,
+ const void *value1,
+ const void *value2,
+ void *context,
+ CORBA_Environment &env
+ );
+
+ traverse_status traverse (
+ const void *value1,
+ const void *value2,
+ VisitRoutine visit,
+ void *context,
+ CORBA_Environment &env
+ );
+
+ size_t size (CORBA_Environment &env);
+ size_t alignment (CORBA_Environment &env);
+
+ static CORBA_TypeCode_ptr _nil ();
+
+ //
+ // Stuff required for COM IUnknown support
+ //
+ ULONG __stdcall AddRef ();
+ ULONG __stdcall Release ();
+ HRESULT __stdcall QueryInterface (
+ REFIID riid,
+ void **ppv
+ );
+ // private:
+ //
+ // the guts of the typecode implementation class: a counted
+ // set of bytes, in marshaled CDR format.
+ //
+ CORBA_ULong _length;
+ CORBA_Octet *_buffer;
+ CORBA_TCKind _kind;
+
+ //
+ // Indirected typecodes share "buffer" with a parent, and
+ // hold a reference to that parent to ensure its memory is
+ // not freed inappropriately.
+ //
+ CORBA_TypeCode_ptr _parent;
+
+ private:
+ unsigned _refcount;
+
+ //
+ // If "orb_owns" is false, the value is a constant typecode with
+ // both the typecode and the buffer statically allocated; the
+ // typecode is never freed. Otherwise the typecode and the
+ // buffer are freed when the refcount goes to zero.
+ //
+ CORBA_Boolean _orb_owns;
+
+ //
+ // No copy constructor or assignment operator supported;
+ // use TypeCode_ptr values, duplicate(), release().
+ //
+ CORBA_TypeCode (const CORBA_TypeCode &src);
+ CORBA_TypeCode &operator = (const CORBA_TypeCode &src);
+};
+
+//
+// TypeCode constants, which are always accessible in all ORB runtimes.
+//
+extern const CORBA_TypeCode_ptr
+ _tc_CORBA_Null,
+ _tc_CORBA_Void,
+
+ _tc_CORBA_Short,
+ _tc_CORBA_Long,
+ _tc_CORBA_LongLong,
+ _tc_CORBA_UShort,
+ _tc_CORBA_ULong,
+ _tc_CORBA_ULongLong,
+
+ _tc_CORBA_Float,
+ _tc_CORBA_Double,
+ _tc_CORBA_LongDouble,
+
+ _tc_CORBA_Boolean,
+ _tc_CORBA_Octet,
+
+ _tc_CORBA_Char,
+ _tc_CORBA_String,
+ _tc_CORBA_WChar,
+ _tc_CORBA_WString,
+
+ _tc_CORBA_Any,
+ _tc_CORBA_TypeCode,
+ _tc_CORBA_Principal,
+
+ _tc_CORBA_Object;
+
diff --git a/TAO/IIOP/lib/onc/Makefile b/TAO/IIOP/lib/onc/Makefile
new file mode 100644
index 00000000000..9848e24c388
--- /dev/null
+++ b/TAO/IIOP/lib/onc/Makefile
@@ -0,0 +1,8 @@
+# @(#)Makefile 1.1 @(#)Makefile 1.1
+
+FILES = \
+ xdr.cpp
+
+ROOT = ../..
+
+include ../Makefile.gen
diff --git a/TAO/IIOP/lib/onc/xdr.cpp b/TAO/IIOP/lib/onc/xdr.cpp
new file mode 100644
index 00000000000..9c7c94f3eef
--- /dev/null
+++ b/TAO/IIOP/lib/onc/xdr.cpp
@@ -0,0 +1,812 @@
+// @(#)xdr.cpp 1.3 95/11/07
+// Copyright 1995 by Sun Microsystems, Inc.
+//
+// XDR/TCP ORB Marshaler/unmarshaler
+//
+// Includes functions to encode 64 and 128 bit quantities, interpretive
+// encoder/decoder.
+//
+// XXX note -- this is incomplete (see xdr.hh) and doesn't do
+// exactly what the Prelude protocol does, particularly in the
+// area of typecodes.
+//
+// XXX implement the put/get primitives for 64 and 128 bit data types
+//
+// XXX strings, principals, typecodes, char arrays, char seqs, and
+// same for octets ... all should marshal the bulk characters tightly
+// packed, four to a word, else this violates the XDR spec.
+//
+// XXX optimization 1: allowed by current XDR spec, when marshaling
+// true bulk data could eliminate a buffer copy by writing long
+// buffers (bigger than 'remainder of current fragment') in single
+// large chunks ... weigh cost of an extra kernel write against data
+// copy getting added. Applies to byte-structured bulk data only,
+// not (portably) to arrays of longs etc.
+//
+// XXX optimization 2: modifies current XDR spec: when marshaling
+// arrays of "short" data (e.g. unicode strings) pack tightly.
+//
+
+#include <unistd.h>
+#include <string.h>
+#include <widec.h>
+
+#include <corba/orb.hh>
+
+#include "runtime/debug.hh"
+
+#include "onc/xdr.hh"
+
+
+//
+// I/O for 64 bit quantities -- integers, doubles
+//
+CORBA_Boolean
+XDR_stream::put_longlong (const CORBA_LongLong &)
+THROWS_NOTHING
+{
+ return CORBA_B_FALSE;
+}
+
+CORBA_Boolean
+XDR_stream::get_longlong (CORBA_LongLong &)
+THROWS_NOTHING
+{
+ return CORBA_B_FALSE;
+}
+
+
+//
+// I/O for 128 bit quantities -- long doubles
+//
+CORBA_Boolean
+XDR_stream::put_longdouble (const CORBA_LongDouble &)
+THROWS_NOTHING
+{
+ return CORBA_B_FALSE;
+}
+
+CORBA_Boolean
+XDR_stream::get_longdouble (CORBA_LongDouble &)
+THROWS_NOTHING
+{
+ return CORBA_B_FALSE;
+}
+
+
+//
+// Encode instances of arbitrary data types based only on typecode. "data"
+// points to the data type; if it's not a primitve data type, the TypeCode
+// interpreter is used to recursively encode its components. "context" is
+// the marshaling stream on which to encode the data value.
+//
+// This is a fairly typical TypeCode interpreter visit() routine; it works
+// on a single data value in conjunction with context information, and must
+// handle all IDL data types.
+//
+CORBA_TypeCode::traverse_status
+XDR_stream::encoder (
+ CORBA_TypeCode_ptr tc,
+ const void *data,
+ const void *,
+ void *context,
+ CORBA_Environment &env
+)
+THROWS_NOTHING
+{
+ CORBA_Boolean continue_encoding = CORBA_B_TRUE;
+ XDR_stream *stream = (XDR_stream *)context;
+
+ switch (tc->_kind) {
+ case tk_null:
+ case tk_void:
+ // nothing to encode!
+ break;
+
+ case tk_char:
+ case tk_octet:
+ continue_encoding = stream->put_char (*(char *)data);
+ break;
+
+ case tk_short:
+ case tk_ushort:
+ continue_encoding = stream->put_short (*(short *)data);
+ break;
+
+ case tk_long:
+ case tk_ulong:
+ case tk_float:
+ continue_encoding = stream->put_long (*(CORBA_Long *)data);
+ break;
+
+ case tk_double:
+ case tk_longlong:
+ case tk_ulonglong:
+ continue_encoding = stream->put_longlong (*(CORBA_LongLong *)data);
+ break;
+
+ case tk_boolean:
+ continue_encoding = stream->put_boolean (*(CORBA_Boolean *)data);
+ break;
+
+ case tk_enum:
+ {
+ //
+ // NOTE assumption that this is in-range.
+ //
+ // XXX should check this, it's a hard-to-recover error
+ // for the other side
+ //
+ unsigned value = *(unsigned *)data;
+ continue_encoding = stream->put_ulong (value);
+ }
+ break;
+
+ case tk_any:
+ {
+ CORBA_Any *any = (CORBA_Any *)data;
+
+ tc = any->type ();
+ if (encoder (_tc_CORBA_TypeCode, &tc, 0, context, env)
+ != CORBA_TypeCode::TRAVERSE_CONTINUE)
+ return CORBA_TypeCode::TRAVERSE_STOP;
+
+ data = any->value ();
+ return encoder (tc, data, 0, context, env);
+ }
+ // NOTREACHED
+
+ case tk_TypeCode:
+ {
+ CORBA_TypeCode_ptr tc2;
+
+ tc2 = *(CORBA_TypeCode_ptr *)data;
+
+ continue_encoding = stream->put_ulong ((CORBA_ULong) tc2->_kind);
+ if (continue_encoding == CORBA_B_FALSE)
+ break;
+
+ switch (tc2->_kind) {
+ //
+ // Most TypeCodes have empty parameter lists
+ //
+ default:
+ break;
+
+ //
+ // A few have "simple" parameter lists
+ //
+ case tk_string:
+ case tk_wstring:
+ continue_encoding = stream->put_ulong (tc2->_length);
+ break;
+
+ //
+ // Indirected typecodes can't occur at "top level" like
+ // this, only nested inside others!
+ //
+ case ~0:
+ dmsg ("indirected typecode at top level!");
+ continue_encoding = CORBA_B_FALSE;
+ break;
+
+ //
+ // The rest have "complex" parameter lists that are already
+ // encoded as bulk octets ... put length, then octets
+ //
+ case tk_objref:
+ case tk_struct:
+ case tk_union:
+ case tk_enum:
+ case tk_sequence:
+ case tk_array:
+ case tk_alias:
+ case tk_except:
+ {
+ unsigned i;
+
+ continue_encoding = stream->put_ulong (tc2->_length);
+ for (i = 0; i < tc2->_length && continue_encoding; i++)
+ continue_encoding =
+ stream->put_octet (tc2->_buffer [i]);
+ }
+ }
+ }
+ break;
+
+ case tk_Principal:
+ {
+ CORBA_Principal_ptr p = *(CORBA_Principal_ptr*) data;
+ unsigned i;
+
+ if (p != 0) {
+ continue_encoding = stream->put_long (p->id.length);
+ for (i = 0; continue_encoding && i < p->id.length; i++)
+ continue_encoding = stream->put_octet (p->id.buffer [i]);
+ } else
+ continue_encoding = stream->put_long (0);
+ }
+ break;
+
+ case tk_objref:
+ // XXX implement me
+ break;
+
+ case tk_sequence:
+ {
+ //
+ // First marshal the sequence length, verifying that
+ // it's within the sequence bounds ...
+ //
+ CORBA_OctetSeq *seq = (CORBA_OctetSeq *) data;
+ CORBA_ULong len = seq ? seq->length : 0;
+
+ if (len > 0) {
+ CORBA_ULong bounds;
+
+ bounds = tc->ulong_param (1, env);
+ if (env.exception () != 0)
+ return CORBA_TypeCode::TRAVERSE_STOP;
+
+ if (bounds != 0 && len > bounds) {
+ env.exception (new CORBA_BAD_PARAM (COMPLETED_MAYBE));
+ return CORBA_TypeCode::TRAVERSE_STOP;
+ }
+ }
+ continue_encoding = stream->put_ulong (len);
+
+ //
+ // Fast exit on error or empty sequence
+ //
+ if (!continue_encoding || len == 0)
+ break;
+ }
+ // FALLTHROUGH
+
+ case tk_struct:
+ case tk_union:
+ case tk_array:
+ case tk_alias:
+ //
+ // Marshal each member in order.
+ //
+ return tc->traverse (data, 0, encoder, context, env);
+
+ case tk_except:
+ //
+ // Convert the the "hidden" TypeCode at the beginning of the
+ // exception into an on-the-wire ID, then marshal the members
+ // in order (traversal skips that hidden typecode, and more).
+ //
+ // NOTE: This is asymmetric with respect to decoding the exception,
+ // since whoever decodes must pull off the ID and map it to the
+ // typecode to be used to unmarshal it (search among legal choices).
+ //
+ {
+ CORBA_String id = tc->id (env);
+
+ if (env.exception () == 0) {
+ continue_encoding =
+ encoder (_tc_CORBA_String, &id, 0, context, env)
+ == CORBA_TypeCode::TRAVERSE_CONTINUE
+ && tc->traverse (data, 0, encoder, context, env);
+ } else
+ continue_encoding = CORBA_B_FALSE;
+ }
+ break;
+
+ case tk_string:
+ {
+ CORBA_String str = *(CORBA_String *) data;
+ CORBA_ULong len, bounds;
+
+ //
+ // Be nice to programmers: treat nulls as empty strings
+ // not errors. (OMG-IDL supports languages that don't use
+ // the C/C++ notion of null v. empty strings; nulls aren't
+ // part of the OMG-IDL string model.)
+ //
+ if (str == 0) {
+ stream->put_ulong (1);
+ stream->put_char (0);
+ break;
+ }
+
+ //
+ // Verify string satisfies bounds requirements. We're not
+ // so permissive as to send messages violating the interface
+ // spec by having excessively long strings!
+ //
+ bounds = tc->ulong_param (0, env);
+ if (env.exception () != 0)
+ return CORBA_TypeCode::TRAVERSE_STOP;
+ len = strlen ((char *)str);
+
+ if (bounds != 0 && len > bounds) {
+ continue_encoding = CORBA_B_FALSE;
+ break;
+ }
+
+ //
+ // Encode the string, followed by a NUL character.
+ //
+ continue_encoding = stream->put_ulong (len + 1);
+ while (continue_encoding != CORBA_B_FALSE && *str)
+ continue_encoding = stream->put_char (*str++);
+ stream->put_char (0);
+ }
+ break;
+
+ case tk_wstring:
+ {
+ wchar_t *str = *(wchar_t **) data;
+ CORBA_ULong len, bounds;
+
+ //
+ // Be nice to programmers: treat nulls as empty strings
+ // not errors. (OMG-IDL supports languages that don't use
+ // the C/C++ notion of null v. empty strings; nulls aren't
+ // part of the OMG-IDL string model.)
+ //
+ if (str == 0) {
+ stream->put_ulong (1);
+ stream->put_wchar (0);
+ break;
+ }
+
+ //
+ // Verify wide string satisfies bounds requirements. We're
+ // not so permissive as to send messages violating the interface
+ // spec by having excessively long strings!
+ //
+ bounds = tc->ulong_param (0, env);
+ if (env.exception () != 0)
+ return CORBA_TypeCode::TRAVERSE_STOP;
+ len = wslen (str);
+ if (bounds != 0 && len > bounds) {
+ continue_encoding = CORBA_B_FALSE;
+ break;
+ }
+
+ //
+ // Encode the wide string, followed by a NUL character.
+ //
+ continue_encoding = stream->put_ulong (wslen (str) + 1);
+ while (continue_encoding != CORBA_B_FALSE && *str)
+ continue_encoding = stream->put_wchar (*str++);
+ stream->put_wchar (0);
+ }
+ break;
+
+ case tk_longdouble:
+ continue_encoding =
+ stream->put_longdouble (*(CORBA_LongDouble *)data);
+ break;
+
+ case tk_wchar:
+ continue_encoding = stream->put_wchar (*(wchar_t *)data);
+ break;
+
+ // case ~0:
+ default:
+ dmsg ("encoder default case ?");
+ continue_encoding = CORBA_B_FALSE;
+ break;
+ }
+
+ if (continue_encoding == CORBA_B_FALSE) {
+ env.exception (new CORBA_MARSHAL (COMPLETED_MAYBE));
+ dmsg ("marshaling encoder detected error");
+ return CORBA_TypeCode::TRAVERSE_STOP;
+ }
+ return CORBA_TypeCode::TRAVERSE_CONTINUE;
+}
+
+
+
+//
+// Array of typecodes used to unmarshal ...
+//
+extern CORBA_TypeCode_ptr __tc_consts [TC_KIND_COUNT];
+
+
+CORBA_TypeCode::traverse_status
+XDR_stream::decoder (
+ CORBA_TypeCode_ptr tc,
+ const void *data,
+ const void *,
+ void *context,
+ CORBA_Environment &env
+)
+THROWS_NOTHING
+{
+ CORBA_Boolean continue_decoding = CORBA_B_TRUE;
+ XDR_stream *stream = (XDR_stream *)context;
+
+ switch (tc->_kind) {
+ case tk_null:
+ case tk_void:
+ // nothing to decode!
+ break;
+
+ case tk_char:
+ case tk_octet:
+ continue_decoding = stream->get_char (*(CORBA_Char *)data);
+ break;
+
+ case tk_short:
+ case tk_ushort:
+ continue_decoding = stream->get_short (*(short *)data);
+ break;
+
+ case tk_long:
+ case tk_ulong:
+ case tk_float:
+ continue_decoding = stream->get_long (*(CORBA_Long *)data);
+ break;
+
+ case tk_longlong:
+ case tk_ulonglong:
+ case tk_double:
+ continue_decoding = stream->get_longlong (*(CORBA_LongLong *)data);
+ break;
+
+ case tk_boolean:
+ continue_decoding = stream->get_boolean (*(CORBA_Boolean *)data);
+ break;
+
+ case tk_enum:
+ {
+ CORBA_ULong val;
+
+ //
+ // NOTE assumption that this is in-range.
+ //
+ // XXX should check this, it's rather hard to recover
+ // from such errors since they "do not occur" and are
+ // essentially never tested for.
+ //
+ continue_decoding = stream->get_ulong (val);
+ *(unsigned *)data = (unsigned) val;
+ }
+ break;
+
+ case tk_any:
+ {
+ CORBA_Any *any = (CORBA_Any *)data;
+ CORBA_TypeCode_ptr tc2;
+ void *value;
+
+ if (decoder (_tc_CORBA_TypeCode, &tc2, 0, context, env)
+ != CORBA_TypeCode::TRAVERSE_CONTINUE)
+ return CORBA_TypeCode::TRAVERSE_STOP;
+
+ value = new CORBA_Octet [tc2->size (env)];
+
+ if (decoder (tc2, value, 0, context, env)
+ != CORBA_TypeCode::TRAVERSE_CONTINUE) {
+ delete value;
+ CORBA_release (tc2);
+ return CORBA_TypeCode::TRAVERSE_STOP;
+ }
+ (void) new (any) CORBA_Any (tc2, value, CORBA_B_TRUE);
+ }
+ break;
+
+ case tk_TypeCode:
+ {
+ CORBA_ULong kind;
+ CORBA_TypeCode_ptr *tcp;
+
+ continue_decoding = stream->get_ulong (kind);
+ if (continue_decoding == CORBA_B_FALSE)
+ break;
+ if (kind >= TC_KIND_COUNT) {
+ continue_decoding = CORBA_B_FALSE;
+ break;
+ }
+
+ tcp = (CORBA_TypeCode_ptr *)data;
+
+ //
+ // Typecodes with empty parameter lists all have preallocated
+ // constants. We use those to reduce memory consumption and
+ // heap access ... also, to speed things up!
+ //
+ if (((*tcp) = __tc_consts [(unsigned) kind]) != 0) {
+ *tcp = __tc_consts [(unsigned) kind];
+ break;
+ } else switch (kind) {
+ //
+ // Need special handling for all kinds of typecodes that have
+ // nonempty parameter lists ...
+ //
+ default: // error: missed a case!
+ env.exception (new CORBA_INTERNAL (COMPLETED_MAYBE));
+ return CORBA_TypeCode::TRAVERSE_STOP;
+
+ //
+ // Some have "simple" parameter lists ... some of these also
+ // have preallocated constants that could be used.
+ //
+ case tk_string:
+ case tk_wstring:
+ {
+ CORBA_ULong bound;
+
+ continue_decoding = stream->get_ulong (bound);
+ if (continue_decoding) {
+ if (bound == 0) {
+ if (kind == tk_string)
+ *tcp = _tc_CORBA_String;
+ else
+ *tcp = _tc_CORBA_WString;
+ } else {
+ *tcp = new CORBA_TypeCode ((CORBA_TCKind) kind,
+ bound, 0, CORBA_B_TRUE);
+ }
+ }
+ }
+ break;
+
+ //
+ // Indirected typecodes, illegal at "top level" but we allow
+ // unmarshaling of them here because we use the same code to
+ // read "off the wire" (where they're illegal) and to read
+ // out of an encapsulation stream. We distinguish the case
+ // where this is legal as described above.
+ //
+ case ~0:
+ // XXX implement me
+ break;
+
+ //
+ // The rest have "complex" parameter lists that are
+ // encoded as bulk octets ...
+ //
+ case tk_objref:
+ case tk_struct:
+ case tk_union:
+ case tk_enum:
+ case tk_sequence:
+ case tk_array:
+ case tk_alias:
+ case tk_except:
+ {
+ unsigned len, i;
+ CORBA_ULong length;
+ CORBA_Octet *buffer;
+
+ continue_decoding = stream->get_ulong (length);
+ if (!continue_decoding)
+ break;
+
+ // if length > MAXUNSIGNED, error ...
+ len = (unsigned) length;
+
+ buffer = new CORBA_Octet [len];
+
+ for (i = 0; i < len && continue_decoding; i++)
+ continue_decoding = stream->get_octet (buffer [i]);
+
+ if (!continue_decoding) {
+ delete buffer;
+ break;
+ }
+ *tcp = new CORBA_TypeCode ((CORBA_TCKind)kind,
+ len, buffer, CORBA_B_TRUE);
+ }
+ }
+ }
+ break;
+
+ case tk_Principal:
+ {
+ CORBA_Principal_ptr *pp = (CORBA_Principal_ptr *)data;
+ CORBA_ULong len;
+
+ continue_decoding = stream->get_ulong (len);
+ if (len == 0)
+ *pp = 0;
+ else {
+ *pp = new CORBA_Principal;
+ (*pp)->id.buffer = new CORBA_Octet [(size_t) len];
+ (*pp)->id.maximum = (*pp)->id.length = len;
+
+ for (unsigned i = 0;
+ continue_decoding != CORBA_B_FALSE && i < len;
+ i++)
+ continue_decoding = stream->get_octet (
+ (*pp)->id.buffer [i]);
+ }
+ }
+ break;
+
+ case tk_objref:
+ // XXX implement me
+ break;
+
+ case tk_sequence:
+ {
+ //
+ // First unmarshal the sequence length ... we trust it
+ // to be right here, on the "be gracious in what you
+ // accept" principle. We don't generate illegal sequences
+ // (i.e. length > bounds).
+ //
+ CORBA_OctetSeq *seq = (CORBA_OctetSeq *) data;
+
+ continue_decoding = stream->get_ulong (seq->length);
+ seq->maximum = seq->length;
+ seq->buffer = 0;
+
+ //
+ // Fast exit on empty sequences or errors
+ //
+ if (!continue_decoding || seq->length == 0)
+ break;
+
+ //
+ // ... then allocate the memory into which we'll unmarshal
+ //
+ CORBA_TypeCode_ptr tc2;
+ size_t size;
+
+ tc2 = tc->typecode_param (0, env);
+ if (env.exception ())
+ return CORBA_TypeCode::TRAVERSE_STOP;
+
+ size = tc2->size (env);
+ if (env.exception ())
+ return CORBA_TypeCode::TRAVERSE_STOP;
+
+ tc2->Release ();
+
+ seq->buffer = new CORBA_Octet [size * (size_t) seq->maximum];
+ }
+ // FALLTHROUGH
+
+ case tk_struct:
+ case tk_union:
+ case tk_array:
+ case tk_alias:
+ //
+ // Unmarshal all the individual elements using the per-member
+ // description held in the "parent" TypeCode.
+ //
+
+ // FALLTHROUGH
+
+ case tk_except:
+ //
+ // For exceptions, the "hidden" type ID near the front of the
+ // on-wire representation was previously unmarshaled and mapped
+ // to the "tc" typcode we're using to traverse the memory ...
+ // at the same time its vtable, refcount, and other state was
+ // established.
+ //
+ // NOTE: This is asymmetric with respect to encoding exceptions.
+ //
+ return tc->traverse (data, 0, decoder, context, env);
+
+ case tk_string:
+ {
+ CORBA_String str;
+ CORBA_ULong len = 0;
+
+ //
+ // On decode, omit the check against specified string bounds,
+ // and cope with illegal "zero length" strings (all lengths
+ // on the wire must include a NUL).
+ //
+ // This is on the principle of being gracious in what we accept;
+ // we don't generate messages that fail to comply with protocol
+ // specs, but we will accept them when it's clear how to do so.
+ //
+ continue_decoding = stream->get_ulong (len);
+ *((CORBA_String*)data) = str = new CORBA_Char [(size_t) (len)];
+ if (len != 0)
+ while (continue_decoding != CORBA_B_FALSE && len-- != 0) {
+ continue_decoding = stream->get_char (*(CORBA_Char *)str);
+ str++;
+ }
+ break;
+ }
+
+ case tk_wstring:
+ {
+ wchar_t *str;
+ CORBA_ULong len = 0;
+
+ //
+ // On decode, omit the check against specified wstring bounds,
+ // and cope with illegal "zero length" strings (all lengths
+ // on the wire must include a NUL).
+ //
+ // This is on the principle of being gracious in what we accept;
+ // we don't generate messages that fail to comply with protocol
+ // specs, but we will accept them when it's clear how to do so.
+ //
+ continue_decoding = stream->get_ulong (len);
+ *((wchar_t **)data) = str = new wchar_t [(size_t) (len)];
+ if (len != 0) {
+ while (continue_decoding != CORBA_B_FALSE && len--) {
+ continue_decoding = stream->get_wchar (*str);
+ str++;
+ }
+ }
+ }
+ break;
+
+ case tk_longdouble:
+ continue_decoding =
+ stream->get_longdouble (*(CORBA_LongDouble *)data);
+ break;
+
+ case tk_wchar:
+ continue_decoding = stream->get_wchar (*(wchar_t *)data);
+ break;
+
+ // case ~0:
+ default:
+ continue_decoding = CORBA_B_FALSE;
+ dmsg ("decode, default case?");
+ break;
+ }
+
+ if (continue_decoding == CORBA_B_FALSE) {
+ env.exception (new CORBA_MARSHAL (COMPLETED_NO));
+ dmsg ("marshaling decoder detected error");
+ return CORBA_TypeCode::TRAVERSE_STOP;
+ }
+ return CORBA_TypeCode::TRAVERSE_CONTINUE;
+}
+
+
+//
+// Write an XDR message fragment out on the stream.
+//
+CORBA_Boolean
+XDR_stream::flush_frag (CORBA_Boolean is_last)
+THROWS_NOTHING
+{
+ return CORBA_B_FALSE;
+
+#if 0
+ int status;
+ CORBA_ULong size, header;
+
+ size = index * sizeof (CORBA_ULong); // byte length of msg
+ if (is_last)
+ header = 0x80000000 | size; // indicates last frag
+ else
+ header = size;
+ buffer [0] = htonl (header);
+
+ //
+ // XXX for portability, loop until there's no error. Some
+ // platforms/mode don't guarantee full TCP writes even when
+ // async (or nonblocking) mode was not set on this socket.
+ //
+ size += sizeof (CORBA_ULong);
+ status = write (fd, &buffer [0], size);
+
+ index = 0;
+
+ return (status == size);
+#endif
+}
+
+
+//
+// Read an XDR message fragment in from the stream.
+//
+CORBA_Boolean
+XDR_stream::read_frag ()
+THROWS_NOTHING
+{
+ // read cookie, split out size and "is last" flag
+ // read rest of buffer
+
+ return CORBA_B_FALSE;
+}
diff --git a/TAO/IIOP/lib/onc/xdr.hh b/TAO/IIOP/lib/onc/xdr.hh
new file mode 100644
index 00000000000..e50544662bf
--- /dev/null
+++ b/TAO/IIOP/lib/onc/xdr.hh
@@ -0,0 +1,281 @@
+// @(#)xdr.hh 1.3 95/11/07
+// Copyright 1995 by Sun Microsystems, Inc.
+//
+// XDR stream interface and implementation (partially implemented)
+//
+// XXX as of 3-Nov-95 XDR_stream should only be relied on to marshal the
+// simplest primitives ... not objrefs, typecodes, etc. Also, the
+// handling of sequences of chars/octets/shorts/wchars is wrong.
+//
+
+#ifndef _xdr_hh
+#define _xdr_hh
+
+#include <sys/types.h>
+#include <netinet/in.h>
+
+//
+// Define on systems that fully support exceptions ... excluding
+// some very common platforms like G++ and VC++ 2.2
+//
+// #define THROWS_NOTHING throw()
+
+//
+// On DevPro's 4.0.1a compilers, null throw specs carry a big
+// performance penalty: slower by about 25% here. Disable!!
+//
+#define THROWS_NOTHING
+
+class XDR_stream
+{
+ public:
+ enum {
+ STANDARD_BUFSIZE = 4096, // ~3 enet packets with TCP
+ BUFFER_LEN = 1 + (STANDARD_BUFSIZE
+ / sizeof (CORBA_Long))
+ };
+
+ XDR_stream (
+ int _fd
+ ) THROWS_NOTHING :
+ fd (_fd)
+ {
+ index = 0;
+ decode_flag = CORBA_B_FALSE;
+ max_index = 0;
+ is_last_frag = CORBA_B_FALSE;
+ }
+
+ ~XDR_stream () THROWS_NOTHING {}
+
+
+ //
+ // Write the last bit of an encoded message ... or tell if we've
+ // decoded all the data in an encoded message we're processing.
+ //
+ // NOTE: these assume the mode is appropriate for these operations.
+ //
+ CORBA_Boolean output_msg_at_end () THROWS_NOTHING
+ { return flush_frag (CORBA_B_TRUE); }
+ CORBA_Boolean input_msg_at_end () THROWS_NOTHING
+ { return is_last_frag && index == max_index; }
+
+ //
+ // Tell if we're decoding or encoding data.
+ //
+ CORBA_Boolean is_decoding () THROWS_NOTHING
+ { return decode_flag; }
+ CORBA_Boolean is_encoding () THROWS_NOTHING
+ { return !is_decoding (); }
+
+ // private ... iff there's a routine to set it!
+ CORBA_Boolean decode_flag; // true iff decoding
+
+ //
+ // ENCODING SUPPORT ...
+ //
+ CORBA_Boolean put32 (CORBA_Long word) THROWS_NOTHING
+ {
+ if (index < (BUFFER_LEN - 1)
+ || (flush_frag (CORBA_B_FALSE)
+ == CORBA_B_TRUE)) {
+ buffer [++index] = htonl (word);
+ return CORBA_B_TRUE;
+ } else
+ return CORBA_B_FALSE;
+ }
+
+ CORBA_Boolean put_byte (char c) THROWS_NOTHING
+ { return put32 (c); }
+ CORBA_Boolean put_short (CORBA_Short s) THROWS_NOTHING
+ { return put32 (s); }
+ CORBA_Boolean put_long (CORBA_Long l) THROWS_NOTHING
+ { return put32 (l); }
+
+ CORBA_Boolean put_longlong (const CORBA_LongLong &ll)
+ THROWS_NOTHING;
+
+ inline CORBA_Boolean put_char (CORBA_Char c) THROWS_NOTHING
+ { return put_byte ((char) c); }
+ inline CORBA_Boolean put_wchar (wchar_t wc) THROWS_NOTHING
+ {
+ //
+ // "wchar_t" isn't always 2 bytes, such
+ // systems might need further conversion
+ // (e.g. hosts with multibyte characters
+ // native, rather than UNICODE)
+ //
+ return put_short ((short)wc);
+ }
+
+ inline CORBA_Boolean put_boolean (CORBA_Boolean b) THROWS_NOTHING
+ { return put_byte ((char)
+ (b != CORBA_B_FALSE)); }
+
+ inline CORBA_Boolean put_octet (CORBA_Octet o) THROWS_NOTHING
+ { return put_byte ((char) o); }
+ inline CORBA_Boolean put_ushort (CORBA_UShort s) THROWS_NOTHING
+ { return put_short ((CORBA_Short) s); }
+ inline CORBA_Boolean put_ulong (CORBA_ULong l) THROWS_NOTHING
+ { return put_long ((CORBA_Long) l); }
+ inline CORBA_Boolean put_ulonglong (const CORBA_ULongLong &ll)
+ THROWS_NOTHING
+ { return
+ put_longlong ((CORBA_LongLong &) ll); }
+
+ inline CORBA_Boolean put_float (float f) THROWS_NOTHING
+ { return put_long (*(CORBA_Long *) &f); }
+ inline CORBA_Boolean put_double (const double &d) THROWS_NOTHING
+ { return
+ put_longlong (*(CORBA_LongLong *) &d); }
+
+ CORBA_Boolean put_longdouble (const CORBA_LongDouble &ld)
+ THROWS_NOTHING;
+
+ //
+ // marshaling interpreter ... 'context' really points to a stream.
+ //
+ static CORBA_TypeCode::traverse_status
+ encoder (
+ CORBA_TypeCode_ptr tc,
+ const void *data,
+ const void *,
+ void *context,
+ CORBA_Environment &env
+ ) THROWS_NOTHING;
+
+ //
+ // DECODING SUPPORT
+ //
+ // XXX fix lack of error reporting here !!
+ //
+
+ CORBA_Long get32 () THROWS_NOTHING
+ {
+ if (index <= max_index
+ || read_frag () == CORBA_B_TRUE)
+ return ntohl (buffer [index++]);
+ else
+ return 0;
+ }
+
+
+ CORBA_Boolean get_byte (char &c) THROWS_NOTHING
+ {
+ c = (char) get32();
+ return CORBA_B_TRUE;
+ }
+
+ CORBA_Boolean get_short (CORBA_Short &s) THROWS_NOTHING
+ {
+ s = (short) get32();
+ return CORBA_B_TRUE;
+ }
+
+ CORBA_Boolean get_long (CORBA_Long &l) THROWS_NOTHING
+ {
+ l = get32();
+ return CORBA_B_TRUE;
+ }
+
+ CORBA_Boolean get_longlong (CORBA_LongLong &ll)
+ THROWS_NOTHING;
+
+ inline CORBA_Boolean get_char (CORBA_Char &o) THROWS_NOTHING
+ { return get_byte ((char &) o); }
+ inline CORBA_Boolean get_wchar (wchar_t &wc) THROWS_NOTHING
+ {
+ short s;
+
+ //
+ // wchar_t isn't always "short"
+ //
+ CORBA_Boolean retval = get_short (s);
+ wc = s;
+ return retval;
+ }
+
+ inline CORBA_Boolean get_boolean (CORBA_Boolean &b) THROWS_NOTHING
+ {
+ CORBA_Char c;
+
+ //
+ // CORBA_Boolean is rarely 'char'
+ //
+ CORBA_Boolean retval = get_char (c);
+ b = (c == 1);
+ return retval;
+ }
+
+ inline CORBA_Boolean get_octet (CORBA_Octet &o) THROWS_NOTHING
+ { return get_byte ((char &) o); }
+ inline CORBA_Boolean get_ushort (CORBA_UShort &s) THROWS_NOTHING
+ { return get_short ((short&) s); }
+ inline CORBA_Boolean get_ulong (CORBA_ULong &l) THROWS_NOTHING
+ { return get_long ((CORBA_Long &) l); }
+ inline CORBA_Boolean get_ulonglong (const CORBA_ULongLong &ull)
+ THROWS_NOTHING
+ { return
+ get_longlong ((CORBA_LongLong &) ull); }
+
+ inline CORBA_Boolean get_float (float &f) THROWS_NOTHING
+ { return get_long ((CORBA_Long &) f); }
+ inline CORBA_Boolean get_double (double &d) THROWS_NOTHING
+ { return
+ get_longlong ((CORBA_LongLong &) d); }
+
+ CORBA_Boolean get_longdouble (CORBA_LongDouble &ld)
+ THROWS_NOTHING;
+
+ //
+ // unmarshaling interpreter ... 'context' really points to a buffer.
+ //
+ static CORBA_TypeCode::traverse_status
+ decoder (
+ CORBA_TypeCode_ptr tc,
+ const void *data,
+ const void *,
+ void *context,
+ CORBA_Environment &env
+ ) THROWS_NOTHING;
+
+ private:
+ //
+ // Low level I/O primitives ... flush a fragment (maybe as the last one),
+ // read a fragment in.
+ //
+ CORBA_Boolean flush_frag (CORBA_Boolean is_last)
+ THROWS_NOTHING;
+ CORBA_Boolean read_frag () THROWS_NOTHING;
+
+ //
+ // The actual buffer and the index to the current entry.
+ // (Next buffer entry read/written is index+1 ...)
+ //
+ CORBA_Long buffer [BUFFER_LEN];
+ unsigned index;
+
+ //
+ // The (TCP) stream on which this writes its message fragments.
+ //
+ const int fd;
+
+ //
+ // Used when reading fragments ... max_index controls where the
+ // end of the fragment is recorded to be, and is_last_frag says
+ // if it's OK to read_frag() to get the next fragment.
+ //
+ // To move to the next message in the stream, create a new XDR
+ // stream (e.g. on the stack).
+ //
+ CORBA_Long max_index;
+ CORBA_Boolean is_last_frag;
+
+ //
+ // Two operations not supported by this class.
+ //
+ XDR_stream (const XDR_stream &);
+ XDR_stream &operator = (const XDR_stream &);
+};
+
+#endif // _xdr_hh
diff --git a/TAO/IIOP/lib/runtime/Makefile b/TAO/IIOP/lib/runtime/Makefile
new file mode 100644
index 00000000000..e570c2c2341
--- /dev/null
+++ b/TAO/IIOP/lib/runtime/Makefile
@@ -0,0 +1,13 @@
+FILES = \
+ any.cpp cdr.cpp corbacom.cpp debug.cpp except.cpp interp.cpp \
+ marshal.cpp object.cpp orbobj.cpp principa.cpp tc_const.cpp \
+ typecode.cpp nvlist.cpp request.cpp toa.cpp
+
+ROOT = ../..
+
+include ../Makefile.gen
+
+t-xdr: t-xdr.cpp
+ $(LINK.cc) -o t-xdr t-xdr.cpp \
+ -qoption ld -R.. -L.. -lcorba \
+ -lsocket -lnsl
diff --git a/TAO/IIOP/lib/runtime/align.hh b/TAO/IIOP/lib/runtime/align.hh
new file mode 100644
index 00000000000..6b9df81b9ff
--- /dev/null
+++ b/TAO/IIOP/lib/runtime/align.hh
@@ -0,0 +1,63 @@
+// @(#)align.hh 1.1 95/11/04
+// Copyright 1994-1995 by Sun Microsystems, Inc.
+//
+// Pointer alignment utilities
+//
+// A "ptr_arith_t" type is defined for doing numerical operations on
+// pointers, such as aligning them. Pointer sizes vary from 2 to 8
+// bytes in today's environments; a portable data type is much needed.
+//
+
+#ifndef _align_hh
+#define _align_hh
+
+//
+// Type for doing arithmetic on pointers ... as elsewhere, we assume
+// that "unsigned" versions of a type are the same size as the "signed"
+// version of the same type.
+//
+
+#if SIZEOF_VOID_P == SIZEOF_INT
+typedef unsigned int ptr_arith_t;
+
+#elif SIZEOF_VOID_P == SIZEOF_LONG
+typedef unsigned long ptr_arith_t;
+
+#elif SIZEOF_VOID_P == SIZEOF_LONG_LONG
+typedef unsigned long long ptr_arith_t;
+
+#else
+# error "Can't find a suitable type for doing pointer arithmetic."
+#endif
+
+
+
+//
+// Efficiently align "value" up to "alignment", knowing that all such
+// boundaries are binary powers and that we're using two's complement
+// arithmetic.
+//
+static inline ptr_arith_t
+align_binary (const ptr_arith_t value, size_t alignment)
+{
+ ptr_arith_t temp = alignment - 1;
+
+ return (value + temp) & ~temp;
+}
+
+
+//
+// Efficiently round "ptr" up to an "alignment" boundary, knowing that
+// all such boundaries are binary powers and that we're using two's
+// complement arithmetic.
+//
+// XXX Returned as "byte pointer" -- CDR module would change to be seen
+// as a "void *". May want to change this to add XDR cleanly.
+//
+static inline unsigned char *
+ptr_align_binary (const unsigned char *ptr, size_t alignment)
+{
+ return (unsigned char *) align_binary ((ptr_arith_t) ptr, alignment);
+}
+
+#endif // _align_hh
diff --git a/TAO/IIOP/lib/runtime/any.cpp b/TAO/IIOP/lib/runtime/any.cpp
new file mode 100644
index 00000000000..d5cbed7b512
--- /dev/null
+++ b/TAO/IIOP/lib/runtime/any.cpp
@@ -0,0 +1,670 @@
+// @(#)any.cpp 1.9 95/11/04
+// Copyright 1994-1995 by Sun Microsystems Inc.
+// All Rights Reserved
+//
+// ORB: Implementation of CORBA_Any
+//
+// This includes three constructors, a destructor, and a "replace" method
+// for the "Any" data type. "Any" values pair a pointer to a data structure
+// in the native binary representation (e.g. C struct) with a TypeCode that
+// describes that data structure.
+//
+// The copy constructor and the destructor each use the TypeCode interpreter
+// with specialized "visit" callback routines. The "visit" routines are
+// used respectively to make "deep copies" and perform "deep frees" of the
+// aritrary values as described by the "Any" value's typecode.
+//
+// Note that these "visit" routines are called directly, and they choose
+// whether or not to use the TypeCode interpreter to examine constituents.
+// In the simple cases, the "visit" routines can do their work without any
+// further calls; only for constructed types is the interpreter's knowledge
+// really required.
+//
+// THREADING NOTE: "Any" is a data structure which must be protected by
+// external critical sections. Like simpler numeric types, "Any" instances
+// are accessed and modified atomically. This implementation is reentrant,
+// so that independent "Any" values may be manipulated concurrently when
+// the underlying programming environment is itself reentrant.
+//
+// COM NOTE: Yes, this is a utility data type whose implementation is
+// fully exposed. Factories for these are not normally used in C++.
+//
+
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+#include <corba/orb.hh>
+
+#include "runtime/debug.hh"
+#include "runtime/thread.hh"
+
+#include <initguid.h>
+
+
+#ifdef _POSIX_THREADS
+//
+// If POSIX threads are available, set up lock covering refcounts.
+//
+static pthread_mutex_t any_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif // _POSIX_THREADS
+
+
+
+CORBA_TypeCode_ptr
+CORBA_Any::type () const
+{
+ return _type;
+}
+
+void *
+CORBA_Any::value () const
+{
+ return _value;
+}
+
+//
+// Default "Any" constructor -- initializes to nulls per the
+// OMG C++ mapping.
+//
+// NOTE: null (zero) typecode pointers are also treated as
+// the null typecode ...
+//
+CORBA_Any::CORBA_Any ()
+{
+ _type = _tc_CORBA_Null;
+ _value = 0;
+ _orb_owns_data = CORBA_B_FALSE;
+ _refcnt = 1;
+}
+
+
+//
+// The more common "Any" constructor has its own copy of a
+// typecode, and either holds or "consumes" an arbitrary data
+// value satisfying the normal binary interface rules.
+//
+CORBA_Any::CORBA_Any (
+ CORBA_TypeCode_ptr tc,
+ void *value,
+ CORBA_Boolean orb_owns_data
+) :
+ _value (value),
+ _orb_owns_data (orb_owns_data)
+{
+ _type = tc;
+ tc->AddRef ();
+ _refcnt = 1;
+}
+
+
+//
+// Helper routine for "Any" copy constructor ...
+//
+// "Deep Copy" from source to dest. Memory is always there to be
+// copied to ... if this calls itself recursively, it ensures that
+// this remains true (only really an issue for sequences).
+//
+// This shows the main reason to pass two values to the "visit"
+// function used by the TypeCode interpreter: it allows the copy
+// to be made without using any additional temporary memory. Most
+// other such "visit" routines use only a single value. This is
+// also slightly atypical in that it doesn't use the "context".
+//
+static CORBA_TypeCode::traverse_status
+deep_copy (
+ CORBA_TypeCode_ptr tc,
+ const void *source,
+ const void *dest,
+ void *, // no context
+ CORBA_Environment &env
+)
+{
+ CORBA_TypeCode::traverse_status retval;
+ CORBA_TCKind my_kind;
+
+ if (!tc) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return CORBA_TypeCode::TRAVERSE_STOP;
+ }
+
+ my_kind = tc->kind (env);
+
+ if (env.exception_type () != NO_EXCEPTION)
+ return CORBA_TypeCode::TRAVERSE_STOP;
+
+ //
+ // Deep copy from "source" to "dest" ... this code "knows" a bit about
+ // representations, verify it when porting to oddball platforms with
+ // non-IEEE floating point values or atypical byte and word sizes.
+ //
+ // See the TypeCode interpreter code for more details about the
+ // representational assumptions here.
+ //
+ retval = CORBA_TypeCode::TRAVERSE_CONTINUE;
+
+ switch (my_kind) {
+ case tk_null:
+ case tk_void:
+ break;
+
+ case tk_char:
+ case tk_octet:
+ *(CORBA_Octet *)dest = *(CORBA_Octet *)source;
+ break;
+
+ case tk_short:
+ case tk_ushort:
+ *(CORBA_Short *)dest = *(CORBA_Short *)source;
+ break;
+
+ case tk_wchar:
+ *(CORBA_WChar *)dest = *(CORBA_WChar *)source;
+ break;
+
+ case tk_long:
+ case tk_ulong:
+ case tk_float:
+ *(CORBA_Long *)dest = *(CORBA_Long *)source;
+ break;
+
+ case tk_longlong:
+ case tk_ulonglong:
+ case tk_double:
+ *(CORBA_LongLong *)dest = *(CORBA_LongLong *)source;
+ break;
+
+ case tk_longdouble:
+ *(CORBA_LongDouble *)dest = *(CORBA_LongDouble *)source;
+ break;
+
+ case tk_boolean:
+ *(CORBA_Boolean *)dest = *(CORBA_Boolean *)source;
+ break;
+
+ case tk_any:
+ (void) new (dest) CORBA_Any (*(CORBA_Any*)source);
+ break;
+
+ case tk_TypeCode:
+ if ((*(CORBA_TypeCode_ptr *)source) != 0)
+ dest = source;
+ else
+ dest = _tc_CORBA_Null;
+ ((CORBA_TypeCode_ptr)dest)->AddRef ();
+ break;
+
+ case tk_Principal:
+ {
+ CORBA_Principal_ptr src, dst;
+
+ src = *(CORBA_Principal_ptr *)source;
+ dst = *(CORBA_Principal_ptr *)dest = new CORBA_Principal;
+
+ //
+ // Principals are just opaque IDs ... copy them
+ //
+ assert (src->id.length <= UINT_MAX);
+ dst->id.length = dst->id.maximum = src->id.length;
+ if (dst->id.length > 0) {
+ dst->id.buffer = new CORBA_Octet [(unsigned) dst->id.length];
+ memcpy (dst->id.buffer, src->id.buffer,
+ (size_t) dst->id.length);
+ } else {
+ dst->id.buffer = 0;
+ }
+ }
+ break;
+
+ case tk_objref:
+ *(CORBA_Object_ptr *)dest = CORBA_Object::
+ _duplicate (*(CORBA_Object_ptr *) source);
+ break;
+
+ case tk_sequence:
+ {
+ CORBA_OctetSeq *src, *dst;
+ CORBA_TypeCode_ptr tcp;
+ size_t size;
+
+ //
+ // Rely on binary format of sequences -- all are the
+ // same except for the type pointed to by "buffer"
+ //
+ src = (CORBA_OctetSeq *)source;
+ dst = (CORBA_OctetSeq *)dest;
+
+ assert (src->length <= UINT_MAX);
+ dst->length = dst->maximum = src->length;
+
+ //
+ // Get the size of each "buffer" element
+ //
+ tcp = tc->typecode_param (0, env);
+ if (env.exception () != 0) {
+ retval = CORBA_TypeCode::TRAVERSE_STOP;
+ break;
+ }
+
+ size = tcp->size (env);
+ if (env.exception () != 0) {
+ retval = CORBA_TypeCode::TRAVERSE_STOP;
+ break;
+ }
+ tcp->Release ();
+
+ //
+ // Now allocate a new (uninitialized) buffer of the right
+ // size to hold that many elements ... fall through and
+ // let a general traverse fill in those buffer elements.
+ //
+ size *= (size_t) src->length;
+ dst->buffer = new CORBA_Octet [size];
+ }
+ // FALLTHROUGH
+
+ case tk_struct:
+ case tk_union:
+ case tk_array:
+ case tk_alias:
+ return tc->traverse (source, dest,
+ (CORBA_TypeCode::VisitRoutine) deep_copy, 0, env);
+
+ case tk_except:
+ //
+ // Exceptions in memory have a "hidden" typecode up front,
+ // used to ensure that memory is appropriately freed and
+ // to hold the exception ID. We just copy that typecode,
+ // the traverse code ignores it completely.
+ //
+ *(CORBA_TypeCode_ptr *) dest = *(CORBA_TypeCode_ptr *) source;
+ (void) (*(CORBA_TypeCode_ptr *) dest)->AddRef ();
+ return tc->traverse (source, dest,
+ (CORBA_TypeCode::VisitRoutine) deep_copy, 0, env);
+
+ case tk_enum:
+ *(int *)dest = *(int *)source;
+ break;
+
+ case tk_string:
+ *(CORBA_String *)dest =
+ CORBA_string_copy (*(CORBA_String *)source);
+ break;
+
+ case tk_wstring:
+ *(CORBA_WString *)dest =
+ CORBA_wstring_copy (*(CORBA_WString *)source);
+ break;
+
+ default:
+ dmsg ("deep copy default case ?");
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ retval = CORBA_TypeCode::TRAVERSE_STOP;
+ break;
+ }
+ return retval;
+}
+
+
+//
+// Copy constructor for "Any".
+//
+CORBA_Any::CORBA_Any (const CORBA_Any &src)
+{
+ CORBA_Environment env;
+ size_t size;
+
+ if (src._type != 0)
+ _type = src._type;
+ else
+ _type = _tc_CORBA_Null;
+
+ _type->AddRef ();
+ _orb_owns_data = CORBA_B_TRUE;
+
+ size = _type->size (env); // XXX check error status
+ _value = (char *) calloc (1, size);
+
+ (void) _type->traverse (src._value, _value,
+ (CORBA_TypeCode::VisitRoutine) deep_copy, 0, env);
+}
+
+
+//
+// Helper routine for "Any" destructor.
+//
+// This frees all the memory pointed to by any given value held inside
+// of an "Any". For most data types it does nothing, since most data
+// types don't hold any memory. For a few, it recurses.
+//
+// This is one of the simplest typecode interpreter callbacks, since
+// in most cases it does nothing. Also, it uses neither the second
+// value nor the context parameter.
+//
+static CORBA_TypeCode::traverse_status
+deep_free (
+ CORBA_TypeCode_ptr tc,
+ const void *value,
+ const void *, // value2 unused
+ void *, // context unused
+ CORBA_Environment &env
+)
+{
+ //
+ // don't do anything if the value is a null pointer
+ //
+ if (!value)
+ return CORBA_TypeCode::TRAVERSE_CONTINUE;
+
+ CORBA_TypeCode::traverse_status retval;
+ CORBA_TCKind my_kind;
+
+ if (!tc) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return CORBA_TypeCode::TRAVERSE_STOP;
+ }
+
+ my_kind = tc->kind (env);
+
+ if (env.exception_type () != NO_EXCEPTION)
+ return CORBA_TypeCode::TRAVERSE_STOP;
+
+ //
+ // Free only embedded pointers ... which don't exist in most
+ // primitive types.
+ //
+ retval = CORBA_TypeCode::TRAVERSE_CONTINUE;
+ switch (my_kind) {
+ case tk_struct:
+ case tk_union:
+ case tk_array:
+ case tk_alias:
+ return tc->traverse (value, 0,
+ (CORBA_TypeCode::VisitRoutine) deep_free, 0, env);
+
+ //
+ // XXX: Exceptions are currently leaked because of bugs
+ // lurking in this area. Keep in mind that there are
+ // two things to free: (a) the typecode in the exception
+ // base class; (b) any pointers held by a user-defined
+ // exception, such as an objref or string.
+ //
+ // Since this code does nothing, it should leak BOTH of those
+ // kinds of memory. Since it's not supposed to be called
+ // except when the exception really is being freed, it should
+ // only be called when the reference count in the exception
+ // base class is zero.
+ //
+ // It's not clear which of those assertions actually hold.
+ //
+ // The code SHOULD be just like the traverse() call for a
+ // structure, with (a) a precondition that the reference
+ // count is zero, (b) an assertion that the typecode in the
+ // exception and "tc" are equivalent, (c) releasing that
+ // typecode found within the exception.
+ //
+ case tk_except:
+ return retval;
+
+
+ case tk_sequence:
+ retval = tc->traverse (value, 0,
+ (CORBA_TypeCode::VisitRoutine) deep_free, 0, env);
+ delete ((CORBA_OctetSeq *)value)->buffer;
+ break;
+
+ case tk_TypeCode:
+ if ((*(CORBA_TypeCode_ptr *)value) != 0)
+ (*(CORBA_TypeCode_ptr *)value)->Release ();
+ break;
+
+ case tk_Principal:
+ CORBA_release (*(CORBA_Principal_ptr *)value);
+ break;
+
+ case tk_objref:
+ CORBA_release (*(CORBA_Object_ptr *)value);
+ break;
+
+ case tk_string:
+ CORBA_string_free (*(CORBA_String *)value);
+ break;
+
+ case tk_wstring:
+ CORBA_wstring_free (*(CORBA_WString *)value);
+ break;
+
+ case tk_any:
+#ifdef __BORLANDC__
+ //
+ // XXX BC++ doesn't yet accept explicit calls to destructors
+ // with this syntax. A simple workaround must exist, though;
+ // other explicit destructor calls work.
+ //
+ dmsg ("Delete Any-in-Any ... memory leak with BC++ 4.5");
+#else
+ ((CORBA_Any *)value)->~CORBA_Any ();
+#endif
+ break;
+
+ default:
+ return CORBA_TypeCode::TRAVERSE_CONTINUE;
+ }
+
+ if (env.exception_type () != NO_EXCEPTION)
+ return CORBA_TypeCode::TRAVERSE_STOP;
+ else
+ return retval;
+}
+
+
+//
+// Destructor for an "Any" deep-frees memory if needed.
+//
+// NOTE that the assertion below will fire on application programmer errors,
+// such as using AddRef/Release out of sync with the true lifetime of an Any
+// value allocated on the stack. BUT it involves changing the refcounting
+// policy so that it's initialized to zero, not one ... which policy affects
+// the whole source base, and not just this data type. Get to this later.
+//
+CORBA_Any::~CORBA_Any ()
+{
+ CORBA_Environment env;
+
+ // assert (_refcnt == 0);
+
+ if (_orb_owns_data) {
+ (void) deep_free (_type, _value, 0, 0, env);
+ delete _value;
+ }
+ if (_type)
+ _type->Release ();
+}
+
+
+//
+// all-at-once replacement of the contents of an "Any"
+//
+void
+CORBA_Any::replace (
+ CORBA_TypeCode_ptr tc,
+ const void *v,
+ CORBA_Boolean orb_owns_data,
+ CORBA_Environment &env
+)
+{
+ if (_orb_owns_data) {
+ (void) deep_free (_type, _value, 0, 0, env);
+ delete _value;
+ }
+
+ if (_type != 0)
+ _type->Release ();
+
+ env.clear ();
+
+ _type = tc;
+ tc->AddRef ();
+ _value = (void *) v;
+ _orb_owns_data = orb_owns_data;
+}
+
+//
+// For COM -- IUnKnown operations
+//
+
+// {A201E4C8-F258-11ce-9598-0000C07CA898}
+DEFINE_GUID (IID_CORBA_Any,
+0xa201e4c8, 0xf258, 0x11ce, 0x95, 0x98, 0x0, 0x0, 0xc0, 0x7c, 0xa8, 0x98);
+
+
+ULONG
+__stdcall
+CORBA_Any::AddRef ()
+{
+#ifdef _POSIX_THREADS
+ Critical region (&any_lock);
+#endif
+
+ return ++_refcnt;
+}
+
+ULONG
+__stdcall
+CORBA_Any::Release ()
+{
+#ifdef _POSIX_THREADS
+ Critical region (&any_lock);
+#endif
+
+ if (--_refcnt != 0)
+ return _refcnt;
+
+#ifdef _POSIX_THREADS
+ region.leave ();
+#endif
+
+ delete this;
+ return 0;
+}
+
+HRESULT
+__stdcall
+CORBA_Any::QueryInterface (
+ REFIID riid,
+ void **ppv
+)
+{
+ *ppv = 0;
+
+ if (IID_CORBA_Any == riid || IID_IUnknown == riid)
+ *ppv = this;
+
+ if (*ppv == 0)
+ return ResultFromScode (E_NOINTERFACE);
+
+ (void) AddRef ();
+ return NOERROR;
+}
+
+
+//
+// VARIANT conversions
+//
+
+// copy constructor
+CORBA_Any::CORBA_Any (const VARIANT &src)
+{
+ _orb_owns_data = CORBA_B_TRUE;
+ _refcnt = 1;
+ _type = _tc_CORBA_Void;
+ _value = 0;
+
+ *this = src;
+}
+
+// assignment operator
+CORBA_Any &
+CORBA_Any::operator = (const VARIANT &src)
+{
+ this->~CORBA_Any ();
+
+ assert ((src.vt & 0xB000) == 0); // XXX better, report exception
+
+ switch (src.vt & 0x0fff) {
+ case VT_EMPTY:
+ _type = _tc_CORBA_Void;
+ _value = 0;
+ break;
+
+ case VT_NULL:
+ _type = _tc_CORBA_Null;
+ _value = 0;
+ break;
+
+ case VT_I2:
+ _type = _tc_CORBA_Short;
+ _value = new CORBA_Short ((src.vt & VT_BYREF)
+ ? (*src.piVal) : src.iVal);
+ break;
+
+ case VT_I4:
+ _type = _tc_CORBA_Long;
+ _value = new CORBA_Long ((src.vt & VT_BYREF)
+ ? (*src.plVal) : src.lVal);
+ break;
+
+ case VT_R4:
+ _type = _tc_CORBA_Float;
+ _value = new CORBA_Float ((src.vt & VT_BYREF)
+ ? (*src.pfltVal) : src.fltVal);
+ break;
+
+ case VT_R8:
+ _type = _tc_CORBA_Double;
+ _value = new CORBA_Double ((src.vt & VT_BYREF)
+ ? (*src.pdblVal) : src.dblVal);
+ break;
+
+ // case VT_CY:
+ // case VT_DATE:
+ // XXX convert currency and date to TBD CORBA conventions
+
+ // case VT_BSTR:
+ // XXX convert to CORBA string
+
+ // case VT_DISPATCH:
+ // case VT_UNKNOWN:
+ // case VT_VARIANT:
+ // XXX convert to CORBA objref or appropriate pseudo-objref
+
+ // case VT_BOOL:
+ // XXX convert to CORBA boolean
+
+ // case VT_ERROR:
+ // XXX what to do?
+
+ case VT_UI1:
+ _type = _tc_CORBA_Octet;
+ _value = new CORBA_Octet ((src.vt & VT_BYREF)
+ ? (*src.pbVal) : src.bVal);
+ break;
+
+ default:
+ // XXX report some exception ... throw it?
+ _type = _tc_CORBA_Void;
+ _value = 0;
+ break;
+ }
+
+ return *this;
+}
+
+CORBA_Any::operator VARIANT ()
+{
+ VARIANT retval;
+
+ // XXX convert it ... or report exception somehow!
+
+ retval.vt = VT_EMPTY;
+ return retval;
+}
diff --git a/TAO/IIOP/lib/runtime/cdr.cpp b/TAO/IIOP/lib/runtime/cdr.cpp
new file mode 100644
index 00000000000..b9652ec14ba
--- /dev/null
+++ b/TAO/IIOP/lib/runtime/cdr.cpp
@@ -0,0 +1,460 @@
+// @(#)cdr.cpp 1.2 95/11/04
+// Copyright 1994-1995 by Sun Microsystems Inc.
+// All Rights Reserved
+//
+// CDR: Encode/Decode basic machine data types
+//
+// Implementation of OMG "Common Data Representation" (CDR) ... there are
+// one routine each for byte/halfword/word/doubleword put/get, which adjust
+// to establish "natural" alignment (the bulk of the code) and then put or
+// get with byteswapping as needed.
+//
+// The implementation knows that native data formats are conformant with
+// OMG-IDL's (and hence CDR's) size requirements, and relies on the fact
+// that (for example) CORBA_Long is always four bytes long even if the
+// environment's "int" is a different size.
+//
+// char, octet 8 bits (1 byte)
+// short, unsigned short 16 bits (2 bytes)
+// long, unsigned long, float 32 bits (4 bytes)
+// double, (unsigned) long long 64 bits (8 bytes)
+// long double 128 bits (16 bytes)
+//
+// Moreover, this "knows" that the native 'char' represents ISO Latin/1
+// characters (an ASCII superset addressing Western European characters)
+// and that "double" and "float" comply with the IEEE standards. (The
+// "long double" may not be a native data type, though.)
+//
+// THREADING NOTE: "CDR" is a data structure which must be protected by
+// external critical sections. Like simpler numeric types, "CDR" instances
+// are accessed and modified atomically. This implementation is reentrant,
+// so that independent "CDR" values may be manipulated concurrently when
+// the underlying programming environment is itself reentrant.
+//
+
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+
+#include <corba/orb.hh>
+
+#include "runtime/debug.hh"
+#include "runtime/cdr.hh"
+
+
+//
+// ENCODING routines ... pad, store. Never swap. Padding uses
+// whatever value is already in the buffer.
+//
+CORBA_Boolean
+CDR::put_byte (
+ char c
+)
+{
+ if (remaining < sizeof (char) && grow (0) == CORBA_B_FALSE)
+ return CORBA_B_FALSE;
+
+ *next++ = (unsigned char) c;
+ remaining--;
+ return CORBA_B_TRUE;
+}
+
+
+CORBA_Boolean
+CDR::put_short (
+ CORBA_Short s
+)
+{
+ register unsigned char *tmp_next;
+ register unsigned temp;
+
+ //
+ // Adjust pointer and count of remaining bytes; maybe
+ // grow the buffer if there's not enough left
+ //
+ tmp_next = ptr_align_binary (next, SHORT_SIZE);
+ temp = SHORT_SIZE + (tmp_next - next);
+ if (temp > remaining) {
+ if (grow (0) == CORBA_B_FALSE)
+ return CORBA_B_FALSE;
+ tmp_next = next + temp - SHORT_SIZE;
+ }
+ remaining -= temp;
+
+ //
+ // copy the half word, native byte order
+ //
+ *(CORBA_Short *)tmp_next = s;
+ next = tmp_next + SHORT_SIZE;
+ return CORBA_B_TRUE;
+}
+
+CORBA_Boolean
+CDR::put_long (
+ CORBA_Long l
+)
+{
+ register unsigned char *tmp_next;
+ register unsigned temp;
+
+ //
+ // Adjust pointer and count of remaining bytes; maybe
+ // grow the buffer if there's not enough left
+ //
+ tmp_next = ptr_align_binary (next, LONG_SIZE);
+ temp = LONG_SIZE + (tmp_next - next);
+ if (temp > remaining) {
+ if (grow (0) == CORBA_B_FALSE)
+ return CORBA_B_FALSE;
+ tmp_next = next + temp - LONG_SIZE;
+ }
+ remaining -= temp;
+
+ //
+ // copy the word, native byte order
+ //
+ *(CORBA_Long *)tmp_next = l;
+
+ next = tmp_next + LONG_SIZE;
+ return CORBA_B_TRUE;
+}
+
+CORBA_Boolean
+CDR::put_longlong (
+ const CORBA_LongLong &ll
+)
+{
+ register unsigned char *tmp_next;
+ register unsigned temp;
+
+ //
+ // Adjust pointer and count of remaining bytes; maybe
+ // grow the buffer if there's not enough left
+ //
+ tmp_next = ptr_align_binary (next, LONGLONG_SIZE);
+ temp = LONGLONG_SIZE + (tmp_next - next);
+ if (temp > remaining) {
+ if (grow (0) == CORBA_B_FALSE)
+ return CORBA_B_FALSE;
+ tmp_next = next + temp - LONGLONG_SIZE;
+ }
+ remaining -= temp;
+
+ //
+ // copy the double word in "native" byte order.
+ //
+ *(CORBA_LongLong *)tmp_next = ll;
+ next = tmp_next + LONGLONG_SIZE;
+ return CORBA_B_TRUE;
+}
+
+CORBA_Boolean
+CDR::put_longdouble (
+ CORBA_LongDouble &ld
+)
+{
+ register unsigned char *tmp_next;
+ register unsigned temp;
+
+ //
+ // Adjust pointer and count of remaining bytes; maybe
+ // grow the buffer if there's not enough left
+ //
+ tmp_next = ptr_align_binary (next, LONGDOUBLE_SIZE);
+ temp = LONGDOUBLE_SIZE + (tmp_next - next);
+ if (temp > remaining) {
+ if (grow (0) == CORBA_B_FALSE)
+ return CORBA_B_FALSE;
+ tmp_next = next + temp - LONGDOUBLE_SIZE;
+ }
+ remaining -= temp;
+
+ //
+ // copy the long double in "native" byte order.
+ //
+ *(CORBA_LongDouble *)tmp_next = ld;
+ next = tmp_next + LONGDOUBLE_SIZE;
+ return CORBA_B_TRUE;
+}
+
+
+//
+// DECODING routines ... adjust pointer, then byteswap as needed.
+//
+
+CORBA_Boolean
+CDR::get_byte (
+ char &c
+)
+{
+ if (remaining < sizeof (char))
+ return CORBA_B_FALSE;
+
+ c = (char) *next++;
+ remaining--;
+ return CORBA_B_TRUE;
+}
+
+
+CORBA_Boolean
+CDR::get_short (
+ CORBA_Short &s
+)
+{
+ register unsigned char *tmp_next;
+ register unsigned temp;
+
+ //
+ // Adjust pointer and count of remaining bytes
+ //
+ tmp_next = ptr_align_binary (next, SHORT_SIZE);
+ temp = SHORT_SIZE + (tmp_next - next);
+ if (temp > remaining)
+ return CORBA_B_FALSE;
+ remaining -= temp;
+
+ //
+ // decode halfword, swapping as needed
+ //
+ if (!do_byteswap) {
+ s = *(CORBA_Short *)tmp_next;
+ next = tmp_next + SHORT_SIZE;
+ } else {
+ register unsigned char *sp = (unsigned char *) &s;
+
+ sp [1] = *tmp_next++;
+ sp [0] = *tmp_next++;
+ next = tmp_next;
+ }
+ return CORBA_B_TRUE;
+}
+
+CORBA_Boolean
+CDR::get_long (
+ CORBA_Long &l
+)
+{
+ register unsigned char *tmp_next;
+ register unsigned temp;
+
+ //
+ // Adjust pointer and count of remaining bytes
+ //
+ tmp_next = ptr_align_binary (next, LONG_SIZE);
+ temp = LONG_SIZE + (tmp_next - next);
+ if (temp > remaining)
+ return CORBA_B_FALSE;
+ remaining -= temp;
+
+ //
+ // decode word, swapping as needed
+ //
+ if (!do_byteswap) {
+ l = *(CORBA_Long *)tmp_next;
+ next = tmp_next + LONG_SIZE;
+ } else {
+ register unsigned char *lp = (unsigned char *) &l;
+
+ //
+ // NOTE: environment-specific speedups abound for this kind
+ // of stuff. This generic code takes advanage of none of them.
+ //
+ lp [3] = *tmp_next++;
+ lp [2] = *tmp_next++;
+ lp [1] = *tmp_next++;
+ lp [0] = *tmp_next++;
+ next = tmp_next;
+ }
+ return CORBA_B_TRUE;
+}
+
+CORBA_Boolean
+CDR::get_longlong (
+ CORBA_LongLong &ll
+)
+{
+ register unsigned char *tmp_next;
+ register unsigned temp;
+
+ //
+ // Adjust pointer and count of remaining bytes
+ //
+ tmp_next = ptr_align_binary (next, LONGLONG_SIZE);
+ temp = LONGLONG_SIZE + (tmp_next - next);
+ if (temp > remaining)
+ return CORBA_B_FALSE;
+ remaining -= temp;
+
+ //
+ // decode doubleword, swapping as needed
+ //
+ if (!do_byteswap) {
+ ll = *(CORBA_LongLong *)tmp_next;
+ next = tmp_next + LONGLONG_SIZE;
+ } else {
+ register unsigned char *llp = (unsigned char *) &ll;
+
+ //
+ // NOTE: environment-specific speedups abound for this kind
+ // of stuff. This generic code takes advanage of none of them.
+ //
+ llp [7] = *tmp_next++;
+ llp [6] = *tmp_next++;
+ llp [5] = *tmp_next++;
+ llp [4] = *tmp_next++;
+ llp [3] = *tmp_next++;
+ llp [2] = *tmp_next++;
+ llp [1] = *tmp_next++;
+ llp [0] = *tmp_next++;
+ next = tmp_next;
+ }
+ return CORBA_B_TRUE;
+}
+
+
+CORBA_Boolean
+CDR::get_longdouble (
+ CORBA_LongDouble &ld
+)
+{
+ register unsigned char *tmp_next;
+ register unsigned temp;
+
+ //
+ // Adjust pointer and count of remaining bytes
+ //
+ tmp_next = ptr_align_binary (next, LONGDOUBLE_SIZE);
+ temp = LONGDOUBLE_SIZE + (tmp_next - next);
+ if (temp > remaining)
+ return CORBA_B_FALSE;
+ remaining -= temp;
+
+ //
+ // copy the long double, swapping bytes as needed
+ //
+ if (!do_byteswap) {
+ ld = *(CORBA_LongDouble *)tmp_next;
+ next = tmp_next + LONGDOUBLE_SIZE;
+ } else {
+ register unsigned char *ldp = (unsigned char *) &ld;
+
+ //
+ // NOTE: this is a single SPARC V9 instruction
+ //
+ ldp [15] = *tmp_next++;
+ ldp [14] = *tmp_next++;
+ ldp [13] = *tmp_next++;
+ ldp [12] = *tmp_next++;
+ ldp [11] = *tmp_next++;
+ ldp [10] = *tmp_next++;
+ ldp [ 9] = *tmp_next++;
+ ldp [ 8] = *tmp_next++;
+ ldp [ 7] = *tmp_next++;
+ ldp [ 6] = *tmp_next++;
+ ldp [ 5] = *tmp_next++;
+ ldp [ 4] = *tmp_next++;
+ ldp [ 3] = *tmp_next++;
+ ldp [ 2] = *tmp_next++;
+ ldp [ 1] = *tmp_next++;
+ ldp [ 0] = *tmp_next++;
+ next = tmp_next;
+ }
+ return CORBA_B_TRUE;
+}
+
+
+CORBA_Boolean
+CDR::skip_string () // ISO/1 or octet string
+{
+ CORBA_ULong len;
+
+ if (get_ulong (len) == CORBA_B_FALSE || len > remaining)
+ return CORBA_B_FALSE; // buffer's changed
+
+ next += (unsigned) len;
+ remaining -= (unsigned) len;
+ return CORBA_B_TRUE;
+}
+
+
+//
+// Grow the CDR buffer, either to a known size (incoming message) or
+// by a standard increment (creating outgoing message).
+//
+// We can't use realloc() because of a constraint that the part of the
+// buffer into which we marshal be aligned according to MAX_ALIGNMENT,
+// which can be a stronger requirement than malloc/realloc places on
+// buffer. This makes growing a buffer on the encode side costly, since
+// it can need to be done repetitively and copies more data each time.
+//
+// NOTE: this code knows about what's involved in the constructor and
+// destructor, as it needs to invoke the constructor and do what the
+// destructor would do (and not in the normal order). It also knows
+// all other state that's significant. Change with care!
+//
+// NOTE: arguably this is a good place to ensure that the memory's zeroed
+// out to comply with Orange Book C2 "object reuse" (meaning data, like
+// I/O buffers) policy. IIOP doesn't mandate such policies though.
+//
+CORBA_Boolean
+CDR::grow (size_t newsize)
+{
+ unsigned char *old_realbuf, *oldbuf;
+ size_t offset;
+ int old_do_swap = do_byteswap;
+
+ //
+ // Iff old buffer was heap allocated, it gets freed soon. In any case,
+ // we need to know which bytes that have been marshaled or read thus
+ // far, so they'll also be in the newly grown buffer.
+ //
+ if (do_free)
+ old_realbuf = real_buffer;
+ else
+ old_realbuf = 0;
+ oldbuf = buffer;
+ assert ((next - buffer) < UINT_MAX);
+ offset = (unsigned) (next - buffer);
+
+ //
+ // Calculate the new buffer's length; if growing for encode, we
+ // don't grow in "small" chunks because of the cost.
+ //
+ size_t new_len;
+
+ if (newsize == 0) {
+ if (length < 4096)
+ new_len = length + 4096;
+ else
+ new_len = length * 2;
+ } else if (newsize <= length) {
+ return CORBA_B_TRUE;
+ } else
+ new_len = newsize;
+
+ //
+ // Get a new buffer that's adequately aligned, and use it to
+ // reinitialize ourselves with the "free this buffer later" flag.
+ //
+ unsigned char *new_buffer;
+
+ new_len += MAX_ALIGNMENT - 1;
+ if ((new_buffer = (unsigned char *) malloc (new_len)) == 0)
+ return CORBA_B_FALSE;
+
+ (void) new (this) CDR (new_buffer, new_len, MY_BYTE_SEX, 1);
+
+ //
+ // Now restore all the relevant old state that we saved earlier,
+ // and free the original buffer if needed. (The first buffer is
+ // normally stack-allocated and so mustn't be freed this way.)
+ //
+ do_byteswap = old_do_swap;
+ memcpy (buffer, oldbuf, offset);
+ skip_bytes (offset);
+
+ if (old_realbuf)
+ free ((char *) old_realbuf);
+
+ return CORBA_B_TRUE;
+}
diff --git a/TAO/IIOP/lib/runtime/cdr.hh b/TAO/IIOP/lib/runtime/cdr.hh
new file mode 100644
index 00000000000..61120e0d247
--- /dev/null
+++ b/TAO/IIOP/lib/runtime/cdr.hh
@@ -0,0 +1,360 @@
+// @(#)cdr.hh 1.2 95/11/04
+// Copyright 1994-1995 by Sun Microsystems Inc.
+// All Rights Reserved
+//
+// CDR: Common Data Representation (CDR) marshaling streams.
+//
+// This implementation assumes that the native numeric representation
+// is two's complement for integers, IEEE single/double for floats. Also
+// that characters are in ISO Latin/1.
+//
+// Note that CDR itself makes no such assumptions, but this implementation
+// makes such assumptions for reasons of efficiency. Careful enhancements
+// could preserve that efficiency where the assumptions are true, yet
+// still allow the code to work when they aren't true.
+//
+// The implementation expects that buffers are aligned according to the
+// strongest CDR alignment restriction.
+//
+// NOTE: this does everything "CDR 1.1" does ... that is, it supports
+// the five extended OMG-IDL data types in UNO Appendix A, which provide
+// richer arithmetic types (64 bit integers, "quad precision" FP) and
+// UNICODE-based characters and strings. Those types are not standard
+// parts of OMG-IDL at this time.
+//
+// THREADING NOTE: CDR data structures must be protected against
+// concurrent access by their owning thread.
+//
+
+
+#ifndef _CDR_HH
+#define _CDR_HH
+
+#include <assert.h>
+
+#include <corba/orb.hh>
+
+#include <runtime/align.hh>
+
+
+//
+// Identify byte order ... this is basically dependent on processor, but some
+// processors support different byte orders (e.g. MIPS, UltraSPARC, PowerPC)
+// as required for different software environments.
+//
+// We currently get this information through the "configure" script, which
+// must (!!) be run before source code can be correctly compiled; too bad
+// we have no way to ensure that the machine on which "configure" ran is
+// the same as the one on which "make" will be run.
+//
+
+#undef LITTLE_ENDIAN
+#undef BIG_ENDIAN
+#undef MY_BYTE_SEX
+
+//
+// PC compilers normally don't assume they'll be given code that runs
+// on other architectures; cope with that limitation once here, so that
+// only truly compiler-specific code needs to use their predefines.
+//
+// NOTE: should really be using "__i386" to be strictly ANSI compliant.
+//
+#if defined (__BORLANDC__) || defined (_M_IX86)
+# if !defined (i386)
+# define i386
+# undef WORDS_BIGENDIAN
+# endif
+#endif
+
+//
+// Yes, we assume no bizarre mixed-endian "nuxi" machine, just as we
+// assume only IEEE arithmetic.
+//
+#if defined (WORDS_BIGENDIAN)
+# define BIG_ENDIAN
+# define MY_BYTE_SEX 0
+#else
+# define LITTLE_ENDIAN
+# define MY_BYTE_SEX 1
+#endif
+
+//
+// The core marshaling primitive: a memory buffer, into which all the basic
+// OMG-IDL datatypes can be placed ... or from which they can be retreived.
+//
+// A particularly useful static member function for this buffer is an
+// interpretive encoding routine, usable as a typecode interpreter callback.
+// Ditto for decoding. These are used to support all OMG-IDL datatypes,
+// even those not supported directly by put/get primitives.
+//
+// Struct members are intentionally exposed; the functionality of this
+// class, and hence the appropriate abstactions for them, hasn't quite
+// settled down enough to settle on fast abstractions that let data be
+// hidden without pointlessly sacrificing speed.
+//
+struct _EXPCLASS CDR
+{
+ //
+ // Define these constants as enums to ensure they get inlined
+ // and to avoid pointless static memory allocations.
+ //
+ enum {
+ //
+ // Constants defined by the CDR protocol. Note that some of these
+ // get reused as part of the standard binary format: unsigned is the
+ // same size as its signed cousin, float is CDR_LONG_SIZE, and double
+ // is CDR_LONGLONG_SIZE.
+ //
+ SHORT_SIZE = 2,
+ LONG_SIZE = 4,
+ LONGLONG_SIZE = 8,
+ LONGDOUBLE_SIZE = 16,
+
+ //
+ // maximal CDR 1.1 alignment: "quad precision" FP
+ // (i.e. "long double", size as above)
+ //
+ MAX_ALIGNMENT = 16,
+
+ //
+ // Default buffer size for request/response messages. These are
+ // normally stack-allocated, and tuning may cause you to want to
+ // change this value. The best value depends on your particular
+ // application mix; you can also change how buffers grow(). Most
+ // remote invocations (statistically) are "small", and the default
+ // used here is perhaps larger than most such messages.
+ //
+ // If this size is "too small" you need to heap-allocate buffers too
+ // often. "Too large" is mostly a waste of stackspace, but stack
+ // frames as large as the system page size (often 4Kb) can easily
+ // overrun the "redzone" at the bottom of most VM-based stacks.
+ //
+ DEFAULT_BUFSIZE = 1430 // Ethernet MTU, less headers
+ };
+
+ //
+ // ENCODING SUPPORT ... adjust pointers as needed, then store in the
+ // native byte order.
+ //
+ // There exist only routines to put byte, halfword (2 bytes), word
+ // (4 bytes), doubleword (8 bytes) and quadword (16 byte) entities,
+ // plus the interpretive encoder.
+ //
+
+ CORBA_Boolean put_byte (char c);
+ CORBA_Boolean put_short (CORBA_Short s);
+ CORBA_Boolean put_long (CORBA_Long l);
+ CORBA_Boolean put_longlong (const CORBA_LongLong &ll);
+
+ inline CORBA_Boolean put_char (CORBA_Char c)
+ { return put_byte ((char) c); }
+ inline CORBA_Boolean put_wchar (wchar_t wc)
+ {
+ //
+ // "wchar_t" isn't always 2 bytes, such
+ // systems might need further conversion
+ // (e.g. hosts with multibyte characters
+ // native, rather than UNICODE)
+ //
+ return put_short ((short)wc);
+ }
+
+ inline CORBA_Boolean put_boolean (CORBA_Boolean b)
+ { return put_byte ((char)
+ (b != CORBA_B_FALSE)); }
+
+ inline CORBA_Boolean put_octet (CORBA_Octet o)
+ { return put_byte ((char) o); }
+ inline CORBA_Boolean put_ushort (CORBA_UShort s)
+ { return put_short ((CORBA_Short) s); }
+ inline CORBA_Boolean put_ulong (CORBA_ULong l)
+ { return put_long ((CORBA_Long) l); }
+ inline CORBA_Boolean put_ulonglong (const CORBA_ULongLong &ll)
+ { return
+ put_longlong ((CORBA_LongLong &) ll); }
+
+ inline CORBA_Boolean put_float (float f)
+ { return put_long (*(CORBA_Long *) &f); }
+ inline CORBA_Boolean put_double (const double &d)
+ { return
+ put_longlong (*(CORBA_LongLong *) &d); }
+
+ CORBA_Boolean put_longdouble (CORBA_LongDouble &ld);
+
+ //
+ // marshaling interpreter ... 'context' really points to a CDR.
+ //
+ static CORBA_TypeCode::traverse_status
+ encoder (
+ CORBA_TypeCode_ptr tc,
+ const void *data,
+ const void *,
+ void *context,
+ CORBA_Environment &env
+ );
+
+ //
+ // DECODING SUPPORT ... same assumptions are made as above, but a
+ // flag is tested to determine whether decode should byteswap or not.
+ // It's cheaper to do it that way than to use virtual functions.
+ //
+
+ CORBA_Boolean get_byte (char &c);
+ CORBA_Boolean get_short (CORBA_Short &s);
+ CORBA_Boolean get_long (CORBA_Long &l);
+ CORBA_Boolean get_longlong (CORBA_LongLong &ll);
+
+ inline CORBA_Boolean get_char (CORBA_Char &o)
+ { return get_byte ((char &) o); }
+ inline CORBA_Boolean get_wchar (wchar_t &wc)
+ {
+ short s;
+
+ //
+ // wchar_t isn't always "short"
+ //
+ CORBA_Boolean retval = get_short (s);
+ wc = s;
+ return retval;
+ }
+
+ inline CORBA_Boolean get_boolean (CORBA_Boolean &b)
+ {
+ CORBA_Char c;
+
+ //
+ // CORBA_Boolean is rarely 'char'
+ //
+ CORBA_Boolean retval = get_char (c);
+ b = (c == 1);
+ return retval;
+ }
+
+ inline CORBA_Boolean get_octet (CORBA_Octet &o)
+ { return get_byte ((char &) o); }
+ inline CORBA_Boolean get_ushort (CORBA_UShort &s)
+ { return get_short ((short&) s); }
+ inline CORBA_Boolean get_ulong (CORBA_ULong &l)
+ { return get_long ((CORBA_Long &) l); }
+ inline CORBA_Boolean get_ulonglong (const CORBA_ULongLong &ull)
+ { return
+ get_longlong ((CORBA_LongLong &) ull); }
+
+ inline CORBA_Boolean get_float (float &f)
+ { return get_long ((CORBA_Long &) f); }
+ inline CORBA_Boolean get_double (double &d)
+ { return
+ get_longlong ((CORBA_LongLong &) d); }
+
+ CORBA_Boolean get_longdouble (CORBA_LongDouble &ld);
+
+ //
+ // unmarshaling interpreter ... 'context' really points to a CDR.
+ //
+ static CORBA_TypeCode::traverse_status
+ decoder (
+ CORBA_TypeCode_ptr tc,
+ const void *data,
+ const void *,
+ void *context,
+ CORBA_Environment &env
+ );
+
+ //
+ // Constructor ... buffer must be aligned for the strictest
+ // CDR alignment requirement, since the algorithms used here
+ // only maintain alignment with respect to &buffer [0].
+ //
+ // Yes, that complicates the grow() primitive.
+ //
+ CDR (
+ unsigned char *buf = 0,
+ unsigned len = 0,
+ int byte_order = MY_BYTE_SEX,
+ int consume_buf = 0
+ ) :
+ real_buffer (buf),
+ do_free (consume_buf),
+ do_byteswap (byte_order != MY_BYTE_SEX)
+ {
+ ptr_arith_t temp = (ptr_arith_t) buf;
+
+ temp += MAX_ALIGNMENT - 1;
+ temp &= ~((ptr_arith_t) MAX_ALIGNMENT - 1);
+ buffer = next = (unsigned char *) temp;
+
+ length = remaining
+ = len - (unsigned) (buffer - real_buffer);
+ }
+
+ ~CDR ()
+ { if (do_free) delete real_buffer; }
+
+ void *operator new (size_t, void *_FAR p)
+ { return p; }
+ void *operator new (size_t s)
+ { return ::operator new (s); }
+ void operator delete (void *p)
+ { ::operator delete (p); }
+
+ //
+ // Used mostly when interpreting typecodes. These may change the
+ // state of a CDR buffer even when errors are reported.
+ //
+ CORBA_Boolean skip_string ();
+ CORBA_Boolean skip_bytes (unsigned nbytes)
+ {
+ if (remaining < nbytes)
+ return CORBA_B_FALSE;
+ remaining -= nbytes;
+ next += nbytes;
+ return CORBA_B_TRUE;
+ }
+
+ //
+ // Also used when interpreting typecodes, but more generally
+ // when getting ready to read from encapsulations. In such
+ // cases the buffer alignment guarantees must be provided by
+ // the caller, this code doesn't verify them. These streams
+ // are "read only".
+ //
+ void setup_encapsulation (
+ unsigned char *buf,
+ unsigned len
+ )
+ {
+ next = buf + 1;
+ remaining = len - 1;
+ do_byteswap = (*buf != MY_BYTE_SEX);
+ do_free = 0;
+ }
+
+ //
+ // Grow the buffer to the identified size ... if it's zero, just
+ // grow it by a standard quantum (e.g. when encoding we can't know
+ // in advance how big it will need to become).
+ //
+ CORBA_Boolean grow (size_t newlength);
+
+ //
+ // Some code needs to know how much is left on encode or decode
+ //
+ size_t bytes_remaining () { return remaining; }
+
+ // private:
+ //
+ // DATA MEMBERS ...
+ //
+ unsigned char *next; // next data goes here
+ size_t remaining; // space left
+
+ unsigned char *real_buffer; // maybe not aligned
+ int do_free;
+
+ unsigned char *buffer;
+ size_t length;
+
+ int do_byteswap; // decode ONLY
+};
+
+#endif // _CDR_HH
diff --git a/TAO/IIOP/lib/runtime/corbacom.cpp b/TAO/IIOP/lib/runtime/corbacom.cpp
new file mode 100644
index 00000000000..b02bcbc149f
--- /dev/null
+++ b/TAO/IIOP/lib/runtime/corbacom.cpp
@@ -0,0 +1,99 @@
+// @(#)corbacom.cpp 1.1 95/08/31
+// Copyright 1994-1995 by Sun Microsystems Inc.
+// All Rights Reserved
+//
+// ORB: support for primitive data types
+//
+
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+#include <corba/orb.hh>
+
+#if defined (HAVE_WIDEC_H)
+# include <widec.h>
+#endif
+
+
+//
+// String utility support; this can need to be integrated with
+// the ORB's own memory allocation subsystem.
+//
+CORBA_String
+CORBA_string_alloc (CORBA_ULong len)
+{
+ return new CORBA_Char [(size_t)(len + 1)];
+}
+
+CORBA_String
+CORBA_string_copy (const CORBA_Char *const str)
+{
+ if (!str)
+ return 0;
+
+ CORBA_String retval = CORBA_string_alloc (strlen (str));
+
+ return strcpy (retval, str);
+}
+
+void
+CORBA_string_free (CORBA_Char *const str)
+{
+ delete str;
+}
+
+
+#if !defined (HAVE_WIDEC_H)
+//
+// NOTE: assuming that these don't exist unless they're declared in
+// that header file ...
+//
+
+extern "C" unsigned
+wslen (const wchar_t *str)
+{
+ unsigned len = 0;
+
+ while (*str++)
+ len++;
+ return len;
+}
+
+extern "C" wchar_t *
+wscpy (wchar_t *dest, const wchar_t *src)
+{
+ wchar_t *retval = dest;
+
+ while ((*dest++ = *src++) != 0)
+ continue;
+ return retval;
+}
+
+#endif // HAVE_WIDEC_H
+
+//
+// Wide Character string utility support; this can need to be
+// integrated with the ORB's own memory allocation subsystem.
+//
+CORBA_WString
+CORBA_wstring_alloc (CORBA_ULong len)
+{
+ return new CORBA_WChar [(size_t) (len + 1)];
+}
+
+CORBA_WString
+CORBA_wstring_copy (const CORBA_WChar *const str)
+{
+ if (*str)
+ return 0;
+
+ CORBA_WString retval = CORBA_wstring_alloc (wslen (str));
+ return wscpy (retval, str);
+}
+
+void
+CORBA_wstring_free (CORBA_WChar *const str)
+{
+ delete str;
+}
+
diff --git a/TAO/IIOP/lib/runtime/debug.cpp b/TAO/IIOP/lib/runtime/debug.cpp
new file mode 100644
index 00000000000..a5e1fe4138d
--- /dev/null
+++ b/TAO/IIOP/lib/runtime/debug.cpp
@@ -0,0 +1,337 @@
+// @(#)debug.cpp 1.3 95/10/02
+// Copyright 1994-1995 by Sun Microsystems Inc.
+// All Rights Reserved
+//
+// ORB: Simple debug/trace support
+//
+// THREADING NOTE: the global values here (debug_{level,filter,stream) are
+// assumed to be modified "safely", e.g. in the main thread as part of
+// process initialization. They are treated as immutable values through
+// all of this debuging package.
+//
+// XXX on Windows, make it always use OutputDebugString() instead of stdio
+//
+
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+#include <corba/orb.hh>
+
+#include "runtime/thread.hh"
+#include "runtime/debug.hh"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#if unix
+#include <sys/types.h>
+
+#elif defined (_WIN32)
+# include <windows.h>
+
+#endif
+
+
+
+
+#ifndef _POSIX_THREADS // _POSIX_THREAD_SAFE_FUNCTIONS implied
+#define flockfile(f)
+#define funlockfile(f)
+#endif // _POSIX_THREADS
+
+unsigned debug_level = 0;
+char *debug_filter = "l";
+static FILE *debug_stream = stderr;
+
+
+//
+// The rest of this file is not needed without -DDEBUG, and unless the
+// vfprintf() call is available it can't work.
+//
+// NOTE: some older platforms have "_doprnt" that provides much the
+// same functionality ... this could be modified to use that routine
+// where it's available.
+//
+#if defined (DEBUG) && defined (HAVE_VPRINTF)
+
+//
+// Support for prefixing debug messages with process ID and, if threaded,
+// the thread ID. This lets messages from different sources be safely
+// disentangled, even though they're interspersed in the output stream.
+//
+static pid_t my_pid;
+
+#if unix
+
+#ifdef _POSIX_THREADS
+//
+// Use POSIX initialization support to initialize just once.
+//
+static pthread_once_t debug_init = PTHREAD_ONCE_INIT;
+
+#define setup() pthread_once(&debug_init, setup_once)
+
+static void
+setup_once ()
+{
+ my_pid = getpid ();
+}
+
+static void
+emit_prefix (FILE *stream)
+{
+ pthread_t self = pthread_self ();
+
+ fprintf (stream, "p%ld t%ld: ", (long) my_pid, (long) self);
+}
+
+#else // !defined (_POSIX_THREADS)
+
+//
+// Without threads, guard initialization so it can be repeated,
+// and don't emit the thread ID in the messages.
+//
+static void
+setup ()
+{
+ if (my_pid == 0) {
+ my_pid = getpid ();
+ // other setup goes here
+ }
+}
+
+#define emit_prefix(stream) fprintf (stream, "p%ld: ", (long) my_pid)
+#endif // !_POSIX_THREADS
+
+#elif defined (_WIN32)
+
+//
+// Not all implementations of Win32 have threads, but in any case
+// this code doesn't yet support Win32 threads.
+//
+static void
+setup ()
+{
+ if (my_pid == 0) {
+ my_pid = GetCurrentProcessId ();
+ // other setup goes here
+ }
+}
+
+#define emit_prefix(stream) fprintf (stream, "p%ld: ", my_pid)
+
+#else
+
+# error "unknown OS platform"
+#endif // OS-specific initialization
+
+
+void _EXPFUNC
+dmsg_filter (
+ const char *_FAR categories,
+ const char *_FAR fmt,
+ ...
+)
+{
+ const char *cp;
+
+ if (!categories || !debug_filter)
+ return;
+
+ if (*debug_filter != '*') { // filter with "*" --> all pass
+ for (cp = categories; *cp; cp++)
+ if (strchr (debug_filter, *cp) != 0)
+ break;
+
+ if (!*cp)
+ return;
+ }
+
+ va_list ap;
+
+ setup ();
+ flockfile (debug_stream);
+ emit_prefix (debug_stream);
+
+ switch (*cp) { // standard categories
+ case 'l': fprintf (debug_stream, "(LEAK) "); break;
+ }
+ va_start (ap, fmt);
+ vfprintf (debug_stream, fmt, ap);
+ va_end (ap);
+ if (strchr (fmt, '\n') == 0)
+ fprintf (debug_stream, "\n");
+ funlockfile (debug_stream);
+
+#if defined (_WIN32)
+ OutputDebugString ("called dmsg_filter\n"); // experimental
+#endif
+}
+
+void _EXPFUNC
+dmsg_filter (unsigned level, const char *_FAR fmt, ...)
+{
+ if (level > debug_level)
+ return;
+
+ va_list ap;
+
+ setup ();
+ flockfile (debug_stream);
+ emit_prefix (debug_stream);
+ va_start (ap, fmt);
+ vfprintf (debug_stream, fmt, ap);
+ va_end (ap);
+ if (strchr (fmt, '\n') == 0)
+ fprintf (debug_stream, "\n");
+ funlockfile (debug_stream);
+
+#if defined (_WIN32)
+ OutputDebugString ("called dmsg_filter\n"); // experimental
+#endif
+}
+
+void _EXPFUNC
+dmsg_v (const char *_FAR fmt, ...)
+{
+ va_list ap;
+
+ setup ();
+ flockfile (debug_stream);
+ emit_prefix (debug_stream);
+ va_start (ap, fmt);
+ vfprintf (debug_stream, fmt, ap);
+ va_end (ap);
+ if (strchr (fmt, '\n') == 0)
+ fprintf (debug_stream, "\n");
+ funlockfile (debug_stream);
+
+#if defined (_WIN32)
+ OutputDebugString ("called dmsg_v\n"); // experimental
+#endif
+}
+
+void _EXPFUNC
+_dmsg_x (
+ CORBA_Environment _FAR &env,
+ const char *_FAR info
+)
+{
+ const CORBA_Exception *ex = env.exception ();
+
+ setup ();
+ flockfile (debug_stream);
+ emit_prefix (debug_stream);
+ fprintf (debug_stream, "exception '%s' at '%s'\n", ex->id (), info);
+ if (env.exception_type () == SYSTEM_EXCEPTION) {
+ CORBA_SystemException *sysex = (CORBA_SystemException *)ex;
+
+ emit_prefix (debug_stream);
+ fprintf (debug_stream, "minor %#lx, completion %#lx\n",
+ sysex->minor (), (long) sysex->completion ());
+ }
+ funlockfile (debug_stream);
+
+#if defined (_WIN32)
+ OutputDebugString ("called _dmsg_x\n"); // experimental
+#endif
+}
+
+void _EXPFUNC
+dmsg_opaque (
+ char *_FAR label,
+ unsigned char *_FAR buffer,
+ unsigned long len)
+{
+ setup ();
+ flockfile (debug_stream);
+ emit_prefix (debug_stream);
+ fprintf (debug_stream, "%s ", label);
+
+ if (len == 0 || !buffer)
+ fprintf (debug_stream, "(empty)");
+ else if (len > UINT_MAX)
+ fprintf (debug_stream, "Oversized opaque data: %ld bytes", len);
+ else {
+ unsigned i;
+
+ for (i = 0; i < len; i++)
+ if (!isprint (buffer [i]))
+ break;
+
+ if (i < len) {
+ if (len >= 20)
+ fprintf (debug_stream, "%ld bytes binary data", len);
+ else {
+ fprintf (debug_stream, "binary data {%2X", buffer [0]);
+ for (i = 1; i < len; i++)
+ fprintf (debug_stream, ", %2x", buffer [i]);
+ fprintf (debug_stream, "}");
+ }
+ } else {
+ if (len >= 50)
+ fprintf (debug_stream, "%ld bytes string data", len);
+ else
+ fprintf (debug_stream, "string data { \"%.*s\" }",
+ (int) len, buffer);
+ }
+ }
+ fprintf (debug_stream, "\n");
+ funlockfile (debug_stream);
+
+#if defined (_WIN32)
+ OutputDebugString ("called dmsg_opaque\n"); // experimental
+#endif
+}
+
+void _EXPFUNC
+dmsg_opaque_full (
+ char *_FAR label,
+ const unsigned char *_FAR buffer,
+ unsigned long len)
+{
+ setup ();
+ flockfile (debug_stream);
+
+ emit_prefix (debug_stream);
+ fprintf (debug_stream, "%s ", label);
+
+ if (len == 0 || !buffer)
+ fprintf (debug_stream, "(empty)");
+ else {
+ unsigned i;
+
+ for (i = 0; i < len; i++)
+ {
+ if (i == 0)
+ fprintf(debug_stream, "\nhex: ");
+ else if ((i % 32) == 0)
+ fprintf(debug_stream, "\n ");
+ else if ((i % 4) == 0)
+ fprintf(debug_stream, " ");
+ fprintf(debug_stream, "%02x", buffer[i]);
+ }
+ for (i = 0; i < len; i++)
+ {
+ if (i == 0)
+ fprintf(debug_stream, "\nchars: ");
+ else if ((i % 32) == 0)
+ fprintf(debug_stream, "\n ");
+ else if ((i % 4) == 0)
+ fprintf(debug_stream, " ");
+ fprintf(debug_stream, "%c ",
+ (isprint(buffer[i]) ? buffer[i] : '?'));
+
+ }
+ fprintf(debug_stream, "\n");
+ }
+ fprintf (debug_stream, "\n");
+ funlockfile (debug_stream);
+
+#if defined (_WIN32)
+ OutputDebugString ("called dmsg_opaque_full\n"); // experimental
+#endif
+}
+
+#endif // DEBUG && HAVE_VPRINTF
diff --git a/TAO/IIOP/lib/runtime/debug.hh b/TAO/IIOP/lib/runtime/debug.hh
new file mode 100644
index 00000000000..55662c37a88
--- /dev/null
+++ b/TAO/IIOP/lib/runtime/debug.hh
@@ -0,0 +1,104 @@
+// @(#)debug.hh 1.1 95/08/31
+// Copyright 1994-1995 by Sun Microsystems Inc.
+// All Rights Reserved
+//
+// debug/trace support.
+//
+
+#ifndef __DEBUG_HH
+#define __DEBUG_HH
+
+#ifndef DECLARED_STRERROR
+extern "C" char *strerror (int);
+#endif // DECLARED_STRERROR
+
+//
+// These are global to simplify is use by other code, very much
+// in particular by getopt and related argument-parsing code
+//
+// THREADING NOTE: don't set them except in an unthreaded environment
+// such as process initialization. They're treated as immutable.
+//
+extern unsigned debug_level; // 0 to ??; higher == more
+extern char *debug_filter; // set by getopt
+
+
+//
+// These are just simple 0, 1, and 2 argument messages that
+// will appear when debugging's enabled, regardless of category.
+// They also just compile out painlessly.
+//
+#ifdef DEBUG
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+// 1, 2, 3 argument messages -- generic
+#define dmsg(s) { if (debug_level) dmsg_v (s); }
+#define dmsg1(s,a1) { if (debug_level) dmsg_v (s, a1); }
+#define dmsg2(s,a1,a2) { if (debug_level) dmsg_v (s, a1, a2); }
+
+// dump CORBA_Exception, if any, with id tag
+#define dexc(env,s) { if (debug_level && env.exception ()) \
+ _dmsg_x (env, s); }
+
+// dump POSIX error indication, if any, with ID tag
+#define dperror(str) { if (debug_level) dmsg_v ("%s: %s", \
+ str, strerror (errno)); }
+
+// dump socket error indication, if any, with ID tag
+#ifdef _WINSOCKAPI_
+#define dsockerr(s) { if (debug_level) dmsg_v ("%s: winsock error %d", \
+ s, WSAGetLastError()); }
+#else
+#define dsockerr(s) dperror(s)
+#endif
+
+#else // !DEBUG
+#define dmsg(s) { }
+#define dmsg1(s,a1) { }
+#define dmsg2(s,a1,a2) { }
+
+#define dexc(env, s) { }
+#define dperror(s) { }
+#define dsockerr(s) { }
+#endif // DEBUG
+
+
+//
+// These don't compile out; you must #ifdef them. This is done
+// intentionally since CPP macros have severe limits, and varargs
+// (or lack thereof) is one of them.
+//
+
+#ifdef DEBUG
+//
+// This is like an fprintf statement except the filter is a set of
+// characters (string). If debug_level is nonzero and any characters
+// in that string are in the "debug_filter" string, the message
+// is then printed. Assign thosee characters as needed.
+//
+extern void _EXPFUNC dmsg_filter (const char *_FAR filter,
+ const char *_FAR fmt, ...);
+
+//
+// Filter according to debug_level instead of category.
+// (For speed, test against debug_level directly.)
+//
+extern void _EXPFUNC dmsg_filter (unsigned level, const char *_FAR fmt, ...);
+
+//
+// General varargs debug message printer, no filtering
+//
+extern void _EXPFUNC dmsg_v (const char *_FAR fmt, ...);
+extern void _EXPFUNC _dmsg_x (CORBA_Environment _FAR &env,
+ const char *_FAR info);
+extern void _EXPFUNC dmsg_opaque (char *_FAR label,
+ unsigned char *_FAR buffer,
+ unsigned long len);
+extern void _EXPFUNC dmsg_opaque_full (char *_FAR label,
+ const unsigned char *_FAR buffer,
+ unsigned long len);
+#endif // DEBUG
+
+#endif // __DEBUG_HH
diff --git a/TAO/IIOP/lib/runtime/except.cpp b/TAO/IIOP/lib/runtime/except.cpp
new file mode 100644
index 00000000000..3c21f0c1a53
--- /dev/null
+++ b/TAO/IIOP/lib/runtime/except.cpp
@@ -0,0 +1,535 @@
+// @(#)except.cpp 1.11 95/11/04
+// Copyright 1994-1995 by Sun Microsystems Inc.
+// All Rights Reserved
+//
+// ORB: Exception handling support
+//
+// THREADING NOTE: calling thread handles mutual exclusion policy
+// on all of these data structures.
+//
+
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include <corba/orb.hh>
+
+#include "runtime/cdr.hh"
+#include "runtime/debug.hh"
+#include "runtime/thread.hh"
+
+#include <initguid.h>
+
+#if defined (HAVE_WIDEC_H)
+# include <widec.h>
+#endif
+
+#ifdef _POSIX_THREADS
+//
+// If POSIX threads are available, set up lock covering refcounts.
+//
+static pthread_mutex_t except_lock = PTHREAD_MUTEX_INITIALIZER;
+
+#else
+
+ // stub out these _POSIX_THREAD_SAFE_FUNCTIONS
+# define flockfile(f)
+# define funlockfile(f)
+#endif // _POSIX_THREADS
+
+
+
+
+// {77420082-F276-11ce-9598-0000C07CA898}
+DEFINE_GUID (IID_CORBA_Exception,
+0x77420082, 0xf276, 0x11ce, 0x95, 0x98, 0x0, 0x0, 0xc0, 0x7c, 0xa8, 0x98);
+
+// {77420083-F276-11ce-9598-0000C07CA898}
+DEFINE_GUID (IID_CORBA_UserException,
+0x77420083, 0xf276, 0x11ce, 0x95, 0x98, 0x0, 0x0, 0xc0, 0x7c, 0xa8, 0x98);
+
+// {77420084-F276-11ce-9598-0000C07CA898}
+DEFINE_GUID (IID_CORBA_SystemException,
+0x77420084, 0xf276, 0x11ce, 0x95, 0x98, 0x0, 0x0, 0xc0, 0x7c, 0xa8, 0x98);
+
+
+CORBA_Exception::CORBA_Exception (
+ CORBA_TypeCode_ptr tc
+) :
+ _type (tc),
+ _refcnt (1)
+{
+ if (_type)
+ _type->AddRef ();
+ assert (_type != 0);
+ assert (_refcnt > 0);
+}
+
+CORBA_Exception::CORBA_Exception (
+ const CORBA_Exception &src
+) :
+ _type (src._type),
+ _refcnt (1)
+{
+ if (_type)
+ _type->AddRef ();
+ assert (_type != 0);
+ assert (_refcnt > 0);
+}
+
+//
+// NOTE: It's this code, not anything defined in a subclass, which
+// is responsible for releasing any storage owned by the exception.
+// It can do this because it's got the typecode.
+//
+CORBA_Exception::~CORBA_Exception ()
+{
+ assert (_refcnt == 0);
+ assert (_type != 0);
+
+ assert (1 == 2);
+}
+
+CORBA_Exception &
+CORBA_Exception::operator = (
+ const CORBA_Exception &src
+)
+{
+ if (_type)
+ _type->Release ();
+ _type = src._type;
+ if (_type)
+ _type->AddRef ();
+ assert (_type != 0);
+ assert (_refcnt > 0);
+
+ return *this;
+}
+
+const CORBA_String
+CORBA_Exception::id () const
+{
+ CORBA_Environment env;
+
+ assert (_refcnt > 0);
+ if (_type)
+ return _type->id (env);
+ else
+ return 0;
+}
+
+const CORBA_TypeCode_ptr
+CORBA_Exception::type () const
+{
+ assert (_refcnt > 0);
+ return _type;
+}
+
+//
+// For COM -- IUnKnown operations
+//
+ULONG
+__stdcall
+CORBA_Exception::AddRef ()
+{
+#ifdef _POSIX_THREADS
+ Critical region (&except_lock);
+#endif
+
+ assert (_refcnt > 0);
+ return ++_refcnt;
+}
+
+ULONG
+__stdcall
+CORBA_Exception::Release ()
+{
+#ifdef _POSIX_THREADS
+ Critical region (&except_lock);
+#endif
+
+ assert (_refcnt > 0);
+ _refcnt--;
+ if (_refcnt != 0)
+ return _refcnt;
+
+#ifdef _POSIX_THREADS
+ region.leave ();
+#endif
+
+ // CORBA_TypeCode_ptr tc = _type->_duplicate ();
+
+ { CORBA_Any free_it_all (_type, this, CORBA_B_TRUE); }
+
+ // tc->Release ();
+
+ return 0;
+}
+
+HRESULT
+__stdcall
+CORBA_Exception::QueryInterface (
+ REFIID riid,
+ void **ppv
+)
+{
+ assert (_refcnt > 0);
+ *ppv = 0;
+
+ if (IID_CORBA_Exception == riid || IID_IUnknown == riid)
+ *ppv = this;
+
+ //
+ // XXX this approach needs modifying to enable returning
+ // UserException, SystemException, and other kinds of pointers.
+ //
+
+ if (*ppv == 0)
+ return ResultFromScode (E_NOINTERFACE);
+
+ (void) AddRef ();
+ return NOERROR;
+}
+
+
+//
+// Avoid zillions of not-quite-inlined copies of utilities.
+//
+CORBA_UserException::CORBA_UserException (
+ CORBA_TypeCode_ptr tc
+) :
+ CORBA_Exception (tc)
+{
+}
+
+CORBA_UserException::~CORBA_UserException ()
+{
+}
+
+CORBA_SystemException::CORBA_SystemException (
+ CORBA_TypeCode_ptr tc,
+ CORBA_ULong code,
+ CORBA_CompletionStatus completed
+) :
+ _minor (code),
+ _completed (completed),
+ CORBA_Exception (tc)
+{
+}
+
+CORBA_SystemException::~CORBA_SystemException ()
+{
+}
+
+
+#define NUM_SYS_EXCEPTIONS 26 // update correctly!
+#define TC_BUFLEN 160 // preallocated tc buffer
+
+static CORBA_TypeCode_ptr sys_exceptions [NUM_SYS_EXCEPTIONS];
+CORBA_ExceptionList __system_exceptions;
+
+//
+// Make the TypeCode for a standard exception ... note that "buffer"
+// holds the (unscoped) name originally, and is then overwritten.
+//
+// When used correctly, initializing system exceptions is only an
+// exercise in CPU time; it allocates no new memory.
+//
+static void
+make_standard_typecode (
+ CORBA_TypeCode_ptr tcp,
+ const char *name,
+ unsigned char *buffer,
+ size_t buflen,
+ CORBA_Environment &env
+)
+{
+ static const char *minor = "minor";
+ static const char *completion = "completion";
+
+ static const unsigned long oc_completion_status [] = {
+ 1, // byte order flag, tricky
+ 0, 0, // type ID omitted
+ 3, // three members
+ 0, 0, // ... whose names are all omitted
+ 0, 0,
+ 0, 0
+ };
+ static CORBA_TypeCode
+ tc_completion_status (tk_enum, sizeof oc_completion_status,
+ (unsigned char *)&oc_completion_status, CORBA_B_FALSE);
+ static const CORBA_TypeCode_ptr completion_status = &tc_completion_status;
+
+
+ //
+ // Create a CDR stream ... juggle the alignment here a bit, we
+ // know it's good enough for tye typecode.
+ //
+ CDR stream (0, buflen);
+
+ stream.next = stream.buffer = buffer;
+
+ //
+ // into CDR stream, stuff (in order):
+ // - byte order flag [4 bytes]
+ // - exception ID [27 + N bytes]
+ // - exception name [4 + N bytes ]
+ // - number of members (2) [4 bytes ]
+ // - foreach member, { name string, typecode } [~40 bytes]
+ //
+ char full_id [100], *strptr = (char *) &full_id;
+
+ (void) sprintf (full_id, "IDL:omg.org/CORBA/%s:1.0", name);
+ assert (strlen (full_id) <= sizeof full_id);
+
+ if (stream.put_byte (MY_BYTE_SEX) != CORBA_B_TRUE
+ || CDR::encoder (_tc_CORBA_String, &strptr, 0, &stream, env)
+ != CORBA_TypeCode::TRAVERSE_CONTINUE
+ || CDR::encoder (_tc_CORBA_String, &name, 0, &stream, env)
+ != CORBA_TypeCode::TRAVERSE_CONTINUE
+ || stream.put_ulong (2L) != CORBA_B_TRUE
+ || CDR::encoder (_tc_CORBA_String, &minor, 0, &stream, env)
+ != CORBA_TypeCode::TRAVERSE_CONTINUE
+ || CDR::encoder (_tc_CORBA_TypeCode, &_tc_CORBA_ULong, 0,
+ &stream, env)
+ != CORBA_TypeCode::TRAVERSE_CONTINUE
+ || CDR::encoder (_tc_CORBA_String, &completion, 0, &stream, env)
+ != CORBA_TypeCode::TRAVERSE_CONTINUE
+ || CDR::encoder (_tc_CORBA_TypeCode, &completion_status, 0,
+ &stream, env)
+ != CORBA_TypeCode::TRAVERSE_CONTINUE) {
+ env.exception (new CORBA_INITIALIZE (COMPLETED_NO));
+ return;
+ }
+
+ //
+ // OK, we stuffed the buffer we were given (or grew a bigger one;
+ // hope to avoid that during initialization). Now build and return
+ // a TypeCode, saving it away in the list of ones that the ORB will
+ // always accept as part of any operation response!
+ //
+ sys_exceptions [__system_exceptions.length++]
+ = new (tcp) CORBA_TypeCode (tk_except,
+ stream.next - stream.buffer,
+ stream.buffer, CORBA_B_FALSE);
+
+ assert (tcp->_length <= TC_BUFLEN);
+ return;
+}
+
+
+//
+// List of standard/system exceptions ... used to create static storage
+// for their typecodes, then later to initialize that storage using the
+// routine above. (It's just too painful to init these typecodes
+// statically in all cases!)
+//
+#define STANDARD_EXCEPTION_LIST \
+ SYSEX (UNKNOWN) \
+ SYSEX (BAD_PARAM) \
+ SYSEX (NO_MEMORY) \
+ SYSEX (IMP_LIMIT) \
+ SYSEX (COMM_FAILURE) \
+ SYSEX (INV_OBJREF) \
+ SYSEX (OBJECT_NOT_EXIST) \
+ SYSEX (NO_PERMISSION) \
+ SYSEX (INTERNAL) \
+ SYSEX (MARSHAL) \
+ SYSEX (INITIALIZE) \
+ SYSEX (NO_IMPLEMENT) \
+ SYSEX (BAD_TYPECODE) \
+ SYSEX (BAD_OPERATION) \
+ SYSEX (NO_RESOURCES) \
+ SYSEX (NO_RESPONSE) \
+ SYSEX (PERSIST_STORE) \
+ SYSEX (BAD_INV_ORDER) \
+ SYSEX (TRANSIENT) \
+ SYSEX (FREE_MEM) \
+ SYSEX (INV_IDENT) \
+ SYSEX (INV_FLAG) \
+ SYSEX (INTF_REPOS) \
+ SYSEX (BAD_CONTEXT) \
+ SYSEX (OBJ_ADAPTER) \
+ SYSEX (DATA_CONVERSION)
+
+//
+// Declare static storage for these ... the buffer is "naturally"
+// aligned and overwritten.
+//
+// XXX this actually doesn't guarantee "natural" alignment, but
+// it works that way in most systems.
+//
+#define SYSEX(name) \
+ static long tc_buf_ ## name [TC_BUFLEN / sizeof (long)]; \
+ static CORBA_TypeCode tc_std_ ## name (tk_except); \
+ CORBA_TypeCode_ptr _tc_CORBA_ ## name = &tc_std_ ## name;
+STANDARD_EXCEPTION_LIST
+#undef SYSEX
+
+
+//
+// Runtime initialization of all standard exception typecodes.
+// Called from CORBA::ORB::init().
+//
+void
+__TC_init_standard_exceptions (CORBA_Environment &env)
+{
+ //
+ // Initialize the list of system exceptions, used when
+ // unmarshaling.
+ //
+ __system_exceptions.length = 0;
+ __system_exceptions.maximum = NUM_SYS_EXCEPTIONS;
+ __system_exceptions.buffer = &sys_exceptions [0];
+
+ //
+ // Initialize the typecodes.
+ //
+#define SYSEX(name) \
+ if (env.exception () == 0) \
+ make_standard_typecode (&tc_std_ ## name, #name, \
+ (unsigned char *) tc_buf_ ## name, \
+ sizeof tc_buf_ ## name, env);
+
+ STANDARD_EXCEPTION_LIST
+#undef SYSEX
+}
+
+#undef STANDARD_EXCEPTION_LIST
+
+//
+// Static initialization of the two user-defined exceptions that
+// are part of the ORB.
+//
+static CORBA_Octet tc_buf_Bounds [] = {
+ 0, 0, 0, 0, // big endian, padded
+ 0, 0, 0, 38, // strlen (id) + 1
+ 'I', 'D', 'L', ':',
+ 'o', 'm', 'g', '.',
+ 'o', 'r', 'g', '/',
+ 'C', 'O', 'R', 'B',
+ 'A', '/', 'T', 'y',
+ 'p', 'e', 'C', 'o',
+ 'd', 'e', '/', 'B',
+ 'o', 'u', 'n', 'd',
+ 's', ':', '1', '.',
+ '0', '\0', 0, 0,
+ 0, 0, 0, 0 // no members to this typecode
+};
+static CORBA_TypeCode tc_std_Bounds (tk_except, sizeof tc_buf_Bounds,
+ tc_buf_Bounds, CORBA_B_FALSE );
+CORBA_TypeCode_ptr _tc_CORBA_Bounds = &tc_std_Bounds;
+
+static CORBA_Octet tc_buf_BadKind [] = {
+ 0, 0, 0, 0, // big endian, padded
+ 0, 0, 0, 39, // strlen (id) + 1
+ 'I', 'D', 'L', ':',
+ 'o', 'm', 'g', '.',
+ 'o', 'r', 'g', '/',
+ 'C', 'O', 'R', 'B',
+ 'A', '/', 'T', 'y',
+ 'p', 'e', 'C', 'o',
+ 'd', 'e', '/', 'B',
+ 'a', 'd', 'K', 'i',
+ 'n', 'd', ':', '1',
+ '.', '0', '\0', 0,
+ 0, 0, 0, 0 // no members to this typecode
+};
+static CORBA_TypeCode tc_std_BadKind (tk_except, sizeof tc_buf_BadKind,
+ tc_buf_BadKind, CORBA_B_FALSE );
+CORBA_TypeCode_ptr _tc_CORBA_BadKind = &tc_std_BadKind;
+
+
+
+//
+// Convenience -- say if the exception is a system exception or not.
+//
+CORBA_ExceptionType
+CORBA_Environment::exception_type () const
+{
+ static char sysex_prefix [] = "IDL:omg.org/CORBA/";
+ static char typecode_extra [] = "TypeCode/";
+
+ if (!_exception)
+ return NO_EXCEPTION;
+
+ //
+ // All exceptions currently (CORBA 2.0) defined in the CORBA
+ // scope are system exceptions ... except for a couple that
+ // are related to TypeCodes.
+ //
+ char *id = _exception->id ();
+
+ if (strncmp (id, sysex_prefix, sizeof sysex_prefix - 1) == 0
+ && strncmp (id + sizeof sysex_prefix - 1,
+ typecode_extra, sizeof typecode_extra - 1) != 0)
+ return SYSTEM_EXCEPTION;
+
+ return USER_EXCEPTION;
+}
+
+
+//
+// Diagnostic utility routine: describe the exception onto
+// the standard I/O stream passed as a parameter.
+//
+// XXX make this a member function on "Environment"
+//
+void _EXPFUNC
+print_exception (
+ const CORBA_Exception *x,
+ const char *info,
+ FILE *stream
+)
+{
+ CORBA_String id = x->id ();
+
+ flockfile (stream);
+ fprintf (stream, "EXCEPTION, %s\n", info);
+
+ //
+ // XXX get rid of this logic, and rely on some member function
+ // on Exception to say if it's user or system exception.
+ //
+ if (strncmp ((char *) id, "IDL:omg.org/CORBA/", 10) == 0
+ && strncmp ((char *) id, "IDL:omg.org/CORBA/TypeCode/", 19) != 0
+ ) {
+ //
+ // XXX this should be a QueryInterface call instead
+ //
+ CORBA_SystemException *x2 = (CORBA_SystemException *)x;
+
+ //
+ // XXX there are a other few "user exceptions" in the CORBA scope,
+ // they're not all standard/system exceptions ... really need
+ // to either compare exhaustively against all those IDs (yeech)
+ // or (preferably) to represent the exception type directly in
+ // the exception value so it can be queried.
+ //
+
+ fprintf (stream, "system exception, ID '%s'\n", id);
+ fprintf (stream, "minor code = %#lx, completed = ", x2->minor ());
+ switch (x2->completion ()) {
+ case COMPLETED_YES:
+ fputs ("YES", stream);
+ break;
+ case COMPLETED_NO:
+ fputs ("NO", stream);
+ break;
+ case COMPLETED_MAYBE:
+ fputs ("MAYBE", stream);
+ break;
+ default:
+ fputs ("**garbage**", stream);
+ break;
+ }
+ fputc ('\n', stream);
+ } else {
+ //
+ // XXX we can use the exception's typecode to dump all the data
+ // held within it ...
+ //
+ fprintf (stream, "user exception, ID '%s'\n", id);
+ }
+ funlockfile (stream);
+}
diff --git a/TAO/IIOP/lib/runtime/interp.cpp b/TAO/IIOP/lib/runtime/interp.cpp
new file mode 100644
index 00000000000..abd6843421f
--- /dev/null
+++ b/TAO/IIOP/lib/runtime/interp.cpp
@@ -0,0 +1,1515 @@
+// @(#)interp.cpp 1.4 95/11/04
+// Copyright 1994-1995 by Sun Microsystems Inc.
+// All Rights Reserved
+//
+// TYPECODE: interpreter, traverses data structures
+//
+// This uses the standard C/C++ representation for data, and knows how to
+// do things like align and pad according to standard rules. It is driven
+// by CDR marshaled representations of TypeCodes.
+//
+// It does two key things: (a) calculate size and alignment restrictions
+// for the data type described by any given typecode; and (b) "visits"
+// each element of a data type in the order those elements are defined
+// in the type's IDL definition.
+//
+// A typical use is that some application-specific "visit" function will
+// be called with a typecode and data value. Then that "visit" function
+// may choose to use the interpreter's knowledge of the environment's
+// size, padding, and alignment rules to help it examine each of the
+// constituents of complex data values. It does so by making a call to
+// TypeCode::traverse(), and passing itself for future recursive calls.
+//
+//
+// NOTE that this module has system dependent parts, and so should be
+// examined when porting to new CPU architectures, compilers, and so forth
+// to make sure it correctly implements the appropriate binary interfaces.
+//
+// Issues of concern are primarily that sizes and representations of CORBA
+// primitive data types are correct (key issues are verified when the
+// ORB initializes) and that the alignment rules are recognized.
+//
+// Also, exceptions have vtables in them, which may cause trouble if they
+// aren't located at the very beginning by the compiler in question.
+//
+// So for example, moving to another CPU architecture which still uses
+// standard sized two's complement integers and IEEE floating point, and
+// expects "natural" alignment, won't be hard. Even using PC style
+// tightly packed data is simple; the alignment rules are just simpler.
+// Most volume microprocessors used in 1995 are correctly supported.
+//
+// Using data representations that are far from the standard C/C++ style
+// data layout is probably not practical with this implementation. LISP
+// systems, as one example, probably won't use "in-memory" representations
+// much like C/C++, even though its "wire form" could directly match CDR.
+//
+//
+// ALSO, the treatment of exceptions may need to be examined in language
+// environments which actually rely on C++ exceptions. The RTTI data that
+// identifies exceptions can easily be ignored by this interpreter (if it's
+// taught about that compiler's RTTI) but it may not be practical for any
+// code not generated by that specific C++ compiler to store such data in
+// the right place to look like a C++ exception, or to throw exceptions
+// when that's needed. (RTTI == "Run Time Typing Information", needed to
+// make C++ exceptions work correctly and partially exposed to users by
+// the ANSI standards comittee. It provides type-safe "downcasting" and
+// other features previously unavailable in C++.)
+//
+//
+// THREADING NOTE: Data structures being traversed should only be modified
+// by the thread doing the traversal. The interpretive code itself is
+// reentrant (recursive!) so presents no threading issues; only the data
+// being fed to the interpreter must be protected against concurrency.
+//
+
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+#include <corba/orb.hh>
+
+#include "runtime/debug.hh"
+#include "runtime/cdr.hh"
+
+
+
+//
+// Utility routines are used to manipulate CDR-encapsulated TypeCode parameter
+// lists, calculating the size and alignment of the data type being described.
+// The TCKind value has always been removed from the CDR stream when these
+// calculator routines get called.
+//
+typedef size_t
+attribute_calculator (
+ CDR *stream,
+ size_t &alignment,
+ CORBA_Environment &env
+);
+
+static attribute_calculator calc_struct_attributes;
+static attribute_calculator calc_exception_attributes;
+static attribute_calculator calc_union_attributes;
+static attribute_calculator calc_alias_attributes;
+static attribute_calculator calc_array_attributes;
+
+
+//
+// Other utility routines are used to skip the parameter
+// lists when they're not needed.
+//
+typedef CORBA_Boolean param_skip_rtn (CDR *);
+
+static CORBA_Boolean
+skip_encapsulation (CDR *stream)
+{
+ return stream->skip_string ();
+}
+
+static CORBA_Boolean
+skip_long (CDR *stream)
+{
+ CORBA_ULong scratch;
+
+ return stream->get_ulong (scratch);
+}
+
+
+//
+// Table supporting calculation of size and alignment requirements for
+// any one instance of a given data types.
+//
+// This is indexed via CDR's TCKind values, which are "frozen" as part of the
+// CDR standard. Entries hold either the size and alignment values for that
+// data type, or a pointer to a function that is used to calculate those
+// values. Function pointers are normally needed only for constructed types.
+//
+// A "skipper" routine is provided for some data types whose size is known
+// statically (e.g. objrefs, structures, strings) but whose typecodes have
+// parameters that sometimes need to be ignored when found in a CDR stream.
+// Any attribute calculator routine always skips parameters in the CDR input
+// stream, so no type with such a routine also needs a "skipper".
+//
+// Rather than growing a set of processor-specific #ifdefs, we calculate
+// most of this table (except functions) at ORB initialization time.
+//
+struct table_element {
+ size_t size;
+ size_t alignment;
+ attribute_calculator *calc;
+ param_skip_rtn *skipper;
+};
+
+static table_element
+table [TC_KIND_COUNT] = {
+ { 0, 1, 0 }, // tk_null
+ { 0, 1, 0 }, // tk_void
+
+ { 0, 1, 0, 0 }, // tk_short
+ { 0, 1, 0, 0 }, // tk_long
+ { 0, 1, 0, 0 }, // tk_ushort
+ { 0, 1, 0, 0 }, // tk_ulong
+
+ { 0, 1, 0, 0 }, // tk_float
+ { 0, 1, 0, 0 }, // tk_double
+
+ { 0, 1, 0, 0 }, // tk_boolean
+ { 0, 1, 0, 0 }, // tk_char
+ { 0, 1, 0, 0 }, // tk_octet
+ { 0, 1, 0, 0 }, // tk_any
+
+ { 0, 1, 0, 0 }, // tk_TypeCode
+ { 0, 1, 0, 0 }, // tk_Principal
+ { 0, 1, 0, skip_encapsulation }, // tk_objref
+
+ { 0, 1, calc_struct_attributes, 0 }, // tk_struct
+ { 0, 1, calc_union_attributes, 0 }, // tk_union
+
+ { 0, 1, 0, skip_encapsulation }, // tk_enum
+ { 0, 1, 0, skip_long }, // tk_string
+ { 0, 1, 0, skip_encapsulation }, // tk_sequence
+ { 0, 1, calc_array_attributes, 0 }, // tk_array
+
+ //
+ // Two TCKind values added in 94-11-7
+ //
+ { 0, 1, calc_alias_attributes, 0 }, // tk_alias
+ { 0, 1, calc_exception_attributes, 0 }, // tk_except
+
+ //
+ // Five extended IDL data types, defined in Appendix A of 94-9-32
+ // but here with different numeric TCKind codes. These types
+ // represent extensions to CORBA (specifically, to IDL) which are
+ // not yet standardized.
+ //
+ { 0, 1, 0, 0 }, // tk_longlong
+ { 0, 1, 0, 0 }, // tk_ulonglong
+ { 0, 1, 0, 0 }, // tk_longdouble
+ { 0, 1, 0, 0 }, // tk_wchar
+ { 0, 1, 0, skip_long } // tk_wstring
+};
+
+
+//
+// Runtime initialization of the table above; note that this compiles down
+// to a set of assignment statements, with the real work done by the C++
+// compiler when this file gets compiled.
+//
+// "Natural alignment" is a policy that the processor controls the alignment
+// of data based on its type. There's variation; some CPUs have a maximum
+// alignment requirement of two or four bytes, others have some type-specific
+// exceptions to the normal "alignment == size" rule.
+//
+// "Fixed" alignment ignores data type when establishing alignment; not all
+// processors support such policies, and those which do often pay a cost to
+// do so (viz. RISC/CISC discussions). The primary example of an OS family
+// that chose "fixed" alignment is Microsoft's x86 systems, which normally
+// align on one byte boundaries to promote data space efficiency.
+//
+//
+// NOTE: typical PC compiler options let you specify other alignments, but
+// none are "natural". Also, they don't apply consistently to all data types.
+// Change the "one byte" assumption with extreme caution! And make sure all
+// header files (e.g. generated by an IDL compiler) make sure that alignment
+// of IDL-defined data types is consistent (one byte).
+//
+#if unix
+#define setup_entry(x,t) \
+ { \
+ struct align_struct_ ## t { \
+ x one; \
+ char dummy [17 - sizeof(x)]; \
+ x two; \
+ }; \
+ \
+ align_struct_ ## t align; \
+ table [t].size = sizeof (x); \
+ table [t].alignment = \
+ (char*) &align.two - (char*) &align.one - 16; \
+ }
+
+#else // PC "fixed" alignment
+#define setup_entry(x,t) \
+ { \
+ table [t].size = sizeof (x); \
+ table [t].alignment = 1; \
+ }
+
+#endif
+
+//
+// Fills in fixed size and alignment values.
+//
+void
+__TC_init_table ()
+{
+ setup_entry (CORBA_Short, tk_short);
+ setup_entry (CORBA_Long, tk_long);
+ setup_entry (CORBA_UShort, tk_ushort);
+ setup_entry (CORBA_ULong, tk_ulong);
+
+ setup_entry (CORBA_Float, tk_float);
+ setup_entry (CORBA_Double, tk_double);
+
+ setup_entry (CORBA_Boolean, tk_boolean);
+ setup_entry (CORBA_Char, tk_char);
+ setup_entry (CORBA_Octet, tk_octet);
+ setup_entry (CORBA_Any, tk_any);
+
+ setup_entry (CORBA_TypeCode_ptr, tk_TypeCode);
+ setup_entry (CORBA_Principal_ptr, tk_Principal);
+ setup_entry (CORBA_Object_ptr, tk_objref);
+
+ enum generic_enum {a, b, c, d};
+
+ // XXX workaround for G++ 2.6.3 bug
+ // setup_entry (generic_enum, tk_enum);
+ table [tk_enum].size = sizeof (generic_enum);
+ table [tk_enum].alignment = sizeof (generic_enum);
+
+ setup_entry (CORBA_String, tk_string);
+ setup_entry (CORBA_OctetSeq, tk_sequence);
+
+ setup_entry (CORBA_LongLong, tk_longlong);
+ setup_entry (CORBA_ULongLong, tk_ulonglong);
+ setup_entry (CORBA_LongDouble, tk_longdouble);
+ setup_entry (CORBA_WChar, tk_wchar);
+ setup_entry (CORBA_WString, tk_wstring);
+}
+
+#undef setup
+
+
+//
+// For a given typecode, figure out its size and alignment needs. This
+// version is used mostly when traversing other typecodes, and follows
+// these rules:
+//
+// - Some typecodes are illegal (can't be nested inside others);
+// - Indirections are allowed;
+// - The whole typecode (including TCKind enum) is in the stream
+//
+// When the routine returns, the stream has skipped this TypeCode.
+//
+// "size" is returned, "alignment" is an 'out' parameter. If it is non-null,
+// "tc" is initialized to hold the contents of the TypeCode; it depends on
+// the contents of the original stream to be valid.
+//
+// XXX explore splitting apart returning the size/alignment data and the
+// TypeCode initialization; union traversal would benefit a bit, but it
+// would need more than that to make it as speedy as struct traversal.
+//
+static size_t
+calc_nested_size_and_alignment (
+ CORBA_TypeCode_ptr tc,
+ CDR *original_stream,
+ size_t &alignment,
+ CORBA_Environment &env
+)
+{
+ //
+ // Get the "kind" ... if this is an indirection, this is a
+ // guess which will soon be updated.
+ //
+ CORBA_ULong temp;
+ CORBA_TCKind kind;
+
+ if (original_stream->get_ulong (temp) == CORBA_B_FALSE) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+
+ env.clear ();
+ kind = (CORBA_TCKind) temp;
+
+ //
+ // Check for indirection, setting up the right CDR stream to
+ // use when getting the rest of the parameters. (We rely on
+ // the fact that indirections may not point to indirections.)
+ //
+ CDR indirected_stream;
+ CDR *stream;
+
+ if (kind == ~0) {
+ CORBA_Long offset;
+
+ //
+ // Get indirection, sanity check it, set up new stream
+ // pointing there.
+ //
+ // XXX access to "real" size limit for this typecode and
+ // use it to check for errors before indirect and to limit
+ // the new stream's length. ULONG_MAX is too much!
+ //
+ if (!original_stream->get_long (offset)
+ || offset >= -8
+ || ((-offset) & 0x03) != 0) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+ offset -= 4; // correct for get_long update
+
+ indirected_stream.next = original_stream->next + (ptr_arith_t) offset;
+ indirected_stream.remaining = (size_t) ULONG_MAX;
+ stream = &indirected_stream;
+
+ //
+ // Fetch indirected-to TCKind, deducing byte order.
+ //
+ if (*indirected_stream.next == 0) // big-endian?
+ indirected_stream.do_byteswap = (MY_BYTE_SEX != 0);
+ else
+ indirected_stream.do_byteswap = (MY_BYTE_SEX == 0);
+
+ if (!indirected_stream.get_ulong (temp)) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+ kind = (CORBA_TCKind) temp;
+
+ } else
+ stream = original_stream;
+
+ //
+ // Check for illegal TCKind enum values ... out of range, or which
+ // represent data values that can't be nested. (Some can't even
+ // exist freestanding!)
+ //
+ if (kind >= TC_KIND_COUNT
+ || kind <= tk_void
+ || kind == tk_except) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+
+ //
+ // Use attribute calculator routine if it exists; these are needed
+ // only for variable-sized data types, with encapsulated parameter
+ // lists that affect the size and alignment of "top level" memory
+ // needed to hold an instance of this type.
+ //
+ if (table [kind].calc != 0) {
+ assert (table [kind].size == 0);
+
+ //
+ // Pull encapsulation length out of the stream.
+ //
+ if (stream->get_ulong (temp) == CORBA_B_FALSE) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+
+ //
+ // Initialize the TypeCode if requested
+ //
+ if (tc) {
+ tc->_kind = kind;
+ tc->_buffer = stream->next;
+ tc->_length = temp;
+ }
+
+ //
+ // Set up a separate stream for the parameters; it may easily
+ // have a different byte order, and this is as simple a way
+ // as any to ensure correctness. Then use the calculator
+ // routine to calculate size and alignment.
+ //
+ CDR sub_encapsulation;
+ size_t size;
+
+ assert (temp <= UINT_MAX);
+ sub_encapsulation.setup_encapsulation (stream->next, (size_t) temp);
+ size = table [kind].calc (&sub_encapsulation, alignment, env);
+
+ //
+ // Check for garbage at end of parameter lists, or other cases
+ // where parameters and the size allocated to them don't jive.
+ //
+ stream->skip_bytes ((unsigned) temp);
+ if (stream->next != sub_encapsulation.next) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+ return size;
+ }
+ assert (table [kind].size != 0); // fixed size data type
+
+ //
+ // Reinitialize the TypeCode if requested; this consumes any TypeCode
+ // parameters in the stream. They only exist for TCKind values that
+ // have parameters, but which represent fixed-size data types in the
+ // binary representation: tk_string, tk_wstring, tk_objref, tk_enum,
+ // and tk_sequence.
+ //
+ if (tc) {
+ CORBA_ULong len;
+
+ tc->_kind = kind;
+ switch (kind) {
+ default:
+ assert (table [kind].skipper == 0);
+ break;
+
+ case tk_string:
+ case tk_wstring:
+ if (stream->get_ulong (len) == CORBA_B_FALSE) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+ tc->_length = len;
+ break;
+
+ case tk_enum:
+ case tk_objref:
+ case tk_sequence:
+ if (stream->get_ulong (len) == CORBA_B_FALSE) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+ tc->_length = len;
+
+ assert (len < UINT_MAX);
+ tc->_buffer = stream->next;
+ stream->skip_bytes ((unsigned) len);
+ break;
+ }
+
+ //
+ // Otherwise, consume any parameters without stuffing them into
+ // a temporary TypeCode.
+ //
+ } else if (table [kind].skipper != 0
+ && table [kind].skipper (stream) == CORBA_B_FALSE) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+
+ //
+ // Return statically known values.
+ //
+ alignment = table [kind].alignment;
+ return table [kind].size;
+}
+
+
+//
+// Given typecode bytes for a structure (or exception), figure out its
+// alignment and size; return size, alignment is an 'out' parameter.
+// Only "tk_struct" (or "tk_except") has been taken out of the stream
+// parameter holding the bytes.
+//
+// We use a one-pass algorithm, calculating size and inter-element
+// padding while recording the strongest alignment restriction. Then
+// we correct the size to account for tail-padding.
+//
+// This routine recognizes that exceptions are just structs with some
+// additional information. Different environments may differ in what
+// that additional information is, so this routine may need to be taught
+// about compiler-specific representation of that additional "RTTI" data.
+//
+static size_t
+calc_struct_and_except_attributes (
+ CDR *stream,
+ size_t &alignment,
+ CORBA_Boolean is_exception,
+ CORBA_Environment &env
+)
+{
+ CORBA_ULong members;
+ size_t size;
+
+ //
+ // Exceptions are like structs, with key additions (all of which
+ // might need to be be applied to structures!): vtable, typecode,
+ // and refcount. The size must include these "hidden" members.
+ //
+ // NOTE: in environments with "true" C++ exceptions, there may
+ // need to be a slot for additional "RTTI" information; maybe it
+ // is part of the vtable, or maybe not. Or, that information
+ // (needed to determine which 'catch' clauses apply) may only be
+ // provided by the compiler to the runtime support for the "throw"
+ // statement.
+ //
+ if (is_exception) {
+ size = sizeof (CORBA_Exception);
+ alignment = table [tk_TypeCode].alignment;
+ } else {
+ alignment = 1;
+ size = 0;
+ }
+
+ //
+ // skip rest of header (type ID and name) and collect the
+ // number of struct members
+ //
+ if (!stream->skip_string ()
+ || !stream->skip_string ()
+ || !stream->get_ulong (members)) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+
+ //
+ // iterate over all the members, skipping their names and
+ // looking only at type data.
+ //
+ for ( ; members != 0; members--) {
+ size_t member_size, member_alignment;
+
+ //
+ // Skip name of the member.
+ //
+ if (!stream->skip_string ()) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+
+ //
+ // Get size and alignment of the member, accounting for
+ // indirection and the various kinds of parameter encoding.
+ //
+ member_size = calc_nested_size_and_alignment (0, stream,
+ member_alignment, env);
+ if (env.exception () != 0)
+ return 0;
+
+ //
+ // Round up the struct size to handle member alignment (by
+ // adding internal padding), then update the current size
+ // to handle the member's size.
+ //
+ size = (size_t) align_binary (size, member_alignment);
+ size += member_size;
+
+ //
+ // Finally update the overall structure alignment requirement,
+ // if this element must be more strongly aligned.
+ //
+ if (member_alignment > alignment)
+ alignment = member_alignment;
+ };
+
+ //
+ // Round up the structure size to match its overall alignment.
+ // This adds tail padding, if needed.
+ //
+ return (size_t) align_binary (size, alignment);
+}
+
+
+//
+// Calculate size and alignment for a structure.
+//
+static size_t
+calc_struct_attributes (
+ CDR *stream,
+ size_t &alignment,
+ CORBA_Environment &env
+)
+{
+ return calc_struct_and_except_attributes (stream,
+ alignment, CORBA_B_FALSE, env);
+}
+
+
+//
+// Calculate size and alignment for an exception.
+//
+static size_t
+calc_exception_attributes (
+ CDR *stream,
+ size_t &alignment,
+ CORBA_Environment &env
+)
+{
+ return calc_struct_and_except_attributes (stream,
+ alignment, CORBA_B_TRUE, env);
+}
+
+
+//
+// Calculate and return sizes for both parts of a union, as needed by
+// other code. Return value is the overall size. The padded size of
+// the discriminant is needed to traverse the two values separately.
+// Unfortunately that is not quite practical to do with a single pass
+// over the typecode: the inter-element padding changes depending on
+// the strictest alignment required by _any_ arm of the union.
+//
+static size_t
+calc_key_union_attributes (
+ CDR *stream,
+ size_t &overall_alignment,
+ size_t &discrim_size_with_pad,
+ CORBA_Environment &env
+)
+{
+ CORBA_ULong members;
+ CORBA_ULong temp;
+ size_t discrim_size;
+ size_t value_alignment, value_size;
+
+ overall_alignment = value_alignment = 1;
+ value_size = discrim_size_with_pad = 0;
+
+ //
+ // Skip initial optional members (type ID and name).
+ //
+ if (!stream->skip_string () // type ID
+ || !stream->skip_string ()) { // typedef name
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+
+ //
+ // Calculate discriminant size and alignment: it's the first
+ // member of the "struct" representing the union. We detect
+ // illegal discriminant kinds a bit later.
+ //
+ CORBA_TypeCode discrim_tc (tk_void);
+
+ discrim_size = calc_nested_size_and_alignment (&discrim_tc,
+ stream, overall_alignment, env);
+ if (env.exception () != 0)
+ return 0;
+
+ //
+ // skip "default used" indicator, and save "member count"
+ //
+ if (!stream->get_ulong (temp) // default used
+ || !stream->get_ulong (members)) { // member count
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+
+ //
+ // iterate over the tuples for all the members; all we care about
+ // is their types, which can affect either alignment or padding
+ // requirement for the union part of the construct.
+ //
+ for ( ; members != 0; members--) {
+ size_t member_size, member_alignment;
+
+ //
+ // Skip member label; its size varies with discriminant type, but
+ // here we don't care about its content. This is where illegal
+ // discriminant kinds are detected.
+ //
+ // NOTE: This modifies 94-9-32 Appendix A to stipulate that
+ // "long long" values are not legal as discriminants.
+ //
+ switch (discrim_tc._kind) {
+ case tk_short:
+ case tk_ushort:
+ case tk_wchar:
+ {
+ CORBA_Short s;
+
+ if (!stream->get_short (s)) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+ }
+ break;
+
+ case tk_long:
+ case tk_ulong:
+ case tk_enum:
+ {
+ CORBA_Long l;
+
+ if (!stream->get_long (l)) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+ }
+ break;
+
+ case tk_boolean:
+ case tk_char:
+ {
+ char c;
+
+ if (!stream->get_byte (c)) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+ }
+ break;
+
+ default:
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+
+ //
+ // We also don't care about any member name.
+ //
+ if (!stream->skip_string ()) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+
+ //
+ // Get the member size and alignment.
+ //
+ member_size = calc_nested_size_and_alignment (0, stream,
+ member_alignment, env);
+ if (env.exception () != 0)
+ return 0;
+
+ //
+ // Save the largest member and alignment. They don't need to
+ // be changed in sync -- e.g. "long double" size is larger
+ // than its alignment restriction on SPARC, x86, and some m68k
+ // platforms.
+ //
+ if (member_size > value_size)
+ value_size = member_size;
+ if (member_alignment > value_alignment)
+ value_alignment = member_alignment;
+ }
+
+ //
+ // Round up the discriminator's size to include padding it needs
+ // in order to be followed by the value.
+ //
+ discrim_size_with_pad = (size_t)
+ align_binary (discrim_size, value_alignment);
+
+ //
+ // Now calculate the overall size of the structure, which is the
+ // discriminator, inter-element padding, value, and tail padding.
+ // We know all of those except tail padding, which is a function
+ // of the overall alignment. (Ensures that arrays of these can
+ // be safely allocated and accessed!)
+ //
+ if (value_alignment > overall_alignment)
+ overall_alignment = value_alignment;
+
+ return (size_t) align_binary (discrim_size_with_pad + value_size,
+ overall_alignment);
+}
+
+
+//
+// Calculate size and alignment for a CORBA discriminated union.
+//
+// Note that this is really a two-element structure. The first element
+// is the discriminator; the second is the value. All normal structure
+// padding/alignment rules apply. In particular, all arms of the
+// union have the same initial address (adequately aligned for any
+// of the members).
+//
+static size_t
+calc_union_attributes (
+ CDR *stream,
+ size_t &alignment,
+ CORBA_Environment &env
+)
+{
+ size_t scratch;
+
+ return calc_key_union_attributes (stream, alignment, scratch, env);
+}
+
+
+//
+// Calculate size and alignment for a typedeffed type.
+//
+static size_t
+calc_alias_attributes (
+ CDR *stream,
+ size_t &alignment,
+ CORBA_Environment &env
+)
+{
+ //
+ // Skip type ID and name in the parameter stream
+ //
+ if (!stream->skip_string () // type ID
+ || !stream->skip_string () // typedef name
+ ) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+
+ //
+ // The typedef is identical to the type for which it stands.
+ //
+ return calc_nested_size_and_alignment (0, stream, alignment, env);
+}
+
+
+//
+// Calculate size and alignment of an array. (All such arrays are
+// described as single dimensional, even though the IDL definition
+// may specify a multidimensional array ... such arrays are treated
+// as nested single dimensional arrays.)
+//
+static size_t
+calc_array_attributes (
+ CDR *stream,
+ size_t &alignment,
+ CORBA_Environment &env
+)
+{
+ size_t member_size;
+ CORBA_ULong member_count;
+
+ //
+ // get size and alignment of the array member
+ //
+ member_size = calc_nested_size_and_alignment (0, stream, alignment, env);
+ if (env.exception () != 0)
+ return 0;
+
+ //
+ // Get and check count of members.
+ //
+ if (stream->get_ulong (member_count) == CORBA_B_FALSE
+ || member_count > UINT_MAX) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+
+ //
+ // Array size is a function only of member number and count
+ //
+ return member_size * (size_t) member_count;
+}
+
+
+//
+// Visit each of the elements of a structure.
+//
+static
+CORBA_TypeCode::traverse_status
+struct_traverse (
+ CDR *stream,
+ const void *value1,
+ const void *value2,
+ CORBA_TypeCode::traverse_status (_FAR *visit) (
+ CORBA_TypeCode_ptr tc,
+ const void *value1,
+ const void *value2,
+ void *context,
+ CORBA_Environment &env
+ ),
+ void *context,
+ CORBA_Environment &env
+)
+{
+ //
+ // Skip over the type ID and type name in the parameters, then
+ // get the number of members.
+ //
+ CORBA_ULong members;
+
+ if (!stream->skip_string () // type ID
+ || !stream->skip_string () // type name
+ || !stream->get_ulong (members)) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return CORBA_TypeCode::TRAVERSE_STOP;
+ }
+
+ //
+ // Visit each member of the structure/exception. The initial
+ // pointer(s) point at the first values to visit. For structs
+ // we could avoid the inter-member padding ... not for the
+ // case of exceptions. No big deal.
+ //
+ // NOTE: For last element, could turn visit() call into something
+ // subject to compiler's tail call optimization and thus save
+ // a stack frame.
+ //
+ CORBA_TypeCode::traverse_status retval;
+
+ for (retval = CORBA_TypeCode::TRAVERSE_CONTINUE;
+ members != 0 && retval == CORBA_TypeCode::TRAVERSE_CONTINUE;
+ members--) {
+ CORBA_TypeCode member_tc (tk_null);
+ size_t size, alignment;
+
+ //
+ // Skip the member's name in the parameter list.
+ //
+ if (!stream->skip_string ()) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return CORBA_TypeCode::TRAVERSE_STOP;
+ }
+
+ //
+ // Get the member's size, alignment, and a temporary TypeCode,
+ // skipping that TypeCode in the stream as we do so.
+ //
+ // This accounts for all variations: different or nonexistent
+ // parameter lists, errors such as out-of-range TCKind values
+ // or nested exceptions, and indirected typecodes.
+ //
+ size = calc_nested_size_and_alignment (&member_tc, stream,
+ alignment, env);
+ if (env.exception () != 0)
+ return CORBA_TypeCode::TRAVERSE_STOP;
+
+ //
+ // Pad the value pointers to account for the alignment requirements
+ // of this member, then visit.
+ //
+ value1 = ptr_align_binary ((const unsigned char *) value1, alignment);
+ value2 = ptr_align_binary ((const unsigned char *) value2, alignment);
+
+ retval = visit (&member_tc, value1, value2, context, env);
+
+ //
+ // Update 'value' pointers to account for the size of the
+ // values just visited.
+ //
+ value1 = size + (char *)value1;
+ value2 = size + (char *)value2;
+
+ if (env.exception () != 0)
+ retval = CORBA_TypeCode::TRAVERSE_STOP;
+ }
+
+ return retval;
+}
+
+
+//
+// cast the discriminant values to the right type and compare them.
+//
+static CORBA_Boolean
+match_value (
+ CORBA_TCKind kind,
+ CDR *tc_stream,
+ const void *value,
+ CORBA_Environment &env
+)
+{
+ CORBA_Boolean retval = CORBA_B_FALSE;
+
+ switch (kind) {
+ case tk_short:
+ case tk_ushort:
+ {
+ CORBA_UShort discrim;
+
+ if (tc_stream->get_ushort (discrim) != CORBA_B_FALSE) {
+ retval = (discrim == *(CORBA_UShort *)value);
+ } else {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ }
+ }
+ break;
+
+ case tk_long:
+ case tk_ulong:
+ {
+ CORBA_ULong discrim;
+
+ if (tc_stream->get_ulong (discrim) != CORBA_B_FALSE) {
+ retval = (discrim == *(CORBA_ULong *)value);
+ } else {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ }
+ }
+ break;
+
+ case tk_enum:
+ {
+ CORBA_ULong discrim;
+
+ if (tc_stream->get_ulong (discrim) != CORBA_B_FALSE) {
+ retval = (discrim == *(unsigned *)value);
+ } else {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ }
+ }
+ break;
+
+ case tk_boolean:
+ {
+ CORBA_Boolean discrim;
+
+ if (tc_stream->get_boolean (discrim) != CORBA_B_FALSE) {
+ retval = (discrim == *(CORBA_Boolean *)value);
+ } else {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ }
+ }
+ break;
+
+ case tk_char:
+ {
+ CORBA_Char discrim;
+
+ if (tc_stream->get_char (discrim) != CORBA_B_FALSE) {
+ retval = (discrim == *(CORBA_Char *)value);
+ } else {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ }
+ }
+ break;
+
+ case tk_wchar:
+ {
+ CORBA_WChar discrim;
+
+ if (tc_stream->get_wchar (discrim) != CORBA_B_FALSE) {
+ retval = (discrim == *(CORBA_WChar *)value);
+ } else {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ }
+ }
+ break;
+
+
+ default:
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ }
+
+ return retval;
+}
+
+//
+// Visit the two elements of the union: the discrminant, and then any
+// specific value as indicated by the discriminant of value1.
+//
+static
+CORBA_TypeCode::traverse_status
+union_traverse (
+ CDR *stream,
+ const void *value1,
+ const void *value2,
+ CORBA_TypeCode::traverse_status
+ (_FAR *visit) (
+ CORBA_TypeCode_ptr tc,
+ const void *value1,
+ const void *value2,
+ void *context,
+ CORBA_Environment &env
+ ),
+ void *context,
+ CORBA_Environment &env
+)
+{
+ size_t discrim_size_with_pad;
+
+ //
+ // Figure out size of discriminant plus padding, used to adjust value
+ // pointers later. This can't be calculated without looking at all
+ // branches of the union ... forcing union traversal to be a two-pass
+ // algorithm, unless/until some data gets squirreled away.
+ //
+ {
+ CDR temp_cdr;
+ size_t scratch;
+
+ temp_cdr.next = stream->next;
+ temp_cdr.remaining = stream->remaining;
+ temp_cdr.do_byteswap = stream->do_byteswap;
+ temp_cdr.do_free = 0;
+
+ (void) calc_key_union_attributes (&temp_cdr, scratch,
+ discrim_size_with_pad, env);
+ }
+ if (env.exception() != 0)
+ return CORBA_TypeCode::TRAVERSE_STOP;
+
+ //
+ // Skip the optional type ID and type name.
+ //
+ if (!stream->skip_string () // type ID, hidden
+ || !stream->skip_string ()) { // typedef name
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return CORBA_TypeCode::TRAVERSE_STOP;
+ }
+
+ //
+ // Get and skip the discriminant's TypeCode. This allow for
+ // indirection (e.g. a complex enum discriminant). We use
+ // that TypeCode to visit the discriminant.
+ //
+ // We know the kind is legal and the TypeCode is valid because
+ // this repeats work we did earlier -- so checks are omitted.
+ //
+ CORBA_TypeCode discrim_tc (tk_null);
+
+ {
+ size_t scratch;
+
+ (void) calc_nested_size_and_alignment (&discrim_tc,
+ stream, scratch, env);
+ }
+
+ if (visit (&discrim_tc, value1, value2, context, env)
+ == CORBA_TypeCode::TRAVERSE_STOP)
+ return CORBA_TypeCode::TRAVERSE_STOP;
+
+ //
+ // Adjust the pointers to point to the other member of the
+ // union; this ensures alignment for any of the values.
+ // Save the pointer to the discriminant though; we need it
+ // to find out which member to visit!
+ //
+ const void *discrim_ptr = value1;
+
+ value1 = discrim_size_with_pad + (char *) value1;
+ value2 = discrim_size_with_pad + (char *) value2;
+
+ //
+ // Get the flag that tells if there's a "default" arm in this
+ // union, then the number of members in the union.
+ //
+ CORBA_Long default_used = 0;
+ CORBA_ULong member_count;
+
+ if (!stream->get_long (default_used)) { // default used
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return CORBA_TypeCode::TRAVERSE_STOP;
+ }
+
+ if (!stream->get_ulong (member_count)) { // member count
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return CORBA_TypeCode::TRAVERSE_STOP;
+ }
+
+ //
+ // Scan to find the tuple whose value matches the discriminator.
+ //
+ // While we're scanning, record any default arm's information.
+ // If we can't find a match for the discriminant value, that arm
+ // will be used later.
+ //
+ unsigned char *default_tc_ptr = 0;
+ size_t default_tc_len;
+
+ while (member_count-- != 0) {
+ //
+ // Test to see if the discriminant value matches the one in
+ // the TypeCode; this skips the the discriminant value in
+ // this CDR stream.
+ //
+ CORBA_Boolean discrim_matched;
+
+ discrim_matched = match_value (discrim_tc._kind,
+ stream, discrim_ptr, env);
+ if (env.exception () != 0)
+ return CORBA_TypeCode::TRAVERSE_STOP;
+
+ //
+ // Skip the name of the member; we never care about it.
+ //
+ if (!stream->skip_string ()) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return CORBA_TypeCode::TRAVERSE_STOP;
+ }
+
+ //
+ // If this is the default member, remember where its
+ // typecode data is stored; we'll use it later.
+ //
+ if (default_used >= 0 && default_used-- == 0) {
+ default_tc_ptr = stream->next;
+ default_tc_len = stream->remaining;
+ }
+
+ //
+ // Get the TypeCode for this member.
+ //
+ // XXX we really don't care about size and alignment this time,
+ // only that we initialize the TypeCode.
+ //
+ CORBA_TypeCode tc (tk_null);
+ size_t scratch;
+
+ (void) calc_nested_size_and_alignment (&tc, stream, scratch, env);
+ if (env.exception () != 0)
+ return CORBA_TypeCode::TRAVERSE_STOP;
+
+ //
+ // If we matched, visit the member and return.
+ //
+ if (discrim_matched)
+ return visit (&tc, value1, value2, context, env);
+ }
+
+ //
+ // If we get here, it means any default arm should be used. We
+ // know at least the basic sanity checks passed; we don't repeat.
+ //
+ if (default_tc_ptr) {
+ CDR temp_str;
+ size_t scratch;
+ CORBA_TypeCode tc (tk_null);
+
+ temp_str.next = default_tc_ptr;
+ temp_str.remaining = default_tc_len;
+ temp_str.do_byteswap = stream->do_byteswap;
+
+ //
+ // Get and use the TypeCode.
+ //
+ // XXX we really don't care about size and alignment this time,
+ // only that we initialize the TypeCode.
+ //
+ (void) calc_nested_size_and_alignment (&tc, &temp_str, scratch, env);
+ return visit (&tc, value1, value2, context, env);
+ }
+ return CORBA_TypeCode::TRAVERSE_CONTINUE;
+}
+
+
+//
+// For each node in "data", visit it. For singleton nodes that's all but
+// a NOP; for structs, unions, etc it's more interesting. The visit routine
+// can descend, if it chooses.
+//
+// NOTE: this does no memory allocation or deallocation except through use
+// of the stack. Or at least, it should do none -- if you find that just
+// traversing a data value allocates any memory, that's a bug to fix!
+//
+CORBA_TypeCode::traverse_status
+CORBA_TypeCode::traverse (
+ const void *value1,
+ const void *value2,
+ CORBA_TypeCode::traverse_status (_FAR *visit) (
+ CORBA_TypeCode_ptr tc,
+ const void *value1,
+ const void *value2,
+ void *context,
+ CORBA_Environment &env
+ ),
+ void *context,
+ CORBA_Environment &env
+)
+{
+ env.clear ();
+
+ //
+ // Quickly accomodate the bulk of cases, which are just (tail) calls
+ // to the visit() routine. We take advantage of the fact that these
+ // are largely in a convenient numeric range to work around poor
+ // optimization of "switch" code in some compilers. This improvement
+ // has in some cases been more than 5% faster (significant).
+ //
+ // NOTE: if for some reason the constants in the protocol spec
+ // (including Appendix A) change, this logic may need to be verified
+ // again. Luckily, changing protocol constants is quite rare; they
+ // normally just get added to (at the end).
+ //
+ if (_kind <= tk_objref
+ || (tk_longlong <= _kind && _kind <= tk_wstring))
+ return visit (this, value1, value2, context, env);
+
+ //
+ // Handle the cases that aren't in convenient numeric ranges.
+ //
+ traverse_status retval;
+
+ switch (_kind) {
+ case tk_string:
+ case tk_enum:
+ return visit (this, value1, value2, context, env);
+
+ //
+ // Typedefs just add a delay, while we skip the typedef ID
+ // and name ...
+ //
+ case tk_alias:
+ {
+ CORBA_TypeCode_ptr tcp;
+ CORBA_Environment env2;
+
+ //
+ // XXX rework for efficiency, this doesn't need to
+ // allocate memory during the traversal!
+ //
+ tcp = typecode_param (2, env);
+ if (env.exception () != 0)
+ return TRAVERSE_STOP;
+
+ retval = tcp->traverse (value1, value2, visit, context, env);
+
+ tcp->Release ();
+ }
+ return retval;
+
+ //
+ // Exceptions in-memory are structures, except that there are data
+ // members "hidden" in front: vtable, typecode, refcount. We skip
+ // them, and allow the traversal code to account for the internal
+ // padding before the other elements of the exception.
+ //
+ // NOTE: see header comment re treatment of these values as "real"
+ // C++ exceptions. C++ RTTI data might need to be skipped. Also,
+ // see the comments in unmarshaling code: hard to throw these values.
+ //
+ // Not enough of the exception runtime is public for binary standards
+ // to exist for C++ exceptions yet. Compiler-specific code will need
+ // to handle examining, unmarshaling, and throwing of CORBA exceptions
+ // (in C++ environments) for some time.
+ //
+ case tk_except:
+ value1 = sizeof (CORBA_Exception) + (char *) value1;
+ value2 = sizeof (CORBA_Exception) + (char *) value2;
+ // FALLTHROUGH
+
+ case tk_struct:
+ //
+ // XXX for OLE Automation, we'll probably need BOTH exceptions
+ // and structs to inherit IUnknown, hence we'll need to be
+ // skipping the vtable pointer ...
+ //
+ {
+ //
+ // Create the sub-encapsulation stream that holds the
+ // parameters for the typecode.
+ //
+ CDR stream;
+
+ stream.setup_encapsulation (_buffer, (size_t) _length);
+
+ return struct_traverse (&stream, value1, value2,
+ visit, context, env);
+ }
+
+ case tk_union:
+ {
+ //
+ // visit the discriminant, then search the typecode for the
+ // relevant union member and then visit that member.
+ //
+ CDR stream;
+
+ stream.setup_encapsulation (_buffer, (size_t) _length);
+
+ return union_traverse (&stream, value1, value2,
+ visit, context, env);
+ }
+
+ //
+ // Sequences are just arrays with bound determined at runtime, rather
+ // than compile time. Multidimensional arrays are nested C-style:
+ // the leftmost dimension in the IDL definition is "outermost", etc.
+ //
+ {
+ CORBA_TypeCode_ptr tc2;
+ size_t size;
+ CORBA_ULong bounds;
+ CORBA_OctetSeq *seq;
+
+ case tk_sequence:
+ //
+ // Find out how many elements there are, and adjust the
+ // data pointers to point to those elements rather than
+ // to the sequence itself.
+ //
+ seq = (CORBA_OctetSeq *)value1;
+
+ bounds = seq->length;
+ value1 = seq->buffer;
+
+ if (value2) {
+ seq = (CORBA_OctetSeq *)value2;
+ value2 = seq->buffer;
+ }
+ goto shared_seq_array_code;
+
+ case tk_array:
+ //
+ // Array bounds are in the typecode itself.
+ //
+ bounds = ulong_param (1, env);
+ if (env.exception () != 0)
+ return TRAVERSE_STOP;
+
+ shared_seq_array_code:
+ //
+ // Find element's type, and size ...
+ //
+ tc2 = typecode_param (0, env);
+ if (env.exception () != 0)
+ return TRAVERSE_STOP;
+
+ size = tc2->size (env);
+ if (env.exception () != 0)
+ return TRAVERSE_STOP;
+
+ //
+ // ... then visit the elements in order.
+ //
+ // NOTE: for last element, could turn visit() call into something
+ // subject to compiler's tail call optimization and thus save
+ // a stack frame
+ //
+ while (bounds--) {
+ if (visit (tc2, value1, value2, context, env) == TRAVERSE_STOP)
+ return TRAVERSE_STOP;
+
+ value1 = size + (char *) value1;
+ value2 = size + (char *) value2;
+ }
+ CORBA_release (tc2);
+ env.clear ();
+ }
+ return TRAVERSE_CONTINUE;
+
+ // case ~0: // indirection, illegal at top level
+ default: // invalid/illegal
+ break;
+
+ } // end switch on typecode "kind"
+
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return TRAVERSE_STOP;
+}
+
+
+//
+// Tell user the size of an instance of the data type described by this
+// typecode ... typically used to allocate memory.
+//
+size_t
+CORBA_TypeCode::size (CORBA_Environment &env)
+{
+ if (_kind >= TC_KIND_COUNT) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+ env.clear ();
+
+ if (table [_kind].calc == 0)
+ return table [_kind].size;
+
+ size_t alignment;
+ CDR stream;
+
+ stream.setup_encapsulation (_buffer, (size_t) _length);
+
+ return table [_kind].calc (&stream, alignment, env);
+}
+
+
+//
+// Tell user the alignment restriction for the data type described by an
+// instance of this data type. Rarely used; provided for completeness.
+//
+size_t
+CORBA_TypeCode::alignment (CORBA_Environment &env)
+{
+ if (_kind >= TC_KIND_COUNT) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+ env.clear ();
+
+ if (table [_kind].calc == 0)
+ return table [_kind].alignment;
+
+ size_t alignment;
+ CDR stream;
+
+ stream.setup_encapsulation (_buffer, (size_t) _length);
+
+ (void) table [_kind].calc (&stream, alignment, env);
+ return alignment;
+}
diff --git a/TAO/IIOP/lib/runtime/marshal.cpp b/TAO/IIOP/lib/runtime/marshal.cpp
new file mode 100644
index 00000000000..60531602eb8
--- /dev/null
+++ b/TAO/IIOP/lib/runtime/marshal.cpp
@@ -0,0 +1,1101 @@
+// @(#)marshal.cpp 1.7 95/11/04
+// Copyright 1994-1995 by Sun Microsystems Inc.
+// All Rights Reserved
+//
+// CDR: Marshaling interpreter
+//
+// This marshaling interpreter is driven by the typecode interpreter. The
+// typecode interpreter understands each compiler environment's rules for
+// data structure layout; this understands CDR's rules for on-the-wire data
+// structure layout.
+//
+// Apart from some high level rules related to construction of complex data
+// types, the marshaling interpreter just knows how to encode primitive data
+// types and allocate memory on decode.
+//
+// NOTE: to reduce the amount of compiled code, this "knows" facts like
+// native float/long/ulong being in legal CDR format, and that "char" is
+// native in ISO Latin/1 (so no transformation is needed, and octet/char
+// marshaling code is identical). On exotic platforms where this is not
+// true, some of the merged "switch" branches will need to be split.
+//
+// REMEMBER: goal is to have the typecode interpreter plus one side of the
+// marshaling interpreter reside in a CPU's code cache; or at least to have
+// as litle as possible _outside_ cache when marshaling. Compiled marshaling
+// code will have a few less instructions, but most will of them will be
+// outside the instruction cache; access time to get at them will be high.
+//
+// NOTE: One interesting optimization is inlining the primitive put/get
+// calls ... it'd typically save at least 40% in terms of instruction count
+// on each of these critical paths by eliminating subroutine call overhead.
+// Since it would increase code size, such changes might not be desirable
+// on machines with small caches. Also, with network I/O being today's most
+// significant bottleneck, such optimizations haven't been well explored.
+//
+// THREADING NOTE: The only threading concern is as always, that data
+// structures being manipulated by any given thread must be reserved to
+// it by some mechanism (e.g. mutex). This uses no mutable data outside
+// of the thread stack, so the onus is entirely on the caller.
+//
+
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+#include <corba/orb.hh>
+
+#include "runtime/debug.hh"
+#include "runtime/cdr.hh"
+
+#include "bridge/giop.hh"
+
+
+#if defined (HAVE_WIDEC_H)
+# include <widec.h>
+#else
+ extern "C" {
+ unsigned wslen (const wchar_t *);
+ wchar_t *wscpy (wchar_t *, const wchar_t *);
+ }
+#endif
+
+extern CORBA_TypeCode TC_opaque;
+
+
+//
+// Encode instances of arbitrary data types based only on typecode. "data"
+// points to the data type; if it's not a primitve data type, the TypeCode
+// interpreter is used to recursively encode its components. "context" is
+// the marshaling stream on which to encode the data value.
+//
+// This is a fairly typical TypeCode interpreter visit() routine; it works
+// on a single data value in conjunction with context information, and must
+// handle all IDL data types.
+//
+CORBA_TypeCode::traverse_status
+CDR::encoder (
+ CORBA_TypeCode_ptr tc,
+ const void *data,
+ const void *,
+ void *context,
+ CORBA_Environment &env
+)
+{
+ CORBA_Boolean continue_encoding = CORBA_B_TRUE;
+ CDR *stream = (CDR *)context;
+
+ switch (tc->_kind) {
+ case tk_null:
+ case tk_void:
+ // nothing to encode!
+ break;
+
+ case tk_char:
+ case tk_octet:
+ continue_encoding = stream->put_char (*(char *)data);
+ break;
+
+ case tk_short:
+ case tk_ushort:
+ continue_encoding = stream->put_short (*(short *)data);
+ break;
+
+ case tk_long:
+ case tk_ulong:
+ case tk_float:
+ continue_encoding = stream->put_long (*(CORBA_Long *)data);
+ break;
+
+ case tk_double:
+ case tk_longlong:
+ case tk_ulonglong:
+ continue_encoding = stream->put_longlong (*(CORBA_LongLong *)data);
+ break;
+
+ case tk_boolean:
+ continue_encoding = stream->put_boolean (*(CORBA_Boolean *)data);
+ break;
+
+ case tk_enum:
+ {
+ //
+ // NOTE assumption that this is in-range.
+ //
+ // XXX should check this, it's a hard-to-recover error
+ // for the other side
+ //
+ unsigned value = *(unsigned *)data;
+ continue_encoding = stream->put_ulong (value);
+ }
+ break;
+
+ case tk_any:
+ {
+ CORBA_Any *any = (CORBA_Any *)data;
+
+ tc = any->type ();
+ if (encoder (_tc_CORBA_TypeCode, &tc, 0, context, env)
+ != CORBA_TypeCode::TRAVERSE_CONTINUE)
+ return CORBA_TypeCode::TRAVERSE_STOP;
+
+ data = any->value ();
+ return encoder (tc, data, 0, context, env);
+ }
+ // NOTREACHED
+
+ case tk_TypeCode:
+ {
+ CORBA_TypeCode_ptr tc2;
+
+ tc2 = *(CORBA_TypeCode_ptr *)data;
+
+ continue_encoding = stream->put_ulong ((CORBA_ULong) tc2->_kind);
+ if (continue_encoding == CORBA_B_FALSE)
+ break;
+
+ switch (tc2->_kind) {
+ //
+ // Most TypeCodes have empty parameter lists
+ //
+ default:
+ break;
+
+ //
+ // A few have "simple" parameter lists
+ //
+ case tk_string:
+ case tk_wstring:
+ continue_encoding = stream->put_ulong (tc2->_length);
+ break;
+
+ //
+ // Indirected typecodes can't occur at "top level" like
+ // this, only nested inside others!
+ //
+ case ~0:
+ dmsg ("indirected typecode at top level!");
+ continue_encoding = CORBA_B_FALSE;
+ break;
+
+ //
+ // The rest have "complex" parameter lists that are already
+ // encoded as bulk octets ... put length, then octets
+ //
+ case tk_objref:
+ case tk_struct:
+ case tk_union:
+ case tk_enum:
+ case tk_sequence:
+ case tk_array:
+ case tk_alias:
+ case tk_except:
+ {
+ unsigned i;
+
+ continue_encoding = stream->put_ulong (tc2->_length);
+ for (i = 0; i < tc2->_length && continue_encoding; i++)
+ continue_encoding =
+ stream->put_octet (tc2->_buffer [i]);
+ }
+ }
+ }
+ break;
+
+ case tk_Principal:
+ {
+ CORBA_Principal_ptr p = *(CORBA_Principal_ptr*) data;
+ unsigned i;
+
+ if (p != 0) {
+ continue_encoding = stream->put_long (p->id.length);
+ for (i = 0; continue_encoding && i < p->id.length; i++)
+ continue_encoding = stream->put_octet (p->id.buffer [i]);
+ } else
+ continue_encoding = stream->put_long (0);
+ }
+ break;
+
+ case tk_objref:
+ //
+ // Current version: objref is really an IIOP_Object.
+ //
+ // This will change in the future; STUB_Object knows how to
+ // marshal itself, that will be used.
+ //
+ // XXX this doesn't actually verify that the stuff got written
+ // OK to the "wire" ...
+ //
+ {
+ CORBA_Object_ptr obj = *(CORBA_Object_ptr *)data;
+
+ //
+ // NIL objrefs ... marshal as empty type hint, no elements.
+ //
+ if (CORBA_is_nil (obj)) {
+ continue_encoding =
+ stream->put_ulong (1) // strlen
+ && stream->put_char (0) // NUL
+ && stream->put_ulong (0); // no profiles
+ break;
+ }
+
+ //
+ // All other objrefs ... narrow to a "real type" that we
+ // recognize, then marshal.
+ //
+ // XXX this will be changed so it narrows to STUB_Object
+ // and then asks that surrogate/proxy to marshal itself.
+ //
+ // For now, the original code is minimally changed.
+ //
+ IIOP_Object *objdata;
+ IIOP::ProfileBody *profile;
+
+ if (obj->QueryInterface (IID_IIOP_Object, (void **)&objdata)
+ != NOERROR) {
+ env.exception (new CORBA_MARSHAL (COMPLETED_NO));
+ return CORBA_TypeCode::TRAVERSE_STOP;
+ }
+ obj->Release ();
+ profile = &objdata->profile;
+
+ //
+ // STRING, a type ID hint
+ //
+ encoder (_tc_CORBA_String, &objdata->type_id, 0, context, env);
+
+ //
+ // UNSIGNED LONG, value one, count of the sequence
+ // of encapsulated protocol profiles;
+ //
+ stream->put_ulong (1);
+
+ //
+ // UNSIGNED LONG, tag for this protocol profile;
+ //
+ stream->put_ulong (IOP::TAG_INTERNET_IOP);
+
+ //
+ // UNSIGNED LONG, number of succeeding bytes in the encapsulation.
+ // We don't actually need to make the encapsulation, as nothing
+ // needs stronger alignment than this longword; it guarantees
+ // the rest is aligned for us.
+ //
+ unsigned hostlen;
+
+ hostlen = strlen ((char *)profile->host);
+ stream->put_ulong (
+ 1 // byte order
+ + 3 // version + pad byte
+ + 4 // sizeof (strlen)
+ + hostlen + 1 // strlen + null
+ + (~hostlen & 01) // optional pad byte
+ + 2 // port
+ + (hostlen & 02) // optional pad short
+ + 4 // sizeof (key length)
+ + profile->object_key.length); // key length
+
+ //
+ // CHAR describing byte order, starting the encapsulation
+ //
+ stream->put_char (MY_BYTE_SEX);
+
+ //
+ // IIOP::Version, two characters (version 1.0)
+ // padding
+ //
+ stream->put_char (profile->iiop_version.major);
+ stream->put_char (profile->iiop_version.minor);
+
+ //
+ // STRING hostname from profile
+ //
+ encoder (_tc_CORBA_String, &profile->host, 0, context, env);
+
+ //
+ // UNSIGNED SHORT port number
+ //
+ stream->put_ushort (profile->port);
+
+ //
+ // OCTET SEQUENCE for object key
+ //
+ encoder (&TC_opaque, &profile->object_key, 0, context, env);
+ }
+ break;
+
+ case tk_sequence:
+ {
+ //
+ // First marshal the sequence length, verifying that
+ // it's within the sequence bounds ...
+ //
+ CORBA_OctetSeq *seq = (CORBA_OctetSeq *) data;
+ CORBA_ULong len = seq ? seq->length : 0;
+
+ if (len > 0) {
+ CORBA_ULong bounds;
+
+ bounds = tc->ulong_param (1, env);
+ if (env.exception () != 0)
+ return CORBA_TypeCode::TRAVERSE_STOP;
+
+ if (bounds != 0 && len > bounds) {
+ env.exception (new CORBA_BAD_PARAM (COMPLETED_MAYBE));
+ return CORBA_TypeCode::TRAVERSE_STOP;
+ }
+ }
+ continue_encoding = stream->put_ulong (len);
+
+ //
+ // Fast exit on error or empty sequence
+ //
+ if (!continue_encoding || len == 0)
+ break;
+ }
+ // FALLTHROUGH
+
+ case tk_struct:
+ case tk_union:
+ case tk_array:
+ case tk_alias:
+ //
+ // Marshal each member in order.
+ //
+ return tc->traverse (data, 0, encoder, context, env);
+
+ case tk_except:
+ //
+ // Convert the the "hidden" TypeCode at the beginning of the
+ // exception into an on-the-wire ID, then marshal the members
+ // in order (traversal skips that hidden typecode, and more).
+ //
+ // NOTE: This is asymmetric with respect to decoding the exception,
+ // since whoever decodes must pull off the ID and map it to the
+ // typecode to be used to unmarshal it (search among legal choices).
+ //
+ {
+ CORBA_String id = tc->id (env);
+
+ if (env.exception () == 0) {
+ continue_encoding =
+ encoder (_tc_CORBA_String, &id, 0, context, env)
+ == CORBA_TypeCode::TRAVERSE_CONTINUE
+ && tc->traverse (data, 0, encoder, context, env);
+ } else
+ continue_encoding = CORBA_B_FALSE;
+ }
+ break;
+
+ case tk_string:
+ {
+ CORBA_String str = *(CORBA_String *) data;
+ CORBA_ULong len, bounds;
+
+ //
+ // Be nice to programmers: treat nulls as empty strings
+ // not errors. (OMG-IDL supports languages that don't use
+ // the C/C++ notion of null v. empty strings; nulls aren't
+ // part of the OMG-IDL string model.)
+ //
+ if (str == 0) {
+ stream->put_ulong (1);
+ stream->put_char (0);
+ break;
+ }
+
+ //
+ // Verify string satisfies bounds requirements. We're not
+ // so permissive as to send messages violating the interface
+ // spec by having excessively long strings!
+ //
+ bounds = tc->ulong_param (0, env);
+ if (env.exception () != 0)
+ return CORBA_TypeCode::TRAVERSE_STOP;
+ len = strlen ((char *)str);
+
+ if (bounds != 0 && len > bounds) {
+ continue_encoding = CORBA_B_FALSE;
+ break;
+ }
+
+ //
+ // Encode the string, followed by a NUL character.
+ //
+ continue_encoding = stream->put_ulong (len + 1);
+ while (continue_encoding != CORBA_B_FALSE && *str)
+ continue_encoding = stream->put_char (*str++);
+ stream->put_char (0);
+ }
+ break;
+
+ case tk_wstring:
+ {
+ wchar_t *str = *(wchar_t **) data;
+ CORBA_ULong len, bounds;
+
+ //
+ // Be nice to programmers: treat nulls as empty strings
+ // not errors. (OMG-IDL supports languages that don't use
+ // the C/C++ notion of null v. empty strings; nulls aren't
+ // part of the OMG-IDL string model.)
+ //
+ if (str == 0) {
+ stream->put_ulong (1);
+ stream->put_wchar (0);
+ break;
+ }
+
+ //
+ // Verify wide string satisfies bounds requirements. We're
+ // not so permissive as to send messages violating the interface
+ // spec by having excessively long strings!
+ //
+ bounds = tc->ulong_param (0, env);
+ if (env.exception () != 0)
+ return CORBA_TypeCode::TRAVERSE_STOP;
+ len = wslen (str);
+ if (bounds != 0 && len > bounds) {
+ continue_encoding = CORBA_B_FALSE;
+ break;
+ }
+
+ //
+ // Encode the wide string, followed by a NUL character.
+ //
+ continue_encoding = stream->put_ulong (wslen (str) + 1);
+ while (continue_encoding != CORBA_B_FALSE && *str)
+ continue_encoding = stream->put_wchar (*str++);
+ stream->put_wchar (0);
+ }
+ break;
+
+ case tk_longdouble:
+ continue_encoding =
+ stream->put_longdouble (*(CORBA_LongDouble *)data);
+ break;
+
+ case tk_wchar:
+ continue_encoding = stream->put_wchar (*(wchar_t *)data);
+ break;
+
+ // case ~0:
+ default:
+ dmsg ("encoder default case ?");
+ continue_encoding = CORBA_B_FALSE;
+ break;
+ }
+
+ if (continue_encoding == CORBA_B_FALSE) {
+ env.exception (new CORBA_MARSHAL (COMPLETED_MAYBE));
+ dmsg ("marshaling encoder detected error");
+ return CORBA_TypeCode::TRAVERSE_STOP;
+ }
+ return CORBA_TypeCode::TRAVERSE_CONTINUE;
+}
+
+
+//
+// This table of TypeCode constants lets us unmarshal most typecodes using
+// the predefined constants, rather than constantly reallocating them.
+//
+// XXX CFRONT-based compilers can't cope with this table initialization,
+// and need some kind of init function. Luckily, they're increasingly
+// rare in any "production" environment.
+//
+const CORBA_TypeCode_ptr
+__tc_consts [TC_KIND_COUNT] = {
+ _tc_CORBA_Null
+ , _tc_CORBA_Void
+ , _tc_CORBA_Short
+ , _tc_CORBA_Long
+ , _tc_CORBA_UShort
+
+ , _tc_CORBA_ULong
+ , _tc_CORBA_Float
+ , _tc_CORBA_Double
+ , _tc_CORBA_Boolean
+ , _tc_CORBA_Char
+
+ , _tc_CORBA_Octet
+ , _tc_CORBA_Any
+ , _tc_CORBA_TypeCode
+ , _tc_CORBA_Principal
+ , 0 // _tc_CORBA_Object ... type ID is CORBA::Object
+
+ , 0 // tk_struct
+ , 0 // tk_union
+ , 0 // tk_enum
+ , 0 // _tc_CORBA_String ... unbounded
+ , 0 // tk_sequence
+
+ , 0 // tk_array
+
+ , 0 // tk_alias
+ , 0 // tk_except
+
+ , _tc_CORBA_LongLong
+ , _tc_CORBA_ULongLong
+ , _tc_CORBA_LongDouble
+ , _tc_CORBA_WChar
+ , 0 // _tc_CORBA_WString ... unbounded
+};
+
+
+//
+// The decoder is exactly the reverse of the encoder, except that:
+//
+// * Unmarshaling some data types involve allocating memory. Such
+// types include sequences (the buffer), objrefs, Principals, Anys,
+// TypeCodes, and strings.
+//
+// * The decoder is used when retrieving typecode parameters from
+// encapsulations. This means it must deal with "tk_indirect",
+// the magic value (~0) signifying typecode indirection.
+//
+// This second case is identified by a bit of a hack: the second "data"
+// value is used to hold the parent typecode, rather than being ignored.
+// This means that all other invocations of decoder() ** MUST ** pass zero
+// for the second data parameter, in case they decode a TypeCode. If they
+// didn't, this case might be signified inappropriately.
+//
+// XXX desirable to have a less hacky solution to that ... pull that code
+// out into a separate routine called both by CDR::decoder() and by the
+// code retrieving typecode parameters from encapsulations.
+//
+CORBA_TypeCode::traverse_status
+CDR::decoder (
+ CORBA_TypeCode_ptr tc,
+ const void *data,
+ const void *parent_typecode,
+ void *context,
+ CORBA_Environment &env
+)
+{
+ CORBA_Boolean continue_decoding = CORBA_B_TRUE;
+ CDR *stream = (CDR *)context;
+
+ switch (tc->_kind) {
+ case tk_null:
+ case tk_void:
+ // nothing to decode!
+ break;
+
+ case tk_char:
+ case tk_octet:
+ continue_decoding = stream->get_char (*(CORBA_Char *)data);
+ break;
+
+ case tk_short:
+ case tk_ushort:
+ continue_decoding = stream->get_short (*(short *)data);
+ break;
+
+ case tk_long:
+ case tk_ulong:
+ case tk_float:
+ continue_decoding = stream->get_long (*(CORBA_Long *)data);
+ break;
+
+ case tk_longlong:
+ case tk_ulonglong:
+ case tk_double:
+ continue_decoding = stream->get_longlong (*(CORBA_LongLong *)data);
+ break;
+
+ case tk_boolean:
+ continue_decoding = stream->get_boolean (*(CORBA_Boolean *)data);
+ break;
+
+ case tk_enum:
+ {
+ CORBA_ULong val;
+
+ //
+ // NOTE assumption that this is in-range.
+ //
+ // XXX should check this, it's rather hard to recover
+ // from such errors since they "do not occur" and are
+ // essentially never tested for.
+ //
+ continue_decoding = stream->get_ulong (val);
+ *(unsigned *)data = (unsigned) val;
+ }
+ break;
+
+ case tk_any:
+ {
+ CORBA_Any *any = (CORBA_Any *)data;
+ CORBA_TypeCode_ptr tc2;
+ void *value;
+
+ if (decoder (_tc_CORBA_TypeCode, &tc2, 0, context, env)
+ != CORBA_TypeCode::TRAVERSE_CONTINUE)
+ return CORBA_TypeCode::TRAVERSE_STOP;
+
+ value = new CORBA_Octet [tc2->size (env)];
+
+ if (decoder (tc2, value, 0, context, env)
+ != CORBA_TypeCode::TRAVERSE_CONTINUE) {
+ delete value;
+ CORBA_release (tc2);
+ return CORBA_TypeCode::TRAVERSE_STOP;
+ }
+ (void) new (any) CORBA_Any (tc2, value, CORBA_B_TRUE);
+ }
+ break;
+
+ case tk_TypeCode:
+ {
+ CORBA_ULong kind;
+ CORBA_TypeCode_ptr *tcp;
+
+ continue_decoding = stream->get_ulong (kind);
+ if (continue_decoding == CORBA_B_FALSE)
+ break;
+ if (kind >= TC_KIND_COUNT) {
+ continue_decoding = CORBA_B_FALSE;
+ break;
+ }
+
+ tcp = (CORBA_TypeCode_ptr *)data;
+
+ //
+ // Typecodes with empty parameter lists all have preallocated
+ // constants. We use those to reduce memory consumption and
+ // heap access ... also, to speed things up!
+ //
+ if (((*tcp) = __tc_consts [(unsigned) kind]) != 0) {
+ *tcp = __tc_consts [(unsigned) kind];
+ break;
+ } else switch (kind) {
+ //
+ // Need special handling for all kinds of typecodes that have
+ // nonempty parameter lists ...
+ //
+ default: // error: missed a case!
+ env.exception (new CORBA_INTERNAL (COMPLETED_MAYBE));
+ return CORBA_TypeCode::TRAVERSE_STOP;
+
+ //
+ // Some have "simple" parameter lists ... some of these also
+ // have preallocated constants that could be used.
+ //
+ case tk_string:
+ case tk_wstring:
+ {
+ CORBA_ULong bound;
+
+ continue_decoding = stream->get_ulong (bound);
+ if (continue_decoding) {
+ if (bound == 0) {
+ if (kind == tk_string)
+ *tcp = _tc_CORBA_String;
+ else
+ *tcp = _tc_CORBA_WString;
+ } else {
+ *tcp = new CORBA_TypeCode ((CORBA_TCKind) kind,
+ bound, 0, CORBA_B_TRUE);
+ }
+ }
+ }
+ break;
+
+ //
+ // Indirected typecodes, illegal at "top level" but we allow
+ // unmarshaling of them here because we use the same code to
+ // read "off the wire" (where they're illegal) and to read
+ // out of an encapsulation stream. We distinguish the case
+ // where this is legal as described above.
+ //
+ case ~0:
+ {
+ CORBA_TypeCode_ptr parent;
+
+ if (parent_typecode == 0) {
+ env.exception (new CORBA_INTERNAL (COMPLETED_MAYBE));
+ return CORBA_TypeCode::TRAVERSE_STOP;
+ }
+ parent = (CORBA_TypeCode_ptr) parent_typecode;
+
+ //
+ // Get the long indicating the encapsulation offset,
+ // then set up indirection stream that's like "stream"
+ // but has space enough only for the typecode and
+ // the length for the encapsulated parameters.
+ //
+ CDR indir_stream;
+ CORBA_Long offset;
+
+ continue_decoding = stream->get_long (offset);
+ if (continue_decoding)
+ continue_decoding = (offset < 0);
+ if (continue_decoding) {
+ indir_stream.buffer = indir_stream.next
+ = stream->next + offset;
+ indir_stream.remaining = indir_stream.length = 8;
+
+ //
+ // Reject indirections outside parent's scope.
+ //
+ if (indir_stream.next < parent->_buffer)
+ continue_decoding = CORBA_B_FALSE;
+ }
+
+ //
+ // Get "kind" and length of target typecode
+ //
+ // XXX this currently assumes the TCKind to which
+ // we indirect is the same byte order as the "parent"
+ // typecode -- not the right assumption; see how
+ // the TypeCode interpreter does it.
+ //
+ CORBA_ULong indir_kind, indir_len;
+
+ if (continue_decoding)
+ continue_decoding = stream->get_ulong (indir_kind);
+ if (continue_decoding
+ && indir_kind >= TC_KIND_COUNT)
+ continue_decoding = CORBA_B_FALSE;
+ if (continue_decoding)
+ continue_decoding = stream->get_ulong (indir_len);
+
+ //
+ // Now construct indirected typecode. This shares the
+ // typecode octets with the "parent" typecode, increasing
+ // the amount of memory sharing and reducing the cost of
+ // getting typecodes.
+ //
+ if (continue_decoding) {
+ *tcp = new CORBA_TypeCode (
+ (CORBA_TCKind) indir_kind,
+ indir_len, indir_stream.next,
+ CORBA_B_FALSE);
+ (*tcp)->_parent = parent;
+ parent->AddRef ();
+ }
+ }
+ break;
+
+ //
+ // The rest have "complex" parameter lists that are
+ // encoded as bulk octets ...
+ //
+ case tk_objref:
+ case tk_struct:
+ case tk_union:
+ case tk_enum:
+ case tk_sequence:
+ case tk_array:
+ case tk_alias:
+ case tk_except:
+ {
+ unsigned len, i;
+ CORBA_ULong length;
+ CORBA_Octet *buffer;
+
+ continue_decoding = stream->get_ulong (length);
+ if (!continue_decoding)
+ break;
+
+ // if length > MAXUNSIGNED, error ...
+ len = (unsigned) length;
+
+ buffer = new CORBA_Octet [len];
+
+ for (i = 0; i < len && continue_decoding; i++)
+ continue_decoding = stream->get_octet (buffer [i]);
+
+ if (!continue_decoding) {
+ delete buffer;
+ break;
+ }
+ *tcp = new CORBA_TypeCode ((CORBA_TCKind)kind,
+ len, buffer, CORBA_B_TRUE);
+ }
+ }
+ }
+ break;
+
+ case tk_Principal:
+ {
+ CORBA_Principal_ptr *pp = (CORBA_Principal_ptr *)data;
+ CORBA_ULong len;
+
+ continue_decoding = stream->get_ulong (len);
+ if (len == 0)
+ *pp = 0;
+ else {
+ *pp = new CORBA_Principal;
+ (*pp)->id.buffer = new CORBA_Octet [(size_t) len];
+ (*pp)->id.maximum = (*pp)->id.length = len;
+
+ for (unsigned i = 0;
+ continue_decoding != CORBA_B_FALSE && i < len;
+ i++)
+ continue_decoding = stream->get_octet (
+ (*pp)->id.buffer [i]);
+ }
+ }
+ break;
+
+ case tk_objref:
+ {
+ //
+ // First, read the type hint.
+ //
+ CORBA_String type_hint;
+
+ decoder (_tc_CORBA_String, &type_hint, 0, context, env);
+
+ //
+ // Read the profiles, discarding all until an IIOP profile comes by.
+ // Once we see an IIOP profile, ignore any further ones.
+ //
+ // XXX this will need to change someday to let different protocol
+ // code be accessed, not just IIOP. Protocol modules will be
+ // dynamically loaded from shared libraries via ORB_init(), and
+ // we just need to be able to access such preloaded libraries here
+ // as we unmarshal objrefs.
+ //
+ CORBA_ULong profiles;
+ IIOP_Object *objdata = 0;
+
+ stream->get_ulong (profiles);
+
+ //
+ // No profiles means a NIL objref.
+ //
+ if (profiles == 0) {
+ *(CORBA_Object_ptr *)data = CORBA_Object::_nil ();
+ delete type_hint;
+ break;
+ }
+ while (profiles-- != 0 && continue_decoding) {
+ CORBA_ULong tmp;
+
+ stream->get_ulong (tmp);
+ if (tmp != IOP::TAG_INTERNET_IOP || objdata != 0) {
+ continue_decoding = stream->skip_string ();
+ continue;
+ }
+
+ //
+ // OK, we've got an IIOP profile. It's going to be
+ // encapsulated ProfileData. Create a new decoding
+ // stream and context for it, and tell the "parent"
+ // stream that this data isn't part of it any more.
+ //
+ continue_decoding = stream->get_ulong (tmp);
+ assert (stream->remaining >= tmp);
+
+ //
+ // Create the decoding stream from the encapsulation
+ // in the buffer, and skip the encapsulation.
+ //
+ CDR str;
+
+ str.setup_encapsulation (stream->next, (size_t) tmp);
+
+ stream->next += (unsigned) tmp;
+ stream->remaining -= (unsigned) tmp;
+
+ objdata = new IIOP_Object (type_hint);
+
+ IIOP::ProfileBody *profile = &objdata->profile;
+
+ //
+ // Read and verify major, minor versions, ignoring
+ // IIOP profiles whose versions we don't understand.
+ //
+ // XXX this doesn't actually go back and skip the
+ // whole encapsulation...
+ //
+ if (!(str.get_octet (profile->iiop_version.major)
+ && profile->iiop_version.major == IIOP::MY_MAJOR
+ && str.get_octet (profile->iiop_version.minor)
+ && profile->iiop_version.minor <= IIOP::MY_MINOR)) {
+ dmsg2 ("detected new v%d.%d IIOP profile",
+ profile->iiop_version.major,
+ profile->iiop_version.minor);
+ objdata->type_id = 0;
+ objdata->Release ();
+ objdata = 0;
+ continue;
+ }
+
+ //
+ // Get host and port
+ //
+ if (decoder (_tc_CORBA_String, &profile->host, 0, &str, env)
+ != CORBA_TypeCode::TRAVERSE_CONTINUE
+ || !str.get_ushort (profile->port)) {
+ env.exception (new CORBA_MARSHAL (COMPLETED_MAYBE));
+ dmsg ("error decoding IIOP host/port");
+ objdata->Release ();
+ return CORBA_TypeCode::TRAVERSE_STOP;
+ }
+
+ //
+ // ... and object key
+ //
+ continue_decoding =
+ (decoder (&TC_opaque, &profile->object_key, 0, &str, env)
+ == CORBA_TypeCode::TRAVERSE_CONTINUE);
+
+ if (str.remaining != 0) {
+ env.exception (new CORBA_MARSHAL (COMPLETED_MAYBE));
+ dmsg ("extra data at end of IIOP profile data");
+ objdata->Release ();
+ return CORBA_TypeCode::TRAVERSE_STOP;
+ }
+ }
+ if (objdata == 0) {
+ env.exception (new CORBA_MARSHAL (COMPLETED_MAYBE));
+ dmsg2 ("no IIOP v%d.%d (or earlier) profile in IOR!",
+ IIOP::MY_MAJOR, IIOP::MY_MINOR);
+ return CORBA_TypeCode::TRAVERSE_STOP;
+ } else {
+ if (objdata->QueryInterface (IID_CORBA_Object, (void **) data)
+ != NOERROR)
+ continue_decoding = CORBA_B_FALSE;
+ objdata->Release ();
+ }
+ }
+ break;
+
+ case tk_sequence:
+ {
+ //
+ // First unmarshal the sequence length ... we trust it
+ // to be right here, on the "be gracious in what you
+ // accept" principle. We don't generate illegal sequences
+ // (i.e. length > bounds).
+ //
+ CORBA_OctetSeq *seq = (CORBA_OctetSeq *) data;
+
+ continue_decoding = stream->get_ulong (seq->length);
+ seq->maximum = seq->length;
+ seq->buffer = 0;
+
+ //
+ // Fast exit on empty sequences or errors
+ //
+ if (!continue_decoding || seq->length == 0)
+ break;
+
+ //
+ // ... then allocate the memory into which we'll unmarshal
+ //
+ CORBA_TypeCode_ptr tc2;
+ size_t size;
+
+ tc2 = tc->typecode_param (0, env);
+ if (env.exception ())
+ return CORBA_TypeCode::TRAVERSE_STOP;
+
+ size = tc2->size (env);
+ if (env.exception ())
+ return CORBA_TypeCode::TRAVERSE_STOP;
+
+ tc2->Release ();
+
+ seq->buffer = new CORBA_Octet [size * (size_t) seq->maximum];
+ }
+ // FALLTHROUGH
+
+ case tk_struct:
+ case tk_union:
+ case tk_array:
+ case tk_alias:
+ //
+ // Unmarshal all the individual elements using the per-member
+ // description held in the "parent" TypeCode.
+ //
+
+ // FALLTHROUGH
+
+ case tk_except:
+ //
+ // For exceptions, the "hidden" type ID near the front of the
+ // on-wire representation was previously unmarshaled and mapped
+ // to the "tc" typcode we're using to traverse the memory ...
+ // at the same time its vtable, refcount, and other state was
+ // established.
+ //
+ // NOTE: This is asymmetric with respect to encoding exceptions.
+ //
+ return tc->traverse (data, 0, decoder, context, env);
+
+ case tk_string:
+ {
+ CORBA_String str;
+ CORBA_ULong len = 0;
+
+ //
+ // On decode, omit the check against specified string bounds,
+ // and cope with illegal "zero length" strings (all lengths
+ // on the wire must include a NUL).
+ //
+ // This is on the principle of being gracious in what we accept;
+ // we don't generate messages that fail to comply with protocol
+ // specs, but we will accept them when it's clear how to do so.
+ //
+ continue_decoding = stream->get_ulong (len);
+ *((CORBA_String*)data) = str = new CORBA_Char [(size_t) (len)];
+ if (len != 0)
+ while (continue_decoding != CORBA_B_FALSE && len-- != 0) {
+ continue_decoding = stream->get_char (*(CORBA_Char *)str);
+ str++;
+ }
+ break;
+ }
+
+ case tk_wstring:
+ {
+ wchar_t *str;
+ CORBA_ULong len = 0;
+
+ //
+ // On decode, omit the check against specified wstring bounds,
+ // and cope with illegal "zero length" strings (all lengths
+ // on the wire must include a NUL).
+ //
+ // This is on the principle of being gracious in what we accept;
+ // we don't generate messages that fail to comply with protocol
+ // specs, but we will accept them when it's clear how to do so.
+ //
+ continue_decoding = stream->get_ulong (len);
+ *((wchar_t **)data) = str = new wchar_t [(size_t) (len)];
+ if (len != 0) {
+ while (continue_decoding != CORBA_B_FALSE && len--) {
+ continue_decoding = stream->get_wchar (*str);
+ str++;
+ }
+ }
+ }
+ break;
+
+ case tk_longdouble:
+ continue_decoding =
+ stream->get_longdouble (*(CORBA_LongDouble *)data);
+ break;
+
+ case tk_wchar:
+ continue_decoding = stream->get_wchar (*(wchar_t *)data);
+ break;
+
+ // case ~0:
+ default:
+ continue_decoding = CORBA_B_FALSE;
+ dmsg ("decode, default case?");
+ break;
+ }
+
+ if (continue_decoding == CORBA_B_FALSE) {
+ env.exception (new CORBA_MARSHAL (COMPLETED_NO));
+ dmsg ("marshaling decoder detected error");
+ return CORBA_TypeCode::TRAVERSE_STOP;
+ }
+ return CORBA_TypeCode::TRAVERSE_CONTINUE;
+}
+
diff --git a/TAO/IIOP/lib/runtime/nvlist.cpp b/TAO/IIOP/lib/runtime/nvlist.cpp
new file mode 100644
index 00000000000..896dd7c098f
--- /dev/null
+++ b/TAO/IIOP/lib/runtime/nvlist.cpp
@@ -0,0 +1,262 @@
+// @(#)nvlist.cpp 1.6 95/11/04
+// Copyright 1994-1995 by Sun Microsystems Inc.
+// All Rights Reserved
+//
+// Implementation of Named Value List
+//
+#include <assert.h>
+#include <memory.h>
+#include <corba/orb.hh>
+
+#include <initguid.h>
+
+#include "runtime/debug.hh"
+#include "runtime/thread.hh"
+
+
+#ifdef _POSIX_THREADS
+//
+// If POSIX threads are available, set up lock covering refcounts.
+//
+static pthread_mutex_t nvlist_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif // _POSIX_THREADS
+
+
+
+//
+// COM's IUnknown support
+//
+
+// {77420087-F276-11ce-9598-0000C07CA898}
+DEFINE_GUID (IID_CORBA_NamedValue,
+0x77420087, 0xf276, 0x11ce, 0x95, 0x98, 0x0, 0x0, 0xc0, 0x7c, 0xa8, 0x98);
+
+
+ULONG
+__stdcall
+CORBA_NamedValue::AddRef ()
+{
+#ifdef _POSIX_THREADS
+ Critical region (&nvlist_lock);
+#endif
+
+ return _refcount++;
+}
+
+ULONG
+__stdcall
+CORBA_NamedValue::Release ()
+{
+#ifdef _POSIX_THREADS
+ Critical region (&nvlist_lock);
+#endif
+
+ assert (this != 0);
+
+ if (--_refcount != 0)
+ return _refcount;
+
+ delete this;
+ return 0;
+}
+
+HRESULT
+__stdcall
+CORBA_NamedValue::QueryInterface (
+ REFIID riid,
+ void **ppv
+)
+{
+ *ppv = 0;
+
+ if (IID_CORBA_NamedValue == riid || IID_IUnknown == riid)
+ *ppv = this;
+
+ if (*ppv == 0)
+ return ResultFromScode (E_NOINTERFACE);
+
+ (void) AddRef ();
+ return NOERROR;
+}
+
+//
+// Reference counting for DII Request object
+//
+void
+CORBA_release (CORBA_NamedValue_ptr nv)
+{
+ if (nv)
+ nv->Release ();
+}
+
+CORBA_Boolean
+CORBA_is_nil (CORBA_NamedValue_ptr nv)
+{
+ return (CORBA_Boolean)(nv == 0);
+}
+
+CORBA_NamedValue::~CORBA_NamedValue ()
+{
+ if (_name)
+ CORBA_string_free ((CORBA_String)_name);
+}
+
+
+//
+// COM's IUnknown support
+//
+
+// {77420088-F276-11ce-9598-0000C07CA898}
+DEFINE_GUID (IID_CORBA_NVList,
+0x77420088, 0xf276, 0x11ce, 0x95, 0x98, 0x0, 0x0, 0xc0, 0x7c, 0xa8, 0x98);
+
+
+ULONG
+__stdcall
+CORBA_NVList::AddRef ()
+{
+#ifdef _POSIX_THREADS
+ Critical region (&nvlist_lock);
+#endif
+
+ return _refcount++;
+}
+
+ULONG
+__stdcall
+CORBA_NVList::Release ()
+{
+#ifdef _POSIX_THREADS
+ Critical region (&nvlist_lock);
+#endif
+
+ assert (this != 0);
+
+ if (--_refcount != 0)
+ return _refcount;
+
+ delete this;
+ return 0;
+}
+
+HRESULT
+__stdcall
+CORBA_NVList::QueryInterface (
+ REFIID riid,
+ void **ppv
+)
+{
+ *ppv = 0;
+
+ if (IID_CORBA_NVList == riid || IID_IUnknown == riid)
+ *ppv = this;
+
+ if (*ppv == 0)
+ return ResultFromScode (E_NOINTERFACE);
+
+ (void) AddRef ();
+ return NOERROR;
+}
+
+//
+// Reference counting for DII Request object
+//
+void
+CORBA_release (CORBA_NVList_ptr nvl)
+{
+ if (nvl)
+ nvl->Release ();
+}
+
+CORBA_Boolean
+CORBA_is_nil (CORBA_NVList_ptr nvl)
+{
+ return (CORBA_Boolean)(nvl == 0);
+}
+
+CORBA_NVList::~CORBA_NVList ()
+{
+ unsigned i;
+
+ for (i = 0; i < _len; i++)
+ (&_values [i])->~CORBA_NamedValue ();
+
+ if (_values)
+ free ((char *)_values);
+ _values = 0;
+ _len = _max = 0;
+}
+
+CORBA_NamedValue_ptr
+CORBA_NVList::add_value (
+ const CORBA_Char *name,
+ const CORBA_Any &value,
+ CORBA_Flags flags,
+ CORBA_Environment &env
+)
+{
+ env.clear ();
+
+ if (!(flags & (CORBA_ARG_IN|CORBA_ARG_OUT|CORBA_ARG_INOUT))) {
+ env.exception (new CORBA_BAD_PARAM (COMPLETED_NO));
+ return 0;
+ }
+
+ //
+ // We track "_len" and "_max" like sequences do; mixing the
+ // "add_arg" and nvlist[i] style accessors produces undefined
+ // behaviour.
+ //
+ unsigned len = _len++;
+
+ //
+ // Extend the array with an _initialized_ element ... relying on
+ // zeroed memory to be sufficiently initialized.
+ //
+ // XXX report malloc failures as errors -- how?
+ //
+ if (_values == 0) {
+ _values = (CORBA_NamedValue_ptr)
+ calloc (_len, sizeof (CORBA_NamedValue));
+ _max = _len;
+ } else if (len >= _max) {
+ _values = (CORBA_NamedValue_ptr) realloc ((char *)_values,
+ sizeof (CORBA_NamedValue) * _len);
+ (void) memset (&_values [_max], 0,
+ sizeof (_values [_max]) * (_len - _max));
+ _max = _len;
+ }
+ assert (_values != 0);
+
+ _values [len]._flags = flags;
+ _values [len]._name = CORBA_string_copy (name);
+
+ if (flags & CORBA_IN_COPY_VALUE) {
+ //
+ // IN_COPY_VALUE means that the parameter is not "borrowed"
+ // by the ORB, but rather that the ORB copies its value.
+ //
+ // Initialize the newly allocated memory using a copy
+ // constructor that places the new "Any" value at just
+ // the right place, and makes a "deep copy" of the data.
+ //
+ (void) new (&_values [len]._any) CORBA_Any (value);
+ } else {
+ //
+ // The normal behaviour for parameters is that the ORB
+ // "borrows" their memory for the duration of calls.
+ //
+ // Initialize the newly allocated "Any" using a normal
+ // constructor that places the new "Any" value at just
+ // the right place, yet doesn't copy the memory (except
+ // for duplicating the typecode).
+ //
+ // NOTE: DSI has yet to be updated so that it's OK to
+ // use such application-allocated memory. It needs at
+ // least a "send the response now" call.
+ //
+ (void) new (&_values [len]._any) CORBA_Any (value.type (),
+ value.value (), CORBA_B_FALSE);
+ }
+ return &_values [len];
+}
diff --git a/TAO/IIOP/lib/runtime/object.cpp b/TAO/IIOP/lib/runtime/object.cpp
new file mode 100644
index 00000000000..e496546fc65
--- /dev/null
+++ b/TAO/IIOP/lib/runtime/object.cpp
@@ -0,0 +1,405 @@
+// @(#)object.cpp 1.9 95/09/19
+// Copyright 1994-1995 by Sun Microsystems Inc.
+// All Rights Reserved
+//
+// ORB: CORBA::Object operations
+//
+
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+#include <corba/orb.hh>
+
+#include <corba/stub.hh>
+#include "runtime/debug.hh"
+
+#include <initguid.h>
+
+//
+// Constructor and destructor are accessible to subclasses
+//
+CORBA_Object::CORBA_Object (IUnknown *_jan)
+: parent (_jan)
+{
+ assert (parent != 0);
+}
+
+CORBA_Object::~CORBA_Object ()
+{
+}
+
+//
+// CORBA dup/release build on top of COM's (why not).
+//
+void
+CORBA_release (
+ CORBA_Object_ptr obj
+)
+{
+ if (obj)
+ obj->Release ();
+}
+
+CORBA_Object_ptr
+CORBA_Object::_duplicate (CORBA_Object_ptr obj)
+{
+ if (obj)
+ obj->AddRef ();
+ return obj;
+}
+
+//
+// Null pointers represent nil objects.
+//
+CORBA_Object_ptr
+CORBA_Object::_nil ()
+{
+ return 0;
+}
+
+CORBA_Boolean
+CORBA_is_nil (CORBA_Object_ptr obj)
+{
+ return (CORBA_Boolean) (obj == 0);
+}
+
+
+//
+// DII hook to objref
+//
+// The mapping for create_request is split into two forms, corresponding to
+// the two usage styles described in CORBA section 6.2.1.
+//
+void
+__stdcall
+CORBA_Object::_create_request (
+ const CORBA_Char *operation,
+ CORBA_NVList_ptr arg_list,
+ CORBA_NamedValue_ptr result,
+ CORBA_Request_ptr &request,
+ CORBA_Flags req_flags,
+ CORBA_Environment &env
+)
+{
+ env.clear ();
+ request = new CORBA_Request (this, operation, arg_list, result, req_flags);
+}
+
+
+CORBA_Request_ptr
+__stdcall
+CORBA_Object::_request (
+ const CORBA_Char *operation,
+ CORBA_Environment &env
+)
+{
+ env.clear ();
+ return new CORBA_Request (this, operation);
+}
+
+
+//
+// GET_INTERFACE ... send a simple call to the object, it returns
+// an InterfaceDef objref.
+//
+static const paramdata Object_get_interface_params [] = {
+ { _tc_CORBA_Object, PARAM_RETURN, 0 }
+ // XXX should be tc_InterfaceDef
+};
+static const calldata Object_get_interface_calldata = {
+ "_interface", CORBA_B_TRUE,
+ 1, &Object_get_interface_params [0],
+ 0, 0
+};
+
+
+CORBA_InterfaceDef_ptr
+__stdcall
+CORBA_Object::_get_interface (
+ CORBA_Environment &env
+)
+{
+ CORBA_InterfaceDef_ptr retval = 0;
+
+ //
+ // At this time, we only have a single generic way to find the
+ // CORBA interface def for an object.
+ //
+ STUB_Object *istub;
+
+ if (QueryInterface (IID_STUB_Object, (void **) &istub) != NOERROR) {
+ env.exception (new CORBA_DATA_CONVERSION (COMPLETED_NO));
+ return retval;
+ }
+ Release ();
+
+ //
+ // NOTE: If istub->type_id is nonzero, we could try asking a
+ // "local" interface repository and avoid costly network I/O.
+ // (It's wrong to have different data associated with the same
+ // interface ID in different repositories; the interface is
+ // the interface, it doesn't change!)
+ //
+ // We need to be prepared to ask the object itself for this
+ // information though, since there's no guarantee that any
+ // local interface repository will really have records of this
+ // particular interface.
+ //
+ istub->do_call (env, &Object_get_interface_calldata, &retval);
+ return retval;
+}
+
+
+//
+// IS_A ... ask the object if it's an instance of the type whose logical
+// type ID is passed as a parameter.
+//
+static const paramdata Object_is_a_params [] = {
+ { _tc_CORBA_Boolean, PARAM_RETURN, 0 },
+ { _tc_CORBA_String, PARAM_IN, 0 }
+};
+static const calldata Object_is_a_calldata = {
+ "_is_a", CORBA_B_TRUE,
+ 2, &Object_is_a_params [0],
+ 0, 0
+};
+
+
+CORBA_Boolean
+__stdcall
+CORBA_Object::_is_a (
+ const CORBA_Char *type_id,
+ CORBA_Environment &env
+)
+{
+ //
+ // At this time, we only have a single generic way to check the
+ // type of an object.
+ //
+ STUB_Object *istub;
+
+ if (QueryInterface (IID_STUB_Object, (void **) &istub) != NOERROR) {
+ env.exception (new CORBA_DATA_CONVERSION (COMPLETED_NO));
+ return CORBA_B_FALSE;
+ }
+ Release ();
+
+ //
+ // NOTE: if istub->type_id is nonzero and we have local knowledge
+ // of it, we can answer this question without a costly remote call.
+ //
+ // That "local knowledge" could come from stubs or skeletons linked
+ // into this process in the best case, or a "near" repository in a
+ // slightly worse case. Or in a trivial case, if the ID being asked
+ // about is the ID we have recorded, we don't need to ask about the
+ // inheritance relationships at all!
+ //
+ // In real systems having local knowledge will be common, though as the
+ // systems built atop ORBs become richer it'll also become common to
+ // have the "real type ID" not be directly understood because it's
+ // more deeply derived than any locally known types.
+ //
+ // XXX if type_id is that of CORBA::Object, "yes, we comply" :-)
+ //
+ if (istub->type_id != 0
+ && strcmp ((char *)type_id, (char *)istub->type_id) == 0)
+ return CORBA_B_TRUE;
+
+ //
+ // Our local knowledge about this type is insufficient to say whether
+ // this reference is to an object of a type which "is_a" subtype of
+ // the type whose ID is passed as a parameter. The implementation
+ // always knows the answer to that question, however!
+ //
+ CORBA_Boolean retval = CORBA_B_FALSE;
+
+ istub->do_call (env, &Object_is_a_calldata, &retval, &type_id);
+ return retval;
+}
+
+
+//
+// GET_IMPLEMENTATION ... send a simple call to the object, it returns
+// an ImplementationDef objref.
+//
+static const paramdata Object_get_implementation_params [] = {
+ { _tc_CORBA_Object, PARAM_RETURN, 0 }
+ // XXX should be tc_ImplementationDef
+};
+static const calldata Object_get_implementation_calldata = {
+ "_implementation", CORBA_B_TRUE,
+ 1, &Object_get_implementation_params [0],
+ 0, 0
+};
+
+
+CORBA_ImplementationDef_ptr
+__stdcall
+CORBA_Object::_get_implementation (
+ CORBA_Environment &env
+)
+{
+ STUB_Object *istub;
+ CORBA_ImplementationDef_ptr retval = 0;
+
+ if (QueryInterface (IID_STUB_Object, (void **) &istub) != NOERROR) {
+ env.exception (new CORBA_DATA_CONVERSION (COMPLETED_NO));
+ return retval;
+ }
+ Release ();
+
+ istub->do_call (env, &Object_get_implementation_calldata, &retval);
+ return retval;
+}
+
+
+//
+// NON_EXISTENT ... send a simple call to the object, which will
+// either elicit a FALSE response or a OBJECT_NOT_EXIST exception.
+// In the latter case, return FALSE.
+//
+static const paramdata Object_non_existent_params [] = {
+ { _tc_CORBA_Boolean, PARAM_RETURN, 0 }
+};
+static const calldata Object_non_existent_calldata = {
+ "_non_existent", CORBA_B_TRUE,
+ 1, &Object_non_existent_params [0],
+ 0, 0
+};
+
+
+CORBA_Boolean
+__stdcall
+CORBA_Object::_non_existent (
+ CORBA_Environment &env
+)
+{
+ CORBA_Boolean retval = CORBA_B_FALSE;
+ CORBA_Exception *x;
+ STUB_Object *istub;
+
+ if (QueryInterface (IID_STUB_Object, (void **) &istub) != NOERROR) {
+ env.exception (new CORBA_DATA_CONVERSION (COMPLETED_NO));
+ return CORBA_B_FALSE;
+ }
+ Release ();
+
+ istub->do_call (env, &Object_non_existent_calldata, &retval);
+
+ if ((x = env.exception ()) != 0) {
+ char *id;
+
+ id = _tc_CORBA_OBJECT_NOT_EXIST->id (env);
+ if (env.exception () == 0
+ && strcmp (id, x->id ()) == 0) {
+ env.clear ();
+ return CORBA_B_TRUE;
+ }
+ //
+ // reporting a "real" exception ...
+ //
+ return CORBA_B_FALSE;
+ } else {
+ env.clear ();
+ return CORBA_B_FALSE;
+ }
+}
+
+
+//
+// Quickly hash an object reference's representation data.
+// Used to create hash tables.
+//
+CORBA_ULong
+__stdcall
+CORBA_Object::_hash (
+ CORBA_ULong maximum,
+ CORBA_Environment &env
+)
+{
+ STUB_Object *istub;
+
+ if (QueryInterface (IID_STUB_Object, (void **) &istub) != NOERROR) {
+ env.exception (new CORBA_DATA_CONVERSION (COMPLETED_NO));
+ return CORBA_B_FALSE;
+ }
+ Release ();
+
+ return istub->hash (maximum, env);
+}
+
+
+//
+// Compare two object references to see if they point to the
+// same object. Used in linear searches, as in hash buckets.
+//
+// XXX would be useful to also have a trivalued comparison predicate,
+// such as strcmp(), to allow more comparison algorithms.
+//
+CORBA_Boolean
+__stdcall
+CORBA_Object::_is_equivalent (
+ CORBA_Object_ptr other_obj,
+ CORBA_Environment &env
+)
+{
+ STUB_Object *istub;
+
+ if (other_obj == this) {
+ env.clear ();
+ return CORBA_B_TRUE;
+ }
+
+ if (QueryInterface (IID_STUB_Object, (void **) &istub) != NOERROR) {
+ env.exception (new CORBA_DATA_CONVERSION (COMPLETED_NO));
+ return CORBA_B_FALSE;
+ }
+ Release ();
+
+ return istub->is_equivalent (other_obj, env);
+}
+
+
+//
+// COM's IUnknown support
+//
+
+#if unix
+//
+// XXX this is not the GUID that Microsoft uses. It can matter.
+//
+
+// {77420089-F276-11ce-9598-0000C07CA898}
+DEFINE_GUID (IID_IUnknown,
+0x77420089, 0xf276, 0x11ce, 0x95, 0x98, 0x0, 0x0, 0xc0, 0x7c, 0xa8, 0x98);
+#endif
+
+// {A201E4C2-F258-11ce-9598-0000C07CA898}
+DEFINE_GUID (IID_CORBA_Object,
+0xa201e4c2, 0xf258, 0x11ce, 0x95, 0x98, 0x0, 0x0, 0xc0, 0x7c, 0xa8, 0x98);
+
+
+ULONG
+__stdcall
+CORBA_Object::AddRef ()
+{
+ return parent->AddRef ();
+}
+
+ULONG
+__stdcall
+CORBA_Object::Release ()
+{
+ return parent->Release ();
+}
+
+HRESULT
+__stdcall
+CORBA_Object::QueryInterface (
+ REFIID riid,
+ void **ppv
+)
+{
+ return parent->QueryInterface (riid, ppv);
+}
+
diff --git a/TAO/IIOP/lib/runtime/orbobj.cpp b/TAO/IIOP/lib/runtime/orbobj.cpp
new file mode 100644
index 00000000000..ae84d6bdd83
--- /dev/null
+++ b/TAO/IIOP/lib/runtime/orbobj.cpp
@@ -0,0 +1,317 @@
+// @(#)orbobj.cpp 1.8 95/09/24
+// Copyright 1994-1995 by Sun Microsystems Inc.
+// All Rights Reserved
+//
+// ORB: CORBA::ORB operations
+//
+// XXX as with TOA, this has a strong coupling to the Internet ORB (IIOP)
+// code. We should make it know less about that protocol component and
+// have a loose table-driven coupling to ORB/protocol library components.
+//
+
+#include <assert.h>
+#include <limits.h>
+#include <signal.h>
+#include <string.h>
+
+#include <corba/orb.hh>
+#include <corba/stub.hh>
+
+#include "runtime/debug.hh"
+#include "runtime/thread.hh"
+
+#include "bridge/iioporb.hh" // XXX
+
+#include <initguid.h>
+
+
+extern void __TC_init_table ();
+extern void __TC_init_standard_exceptions (CORBA_Environment &env);
+
+#ifdef _POSIX_THREADS
+static pthread_mutex_t refcnt_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+#if defined (SIG_IGN_BROKEN)
+# undef SIG_IGN
+# define SIG_IGN ((RETSIGTYPE (*)(int))1)
+#endif // NeXT
+
+
+//
+// Constructor and destructor are accessible to subclasses
+//
+CORBA_ORB::CORBA_ORB ()
+{
+ _refcount = 1;
+}
+
+CORBA_ORB::~CORBA_ORB ()
+{
+ assert (_refcount == 0);
+}
+
+//
+// CORBA dup/release build on top of COM's (why not).
+//
+void
+CORBA_release (
+ CORBA_ORB_ptr obj
+)
+{
+ if (obj)
+ obj->Release ();
+}
+
+CORBA_ORB_ptr
+CORBA_ORB::_duplicate (CORBA_ORB_ptr obj)
+{
+ if (obj)
+ obj->AddRef ();
+ return obj;
+}
+
+//
+// Null pointers represent nil objects.
+//
+CORBA_ORB_ptr
+CORBA_ORB::_nil ()
+{
+ return 0;
+}
+
+CORBA_Boolean
+CORBA_is_nil (CORBA_ORB_ptr obj)
+{
+ return (CORBA_Boolean) (obj == 0);
+}
+
+
+//
+// COM's IUnknown support
+//
+
+// {A201E4C6-F258-11ce-9598-0000C07CA898}
+DEFINE_GUID (IID_CORBA_ORB,
+0xa201e4c6, 0xf258, 0x11ce, 0x95, 0x98, 0x0, 0x0, 0xc0, 0x7c, 0xa8, 0x98);
+
+// {A201E4C7-F258-11ce-9598-0000C07CA898}
+DEFINE_GUID (IID_STUB_Object,
+0xa201e4c7, 0xf258, 0x11ce, 0x95, 0x98, 0x0, 0x0, 0xc0, 0x7c, 0xa8, 0x98);
+
+
+ULONG
+__stdcall
+CORBA_ORB::AddRef ()
+{
+#ifdef _POSIX_THREADS
+ Critical region (&refcnt_lock);
+#endif
+
+ return _refcount++;
+}
+
+ULONG
+__stdcall
+CORBA_ORB::Release ()
+{
+#ifdef _POSIX_THREADS
+ Critical region (&refcnt_lock);
+#endif
+
+ assert (this != 0);
+
+ if (--_refcount != 0)
+ return _refcount;
+
+#ifdef _POSIX_THREADS
+ region.leave ();
+#endif
+
+ delete this;
+ return 0;
+}
+
+
+//
+// ORB initialisation, per OMG document 94-9-46.
+//
+// XXX in addition to the "built in" Internet ORB, there will be ORBs which
+// are added separately, e.g. through a DLL listed in the registry. Registry
+// will be used to assign orb names and to establish which is the default.
+//
+static CORBA_ORB_ptr the_orb;
+
+CORBA_ORB_ptr
+CORBA_ORB_init (
+ int &, // argc
+ char *const *, // argv
+ char *orb_name,
+ CORBA_Environment &env
+)
+{
+#ifdef _POSIX_THREADS
+ static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+
+ Critical region (&lock);
+#endif // _POSIX_THREADS
+
+ env.clear ();
+
+ //
+ // Initialising is done only once.
+ //
+ // XXX Applications that can't tell if they've initialized (e.g.
+ // some library modules) must check for a particular error and ignore
+ // it if they get it. We need a minor code to indicate this case.
+ // In general, one-time initialization is suboptimal.
+ //
+ // XXX We also need to enable initialising more than one ORB!!
+ //
+ if (the_orb) {
+ env.exception (new CORBA_INITIALIZE (COMPLETED_NO));
+ return 0;
+ }
+
+ //
+ // Verify some of the basic implementation requirements. This test
+ // gets optimized away by a decent compiler (or else the rest of the
+ // routine does).
+ //
+ // NOTE: we still "just" assume that native floating point is IEEE.
+ //
+ if (sizeof (CORBA_Short) != 2
+ || sizeof (CORBA_Long) != 4
+ || sizeof (CORBA_LongLong) != 8
+ || sizeof (CORBA_Float) != 4
+ || sizeof (CORBA_Double) != 8
+ || sizeof (CORBA_LongDouble) != 16
+ || sizeof (CORBA_WChar) < 2
+ || sizeof (void *) != SIZEOF_VOID_P
+ ) {
+ env.exception (new CORBA_INITIALIZE (COMPLETED_NO));
+ return 0;
+ }
+
+ //
+ // ignoring argc, argv for now -- no arguments we care about
+ //
+ // XXX should remove any of the "-ORB*" arguments that we know
+ // about ... and report errors for the rest.
+ //
+
+#ifdef DEBUG
+ //
+ // Make it a little easier to debug programs using this code.
+ //
+ {
+ char *value = getenv ("ORB_DEBUG");
+
+ if (value != 0) {
+ debug_level = atoi (value);
+ if (debug_level <= 0)
+ debug_level = 1;
+ dmsg1 ("debug_level == %d", debug_level);
+ }
+ }
+#endif // DEBUG
+
+ //
+ // On Win32, we should be collecting information from the Registry
+ // such as what ORBs are configured, specific configuration details
+ // like whether they generate IOR or URL style stringified objrefs
+ // and which addresses they listen to (e.g. allowing multihomed
+ // hosts to implement firewalls), user-meaningful orb names (they
+ // will normally indicate domains), and more.
+ //
+ // On UNIX, we should collect that from some private config file.
+ //
+ // Instead, this just treats the "internet" ORB name specially and
+ // makes it always use URL-style stringified objrefs, where the
+ // hostname and TCP port number are explicit (and the whole objref
+ // is readable by mortals).
+ //
+ CORBA_Boolean use_ior;
+
+ if (orb_name != 0 && strcmp (orb_name, "internet") == 0)
+ use_ior = CORBA_B_FALSE;
+ else
+ use_ior = CORBA_B_TRUE;
+
+#ifdef SIGPIPE
+ //
+ // Impractical to have each call to the ORB protect against the
+ // implementation artifact of potential writes to dead connections,
+ // as it'd be way expensive. Do it here; who cares about SIGPIPE
+ // in these kinds of applications, anyway?
+ //
+ (void) signal (SIGPIPE, SIG_IGN);
+#endif // SIGPIPE
+
+#if defined (_WINSOCKAPI_)
+ //
+ // winsock needs explicit initialization, and applications must manage
+ // versioning problems directly.
+ //
+ WSADATA wsadata;
+
+ if (WSAStartup (MAKEWORD (1, 1), &wsadata) != 0) {
+ dsockerr ("WSAStartup");
+ env.exception (new CORBA_INITIALIZE (COMPLETED_NO));
+ return 0;
+ }
+ if (LOBYTE (wsadata.wVersion) != 1 || HIBYTE (wsadata.wVersion != 1)) {
+ dmsg2 ("bad winsock version %d.%d",
+ HIBYTE (wsadata.wVersion), LOBYTE (wsadata.wVersion));
+ env.exception (new CORBA_INITIALIZE (COMPLETED_NO));
+ return 0;
+ }
+#endif // _WINSOCKAPI_
+
+ //
+ // Call various internal initialization routines.
+ //
+ __TC_init_table ();
+ __TC_init_standard_exceptions (env);
+ if (env.exception () != 0)
+ return 0;
+
+ //
+ // Inititalize the "ORB" pseudo-object now.
+ //
+ the_orb = new IIOP_ORB (use_ior);
+
+ return the_orb;
+}
+
+void
+CORBA_ORB::create_list (
+ CORBA_Long count,
+ CORBA_NVList_ptr &retval
+)
+{
+ assert (count <= UINT_MAX);
+
+ retval = new CORBA_NVList;
+
+ if (count != 0) {
+ retval->_len = 0;
+ retval->_max = (unsigned) count;
+ retval->_values = (CORBA_NamedValue_ptr) calloc ((unsigned) count,
+ sizeof (CORBA_NamedValue));
+ }
+}
+
+
+//
+// This is a server-side internal routine; it's not available to any
+// portable code except method code, which moreover may not access the
+// state variable directly since its implemention may differ between ORBs.
+//
+// XXX it's server-side so should be OA-specific and not in this module
+//
+CORBA_ORB_ptr
+_orb ()
+{
+ return the_orb;
+}
diff --git a/TAO/IIOP/lib/runtime/principa.cpp b/TAO/IIOP/lib/runtime/principa.cpp
new file mode 100644
index 00000000000..150031b5f68
--- /dev/null
+++ b/TAO/IIOP/lib/runtime/principa.cpp
@@ -0,0 +1,107 @@
+// @(#)principa.cpp 1.4 95/11/04
+// Copyright 1994-1995 by Sun Microsystems Inc.
+// All Rights Reserved
+//
+// ORB: Principal identifier pseudo-objref
+//
+
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+#include <corba/orb.hh>
+
+#include <initguid.h>
+
+#include "runtime/thread.hh"
+
+
+#ifdef _POSIX_THREADS
+//
+// If POSIX threads are available, set up lock covering refcounts.
+//
+static pthread_mutex_t principal_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif // _POSIX_THREADS
+
+
+void
+CORBA_release (CORBA_Principal_ptr principal)
+{
+ if (principal)
+ principal->Release ();
+}
+
+CORBA_Boolean
+CORBA_is_nil (CORBA_Principal_ptr principal)
+{
+ return (CORBA_Boolean)(principal == 0);
+}
+
+CORBA_Principal::CORBA_Principal ()
+{
+}
+
+CORBA_Principal::~CORBA_Principal ()
+{
+ assert (_refcount == 0);
+
+ if (id.buffer)
+ delete id.buffer;
+}
+
+//
+// For COM -- IUnKnown operations
+//
+
+// {A201E4C0-F258-11ce-9598-0000C07CA898}
+DEFINE_GUID (IID_CORBA_Principal,
+0xa201e4c0, 0xf258, 0x11ce, 0x95, 0x98, 0x0, 0x0, 0xc0, 0x7c, 0xa8, 0x98);
+
+
+ULONG
+__stdcall
+CORBA_Principal::AddRef ()
+{
+#ifdef _POSIX_THREADS
+ Critical region (&principal_lock);
+#endif
+
+ return ++_refcount;
+}
+
+ULONG
+__stdcall
+CORBA_Principal::Release ()
+{
+#ifdef _POSIX_THREADS
+ Critical region (&principal_lock);
+#endif
+
+ if (--_refcount != 0)
+ return _refcount;
+
+#ifdef _POSIX_THREADS
+ region.leave ();
+#endif
+
+ delete this;
+ return 0;
+}
+
+HRESULT
+__stdcall
+CORBA_Principal::QueryInterface (
+ REFIID riid,
+ void **ppv
+)
+{
+ *ppv = 0;
+
+ if (IID_CORBA_Principal == riid || IID_IUnknown == riid)
+ *ppv = this;
+
+ if (*ppv == 0)
+ return ResultFromScode (E_NOINTERFACE);
+
+ (void) AddRef ();
+ return NOERROR;
+}
diff --git a/TAO/IIOP/lib/runtime/request.cpp b/TAO/IIOP/lib/runtime/request.cpp
new file mode 100644
index 00000000000..2143603ae2c
--- /dev/null
+++ b/TAO/IIOP/lib/runtime/request.cpp
@@ -0,0 +1,168 @@
+// @(#)request.cpp 1.6 95/09/24
+// Copyright 1994-1995 by Sun Microsystems Inc.
+// All Rights Reserved
+//
+// Implementation of Dynamic Invocation Interface
+//
+#include <corba/orb.hh>
+#include <corba/stub.hh>
+
+#include <initguid.h>
+
+#include "runtime/debug.hh"
+#include "runtime/cdr.hh"
+#include "runtime/thread.hh"
+
+
+// {77420085-F276-11ce-9598-0000C07CA898}
+DEFINE_GUID (IID_CORBA_Request,
+0x77420085, 0xf276, 0x11ce, 0x95, 0x98, 0x0, 0x0, 0xc0, 0x7c, 0xa8, 0x98);
+
+#ifdef _POSIX_THREADS
+static pthread_mutex_t refcnt_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif // _POSIX_THREADS
+
+
+ULONG
+__stdcall
+CORBA_Request::AddRef ()
+{
+#ifdef _POSIX_THREADS
+ Critical region (&refcnt_lock);
+#endif
+
+ return _refcount++;
+}
+
+ULONG
+__stdcall
+CORBA_Request::Release ()
+{
+#ifdef _POSIX_THREADS
+ Critical region (&refcnt_lock);
+#endif
+
+ assert (this != 0);
+
+ if (--_refcount != 0)
+ return _refcount;
+
+ delete this;
+ return 0;
+}
+
+HRESULT
+__stdcall
+CORBA_Request::QueryInterface (
+ REFIID riid,
+ void **ppv
+)
+{
+ *ppv = 0;
+
+ if (IID_CORBA_Request == riid || IID_IUnknown == riid)
+ *ppv = this;
+
+ if (*ppv == 0)
+ return ResultFromScode (E_NOINTERFACE);
+
+ (void) AddRef ();
+ return NOERROR;
+}
+
+//
+// Reference counting for DII Request object
+//
+void
+CORBA_release (CORBA_Request_ptr req)
+{
+ if (req)
+ req->Release ();
+}
+
+CORBA_Boolean
+CORBA_is_nil (CORBA_Request_ptr req)
+{
+ return (CORBA_Boolean)(req == 0);
+}
+
+//
+// DII Request class implementation
+//
+CORBA_Request::CORBA_Request (
+ CORBA_Object_ptr obj,
+ const CORBA_Char *op,
+ CORBA_NVList_ptr args,
+ CORBA_NamedValue_ptr result,
+ CORBA_Flags flags
+) :
+ _args (args),
+ _result (result),
+ _flags (flags),
+ _refcount (1)
+{
+ _target = CORBA_Object::_duplicate (obj);
+ _opname = CORBA_string_copy (op);
+}
+
+
+CORBA_Request::CORBA_Request (
+ CORBA_Object_ptr obj,
+ const CORBA_Char *op
+) :
+ _flags (0),
+ _refcount (1)
+{
+ _target = CORBA_Object::_duplicate (obj);
+ _opname = CORBA_string_copy (op);
+
+ _args = new CORBA_NVList;
+ _result = new CORBA_NamedValue;
+}
+
+CORBA_Request::~CORBA_Request ()
+{
+ assert (_refcount == 0);
+
+ CORBA_release (_target);
+ CORBA_string_free ((CORBA_String)_opname);
+ CORBA_release (_args);
+ CORBA_release (_result);
+}
+
+//
+// The public DII interfaces: normal and oneway calls.
+//
+// NOTE that using DII, programmers can get the special behaviour of
+// discarding the response for normal calls. This doesn't change the
+// semantics of any OMG-IDL interface, it just streamlines control flow
+// in some exotic situations.
+//
+void
+CORBA_Request::invoke ()
+{
+ STUB_Object *stub;
+
+ if (_target->QueryInterface (IID_STUB_Object, (void **) &stub) != NOERROR) {
+ _env.exception (new CORBA_DATA_CONVERSION (COMPLETED_NO));
+ return;
+ }
+
+ stub->do_dynamic_call ((char *)_opname, CORBA_B_TRUE,
+ _args, _result, _flags, _exceptions, _env);
+ stub->Release ();
+}
+
+void
+CORBA_Request::send_oneway ()
+{
+ STUB_Object *stub;
+
+ if (_target->QueryInterface (IID_STUB_Object, (void **) &stub) != NOERROR) {
+ _env.exception (new CORBA_DATA_CONVERSION (COMPLETED_NO));
+ return;
+ }
+ stub->do_dynamic_call ((char *)_opname, CORBA_B_TRUE,
+ _args, _result, _flags, _exceptions, _env);
+ stub->Release ();
+}
diff --git a/TAO/IIOP/lib/runtime/t-xdr.cpp b/TAO/IIOP/lib/runtime/t-xdr.cpp
new file mode 100644
index 00000000000..fcfb99fd72c
--- /dev/null
+++ b/TAO/IIOP/lib/runtime/t-xdr.cpp
@@ -0,0 +1,268 @@
+// XDR record stream ... test encode performance against CDR, using
+// normal kinds of inlining performance hacks
+//
+// XXX as of 3-Nov-95 XDR_stream should only be relied on to marshal the
+// simplest primitives ... not objrefs, typecodes, etc. Also, the
+// handling of sequences of chars/octets/shorts/wchars is wrong.
+//
+// It's suitable only for a simple performance test just now ...
+//
+
+
+#include <string.h>
+#include <unistd.h>
+#include <widec.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <corba/orb.hh>
+
+#include "runtime/cdr.hh"
+#include "runtime/debug.hh"
+
+#include "onc/xdr.hh"
+
+
+// A structure that's somewhat representative of an IIOP message
+// in terms of overall complexity, so that its encoding cost is
+// "interesting"
+
+typedef CORBA_SEQUENCE <CORBA_Octet> opaque;
+
+struct interesting {
+
+// A call that's mostly going to be "on the mark" for IIOP-ish
+// messages with small numbers of parameters:
+
+// 4 chars magic
+// 2 bytes version
+// 1 byte byte-order
+// 1 byte message type ---> 8 bytes "pure header"
+ CORBA_Char hdr_bytes [8];
+// 1 word message size --=> end of GIOP::MessageHeader
+ CORBA_ULong hdr_len;
+
+// Service Context (1 word min)
+ CORBA_ULong empty_ctx;
+// 1 word request id
+ CORBA_ULong request_id;
+// 1 byte response-expected flag
+ CORBA_Boolean response_expected;
+// [ CDR: 3 bytes padding ]
+// opaque object key (1 word min; typically less than 16 bytes)
+ opaque object_key;
+// string operation name (non-empty ... often less than 10 bytes)
+ CORBA_String opname;
+// Principal client (1 word min)
+ opaque client_id;
+
+// --=> END OF GIOP::RequestHeader
+
+// ... small number of parameters with any significance
+
+// 2 word parameters
+ CORBA_ULong param1;
+ CORBA_ULong param2;
+// 1 string parameter
+ CORBA_String param3;
+
+};
+
+// XXX declare CDR typecode for above type ... initialize and use
+// one instance in the test below
+
+extern CORBA_TypeCode TC_opaque;
+
+static void
+do_test (
+ int use_XDR,
+ CORBA_TypeCode_ptr tc,
+ void *data
+)
+{
+ unsigned loopcount = 100 * 1000;
+ unsigned i;
+ unsigned error_count = 0;
+ timeval before, after;
+ CORBA_String opname = "kill_husband";
+ opaque key;
+ CORBA_Boolean status;
+
+ key.buffer = (CORBA_Octet *) "jacqueline";
+ key.length = key.maximum = 10;
+
+ if (gettimeofday (&before, 0) < 0)
+ dperror ("gettimeofday before");
+
+ if (use_XDR) {
+
+ // Using XDR APIs and encoding rules ...
+ // encode the structure repeatedly
+
+ for (i = 0; i < loopcount; i++) {
+ CORBA_Environment env;
+ XDR_stream stream (-1);
+
+ // GIOP header plus most of request header
+ status = status
+ && stream.put_long ('GIOP') // magic
+ && stream.put_long ('\01\01\01\01') // version etc
+ && stream.put_long (99) // msg len
+ && stream.put_long (0) // no svc ctx
+ && stream.put_long (42) // request ID
+ && stream.put_boolean (CORBA_B_TRUE)// response?
+ ;
+
+ if (status)
+ status = XDR_stream::encoder (&TC_opaque, &key, 0, &stream, env)
+ == CORBA_TypeCode::TRAVERSE_CONTINUE;
+
+ if (status)
+ status = XDR_stream::encoder (_tc_CORBA_String, &opname,
+ 0, &stream, env)
+ == CORBA_TypeCode::TRAVERSE_CONTINUE;
+
+ /*
+ if (status)
+ status = XDR_stream::encoder (_tc_CORBA_Principal, &key,
+ 0, &stream, env)
+ == CORBA_TypeCode::TRAVERSE_CONTINUE;
+ */
+
+ // Parameters: two longs, a string
+ status = status
+ && stream.put_long (99)
+ && stream.put_long (-3455);
+ if (status)
+ status = XDR_stream::encoder (_tc_CORBA_String, &opname,
+ 0, &stream, env)
+ == CORBA_TypeCode::TRAVERSE_CONTINUE;
+
+ // Gratuitous extra "interesting" data
+ status = XDR_stream::encoder (tc, data, 0, &stream, env)
+ == CORBA_TypeCode::TRAVERSE_CONTINUE;
+
+
+ if (status != CORBA_B_TRUE)
+ error_count++;
+ }
+
+ } else {
+
+ // This branch is the same, but using CDR APIs and encoding ...
+ // encode the structure repeatedly
+
+ for (i = 0; i < loopcount; i++) {
+ CORBA_Environment env;
+ unsigned char buffer [CDR::DEFAULT_BUFSIZE];
+ CDR stream (buffer, sizeof buffer);
+
+ // GIOP header plus most of request header
+ status = status
+ && stream.put_long ('GIOP') // magic
+ && stream.put_long ('\01\01\01\01') // version etc
+ && stream.put_long (99) // msg len
+ && stream.put_long (0) // no svc ctx
+ && stream.put_long (42) // request ID
+ && stream.put_boolean (CORBA_B_TRUE)// response?
+ ;
+
+ if (status)
+ status = CDR::encoder (&TC_opaque, &key, 0, &stream, env)
+ == CORBA_TypeCode::TRAVERSE_CONTINUE;
+
+ if (status)
+ status = CDR::encoder (_tc_CORBA_String, &opname,
+ 0, &stream, env)
+ == CORBA_TypeCode::TRAVERSE_CONTINUE;
+
+ /*
+ if (status)
+ status = CDR::encoder (_tc_CORBA_Principal, &key,
+ 0, &stream, env)
+ == CORBA_TypeCode::TRAVERSE_CONTINUE;
+ */
+
+ // Parameters: two longs, a string
+ status = status
+ && stream.put_long (99)
+ && stream.put_long (-3455);
+ if (status)
+ status = CDR::encoder (_tc_CORBA_String, &opname,
+ 0, &stream, env)
+ == CORBA_TypeCode::TRAVERSE_CONTINUE;
+
+ // Gratuitous extra "interesting" data
+ status = CDR::encoder (tc, data, 0, &stream, env)
+ == CORBA_TypeCode::TRAVERSE_CONTINUE;
+
+
+ if (status != CORBA_B_TRUE)
+ error_count++;
+ }
+
+ }
+
+ if (gettimeofday (&after, 0) < 0)
+ dperror ("gettimeofday after");
+
+ if (loopcount > 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 /= loopcount;
+
+ printf ("%s average encode time\t= %ld.%.03ldms, \t"
+ "%ld calls/second\n",
+ use_XDR ? "XDR" : "CDR",
+ us / 1000, us % 1000,
+ 1000000L / us);
+ }
+
+ printf ("%d calls, %d errors\n", loopcount, error_count);
+ }
+}
+
+
+int
+main (
+ int argc,
+ char **argv
+)
+{
+ int c;
+ int use_XDR = 1;
+ CORBA_TypeCode_ptr tc = _tc_CORBA_TypeCode;
+ void *data = tc;
+
+ while ((c = getopt (argc, argv, "cx")) != EOF) {
+ switch (c) {
+ case 'c':
+ use_XDR = 0;
+ continue;
+
+ case 'x':
+ use_XDR = 1;
+ continue;
+
+ case '?':
+ default:
+// usage:
+ fprintf (stderr, "usage: %s"
+ , " [-cx]"
+ , "\n"
+ , argv [0]
+ );
+ }
+ }
+
+ do_test (1, tc, data); // XDR-ish
+ do_test (0, tc, data); // CDR
+
+ return 0;
+}
+
diff --git a/TAO/IIOP/lib/runtime/tc_const.cpp b/TAO/IIOP/lib/runtime/tc_const.cpp
new file mode 100644
index 00000000000..2ec2be262e8
--- /dev/null
+++ b/TAO/IIOP/lib/runtime/tc_const.cpp
@@ -0,0 +1,133 @@
+// @(#)tc_const.cpp 1.3 95/09/12
+// Copyright 1994-1995 by Sun Microsystems Inc.
+// All Rights Reserved
+//
+// ORB: All the CORBA-specified typecode constants.
+//
+// NOTE: IFR TypeCode constants aren't here; they're left for an IDL
+// compiler to generate from the appropriate IDL source.
+//
+// NOTE: it'd be nice to have these not use init sections. Most can easily
+// be in readonly data (e.g. text segment, ROM) rather than writable data;
+// that speeds program startup and page sharing in shared libraries.
+//
+// THREADING NOTE: no issues, these are immutable constants
+//
+
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+#include <corba/orb.hh>
+
+//
+// Null and void
+//
+static CORBA_TypeCode tc_null (tk_null);
+const CORBA_TypeCode_ptr _tc_CORBA_Null = (CORBA_TypeCode_ptr) &tc_null;
+
+CORBA_TypeCode_ptr
+CORBA_TypeCode::_nil ()
+{
+ return &tc_null;
+}
+
+static CORBA_TypeCode tc_void (tk_void);
+const CORBA_TypeCode_ptr _tc_CORBA_Void = &tc_void;
+
+//
+// Basic numeric types: short, long, longlong, and unsigned variants
+//
+static CORBA_TypeCode tc_short (tk_short);
+const CORBA_TypeCode_ptr _tc_CORBA_Short = &tc_short;
+
+static CORBA_TypeCode tc_long (tk_long);
+const CORBA_TypeCode_ptr _tc_CORBA_Long = &tc_long;
+
+static CORBA_TypeCode tc_longlong (tk_longlong);
+const CORBA_TypeCode_ptr _tc_CORBA_LongLong = &tc_longlong;
+
+static CORBA_TypeCode tc_ushort (tk_ushort);
+const CORBA_TypeCode_ptr _tc_CORBA_UShort = &tc_ushort;
+
+static CORBA_TypeCode tc_ulong (tk_ulong);
+const CORBA_TypeCode_ptr _tc_CORBA_ULong = &tc_ulong;
+
+static CORBA_TypeCode tc_ulonglong (tk_ulonglong);
+const CORBA_TypeCode_ptr _tc_CORBA_ULongLong = &tc_ulonglong;
+
+//
+// Floating point types: single, double, quad precision
+//
+static CORBA_TypeCode tc_float (tk_float);
+const CORBA_TypeCode_ptr _tc_CORBA_Float = &tc_float;
+
+static CORBA_TypeCode tc_double (tk_double);
+const CORBA_TypeCode_ptr _tc_CORBA_Double = &tc_double;
+
+static CORBA_TypeCode tc_longdouble (tk_longdouble);
+const CORBA_TypeCode_ptr _tc_CORBA_LongDouble = &tc_longdouble;
+
+//
+// Various simple quantities
+//
+static CORBA_TypeCode tc_boolean (tk_boolean);
+const CORBA_TypeCode_ptr _tc_CORBA_Boolean = &tc_boolean;
+
+static CORBA_TypeCode tc_octet (tk_octet);
+const CORBA_TypeCode_ptr _tc_CORBA_Octet = &tc_octet;
+
+//
+// Internationalization-related data types: ISO Latin/1 and "wide"
+// characters, and strings of each. "wchar" is probably Unicode 1.1,
+// "wstring" being null-terminated sets thereof.
+//
+static CORBA_TypeCode tc_char (tk_char);
+const CORBA_TypeCode_ptr _tc_CORBA_Char = &tc_char;
+
+static CORBA_TypeCode tc_wchar (tk_wchar);
+const CORBA_TypeCode_ptr _tc_CORBA_WChar = &tc_wchar;
+
+static CORBA_TypeCode tc_string (tk_string);
+const CORBA_TypeCode_ptr _tc_CORBA_String = &tc_string;
+
+static CORBA_TypeCode tc_wstring (tk_wstring);
+const CORBA_TypeCode_ptr _tc_CORBA_WString = &tc_wstring;
+
+//
+// Various things that can be passed as "general" parameters:
+// Any, TypeCode_ptr, Principal_ptr, Object_ptr
+//
+static CORBA_TypeCode tc_any (tk_any);
+const CORBA_TypeCode_ptr _tc_CORBA_Any = &tc_any;
+
+static CORBA_TypeCode tc_typecode (tk_TypeCode);
+const CORBA_TypeCode_ptr _tc_CORBA_TypeCode = &tc_typecode;
+
+static CORBA_TypeCode tc_principal (tk_Principal);
+const CORBA_TypeCode_ptr _tc_CORBA_Principal = &tc_principal;
+
+//
+// typecode for objref is complex, has two string parameters
+//
+// NOTE: Must be four-byte aligned
+//
+static const unsigned char oc_objref [] = {
+ 0, 0, 0, 0, // big endian encoding (+ padding)
+ 0, 0, 0, 29, // 29 char string + 3 pad bytes
+ 'I', 'D', 'L', ':',
+ 'o', 'm', 'g', '.',
+ 'o', 'r', 'g', '/',
+ 'C', 'O', 'R', 'B',
+ 'A', '/', 'O', 'b',
+ 'j', 'e', 'c', 't',
+ ':', '1', '.', '0',
+ '\0', 0, 0, 0,
+ 0, 0, 0, 7, // 7 chars "Object" + 1 pad byte
+ 'O', 'b', 'j', 'e',
+ 'c', 't', '\0', 0,
+};
+static CORBA_TypeCode
+ tc_objref (tk_objref, sizeof oc_objref,
+ (unsigned char *)&oc_objref, CORBA_B_FALSE);
+const CORBA_TypeCode_ptr _tc_CORBA_Object = &tc_objref;
+
diff --git a/TAO/IIOP/lib/runtime/thread.hh b/TAO/IIOP/lib/runtime/thread.hh
new file mode 100644
index 00000000000..372ca7bcfe8
--- /dev/null
+++ b/TAO/IIOP/lib/runtime/thread.hh
@@ -0,0 +1,185 @@
+// @(#)thread.hh 1.3 95/09/29
+// Copyright 1995 by Sun Microsystems, Inc
+// All Rights Reserved
+//
+// THREADING: simple thread utility classes
+//
+// Instances of these classes are placed at the beginning of a lexical
+// scope to ensure that all exits from that scope restore thread or
+// synchronization state to its original values. Thread state includes
+// ansynchronous cancellability, synchronization state includes locks
+// that cover data structures that are shared between threads.
+//
+// NOTE: supports only POSIX and SVR4 threads for the moment. Win32
+// threads can be supported sometime later.
+//
+
+#ifndef _THREAD_HH
+#define _THREAD_HH
+
+#ifdef unix
+#include <unistd.h> // may define _POSIX_THREADS
+#endif // unix
+
+#ifdef _POSIX_THREADS
+#include <pthread.h>
+
+//
+// This ugliness is called for by OSF/1 v3.0, which defines the POSIX.1c
+// symbol "_POSIX_THREADS" even though it is noncompliant.
+//
+// We make the assumption that PTHREAD_MUTEX_INITIALIXER is a preprocessor
+// symbol, although POSIX does not require that, since since it works on
+// all the POSIX.1c implementations we've seen.
+//
+# ifndef PTHREAD_MUTEX_INITIALIZER
+# undef _POSIX_THREADS
+# endif // not really POSIX.1c threads
+#endif
+
+//
+// Use native threading on Solaris 2.2 and later.
+//
+// XXX this is a temporary kluge; "autoconf" should kick in the
+// appropriate POSIX threads emulation when it's not native.
+//
+#if defined (sun) && !defined (_POSIX_THREADS) && !defined (FAKE_POSIX_THREADS)
+# define FAKE_POSIX_THREADS
+#endif // 2.2 <= "solaris version < 2.5
+
+
+#ifdef FAKE_POSIX_THREADS
+//
+// To use SVR4 native threads, enable FAKE_POSIX_THREADS. This is
+// intentionally not autoconfigured, since it's only really needed on
+// Solaris versions before 2.5. POSIX threads are the way to go
+// longer term, on all compliant platforms.
+//
+// NOTE: this is only a partial implementation !!! Enough to make
+// the IIOP engine work as it's coded as of 9-Aug-95. If you start
+// to use different POSIX options, these macros could stop working.
+//
+#define _POSIX_THREADS // only as much as is defined here!
+
+#include <thread.h>
+#include <synch.h>
+
+typedef thread_t pthread_t;
+typedef mutex_t pthread_mutex_t;
+typedef cond_t pthread_cond_t;
+typedef unsigned long pthread_attr_t;
+typedef thread_key_t pthread_key_t;
+
+
+#define PTHREAD_MUTEX_INITIALIZER DEFAULTMUTEX
+#define PTHREAD_COND_INITIALIZER DEFAULTCV
+
+#define pthread_mutex_lock mutex_lock
+#define pthread_mutex_unlock mutex_unlock
+#define pthread_cond_wait cond_wait
+
+struct pthread_once_t {
+ mutex_t lock;
+ int called_once;
+};
+
+#define PTHREAD_ONCE_INIT { DEFAULTMUTEX, 0 }
+
+inline void
+pthread_once (pthread_once_t *var, void (*fn)())
+{
+ mutex_lock (&var->lock);
+ if (var->called_once == 0) {
+ (fn)();
+ var->called_once = 1;
+ }
+ mutex_unlock (&var->lock);
+}
+
+#define pthread_self thr_self
+
+#define pthread_key_create thr_keycreate
+#define pthread_attr_init(ap) ((*ap) = 0)
+#define pthread_attr_setdetachstate(ap,v) ((*ap) |= (v))
+
+#define PTHREAD_CREATE_DETACHED THR_DETACHED
+
+inline void *
+pthread_getspecific (pthread_key_t key)
+{
+ void *vp;
+
+ thr_getspecific (key, &vp);
+ return vp;
+}
+
+#define pthread_setspecific thr_setspecific
+
+inline int
+pthread_create (
+ pthread_t *tidp,
+ pthread_attr_t *attrs,
+ void *(func)(void *),
+ void *arg
+)
+{
+ return thr_create (0, 0, func, arg, *attrs, tidp);
+}
+
+#endif // FAKE_POSIX_THREADS
+
+
+#ifdef _POSIX_THREADS
+//
+// Stick one of these at the beginning of a block that hosts a critical
+// section, passing it a pointer to the lock guarding that section. The
+// destructor will release it on all code paths, eliminating one class of
+// common threading errors.
+//
+class Critical {
+ public:
+ Critical (pthread_mutex_t *l) : lock (l)
+ { enter (); }
+
+ ~Critical ()
+ { leave (); }
+
+ void leave ()
+ { (void) pthread_mutex_unlock (lock); }
+ void enter ()
+ { (void) pthread_mutex_lock (lock); }
+ void pause (pthread_cond_t *condition)
+ { (void) pthread_cond_wait (condition, lock); }
+
+ private:
+ pthread_mutex_t *lock;
+};
+
+
+//
+// Stick one of these at the beginning of a block that can't support
+// asynchronous cancellation, and which must be cancel-safe.
+//
+class ForceSynchronousCancel {
+ public:
+ //
+ // MIT Pthreads 1.60 doesn't include cancellation; this is good, it
+ // gives time to ensure that stack unwinding for cancellation (in C)
+ // interoperates with unwinding for C++ exceptions so that both
+ // resource reclamation systems interwork correctly.
+ //
+#ifdef PTHREAD_CANCEL_DEFERRED
+ ForceSynchronousCancel ()
+ { (void) pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old_type); }
+
+ ~ForceSynchronousCancel ()
+ { (void) pthread_setcanceltype (old_type, &old_type); }
+
+ private:
+ int old_type;
+#endif // PTHREAD_CANCEL_DEFERRED
+};
+
+#endif // _POSIX_THREADS
+
+#endif // _THREAD_HH
diff --git a/TAO/IIOP/lib/runtime/toa.cpp b/TAO/IIOP/lib/runtime/toa.cpp
new file mode 100644
index 00000000000..e60191a80e7
--- /dev/null
+++ b/TAO/IIOP/lib/runtime/toa.cpp
@@ -0,0 +1,146 @@
+// @(#)toa.cpp 1.3 95/09/29
+// Copyright 1994-1995 by Sun Microsystems Inc.
+// All Rights Reserved
+//
+// TOA initialisation -- both anonymous and (for system bootstrapping)
+// named TOAs.
+//
+// XXX at this time, there's a strong linkage between this code and
+// the modules knowing about IIOP. In the future, a looser coupling
+// between OA initialiszation and protocol components is desired.
+//
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#if unix
+#include <unistd.h>
+#include <netdb.h>
+
+#else
+#include <winsock.h>
+
+#endif
+
+#include <corba/orb.hh>
+#include <corba/toa.hh>
+
+#include "runtime/thread.hh"
+#include "runtime/debug.hh"
+
+// XXX this should not know implementation or other details of any
+// protocol modules! This is an implementation shortcut only.
+
+#include "bridge/iioporb.hh"
+#include "bridge/connmgr.hh"
+#include "bridge/tcpoa.hh"
+
+#include <initguid.h>
+
+
+// {A201E4C8-F258-11ce-9598-0000C07CA898}
+DEFINE_GUID (IID_TOA,
+0xa201e4c8, 0xf258, 0x11ce, 0x95, 0x98, 0x0, 0x0, 0xc0, 0x7c, 0xa8, 0x98);
+
+
+//
+// A "Named TOA" is used in bootstrapping some part of the ORB since
+// it's name-to-address binding is managed by the OS. Examples of such
+// bindings are /etc/services (for TCP) and /etc/rpc (for ONC RPC). The
+// nam" of a TOA is only guaranteed to be unique within the domain of a
+// single system, as a rule; two hosts would have distinct "king" TOAs.
+//
+// For network endpoints, most such names are manually administered.
+// Some other namespaces (AF_UNIX filesystem names for example) have a
+// more formal underlying name service that can be dynamically updated
+// while not compromising sysem security.
+//
+// The address family used by the TOA is found from the ORB passed in.
+//
+// XXX the coupling could stand to be looser here, so this module did
+// not know specifically about the Internet ORB !!
+//
+TOA_ptr
+TOA::get_named_toa (
+ CORBA_ORB_ptr orb,
+ CORBA_String name,
+ CORBA_Environment &env
+)
+{
+ env.clear ();
+
+ //
+ // If the ORB is an Internet ORB, we know this must be a TCP OA.
+ //
+ {
+ IIOP_ORB *internet;
+
+ if (orb->QueryInterface (IID_IIOP_ORB, (void **)&internet)
+ == NOERROR) {
+ TCP_OA *tcp_oa;
+
+ internet->Release ();
+
+ //
+ // TCP_OA initialization with name specified; it'll
+ // come from /etc/services if it's not a port number.
+ //
+ tcp_oa = TCP_OA::init (orb, name, env);
+ if (env.exception () != 0)
+ return 0;
+ else
+ return tcp_oa; // derives from TOA
+ }
+ }
+
+ //
+ // We don't know how to deal with this kind of ORB. Report error.
+ //
+ env.exception (new CORBA_BAD_PARAM (COMPLETED_NO));
+ return 0;
+}
+
+
+//
+// An "Anonymous" TOA is used more routinely. The name used doesn't
+// matter to anyone; it is only used to create object references with
+// a short lifespan, namely that of the process acquiring this TOA.
+//
+TOA_ptr
+TOA::get_toa (
+ CORBA_ORB_ptr orb,
+ CORBA_Environment &env
+)
+{
+ env.clear ();
+
+ //
+ // If the ORB is an Internet ORB, we know this must be a TCP OA.
+ //
+ {
+ IIOP_ORB *internet;
+
+ if (orb->QueryInterface (IID_IIOP_ORB, (void **)&internet)
+ == NOERROR) {
+ TCP_OA *tcp_oa;
+
+ internet->Release ();
+
+ //
+ // TCP_OA initialization with null name means anonymous OA
+ //
+ tcp_oa = TCP_OA::init (orb, 0, env);
+ if (env.exception () != 0)
+ return 0;
+ else
+ return tcp_oa; // derives from TOA
+ }
+ }
+
+ //
+ // We don't know how to deal with this kind of ORB. Report error.
+ //
+ env.exception (new CORBA_BAD_PARAM (COMPLETED_NO));
+ return 0;
+}
diff --git a/TAO/IIOP/lib/runtime/typecode.cpp b/TAO/IIOP/lib/runtime/typecode.cpp
new file mode 100644
index 00000000000..c18806cf639
--- /dev/null
+++ b/TAO/IIOP/lib/runtime/typecode.cpp
@@ -0,0 +1,712 @@
+// @(#)typecode.cpp 1.4 95/09/19
+// Copyright 1994-1995 by Sun Microsystems Inc.
+// All Rights Reserved
+//
+// TYPECODE: basic implementation of TypeCodes
+//
+// Typecodes essentially consist of just the CDR octets that get marshaled
+// and unmarshaled, and this code knows how to parse those octets and answer
+// questions CORBA's TypeCode APIs require.
+//
+// NOTE: This isn't well tuned performance-wise. Given how much is variable
+// (byte order, alignment) it's clear tuning has its limits with respect to
+// CDR bytecode interpretation.
+//
+// THREADING NOTE: Typecodes are readonly data structures, and the only
+// mutual exclusion relates to reference counting and construction.
+//
+
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+#include <corba/orb.hh>
+
+#include "runtime/debug.hh"
+#include "runtime/cdr.hh"
+#include "runtime/thread.hh"
+
+#include <memory.h>
+#include <sys/types.h>
+
+#include <initguid.h>
+
+
+#ifdef _POSIX_THREADS
+//
+// If POSIX threads are available, set up lock covering refcounts.
+//
+static pthread_mutex_t refcnt_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif // _POSIX_THREADS
+
+
+void
+CORBA_release (CORBA_TypeCode_ptr tc)
+{
+ if (tc)
+ tc->Release ();
+}
+
+CORBA_Boolean
+CORBA_is_nil (CORBA_TypeCode_ptr tc)
+{
+ return (CORBA_Boolean) (tc == 0);
+}
+
+//
+// Constructor for CONSTANT typecodes with empty parameter lists.
+// These are only created once, and those constants are shared.
+//
+CORBA_TypeCode::CORBA_TypeCode (
+ CORBA_TCKind kind
+) :
+ _length (0),
+ _buffer (0),
+ _kind (kind),
+ _parent (0),
+ _refcount (1),
+ _orb_owns (CORBA_B_FALSE)
+{
+}
+
+
+//
+// Constructor for all other typecodes, including constants with non-empty
+// parameter lists. See "corba.hh" for details.
+//
+CORBA_TypeCode::CORBA_TypeCode (
+ CORBA_TCKind kind,
+ CORBA_ULong length,
+ CORBA_Octet *buffer,
+ CORBA_Boolean orb_owns_tc
+) :
+ _length (length),
+ _buffer (buffer),
+ _kind (kind),
+ _parent (0),
+ _refcount (1),
+ _orb_owns (orb_owns_tc)
+{
+ //
+ // The CDR code used to interpret TypeCodes requires in-memory
+ // alignments to match the "on-the-wire" alignments, simplifying
+ // algorithms used to marshal/unmarshal.
+ //
+ // However, it's often hard to get compilers (in particular) to
+ // generate data that's so aligned, since C++ doesn't provide
+ // primitives giving control at that low a level. Although there
+ // are ways to get that alignment which work in almost all cases,
+ // we need to ensure adequate alignment in _all_ cases.
+ //
+ // This code exists to ensure such alignment; since the constructor
+ // is intended only for use by an IDL compiler or ORB code, it's
+ // not currently a priority to ensure the allocated code is freed.
+ //
+ if ((((ptr_arith_t)buffer) & 0x03) != 0) {
+ ptr_arith_t temp;
+
+ temp = (ptr_arith_t) malloc (length + 4);
+ temp += 3;
+ temp &= ~0x03;
+ _buffer = (CORBA_Octet *) temp;
+
+ (void) memcpy (_buffer, buffer, (size_t) length);
+ _orb_owns = CORBA_B_FALSE; // XXX may leak
+ }
+}
+
+
+//
+// Destructor. For "indirected" typecodes, the typecode reuses the buffer
+// owned by its parent, and so rather than deleting the buffer it just drops
+// the parent's refcount.
+//
+CORBA_TypeCode::~CORBA_TypeCode ()
+{
+ if (_parent)
+ _parent->Release ();
+ else if (_orb_owns)
+ delete _buffer;
+}
+
+
+//
+// COM's IUnknown support
+//
+//
+
+// {A201E4C1-F258-11ce-9598-0000C07CA898}
+DEFINE_GUID (IID_CORBA_TypeCode,
+0xa201e4c1, 0xf258, 0x11ce, 0x95, 0x98, 0x0, 0x0, 0xc0, 0x7c, 0xa8, 0x98);
+
+
+ULONG
+__stdcall
+CORBA_TypeCode::AddRef ()
+{
+#ifdef _POSIX_THREADS
+ Critical region (&refcnt_lock);
+#endif
+
+ return _refcount++;
+}
+
+ULONG
+__stdcall
+CORBA_TypeCode::Release ()
+{
+#ifdef _POSIX_THREADS
+ Critical region (&refcnt_lock);
+#endif
+
+ assert (this != 0);
+
+ if (--_refcount != 0)
+ return _refcount;
+ if (_orb_owns)
+ delete this;
+ return 0;
+}
+
+HRESULT
+__stdcall
+CORBA_TypeCode::QueryInterface (
+ REFIID riid,
+ void **ppv
+)
+{
+ *ppv = 0;
+
+ if (IID_CORBA_TypeCode == riid || IID_IUnknown == riid)
+ *ppv = this;
+
+ if (*ppv == 0)
+ return ResultFromScode (E_NOINTERFACE);
+
+ (void) AddRef ();
+ return NOERROR;
+}
+
+
+//
+// just fetch the 'kind' field out of the typecode
+//
+CORBA_TCKind
+CORBA_TypeCode::kind (
+ CORBA_Environment &env
+) const
+{
+ env.clear ();
+ return _kind;
+}
+
+
+//
+// skip a typecode encoding in a given CDR stream
+//
+static CORBA_Boolean
+skip_typecode(
+ CDR &stream
+)
+{
+ CORBA_ULong kind;
+ CORBA_ULong temp;
+
+ if (!stream.get_ulong (kind)
+ || kind >= TC_KIND_COUNT)
+ return CORBA_B_FALSE;
+
+ switch (kind) {
+ //
+ // Most TypeCodes have empty parameter lists, nothing to skip
+ //
+ default:
+ break;
+
+ //
+ // Some have single integer parameters, easy to skip.
+ //
+ // have preallocated constants that could be used.
+ //
+ case tk_string:
+ case tk_wstring:
+ case ~0:
+ return stream.get_ulong (temp);
+
+ //
+ // The rest have "complex" parameter lists that are
+ // encoded as bulk octets ... just skip them
+ //
+ case tk_objref:
+ case tk_struct:
+ case tk_union:
+ case tk_enum:
+ case tk_sequence:
+ case tk_array:
+ case tk_alias:
+ case tk_except:
+ return stream.get_ulong (temp) != CORBA_B_FALSE
+ && stream.skip_bytes (temp) != CORBA_B_FALSE;
+ }
+
+ return CORBA_B_TRUE;
+}
+
+
+//
+// Return member labels for tk_union typecodes.
+//
+CORBA_Any_ptr
+CORBA_TypeCode::member_label (
+ CORBA_ULong n,
+ CORBA_Environment &env
+) const
+{
+ env.clear ();
+
+ CDR stream;
+
+ stream.setup_encapsulation(_buffer, (size_t)_length);
+
+ //
+ // this function is only applicable to the tk_union TC
+ //
+ if (_kind != tk_union) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+
+ //
+ // skip ID and name, and then get the discriminant TC
+ //
+ CORBA_TypeCode_ptr tc = 0;
+
+ if (!stream.skip_string () // type ID, hidden
+ || !stream.skip_string () // typedef name
+ || CDR::decoder (_tc_CORBA_TypeCode, &tc, this, &stream, env)
+ != CORBA_TypeCode::TRAVERSE_CONTINUE) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+
+ //
+ // skip default used, and get member count
+ //
+ CORBA_ULong member_count;
+
+ if (!stream.get_ulong (member_count) // default used
+ || !stream.get_ulong (member_count)
+ ) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+
+ //
+ // If caller asked for the label for a nonexistent member, they
+ // get an error report!
+ //
+ if (n >= member_count) {
+ env.exception (new CORBA_BAD_PARAM (COMPLETED_NO));
+ return 0;
+ }
+
+ //
+ // Get the n-th member label; they're all the same size and have
+ // no nested pointers, so we just overwrite each one with the
+ // enxt parameter.
+ //
+ void *buf = new CORBA_Octet [tc->size (env)];
+
+ if (env.exception () != 0)
+ return 0;
+
+ for (CORBA_ULong i = 0; i <= n; i++) {
+ if (CDR::decoder (tc, buf, this, &stream, env)
+ != CORBA_TypeCode::TRAVERSE_CONTINUE
+ || !stream.skip_string () // member name
+ || !skip_typecode (stream)) { // member TC
+ delete buf;
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+ }
+
+ //
+ // return the member label as an any
+ //
+ CORBA_Any *retval;
+
+ retval = new CORBA_Any(tc, buf, CORBA_B_TRUE);
+ tc->Release ();
+ return retval;
+}
+
+
+//
+// say how many parameters this typecode has; normally a fixed number, some
+// are variable length.
+//
+// NOTE: This refers to "real" parameters, not what shows up in the IFR
+// spec !! That is, "hidden" parameters are counted here, this doesn't
+// strictly comply with what CORBA says "param_count" provides.
+//
+CORBA_ULong
+CORBA_TypeCode::param_count (
+ CORBA_Environment &env
+) const
+{
+ env.clear ();
+
+ switch (_kind) {
+ default:
+ return 0;
+
+ case tk_string:
+ case tk_wstring:
+ return 1;
+
+ case tk_objref:
+ case tk_sequence:
+ case tk_array:
+ return 2;
+
+ case tk_alias:
+ return 3;
+
+ case tk_except:
+ case tk_struct:
+ {
+ CORBA_ULong members;
+ CDR stream;
+
+ stream.setup_encapsulation(_buffer, (size_t)_length);
+
+ // skip rest of header (type ID and name) and collect the
+ // number of struct members
+ if (!stream.skip_string () // ID
+ || !stream.skip_string () // struct name
+ || !stream.get_ulong (members)) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+
+ return 3 + 2 * members;
+ }
+ case tk_enum:
+ {
+ CORBA_ULong members;
+ CDR stream;
+
+ stream.setup_encapsulation(_buffer, (size_t)_length);
+
+ // skip rest of header (type ID and name) and collect the
+ // number of struct members
+ if (!stream.skip_string () // ID
+ || !stream.skip_string () // typedef name
+ || !stream.get_ulong (members)) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+
+ return 3 + members;
+ }
+ case tk_union:
+ {
+ CORBA_ULong members;
+ CDR stream;
+
+ stream.setup_encapsulation(_buffer, (size_t)_length);
+
+ // skip rest of header (type ID, name, etc...) and collect the
+ // number of struct members
+ if (!stream.skip_string () // ID
+ || !stream.skip_string () // struct name
+ || !skip_typecode (stream) // discriminant TC
+ || !stream.get_ulong (members) // default used
+ || !stream.get_ulong (members) // real member count
+ ) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+
+ return 5 + 3 * members;
+ }
+ }
+}
+
+
+//
+// Internal hack, used until member_count() and length() are implemented.
+// Doesn't support all the types that those routines support.
+//
+CORBA_ULong
+CORBA_TypeCode::ulong_param (
+ CORBA_ULong n,
+ CORBA_Environment &env
+) const
+{
+ CORBA_ULong temp;
+
+ temp = param_count (env); // clears env
+ if (env.exception ())
+ return 0;
+
+ if (temp < n) {
+ env.exception (new CORBA_Bounds);
+ return 0;
+ }
+
+ //
+ // Get parameters for non-empty typecodes; their parameter lists are
+ // encapsulated CDR (for complex ones) or inlined (for simple ones).
+ //
+ switch (_kind) {
+ default: // most have no long params
+ break;
+
+ //
+ // Array, sequence ... complex parameter lists
+ //
+ case tk_array: // param 1 is an integer
+ case tk_sequence: // ... identical content
+ {
+ if (n == 0)
+ break;
+
+ //
+ // Build CDR stream for encapsulated params, and skip the
+ // typecode up front.
+ //
+ CDR stream;
+
+ stream.setup_encapsulation (_buffer, (size_t)_length);
+ if (!skip_typecode (stream)) {
+ env.exception (new CORBA_BAD_PARAM (COMPLETED_NO));
+ return 0;
+ }
+
+ //
+ // Then comes the "bounds" parameter.
+ //
+ if (!stream.get_ulong (temp))
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return temp;
+ }
+
+ //
+ // string, wstring ... simple parameter lists, containing just
+ // the string bounds (zero indicates unbounded). Stored specially
+ //
+ case tk_string:
+ case tk_wstring:
+ if (n != 0)
+ break;
+ return _length;
+ }
+ env.exception (new CORBA_BAD_PARAM (COMPLETED_NO));
+ return 0;
+}
+
+
+//
+// Internal hack, used until member_type(), discriminator_type(),
+// and content_type() are implemented.
+//
+// NOTE special calling convention for CDR::decoder() when we're
+// potentially deencapsulating an indirected typecode: the "data2"
+// value indicates that this typecode is the parent. See comments
+// at CDR::decoder() for further details.
+//
+CORBA_TypeCode_ptr
+CORBA_TypeCode::typecode_param (
+ CORBA_ULong n,
+ CORBA_Environment &env
+) const
+{
+ CORBA_ULong temp;
+
+ temp = param_count (env); // clears env
+ if (env.exception ())
+ return 0;
+
+ if (temp < n) {
+ env.exception (new CORBA_Bounds);
+ return 0;
+ }
+
+ //
+ // Build the de-encapsulating CDR stream, bypassing the stringent
+ // alignment tests (we're a bit looser in what we need here, and
+ // we _know_ we're OK). Then skip the byte order code.
+ //
+ CDR stream;
+ CORBA_TypeCode_ptr tc = 0;
+
+ stream.setup_encapsulation (_buffer, (size_t)_length);
+
+ switch (_kind) {
+ default: // most have no tc params
+ break;
+
+ case tk_sequence: // param 0 is a tc
+ case tk_array:
+ if (n != 0)
+ break;
+ if (CDR::decoder (_tc_CORBA_TypeCode, &tc, this, &stream, env)
+ != CORBA_TypeCode::TRAVERSE_CONTINUE) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+ return tc;
+
+ case tk_alias: // #1 is a tc
+ if (n != 2)
+ break;
+ if (!stream.skip_string () // type ID, hidden
+ || !stream.skip_string () // typedef name
+ || CDR::decoder (_tc_CORBA_TypeCode, &tc, this, &stream, env)
+ != CORBA_TypeCode::TRAVERSE_CONTINUE) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+ return tc;
+
+ case tk_except:
+ case tk_struct: // #5 and up are tc, index from 0
+ if ((n < 4) || (n & 0x1)) { // tc is at odd number of param list
+ env.exception (new CORBA_Bounds);
+ return 0;
+ }
+
+ if (!stream.skip_string () // type ID, hidden
+ || !stream.skip_string () // typedef name
+ || !stream.get_ulong (temp)) { // member count
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ } else {
+ CORBA_ULong i;
+ temp = (n - 3) / 2;
+
+ // skip member pairs to the one we want
+ for (i = 0; i < temp; i++) {
+ // skip to the member being asked
+ if (!stream.skip_string () // member name
+ || !skip_typecode (stream)) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+ }
+
+ if (!stream.skip_string ()
+ || CDR::decoder (_tc_CORBA_TypeCode, &tc, this, &stream,
+ env)!= CORBA_TypeCode::TRAVERSE_CONTINUE) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+ return tc;
+ }
+
+ case tk_union: // #6 and up are tc, index from 0
+ if (n != 2 && (n < 7 || (n - 7) % 3)) {
+ env.exception (new CORBA_Bounds);
+ return 0;
+ }
+
+ if (!stream.skip_string () // type ID, hidden
+ || !stream.skip_string () // typedef name
+ || CDR::decoder (_tc_CORBA_TypeCode, &tc, this, &stream, env)
+ != CORBA_TypeCode::TRAVERSE_CONTINUE // TC
+ ) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ } else if (!stream.get_ulong (temp) // default used
+ || !stream.get_ulong (temp) // member count
+ ) {
+ tc->Release ();
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+
+ if (n == 2)
+ return tc;
+
+ temp = (n - 7) / 3;
+
+ //
+ // skip to the member requested
+ //
+ CORBA_ULong i;
+ CORBA_Long scratch; // always big enough
+
+ for (i = 0; i < temp; i++) {
+
+ if (CDR::decoder (tc, &scratch, this, &stream, env) // member label
+ != CORBA_TypeCode::TRAVERSE_CONTINUE
+ || !stream.skip_string () // member name
+ || !skip_typecode (stream)) { // member typecode
+ tc->Release ();
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+ }
+
+ if (CDR::decoder (tc, &scratch, this, &stream, env) // member label
+ != CORBA_TypeCode::TRAVERSE_CONTINUE
+ || !stream.skip_string () // member name
+ ) {
+ tc->Release ();
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+ tc->Release ();
+
+ if (CDR::decoder (_tc_CORBA_TypeCode, &tc, this, &stream, env)
+ != CORBA_TypeCode::TRAVERSE_CONTINUE) {
+ env.exception (new CORBA_BAD_TYPECODE (COMPLETED_NO));
+ return 0;
+ }
+ return tc;
+ }
+
+ env.exception (new CORBA_BAD_PARAM (COMPLETED_NO));
+ return 0;
+}
+
+
+//
+// Return the type ID (RepositoryId) for the TypeCode; it may be empty.
+//
+// NOTE the string returned here is owned by the typecode!!
+//
+CORBA_String
+CORBA_TypeCode::id (
+ CORBA_Environment &env
+) const
+{
+ env.clear ();
+
+ switch (_kind) {
+ //
+ // These are all complex typecodes, which have as their first parameter
+ // (number zero) a repository/type ID string encoded per CDR rules.
+ // That means we can just return a pointer to that string directly!
+ //
+ case tk_objref:
+ case tk_struct:
+ case tk_union:
+ case tk_enum:
+ case tk_alias:
+ case tk_except:
+ return (CORBA_String) (_buffer
+ + 4 // skip byte order flag and padding
+ + 4 // skip (strlen + 1)
+ );
+
+ //
+ // No other typecodes ever have type IDs
+ //
+ default:
+ env.exception (new CORBA_BAD_PARAM (COMPLETED_NO));
+ return 0;
+ }
+}
+
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);
+}
+