The client uses this function to establish LPC communication with the server. The name of the port to connect to is specified as a Unicode string in the PortName parameter. The second parameter, unknown at this time, cannot pass as NULL because the function fails the validation checks otherwise. The third parameter operates only when you use the shared section LPC. It is a pointer to a structure, described as follows:
The Length field in this structure specifies the size of the structure; it is always set to 24. The caller of this functionthe clientfills the SectionHandle and SectionSize fields, apart from the Length. The CreateFileMapping() function can create a shared section of required size. Upon return from the NtConnectPort() function, the ClientBaseAddress and ServerBaseAddress fields, in the LPCSECTIONINFO structure, contain the addresses where the section is mapped in the client address space and the server address space, respectively.
The next parameter to the NtConnectPort() functionmapInfoalso functions only for the shared section LPC. This parameter is a pointer to a structure described as follows:
This structure duplicates the information in the LPCSECTIONINFO structure. The client needs to fill only the Length field, which it always sets to 12the size of the structure. We have not been able to decipher the significance of passing this structure to the NtConnectPort() function. Still, you have to pass a valid structure; if you pass a NULL pointer, the function fails. We have observed that the two members of the structure, namely, SectionSize and ServerBaseAddress, zero out on return from the function.
We do not know the next parameter sent to the NtConnectPort() function, so set it as NULL.
The client can send some information to the server with the connection request. The server receives this information via the LPC message, which it gets from the NtReplyWaitReceivePort() function in case of a connection request. The ConnectInfo parameter points to this connection information. The size of the connection information passes through the pConnectInfoLength parameter that is a pointer to a double word. The server, also, can send back some information to the client at connection time. This information returns in the same ConnectInfo buffer, and the pConnectInfoLength is set to indicate the length of the returned connection information.
This function is used by the server side of LPC to receive requests from clients and reply to them. The first parameter is the port handle obtained from the NtCreatePort() function. The second parameter, currently unknown, can be passed as NULL. The third parameter is the message that serves as a reply to the previous client request. This parameter can be NULL, in which case the function simply accepts a request from the client. The fourth parameter, a pointer to a LpcMessage structure, fills, on return from the function, with the request information. Both the third and the fourth parameters are pointers to the LpcMessage structure, which we display here.
The ActualMessageLength field is set to the size of the actual message stored in the MessageData field, whereas the TotalMessageLength is set to the size of the entire LpcMessage structure along with the MessageData. The system, not the client-server, sets the MessageType field. There are several message types. We detail the important ones:
LPC_REQUEST
The server receives this type of message when a client sends a request using the NtRequestWaitReplyPort() function. The server should reply to this message using the NtReplyPort() function or the NtReplyWaitReceivePort() function. The server should not reply to any messages other than the LPC_REQUEST messages. The NtRequestWaitReplyPort() function waits until it gets the reply from the server and then returns the reply message to the client. Effectively, the client thread that calls the NtRequestWaitReplyPort() function hangs if the server does not send a reply message.
LPC_REPLY
The client receives this type of message from the NtRequestWaitReplyPort() function, when the server replies to the request.
LPC_DATAGRAM
The server receives this type of message when a client sends a request using the NtRequestPort() function. As the name of the message type implies, the client does not get a reply from the server for this kind of message. If the server tries to reply to this message using the NtReplyPort() function or the NtReplyWaitReceivePort() function, the function fails and returns an error.
LPC_PORT_CLOSED
The server receives this type of message when a client closes the port handle. If a client dies without closing the port handle, the operating system closes the handle on behalf of the client. Thus, the server gets the LPC_PORT_CLOSED message in any case and can use it to free the per-client resources it allocates.
LPC_CLIENT_DIED
The server receives this type of message when a client dies. Refer to the description of the NtRegisterThreadTerminatePort() function for more information.
LPC_CONNECTION_REQUEST
The corresponding server receives this type of message when a client tries to connect to a port using the NtConnectPort() function.
The next fields in the LpcMessage structure are set, by the system, to the clients process ID and thread ID, respectively. The next field is set to the unique message ID generated by the system. The server can rely on these fields because the operating system, not the client, sets them. These fields do not make sense in the messages received by the client and therefore are set to zero in the messages returned by the NtRequestWaitReplyPort() function.
Only the shared section LPC uses the SharedSectionSize field. The system sets this field to the size of the shared section when it passes a LPC_CONNECTION_REQUEST type of message to the server.
The last field is the actual message and is a variable length field. The client-server can choose to allocate only enough memory space to hold the structure parameters and the actual message. When passing a pointer to this structure for receiving a message, you must allocate enough memory space to fit the message the process can send at the other end of the port. If you fail to do it, you will receive an Invalid Access or similar kind of fault. To be on the safer side, you should always allocate for the maximum-sized message while passing a pointer for receiving a message.
Whenever the server receives a connection request, it follows a connection establishment procedure by first calling the NtAcceptConnectPort() function and then the NtCompleteConnectPort() function. This sequence of operations establishes a communication channel between the client and the server. The client end of the channel represents the handle that it gets from the NtConnectPort() function. The first parameter to NtAcceptConnectPort() is a port handle pointer set to another handle to the message port on return. This handle is the server-side end of the communication channel, although the server can use the handle returned from the NtCreatePort() function to accept requests from all clients. The server can close the handle, returned by the NtAcceptConnectPort() function, when it no longer wants to accept requests using the particular communication channel. Any further requests by the client on a closed communication channel will fail.
We have not been able to decipher the second parametergenerally set to zero. The third parameter is the LPC message returned to the client as the connection information from the server. The fourth parameter, named acceptIt, is passed as 0 if the server cannot accept the connection request. The server passes acceptIt as a nonzero value if it can accept the connection request. The fifth parameter, not deciphered yet, can be set to zero. The last parameter is a pointer to the LpcSectionMapInfo structure, which fills with appropriate data upon return. We already explained the members of this structure. This structure supplies shared-section information for future use by the server for communicating with the client.
NtCompleteConnectPort
int _stdcall
NtCompleteConnectPort(
HANDLE PortHandle);
The server finishes the connection procedure with the NtCompleteConnectPort() function. The only parameter to this function is the port handle returned by the previous call to the NtAcceptConnectPort() function. The client waits in the NtCon-nectPort() function until the server completes the connection procedure by calling the NtCompleteConnectPort() function.
NtRequestWaitReplyPort
int _stdcall
NtRequestWaitReplyPort(
HANDLE PortHandle,
PLPCMESSAGE pLpcMessageIn,
PLPCMESSAGE pLpcMessageOut);
The client uses this function to send a request and wait for a reply to/from the server. The first parameter is the port handle obtained via a previous call to the NtConnectPort() function. The pLpcMessageIn parameter is a pointer to a LPC request message sent to the server. The last parameter is a pointer to another LPC message structure that fills with the reply message from the server, on return from the function.
NtListenPort
int _stdcall
NtListenPort(
HANDLE PortHandle,
PLPCMESSAGE pLpcMessage);
This very small function internally uses the NtReplyWaitReceivePort() function. Here we present the pseudocode of this function:
As you can see from this pseudocode, the NtListenPort() function ignores all messages except connection requests. You cannot use this function if servicing multiple clients. While servicing multiple clients, a server gets a mix of connection requests and other client requests. The server needs to sort out the connection requests from the other requests and perform appropriate processing. If only a single client can connect at a time, the server can get the connection request using the NtListenPort() function and then start a loop to accept and process other client requests.
NtRequestPort
int _stdcall
NtRequestPort(
HANDLE PortHandle,
PLPCMESSAGE pLpcMessage);
This function just sends a message on the port and returns. The server thread waiting on this port gets the message and does the required processing. The server thread need not return the results to the caller. In this case, the message type in the header is LPC_DATAGRAM. A message sent using this function resembles a datagram in the sense that the sender does not receive an acknowledgment.
NtReplyPort
int _stdcall
NtReplyPort(
HANDLE PortHandle,
PLPCMESSAGE pLpcMessage);
The server uses this function if it wants to send a reply to the client and does not want to be blocked for the next request from the client. The first parameter to this function is the port handle, and the second parameter is the reply message sent to the client.
NtRegisterThreadTerminatePort
int _stdcall
NtRegisterThreadTerminatePort(
HANDLE PortHandle);
If a client calls this function after connecting to a port, then the operating system sends the LPC_CLIENT_DIED message to the server when the client dies. Even if the client closes the port handle and keeps running, the system maintains a reference to the port. Therefore, the operating system sends the LPC_PORT_CLOSED message after the LPC_CLIENT_DIED message and not after the client closes the port handle.
NtSetDefaultHardErrorPort
int _stdcall
NtSetDefaultHardErrorPort(
HANDLE PortHandle);
The CSRSS subsystem calls this function during its initialization. The NtRaiseHardError() function, called in case of serious system errors, sends a message to the registered hard error port. Hence, the CSRSS subsystem can pop up the message when application startup problems appear. The kernel houses only one set of global variables. These variables store the pointer to the hard error port so only one process can capture system errors. On Windows NT, this happens to be the Win32 subsystem. Calling this function requires special privilege.
Here, we present the pseudocode for this function:
NtSetDefaultHardErrorPort(HANDLE PortHandle)
{
if (PrivilegeNotHeld)
return STATUS_PRIVILEGE_NOT_HELD);
if (ExReadyForErrors == 0) {
Get a pointer to the kernel port object from
PortHandle;
ExpDefaultErrorPort =
pointer to kernel port object;
ExpDefaultErrorPortProcess = CurrentProcess;
ExReadyForErrors = 1;
} else {
return STATUS_UNSUCCESSFUL
}
return STATUS_SUCCESS;
}
Order Your SQL Fundamentals CD Today! Learn how to use SQL Server, understand Office integration techniques and dive into the essentials of SQL Express and Visual Basic with this free SQL Fundamentals CD.
You've Deployed SharePoint...Now What? This one-day free online conference delivers the technical knowledge needed to kick MOSS up a notch. In one information-packed day, independent SharePoint experts will present practical, real-world information and provide take-away, ready-to-use solutions
What Would You Do If You Ran Microsoft? ITTV's 2008 inaugural video contest, "If I Ran Microsoft..." is your chance to tell it like it is. Be goofy or be serious, but don"t miss this chance to have fun, win prizes, and go viral in a major way.
Maximize Your SharePoint Investment This web seminar discusses how true bi-directional replication of SharePoint content from one server to another enables branch offices to maintain access to current SharePoint content.