- fix copyright year
[m6w6/ext-http] / http_persistent_handle_api.c
index 159d378f50b1870089bb2e0c01aeb29288ea5b39..1b451e78ae9c90d455f08130000f139af4701fea 100644 (file)
@@ -6,18 +6,22 @@
     | modification, are permitted provided that the conditions mentioned |
     | in the accompanying LICENSE file are met.                          |
     +--------------------------------------------------------------------+
-    | Copyright (c) 2004-2006, Michael Wallner <mike@php.net>            |
+    | Copyright (c) 2004-2007, Michael Wallner <mike@php.net>            |
     +--------------------------------------------------------------------+
 */
 
 /* $Id$ */
 
 #include "php_http.h"
+#include "php_http_api.h"
 
 #ifdef HTTP_HAVE_PERSISTENT_HANDLES
-
 #include "php_http_persistent_handle_api.h"
 
+#ifndef HTTP_DEBUG_PHANDLES
+#      define HTTP_DEBUG_PHANDLES 0
+#endif
+
 static HashTable http_persistent_handles_hash;
 #ifdef ZTS
 #      define LOCK() tsrm_mutex_lock(http_persistent_handles_lock)
@@ -28,34 +32,70 @@ static MUTEX_T http_persistent_handles_lock;
 #      define UNLOCK()
 #endif
 
-typedef struct _http_persistent_handles_hash_entry_t {
-       HashTable list;
+typedef struct _http_persistent_handle_t {
+       void *ptr;
+} http_persistent_handle;
+
+typedef HashTable *http_persistent_handle_list;
+
+typedef struct _http_persistent_handle_provider_t {
+       http_persistent_handle_list list; /* "ident" => array(handles) entries */
        http_persistent_handle_ctor ctor;
        http_persistent_handle_dtor dtor;
-} http_persistent_handles_hash_entry;
+} http_persistent_handle_provider;
 
-typedef struct _http_persistent_handles_list_entry_t {
-       void *handle;
-} http_persistent_handles_list_entry;
 
