1 /* 2 * Copyright 2008 Hans Leidekker for CodeWeavers 3 * 4 * Based on the handle implementation from wininet. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include "config.h" 22 #include "ws2tcpip.h" 23 #include <stdarg.h> 24 25 #include "windef.h" 26 #include "winbase.h" 27 #include "winhttp.h" 28 29 #include "wine/debug.h" 30 #include "winhttp_private.h" 31 32 WINE_DEFAULT_DEBUG_CHANNEL(winhttp); 33 34 #define HANDLE_CHUNK_SIZE 0x10 35 36 static CRITICAL_SECTION handle_cs; 37 static CRITICAL_SECTION_DEBUG handle_cs_debug = 38 { 39 0, 0, &handle_cs, 40 { &handle_cs_debug.ProcessLocksList, &handle_cs_debug.ProcessLocksList }, 41 0, 0, { (ULONG_PTR)(__FILE__ ": handle_cs") } 42 }; 43 static CRITICAL_SECTION handle_cs = { &handle_cs_debug, -1, 0, 0, 0, 0 }; 44 45 static struct object_header **handles; 46 static ULONG_PTR next_handle; 47 static ULONG_PTR max_handles; 48 49 struct object_header *addref_object( struct object_header *hdr ) 50 { 51 ULONG refs = InterlockedIncrement( &hdr->refs ); 52 TRACE("%p -> refcount = %d\n", hdr, refs); 53 return hdr; 54 } 55 56 struct object_header *grab_object( HINTERNET hinternet ) 57 { 58 struct object_header *hdr = NULL; 59 ULONG_PTR handle = (ULONG_PTR)hinternet; 60 61 EnterCriticalSection( &handle_cs ); 62 63 if ((handle > 0) && (handle <= max_handles) && handles[handle - 1]) 64 hdr = addref_object( handles[handle - 1] ); 65 66 LeaveCriticalSection( &handle_cs ); 67 68 TRACE("handle 0x%lx -> %p\n", handle, hdr); 69 return hdr; 70 } 71 72 void release_object( struct object_header *hdr ) 73 { 74 ULONG refs = InterlockedDecrement( &hdr->refs ); 75 TRACE("object %p refcount = %d\n", hdr, refs); 76 if (!refs) 77 { 78 if (hdr->type == WINHTTP_HANDLE_TYPE_REQUEST) close_connection( (struct request *)hdr ); 79 80 send_callback( hdr, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, &hdr->handle, sizeof(HINTERNET) ); 81 82 TRACE("destroying object %p\n", hdr); 83 if (hdr->type != WINHTTP_HANDLE_TYPE_SESSION) list_remove( &hdr->entry ); 84 hdr->vtbl->destroy( hdr ); 85 } 86 } 87 88 HINTERNET alloc_handle( struct object_header *hdr ) 89 { 90 struct object_header **p; 91 ULONG_PTR handle, num; 92 93 list_init( &hdr->children ); 94 hdr->handle = NULL; 95 96 EnterCriticalSection( &handle_cs ); 97 if (!max_handles) 98 { 99 num = HANDLE_CHUNK_SIZE; 100 if (!(p = heap_alloc_zero( sizeof(ULONG_PTR) * num ))) goto end; 101 handles = p; 102 max_handles = num; 103 } 104 if (max_handles == next_handle) 105 { 106 num = max_handles * 2; 107 if (!(p = heap_realloc_zero( handles, sizeof(ULONG_PTR) * num ))) goto end; 108 handles = p; 109 max_handles = num; 110 } 111 handle = next_handle; 112 if (handles[handle]) ERR("handle isn't free but should be\n"); 113 114 handles[handle] = addref_object( hdr ); 115 hdr->handle = (HINTERNET)(handle + 1); 116 while ((next_handle < max_handles) && handles[next_handle]) next_handle++; 117 118 end: 119 LeaveCriticalSection( &handle_cs ); 120 return hdr->handle; 121 } 122 123 BOOL free_handle( HINTERNET hinternet ) 124 { 125 BOOL ret = FALSE; 126 ULONG_PTR handle = (ULONG_PTR)hinternet; 127 struct object_header *hdr = NULL, *child, *next; 128 129 EnterCriticalSection( &handle_cs ); 130 131 if ((handle > 0) && (handle <= max_handles)) 132 { 133 handle--; 134 if (handles[handle]) 135 { 136 hdr = handles[handle]; 137 TRACE("destroying handle 0x%lx for object %p\n", handle + 1, hdr); 138 handles[handle] = NULL; 139 ret = TRUE; 140 } 141 } 142 143 LeaveCriticalSection( &handle_cs ); 144 145 if (hdr) 146 { 147 LIST_FOR_EACH_ENTRY_SAFE( child, next, &hdr->children, struct object_header, entry ) 148 { 149 TRACE("freeing child handle %p for parent handle 0x%lx\n", child->handle, handle + 1); 150 free_handle( child->handle ); 151 } 152 release_object( hdr ); 153 } 154 155 EnterCriticalSection( &handle_cs ); 156 if (next_handle > handle && !handles[handle]) next_handle = handle; 157 LeaveCriticalSection( &handle_cs ); 158 159 return ret; 160 } 161