Authors: Greg Turner <gmturner007@ameritech.net>, Ove Kaaven <ovek@transgaming.com>
- preliminary implementation of endpoint-mapping via a new on-demand server-ish process - more header fixups - (re)implement RpcEpRegisterA, RpcEpUnregister, and RpcEpResolveBinding using the new rpcss functionality - update the todo list in rpcrt4_main.c a bit - many beautifications and touch-ups - command-line configurable timeout - micro-client imbedded in np_server.c
This commit is contained in:
parent
2db04157c7
commit
d77294a8ec
|
@ -1529,6 +1529,7 @@ programs/regapi/Makefile
|
||||||
programs/regedit/Makefile
|
programs/regedit/Makefile
|
||||||
programs/regsvr32/Makefile
|
programs/regsvr32/Makefile
|
||||||
programs/regtest/Makefile
|
programs/regtest/Makefile
|
||||||
|
programs/rpcss/Makefile
|
||||||
programs/rundll32/Makefile
|
programs/rundll32/Makefile
|
||||||
programs/uninstaller/Makefile
|
programs/uninstaller/Makefile
|
||||||
programs/view/Makefile
|
programs/view/Makefile
|
||||||
|
|
|
@ -19,9 +19,11 @@ C_SRCS = \
|
||||||
ndr_ole.c \
|
ndr_ole.c \
|
||||||
ndr_stubless.c \
|
ndr_stubless.c \
|
||||||
rpc_binding.c \
|
rpc_binding.c \
|
||||||
|
rpc_epmap.c \
|
||||||
rpc_message.c \
|
rpc_message.c \
|
||||||
rpc_server.c \
|
rpc_server.c \
|
||||||
rpcrt4_main.c
|
rpcrt4_main.c \
|
||||||
|
rpcss_np_client.c
|
||||||
|
|
||||||
SUBDIRS = tests
|
SUBDIRS = tests
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
#ifndef __WINE_RPC_BINDING_H
|
#ifndef __WINE_RPC_BINDING_H
|
||||||
#define __WINE_RPC_BINDING_H
|
#define __WINE_RPC_BINDING_H
|
||||||
|
|
||||||
|
#include "wine/rpcss_shared.h"
|
||||||
|
|
||||||
/* don't know what MS's structure looks like */
|
/* don't know what MS's structure looks like */
|
||||||
typedef struct _RpcBinding
|
typedef struct _RpcBinding
|
||||||
{
|
{
|
||||||
|
@ -57,5 +59,8 @@ RPC_STATUS RPCRT4_ExportBinding(RpcBinding** Binding, RpcBinding* OldBinding);
|
||||||
RPC_STATUS RPCRT4_DestroyBinding(RpcBinding* Binding);
|
RPC_STATUS RPCRT4_DestroyBinding(RpcBinding* Binding);
|
||||||
RPC_STATUS RPCRT4_OpenBinding(RpcBinding* Binding);
|
RPC_STATUS RPCRT4_OpenBinding(RpcBinding* Binding);
|
||||||
RPC_STATUS RPCRT4_CloseBinding(RpcBinding* Binding);
|
RPC_STATUS RPCRT4_CloseBinding(RpcBinding* Binding);
|
||||||
|
BOOL RPCRT4_RPCSSOnDemandCall(PRPCSS_NP_MESSAGE msg, char *vardata_payload, PRPCSS_NP_REPLY reply);
|
||||||
|
HANDLE RPCRT4_GetMasterMutex(void);
|
||||||
|
HANDLE RPCRT4_RpcssNPConnect(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,246 @@
|
||||||
|
/*
|
||||||
|
* RPC endpoint mapper
|
||||||
|
*
|
||||||
|
* Copyright 2002 Greg Turner
|
||||||
|
* Copyright 2001 Ove Kåven, TransGaming Technologies
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* TODO:
|
||||||
|
* - actually do things right
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "windef.h"
|
||||||
|
#include "winbase.h"
|
||||||
|
#include "winerror.h"
|
||||||
|
#include "winreg.h"
|
||||||
|
|
||||||
|
#include "rpc.h"
|
||||||
|
|
||||||
|
#include "wine/debug.h"
|
||||||
|
|
||||||
|
#include "rpc_binding.h"
|
||||||
|
|
||||||
|
WINE_DEFAULT_DEBUG_CHANNEL(ole);
|
||||||
|
|
||||||
|
/* The "real" RPC portmapper endpoints that I know of are:
|
||||||
|
*
|
||||||
|
* ncadg_ip_udp: 135
|
||||||
|
* ncacn_ip_tcp: 135
|
||||||
|
* ncacn_np: \\pipe\epmapper (?)
|
||||||
|
* ncalrpc: epmapper
|
||||||
|
*
|
||||||
|
* If the user's machine ran a DCE RPC daemon, it would
|
||||||
|
* probably be possible to connect to it, but there are many
|
||||||
|
* reasons not to, like:
|
||||||
|
* - the user probably does *not* run one, and probably
|
||||||
|
* shouldn't be forced to run one just for local COM
|
||||||
|
* - very few Unix systems use DCE RPC... if they run a RPC
|
||||||
|
* daemon at all, it's usually Sun RPC
|
||||||
|
* - DCE RPC registrations are persistent and saved on disk,
|
||||||
|
* while MS-RPC registrations are documented as non-persistent
|
||||||
|
* and stored only in RAM, and auto-destroyed when the process
|
||||||
|
* dies (something DCE RPC can't do)
|
||||||
|
*
|
||||||
|
* Of course, if the user *did* want to run a DCE RPC daemon anyway,
|
||||||
|
* there would be interoperability advantages, like the possibility
|
||||||
|
* of running a fully functional DCOM server using Wine...
|
||||||
|
*/
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* RpcEpRegisterA (RPCRT4.@)
|
||||||
|
*/
|
||||||
|
RPC_STATUS WINAPI RpcEpRegisterA( RPC_IF_HANDLE IfSpec, PRPC_BINDING_VECTOR BindingVector,
|
||||||
|
PUUID_VECTOR UuidVector, LPSTR Annotation )
|
||||||
|
{
|
||||||
|
RPCSS_NP_MESSAGE msg;
|
||||||
|
RPCSS_NP_REPLY reply;
|
||||||
|
char *vardata_payload, *vp;
|
||||||
|
PRPC_SERVER_INTERFACE If = (PRPC_SERVER_INTERFACE)IfSpec;
|
||||||
|
unsigned long c;
|
||||||
|
RPC_STATUS rslt = RPC_S_OK;
|
||||||
|
|
||||||
|
TRACE("(%p,%p,%p,%s)\n", IfSpec, BindingVector, UuidVector, debugstr_a(Annotation));
|
||||||
|
TRACE(" ifid=%s\n", debugstr_guid(&If->InterfaceId.SyntaxGUID));
|
||||||
|
for (c=0; c<BindingVector->Count; c++) {
|
||||||
|
RpcBinding* bind = (RpcBinding*)(BindingVector->BindingH[c]);
|
||||||
|
TRACE(" protseq[%ld]=%s\n", c, debugstr_a(bind->Protseq));
|
||||||
|
TRACE(" endpoint[%ld]=%s\n", c, debugstr_a(bind->Endpoint));
|
||||||
|
}
|
||||||
|
if (UuidVector) {
|
||||||
|
for (c=0; c<UuidVector->Count; c++)
|
||||||
|
TRACE(" obj[%ld]=%s\n", c, debugstr_guid(UuidVector->Uuid[c]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: Do something with annotation. */
|
||||||
|
|
||||||
|
/* construct the message to rpcss */
|
||||||
|
msg.message_type = RPCSS_NP_MESSAGE_TYPEID_REGISTEREPMSG;
|
||||||
|
msg.message.registerepmsg.iface = If->InterfaceId;
|
||||||
|
msg.message.registerepmsg.no_replace = 0;
|
||||||
|
|
||||||
|
msg.message.registerepmsg.object_count = (UuidVector) ? UuidVector->Count : 0;
|
||||||
|
msg.message.registerepmsg.binding_count = BindingVector->Count;
|
||||||
|
|
||||||
|
/* calculate vardata payload size */
|
||||||
|
msg.vardata_payload_size = msg.message.registerepmsg.object_count * sizeof(UUID);
|
||||||
|
for (c=0; c < msg.message.registerepmsg.binding_count; c++) {
|
||||||
|
RpcBinding *bind = (RpcBinding *)(BindingVector->BindingH[c]);
|
||||||
|
msg.vardata_payload_size += strlen(bind->Protseq) + 1;
|
||||||
|
msg.vardata_payload_size += strlen(bind->Endpoint) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate the payload buffer */
|
||||||
|
vp = vardata_payload = LocalAlloc(LPTR, msg.vardata_payload_size);
|
||||||
|
if (!vardata_payload)
|
||||||
|
return RPC_S_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
/* populate the payload data */
|
||||||
|
for (c=0; c < msg.message.registerepmsg.object_count; c++) {
|
||||||
|
CopyMemory(vp, UuidVector->Uuid[c], sizeof(UUID));
|
||||||
|
vp += sizeof(UUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (c=0; c < msg.message.registerepmsg.binding_count; c++) {
|
||||||
|
RpcBinding *bind = (RpcBinding*)(BindingVector->BindingH[c]);
|
||||||
|
unsigned long pslen = strlen(bind->Protseq) + 1, eplen = strlen(bind->Endpoint) + 1;
|
||||||
|
CopyMemory(vp, bind->Protseq, pslen);
|
||||||
|
vp += pslen;
|
||||||
|
CopyMemory(vp, bind->Endpoint, eplen);
|
||||||
|
vp += eplen;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* send our request */
|
||||||
|
if (!RPCRT4_RPCSSOnDemandCall(&msg, vardata_payload, &reply))
|
||||||
|
rslt = RPC_S_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
/* free the payload buffer */
|
||||||
|
LocalFree(vardata_payload);
|
||||||
|
|
||||||
|
return rslt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* RpcEpUnregister (RPCRT4.@)
|
||||||
|
*/
|
||||||
|
RPC_STATUS WINAPI RpcEpUnregister( RPC_IF_HANDLE IfSpec, PRPC_BINDING_VECTOR BindingVector,
|
||||||
|
PUUID_VECTOR UuidVector )
|
||||||
|
{
|
||||||
|
RPCSS_NP_MESSAGE msg;
|
||||||
|
RPCSS_NP_REPLY reply;
|
||||||
|
char *vardata_payload, *vp;
|
||||||
|
PRPC_SERVER_INTERFACE If = (PRPC_SERVER_INTERFACE)IfSpec;
|
||||||
|
unsigned long c;
|
||||||
|
RPC_STATUS rslt = RPC_S_OK;
|
||||||
|
|
||||||
|
TRACE("(%p,%p,%p)\n", IfSpec, BindingVector, UuidVector);
|
||||||
|
TRACE(" ifid=%s\n", debugstr_guid(&If->InterfaceId.SyntaxGUID));
|
||||||
|
for (c=0; c<BindingVector->Count; c++) {
|
||||||
|
RpcBinding* bind = (RpcBinding*)(BindingVector->BindingH[c]);
|
||||||
|
TRACE(" protseq[%ld]=%s\n", c, debugstr_a(bind->Protseq));
|
||||||
|
TRACE(" endpoint[%ld]=%s\n", c, debugstr_a(bind->Endpoint));
|
||||||
|
}
|
||||||
|
if (UuidVector) {
|
||||||
|
for (c=0; c<UuidVector->Count; c++)
|
||||||
|
TRACE(" obj[%ld]=%s\n", c, debugstr_guid(UuidVector->Uuid[c]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* construct the message to rpcss */
|
||||||
|
msg.message_type = RPCSS_NP_MESSAGE_TYPEID_UNREGISTEREPMSG;
|
||||||
|
msg.message.unregisterepmsg.iface = If->InterfaceId;
|
||||||
|
|
||||||
|
msg.message.unregisterepmsg.object_count = (UuidVector) ? UuidVector->Count : 0;
|
||||||
|
msg.message.unregisterepmsg.binding_count = BindingVector->Count;
|
||||||
|
|
||||||
|
/* calculate vardata payload size */
|
||||||
|
msg.vardata_payload_size = msg.message.unregisterepmsg.object_count * sizeof(UUID);
|
||||||
|
for (c=0; c < msg.message.unregisterepmsg.binding_count; c++) {
|
||||||
|
RpcBinding *bind = (RpcBinding *)(BindingVector->BindingH[c]);
|
||||||
|
msg.vardata_payload_size += strlen(bind->Protseq) + 1;
|
||||||
|
msg.vardata_payload_size += strlen(bind->Endpoint) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate the payload buffer */
|
||||||
|
vp = vardata_payload = LocalAlloc(LPTR, msg.vardata_payload_size);
|
||||||
|
if (!vardata_payload)
|
||||||
|
return RPC_S_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
/* populate the payload data */
|
||||||
|
for (c=0; c < msg.message.unregisterepmsg.object_count; c++) {
|
||||||
|
CopyMemory(vp, UuidVector->Uuid[c], sizeof(UUID));
|
||||||
|
vp += sizeof(UUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (c=0; c < msg.message.unregisterepmsg.binding_count; c++) {
|
||||||
|
RpcBinding *bind = (RpcBinding*)(BindingVector->BindingH[c]);
|
||||||
|
unsigned long pslen = strlen(bind->Protseq) + 1, eplen = strlen(bind->Endpoint) + 1;
|
||||||
|
CopyMemory(vp, bind->Protseq, pslen);
|
||||||
|
vp += pslen;
|
||||||
|
CopyMemory(vp, bind->Endpoint, eplen);
|
||||||
|
vp += eplen;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* send our request */
|
||||||
|
if (!RPCRT4_RPCSSOnDemandCall(&msg, vardata_payload, &reply))
|
||||||
|
rslt = RPC_S_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
/* free the payload buffer */
|
||||||
|
LocalFree(vardata_payload);
|
||||||
|
|
||||||
|
return rslt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* RpcEpResolveBinding (RPCRT4.@)
|
||||||
|
*/
|
||||||
|
RPC_STATUS WINAPI RpcEpResolveBinding( RPC_BINDING_HANDLE Binding, RPC_IF_HANDLE IfSpec )
|
||||||
|
{
|
||||||
|
RPCSS_NP_MESSAGE msg;
|
||||||
|
RPCSS_NP_REPLY reply;
|
||||||
|
PRPC_CLIENT_INTERFACE If = (PRPC_CLIENT_INTERFACE)IfSpec;
|
||||||
|
RpcBinding* bind = (RpcBinding*)Binding;
|
||||||
|
|
||||||
|
TRACE("(%p,%p)\n", Binding, IfSpec);
|
||||||
|
TRACE(" protseq=%s\n", debugstr_a(bind->Protseq));
|
||||||
|
TRACE(" obj=%s\n", debugstr_guid(&bind->ObjectUuid));
|
||||||
|
TRACE(" ifid=%s\n", debugstr_guid(&If->InterfaceId.SyntaxGUID));
|
||||||
|
|
||||||
|
/* FIXME: totally untested */
|
||||||
|
|
||||||
|
/* just return for fully bound handles */
|
||||||
|
if (bind->Endpoint && (bind->Endpoint[0] != '\0'))
|
||||||
|
return RPC_S_OK;
|
||||||
|
|
||||||
|
/* construct the message to rpcss */
|
||||||
|
msg.message_type = RPCSS_NP_MESSAGE_TYPEID_RESOLVEEPMSG;
|
||||||
|
msg.message.resolveepmsg.iface = If->InterfaceId;
|
||||||
|
msg.message.resolveepmsg.object = bind->ObjectUuid;
|
||||||
|
|
||||||
|
msg.vardata_payload_size = strlen(bind->Protseq) + 1;
|
||||||
|
|
||||||
|
/* send the message */
|
||||||
|
if (!RPCRT4_RPCSSOnDemandCall(&msg, bind->Protseq, &reply))
|
||||||
|
return RPC_S_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
/* empty-string result means not registered */
|
||||||
|
if (reply.as_string[0] == '\0')
|
||||||
|
return EPT_S_NOT_REGISTERED;
|
||||||
|
|
||||||
|
/* otherwise we fully bind the handle & return RPC_S_OK */
|
||||||
|
return RPCRT4_ResolveBinding(Binding, reply.as_string);
|
||||||
|
}
|
|
@ -53,12 +53,12 @@
|
||||||
@ stub RpcCertGeneratePrincipalNameA
|
@ stub RpcCertGeneratePrincipalNameA
|
||||||
@ stub RpcCertGeneratePrincipalNameW
|
@ stub RpcCertGeneratePrincipalNameW
|
||||||
@ stub RpcCompleteAsyncCall
|
@ stub RpcCompleteAsyncCall
|
||||||
@ stub RpcEpRegisterA
|
@ stdcall RpcEpRegisterA(ptr ptr ptr str) RpcEpRegisterA
|
||||||
@ stub RpcEpRegisterW
|
@ stub RpcEpRegisterW
|
||||||
@ stub RpcEpRegisterNoReplaceA
|
@ stub RpcEpRegisterNoReplaceA
|
||||||
@ stub RpcEpRegisterNoReplaceW
|
@ stub RpcEpRegisterNoReplaceW
|
||||||
@ stub RpcEpResolveBinding
|
@ stdcall RpcEpResolveBinding(ptr ptr) RpcEpResolveBinding
|
||||||
@ stub RpcEpUnregister
|
@ stdcall RpcEpUnregister(ptr ptr ptr) RpcEpUnregister
|
||||||
@ stub RpcErrorAddRecord # wxp
|
@ stub RpcErrorAddRecord # wxp
|
||||||
@ stub RpcErrorClearInformation # wxp
|
@ stub RpcErrorClearInformation # wxp
|
||||||
@ stub RpcErrorEndEnumeration # wxp
|
@ stub RpcErrorEndEnumeration # wxp
|
||||||
|
|
|
@ -23,13 +23,11 @@
|
||||||
* a bit of work needs to be done here. widl currently doesn't generate stubs
|
* a bit of work needs to be done here. widl currently doesn't generate stubs
|
||||||
* for RPC invocation -- it will need to; this is tricky because the MIDL compiler
|
* for RPC invocation -- it will need to; this is tricky because the MIDL compiler
|
||||||
* does some really wierd stuff. Then again, we don't neccesarily have to
|
* does some really wierd stuff. Then again, we don't neccesarily have to
|
||||||
* make widl work like MIDL, so it could be worse.
|
* make widl work like MIDL, so it could be worse. Lately Ove has been working on
|
||||||
|
* some widl enhancements.
|
||||||
*
|
*
|
||||||
* - RPC has a quite featureful error handling mechanism; none of it is implemented
|
* - RPC has a quite featureful error handling mechanism; basically none of this is
|
||||||
* right now.
|
* implemented right now.
|
||||||
*
|
|
||||||
* - The server portions of the patch don't seem to be getting accepted by
|
|
||||||
* Alexandre. Instead, we are working on "rpcss.exe.so" which will replace them.
|
|
||||||
*
|
*
|
||||||
* - There are several different memory allocation schemes for MSRPC.
|
* - There are several different memory allocation schemes for MSRPC.
|
||||||
* I don't even understand what they all are yet, much less have them
|
* I don't even understand what they all are yet, much less have them
|
||||||
|
@ -42,13 +40,16 @@
|
||||||
* API's & gracefully ignore the irrelevant stuff (to a small extent we already do).
|
* API's & gracefully ignore the irrelevant stuff (to a small extent we already do).
|
||||||
*
|
*
|
||||||
* - Some transports are not yet implemented. The existing transport implementations
|
* - Some transports are not yet implemented. The existing transport implementations
|
||||||
* are incomplete; the various transports probably ought to be supported in a more
|
* are incomplete and many seem to be buggy
|
||||||
|
*
|
||||||
|
* - The various transports that we do support ought to be supported in a more
|
||||||
* object-oriented manner, like in DCE's RPC implementation, instead of cluttering
|
* object-oriented manner, like in DCE's RPC implementation, instead of cluttering
|
||||||
* up the code with conditionals like we do now.
|
* up the code with conditionals like we do now.
|
||||||
*
|
*
|
||||||
* - Data marshalling: So far, only the very beginnings of an implementation
|
* - Data marshalling: So far, only the very beginnings of an implementation
|
||||||
* exist in wine. NDR protocol itself is documented, but the MS API's to
|
* exist in wine. NDR protocol itself is documented, but the MS API's to
|
||||||
* convert data-types in memory into NDR are not.
|
* convert data-types in memory into NDR are not. This is a bit of a challenge,
|
||||||
|
* but it is at the top of Greg's queue and should be improving soon.
|
||||||
*
|
*
|
||||||
* - ORPC is RPC for OLE; once we have a working RPC framework, we can
|
* - ORPC is RPC for OLE; once we have a working RPC framework, we can
|
||||||
* use it to implement out-of-process OLE client/server communications.
|
* use it to implement out-of-process OLE client/server communications.
|
||||||
|
@ -56,13 +57,15 @@
|
||||||
* and the marshalling going on here. This is a good thing, since marshalling
|
* and the marshalling going on here. This is a good thing, since marshalling
|
||||||
* doesn't work yet. But once it does, obviously there will be the opportunity
|
* doesn't work yet. But once it does, obviously there will be the opportunity
|
||||||
* to implement out-of-process OLE using wine's rpcrt4 or some derivative.
|
* to implement out-of-process OLE using wine's rpcrt4 or some derivative.
|
||||||
|
* This may require some collaboration between the RPC workers and the OLE
|
||||||
|
* workers, of course.
|
||||||
*
|
*
|
||||||
* - In-source API Documentation, at least for those functions which we have
|
* - In-source API Documentation, at least for those functions which we have
|
||||||
* implemented, but preferably for everything we can document, would be nice.
|
* implemented, but preferably for everything we can document, would be nice.
|
||||||
* Some stuff is undocumented by Microsoft and we are guessing how to implement
|
* Some stuff is undocumented by Microsoft and we are guessing how to implement
|
||||||
* (in these cases we should document the behavior we implemented, or, if there
|
* (in these cases we should document the behavior we implemented, or, if there
|
||||||
* is no implementation, at least hazard some kind of guess, and put a few
|
* is no implementation, at least hazard some kind of guess, and put a few
|
||||||
* question marks after it ;) ).
|
* question marks after it ;) ).
|
||||||
*
|
*
|
||||||
* - Stubs. Lots of stuff is defined in Microsoft's headers, including undocumented
|
* - Stubs. Lots of stuff is defined in Microsoft's headers, including undocumented
|
||||||
* stuff. So let's make a stub-farm and populate it with as many rpcrt4 api's as
|
* stuff. So let's make a stub-farm and populate it with as many rpcrt4 api's as
|
||||||
|
@ -70,9 +73,9 @@
|
||||||
*
|
*
|
||||||
* - Name services: this part hasn't even been started.
|
* - Name services: this part hasn't even been started.
|
||||||
*
|
*
|
||||||
* - Concurrency: right now I don't think (?) we handle more than one request at a time;
|
* - Concurrency: right now I have not tested more than one request at a time;
|
||||||
* we are supposed to be able to do this, and to queue requests which exceed the
|
* we are supposed to be able to do this, and to queue requests which exceed the
|
||||||
* concurrency limit. Lots of scenarios are untested.
|
* concurrency limit.
|
||||||
*
|
*
|
||||||
* - Protocol Towers: Totally unimplemented.... I think.
|
* - Protocol Towers: Totally unimplemented.... I think.
|
||||||
*
|
*
|
||||||
|
@ -82,7 +85,7 @@
|
||||||
*
|
*
|
||||||
* - Statistics: we are supposed to be keeping various counters. we aren't.
|
* - Statistics: we are supposed to be keeping various counters. we aren't.
|
||||||
*
|
*
|
||||||
* - Connectionless RPC: unimplemented.
|
* - Connectionless RPC: unimplemented (DNE in win9x so not a top priority)
|
||||||
*
|
*
|
||||||
* - XML RPC: Dunno if microsoft does it... but we'd might as well just for kicks.
|
* - XML RPC: Dunno if microsoft does it... but we'd might as well just for kicks.
|
||||||
*
|
*
|
||||||
|
@ -133,12 +136,19 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "rpc_binding.h"
|
#include "rpc_binding.h"
|
||||||
|
#include "rpcss_np_client.h"
|
||||||
|
|
||||||
#include "wine/debug.h"
|
#include "wine/debug.h"
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(ole);
|
WINE_DEFAULT_DEBUG_CHANNEL(ole);
|
||||||
|
|
||||||
static UUID uuid_nil;
|
static UUID uuid_nil;
|
||||||
|
static HANDLE master_mutex;
|
||||||
|
|
||||||
|
HANDLE RPCRT4_GetMasterMutex(void)
|
||||||
|
{
|
||||||
|
return master_mutex;
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* DllMain
|
* DllMain
|
||||||
|
@ -157,10 +167,15 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
||||||
{
|
{
|
||||||
switch (fdwReason) {
|
switch (fdwReason) {
|
||||||
case DLL_PROCESS_ATTACH:
|
case DLL_PROCESS_ATTACH:
|
||||||
break;
|
master_mutex = CreateMutexA( NULL, FALSE, RPCSS_MASTER_MUTEX_NAME);
|
||||||
|
if (!master_mutex)
|
||||||
|
ERR("Failed to create master mutex\n");
|
||||||
|
break;
|
||||||
|
|
||||||
case DLL_PROCESS_DETACH:
|
case DLL_PROCESS_DETACH:
|
||||||
break;
|
CloseHandle(master_mutex);
|
||||||
|
master_mutex = (HANDLE) NULL;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -673,6 +688,99 @@ RPC_STATUS WINAPI UuidFromStringW(LPWSTR s, UUID *uuid)
|
||||||
|
|
||||||
HRESULT WINAPI RPCRT4_DllRegisterServer( void )
|
HRESULT WINAPI RPCRT4_DllRegisterServer( void )
|
||||||
{
|
{
|
||||||
FIXME( "(): stub\n" );
|
FIXME( "(): stub\n" );
|
||||||
return S_OK;
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL RPCRT4_StartRPCSS(void)
|
||||||
|
{
|
||||||
|
PROCESS_INFORMATION pi;
|
||||||
|
STARTUPINFOA si;
|
||||||
|
static char cmd[6];
|
||||||
|
BOOL rslt;
|
||||||
|
|
||||||
|
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
|
||||||
|
ZeroMemory(&si, sizeof(STARTUPINFOA));
|
||||||
|
si.cb = sizeof(STARTUPINFOA);
|
||||||
|
|
||||||
|
/* apparently it's not OK to use a constant string below */
|
||||||
|
CopyMemory(cmd, "rpcss", 6);
|
||||||
|
|
||||||
|
/* FIXME: will this do the right thing when run as a test? */
|
||||||
|
rslt = CreateProcessA(
|
||||||
|
NULL, /* executable */
|
||||||
|
cmd, /* command line */
|
||||||
|
NULL, /* process security attributes */
|
||||||
|
NULL, /* primary thread security attributes */
|
||||||
|
FALSE, /* inherit handles */
|
||||||
|
0, /* creation flags */
|
||||||
|
NULL, /* use parent's environment */
|
||||||
|
NULL, /* use parent's current directory */
|
||||||
|
&si, /* STARTUPINFO pointer */
|
||||||
|
&pi /* PROCESS_INFORMATION */
|
||||||
|
);
|
||||||
|
|
||||||
|
if (rslt) {
|
||||||
|
CloseHandle(pi.hProcess);
|
||||||
|
CloseHandle(pi.hThread);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rslt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* RPCRT4_RPCSSOnDemandCall (internal)
|
||||||
|
*
|
||||||
|
* Attempts to send a message to the RPCSS process
|
||||||
|
* on the local machine, invoking it if necessary.
|
||||||
|
* For remote RPCSS calls, use.... your imagination.
|
||||||
|
*
|
||||||
|
* PARAMS
|
||||||
|
* msg [I] pointer to the RPCSS message
|
||||||
|
* vardata_payload [I] pointer vardata portion of the RPCSS message
|
||||||
|
* reply [O] pointer to reply structure
|
||||||
|
*
|
||||||
|
* RETURNS
|
||||||
|
* TRUE if successful
|
||||||
|
* FALSE otherwise
|
||||||
|
*/
|
||||||
|
BOOL RPCRT4_RPCSSOnDemandCall(PRPCSS_NP_MESSAGE msg, char *vardata_payload, PRPCSS_NP_REPLY reply)
|
||||||
|
{
|
||||||
|
HANDLE client_handle;
|
||||||
|
int i, j = 0;
|
||||||
|
|
||||||
|
TRACE("(msg == %p, vardata_payload == %p, reply == %p)\n", msg, vardata_payload, reply);
|
||||||
|
|
||||||
|
client_handle = RPCRT4_RpcssNPConnect();
|
||||||
|
|
||||||
|
while (!client_handle) {
|
||||||
|
/* start the RPCSS process */
|
||||||
|
if (!RPCRT4_StartRPCSS()) {
|
||||||
|
ERR("Unable to start RPCSS process.\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
/* wait for a connection (w/ periodic polling) */
|
||||||
|
for (i = 0; i < 60; i++) {
|
||||||
|
Sleep(200);
|
||||||
|
client_handle = RPCRT4_RpcssNPConnect();
|
||||||
|
if (client_handle) break;
|
||||||
|
}
|
||||||
|
/* we are only willing to try twice */
|
||||||
|
if (j++ >= 1) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!client_handle) {
|
||||||
|
/* no dice! */
|
||||||
|
ERR("Unable to connect to RPCSS process!\n");
|
||||||
|
SetLastError(RPC_E_SERVER_DIED_DNE);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* great, we're connected. now send the message */
|
||||||
|
if (!RPCRT4_SendReceiveNPMsg(client_handle, msg, vardata_payload, reply)) {
|
||||||
|
ERR("Something is amiss: RPC_SendReceive failed.\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,151 @@
|
||||||
|
/*
|
||||||
|
* RPCSS named pipe client implementation
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002 Greg Turner
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "winbase.h"
|
||||||
|
#include "wine/rpcss_shared.h"
|
||||||
|
#include "wine/debug.h"
|
||||||
|
|
||||||
|
#include "rpc_binding.h"
|
||||||
|
|
||||||
|
WINE_DEFAULT_DEBUG_CHANNEL(ole);
|
||||||
|
|
||||||
|
HANDLE RPCRT4_RpcssNPConnect(void)
|
||||||
|
{
|
||||||
|
HANDLE the_pipe = NULL;
|
||||||
|
DWORD dwmode, wait_result;
|
||||||
|
HANDLE master_mutex = RPCRT4_GetMasterMutex();
|
||||||
|
|
||||||
|
TRACE("\n");
|
||||||
|
|
||||||
|
while (TRUE) {
|
||||||
|
|
||||||
|
wait_result = WaitForSingleObject(master_mutex, MASTER_MUTEX_TIMEOUT);
|
||||||
|
switch (wait_result) {
|
||||||
|
case WAIT_ABANDONED:
|
||||||
|
case WAIT_OBJECT_0:
|
||||||
|
break;
|
||||||
|
case WAIT_FAILED:
|
||||||
|
case WAIT_TIMEOUT:
|
||||||
|
default:
|
||||||
|
ERR("This should never happen: couldn't enter mutex.\n");
|
||||||
|
return (HANDLE) NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* try to open the client side of the named pipe. */
|
||||||
|
the_pipe = CreateFileA(
|
||||||
|
NAME_RPCSS_NAMED_PIPE, /* pipe name */
|
||||||
|
GENERIC_READ | GENERIC_WRITE, /* r/w access */
|
||||||
|
0, /* no sharing */
|
||||||
|
NULL, /* no security attributes */
|
||||||
|
OPEN_EXISTING, /* open an existing pipe */
|
||||||
|
0, /* default attributes */
|
||||||
|
NULL /* no template file */
|
||||||
|
);
|
||||||
|
|
||||||
|
if (the_pipe != INVALID_HANDLE_VALUE)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (GetLastError() != ERROR_PIPE_BUSY) {
|
||||||
|
WARN("Unable to open named pipe %s (assuming unavailable).\n",
|
||||||
|
debugstr_a(NAME_RPCSS_NAMED_PIPE));
|
||||||
|
the_pipe = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
WARN("Named pipe busy (will wait)\n");
|
||||||
|
|
||||||
|
if (!ReleaseMutex(master_mutex))
|
||||||
|
ERR("Failed to release master mutex. Expect deadlock.\n");
|
||||||
|
|
||||||
|
/* wait for the named pipe. We are only
|
||||||
|
willing to wait only 5 seconds. It should be available /very/ soon. */
|
||||||
|
if (! WaitNamedPipeA(NAME_RPCSS_NAMED_PIPE, MASTER_MUTEX_WAITNAMEDPIPE_TIMEOUT))
|
||||||
|
{
|
||||||
|
ERR("Named pipe unavailable after waiting. Something is probably wrong.\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (the_pipe) {
|
||||||
|
dwmode = PIPE_READMODE_MESSAGE;
|
||||||
|
/* SetNamedPipeHandleState not implemented ATM, but still seems to work somehow. */
|
||||||
|
if (! SetNamedPipeHandleState(the_pipe, &dwmode, NULL, NULL))
|
||||||
|
WARN("Failed to set pipe handle state\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ReleaseMutex(master_mutex))
|
||||||
|
ERR("Uh oh, failed to leave the RPC Master Mutex!\n");
|
||||||
|
|
||||||
|
return the_pipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL RPCRT4_SendReceiveNPMsg(HANDLE np, PRPCSS_NP_MESSAGE msg, char *vardata, PRPCSS_NP_REPLY reply)
|
||||||
|
{
|
||||||
|
DWORD count;
|
||||||
|
UINT32 payload_offset;
|
||||||
|
RPCSS_NP_MESSAGE vardata_payload_msg;
|
||||||
|
|
||||||
|
TRACE("(np == %p, msg == %p, vardata == %p, reply == %p)\n",
|
||||||
|
np, msg, vardata, reply);
|
||||||
|
|
||||||
|
if (! WriteFile(np, msg, sizeof(RPCSS_NP_MESSAGE), &count, NULL)) {
|
||||||
|
ERR("write failed.\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count != sizeof(RPCSS_NP_MESSAGE)) {
|
||||||
|
ERR("write count mismatch.\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* process the vardata payload if neccesary */
|
||||||
|
vardata_payload_msg.message_type = RPCSS_NP_MESSAGE_TYPEID_VARDATAPAYLOADMSG;
|
||||||
|
vardata_payload_msg.vardata_payload_size = 0; /* meaningless */
|
||||||
|
for ( payload_offset = 0; payload_offset < msg->vardata_payload_size;
|
||||||
|
payload_offset += VARDATA_PAYLOAD_BYTES ) {
|
||||||
|
TRACE("sending vardata payload. vd=%p, po=%d, ps=%d\n", vardata,
|
||||||
|
payload_offset, msg->vardata_payload_size);
|
||||||
|
ZeroMemory(vardata_payload_msg.message.vardatapayloadmsg.payload, VARDATA_PAYLOAD_BYTES);
|
||||||
|
CopyMemory(vardata_payload_msg.message.vardatapayloadmsg.payload,
|
||||||
|
vardata,
|
||||||
|
min( VARDATA_PAYLOAD_BYTES, msg->vardata_payload_size - payload_offset ));
|
||||||
|
vardata += VARDATA_PAYLOAD_BYTES;
|
||||||
|
if (! WriteFile(np, &vardata_payload_msg, sizeof(RPCSS_NP_MESSAGE), &count, NULL)) {
|
||||||
|
ERR("vardata write failed at %u bytes.\n", payload_offset);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! ReadFile(np, reply, sizeof(RPCSS_NP_REPLY), &count, NULL)) {
|
||||||
|
ERR("read failed.\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count != sizeof(RPCSS_NP_REPLY)) {
|
||||||
|
ERR("read count mismatch. got %ld, expected %u.\n", count, sizeof(RPCSS_NP_REPLY));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* message execution was successful */
|
||||||
|
return TRUE;
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2002 Greg Turner
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __WINE_RPCSS_NP_CLIENT_H
|
||||||
|
#define __WINE_RPCSS_NP_CLIENT_H
|
||||||
|
|
||||||
|
/* rpcss_np_client.c */
|
||||||
|
HANDLE RPC_RpcssNPConnect(void);
|
||||||
|
BOOL RPCRT4_SendReceiveNPMsg(HANDLE, PRPCSS_NP_MESSAGE, char *, PRPCSS_NP_REPLY);
|
||||||
|
|
||||||
|
#endif /* __RPCSS_NP_CLINET_H */
|
|
@ -21,6 +21,21 @@
|
||||||
|
|
||||||
#include "windef.h"
|
#include "windef.h"
|
||||||
|
|
||||||
|
/* avoid delving into windows.h ifndef __WINE__; this
|
||||||
|
would pull in rpcndr.h, which needs rpcdcep.h, which
|
||||||
|
needs us, in turn, causing a compile failure */
|
||||||
|
#ifndef RPC_NO_WINDOWS_H
|
||||||
|
#define __NO_HAD_RPC_NO_WINDOWS_H
|
||||||
|
#define RPC_NO_WINDOWS_H
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "rpc.h"
|
||||||
|
|
||||||
|
#ifdef __NO_HAD_RPC_NO_WINDOWS_H
|
||||||
|
#undef RPC_NO_WINDOWS_H
|
||||||
|
#undef __NO_HAD_RPC_NO_WINDOWS_H
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef GUID_DEFINED
|
#ifndef GUID_DEFINED
|
||||||
#include "guiddef.h"
|
#include "guiddef.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
#ifndef __WINE_RPCDCEP_H
|
#ifndef __WINE_RPCDCEP_H
|
||||||
#define __WINE_RPCDCEP_H
|
#define __WINE_RPCDCEP_H
|
||||||
|
|
||||||
|
#include "rpcdce.h"
|
||||||
|
|
||||||
typedef struct _RPC_VERSION {
|
typedef struct _RPC_VERSION {
|
||||||
unsigned short MajorVersion;
|
unsigned short MajorVersion;
|
||||||
unsigned short MinorVersion;
|
unsigned short MinorVersion;
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
#define __WINE_RPCNDR_H
|
#define __WINE_RPCNDR_H
|
||||||
|
|
||||||
#include "basetsd.h"
|
#include "basetsd.h"
|
||||||
#include "rpc.h"
|
#include "rpcdcep.h"
|
||||||
|
|
||||||
/* stupid #if can't handle casts... this __stupidity
|
/* stupid #if can't handle casts... this __stupidity
|
||||||
is just a workaround for that limitation */
|
is just a workaround for that limitation */
|
||||||
|
|
|
@ -1475,6 +1475,7 @@ BOOL WINAPI SetFileSecurityW(LPCWSTR,SECURITY_INFORMATION,PSECURITY_DESCR
|
||||||
BOOL WINAPI SetFileTime(HANDLE,const FILETIME*,const FILETIME*,const FILETIME*);
|
BOOL WINAPI SetFileTime(HANDLE,const FILETIME*,const FILETIME*,const FILETIME*);
|
||||||
BOOL WINAPI SetHandleInformation(HANDLE,DWORD,DWORD);
|
BOOL WINAPI SetHandleInformation(HANDLE,DWORD,DWORD);
|
||||||
BOOL WINAPI SetKernelObjectSecurity(HANDLE,SECURITY_INFORMATION,PSECURITY_DESCRIPTOR);
|
BOOL WINAPI SetKernelObjectSecurity(HANDLE,SECURITY_INFORMATION,PSECURITY_DESCRIPTOR);
|
||||||
|
BOOL WINAPI SetNamedPipeHandleState(HANDLE,LPDWORD,LPDWORD,LPDWORD);
|
||||||
BOOL WINAPI SetPriorityClass(HANDLE,DWORD);
|
BOOL WINAPI SetPriorityClass(HANDLE,DWORD);
|
||||||
BOOL WINAPI SetLocalTime(const SYSTEMTIME*);
|
BOOL WINAPI SetLocalTime(const SYSTEMTIME*);
|
||||||
BOOL WINAPI SetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR,BOOL,PACL,BOOL);
|
BOOL WINAPI SetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR,BOOL,PACL,BOOL);
|
||||||
|
|
|
@ -0,0 +1,145 @@
|
||||||
|
/*
|
||||||
|
* RPCSS shared definitions
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002 Greg Turner
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __WINE_RPCSS_SHARED_H
|
||||||
|
#define __WINE_RPCSS_SHARED_H
|
||||||
|
|
||||||
|
#include "basetsd.h"
|
||||||
|
#include "winnt.h"
|
||||||
|
|
||||||
|
#include "rpcdcep.h"
|
||||||
|
|
||||||
|
#define RPCSS_NP_PROTOCOL_VERSION 0x0000
|
||||||
|
|
||||||
|
#define RPCSS_STRINGIFY_MACRO(x) RPCSS_STRINGIFY_MACRO2(x)
|
||||||
|
#define RPCSS_STRINGIFY_MACRO2(x) #x
|
||||||
|
|
||||||
|
#define STRINGIFIED_RPCSS_NP_PROTOCOL_VERSION \
|
||||||
|
RPCSS_STRINGIFY_MACRO(RPCSS_NP_PROTOCOL_VERSION)
|
||||||
|
|
||||||
|
/* only local communications are supported so far on this pipe.
|
||||||
|
until this changes, we can just use a constant pipe-name */
|
||||||
|
#define NAME_RPCSS_NAMED_PIPE \
|
||||||
|
("\\\\.\\pipe\\RpcssNP" STRINGIFIED_RPCSS_NP_PROTOCOL_VERSION)
|
||||||
|
|
||||||
|
/* mutex is local only... perhaps this ought to be part of the pipe
|
||||||
|
protocol for remote wine<->wine connections? */
|
||||||
|
#define RPCSS_MASTER_MUTEX_NAME \
|
||||||
|
("RPCSSMasterMutex" STRINGIFIED_RPCSS_NP_PROTOCOL_VERSION)
|
||||||
|
|
||||||
|
/* payloads above 1K are fragmented into multiple messages */
|
||||||
|
#define VARDATA_PAYLOAD_BYTES 1024
|
||||||
|
|
||||||
|
/* ick -- maybe we should pass a handle to a mailslot or something? */
|
||||||
|
#define MAX_RPCSS_NP_REPLY_STRING_LEN 512
|
||||||
|
|
||||||
|
/* number of microseconds/10 to wait for master mutex before giving up */
|
||||||
|
#define MASTER_MUTEX_TIMEOUT 6000000
|
||||||
|
|
||||||
|
/* number of miliseconds to wait on the master mutex after it returns BUSY */
|
||||||
|
#define MASTER_MUTEX_WAITNAMEDPIPE_TIMEOUT 5000
|
||||||
|
|
||||||
|
/* a data payload; not a normal message */
|
||||||
|
#define RPCSS_NP_MESSAGE_TYPEID_VARDATAPAYLOADMSG 1
|
||||||
|
typedef struct _RPCSS_NP_MESSAGE_UNION_VARDATAPAYLOADMSG {
|
||||||
|
char payload[VARDATA_PAYLOAD_BYTES];
|
||||||
|
} RPCSS_NP_MESSAGE_UNION_VARDATAPAYLOADMSG;
|
||||||
|
|
||||||
|
/* RANMSG:
|
||||||
|
* Simply tells the server that another rpcss instance ran.
|
||||||
|
* The server should respond by resetting its timeout to the
|
||||||
|
* full lazy timeout.
|
||||||
|
*/
|
||||||
|
#define RPCSS_NP_MESSAGE_TYPEID_RANMSG 2
|
||||||
|
typedef struct _RPCSS_NP_MESSAGE_UNION_RANMSG {
|
||||||
|
long timeout;
|
||||||
|
} RPCSS_NP_MESSAGE_UNION_RANMSG;
|
||||||
|
|
||||||
|
/* REGISTEREPMSG:
|
||||||
|
* Registers endpoints with the endpoint server.
|
||||||
|
* object_count and binding_count contain the number
|
||||||
|
* of object uuids and endpoints in the vardata payload,
|
||||||
|
* respectively.
|
||||||
|
*/
|
||||||
|
#define RPCSS_NP_MESSAGE_TYPEID_REGISTEREPMSG 3
|
||||||
|
typedef struct _RPCSS_NP_MESSAGE_UNION_REGISTEREPMSG {
|
||||||
|
RPC_SYNTAX_IDENTIFIER iface;
|
||||||
|
int object_count;
|
||||||
|
int binding_count;
|
||||||
|
int no_replace;
|
||||||
|
} RPCSS_NP_MESSAGE_UNION_REGISTEREPMSG;
|
||||||
|
|
||||||
|
/* UNREGISTEREPMSG:
|
||||||
|
* Unregisters endpoints with the endpoint server.
|
||||||
|
* object_count and binding_count contain the number
|
||||||
|
* of object uuids and endpoints in the vardata payload,
|
||||||
|
* respectively.
|
||||||
|
*/
|
||||||
|
#define RPCSS_NP_MESSAGE_TYPEID_UNREGISTEREPMSG 4
|
||||||
|
typedef struct _RPCSS_NP_MESSAGE_UNION_UNREGISTEREPMSG {
|
||||||
|
RPC_SYNTAX_IDENTIFIER iface;
|
||||||
|
int object_count;
|
||||||
|
int binding_count;
|
||||||
|
} RPCSS_NP_MESSAGE_UNION_UNREGISTEREPMSG;
|
||||||
|
|
||||||
|
/* RESOLVEEPMSG:
|
||||||
|
* Locates an endpoint registered with the endpoint server.
|
||||||
|
* Vardata contains a single protseq string. This is a bit
|
||||||
|
* silly: the protseq string is probably shorter than the
|
||||||
|
* reply (an endpoint string), which is truncated at
|
||||||
|
* MAX_RPCSS_NP_REPLY_STRING_LEN, at least for the moment.
|
||||||
|
* returns the empty string if the requested endpoint isn't
|
||||||
|
* registered.
|
||||||
|
*/
|
||||||
|
#define RPCSS_NP_MESSAGE_TYPEID_RESOLVEEPMSG 5
|
||||||
|
typedef struct _RPCSS_NP_MESSAGE_UNION_RESOLVEEPMSG {
|
||||||
|
RPC_SYNTAX_IDENTIFIER iface;
|
||||||
|
UUID object;
|
||||||
|
} RPCSS_NP_MESSAGE_UNION_RESOLVEEPMSG;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
RPCSS_NP_MESSAGE_UNION_RANMSG ranmsg;
|
||||||
|
RPCSS_NP_MESSAGE_UNION_VARDATAPAYLOADMSG vardatapayloadmsg;
|
||||||
|
RPCSS_NP_MESSAGE_UNION_REGISTEREPMSG registerepmsg;
|
||||||
|
RPCSS_NP_MESSAGE_UNION_UNREGISTEREPMSG unregisterepmsg;
|
||||||
|
RPCSS_NP_MESSAGE_UNION_RESOLVEEPMSG resolveepmsg;
|
||||||
|
} RPCSS_NP_MESSAGE_UNION;
|
||||||
|
|
||||||
|
/* vardata_payload_size specifies the number of bytes
|
||||||
|
* to be transferred over the pipe in VARDATAPAYLOAD
|
||||||
|
* messages (divide by VARDATA_PAYLOAD_BYTES to
|
||||||
|
* get the # of payloads)
|
||||||
|
*/
|
||||||
|
typedef struct _RPCSS_NP_MESSAGE {
|
||||||
|
UINT32 message_type;
|
||||||
|
RPCSS_NP_MESSAGE_UNION message;
|
||||||
|
UINT32 vardata_payload_size;
|
||||||
|
} RPCSS_NP_MESSAGE, *PRPCSS_NP_MESSAGE;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
/* some of these aren't used, but I guess we don't care */
|
||||||
|
UINT as_uint;
|
||||||
|
INT as_int;
|
||||||
|
void *as_pvoid;
|
||||||
|
HANDLE as_handle;
|
||||||
|
char as_string[MAX_RPCSS_NP_REPLY_STRING_LEN]; /* FIXME: yucky */
|
||||||
|
} RPCSS_NP_REPLY, *PRPCSS_NP_REPLY;
|
||||||
|
|
||||||
|
#endif /* __WINE_RPCSS_SHARED_H */
|
|
@ -17,6 +17,7 @@ SUBDIRS = \
|
||||||
regedit \
|
regedit \
|
||||||
regsvr32 \
|
regsvr32 \
|
||||||
regtest \
|
regtest \
|
||||||
|
rpcss \
|
||||||
rundll32 \
|
rundll32 \
|
||||||
uninstaller \
|
uninstaller \
|
||||||
view \
|
view \
|
||||||
|
@ -39,6 +40,7 @@ INSTALLSUBDIRS = \
|
||||||
progman \
|
progman \
|
||||||
regedit \
|
regedit \
|
||||||
regsvr32 \
|
regsvr32 \
|
||||||
|
rpcss \
|
||||||
rundll32 \
|
rundll32 \
|
||||||
uninstaller \
|
uninstaller \
|
||||||
wcmd \
|
wcmd \
|
||||||
|
@ -68,6 +70,7 @@ INSTALLPROGS = \
|
||||||
|
|
||||||
# Symlinks to apps that we want to run from inside the source tree
|
# Symlinks to apps that we want to run from inside the source tree
|
||||||
SYMLINKS = \
|
SYMLINKS = \
|
||||||
|
rpcss.exe \
|
||||||
wcmd.exe \
|
wcmd.exe \
|
||||||
wineconsole.exe \
|
wineconsole.exe \
|
||||||
winedbg.exe \
|
winedbg.exe \
|
||||||
|
@ -116,6 +119,9 @@ check test:: $(SUBDIRS:%=%/__test__)
|
||||||
|
|
||||||
# Rules for symlinks
|
# Rules for symlinks
|
||||||
|
|
||||||
|
rpcss.exe$(DLLEXT): rpcss/rpcss.exe$(DLLEXT)
|
||||||
|
$(RM) $@ && $(LN_S) rpcss/rpcss.exe$(DLLEXT) $@
|
||||||
|
|
||||||
wcmd.exe$(DLLEXT): wcmd/wcmd.exe$(DLLEXT)
|
wcmd.exe$(DLLEXT): wcmd/wcmd.exe$(DLLEXT)
|
||||||
$(RM) $@ && $(LN_S) wcmd/wcmd.exe$(DLLEXT) $@
|
$(RM) $@ && $(LN_S) wcmd/wcmd.exe$(DLLEXT) $@
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
Makefile
|
||||||
|
rpcss.exe.dbg.c
|
||||||
|
rpcss.exe.spec.c
|
|
@ -0,0 +1,16 @@
|
||||||
|
TOPSRCDIR = @top_srcdir@
|
||||||
|
TOPOBJDIR = ../..
|
||||||
|
SRCDIR = @srcdir@
|
||||||
|
VPATH = @srcdir@
|
||||||
|
MODULE = rpcss.exe
|
||||||
|
APPMODE = cui
|
||||||
|
IMPORTS = kernel32
|
||||||
|
|
||||||
|
C_SRCS = \
|
||||||
|
epmap_server.c \
|
||||||
|
np_server.c \
|
||||||
|
rpcss_main.c
|
||||||
|
|
||||||
|
@MAKE_PROG_RULES@
|
||||||
|
|
||||||
|
### Dependencies:
|
|
@ -0,0 +1,210 @@
|
||||||
|
/*
|
||||||
|
* RPC endpoint mapper server
|
||||||
|
*
|
||||||
|
* Copyright (C) 2001 Ove Kåven, TransGaming Technologies Inc,
|
||||||
|
* Copyright (C) 2002 Greg Turner
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "rpcss.h"
|
||||||
|
#include "rpc.h"
|
||||||
|
#include "wine/debug.h"
|
||||||
|
|
||||||
|
WINE_DEFAULT_DEBUG_CHANNEL(ole);
|
||||||
|
|
||||||
|
struct epmap_entry
|
||||||
|
{
|
||||||
|
struct epmap_entry *next;
|
||||||
|
RPC_SYNTAX_IDENTIFIER iface;
|
||||||
|
UUID object;
|
||||||
|
char *protseq;
|
||||||
|
char *endpoint;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct epmap_entry *epmap;
|
||||||
|
|
||||||
|
static const UUID nil_object;
|
||||||
|
|
||||||
|
char *mystrdup(const char *str) {
|
||||||
|
char *rval;
|
||||||
|
rval = LocalAlloc(LPTR, strlen(str)+1);
|
||||||
|
CopyMemory(rval, str, strlen(str)+1);
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct epmap_entry *find_endpoint(const RPC_SYNTAX_IDENTIFIER *iface,
|
||||||
|
const char *protseq, const UUID *object)
|
||||||
|
{
|
||||||
|
struct epmap_entry *map;
|
||||||
|
for (map=epmap; map; map=map->next) {
|
||||||
|
if (memcmp(&map->iface, iface, sizeof(RPC_SYNTAX_IDENTIFIER))) continue;
|
||||||
|
if (memcmp(&map->object, object, sizeof(UUID))) continue;
|
||||||
|
if (strcmp(map->protseq, protseq)) continue;
|
||||||
|
WINE_TRACE("found.\n");
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
WINE_TRACE("not found.\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void register_endpoint(const RPC_SYNTAX_IDENTIFIER *iface, const char *protseq,
|
||||||
|
const char *endpoint, const UUID *objects, int objcount,
|
||||||
|
int no_replace)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
|
||||||
|
WINE_TRACE("(protseq == %s, endpoint == %s, objcount == %i, no_replace == %i)\n",
|
||||||
|
wine_dbgstr_a(protseq), wine_dbgstr_a(endpoint), objcount, no_replace);
|
||||||
|
|
||||||
|
if (!objcount) {
|
||||||
|
objects = &nil_object;
|
||||||
|
objcount = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (c=0; c<objcount; c++) {
|
||||||
|
struct epmap_entry *map = NULL;
|
||||||
|
if (!no_replace)
|
||||||
|
map = find_endpoint(iface, protseq, &objects[c]);
|
||||||
|
if (map) {
|
||||||
|
LocalFree(map->endpoint);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
map = LocalAlloc(LPTR, sizeof(struct epmap_entry));
|
||||||
|
memcpy(&map->iface, iface, sizeof(RPC_SYNTAX_IDENTIFIER));
|
||||||
|
memcpy(&map->object, &objects[c], sizeof(UUID));
|
||||||
|
map->protseq = mystrdup(protseq);
|
||||||
|
map->next = epmap;
|
||||||
|
epmap = map;
|
||||||
|
}
|
||||||
|
WINE_TRACE(" mapping endpoint (protseq == %s, endpoint == %s, uuid == %s)\n",
|
||||||
|
wine_dbgstr_a(protseq), wine_dbgstr_a(endpoint), wine_dbgstr_guid(&objects[c]));
|
||||||
|
map->endpoint = mystrdup(endpoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void unregister_endpoint(const RPC_SYNTAX_IDENTIFIER *iface, const char *protseq,
|
||||||
|
const char *endpoint, const UUID *objects, int objcount)
|
||||||
|
{
|
||||||
|
struct epmap_entry *map, *prev, *nprev, *next;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
WINE_TRACE("(protseq == %s, endpoint == %s, objcount == %i)\n",
|
||||||
|
wine_dbgstr_a(protseq), wine_dbgstr_a(endpoint), objcount);
|
||||||
|
|
||||||
|
if (!objcount) {
|
||||||
|
objects = &nil_object;
|
||||||
|
objcount = 1;
|
||||||
|
}
|
||||||
|
prev=NULL;
|
||||||
|
nprev=NULL;
|
||||||
|
map=epmap;
|
||||||
|
while(map) {
|
||||||
|
next = map->next;
|
||||||
|
nprev = map;
|
||||||
|
if (memcmp(&map->iface, iface, sizeof(RPC_SYNTAX_IDENTIFIER))) goto cont;
|
||||||
|
for (c=0; c<objcount; c++)
|
||||||
|
if (!memcmp(&map->object, &objects[c], sizeof(UUID))) break;
|
||||||
|
if (c==objcount) goto cont;
|
||||||
|
if (strcmp(map->protseq, protseq)) goto cont;
|
||||||
|
|
||||||
|
WINE_TRACE(" unmapping: (protseq == %s, endpoint == %s, uuid == %s)\n",
|
||||||
|
wine_dbgstr_a(map->protseq), wine_dbgstr_a(map->endpoint),
|
||||||
|
wine_dbgstr_guid(&map->object));
|
||||||
|
|
||||||
|
if (prev) prev->next = map->next;
|
||||||
|
else epmap = map->next;
|
||||||
|
nprev = prev;
|
||||||
|
|
||||||
|
LocalFree(map->protseq);
|
||||||
|
LocalFree(map->endpoint);
|
||||||
|
LocalFree(map);
|
||||||
|
|
||||||
|
cont:
|
||||||
|
|
||||||
|
prev = nprev;
|
||||||
|
map = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void resolve_endpoint(const RPC_SYNTAX_IDENTIFIER *iface, const char *protseq,
|
||||||
|
const UUID *object, char *rslt_ep)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
struct epmap_entry *map;
|
||||||
|
|
||||||
|
if (!(map = find_endpoint(iface, protseq, object))) return;
|
||||||
|
|
||||||
|
len = min( MAX_RPCSS_NP_REPLY_STRING_LEN, strlen(map->endpoint)+1 );
|
||||||
|
if (len) memcpy(rslt_ep, map->endpoint, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *get_string(const char**ptr, const char*end)
|
||||||
|
{
|
||||||
|
const char *str = *ptr, *nptr = str;
|
||||||
|
|
||||||
|
while (nptr < end && *nptr) nptr++;
|
||||||
|
if (nptr == end)
|
||||||
|
return NULL;
|
||||||
|
*ptr = nptr + 1;
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL RPCSS_EpmapEmpty(void)
|
||||||
|
{
|
||||||
|
return (!epmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RPCSS_RegisterRpcEndpoints(RPC_SYNTAX_IDENTIFIER iface, int object_count,
|
||||||
|
int binding_count, int no_replace, char *vardata, long vardata_size)
|
||||||
|
{
|
||||||
|
const char *data = vardata;
|
||||||
|
const char *end = data + vardata_size;
|
||||||
|
UUID *objects = (UUID *)data;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
data += object_count * sizeof(UUID);
|
||||||
|
for (c=0; c < binding_count; c++) {
|
||||||
|
const char *protseq = get_string(&data, end);
|
||||||
|
const char *endpoint = get_string(&data, end);
|
||||||
|
if (protseq && endpoint)
|
||||||
|
register_endpoint(&iface, protseq, endpoint, objects, object_count, no_replace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RPCSS_UnregisterRpcEndpoints(RPC_SYNTAX_IDENTIFIER iface, int object_count,
|
||||||
|
int binding_count, char *vardata, long vardata_size)
|
||||||
|
{
|
||||||
|
const char *data = vardata;
|
||||||
|
const char *end = data + vardata_size;
|
||||||
|
const UUID *objects = (UUID *)data;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
data += object_count * sizeof(UUID);
|
||||||
|
for (c=0; c < binding_count; c++) {
|
||||||
|
const char *protseq = get_string(&data, end);
|
||||||
|
const char *endpoint = get_string(&data, end);
|
||||||
|
if (protseq && endpoint)
|
||||||
|
unregister_endpoint(&iface, protseq, endpoint, objects, object_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RPCSS_ResolveRpcEndpoints(RPC_SYNTAX_IDENTIFIER iface, UUID object, char *protseq, char *rslt_ep)
|
||||||
|
{
|
||||||
|
resolve_endpoint(&iface, protseq, &object, rslt_ep);
|
||||||
|
}
|
|
@ -0,0 +1,555 @@
|
||||||
|
/*
|
||||||
|
* RPCSS named pipe server
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002 Greg Turner
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "rpcss.h"
|
||||||
|
#include "wine/debug.h"
|
||||||
|
|
||||||
|
WINE_DEFAULT_DEBUG_CHANNEL(ole);
|
||||||
|
|
||||||
|
static HANDLE np_server_end;
|
||||||
|
static HANDLE np_server_work_event;
|
||||||
|
static CRITICAL_SECTION np_server_cs;
|
||||||
|
static LONG srv_thread_count;
|
||||||
|
static BOOL server_live;
|
||||||
|
|
||||||
|
LONG RPCSS_SrvThreadCount(void)
|
||||||
|
{
|
||||||
|
return srv_thread_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL RPCSS_UnBecomePipeServer(void)
|
||||||
|
{
|
||||||
|
BOOL rslt = TRUE;
|
||||||
|
DWORD wait_result;
|
||||||
|
HANDLE master_mutex = RPCSS_GetMasterMutex();
|
||||||
|
|
||||||
|
WINE_TRACE("\n");
|
||||||
|
|
||||||
|
wait_result = WaitForSingleObject(master_mutex, MASTER_MUTEX_TIMEOUT);
|
||||||
|
|
||||||
|
switch (wait_result) {
|
||||||
|
case WAIT_ABANDONED: /* ? */
|
||||||
|
case WAIT_OBJECT_0:
|
||||||
|
/* we have ownership */
|
||||||
|
break;
|
||||||
|
case WAIT_FAILED:
|
||||||
|
case WAIT_TIMEOUT:
|
||||||
|
default:
|
||||||
|
WINE_ERR("This should never happen: couldn't enter mutex.\n");
|
||||||
|
/* this is totally unacceptable. no graceful out exists */
|
||||||
|
assert(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now that we have the master mutex, we can safely stop
|
||||||
|
listening on the pipe. Before we proceed, we do a final
|
||||||
|
check that it's OK to shut down to ensure atomicity */
|
||||||
|
|
||||||
|
if (!RPCSS_ReadyToDie())
|
||||||
|
rslt = FALSE;
|
||||||
|
else {
|
||||||
|
WINE_TRACE("shutting down pipe.\n");
|
||||||
|
server_live = FALSE;
|
||||||
|
if (!CloseHandle(np_server_end))
|
||||||
|
WINE_WARN("Failed to close named pipe.\n");
|
||||||
|
if (!CloseHandle(np_server_work_event))
|
||||||
|
WINE_WARN("Failed to close the event handle.\n");
|
||||||
|
DeleteCriticalSection(&np_server_cs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ReleaseMutex(master_mutex))
|
||||||
|
WINE_ERR("Unable to leave master mutex!??\n");
|
||||||
|
|
||||||
|
return rslt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RPCSS_ServerProcessRANMessage(PRPCSS_NP_MESSAGE pMsg, PRPCSS_NP_REPLY pReply)
|
||||||
|
{
|
||||||
|
WINE_TRACE("\n");
|
||||||
|
/* we do absolutely nothing, but on the server end,
|
||||||
|
the lazy timeout is reset as a result of our connection. */
|
||||||
|
RPCSS_SetMaxLazyTimeout(pMsg->message.ranmsg.timeout);
|
||||||
|
RPCSS_SetLazyTimeRemaining(RPCSS_GetMaxLazyTimeout());
|
||||||
|
pReply->as_uint = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RPCSS_ServerProcessREGISTEREPMessage(PRPCSS_NP_MESSAGE pMsg, PRPCSS_NP_REPLY pReply,
|
||||||
|
char *vardata)
|
||||||
|
{
|
||||||
|
WINE_TRACE("\n");
|
||||||
|
|
||||||
|
RPCSS_RegisterRpcEndpoints(
|
||||||
|
pMsg->message.registerepmsg.iface,
|
||||||
|
pMsg->message.registerepmsg.object_count,
|
||||||
|
pMsg->message.registerepmsg.binding_count,
|
||||||
|
pMsg->message.registerepmsg.no_replace,
|
||||||
|
vardata,
|
||||||
|
pMsg->vardata_payload_size
|
||||||
|
);
|
||||||
|
|
||||||
|
/* no reply */
|
||||||
|
pReply->as_uint = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RPCSS_ServerProcessUNREGISTEREPMessage(PRPCSS_NP_MESSAGE pMsg,
|
||||||
|
PRPCSS_NP_REPLY pReply, char *vardata)
|
||||||
|
{
|
||||||
|
WINE_TRACE("\n");
|
||||||
|
|
||||||
|
RPCSS_UnregisterRpcEndpoints(
|
||||||
|
pMsg->message.unregisterepmsg.iface,
|
||||||
|
pMsg->message.unregisterepmsg.object_count,
|
||||||
|
pMsg->message.unregisterepmsg.binding_count,
|
||||||
|
vardata,
|
||||||
|
pMsg->vardata_payload_size
|
||||||
|
);
|
||||||
|
|
||||||
|
/* no reply */
|
||||||
|
pReply->as_uint = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RPCSS_ServerProcessRESOLVEEPMessage(PRPCSS_NP_MESSAGE pMsg,
|
||||||
|
PRPCSS_NP_REPLY pReply, char *vardata)
|
||||||
|
{
|
||||||
|
WINE_TRACE("\n");
|
||||||
|
|
||||||
|
/* for now, reply is placed into *pReply.as_string, on success, by RPCSS_ResolveRpcEndpoints */
|
||||||
|
ZeroMemory(pReply->as_string, MAX_RPCSS_NP_REPLY_STRING_LEN);
|
||||||
|
RPCSS_ResolveRpcEndpoints(
|
||||||
|
pMsg->message.resolveepmsg.iface,
|
||||||
|
pMsg->message.resolveepmsg.object,
|
||||||
|
vardata,
|
||||||
|
pReply->as_string
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RPCSS_ServerProcessMessage(PRPCSS_NP_MESSAGE pMsg, PRPCSS_NP_REPLY pReply, char *vardata)
|
||||||
|
{
|
||||||
|
WINE_TRACE("\n");
|
||||||
|
switch (pMsg->message_type) {
|
||||||
|
case RPCSS_NP_MESSAGE_TYPEID_RANMSG:
|
||||||
|
RPCSS_ServerProcessRANMessage(pMsg, pReply);
|
||||||
|
break;
|
||||||
|
case RPCSS_NP_MESSAGE_TYPEID_REGISTEREPMSG:
|
||||||
|
RPCSS_ServerProcessREGISTEREPMessage(pMsg, pReply, vardata);
|
||||||
|
break;
|
||||||
|
case RPCSS_NP_MESSAGE_TYPEID_UNREGISTEREPMSG:
|
||||||
|
RPCSS_ServerProcessUNREGISTEREPMessage(pMsg, pReply, vardata);
|
||||||
|
break;
|
||||||
|
case RPCSS_NP_MESSAGE_TYPEID_RESOLVEEPMSG:
|
||||||
|
RPCSS_ServerProcessRESOLVEEPMessage(pMsg, pReply, vardata);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
WINE_ERR("Message type unknown!! No action taken.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* each message gets its own thread. this is it. */
|
||||||
|
VOID HandlerThread(LPVOID lpvPipeHandle)
|
||||||
|
{
|
||||||
|
RPCSS_NP_MESSAGE msg, vardata_payload_msg;
|
||||||
|
char *c, *vardata = NULL;
|
||||||
|
RPCSS_NP_REPLY reply;
|
||||||
|
DWORD bytesread, written;
|
||||||
|
BOOL success, had_payload = FALSE;
|
||||||
|
HANDLE mypipe;
|
||||||
|
|
||||||
|
mypipe = (HANDLE) lpvPipeHandle;
|
||||||
|
|
||||||
|
WINE_TRACE("mypipe: %p\n", mypipe);
|
||||||
|
|
||||||
|
success = ReadFile(
|
||||||
|
mypipe, /* pipe handle */
|
||||||
|
(char *) &msg, /* message buffer */
|
||||||
|
sizeof(RPCSS_NP_MESSAGE), /* message buffer size */
|
||||||
|
&bytesread, /* receives number of bytes read */
|
||||||
|
NULL /* not overlapped */
|
||||||
|
);
|
||||||
|
|
||||||
|
if (msg.vardata_payload_size) {
|
||||||
|
had_payload = TRUE;
|
||||||
|
/* this fudge space allows us not to worry about exceeding the buffer space
|
||||||
|
on the last read */
|
||||||
|
vardata = LocalAlloc(LPTR, (msg.vardata_payload_size) + VARDATA_PAYLOAD_BYTES);
|
||||||
|
if (!vardata) {
|
||||||
|
WINE_ERR("vardata memory allocation failure.\n");
|
||||||
|
success = FALSE;
|
||||||
|
} else {
|
||||||
|
for ( c = vardata; (c - vardata) < msg.vardata_payload_size;
|
||||||
|
c += VARDATA_PAYLOAD_BYTES) {
|
||||||
|
success = ReadFile(
|
||||||
|
mypipe,
|
||||||
|
(char *) &vardata_payload_msg,
|
||||||
|
sizeof(RPCSS_NP_MESSAGE),
|
||||||
|
&bytesread,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
if ( (!success) || (bytesread != sizeof(RPCSS_NP_MESSAGE)) ||
|
||||||
|
(vardata_payload_msg.message_type != RPCSS_NP_MESSAGE_TYPEID_VARDATAPAYLOADMSG) ) {
|
||||||
|
WINE_ERR("vardata payload read failure! (s=%s,br=%ld,exp_br=%d,mt=%u,mt_exp=%u\n",
|
||||||
|
success ? "TRUE" : "FALSE", bytesread, sizeof(RPCSS_NP_MESSAGE),
|
||||||
|
vardata_payload_msg.message_type, RPCSS_NP_MESSAGE_TYPEID_VARDATAPAYLOADMSG);
|
||||||
|
success = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
CopyMemory(c, vardata_payload_msg.message.vardatapayloadmsg.payload, VARDATA_PAYLOAD_BYTES);
|
||||||
|
WINE_TRACE("payload read.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (success && (bytesread == sizeof(RPCSS_NP_MESSAGE))) {
|
||||||
|
WINE_TRACE("read success.\n");
|
||||||
|
/* process the message and send a reply, serializing requests. */
|
||||||
|
EnterCriticalSection(&np_server_cs);
|
||||||
|
WINE_TRACE("processing message.\n");
|
||||||
|
RPCSS_ServerProcessMessage(&msg, &reply, vardata);
|
||||||
|
LeaveCriticalSection(&np_server_cs);
|
||||||
|
|
||||||
|
if (had_payload) LocalFree(vardata);
|
||||||
|
|
||||||
|
WINE_TRACE("message processed, sending reply....\n");
|
||||||
|
|
||||||
|
success = WriteFile(
|
||||||
|
mypipe, /* pipe handle */
|
||||||
|
(char *) &reply, /* reply buffer */
|
||||||
|
sizeof(RPCSS_NP_REPLY), /* reply buffer size */
|
||||||
|
&written, /* receives number of bytes written */
|
||||||
|
NULL /* not overlapped */
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( (!success) || (written != sizeof(RPCSS_NP_REPLY)) )
|
||||||
|
WINE_WARN("Message reply failed. (successs=%s, br=%ld, exp_br=%d)\n",
|
||||||
|
success ? "TRUE" : "FALSE", written, sizeof(RPCSS_NP_REPLY));
|
||||||
|
else
|
||||||
|
WINE_TRACE("Reply sent successfully.\n");
|
||||||
|
} else
|
||||||
|
WINE_WARN("Message receipt failed.\n");
|
||||||
|
|
||||||
|
FlushFileBuffers(mypipe);
|
||||||
|
DisconnectNamedPipe(mypipe);
|
||||||
|
CloseHandle(mypipe);
|
||||||
|
InterlockedDecrement(&srv_thread_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID NPMainWorkThread(LPVOID ignored)
|
||||||
|
{
|
||||||
|
BOOL connected;
|
||||||
|
HANDLE hthread, master_mutex = RPCSS_GetMasterMutex();
|
||||||
|
DWORD threadid, wait_result;
|
||||||
|
|
||||||
|
WINE_TRACE("\n");
|
||||||
|
|
||||||
|
while (server_live) {
|
||||||
|
connected = ConnectNamedPipe(np_server_end, NULL) ?
|
||||||
|
TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
|
||||||
|
|
||||||
|
if (connected) {
|
||||||
|
/* is "work" the act of connecting pipes, or the act of serving
|
||||||
|
requests successfully? for now I will make it the former. */
|
||||||
|
if (!SetEvent(np_server_work_event))
|
||||||
|
WINE_WARN("failed to signal np_server_work_event.\n");
|
||||||
|
|
||||||
|
/* Create a thread for this client. */
|
||||||
|
InterlockedIncrement(&srv_thread_count);
|
||||||
|
hthread = CreateThread(
|
||||||
|
NULL, /* no security attribute */
|
||||||
|
0, /* default stack size */
|
||||||
|
(LPTHREAD_START_ROUTINE) HandlerThread,
|
||||||
|
(LPVOID) np_server_end, /* thread parameter */
|
||||||
|
0, /* not suspended */
|
||||||
|
&threadid /* returns thread ID (not used) */
|
||||||
|
);
|
||||||
|
|
||||||
|
if (hthread) {
|
||||||
|
WINE_TRACE("Spawned handler thread: %p\n", hthread);
|
||||||
|
CloseHandle(hthread);
|
||||||
|
|
||||||
|
/* for safety's sake, hold the mutex while we switch the pipe */
|
||||||
|
|
||||||
|
wait_result = WaitForSingleObject(master_mutex, MASTER_MUTEX_TIMEOUT);
|
||||||
|
|
||||||
|
switch (wait_result) {
|
||||||
|
case WAIT_ABANDONED: /* ? */
|
||||||
|
case WAIT_OBJECT_0:
|
||||||
|
/* we have ownership */
|
||||||
|
break;
|
||||||
|
case WAIT_FAILED:
|
||||||
|
case WAIT_TIMEOUT:
|
||||||
|
default:
|
||||||
|
/* huh? */
|
||||||
|
wait_result = WAIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wait_result == WAIT_FAILED) {
|
||||||
|
WINE_ERR("Couldn't enter master mutex. Expect prolems.\n");
|
||||||
|
} else {
|
||||||
|
/* now create a new named pipe instance to listen on */
|
||||||
|
np_server_end = CreateNamedPipe(
|
||||||
|
NAME_RPCSS_NAMED_PIPE, /* pipe name */
|
||||||
|
PIPE_ACCESS_DUPLEX, /* pipe open mode */
|
||||||
|
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, /* pipe-specific modes */
|
||||||
|
PIPE_UNLIMITED_INSTANCES, /* maximum instances */
|
||||||
|
sizeof(RPCSS_NP_REPLY), /* output buffer size */
|
||||||
|
sizeof(RPCSS_NP_MESSAGE), /* input buffer size */
|
||||||
|
2000, /* time-out interval */
|
||||||
|
NULL /* SD */
|
||||||
|
);
|
||||||
|
|
||||||
|
if (np_server_end == INVALID_HANDLE_VALUE) {
|
||||||
|
WINE_ERR("Failed to recreate named pipe!\n");
|
||||||
|
/* not sure what to do? */
|
||||||
|
assert(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ReleaseMutex(master_mutex))
|
||||||
|
WINE_ERR("Uh oh. Couldn't leave master mutex. Expect deadlock.\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
WINE_ERR("Failed to spawn handler thread!\n");
|
||||||
|
DisconnectNamedPipe(np_server_end);
|
||||||
|
InterlockedDecrement(&srv_thread_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WINE_TRACE("Server thread shutdown.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE RPCSS_NPConnect(void)
|
||||||
|
{
|
||||||
|
HANDLE the_pipe = NULL;
|
||||||
|
DWORD dwmode, wait_result;
|
||||||
|
HANDLE master_mutex = RPCSS_GetMasterMutex();
|
||||||
|
|
||||||
|
WINE_TRACE("\n");
|
||||||
|
|
||||||
|
while (TRUE) {
|
||||||
|
|
||||||
|
wait_result = WaitForSingleObject(master_mutex, MASTER_MUTEX_TIMEOUT);
|
||||||
|
switch (wait_result) {
|
||||||
|
case WAIT_ABANDONED:
|
||||||
|
case WAIT_OBJECT_0:
|
||||||
|
break;
|
||||||
|
case WAIT_FAILED:
|
||||||
|
case WAIT_TIMEOUT:
|
||||||
|
default:
|
||||||
|
WINE_ERR("This should never happen: couldn't enter mutex.\n");
|
||||||
|
return (HANDLE) NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* try to open the client side of the named pipe. */
|
||||||
|
the_pipe = CreateFileA(
|
||||||
|
NAME_RPCSS_NAMED_PIPE, /* pipe name */
|
||||||
|
GENERIC_READ | GENERIC_WRITE, /* r/w access */
|
||||||
|
0, /* no sharing */
|
||||||
|
NULL, /* no security attributes */
|
||||||
|
OPEN_EXISTING, /* open an existing pipe */
|
||||||
|
0, /* default attributes */
|
||||||
|
NULL /* no template file */
|
||||||
|
);
|
||||||
|
|
||||||
|
if (the_pipe != INVALID_HANDLE_VALUE)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (GetLastError() != ERROR_PIPE_BUSY) {
|
||||||
|
WINE_WARN("Unable to open named pipe %s (assuming unavailable).\n",
|
||||||
|
wine_dbgstr_a(NAME_RPCSS_NAMED_PIPE));
|
||||||
|
the_pipe = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
WINE_WARN("Named pipe busy (will wait)\n");
|
||||||
|
|
||||||
|
if (!ReleaseMutex(master_mutex))
|
||||||
|
WINE_ERR("Failed to release master mutex. Expect deadlock.\n");
|
||||||
|
|
||||||
|
/* wait for the named pipe. We are only
|
||||||
|
willing to wait only 5 seconds. It should be available /very/ soon. */
|
||||||
|
if (! WaitNamedPipeA(NAME_RPCSS_NAMED_PIPE, MASTER_MUTEX_WAITNAMEDPIPE_TIMEOUT))
|
||||||
|
{
|
||||||
|
WINE_ERR("Named pipe unavailable after waiting. Something is probably wrong.\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (the_pipe) {
|
||||||
|
dwmode = PIPE_READMODE_MESSAGE;
|
||||||
|
/* SetNamedPipeHandleState not implemented ATM, but still seems to work somehow. */
|
||||||
|
if (! SetNamedPipeHandleState(the_pipe, &dwmode, NULL, NULL))
|
||||||
|
WINE_WARN("Failed to set pipe handle state\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ReleaseMutex(master_mutex))
|
||||||
|
WINE_ERR("Uh oh, failed to leave the RPC Master Mutex!\n");
|
||||||
|
|
||||||
|
return the_pipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL RPCSS_SendReceiveNPMsg(HANDLE np, PRPCSS_NP_MESSAGE msg, PRPCSS_NP_REPLY reply)
|
||||||
|
{
|
||||||
|
DWORD count;
|
||||||
|
|
||||||
|
WINE_TRACE("(np == %p, msg == %p, reply == %p)\n", np, msg, reply);
|
||||||
|
|
||||||
|
if (! WriteFile(np, msg, sizeof(RPCSS_NP_MESSAGE), &count, NULL)) {
|
||||||
|
WINE_ERR("write failed.\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count != sizeof(RPCSS_NP_MESSAGE)) {
|
||||||
|
WINE_ERR("write count mismatch.\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! ReadFile(np, reply, sizeof(RPCSS_NP_REPLY), &count, NULL)) {
|
||||||
|
WINE_ERR("read failed.\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count != sizeof(RPCSS_NP_REPLY)) {
|
||||||
|
WINE_ERR("read count mismatch. got %ld, expected %u.\n", count, sizeof(RPCSS_NP_REPLY));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* message execution was successful */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL RPCSS_BecomePipeServer(void)
|
||||||
|
{
|
||||||
|
RPCSS_NP_MESSAGE msg;
|
||||||
|
RPCSS_NP_REPLY reply;
|
||||||
|
BOOL rslt = TRUE;
|
||||||
|
HANDLE client_handle, hthread, master_mutex = RPCSS_GetMasterMutex();
|
||||||
|
DWORD threadid, wait_result;
|
||||||
|
|
||||||
|
WINE_TRACE("\n");
|
||||||
|
|
||||||
|
wait_result = WaitForSingleObject(master_mutex, MASTER_MUTEX_TIMEOUT);
|
||||||
|
|
||||||
|
switch (wait_result) {
|
||||||
|
case WAIT_ABANDONED: /* ? */
|
||||||
|
case WAIT_OBJECT_0:
|
||||||
|
/* we have ownership */
|
||||||
|
break;
|
||||||
|
case WAIT_FAILED:
|
||||||
|
case WAIT_TIMEOUT:
|
||||||
|
default:
|
||||||
|
WINE_ERR("Couldn't enter master mutex.\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now we have the master mutex. during this time we will
|
||||||
|
*
|
||||||
|
* o check if an rpcss already listens on the pipe. If so,
|
||||||
|
* we will tell it we were invoked, which will cause the
|
||||||
|
* other end to update its timeouts. After, we just return
|
||||||
|
* false.
|
||||||
|
*
|
||||||
|
* o otherwise, we establish the pipe for ourselves and get
|
||||||
|
* ready to listen on it
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ((client_handle = RPCSS_NPConnect()) != NULL) {
|
||||||
|
msg.message_type = RPCSS_NP_MESSAGE_TYPEID_RANMSG;
|
||||||
|
msg.message.ranmsg.timeout = RPCSS_GetMaxLazyTimeout();
|
||||||
|
msg.vardata_payload_size = 0;
|
||||||
|
if (!RPCSS_SendReceiveNPMsg(client_handle, &msg, &reply))
|
||||||
|
WINE_ERR("Something is amiss: RPC_SendReceive failed.\n");
|
||||||
|
rslt = FALSE;
|
||||||
|
}
|
||||||
|
if (rslt) {
|
||||||
|
np_server_work_event = CreateEventA(NULL, FALSE, FALSE, "RpcNpServerWorkEvent");
|
||||||
|
if (np_server_work_event == NULL) {
|
||||||
|
/* dunno what we can do then */
|
||||||
|
WINE_ERR("Unable to create the np_server_work_event\n");
|
||||||
|
assert(FALSE);
|
||||||
|
}
|
||||||
|
InitializeCriticalSection(&np_server_cs);
|
||||||
|
|
||||||
|
np_server_end = CreateNamedPipe(
|
||||||
|
NAME_RPCSS_NAMED_PIPE, /* pipe name */
|
||||||
|
PIPE_ACCESS_DUPLEX, /* pipe open mode */
|
||||||
|
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, /* pipe-specific modes */
|
||||||
|
PIPE_UNLIMITED_INSTANCES, /* maximum number of instances */
|
||||||
|
sizeof(RPCSS_NP_REPLY), /* output buffer size */
|
||||||
|
sizeof(RPCSS_NP_MESSAGE), /* input buffer size */
|
||||||
|
2000, /* time-out interval */
|
||||||
|
NULL /* SD */
|
||||||
|
);
|
||||||
|
|
||||||
|
if (np_server_end == INVALID_HANDLE_VALUE) {
|
||||||
|
WINE_ERR("Failed to create named pipe!\n");
|
||||||
|
DeleteCriticalSection(&np_server_cs);
|
||||||
|
if (!CloseHandle(np_server_work_event)) /* we will leak the handle... */
|
||||||
|
WINE_WARN("Failed to close np_server_work_event handle!\n");
|
||||||
|
np_server_work_event = NULL;
|
||||||
|
np_server_end = NULL;
|
||||||
|
rslt = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
server_live = rslt;
|
||||||
|
|
||||||
|
if (rslt) {
|
||||||
|
/* OK, now spawn the (single) server thread */
|
||||||
|
hthread = CreateThread(
|
||||||
|
NULL, /* no security attribute */
|
||||||
|
0, /* default stack size */
|
||||||
|
(LPTHREAD_START_ROUTINE) NPMainWorkThread,
|
||||||
|
(LPVOID) NULL, /* thread parameter */
|
||||||
|
0, /* not suspended */
|
||||||
|
&threadid /* returns thread ID (not used) */
|
||||||
|
);
|
||||||
|
if (hthread) {
|
||||||
|
WINE_TRACE("Created server thread.\n");
|
||||||
|
CloseHandle(hthread);
|
||||||
|
} else {
|
||||||
|
WINE_ERR("Serious error: unable to create server thread!\n");
|
||||||
|
if (!CloseHandle(np_server_work_event)) /* we will leak the handle... */
|
||||||
|
WINE_WARN("Failed to close np_server_work_event handle!\n");
|
||||||
|
if (!CloseHandle(np_server_end)) /* we will leak the handle... */
|
||||||
|
WINE_WARN("Unable to close named pipe handle!\n");
|
||||||
|
DeleteCriticalSection(&np_server_cs);
|
||||||
|
np_server_end = NULL;
|
||||||
|
np_server_work_event = NULL;
|
||||||
|
rslt = FALSE;
|
||||||
|
server_live = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!ReleaseMutex(master_mutex))
|
||||||
|
WINE_ERR("Unable to leave master mutex!??\n");
|
||||||
|
|
||||||
|
return rslt;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL RPCSS_NPDoWork(void)
|
||||||
|
{
|
||||||
|
DWORD waitresult = WaitForSingleObject(np_server_work_event, 1000);
|
||||||
|
|
||||||
|
if (waitresult == WAIT_TIMEOUT)
|
||||||
|
return FALSE;
|
||||||
|
if (waitresult == WAIT_OBJECT_0)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* RPCSS definitions
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002 Greg Turner
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __WINE_RPCSS_H
|
||||||
|
#define __WINE_RPCSS_H
|
||||||
|
|
||||||
|
#include "wine/rpcss_shared.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
|
/* in seconds */
|
||||||
|
#define RPCSS_DEFAULT_MAX_LAZY_TIMEOUT 30
|
||||||
|
|
||||||
|
/* rpcss_main.c */
|
||||||
|
HANDLE RPCSS_GetMasterMutex(void);
|
||||||
|
BOOL RPCSS_ReadyToDie(void);
|
||||||
|
void RPCSS_SetLazyTimeRemaining(long);
|
||||||
|
long RPCSS_GetLazyTimeRemaining(void);
|
||||||
|
void RPCSS_SetMaxLazyTimeout(long);
|
||||||
|
long RPCSS_GetMaxLazyTimeout(void);
|
||||||
|
|
||||||
|
/* epmap_server.c */
|
||||||
|
BOOL RPCSS_EpmapEmpty(void);
|
||||||
|
BOOL RPCSS_NPDoWork(void);
|
||||||
|
void RPCSS_RegisterRpcEndpoints(RPC_SYNTAX_IDENTIFIER iface, int object_count,
|
||||||
|
int binding_count, int no_replace, char *vardata, long vardata_size);
|
||||||
|
void RPCSS_UnregisterRpcEndpoints(RPC_SYNTAX_IDENTIFIER iface, int object_count,
|
||||||
|
int binding_count, char *vardata, long vardata_size);
|
||||||
|
void RPCSS_ResolveRpcEndpoints(RPC_SYNTAX_IDENTIFIER iface, UUID object,
|
||||||
|
char *protseq, char *rslt_ep);
|
||||||
|
|
||||||
|
/* named_pipe_kludge.c */
|
||||||
|
BOOL RPCSS_BecomePipeServer(void);
|
||||||
|
BOOL RPCSS_UnBecomePipeServer(void);
|
||||||
|
LONG RPCSS_SrvThreadCount(void);
|
||||||
|
|
||||||
|
#endif /* __WINE_RPCSS_H */
|
|
@ -0,0 +1,316 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2001, Ove Kåven, TransGaming Technologies Inc.
|
||||||
|
* Copyright 2002 Greg Turner
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* ---- rpcss_main.c:
|
||||||
|
* Initialize and start serving requests. Bail if rpcss already is
|
||||||
|
* running.
|
||||||
|
*
|
||||||
|
* ---- RPCSS.EXE:
|
||||||
|
*
|
||||||
|
* Wine needs a server whose role is somewhat like that
|
||||||
|
* of rpcss.exe in windows. This is not a clone of
|
||||||
|
* windows rpcss at all. It has been given the same name, however,
|
||||||
|
* to provide for the possibility that at some point in the future,
|
||||||
|
* it may become interface compatible with the "real" rpcss.exe on
|
||||||
|
* Windows.
|
||||||
|
*
|
||||||
|
* ---- KNOWN BUGS / TODO:
|
||||||
|
*
|
||||||
|
* o Service hooks are unimplemented (if you bother to implement
|
||||||
|
* these, also implement net.exe, at least for "net start" and
|
||||||
|
* "net stop" (should be pretty easy I guess, assuming the rest
|
||||||
|
* of the services API infrastructure works.
|
||||||
|
*
|
||||||
|
* o Is supposed to use RPC, not random kludges, to map endpoints.
|
||||||
|
*
|
||||||
|
* o Probably name services should be implemented here as well.
|
||||||
|
*
|
||||||
|
* o Wine's named pipes (in general) may not interoperate with those of
|
||||||
|
* Windows yet (?)
|
||||||
|
*
|
||||||
|
* o There is a looming problem regarding listening on priveleged
|
||||||
|
* ports. We will need to be able to coexist with SAMBA, and able
|
||||||
|
* to function without running winelib code as root. This may
|
||||||
|
* take some doing, including significant reconceptualization of the
|
||||||
|
* role of rpcss.exe in wine.
|
||||||
|
*
|
||||||
|
* o Who knows? Whatever rpcss does, we ought to at
|
||||||
|
* least think about doing... but what /does/ it do?
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "rpcss.h"
|
||||||
|
#include "winnt.h"
|
||||||
|
|
||||||
|
#include "wine/debug.h"
|
||||||
|
|
||||||
|
WINE_DEFAULT_DEBUG_CHANNEL(ole);
|
||||||
|
|
||||||
|
static HANDLE master_mutex;
|
||||||
|
static long max_lazy_timeout = RPCSS_DEFAULT_MAX_LAZY_TIMEOUT;
|
||||||
|
|
||||||
|
HANDLE RPCSS_GetMasterMutex(void)
|
||||||
|
{
|
||||||
|
return master_mutex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RPCSS_SetMaxLazyTimeout(long mlt)
|
||||||
|
{
|
||||||
|
/* FIXME: this max ensures that no caller will decrease our wait time,
|
||||||
|
but could have other bad results. fix: Store "next_max_lazy_timeout"
|
||||||
|
and install it as neccesary next time we "do work"? */
|
||||||
|
max_lazy_timeout = max(RPCSS_GetLazyTimeRemaining(), mlt);
|
||||||
|
}
|
||||||
|
|
||||||
|
long RPCSS_GetMaxLazyTimeout(void)
|
||||||
|
{
|
||||||
|
return max_lazy_timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* when do we just give up and bail? (UTC) */
|
||||||
|
static SYSTEMTIME lazy_timeout_time;
|
||||||
|
|
||||||
|
#if defined(NONAMELESSSTRUCT)
|
||||||
|
#define FILETIME_TO_ULARGEINT(filetime, ularge) \
|
||||||
|
( ularge.s.LowPart = filetime.dwLowDateTime, \
|
||||||
|
ularge.s.HighPart = filetime.dwHighDateTime )
|
||||||
|
#define ULARGEINT_TO_FILETIME(ularge, filetime) \
|
||||||
|
( filetime.dwLowDateTime = ularge.s.LowPart, \
|
||||||
|
filetime.dwHighDateTime = ularge.s.HighPart )
|
||||||
|
#else
|
||||||
|
#define FILETIME_TO_ULARGEINT(filetime, ularge) \
|
||||||
|
( ularge.LowPart = filetime.dwLowDateTime, \
|
||||||
|
ularge.HighPart = filetime.dwHighDateTime )
|
||||||
|
#define ULARGEINT_TO_FILETIME(ularge, filetime) \
|
||||||
|
( filetime.dwLowDateTime = ularge.LowPart, \
|
||||||
|
filetime.dwHighDateTime = ularge.HighPart )
|
||||||
|
#endif /* NONAMELESSSTRUCT */
|
||||||
|
|
||||||
|
#define TEN_MIL 10000000LL
|
||||||
|
|
||||||
|
/* returns time remaining in seconds */
|
||||||
|
long RPCSS_GetLazyTimeRemaining(void)
|
||||||
|
{
|
||||||
|
SYSTEMTIME st_just_now;
|
||||||
|
FILETIME ft_jn, ft_ltt;
|
||||||
|
ULARGE_INTEGER ul_jn, ul_ltt;
|
||||||
|
|
||||||
|
GetSystemTime(&st_just_now);
|
||||||
|
SystemTimeToFileTime(&st_just_now, &ft_jn);
|
||||||
|
FILETIME_TO_ULARGEINT(ft_jn, ul_jn);
|
||||||
|
|
||||||
|
SystemTimeToFileTime(&lazy_timeout_time, &ft_ltt);
|
||||||
|
FILETIME_TO_ULARGEINT(ft_ltt, ul_ltt);
|
||||||
|
|
||||||
|
if (ul_jn.QuadPart > ul_ltt.QuadPart)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return (ul_ltt.QuadPart - ul_jn.QuadPart) / TEN_MIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RPCSS_SetLazyTimeRemaining(long seconds)
|
||||||
|
{
|
||||||
|
SYSTEMTIME st_just_now;
|
||||||
|
FILETIME ft_jn, ft_ltt;
|
||||||
|
ULARGE_INTEGER ul_jn, ul_ltt;
|
||||||
|
|
||||||
|
WINE_TRACE("(seconds == %ld)\n", seconds);
|
||||||
|
|
||||||
|
assert(seconds >= 0); /* negatives are not allowed */
|
||||||
|
|
||||||
|
GetSystemTime(&st_just_now);
|
||||||
|
SystemTimeToFileTime(&st_just_now, &ft_jn);
|
||||||
|
FILETIME_TO_ULARGEINT(ft_jn, ul_jn);
|
||||||
|
|
||||||
|
/* we want to find the time ltt, s.t. ltt = just_now + seconds */
|
||||||
|
ul_ltt.QuadPart = ul_jn.QuadPart + seconds * TEN_MIL;
|
||||||
|
|
||||||
|
/* great. just remember it */
|
||||||
|
ULARGEINT_TO_FILETIME(ul_ltt, ft_ltt);
|
||||||
|
if (! FileTimeToSystemTime(&ft_ltt, &lazy_timeout_time))
|
||||||
|
assert(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef FILETIME_TO_ULARGEINT
|
||||||
|
#undef ULARGEINT_TO_FILETIME
|
||||||
|
#undef TEN_MIL
|
||||||
|
|
||||||
|
BOOL RPCSS_work(void)
|
||||||
|
{
|
||||||
|
return RPCSS_NPDoWork();
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL RPCSS_Empty(void)
|
||||||
|
{
|
||||||
|
BOOL rslt = TRUE;
|
||||||
|
|
||||||
|
rslt = RPCSS_EpmapEmpty();
|
||||||
|
|
||||||
|
return rslt;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL RPCSS_ReadyToDie(void)
|
||||||
|
{
|
||||||
|
long ltr = RPCSS_GetLazyTimeRemaining();
|
||||||
|
LONG stc = RPCSS_SrvThreadCount();
|
||||||
|
BOOL empty = RPCSS_Empty();
|
||||||
|
return ( empty && (ltr <= 0) && (stc == 0) );
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL RPCSS_Initialize(void)
|
||||||
|
{
|
||||||
|
WINE_TRACE("\n");
|
||||||
|
|
||||||
|
master_mutex = CreateMutexA( NULL, FALSE, RPCSS_MASTER_MUTEX_NAME);
|
||||||
|
if (!master_mutex) {
|
||||||
|
WINE_ERR("Failed to create master mutex\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!RPCSS_BecomePipeServer()) {
|
||||||
|
WINE_WARN("Server already running: exiting.\n");
|
||||||
|
|
||||||
|
CloseHandle(master_mutex);
|
||||||
|
master_mutex = NULL;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* returns false if we discover at the last moment that we
|
||||||
|
aren't ready to terminate */
|
||||||
|
BOOL RPCSS_Shutdown(void)
|
||||||
|
{
|
||||||
|
if (!RPCSS_UnBecomePipeServer())
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!CloseHandle(master_mutex))
|
||||||
|
WINE_WARN("Failed to release master mutex\n");
|
||||||
|
|
||||||
|
master_mutex = (HANDLE)NULL;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RPCSS_MainLoop(void)
|
||||||
|
{
|
||||||
|
BOOL did_something_new;
|
||||||
|
|
||||||
|
WINE_TRACE("\n");
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
did_something_new = FALSE;
|
||||||
|
|
||||||
|
while ( (! did_something_new) && (! RPCSS_ReadyToDie()) )
|
||||||
|
did_something_new = (RPCSS_work() || did_something_new);
|
||||||
|
|
||||||
|
if ((! did_something_new) && RPCSS_ReadyToDie())
|
||||||
|
break; /* that's it for us */
|
||||||
|
|
||||||
|
if (did_something_new)
|
||||||
|
RPCSS_SetLazyTimeRemaining(max_lazy_timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL RPCSS_ProcessArgs( int argc, char **argv )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char *c,*c1;
|
||||||
|
|
||||||
|
for (i = 1; i < argc; i++) {
|
||||||
|
c = argv[i];
|
||||||
|
while (*c == ' ') c++;
|
||||||
|
if ((*c != '-') && (*c != '/'))
|
||||||
|
return FALSE;
|
||||||
|
c++;
|
||||||
|
switch (*(c++)) {
|
||||||
|
case 't':
|
||||||
|
case 'T':
|
||||||
|
while (*c == ' ') c++;
|
||||||
|
if (*c == '\0') {
|
||||||
|
/* next arg */
|
||||||
|
if (++i >= argc)
|
||||||
|
return FALSE;
|
||||||
|
c = argv[i];
|
||||||
|
while (*c == ' ') c++;
|
||||||
|
if (c == '\0')
|
||||||
|
return FALSE;
|
||||||
|
} else
|
||||||
|
return FALSE;
|
||||||
|
max_lazy_timeout = strtol(c, &c1, 0);
|
||||||
|
if (c == c1)
|
||||||
|
return FALSE;
|
||||||
|
c = c1;
|
||||||
|
if (max_lazy_timeout <= 0)
|
||||||
|
return FALSE;
|
||||||
|
if (max_lazy_timeout == LONG_MAX)
|
||||||
|
return FALSE;
|
||||||
|
WINE_TRACE("read timeout argument: %ld\n", max_lazy_timeout);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
while (*c == ' ') c++;
|
||||||
|
if (*c != '\0') return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RPCSS_Usage(void)
|
||||||
|
{
|
||||||
|
printf("\nWine RPCSS\n");
|
||||||
|
printf("\nsyntax: rpcss [-t timeout]\n\n");
|
||||||
|
printf(" -t: rpcss (or the running rpcss process) will\n");
|
||||||
|
printf(" execute with at least the specified timeout.\n");
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main( int argc, char **argv )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We are invoked as a standard executable; we act in a
|
||||||
|
* "lazy" manner. We open up our pipe, and hang around until we have
|
||||||
|
* nothing left to do, and then silently terminate. When we're needed
|
||||||
|
* again, rpcrt4.dll.so will invoke us automatically.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!RPCSS_ProcessArgs(argc, argv)) {
|
||||||
|
RPCSS_Usage();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we want to wait for something to happen, and then
|
||||||
|
timeout when no activity occurs. */
|
||||||
|
RPCSS_SetLazyTimeRemaining(max_lazy_timeout);
|
||||||
|
|
||||||
|
if (RPCSS_Initialize()) {
|
||||||
|
do
|
||||||
|
RPCSS_MainLoop();
|
||||||
|
while (!RPCSS_Shutdown());
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue