			Brutus Design Overview

Author:
	Jules Colding <colding@omesc.com>
	Copyright (C) 2004-2006, OMC Denmark ApS


License:
        Copying and distribution of this file, with or without modification,
        are permitted in any medium without royalty provided the copyright
        notice and this notice are preserved.


FILES:

*	main.cpp:
	This files does command line processing and starts the server process.
	
*	ntsvc.cpp.
	Contains all of the NT service functionality. 

	All of the main initialization work is done in svc().
	The orb, the root poa and the root poa manager are bootstrapped in
	svc().

	svc():
	The Brutus naming root is created after bootstrapping of the
	Name Service. The reference to the BrutusSession object is binded
	to this naming context. The BrutusSession object is responsible for
	Brutus server management functionality.

	A vector of pointers to ManagedBrutusGroup objects is created. Each
	of these ManagedBrutusGroup objects will create and register a
	BrutusLogOn object which serves as a BRUTUS::IMAPISession factory. 
	They will likewise create a child poa to the poa given as parameter 
	to the constructor for ManagedBrutusGroup. 

	This child poa is activated in svc() after creation of the entire
	vector<ManagedBrutusGroup*>. The poa for the ManagedBrutusGroup
	happens to be a child of the Brutus root poa <brutus_poa> which is 
	a child of the root poa <root_poa>.

*	managed_group.cpp:
	Implements "class ManagedBrutusGroup". 

	ManagedBrutusGroup will create a child poa from the poa given among
	the constructor arguments. This poa will serve as parent for child
	poas created afterwards for each BrutusSession object in LogOn().

	A BrutusLogOn object will be instantiated in the constructor,
	registered under the ManagedBrutusGroup's poa and binded to this
	group's naming context. The BrutusLogOn object will use the same poa
	as the ManagedBrutusGroup.

	A stack allocated instance of SessionRegistry is created in the
	constructor. A pointer to this instance is given to the BrutusLogOn
	factory object.

*	BrutusLogOnS_impl.cpp
	Implements BrutusLogOn.

	Will use the ManagedBrutusGroup's poa.

	LogOn() will register all sessions in the SessionRegistry object
	given to it in its constructor.


POA Hierachy:

		Root POA
		   |
		   |
	    BrutusSession POA ("BRUTUS_POA")
	           |
		   | 
		   |
	ManagedBrutusGroup POA 
	      ______|____ ___
             /      |        \
IMAPISession POA    |     IMAPISession POA (POA Name = "<MAPI Profile Name>")
 (profile :1)	    |           (profile :n)
            IMAPISession POA
	      (profile :2)


	 The ManagedBrutusGroup POA will have the servant activator for the
	 BrutusLogOn and the BrutusSession POA registered under it.


Bootstrapping:
	Brutus makes use of the corbaloc mechanism as descibed in the TAO FAQ.

	The server key for the BrutusLogOn object is:
   
            BrutusLogOn::IOR_TABLE_KEY
 
	For each BrutusLogOn object there is a BrutusSession object. The server 
	key is named similar to the BrutusLogOn object:

            BrutusSession::IOR_TABLE_KEY

	The BrutusSession object is exposed on the same endpoint as the 
	BrutusLogOn object.


