The undersigned, appointed by the Dean of the Graduate School, have examined the thesis entitled

 

Interconnecting Personal Computers with the Distributed Computing Environment

 

presented by

James E. Ries

 

a candidate for the degree of

Master of Science

 

and hereby certify that in their opinion it is worthy of acceptance.

 

 

______________________________

Dr. Gordon K. Springer

 

 

______________________________

Dr. Anupam Joshi

 

 

______________________________

Dr. Timothy B. Patrick


 

INTERCONNECTING PERSONAL COMPUTERS WITH THE DISTRIBUTED COMPUTING ENVIRONMENT

 

 


A Thesis Presented to the Faculty of the Graduate School

University of Missouri-Columbia

 

 

In Partial Fulfillment of the Requirements for the Degree

Master of Science

 

 


by

JAMES E. RIES

Prof. Gordon K. Springer, Thesis Supervisor

JULY 1998


Acknowledgements

 

This has been a long journey with many twists and turns.  I would certainly still be lost, far back on the path were it not for the patience, insistence, and good sense of Professor Gordon Springer, who helped me over the blockages in the path and demanded that I keep going.  I would truly be lost on this path and the greater path of life without the support of my wife, Laura, who gave up many plans to instead see that I had the opportunity to work on this document and all of the research which went before it.  I would also be far short of the end, without the help of my daughter, Abbie, who was kind enough to start sleeping through the night at a very young age.


Abstract

 

 

This thesis seeks to demonstrate that personal computers can be integrated into the Distributed Computing Environment (DCE) and to illustrate the compromises that exist among various methods of such integration.  An existing sample DCE application, BINOP, is ported using two of the possible methods.  The strengths and weaknesses of each method are explicated.  Several third party software packages are examined as a means for simplifying the porting of DCE applications, and as ways to enhance the function of DCE applications running on personal computers.

            In acknowledgement of the general movement toward object-oriented paradigms, various attempts to bring object-oriented technology to distributed computing are discussed with respect to the personal computer and to the synergies of these approaches with DCE.  These include Microsoft’s Distributed Component Object Model (DCOM), Hewlett Packard’s Object-Oriented DCE (OODCE), and the Object Management Group’s (OMG) Component Object Resource Broker Architecture (CORBA).


Table of Contents

 

Acknowledgements....................................................................................................... ii

Abstract............................................................................................................................ iii

Table of Contents.......................................................................................................... iv

List of Figures................................................................................................................. vi

1. Introduction................................................................................................................. 1

1.2 The challenges...................................................................................................... 1

1.3 Why DCE?............................................................................................................. 5

1.4 Programming in the DCE world.......................................................................... 7

1.5 What about the future?....................................................................................... 10

2. Choosing Platforms................................................................................................ 11

2.1 Microsoft DOS and Windows 3.x...................................................................... 11

2.2 Microsoft Windows 95........................................................................................ 17

2.3 Microsoft Windows NT....................................................................................... 18

2.4 IBM OS/2 and Apple Macintosh........................................................................ 19

2.5 OS choices conclusion....................................................................................... 20

3. What You Need......................................................................................................... 22

3.1 Supported protocol stacks................................................................................. 23

3.2 Development kits................................................................................................ 24

3.3 Hardware............................................................................................................. 25

3.4 Summary of what you need................................................................................ 25

4. Third Party Tools...................................................................................................... 27

4.1 Digital DCE for Windows NT and Windows 95............................................... 27

4.2 Gradient’s PC/DCE............................................................................................ 29

4.3 Hewlett-Packard OODCE.................................................................................. 30

5. Porting An Existing OSF DCE Application to Microsoft Platforms (BINOP) 31

5.1 Straight Microsoft................................................................................................ 32

5.2 Full DCE.............................................................................................................. 36

6. The Future (Is Sooner Than You Think)............................................................. 41

6.1 DCOM.................................................................................................................. 41

6.2 CORBA................................................................................................................ 46

6.3 WWW and DCE.................................................................................................. 48

7. Conclusion................................................................................................................ 52

Glossary.......................................................................................................................... 55

References..................................................................................................................... 57

Appendix A: BINOP Source Code........................................................................... 59


List of Figures

 

Figure 1: Microsoft Windows NT Architecture....................................................................... 9

Figure 2: Share of US PC’s Using Top Four Operating Systems........................................... 12

Figure 3: 1997 OS Shipments With PC Systems Worldwide – Market Share....................... 13

Figure 4: Summary Of Requirements For RPC On Microsoft Platforms................................ 26

Figure 5: Successful WIN32RAW Binopc Run.................................................................... 33

Figure 6: WIN32RAW Binopc Run With Communication Error........................................... 34

Figure 7: Windows NT OS Error Dialog.............................................................................. 34

Figure 8: WIN32 Binopc Run With Communication Error.................................................... 35

Figure 9: DCOM Architecture............................................................................................. 43

Figure 10: OMG’s CORBA................................................................................................ 47

Figure 11: DCE-Web.......................................................................................................... 50


1. Introduction

 

 

This thesis seeks to demonstrate that personal computers (PC’s) can be integrated into the Distributed Computing Environment (DCE) and to illustrate the compromises that exist among various methods of such integration.  The thesis was initially conceived as a tutorial on porting DCE applications to PC’s.  It was also to provide a guide to writing applications that are generally portable across all DCE and environments that support Remote Procedure Calls (RPC).  As work on the thesis progressed, it became clear that it would be necessary to not only examine ways that PC’s can be integrated into DCE, but also to explore the role of personal computers in distributed computing in general.

 

1.2 The challenges

Most computing environments deployed within businesses, schools, universities, and other organizations today are heterogeneous in nature.  That is, no one vendor’s products are used exclusively to meet all of the computing needs of all users within these organizations.  Some sub-groups may use Unix workstations from a variety of vendors, including Sun Microsystems, Digital Equipment Corporation, Hewlett Packard, and many others.  Some may use IBM standard personal computers, running such operating systems as Microsoft DOS, Microsoft Windows, Microsoft Windows 95, Microsoft Windows NT, IBM OS/2, or one of many versions of Unix.  It is also the case that these personal computers may be obtained from a wide selection of vendors.  Some users may use mainframes or minicomputers (such as IBM’s AS/400) from IBM and other sources.  In addition, many users may use some or all of these platforms at various times for differing tasks, since some platforms tend to be used for specialized purposes.

Yet, with this dizzying array of heterogeneous hardware, peripherals, and software, there exists a need for interoperability.  The information contained on one system may be needed to perform an analysis on another system.  Although data may have many representations on the disparate platforms (e.g., EBCDIC or ASCII), the information stored on each of these systems must be made to cross the boundaries among machines.  That is, the increasingly naïve users of computing systems should not have to be concerned with the technical details regarding the way data is stored or even where it is stored.  They should simply be able to find and utilize the information that they seek.

Although typical computing environments are composed of a mix of platforms, these platforms are typically interconnected through some form of network.  A larger heterogeneous network may be composed of locally homogeneous subnetworks, each operating over a possibly unique topology (e.g., ATM, ethernet, or token ring) and a possibly unique protocol (e.g., TCP/IP, IPX, Netbios, Netbeui [Netbios Extended User Interface], DECnet, etc.).  However, the subnetworks that comprise this larger network are all typically interconnected via bridges and gateways to form an intranet (which may, in fact, be connected to the global Internet).  This configuration allows an organization to exchange information among its component platforms, as long as the data can be coaxed into a format appropriate for its destination platform.  Of course, moving data from platform to platform can be a significant problem in and of itself.  It may require translation from one encoding scheme to another (such as big-endian notation to little-endian notation) and perhaps from one application’s proprietary format to another (such as Wordperfect to Word).

Moreover, performance problems can arise if large quantities of data are to be transported across the network to be operated upon by a remote computer.  This can be a very time-consuming process and can quickly use up all available bandwidth (the capacity of a network to transport data) if it is a common occurrence.  This may result in performance issues for all users of the network, not merely for the user or set of users who require the transport of the data in question.

The task for programmers to make all disparate platforms and networks work seamlessly together is immense.  What is really needed is a way for programmers to write programs in the way they are accustomed (i.e., with the assumption that data and code dwell on the same physical machine), while remapping the programmer’s code to work across the network.

Users also benefit from the concept of transparency.  A typical user of a computer system simply wishes to get work done.  That is, the user wants to know about some information and perhaps put it together with other information that exists elsewhere on the network.  It should not be up to the user to discover which physical machine or computing platform happens to house this information.  Rather, the user should employ the same means when working with data that is stored on the network or on the local workstation.

The problems presented by heterogeneity of hardware platforms and operating systems, limited communications bandwidth, and the need to transparently code distributed systems are far from trivial.  In the past (and even today), distributed applications have been built without regard to previously developed applications.  These applications are usually written utilizing the TCP/IP protocol (e.g., web browsers), the IPX protocol (e.g., Novell Netware file servers), or some other custom protocol.  This has resulted in systems that are limited with regard to platform and/or operating system, and which required highly specific expertise on the part of applications developers.  For example, many Novell Netware applications have not survived the recent and swift conversion to TCP/IP.  These problems beg for an abstraction layer which hides the specifics of individual protocols from the application developer and which allows the developer to write code with little regard for whether code executes on the local machine or on another machine located across the network.

            The client/server style of coding helps the developer to make this abstraction.  The developer creates a client application that provides, minimally, a user interface.  The client application relies upon a server that may be located remotely to do some or all of the actual computing work.  This distribution of computing effort allows the server to run in closer proximity to the data on which it operates, perhaps on the same physical machine.  This can reduce the bandwidth problems discussed earlier.  However, without some additional layer of abstraction, the distribution still does not free the developer from many of the details of wire protocols and platform dependencies.

 

1.3 Why DCE?

The Open Software Foundation (OSF; now called the Open Group [22]) has developed a standard for distributed computing called the Distributed Computing Environment (DCE).  DCE is rapidly becoming the standard for the interoperation of heterogeneous computers that run some implementation of the Unix operating system.  In fact, DCE run-time services are being incorporated into the base operating systems support provided by many manufacturers.  DCE allows clients on one platform to access servers on another, without regard to the hardware, operating system, or available network transports between and among the cooperating machines.  In theory, this frees the application developer from mundane tasks and provides a layer of abstraction on which to rest the development process: The application developer creates a client and a server, each of which should be able to run on any platform, operating system, or transport.

In practice, this works quite well for many of the operating systems that support DCE.  These include Digital Equipment Corporation’s line of Alpha workstations running Digital Unix, HP systems running HP/UX, IBM’s RS/6000 line running AIX, Silicon Graphics machines running IRIX, Cray Supercomputers, and even Sun workstations with the addition of some third party software.  In many environments, these platforms can co-exist using DCE very effectively.  However, many real environments today, both academic and commercial, contain large numbers of personal computers based on the IBM standard using Intel processor chips.  The vast majority of these machines run Microsoft Corporation operating systems; primarily Microsoft DOS, Microsoft Windows 3.0 and successors (a.k.a. Windows 3.x), Microsoft Windows 95 and its successors (a.k.a. Windows 9x), and Microsoft Windows NT.  In order to make a DCE application available to the greatest number of users, the client portion (at least) must be made to run on the various Microsoft-based operating systems.

Microsoft itself has recognized the need for its operating systems to function in the DCE world.  To facilitate this, Microsoft provides support for the core component of DCE; the remote procedure call (RPC; see [19]).  The RPC is a standard way to create a procedure which runs on a server that can be called from a client just as though this procedure were a normal procedure, local to the client.  In the case of DOS and Windows 3.x, this support is in the form of a toolkit of redistributable dynamic link libraries (DLL’s) that can be freely added to machines running one of these operating systems.  In the case of Windows 9x and Windows NT, support is built into the system itself.

However, Microsoft’s implementations of RPC’s are not based on the Open Group’s source code for DCE, as are most other manufacturers’ implementations.  Worse, Microsoft does not provide interoperability with other DCE functions that are standard in true DCE environments.  Such important functions as Cell Directory Service (CDS), security service, Distributed Time System (DTS), and DCE threads are unavailable in current Microsoft operating systems.  CDS provides a mechanism for discovering services which are available within a DCE cell.  DTS is a service which keeps time accurate and consistent among the cell members.  The security service provides authentication and encryption capability, and DCE threads are the standard POSIX threads which allow multiple threads of execution within a single program.

Due to the limited compatibility, many programs originally written for the DCE environment cannot be run, or even compiled, on Microsoft platforms.  The goal of this paper is to explore ways that the popular PC environments can function as a part of the Distributed Computing Environment.  In some cases this entails adding additional software to these platforms, writing work-around code to deal with incompatibilities, and sometimes even submitting to a loss of functionality.  Each of the popular PC environments has its own challenges and limitations.

 

1.4 Programming in the DCE world

The Distributed Computing Environment runs best and is fully functional on a variety of Unix based platforms and the IBM mainframe systems (e.g., AS/400, VM, and OS/390).  By fully functional, it is meant that all of the standard DCE services are available on these platforms.  The basic services (see [14]) include the Cell Directory Service (CDS), the Distributed Time Service (DTS), security services, Remote Procedure Calls (RPC), and the Distributed File System (DFS).  A fully featured DCE client machine has a CDS clerk (a clerk is a process running on a client machine which provides access to a given service), a DTS clerk, a Security clerk, DFS client software, and a DCE runtime library.  Each DCE server system may have some or all of the client software, plus it may include a CDS server, a DTS server, a DFS server, and a Security server.

A typical developer of a DCE application can assume that most or all of these services are available to his or her program.  Furthermore, since DCE has grown out of Unix and Unix-like environments, the developer typically assumes that standard Unix operating systems calls and standard ANSI C library support is available.  In general, it is assumed that the target system is POSIX compliant.

POSIX is an attempt to standardize the disparate flavors of Unix.  It is a set of IEEE standards (IEEE 10003.0 to 10003.22 a.k.a. POSIX level 0 to POSIX level 22) which define minimal requirements for an operating system to be considered compliant.  There are several levels of POSIX compatibility.  One of the serious problems for writing applications which function across Unix and PC platforms is that most PC platforms are not strictly POSIX compliant.  Even Microsoft Windows NT (NT) is merely POSIX level 1 compliant.  Since threading, for example, is not a requirement until POSIX level 4a, applications running on NT cannot presume thread support.

An even more difficult problem is NT’s support for POSIX.  POSIX on NT is implemented as a compatibility “subsystem”.  Windows NT was designed with a protected kernel that provides basic operating system services.  On top of this kernel, a layer of subsystems is provided which run as standard user mode applications (see Figure 1).  These subsystems add richer functionality that is not available directly from the kernel.  Supplied with the OS, are OS/2 and POSIX subsystems.  These subsystems are on an equal footing with standard Win32 applications in terms of services available to them.  However, these subsystems have their own executable formats.  They cannot be linked with standard libraries available to typical Win32 applications.


Figure 1: Microsoft Windows NT Architecture

 From “The Foundations of Microsoft Windows NT System Architecture” whitepaper by Microsoft Corporation, September 1997.

 

Since POSIX applications cannot link to standard Win32 libraries, they cannot take advantage of the rich functionality available to typical Win32 applications. Since there are few libraries available for the POSIX subsystem, POSIX applications are reduced to the role of poor step-relatives when compared to their Win32 counterparts.  Further confounding the situation, is the fact that DOS, Windows 3.x, and Windows 95 do not even purport to be POSIX compliant, as does NT.

 

1.5 What about the future?

It seems clear that DCE will continue to be important for the foreseeable future.  While arguments about what to distribute (e.g., the current concern with distributed object technology) may continue, there seems to be little question on the choice of whether or not to distribute.  The major camps regarding distributed objects both support DCE after a fashion.  The Object Management Group’s (OMG) Common Object Request Broker Architecture (CORBA) (see http://www.omg.org/corba/corbiiop.htm) standard contains provisions for interoperation with DCE.  Microsoft’s Distributed Component Object Model (DCOM) sits securely atop DCE’s RPC.  The Open Group has recently published standards for interoperation of the World Wide Web (WWW) with DCE (see http://www.camb.opengroup.org/RI/www/dceweb/).  Each of these is further examined in Section 6.

DCE has been making great strides into corporate America and the world as well.  As downsizing and right-sizing continue to drive companies away from completely centralized databases and applications, client-server and peer computing have made DCE an attractive standard.  As DCE continues to penetrate corporate America, it will become increasingly important for personal computers (deployed on great numbers of corporate desktops) to be able to participate as standard DCE platforms.  This project demonstrates that it is possible for personal computers to fulfill this role, with varying success, depending on the operating system and third party tools available.


2. Choosing Platforms

 

Software developers who wish to deploy distributed applications must make allowances for the operating systems and platforms that are deployed within their target organizations.  Although the developer may wish to leverage DCE, the target platforms may not support DCE, or may support it only partially.  Nonetheless, few organizations can afford to replace large numbers of systems, and this may require that developers find ways to integrate existing platforms into their solutions.

 

2.1 Microsoft DOS and Windows 3.x

The Microsoft Disk Operating System (DOS) and the windowing system that runs on top of it, Microsoft Windows 3.x, are very nearly ubiquitous in the PC environment.  Almost every PC ever made has been bundled with some flavor of DOS (including some compatible non-Microsoft versions such as products from IBM and Digital Research).  Since the introduction of Microsoft Windows 3.0, almost all PC’s are also bundled with Windows.  Windows 9x and Windows NT have replaced DOS and Windows 3.x (see Figure 3) in recent years in bundles with new machines.  However, the two-headed operating system of DOS/Windows 3.x remains deployed on vast numbers of corporate, academic, and home personal computers (see Figure 2).

 


Figure 2: Share of US PC’s Using Top Four Operating Systems

From Computer Intelligence InfoBeads study.  Used in accordance with “InfoBead End-User License Agreement” (see http://www.ci.infobeads.com/InfoBeads/Pages/Viewer/VIEWER_REGISTRATION.ASP?INFOBEAD_ID=C0000938AA)

 

 

 


Figure 3: 1997 OS Shipments With PC Systems Worldwide – Market Share

From Computer Intelligence InfoBeads study.  Used in accordance with “InfoBead End-User License Agreement” (see

http://www.ci.infobeads.com/InfoBeads/Pages/Viewer/VIEWER_REGISTRATION.ASP?INFOBEAD_ID=M0000913AB)

 

These facts might lead one to the conclusion that any project seeking to integrate personal computers into the world of the DCE would need to include support for DOS and Windows 3.x.  Unfortunately, these operating systems were not designed with remote computing in mind, and therefore do not support many of the features that make it possible to fully integrate them with DCE.

There are, however, “work arounds” that allow some degree of interoperability for these operating systems.  Microsoft provides a freely distributable product called Microsoft Remote Procedure Call Run-time that adds basic RPC functionality to DOS and Windows 3.x, but lacks all of the other standard DCE services.  By installing the Microsoft Remote Procedure Call Run-time on a DOS or Windows 3.x workstation, some very simple DCE applications can be made to run in this environment.  However, as shall be discussed later, such an application not only suffers from the lack of the aforementioned DCE services, but may also require a significant porting effort to compensate for differences in system calls, and general lack of POSIX compliance displayed by this environment.

 

2.1.2 Third party solutions

Another possible way to bring DOS/Windows 3.x into the DCE fold is through a set of commercial products from Gradient Technologies, Inc. (see http://www.gradient.com/Products/Pc-dce/dce_frt.htm) collectively called PC-DCE.  PC-DCE consists of the PC-DCE Runtime Kit which must be installed on each workstation that runs a DCE application that has been ported using PC-DCE plus an Application Developer’s Kit which provides all of the tools (e.g., IDL compiler, UUID Generator, libraries, and source headers) needed by a developer to port or write a DCE application.  Additional information on the Gradient product is provided in Section 4.2.  Even presuming that the PC-DCE product solves all other incompatibility issues between DOS/Windows 3.x and DCE proper, it is still a significant disadvantage to a developer to require a “for-cost” runtime that all users of a product would have to purchase or that would have to be redistributed with the product, thus increasing the base product cost.

However, even with third party additions to DOS and/or Windows 3.x, there is no support for the server portion of DCE services.  That is, the client (or “clerk” in DCE terminology) side of the various services may be available if the appropriate third party add-on is installed.  The server side portion of these various services must be run on a Unix machine within the cell or, as shall be demonstrated, from a Windows NT machine with third party add-ons.

 

2.1.3 Intermediary servers

One additional method for integrating DOS/Windows 3.1 workstations, as well as Windows 95 or Windows NT workstations, into the DCE standard environment is through the use of intermediary servers.  Intermediary servers are programs which act as servers in one environment and clients in another, forwarding the requests they receive to servers in the final target environment.  In this way, these programs bridge two disparate environments.  For more detailed information, see Shirolkar [27].

An intermediary server strategy could be employed on a machine (e.g., a Unix workstation) which is a normal member of a DCE cell.  If this machine also supported a protocol that is accessible to typical PC machines (e.g., IPX or TCP/IP), it could function as an intermediary server.  That is, a program could be written that accepts requests via, for example, TCP/IP and then makes a corresponding call to a true DCE server application that actually services the request and returns information to the intermediary server.  The intermediary could then return the results to the client via the client’s understood protocol.

This system would allow PC clients to access specific DCE servers without any additional software.  However, it would require that a custom intermediary server be written for each server to which access was desired.  While this might be a very good solution if an organization required access to only one or a small number of DCE servers from their personal computers, the effort involved with writing many intermediary servers in the more general case might be deemed too great.

Sirish [28] proposes a variation on intermediary servers called application gateways.  An application gateway is a mechanism for redirecting the input/output of a client (or stand-alone) program.  This solution allows a PC to talk to an application gateway that is running on a member of a DCE cell, again via a protocol supported by both the PC and the DCE machine.  However, in this scenario, the PC is actually interoperating with a DCE client program.  The client program communicates as normal with the DCE server, but the user interface is remotely transported to the PC, essentially enabling the PC to function as a DCE client.

The primary drawback of such a solution is that it can only work with programs that use standard I/O mechanisms such as the stdio library.  Modern windowing user interfaces could conceivably be supported as well, but this would likely increase bandwidth requirements significantly.  Another disadvantage of this solution is that it requires recompilation of the client software, which may not be possible in some instances due to the lack of source code availability.

 

2.2 Microsoft Windows 95

In late 1995, Microsoft released the successor to Windows 3.x, dubbed Windows 95.  Windows 95 was a dramatic departure from Windows 3.x with regard to user interface, as well as some of its internal architecture.  Windows 9x refers to Windows 95 and its successors (Windows 98 has only recently been released at the time of this writing).  Windows 9x is largely a 32 bit operating system, while Windows 3.x is completely 16 bit.  In the Microsoft world, this means not only that Windows 9x supports 32 bit integers, but more importantly that it natively supports a set of API’s (Application Programming Interfaces) called Win32, as well as many advanced OS features such as threading.  Win32 is the basis for writing applications that run on both Windows 9x and Windows NT.

Although Windows 9x is dramatically more advanced than Windows 3.x, it remains focused on backward compatibility with DOS and Windows 3.x applications.  This means that much of Windows 9x retains 16 bit subsystems and that the designers of Windows 9x continue to choose compatibility when tradeoffs exist between support for legacy applications and robustness and/or security.  Microsoft has stated that Windows 9x will continue to support virtually all DOS and Windows 3.x applications, including “poorly behaved” games and other applications.  By committing to the support of these legacy applications, Microsoft is forced to allow applications to perform dangerous operations (such as, in some cases, writing to memory that is in the process space of another application) that may compromise the integrity of the entire OS session.

In terms of support for DCE applications, Windows 9x natively ships with support for RPC’s, but does not support any of the other DCE services.  Here again, as with Windows 3.x, a DCE developer porting an application to Windows 9x would come up against the lack of DCE services as well as the total lack of POSIX support.  An application written for even the most basic level of POSIX compliance does not typically compile under Windows 9x.  Again, a third party add-on such as Gradient’s products can somewhat improve this situation, but the developer then must rely on deployment of the third party product upon all target workstations (and must be prepared for the consequences of the associated expense).

As with DOS and Windows 3.x, there are currently no add-ons for Windows 9x which implement the server side of the various DCE services.  Therefore a Unix workstation or a Windows NT machine is required to provide the server side services within a DCE cell.

 

2.3 Microsoft Windows NT

Windows NT is Microsoft’s modern fully 32 bit operating system.  Unlike Windows 9x, which was developed from earlier Windows 3.x code, Windows NT was written from the ground up with the goal of being a secure and robust operating system.  Since its introduction, many features have been added to Windows NT and some code is now shared between the development teams at Microsoft, which work on Windows 9x and Windows NT respectively.  It has been noted in the press that sharing code with the Windows 9x team may tend to compromise the NT design goals of robustness and security.  Personal experience tends to validate this criticism.

Windows NT natively supports RPC’s in the same way that Windows 9x does.  The Microsoft implementation of RPC is compatible with DCE RPC, but is developed independently by Microsoft.  Windows NT does not ship with any DCE services beyond RPC.  However, Gradient and Digital Equipment Corporation both provide solutions that fully implement DCE client (clerk) services on Windows NT.  Windows NT can also be extended to provide the DCE server side services (CDS server,  DTS server,  DFS server, and Security server) via packages available from each of these vendors.

 

2.4 IBM OS/2 and Apple Macintosh

While the Microsoft family of operating systems dominate in terms of installed base (see Figure 2), there are still many installations which have large numbers of Apple Macintosh computers running their own proprietary “System” operating system (currently System 8).  Likewise, certain organizations have large numbers of IBM’s OS/2 operating systems deployed.

Currently, the Apple Macintosh may be integrated into the DCE world only through the DCE client extensions supplied by Gradient (see http://www.gradient.com/Products/Pc-dce/pcdce_front.htm).  Gradient’s kit supplies the same client or clerk side services, as do the analogous kits for Windows 3.x, Windows 9x, and Windows NT.  IBM’s OS/2 can be brought into the DCE world through either Gradient’s product (again, with the same features as those available on the Macintosh platform), or through IBM’s own DCE package (http://www.networking.ibm.com/dce/dceprod.html).  In addition, IBM has recently introduced a new product called Directory Systems Series (DSS; see http://www.software.ibm.com/is/sw-servers/directory/index.html) which provides the server side software for DCE on OS/2 servers (as well as other platforms for that matter).

2.5 OS choices conclusion

While Apple Macintosh computers and computers running IBM’s OS/2 are certainly relevant and important to certain environments, they have each essentially become niche players.  Therefore, these two operating systems are excluded from further discussion.

A similar case can be made that Microsoft DOS and Microsoft Windows 3.x systems are rapidly fading into the past and should not be considered further either.  Though this is true to some extent, there remain vast numbers (see Figure 2) of DOS and Windows 3.x clients deployed throughout business and academia.  It seems premature to discard consideration of these platforms entirely.  Though neither can be full players in the DCE world due to their inherent lack of capabilities (e.g., true threading), they can, in many cases, be used for client-side solutions which leverage the more mature capabilities available on servers from other environments.  For example, a single-threaded DOS DCE client application may be completely sufficient to access and utilize a multi-threaded DCE server application running on a Windows NT system or a Unix system.

In the next section the tools and environment needed to implement a DCE application on each of the selected target platforms will be explored.  Each of the DOS/Windows 3.x, Windows 9.x, and Windows NT platforms has unique requirements and can benefit from specific additional third party software in order to function as part of a DCE cell.


3. What You Need

 

This chapter provides a minimal list of software and tools that are required to create an RPC enabled application.  Such applications are not fully DCE enabled, lacking security, name services, and distributed file system support.  However, applications written with these minimal standard Microsoft tools can be distributed without a need for expensive and cumbersome third party software, and are able to interoperate with standard DCE applications through RPC’s.

One alternative to forgoing CDS capability that can augment this approach is to install the Name Service Interface Daemon (NSID).  NSID can be installed on a CDS capable client (such as an NT workstation with Digital DCE installed).  NSID can then forward Microsoft RPC calls to the real CDS in the cell.  NSID can thus partially obviate the need for CDS support on all client workstations.  However, all Microsoft RPC clients in the cell will have to be configured to access the specific machine with NSID installed, and this can present both configuration and load-balancing issues (i.e., the machine with NSID installed may be overtaxed if many clients utilize it).  This problem can be mitigated by deploying multiple instances of NSID to balance the load, but the lack of any centralized capability for configuring clients could prove problematic.

 

3.1 Supported protocol stacks

DCE is able to sit atop a long list of supported wire protocols.  Wire protocols, or protocol stacks in Microsoft parlance, are software modules which essentially implement the Data Link Layer, the Network Layer, and the Transport Layer of the Open Systems Interconnection (OSI) Reference model.  However, in Microsoft environments, DCE must sit atop a protocol stack that is specifically designed to support DCE.  For DOS and Windows 3.x, this generally means a stack called the Microsoft Remote Procedure Call 16 Bit Run-time (Microsoft RPC RT16).  Despite its name, Microsoft RPC RT16 provides not only the actual RPC run-time modules, but also a wide selection of underlying protocol stacks.  These include UDP/IP, TCP/IP, Named Pipes, Netbios, DEC Net, SPX, and IPX, all for use under both Windows 3.x and MS DOS.

Microsoft RPC RT16 is available from Microsoft as part of the Windows 32 SDK which is included in the Microsoft Developer Network Library (MSDN).  MSDN is a set of software and reference material available via an annual subscription from Microsoft.  The January 1998 edition of MSDN provides the RPC RT16 on disk number 7 in the directory \MSTOOLS\RPC_RT16.  Windows for Workgroups 3.11 came with a protocol stack that is essentially the same as RPC RT16, and so does not require installation of this additional software.  Installations using Microsoft LAN Manager also natively support the RPC RT16, and do not require additional software.

Other protocol stacks which support Windows Sockets may also function correctly as RPC transports for DOS and Windows 3.x environments, but there are no guarantees.  Windows 9x and Windows NT each come equipped with native protocol stacks that support Microsoft’s RPC, as well as the necessary RPC run-time.  No additional software is required.

 

3.2 Development kits

In order to use RPC’s (the base feature that is available as a standard for Microsoft operating systems), a developer of software needs the appropriate software development kit (SDK).  This SDK consists of the appropriate C language header files, libraries, and binary tools needed to create an RPC enabled application.  In the case of DOS and Windows 3.x, this is provided as an add-on called the Microsoft Remote Procedure Call SDK (RPC SDK).  Like the RPC RT16, the RPC SDK is available as part of MSDN. In the January 1998 edition, RPC SDK is included on disk number 7 under the \MSTOOLS\RPC_SDK subdirectory.

For 32 bit environments (i.e., Windows 9.x and Windows NT), the requisite header files, libraries, and tools are available as a standard part of Microsoft’s C compiler.  The current version at the time of this writing is Visual C++ version 5.0 (VC 5).  No additional software is required if a standard VC 5 installation is used.  Non-Microsoft compilers are supported for Win32 if they can link to standard Microsoft libraries.  The requisite libraries are also included in MSDN and called the Win32 SDK.  The Win32 SDK is on disk number 7 under the \MSTOOLS subdirectory in the January 1998 edition of MSDN.

 

3.3 Hardware

Apart from a standard IBM compatible PC, the main hardware requirement to utilize RPC’s is an NDIS compliant network card.  Most all network cards currently available on the market come with NDIS drivers, and so hardware is typically not an issue.

            As is the goal of DCE, the types of network card and network topology are not at issue.  Token ring, Ethernet, and other topologies that support NDIS are transparently supported.

 

3.4 Summary of what you need

By installing the appropriate protocol stack and the requisite RPC run-time code on an IBM standard PC with a network card that supports NDIS drivers, one has all that is needed to run a simple application that can use RPC’s.  Such applications can interoperate with standard DCE applications running on any DCE compliant machine, provided that only RPC facilities are needed.  If security services, name services, threading, or any other DCE service is required on the client PC, additional software is needed.  To develop limited applications such as this, one also needs the appropriate SDK software.

For some simple applications, these requirements are quite sufficient.  Nonetheless, the developer of such an application must be clear that the target platform is, in fact, a PC.  The developer must not assume when writing code that POSIX support is available, and must not rely on any DCE service, save RPC.  This is fine for an application that simply makes a call to be executed on a remote machine.  However, most real world applications certainly require security, and likely require name space service.  In addition, the great strength of DCE is that it promises to free developers from making assumptions about platforms.  This makes the basic solution available from Microsoft rather unsatisfying.  A more complete solution must include some third party software to add DCE features and services that are not available from Microsoft.

Figure 4: Summary Of Requirements For RPC On Microsoft Platforms


 



4. Third Party Tools

 

In this chapter, software that simplifies and improves the integration of personal computers into DCE is explored.  This includes tools provided by third party companies that add to the native capabilities of PC operating systems by adding support for additional DCE services, or enhancing the environment of developers seeking to write DCE compatible code.

 

4.1 Digital DCE for Windows NT and Windows 95

Digital Equipment Corporation (DEC; now a subsidiary of Compaq Computer Corporation) offers a full implementation of DCE for Windows NT and Windows 95 (see http://www.dec.com/dce/).  Products are available both for the client (or clerk) side and for the server side of DCE for Windows NT, and for the client side for Windows 95.  IBM offers the same set of products rebranded under the IBM name.

For this project, version 1.1 of the client side product on the Windows NT platform was tested.  The product comes in two parts.  The first is called “Digital DCE for Windows NT Runtime”, and must be deployed on any NT workstation that is to be part of a standard DCE cell.  The second part is called “Digital DCE for Windows NT ADK”, meaning the “Application Development Kit”.  Those who wish to write (as opposed to use) DCE applications on NT require this part.  It includes the needed binary tools (e.g., the IDL compiler) as well as the header files and libraries needed to create a full-fledged DCE application.

Digital DCE for Windows NT includes fully DCE-compliant RPC (though still sitting atop Microsoft’s implementation of RPC rather than the Open Group source), POSIX threads, Security Client, CDS Clerk, Name Service Interface Daemon (NSID), and Distributed Time Service Clerk (DTS).  Additional packages are available to provide DCE Security Server and CDS Server on the NT platform.  With the runtime product installed on NT, a workstation was successfully configured as a normal DCE machine within a University of Missouri campus DCE cell, even though the NT workstation was initially located in the Datastorm Technologies offices across town from the University campus.

Version 1.1 of Digital DCE was designed to run on Windows NT 3.51.  For this project, the software was deployed on Windows NT 4.0 as well.  However, version 1.1 seems to require a dynamic link library (DLL) which was only installed under Windows NT 3.51.  When installing the product on NT 4.0, it is necessary to copy RPCDCE4.DLL into the \WINNT\SYSTEM32 directory before applications compiled with the ADK will run.  RPCDCE4.DLL ships with Windows NT 3.5.  Another difficulty with version 1.1, is the necessity of cell administrator security to install the product.  Digital claims that this will not be necessary for the new “Local Client” option in version 2.0 (see http://www.dec.com/dce/products/v20ntwp.htm), which incidentally adds support for C++ applications.  Since version 2.0 is designed to run on NT 4.0, it seems likely that the dependency on RPCDCE4.DLL will also be removed.

As mentioned, Digital also provides a client side DCE package for Windows 95 (see http://www.dec.com/dce/dcefiles/win95.htm).  This has not been tested as a part of this project, but will likely have some of the same advantages and disadvantages of the NT product (e.g., porting “normal” DCE applications that assume full POSIX compliance will continue to be a challenge).  There is no Security Server or CDS Server module available for Windows 95, so Windows 95 DCE installations require either a Unix machine in the cell to provide these services or a Windows NT machine with such modules installed.

 

4.2 Gradient’s PC/DCE

Like Digital’s offering, Gradient provides DCE software that has been ported from the standard OSF DCE source code to PC environments (see http://www.gradient.com/Products/Pc-dce/pcdce_front.htm).  Gradient offers runtime and ADK modules for Windows NT and Windows 95, as well as Security Server and CDS Server modules for NT.  Gradient also offers runtime and ADK modules for Windows 3.1 and Apple Macintosh platforms.

Gradient’s products are available for testing through a free limited-time download (see http://www.gradient.com/Products/evals/evals.htm).  However, this program was not available in time to allow testing on Gradient’s platform.  Previously, Gradient’s software was not available for free evaluations and the cost of procuring the software was deemed prohibitive.  Nonetheless, since Gradient’s products are based on OSF source code, it seems likely that they may be a very viable alternative to Digital’s products.

 

4.3 Hewlett-Packard OODCE

OODCE is a set of C++ classes layered on top of the standard DCE API’s.  The goal is to simplify DCE development and bring it more naturally into the C++/Object-Oriented world.  However, OODCE is currently a proprietary extension to DCE available only for Hewlett-Packard’s HP/9000 Unix platform (see http://www.hp.com/gsy/3b4.html).  While applications written in OODCE are interoperable with traditional C based DCE applications, the code itself is non-portable.

Although OODCE may allow developers in a purely HP/9000 environment to write DCE code more quickly and reliably, the sacrifice of true cross-platform coding seems too great.  As concepts from OODCE make their way into the OSF DCE standard, it will be appropriate to take advantage of them.  However, until then, it may be best to ignore this proprietary solution.

 


5. Porting An Existing OSF DCE Application to Microsoft Platforms (BINOP)

 

BINOP is a program written by Prof. Gordon K. Springer at the University of Missouri-Columbia to demonstrate DCE remote procedure calls.  The BINOP client module communicates with BINOP servers that are registered in the DCE namespace by issuing calls to them to do additions and subtractions.  BINOP is composed of a demonstration shell (BINOPDEMO), a worker client (BINOPC), a statistics gathering client (BINOPST), a help-providing client (BINOPHLP), and a server (BINOPS).  While the actual work performed by BINOP is trivial, the program serves to demonstrate RPC’s, the utility of the CDS, strategies for finding servers outside the local cell, and the client-per-thread server strategy.

BINOP can be built for DEC Alpha, Mips, Cray, HP 9000, IBM RS6000, and IBM mainframe platforms.  It was written with standard DCE platforms in mind as the target, presuming that most standard Unix facilities are also available.  This project sought to make a BINOP build and run on Microsoft platforms.  To that end, the results are available in Appendix A: BINOP Source Code.  As will be noted, there are several ways to build and use BINOP on Microsoft platforms, each with various tradeoffs in terms of features, portability, and requirements.  In the end, BINOP was able to interoperate with standard DCE BINOP servers using a DOS/Windows 3.x client and with a Win32 client.  Using Digital DCE for Windows NT, it was also possible to setup a BINOP server on the NT platform that could be accessed from any other DCE platform client.

 

5.1 Straight Microsoft

The first step in porting BINOP to Microsoft platforms was to try to make BINOP as fully functional as possible using only the native Microsoft tools available.  This meant that it should be possible to build BINOP with only Visual C++ installed on Win32 platforms, and with only Visual C++ and the RPC SDK installed on DOS and Windows 3.x platforms.  Of course, where BINOP uses DCE or Unix facilities that are unavailable on Microsoft platforms, it is necessary to either write workarounds or simply live with the loss of functionality.

This goal was accomplished only for the BINOPC program.  BINOPC is the worker executable that actually makes the addition and subtraction RPC’s.  Even here, however there was a need to conditionally compile portions of the code.  For example, the file MAKEPASS.C includes PTHREAD.H.  This is a support file for POSIX threads.  Since Microsoft platforms do not directly support POSIX threads, this header file had to be conditionally excluded (based on the Win32RAW macro, which was used to indicate a Microsoft native only compilation).  In addition, the Microsoft DCE compatibility file DCEPORT.H had to be included since Microsoft changed the names and calling conventions of many standard DCE API’s in their implementation of the RPC (e.g., rpc_binding_vector_free() becomes RpcBindingVectorFree()).

Several other compromises were necessary, including conditionally removing the error handling for the RPC’s in MAKEPASS.C since the TRY-CATCH syntax has been changed under current Microsoft compilers.  TRY, CATCH, CATCH_ALL, and ENDTRY are macros used for structured exception handling in the C and C++ languages.  While Microsoft provides a header file called DCEPORT.H to map these macros (as well as make numerous other remappings) to appropriate Microsoft syntax, the mappings currently appear to be outdated.

Figure 5 shows a successful trial run of the BINOPC client compiled using the WIN32RAW target (and thereby lacking the error handling mentioned).  Notice that the program completes the series of additions and subtractions successfully.  This trial was performed on a Windows NT 4.0 workstation that was interoperating with a BINOPS server, running on a Digital Unix machine called “Condor” on the University of Missouri campus.

Figure 5: Successful WIN32RAW Binopc Run.

 

Figure 6 shows the same BINOPC client, again running on the same Windows NT machine and communicating with the same Digital Unix machine.  After the program printed the result “38”, a communication failure was simulated by disconnecting Windows NT Dial-up Networking (which was being used to achieve Internet connectivity).  Figure 7 shows the error dialog displayed by Windows NT when this communication error occurred.  Clearly, this is not a desirable way to handle such a fault.

Figure 6: WIN32RAW Binopc Run With Communication Error.

Figure 7: Windows NT OS Error Dialog.

           

Figure 8 shows BINOPC on the same Windows NT workstation, but recompiled using the WIN32 target (discussed in Section 5.2).  Again, the program is communicating with the “Condor” BINOPS server, and again a communications error is simulated.  This time, however, the error handling code is in place, and the program gracefully degrades by reporting the error.

Figure 8: WIN32 Binopc Run With Communication Error.

 

An effort was made to port the remainder of the BINOP code to the “Win32RAW” platform.  However, it eventually seemed clear that the amount of code necessary to accomplish this without use of third party software was prohibitive.  For example, in order to port the server code properly, it would be necessary to write a custom implementation of POSIX threads.  Since DOS and Windows 3.x do not support true threads, this seemed beyond reason.  Although mapping POSIX threads to Win32 threads would certainly have been possible, it was more sensible to rely on a third party product for POSIX threads as well as many other standard DCE features.

 

5.2 Full DCE

After creating the raw build of BINOP, a build of the BINOP source that relied on the Digital DCE for Windows NT ADK for compilation and on the Digital DCE for Windows NT Runtime for execution of the resultant binaries was created.  As can be seen from the source in Appendix A, this build is termed the Win32 build.  The goal for this build was to fully port BINOP and be able to run both clients and servers on a Windows NT platform.  This goal assumes that the Digital DCE for Windows NT Runtime is installed and that the host machine is properly configured as part of a DCE cell.  That is, it is assumed that there is a machine in the cell providing the CDS server and security server and that the host is able to access them in standard DCE fashion.  No assumption is made with regard to supported wire protocols, though tests for this project focused on TCP/IP and UDP/IP since these protocols are available on nearly every platform.

 

5.2.1 Porting difficulties

Again, the porting process uncovered serious incompatibilities between standard DCE platforms and the Microsoft platforms that had to be worked around, even with the additional Digital software.  Many problems were sufficiently subtle that long hours of pouring over the code were necessary to discover their source.  Even small differences can cause code to fail.  For example, code that attempts to parse a file path must look for a backslash (“\”) on Microsoft platforms and a forward slash (“/”) on Unix platforms.  This was dealt with in BINOPS.C.  Also in BINOPS.C, it was necessary to change a function (rindex()) that was not strictly POSIX compliant to its POSIX equivalent (strrchr()).

Any code that deals directly with file systems or file permissions also tends to fail.  One such function is the umask() function which is unsupported on Microsoft platforms.  There were many other incompatibilities that were essentially the result of NT’s lack of POSIX compliance in its Win32 subsystem or minor variances from POSIX in the BINOP code.  These incompatibilities are identified throughout the code in Appendix A where conditional compilation constructs based upon the Win32 macro are used.

Several other incompatibility challenges arose due to the fact that even using Digital DCE for Windows NT, one is still left using Microsoft’s implementation of RPC’s and the RPC set of API’s.  For example, in BINOPST.C, special code was added to deal with a difference under the Microsoft implementation of the rpc_mgmt_inq_stats() function.  Here, the universal unique identifier (UUID) of the server is required for this API, rather than the client as is the case under standard DCE.  Since Gradient’s product is reputed to use OSF source even for RPC’s, it may not suffer from some of the incompatibilities of Digital’s product.  This was not tested, however.

Perhaps the most difficult compatibility problem to track down was a difference in Microsoft’s implementation of a DCE interface-specification.  An interface-specification is an opaque data structure containing information the RPC run-time library uses to communicate with the stubs.  A stub is a piece of code created by an IDL compiler, which acts as a surrogate for a function.  A stub communicates with the RPC runtime in order to contact remote processes, marshals and/or unmarshals parameters, and then calls the actual worker function that it represents.  Under standard DCE, the IDL compiler-generated IDL_ifspec variable is a rpc_if_rep_t structure, while under Microsoft it is a RPC_CLIENT_INTERFACE structure.  Admittedly, these are considered to be “opaque” structures that are not strictly supposed to be used by application programs.  However, the server finding module used by BINOP (FINDSRVS) utilizes the interface-specification as a convenient way to pass UUID’s to the finding server, and this technique works fine on all standard DCE platforms.  Since Microsoft’s structure is dramatically different in format than the standard structure used by DCE, it was necessary to create a temporary structure and use it to reformat the information contained in Microsoft’s structure under Win32.  It should be noted that incompatibilities between Microsoft RPC and DCE RPC were almost completely undocumented, prior to the publication of this document.  Many months were spent discovering the causes of problems such as the interface-specification incompatibility.

The build process itself also suffered from platform incompatibilities.  For example, the syntax of the standard Unix MAKE utility is slightly different than the Microsoft NMAKE utility.  The Unix makefile’s for BINOP contained lines with the ‘date’ macro, which simply does not evaluate under Microsoft’s NMAKE (under Unix it prints the current date).  For this project, a proprietary utility called TM that echoes the current time and date was substituted.    Other incompatibilities included the lack of the Unix CHMOD utility on Microsoft platforms and differing syntax for dealing with library files.

 

5.2.2 Platform advantages

While there were limitations and difficulties in moving BINOP to the Win32 platform, there were also opportunities to take advantage of platform specific strengths and features.  Since there was no direct concept of a Unix daemon process under Win32, the ability for the BINOP server to run as a Win32 service was added.  A service is a user-interface-less program that can be controlled via the Microsoft Control Panel Service applet.  This applet allows the user to start, stop, pause, and control the automatic start-up options for the service.  Some Microsoft-supplied code was modified and included in the project, in order to turn BINOPS into a service.  However, it should be noted that it was a significant task even with the Microsoft code to turn BINOPS into a service, since BINOPS was designed to execute as a Unix daemon process.  Some instability was encountered when running the server for long periods of time as a service, but this was not conclusively proven to be related to the service code.

For the future, it would be sensible to take advantage of the rich user interface features of the Win32 platform.  It would be possible to further separate the user interface portions of BINOP from the worker portions.  This would facilitate replacing the user interface modules in a platform specific manner, allowing Win32 in particular to have an excellent user interface.  This was not done, but would be a relatively straightforward extension of the porting process.

 

5.2.3 General challenges

In addition to the direct issues involved with porting BINOP to the Win32 platform, several issues that are general to setting up and using DCE in the real world were encountered during the project.  Since some of the effort took place on the University of Missouri campus and some took place in a private business (Datastorm Technologies, Inc. – now the Columbia, Missouri site for Quarterdeck Corporation), several problems became apparent that might not otherwise surface in a project that was conducted in one physical locale.  For example, it was found that the Distributed Time Service (DTS) was often generating errors due to occasional extended lags in routing packets between the two sites (although the two sites were located within the same city, packets often went across the country, taking as many as 20 hops, before getting to the other site!).

Toward the end of the project, Quarterdeck installed a “firewall”, ostensibly to protect its network from unwanted outside influences.  This firewall was configured to allow certain of the most popular types of TCP/IP traffic to pass through it (e.g., HTTP, FTP, etc.).  The firewall was not, however, configured to allow DCE traffic to pass through it.  This effectively ended the ability to do multi-site testing for this project.  Client-side testing was largely possible through dial-up TCP/IP (PPP), but since DCE requires a static IP address endpoint for actual membership in a cell, server side testing on the dialing host was not possible.  As DCE becomes more prevalent in private businesses, firewalls must evolve to support the multi-protocol and multi-port nature of DCE.


 6. The Future (Is Sooner Than You Think)

 

6.1 DCOM

DCOM is Microsoft’s Distributed Component Object Model.  DCOM allows an object to be utilized by a client program without regard to whether the component is actually executing on the local machine or across a network.  It is based on the Component Object Model (COM), which is Microsoft’s standard for creating reusable components   (see http://www.microsoft.com/com/ and the seminal Inside OLE 2nd Edition by Kraig Brockschmidt, Microsoft Press, 1995).  While COM itself is not concerned with distributed computing, Microsoft has built COM on top of an Interface Definition Language (IDL) scheme that is very similar to the IDL facilities in both DCE and CORBA (see section 6.2 for a discussion of CORBA).  The object methods in the COM IDL files can have attributes that correspond to DCE RPC’s (e.g., [in], [out], etc.).

With Microsoft’s introduction of DCOM (see the DCOM specification: (http://www.microsoft.com/oledev/olecom/draft-brown-dcom-v1-spec-01.txt, which is an Internet Engineering Task Force (IETF) working document) in Windows NT 4.0, standard COM objects can be “remoted”.  That is, Microsoft provides marshaling code via their IDL compiler, the Microsoft Interface Definition Language compiler (MIDL), that allows methods of defined objects to execute on a remote machine.  In fact, this remoting mechanism is Microsoft’s RPC!  This means that standard RPC code can be written to take advantage of services provided by DCOM objects, with the proviso that RPC code would have to deal with C++ name mangling (see Glossary entry on name mangling) and with special DCOM protocol concerns, noted hereafter.  In an effort to make DCOM more open, Microsoft has entered into a project with the Open Group to make this technology available on other platforms (see http://www.activex.org/announce/ActiveX_Core_Technologies.htm).


Figure 9: DCOM Architecture

 

Adapted and simplified from “C++ Report” January 1998, p. 26 Patterns++ column.

 

Figure 9 shows a simplified view of the DCOM architecture.  Essentially, Microsoft has added an infrastructure that transparently creates and manages objects on remote machines, so the writer of the client application does not need to know anything about RPC’s.  For example, the author of the client application does not need to know whether or not the server on the remote machine is running.  The application simply creates and uses the object, and DCOM takes care of actually creating and shutting down the server object as necessary.

It is worth noting, however, that Microsoft has not currently defined a scheme for object discovery.  That is, DCOM does not have anything akin to DCE’s Cell Directory Service.  A client DCOM application (or at least a field in the client machine’s registry database) does need to know on what machine the remote object is executing!  Microsoft plans to correct this problem in the future through the proliferation of their Active Directory Services (see http://www.microsoft.com/ntserver/guide/activedirectory.asp).

Microsoft hopes that DCOM will become a cross platform standard that essentially replaces DCE.  In partnership with Microsoft, Software AG is currently porting DCOM to various non-Microsoft platforms, including IBM MVS, Sun Solaris, Digital Unix, and several others (see http://www.sagus.com/Prod-i~1/Net-comp/dcom/index.htm).

 

6.1.1 DCOM/DCE interoperability mechanics

The following is a brief discussion of the mechanics that allow DCOM to sit atop DCE RPC.  Note that much of the code to implement DCOM’s scheme is automatically generated by the MIDL compiler, and is not typically a concern for a developer merely wishing to utilize DCOM.  For complete details of the DCOM protocols see Microsoft [17], and Stal [29].

Each computer supporting DCOM provides a service known as the “Object Exporter”.  The Object Exporter communicates via standard DCE RPC on well-known endpoints (protocol specific identifiers unique to a given server process, such as a TCP/IP port number), and its function is very similar to the standard DCE endpoint mapper.  The DCE endpoint mapper is a service that runs on any workstation having DCE servers, and in most implementations is simply a component of the RPC daemon.  The service tracks the endpoints the servers on that node are currently using, and communicates this information to the RPC runtime of clients wishing to use a given server.  In fact, Microsoft has proposed that the special endpoints used by the Object Exporter to talk to the runtime be the same as that used by the DCE endpoint mapper.

The Object Exporter supports several remotely callable procedures, bound up in what Microsoft refers to as the IObjectExporter interface.  This name is somewhat misleading because it seems to imply that IObjectExporter is a COM interface, when in fact it is not.  Actually, IObjectExporter is merely a collection of the following RPC’s implemented on every computer that supports DCOM: ResolveOxid(), SimplePing(), and ComplexPing().

Every DCOM object provided by a server must support the IRemUnknown interface.  Unlike IObjectExporter, this is a true COM interface.  Its methods are similar to those in the standard COM IUnknown interface with the “Rem” prefix added: RemQueryInterface(), RemAddRef(), and RemRelease().

By implementing these interfaces, and dealing with standard C++ name mangling, any platform should be able to support DCOM.  At least, of course, until Microsoft changes the rules!  It is worth noting that Microsoft hopes to make DCOM into a platform independent standard, although history tells us that Microsoft generally respects only those standards over which it has control.

 

6.2 CORBA

The Common Object Request Broker Architecture (CORBA) is the Object Management Group’s (OMG) (see http://www.omg.org/corba/) answer to the problems of distributed computing.  While similar to DCE and DCOM in that it uses an Interface Definition Language (IDL) to specify remote object procedures and methods, it does not build directly upon standard RPC’s.  The designers of CORBA consider the wire protocol an implementation detail (while RPC specifies a layer above the wire protocol and allows various wire protocols to “plug in” to it).  The strength of this approach is that any protocol can potentially be used by an implementation of a CORBA Object Request Broker (ORB).  The weakness, of course, is that there are no clear means for ORB’s using different wire protocols to interoperate.


Figure 10: OMG’s CORBA

Adapted and simplified from “C++ Report” January 1998, p. 26 Patterns++ column.

 

Figure 10 is a bird’s eye view of OMG’s flexible CORBA architecture.  Note that a TCP socket is specified as the transport for the CORBA remote function.  This is actually true specifically for the Internet Inter-ORB Protocol (IIOP), which is a particular implementation of an ORB protocol that is commonly implemented by vendors of various ORB’s.  If this ORB protocol is implemented on all ORB’s involved in a given communication session, then the ORB’s can interoperate.  Again, a given vendor’s ORB may use any wire protocol, but most will also support IIOP in order to work in multi-vendor environments. 

Like DCE, CORBA is not a standard part of common personal computer environments.  In order to deploy CORBA clients and servers on PC’s, it is necessary to install additional third party software.  For example, Digital Equipment Corporation sells a product called Object Broker, which includes PC desktop connectivity with CORBA (see http://www.digital.com/objectbroker/).  The product accomplishes this by mapping CORBA functionality to Microsoft OLE/COM for use on the PC.  The Distributed System Object Model (DSOM), which is IBM’s CORBA ORB, is also available for Microsoft Windows platforms, as well as IBM OS/2 (see http://www.software.ibm.com/ad/somobjects/).

 

6.3 WWW and DCE

The World Wide Web (WWW or Web) has become a popular tool for nearly every networked computer.  The Web was initially a medium for the exchange of academic information, and soon grew to provide corporate and recreational information as well.  However, recently, businesses have begun to use the Web to truly conduct business, through electronic commerce, electronic brokerage services, and connection of geographically diverse corporate Intranets.  With this change has come a need for security and authentication.  Many businesses still resist connecting their internal networks to the Internet, feeling that these security issues are inadequately addressed.

The organization responsible for the continued development of the DCE standard (The Open Group) has supported the “DCE Web Project” in an attempt to resolve these concerns (see http://www.camb.opengroup.org/www/dceweb/ and http://www.camb.opengroup.org/RI/www/prism/index.html).  The initial strategy of the project is to provide what is called a Secure Local Proxy (SLP) for browsers within the corporate Intranet.  This means that browsers on desktops within a corporation (presumably behind a firewall) can reach a proxy (installed on that client machine) through standard browser means (i.e., the HTTP protocol).  The proxy may then access secure information via DCE connection to other internal resources, allowing for standard DCE encryption and authentication services, as well as the ability to use CDS for discovering relevant servers (and thereby potentially providing such services as load-balancing).  This scheme allows a corporation to internally publish sensitive or secured information on the “DCE Web”, and yet allow users to access this information through the standard browsers to which they’ve become accustomed.

An auxiliary strategy for the project is to provide a Security Domain Gateway (SDG), accessible through the standard Secure Sockets Layer (SSL) protocol (which is now available to most popular web browsers).  Here, no installation of software on client machines is necessary.  SSL is employed to provide security and authentication from the client to the SDG, and the SDG uses a temporary DCE identity (derived from the SSL properties of the client) to access secure DCE resources.  Like the SLP strategy, the SDG can also take advantage of other DCE services such as CDS.  Organizations can determine which groups of users can access a given document through standard DCE Access Control Lists (ACL).  This solution is essentially an intermediary server for web browser applications (see Section 2.1.3).

Both the SLP and the SDG can access the multi-protocol DCE Web Server.  This third component allows corporations to publish given documents through standard Web methods (e.g., HTTP), but to also publish security sensitive documents as available only through secure DCE methods, invoked by either the SLP or the SDG.  Figure 11, following, illustrates the general architecture of the complete DCE Web project.

Figure 11: DCE-Web

The Open Software Group provided this clip art.

 

The Open Software Group’s DCE Web project is a viable alternative to true DCE client software for organizations primarily interested in deploying DCE security on their personal computers.  While this method of integrating PC’s into DCE does not allow standard DCE software to run on client machines, it does provide a middle ground that may be very useful for some organizations.


7. Conclusion

 

DCE can solve many of the inherent problems of distributed computing.  It allows heterogeneous computers to interoperate across a wide variety of network topologies and protocols.  It allows software developers to write traditional functionally-decomposed code with little consideration for which functions are executing locally and which ones are actually being executed on a remote system.  DCE improves the use of network bandwidth by allowing developers to deploy computing functions in close physical proximity to data resources, thus dramatically reducing the volume of data that must be transmitted across the network.

However, DCE is not yet fully the seamless solution that is advertised.  This is largely due to incompatibilities between standard DCE implementations and partial implementations of DCE contained in the widely deployed Microsoft family of operating systems for personal computers.  This problem can be viewed as falling under the category of accidental complexity (as opposed to inherent complexity), since it has essentially been introduced by Microsoft’s failure to adhere to the DCE standard.  Nonetheless, few software developers can afford to ignore the Microsoft family of platforms since they are nearly ubiquitous in most business and academic settings.  Hopefully, this thesis can be used as a guide to choose among the wide variety of possible methods to overcome these problems.

In addition to accidental complexities, there are inherent complexities in distributed computing that are not addressed by DCE.  Microsoft’s DCOM essentially recasts DCE in an object-oriented paradigm, but it does not truly add much in the way of solving several major challenges.  The promise of distributed computing is decoupling: decoupling code from its components’ execution contexts (as DCE does), decoupling compile-time interfaces from their run-time implementations (as COM does and DCE can be made to do), and someday decoupling compile-time semantic need from run-time syntax (which is currently not done).

The last of these is an item for future research.  It seems that DCOM, through OLE automation, has gone far enough to provide syntactic information for using distributed objects.  This is accomplished through “type libraries” which provide binary representations of syntactic information.  For example, it is possible to write a program that can construct calls to DCOM objects about which the program had no knowledge at compile time.  So, a program might be able to call SpellCheck(“string1”, “string2”).  However, there is no method in DCOM for the program to discern the meaning of the function or its arguments.

A program might discover an object out somewhere in the Internet which provides this SpellCheck() function.  It might discover that the function takes two arguments, each of which is a string.  It might even discover that the names of the arguments are “StringToBeChecked” and “DictionaryFileName”.  However, the program has no way of determining the meaning or semantic information behind these parameter names.

In the end, DCE is an excellent solution for many of the problems of distributed computing.  However, it is not a panacea.  Distributed computing, by its very nature, intensifies the difficulties inherent in writing cross platform applications, and DCE itself has no answer for this.  DCE does not solve the problems of differing operating system capabilities (e.g., lack of POSIX support), nor does it guarantee that every platform will implement all of its features.  Nonetheless, DCE can help make distributed computing less effort intensive for programmers, and it can help to make cross platform applications possible if some care is taken by the developer.  Even Microsoft environments with their legendary lax adherence to standards can be brought into the DCE fold and made to interoperate with other DCE systems.

This thesis has demonstrated that a DCE application can be ported to prevalent PC environments and that such an application can easily interoperate with a DCE cell containing a variety of heterogeneous systems.  Although PC environments may natively lack full DCE compliance, third party solutions along with some custom work-arounds can be employed to provide nearly complete interoperation.  This author has learned a great deal about porting applications between Unix and PC platforms, DCE’s influence and relevance to other distributed technologies such as DCOM and CORBA, and particularly about the tendency of a certain large software company to create standards rather than adhere to them.  The author has tried to pass on this knowledge, through this document, that others may benefit should they find themselves on this same path.


 

Glossary

 

API – Application Programming Interface.

Bandwidth – The capacity of a network to transport data, typically measured in mega-bits per second.

Big-endian/little-endian – Data storage techniques.  Little-endian systems place the least significant byte first and the most significant byte last.  Big-endian orders bytes in the opposite manner.  These storage schemes are respectively employed on various processors.

Client/Server – A style of programming in which code is distributed between clients and servers.  Typically, client applications present and retrieve information from users while server applications perform calculations and retrieve data.  It is often useful to locate servers “near” to their data sources (i.e., on the same machine or a short number of network hops away from the data).

DCE – Distributed Computing Environment.  This is a software architecture for distributed applications developed by OSF.

Endpoint – A protocol specific identifier (e.g., a TCP/IP port number), unique to a given DCE server process.  Upon obtaining an endpoint, a DCE client may use it to directly communicate with a DCE server.

IDL – Interface Definition Language.  This is a language used to specify how parameters are passed between entities in a distributed application.  It is converted by an IDL compiler to either C or C++.  The language specifies interfaces or functions that are to be deployed remotely.  It includes special keywords to indicate how parameters are to be transported across the network, such as [in] or [out].

Marshaling – The process of turning data structures into a bit-stream representation suitable for transmission across a network.

MSDN – Microsoft Developer Network.  This is a subscription service available from Microsoft which provides documentation and software development kits for Microsoft platforms.

Name Mangling - Name mangling or name decoration is the practice of most C++ compilers of creating unique names for method entry points by adding the class name and some special characters to represent the parameters.  For example, int MyClass::MyFunc(int I) might be exported as MyFunc@MyClass@i.  This guarantees that each method has a unique entry point name, so it is legal to have additional functions with the same name such as MyClass::MyFunc(char c).  The specific scheme used to create mangled names is an implementation detail for each compiler.  There is no standard.

RPC – Remote Procedure Call.  This is the foundation upon which DCE is built.  Microsoft’s version of RPC is binary compatible with DCE, but is not based on the same source code.

Stub - A piece of code created by an IDL compiler, which acts as a surrogate for a function.  A stub communicates with the RPC runtime in order to contact remote processes, marshals and/or unmarshals parameters, and then calls the actual worker function that it represents.

UUID – Universally Unique Identifier.  This is a key value that is guaranteed to be unique.  It is also referred to as a GUID or Globally Unique Identifier by Microsoft.

Win32 – The API used to write programs that can run on either Windows 9x or Windows NT.

Windows 3.x – Any of the 16 bit family of Microsoft Windows products, including Windows 3.0, Windows 3.1, Windows 3.11, and Windows for Workgroups 3.11.

Windows 9x – Any of the 32 bit “compatibility” Microsoft Windows products, including Windows 95, Windows 98, and beyond.  These are referred to by the term “compatibility” in order to distinguish them as products designed to maintain compatibility with older products (DOS applications, Windows 3.x applications, etc.).  This differentiates this group from Windows NT.

Windows NT – Any version of Microsoft Windows NT, including Windows NT 3.5, Windows NT 4.0, Windows NT 5.0, and beyond.  These products were designed to compete with Unix and other robust operating systems used for “mission critical” applications.  Dave Cutler, who was instrumental in developing the VMS operating system while at Digital Equipment Corporation, led the development of Windows NT.


 

References

 

1.      Active Group World Wide Web site, http://www.activex.org.

2.      Don Box, Essential COM, Addison Wesley Longman, Inc., 1998.

3.      Chappell and Associates Report, http://www.camb.opengroup.org/dce/3rd-party/ChapRpt1.html.

4.      Digital Equipment Corporation, “Digital Distributed Computing Environment (DCE) for Windows NT”, in the Microsoft Developer Network under Backgrounder\Platform Articles\Networking, October 1994.

5.      Digital Equipment Corporation World Wide Web site, http://www.dec.com.

6.      Digital Equipment Corporation, “Digital DCE for Windows NT helpfiles”, 1996.

7.      Gradient World Wide Web site, http://www.gradient.com.

8.      Richard Grimes, Professional DCOM Programming, Wrox Press Ltd., 1997.

9.      Hewlett Packard World Wide Web site, http://www.hp.com.

10.  P. E. Chung, Y. Huang, S. Yajnik, D. Liand, J. Shih, C. Y. Wang, and Y. M. Wang, “DCOM and CORBA: Side by Side, Step by Step, and Layer by Layer”, Patterns++ Column, C++ Report, SIGS Publications, Inc., January 1998.

11.  IBM World Wide Web software site, http://ww.software.ibm.com.

12.  IBM World Wide Web networking site, http://www.networking.ibm.com.

13.  Infobeads World Wide Web site, http://www.ci.infobeads.com.

14.  Harold W. Lockhart, Jr., OSF DCE Guide to Developing Distributed Applications, McGraw-Hill, Inc., 1994.

15.  Microsoft Corporation, “The Foundations of Microsoft Windows NT System Architecture”, September 1997.

16.  Microsoft Corporation, “Windows NT Resource Kit”, 1997.

17.  Microsoft Corporation, “The Component Object Model Specification”, Draft 0.9, October 24, 1995.  Available on MSDN.

18.  Microsoft Corporation World Wide Web site, http://www.microsoft.com.

19.  Microsoft Corporation, Microsoft Developers Network (MSDN) CD collection, “Platform SDK Documentation – Networking and Distributed Services – RPC – The Microsoft RPC Model”, January 1998.

20.  Microsoft Corporation, Microsoft Developers Network (MSDN) CD collection, January 1998.

21.  Object Management Group World Wide Web site, http://www.omg.org.

22.  Open Group World Wide Web site, http://www.camb.opengroup.org.

23.  Ward Rosenberry, David Kenney, and Gerry Fisher, Understanding DCE, O’Reilly and Associates, Inc., 1992.

24.  Ward Rosenberry and Jim Teague, Distributing Applications Across DCE and Windows NT, O’Reilly and Associates, Inc., 1993.

25.  John Shirley and Ward Rosenberry, Microsoft RPC Programming Guide, O’Reilly and Associates, Inc., 1995.

26.  John Shirley, Wei Hu, and David Magid, Guide to Writing DCE Applications, O’Reilly and Associates, Inc., 1994.

27.  Swapnesh C. Shirolkar, “Intermediary Servers”, Masters Thesis, University of Missouri, 1994.

28.  Vepa V. Sirish, “Application Level Gateways”, Masters Thesis, University of Missouri, 1996.

29.  Michael Stal, Siemens AG, “Distributed Object Computing”, presented at the 1997 OOPSLA conference in Atlanta, GA., sponsored by the Association for Computing Machinery (ACM).

30.  Bjarne Stroustrup, The C++ Programming Language, Third Edition, Addision Wesley Longman, Inc., 1997.

31.  Andrew S. Tanenbaum, Computer Networks, Second Edition, Prentice-Hall, Inc., 1988.


Appendix A: BINOP Source Code

 

The code, including the build environment, for the BINOP project was originally written by Prof. Gordon K. Springer of the University of Missouri-Columbia .  Included here is a modified version of BINOP, used with permission of the author, which can be built and executed on Microsoft platforms.  The files SERVICE.H and SERVICE.C were originally written by Microsoft as samples and are included here in slightly modified form as part of the BINOP project.

Note that there are two build targets: Win32 and Win32RAW.  The Win32RAW target builds the project with only the Microsoft supplied DCE services (i.e., Microsoft RPC).  This target only builds BINOPC, the BINOP worker client program, since BINOPC only requires RPC to function, and the target does not require any special tools, libraries, or headers save the Microsoft-supplied utility header file, DCEPORT.H.  The Win32 target builds the complete BINOP project, but requires the Digital DCE ADK in order to build.  The resultant binaries from the Win32 target require the Digital DCE Runtime in order to execute.

It is helpful to note that several environment variables control the execution of the various BINOP programs.  The variable “PRINCIPAL” controls the principal name that is used by a server (either FINDS or BINOPS) to login to a DCE cell.  Similarly, the variable “PASSWORD_FILE” directs the server programs to the location of a file that contains an (optionally) encrypted password for the principal.  The “MUNS_CONF” variable provides a space-delimited list of FINDS servers that can be used to lookup BINOPS servers.  For the purposes of easy demonstration, each of these variables has a predefined default.  The WIN32 platform defaults follow:  PRINCIPAL defaults to “Springer”.  PASSWORD_FILE defaults to “D:\Thesis\password.fil”.  MUNS_CONF defaults to “D:\Thesis\muns.cfg”.

 


BINOP Subproject

 

FILE:BINOP1.C

/*************************************************************************

 * DCE Program Binop1:  BINOP1.C - Functions in the Binop V2 Interface

 *

 * Author:   G.K. Springer

 * Date:     June 1991

 * Node:     condor.cs.missouri.edu

 * Location: Computer Science Department, University of Missouri-Columbia

 *

 * Purpose:  Demonstrate DCE Application Program

 *

 * Function: Define the addition and subtraction functions in Server.

 *           This code is invoked directly by the Binop Server (BINOPS.C)

 *           and indirectly from the Binop Client (BINOPC.C)

 *

 *   V2 has two functions exported by the server: binop_add & binop_sub

 *

 * Syntax: None - these are the functions the client calls in the server

 *

 * Change Log:

 *  03/26/93 - GKS - Defined Version 1 Exported Functions

 *  09/15/93 - GKS - Redefined coding for use in DCE

 *

 *************************************************************************/

 

#include "binop1.h"  /* NIDL generated Interface Definition */

 

 

/*************************************************************************

 * Remote ADD function in the Binop Server Interface

 *************************************************************************/

void binop_add

#ifdef IDL_PROTOTYPES

(

  /*  [in]  */ handle_t     h,

  /*  [in]  */ idl_long_int a,

  /*  [in]  */ idl_long_int b,

  /*  [out] */ idl_long_int *c

)

#else

(h, a, b, c)

  /*  [in]  */ handle_t     h;

  /*  [in]  */ idl_long_int a;

  /*  [in]  */ idl_long_int b;

  /*  [out] */ idl_long_int *c;

#endif

{

  *c = a + b;     /* Compute result and return to caller */

}  /* end binop_add() */

 

/*************************************************************************

 * Remote SUBTRACTION function in the Binop Server Interface

 *************************************************************************/

void binop_sub

#ifdef IDL_PROTOTYPES

(

  /*  [in]  */ handle_t     h,

  /*  [in]  */ idl_long_int a,

  /*  [in]  */ idl_long_int b,

  /*  [out] */ idl_long_int *c

)

#else

(h, a, b, c)

  /*  [in]  */ handle_t     h;

  /*  [in]  */ idl_long_int a;

  /*  [in]  */ idl_long_int b;

  /*  [out] */ idl_long_int *c;

#endif

{

  *c = a - b;      /* compute result and return to caller */

}  /* end binop_sub() */

 

 


FILE:BINOP1.IDL

/*

 *   IDL definition of special binary operations server (BINOP)

 *

 *   Exports Functions: binop$add and binop$sub

 *   Uses: IP Communication to a system allocated port

 *

 *  By: G.K. Springer - July 1991

 *  Modified: GKS - March 1993

 *            GKS - redone for DCE implementation

 */

 

[

uuid(249dacc0-ac8d-11cc-89ce-08002b37598d),

version(1.0)

]

 

 

interface binop

{

/* Define Addition Exported Function */

[idempotent]

void binop_add(

    [in]  handle_t  h,    /* Communication Handle */

    [in]  long  a,        /* Parameter 1 for add */

    [in]  long  b,        /* Parameter 2 for add */

    [out] long  *c        /* Result of add to return */

    );

 

/* Define Subtraction Exported Function */

[idempotent]

void binop_sub(

    [in]  handle_t  h,    /* Communication Handle */

    [in]  long  a,        /* Parameter 1 for subtract */

    [in]  long  b,        /* Parameter 2 for subtract */

    [out] long  *c        /* Result of subtract to return */

    );

}

 

 


FILE:BINOPC.C

/*************************************************************************

 * DCE Program Binopc:  BINOPC.C - Client Application Program

 *

 * Author:   G.K. Springer

 * Date:     October 1993

 * Node:     condor.cs.missouri.edu

 * Location: Computer Science Department, University of Missouri-Columbia

 *

 * Purpose:  Demonstrate DCE Application Program

 *

 * Function: Implement an addition and subtraction RPC service.

 *

 * Syntax:   This program is invoked with the command line:

 *               BINOPC <server_host> <num_passes>

 *           where:

 *            server_host - identifies the host where server is running

 *            num_passes  - indicates how many loops of requests to perform

 *

 * Example:  binopc cyclone.cs.missouri.edu 3

 *************************************************************************/

/*

 * Standard C Include files

 */

#include <stdio.h>

#ifndef WIN32

#include <unistd.h>

#endif

#ifndef WIN32RAW

#include <pthread.h>

#endif

 

/* Include NCS Definitions */

#ifdef WIN32RAW

#include <rpc.h>

#include "dceport.h"

#else

#include <dce/rpc.h>  /* DCE RPC definitions */

#endif

#include "binop1.h"   /* NIDL generated Interface definitions */

#include "binopnms.h" /* Binop Name Strings */

 

 

/***************************************************************************

 * BINOPC -  Client Main Program

 ***************************************************************************/

main(int   argc, char  **argv)

{

  int                  passes;  /* Input parameter for passes to run */

  int                  i;       /* temp loop counter */

  int                  result;  /* temp result */

  rpc_if_id_t          ifid;  /* interface identifier */

  unsigned32           st;  /* Return status from RPC calls */

  rpc_binding_handle_t rh;  /* RPC handle for communication */

  unsigned_char_t      *string_binding;  /* String binding handle */

  rpc_protseq_vector_t *protvec;   /* protocol sequence vector */

  char                 host[NMLEN];  /* hostname for server */

 

/***************************************************************************

 * Start of main() program

 ***************************************************************************/

   if (argc < 3) {

       fprintf(stdout,"usage: %s hostname passes\n", *argv);

       exit(1);

       }

 

   strcpy(host, argv[1]); /* move Server hostname */

   passes = atoi(argv[2]); /* get number of passes to run */

 

/* Find supported protocols on this system */

   rpc_network_inq_protseqs( &protvec, &st);  /* get protocol strings */

   if (st != rpc_s_ok) {

      fprintf(stdout, "%s: Cannot obtain supported protocols\n", *argv);

      exit(1);

      }

 

   fprintf(stdout, "This system supports %d protocols\n", protvec->count);

   for (i=0; i<protvec->count; i++) {

      fprintf(stdout, "Protocol %d: %s\n", i, protvec->protseq[i]);

      }

   fflush(stdout);

 

/*************************************************************************

 * Loop thru protocols to find a binding handle that is active on host

 *************************************************************************/

   for (i=0; i<protvec->count; i++) {

 

   /* Compose the string first so handle can be obtained from it */

      rpc_string_binding_compose((unsigned_char_t *)OBJSTR,

         protvec->protseq[i], (unsigned_char_t *)host,

         NULL, NULL, &string_binding, &st);

      if (st != rpc_s_ok) {

          fprintf(stdout,"Cannot compose string binding\n");

          result = -1;

          }

 

      /* Get the partially bound handle from the constructed string */

      rpc_binding_from_string_binding (string_binding, &rh, &st);

      if (st != rpc_s_ok) {

        printf("Cannot convert name %s to binding\n",string_binding);

        result = -1;

        }

      else result = 0;

 

      /* Free the string info we don't need any more */

      rpc_string_free(&string_binding, &st);

      /* Set timeout commensurate with the protocol */

      rpc_mgmt_set_com_timeout(rh, i+1, &st);

      rpc_ep_resolve_binding(rh, C_IFSPEC, &st);

      if (st != rpc_s_ok) result=-1;

      if (result==0) break;

      }  /* end of for loop to build a handle */

 

/* We have a handle or we don't - so free protocol vector */

   rpc_protseq_vector_free(&protvec, &st);

   if (result != 0) {

      printf("Unable to connect to server on %s\n", host);

      exit(1);

      }

  

/***********************************************************************

 * All set - make appropriate number of passes to Server RPC Functions

 ***********************************************************************/

   makepass(rh, passes);  /* All work is done in this routine */

   exit(0);  /* We are done - Let's go home */

}  /* End BINOPC main() */

 


FILE:BINOPDEM.C

/****************************************************************************

 * DCE Demo Program:  BINOPDEMO.C - Client Application

 *

 * Author:   G.K. Springer

 * Date:     February 1992

 * Node:     condor.cs.missouri.edu

 * Location: Computer Science Department - MU, Columbia, MO.

 *

 * Purpose:  Demonstrate DCE Application Program

 *

 * Function: Implement an addition and subtraction RPC service.

 *

 * Syntax:   This program is invoked with the command line:

 *              BINOPDEMO

 *

 * Change Log:

 * 09/93 - GKS - Rewrite code for DCE Nameservice Lookup

 *

 ****************************************************************************/

 

/*

 * Standard C Include files

 */

#include <stdio.h>

#ifndef WIN32

#include <unistd.h>

#endif

#include <stdlib.h>

#include <signal.h>

#include <sys/types.h>

#include <time.h>

#include <pthread.h>

 

/*

 * Include DCE Definitions

 */

#include <dce/rpc.h>  /* DCE RPC definitions */

#include <dce/dce_error.h>  /* DCE error definitions */

#include "binop1.h"  /* NIDL generated Interface definitions */

#include "binopnms.h"  /* Binop Name Definitions */

char     *mc = {"bcdefghijk"};

 

#ifdef WIN32

#define  CLEARIT  "cls"

#else

#define  CLEARIT  "clear"

#endif

 

#define  HELPER   "binophlp | more"

#define  STATS    "binopst | more"

#define  MaxSrv   20

 

 

/***********************************************************************

 * BINOPDEMO -  Demo Main Program

 ***********************************************************************/

main(int argc, char **argv)

{

   int            passes;   /* Input parameter for passes to run */

   int            num_entry;  /* Number of server registrations */

   int            nsrv;  /* number of servers in demo run */

   int            i, j, l;   /* Temp variables */

   int            index[MaxSrv+1];  /* Index to servers */

   int            proto[MaxSrv+1]; /* Index to handles we use */

   rpc_binding_vector_t   *results;   /* NS lookup results */

   unsigned32     st;  /* Return status from RPC calls */

   char           group_name[NMLEN];  /* name of group to search NS */

   char           ch; /* read character input */

   char           maxsrv; /* max servers in run */

   char           string[256], *sp;

   unsigned_char_t *string_binding;

 

/***************************************************************************

 * Start of main() program

 ***************************************************************************/

   printf("Please wait a minute while we get setup ...\n");

/*

 *  Lookup the BINOP Object Uuid in the DCE NameService Database

 */

   strcpy(group_name, GRPNAME);  /* identify the group desired */

   num_entry = findsrvs(group_name, OBJSTR, binop_v1_0_c_ifspec, &results,

                   MaxSrv, &st);  /* lookup servers */

   if (num_entry == 0)  {  /* No servers found registered */

      printf("Lookup for BINOP Servers Failed - %s\n", dcemsg(st));

      }

 

/*

 * Sort out the unique servers in the list of handles

 */

   j = s_handle(num_entry, &nsrv, results, index, proto);

 

 /*

 *  For each server found running, complete the binding information

 */

   for (i=0; i<nsrv; i++)  {

      rpc_mgmt_set_com_timeout(results->binding_h[proto[i]],

          rpc_c_binding_min_timeout, &st); /* timeout quickly */

      rpc_ep_resolve_binding(results->binding_h[proto[i]],

                             binop_v1_0_c_ifspec, &st);

      }  /* End for each server loop */

  

   maxsrv = 'a' + nsrv;

   passes = 1; /* get number of passes to run */

 

 

/************************************************************************

 *  Loop on the menu until request to quit

 ************************************************************************/

  for (;;) {

     system(CLEARIT);

     printf("\t\tDCE Remote Procedure Call Demonstration\n");

     printf("\t\t---------------------------------------\n\n");

     printf("a:  Issue RPC requests to ALL Systems\n");

     for (i=0; i < nsrv; i++) { /* Output the menu for servers */

        printf("%1c:  Issue RPC requests to ", mc[i]);

        p_handle(results->binding_h[proto[i]]); /* print who we talk to */

        }

     if(nsrv > 0) printf("\n");

     printf("r:  Refind the running servers\n");

     printf("s:  Print statistics from servers\n");

     printf("u:  Print a description of the RPC Demo\n\n");

     printf("q:  Terminate the Demo\n\n");

     printf("Please enter the character for the menu item desired\n");

 

     sp =gets(string);

     if (sp == NULL) break;

     l = sscanf(string,"%c",&ch);

     if (l == 1) {

        if (((ch<'a') | (ch > maxsrv)) &

             (ch!='u') & (ch!='q') & (ch!='r') & (ch!='s') ) ch='z';

     else {

        i = ch - 'b';  /* get index of hostname desired */

        if ((ch>'a') & (ch<'k')) ch='b'; /* access 1 server */

        }

 

        switch (ch) {

        case 'a': system(CLEARIT);

                  for (i=0; i<nsrv; i++) {  /* Call all servers */

                     makepass(results->binding_h[proto[i]], passes);

                     }

                  break;

        case 'b': system(CLEARIT);

                  makepass(results->binding_h[proto[i]], passes);

                  break;

        case 'r': rpc_binding_vector_free(&results, &st);  /* free vector */

                  num_entry = findsrvs(group_name, OBJSTR, binop_v1_0_c_ifspec,

                                  &results, MaxSrv, &st);  /* lookup servers */

                  j = s_handle(num_entry, &nsrv, results, index, proto);

                  maxsrv = 'a' + nsrv;  /* identify last server index */

                  for (i=0; i<nsrv; i++)  {

                     rpc_ep_resolve_binding(results->binding_h[proto[i]],

                         binop_v1_0_c_ifspec, &st);

                     }  /* End for each server loop */

                  break;  /* done - just go back and redisplay menu */

        case 's': system(CLEARIT);  /* show stats on servers */

                  system(STATS);  /* give them stats from the servers */

                  break;

        case 'u': system(CLEARIT);

                  system(HELPER);  /* give them help info on demo */

                  break;

        case 'q': printf("\n***End of RPC Demo***\n");

                  rpc_binding_vector_free(&results, &st);  /* free vector */

                  exit(0); /* We are done - Let's go home */

        default:  printf("Invalid option selected - try again.\n");

                  break;

        }  /* end switch */

     }  /* end if */

  printf("\nHit ENTER key to make next selection\n");

  sp =gets(string);

  if (sp == NULL) break;

  }  /* end for */

  rpc_binding_vector_free(&results, &st);  /* free binding vector */

  exit(0);

 

}  /* End BINOPDEMO main() */

 

 


FILE:BINOPHLP.C

/****************************************************************************

 *  BINOPHLP.C - Print HELP information about the BINOPDEMO demonstration.

 *

 * Author:   G.K. Springer

 * Date:     March 1993

 * Node:     cyclone.cs.missouri.edu

 * Location: Computer Science Department - MU, Columbia, MO.

 *

 * Purpose:  Tell user about the BINOPDEMO demonstration program.

 * Function: This program simply prints lines to stdout that explains the

 *           demonstration program.  This program is invoked from the demo

 *           menu (option 'h').  During its execution, this program searches

 *           for the BINOP servers registered in the network.  For each

 *           server found, bind to the server and print out the information

 *           found in the Location Broker database about the server.  This

 *           information may or may not exactly agree with the servers listed

 *           on the menu and an entirely new lookup is performed here.  If

 *           there is a disagreement with the menu, requesting the demo to

 *           relookup the servers should put this HELP and the menu back in

 *           synchronization.

 *

 * Change Log:

 *  09/93 - GKS - Revised for use in DCE environment

 ****************************************************************************/

 

/*

 * Standard C Include files

 */

#include <pthread.h>

#ifndef WIN32

#include <unistd.h>

#endif

#include <stdio.h>

#include <stdlib.h>

#include <signal.h>

#include <sys/types.h>

 

/*

 * DCE Definitions

 */

#include <dce/rpc.h>

#include <dce/rpcexc.h>

#include <dce/uuid.h>

 

/* Include DCE Application Definitions */

#include "binop1.h"   /* IDL generated Interface definition */

#include "binopnms.h"  /* Binop Name Strings */

 

extern char *error_text();

#define MaxSrv  6

 

 

/************************************************************************

 * BINOPHLP -  Server Status Main Program

 ***********************************************************************/

main(int argc, char **argv)

{

  int            i,j;         /* Counters - temp */

  unsigned32     st;          /* Status of calls made */

  unsigned32     max_entry;   /* NS lookup max entries */

  unsigned32     num_entry;   /* NS lookup num entries returned */

  rpc_binding_vector_t  *results;  /* NS lookup results */

  char           group_name[NMLEN];  /* name of group to search NS */

 

/************************************************************************

 *   Start of main program

 ***********************************************************************/

 

/* Print help info about the binopdemo program */

 

printf("              DCE Remote Procedure Call Demonstration\n");

printf("              ---------------------------------------\n");

printf("\n");

printf("\n");

printf("This demonstration shows the operation of using remote  procedure\n");

printf("calls from one workstation to another workstation that is running\n");

printf("a server. In this demonstration, some number of servers have been\n");

printf("started on separate machines in the network.  The exact number is\n");

printf("not known until this program  searches the network  to find where\n");

printf("the servers are located.   The servers found to be running in the\n");

printf("network will be listed on the main menu of this demonstration. If\n");

printf("no servers  are found to be running, no servers will be listed on\n");

printf("the menu.  The search for the location of running servers is done\n");

printf("by using  Distributed Computing Environment (DCE) Name Service to\n");

printf("find the servers that have \"registered\" themselves in the network.\n");

printf("\n");

printf("Each time  this demonstration program is run,  a different set of\n");

printf("servers  may be listed on  the menu.   Depending upon  where each\n");

printf("server has been started,  this demonstration  program will locate\n");

printf("them dynamically and list  only those servers  that are currently\n");

printf("active in the network.  By looking at the server locations listed\n");

printf("on the main menu,  you can see where they are located and be able\n");

printf("to request services from them individually or as a group.   As an\n");

printf("example, the current list of registered servers is:\n");

printf("\n");

 

/*

 *  Lookup the BINOP Object Uuid in the NameService Database

 */

   strcpy(group_name, GRPNAME);  /* identify the group desired */

   num_entry = findsrvs(group_name, OBJSTR, binop_v1_0_c_ifspec, &results,

                        MaxSrv, &st);  /* lookup servers */

  if (num_entry == 0)  {  /* No servers found registered */

     printf("\n\t*** No Binop Servers are currently registered ***\n");

     }

  else {

    /*

     *  For each server found running, Print out where it is located.

     */

     printf("\n");

     for (j=0; j<num_entry; j++)  {

        rpc_mgmt_set_com_timeout(results->binding_h[j],

            rpc_c_binding_min_timeout, &st); /* timeout quickly */

        printf("\tServer %c:  ", 'b'+j);

        p_handle(results->binding_h[j]); /* print who we talk to */

        }  /* end for */

     rpc_binding_vector_free(&results, &st);  /* free binding vector */

     }  /* end else */

 

printf("\n");

printf("\n");

printf("Each of the servers offer two services; an addition service and a\n");

printf("subtraction  service.   Each  request  to  a  server  passes  two\n");

printf("parameters, A and B, which are to be operated upon by the server.\n");

printf("The  addition  service  ADDS  the  two parameters and returns the\n");

printf("result C to the caller.  The subtraction  service  SUBTRACTS  the\n");

printf("two parameters and returns the result C to the caller.\n");

printf("\n");

printf("In this demo, a loop that performs 50 requests to the add service\n");

printf("and  50  requests  to  the  subtract  service  are  made  to  the\n");

printf("designated server.  As the result from each request  is  returned\n");

printf("to the caller (this demo program), it is displayed on the screen.\n");

printf("This lets you see how quickly each of the requests are  serviced.\n");

printf("Timing  is  done  across  all of the requests and a final line is\n");

printf("written  to  the  screen  that  shows  the  average   number   of\n");

printf("milliseconds each particular request took to complete.\n");

printf("\n");

printf("The requests to the servers are all of the form:\n");

printf("\n");

printf("       c = i + i    (for Addition Service)\n");

printf("\n");

printf("       c = 51 - i   (for Subtraction Service)\n");

printf("\n");

printf("   where: i is the index of loop sending requests to the server.\n");

printf("          c is the result computed by the server and returned to\n");

printf("            the caller.\n");

printf("\n");

printf("\n");

printf("Although this is a very simple demonstration, it shows the  power\n");

printf("of  being  able  to  utilize  the  computational power of another\n");

printf("machine to  perform  the  operations  needed  by  an  application\n");

printf("program.    There   is  no  limit  to  the  type  and  volume  of\n");

printf("computations that could be performed by the server.  If you think\n");

printf("about  it,  the server could be a very large machine (like a CRAY\n");

printf("supercomputer) which could perform the  needed  computations  far\n");

printf("faster  than the local application program could perform them for\n");

printf("itself.\n");

printf("\n");

printf("Since the calls to the server are made in the  same  way  as  you\n");

printf("would  make  them to a procedure or function in your own program,\n");

printf("the amount of time needed to build such distributed  applications\n");

printf("is actually very small.  As a case in point, the actual code used\n");

printf("to make the server requests in this demo are shown below.\n");

printf("\n");

printf("To run this demo, simply select one of the options  displayed  on\n");

printf("the menu screen and sit back and watch what happens.\n");

printf("\n");

printf("Hope you enjoy the demonstration!!\n");

printf("\n");

printf("\n");

printf("\n");

printf("\n");

printf("  Source Code used in DEMO to make Server Requests\n");

printf("  ------------------------------------------------\n");

printf("\n");

printf("\n");

printf("/*****************************************************************\n");

printf(" * makepass() - run the demo on one of the requested servers      \n");

printf(" *****************************************************************/\n");

printf("makepass(handle_t rh, int passes) \n");

printf("{\n");

printf("   int       k;      /* Temp counter for passes run */\n");

printf("   int       i, n;   /* Temp variables */\n");

printf("   status_t  st;     /* Return status from RPC calls */\n");

printf("   int start_time, stop_time; /* Timing variables */\n");

printf(" \n");

printf("   printf(\"\\nStart Requests to Server: \\n\");\n");

printf("   p_handle(rh);\n");

printf("\n");

printf("/*********************************************************************\n");

printf(" * Loop for the requested number of passes to Server RPC Functions\n");

printf(" *********************************************************************/\n");

printf("   for (k = 1; k <= passes; k++) {\n");

printf("      start_time = time(NULL);  /* Get TOD at start of a pass */\n");

printf(" \n");

printf("     /*\n");

printf("      * Call addition service the required number of times\n");

printf("      */\n");

printf("      for (i = 1; i <= CALLS_PER_PASS; i++) {\n");

printf("         binop_add(rh, i, i, &n);  /* Call RPC ADD service on Server */\n");

printf("         printf(\"%%3d \",n); /* Print result returned */\n");

printf("         /* add a newline every 10 results returned */\n");

printf("         if ((i%%10 == 0) && (i != CALLS_PER_PASS)) printf(\"\\n\");\n");

printf("         }  /* end for i - addition loop */\n");

printf("      printf(\"  *** end of addition ***\\n\");\n");

printf(" \n");

printf("     /*\n");

printf("      * Call subtraction service the required number of times\n");

printf("      */\n");

printf("      for (i = 1; i <= CALLS_PER_PASS; i++) {\n");

printf("         binop_sub(rh, CALLS_PER_PASS+1 , i, &n); /* Call RPC SUB service */\n");

printf("         printf(\"%%3d \",n);  /* Print result returned */\n");

printf("         /* add a newline every 10 results returned */\n");

printf("         if ((i%%10 == 0) && (i != CALLS_PER_PASS)) printf(\"\\n\");\n");

printf("         }  /* end for i - subtraction loop */\n");

printf("      printf(\"  *** end of subtraction ***\\n\");\n");

printf(" \n");

printf("     /*\n");

printf("      * Calculate average time to process a call\n");

printf("      */\n");

printf("      stop_time = time(NULL);  /* Get TOD at end of pass */\n");

printf("      printf(\"***** pass %%3d; real/call: %%2d ms\\n\",\n");

printf("         k, ((stop_time - start_time) * 1000) / (2*CALLS_PER_PASS));\n");

printf("      }  /* end for k - number of passes */\n");

printf("}  /* end makepass() */\n");

printf("\n");

 

exit(0);

}  /* end binophlp() */

 

 


FILE:BINOPMSG.C

/****************************************************************************

 * BINOPSMSG.C - Get DCE Error Messages from error message table.

 *

 * Author:   G.K. Springer

 * Date:     March 1993

 * Node:     cyclone.cs.missouri.edu

 * Location: Computer Science Department - MU, Columbia, MO.

 *

 * Purpose:  Utility to get an NCS run-time error message from the message

 *           table and return the message string to the caller.

 * Function: Access external message table by error number and return string

 *           to the caller.

 *

 * Change Log:

 *  09/93 - GKS - Changed for DCE implementation

 *

 * Note:

 *  To get error messages an environment variable NLSPATH is required.

 *  Define it as:  setenv NLSPATH "/opt/dcelocal/nls/msg/en_US.88591/%N"

 *

 ****************************************************************************/

 

/* Include DCE Definitions */

#include <dce/rpc.h>

#include <dce/dce_error.h>

 

char *error_text(int st)

{

  int         err_st;   /*CRAY*/

  static char buff[dce_c_error_string_len];

 

  dce_error_inq_text(st, buff, &err_st);

  if (err_st != -1) return(buff);

  else  {

     if (st == 0xc038a0e0) 

        sprintf(buff, "DCE/RT - Server not responding");

     else

        sprintf(buff, "DCE/RT - No error text translation, st=%08x",st);

     return(buff);

     }

     

}  /* binopsmsg() */

 

 


FILE:BINOPNMS.H

/*************************************************************************

 * DCE Program Binop:  BINOPNMS.H - Include File.

 *

 * Author:   G.K. Springer

 * Date:     September 1993

 * Node:     condor.cs.missouri.edu

 *

 * Purpose:  Include file for BINOP application programs

 *

 * Function: Define the OBJ UUID string, Group Name, Entry Name

 *           and Annotation Names for the Binop Application code.

 *

 * Syntax:   Include file for C syntax programs

 *

 * Update Log:

 * 09/93 - GKS - Rewrite of code for DCE environment

 *************************************************************************/

 

#define  GRPNAME  "/.:/hpcc/Binop_Group"

#define  ENTNAME  "/.:/hpcc/Binop_"

//#define  GRPNAME  "/.:/hpcc/test/Binop_Group"

//#define  ENTNAME  "/.:/hpcc/test/Binop_"

#define  EPNAME   "BINOP Server V2"

#define  NMLEN    50

 

#define  S_IFSPEC  binop_v1_0_s_ifspec

#define  C_IFSPEC  binop_v1_0_c_ifspec

#define  OBJSTR   "aaaa4000-b04b-11cc-bf88-08002b37598d"

 

 


FILE:BINOPS.C

/*************************************************************************

 * DCE Program Binops:  BINOPS.C - Server Routine.

 *

 * Author:   G.K. Springer

 * Date:     June 1991

 * Node:     condor.cs.missouri.edu

 * Place:    Computer Science Department, University of Missouri-Columbia

 *

 * Purpose:  Demonstrate DCE Application Program

 *

 * Function: Implement an addition and subtraction RPC service.

 *

 * Syntax: This program is invoked with the command line:

 *            BINOPS  [&]     (should invoke program in background)

 *

 * Change Log:

 *  10/93 - GKS - Rework code to run in DCE environment using DCE Name

 *                Service across multiple DCE Cells.

 * Note:

 *    February 1994 - GKS - Added processing code

 *    A dedicated signal catching thread is used to allow the server to

 *    terminate gracefully in the presence of a fatal asynchronous signal.

 *    This thread is created by the server and gains control in sigcatch()

 *    whenever a non-DCE termination signal is received by the server.

 *

 *    A dedicated self-authentication thread is used to keep the server's

 *    credentials current.  It wakes up just prior to the credentials

 *    expiring and reauthenticates itself to DCE so it always remains

 *    authenticated - regardless of what its expiration limit is and how

 *    long it has been running.  One requirement is the principle must be

 *    able to refresh its certificates and the ticket lifetime must be

 *    greater than 10 minutes.

 *************************************************************************/

 

/*

 * Standard C Include files

 */

#include <stdio.h>

 

#ifndef WIN32

#include <unistd.h>

#include <sys/errno.h>

#else

#include <errno.h>

#endif

 

#include <stdlib.h>

#include <string.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <pthread.h>

 

/* Include DCE Definitions */

#include <dce/rpc.h>  /* DCE RPC definitions */

 

char            *pnm;                   /* program name pointer for msgs */

char            msg[144];               /* For time-stamped messages */

#ifndef WIN32

pid_t           pid;                    /* Process id of the server */

#else

int           pid;                    /* Process id of the server */

#endif

uuid_t          objuuid;                /* binary object uuid string */

rpc_if_id_t     ifid;                   /* interface identifier */

uuid_vector_t   *obj_uuid_vector;       /* object uuid vector for register */

rpc_binding_vector_t  *binding_vector;  /* Bindings for server */

int             logflg;

 

/* Define Server Specific Functions and Names */

#include <musrv.h>

 

 

/***************************************************************************/

/***************************************************************************/

/* This conditional code has been added to allow WIN32 servers to start as */

/* services.  The utility code contained in service.h and service.c is     */

/* taken from a Microsoft sample program called "Simple Service".  It is   */

/* included with minor modifications.                                      */

/* JimR 3/1/97                                                             */

/***************************************************************************/

#ifdef WIN32

#ifndef NODAEMON

 

#include <service.h>

 

#define SZAPPNAME                               "BinopS"

#define SZSERVICENAME                    "BinopS"

#define SZSERVICEDISPLAYNAME      "DCE BINOP Server"

#define SZDEPENDENCIES                   ""

 

#include <service.c>

 

VOID ServiceStart (DWORD dwArgc, LPTSTR *lpszArgv)

{

       /**********************************************/

       /* PROBLEM! - We really shouldn't tell control*/

       /* panel that we are up and running until we  */

       /* have registered the endpoints and all.     */

       /* However, this way allows WIN32 to act more */

       /* nearly like the other environments.        */

       /**********************************************/

 

       /* Let control panel know that we are running */

       ReportStatusToSCMgr(SERVICE_RUNNING,NO_ERROR,0);

 

       /* Start doing our work as usual */

       main_worker(lpszArgv);

}

 

VOID ServiceStop()

{

       /* Warn the SCMgr that we may take up to 10 secs to stop */

       ReportStatusToSCMgr(SERVICE_STOP_PENDING,NO_ERROR,10000);

 

       /* Fake a CTRL-C to shutdown service */

       SignalHandlerRoutine(CTRL_C_EVENT);

}

 

#else         /* NODAEMON */

main(int argc, char **argv)

{

       main_worker(argv);

}

#endif /* NODAEMON */

 

#else         /* WIN32 */

main(int argc, char **argv)

{

       main_worker(argv);

}

#endif /* WIN32 */

/***************************************************************************/

/***************************************************************************/

 

 

 

/***************************************************************************

 * Server Main Program

 ***************************************************************************/

main_worker(char **argv)

{

  double         dum1;  /* Force vars to align on a double boundary */

  int            i;     /* loop index */

  char           logname[128];  /* name of the log file */

  FILE           *fp;   /* temp file pointer to log file */

  unsigned32     st;    /* DCE status return codes on calls */

  unsigned32     thread_stk_size;  /* stack size for threads */

  int            thread_status;

  pthread_t      refresh_thread;   /* refresh thread to keep server

                                    * sec_credentials active */

  pthread_t      sigcatch_thread;  /* signal catching thread for

                                    * graceful shutdowns */

  pthread_attr_t attr;  /* attributes of a thread */

 

/************************************************************************

 *   Start of main program

 ************************************************************************/

 

/* get short name of program */

#ifdef WIN32

/* JimR Note - Changed from rindex to strrchr since only the latter */

/* is supported on MS platforms and is also supported on all UNIX   */

#define rindex strrchr

/* JimR Note - looking for slash on Unix, or backslash on MS platforms */

#define PathDelimiter      '\\'

#else

#define PathDelimiter      '/'

#endif

  pnm = rindex(*argv, PathDelimiter);

  if (pnm == NULL) pnm = *argv;

  else pnm = pnm+1;

 

#ifndef WIN32

  umask(027);  /* make desired file mode creation mask */

#endif

  regstat = 0;  /* init registration status */

 

#ifndef NODAEMON

/************************************************************************

 * Compile this code if we are creating a Daemon Server

 ************************************************************************/

 

/* create name of log file and test its use for stdout and stderr */

  sprintf(logname, "%s/%s.log", LOGDIR, pnm);

  if ((fp = fopen(logname, "a")) == NULL) {

     sprintf(msg, "%s: could not open log:\n\t%s", pnm, logname);

     tmsg(msg);

     exit(1);

     }

 

/* make ourselves into a daemon */

  i = daemon_init();

  if (i < 0) {

     sprintf(msg, "%s: error forking child process\n", pnm);

     tmsg(msg);

     fclose(fp);

     exit(1);

     }

 

/* we are now a daemon - so redirect stdout and stderr to log file */

  if (freopen(logname, "a", stdout) == NULL) {

     fprintf(fp, "%s: could not reopen stdout to log:\n\t%s", pnm, logname);

     exit(1);

     }

  if (freopen(logname, "a", stderr) == NULL) {

     fprintf(fp, "%s: could not reopen stderr to log:\n\t%s", pnm, logname);

     exit(1);

     }

  fclose(fp);   /* and close the temp file pointer */

#endif

 

  printf("\n************************************************************\n");

  sprintf(msg, "%s: Server starting execution...", pnm);

  tmsg(msg);

  logflg= 1;

 

#include <srvbase.h>  /* bring in code for the base server */

 

} /* end main */

 

#include <srvcln.h>  /* bring in code for the base cleanup routines */

 

 


FILE:BINOPST.C

/****************************************************************************

 * BINOPST.C - Print Statistics about BINOP servers running on network.

 *

 * Author:   G.K. Springer

 * Date:     November 1991

 * Node:     cyclone.cs.missouri.edu

 * Location: Computer Science Department - MU, Columbia, MO.

 *

 * Purpose:  Use rpc call to get server stats from BINOP servers running.

 * Function: Lookup the BINOP servers registered in the network.  For each

 *           server found, bind to the server and issue an inquire stats

 *           request and print out the returned statistics.  If the server

 *           does not respond (using short timeout periods), print an

 *           error message so indicating.  This code uses the pthread

 *           error handling facilities built into DCE RunTime code.

 *

 * Change Log:

 * 09/93 - GKS - Rewrite code for DCE Nameservice Lookup

 *

 ****************************************************************************/

 

/*

 * Standard C Include files

 */

#include <stdio.h>

#ifndef WIN32

#include <unistd.h>

#include <sys/errno.h>

#else

#include <errno.h>

#endif

#include <stdlib.h>

#include <sys/types.h>

 

/* Include DCE Definitions */

#include <pthread.h>

#include <dce/rpc.h>  /* DCE RPC definitions */

#include <dce/rpcexc.h>

 

/* Include DCE Application Definitions */

#include "binop1.h"   /* IDL generated Interface definition */

#include "binopnms.h"

 

#define MaxSrv  6

 

char *dcemsg();

unsigned32 p_handle();

 

static char *stname[] = { "   Calls In:   ",

                          "   Calls Out:  ",

                          "   Packets In: ",

                          "   Packets Out:" };

 

/************************************************************************

 *  Server Status Main Program

 ***********************************************************************/

 

main(int argc, char **argv)

{

   int                i,j;           /* Counters - temp */

   int                max_entry;     /* LB lookup max entries */

   int                num_entry;     /* LB lookup num entries returned */

   unsigned32         st;            /* Status of calls made */

   rpc_stats_vector_t *stats;        /* Array of stat values returned */

   rpc_binding_vector_t *results;    /* LB lookup results */

   char               group_name[NMLEN];  /* name of group to search NS */

 

 

/************************************************************************

 *   Start of main program

 ***********************************************************************/

   printf("\n************ Start Stats from BINOPS Servers ************\n");

   system("echo %_date% %_time%");  /* timestamp the output */

 

/*

 *  Lookup the Object Uuid in the NameService Database

 */

   if (argc == 1) {

      strcpy(group_name, GRPNAME);  /* identify the group desired */

      }

   else {

      strcpy(group_name, *(argv+1));  /* user specified the name */

      }

 

   max_entry = MaxSrv;

 

       #ifdef DEBUG

       printf("Looking up group name: %s.\n",group_name);

       #endif

 

   num_entry = findsrvs(group_name, OBJSTR, C_IFSPEC,

                        &results, max_entry, &st);  /* lookup servers */

   printf("Lookup  status: %08x  num_entry= %d\n", st, num_entry);

 

   if (num_entry == 0)  {  /* No servers found registered */

      printf("Lookup for BINOPS Servers Failed - %s\n", dcemsg(st));

      exit(1);

      }

 

/*

 *   Found at least 1 server - allocate a RPC handle to use

 */

   printf("--------------------------------------------------------\n");

 

/*

 *  For each server found running, inquire about its status

 */

for (j=0; j<num_entry; j++)  {

   rpc_mgmt_set_com_timeout(results->binding_h[j],

       rpc_c_binding_min_timeout, &st); /* timeout quickly */

   printf("   Server: ");

   if (p_handle(results->binding_h[j]) == 1) {  /* print who we talk to */

      printf("\tserver registered, but not communicating\n");

      printf("--------------------------------------------------------\n");

      }

   else {

    TRY {

 

              /*******************************************************/

              /* Notes on why this WIN32 specific hack is necessary  */

              /* - Jim Ries 10/15/95                                 */

              /*                                                     */

              /* Under NT, it seems that the binding handle returned */

              /* by findsrvs() in result has the uuid of OBJSTR.     */

              /* At least under NT, this is correct for making       */

              /* actual calls that do work, e.g, things that binopc  */

              /* would like to do.  However, in order to talk to the */

              /* management entry point vector (EPV), one needs the  */

              /* type uuid assigned to the server via the            */

              /* rpc_object_set_type() call.  Therefore, we must     */

              /* inquire what that id is (using S_IFSPEC for which   */

              /* we must link in the idl-generated server module)    */

              /* and change the object uuid of the binding handle.   */

              /*******************************************************/

              #ifdef WIN32

              {

                     uuid_t                     tuuid;

                     rpc_if_id_t                ifid;                   /* interface identifier */

 

                     #ifdef DEBUG

                     unsigned_char_t *    tmp;

 

                     rpc_binding_inq_object(results->binding_h[j],&tuuid,&st);

                     uuid_to_string(&tuuid,&tmp,&st);

                     printf("The object uuid of the binding handle is: %s\n",tmp);

                     #endif

 

                     rpc_if_inq_id(S_IFSPEC, &ifid, &st);

 

                     #ifdef DEBUG

                     uuid_to_string(&ifid.uuid,&tmp,&st);

                     printf("Changing the binding handle uuid to: %s\n",tmp);

                     #endif

 

                     rpc_binding_set_object(results->binding_h[j],&ifid.uuid,&st);

              }

              #endif

 

     /* Get server statistics and print them out */

     rpc_mgmt_inq_stats(results->binding_h[j], &stats, &st);

     if (st == rpc_s_ok) {

        for (i=0; i<stats->count; i++) printf("%s %d\n", stname[i],

             stats->stats[i]);

        printf("--------------------------------------------------------\n");

        rpc_mgmt_stats_vector_free(&stats, &st);  /* free stats vector */

        }

     else {

        printf("   ***Error*** - Could not obtain stats from server\n");

        printf("--------------------------------------------------------\n");

        }

     }

/*

 *   Comes here on a communication error.

 */

CATCH (rpc_x_comm_failure) {

      printf("   ***Error*** - Server not responding!\n");

      printf("--------------------------------------------------------\n");

      }

/*

 *   Comes here on all other errors.

 */

CATCH_ALL {

      printf("   ***Error*** - %s\n", dcemsg(st));

      printf("--------------------------------------------------------\n");

      }

ENDTRY;

   }  /* if p_handle() */

  }  /* End for each server loop */

 

   rpc_binding_vector_free(&results, &st);  /* free binding vector */

   printf("************ End of Stats from BINOPS Servers ***********\n\n");

   exit(0);

}  /* end main() */

 

 


FILE:DCEPORT.H

/*++

 

Copyright (c) 1993-1994 Microsoft Corporation

 

Module Name:

 

    dceport.h

 

Abstract:

 

    Include file defining types and macros which map DCE RPC APIs to

    Microsoft RPC APIs.  Useful when porting DCE RPC applications to MS RPC.

 

--*/

 

#ifndef DCEPORT_H

#define DCEPORT_H

 

#ifdef __cplusplus

extern "C" {

#endif

 

/*

** Define various idl types

*/

#define idl_char                unsigned char

#define idl_boolean             unsigned char

#define idl_byte                unsigned char

#define idl_small_int           char

#define idl_usmall_int          unsigned char

#define idl_short_int           signed short

#define idl_ushort_int          unsigned short

#define idl_long_int            long

#define idl_ulong_int           unsigned long

#define boolean32               unsigned long

#define unsigned32              unsigned long

#define unsigned16              unsigned short

#define idl_true                1

#define idl_false               0

#define unsigned_char_t         unsigned char

typedef unsigned char __RPC_FAR *unsigned_char_p_t;

typedef void __RPC_FAR          *idl_void_p_t;

 

#ifndef _ERROR_STATUS_T_DEFINED

typedef unsigned long error_status_t;

#define _ERROR_STATUS_T_DEFINED

#endif

 

/*

** Define various DCE RPC types

*/

#define rpc_if_handle_t             RPC_IF_HANDLE

#define rpc_ns_handle_t             RPC_NS_HANDLE

#define rpc_authz_handle_t          RPC_AUTHZ_HANDLE

#define rpc_auth_identity_handle_t  RPC_AUTH_IDENTITY_HANDLE

#define rpc_sm_thread_handle_t      RPC_SS_THREAD_HANDLE

#define rpc_mgr_epv_t               RPC_MGR_EPV __RPC_FAR *

#define rpc_object_inq_fn_t         RPC_OBJECT_INQ_FN __RPC_FAR *

#define rpc_auth_key_retrieval_fn_t RPC_AUTH_KEY_RETRIEVAL_FN

#define rpc_mgmt_authorization_fn_t RPC_MGMT_AUTHORIZATION_FN

 

/*

** Define rpc_binding_vector_t to match DCE

*/

#ifdef rpc_binding_vector_t

#undef rpc_binding_vector_t

#endif

 

typedef struct

{

     unsigned long           count;

     handle_t                binding_h[1];

} rpc_binding_vector_t, __RPC_FAR *rpc_binding_vector_p_t;

 

/*

** Define rpc_protseq_vector_t to match DCE

*/

 

typedef struct

{

    unsigned long           count;

    unsigned char *         protseq[1];

} rpc_protseq_vector_t, __RPC_FAR *rpc_protseq_vector_p_t;

 

/*

** Define rpc_stats_vector_t to match DCE

*/

 

typedef struct

{

    unsigned long           count;

    unsigned long           stats[1];

} rpc_stats_vector_t, __RPC_FAR *rpc_stats_vector_p_t;

 

/*

** Define uuid_t to match DCE

*/

#ifdef uuid_t

#undef uuid_t

#endif

 

typedef struct

{

    unsigned long            time_low;

    unsigned short           time_mid;

    unsigned short           time_hi_and_version;

    unsigned char            clock_seq_hi_and_reserved;

    unsigned char            clock_seq_low;

    unsigned char            node[6];

} uuid_t, __RPC_FAR *uuid_p_t;

 

/*

** Define uuid_vector_t to match DCE

*/

#ifdef uuid_vector_t

#undef uuid_vector_t

#endif

 

typedef struct

{

     unsigned long           count;

     uuid_p_t                uuid[1];

} uuid_vector_t, __RPC_FAR *uuid_vector_p_t;

 

/*

** Define rpc_if_id_t and rpc_if_id_p_t to match DCE

*/

 

typedef struct

{

    uuid_t                   uuid;

    unsigned short           vers_major;

    unsigned short           vers_minor;

} rpc_if_id_t, __RPC_FAR *rpc_if_id_p_t;

 

/*

** Define rpc_if_id_vector_t to match DCE

*/

 

typedef struct

{

    unsigned long           count;

    rpc_if_id_p_t           if_id[1];

} rpc_if_id_vector_t, __RPC_FAR *rpc_if_id_vector_p_t;

 

/*

** The MinThreads parameters to RpcServerListen()

** is not part of the DCE API rpc_server_listen().

** This is the default value.

*/

 

#define rpc_c_listen_min_threads_default 1

 

/*

** Define various constants

*/

#define rpc_c_ns_syntax_default            RPC_C_NS_SYNTAX_DEFAULT

#define rpc_c_ns_syntax_dce                RPC_C_SYNTAX_DCE

#define rpc_c_ns_default_exp_age           RPC_C_DEFAULT_EXP_AGE

#define rpc_c_protseq_max_reqs_default     RPC_C_PROTSEQ_MAX_REQS_DEFAULT

#define rpc_c_protseq_max_calls_default    RPC_C_PROTSEQ_MAX_REQS_DEFAULT

#define rpc_c_listen_max_calls_default     RPC_C_LISTEN_MAX_CALLS_DEFAULT

#define rpc_c_ep_all_elts                  RPC_C_EP_ALL_ELTS

#define rpc_c_ep_match_by_if               RPC_C_EP_MATCH_BY_IF

#define rpc_c_ep_match_by_obj              RPC_C_EP_MATCH_BY_OBJ

#define rpc_c_ep_match_by_both             RPC_C_EP_MATCH_BY_BOTH

#define rpc_c_vers_all                     RPC_C_VERS_ALL

#define rpc_c_vers_compatible              RPC_C_VERS_COMPATIBLE

#define rpc_c_vers_exact                   RPC_C_VERS_EXACT

#define rpc_c_vers_major_only              RPC_C_VERS_MAJOR_ONLY

#define rpc_c_vers_upto                    RPC_C_VERS_UPTO

#define rpc_c_profile_default_elt          RPC_C_PROFILE_DEFAULT_ELT

#define rpc_c_profile_all_elts             RPC_C_PROFILE_ALL_ELTS

#define rpc_c_profile_match_by_if          RPC_C_PROFILE_MATCH_BY_IF

#define rpc_c_profile_match_by_mbr         RPC_C_PROFILE_MATCH_BY_MBR

#define rpc_c_profile_match_by_both        RPC_C_PROFILE_MATCH_BY_BOTH

#define rpc_c_binding_min_timeout          RPC_C_BINDING_MIN_TIMEOUT

#define rpc_c_binding_default_timeout      RPC_C_BINDING_DEFAULT_TIMEOUT

#define rpc_c_binding_max_timeout          RPC_C_BINDING_MAX_TIMEOUT

#define rpc_c_binding_infinite_timeout     RPC_C_BINDING_INFINITE_TIMEOUT

#define rpc_c_stats_calls_in               RPC_C_STATS_CALLS_IN

#define rpc_c_stats_calls_out              RPC_C_STATS_CALLS_OUT

#define rpc_c_stats_pkts_in                RPC_C_STATS_PKTS_IN

#define rpc_c_stats_pkts_out               RPC_C_STATS_PKTS_OUT

#define rpc_c_mgmt_inq_if_ids              RPC_C_MGMT_INQ_IF_IDS

#define rpc_c_mgmt_inq_princ_name          RPC_C_MGMT_INQ_PRINC_NAME

#define rpc_c_mgmt_inq_stats               RPC_C_MGMT_INQ_STATS

#define rpc_c_mgmt_inq_server_listen       RPC_C_MGMT_INQ_SERVER_LISTEN

#define rpc_c_mgmt_stop_server_listen      RPC_C_MGMT_STOP_SERVER_LISTEN

#define rpc_c_mgmt_cancel_infinite_timeout RPC_C_CANCEL_INFINITE_TIMEOUT

 

/*

** Define DCE API equivalents

*/

#define rpc_binding_copy(source,dest,status) \

                *(status) = RpcBindingCopy(source,dest)

 

#define rpc_binding_free(binding,status) *(status) = RpcBindingFree(binding)

 

#define rpc_binding_from_string_binding(string_binding,binding,status) \

                *(status) = RpcBindingFromStringBinding(string_binding,binding)

 

#define rpc_binding_inq_auth_client(binding,privs,princ_name,protect_level, \

                authn_svc,authz_svc,status) \

                *(status) = RpcBindingInqAuthClient(binding,privs,princ_name, \

                protect_level,authn_svc,authz_svc)

 

#define rpc_binding_inq_auth_info(binding,princ_name,protect_level,\

                authn_svc,auth_identity,authz_svc,status) \

                *(status) = RpcBindingInqAuthInfo(binding,princ_name, \

                protect_level,authn_svc,auth_identity,authz_svc)

 

#define rpc_binding_inq_object(binding,object_uuid,status) \

                *(status) = RpcBindingInqObject(binding,\

                (UUID __RPC_FAR *)object_uuid)

 

#define rpc_binding_reset(binding,status) *(status) = RpcBindingReset(binding)

 

#define rpc_binding_server_from_client(cbinding,sbinding,status) \

                *(status) = RpcBindingServerFromClient(cbinding,sbinding)

 

#define rpc_binding_set_auth_info(binding,princ_name,protect_level,\

                authn_svc,auth_identity,authz_svc,status) \

                *(status) = RpcBindingSetAuthInfo(binding,princ_name,\

                protect_level,authn_svc,auth_identity,authz_svc)

 

#define rpc_binding_set_object(binding,object_uuid,status) \

                *(status) = RpcBindingSetObject(binding,\

                (UUID __RPC_FAR *)object_uuid)

 

#define rpc_binding_to_string_binding(binding,string_binding,status) \

                *(status) = RpcBindingToStringBinding(binding,string_binding)

 

#define rpc_binding_vector_free(binding_vector,status) \

                *(status) = RpcBindingVectorFree(\

                (RPC_BINDING_VECTOR __RPC_FAR * __RPC_FAR *)binding_vector)

 

#define rpc_ep_register(if_spec,binding_vec,object_uuid_vec,annotation,\

                status)\

                *(status) = RpcEpRegister(if_spec,\

                (RPC_BINDING_VECTOR __RPC_FAR *)binding_vec, \

                (UUID_VECTOR __RPC_FAR *)object_uuid_vec, annotation)

 

#define rpc_ep_register_no_replace(if_spec,binding_vec,object_uuid_vec,\

                annotation,status) \

                *(status) = RpcEpRegisterNoReplace(if_spec,\

                (RPC_BINDING_VECTOR __RPC_FAR *)binding_vec,\

                (UUID_VECTOR __RPC_FAR *)object_uuid_vec,annotation)

 

#define rpc_ep_resolve_binding(binding_h,if_spec,status) \

                *(status) = RpcEpResolveBinding(binding_h,if_spec)

 

#define rpc_ep_unregister(if_spec,binding_vec,object_uuid_vec,status) \

                *(status) = RpcEpUnregister(if_spec,\

                (RPC_BINDING_VECTOR __RPC_FAR *)binding_vec,\

                (UUID_VECTOR __RPC_FAR *)object_uuid_vec)

 

#define rpc_if_id_vector_free(if_id_vector,status) \

                *(status) = RpcIfIdVectorFree(\

                (RPC_IF_ID_VECTOR __RPC_FAR * __RPC_FAR *)if_id_vector)

 

#define rpc_if_inq_id(if_spec,if_id,status) \

                *(status) = RpcIfInqId(if_spec,(RPC_IF_ID __RPC_FAR *)if_id)

 

#define rpc_if_register_auth_info(if_spec,princ_name,protect_level,\

                authn_svc,auth_identity,authz_svc,status) \

                *(status) = RpcIfRegisterAuthInfo(if_spec,princ_name,\

                protect_level,authn_svc,auth_identity,authz_svc)

 

#define rpc_mgmt_ep_elt_inq_begin(ep_binding,inquiry_type,if_id,vers_option,\

                object_uuid,inquiry_context,status) \

                *(status) = RpcMgmtEpEltInqBegin(ep_binding,inquiry_type,if_id,\

                vers_option,object_uuid,inquiry_context)

 

#define rpc_mgmt_ep_elt_inq_done(inquiry_context,status) \

                *(status) = RpcMgmtEpEltInqDone(inquiry_context)

 

#define rpc_mgmt_ep_elt_inq_next(inquiry_context,if_id,binding,object_uuid,\

                annotation,status) \

                *(status) = RpcMgmtEpEltInqNext(inquiry_context,if_id,binding,\

                object_uuid,annotation)

 

#define rpc_mgmt_ep_unregister(ep_binding,if_id,binding,object_uuid,status) \

                *(status) = RpcMgmtEpUnregister(ep_binding,if_id,binding,\

                object_uuid)

 

#define rpc_mgmt_inq_com_timeout(binding,timeout,status) \

                *(status) = RpcMgmtInqComTimeout(binding,timeout)

 

#define rpc_mgmt_inq_dflt_protect_level(authn_svc,level,status) \

                *(status) = RpcMgmtInqDefaultProtectLevel(authn_svc,level)

 

#define rpc_mgmt_inq_if_ids(binding,if_id_vector,status) \

                *(status) = RpcMgmtInqIfIds((bindings),\

                (RPC_IF_ID_VECTOR __RPC_FAR * __RPC_FAR *)(if_id_vector))

 

#define rpc_mgmt_inq_server_princ_name(binding,authn_svc,princ_name,status) \

                *(status) = RpcMgmtInqServerPrincName(binding,authn_svc,\

                princ_name)

 

#define rpc_mgmt_inq_stats(binding,statistics,status) \

                *(status) = RpcMgmtInqStats(binding,\

                (RPC_STATS_VECTOR __RPC_FAR * __RPC_FAR *)statistics)

 

#define rpc_mgmt_is_server_listening(binding,status) \

                ( ((*(status) = RpcMgmtIsServerListening(binding)) == RPC_S_OK) \

                ? (1) : (*(status) == RPC_S_NOT_LISTENING) \

                ? (*(status) = RPS_S_OK, 0) : (0) )

 

#define rpc_mgmt_set_authorization_fn(authz_fn,status) \

                *(status) = RpcMgmtSetAuthorizathionFn(authz_fn)

 

#define rpc_mgmt_set_cancel_timeout(seconds,status) \

                *(status) = RpcMgmtSetCancelTimeout(seconds)

 

#define rpc_mgmt_set_com_timeout(binding,timeout,status) \

                *(status) = RpcMgmtSetComTimeout(binding,timeout)

 

#define rpc_mgmt_set_server_stack_size(size,status) \

                *(status) = RpcMgmtSetServerStackSize(size)

 

#define rpc_mgmt_stats_vector_free(stats,status) \

                *(status) = RpcMgmtStatsVectorFree(\

                (RPC_STATS_VECTOR __RPC_FAR * __RPC_FAR *)stats)

 

#define rpc_mgmt_stop_server_listening(binding,status) \

                *(status) = RpcMgmtStopServerListening(binding)

 

#define rpc_network_inq_protseqs(prots,status) \

                *(status) = RpcNetworkInqProtseqs(\

                (RPC_PROTSEQ_VECTOR __RPC_FAR * __RPC_FAR *)prots)

 

#define rpc_network_is_protseq_valid(protseq,status) \

                *(status) = RpcNetworkIsProtseqValid(protseq)

 

/*

** Define NSI equivalents

*/

#define rpc_ns_binding_export(name_syntax,entry_name,if_spec,\

                binding_vector, uuid_vector,status) \

                *(status) = RpcNsBindingExport(name_syntax,entry_name,\

                if_spec, (RPC_BINDING_VECTOR *)binding_vector,\

                (UUID_VECTOR __RPC_FAR *)uuid_vector)

 

#define rpc_ns_binding_import_begin(name_syntax,entry_name,if_spec,\

                object_uuid,import_context,status) \

                *(status) = RpcNsBindingImportBegin(name_syntax,entry_name,\

                if_spec,(UUID __RPC_FAR *)object_uuid,import_context)

 

#define rpc_ns_binding_import_done(import_context,status) \

                *(status) = RpcNsBindingImportDone(import_context)

 

#define rpc_ns_binding_import_next(import_context,binding,status) \

                *(status) = RpcNsBindingImportNext(import_context,binding)

 

#define rpc_ns_binding_inq_entry_name(binding,name_syntax,entry_name,status)\

                *(status) = RpcNsBindingInqEntryName(binding,name_syntax,\

                entry_name)

 

#define rpc_ns_binding_lookup_begin(name_syntax,entry_name,if_spec,\

                object_uuid,max_count,lookup_context,status) \

                *(status) = RpcNsBindingLookupBegin(name_syntax,entry_name,\

                if_spec,(UUID __RPC_FAR *)object_uuid,max_count,lookup_context)

 

#define rpc_ns_binding_lookup_done(lookup_context,status) \

                *(status) = RpcNsBindingLookupDone(lookup_context)

 

#define rpc_ns_binding_lookup_next(lookup_context,binding_vector,status) \

                *(status) = RpcNsBindingLookupNext(lookup_context, \

                (RPC_BINDING_VECTOR __RPC_FAR * __RPC_FAR *)binding_vector)

 

#define rpc_ns_binding_select(binding_vector,binding,status) \

                *(status) = RpcNsBindingSelect(\

                (RPC_BINDING_VECTOR __RPC_FAR *)binding_vector,binding)

 

#define rpc_ns_binding_unexport(name_syntax,entry_name,if_spec,\

                uuid_vector,status) \

                *(status) = RpcNsBindingUnexport(name_syntax,entry_name,\

                if_spec, (UUID_VECTOR __RPC_FAR *)uuid_vector)

 

#define rpc_ns_entry_expand_name(name_syntax,entry_name,expanded_name,\

                status)\

                *(status) = RpcNsEntryExpandName(name_syntax,entry_name,\

                expanded_name)

 

#define rpc_ns_entry_object_inq_begin(name_syntax,entry_name,\

                inquiry_context,status)\

                *(status) = RpcNsEntryObjectInqBegin(name_syntax,\

                entry_name,inquiry_context)

 

#define rpc_ns_entry_object_inq_done(inquiry_context,status) \

                *(status) = RpcNsEntryObjectInqDone(inquiry_context)

 

#define rpc_ns_entry_object_inq_next(inquiry_context,object_uuid,status) \

                *(status) = RpcNsEntryObjectInqNext(inquiry_context,\

                (UUID __RPC_FAR *)object_uuid)

 

#define rpc_ns_group_delete(name_syntax,group_name,status) \

                *(status) = RpcNsGroupDelete(name_syntax,group_name)

 

#define rpc_ns_group_mbr_add(name_syntax,group_name,member_name_syntax,\

                member_name,status) \

                *(status) = RpcNsGroupMbrAdd(name_syntax,group_name,\

                member_name_syntax,member_name)

 

#define rpc_ns_group_mbr_inq_begin(name_syntax,group_name,member_name_syntax,\

                inquiry_context,status) \

                *(status) = RpcNsGroupMbrInqBegin(name_syntax,group_name,\

                member_name_syntax,inquiry_context)

 

#define rpc_ns_group_mbr_inq_done(inquiry_context,status) \

                *(status) = RpcNsGroupMbrInqDone(inquiry_context)

 

#define rpc_ns_group_mbr_inq_next(inquiry_context,member_name,status) \

                *(status) = RpcNsGroupMbrInqNext(inquiry_context,member_name)

 

#define rpc_ns_group_mbr_remove(name_syntax,group_name,member_name_syntax,\

                member_name,status) \

                *(status) = RpcNsGroupMbrRemove(name_syntax,group_name,\

                member_name_syntax,member_name)

 

#define rpc_ns_mgmt_binding_unexport(name_syntax,entry_name,if_id,vers_option,\

                uuid_vector,status) \

                *(status) = RpcNsMgmtBindingUnexport(name_syntax,entry_name,\

                (RPC_IF_ID __RPC_FAR *)if_id,vers_option,\

                (UUID_VECTOR __RPC_FAR *)uuid_vector)

 

#define rpc_ns_mgmt_entry_create(name_syntax,entry_name,status) \

                *(status) = RpcNsMgmtEntryCreate(name_syntax,entry_name)

 

#define rpc_ns_mgmt_entry_delete(name_syntax,entry_name,status) \

                *(status) = RpcNsMgmtEntryDelete(name_syntax,entry_name)

 

#define rpc_ns_mgmt_entry_inq_if_ids(name_syntax,entry_name,if_id_vector,\

                status) \

                *(status) = RpcNsMgmtEntryInqIfIds(name_syntax,entry_name,\

                (RPC_IF_ID_VECTOR __RPC_FAR * __RPC_FAR *)if_id_vector)

 

#define rpc_ns_mgmt_handle_set_exp_age(ns_handle,expiration_age,status) \

                *(status) = RpcNsMgmtHandleSetExpAge(ns_handle,expiration_age)

 

#define rpc_ns_mgmt_inq_exp_age(expiration_age,status) \

                *(status) = RpcNsMgmtInqExpAge(expiration_age)

 

#define rpc_ns_mgmt_set_exp_age(expiration_age,status) \

                *(status) = RpcNsMgmtSetExpAge(expiration_age)

 

#define rpc_ns_profile_delete(name_syntax,profile_name,status) \

                *(status) = RpcNsProfileDelete(name_syntax,profile_name)

 

#define rpc_ns_profile_elt_add(name_syntax,profile_name,if_id,\

                member_name_syntax,member_name,priority,annotation,status) \

                *(status) = RpcNsProfileEltAdd(name_syntax,profile_name,\

                (RPC_IF_ID __RPC_FAR *)if_id,member_name_syntax,member_name,\

                priority,annotation)

 

#define rpc_ns_profile_elt_inq_begin(name_syntax,profile_name,inquiry_type,\

                if_id,if_vers_option,member_name_syntax,\

                member_name,inquiry_context,status) \

                *(status) = RpcNsProfileEltInqBegin(name_syntax,profile_name,\

                inquiry_type,(RPC_IF_ID __RPC_FAR *)if_id,if_vers_option,\

                member_name_syntax,member_name,inquiry_context)

 

#define rpc_ns_profile_elt_inq_done(inquiry_context,status) \

                *(status) = RpcNsProfileEltInqDone(inquiry_context)

 

#define rpc_ns_profile_elt_inq_next(inquiry_context,if_id,member_name,\

                priority,annotation,status) \

                *(status) = RpcNsProfileEltInqNext(inquiry_context,\

                (RPC_IF_ID __RPC_FAR *)if_id,member_name,priority,annotation)

 

#define rpc_ns_profile_elt_remove(name_syntax,profile_name,if_id,\

                member_name_syntax,member_name,status) \

                *(status) = RpcNsProfileEltRemove(name_syntax,profile_name,\

                (RPC_IF_ID __RPC_FAR *)if_id,member_name_syntax,member_name)

 

#define rpc_object_inq_type(object_uuid,type_uuid,status) \

                *(status) = RpcObjectInqType((UUID __RPC_FAR *)object_uuid,\

                (UUID __RPC_FAR *)type_uuid)

 

#define rpc_object_set_inq_fn(inq_fn,status) \

                *(status) = RpcObjectSetInqFn(inq_fn)

 

#define rpc_object_set_type(object_uuid,type_uuid,status) \

                *(status) = RpcObjectSetType((UUID __RPC_FAR *)object_uuid,\

                (UUID __RPC_FAR *)type_uuid)

 

#define rpc_protseq_vector_free(protseq_vector,status) \

                *(status) = RpcProtseqVectorFree( \

                (RPC_PROTSEQ_VECTOR __RPC_FAR * __RPC_FAR *)protseq_vector)

 

#define rpc_server_inq_bindings(binding_vector,status) \

                *(status) = RpcServerInqBindings(\

                (RPC_BINDING_VECTOR __RPC_FAR * __RPC_FAR *)binding_vector)

 

#define rpc_server_inq_if(if_spec,type_uuid,mgr_epv,status) \

                *(status) = RpcServerInqIf(if_spec,(UUID __RPC_FAR *)type_uuid,\

                (RPC_MGR_EPV __RPC_FAR *)mgr_epv)

 

#define rpc_server_listen(max_calls,status) \

                *(status) = RpcServerListen(rpc_c_listen_min_threads_default,\

                max_calls,0)

 

#define rpc_server_register_auth_info(princ_name,auth_svc,get_key_func,arg,\

                status) \

                *(status) = RpcServerRegisterAuthInfo(princ_name,auth_svc,\

                get_key_func,arg)

 

#define rpc_server_register_if(if_spec,type_uuid,mgr_epv,status) \

                *(status) = RpcServerRegisterIf(if_spec,\

                (UUID __RPC_FAR *)type_uuid,(RPC_MGR_EPV __RPC_FAR *)mgr_epv)

 

#define rpc_server_unregister_if(if_spec,type_uuid,status) \

                *(status) = RpcServerUnregisterIf(if_spec,(UUID *)type_uuid,0)

 

#define rpc_server_use_all_protseqs(max_call_requests,status) \

                *(status) = RpcServerUseAllProtseqs(max_call_requests,0)

 

#define rpc_server_use_all_protseqs_if(max_call_requests,if_spec,status) \

                *(status) = RpcServerUseAllProtseqsIf(max_call_requests,\

                if_spec,0)

 

#define rpc_server_use_protseq(protseq,max_call_requests,status) \

                *(status) = RpcServerUseProtseq(protseq,max_call_requests,0)

 

#define rpc_server_use_protseq_ep(protseq,max_call_requests,endpoint,status)\

                *(status) = RpcServerUseProtseqEp(protseq,max_call_requests,\

                endpoint,0)

 

#define rpc_server_use_protseq_if(protseq,max_call_requests,if_spec,status) \

                *(status) = RpcServerUseProtseqIf(protseq,max_call_requests,\

                if_spec,0)

 

#define rpc_sm_alloce(size,status) *(status) = RpcSmAllocate(size)

 

#define rpc_sm_client_free(ptr,status) *(status) = RpcSmClientFree(ptr)

 

#define rpc_sm_destroy_client_context(context,status) \

                *(status) = RpcSmDestroyClientContext(context)

 

#define rpc_sm_disable_allocate(status) *(status) = RpcSmDisableAllocate()

 

#define rpc_sm_enable_allocate(status) *(status) = RpcSmEnableAllocate()

 

#define rpc_sm_free(ptr,status) *(status) = RpcSmFree(ptr)

 

#define rpc_sm_get_thread_handle(status) RpcSmGetThreadHandle(status)

 

#define rpc_sm_set_client_alloc_free(alloc,free,status) \

                *(status) = RpcSmSetClientAllocFree(alloc,free)

 

#define rpc_sm_set_thread_handle(id,status) \

                *(status) = RpcSmSetThreadHandle(id)

 

#define rpc_sm_swap_client_alloc_free(alloc,free,old_alloc,old_free,status) \

                *(status) = RpcSmSwapClientAllocFree(alloc,free \

                old_alloc, old_free)

 

#define rpc_string_binding_compose(object_uuid,protseq,netaddr,endpoint,\

                options,binding,status) \

                *(status) = RpcStringBindingCompose(object_uuid,protseq,\

                netaddr,endpoint,options,binding)

 

#define rpc_string_binding_parse(string_binding,object_uuid,protseq,netaddr,\

                endpoint,options,status) \

                *(status) = RpcStringBindingParse(string_binding,\

                object_uuid,protseq,netaddr,endpoint,options)

 

#define rpc_string_free(string,status) *(status) = RpcStringFree(string)

 

#define uuid_compare(uuid1,uuid2,status) \

                UuidCompare((UUID __RPC_FAR *)(uuid1),\

                            (UUID __RPC_FAR *)(uuid2),(status))

 

#define uuid_create(uuid,status) \

                *(status) = UuidCreate((UUID __RPC_FAR *)uuid)

 

#define uuid_create_nil(uuid,status) \

                *(status) = UuidCreateNil((UUID __RPC_FAR *)uuid)

 

#define uuid_equal(uuid1,uuid2,status) \

                UuidEqual((UUID __RPC_FAR *)(uuid1), \

                          (UUID __RPC_FAR *)(uuid2), (status))

 

#define uuid_from_string(string,uuid,status) \

                *(status) = UuidFromString(string,(UUID __RPC_FAR *)uuid)

 

#define uuid_hash(uuid,status) \

                UuidHash((UUID __RPC_FAR *)(uuid),(status))

 

#define uuid_is_nil(uuid,status) \

                UuidIsNil((UUID __RPC_FAR *)(uuid), (status))

 

#define uuid_to_string(uuid,string,status)\

                *(status) = UuidToString((UUID __RPC_FAR *)uuid,string)

 

 

#define true  1

#define false 0

 

/*

** Define exception handling equivalents

**

*/

#if defined (__RPC_WIN16__) || defined (__RPC_DOS__)

 

#define TRY                                       \

    {                                                \

    int _exception_mode_finally;                     \

    int _exception_code;                             \

    ExceptionBuff exception;                         \

    _exception_code = RpcSetException(&exception);   \

    if (!_exception_code)                            \

    {

 

#define CATCH_ALL                                 \

        _exception_mode_finally = false;             \

        RpcLeaveException();                         \

        }                                            \

        else                                         \

        {

/*

 * #define CATCH(X)                               \

 *   }else if ((unsigned long)RpcExceptionCode()==(unsigned long)X) {

 */

#define FINALLY                                   \

        _exception_mode_finally = true;              \

        RpcLeaveException();                         \

        } {

#define ENDTRY                                    \

          }                                               \

        if (_exception_mode_finally && _exception_code)  \

            RpcRaiseException(_exception_code);           \

        }

 

#endif /* WIN16 or DOS */

 

 

#if defined (__RPC_WIN32__)

#define TRY             try {

/*

 * #define CATCH(X)        \

 *                      } except (GetExceptionCode() == X ? \

 *                        EXCEPTION_EXECUTE_HANDLER : \

 *                        EXCEPTION_CONTINUE_SEARCH) {

 */

#define CATCH catch

#define CATCH_ALL       } except (EXCEPTION_EXECUTE_HANDLER) {

#define FINALLY         } finally {

#define ENDTRY          }

#endif /* WIN32 */

 

#define RAISE(v)   RpcRaiseException(v)

#define RERAISE    RpcRaiseException(RpcExceptionCode())

#define THIS_CATCH RpcExceptionCode()

 

/*

** DCE Status code mappings

*/

#ifndef rpc_s_ok

#define rpc_s_ok                        RPC_S_OK

#endif

#ifndef error_status_ok

#define error_status_ok                 RPC_S_OK

#endif

#define ept_s_cant_perform_op           EPT_S_CANT_PERFORM_OP

#define ept_s_invalid_entry             EPT_S_INVALID_ENTRY

#define ept_s_not_registered            EPT_S_NOT_REGISTERED

#define rpc_s_already_listening         RPC_S_ALREADY_LISTENING

#define rpc_s_already_registered        RPC_S_ALREADY_REGISTERED

#define rpc_s_binding_has_no_auth       RPC_S_BINDING_HAS_NO_AUTH

#define rpc_s_binding_imcomplete        RPC_S_BINDING_IMCOMPLETE

#define rpc_s_call_cancelled            RPC_S_CALL_CANCELLED

#define rpc_s_call_failed               RPC_S_CALL_FAILED

#define rpc_s_cant_bind_socket          RPC_S_CANNOT_BIND

#define rpc_s_cant_create_socket        RPC_S_CANT_CREATE_ENDPOINT

#define rpc_s_comm_failure              RPC_S_COMM_FAILURE

#define rpc_s_connect_no_resources      RPC_S_OUT_OF_RESOURCES

#define rpc_s_cthread_create_failed     RPC_S_OUT_OF_THREADS

#define rpc_s_endpoint_not_found        RPC_S_NO_ENDPOINT_FOUND

#define rpc_s_entry_already_exists      RPC_S_ENTRY_ALREADY_EXISTS

#define rpc_s_entry_not_found           RPC_S_ENTRY_NOT_FOUND

#define rpc_s_fault_addr_error          RPC_S_ADDRESS_ERROR

#define rpc_s_fault_fp_div_by_zero      RPC_S_FP_DIV_ZERO

#define rpc_s_fault_fp_overflow         RPC_S_FP_OVERFLOW

#define rpc_s_fault_fp_underflow        RPC_S_FP_UNDERFLOW

#define rpc_s_fault_int_div_by_zero     RPC_S_ZERO_DIVIDE

#define rpc_s_fault_invalid_bound       RPC_S_INVALID_BOUND

#define rpc_s_fault_invalid_tag         RPC_S_INVALID_TAG

#define rpc_s_fault_remote_no_memory    RPC_S_SERVER_OUT_OF_MEMORY

#define rpc_s_fault_unspec              RPC_S_CALL_FAILED

#define rpc_s_incomplete_name           RPC_S_INCOMPLETE_NAME

#define rpc_s_interface_not_found       RPC_S_INTERFACE_NOT_FOUND

#define rpc_s_internal_error            RPC_S_INTERNAL_ERROR

#define rpc_s_inval_net_addr            RPC_S_INVALID_NET_ADDR

#define rpc_s_invalid_arg               RPC_S_INVALID_ARG

#define rpc_s_invalid_binding           RPC_S_INVALID_BINDING

#define rpc_s_invalid_endpoint_format   RPC_S_INVALID_ENDPOINT_FORMAT

#define rpc_s_invalid_naf_id            RPC_S_INVALID_NAF_IF

#define rpc_s_invalid_name_syntax       RPC_S_INVALID_NAME_SYNTAX

#define rpc_s_invalid_rpc_protseq       RPC_S_INVALID_RPC_PROTSEQ

#define rpc_s_invalid_string_binding    RPC_S_INVALID_STRING_BINDING

#define rpc_s_invalid_timeout           RPC_S_INVALID_TIMEOUT

#define rpc_s_invalid_vers_option       RPC_S_INVALID_VERS_OPTION

#define rpc_s_max_calls_too_small       RPC_S_MAX_CALLS_TOO_SMALL

#define rpc_s_mgmt_op_disallowed        RPC_S_ACCESS_DENIED

#define rpc_s_name_service_unavailable  RPC_S_NAME_SERVICE_UNAVAILABLE

#define rpc_s_no_bindings               RPC_S_NO_BINDINGS

#define rpc_s_no_entry_name             RPC_S_NO_ENTRY_NAME

#define rpc_s_no_interfaces             RPC_S_NO_INTERFACES

#define rpc_s_no_interfaces_exported    RPC_S_NO_INTERFACES_EXPORTED

#define rpc_s_no_memory                 RPC_S_OUT_OF_MEMORY

#define rpc_s_no_more_elements          RPC_X_NO_MORE_ENTRIES

#define rpc_s_no_more_bindings          RPC_S_NO_MORE_BINDINGS

#define rpc_s_no_more_members           RPC_S_NO_MORE_MEMBERS

#define rpc_s_no_ns_permission          RPC_S_ACCESS_DENIED

#define rpc_s_no_princ_name             RPC_S_NO_PRINC_NAME

#define rpc_s_no_protseqs               RPC_S_NO_PROTSEQS

#define rpc_s_no_protseqs_registered    RPC_S_NO_PROTSEQS_REGISTERED

#define rpc_s_not_rpc_tower             RPC_S_CANNOT_SUPPORT

#define rpc_s_not_supported             RPC_S_CANNOT_SUPPORT

#define rpc_s_not_authorized            RPC_S_ACCESS_DENIED

#define rpc_s_nothing_to_unexport       RPC_S_NOTHING_TO_UNEXPORT

#define rpc_s_object_not_found          RPC_S_OBJECT_NOT_FOUND

#define rpc_s_protocol_error            RPC_S_PROTOCOL_ERROR

#define rpc_s_protseq_not_supported     RPC_S_PROTSEQ_NOT_SUPPORTED

#define rpc_s_server_too_busy           RPC_S_SERVER_TOO_BUSY

#define rpc_s_string_too_long           RPC_S_STRING_TOO_LONG

#define rpc_s_type_already_registered   RPC_S_TYPE_ALREADY_REGISTERED

#define rpc_s_unknown_authn_service     RPC_S_UNKNOWN_AUTHN_SERVICE

#define rpc_s_unknown_authz_service     RPC_S_UNKNOWN_AUTHZ_SERVICE

#define rpc_s_unknown_if                RPC_S_UNKNOWN_IF

#define rpc_s_unknown_mgr_type          RPC_S_UNKNOWN_MGR_TYPE

#define rpc_s_unknown_reject            RPC_S_CALL_FAILED_DNE

#define rpc_s_unsupported_name_syntax   RPC_S_UNSUPPORTED_NAME_SYNTAX

#define rpc_s_unsupported_type          RPC_S_UNSUPPORTED_TYPE

#define rpc_s_wrong_boot_time           RPC_S_CALL_FAILED_DNE

#define rpc_s_wrong_kind_of_binding     RPC_S_WRONG_KIND_OF_BINDING

#define uuid_s_ok                       RPC_S_OK

#define uuid_s_internal_error           RPC_S_INTERNAL_ERROR

#define uuid_s_invalid_string_uuid      RPC_S_INVALID_STRING_UUID

#define uuid_s_no_address               RPC_S_UUID_NO_ADDRESS

 

/*

** DCE Exception mappings

*/

 

#define rpc_x_comm_failure              RPC_S_COMM_FAILURE

#define rpc_x_connect_no_resources      RPC_S_OUT_OF_RESOURCES

#define rpc_x_entry_not_found           RPC_S_ENTRY_NOT_FOUND

#define rpc_x_incomplete_name           RPC_S_INCOMPLETE_NAME

#define rpc_x_invalid_arg               RPC_S_INVALID_ARG

#define rpc_x_invalid_binding           RPC_S_INVALID_BINDING

#define rpc_x_invalid_bound             RPC_X_INVALID_BOUND

#define rpc_x_invalid_endpoint_format   RPC_S_INVALID_ENDPOINT_FORMAT

#define rpc_x_invalid_naf_id            RPC_S_INVALID_NAF_IF

#define rpc_x_invalid_name_syntax       RPC_S_INVALID_NAME_SYNTAX

#define rpc_x_invalid_rpc_protseq       RPC_S_INVALID_RPC_PROTSEQ

#define rpc_x_invalid_tag               RPC_X_INVALID_TAG

#define rpc_x_invalid_timeout           RPC_S_INVALID_TIMEOUT

#define rpc_x_no_memory                 RPC_X_NO_MEMORY

#define rpc_x_object_not_found          RPC_S_OBJECT_NOT_FOUND

#define rpc_x_protocol_error            RPC_S_PROTOCOL_ERROR

#define rpc_x_protseq_not_supported     RPC_S_PROTSEQ_NOT_SUPPORTED

#define rpc_x_server_too_busy           RPC_S_SERVER_TOO_BUSY

#define rpc_x_ss_char_trans_open_fail   RPC_X_SS_CHAR_TRANS_OPEN_FAIL

#define rpc_x_ss_char_trans_short_file  RPC_X_SS_CHAR_TRANS_SHORT_FILE

#define rpc_x_ss_context_damaged        RPC_X_SS_CONTEXT_DAMAGED

#define rpc_x_ss_context_mismatch       RPC_X_SS_CONTEXT_MISMATCH

#define rpc_x_ss_in_null_context        RPC_X_SS_IN_NULL_CONTEXT

#define rpc_x_string_too_long           RPC_S_STRING_TOO_LONG

#define rpc_x_unknown_if                RPC_S_UNKNOWN_IF

#define rpc_x_unknown_mgr_type          RPC_S_UNKNOWN_MGR_TYPE

#define rpc_x_unsupported_name_syntax   RPC_S_UNSUPPORTED_NAME_SYNTAX

#define rpc_x_unsupported_type          RPC_S_UNSUPPORTED_TYPE

#define rpc_x_wrong_boot_time           RPC_S_CALL_FAILED_DNE

#define rpc_x_wrong_kind_of_binding     RPC_S_WRONG_KIND_OF_BINDING

#define uuid_x_internal_error           RPC_S_INTERNAL_ERROR

 

#ifdef __cplusplus

}

#endif

 

#endif /* DCEPORT_H */

 

 


FILE:MAKEFILE

############################################################################

# Makefile for binopc and binops client/server DCE application program

#

# Author:   G.K. Springer at U of MO - Columbia

# Date:     June 1991

# Node:     condor.cs.missouri.edu

# Place:    Computer Science Department, University of Missouri-Columbia

#

# Purpose:  Demonstrate the coding for a simple DCE RPC application.

#           The application makes 100 requests to a server to perform 50

#           additions and 50 subtractions in sequence to see the effect

#           of making these requests across the network.

#

# Function: Client calls upon a server to compute either the addition or

#           or subtraction of two numbers passed as parameters in a RPC

#           call.  The RPC functions return the result to the caller.

#           This application uses a server that exports two RPC functions;

#           an addition function and a subtraction function.  The client

#           performs a specifiable number of calls to the add function and

#           the same number of calls to the subtract function in order to

#           time the average amount of time needed to complete a single call.

#           The results of the computations and the time/call are written

#           to stdout.

#

# Update Log:

#   6/28/91 - Corrected Makefile to support building individual components

#   3/26/93 - Upgraded code to handle multiple versions of interface and

#             set makefile so it can handle makes on different platforms.

#             For Apollo:  make

#                 DEC:     make GENSYS=-DDEC

#                 RS/6000: make GENSYS=-DIBMRISC LIB2=-lbsd

#  10/25/93 - Changes to build code for a DCE system

#             Code to build system on different platforms is separated

#             into separate makefiles so the application can be created

#             on multiple platforms:

#             where:  platform is one of [alpha, cray, mips or rs6000]

#             if a particular component is to be built, use the MK

#             macro of Make to specify the component that is to be built.

#

#             For example: make  alpha     builds entire system

#                          make  alpha MK=clean     cleans up after build

#                          make  cray  MK=binops    builds server on cray

#   4/22/95 - JimR: Completed section for Win32 builds.  Note that we are

#             dependent on the tm.exe utility.

#   2/26/98 - JimR: Merged in old Microsoft native way to build (WIN32RAW).

#

############################################################################

 

 

############################################################################

## This is a heuristic to make sure that WIN32 is set when building on NT ##

!ifdef CPU

WIN32=1

!endif

############################################################################

 

 

############################################################################

## This is necessary to set specific flags for PC environments            ##

!ifdef WIN32

CFLAGS=/c /GX /I. /I.. /I..\..\include /I..\..\logger /I..\..\service -D_X86_=1 -G3 -Gz -DDCENT -Didl_char=char -D_MSDOS -DEP -DWIN32=1 /nologo /Zp1

 

!      ifdef DEBUG

CFLAGS=$(CFLAGS) -DDEBUG -Od -Zi

!      endif  // DEBUG

 

!      ifdef NOCERT

CFLAGS=$(CFLAGS) -DNOCERT

!      endif  // NOCERT

 

!      ifdef NODAEMON

CFLAGS=$(CFLAGS) -DNODAEMON

!      endif  // NODAEMON

 

!endif // WIN32

############################################################################

 

 

!ifdef WIN32

default:

       @echo.

       @echo Making Binop Demo Application

       @echo.

       @echo No system specified for the make.

       @echo.

       @echo Usage:  make  sysname  [MK=components_to_build]

       @echo where:

       @echo sysname is one of [ alpha cray mips rs6000 win32 win32raw]

       @echo.

!else

default:

       @echo ' '

       @echo 'Making Binop Demo Application'

       @echo ' '

       @echo '  No system specified for the make.'

       @echo ' '

       @echo '     Usage:  make  sysname  [MK=components_to_build]'

       @echo '        where:'

       @echo '          sysname is one of [ alpha cray mips rs6000 win32]'

       @echo ' '

!endif

 

# Make the code on WIN32 platforms (Windows 95 and NT), assuming full DCE support

WIN32: makefile.bin

       @tm start

       @echo Build Binop Demo on WIN32

       @if not exist build.win md build.win

       @if not exist ..\build.wbn md ..\build.wbn

       @cd build.win

       @echo building with these CFLAGS=$(CFLAGS)

       @$(MAKE) /nologo -f ..\makefile.bin \

      WIN32=1 \

      TSRC=.. \

      T1=..\..\build.wbn \

      IDL=idl \

          IDLFLAGS= \

              CFLAGS="$(CFLAGS)" \

              LINKFLGS= \

      LIBS="pthreads.lib libdce.lib wsock32.lib advapi32.lib" \

      LIB2= \

      GENSYS=WIN32

       @echo Build on WIN32 complete

       @tm stop

 

# Make the code on WIN32 platforms (Windows 95 and NT), assuming full DCE support

WIN32RAW: makefile.bin

       @tm start

       @echo Build Binop Demo on WIN32RAW

       @if not exist build.win md build.win

       @if not exist ..\build.wbn md ..\build.wbn

       @cd build.win

       @echo building with these CFLAGS=$(CFLAGS)

       @$(MAKE) /nologo -f ..\makefile.bin \

      WIN32RAW=1 \

      WIN32=1 \

      TSRC=.. \

      T1=..\..\build.wbn \

      IDL=midl \

          IDLFLAGS=/osf \

              CFLAGS="$(CFLAGS) /DWIN32RAW" \

              LINKFLGS= \

      LIBS=rpcrt4.lib \

      LIB2= \

      GENSYS=WIN32

       @echo Build on WIN32RAW complete

       @tm stop

 

# Make the code on ALPHA platforms

alpha: Makefile.bindemo

       @echo

       @echo Build Binop Demo on ALPHA - `date`

       @if [ ! -d "Build.alpha" ] ; then mkdir Build.alpha ; fi ;

       @if [ ! -d "Build.abin" ] ; then ln -s ../../bin Build.abin ; fi ;

       @cd Build.alpha ;\

         $(MAKE) $(MFLAGS) -f ../Makefile.bindemo \

           TSRC='..' \

          T1='../Build.abin' \

           IDL=/usr/bin/idl \

          IDLFLAGS='-v -keep c_source -no_cpp' \

           CFLAGS='-c -DLOG -Dalpha -D_SHARED_LIBRARIES -I. -I.. -I../../include -D_REENTRANT -w' \

           LIBS='-L../Build.abin -llogger -lmuns -ldce -lpthreads -lc_r -lmach -lm' \

           LIB2='' \

           GENSYS=alpha \

           $(MK)

       @echo Build on ALPHA complete - `date`

 

# Make the code on Cray C90 at PSC

cray:  Makefile.bindemo

       @echo

       @echo Build Binop Demo on CRAY - `date`

       @if [ ! -d "Build.cray" ] ; then mkdir Build.cray ; fi ;

       @if [ ! -d "Build.cbin" ] ; then ln -s ../../bin Build.cbin ; fi ;

       @cd Build.cray ;\

         $(MAKE) $(MFLAGS) -f ../Makefile.bindemo \

          TSRC='..' \

          T1='../Build.cbin' \

          IDL=/opt/dcelocal/bin/idl \

          IDLFLAGS='-v -keep c_source -no_cpp' \

          CFLAGS='-c -std1 -DLOG -Dcray -DNODAEMON -I. -I/usr/include/dce -I.. -I../../include -w' \

          LIBS='-L../Build.cbin -llogger -lmuns -ldce' \

          LIB2='' \

          GENSYS=cray \

           $(MK)

       @echo Build on CRAY complete - `date`

 

# Make the code on RS6000

rs6000:       Makefile.bindemo

       @echo

       @echo Build Binop Demo on RS6000 - `date`

       @if [ ! -d "Build.rs6000" ] ; then mkdir Build.rs6000 ; fi ;

       @if [ ! -d "Build.rbin" ] ; then ln -s ../../bin Build.rbin ; fi ;

       @cd Build.rs6000 ;\

         $(MAKE) $(MFLAGS) -f ../Makefile.bindemo \

          TSRC='..' \

          T1=../Build.rbin \

          IDL=/usr/bin/idl \

          IDLFLAGS='-v -keep c_source -I/usr/include/dce -no_cpp' \

          CFLAGS='-c -Dunix -qlanglvl=ansi -D_ALL_SOURCE -D_ANSI_C_SOURCE -I/usr/include/dce -I. -I.. -I../../include -w' \

          CC=/bin/xlc_r \

          LIBS='-L/usr/lib -L. -L../Build.rbin -lmuns -ldce' \

          LIB2='-lXm -lXt -lX11' \

          GENSYS=rs6000 \

          $(MK)

       @echo Build on RS6000 complete - `date`

 

.DEFAULT:

       @echo defaulting on "$@"  - don't know how to build it.

 

 


FILE:MAKEFILE.BIN

############################################################################

# Makefile for binopc and binops client/server DCE application program

#

# Author:   G.K. Springer at U of MO - Columbia

# Date:     Modified code created on 06/25/91 at MU.

# Node:     condor.cs.missouri.edu

# Place:    Computer Science Department, University of Missouri- Columbia

#

# Essentials to build the code on all platforms.  This is a dependant make

# file of the Binopdemo application makefile.

#

# Update Log:

#   9/08/93 - Changes to build code for a DCE system

#  04/22/95 - JimR: Changes for WIN32 compatibility

#

############################################################################

 

!IFDEF WIN32

 

!IFDEF DEBUG

LINK = link /DEBUG $(LINKFLGS)

!ELSE

LINK = link $(LINKFLGS)

!ENDIF

 

!IFDEF WIN32RAW

OBJC   = binop1_c.obj makepass.obj binopc.obj

!ELSE

OBJC   = binop1_cstub.obj makepass.obj binopc.obj

!ENDIF

OBJS   = binop1_sstub.obj binop1.obj binops.obj

OBJD   = binop1_cstub.obj makepass.obj binopdem.obj

OBJHLP = binop1_cstub.obj binophlp.obj

OBJST  = binop1_cstub.obj binopst.obj binop1_sstub.obj

SRVINC  = $(TSRC)\..\include\srvbase.h $(TSRC)\..\include\srvcln.h \

          $(TSRC)\musrv.h $(TSRC)\binopnms.h

 

 

#################################################################

# Default - build all of the code (binopc and binops)

#################################################################

#ALL:  $(T1)\binops.exe $(T1)\binopc.exe $(T1)\binopst.exe \

#        $(T1)\binophlp.exe $(T1)\binopdem.exe

 

# We can only build the client without the DCE extensions

!IFDEF WIN32RAW

ALL:   $(T1)\binopc.exe

!ELSE

ALL:   $(T1)\binopc.exe $(T1)\binopdem.exe $(T1)\binophlp.exe \

              $(T1)\binopst.exe $(T1)\binops.exe

!ENDIF

 

#################################################################

# Make the Server side of the process

#################################################################

#$(T1)\libmuns.a:

#$(T1)\libmutl.a:

#$(T1)\binops.exe:   $(OBJS) $(T1)\libmuns.a $(T1)\libmutl.a

$(T1)\binops.exe:    $(OBJS) $(T1)\muns.lib $(T1)\mutl.lib

       $(LINK) $(LIBS) $(LIB2) $(T1)\muns.lib $(T1)\mutl.lib /OUT:$(T1)\binops.exe $(OBJS)

#      $(CC) -o $(T1)\binops $(OBJS) -L$(T1) -lmutl $(LIBS) $(LIB2)

#      chmod 700 $(T1)\binops

#      chmod u+s $(T1)\binops

binops.obj:   binop1.h $(SRVINC) $(TSRC)\binops.c

       $(CC) $(CFLAGS) $(TSRC)\binops.c

binop1.obj:   binop1.h $(TSRC)\binop1.c

       $(CC) $(CFLAGS) $(TSRC)\binop1.c

#binop1_sstub.obj:   binop1.h binop1_sstub.c

#      @echo

#      @echo Make the server program

#      $(CC) $(CFLAGS) binop1_sstub.c

 

#################################################################

# Make the Client side of the application

#################################################################

!IFDEF WIN32RAW

$(T1)\binopc.exe:    $(OBJC)

       $(LINK) $(LIBS) $(LIB2) /OUT:$(T1)\binopc.exe $(OBJC)

!ELSE

$(T1)\binopc.exe:    $(OBJC) $(T1)\muns.lib

       $(LINK) $(LIBS) $(LIB2) $(T1)\muns.lib /OUT:$(T1)\binopc.exe $(OBJC)

!ENDIF

#      chmod 755 $(T1)\binopc

binopc.obj:   binop1.h $(TSRC)\binopc.c

       $(CC) $(CFLAGS) $(TSRC)\binopc.c

!IFDEF WIN32RAW

binop1_c.obj: binop1.h binop1_c.c

       @echo

       @echo Make the client program

       $(CC) $(CFLAGS) binop1_c.c

!ENDIF

 

#################################################################

# Make the BINOPDEMO Program

#################################################################

$(T1)\binopdem.exe:  $(OBJD) $(T1)\muns.lib

       $(LINK) $(LIBS) $(LIB2) $(T1)\muns.lib /OUT:$(T1)\binopdem.exe $(OBJD)

#      chmod 755 $(T1)\binopdem

binopdem.obj: binop1.h $(TSRC)\binopnms.h $(TSRC)\binopdem.c

       @echo

       @echo Make the demonstration program

       $(CC) $(CFLAGS) $(TSRC)\binopdem.c

 

#################################################################

# Make the BINOPST Program

#################################################################

$(T1)\binopst.exe:   $(OBJST) $(T1)\muns.lib $(T1)\mutl.lib

       $(LINK) $(LIBS) $(LIB2) $(T1)\muns.lib $(T1)\mutl.lib /OUT:$(T1)\binopst.exe $(OBJST)

#      $(CC) -o $(T1)\binopst $(OBJST) $(LIBS) $(LIB2)

#      chmod 755 $(T1)\binopst

binopst.obj:  binop1.h $(TSRC)\binopnms.h $(TSRC)\binopst.c

       @echo

       @echo Make the binop statistics program

       $(CC) $(CFLAGS) $(TSRC)\binopst.c

 

#################################################################

# Make the BINOPHLP Program

#################################################################

$(T1)\binophlp.exe:  $(OBJHLP) $(T1)\muns.lib

       $(LINK) $(LIBS) $(LIB2) $(T1)\muns.lib /OUT:$(T1)\binophlp.exe $(OBJHLP)

#      $(CC) -o $(T1)\binophlp $(OBJHLP) $(LIBS) $(LIB2)

#      chmod 755 $(T1)\binophlp

binophlp.obj: binop1.h $(TSRC)\binophlp.c

       @echo

       @echo Make the binop demonstration help program

       $(CC) $(CFLAGS) $(TSRC)\binophlp.c

 

#################################################################

# Make the Utility Code for Application

#################################################################

makepass.obj: binop1.h $(TSRC)\makepass.c

       $(CC) $(CFLAGS) $(TSRC)\makepass.c

#makepass.obj:       binop1.h $(TSRC)\makepass.cpp

#      $(CC) $(CFLAGS) $(TSRC)\makepass.cpp

 

 

 

#################################################################

# Call IDL compiler to build DCE stubs from idl definition

#################################################################

$(TSRC)\binop1.idl:

!IFDEF WIN32RAW

binop1_c.obj binop1_s.obj binop1.h:      $(TSRC)\binop1.idl

!ELSE

binop1_cstub.obj binop1_sstub.obj binop1.h:     $(TSRC)\binop1.idl

!ENDIF

       @echo

       @echo Create DCE stub code for the client and server

       $(IDL) $(IDLFLAGS) $(TSRC)\binop1.idl

 

#################################################################

# Cleanup files after build, including possibly the code modules

#################################################################

clean:

       @echo

       @echo Cleanup the binop directory

#      - rm -f binop*.obj makepass.obj binop1*.c binop1.h

#      - rm -i $(T1)\binops $(T1)\binopc $(T1)\binopdem $(T1)\binopst \

#        $(T1)\binophlp

 

 

!ELSE

 

 

 

OBJC   = binop1_cstub.o makepass.o binopc.o

OBJS   = binop1_sstub.o binop1.o binops.o

OBJD   = binop1_cstub.o makepass.o binopdemo.o

OBJHLP = binop1_cstub.o binophlp.o

OBJST  = binop1_cstub.o binopst.o

SRVINC  = $(TSRC)/../include/srvbase.h $(TSRC)/../include/srvcln.h \

          $(TSRC)/musrv.h $(TSRC)/binopnms.h

 

 

#################################################################

# Default - build all of the code (binopc and binops)

#################################################################

ALL:   $(T1)/binops $(T1)/binopc $(T1)/binopst \

        $(T1)/binophlp $(T1)/binopdemo

 

#################################################################

# Make the Server side of the process

#################################################################

$(T1)/libmuns.a:

$(T1)/libmutl.a:

$(T1)/binops: $(OBJS) $(T1)/libmuns.a $(T1)/libmutl.a

       $(CC) -o $(T1)/binops $(OBJS) -L$(T1) -lmutl $(LIBS) $(LIB2)

       chmod 700 $(T1)/binops

       chmod u+s $(T1)/binops

binops.o:     binop1.h $(SRVINC) $(TSRC)/binops.c

       $(CC) $(CFLAGS) $(TSRC)/binops.c

binop1.o:     binop1.h $(TSRC)/binop1.c

       $(CC) $(CFLAGS) $(TSRC)/binop1.c

binop1_sstub.o:      binop1.h binop1_sstub.c

       @echo

       @echo Make the server program

       $(CC) $(CFLAGS) binop1_sstub.c

 

#################################################################

# Make the Client side of the application

#################################################################

$(T1)/binopc: $(OBJC) $(T1)/libmuns.a

       $(CC) -o $(T1)/binopc $(OBJC) $(LIBS) $(LIB2)

       chmod 755 $(T1)/binopc

binopc.o:     binop1.h $(TSRC)/binopc.c

       $(CC) $(CFLAGS) $(TSRC)/binopc.c

binop1_cstub.o:      binop1.h binop1_cstub.c

       @echo

       @echo Make the client program

       $(CC) $(CFLAGS) binop1_cstub.c

 

#################################################################

# Make the BINOPDEMO Program

#################################################################

$(T1)/binopdemo:     $(OBJD) $(T1)/libmuns.a

       $(CC) -o $(T1)/binopdemo $(OBJD) $(LIBS) $(LIB2)

       chmod 755 $(T1)/binopdemo

binopdemo.o:  binop1.h $(TSRC)/binopnms.h $(TSRC)/binopdemo.c

       @echo

       @echo Make the demonstration program

       $(CC) $(CFLAGS) $(TSRC)/binopdemo.c

 

#################################################################

# Make the BINOPST Program

#################################################################

$(T1)/binopst:       $(OBJST) $(T1)/libmuns.a $(T1)/libmutl.a

       $(CC) -o $(T1)/binopst $(OBJST) $(LIBS) $(LIB2)

       chmod 755 $(T1)/binopst

binopst.o:    binop1.h $(TSRC)/binopnms.h $(TSRC)/binopst.c

       @echo

       @echo Make the binop statistics program

       $(CC) $(CFLAGS) $(TSRC)/binopst.c

 

#################################################################

# Make the BINOPHLP Program

#################################################################

$(T1)/binophlp:      $(OBJHLP) $(T1)/libmuns.a

       $(CC) -o $(T1)/binophlp $(OBJHLP) $(LIBS) $(LIB2)

       chmod 755 $(T1)/binophlp

binophlp.o:   binop1.h $(TSRC)/binophlp.c

       @echo

       @echo Make the binop demonstration help program

       $(CC) $(CFLAGS) $(TSRC)/binophlp.c

 

#################################################################

# Make the Utility Code for Application

#################################################################

makepass.o:   binop1.h $(TSRC)/makepass.c

       $(CC) $(CFLAGS) $(TSRC)/makepass.c

 

 

#################################################################

# Call IDL compiler to build DCE stubs from idl definition

#################################################################

$(TSRC)/binop1.idl:

binop1_cstub.c binop1_sstub.c binop1.h:  $(TSRC)/binop1.idl

       @echo

       @echo Create DCE stub code for the client and server

       $(IDL) $(IDLFLAGS) $(TSRC)/binop1.idl

 

#################################################################

# Cleanup files after build, including possibly the code modules

#################################################################

clean:

       @echo

       @echo Cleanup the binop directory

       - rm -f binop*.o makepass.o binop1*stub.c binop1.h

       - rm -i $(T1)/binops $(T1)/binopc $(T1)/binopdemo $(T1)/binopst \

         $(T1)/binophlp

!ENDIF

 

 


FILE:MAKEPASS.C

/*************************************************************************

 * DCE Function MAKEPASS.C - Function to make RPC calls to a Binop Server

 *

 * Author:   G.K. Springer

 * Date:     October 1993

 * Node:     condor.cs.missouri.edu

 * Location: Computer Science Department, University of Missouri-Columbia

 *

 * Purpose:  Demonstrate DCE Application Program

 *

 * Function: Implement an addition and subtraction RPC service.

 *

 * Syntax:   This function implements the actual RPC calls to the Server

 *              makepass(rh, num_passes)

 *         where:

 *            rh          - is a partially bound comm handle to server

 *            num_passes  - indicates how many loops of requests to perform

 *

 * Change Log:

 *  09/93 - GKS - Fixup for DCE implementation

 *************************************************************************/

 

/*

 * Standard C Include files

 */

#include <stdio.h>

 

#ifdef WIN32

#include <time.h>

#else

#include <sys/time.h>

#endif

 

#ifndef       WIN32RAW

#include <pthread.h>

 

/* Include DCE Definitions */

#include <dce/rpc.h>  /* DCE RPC definitions */

#include <dce/rpcexc.h>  /* DCE RPC exceptions */

#include <dce/dce_error.h>  /* DCE error definitions */

#else         /* WIN32 RAW */

#include <rpc.h>

#include "dceport.h"

#endif /* WIN32 RAW */

 

#include "binop1.h"  /* NIDL generated Interface definitions */

 

#define CALLS_PER_PASS 50

 

 

/***********************************************************************

 * makepass() - Send RPC requests to one of the requested servers

 *

 * Parameters:

 *    handle_t  rh;     -  Communication Handle

 *    int       passes; -  Number of passes to run

 ***********************************************************************/

makepass(handle_t rh, int passes)

{

   int          k;      /* Temp counter for passes run */

   int          i;      /* Temp variables */

   idl_long_int n;      /* return result from  RPC call */

   unsigned32   st;     /* Return status from RPC calls */

   int          start_time, stop_time;  /* Timing variables */

 

/* Start of processing */

   printf("\nStart Requests to: ");

   rpc_ep_resolve_binding(rh, binop_v1_0_c_ifspec, &st);

   rpc_mgmt_set_com_timeout(rh, rpc_c_binding_min_timeout, &st);

 

       #ifndef WIN32RAW

   st=p_handle(rh);

       #endif

 

   printf("\n");

 

/***********************************************************************

 * Loop for the requested number of passes to Server RPC Functions

 ***********************************************************************/

#ifndef WIN32RAW

TRY {

#endif

 for (k = 1; k <= passes; k++) {

   start_time = time(NULL);  /* Get TOD at start of a pass */

 /*

  * Call addition service the required number of times

  */

   for (i = 1; i <= CALLS_PER_PASS; i++) {

      binop_add(rh, i, i, &n);  /* Call RPC ADD service on Server */

      printf("%3d ",n);  /* Print result returned */

      /* add a newline every 10 results returned */

      if ((i%10 == 0) && (i != CALLS_PER_PASS)) printf("\n");

      fflush(stdout);

      if (n != i+i)  /* Check that we got correct result */

         printf("\n %ld + %ld is NOT %ld\n", i, i, n);

      }  /* end for i - addition loop */

      printf("  *** end of addition ***\n");

 

 /*

  * Call subtraction service the required number of times

  */

   for (i = 1; i <= CALLS_PER_PASS; i++) {

   /*

    *   Check to see if an error occurred - returns here on an error.

    */

      binop_sub(rh, CALLS_PER_PASS+1 , i, &n); /* Call RPC SUB service */

      printf("%3d ",n);  /* Print result returned */

      /* add a newline every 10 results returned */

      if ((i%10 == 0) && (i != CALLS_PER_PASS)) printf("\n");

      fflush(stdout);

      if (n != CALLS_PER_PASS+1-i)  /* Check that we got correct result */

         printf("\n %ld - %ld is NOT %ld\n", CALLS_PER_PASS, i, n);

      }  /* end for i - subtraction loop */

      printf("  *** end of subtraction ***\n");

 

/*

 * Calculate average time to process a call

 */

   stop_time = time(NULL);  /* Get TOD and end of pass */

   printf("***** pass %3d; real/call: %2d ms\n",

           k, ((stop_time - start_time) * 1000) / (2*CALLS_PER_PASS));

   }  /* end for k - number of passes */

#ifndef       WIN32RAW

}

 

CATCH (rpc_x_comm_failure) {

   printf("\t***ERROR*** Communication failure during RPC call\n");

   }

 

CATCH_ALL {

   printf("\t***ERROR*** Error occurred during RPC call\n");

   }

 

ENDTRY;

#endif /* WIN32RAW */

return;

}  /* end makepass() */

 

 


FILE:MUSRV.H

/*************************************************************************

 * Include File:  musrv.h - Include common definitions used by a server

 *

 * Author:   G.K. Springer

 * Date:     February 1994

 * Node:     condor.cs.missouri.edu

 * Place:    Computer Science Department, University of Missouri-Columbia

 *

 * Purpose:  Define common routines and constants used by an application

 *           server using DCE.

 *

 * Function: Define symbolic contants and include files used by a server

 *

 * Syntax:   This is an include file called from the server source code

 *

 * Change Log:

 *  02/95 GKS - Added code for generating unique logging transaction ids

 *

 *************************************************************************/

 

#ifndef MUSRV

#define MUSRV 1

 

/* Define Server Principal and interface routines to identify and refresh

 * the server's DCE security credentials

 */

/* JimR Note - PROBLEM! - It seems that this should be taken from the */

/* login name of whomever is currently signed on when the server is   */

/* started.  Hard-coding here seems like a bummer.                    */

static char     *principal = "springer";

 

/* Identify Common Utility Functions for Server */

void tmsg();     /* Print time-stamped messages */

char *dcemsg();  /* DCE error msg lookup routine */

unsigned32 p_handle(rpc_binding_handle_t); /* print a binding handle as text */

 

/* Bring in Application Specific Server Include Files */

#include <binop1.h>  /* DCE IDL generated header file for the server */

#include <binopnms.h>      /* DCE NS names for this server */

#include <daemon.h>     /* to make the server into a daemon */

#include <dceconfig.h>  /* names needed by server for log info */

 

#ifdef LOG

#include <log.h>        /* For LogServer Usage */

#include <newtrid.h>    /* For generating transaction ids */

unsigned32    trsrv;  /* Transaction id for the Server */

#endif

 

/* Define Names used for Server Registration */

int             regstat;              /* Registration status */

char            entry_name[NMLEN];    /* Name Service Entry Name */

char            group_name[NMLEN];    /* Name Service Group Name */

char            annotation[NMLEN];    /* Server annotation in end point map */

char            hostname[NMLEN];      /* Name of our host */

char            s_objstr[40];         /* Server Object UUID String */

 

static void     cleanup();            /* unregister server routine */

void            cleanup_usr();   /* User defined cleanup prior to unregister */

 

int             signo;   /* Signal number causing a termination */

pthread_addr_t       sigcatch(pthread_addr_t); /*signal handling thread fn */

 

#ifdef WIN32

BOOL SignalHandlerRoutine(DWORD dwCtrlType);

#endif

 

/*

 * For validating an authenticated user for credential renewal

 */

 

/* The login module exports these four interfaces */

void mulogin();

pthread_addr_t refresh_context();

#ifdef WIN32

/* JimR Note - We need this prototype in order to work in WIN32 */

void key_retrieval_function(

       void *arg,    /* argument to this function:

                      * not used */

       unsigned_char_t * server_princ_name,     /* server principal

                                          * name: not used */

       unsigned32 key_type, /* des or plain? not

                            * used */

       unsigned32 key_ver, /* version number: not

                            * used */

       void **key,   /* pointer to a structure

                      * holding the secret key */

       unsigned32 * status);

#else

void key_retrieval_function();

#endif

 

/* This krb_key_t structure is a workaround to a problem with the definition

 * of the key retrieval function in rpc_server_register_auth_info(3rpc).

 * The key structure is not described nor exported to the programmer.  This

 * structure resembles the structure used internal to the security library, and

 * for the current implementation, works to supply a valid key to the RPC

 * runtime.

 */

typedef struct {

  unsigned int keytype;        /* des or plain? */

  int length;                  /* number of characters in the password */

  char *contents;              /* points to the encrypted password */

} krb_key_t;

 

#endif

 

 

 


DCEUTIL Subproject

 

 

FILE:CLEANUP_.C

/*************************************************************************

 * DCE Function CLEANUP_USR:  CLEANUP_USR.C - Server Utility Function.

 *

 * Author:   G.K. Springer

 * Date:     March 1995

 * Node:     condor.cs.missouri.edu

 * Place:    Computer Science Department, University of Missouri-Columbia

 *

 * Purpose:  This is a utility function to allow user written code to be

 *           used in a standard server.  At the termination of a server's

 *           processing, a function named: cleanup() is executed to cause

 *           the server to unregister itself with the DCE Runtime Routines.

 *           Just prior to doing the unregister, a call is made to a

 *           function named: cleanup_user() to permit any user needed

 *           cleanup processing to be performed.  A single parameter which

 *           is the signal value that got the processing into the cleanup()

 *           routine in the first place. 

 *

 * Function: This routine is called by cleanup() in the DCE server module

 *           (include file: srvcln.h).  This routine simply returns to

 *           the cleanup() routine to unregister the server.  If a user

 *           desires to perform some specific cleanup function, a routine

 *           with this function name needs to be included in the code used

 *           when linking the server module.  This routine only serves to

 *           avoid unresolved reference when no special cleanup is needed.

 *

 *

 * Syntax: This program is invoked with the function call:

 *            cleanup_usr(signo);

 *

 * Change Log:

 *

 *************************************************************************/

 

void

cleanup_usr(int signo)

{                          /* User cleanup routine */

   /*

    * This routine does nothing but return control to caller.

    *

    * Input arg is the signal that got to the cleanup() routine

    *

    * Perform any desired processing needed to cleanup server environment

    * before unregistering and shutting down the server

    */

   return;                 /* return to cleanup() to finish server

                            * unregistering */

}                          /* End of cleanup_usr() routine. */

 


FILE:EP_RETAI.C

 

                       /* file name : ep_retain.c  */

#include <stdio.h>

#include <dce/rpc.h>

#include <dce/dce_error.h>

#include <errno.h>

#include <stdlib.h>

 

#ifdef WIN32

#include <winsock.h>

#else

#include <netinet/in.h>                /* for inet_addr() */

#include <arpa/inet.h>

#include <netdb.h>                     /* for gethostbyname_r() */

#endif

 

#include <dceconfig.h>   /* our local dce configuration file */

 

#ifndef  INADDR_NONE

#  define   INADDR_NONE 0xffffffff

#endif

 

 

extern   char  *pnm;

 

void  ep_retain(

   rpc_binding_vector_t **abvec,       /* binding vector returned */

   unsigned_char_t      *retain_addr,  /* address to retain */

   unsigned32           *st)           /* return status  */

{

rpc_binding_vector_t *bvec,*bvec1;    /* binding vectors */

rpc_binding_handle_t *abinding;        /* and binding handle */

unsigned_char_t   *str_binding,        /* string binding returned */

                  *network_addr;       /* network address returned after */

                                       /* parsing.  */

char  *the_ip_addr;                    /* ip address to retain */

#if defined(LIMITADDR)

struct   in_addr        *net_addr;     /* an internet ...address */

struct   hostent     *ahptr;           /* a ptr */

struct   hostent     ahp;              /* for gethostbyname_r() */

struct   hostent_data   ahd;           /* for gethostbyname_r() */

char  msg[144];

int   vector_cnt,i;                    /* size of bind vector  */

unsigned32 err=rpc_s_ok;               /* assume no error initially */

 

/*

 * Check if we have been given a dotted address, or symbolic name.

 */

 

#ifdef DEBUG

   sprintf(msg,"%s(ep_retain): Entered",pnm); tmsg(msg);

   sprintf(msg,"%s(ep_retain): retain %s",pnm,retain_addr); tmsg(msg);

#endif

   *abvec=NULL;  /* preset for a null binding vector structure */

  

   if (inet_addr((char *)retain_addr) == INADDR_NONE) { /* not dotted */

      memset((char *)&ahd,0,sizeof(struct hostent_data)); /* zero fill  */

      memset((char *)&ahp,0,sizeof(struct hostent)); /* zero fill  */

        if(ahptr=gethostbyname((char  *)retain_addr)) {

            net_addr=(struct in_addr *)ahptr->h_addr;

         the_ip_addr=inet_ntoa(*net_addr); /*dotted addr in string form */

      } else {  /* been an error. Shouldn't happen 'cause we are looking */

                /* up our m/c's address and not a remote m/c. */

         sprintf(msg,"%s:gethostbyname_r():%s",pnm,strerror(errno));

         tmsg(msg); *st=errno;         /* save the errno */

         return;

      }

   } else {                             /* it is a dotted address */

      the_ip_addr= (char *)retain_addr; /* point to it */

   }

 

#ifdef DEBUG

   sprintf(msg,"%s(ep_retain): Address to retain:%s",pnm,the_ip_addr);

   tmsg(msg);

#endif

 

/*

 * Sift through the binding vectors, and retain only those vectors that

 * contain the address passed. The address is the ip-address.

 */

 

   rpc_server_inq_bindings(&bvec,st);

   if (*st != rpc_s_ok) {

      sprintf(msg,"%s(ep_retain): Can't inquire server bindings\n\t%s",

                     pnm,dcemsg(*st));

      tmsg(msg);

      return;

      }

   /*

    * Now, scan the binding vector, and remove those entries that do not

    * have the address passed to us.

    * Parse the binding handle and extract the ip-address.

    */

   vector_cnt=0;                       /* initialize */

   for(i=0;i<bvec->count;i++) {

      rpc_binding_to_string_binding(bvec->binding_h[i],&str_binding,st);

      if (*st!=rpc_s_ok) {

         sprintf(msg,

            "%s(ep_retain): Cannot convert binding handle to string [%d]\n\t%s",

            pnm,dcemsg(*st),i);

         tmsg(msg); err=*st;

         continue;                     /* try the next one   */

         }

      /* Extract the ip-address from  this binding handle */

      rpc_string_binding_parse(

         str_binding,

         NULL,                         /* no obj uuid required */

         NULL,                         /* no need for prot seq */

         &network_addr,                /* want the network addr */

         NULL,                         /* no endpoint required */

         NULL,                         /* no need for network options. */

         st);                          /* status */

      if (*st !=rpc_s_ok) {

         sprintf(msg,

            "%s(ep_retain): Cannot parse string binding\n\t%s",pnm,dcemsg(*st));

         tmsg(msg); err=*st;

         continue;                     /* will skip the rest */

         }

#ifdef DEBUG

   sprintf(msg,"%s(ep_retain): %d:Extracted ip_addr:%s",pnm,i,network_addr);

   tmsg(msg); 

#endif

 

      if (strcmp(network_addr,the_ip_addr) != 0 ) {

         /* get rid of this  binding handle */

         rpc_binding_free(&bvec->binding_h[i],st);

         if (*st!=rpc_s_ok) {

            sprintf(msg,"%s(ep_retain): Cannot free binding handle:\n\t%s",

                           pnm,dcemsg(*st));

            tmsg(msg);

            err=*st;

            }   

#ifdef DEBUG

         else {

            sprintf(msg,"%s(ep_retain): Removed binding handle %d",

                    pnm, i);

            tmsg(msg);  

            }

#endif

         } /* if get_rid_of */

      else  {

         vector_cnt++;                 /* keep track of how many */

         }  /* end else netaddr */

 

      /* Still need to free the strings returned by the other routines. */

      rpc_string_free(&network_addr,st);

      if (*st != rpc_s_ok) {

         sprintf(msg,"%s:rpc_string_free():%s",pnm,dcemsg(*st));

         tmsg(msg); err=*st;

         continue;

      }

      rpc_string_free(&str_binding,st);

      if (*st != rpc_s_ok) {

         sprintf(msg,"%s:rpc_string_free():%s",pnm,dcemsg(*st));

         tmsg(msg);err=*st;

         continue;

      }          

   } /* For() */

 

   /*

    * Create a new binding vector, that does not contain the entries removed.

    * Copy only the non-null entries.

    */

#ifdef DEBUG

   sprintf(msg,"%s(ep_retain): size of binding vector:%d",pnm,vector_cnt);

   tmsg(msg);

#endif

  

   i=vector_cnt;

    

   bvec1=(rpc_binding_vector_t *)malloc(sizeof(rpc_binding_vector_t)*i);

   if (bvec1==(rpc_binding_vector_t *)NULL) { /* malloc failed */

      sprintf(msg,"%s(ep_retain): malloc failed: %s",pnm,strerror(errno));

      tmsg(msg);

      *st=errno;

      return;

   }

#ifdef DEBUG

   else  {

      sprintf(msg,"%s(ep_retain): malloc done:",pnm);tmsg(msg);

      }

#endif

 

   bvec1->count=i;                     /* # of binding handles in new vector */

   vector_cnt=0;                       /* index for the vector to construct */

   for (i=0;i<bvec->count;i++) {       /* traverse the old vector  */

      if (bvec->binding_h[i]) {        /* not been removed */

         rpc_binding_copy(bvec->binding_h[i], /* so copy from source... */

                       &(bvec1->binding_h[vector_cnt++]), /* to destination */

                       st);         /* status */

         if (*st!=rpc_s_ok) {

            sprintf(msg,"%s(ep_retain): Failed to copy binding handle\n\t%s",

                           pnm,dcemsg(*st));

            tmsg(msg);

            break;                     /* leave the for loop */

            }

#ifdef DEBUG

         else {

            sprintf(msg,"%s(ep_retain): did handle copy for %d",

                    pnm, i);

            tmsg(msg);

            }

#endif

         } /* if bvec */

      } /* for() */

 

   /*

    * return a copy of the newly constructed binding vector.

    */

   if (vector_cnt == bvec1->count)     /* should match */

      *abvec=bvec1;                    /* return the newly created vector */

   else  {                             /* some error occured */

      *abvec=NULL;                     /* will get nothing! */

      sprintf(msg,"%s:Copy failed: bvect1->cnt=%d, vec_cnt=%d",

                     pnm,bvec1->count,vector_cnt);

      tmsg(msg);

      }

 

   /* Can get rid of the orignal binding vector now. */

   rpc_binding_vector_free(&bvec,st);

   if (*st!=rpc_s_ok) {

      sprintf(msg,

         "%s(ep_retain): Warning:Couldn't free a binding vector:\n\t%s",

                  pnm,dcemsg(*st));

      tmsg(msg);

      } 

#else

   char  msg[144];

 

/* This routine is null on all systems we don't want to limit the DCE

   registration addresses for.  Just return the binding vector that has

   been registered on this system.

 */

 

/*

 * Get current binding vector, and return it to the caller.

 */

   rpc_server_inq_bindings(&bvec,st);

   if (*st != rpc_s_ok) {

      sprintf(msg,"%s(ep_retain): Can't inquire server bindings\n\t%s",

                     pnm,dcemsg(*st));

      tmsg(msg);

      *abvec=NULL;  /* return a null binding vector structure */

      }

   else

      *abvec = bvec;  /* this is the full binding vector */

#endif

 

#ifdef DEBUG

   sprintf(msg,"%s(ep_retain): Returning",pnm); tmsg(msg);

#endif

   return;                             /* and return */

} /* end ep_retain */

 

 


FILE:MAKEFILE

############################################################################

# Makefile for MU Utility Functions for DCE server programs

#

# Author:   G.K. Springer at U of MO - Columbia

# Date:     February 13, 1994

# Node:     condor.cs.missouri.edu

# Place:    Computer Science Department, University of Missouri-Columbia

#

# Purpose:  Create DCE authentication functions for servers to get their

#           DCE authentication tickets and to refresh their credentials

#           prior to them expiring.

#

# Function: Authentication occurs via the creation of an internal function

#           to request an authentication ticket and to refresh the ticket

#           prior to its expiration.  Just the authentication processing

#           is done via a request from a server routine. 

#           This code also includes an encryption and decryption routine

#           so the principle's password can be stored on disk as an

#           encrypted string.  If the server starts with stdin pointed to

#           a terminal, the user will be prompted for the principle's

#           password.  If stdin is a file, the first file line will be read

#           and decrypted and this decrypted string will be passed to the

#           authentication as the principle's password.

#

#

# Update Log:

#  02/13/94 - Created the authentication functions.

#

#             For example: make  alpha     builds entire system on alpha

#                          make  alpha MK=clean     cleans up after build

#                          make  cray  MK=all       builds all items on cray

#

############################################################################

 

############################################################################

## This is a heuristic to make sure that WIN32 is set when building on NT ##

!ifdef CPU

WIN32=1

!endif

############################################################################

 

 

############################################################################

## This is necessary to set specific flags for PC environments            ##

!ifdef WIN32

CFLAGS=/c /Dwin32=1 /GX /I. /I.. /I..\..\include /I..\..\logger -D_X86_=1 -G3 -Gz -DDCENT -Didl_char=char -D_MSDOS -DEP -DWIN32=1 /nologo /Zp1

 

!      ifdef DEBUG

CFLAGS=$(CFLAGS) -DDEBUG -Od -Zi

!      endif

 

!      ifdef NOCERT

CFLAGS=$(CFLAGS) -DNOCERT

!      endif

 

!      ifdef NODAEMON

CFLAGS=$(CFLAGS) -DNODAEMON

!      endif

 

!      ifdef JIMR_TEST_EXPIRATION

CFLAGS=$(CFLAGS) -DJIMR_TEST_EXPIRATION=1      

!      endif

 

!endif

############################################################################

 

 

default:

       @echo.

       @echo Making MU Utility Functions

       @echo.

       @echo No system specified for the make.

       @echo.

       @echo Usage:  make  sysname  [MK=components_to_build]

       @echo where:

       @echo sysname is one of [ alpha cray mips rs6000 win32 ]

       @echo.

 

# Make the code on ALPHA platforms

alpha: Makefile.utilfns

       @echo Cannot build $(@B) due to makefile incompatibilities.

 

# Make the code on Cray C90 at PSC

cray:  Makefile.utilfns

       @echo Cannot build $(@B) due to makefile incompatibilities.

 

# Make the code on HPUX platforms

hpux:  Makefile.utilfns

       @echo Cannot build $(@B) due to makefile incompatibilities.

 

# Make the code on RS6000

rs6000:       Makefile.utilfns

       @echo Cannot build $(@B) due to makefile incompatibilities.

 

 

# Make the code on WIN32 platforms

WIN32: Makefile.uti

       @tm start

       @echo .

       @echo Build MU DCE Authentication Services on $(COMPUTERNAME) - WIN32

       @if not exist build.win md build.win

       @if not exist ..\build.wbn md ..\build.wbn

       @cd build.win

       $(MAKE) /nologo -f ..\makefile.uti \

      WIN32=1 \

      TSRC=.. \

      T1=..\..\build.wbn \

      IDL=idl \

          IDLFLAGS= \

              CFLAGS="$(CFLAGS)" \

              LINKFLGS= \

      LIBS="pthreads.lib libdce.lib wsock32.lib" \

      LIB2= \

      GENSYS=WIN32

       @echo Build on $(COMPUTERNAME) complete

       @tm stop

 

.DEFAULT:

       @echo defaulting on "$@"  - don't know how to build it.

 

 


FILE:MAKEFILE.UTI

# Makefile to build the encryption and decryption utility functions

OBJF   = mulogin.obj simdecry.obj cleanup_.obj ep_retai.obj

 

all:   simdecry.obj mulogin.obj cleanup_.obj ep_retai.obj $(T1)/mutl.lib

 

simdecry.obj: $(TSRC)/simcry.h $(TSRC)/simdecry.c

       $(CC) $(CFLAGS) $(TSRC)/simdecry.c

 

mulogin.obj:  $(TSRC)/mulogin.h $(TSRC)/mulogin.c

       $(CC) $(CFLAGS) $(TSRC)/mulogin.c

 

ep_retai.obj: $(TSRC)/ep_retai.c $(TSRC)/../include/dceconfig.h

       $(CC) $(CFLAGS) $(TSRC)/ep_retai.c

 

cleanup_.obj: $(TSRC)/cleanup_.c

       $(CC) $(CFLAGS) $(TSRC)/cleanup_.c

 

#################################################################

# Make the MU Utility Library for users to link with their code

#################################################################

$(T1)/mutl.lib:      $(OBJF)

       @echo .

       @echo Create the MUTL subroutine library

       lib /OUT:$(T1)\mutl.lib $(OBJF)

#      lorder $(OBJF) | tsort | xargs ar crv $(T1)/mutl.a

#      chmod 640 $(T1)/mutl.a

 

#################################################################

# Cleanup files after build, including possibly the code modules

#################################################################

clean:

       @echo

       @echo Cleanup the dce utility directory

       @del mulogin.obj cleanup_.obj ep_retai.obj $(T1)/mutl.lib

 

 


FILE:MULOGIN.C

 

/*****************************************************************************

 * mulogin.c

 *

 * This module contains the code for obtaining and maintaining the

 * server's secret key.  This key is used to establish and refresh the

 * user's credentials and also to supply the key on demand when the RPC

 * runtime needs to decrypt an authenticated client request.

 *

 * The user is prompted to type in the server's secret key.  The key is

 * then encrypted and stored in memory.  This code does not depend on

 * the existence of a particular keytab file to hold the secret key.

 *****************************************************************************/

 

#include <pthread.h>       /* needed for refresh_context

                            * declaration */

#include <time.h>

#include <stdio.h>

#include <string.h>

 

#ifndef WIN32

#include <termios.h>

#include <unistd.h>

#else

#include <io.h>

#endif

 

#include <errno.h>

 

#include <dce/rpc.h>

#include <dce/sec_login.h>

#include <dce/dce_error.h>

#include "mulogin.h"

 

#define TRUE 1

#define FALSE 0

 

/*

 * these variables and functions are global and defined in server

 * main()

 */

extern char    *pnm;

extern char     msg[144];

extern void     tmsg();

extern char    *dcemsg();

 

void            terminate_thread();

 

/* these variables are global and private to this module */

static sec_passwd_rec_t *master_passwd;

static sec_passwd_rec_t passwd;

static sec_login_handle_t login_context;

 

/* these are forward declarations for routines private to this module */

static void     read_password();

static void     refresh_login_context();

static void     turn_echo_off();

static void     turn_echo_on();

static void

get_encrypted_password(char *, error_status_t *);

static char     sprincipal[64];

 

static void     get_password();

 

 

/*

 * Create a new login context for this server using the server's

 * principal name and secret key.  As a result, the server will obtain

 * credentials that can be used when acting as a client to another

 * server (such as the security server itself) requiring authenticated

 * access.

 */

void

mulogin(char *principal)

{

   error_status_t  st;

   boolean32       reset_passwd = 0;

   sec_login_auth_src_t auth_src;

   boolean32       authenticated = FALSE;

   boolean32       certchk;

 

 

   /* Establish the name of the server principal for this run */

   strcpy(sprincipal, principal); /* save server principal's name */

 

   /*

    * initialize the login context.  It retrieves sealed credentials

    * that have not yet been encrypted in the server principal's

    * password.

    */

   if (!sec_login_setup_identity(

               (unsigned_char_p_t) sprincipal,  /* principal name */

               sec_login_no_flags, /* allow credentials to

                                   * be inherited by child

                                   * processes */

               &login_context,     /* get a handle to the

                                   * login context */

               &st)) {      /* status code */

      sprintf(msg,

          "%s(login): sec_login_setup_identity failed\n\ts=%08x\t%s",

             pnm, st, dcemsg(st));

      tmsg(msg);

      exit(1);

   }

#ifdef DEBUG

   else {

      sprintf(msg, "%s(login): sec_login_setup_identity succeeded",

             pnm);

      tmsg(msg);

   }

#endif

 

   while (!authenticated) {

 

#ifdef DEBUG

      sprintf(msg, "%s(login): call read_passwd", pnm);

      tmsg(msg);

#endif

      read_password();            /* get the server's secret key */

 

      /*

       * validate the credentials obtained in the

       * sec_login_setup_identity called above.  We pass the passwd

       * structure because this routine will overwrite the password

       * with NULLs.  However, we need to remember the key in order to

       * refresh credentials right before they expire.

       */

#ifdef DEBUG

      sprintf(msg, "%s(login): call validate_id", pnm);

      tmsg(msg);

#endif

      sec_login_validate_identity(

                login_context,     /* handle to login

                                   * context */

                &passwd,    /* supply the server's

                            * secret key which we

                            * obtained from the

                            * user */

                &reset_passwd,     /* gets back an

                                   * indication of whether

                                   * or not the password

                                   * has changed since

                                   * last validation. */

                &auth_src,  /* gets back the

                            * authority that

                            * validated the the

                            * credentials: network

                            * or local */

                &st);

 

      if (st != error_status_ok) {

        if (st == sec_rgy_passwd_invalid) {

           printf("Password invalid.\n");

           continue;

        } else {

           sprintf(msg,

              "%s(login): sec_login_validate_identity failed\n\ts=%08x\t%s",

              pnm, st, dcemsg(st));

           tmsg(msg);

           exit(1);

        }

      } else {

        /*

         * if sec_login_validate_identity succeeds, then the user

         * supplied a valid password.  No need to continue prompting.

         */

        authenticated = TRUE;

#ifdef DEBUG

        sprintf(msg,

         "%s(login): validate_identity succeeded\n\tauth=%d\ts=%08x",

               pnm, auth_src, st);

        tmsg(msg);

#endif

      }

 

      /* make sure that the authentication service is not an impostor */

#ifdef DEBUG

      sprintf(msg, "%s(login): call certify_id", pnm);

      tmsg(msg);

#endif

      certchk = sec_login_certify_identity(login_context, &st);

#ifdef DEBUG

      sprintf(msg, "%s(login): Back from certify_id\n\tcert=%d\tst=%08x",

             pnm, certchk, st);

      tmsg(msg);

#endif

      if (st != rpc_s_ok) {

        sprintf(msg,

        "%s(login): sec_login_certify_identity failed\n\ts=%08x\t%s",

               pnm, st, dcemsg(st));

        tmsg(msg);

      }

#ifdef DEBUG

      else {

        sprintf(msg,

             "%s(login): sec_login_certify_identity succeeded", pnm);

        tmsg(msg);

      }

#endif

 

      /*

       * Establish this new login context as the current context.  If

       * the server was started by an authenticated user, these new

       * credentials will be used in place of the credentials inherited

       * from the user.

       */

#ifdef DEBUG

      sprintf(msg, "%s(login): call set_context", pnm);

      tmsg(msg);

#endif

      sec_login_set_context(login_context, &st);

      if (st != rpc_s_ok) {

        sprintf(msg,

             "%s(login): sec_login_set_context failed\n\ts=%08x\t%s",

               pnm, st, dcemsg(st));

        tmsg(msg);

        exit(1);

      }

#ifdef DEBUG

      else {

        sprintf(msg,

               "%s(login): sec_login_set_context succeeded", pnm);

        tmsg(msg);

      }

#endif

   }                       /* while */

}

 

 

/*

 * refresh_context is the routine where the refresh_thread will

 * execute. It is responsible for keeping the server's credentials

 * valid.  It finds out when the credentials are due to expire, then

 * goes to sleep.  It wakes up about ten minutes before the credentials

 * are due to expire and attempts to refresh them using the secret key

 * stored at startup time.  If the secret key for this server has

 * changed in the registry database while this server has been running,

 * the refresh operation will fail.

 */

 

pthread_addr_t

refresh_context()

{

   signed32        expiration;    /* absolute time in seconds of

                            * expiration */

   error_status_t  st;            /* status codes */

   time_t          now;           /* current time of day */

   int             seconds; /* number of seconds until expiration */

   int             ten_minutes = 10 * 60;       /* number of seconds in

                                          * ten minutes */

   struct timespec ts;            /* for time manipulation */

 

 

   while (1) {

#ifdef DEBUG

      sprintf(msg, "%s(refresh): call get_expiration", pnm);

      tmsg(msg);

#endif

      sec_login_set_context(login_context, &st);

      /* get the absolute expiration time expressed in seconds */

      sec_login_get_expiration(login_context, &expiration, &st);

      if (st != rpc_s_ok) {

        sprintf(msg,

        "%s(refresh): sec_login_get_expiration failed\n\ts=%08x\t%s",

               pnm, st, dcemsg(st));

        tmsg(msg);

        terminate_thread();

      }                           /* end if get_expiration */

      /*

       * a Since the sleeping time is approximate, and system clocks

       * can drift and be corrected by DTS, we recheck the time of day

       * up front after waking up.  In most cases, we'll only sleep

       * once and when we wake up, it will be time to refresh the

       * context.

       */

      while (1) {

        time(&now);

 

#ifdef DEBUG

       #ifdef JIMR_TEST_EXPIRATION

       expiration=now+ten_minutes; // expire in 10 minutes

       #endif

#endif

 

        seconds = expiration - now;      /* compute the number of

                                   * seconds until the

                                   * credentials expire */

#ifdef DEBUG

        sprintf(msg, "%s(refresh): calc expire\n\tsecs=%d  expire=%d  now=%d",

               pnm, seconds, expiration, now);

        tmsg(msg);

#endif

 

        if (seconds <= ten_minutes) {    /* are we within 10 minutes? */

           sprintf(msg, "%s(refresh): refreshing credentials", pnm);

           tmsg(msg);

           refresh_login_context();      /* refresh the credentials */

#ifdef DEBUG

           sprintf(msg, "%s(refresh): back from refresh_login_context", pnm);

           tmsg(msg);

#endif

           break;

        } else

           ts.tv_sec = seconds - ten_minutes;

        ts.tv_nsec = 0;

#ifdef DEBUG

        sprintf(msg, "%s(refresh): call delay_np %d",

               pnm, ts.tv_sec);

        tmsg(msg);

#endif

        pthread_delay_np(&ts);    /* this thread should sleep until it is

                            * time to refresh the context */

#ifdef DEBUG

        sprintf(msg, "%s(refresh): return from delay_np %d",

               pnm, ts.tv_sec);

        tmsg(msg);

#endif

      }                           /* end inner while loop */

   }                       /* end outer while loop */

}                          /* end refresh_context() */

 

 

/*

 * This alternate key retrieval function grabs the secret key from

 * where it is stored in memory.  No need to look in a file.  This

 * routine is called during the rpc_server_register_auth_info and

 * everytime an authenticated client request is received.  The RPC

 * runtime uses the key this routine provides to decrypt the client

 * message.

 *

 * The interface to key_retrieval_function is standard.  It is described

 * in the DCE reference manual under

 * rpc_server_register_auth_info(3rpc). The standard arguments are

 * intended to be used to select the proper key from a list of keys

 * such as might be found in a keytab file.  Since we only store one

 * key, we don't need to use the arguments provided.  The DCE1.0

 * documentation does not describe the structure of the key that the

 * RPC runtime expects.  That structure is not currently exported to

 * the programmer.  As a workaround, we create a structure of the

 * correct size and field names. If the internal implementation

 * changes, this code will break.

 */

 

void key_retrieval_function(

       void *arg,    /* argument to this function:

                      * not used */

       unsigned_char_t * server_princ_name,     /* server principal

                                          * name: not used */

       unsigned32 key_type, /* des or plain? not

                            * used */

       unsigned32 key_ver, /* version number: not

                             * used */

       void **key,   /* pointer to a structure

                      * holding the secret key */

       unsigned32 * status)

{

 

   krb_key_t      *ourkey; /* krb_key_t resembles the key

                            * structure expected by the rpc

                            * runtime. */

 

   ourkey = (krb_key_t *) malloc(sizeof(krb_key_t));

   if (ourkey == NULL) {

      sprintf(msg, "%s(keyret): malloc failed errno=%d - exiting",

             pnm, errno);

      tmsg(msg);

      terminate_thread();

      }

   ourkey->keytype = (unsigned int) master_passwd->key.key_type;

   ourkey->length = sizeof(sec_passwd_des_key_t);

   ourkey->contents = (char *) malloc(ourkey->length);

   if (ourkey->contents == NULL) {

      sprintf(msg, "%s(keyret): malloc failed errno=%d - exiting",

             pnm, errno);

      tmsg(msg);

      terminate_thread();

      }

   strncpy((char *) ourkey->contents,

          (char *) master_passwd->key.tagged_union.des_key,

          ourkey->length);

 

   *key = (void *) ourkey;

   *status = error_status_ok;

#ifdef DEBUG

   sprintf(msg, "%s(keyret): key retrieval succeeded", pnm);

   tmsg(msg);

#endif

}

 

 

/*

 * read_password prompts the user for the server's secret key rather

 * than looking in a keytab file.  This routine is called once on

 * startup, so only an administrator who knows the password may start

 * this program.

 */

 

static void read_password()

{

   static int      num_tries;

 

   char            buf[100];      /* store the cleartext password */

   char           *returnptr;     /* result of gets */

   boolean32       good_password = FALSE;       /* return when

                                          * good_password = TRUE */

   error_status_t  st;            /* status codes */

   int             termstat;      /* =1 if stdin is a terminal */

       #ifdef WIN32

       char                       *szPasswordFile;

       #endif

 

#ifdef DEBUG

   sprintf(msg, "%s(readpw): Entered", pnm);

   tmsg(msg);

#endif

   termstat = isatty(0);   /* determine if stdin is a terminal */

 

       /****************************************************************/

       /* This hack is necessary if we are running as a service, since */

       /* isatty() erroneously reports that stdin is a terminal.       */

       #ifndef NODAEMON

       #ifdef WIN32

              termstat=0;

       #endif /* WIN32 */

       #endif /* NODAEMON */

       /****************************************************************/

 

   while ((!good_password) && (num_tries < 3)) {

      if (termstat) {             /* stdin is a terminal - so prompt user */

        printf("Enter password for %s: ", sprincipal);

        setbuf(stdin, NULL);      /* turn off buffering to avoid having a

                            * cleartext password in a libc buffer. */

        turn_echo_off();    /* set the terminal so that the

                            * password will not appear on the

                            * screen as the user types it */

         *buf = '\0';  /* make sure we have an empty buffer */

        returnptr = gets(buf);    /* get clear text password from the

                            * user */

        turn_echo_on();     /* reset the terminal back to normal */

        printf("\n");

      } else {

        num_tries = 2;

         *buf = '\0';  /* make sure we have an empty buffer */

 

        /*************************************************************/

    /* Since we will not be able to redirect stdin for a service */

        /* under WIN32, we will need to programmatically redirect it */

        /* to a file defined by an environment variable.  Since we   */

        /* may be testing by normal redirection, we will accept stdin*/

        /* as is, if there is no environment variable set.           */

        /*************************************************************/

    #ifdef WIN32

        szPasswordFile=getenv("PASSWORD_FILE");

 

        /* PROBLEM! - This is just a test to see if I can force this thing */

        if (szPasswordFile==NULL)

              szPasswordFile="D:\\thesis\\PASSWORD.FIL";

 

        if (szPasswordFile==NULL)

        {

              #ifdef DEBUG

              sprintf(msg, "%s(readpw): PASSWORD_FILE env variable not found.", pnm);

              tmsg(msg);

              #endif

        }

        else

        {

               if ((freopen(szPasswordFile, "r", stdin) == NULL))

           {

                     printf("*** Unable to redirect stdin to get principal password ***\n");

           }

        }

        /* Rather than exiting here, just let the password fail.     */

        #endif

        /*************************************************************/

 

 

        returnptr = gets(buf);

        if ((returnptr != NULL) && (strlen(buf) > 0)) {

           simdecry(buf);

            }

         }

 

      if ((returnptr != NULL) && (strlen(buf) > 0)) {  /* if gets succeeded */

        /*

         * initialize the password structure that must be passed to

         * establish a login context.  Loads the master_passwd global

         * variable.

         */

        get_encrypted_password(buf, &st);

        memset(buf, ' ', sizeof(buf));   /* blank out the cleartext

                                   * password */

        if (st == error_status_ok)

           good_password = TRUE;  /* just means that gets

                                   * returned a non-zero length

                                   * string */

      } /* gets succeeded */

      else { }  /* else gets failed */

#ifdef DEBUG

      sprintf(msg, "%s(readpw): pswd check = %d", pnm, good_password);

      tmsg(msg);

#endif

      ++num_tries;

   }                       /* end while */

   if (good_password) {

      /*

       * copy information from the master passwd into the structure

       * that will be supplied to the security api.

       */

      passwd.key.key_type = sec_passwd_des;

      passwd.pepper = NULL;

      passwd.version_number = master_passwd->version_number;

      get_password();             /* load the secret key itself */

#ifdef DEBUG

      sprintf(msg, "%s(readpw): Authenticated password success", pnm);

      tmsg(msg);

#endif

   } else {

      sprintf(msg,

        "%s(readpw): Invalid authentication password; Exiting", pnm);

      tmsg(msg);

      exit(1);

   }

#ifdef DEBUG

   sprintf(msg, "%s(readpw): Exiting", pnm);

   tmsg(msg);

#endif

}                          /* end read_password */

 

 

/*

 * get_password copies the contents of the master password structure

 * into a passwd structure that can be overwritten.  We must maintain

 * the master copy of the password structure because it contains our

 * only record of the server's secret key.

 */

 

static void

get_password()

{

   strncpy((char *) passwd.key.tagged_union.des_key,

          (char *) master_passwd->key.tagged_union.des_key,

          sizeof(sec_passwd_des_key_t));

}

 

 

/*

 * refresh_login_context refreshes the server's credentials.  We assume

 * that valid credentials are really needed throughout the run of the

 * program.

 */

 

static void

refresh_login_context()

{

   error_status_t  st;

   boolean32       reset_passwd = 0;

   sec_login_auth_src_t auth_src;

   boolean32       certchk; /* return value from certification */

 

 

#ifdef DEBUG

   sprintf(msg, "%s(reflog): call refresh identity", pnm);

#endif

   sec_login_refresh_identity(login_context, &st);

   if (st != error_status_ok) {

      sprintf(msg,

       "%s(reflog): sec_login_refresh_identity failed\n\ts=%08x\t%s",

             pnm, st, dcemsg(st));

      tmsg(msg);

      terminate_thread();

   }

#ifdef DEBUG

   sprintf(msg, "%s(reflog): call get_password", pnm);

   tmsg(msg);

#endif

   get_password();         /* reload password structure from

                            * master copy */

 

#ifdef DEBUG

   sprintf(msg, "%s(reflog): call login_validate_identity", pnm);

   tmsg(msg);

#endif

   if ((!sec_login_validate_identity(

            login_context,  /* handle to the login context */

            &passwd,        /* holds the secret key */

            &reset_passwd,  /* returns whether or not the password has

                            * changed. */

            &auth_src,            /* authority that validated login

                            * context: local or network authority? */

            &st))           /* returned status code */

       ||(st != error_status_ok)) {

 

      sprintf(msg,

       "%s(reflog): sec_login_validate_identity failed\n\ts=%08x\t%s",

             pnm, st, dcemsg(st));

      tmsg(msg);

      terminate_thread();

   }

   sprintf(msg,

        "%s(reflog): validate_identity succeeded\n\tauth=%d\ts=%08x",

          pnm, auth_src, st);

   tmsg(msg);

 

#ifdef DEBUG

   sprintf(msg, "%s(reflog): call sec_login_certify_identity", pnm);

   tmsg(msg);

#endif

   certchk = sec_login_certify_identity(login_context, &st);

#ifdef DEBUG

   sprintf(msg,

          "%s(reflog): back from certify_identity\n\tcert=%d\ts=%08x",

          pnm, certchk, st);

   tmsg(msg);

#endif

   if (st != rpc_s_ok) {

      sprintf(msg,

       "%s(reflog): sec_login_certify_identity failed\n\ts=%08x\t%s",

             pnm, st, dcemsg(st));

      tmsg(msg);

      terminate_thread();

   }

#ifdef DEBUG

   sprintf(msg, "%s(reflog): returning from refresh context", pnm);

   tmsg(msg);

#endif

}

 

/*

 * When an API is provided for converting a plaintext password into an

 * encrypted password, this routine can be rewritten to take advantage

 * of the new API.  Depending on what the API is, this interface might

 * have to change and the calling code rewritten as well.  For now, we

 * use a workaround: we create a temporary keytab file with the

 * encrypted key.  This file exists just long enough to read back the

 * encrypted key.  The encrypted key is stored in memory and retrieved

 * for refreshing credentials and for decrypting authenticated client

 * requests.

 */

static void get_encrypted_password(

              char *buf,

              error_status_t *st)

{

   char            tempest[32];

   char           *tempfilename;

   unsigned32     tstat;

   sec_passwd_rec_t key;

 

       #ifdef WIN32

       char                       szWin32FileName[MAX_PATH];

       #endif

 

#ifdef DEBUG

   sprintf(msg, "%s(getpwd): Entered", pnm);

   tmsg(msg);

#endif

   *st = error_status_ok;

 

   /*

    * create a temporary keytab filename.  A file by this name will be

    * created by sec_key_mgmt_set_key.  This function is not reentrant. 

    */

   tempfilename = tempnam("/tmp", pnm);

 

       #ifdef WIN32

       /* JimR Note - We should probably always free the tempfilename */

       /* that is returned by tempnam on any platform.  Otherwise,    */

       /* we will have memory leaks.  Not a big deal, since it occurs */

       /* no more than 3 times (3 password tries).                    */

 

       /* Save the allocated file name */

       strcpy(szWin32FileName,tempfilename);

 

       /* Free the allocated buffer */

       free(tempfilename);

 

       /* We need to get rid of drive letters if we are in WIN32 since */

       /* they will be seen as key type specifiers, e.g., FILE:        */

       tempfilename=strchr(szWin32FileName,':');

 

       /* If there was no drive letter in the temp name, use full name */

       /* Otherwise, move past the colon.                              */

       if (tempfilename==NULL)

              tempfilename=szWin32FileName;

       else

              tempfilename++;

 

       #ifdef DEBUG

       sprintf(msg, "%s(get_encrypted_password): tempfilename=%s", pnm, tempfilename);

       tmsg(msg);

       #endif /* DEBUG */

 

       #endif /* WIN32 */

 

   /*

    * initialize the key structure that will be used to construct the

    * encrypted password that will be written to the keytab file

    */

   key.version_number = 1;

   key.key.key_type = sec_passwd_plain;

   key.key.tagged_union.plain = (unsigned char *) buf;

 

   /* write the password into the temporary keytab file */

   sec_key_mgmt_set_key(rpc_c_authn_dce_secret,

              tempfilename, /* keytab file */

              sprincipal,

              1,     /* version number */

              &key,  /* cleartext password */

              &tstat);

   if (tstat != error_status_ok) {

      sprintf(msg,

             "%s(getpwd): sec_key_mgmt_set_key failed\n\trc=%08x  %s",

              pnm, tstat, dcemsg(tstat));

      tmsg(msg);

      unlink(tempfilename); /* get rid of temporary keytab file */

      *st = tstat;

#ifdef DEBUG

      sprintf(msg, "%s(getpwd): Exiting", pnm);

      tmsg(msg);

#endif

      return;                   /* return with unsuccessful status */

   }

   /*

    * Now read back the encrypted password from the same keytab file

    * just created above

    */

   sec_key_mgmt_get_key(rpc_c_authn_dce_secret,

              tempfilename,

              sprincipal,

              1,

              &master_passwd,      /* encrypted password */

              &tstat);

   if (tstat != error_status_ok) {

      sprintf(msg,

             "%s(getpwd): sec_key_mgmt_get_key failed\n\trc=%08x  %s",

              pnm, tstat, dcemsg(tstat));

      tmsg(msg);

      unlink(tempfilename); /* get rid of temporary keytab file */

      *st = tstat;

#ifdef DEBUG

   sprintf(msg, "%s(getpwd): Exiting", pnm);

   tmsg(msg);

#endif

      return;                   /* return with unsuccessful status */

   }

   /*

    * The tempfilename could be overwritten with null words to assure

    * the disk copy does not have the encrypted master_passwd in it.

    */

   unlink(tempfilename);   /* get rid of temporary keytab file */

#ifdef DEBUG

   sprintf(msg, "%s(getpwd): get encrypted password success", pnm);

   tmsg(msg);

#endif

#ifdef DEBUG

   sprintf(msg, "%s(getpwd): Exiting", pnm);

   tmsg(msg);

#endif

 

}

 

#ifndef WIN32

/*

 * Terminal IO state information shared between turn_echo_off and

 * turn_echo_on.

 */

static struct termios save_control;

#endif

 

static void turn_echo_off()

{

#ifndef WIN32

   struct termios  echo_control;

 

   if (tcgetattr(0, &echo_control) == -1) {

      printf("\n%s(turn_ecoff): tcgetattr failed\n", pnm);

      printf("Warning: your password will be visible\n");

      fflush(stdout);

   }

   save_control = echo_control;

   echo_control.c_lflag &= ~(ECHO | ECHONL);

 

   (void) tcsetattr(0, TCSANOW, &echo_control);

#endif

}

 

static void turn_echo_on()

{

#ifndef WIN32

   (void) tcsetattr(0, TCSANOW, &save_control);

#endif

}

 

 

/*

 * terminate_thread() -- Terminate the current thread.  This is called

 * in place of exit in any routines that could be called by manager

 * functions so the server process can clean up and exit without

 * leaving any orphaned clients.  If the server simply exits any other

 * manager threads would disappear, causing clients to timeout with a

 * partially executed request.

 */

void terminate_thread()

{

   error_status_t  st;            /* returned by DCE calls */

 

   sprintf(msg, "%s(term_thread): Terminating processing...", pnm);

   tmsg(msg);

 

   /*

    * Stop the server from listening for more requests, but let current

    * requests run to completion.

    */

   rpc_mgmt_stop_server_listening(NULL, &st);

   if (st != rpc_s_ok)

      sprintf(msg, "%s(term_thread): cannot stop server listening", pnm);

   else

      sprintf(msg, "%s(term_thread): stopped server listening", pnm);

   tmsg(msg);

 

   pthread_exit((pthread_addr_t) NULL);

}

 

 

 


FILE:MULOGIN.H

/*

 * For validating an authenticated user for credential renewal

 */

 

/* The login module exports these three interfaces */

void            mulogin();

pthread_addr_t  refresh_context();

//void            key_retrieval_function();

void key_retrieval_function(

       void *arg,    /* argument to this function:

                      * not used */

       unsigned_char_t * server_princ_name,     /* server principal

                                          * name: not used */

       unsigned32 key_type, /* des or plain? not

                            * used */

       unsigned32 key_ver, /* version number: not

                            * used */

       void **key,   /* pointer to a structure

                      * holding the secret key */

       unsigned32 * status);

 

/*

 * This krb_key_t structure is a workaround to a problem with the

 * definition of the key retrieval function in

 * rpc_server_register_auth_info(3rpc). The key structure is not

 * described nor exported to the programmer.  This structure resembles

 * the structure used internal to the security library, and for the

 * current implementation, works to supply a valid key to the RPC

 * runtime.

 */

typedef struct {

   unsigned int    keytype; /* des or plain? */

   int             length; /* number of characters in the password */

   char           *contents;      /* points to the encrypted password */

}               krb_key_t;

 


FILE:SIMCRY.H

void simcry(char *inbuf);

void simdecry(char *inbuf);

 

 


FILE:SIMDECRY.C

#include "simcry.h"

/*****************************************************************/

/* simdecry is a dummy function.  In the real version, we would  */

/* decrypt the buffer in place.  This empty function is included */

/* to avoid link errors in the non-encrypting version.           */

/*****************************************************************/

void simdecry(char *inbuf)

{

}


FINDEM Subproject

 

 

FILE:DCEMSG.C

/*************************************************************************

 * Utility Function:  dcemsg.c - Find DCE error messages in message table

 *

 * Author:   G.K. Springer

 * Date:     March 1993

 * Node:     condor.cs.missouri.edu

 * Place:    Computer Science Department, University of Missouri-Columbia

 *

 * Purpose:  Utility to get a DCE run-time error message from the message

 *           table and return the message string to the caller.

 *

 * Function: Convert DCE status code to a text string and place it in

 *           a string buffer to return to the caller.

 *

 * Syntax: This is a utility function called from an application:

 *            ptr = dcemsg(st);   where: st is a DCE status code to convert

 *         and ptr is the address of a text string returned to caller.

 *

 * Change Log:

 *

 *

 * Note:

 *  To get error messages an environment variable NLSPATH is required.

 *  Define it as:  setenv NLSPATH "/opt/dcelocal/nls/msg/en_US.88591/%N"

 *************************************************************************/

 

#include <stdio.h>

#include <dce/rpc.h>

#include <dce/dce_error.h>

 

char *dcemsg(unsigned32 st)

{

  int         err_st;   /*CRAY*/

  static char buff[dce_c_error_string_len];

 

  dce_error_inq_text(st, (unsigned char *)buff, &err_st);

  if (err_st != -1) return(buff);

  else  {

     if (st == 0xc038a0e0) 

        sprintf(buff, "(dce/rt) - Server not responding");

     else

        sprintf(buff, "(dce/rt) - No error text translation, st=%08x",st);

     return(buff);

     }

}  /* end dcemsg() */

 

 


FILE:FDUMMY.IDL

/*

 *   IDL definition for a dummy interface to be used by Findc 

 *

 *   Exports Functions: dummy1, dummy2 and dummy3

 *

 *  By: G.K. Springer - October 1993

 *  Modified:

 */

 

[

uuid(12345678-ac8d-11cc-89ce-08002b37598d),

version(1.0)

]

 

 

interface fdummy

{

/* Define Dummy1 Exported Function */

void dummy1(

    [in]  handle_t  h,    /* Communication Handle */

    [in]  long  a,        /* Parameter 1 */

    [in]  long  b,        /* Parameter 2 */

    [out] long  *c        /* Result to return */

    );

 

/* Define Dummy2 Exported Function */

void dummy2(

    [in]  handle_t  h,    /* Communication Handle */

    [in]  long  a,        /* Parameter 1 */

    [in]  long  b,        /* Parameter 2 */

    [out] long  *c        /* Result to return */

    );

 

/* Define Dummy3 Exported Function */

void dummy3(

    [in]  handle_t  h,    /* Communication Handle */

    [in]  long  a,        /* Parameter 1 */

    [in]  long  b,        /* Parameter 2 */

    [out] long  *c        /* Result to return */

    );

 

}  /* end fdummy idl */

 

 


FILE:FINDNAME.C

/****************************************************************************

 * FINDNAMES.C - Manager code for MU Nameservice Lookup on network.

 *

 * Author:   G.K. Springer

 * Date:     October 1993

 * Node:     condor.cs.missouri.edu

 * Location: Computer Science Department - MU, Columbia, MO.

 *

 * Purpose:  Use rpc call to get server registrations from remote cells.

 * Function: Lookup the servers registered in the network.  For each

 *           server found, convert registration to a fully-bound character

 *           string and return the set of registrations to the caller.

 *

 * Change Log:

 * 09/93 - GKS - Rewrite code for DCE Nameservice Lookup

 * 10/95 - GKS - remove conversion of Inet_addr to symbolic hostname format.

 *

 ****************************************************************************/

 

/*

/* Standard C Include files

 */

#include <stdio.h>

#include <signal.h>

 

#ifndef WIN32

#include <unistd.h>

#endif

 

#include <string.h>

#include <sys/types.h>

#include <time.h>

 

#ifdef WIN32

#include <winsock.h>

#else

#include <sys/socket.h>

#include <netinet/in.h>

#include <netdb.h>

#include <arpa/inet.h>

#endif

 

 

/*

 * DCE Definitions

 */

#include <dce/idlbase.h>

#include <dce/rpc.h>

#include <dce/nbase.h>

#include <dce/stubbase.h>

#include <dce/rpcexc.h>

#include <dce/uuid.h>

#include <dce/dce_error.h>  /* DCE error definitions */

 

 

/* Include DCE Application Definitions */

#include "finds.h"     /* IDL generated Interface definition */

#include "findsnms.h"  /* FindServer Name Strings */

#include "fdummy.h"    /* Dummy ifspec to modify */

#include "fdummy.c"    /* include our dummy interface */

 

void        tmsg();

static  char        msg[144];

static  int         findsnms();

static  unsigned32  convert_binding();

 

static  char *portnull = "NULL";

 

/************************************************************************

 * FINDNAMES -  Server Manager Code - DCE NameService Lookup on Remote

 ***********************************************************************/

rstring findnames

#ifdef IDL_PROTOTYPES

(

  /*  [in]  */ handle_t     h,

  /*  [in]  */ grpname      group_name,

  /*  [in]  */ objname      obj_str,

  /*  [in]  */ gks_ifnm     if_str,

  /*  [in]  */ unsigned32   max_entry,

  /*  [out] */ unsigned32   *num_entry,

  /*  [out] */ unsigned32   *stat

)

#else

(h, group_name, obj_str, if_str, max_entry, num_entry, names, st)

  /*  [in]  */ handle_t     h;

  /*  [in]  */ grpname      group_name;

  /*  [in]  */ objname      obj_str;

  /*  [in]  */ gks_ifnm     if_str;

  /*  [in]  */ unsigned32   max_entry;

  /*  [out] */ unsigned32   *num_entry;

  /*  [out] */ unsigned32   *stat;

#endif

{

   int                i,j,k;         /* Counters - temp */

   unsigned32         st;            /* Status of calls made */

   char               string[2048];

   char               strhandle[128]; /* holds string form of handles */

   rstring            names;

   char               tname[96];    

   rpc_binding_vector_t *results;

   uuid_t              myuuid;

       #ifdef WIN32

       RPC_CLIENT_INTERFACE *gks_ifspec;

       #else

   rpc_if_rep_t       *gks_ifspec;   /* pointer to ifspec */

       #endif

 

 

/************************************************************************

 *   Start of exported function

 ***********************************************************************/

   memset(string,0,sizeof(string));

   names = NULL;

 

       #ifdef WIN32

       gks_ifspec=(RPC_CLIENT_INTERFACE *)fdummy_v1_0_c_ifspec;

       memcpy( (char *) &(*gks_ifspec).InterfaceId, (char *) &if_str.id, sizeof(myuuid));

       #else

   gks_ifspec = (rpc_if_rep_t *) fdummy_v1_0_c_ifspec;  /* dummy ifspec addr */

   (*gks_ifspec).ifspec_vers = if_str.ifverrep;

   (*gks_ifspec).opcnt = if_str.opcnt;

   (*gks_ifspec).vers  = if_str.ifver;

   memcpy( (char *) &(*gks_ifspec).id, (char *) &if_str.id, sizeof(myuuid));

   (*gks_ifspec).stub_rtl_if_vers = if_str.rtlver;

       #endif

 

#ifdef DEBUG

   k = str_handle(h, strhandle);

   if (k != rpc_s_ok) {

      sprintf(msg, "findnames: error converting caller handle  st=%08x\n",k);

      tmsg(msg);

      }

       #ifdef WIN32

   sprintf(msg, "findnames: %s\n\t grp=%s\n\t obj=%s",

           strhandle, group_name, obj_str);

   tmsg(msg);

   printf("\t if=%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",

      ((uuid_t *)&((*gks_ifspec).InterfaceId))->time_low,

      ((uuid_t *)&((*gks_ifspec).InterfaceId))->time_mid,

      ((uuid_t *)&((*gks_ifspec).InterfaceId))->time_hi_and_version,

      ((uuid_t *)&((*gks_ifspec).InterfaceId))->clock_seq_hi_and_reserved,

      ((uuid_t *)&((*gks_ifspec).InterfaceId))->clock_seq_low,

      ((uuid_t *)&((*gks_ifspec).InterfaceId))->node[0],

      ((uuid_t *)&((*gks_ifspec).InterfaceId))->node[1],

      ((uuid_t *)&((*gks_ifspec).InterfaceId))->node[2],

      ((uuid_t *)&((*gks_ifspec).InterfaceId))->node[3],

      ((uuid_t *)&((*gks_ifspec).InterfaceId))->node[4],

      ((uuid_t *)&((*gks_ifspec).InterfaceId))->node[5]

      );

       #else

   sprintf(msg, "findnames: %s\n\t grp=%s\n\t obj=%s",

           strhandle, group_name, obj_str);

   tmsg(msg);

   printf("\t if=%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",

      (*gks_ifspec).id.time_low,

      (*gks_ifspec).id.time_mid,

      (*gks_ifspec).id.time_hi_and_version,

      (*gks_ifspec).id.clock_seq_hi_and_reserved,

      (*gks_ifspec).id.clock_seq_low,

      (*gks_ifspec).id.node[0],

      (*gks_ifspec).id.node[1],

      (*gks_ifspec).id.node[2],

      (*gks_ifspec).id.node[3],

      (*gks_ifspec).id.node[4],

      (*gks_ifspec).id.node[5]

      );

       #endif

#endif

 

 

/* lookup servers */

#ifdef DEBUG

   tmsg("findnames: call findsnms");

#endif

   k = findsnms(group_name, obj_str, gks_ifspec, &results,

                max_entry, &st); 

#ifdef DEBUG

   sprintf(msg, "findsnames: findsnms Num=%d status=%08x", k, st);

   tmsg(msg);

#endif

 

    if (k == 0)  {  /* No servers found registered */

      *num_entry = 0;

      *stat = st;

      return(names);

      }

 

/*

 *  For each server found running, inquire about its status

 */

   i=0;

for (j=0; j<k; j++)  {

   rpc_ep_resolve_binding(results->binding_h[j],

           (rpc_if_handle_t) gks_ifspec, &st);

   st = convert_binding(results->binding_h[j],

           tname); /* print who we have */

   if (st == rpc_s_ok) {

      i++;

      strcat(string, tname);

      }

   if (i == max_entry) break;  /* quit if have all we want to get */

   }  /* End for each server loop */

 

   rpc_binding_vector_free(&results, &st);  /* free binding vector */

   *num_entry=i;

   *stat=0;

   j=strlen(string+1);

   names = (rstring)rpc_ss_allocate((unsigned)j);

   strcpy((char *)names, (char *)string);

   return(names);

}  /* end findnames() */

 

 

/***********************************************************************

 *  convert_binding() - Convert info about bound handle

 ***********************************************************************/

 

static unsigned32 convert_binding(rpc_binding_handle_t rh, char *name)

{

   unsigned32      st;  /* DCE status codes from calls */

   unsigned_char_t *string_binding;  /* String format of binding info */

   unsigned_char_t *uuid, *protseq, *netaddr, *endpoint, *netopt;

   unsigned_char_t *pep;

 

   strcpy(name, "");  /* preinit string to null string */

  

/* convert binding handle to string representation */

   rpc_binding_to_string_binding(rh, &string_binding, &st);

   if(st != rpc_s_ok){

      return st;

      }

 

/* Parse the string into its component parts */

   rpc_string_binding_parse (string_binding, &uuid, &protseq, &netaddr,

                             &endpoint, &netopt, &st);

   if (st != rpc_s_ok) {

      return st;

      }

/* 10/11/95 GKS - remove the conversion to symbolic hostname */

/*                and fixup result string to return to caller */

   if (strlen((char *)endpoint) == 0)

        pep = (unsigned_char_t *)portnull;  /* return null */

   else pep = endpoint;  /* or the actual port number found */

   sprintf(name, "%s %s %s \n", (char *) netaddr, (char *) pep,

           (char *) protseq);

//   sprintf(name, "#%s %s %s \n", (char *) netaddr, (char *) pep,

//           (char *) protseq);

  

/* Free string when done */

   rpc_string_free(&string_binding, &st);

   return st;

}  /* end convert_binding() */

 


 

/*************************************************************************

 * FINDSNMS.C - DCE Utility - Perform DCE NameService Lookup

 *

 * Author:   G.K. Springer

 * Date:     September 1993

 * Node:     condor.cs.missouri.edu

 * Location: Computer Science Department, University of Missouri-Columbia

 *

 * Purpose:  DCE Utility Function to Perform NameService Lookups

 *

 * Function: Search the DCE NameService Database for matching entries of

 *           a service that is desired to know about or access.

 *

 * Syntax:   This is a utility function called by an application program.  It

 *           returns a vector of binding handles to the matching entries in

 *           the NameService Database.  The call to this routine is:

 *              num_srvent = findsrvs( NSstart, objuuid, ifspec, results,

 *                                     max_entry, stat)

 *         where:

 *            num_srvent - is number of servers found during lookup

 *            NSstart    - identifies NS lookup starting location (string)

 *            objuuid    - is encoded uuid for Object to find or NULL

 *            ifspec     - is the interface specification to look up

 *            results    - is pointer to vector of server handles found

 *            max_entry  - is max number of servers user wants to find

 *            stat       - returns status code from lookup operations

 *

 * Change Log:

 *  09/93 - GKS - Rewrite code for DCE based on earlier NCS implementation.

 *************************************************************************/

 

 

/****************************************************************************

 * findsnms() - Use DCE Name Service to find network servers

 *

 * Parameters:

 *    char                 *group_name  -  NS start lookup location

 *    char                 *objstr      -  Object UUID string or NULL

 *    struct rpc_if_handle_t if_handle  -  Interface Specification

 *    rpc_binding_vector_t **results    -  Lookup results from NS

 *    unsigned32           max_entry;   -  max number of servers to find

 *    unsigned32           *stat;       -  status from lookup

 * Returns:

 *    count of number of servers found during lookup

 *    pointer to vector of lookup results (lookup alloc storage for vector)

 *    status code indicating success or failure

 ****************************************************************************/

static int findsnms(char  *group_name, 

         char  *objstr, 

         rpc_if_handle_t  if_handle,

         rpc_binding_vector_t **results,

         unsigned32  max_entry,

         unsigned32  *stat)

{

      int                  k; /* counter - temp */

      int                  num_entry;  /* LB lookup num entries returned */

      int                  i,j;  /* Counters - temp */

      unsigned32           st;  /* Status of calls made */

      rpc_ns_handle_t      import_context;  /* handle to import from ns */

      uuid_t               objuuid;  /* object uuid encoded format */

      rpc_binding_vector_t *lbres;  /* LB lookup results */

 

/************************************************************************

 *   Start of findsnms() server location finder

 ***********************************************************************/

   uuid_from_string((unsigned_char_t *)objstr, &objuuid,

                    &st); /* get encoded obj uuid */

 

/*

 * First we position ourselves to a start location in NS Database

 */

   rpc_ns_binding_lookup_begin(     /* set context to import binding handles */

       rpc_c_ns_syntax_default,     /* use default syntax */

       (unsigned char *) group_name,   /* group name for servers */

       if_handle,                   /* interface specification */

       &objuuid,                    /* object UUID of servers */

       max_entry,                   /* max entries to locate */

       &import_context,             /* import context obtained */

       &st);                        /* status of request */

   if (st != rpc_s_ok) {  /* error - couldn't get positioned in NS */

#ifdef DEBUG

      sprintf(msg, "findsnms: lookup_begin failed st=%08x", st);

      tmsg(msg);

#endif

      *stat = st;

      return 0;

      }

 

/*

 * We want the latest NSI data we can get so let's update the local data

 * that is no more than 1 minute old

 */

   rpc_ns_mgmt_handle_set_exp_age(import_context, 60, &st);

   if (st != rpc_s_ok) {

      /*can't get latest data so just use default one */

      rpc_ns_binding_lookup_done(&import_context, &st);

      rpc_ns_binding_lookup_begin(  /* set context to import binding handles */

          rpc_c_ns_syntax_default,     /* use default syntax */

          (unsigned char *) group_name,   /* group name for servers */

          if_handle,                   /* interface specification */

          &objuuid,                    /* object UUID of servers */

          max_entry,                   /* max entries to locate */

          &import_context,             /* import context obtained */

          &st);                        /* status of request */

      if (st != rpc_s_ok) {  /* error - couldn't get positioned in NS */

         *stat = st;

         return 0;

         }

      }

 

/*

 *  Lookup the interface id in the Name Service Database

 */

   rpc_ns_binding_lookup_next(import_context, &lbres, &st);

   if (st != rpc_s_ok) {  /* error - couldn't get any entries from NS */

#ifdef DEBUG

      sprintf(msg, "findsnms: lookup_next  failed st=%08x", st);

      tmsg(msg);

#endif

      *stat = st;

      return 0;

      }

   j = lbres->count;  /* save number of entries found so far */

   *results = lbres;

 

/*

 * We need to tell NS we are done with the lookup

 */

   rpc_ns_binding_lookup_done(&import_context, &st);

   if (st != rpc_s_ok) {

#ifdef DEBUG

      sprintf(msg, "findsnms: lookup_done  failed st=%08x", st);

      tmsg(msg);

#endif

      printf("Error closing NS lookup processing\n");

      }

 

/*

 * Return info we found to caller

 */

   num_entry = j;  /* put the total into num_entry */

   if (num_entry > 0) *stat = 0;  /* we found a server */

   else *stat = st;  /* no server - use last status code */

   return num_entry;

}  /* end findsnms() */

 

 

#if 0

/*******************************************************************

 * tmsg() - Write a time-stamped msg to stdout

 *******************************************************************/

static void tmsg(msg)

  char    *msg;        /* message to output */

{

  time_t  btime;       /* holds clock value */

  char    *timestamp;  /* pointer to converted timestamp */

 

  time(&btime);  /* get current TOD */

  timestamp = ctime(&btime);  /* get TOD string */

  *(timestamp+20) = 0;  /* Terminate string after the time field */

  fprintf(stdout,"%s  %s\n", timestamp, msg);  /* print the msg with TOD */

  fflush(stdout);  /* force out the message */

  return;

}  /* end tmsg() */

#endif

 

 


FILE:FINDS.C

/*************************************************************************

 * DCE Program Finds:  FINDS.C - Server Routine.

 *

 * Author:   G.K. Springer

 * Date:     June 1991

 * Node:     condor.cs.missouri.edu

 * Place:    Computer Science Department, University of Missouri-Columbia

 *

 * Purpose:  Demonstrate DCE Application Program

 *

 * Function: Implement an addition and subtraction RPC service.

 *

 * Syntax: This program is invoked with the command line:

 *            FINDS  [&]     (should invoke program in background)

 *

 * Change Log:

 *  10/93 - GKS - Rework code to run in DCE environment using DCE Name

 *                Service across multiple DCE Cells.

 *

 * Note:

 *    February 1994 - GKS - Added processing code

 *    A dedicated signal catching thread is used to allow the server to

 *    terminate gracefully in the presence of a fatal asynchronous signal.

 *    This thread is created by the server and gains control in sigcatch()

 *    whenever a non-DCE termination signal is received by the server.

 *

 *    A dedicated self-authentication thread is used to keep the server's

 *    credentials current.  It wakes up just prior to the credentials

 *    expiring and reauthenticates itself to DCE so it always remains

 *    authenticated - regardless of what its expiration limit is and how

 *    long it has been running.  One requirement is the principle must be

 *    able to refresh its certificates and the ticket lifetime must be

 *    greater than 10 minutes.

 *************************************************************************/

 

/*

 * Standard C Include files

 */

#include <stdio.h>

 

#ifndef WIN32

#include <unistd.h>

#include <sys/errno.h>

#else

#include <errno.h>

#endif

 

#include <stdlib.h>

#include <string.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <pthread.h>

 

/* Include DCE Definitions */

#include <dce/rpc.h>  /* DCE RPC definitions */

 

char            *pnm;                   /* program name pointer for msgs */

char            msg[144];               /* For time-stamped messages */

#ifndef WIN32

pid_t           pid;                    /* Process id of the server */

#else

int           pid;                    /* Process id of the server */

#endif

uuid_t          objuuid;                /* binary object uuid string */

rpc_if_id_t     ifid;                   /* interface identifier */

uuid_vector_t   *obj_uuid_vector;       /* object uuid vector for register */

rpc_binding_vector_t  *binding_vector;  /* Bindings for server */

 

/* Define Server Specific Functions and Names */

#include <musrv.h>

 

/* This server needs 32K thread stacks */

#define STACKSIZE 32768

 

/***************************************************************************/

/***************************************************************************/

/* This conditional code has been added to allow WIN32 servers to start as */

/* services.  The utility code contained in service.h and service.c is     */

/* taken from a Microsoft sample program called "Simple Service".  It is   */

/* included with minor modifications.                                      */

/* JimR 3/1/97                                                             */

/***************************************************************************/

#ifdef WIN32

#ifndef NODAEMON

 

#include <service.h>

 

#define SZAPPNAME                               "FindS"

#define SZSERVICENAME                    "FindS"

#define SZSERVICEDISPLAYNAME      "DCE Server Locator"

#define SZDEPENDENCIES                   ""

 

#include <service.c>

 

VOID ServiceStart (DWORD dwArgc, LPTSTR *lpszArgv)

{

       /**********************************************/

       /* PROBLEM! - We really shouldn't tell control*/

       /* panel that we are up and running until we  */

       /* have registered the endpoints and all.     */

       /* However, this way allows WIN32 to act more */

       /* nearly like the other environments.        */

       /**********************************************/

 

       /* Let control panel know that we are running */

       ReportStatusToSCMgr(SERVICE_RUNNING,NO_ERROR,0);

 

       /* Start doing our work as usual */

       main_worker(lpszArgv);

}

 

VOID ServiceStop()

{

       /* Warn the SCMgr that we may take up to 10 secs to stop */

       ReportStatusToSCMgr(SERVICE_STOP_PENDING,NO_ERROR,10000);

 

       /* Fake a CTRL-C to shutdown service */

       SignalHandlerRoutine(CTRL_C_EVENT);

}

 

#else         /* NODAEMON */

main(int argc, char **argv)

{

       main_worker(argv);

}

#endif /* NODAEMON */

 

#else         /* WIN32 */

main(int argc, char **argv)

{

       main_worker(argv);

}

#endif /* WIN32 */

/***************************************************************************/

/***************************************************************************/

 

 

 

/***************************************************************************

 * Server Main Program

 ***************************************************************************/

main_worker(char **argv)

{

  double         dum1;  /* Force vars to align on a double boundary */

  int            i;     /* loop index */

  char           logname[128];  /* name of the log file */

  FILE           *fp;   /* temp file pointer to log file */

  unsigned32     st;    /* DCE status return codes on calls */

  unsigned32     thread_stk_size;  /* stack size for threads */

  int            thread_status;

  pthread_t      refresh_thread;   /* refresh thread to keep server

                                    * sec_credentials active */

  pthread_t      sigcatch_thread;  /* signal catching thread for

                                    * graceful shutdowns */

  pthread_attr_t attr;  /* attributes of a thread */

  rpc_protseq_vector_t *protvec;   /* protocol sequence vector */

 

/************************************************************************

 *   Start of main program

 ************************************************************************/

 

/* Find supported protocols on this system */

   rpc_network_inq_protseqs( &protvec, &st);  /* get protocol strings */

   if (st != rpc_s_ok) {

      fprintf(stdout, "%s: Cannot obtain supported protocols\n", *argv);

      exit(1);

      }

 

   fprintf(stdout, "This system supports %d protocols\n", protvec->count);

   for (i=0; i<protvec->count; i++) {

      fprintf(stdout, "Protocol %d: %s\n", i, protvec->protseq[i]);

      }

   fflush(stdout);

 

 

/* get short name of program */

#ifdef WIN32

  pnm = NULL;

#else

  pnm = rindex(*argv, '/');

#endif

  if (pnm == NULL) pnm = *argv;

  else pnm = pnm+1;

 

#ifndef WIN32

  umask(027);  /* make desired file mode creation mask */

#endif

  regstat = 0;  /* init registration status */

 

#ifndef NODAEMON

/************************************************************************

 * Compile this code if we are creating a Daemon Server

 ************************************************************************/

 

/* create name of log file and test its use for stdout and stderr */

  sprintf(logname, "%s/%s.log", LOGDIR, pnm);

  if ((fp = fopen(logname, "a")) == NULL) {

     sprintf(msg, "%s: could not open log:\n\t%s", pnm, logname);

     tmsg(msg);

     exit(1);

     }

 

/* make ourselves into a daemon */

  i = daemon_init();

  if (i < 0) {

     sprintf(msg, "%s: error forking child process\n", pnm);

     tmsg(msg);

     fclose(fp);

     exit(1);

     }

 

/* we are now a daemon - so redirect stdout and stderr to log file */

  if (freopen(logname, "a", stdout) == NULL) {

     fprintf(fp, "%s: could not reopen stdout to log:\n\t%s", pnm, logname);

     exit(1);

     }

  if (freopen(logname, "a", stderr) == NULL) {

     fprintf(fp, "%s: could not reopen stderr to log:\n\t%s", pnm, logname);

     exit(1);

     }

  fclose(fp);   /* and close the temp file pointer */

#endif

 

  printf("\n************************************************************\n");

  sprintf(msg, "%s: Server starting execution...", pnm);

  tmsg(msg);

 

#include <srvbase.h>  /* bring in code for the base server */

 

} /* end main */

 

#include <srvcln.h>  /* bring in code for the base cleanup routines */

 

 


FILE:FINDS.IDL

/*

 *   IDL definition of special DCE NameService server (FINDSRVS)

 *

 *   Exports Functions: findsrv

 *   Uses: IP Communication to a system allocated port

 *

 *  By: G.K. Springer - October 1993

 *  Modified:

 */

 

[

uuid(0d13c140-cfcc-11cc-b751-08002b37598d),

version(1.0)

]

interface finds

{

   import "dce/rpctypes.idl";

 

   const   long     maxlen=50;

   typedef [string] char grpname[maxlen+1];

   typedef [string] char objname[maxlen+1];

   typedef [string,ptr] char *rstring;

   typedef struct gks_if {

             unsigned16  ifverrep;

             unsigned16  opcnt;

             unsigned32  ifver;

             uuid_t      id;

             unsigned16  rtlver;

             } gks_ifnm;

 

/* Define findsrv Exported Function */

[idempotent]

rstring findnames(

    [in]  handle_t   h,         /*  NCS handle for communication  */

    [in]  grpname    grpnm,     /*  group name to start search    */

    [in]  objname    objnm,     /*  object name string to find    */

    [in]  gks_ifnm   ifnm,      /*  interface name to find        */

    [in]  unsigned32 maxntry,   /*  max number of registrations   */

    [out] unsigned32 *numntry,  /* actual count of entries found */

    [out] unsigned32 *rc        /* Return code */

    );

 

}

 

 


FILE:FINDSLOC.H

/************************************************************************

 * findsloc.h - List possible Nameserver sites for servers

 *

 * Author:   G.K. Springer

 * Date:     October 1993

 * Node:     condor.cs.missouri.edu

 * Place:    Computer Science Department, University of Missouri-Columbia

 *

 * Purpose:  Identify possible Nameserver locations

 *

 * Function: The defined constant array is used during a location lookup

 *           to determine if there is a registered server running at one

 *           of the identified DCE cells we are interested in.  We contact

 *           our server in each cell to lookup the servers of interest

 *           for us and return the binding handles for the server if any

 *           are found.

 *

 * Change Log:

 *

 ************************************************************************/

 

#ifndef FINDSRVS

#define FINDSRVS  1

 

static  char  *SrvLoc[] = {

                      "condor.cs.missouri.edu" ,

                      "warhol.psc.edu         " 

                    };

static  long  SrvNum    = sizeof(SrvLoc) / sizeof(char *);

#endif

 

 


FILE:FINDSNMS.H

/*************************************************************************

 * DCE Program Binop:  BINOPNMS.H - Include File.

 *

 * Author:   G.K. Springer

 * Date:     September 1993

 * Node:     condor.cs.missouri.edu

 *

 * Purpose:  Include file for BINOP application programs

 *

 * Function: Define the OBJ UUID string, Group Name, Entry Name

 *           and Annotation Names for the Binop Application code.

 *

 * Syntax:   Include file for C syntax programs

 *

 * Update Log:

 * 09/93 - GKS - Rewrite of code for DCE environment

 *************************************************************************/

 

//#define  GRPNAME  "/.:/hpcc/test/MUNS_Group"

//#define  ENTNAME  "/.:/hpcc/test/MUNS_"

#define  GRPNAME  "/.:/hpcc/MUNS_Group"

#define  ENTNAME  "/.:/hpcc/MUNS_"

 

#define  EPNAME   "MU NameService"

#define  NMLEN    50

 

#define  S_IFSPEC  finds_v1_0_s_ifspec

#define  C_IFSPEC  finds_v1_0_c_ifspec

#define  OBJSTR   "11110000-b04b-11cc-bf88-08002b37598d"

 

 


FILE:FINDSRVS.C

/*************************************************************************

 * DCE Function Findsrvs:  FINDC.C - Client Application Program

 *

 * Author:   G.K. Springer

 * Date:     October 1993

 * Node:     condor.cs.missouri.edu

 * Location: Computer Science Department, University of Missouri-Columbia

 *

 * Purpose:  Demonstrate DCE Application Program

 *

 * Function: Implement an addition and subtraction RPC service.

 *

 * Syntax:   This program is invoked with the command line:

 *               FINDC <server_host> <num_passes>

 *           where:

 *            server_host - identifies the host where server is running

 *            num_passes  - indicates how many loops of requests to perform

 *

 * Example:  findc cyclone.cs.missouri.edu 3

 *************************************************************************/

/*

 * Standard C Include files

 */

#include <stdio.h>

#ifndef WIN32

#include <unistd.h>

#include <sys/errno.h>

#else

#include <errno.h>

#endif

#include <string.h>

#include <sys/types.h>

#include <sys/stat.h>

#ifdef WIN32

#include <winsock.h>

#else

#include <sys/socket.h>

#include <netinet/in.h>

#include <netdb.h>

#include <arpa/inet.h>

#endif

 

/*

 * DCE Definitions

 */

#include <dce/idlbase.h>

#include <dce/rpc.h>

#include <dce/nbase.h>

#include <dce/stubbase.h>

#include <dce/rpcexc.h>

#include <dce/uuid.h>

#include <dce/dce_error.h>  /* DCE error definitions */

 

#include "finds.h"    /* NIDL generated Interface definitions */

#include "findsnms.h" /* Finds Name Strings */

#include "findsloc.h" /* Names of Cell Locations to communicate with */

#include "dceconfig.h"  /* MU DCE Configuration in Cell */

 

#ifdef DEBUG

#include "fdummy.h"

#include "fdummy.c"

#endif

 

static char     *findsmsg();

static int      print_handle();

 

#ifndef MUNSCONF

#define MUNSCONF "/d2/hpcc/sc93/bin/MUNS.config" /* Name of MUNS config file */

#endif

 

/*********************************************************************

***                                                                ***

***  findsrvs() - Use CDS NameService to find network servers      ***

***                                                                ***

***  Parameters Passed :                                           ***

***    unsigned_char_t      *obj_uuid    -  object uuid str ptr    ***

***    rpc_if_handle_t      *ifhandle    -  ifspec for application ***

***    rpc_binding_vector_t **results    -  ptr to binding vector  ***

***    unsigned32           max_entry    -  max servers to find    ***

***    unsigned32           *st          -  status from lookup     ***

***                                                                ***

**********************************************************************/

int findsrvs(unsigned_char_t      *grp_name,

             unsigned_char_t      *obj_uuid,

             rpc_if_rep_t         *ifhandle,

             rpc_binding_vector_t **results,

             unsigned32           max_entry,

             unsigned32           *st

             )

{

  int                  passes;  /* Input parameter for passes to run */

  unsigned32           rst;  /* Return status from RPC calls */

  unsigned32           statsav;  /* status from NameService Lookup */

  rpc_binding_handle_t rh;  /* RPC handle for communication */

  unsigned_char_t      *string_binding;  /* String binding handle */

  rstring              names;  /* return value from call */

  grpname              group_name;  /*start NS search here */

  objname              obj_str;  /* uuid of object to find */

  gks_ifnm             if_str;  /* encoded ifspec to find */

  unsigned32           num_entry;  /* number of NS entries found */

  unsigned32           ecount;  /* count of servers found from 1 NS */

  int                  i,j,k;  /* Counters - temp */

  unsigned_char_t      protseq[32];

  unsigned_char_t      hostnm[64];

  unsigned_char_t      portnm[16];

  size_t               bvsize;  /* binding vector size */

  char                 *cptr;  /* points to where we are in string */

  rpc_binding_vector_t *tv;

  double               align1;   /* dummy for alignment */

  int                  srvnum;  /* number of servers */

  char                 srvloc[10][64];  /* Locations of DCE servers */

  char                 strings[4096];  /* quick and dirty setup */

  FILE                 *dfile;  /* file pointer for reading */

  struct stat          dloc;  /* stat structure for name lookup */

  char                 *lptr;  /* line pointer for reading */

  char                 inp[128];  /* input area for reading */

  char                 *homedir;  /* pointer to user's home directory name */

  char                 *muns_conf; /* pointer to NS config names in env */

  char                 hdir[128]; /* home directory MUNS filename */

 

  #ifdef WIN32

  RPC_CLIENT_INTERFACE *pRCI=(RPC_CLIENT_INTERFACE *)ifhandle;

  #endif

 

 

/***************************************************************************

 * Start of findsrvs() Identify the Locations of cells to contact

 ***************************************************************************/

 

  muns_conf = getenv("MUNS_CONF"); /* see if NS Config is in environment tbl */

  if (muns_conf != NULL) {

     /* NS configuration is in environment variable - use them */

#ifdef DEBUG

     printf("using environment NS config: %s\n", muns_conf);

#endif

     i = 0;  /* index of name we are working on */

     srvnum = 0;  /* we haven't found any server names yet */

     lptr = muns_conf;  /* get pointer to the string with names */

     while (*lptr != '\0') {  /* scan to the end of the string */

        /* find next non-blank character in string */

        while (*lptr == ' ') lptr++;  /* skip over any blank chars */

        if (isgraph(*lptr)) {  /* have a legitimate 1st char */

           cptr = inp;  /* point to a temporary area for name */

           while (isgraph(*lptr)) *cptr++ = *lptr++;

           *cptr = '\0';  /* terminate string properly */

           strcpy(srvloc[srvnum++], inp);  /* copy to location array */

           } /* end if a graphical char...a blank is NOT one */

        } /* end while *lptr */

     }

  /* NS configuration not in env - so we use user spec or system spec */

  else {

     homedir = getenv("HOME");  /* get home directory name */

     if (homedir == NULL) {

        strcpy(hdir, MUNSCONF); /* use system default NS config */

        }

     else {

        sprintf(hdir, "%s/.munsrc", homedir);

        if (stat(hdir, &dloc) == -1) { /* does user config file exist? */

           /* no - use the system default file */

           strcpy(hdir, MUNSCONF);

#ifdef DEBUG

           printf("using system's NS config filename: %s\n", hdir);

#endif

           }

        else {

           /* yes - use the user's override NS Config file */

#ifdef DEBUG

           printf("using user's NS config filename: %s\n", hdir);

#endif

           }

        }

      srvnum=0;

      lptr = NULL;

      if (stat(hdir, &dloc) != -1) {  /* config file exist? */

         if ((dfile=fopen(hdir, "r")) != NULL) { /* Got config file */

         for (i=0; i<10; i++) {

            if ((lptr=fgets(inp, sizeof(inp), dfile)) != NULL) {

               if (*inp != '#') { /* have a name of a DCE Server */

                  inp[strlen(inp)-1] = '\0';  /* kill newline char */

                  if (strlen(inp) > 0) {

                     strcpy(srvloc[srvnum], inp); /* save name in array */

                     srvnum++;  /* increment server count */

                     }

                  } /* end of 1 name processing */

               } /* end of if    processing */

               else break;

            } /* end for */

            fclose(dfile);  /* close config file */

            } /* end read MUNS.config file processing */

         } /* end if stat processing */

     }  /* end else find config info from a file */

#ifdef DEBUG

   printf("findsrvs: %d servers found from config file\n", srvnum);

#endif

 

/* See if we were able to process the config file */

   if (srvnum == 0)  {  /* no config file so build from prototype setup */

      srvnum = SrvNum;  /* Get number of servers from findsloc.h */

      for (i=0; i<SrvNum; i++) {  /* build the server array */

         strcpy(srvloc[i], SrvLoc[i]);  /* copy to location array */

         }  /* end of build from prototypes */

      } /* end of no config file processing */

 

#ifdef DEBUG

   if (srvnum != 0) {  /* print the list of Possible Name Servers */

      for (i=0; i<srvnum; i++) {

         printf("findsrvs: server[%d]: %s\n", i, srvloc[i]);

         }

      }  /* end if */

#endif

 

/***************************************************************************

 * Start of findsrvs() DCE NameService Lookup Function

 ***************************************************************************/

   num_entry = 0;  /* initialize the counter */

   memset(strings, 0, 4096);  /* clear the array of server names */

   if (grp_name != NULL)

      strcpy((char *) group_name, (char *) grp_name);

   else

      strcpy((char *) group_name, "/.:");  /* default at cell start */

   strcpy((char *) obj_str, (char *) obj_uuid);

 

       #ifdef WIN32

       if_str.ifverrep=1;   /* PROBLEM! - hack */

   if_str.opcnt = 1;       /* PROBLEM! - hack */

   if_str.ifver = 1;       /* PROBLEM! - hack */

   memcpy((char *) &if_str.id, (char *) &(*pRCI).InterfaceId, sizeof(uuid_t));

   if_str.rtlver = 2;      /* PROBLEM! - hack */

       #else

/* First we copy user's ifspec info to our structure to send to server */

   if_str.ifverrep = (*ifhandle).ifspec_vers;

   if_str.opcnt = (*ifhandle).opcnt;

   if_str.ifver = (*ifhandle).vers;

   memcpy((char *) &if_str.id, (char *) &(*ifhandle).id, sizeof(uuid_t));

   if_str.rtlver = (*ifhandle).stub_rtl_if_vers;

       #endif

 

/*

 *  Loop through each DCE Cell we want to look in for Applications

 */

for (passes=0; passes<srvnum; passes++) {

#ifdef DEBUG

   fprintf(stdout,"Try: %s\n", srvloc[passes]);

#endif

 

/* Compose the string first so that handle can be obtained from that */

   rpc_string_binding_compose((unsigned_char_t *)OBJSTR,

       (unsigned_char_t *)"ncadg_ip_udp", (unsigned_char_t *)srvloc[passes],

/* Testing 2/97 don't use cn protocol

       (unsigned_char_t *)"ncacn_ip_tcp", (unsigned_char_t *)srvloc[passes],

*/

       NULL, NULL, &string_binding, &rst);

   if( rst != rpc_s_ok) {

#ifdef DEBUG

       fprintf(stdout,"Cannot compose string binding\n\t%s\n",

                findsmsg(rst));

#endif

        *results = NULL;

       *st=0xdead0001;

        return(0);

       }

 

/* Get the partially bound handle from the constructed string */

   rpc_binding_from_string_binding (string_binding, &rh, &rst);

   if (rst != rpc_s_ok) {

#ifdef DEBUG

       printf("Cannot convert name %s to binding\n\t%s\n",

               string_binding, findsmsg(rst));

#endif

        rpc_string_free(&string_binding, &rst);  /* free string storage */

        *results = NULL;

       *st=0xdead0002;

        return(0);

       }

 

   rpc_string_free(&string_binding, &rst);  /* free string storage */

#ifdef DEBUG

   if (rst != rpc_s_ok)

      printf("Can't free NS string bindings\n\t%s\n", findsmsg(rst));

#endif

 

 

 

#ifdef DEBUG

{

   rpc_if_rep_t       *gks_ifspec;   /* pointer to ifspec */

   gks_ifspec = (rpc_if_rep_t *) fdummy_v1_0_c_ifspec;  /* dummy ifspec addr */

   (*gks_ifspec).ifspec_vers = if_str.ifverrep;

   (*gks_ifspec).opcnt = if_str.opcnt;

   (*gks_ifspec).vers  = if_str.ifver;

   memcpy( (char *) &(*gks_ifspec).id, (char *) &if_str.id, sizeof(uuid_t));

   (*gks_ifspec).stub_rtl_if_vers = if_str.rtlver;

 

   printf("About to call findnames: \n\tgrp=%s\n\tobj=%s", group_name, obj_str);

   printf("\n\t if=%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",

      (*gks_ifspec).id.time_low,

      (*gks_ifspec).id.time_mid,

      (*gks_ifspec).id.time_hi_and_version,

      (*gks_ifspec).id.clock_seq_hi_and_reserved,

      (*gks_ifspec).id.clock_seq_low,

      (*gks_ifspec).id.node[0],

      (*gks_ifspec).id.node[1],

      (*gks_ifspec).id.node[2],

      (*gks_ifspec).id.node[3],

      (*gks_ifspec).id.node[4],

      (*gks_ifspec).id.node[5]

      );

}

#endif

/***********************************************************************

 * All set - make appropriate number of passes to Server RPC Functions

 ***********************************************************************/

TRY

   /* 2/97 - try to prevent long waits for dead DCE cells */

   rpc_mgmt_set_com_timeout(rh, 4, &rst);

   names = findnames(rh, group_name, obj_str, if_str, max_entry,

              &ecount, &statsav);  /* All work is done in this routine */

/*

 * Handle any errors that might occur

 */

CATCH (rpc_x_comm_failure)

#ifdef DEBUG

      printf("findsrvs: CDS NameService on %s - communication failure\n",

             srvloc[passes]);

#endif

CATCH_ALL

#ifdef DEBUG

   if (statsav == 0)

      printf("findsrvs: CDS NameService on %s - not responding\n",

             srvloc[passes]);

   else

      printf("findsrvs: CDS NameService on %s - unknown error\n",

             srvloc[passes]);

#endif

   names = NULL; ecount = 0;

ENDTRY;

#ifdef DEBUG

   if (statsav == 0) {

      printf("findsrvs: return st=%08x  num_entry=%d\n",

             statsav, ecount); fflush(stdout);

      }

   else  {

      printf("findsrvs: return st=%08x  num_entry=%d\n\t%s\n",

             statsav, ecount, findsmsg(statsav));  fflush(stdout);

      }

#endif

/* We found some names so save them in our strings array */

   if (names != NULL && ecount != 0) {

      strcat(strings, (char *) names);  /* preserve what we got back */

      free(names);  /* free the ss_alloc string */

      num_entry = num_entry + ecount;  /* increment count of servers */

      }

   if (num_entry >= max_entry) break;  /* quit if we have enough */

   }  /* end of for loop looking at different cells */

 

/*

 * Finished the search, so create the binding vector from the results

 */

  if (num_entry == 0) {  /* nothing was found - so tell user bad news */

     *st = statsav;  /* return last status code */

     *results = NULL;  /* return a null binding vector */

     return (0);  /* show no entries found */

     }

 

/* Have some entries - so build the binding vector */

   cptr = strings;  /* point to start of returned answer string */

   if (num_entry > max_entry) num_entry = max_entry; 

   bvsize = sizeof(rpc_binding_vector_t) +

            (num_entry -1) * sizeof(rpc_binding_handle_t);

#ifdef DEBUG

   printf("findsrvs: Build binding vector for %d strings size=%d\n",

          num_entry, bvsize);

   fflush(stdout);

#endif

   tv = (rpc_binding_vector_t *) malloc(bvsize);  /* get vector */

   if (tv == NULL) {  /* no storage available for vector */

#ifdef DEBUG

   printf("findsrvs: no storage for binding vector\n");

   fflush(stdout);

#endif

      *results = NULL;

      *st = 0xdead0003;  /* show an error */

      return (0);  /* give them some bad news */

      }

 

/* Have the storage so build the entries in the vector */

#ifdef DEBUG

   printf("findsrvs: strings of nodes found\n%s", strings);

   fflush(stdout);

#endif

   memset((char *) tv, 0, bvsize);  /* clear out vector */

   tv->count = num_entry;  /* save number of entries found */

 

   for (i=0, k=0; i<num_entry; i++) {

      j = sscanf(cptr, "%s %s %s", hostnm, portnm, protseq);

      if (j != 3) break;  /* something is wrong so just stop it here */

      if (strcmp((char*) portnm, "NULL") == 0) strcpy((char *) portnm, "");

      rpc_string_binding_compose(obj_str, protseq, hostnm, portnm,

            NULL, &string_binding, &rst);  /* compose the string */

      if (rst != rpc_s_ok) {

#ifdef DEBUG

         printf("Can't create string binding for server %s\n\t%s\n",

                hostnm, findsmsg(rst));

#endif

         }

      else {

         rpc_binding_from_string_binding(string_binding,

             &tv->binding_h[k], &rst);  /* create the handle */

         if (rst == rpc_s_ok) k++;  /* increment count of handles made */

         }

      rpc_string_free(&string_binding, &rst);  /* free string storage */

#ifdef DEBUG

      if (rst != rpc_s_ok)

         printf("Can't free string bindings\n\t%s\n", findsmsg(rst));

#endif

 

/* handle may have been created, so now we just go on to next entry */

      while (*cptr != '\n') cptr++;  /* skip to next "line" in string */

      cptr++;  /* skip past the newline */

      }  /* end for loop - one entry done */

 

#ifdef DEBUG

/*

 *  Print out the converted strings of servers found from NS

 */

printf("findsrvs:  Print the binding vector \n");

for (j=0; j<tv->count; j++)  {

   print_handle(tv->binding_h[j]); /* print who we talk to */

   }

#endif

 

/*

 * Have the vector built - so now we fix the results and return.

 *  st value taken from findnames call, binding vector created

 *  from the malloc() call.  User must free the vector storage.

 */

   if (k) *st=0;   /* have some names return success */

   else

      *st = statsav;  /* return the last lookup status */

   *results = tv;

   return (k);  /* k has actual count of handles we produced */

 

}  /* End findsrvs() */

 


 

/***********************************************************************

 *  print_handle() - Print info about bound handle

 ***********************************************************************/

 

static int print_handle(rpc_binding_handle_t rh)

{

   unsigned32      st;  /* DCE status codes from calls */

   struct in_addr  haddr;  /* binary host addr in network order */

   struct in_addr  *ahaddr=&haddr;

   unsigned_char_t *string_binding;  /* String format of binding info */

   unsigned_char_t *uuid, *protseq, *netaddr, *endpoint, *netopt;

   struct hostent  *hp, *gethostbyaddr();

  

/* convert binding handle to string representation */

   rpc_binding_to_string_binding(rh, &string_binding, &st);

   if(st != rpc_s_ok){

      fprintf(stdout,"Couldn't convert binding to string binding\n");

      return st;

      }

 

/* Parse the string into its component parts */

   rpc_string_binding_parse (string_binding, &uuid, &protseq, &netaddr,

                             &endpoint, &netopt, &st);

   if (st != rpc_s_ok) {

      fprintf(stdout, "Can't parse string binding\n");

      return st;

      }

 

/*

 * Use net address to get full Inet name of server host

 */

   haddr.s_addr=inet_addr(netaddr);

   hp = gethostbyaddr((char *) ahaddr, 4, AF_INET);

/* Print the binding information */

   if (hp == NULL)

      fprintf(stdout, "%s[%s] - %s\n", (char *) netaddr, (char *) endpoint,

              (char *) protseq);

   else

      fprintf(stdout, "%s[%s] - %s\n", hp->h_name, (char *) endpoint,

              (char *) protseq);

  

/* Free string when done */

   rpc_string_free(&string_binding, &st);

   return st;

}  /* end print_handle() */

 


 

/****************************************************************************

 * FINDSMSG.C - Get DCE Error Messages from error message table.

 *

 * Author:   G.K. Springer

 * Date:     March 1993

 * Node:     cyclone.cs.missouri.edu

 * Location: Computer Science Department - MU, Columbia, MO.

 *

 * Purpose:  Utility to get an NCS run-time error message from the message

 *           table and return the message string to the caller.

 * Function: Access external message table by error number and return string

 *           to the caller.

 *

 * Change Log:

 *  09/93 - GKS - Changed for DCE implementation

 *

 * Note:

 *  To get error messages an environment variable NLSPATH is required.

 *  Define it as:  setenv NLSPATH "/opt/dcelocal/nls/msg/en_US.88591/%N"

 *

 ****************************************************************************/

 

static char *findsmsg(unsigned32 st)

{

  int         err_st;   /*CRAY*/

  static char buff[dce_c_error_string_len];

 

  dce_error_inq_text(st, (unsigned char *)buff, &err_st);

  if (err_st != -1) return(buff);

  else  {

     if (st == 0xc038a0e0) 

        sprintf(buff, "(dce/rt) - Server not responding");

     else

        sprintf(buff, "(dce/rt) - No error text translation, st=%08x",st);

     return(buff);

     }

}  /* end findsmsg() */

 

 


FILE:FINDST.C

/****************************************************************************

 * FINDST.C - Print Statistics about FINDS servers running on network.

 *

 * Author:   G.K. Springer

 * Date:     November 1991

 * Node:     cyclone.cs.missouri.edu

 * Location: Computer Science Department - MU, Columbia, MO.

 *

 * Purpose:  Use rpc call to get server stats from FINDS servers running.

 * Function: Lookup the FINDS servers registered in the network.  For each

 *           server found, bind to the server and issue an inquire stats

 *           request and print out the returned statistics.  If the server

 *           does not respond (using short timeout periods), print an

 *           error message so indicating.  This code uses the pthread

 *           error handling facilities built into DCE RunTime code.

 *

 * Change Log:

 * 09/93 - GKS - Rewrite code for DCE Nameservice Lookup

 * 02/96 - GKS - Sort multiple registrations into list of unique servers

 *

 ****************************************************************************/

/*

 * Standard C Include files

 */

#include <stdio.h>

#ifndef WIN32

#include <unistd.h>

#include <sys/errno.h>

#else

#include <errno.h>

#endif

#include <stdlib.h>

#include <sys/types.h>

 

/* Include DCE Definitions */

#include <pthread.h>

#include <dce/rpc.h>  /* DCE RPC definitions */

#include <dce/rpcexc.h>

 

/* Include DCE Application Definitions */

#include "finds.h"   /* IDL generated Interface definition */

#include "findsnms.h"

 

#define MaxSrv  6

 

char *dcemsg();

unsigned32 p_handle();

 

static char *stname[] = { "   Calls In:   ",

                          "   Calls Out:  ",

                          "   Packets In: ",

                          "   Packets Out:" };

 

/************************************************************************

 * FINDST -  Server Status Main Program

 ***********************************************************************/

 

main(int argc, char **argv)

{

   int                i,j;           /* Counters - temp */

   int                index[MaxSrv+1]; /* index to unique servers */

   int                proto[MaxSrv+1]; /* index to unique server protocols */

   int                num_srvs;      /* number of unique servers */

   int                comflag;

   int                max_entry;     /* LB lookup max entries */

   int                num_entry;     /* LB lookup num entries returned */

   unsigned32         st;            /* Status of calls made */

   rpc_stats_vector_t *stats;        /* Array of stat values returned */

   rpc_binding_vector_t *results;    /* LB lookup results */

   char               group_name[NMLEN];  /* name of group to search NS */

 

 

/************************************************************************

 *   Start of main program

 ***********************************************************************/

   printf("\n************ Start Stats from FINDS Servers ************\n");

       #ifdef WIN32

   system("echo %_date%");  /* timestamp the output */

       #else

   system("date");  /* timestamp the output */

       #endif

 

/*

 *  Lookup the FINDS Object Uuid in the NameService Database

 */

   if (argc == 1) {

      strcpy(group_name, GRPNAME);  /* identify the group desired */

      }

   else {

      strcpy(group_name, *(argv+1));  /* user specified the name */

      }

 

       #ifdef DEBUG

       printf("Looking for group: %s\n",group_name);

       #endif

 

   max_entry = MaxSrv;

 

   num_entry = findsrvs(group_name, OBJSTR, C_IFSPEC,

                        &results, max_entry, &st);  /* lookup servers */

 

   if (num_entry == 0)  {  /* No servers found registered */

          printf("Lookup  status: %08x  num_entry= %d\n", st, num_entry);

      printf("Lookup for FINDS Servers Failed\n\t%s\n", dcemsg(st));

      exit(1);

      }

 

/* Sort out the Server handles and locate unique servers */

   j = s_handle(num_entry, &num_srvs, results, index, proto);

   printf("Lookup  status: %08x  num_srvs=%d (%d entries)\n",

          st, num_srvs, num_entry);

 

 /*

 *   Found at least 1 server - allocate a RPC handle to use

 */

   printf("--------------------------------------------------------\n");

 

/*

 *  For each server found running, inquire about its status

 */

for (j=0; j<num_srvs; j++)  {

      comflag=0;

      for (i=index[j]; i<index[j+1]; i++) {

         if (i == index[j]) printf("   Server: ");

         else printf("           ");

         /* print who we are talking to */

         comflag += p_handle(results->binding_h[i]);

         }

   if ((comflag > 0) || (proto[j] == -1)) {

      if (proto[j] == -1)

         printf("\tserver registered with protocol not supported here\n");

      else

         printf("\tserver registered, but not communicating\n");

      printf("--------------------------------------------------------\n");

      }

   else {

    rpc_mgmt_set_com_timeout(results->binding_h[proto[j]],

        rpc_c_binding_min_timeout, &st); /* timeout quickly */

    TRY {

       /*******************************************************/

       /* Notes on why this WIN32 specific hack is necessary  */

       /* - Jim Ries 10/15/95                                 */

       /*                                                     */

       /* Under NT, it seems that the binding handle returned */

       /* by findsrvs() in result has the uuid of OBJSTR.     */

       /* At least under NT, this is correct for making       */

       /* actual calls that do work, e.g, things that binopc  */

       /* would like to do.  However, in order to talk to the */

       /* management entry point vector (EPV), one needs the  */

       /* type uuid assigned to the server via the            */

       /* rpc_object_set_type() call.  Therefore, we must     */

       /* inquire what that id is (using C_IFSPEC for which   */

       /* we must link in the idl-generated server module)    */

       /* and change the object uuid of the binding handle.   */

       /*******************************************************/

       {

        uuid_t        tuuid;

        rpc_if_id_t   ifid;    /* interface identifier */

 

#ifdef DEBUG

        unsigned_char_t *  tmp;

 

       rpc_binding_inq_object(results->binding_h[proto[j]],&tuuid,&st);

       uuid_to_string(&tuuid,&tmp,&st);

       printf("The object uuid of the binding handle is: %s\n",tmp);

#endif

 

       rpc_if_inq_id(C_IFSPEC, &ifid, &st);

 

#ifdef DEBUG

       uuid_to_string(&ifid.uuid,&tmp,&st);

       printf("Changing the binding handle uuid to: %s\n",tmp);

#endif

       rpc_binding_set_object(results->binding_h[proto[j]],&ifid.uuid,&st);

       }

 

     /* Get server statistics and print them out */

     rpc_mgmt_inq_stats(results->binding_h[j], &stats, &st);

     if (st == rpc_s_ok) {

        for (i=0; i<stats->count; i++) printf("%s %d\n", stname[i],

             stats->stats[i]);

        printf("--------------------------------------------------------\n");

        rpc_mgmt_stats_vector_free(&stats, &st);  /* free stats vector */

        }

     else {

                     #ifdef DEBUG

                     switch (st)

                     {

                           case rpc_s_invalid_binding:

                                  printf("Error: Invalid binding handle.\n");

                                  break;

 

                           case rpc_s_wrong_kind_of_binding:

                                  printf("Error: Wrong kind of binding.\n");

                                  break;

 

                           case rpc_s_binding_incomplete:

                                  printf("Error: Binding incomplete.\n");

                                  break;

 

                           case rpc_s_comm_failure:

                                  printf("Error: Communications failure.\n");

                                  break;

 

                           case rpc_s_mgmt_op_disallowed:

                                  printf("Error: Management operation not allowed.\n");

                                  break;

 

                           case rpc_s_unsupported_type:

                                  printf("Error: Unsupported Type.\n");

                                  break;

 

                           default:

                                  printf("Error: Unknown error: %ld.\n",st);

                     }

                     #endif

 

        printf("Could not obtain stats from server\n");

        printf("--------------------------------------------------------\n");

        }

     }

/*

 *   Comes here on a communication error.

 */

CATCH (rpc_x_comm_failure) {

      printf("   ***Error*** - Server not responding!\n");

      printf("--------------------------------------------------------\n");

      }

/*

 *   Comes here on all other errors.

 */

CATCH_ALL {

      printf("   ***Error*** - %s\n", dcemsg(st));

      printf("--------------------------------------------------------\n");

      }

ENDTRY;

   }  /* end if p_handle() */

 }  /* End for each server loop */

 

   rpc_binding_vector_free(&results, &st);  /* free binding vector */

   printf("************ End of Stats from FINDS Servers ***********\n\n");

   exit(0);

}  /* end main() */

 

 


FILE:MAKEFILE

############################################################################

# Makefile for findc and finds client/server DCE application program

#

# Author:   G.K. Springer at U of MO - Columbia

# Date:     October 21, 1993

# Node:     condor.cs.missouri.edu

# Place:    Computer Science Department, University of Missouri-Columbia

#

# Purpose:  Create a cross-cell DCE NameService Lookup Applcation.

#           Any user can use the findsrvs() function to look for servers

#           registered in any of the cells that findservs() is authorized

#           to look in.  It returns a rpc_binding_vector containing the

#           binding handles for any servers found during the lookup.

#

# Function: Client calls upon a server to look for any application server

#           specified by the user registered in the DCE CDS Name Service.

#           It will look in any DCE cell that has a DCE server running

#           (finds) and ask the server to lookup the registration on its

#           behalf in a remote cell.  The server returns a list of handles

#           for all servers found running in the remote cell.  A list of

#           remote cells is provided so findsrvs() only looks in cells it

#           has been designated to operate in.  The user is returned a

#           binding_vector of all servers found registered in any of the

#           designated DCE cells.  In short the findsrvs() function creates

#           a minimal GDS service lacking such a service on the local cell.

#

#

# Update Log:

#  10/30/93 - Changes to build code for a DCE system

#             Code to build system on different platforms is separated

#             so the same make file can be used to build the code on every

#             platform.

#             where:  platform is one of [alpha, cray, hpux, rs6000]

#             if a particular component is to be built, use the MK

#             macro of Make to specify the component that is to be built.

#

#             For example: make  alpha     builds entire system on alpha

#                          make  alpha MK=clean     cleans up after build

#                          make  cray  MK=finds     builds server on cray

#

############################################################################

 

############################################################################

## This is a heuristic to make sure that WIN32 is set when building on NT ##

!ifdef CPU

WIN32=1

!endif

############################################################################

 

 

############################################################################

## This is necessary to set specific flags for PC environments            ##

!ifdef WIN32

CFLAGS=/c /GX /I. /I.. /I..\..\include /I..\..\logger /I..\..\service -D_X86_=1 -G3 -Gz -DDCENT -Didl_char=char -D_MSDOS -DEP -DWIN32=1 /nologo /Zp1

 

!      ifdef DEBUG

CFLAGS=$(CFLAGS) -DDEBUG -Od -Zi

LINKFLGS=/DEBUG

!      endif  // DEBUG

 

!      ifdef NOCERT

CFLAGS=$(CFLAGS) -DNOCERT

!      endif  // NOCERT

 

!      ifdef NODAEMON

CFLAGS=$(CFLAGS) -DNODAEMON

!      endif  // NODAEMON

 

!endif // WIN32

############################################################################

 

default:

       @echo.

       @echo Making FINDSRVS Services Application

       @echo.

       @echo   No system specified for the make.

       @echo.

       @echo      Usage:  make  sysname  [MK=components_to_build]

       @echo         where:

       @echo           sysname is one of [ alpha cray hpux rs6000 win32]

       @echo.

 

# Make the code on WIN32 platforms (Windows 95 and NT)

WIN32: makefile.fin

       @tm start

       @echo Build Findsrvs Services on WIN32

       @if not exist build.win md build.win

       @if not exist ..\build.wbn md ..\build.wbn

       @cd build.win

       $(MAKE) /nologo -f ..\makefile.fin \

      WIN32=1 \

      TSRC=.. \

      T1=..\..\build.wbn \

      IDL=idl \

#         IDLFLAGS="-cc_cmd cl.exe -cc_opt -Zp1 -cc_opt -c -cc_opt -D_X86 -cc_opt -DDCENT -cc_opt -D_MSDOS -cc_opt -DEP -cc_opt -DWIN32=1 -cc_opt -G3 -cc_opt -GX -cc_opt -Didl_char=char" \

              IDLFLAGS= \

              CFLAGS="$(CFLAGS)" \

              LINKFLGS="$(LINKFLGS) /NOLOGO"\

      LIBS="pthreads.lib libdce.lib wsock32.lib advapi32.lib" \

      LIB2= \

      GENSYS=WIN32

       @echo Build on WIN32 complete

       @tm stop

 

# Make the code on ALPHA platforms

alpha: Makefile.findsrvs

       @echo

       @echo Build Findsrvs Services on ALPHA - `date`

       @if [ ! -d "Build.alpha" ] ; then mkdir Build.alpha ; fi ;

       @if [ ! -d "Build.abin" ] ; then ln -s ../../bin Build.abin ; fi ;

       @cd Build.alpha ;\

         $(MAKE) $(MFLAGS) -f '../Makefile.findsrvs' \

           TSRC='..' \

          T1='../Build.abin' \

           IDL=/usr/bin/idl \

          IDLFLAGS='-v -keep c_source -no_cpp' \

           CFLAGS='-c -Dalpha -D_SHARED_LIBRARIES -I. -I.. -I../../include -D_REENTRANT -w' \

          CFLAG2='' \

           LIBS='-ldce -lpthreads -lc_r -lmach -lm' \

           LIB2='' \

           GENSYS=alpha \

           $(MK)

       @echo Build on ALPHA complete - `date`

 

# Make the code on Cray C90 at PSC

cray:  Makefile.findsrvs

       @echo

       @echo Build Findsrvs Services on CRAY - `date`

       @if [ ! -d "Build.cray" ] ; then mkdir Build.cray ; fi ;

       @if [ ! -d "Build.cbin" ] ; then ln -s ../../bin Build.cbin ; fi ;

       @cd Build.cray ;\

         $(MAKE)           -f '../Makefile.findsrvs' \

          TSRC='..' \

          T1='../Build.cbin' \

          IDL=/opt/dcelocal/bin/idl \

          IDLFLAGS='-v -keep c_source -no_cpp' \

          CFLAGS='-c -Dcray -DNODAEMON -I. -I.. -I../../include -I/usr/include/dce -w' \

          CFLAG2='' \

          CC=cc \

          LIBS='-ldce' \

          LIB2='' \

          GENSYS=cray \

           $(MK)

       @echo Build on CRAY complete - `date`

 

# Make the code on HPUX platforms

hpux:  Makefile.findsrvs

       @echo

       @echo Build Findsrvs Services on HPUX - `date`

       @if [ ! -d "Build.hpux" ] ; then mkdir Build.hpux ; fi ;

       @if [ ! -d "Build.hbin" ] ; then ln -s ../../bin Build.hbin ; fi ;

       @cd Build.hpux ;\

         $(MAKE) $(MFLAGS) -f '../Makefile.findsrvs' \

           TSRC='..' \

          T1='../Build.hbin' \

           IDL=/usr/bin/idl \

          IDLFLAGS='-v -keep c_source -no_cpp' \

           CC=c89 \

           CFLAGS='-c -Dhpux -I. -I.. -I../../include -I/usr/include/reentrant -D_REENTRANT -D_POSIX_SOURCE -D_HPUX_SOURCE -w' \

          CFLAG2='' \

          LIBS='-Wl,-a,archive -ldce -lc_r -lm' \

           LIB2='' \

           GENSYS=hpux \

           $(MK)

       @echo Build on HPUX complete - `date`

 

# Make the code on RS6000

rs6000:       Makefile.findsrvs

       @echo

       @echo Build Findsrvs Services on RS6000 - `date`

       @if [ ! -d "Build.rs6000" ] ; then mkdir Build.rs6000 ; fi ;

       @if [ ! -d "Build.rbin" ] ; then ln -s ../../bin Build.rbin ; fi ;

       @cd Build.rs6000 ;\

         $(MAKE) $(MFLAGS) -f ../Makefile.findsrvs \

          TSRC='..' \

          T1=../Build.rbin \

          IDL=/opt/dce/bin/idl \

          IDLFLAGS='-v -keep c_source -I/opt/dce/share/include -no_cpp' \

          CFLAGS='-c -Dunix -D_ALL_SOURCE -D_ANSI_C_SOURCE -I/opt/dce/share/include -I. -I.. -I../../include -w' \

          CFLAG2='' \

          CC=c89 \

          LIBS='-L/usr/lib -L. -L../Build.rbin -lpthreads -ldce' \

          LIB2='-lXm -lXt -lX11' \

          GENSYS=rs6000 \

           $(MK)

       @echo Build on RS6000 complete - `date`

 

 

.DEFAULT:

       @echo defaulting on "$@"  - don't know how to build it.

 

 


FILE:MAKEFILE.FIN

#----------------------------------------------------------------

# Makefile essentials to build the finds and findsrvs application

#----------------------------------------------------------------

 

!IFDEF WIN32

LINK = link $(LINKFLGS)

OBJF   = finds_cstub.obj p_handle.obj s_handle.obj dcemsg.obj tmsg.obj sigcatch.obj \

              str_handle.obj findsrvs.obj

OBJS   = finds_sstub.obj findname.obj tmsg.obj dcemsg.obj sigcatch.obj \

         p_handle.obj str_handle.obj finds.obj

OBJST  = findst.obj finds_sstub.obj

SRVINC  = $(TSRC)\..\include\srvbase.h $(TSRC)\..\include\srvcln.h \

          $(TSRC)\musrv.h $(TSRC)\findsnms.h

 

 

#################################################################

# Default - build all of the code

#################################################################

ALL:   $(T1)\finds.exe findsrvs.obj $(T1)\muns.lib $(T1)\findst.exe

 

#################################################################

# Make the Server side of the process

#################################################################

#$(T1)\finds: $(OBJS) $(T1)\libmutl.a

$(T1)\finds.exe:     $(OBJS) $(T1)\mutl.lib

       $(LINK) $(LIBS) $(LIB2) $(T1)\mutl.lib /OUT:$(T1)\finds.exe $(OBJS)

#      chmod 700 $(T1)\finds

#      chmod u+s $(T1)\finds

finds.obj:    finds.h $(SRVINC) $(TSRC)\finds.c

       $(CC) $(CFLAGS) $(TSRC)\finds.c

findname.obj: finds.h fdummy.h fdummy.c $(TSRC)\findname.c

       $(CC) $(CFLAGS) $(TSRC)\findname.c

#finds_s.obj: finds.h finds_s.c

#      @echo

#      @echo Make the server program

#      $(CC) $(CFLAGS) finds_s.c

 

#################################################################

# Make the FINDSRVS User Callable Function side of the application

#################################################################

findsrvs.obj: finds.h finds_cstub.obj $(TSRC)\findsloc.h $(TSRC)\findsrvs.c

       $(CC) $(CFLAGS) $(CFLAG2) $(TSRC)\findsrvs.c

#finds_c.obj: finds.h finds_c.c

#      @echo

#      @echo Make the client program

#      $(CC) $(CFLAGS) finds_c.c

 

#################################################################

# Make the FINDSRVS Library for users to link with their code

#################################################################

$(T1)\muns.lib:      $(OBJF)

       @echo

       @echo Make the MUNS subroutine library

       lib /OUT:$(T1)\muns.lib $(OBJF)

 

#################################################################

# Make the FINDST Program

#################################################################

#$(T1)\findst:       $(OBJST) $(T1)\muns.lib $(T1)\libmutl.a

$(T1)\findst.exe:    $(OBJST)

       $(LINK) $(LIBS) $(LIB2) $(T1)\muns.lib /OUT:$(T1)\findst.exe $(OBJST)

#      chmod 755 $(T1)\findst

findst.obj:   finds.h $(TSRC)\findst.c

       @echo

       @echo Make the findsrv statistics program

       $(CC) $(CFLAGS) $(TSRC)\findst.c

 

#################################################################

# Call IDL compiler to build DCE stubs from idl definition

#################################################################

$(TSRC)\finds.idl:

       @echo found finds.idl file

 

finds_cstub.obj finds_sstub.obj finds.h: $(TSRC)\finds.idl

       @echo

       @echo Create DCE stub code for the client and server

       $(IDL) $(IDLFLAGS) -keep all $(TSRC)\finds.idl

 

#################################################################

# Call IDL compiler to build DCE stubs for Dummy IDL definition

#################################################################

$(TSRC)\fdummy.idl:

       @echo found fdummy.idl file

fdummy.c fdummy.h:   $(TSRC)\fdummy.idl

       @echo

       @echo Create DCE stub code for the dummy interface

       $(IDL) $(IDLFLAGS) -keep c_source -server none -cstub fdummy.c $(TSRC)\fdummy.idl

 

#################################################################

# Create the utility functions for the application

#################################################################

p_handle.obj: $(TSRC)\p_handle.c

       $(CC) $(CFLAGS) $(TSRC)\p_handle.c

s_handle.obj: $(TSRC)\s_handle.c

       $(CC) $(CFLAGS) $(TSRC)\s_handle.c

str_handle.obj:      $(TSRC)\str_handle.c

       $(CC) $(CFLAGS) $(TSRC)\str_handle.c

sigcatch.obj: $(TSRC)\sigcatch.c

       $(CC) $(CFLAGS) $(TSRC)\sigcatch.c

dcemsg.obj:   $(TSRC)\dcemsg.c

       $(CC) $(CFLAGS) $(TSRC)\dcemsg.c

tmsg.obj:     $(TSRC)\tmsg.c

       $(CC) $(CFLAGS) $(TSRC)\tmsg.c

 

#################################################################

# Cleanup files after build, including possibly the code modules

#################################################################

clean:

       @echo

       @echo Cleanup the findsrv directory

#      @- rm -i find*.obj finds_*.c fdummy*.[ch] finds.h \

#        p_handle.obj sigcatch.obj dcemsg.obj tmsg.obj \

#        $(T1)\finds $(T1)\findst $(T1)\libmuns.a

 

###################################################################

###################################################################

###################################################################

###################################################################

!ELSE

###################################################################

###################################################################

###################################################################

###################################################################

 

OBJF   = finds_cstub.o p_handle.o dcemsg.o tmsg.o sigcatch.o findsrvs.o

OBJS   = finds_sstub.o findnames.o tmsg.o dcemsg.o sigcatch.o \

         p_handle.o finds.o

OBJST  = findst.o

SRVINC  = $(TSRC)/../include/srvbase.h $(TSRC)/../include/srvcln.h \

          $(TSRC)/musrv.h $(TSRC)/findsnms.h

 

 

#################################################################

# Default - build all of the code

#################################################################

ALL:   $(T1)/finds findsrvs.o $(T1)/libmuns.a $(T1)/findst

 

#################################################################

# Make the Server side of the process

#################################################################

$(T1)/finds:  $(OBJS) $(T1)/libmutl.a

       $(CC) -o $(T1)/finds $(OBJS) -L$(T1) -lmutl $(LIBS) $(LIB2)

       chmod 700 $(T1)/finds

       chmod u+s $(T1)/finds

finds.o:      finds.h $(SRVINC) $(TSRC)/finds.c

       $(CC) $(CFLAGS) $(TSRC)/finds.c

findnames.o:  finds.h fdummy.h fdummy.c $(TSRC)/findnames.c

       $(CC) $(CFLAGS) $(TSRC)/findnames.c

finds_sstub.o:       finds.h finds_sstub.c

       @echo

       @echo Make the server program

       $(CC) $(CFLAGS) finds_sstub.c

 

#################################################################

# Make the FINDSRVS User Callable Function side of the application

#################################################################

findsrvs.o:   finds.h finds_cstub.o $(TSRC)/findsloc.h $(TSRC)/findsrvs.c

       $(CC) $(CFLAGS) $(CFLAG2) $(TSRC)/findsrvs.c

finds_cstub.o:       finds.h finds_cstub.c

       @echo

       @echo Make the client program

       $(CC) $(CFLAGS) finds_cstub.c

 

#################################################################

# Make the FINDSRVS Library for users to link with their code

#################################################################

$(T1)/libmuns.a:     $(OBJF)

       @echo

       @echo Make the MUNS subroutine library

       lorder $(OBJF) | tsort | xargs ar crv $(T1)/libmuns.a

       chmod 644 $(T1)/libmuns.a

 

#################################################################

# Make the FINDST Program

#################################################################

$(T1)/findst: $(OBJST) $(T1)/libmuns.a $(T1)/libmutl.a

       $(CC) -o $(T1)/findst $(OBJST) -L$(T1) -lmuns $(LIBS) $(LIB2)

       chmod 755 $(T1)/findst

findst.o:     finds.h $(TSRC)/findst.c

       @echo

       @echo Make the findsrv statistics program

       $(CC) $(CFLAGS) $(TSRC)/findst.c

 

#################################################################

# Call IDL compiler to build DCE stubs from idl definition

#################################################################

$(TSRC)/finds.idl:

       @echo found finds.idl file

 

finds_cstub.c finds_sstub.c finds.h:     $(TSRC)/finds.idl

       @echo

       @echo Create DCE stub code for the client and server

       $(IDL) $(IDLFLAGS) $(TSRC)/finds.idl

 

#################################################################

# Call IDL compiler to build DCE stubs for Dummy IDL definition

#################################################################

$(TSRC)/fdummy.idl:

       @echo found fdummy.idl file

fdummy.c fdummy.h:   $(TSRC)/fdummy.idl

       @echo

       @echo Create DCE stub code for the dummy interface

       $(IDL) $(IDLFLAGS) -server none -cstub fdummy.c $(TSRC)/fdummy.idl

 

#################################################################

# Create the utility functions for the application

#################################################################

p_handle.o:   $(TSRC)/p_handle.c

       $(CC) $(CFLAGS) $(TSRC)/p_handle.c

sigcatch.o:   $(TSRC)/sigcatch.c

       $(CC) $(CFLAGS) $(TSRC)/sigcatch.c

dcemsg.o:     $(TSRC)/dcemsg.c

       $(CC) $(CFLAGS) $(TSRC)/dcemsg.c

tmsg.o:       $(TSRC)/tmsg.c

       $(CC) $(CFLAGS) $(TSRC)/tmsg.c

 

#################################################################

# Cleanup files after build, including possibly the code modules

#################################################################

clean:

       @echo

       @echo Cleanup the findsrv directory

       @- rm -i find*.o finds_*stub.c fdummy*.[ch] finds.h \

         p_handle.o sigcatch.o dcemsg.o tmsg.o \

         $(T1)/finds $(T1)/findst $(T1)/libmuns.a

 

!ENDIF

 


FILE:MUSRV.H

/*************************************************************************

 * Include File:  musrv.h - Include common definitions used by a server

 *

 * Author:   G.K. Springer

 * Date:     February 1994

 * Node:     condor.cs.missouri.edu

 * Place:    Computer Science Department, University of Missouri-Columbia

 *

 * Purpose:  Define common routines and constants used by an application

 *           server using DCE.

 *

 * Function: Define symbolic contants and include files used by a server

 *

 * Syntax:   This is an include file called from the server source code

 *

 * Change Log:

 *  02/95 GKS - Added code for generating unique logging transaction ids

 *

 *************************************************************************/

 

#ifndef MUSRV

#define MUSRV 1

 

/* Define Server Principal and interface routines to identify and refresh

 * the server's DCE security credentials

 */

/* JimR Note - PROBLEM! - It seems that this should be taken from the */

/* login name of whomever is currently signed on when the server is   */

/* started.  Hard-coding here seems like a bummer.                    */

static char     *principal = "springer";

 

/* Identify Common Utility Functions for Server */

void tmsg();     /* Print time-stamped messages */

char *dcemsg();  /* DCE error msg lookup routine */

unsigned32 p_handle(); /* print a binding handle as text */

 

/* Bring in Application Specific Server Include Files */

#include <finds.h>   /* DCE IDL generated header file for the server */

#include <findsnms.h>      /* DCE NS names for this server */

#include <daemon.h>     /* to make server into a daemon */

#include <dceconfig.h>  /* names for logging from server */

 

#ifdef LOG

#include <log.h>        /* For LogServer Usage */

#include <newtrid.h>    /* For generating transaction ids */

unsigned32    trsrv;  /* Transaction id for the Server */

#endif

 

/* Define Names used for Server Registration */

int             regstat;              /* Registration status */

char            entry_name[NMLEN];    /* Name Service Entry Name */

char            group_name[NMLEN];    /* Name Service Group Name */

char            annotation[NMLEN];    /* Server annotation in end point map */

char            hostname[NMLEN];      /* Name of our host */

char            s_objstr[40];         /* Server Object UUID String */

 

static void     cleanup();            /* unregister server routine */

void            cleanup_usr(int);   /* User defined cleanup prior to unregister */

 

int             signo;   /* Signal number causing a termination */

pthread_addr_t       sigcatch(pthread_addr_t); /*signal handling thread fn */

 

#ifdef WIN32

BOOL SignalHandlerRoutine(DWORD dwCtrlType);

#endif

 

/*

 * For validating an authenticated user for credential renewal

 */

 

/* The login module exports these three interfaces */

void mulogin();

pthread_addr_t refresh_context();

void key_retrieval_function(

                     void *arg,

                     unsigned_char_t * server_princ_name,

                     unsigned32 key_type,

                     unsigned32 key_ver,

                     void **key,

                     unsigned32 * status);

 

//void key_retrieval_function();

 

/* This krb_key_t structure is a workaround to a problem with the definition

 * of the key retrieval function in rpc_server_register_auth_info(3rpc).

 * The key structure is not described nor exported to the programmer.  This

 * structure resembles the structure used internal to the security library, and

 * for the current implementation, works to supply a valid key to the RPC

 * runtime.

 */

typedef struct {

  unsigned int keytype;        /* des or plain? */

  int length;                  /* number of characters in the password */

  char *contents;              /* points to the encrypted password */

} krb_key_t;

 

#endif

 

 


FILE:P_HANDLE.C

/*************************************************************************

 * Utility Function:  p_handle.c - Convert and print a DCE binding_handle

 *

 * Author:   G.K. Springer

 * Date:     March 1993

 * Node:     condor.cs.missouri.edu

 * Place:    Computer Science Department, University of Missouri-Columbia

 *

 * Purpose:  Utility Function to convert a DCE binding_handle to text

 *

 * Function: Convert handle to a string and print it to stdout.

 *

 * Syntax: This is a utility function called from an application:

 *             x = p_handle(rh);

 *         where:

 *            x  - is an int containing a DCE error status code

 *            rh - is a rpc_binding handle in DCE

 *

 * Change Log:

 *

 *************************************************************************/

 

/* Include Standard C Definitions */

#include <stdio.h>

#include <sys/types.h>

 

#ifdef WIN32

#include <winsock.h>

#else

#include <sys/socket.h>

#include <netinet/in.h>

#include <netdb.h>

#include <arpa/inet.h>

#endif

 

/* Include DCE Definitions */

#include <dce/rpc.h>  /* DCE RPC definitions */

 

unsigned32 p_handle(rpc_binding_handle_t rh)

{

   unsigned32      st;  /* DCE status codes from calls */

   struct in_addr  haddr;  /* binary host addr in network order */

   struct in_addr  *ahaddr=&haddr;

   unsigned_char_t *string_binding;  /* String format of binding info */

   unsigned_char_t *uuid, *protseq, *netaddr, *endpoint, *netopt;

   struct hostent  *hp, *gethostbyaddr();

  

/* convert binding handle to string representation */

   rpc_binding_to_string_binding(rh, &string_binding, &st);

   if(st != rpc_s_ok){

      printf("Couldn't convert binding to string binding\n");

      return st;

      }

 

/* Parse the string into its component parts */

   rpc_string_binding_parse (string_binding, &uuid, &protseq, &netaddr,

                             &endpoint, &netopt, &st);

   if (st != rpc_s_ok) {

      printf("Can't parse string binding\n");

      return st;

      }

 

/*

 * Use net address to get full Inet name of server host

 */

   haddr.s_addr=inet_addr(netaddr);

   hp = gethostbyaddr((char *) ahaddr, 4, AF_INET);

/* Print the binding information */

   if (hp == NULL)

      printf("%s[%s] - %s\n", (char *) netaddr, (char *) endpoint,

              (char *) protseq);

   else

      printf("%s[%s] - %s\n", hp->h_name, (char *) endpoint,

              (char *) protseq);

  

/* Free string when done */

   rpc_string_free(&string_binding, &st);

   if (st != rpc_s_ok) printf("Can't free rpc string\n");

   if (strlen((char *) endpoint) == 0) return 1;  /* endpoint not available */

   else return st;

}  /* end p_handle() */

 

 


FILE:P_HANDLE.NC

/*************************************************************************

 * Utility Function:  p_handle.c - Convert and print a DCE binding_handle

 *

 * Author:   G.K. Springer

 * Date:     March 1993

 * Node:     condor.cs.missouri.edu

 * Place:    Computer Science Department, University of Missouri-Columbia

 *

 * Purpose:  Utility Function to convert a DCE binding_handle to text

 *

 * Function: Convert handle to a string and print it to stdout.

 *

 * Syntax: This is a utility function called from an application:

 *             x = print_handle(rh);

 *         where:

 *            x  - is an int containing a DCE error status code

 *            rh - is a rpc_binding handle in DCE

 *

 * Change Log:

 *

 *************************************************************************/

 

/* Include Standard C Definitions */

#include <stdio.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <netdb.h>

#include <arpa/inet.h>

 

/* Include DCE Definitions */

#include <dce/rpc.h>  /* DCE RPC definitions */

 

unsigned32 p_handle(rpc_binding_handle_t rh,

   rpc_if_handle_t *if_id,

   uuid_t  *obj_id

   )

{

   unsigned32      st;  /* DCE status codes from calls */

   struct in_addr  haddr;  /* binary host addr in network order */

   struct in_addr  *ahaddr=&haddr;

   unsigned_char_t *string_binding;  /* String format of binding info */

   unsigned_char_t *uuid, *protseq, *netaddr, *endpoint, *netopt;

   struct hostent  *hp, *gethostbyaddr();

   int                i,j;           /* Counters - temp */

   rpc_ep_inq_handle_t inq_context;  /* Context for ep-map inquiries */

   unsigned_char_t    *annotation;   /* annotation string from ep map */

  unsigned32           rst;  /* Return status from RPC calls */

  rpc_binding_handle_t eprh;  /* RPC handle for communication */

  unsigned_char_t      *string_epmap;  /* String binding handle */

   rpc_binding_handle_t bhand;       /* binding handle from ep map */

  

/* convert binding handle to string representation */

   rpc_binding_to_string_binding(rh, &string_binding, &st);

   if(st != rpc_s_ok){

      printf("Couldn't convert binding to string binding\n");

      return st;

      }

 

/* Parse the string into its component parts */

   rpc_string_binding_parse (string_binding, &uuid, &protseq, &netaddr,

                             &endpoint, &netopt, &st);

   if (st != rpc_s_ok) {

      printf("Can't parse string binding\n");

      return st;

      }

 

/*

 * Use net address to get full Inet name of server host

 */

   haddr.s_addr=inet_addr(netaddr);

   hp = gethostbyaddr((char *) ahaddr, 4, AF_INET);

/* Print the binding information */

   if (hp == NULL)

      printf("%s[%s] - %s\n", (char *) netaddr, (char *) endpoint,

              (char *) protseq);

   else

      printf("%s[%s] - %s\n", hp->h_name, (char *) endpoint,

              (char *) protseq);

 

/* Compose string handle so that we can talk to EP map daemon */

   rpc_string_binding_compose("", "ncacn_ip_tcp", hp->h_name,

             NULL, NULL, &string_epmap, &rst);

   if( rst != rpc_s_ok) {

       fprintf(stdout,"Cannot compose ep string binding\n\t%s\n",

                dcemsg(rst));

       }

 

/* Get the partially bound handle from the constructed string */

   rpc_binding_from_string_binding (string_epmap, &eprh, &rst);

   if (rst != rpc_s_ok) {

       printf("Cannot convert ep name %s to binding\n\t%s\n",

               string_epmap, dcemsg(rst));

        rpc_string_free(&string_epmap, &rst);  /* free string storage */

        return(0);

       }

 

   rpc_string_free(&string_epmap, &rst);  /* free string storage */

   if (rst != rpc_s_ok)

      printf("Can't free ep string bindings\n\t%s\n", dcemsg(rst));

 

/* See about getting the annotation field from ep map */

   rpc_mgmt_ep_elt_inq_begin(

      eprh,                    /* a binding handle where server is */

      rpc_c_ep_match_by_both,  /* match on both IF and Object */

      if_id,                   /* IF specification */

      rpc_c_vers_all,          /* take all versions */

      obj_id,                  /* Object uuid string to find */

      &inq_context,            /* returned inquiry context */

      &st);

   if (st == rpc_s_ok) {  /* have a context so get the annotation */

      rpc_mgmt_ep_elt_inq_next(

         inq_context,

         if_id,    /* no interface to be returned */

         &bhand,   /* no binding handle to be returned */

         NULL,     /* no object uuid to be returned */

         &annotation,  /* we want the annotation string */

         &st);  /* get the annotation string from ep map */

      if (st == rpc_s_ok) {

         printf("   Annotation: %s\n", annotation);

         rpc_string_free(&annotation, &st);

         }

      else {

         printf("could not get annotation string - %s\n", dcemsg(st));

         }

      rpc_mgmt_ep_elt_inq_done(&inq_context, &st); /*release inq context */

      }

   else {

      printf("cannot get annotation context - %s\n", dcemsg(st));

      }

        

/* Free string when done */

   rpc_string_free(&string_binding, &st);

   return st;

}  /* end p_handle() */

 

 


FILE:SIGCATCH.C

/*************************************************************************

 * Utility File:  sigcatch.c - Thread function to catch asynchronous signals

 *

 * Author:   G.K. Springer

 * Date:     February 1994

 * Node:     condor.cs.missouri.edu

 * Place:    Computer Science Department, University of Missouri-Columbia

 *

 * Purpose:  Utility Function to catch asynchronous signals in DCE environ.

 *

 * Function: Server creates a thread to catch asynchronous signals and

 *           this function does the processing when the desired signal

 *           is detected.  It sits in a thread_wait condition until the

 *           signal actually occurs.

 *           When it awakens, it tells a DCE server to quit listening and

 *           to shut itself down gracefully.

 *

 * Syntax: This function is called with the syntax:

 *            pthread_create(..,..,..,sigcatch,0);  where sigcatch

 *         is the name of this function to process the signals.

 *

 * Change Log:

 *

 *************************************************************************/

 

#include <stdio.h>

#include <pthread.h>

#include <dce/rpc.h>

 

/* Global Definitions */

extern char     *pnm;

extern char     msg[144];

extern int      signo;      /* Signal number causing a termination */

pthread_addr_t       sigcatch(pthread_addr_t); /*signal handling thread fn */

void            tmsg();  /* time-stamp messages */

 

 

/***************************************************************************

 * sigcatch

 *

 * This is the routine that the signal catching thread executes.  It waits

 * for a fatal asynchronous signal, then tells the server to stop listening

 * for further requests and to allow current requests to finish before

 * returning from rpc_server_listen.

 **************************************************************************/

pthread_addr_t sigcatch(pthread_addr_t arg)

{

/* PROBLEM! - This is quite serious that we can't respond to signals */

/* under WIN32!  These API's are simply not supported.  We need a    */

/* work-around.                                                      */

#ifndef WIN32

  sigset_t mask;                    /* bit mask of signals for which we want

                                       notification */

  error_status_t st;

 

/*

 * initialize the signal mask.  Turn on the bits corresponding to

 * SIGINT, SIGQUIT, SIGTERM, SIGUSR1, etc

 */

#ifdef DEBUG

  sprintf(msg, "%s(sigcatch): to initialize", pnm);

  tmsg(msg);  /* issue debug msg */

#endif

  sigemptyset(&mask);

  sigaddset(&mask, SIGINT);

  sigaddset(&mask, SIGQUIT);

  sigaddset(&mask, SIGTERM);

  sigaddset(&mask, SIGUSR1);

#ifdef cray

  sigaddset(&mask, SIGSHUTDN);

#endif

 

#ifdef DEBUG

  sprintf(msg, "%s(sigcatch): mask has been set : %08x", pnm, mask);

  tmsg(msg);

#endif

 

/*

 * Calling sigwait will cause this thread to block until the process receives

 * one of the signals in the mask.  In this case the mask contains SIGTERM,

 * SIGINT, or SIGHUP.  If no threads were waiting for these fatal asynchronous

 * signals and such a signal were received, the process would die immediately

 * without giving the server a chance to unregister its bindings with the

 * endpoint mapper.  sigwait is the only way to catch a fatal asynchronous

 * signal and have the opportunity to cleanup before exiting.

 */

 

#ifdef DEBUG

  sprintf(msg, "%s(sigcatch): await the signal", pnm);

  tmsg(msg);

#endif

 

/*

 * Wait here until a desired signal is reflected to the thread

 */

#ifdef WIN32

  signo = sigsuspend(&mask);

#else

  signo = sigwait(&mask);

#endif

 

/* Stop the server from listening for more requests, and let current

 * requests run to completion.  This routine causes rpc_server_listen

 * to return.

 *

 * Notice that if there are pending RPC's that don't complete in a timely

 * manner, another fatal signal will kill the server.  We no longer have

 * a thread to catch fatal signals.

 */

  sprintf(msg, "%s(sigcatch): Signal %d received!", pnm, signo);

  tmsg(msg);

  rpc_mgmt_stop_server_listening(NULL, &st);

  if (st != rpc_s_ok)

     sprintf(msg, "%s(sigcatch): can't stop server listening:\n\t%s",

             pnm, dcemsg(st));

  else

     sprintf(msg, "%s(sigcatch): stopped server listening", pnm);

  tmsg(msg);

#endif // Not WIN32

 

  pthread_exit((pthread_addr_t)NULL);

}

 

#ifdef WIN32

BOOL SignalHandlerRoutine(DWORD dwCtrlType)

{

       BOOL   fRC;

       error_status_t st;

 

       switch (dwCtrlType)

       {

              case CTRL_C_EVENT:

              case CTRL_BREAK_EVENT:

              case CTRL_CLOSE_EVENT:

              case CTRL_LOGOFF_EVENT:

              case CTRL_SHUTDOWN_EVENT:

                     sprintf(msg, "%s(SignalHandlerRoutine): Signal %lu received!", pnm, dwCtrlType);

                     signo=dwCtrlType;

                     tmsg(msg);

                     rpc_mgmt_stop_server_listening(NULL, &st);

                     if (st != rpc_s_ok)

                           sprintf(      msg, "%s(SignalHandlerRoutine): can't stop server listening:\n\t%s",

                                                pnm, dcemsg(st));

                     else

                           sprintf(msg, "%s(SignalHandlerRoutine): stopped server listening", pnm);

                     tmsg(msg);

                     fRC=TRUE;

                     break;

 

              default:

                     fRC=FALSE;

                     break;

       }

 

       return(fRC);

}

#endif

 

 


FILE:str_handle.c

/*************************************************************************

 * Utility Function:  str_handle.c - Convert and return a DCE binding_handle

 *

 * Author:   G.K. Springer

 * Date:     March 1993

 * Node:     condor.cs.missouri.edu

 * Place:    Computer Science Department, University of Missouri-Columbia

 *

 * Purpose:  Utility Function to convert a DCE binding_handle to text

 *

 * Function: Convert handle to a string and return string to caller.

 *

 * Syntax: This is a utility function called from an application:

 *             x = p_handle(rh, string);

 *         where:

 *            x  - is an int containing a DCE error status code

 *            rh - is a rpc_binding handle in DCE

 *           str - is a string to contain the converted handle

 *                 (max length of string is 64 bytes)

 *

 * Change Log:

 *

 *************************************************************************/

 

/* Include Standard C Definitions */

#include <stdio.h>

#include <sys/types.h>

#ifdef WIN32

#include <winsock.h>

#else

#include <sys/socket.h>

#include <netinet/in.h>

#include <netdb.h>

#include <arpa/inet.h>

#endif

 

/* Include DCE Definitions */

#include <dce/rpc.h>  /* DCE RPC definitions */

 

unsigned32 str_handle(rpc_binding_handle_t rh, char *str)

{

   unsigned32      st;  /* DCE status codes from calls */

   struct in_addr  haddr;  /* binary host addr in network order */

   struct in_addr  *ahaddr=&haddr;

   unsigned_char_t *string_binding;  /* String format of binding info */

   unsigned_char_t *uuid, *protseq, *netaddr, *endpoint, *netopt;

   struct hostent  *hp, *gethostbyaddr();

   char            cvthand[64];

  

/* convert binding handle to string representation */

   rpc_binding_to_string_binding(rh, &string_binding, &st);

   if(st != rpc_s_ok){

      strcpy(str,"Couldn't convert binding to string binding");

      return st;

      }

 

/* Parse the string into its component parts */

   rpc_string_binding_parse (string_binding, &uuid, &protseq, &netaddr,

                             &endpoint, &netopt, &st);

   if (st != rpc_s_ok) {

      strcpy(str,"Can't parse string binding");

      return st;

      }

 

/*

 * Use net address to get full Inet name of server host

 */

   haddr.s_addr=inet_addr(netaddr);

   hp = gethostbyaddr((char *) ahaddr, 4, AF_INET);

/* Print the binding information */

   if (hp == NULL)

      sprintf(cvthand,"%s[%s]-%s\0", (char *) netaddr, (char *) endpoint,

              (char *) protseq+9);

   else

      sprintf(cvthand,"%s[%s]-%s\0", hp->h_name, (char *) endpoint,

              (char *) protseq+9);

   if (strlen(cvthand) < 64) {

      strcpy(str, cvthand);

      }

   else {

      strncpy(str,cvthand, 63);

      *(str+63) = '\0';

      }

  

/* Free string when done */

   rpc_string_free(&string_binding, &st);

/*   if (st != rpc_s_ok) printf("Can't free rpc string\n"); */

   if (strlen((char *) endpoint) == 0) return 1;  /* endpoint not available */

   else return st;

}  /* end str_handle() */

 

 


FILE:s_handle.c

 

/*************************************************************************

 * Utility Function:  s_handle.c - Sort out unique servers in binding vector

 *

 * Author:   G.K. Springer

 * Date:     February 1996

 * Node:     condor.cs.missouri.edu

 * Place:    Computer Science Department, University of Missouri-Columbia

 *

 * Purpose:  Utility Function to sort out what unique DCE servers exist

 *           within a set of binding handles contained in a binding vector.

 *

 * Function: Determine the unique servers contained in a binding vector and

 *           return the number of servers found as well as an array of

 *           indexes which point to the binding vector position where the

 *           first handle of a server is located.

 *

 * Syntax: This is a utility function called from an application:

 *             x = p_handle(rh);

 *         where:

 *            x  - is an int containing a DCE error status code

 *            rh - is a rpc_binding handle in DCE

 *

 * Change Log:

 *

 *************************************************************************/

 

/*

 * Standard C Include files

 */

#include <stdio.h>

#ifndef WIN32

#include <unistd.h>

#include <sys/errno.h>

#else

#include <errno.h>

#endif

#include <stdlib.h>

#include <sys/types.h>

 

/* Include DCE Definitions */

#include <pthread.h>

#include <dce/rpc.h>  /* DCE RPC definitions */

#include <dce/rpcexc.h>

 

int s_handle(int tot_h, int *t_srv, rpc_binding_vector_t *b,

                    int *index, int *protidx)

/* Parameters

   [in]      tot_h  - Number of handles in the binding vector

   [out]     t_srv  - Number of distinct servers in the vector

   [in]      b      - binding vector of handles to traverse

   [out]     index  - index into vector where 1st handle of a server is

   [out]     protidx - index of 1st server handle with a protocol this system

                       will communicate with.

 */

 

{

   unsigned32      st;  /* DCE status codes from calls */

   unsigned_char_t *string_binding[2];  /* String format of binding info */

   unsigned_char_t *uuid[2], *netaddr[2], *protseq[2];

   int             i, j, k;          /* temp counters */

  

   *index = 0;  /* 1st handle is always unique */

   *protidx = -1; /* Unverified protocol for this handle */

   *(index+1) = tot_h;  /* assume all entries are same server */

   *t_srv = 1;    /* so we have 1 server at least */

   j = 0;  /* index of server we are interested in right now */

   k = 1;  /* index of server to determine if is same as one we are viewing*/

 

   rpc_binding_to_string_binding(b->binding_h[0], &string_binding[j], &st);

   /* Parse the string into its component parts */

   rpc_string_binding_parse (string_binding[j], &uuid[j], &protseq[j],

                             &netaddr[j], NULL, NULL, &st);

   if (st != rpc_s_ok) return 1;  /* return with an error */

 

/* see if our system supports this server protocol sequence */

   rpc_network_is_protseq_valid(protseq[j], &st);

   if (st == rpc_s_ok) *protidx = 0;  /* yes we are okay here */

   else  *protidx = -1;  /* this protocol not supported */

 

/* Loop thru all binding handles and find unique servers */

   for (i=1; i<tot_h; i++)  {

/* convert binding handle to string representation */

   rpc_binding_to_string_binding(b->binding_h[i], &string_binding[k], &st);

   if (st != rpc_s_ok) return 1;

 

/* Parse the string into its component parts */

   rpc_string_binding_parse(string_binding[k], &uuid[k], &protseq[k],

                            &netaddr[k], NULL, NULL, &st);

   if (st != rpc_s_ok) return 1;

 

   if ((strcmp(uuid[j],uuid[k])!=0)||(strcmp(netaddr[j],netaddr[k]) != 0)) {

      /* we have a new server so keep track of it */

       *(index+*t_srv) = i;  /* save index of handle */

       rpc_network_is_protseq_valid(protseq[k], &st);

       if (st == rpc_s_ok) *(protidx+*t_srv) = i;  /* yes we are okay here */

       else *(protidx+*t_srv) = -1;  /* this is not supported */

       *t_srv += 1;        /* incr server count */

       j ^= 1;  /* reverse the subscript of main server info to scan */

       k ^= 1;  /* reverse subscript of the new server to look at */

       }

   else { /* Same server, so see if we have a supported protocol or not */

      if (*(protidx+*t_srv-1) == -1) {

         rpc_network_is_protseq_valid(protseq[k], &st);

         if (st == rpc_s_ok) *(protidx+*t_srv-1) = i; /* yes we are okay here */

         }

      } /* end else */

 

   /* Free the strings of server we no longer need to consider */

   rpc_string_free(&uuid[k], &st);  /* Free uuid str */

   rpc_string_free(&netaddr[k], &st);  /* Free netaddr str */

   rpc_string_free(&protseq[k], &st);  /* Free protseq str */

   rpc_string_free(&string_binding[k], &st);  /* Free binding str */

   }  /* end for loop */

 

/* Free the strings of server we no longer need to consider */

   rpc_string_free(&uuid[j], &st);  /* Free uuid str */

   rpc_string_free(&netaddr[j], &st);  /* Free netaddr str */

   rpc_string_free(&protseq[j], &st);  /* Free protseq str */

   rpc_string_free(&string_binding[j], &st);  /* Free binding str */

   *(index+*t_srv) = tot_h;  /* save index of last handle in vector */

   return 0;

}  /* end s_handle() */

 

 


FILE:TMSG.C

/*************************************************************************

 * Utility Function:  tmsg.c - Write a time-stamped message to stdout

 *

 * Author:   G.K. Springer

 * Date:     June 1991

 * Node:     condor.cs.missouri.edu

 * Place:    Computer Science Department, University of Missouri-Columbia

 *

 * Purpose:  Utility Function to write time-stamped messages

 *

 * Function: Create a time-stamp and preface msg with this stamp % thread

id

 *

 * Syntax: This function is called with the syntax:

 *            tmsg(msg)     where: msg is a pointer to the message

 *

 * Change Log:

 *  04/22/94 - add the thread id of the caller of this routine

 *************************************************************************/

 

#include <stdio.h>

#include <time.h>

#include <pthread.h>

 

void tmsg(msg)

  char    *msg;        /* message to output */

{

  time_t     btime;       /* holds clock value */

  char       *timestamp;  /* pointer to converted timestamp */

  pthread_t  thid;     /* thread id of the caller */

 

  time(&btime);  /* get current TOD */

  timestamp = ctime(&btime);  /* get TOD string */

  thid = pthread_self();  /* get thread id of caller */

  *(timestamp+19) = 0;  /* Terminate string after the time field */

  fprintf(stdout,"%s[%02d]  %s\n",

          timestamp, thid.field2, msg);  /* print the msg */

  fflush(stdout);  /* force out the message */

  return;

}  /* end tmsg() */

 

 


FILE:z.sigtest.c

/*************************************************************************

 * Test Program:  sigtest.c  - Test Thread Signal Handling on Cray C90

 *

 * Author:   G.K. Springer

 * Date:     February 1994

 * Node:     condor.cs.missouri.edu

 * Place:    Computer Science Department, University of Missouri-Columbia

 *

 * Purpose:  Test how Thread signals are handled on a Cray C90.

 *

 * Function: Main program sets up a dedicated thread to process asynchronous

 *           signals in the function sigcatch().  Upon creation of the

 *           thread, main() yields to this thread to initialize the signal

 *           mask and then issue a sigwait() to await the desired signal.

 *           Upon receiving the signal, sigcatch sets the variable done=1

 *           which will be inspected by main() after each sleep().  main()

 *           issues a sleep() for 15 secs and will continue to do so in a

 *           loop until done=1.  If it gets the opportunity to do so, it will

 *           then terminate the execution of main().

 *

 *           sigcatch() initializes by setting the signals it wants to trap

 *           and setting the thread to be the highest priority thread in the

 *           FIFO scheduling queue.  It then issues a sigwait() to block the

 *           thread until the signal is intercepted.  Upon trapping the

 *           desired signal, it prints a message and sets done=1 and then

 *           does a pthread_exit() so this thread will shutdown completely.

 *           main() is set so it will ignore the thread termination, but

 *           will, itself, terminate when the variable done=1 is set.

 *

 * Syntax:   the program is called with no command line arguments, but

 *           should be placed in the background so that desired signals

 *           can be thrown its way. (viz., kill -USR1  pid)

 *           If signal is trapped, it may take up to 15 secs before the

 *           main() function terminates since it is sleeping and will only

 *           look for done=1 after it awakens each time.

 *

 * Compilation:  This code is compiled using the command line:

 *           cc -o sigtest -Dcray -I/usr/include/dce -ldce sigtest.c

 *

 * Change Log:

 *

 * NOTES:

 *     I have determined that signals not generally set for a process

 *     (such as SIGUSR1 and SIGSHUTDN) can be trapped via this code.  Thus,

 *     I have a temporary workaround for my DCE server code...namely, I can

 *     issue a kill -USR1  server_pid when I want the server to shutdown

 *     gracefully.  However, signals like SIGTERM should also work, but they

 *     don't.  I cannot get control in the signal handling thread for signals

 *     that I would normally take to be asynchronous...SIGQUIT, SIGINT,

 *     SIGTERM, etc.  Since the signal handling thread is the highest

 *     priority in the FIFO queue, I would like to hope that IT would be

 *     the thread to receive the signal before any other thread would be

 *     the recipient of such signals.  If it was, at least in my case, it

 *     would cause all other threads to obey a "terminate" request since

 *     my server signal handler would issue a rpc_stop_server_listening()

 *     request and all would go according to plan to allow the server to

 *     shutdown gracefully.  Except for handling the standard asynch signals,

 *     which works on all other platforms I have tried (DEC, IBM AIX, HP/UX),

 *     it would be helpful if these signals could be reflected to threads

 *     on the Cray in much the same way.

 *

 *     Of the signals actually specified to be trapped, only SIGUSR1 and

 *     SIGSHUTDN are actually trapped and give this test program the

 *     opportunity to shutdown naturally.

 *

 *            /gks

 *************************************************************************/

/*

 * Standard C Include files

 */

#include <stdio.h>

#include <unistd.h>

#include <stdlib.h>

/*

#include <sys/types.h>

*/

#include <sys/errno.h>

#include <pthread.h>

#include <dce/rpc.h>

#include <time.h>

 

char            *pnm;                   /* program name pointer for msgs */

char            msg[144];               /* For time-stamped messages */

int             done = 0;  /* done=1 tells main() to terminate execution */

int             signo;      /* Signal number causing a termination */

pthread_addr_t       sigcatch(pthread_addr_t); /*signal handling thread fn */

void            tmsg();  /* time-stamp messages */

 

 

/***************************************************************************

 * Server Main Program

 ***************************************************************************/

main(int argc, char **argv)

{

  double         dum1;  /* Force vars to align on a double boundary */

  unsigned32     st;    /* DCE status return codes on calls */  /*CRAY*/

  int            i;     /* loop index */

  pthread_t      refresh_thread;   /* refresh thread to keep server

                                    * sec_credentials active */

  pthread_t      sigcatch_thread;  /* signal catching thread for

                                    * graceful shutdowns */

  int            thread_status;

  unsigned32     thread_stk_size;  /* stack size for threads */

  pthread_attr_t attr;  /* attributes of a thread */

 

/************************************************************************

 *   Start of main program

 ************************************************************************/

  pnm = *argv;  /* keep pointer to program name */

  printf("\n");

  sprintf(msg, "%s: Server starting execution...", pnm);

  tmsg(msg);

 

/*

 * Setup dedicated thread to catch asynchronous signals to allow a

 * graceful shutdown.  This allows for unregistering the server

 * before server termination.

 */

 

/* start the signal catching thread */

   thread_status = pthread_create(

                   &sigcatch_thread,    /* store thread id to detach */

                   pthread_attr_default,/* use default thread attributes */

                   sigcatch,            /* start executing in sigcatch() */

                   0);                  /* argument to sigcatch routine */

 

   if (thread_status != 0){

      sprintf(msg, "%s: pthread_create failed: errno = %d", pnm, errno);

      tmsg(msg);

      exit(EXIT_FAILURE);

     }

 

/*

 * we're not interested in a return value from sigcatch_thread, so allow

 * the runtime to reclaim storage when this thread finishes.

 */

   thread_status = pthread_detach(&sigcatch_thread);

   if (thread_status != 0){

      sprintf(msg, "%s: pthread_detach failed: errno = %d", pnm, errno);

      tmsg(msg);

      exit(EXIT_FAILURE);

     }

 

/* force a context switch to the signal catching thread */

   pthread_yield();  /* allow the thread to setup its signal handling */

 

/*  Now we just wait until one of the signals is issued that we want to

    trap.  Signal handler will set done=1 when the signal is trapped

*/

   while (! done) {

      printf("still waiting\n"); fflush(stdout);

      sleep(15);

      }

 

   sprintf(msg, "%s: Server shutting down...",pnm);  /* Tellem we're going */

   tmsg(msg);

   exit(0);   /* exit gracefully as we go down */

}  /* end main() */

 

 

 

/*************************************************************************

 * Include File:  sigcatch.h - Thread function to catch asynchronous signals

 *

 * Author:   G.K. Springer

 * Date:     February 1994

 * Node:     condor.cs.missouri.edu

 * Place:    Computer Science Department, University of Missouri-Columbia

 *

 * Purpose:  Utility Function to catch asynchronous signals in DCE environ.

 *

 * Function: Server creates a thread to catch asynchronous signals and

 *           this function does the processing when the desired signal

 *           is detected.  It sits in a thread_wait condition until the

 *           signal actually occurs.

 *           When it awakens, it tells a DCE server to quit listening and

 *           to shut itself down gracefully.

 *

 * Syntax: This function is called with the syntax:

 *            pthread_create(..,..,..,sigcatch,0);  where sigcatch

 *         is the name of this function to process the signals.

 *

 * Change Log:

 *

 *************************************************************************/

 

 

 

/***************************************************************************

 * sigcatch

 *

 * This is the routine that the signal catching thread executes.  It waits

 * for a fatal asynchronous signal, then tells the server to stop listening

 * for further requests and to allow current requests to finish before

 * returning from rpc_server_listen.

 **************************************************************************/

pthread_addr_t sigcatch(pthread_addr_t arg)

{

  sigset_t mask;                    /* bit mask of signals for which we want

                                       notification */

  error_status_t st;

  pthread_t      my_id; /* thread id for this thread */

  int         i;

                                     

/* initialize the signal mask.  Turn on the bits corresponding to

 * SIGTERM, SIGINT, etc.

 */

  sprintf(msg, "%s(sigcatch): to initialize", pnm);

  tmsg(msg);

  my_id = pthread_self();  /* determine who we are */

 

/* Setup an empty signal mask and then add members to the set and

 * test to see that the signal was actually added to the set.

 */

  sigemptyset(&mask);

  printf("sigcatch: emptyset mask=%08x\n",mask);

  sigaddset(&mask, SIGHUP);

  i = sigismember(&mask, SIGHUP);

  printf("sigcatch: SIGHUP  mask=%08x,  i=%d\n",mask,i);

  sigaddset(&mask, SIGTERM);

  i = sigismember(&mask, SIGTERM);

  printf("sigcatch: SIGTERM  mask=%08x,  i=%d\n",mask,i);

  sigaddset(&mask, SIGINT);

  i = sigismember(&mask, SIGINT );

  printf("sigcatch: SIGINT   mask=%08x,  i=%d\n",mask,i);

  sigaddset(&mask, SIGQUIT);

  i = sigismember(&mask, SIGQUIT);

  printf("sigcatch: SIGQUIT  mask=%08x,  i=%d\n",mask,i);

  sigaddset(&mask, SIGUSR1);

  i = sigismember(&mask, SIGUSR1);

  printf("sigcatch: SIGUSR1  mask=%08x,  i=%d\n",mask,i);

#ifdef cray

  sigaddset(&mask, SIGSHUTDN);

  i = sigismember(&mask, SIGSHUTDN);

  printf("sigcatch: SIGSHUTDN  mask=%08x,  i=%d\n",mask,i);

#endif

  sprintf(msg, "sigcatch: mask has been set : %08x",mask);

  tmsg(msg);

 

/*

 * Calling sigwait will cause this thread to block until the process receives

 * one of the signals in the mask.  In this case the mask contains SIGTERM,

 * SIGINT, etc.  If no threads were waiting for these fatal asynchronous

 * signals and such a signal were received, the process would die immediately

 * without giving the server a chance to unregister its bindings with the

 * endpoint mapper.  sigwait is the only way to catch a fatal asynchronous

 * signal and have the opportunity to cleanup before exiting.

 */

 

/* set our scheduling policy so we guarantee getting control when a signal

 * comes into us asynchronously

 */

  signo = pthread_setscheduler(my_id, SCHED_FIFO, PRI_FIFO_MAX);

  if (!signo) {

     sprintf(msg, "sigcatch: setscheduler failed st=%d\n", signo);

     tmsg(msg);

     }

 

  tmsg("sigcatch: will await a signal");

  signo = sigwait(&mask);

  tmsg("sigcatch: after the signal");

 

/* Stop the server from listening for more requests, and let current

 * requests run to completion.  This routine causes rpc_server_listen

 * to return.

 *

 * Notice that if there are pending RPC's that don't complete in a timely

 * manner, another fatal signal will kill the server.  We no longer have

 * a thread to catch fatal signals.

 */

 

  sprintf(msg, "sigcatch: Signal %d received!", signo);

  tmsg(msg);

  tmsg("sigcatch: stopped server listening");

 

  done = 1; /* here we just set done so main() will quit after its wait */

  pthread_exit((pthread_addr_t)NULL);  /* terminate this thread */

}  /* end sigcatch() */

 

 

/*************************************************************************

 * Utility Function:  tmsg.c - Write a time-stamped message to stdout

 *

 * Author:   G.K. Springer

 * Date:     June 1991

 * Node:     condor.cs.missouri.edu

 * Place:    Computer Science Department, University of Missouri-Columbia

 *

 * Purpose:  Utility Function to write time-stamped messages

 *

 * Function: Create a time-stamp and preface msg with this stamp

 *

 * Syntax: This function is called with the syntax:

 *            tmsg(msg)     where: msg is a pointer to the message

 *

 * Change Log:

 *

 *************************************************************************/

 

void tmsg(msg)

  char    *msg;        /* message to output */

{

  time_t  btime;       /* holds clock value */

  char    *timestamp;  /* pointer to converted timestamp */

 

  time(&btime);  /* get current TOD */

  timestamp = ctime(&btime);  /* get TOD string */

  *(timestamp+20) = 0;  /* Terminate string after the time field */

  fprintf(stdout,"%s  %s\n", timestamp, msg);  /* print the msg with TOD */

  fflush(stdout);  /* force out the message */

  return;

}  /* end tmsg() */

 


INCLUDE Subproject

 

 

FILE:DAEMON.H

/*************************************************************************

 * DCE Utility DAEMON.H    - Function to turn server into a daemon process

 *

 * Author:   G.K. Springer

 * Date:     March 1994

 * Node:     condor.cs.missouri.edu

 * Place:    Computer Science Department, University of Missouri-Columbia

 *

 * Purpose:  Utility function to run a server as a daemon process.

 *

 * Function: Contains the code needed to run a server as a daemon process.

 *           If root starts this process, use setuid and setgid to be those

 *           of the server "principal" so root never runs the process.

 *

 * Syntax:   This function is called using the syntax:

 *              x = daemon_init();

 *           Where: x=0 if successful and x=-1 if forking fails.

 *           Note:  parent process terminates here if fork was successful

 *                  and only the child (the daemon process) continues.

 *

 * Change Log:

 *    06/27/95 - GKS - Added code to change the uid and gid of process if

 *                     root is the one starting the program.  This removes

 *                     the need to set the suid bit on the linked module.

 *

 *************************************************************************/

#ifndef WIN32

#include <pwd.h>  /* make sure we have the pw entry structure defined */

#endif

 

/**************************************************************************

 * daemon_init() - create a child process of server to run as a daemon

 **************************************************************************/

int daemon_init(void)

{

#ifndef WIN32

  uid_t   uid;  /* UID of user: "principal" defined im musrv.h */

  gid_t   gid;  /* GID of group: "principal"s gid */

  int     i1, i2;

  struct passwd  *pwentry;

 

/* If we start as root, change to the proper UID and GID */

  uid=getuid();

  if (uid == 0) {

     if ((pwentry=getpwnam(principal)) == NULL) {

        sprintf(msg, "%s: Unable to get pw entry for %s\n", pnm, principal);

        tmsg(msg);

        return(-1);  /* return with a failure */

        }

     else {

        uid = pwentry->pw_uid; /* get uid from passwd entry */

        gid = pwentry->pw_gid; /* get gid from passwd entry */

        i2 = setgid(gid);  /* set new gid */

        i1 = setuid(uid);  /* set new uid */

#ifdef DEBUG

        sprintf(msg, "%s: running as %s uid=%d and gid=%d\n", pnm, principal,

           uid, gid);

        tmsg(msg);

#endif

        }

     }  /* end test for root starting the process */

 

/* Now we become a daemon under the new UID and GID if changed */

  if ((pid=fork()) < 0)  {

     return(-1);  /* The fork failed so we return with error */

     }

  else  if (pid != 0)  {

#ifdef SILENT

     sprintf(msg, "%s: daemon process id is: %d", pnm, pid);

     tmsg(msg); /* last gasp for the parent process */

#endif

     exit(0);  /* the parent goes away */

     }

 

/*  The child process continues as a daemon process */

  setsid();    /* become a session leader */

  umask(027);  /* mak