From c707e23675d0ffa94151639def4abb6a7c7b8564 Mon Sep 17 00:00:00 2001 From: Ove Kaaven Date: Thu, 22 May 2003 03:36:00 +0000 Subject: [PATCH] Initial support for RPC call failures, by catching RPC server exceptions and returning simple failure packets, and throwing exceptions on the client side when unmarshalling the failure packet. --- dlls/rpcrt4/ndr_midl.c | 4 ++++ dlls/rpcrt4/rpc_message.c | 24 ++++++++++++++++++++++-- dlls/rpcrt4/rpc_misc.h | 28 ++++++++++++++++++++++++++++ dlls/rpcrt4/rpc_server.c | 27 +++++++++++++++++++++++++-- 4 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 dlls/rpcrt4/rpc_misc.h diff --git a/dlls/rpcrt4/ndr_midl.c b/dlls/rpcrt4/ndr_midl.c index d364189ab51..09b236f265c 100644 --- a/dlls/rpcrt4/ndr_midl.c +++ b/dlls/rpcrt4/ndr_midl.c @@ -106,6 +106,10 @@ void WINAPI NdrProxySendReceive(void *This, pStubMsg->BufferStart = pStubMsg->RpcMsg->Buffer; pStubMsg->BufferEnd = pStubMsg->BufferStart + pStubMsg->BufferLength; pStubMsg->Buffer = pStubMsg->BufferStart; + + /* raise exception if call failed */ + if (hr == RPC_S_CALL_FAILED) RpcRaiseException(*(DWORD*)pStubMsg->Buffer); + else if (FAILED(hr)) RpcRaiseException(hr); } /*********************************************************************** diff --git a/dlls/rpcrt4/rpc_message.c b/dlls/rpcrt4/rpc_message.c index 1c73c4552b3..d2e7e1d4588 100644 --- a/dlls/rpcrt4/rpc_message.c +++ b/dlls/rpcrt4/rpc_message.c @@ -37,6 +37,7 @@ #include "wine/debug.h" #include "rpc_binding.h" +#include "rpc_misc.h" #include "rpc_defs.h" WINE_DEFAULT_DEBUG_CHANNEL(ole); @@ -111,7 +112,9 @@ RPC_STATUS WINAPI I_RpcSend(PRPC_MESSAGE pMsg) /* initialize packet header */ memset(&hdr, 0, sizeof(hdr)); hdr.rpc_ver = 4; - hdr.ptype = bind->server ? PKT_RESPONSE : PKT_REQUEST; + hdr.ptype = bind->server + ? ((pMsg->RpcFlags & WINE_RPCFLAG_EXCEPTION) ? PKT_FAULT : PKT_RESPONSE) + : PKT_REQUEST; hdr.object = *obj; /* FIXME: IIRC iff no object, the header structure excludes this elt */ hdr.if_id = (bind->server) ? sif->InterfaceId.SyntaxGUID : cif->InterfaceId.SyntaxGUID; hdr.if_vers = @@ -227,10 +230,27 @@ RPC_STATUS WINAPI I_RpcReceive(PRPC_MESSAGE pMsg) goto fail; } + status = RPC_S_PROTOCOL_ERROR; + + switch (hdr.ptype) { + case PKT_RESPONSE: + if (bind->server) goto fail; + break; + case PKT_REQUEST: + if (!bind->server) goto fail; + break; + case PKT_FAULT: + pMsg->RpcFlags |= WINE_RPCFLAG_EXCEPTION; + status = RPC_S_CALL_FAILED; /* ? */ + goto fail; + default: + goto fail; + } + /* success */ status = RPC_S_OK; - /* FIXME: check packet type, destination, etc? */ + /* FIXME: check destination, etc? */ break; } fail: diff --git a/dlls/rpcrt4/rpc_misc.h b/dlls/rpcrt4/rpc_misc.h new file mode 100644 index 00000000000..49c483e5c4b --- /dev/null +++ b/dlls/rpcrt4/rpc_misc.h @@ -0,0 +1,28 @@ +/* + * RPC definitions + * + * Copyright 2003 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 + * + */ + +#ifndef __WINE_RPC_MISC_H +#define __WINE_RPC_MISC_H + +/* flags for RPC_MESSAGE.RpcFlags */ +#define WINE_RPCFLAG_EXCEPTION 0x0001 + +#endif /* __WINE_RPC_MISC_H */ diff --git a/dlls/rpcrt4/rpc_server.c b/dlls/rpcrt4/rpc_server.c index 4e341924b1b..95955a03a07 100644 --- a/dlls/rpcrt4/rpc_server.c +++ b/dlls/rpcrt4/rpc_server.c @@ -31,10 +31,13 @@ #include "winreg.h" #include "rpc.h" +#include "excpt.h" #include "wine/debug.h" +#include "wine/exception.h" #include "rpc_server.h" +#include "rpc_misc.h" #include "rpc_defs.h" #define MAX_THREADS 128 @@ -63,7 +66,7 @@ static RpcPacket* spacket_head; static RpcPacket* spacket_tail; static HANDLE server_sem; -static DWORD worker_count, worker_free; +static DWORD worker_count, worker_free, worker_tls; static RpcServerInterface* RPCRT4_find_interface(UUID* object, UUID* if_id) { @@ -110,6 +113,18 @@ static RpcPacket* RPCRT4_pop_packet(void) return packet; } +static WINE_EXCEPTION_FILTER(rpc_filter) +{ + PRPC_MESSAGE msg; + msg = TlsGetValue(worker_tls); + I_RpcFreeBuffer(msg); + msg->RpcFlags |= WINE_RPCFLAG_EXCEPTION; + msg->BufferLength = sizeof(DWORD); + I_RpcGetBuffer(msg); + *(DWORD*)msg->Buffer = GetExceptionCode(); + return EXCEPTION_EXECUTE_HANDLER; +} + static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, void* buf) { RpcBinding* pbind; @@ -117,6 +132,7 @@ static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, void* buf RpcServerInterface* sif; RPC_DISPATCH_FUNCTION func; + TlsSetValue(worker_tls, &msg); memset(&msg, 0, sizeof(msg)); msg.BufferLength = hdr->len; msg.Buffer = buf; @@ -152,7 +168,12 @@ static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, void* buf MAKEWORD(hdr->drep[2], 0)); /* dispatch */ - if (func) func(&msg); + __TRY { + if (func) func(&msg); + } __EXCEPT(rpc_filter) { + /* failure packet was created in rpc_filter */ + TRACE("exception caught, returning failure packet\n"); + } __ENDTRY /* send response packet */ I_RpcSend(&msg); @@ -176,6 +197,7 @@ static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, void* buf HeapFree(GetProcessHeap(), 0, buf); I_RpcFreeBuffer(&msg); msg.Buffer = NULL; + TlsSetValue(worker_tls, NULL); } static DWORD CALLBACK RPCRT4_worker_thread(LPVOID the_arg) @@ -411,6 +433,7 @@ static void RPCRT4_start_listen(void) if (! ++listen_count) { if (!mgr_event) mgr_event = CreateEventA(NULL, TRUE, FALSE, NULL); if (!server_sem) server_sem = CreateSemaphoreA(NULL, 0, MAX_THREADS, NULL); + if (!worker_tls) worker_tls = TlsAlloc(); std_listen = TRUE; server_thread = CreateThread(NULL, 0, RPCRT4_server_thread, NULL, 0, NULL); LeaveCriticalSection(&listen_cs);