-static inline void http_persistent_handles_hash_dtor_ex(http_persistent_handles_hash_entry *hentry, void (*list_dtor)(HashTable*))
+static inline STATUS http_persistent_handle_list_find(http_persistent_handle_list parent_list, http_persistent_handle_list **ident_list, int create TSRMLS_DC)
 {
-       http_persistent_handles_list_entry *lentry;
+       http_persistent_handle_list new_list;
        
-       for (   zend_hash_internal_pointer_reset(&hentry->list);
-                       SUCCESS == zend_hash_get_current_data(&hentry->list, (void *) &lentry);
-                       zend_hash_move_forward(&hentry->list)) {
-               hentry->dtor(lentry->handle);
+       if (SUCCESS == zend_hash_quick_find(parent_list, HTTP_G->persistent.handles.ident.s, HTTP_G->persistent.handles.ident.l, HTTP_G->persistent.handles.ident.h, (void *) ident_list)) {
+               return SUCCESS;
        }
        
-       if (list_dtor) {
-               list_dtor(&hentry->list);
+       if (create) {
+               if ((new_list = pemalloc(sizeof(HashTable), 1))) {
+                       if (SUCCESS == zend_hash_init(new_list, 0, NULL, NULL, 1)) {
+                               if (SUCCESS == zend_hash_quick_add(parent_list, HTTP_G->persistent.handles.ident.s, HTTP_G->persistent.handles.ident.l, HTTP_G->persistent.handles.ident.h, (void *) &new_list, sizeof(http_persistent_handle_list), (void *) ident_list)) {
+                                       return SUCCESS;
+                               }
+                               zend_hash_destroy(new_list);
+                       }
+                       pefree(new_list, 1);
+               }
        }
+       
+       return FAILURE;
 }
 
-static void http_persistent_handles_hash_dtor(void *h)
+static inline void http_persistent_handle_list_dtor(http_persistent_handle_list list, http_persistent_handle_dtor dtor)
 {
-       http_persistent_handles_hash_dtor_ex(h, zend_hash_destroy);
+       HashPosition pos;
+       http_persistent_handle *handle;
+       
+       FOREACH_HASH_VAL(pos, list, handle) {
+#if HTTP_DEBUG_PHANDLES
+               fprintf(stderr, "DESTROY: %p\n", handle->ptr);
+#endif
+               
+               dtor(handle->ptr);
+       }
+       zend_hash_clean(list);
+}
+
+static void http_persistent_handles_hash_dtor(void *p)
+{
+       http_persistent_handle_provider *provider = (http_persistent_handle_provider *) p;
+       http_persistent_handle_list *list;
+       HashPosition pos;
+       
+       FOREACH_HASH_VAL(pos, provider->list, list) {
+               http_persistent_handle_list_dtor(*list, provider->dtor);
+               zend_hash_destroy(*list);
+               pefree(*list, 1);
+       }
+       zend_hash_destroy(provider->list);
+       pefree(provider->list, 1);
 }
 
 PHP_MINIT_FUNCTION(http_persistent_handle)
@@ -78,106 +118,151 @@ PHP_MSHUTDOWN_FUNCTION(http_persistent_handle)
 
 PHP_HTTP_API STATUS _http_persistent_handle_provide_ex(const char *name_str, size_t name_len, http_persistent_handle_ctor ctor, http_persistent_handle_dtor dtor)
 {
-       STATUS status = SUCCESS;
-       http_persistent_handles_hash_entry e;
-       
-       zend_hash_init(&e.list, 0, NULL, NULL, 1);
-       e.ctor = ctor;
-       e.dtor = dtor;
+       STATUS status = FAILURE;
+       http_persistent_handle_provider provider;
        
        LOCK();
-       if (SUCCESS != zend_hash_add(&http_persistent_handles_hash, (char *) name_str, name_len+1, (void *) &e, sizeof(http_persistent_handles_hash_entry), NULL)) {
-               zend_hash_destroy(&e.list);
-               status = FAILURE;
+       provider.list = pemalloc(sizeof(HashTable), 1);
+       if (provider.list) {
+               provider.ctor = ctor;
+               provider.dtor = dtor;
+               zend_hash_init(provider.list, 0, NULL, NULL, 1);
+               
+#if HTTP_DEBUG_PHANDLES
+               fprintf(stderr, "PROVIDE: %p (%s)\n", provider.list, name_str);
+#endif
+               
+               if (SUCCESS == zend_hash_add(&http_persistent_handles_hash, (char *) name_str, name_len+1, (void *) &provider, sizeof(http_persistent_handle_provider), NULL)) {
+                       status = SUCCESS;
+               } else {
+                       pefree(provider.list, 1);
+               }
        }
        UNLOCK();
        
        return status;
 }
 
-PHP_HTTP_API void _http_persistent_handle_cleanup_ex(const char *name_str, size_t name_len)
+PHP_HTTP_API STATUS _http_persistent_handle_acquire_ex(const char *name_str, size_t name_len, void **handle_ptr TSRMLS_DC)
 {
-       http_persistent_handles_hash_entry *hentry;
+       STATUS status = FAILURE;
+       ulong index;
+       http_persistent_handle_provider *provider;
+       http_persistent_handle_list *list;
+       http_persistent_handle *handle;
        
+       *handle_ptr = NULL;
        LOCK();
-       if (name_str && name_len) {
-               if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, (char *) name_str, name_len+1, (void *) &hentry)) {
-                       http_persistent_handles_hash_dtor_ex(hentry, zend_hash_clean);
+       if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, (char *) name_str, name_len+1, (void *) &provider)) {
+               if (SUCCESS == http_persistent_handle_list_find(provider->list, &list, 0 TSRMLS_CC)) {
+                       zend_hash_internal_pointer_end(*list);
+                       if (HASH_KEY_NON_EXISTANT != zend_hash_get_current_key(*list, NULL, &index, 0) && SUCCESS == zend_hash_get_current_data(*list, (void *) &handle)) {
+                               *handle_ptr = handle->ptr;
+                               zend_hash_index_del(*list, index);
+                       }
                }
-       } else {
-               for (   zend_hash_internal_pointer_reset(&http_persistent_handles_hash);
-                               SUCCESS == zend_hash_get_current_data(&http_persistent_handles_hash, (void *) &hentry);
-                               zend_hash_move_forward(&http_persistent_handles_hash)) {
-                       http_persistent_handles_hash_dtor_ex(hentry, zend_hash_clean);
+               if (*handle_ptr || (*handle_ptr = provider->ctor())) {
+                       status = SUCCESS;
                }
        }
        UNLOCK();
+       
+#if HTTP_DEBUG_PHANDLES
+       fprintf(stderr, "ACQUIRE: %p (%s)\n", *handle_ptr, name_str);
+#endif
+       
+       return status;
 }
 
-PHP_HTTP_API int _http_persistent_handle_statall_ex(char ***names, int **counts, int persistent)
+PHP_HTTP_API STATUS _http_persistent_handle_release_ex(const char *name_str, size_t name_len, void **handle_ptr TSRMLS_DC)
 {
-       int i, n;
-       char *key;
-       http_persistent_handles_hash_entry *hentry;
+       STATUS status = FAILURE;
+       http_persistent_handle_provider *provider;
+       http_persistent_handle_list *list;
+       http_persistent_handle handle = {*handle_ptr};
        
        LOCK();
-       if ((n = zend_hash_num_elements(&http_persistent_handles_hash))) {
-               *names = safe_pemalloc(n, sizeof(char **), 0, persistent);
-               *counts = safe_pemalloc(n, sizeof(int), 0, persistent);
-               
-               for (   i = 0, zend_hash_internal_pointer_reset(&http_persistent_handles_hash);
-                               HASH_KEY_NON_EXISTANT != zend_hash_get_current_key(&http_persistent_handles_hash, &key, NULL, 0) &&
-                               SUCCESS == zend_hash_get_current_data(&http_persistent_handles_hash, (void *) &hentry);
-                               ++i, zend_hash_move_forward(&http_persistent_handles_hash)) {
-                       (*names)[i] = pestrdup(key, persistent);
-                       (*counts)[i] = zend_hash_num_elements(&hentry->list);
+       if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, (char *) name_str, name_len+1, (void *) &provider)) {
+               if (    SUCCESS == http_persistent_handle_list_find(provider->list, &list, 1 TSRMLS_CC) &&
+                               SUCCESS == zend_hash_next_index_insert(*list, (void *) &handle, sizeof(http_persistent_handle), NULL)) {
+                       status = SUCCESS;
                }
        }
        UNLOCK();
        
-       return n;
+#if HTTP_DEBUG_PHANDLES
+       fprintf(stderr, "RELEASE: %p (%s)\n", *handle_ptr, name_str);
+#endif
+       
+       return status;
 }
-
-PHP_HTTP_API STATUS _http_persistent_handle_acquire_ex(const char *name_str, size_t name_len, void **handle)
+       
+PHP_HTTP_API void _http_persistent_handle_cleanup_ex(const char *name_str, size_t name_len, int current_ident_only TSRMLS_DC)
 {
-       STATUS status = FAILURE;
-       ulong index;
-       http_persistent_handles_hash_entry *hentry;
-       http_persistent_handles_list_entry *lentry;
+       http_persistent_handle_provider *provider;
+       http_persistent_handle_list *list;
+       HashPosition pos1, pos2;
        
        LOCK();
-       if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, (char *) name_str, name_len+1, (void *) &hentry)) {
-               zend_hash_internal_pointer_end(&hentry->list);
-               if (    HASH_KEY_NON_EXISTANT != zend_hash_get_current_key(&hentry->list, NULL, &index, 0) &&
-                               SUCCESS == zend_hash_get_current_data(&hentry->list, (void *) &lentry)) {
-                       *handle = lentry->handle;
-                       zend_hash_index_del(&hentry->list, index);
-                       status = SUCCESS;
-               } else if ((*handle = hentry->ctor())) {
-                       status = SUCCESS;
+       if (name_str && name_len) {
+               if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, (char *) name_str, name_len+1, (void *) &provider)) {
+                       if (current_ident_only) {
+                               if (SUCCESS == http_persistent_handle_list_find(provider->list, &list, 0 TSRMLS_CC)) {
+                                       http_persistent_handle_list_dtor(*list, provider->dtor);
+                               }
+                       } else {
+                               FOREACH_HASH_VAL(pos1, provider->list, list) {
+                                       http_persistent_handle_list_dtor(*list, provider->dtor);
+                               }
+                       }
+               }
+       } else {
+               FOREACH_HASH_VAL(pos1, &http_persistent_handles_hash, provider) {
+                       if (current_ident_only) {
+                               if (SUCCESS == http_persistent_handle_list_find(provider->list, &list, 0 TSRMLS_CC)) {
+                                       http_persistent_handle_list_dtor(*list, provider->dtor);
+                               }
+                       } else {
+                               FOREACH_HASH_VAL(pos2, provider->list, list) {
+                                       http_persistent_handle_list_dtor(*list, provider->dtor);
+                               }
+                       }
                }
        }
        UNLOCK();
-       
-       return status;
 }
 