The login process:
	A rather complicated series of events takes place when a Brutus client 
	attempts to logon to a Brutus Server. It goes like this:

	1) A Brutus client invokes CreateProfile() on the BrutusLogOn
	interface. 

	(The remote BrutusLogOn object is actually an object that the client has
	been redirected too when the client ORB received the ForwardRequest
	exception from the initial BrutusLogOn object invocation, but this is an
	implementation detail that is unimportant for the current discussion.)

	2) A MAPI profile is generated. The profile is by default an MMP file
	that is created as C:\MMP\<profile name>.mmp. It is supported to put it
	in the registry, but that would scale poorly.
	
	3) The Brutus client will receive BRUTUS_S_OK to indicate that the
	profile has been created.
	
	4) The newly created profile, or a profile that was created in an
	earlier run, is used in BrutusLogOn::Logon().
	
	5) The first thing that Logon() does is to check that the LifeLine 'in'
	parameter is a valid call-back BrutusCheck reference. 
	
	Now assume that we are working in PROCESS_PER_SESSION enabled mode.
	
	6) BrutusLogOn will now attempt to cause the creation of an impersonated
	proxy process (proxy.exe is the executable) that can host the client
	MAPI session. Brutus Server itself does not spawn the proxy process, but
	more about that later. 
	
	What are the requirements for all of this? 
	
	One very important requirement is that the Brutus Server process will
	need some way to communicate with the proxy process. Remember that the
	client MAPI session is encapsulated within a BRUTUS::IMAPISession CORBA
	object that is incarnated from within the proxy process. The IOR of the
	BRUTUS::IMAPISession object must be returned to the client as an out
	parameter from the BrutusLogOn::Logon() method.
	
	So we have the Brutus Server process and a spawned proxy process. The
	proxy process creates the IOR and must have some way to return that IOR
	to the Brutus Server process so that it can be returned to the client as
	an 'out' parameter from the BrutusLogOn::Logon() method.
	
	The communication between the Brutus Server process and any proxy
	process is the responsibility of the ProxyMgr server. Please take a look
	at the brutus-server/ProxyMgr/proxy_manager.idl interface definition. The
	Proxy Manager is also responsible for the actual spawning of proxy
	processes.
	
	The details of operation are not needed to understand what goes on, but
	please familiarize yourself with the interface if you are curious.
	
	I will now continue the explanation of what goes on during the
	BrutusLogOn::Logon() method invocation.
	
	7) The create_session() function is called by BrutusLogOn::Logon() after
	the LifeLine reference has been validated.
	
	8) create_session() (line 599 onwards in BrutusLogOnS_impl.cpp) starts
	by making sure that it has a valid reference to the Proxy Manager at
	lines 602-613.
	
	9) The user credentials are now passed (at line 623) to the Proxy
	Manager which will store them until they are needed by the session
	proxy. See BRUTUS_ProxyManager_i::setUser() at line 44 in
	ProxyMgr/proxy_managerS_impl.cpp for the implementation. 
	
	10) create_session() will now (at line 644) invoke
	ProxyMgr::getSession() which blocks until a BRUTUS::IMAPISession
	reference is ready. 
	
	11) The first thing that ProxyMgr::getSession() does is to look up the
	user credentials in its local cache (line 178 in
	proxy_managerS_impl.cpp).
	
	12) The Proxy Manager will now spawn a session proxy on behalf of the
	client (line 210 in proxy_managerS_impl.cpp).
	
	13) The Proxy Manager will launch a thread to monitor the proxy process
	(see the comment at line 224).
	
	14) It is now the responsibility of the proxy process itself to drive
	the operations forward. Go to SessionProxy/main.cpp at line 481 to get
	to main().
	
	15) main() starts by initializing the signal handling at line 516.
	
	16) The current working directory is set and error dialogs are disabled
	to make the proxy process run without any user interaction.
	
	17) The configuration is loaded in lines 539-593 and the client ORB is
	initialized at line 596. 
	
	18) The interesting stuff happens at line 633. This is where the proxy
	process is getting the user credentials from the Proxy Manager. Now,
	assuming that the credentials are retrieved without any errors, we
	impersonate the proxy process with the user credentials. This happens at
	lines 651-690.
	
	After impersonating we get ready to start the CORBA subsystem. Just skip
	these trivial tasks and go straight to line 765.
	
	19) At line 765 MAPI is initialized. The LifeLine, as retrieved from the
	ProxyMgr::getUser() method, is transformed from a stringified IOR into a
	real object reference at line 779 and a timeout policy is put onto it at
	line 797. 
	
	The timeout policy will make sure that any prolonged lifeline answer
	times from the client will be treated as a lifeline response failure and
	cause the proxy process to be cleaned up.
	
	20) The create_session() function call at line 812 will create a native
	MAPI session for the client and incarnate a BRUTUS::IMAPISession object
	encapsulating the native MAPI session.
	
	21) The proxy process will now (at line 839) communicate the stringified
	IOR of the BRUTUS::IMAPISession object back to the Proxy Manager by
	invoking ProxyMgr::setSession(). The next thing done by the proxy
	process is merely to start the ORB processing loop at line 875 and start
	to serve client requests.
	
	22) But the game isn't over yet. The client still has to receive the
	BRUTUS::IMAPISession reference. Go back to proxy_managerS_impl.cpp at
	line 224 where we left it while following the creation of the proxy
	process.
	
	23) We are now back in proxy_managerS_impl.cpp and will progress to line
	264. This is a loop that will wait for the spawn status to change. The
	spawn status will change as a result of the proxy process invoking
	ProxyMgr::setSession(). The loop will also (at line 274) check for a
	crashed or otherwise dead proxy process.
	
	24) The SessionIOR 'out' paramter is now populated with a stringified
	version of the BRUTUS::IMAPISession reference as given to the Proxy
	Manager by the proxy process.
	
	25) The ProxyMgr::getSession() method now returns and we can continue
	from create_session() at line 644 in BrutusLogOnS_impl.cpp.
	
	26) The Session 'out' parameter is then, assuming everything went well,
	assigned (at line 694) to the new session reference from
	ProxyMgr::getSession().
	
	27) create_session() will return at line 915 and control is returned to
	Logon() at line 259 which will deliver the new BRUTUS::IMAPISession to
	the Brutus client.


Return values:
       A direct translation "HRESULT ==> BRESULT" will always be 
       attempted. No exceptions will be thrown if MAPI returns a 
       supported value. 

       Of all exceptions only CORBA system exceptions will be actively
       thrown from Brutus. CORBA::NO_MEMORY is the only exeption that 
       is ever explicitely returned from the servant code. 

       The regular CORBA exection rules apply to out and inout method
       parameters upon recieving an exception from Brutus. Please see
       "Advanced CORBA Programming with C++", section 9.8.3.
       
       Only memory allocation failures by the servant implementation 
       will result in CORBA::NO_MEMORY. 

       No exception will be returned if MAPI manages to return 
       E_NOT_ENOUGH_MEMORY. In this case BRUTUS_E_NOT_ENOUGH_MEMORY 
       is returned from the servant.
