#include "php7_ext_wrapper.h" #include "ext/standard/info.h" #include #include #include #include #include #include #include #include "common_define.h" #include "local_ip_func.h" #include "logger.h" #include "hash.h" #include "sockopt.h" #include "shared_func.h" #include "id_generator.h" #include "system_info.h" #include "fastcommon.h" #define MAJOR_VERSION 1 #define MINOR_VERSION 0 #define PATCH_VERSION 8 #define PHP_IDG_RESOURCE_NAME "fastcommon_idg" #define DEFAULT_SN_FILENAME "/tmp/fastcommon_id_generator.sn" typedef struct { struct idg_context idg_context; } PHPIDGContext; static int le_consumer; static PHPIDGContext *last_idg_context = NULL; typedef struct { int alloc; int count; LogContext *contexts; } LoggerArray; static LoggerArray logger_array = {0, 0, NULL}; static zval php_error_log; static zval *error_log_func = NULL; #if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 3) const zend_fcall_info empty_fcall_info = { 0, NULL, NULL, NULL, NULL, 0, NULL, NULL, 0 }; #undef ZEND_BEGIN_ARG_INFO_EX #define ZEND_BEGIN_ARG_INFO_EX(name, pass_rest_by_reference, return_reference, required_num_args) \ static zend_arg_info name[] = { \ { NULL, 0, NULL, 0, 0, 0, pass_rest_by_reference, return_reference, required_num_args }, #endif // Every user visible function must have an entry in fastcommon_functions[]. zend_function_entry fastcommon_functions[] = { ZEND_FE(fastcommon_version, NULL) ZEND_FE(fastcommon_gethostaddrs, NULL) ZEND_FE(fastcommon_time33_hash, NULL) ZEND_FE(fastcommon_simple_hash, NULL) ZEND_FE(fastcommon_get_line_distance_km, NULL) ZEND_FE(fastcommon_get_first_local_ip, NULL) ZEND_FE(fastcommon_get_next_local_ip, NULL) ZEND_FE(fastcommon_is_private_ip, NULL) ZEND_FE(fastcommon_id_generator_init, NULL) ZEND_FE(fastcommon_id_generator_next, NULL) ZEND_FE(fastcommon_id_generator_get_extra, NULL) ZEND_FE(fastcommon_id_generator_get_timestamp, NULL) ZEND_FE(fastcommon_id_generator_destroy, NULL) ZEND_FE(fastcommon_get_ifconfigs, NULL) ZEND_FE(fastcommon_get_cpu_count, NULL) ZEND_FE(fastcommon_get_sysinfo, NULL) ZEND_FE(fastcommon_error_log, NULL) {NULL, NULL, NULL} /* Must be the last line */ }; zend_module_entry fastcommon_module_entry = { STANDARD_MODULE_HEADER, "fastcommon", fastcommon_functions, PHP_MINIT(fastcommon), PHP_MSHUTDOWN(fastcommon), NULL,//PHP_RINIT(fastcommon), NULL,//PHP_RSHUTDOWN(fastcommon), PHP_MINFO(fastcommon), "1.08", STANDARD_MODULE_PROPERTIES }; #ifdef COMPILE_DL_FASTCOMMON ZEND_GET_MODULE(fastcommon) #endif ZEND_RSRC_DTOR_FUNC(id_generator_dtor) { #if PHP_MAJOR_VERSION < 7 if (rsrc->ptr != NULL) { PHPIDGContext *php_idg_context = (PHPIDGContext *)rsrc->ptr; id_generator_destroy(&php_idg_context->idg_context); if (last_idg_context == php_idg_context) { last_idg_context = NULL; } efree(php_idg_context); rsrc->ptr = NULL; } #else if (res->ptr != NULL) { PHPIDGContext *php_idg_context = (PHPIDGContext *)res->ptr; id_generator_destroy(&php_idg_context->idg_context); if (last_idg_context == php_idg_context) { last_idg_context = NULL; } efree(php_idg_context); res->ptr = NULL; } #endif } PHP_MINIT_FUNCTION(fastcommon) { log_init(); le_consumer = zend_register_list_destructors_ex(id_generator_dtor, NULL, PHP_IDG_RESOURCE_NAME, module_number); return SUCCESS; } PHP_MSHUTDOWN_FUNCTION(fastcommon) { if (logger_array.count > 0) { LogContext *ctx; LogContext *end; end = logger_array.contexts + logger_array.count; for (ctx=logger_array.contexts; ctx 1) { logError("file: "__FILE__", line: %d, " "fastcommon_gethostaddrs parameters count: %d is invalid", __LINE__, argc); RETURN_BOOL(false); } if_alias_prefix = NULL; if_prefix_len = 0; if (zend_parse_parameters(argc TSRMLS_CC, "|s", &if_alias_prefix, &if_prefix_len) == FAILURE) { logError("file: "__FILE__", line: %d, " "zend_parse_parameters fail!", __LINE__); RETURN_BOOL(false); } if (if_alias_prefix == NULL || if_prefix_len == 0) { alias_count = 0; if_alias_prefixes[0] = NULL; } else { alias_count = 1; if_alias_prefixes[0] = if_alias_prefix; } count = 0; if (gethostaddrs(if_alias_prefixes, alias_count, ip_addresses, FAST_MAX_LOCAL_IP_ADDRS, &count) != 0) { RETURN_BOOL(false); } uniq_count = 0; for (k=0; k 6) { logError("file: "__FILE__", line: %d, " "fastcommon_id_generator_init parameters count: %d is invalid", __LINE__, argc); RETURN_BOOL(false); } filename = DEFAULT_SN_FILENAME; filename_len = 0; machine_id = 0; mid_bits = 16; extra_bits = 0; sn_bits = 16; mode = ID_GENERATOR_DEFAULT_FILE_MODE; if (zend_parse_parameters(argc TSRMLS_CC, "|slllll", &filename, &filename_len, &machine_id, &mid_bits, &extra_bits, &sn_bits, &mode) == FAILURE) { logError("file: "__FILE__", line: %d, " "zend_parse_parameters fail!", __LINE__); RETURN_BOOL(false); } php_idg_context = (PHPIDGContext *)emalloc(sizeof(PHPIDGContext)); if (php_idg_context == NULL) { logError("file: "__FILE__", line: %d, " "emalloc %d bytes fail!", __LINE__, (int)sizeof(PHPIDGContext)); RETURN_BOOL(false); } if (id_generator_init_extra_ex(&php_idg_context->idg_context, filename, machine_id, mid_bits, extra_bits, sn_bits, mode) != 0) { RETURN_BOOL(false); } last_idg_context = php_idg_context; ZEND_REGISTER_RESOURCE(return_value, php_idg_context, le_consumer); } /* long/string fastcommon_id_generator_next([int extra = 0, $handle = NULL]) return id for success, false for fail return long in 64 bits OS, return string in 32 bits Os */ ZEND_FUNCTION(fastcommon_id_generator_next) { int argc; long extra; int64_t id; zval *zhandle; PHPIDGContext *php_idg_context; struct idg_context *context; argc = ZEND_NUM_ARGS(); if (argc > 2) { logError("file: "__FILE__", line: %d, " "fastcommon_id_generator_next parameters count: %d is invalid", __LINE__, argc); RETURN_BOOL(false); } extra = 0; zhandle = NULL; if (zend_parse_parameters(argc TSRMLS_CC, "|lz", &extra, &zhandle) == FAILURE) { logError("file: "__FILE__", line: %d, " "zend_parse_parameters fail!", __LINE__); RETURN_BOOL(false); } if (zhandle != NULL && !ZVAL_IS_NULL(zhandle)) { ZEND_FETCH_RESOURCE(php_idg_context, PHPIDGContext *, &zhandle, -1, PHP_IDG_RESOURCE_NAME, le_consumer); context = &php_idg_context->idg_context; } else { if (last_idg_context == NULL) { logError("file: "__FILE__", line: %d, " "must call fastcommon_id_generator_init first", __LINE__); RETURN_BOOL(false); } context = &last_idg_context->idg_context; } if (id_generator_next_extra(context, extra, &id) != 0) { RETURN_BOOL(false); } #if OS_BITS == 64 RETURN_LONG(id); #else { char buff[32]; int len; len = sprintf(buff, "%"PRId64, id); ZEND_RETURN_STRINGL(buff, len, 1); } #endif } /* int fastcommon_id_generator_get_extra(long id [, $handle = NULL]) return the extra data */ ZEND_FUNCTION(fastcommon_id_generator_get_extra) { int argc; long id; zval *zhandle; PHPIDGContext *php_idg_context; struct idg_context *context; argc = ZEND_NUM_ARGS(); if (argc > 2) { logError("file: "__FILE__", line: %d, " "fastcommon_id_generator_get_extra parameters count: %d is invalid", __LINE__, argc); RETURN_BOOL(false); } zhandle = NULL; if (zend_parse_parameters(argc TSRMLS_CC, "l|z", &id, &zhandle) == FAILURE) { logError("file: "__FILE__", line: %d, " "zend_parse_parameters fail!", __LINE__); RETURN_BOOL(false); } if (zhandle != NULL && !ZVAL_IS_NULL(zhandle)) { ZEND_FETCH_RESOURCE(php_idg_context, PHPIDGContext *, &zhandle, -1, PHP_IDG_RESOURCE_NAME, le_consumer); context = &php_idg_context->idg_context; } else { if (last_idg_context == NULL) { logError("file: "__FILE__", line: %d, " "must call fastcommon_id_generator_init first", __LINE__); RETURN_BOOL(false); } context = &last_idg_context->idg_context; } if (context->fd < 0) { logError("file: "__FILE__", line: %d, " "must call fastcommon_id_generator_init first", __LINE__); RETURN_BOOL(false); } RETURN_LONG(id_generator_get_extra(context, id)); } /* bool fastcommon_id_generator_destroy([resource handle = NULL]) return true for success, false for fail */ ZEND_FUNCTION(fastcommon_id_generator_destroy) { int argc; zval *zhandle; PHPIDGContext *php_idg_context; struct idg_context *context; argc = ZEND_NUM_ARGS(); if (argc > 1) { logError("file: "__FILE__", line: %d, " "fastcommon_id_generator_destroy parameters count: %d is invalid", __LINE__, argc); RETURN_BOOL(false); } zhandle = NULL; if (zend_parse_parameters(argc TSRMLS_CC, "|z", &zhandle) == FAILURE) { logError("file: "__FILE__", line: %d, " "zend_parse_parameters fail!", __LINE__); RETURN_BOOL(false); } if (zhandle != NULL && !ZVAL_IS_NULL(zhandle)) { ZEND_FETCH_RESOURCE(php_idg_context, PHPIDGContext *, &zhandle, -1, PHP_IDG_RESOURCE_NAME, le_consumer); context = &php_idg_context->idg_context; } else { if (last_idg_context == NULL) { logError("file: "__FILE__", line: %d, " "must call fastcommon_id_generator_init first", __LINE__); RETURN_BOOL(false); } context = &last_idg_context->idg_context; last_idg_context = NULL; } id_generator_destroy(context); RETURN_BOOL(true); } /* long fastcommon_id_generator_get_timestamp(long id [, $handle = NULL]) return the timestamp */ ZEND_FUNCTION(fastcommon_id_generator_get_timestamp) { int argc; long id; zval *zhandle; PHPIDGContext *php_idg_context; struct idg_context *context; argc = ZEND_NUM_ARGS(); if (argc > 2) { logError("file: "__FILE__", line: %d, " "fastcommon_id_generator_get_timestamp parameters count: %d is invalid", __LINE__, argc); RETURN_BOOL(false); } zhandle = NULL; if (zend_parse_parameters(argc TSRMLS_CC, "l|z", &id, &zhandle) == FAILURE) { logError("file: "__FILE__", line: %d, " "zend_parse_parameters fail!", __LINE__); RETURN_BOOL(false); } if (zhandle != NULL && !ZVAL_IS_NULL(zhandle)) { ZEND_FETCH_RESOURCE(php_idg_context, PHPIDGContext *, &zhandle, -1, PHP_IDG_RESOURCE_NAME, le_consumer); context = &php_idg_context->idg_context; } else { if (last_idg_context == NULL) { logError("file: "__FILE__", line: %d, " "must call fastcommon_id_generator_init first", __LINE__); RETURN_BOOL(false); } context = &last_idg_context->idg_context; } if (context->fd < 0) { logError("file: "__FILE__", line: %d, " "must call fastcommon_id_generator_init first", __LINE__); RETURN_BOOL(false); } RETURN_LONG(id_generator_get_timestamp(context, id)); } /* array fastcommon_get_ifconfigs() return the ifconfig array, return false for error */ ZEND_FUNCTION(fastcommon_get_ifconfigs) { #define MAX_IFCONFIGS 16 int argc; int count; int i; FastIFConfig if_configs[MAX_IFCONFIGS]; zval *ifconfig_array; argc = ZEND_NUM_ARGS(); if (argc != 0) { logError("file: "__FILE__", line: %d, " "fastcommon_get_ifconfigs parameters count: %d is invalid, expect 0", __LINE__, argc); RETURN_BOOL(false); } if ((getifconfigs(if_configs, MAX_IFCONFIGS, &count)) != 0) { RETURN_BOOL(false); } array_init(return_value); for (i=0; ilog_filename, filename) == 0) { return ctx; } } return NULL; } static LogContext *alloc_logger_context(const char *filename) { LogContext *ctx; if (logger_array.alloc <= logger_array.count) { int alloc; int bytes; LogContext *contexts; alloc = logger_array.alloc == 0 ? 2 : 2 * logger_array.alloc; bytes = sizeof(LogContext) * alloc; contexts = (LogContext *)malloc(bytes); if (contexts == NULL) { logError("file: "__FILE__", line: %d, " "malloc %d bytes fail", __LINE__, bytes); return NULL; } if (logger_array.count > 0) { memcpy(contexts, logger_array.contexts, sizeof(LogContext) * logger_array.count); free(logger_array.contexts); } logger_array.contexts = contexts; logger_array.alloc = alloc; } ctx = logger_array.contexts + logger_array.count; if (log_init_ex(ctx) != 0) { return NULL; } if (log_set_filename_ex(ctx, filename) != 0) { return NULL; } logger_array.count++; return ctx; } static LogContext *get_logger_context(const char *filename) { LogContext *ctx; if ((ctx=fetch_logger_context(filename)) != NULL) { return ctx; } return alloc_logger_context(filename); } #define _INIT_ZSTRING(z, s, len) \ do { \ INIT_ZVAL(z); \ if (s == NULL) { \ ZVAL_NULL(&z); \ } else { \ ZVAL_STRINGL(&z, s, len, 0); \ } \ } while (0) /* boolean fastcommon_error_log(string $message [, int $message_type = 0, string $destination = null, string $extra_headers = null]) return true on success, false on failure */ ZEND_FUNCTION(fastcommon_error_log) { int argc; zend_size_t message_type; char *message; char *filename; char *extra_headers; long msg_len; long filename_len; long header_len; argc = ZEND_NUM_ARGS(); if (argc == 0) { logError("file: "__FILE__", line: %d, " "fastcommon_error_log parameters count: %d is invalid", __LINE__, argc); RETURN_BOOL(false); } message_type = 0; filename = NULL; extra_headers = NULL; filename_len = 0; header_len = 0; if (zend_parse_parameters(argc TSRMLS_CC, "s|lss", &message, &msg_len, &message_type, &filename, &filename_len, &extra_headers, &header_len) == FAILURE) { logError("file: "__FILE__", line: %d, " "zend_parse_parameters fail!", __LINE__); RETURN_BOOL(false); } if (message_type == 3 && filename != NULL) { LogContext *ctx; if ((ctx=get_logger_context(filename)) != NULL) { if (msg_len > 0 && message[msg_len - 1] == '\n') { --msg_len; } log_it_ex2(ctx, NULL, message, msg_len, false, false); RETURN_BOOL(true); } } { zval *args[4]; zval zmessage; zval ztype; zval zfilename; zval zheader; if (error_log_func == NULL) { error_log_func = &php_error_log; INIT_ZVAL(php_error_log); ZVAL_STRINGL(&php_error_log, "error_log", sizeof("error_log") - 1, 1); } _INIT_ZSTRING(zmessage, message, msg_len); INIT_ZVAL(ztype); ZVAL_LONG(&ztype, message_type); _INIT_ZSTRING(zfilename, filename, filename_len); _INIT_ZSTRING(zheader, extra_headers, header_len); args[0] = &zmessage; args[1] = &ztype; args[2] = &zfilename; args[3] = &zheader; if (zend_call_user_function_wrapper(EG(function_table), NULL, error_log_func, return_value, 4, args TSRMLS_CC) == FAILURE) { logError("file: "__FILE__", line: %d, " "call function: %s fail", __LINE__, Z_STRVAL_P(error_log_func)); RETURN_BOOL(false); } } }