-PHP_HTTP_API STATUS _http_persistent_handle_release_ex(const char *name_str, size_t name_len, void **handle)
+PHP_HTTP_API HashTable *_http_persistent_handle_statall_ex(HashTable *ht)
 {
-       STATUS status = FAILURE;
-       http_persistent_handles_hash_entry *hentry;
-       http_persistent_handles_list_entry lentry;
+       zval *zlist, *zentry;
+       HashPosition pos1, pos2;
+       HashKey key1 = initHashKey(0), key2 = initHashKey(0);
+       http_persistent_handle_provider *provider;
+       http_persistent_handle_list *list;
        
        LOCK();
-       if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, (char *) name_str, name_len+1, (void *) &hentry)) {
-               lentry.handle = *handle;
-               if (SUCCESS == zend_hash_next_index_insert(&hentry->list, (void *) &lentry, sizeof(http_persistent_handles_list_entry), NULL)) {
-                       status = SUCCESS;
+       if (zend_hash_num_elements(&http_persistent_handles_hash)) {
+               if (!ht) {
+                       ALLOC_HASHTABLE(ht);
+                       zend_hash_init(ht, 0, NULL, ZVAL_PTR_DTOR, 0);
                }
+               
+               FOREACH_HASH_KEYVAL(pos1, &http_persistent_handles_hash, key1, provider) {
+                       MAKE_STD_ZVAL(zlist);
+                       array_init(zlist);
+                       FOREACH_HASH_KEYVAL(pos2, provider->list, key2, list) {
+                               MAKE_STD_ZVAL(zentry);
+                               ZVAL_LONG(zentry, zend_hash_num_elements(*list));
+                               zend_hash_quick_add(Z_ARRVAL_P(zlist), key2.str, key2.len, key2.num, (void *) &zentry, sizeof(zval *), NULL);
+                       }
+                       zend_hash_quick_add(ht, key1.str, key1.len, key1.num, (void *) &zlist, sizeof(zval *), NULL);
+               }
+       } else if (ht) {
+               ht = NULL;
        }
        UNLOCK();
        
-       return status;
+       return ht;
 }
 
 #endif /* HTTP_HAVE_PERSISTENT_HANDLES */