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 "wine/port.h" 23 #include "wine/debug.h" 24 25 #include <stdarg.h> 26 27 #include "windef.h" 28 #include "winbase.h" 29 #include "winhttp.h" 30 31 #include "winhttp_private.h" 32 33 WINE_DEFAULT_DEBUG_CHANNEL(winhttp); 34 35 #define HANDLE_CHUNK_SIZE 0x10 36 37 static CRITICAL_SECTION handle_cs; 38 static CRITICAL_SECTION_DEBUG handle_cs_debug = 39 { 40 0, 0, &handle_cs, 41 { &handle_cs_debug.ProcessLocksList, &handle_cs_debug.ProcessLocksList }, 42 0, 0, { (ULONG_PTR)(__FILE__ ": handle_cs") } 43 }; 44 static CRITICAL_SECTION handle_cs = { &handle_cs_debug, -1, 0, 0, 0, 0 }; 45 46 static object_header_t **handles; 47 static ULONG_PTR next_handle; 48 static ULONG_PTR max_handles; 49 50 object_header_t *addref_object( object_header_t *hdr ) 51 { 52 ULONG refs = InterlockedIncrement( &hdr->refs ); 53 TRACE("%p -> refcount = %d\n", hdr, refs); 54 return hdr; 55 } 56 57 object_header_t *grab_object( HINTERNET hinternet ) 58 { 59 object_header_t *hdr = NULL; 60 ULONG_PTR handle = (ULONG_PTR)hinternet; 61 62 EnterCriticalSection( &handle_cs ); 63 64 if ((handle > 0) && (handle <= max_handles) && handles[handle - 1]) 65 hdr = addref_object( handles[handle - 1] ); 66 67 LeaveCriticalSection( &handle_cs ); 68 69 TRACE("handle 0x%lx -> %p\n", handle, hdr); 70 return hdr; 71 } 72 73 void release_object( object_header_t *hdr ) 74 { 75 ULONG refs = InterlockedDecrement( &hdr->refs ); 76 TRACE("object %p refcount = %d\n", hdr, refs); 77 if (!refs) 78 { 79 if (hdr->type == WINHTTP_HANDLE_TYPE_REQUEST) close_connection( (request_t *)hdr ); 80 81 send_callback( hdr, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, &hdr->handle, sizeof(HINTERNET) ); 82 83 TRACE("destroying object %p\n", hdr); 84 if (hdr->type != WINHTTP_HANDLE_TYPE_SESSION) list_remove( &hdr->entry ); 85 hdr->vtbl->destroy( hdr ); 86 } 87 } 88 89 HINTERNET alloc_handle( object_header_t *hdr ) 90 { 91 object_header_t **p; 92 ULONG_PTR handle, num; 93 94 list_init( &hdr->children ); 95 hdr->handle = NULL; 96 97 EnterCriticalSection( &handle_cs ); 98 if (!max_handles) 99 { 100 num = HANDLE_CHUNK_SIZE; 101 if (!(p = heap_alloc_zero( sizeof(ULONG_PTR) * num ))) goto end; 102 handles = p; 103 max_handles = num; 104 } 105 if (max_handles == next_handle) 106 { 107 num = max_handles * 2; 108 if (!(p = heap_realloc_zero( handles, sizeof(ULONG_PTR) * num ))) goto end; 109 handles = p; 110 max_handles = num; 111 } 112 handle = next_handle; 113 if (handles[handle]) ERR("handle isn't free but should be\n"); 114 115 handles[handle] = addref_object( hdr ); 116 hdr->handle = (HINTERNET)(handle + 1); 117 while ((next_handle < max_handles) && handles[next_handle]) next_handle++; 118 119 end: 120 LeaveCriticalSection( &handle_cs ); 121 return hdr->handle; 122 } 123 124 BOOL free_handle( HINTERNET hinternet ) 125 { 126 BOOL ret = FALSE; 127 ULONG_PTR handle = (ULONG_PTR)hinternet; 128 object_header_t *hdr = NULL, *child, *next; 129 130 EnterCriticalSection( &handle_cs ); 131 132 if ((handle > 0) && (handle <= max_handles)) 133 { 134 handle--; 135 if (handles[handle]) 136 { 137 hdr = handles[handle]; 138 TRACE("destroying handle 0x%lx for object %p\n", handle + 1, hdr); 139 handles[handle] = NULL; 140 ret = TRUE; 141 } 142 } 143 144 LeaveCriticalSection( &handle_cs ); 145 146 if (hdr) 147 { 148 LIST_FOR_EACH_ENTRY_SAFE( child, next, &hdr->children, object_header_t, entry ) 149 { 150 TRACE("freeing child handle %p for parent handle 0x%lx\n", child->handle, handle + 1); 151 free_handle( child->handle ); 152 } 153 release_object( hdr ); 154 } 155 156 EnterCriticalSection( &handle_cs ); 157 if (next_handle > handle && !handles[handle]) next_handle = handle; 158 LeaveCriticalSection( &handle_cs ); 159 160 return ret; 161 } 162