|  | /* | 
|  | * Endpoint Mapper | 
|  | * | 
|  | * Copyright (C) 2007 Robert Shearman for CodeWeavers | 
|  | * | 
|  | * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
|  | */ | 
|  |  | 
|  | #include "epm.h" | 
|  |  | 
|  | #include "wine/debug.h" | 
|  | #include "wine/list.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(ole); | 
|  |  | 
|  | struct registered_ept_entry | 
|  | { | 
|  | struct list entry; | 
|  | GUID object; | 
|  | RPC_SYNTAX_IDENTIFIER iface; | 
|  | RPC_SYNTAX_IDENTIFIER syntax; | 
|  | char *protseq; | 
|  | char *endpoint; | 
|  | char *address; | 
|  | char annotation[ept_max_annotation_size]; | 
|  | }; | 
|  |  | 
|  | static struct list registered_ept_entry_list = LIST_INIT(registered_ept_entry_list); | 
|  |  | 
|  | static CRITICAL_SECTION csEpm; | 
|  | static CRITICAL_SECTION_DEBUG critsect_debug = | 
|  | { | 
|  | 0, 0, &csEpm, | 
|  | { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, | 
|  | 0, 0, { (DWORD_PTR)(__FILE__ ": csEpm") } | 
|  | }; | 
|  | static CRITICAL_SECTION csEpm = { &critsect_debug, -1, 0, 0, 0, 0 }; | 
|  |  | 
|  | static const UUID nil_object; | 
|  |  | 
|  | /* must be called inside csEpm */ | 
|  | static void delete_registered_ept_entry(struct registered_ept_entry *entry) | 
|  | { | 
|  | I_RpcFree(entry->protseq); | 
|  | I_RpcFree(entry->endpoint); | 
|  | I_RpcFree(entry->address); | 
|  | list_remove(&entry->entry); | 
|  | HeapFree(GetProcessHeap(), 0, entry); | 
|  | } | 
|  |  | 
|  | static struct registered_ept_entry *find_ept_entry( | 
|  | const RPC_SYNTAX_IDENTIFIER *iface, const RPC_SYNTAX_IDENTIFIER *syntax, | 
|  | const char *protseq, const char *endpoint, const char *address, | 
|  | const UUID *object) | 
|  | { | 
|  | struct registered_ept_entry *entry; | 
|  | LIST_FOR_EACH_ENTRY(entry, ®istered_ept_entry_list, struct registered_ept_entry, entry) | 
|  | { | 
|  | if (memcmp(&entry->iface, iface, sizeof(RPC_SYNTAX_IDENTIFIER))) continue; | 
|  | if (memcmp(&entry->syntax, syntax, sizeof(RPC_SYNTAX_IDENTIFIER))) continue; | 
|  | if (strcmp(entry->protseq, protseq)) continue; | 
|  | if (memcmp(&entry->object, object, sizeof(UUID))) continue; | 
|  | WINE_TRACE("found entry with iface %d.%d %s, syntax %d.%d %s, protseq %s, object %s\n", | 
|  | entry->iface.SyntaxVersion.MajorVersion, entry->iface.SyntaxVersion.MinorVersion, | 
|  | wine_dbgstr_guid(&entry->iface.SyntaxGUID), | 
|  | entry->syntax.SyntaxVersion.MajorVersion, entry->syntax.SyntaxVersion.MinorVersion, | 
|  | wine_dbgstr_guid(&entry->syntax.SyntaxGUID), protseq, | 
|  | wine_dbgstr_guid(&entry->object)); | 
|  | return entry; | 
|  | } | 
|  | WINE_TRACE("not found\n"); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | void __RPC_USER ept_lookup_handle_t_rundown(ept_lookup_handle_t entry_handle) | 
|  | { | 
|  | WINE_FIXME("%p\n", entry_handle); | 
|  | } | 
|  |  | 
|  | void ept_insert(handle_t h, | 
|  | unsigned32 num_ents, | 
|  | ept_entry_t entries[], | 
|  | boolean32 replace, | 
|  | error_status_t *status) | 
|  | { | 
|  | unsigned32 i; | 
|  | RPC_STATUS rpc_status; | 
|  |  | 
|  | WINE_TRACE("(%p, %lu, %p, %lu, %p)\n", h, num_ents, entries, replace, status); | 
|  |  | 
|  | *status = RPC_S_OK; | 
|  |  | 
|  | EnterCriticalSection(&csEpm); | 
|  |  | 
|  | for (i = 0; i < num_ents; i++) | 
|  | { | 
|  | struct registered_ept_entry *entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry)); | 
|  | if (!entry) | 
|  | { | 
|  | /* FIXME: cleanup code to delete added entries */ | 
|  | *status = EPT_S_CANT_PERFORM_OP; | 
|  | break; | 
|  | } | 
|  | list_init(&entry->entry); | 
|  | memcpy(entry->annotation, entries[i].annotation, sizeof(entries[i].annotation)); | 
|  | rpc_status = TowerExplode(entries[i].tower, &entry->iface, &entry->syntax, | 
|  | &entry->protseq, &entry->endpoint, | 
|  | &entry->address); | 
|  | if (rpc_status != RPC_S_OK) | 
|  | { | 
|  | WINE_WARN("TowerExplode failed %lu\n", rpc_status); | 
|  | *status = rpc_status; | 
|  | break; /* FIXME: more cleanup? */ | 
|  | } | 
|  |  | 
|  | entry->object = entries[i].object; | 
|  |  | 
|  | if (replace) | 
|  | { | 
|  | /* FIXME: correct find algorithm */ | 
|  | struct registered_ept_entry *old_entry = find_ept_entry(&entry->iface, &entry->syntax, entry->protseq, entry->endpoint, entry->address, &entry->object); | 
|  | if (old_entry) delete_registered_ept_entry(old_entry); | 
|  | } | 
|  | list_add_tail(®istered_ept_entry_list, &entry->entry); | 
|  | } | 
|  |  | 
|  | LeaveCriticalSection(&csEpm); | 
|  | } | 
|  |  | 
|  | void ept_delete(handle_t h, | 
|  | unsigned32 num_ents, | 
|  | ept_entry_t entries[], | 
|  | error_status_t *status) | 
|  | { | 
|  | unsigned32 i; | 
|  | RPC_STATUS rpc_status; | 
|  |  | 
|  | *status = RPC_S_OK; | 
|  |  | 
|  | WINE_TRACE("(%p, %lu, %p, %p)\n", h, num_ents, entries, status); | 
|  |  | 
|  | EnterCriticalSection(&csEpm); | 
|  |  | 
|  | for (i = 0; i < num_ents; i++) | 
|  | { | 
|  | struct registered_ept_entry *entry; | 
|  | RPC_SYNTAX_IDENTIFIER iface, syntax; | 
|  | char *protseq; | 
|  | char *endpoint; | 
|  | char *address; | 
|  | rpc_status = TowerExplode(entries[i].tower, &iface, &syntax, &protseq, | 
|  | &endpoint, &address); | 
|  | if (rpc_status != RPC_S_OK) | 
|  | break; | 
|  | entry = find_ept_entry(&iface, &syntax, protseq, endpoint, address, &entries[i].object); | 
|  | if (entry) | 
|  | delete_registered_ept_entry(entry); | 
|  | else | 
|  | { | 
|  | *status = EPT_S_NOT_REGISTERED; | 
|  | break; | 
|  | } | 
|  | I_RpcFree(protseq); | 
|  | I_RpcFree(endpoint); | 
|  | I_RpcFree(address); | 
|  | } | 
|  |  | 
|  | LeaveCriticalSection(&csEpm); | 
|  | } | 
|  |  | 
|  | void ept_lookup(handle_t h, | 
|  | unsigned32 inquiry_type, | 
|  | uuid_p_t object, | 
|  | rpc_if_id_p_t interface_id, | 
|  | unsigned32 vers_option, | 
|  | ept_lookup_handle_t *entry_handle, | 
|  | unsigned32 max_ents, | 
|  | unsigned32 *num_ents, | 
|  | ept_entry_t entries[], | 
|  | error_status_t *status) | 
|  | { | 
|  | WINE_FIXME("(%p, %p, %p): stub\n", h, entry_handle, status); | 
|  |  | 
|  | *status = EPT_S_CANT_PERFORM_OP; | 
|  | } | 
|  |  | 
|  | void ept_map(handle_t h, | 
|  | uuid_p_t object, | 
|  | twr_p_t map_tower, | 
|  | ept_lookup_handle_t *entry_handle, | 
|  | unsigned32 max_towers, | 
|  | unsigned32 *num_towers, | 
|  | twr_p_t *towers, | 
|  | error_status_t *status) | 
|  | { | 
|  | RPC_STATUS rpc_status; | 
|  | RPC_SYNTAX_IDENTIFIER iface, syntax; | 
|  | char *protseq; | 
|  | struct registered_ept_entry *entry; | 
|  |  | 
|  | *status = RPC_S_OK; | 
|  | *num_towers = 0; | 
|  |  | 
|  | WINE_TRACE("(%p, %p, %p, %p, %lu, %p, %p, %p)\n", h, object, map_tower, | 
|  | entry_handle, max_towers, num_towers, towers, status); | 
|  |  | 
|  | rpc_status = TowerExplode(map_tower, &iface, &syntax, &protseq, | 
|  | NULL, NULL); | 
|  | if (rpc_status != RPC_S_OK) | 
|  | { | 
|  | *status = rpc_status; | 
|  | return; | 
|  | } | 
|  |  | 
|  | EnterCriticalSection(&csEpm); | 
|  |  | 
|  | LIST_FOR_EACH_ENTRY(entry, ®istered_ept_entry_list, struct registered_ept_entry, entry) | 
|  | { | 
|  | if (IsEqualGUID(&entry->iface.SyntaxGUID, &iface.SyntaxGUID) && | 
|  | (entry->iface.SyntaxVersion.MajorVersion == iface.SyntaxVersion.MajorVersion) && | 
|  | (entry->iface.SyntaxVersion.MinorVersion >= iface.SyntaxVersion.MinorVersion) && | 
|  | !memcmp(&entry->syntax, &syntax, sizeof(syntax)) && | 
|  | !strcmp(entry->protseq, protseq) && | 
|  | ((!object && IsEqualGUID(&entry->object, &nil_object)) || IsEqualGUID(object, &entry->object))) | 
|  | { | 
|  | if (*num_towers < max_towers) | 
|  | { | 
|  | rpc_status = TowerConstruct(&entry->iface, &entry->syntax, | 
|  | entry->protseq, entry->endpoint, | 
|  | entry->address, | 
|  | &towers[*num_towers]); | 
|  | if (rpc_status != RPC_S_OK) | 
|  | { | 
|  | *status = rpc_status; | 
|  | break; /* FIXME: more cleanup? */ | 
|  | } | 
|  | } | 
|  | (*num_towers)++; | 
|  | } | 
|  | } | 
|  |  | 
|  | LeaveCriticalSection(&csEpm); | 
|  | } | 
|  |  | 
|  | void ept_lookup_handle_free(handle_t h, | 
|  | ept_lookup_handle_t *entry_handle, | 
|  | error_status_t *status) | 
|  | { | 
|  | WINE_FIXME("(%p, %p, %p): stub\n", h, entry_handle, status); | 
|  |  | 
|  | *status = EPT_S_CANT_PERFORM_OP; | 
|  | } | 
|  |  | 
|  | void ept_inq_object(handle_t h, | 
|  | GUID *ept_object, | 
|  | error_status_t *status) | 
|  | { | 
|  | WINE_FIXME("(%p, %p, %p): stub\n", h, ept_object, status); | 
|  |  | 
|  | *status = EPT_S_CANT_PERFORM_OP; | 
|  | } | 
|  |  | 
|  | void ept_mgmt_delete(handle_t h, | 
|  | boolean32 object_speced, | 
|  | uuid_p_t object, | 
|  | twr_p_t tower, | 
|  | error_status_t *status) | 
|  | { | 
|  | WINE_FIXME("(%p, %ld, %p, %p, %p): stub\n", h, object_speced, object, tower, status); | 
|  |  | 
|  | *status = EPT_S_CANT_PERFORM_OP; | 
|  | } |