tinymux/specs/outofproc.txt
2007-09-13 22:50:46 -07:00

149 lines
5.8 KiB
Text

I. Summary.
Custom marshaling uses mux_IMarshal to turn an interface pointer in one
process into a buffer that another process can use to create a proxy. As a
side-effect of doing this, a new association between proxy and server is
created.
How the request to create a server is propagated from client to server, the
communication mechanism, and how new associations are created is much less
specified. These could be anything, but our design needs to be more specific.
Our approach to the design will take two steps:
1. Ignore the communication channel for a moment by going through the
marshaling steps within the same process. The interfaces for doing this
must use only fundamental data types -- no interface pointers.
2. Assume when the communication channel is first established, an instance
of these components and all the associations between them exist a priori.
This first connection is not created. It simply exists.
II. Design Increments.
A. Ignore the real channel.
i. Sequence.
- Call QueryInterface() and get the object's mux_IMarshal interface.
- Call mux_IMarshal::GetUnmarshalClass() to get the proxy CID.
- Call mux_IMarshal::MarshalInterface().
- This allocates a buffer and sets up a callback function. A pointer to
both are included in the marshaled interface packet.
- mux_CreateInstance the proxy with the proxy CID.
- Get the proxy's mux_IMarshal interface.
- Call mux_IMarshal::UnmarshalInterface to obtain the proxy interface.
- The proxy places parameters as necessary in the buffer and calls the
'SendReceive' callback function.
ii. Interfaces.
interface mux_IBootstrap : public mux_IUknown
{
(MUX_CID cidProxy, Custom Marshal Data) RemoteCreateInstance(MUX_CID cid, MUX_IID iid);
};
B. A priori setup.
i. Sequence.
- Setup channel 0 to listen for call frames. This is the a priori
channel.
- When a call frame to channel 0 is received, it will contain cid and iid.
Create the requested object, and get its mux_IMarshal interface. Since
we are using custom marshaling, we assume the mux_IMarshal interface
must exist.
- Get the proxy CID.
- mux_IMarshal::MarshalInterface() allocates a new channel (e.g., 1)
and sets up a callback function to receive data from that channel.
- The interface pointer for the created object is saved as a channel
attribute.
- The allocated channel number is included in the Custom Marshal Data.
- A return frame is constructed which includes the proxy CID and the new
channel number. The ToChannel of this return frame is 0. The new
channel number is contained in the Custom Marshaled Data.
- mux_CreateInstance the proxy with the proxy CID.
- Call mux_IMarshal::UnmarshalInterface with the new channel number.
- Depending on how the low-level transport is implemented, it may need the
new channel number. The proxy would inform the lower-level of the new
channel at this time.
- The proxy is now able to communicate with its component.
Notice that the receiver assigns the channel number. The sender and
receiver always use the receiver-assigned channel number. The two
processes maintain their channel numbers indepdendently. For example,
they could both assign channel 10 to different associations. Channel 10
in netmux would have nothing to do with channel 10 in the stubslave.
A return frame should necessarily match the last outstanding call frame.
This design does not support Message Frames to callers. There's no
associated function to handle an unexpected incoming frame. Only callees
can receive Message Frames.
C. Standard Marshaling.
As discussed above, while custom marshaling leaves the transport details
out, a minimum implementation across a Unix pipe requires channels and a
callback function on the callee side.
We can implement standard marshaling on top of this using one callback
function for the stub manager, and there needs to be only one stub
manager. The stub manager is part of the standard marshaling, there is
only one, and it isn't used by anyone else directly.
One could argue that either type of marshaling can be built on top of the
other, but it is helpful at this stage of development to see that our
implementation of custom marshaling supports interfaces while depending
only on transport-related function calls. Likewise, our implementation
of standard marshaling provides a transport-independent framework while
depending on an internal instance of custom marshaling.
In other words, we enable others to marshal their interfaces with our
custom or standard marshaling interfaces, but we are using custom marshaled
interfaces ourselves to provide standard marshaling, we can't share it,
and we don't need to share it.
III. Packet Format.
A. Call Frame.
CallMagic 0xC39B71F9
Length 0x--------
ToChannel 0x--------
Data..................
......................
......................
EndMagic 0x27118B26
B. Return Frame.
ReturnMagic 0x35972DD0
Length 0x--------
ToChannel 0x--------
Data..................
......................
......................
EndMagic 0x27118B26
C. Message Frame (non-blocking).
MsgMagic 0xF69E1836
Length 0x--------
ToChannel 0x--------
Data..................
......................
......................
EndMagic 0x27118B26
D. Disconnect Frame.
DiscMagic 0x960AA381
Length 0x--------
ToChannel 0x--------
Data..................
......................
......................
EndMagic 0x27118B26