mirror of
https://github.com/alliedmodders/hl2sdk.git
synced 2025-12-09 03:28:24 +00:00
* Replace protobuf 2.6.1 with 3.21.8 * Update/add protobuf libs * Add CS2 protos * Remove old csgo/dota protos * Add versioned protoc bin * Comment out Valve's `schema` define for now * Use ENetworkDisconnectionReason * Fix-up `offsetof` to avoid errors on some Clang versions
358 lines
12 KiB
C
358 lines
12 KiB
C
// Protocol Buffers - Google's data interchange format
|
|
// Copyright 2008 Google Inc. All rights reserved.
|
|
// https://developers.google.com/protocol-buffers/
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are
|
|
// met:
|
|
//
|
|
// * Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
// * Redistributions in binary form must reproduce the above
|
|
// copyright notice, this list of conditions and the following disclaimer
|
|
// in the documentation and/or other materials provided with the
|
|
// distribution.
|
|
// * Neither the name of Google Inc. nor the names of its
|
|
// contributors may be used to endorse or promote products derived from
|
|
// this software without specific prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
#include "protobuf.h"
|
|
|
|
#include <php.h>
|
|
#include <Zend/zend_interfaces.h>
|
|
|
|
#include "arena.h"
|
|
#include "array.h"
|
|
#include "convert.h"
|
|
#include "def.h"
|
|
#include "map.h"
|
|
#include "message.h"
|
|
#include "names.h"
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Module "globals"
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Despite the name, module "globals" are really thread-locals:
|
|
// * PROTOBUF_G(var) accesses the thread-local variable for 'var'. Either:
|
|
// * PROTOBUF_G(var) -> protobuf_globals.var (Non-ZTS / non-thread-safe)
|
|
// * PROTOBUF_G(var) -> <Zend magic> (ZTS / thread-safe builds)
|
|
|
|
#define PROTOBUF_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(protobuf, v)
|
|
|
|
ZEND_BEGIN_MODULE_GLOBALS(protobuf)
|
|
// Set by the user to make the descriptor pool persist between requests.
|
|
zend_bool keep_descriptor_pool_after_request;
|
|
|
|
// Set by the user to make the descriptor pool persist between requests.
|
|
zend_class_entry* constructing_class;
|
|
|
|
// A upb_DefPool that we are saving for the next request so that we don't have
|
|
// to rebuild it from scratch. When keep_descriptor_pool_after_request==true,
|
|
// we steal the upb_DefPool from the global DescriptorPool object just before
|
|
// destroying it.
|
|
upb_DefPool *global_symtab;
|
|
|
|
// Object cache (see interface in protobuf.h).
|
|
HashTable object_cache;
|
|
|
|
// Name cache (see interface in protobuf.h).
|
|
HashTable name_msg_cache;
|
|
HashTable name_enum_cache;
|
|
|
|
// An array of descriptor objects constructed during this request. These are
|
|
// logically referenced by the corresponding class entry, but since we can't
|
|
// actually write a class entry destructor, we reference them here, to be
|
|
// destroyed on request shutdown.
|
|
HashTable descriptors;
|
|
ZEND_END_MODULE_GLOBALS(protobuf)
|
|
|
|
void free_protobuf_globals(zend_protobuf_globals *globals) {
|
|
zend_hash_destroy(&globals->name_msg_cache);
|
|
zend_hash_destroy(&globals->name_enum_cache);
|
|
upb_DefPool_Free(globals->global_symtab);
|
|
globals->global_symtab = NULL;
|
|
}
|
|
|
|
ZEND_DECLARE_MODULE_GLOBALS(protobuf)
|
|
|
|
upb_DefPool *get_global_symtab() {
|
|
return PROTOBUF_G(global_symtab);
|
|
}
|
|
|
|
// This is a PHP extension (not a Zend extension). What follows is a summary of
|
|
// a PHP extension's lifetime and when various handlers are called.
|
|
//
|
|
// * PHP_GINIT_FUNCTION(protobuf) / PHP_GSHUTDOWN_FUNCTION(protobuf)
|
|
// are the constructor/destructor for the globals. The sequence over the
|
|
// course of a process lifetime is:
|
|
//
|
|
// # Process startup
|
|
// GINIT(<Main Thread Globals>)
|
|
// MINIT
|
|
//
|
|
// foreach request:
|
|
// RINIT
|
|
// # Request is processed here.
|
|
// RSHUTDOWN
|
|
//
|
|
// foreach thread:
|
|
// GINIT(<This Thread Globals>)
|
|
// # Code for the thread runs here.
|
|
// GSHUTDOWN(<This Thread Globals>)
|
|
//
|
|
// # Process Shutdown
|
|
// #
|
|
// # These should be running per the docs, but I have not been able to
|
|
// # actually get the process-wide shutdown functions to run.
|
|
// #
|
|
// # MSHUTDOWN
|
|
// # GSHUTDOWN(<Main Thread Globals>)
|
|
//
|
|
// * Threads can be created either explicitly by the user, inside a request,
|
|
// or implicitly by the runtime, to process multiple requests concurrently.
|
|
// If the latter is being used, then the "foreach thread" block above
|
|
// actually looks like this:
|
|
//
|
|
// foreach thread:
|
|
// GINIT(<This Thread Globals>)
|
|
// # A non-main thread will only receive requests when using a threaded
|
|
// # MPM with Apache
|
|
// foreach request:
|
|
// RINIT
|
|
// # Request is processed here.
|
|
// RSHUTDOWN
|
|
// GSHUTDOWN(<This Thread Globals>)
|
|
//
|
|
// That said, it appears that few people use threads with PHP:
|
|
// * The pthread package documented at
|
|
// https://www.php.net/manual/en/class.thread.php nas not been released
|
|
// since 2016, and the current release fails to compile against any PHP
|
|
// newer than 7.0.33.
|
|
// * The GitHub master branch supports 7.2+, but this has not been released
|
|
// to PECL.
|
|
// * Its owner has disavowed it as "broken by design" and "in an untenable
|
|
// position for the future": https://github.com/krakjoe/pthreads/issues/929
|
|
// * The only way to use PHP with requests in different threads is to use the
|
|
// Apache 2 mod_php with the "worker" MPM. But this is explicitly
|
|
// discouraged by the documentation: https://serverfault.com/a/231660
|
|
|
|
static PHP_GSHUTDOWN_FUNCTION(protobuf) {
|
|
if (protobuf_globals->global_symtab) {
|
|
free_protobuf_globals(protobuf_globals);
|
|
}
|
|
}
|
|
|
|
static PHP_GINIT_FUNCTION(protobuf) {
|
|
protobuf_globals->global_symtab = NULL;
|
|
}
|
|
|
|
/**
|
|
* PHP_RINIT_FUNCTION(protobuf)
|
|
*
|
|
* This function is run at the beginning of processing each request.
|
|
*/
|
|
static PHP_RINIT_FUNCTION(protobuf) {
|
|
// Create the global generated pool.
|
|
// Reuse the symtab (if any) left to us by the last request.
|
|
upb_DefPool *symtab = PROTOBUF_G(global_symtab);
|
|
if (!symtab) {
|
|
PROTOBUF_G(global_symtab) = symtab = upb_DefPool_New();
|
|
zend_hash_init(&PROTOBUF_G(name_msg_cache), 64, NULL, NULL, 0);
|
|
zend_hash_init(&PROTOBUF_G(name_enum_cache), 64, NULL, NULL, 0);
|
|
}
|
|
|
|
zend_hash_init(&PROTOBUF_G(object_cache), 64, NULL, NULL, 0);
|
|
zend_hash_init(&PROTOBUF_G(descriptors), 64, NULL, ZVAL_PTR_DTOR, 0);
|
|
PROTOBUF_G(constructing_class) = NULL;
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* PHP_RSHUTDOWN_FUNCTION(protobuf)
|
|
*
|
|
* This function is run at the end of processing each request.
|
|
*/
|
|
static PHP_RSHUTDOWN_FUNCTION(protobuf) {
|
|
// Preserve the symtab if requested.
|
|
if (!PROTOBUF_G(keep_descriptor_pool_after_request)) {
|
|
free_protobuf_globals(ZEND_MODULE_GLOBALS_BULK(protobuf));
|
|
}
|
|
|
|
zend_hash_destroy(&PROTOBUF_G(object_cache));
|
|
zend_hash_destroy(&PROTOBUF_G(descriptors));
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Object Cache.
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void Descriptors_Add(zend_object *desc) {
|
|
// The hash table will own a ref (it will destroy it when the table is
|
|
// destroyed), but for some reason the insert operation does not add a ref, so
|
|
// we do that here with ZVAL_OBJ_COPY().
|
|
zval zv;
|
|
ZVAL_OBJ_COPY(&zv, desc);
|
|
zend_hash_next_index_insert(&PROTOBUF_G(descriptors), &zv);
|
|
}
|
|
|
|
void ObjCache_Add(const void *upb_obj, zend_object *php_obj) {
|
|
zend_ulong k = (zend_ulong)upb_obj;
|
|
zend_hash_index_add_ptr(&PROTOBUF_G(object_cache), k, php_obj);
|
|
}
|
|
|
|
void ObjCache_Delete(const void *upb_obj) {
|
|
if (upb_obj) {
|
|
zend_ulong k = (zend_ulong)upb_obj;
|
|
int ret = zend_hash_index_del(&PROTOBUF_G(object_cache), k);
|
|
PBPHP_ASSERT(ret == SUCCESS);
|
|
}
|
|
}
|
|
|
|
bool ObjCache_Get(const void *upb_obj, zval *val) {
|
|
zend_ulong k = (zend_ulong)upb_obj;
|
|
zend_object *obj = zend_hash_index_find_ptr(&PROTOBUF_G(object_cache), k);
|
|
|
|
if (obj) {
|
|
ZVAL_OBJ_COPY(val, obj);
|
|
return true;
|
|
} else {
|
|
ZVAL_NULL(val);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Name Cache.
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void NameMap_AddMessage(const upb_MessageDef *m) {
|
|
for (int i = 0; i < 2; ++i) {
|
|
char *k = GetPhpClassname(upb_MessageDef_File(m), upb_MessageDef_FullName(m), (bool)i);
|
|
zend_hash_str_add_ptr(&PROTOBUF_G(name_msg_cache), k, strlen(k), (void*)m);
|
|
if (!IsPreviouslyUnreservedClassName(k)) {
|
|
free(k);
|
|
return;
|
|
}
|
|
free(k);
|
|
}
|
|
}
|
|
|
|
void NameMap_AddEnum(const upb_EnumDef *e) {
|
|
char *k = GetPhpClassname(upb_EnumDef_File(e), upb_EnumDef_FullName(e), false);
|
|
zend_hash_str_add_ptr(&PROTOBUF_G(name_enum_cache), k, strlen(k), (void*)e);
|
|
free(k);
|
|
}
|
|
|
|
const upb_MessageDef *NameMap_GetMessage(zend_class_entry *ce) {
|
|
const upb_MessageDef *ret =
|
|
zend_hash_find_ptr(&PROTOBUF_G(name_msg_cache), ce->name);
|
|
|
|
if (!ret && ce->create_object && ce != PROTOBUF_G(constructing_class)) {
|
|
#if PHP_VERSION_ID < 80000
|
|
zval tmp;
|
|
zval zv;
|
|
ZVAL_OBJ(&tmp, ce->create_object(ce));
|
|
zend_call_method_with_0_params(&tmp, ce, NULL, "__construct", &zv);
|
|
zval_ptr_dtor(&tmp);
|
|
#else
|
|
zval zv;
|
|
zend_object *tmp = ce->create_object(ce);
|
|
zend_call_method_with_0_params(tmp, ce, NULL, "__construct", &zv);
|
|
OBJ_RELEASE(tmp);
|
|
#endif
|
|
zval_ptr_dtor(&zv);
|
|
ret = zend_hash_find_ptr(&PROTOBUF_G(name_msg_cache), ce->name);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
const upb_EnumDef *NameMap_GetEnum(zend_class_entry *ce) {
|
|
const upb_EnumDef *ret =
|
|
zend_hash_find_ptr(&PROTOBUF_G(name_enum_cache), ce->name);
|
|
return ret;
|
|
}
|
|
|
|
void NameMap_EnterConstructor(zend_class_entry* ce) {
|
|
assert(!PROTOBUF_G(constructing_class));
|
|
PROTOBUF_G(constructing_class) = ce;
|
|
}
|
|
|
|
void NameMap_ExitConstructor(zend_class_entry* ce) {
|
|
assert(PROTOBUF_G(constructing_class) == ce);
|
|
PROTOBUF_G(constructing_class) = NULL;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Module init.
|
|
// -----------------------------------------------------------------------------
|
|
|
|
zend_function_entry protobuf_functions[] = {
|
|
ZEND_FE_END
|
|
};
|
|
|
|
static const zend_module_dep protobuf_deps[] = {
|
|
ZEND_MOD_OPTIONAL("date")
|
|
ZEND_MOD_END
|
|
};
|
|
|
|
PHP_INI_BEGIN()
|
|
STD_PHP_INI_ENTRY("protobuf.keep_descriptor_pool_after_request", "0",
|
|
PHP_INI_ALL, OnUpdateBool,
|
|
keep_descriptor_pool_after_request, zend_protobuf_globals,
|
|
protobuf_globals)
|
|
PHP_INI_END()
|
|
|
|
static PHP_MINIT_FUNCTION(protobuf) {
|
|
REGISTER_INI_ENTRIES();
|
|
Arena_ModuleInit();
|
|
Array_ModuleInit();
|
|
Convert_ModuleInit();
|
|
Def_ModuleInit();
|
|
Map_ModuleInit();
|
|
Message_ModuleInit();
|
|
return SUCCESS;
|
|
}
|
|
|
|
static PHP_MSHUTDOWN_FUNCTION(protobuf) {
|
|
UNREGISTER_INI_ENTRIES();
|
|
return SUCCESS;
|
|
}
|
|
|
|
zend_module_entry protobuf_module_entry = {
|
|
STANDARD_MODULE_HEADER_EX,
|
|
NULL,
|
|
protobuf_deps,
|
|
"protobuf", // extension name
|
|
protobuf_functions, // function list
|
|
PHP_MINIT(protobuf), // process startup
|
|
PHP_MSHUTDOWN(protobuf), // process shutdown
|
|
PHP_RINIT(protobuf), // request shutdown
|
|
PHP_RSHUTDOWN(protobuf), // request shutdown
|
|
NULL, // extension info
|
|
PHP_PROTOBUF_VERSION, // extension version
|
|
PHP_MODULE_GLOBALS(protobuf), // globals descriptor
|
|
PHP_GINIT(protobuf), // globals ctor
|
|
PHP_GSHUTDOWN(protobuf), // globals dtor
|
|
NULL, // post deactivate
|
|
STANDARD_MODULE_PROPERTIES_EX
|
|
};
|
|
|
|
ZEND_GET_MODULE(protobuf)
|