static PHP_METHOD(swoole_process, alarm) { long usec = 0; long type = ITIMER_REAL; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|l", &usec, &type) == FAILURE) { return; } if (!SWOOLE_G(cli)) { swoole_php_fatal_error(E_ERROR, "cannot use swoole_process::alarm here."); RETURN_FALSE; } if (SwooleG.timer.fd != 0) { swoole_php_fatal_error(E_WARNING, "cannot use both timer and alarm at the same time."); RETURN_FALSE; } struct timeval now; if (gettimeofday(&now, NULL) < 0) { swoole_php_error(E_WARNING, "gettimeofday() failed. Error: %s[%d]", strerror(errno), errno); RETURN_FALSE; } struct itimerval timer_set; bzero(&timer_set, sizeof(timer_set)); if (usec > 0) { long _sec = usec / 1000000; long _usec = usec - (_sec * 1000000); timer_set.it_interval.tv_sec = _sec; timer_set.it_interval.tv_usec = _usec; timer_set.it_value.tv_sec = _sec; timer_set.it_value.tv_usec = _usec; if (timer_set.it_value.tv_usec > 1e6) { timer_set.it_value.tv_usec = timer_set.it_value.tv_usec - 1e6; timer_set.it_value.tv_sec += 1; } } if (setitimer(type, &timer_set, NULL) < 0) { swoole_php_error(E_WARNING, "setitimer() failed. Error: %s[%d]", strerror(errno), errno); RETURN_FALSE; } RETURN_TRUE; }
static PHP_METHOD(swoole_mysql, on) { char *name; zend_size_t len; zval *cb; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &name, &len, &cb) == FAILURE) { return; } mysql_client *client = swoole_get_object(getThis()); if (!client) { swoole_php_fatal_error(E_WARNING, "object is not instanceof swoole_mysql."); RETURN_FALSE; } if (strncasecmp("close", name, len) == 0) { zend_update_property(swoole_mysql_class_entry_ptr, getThis(), ZEND_STRL("onClose"), cb TSRMLS_CC); client->onClose = sw_zend_read_property(swoole_mysql_class_entry_ptr, getThis(), ZEND_STRL("onClose"), 0 TSRMLS_CC); sw_copy_to_stack(client->onClose, client->_onClose); } else { swoole_php_error(E_WARNING, "Unknown event type[%s]", name); RETURN_FALSE; } RETURN_TRUE; }
static PHP_METHOD(swoole_table, set) { zval *array; char *key; zend_size_t keylen; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa", &key, &keylen, &array) == FAILURE) { RETURN_FALSE; } swTable *table = swoole_get_object(getThis()); if (!table->memory) { swoole_php_fatal_error(E_ERROR, "Must create table first."); RETURN_FALSE; } sw_atomic_t *_lock = NULL; swTableRow *row = swTableRow_set(table, key, keylen, &_lock); if (!row) { sw_spinlock_release(_lock); swoole_php_error(E_WARNING, "Unable to allocate memory."); RETURN_FALSE; } swTableColumn *col; zval *v; char *k; uint32_t klen; int ktype; HashTable *_ht = Z_ARRVAL_P(array); SW_HASHTABLE_FOREACH_START2(_ht, k, klen, ktype, v) { col = swTableColumn_get(table, k, klen); if (k == NULL || col == NULL) { continue; } else if (col->type == SW_TABLE_STRING) { convert_to_string(v); swTableRow_set_value(row, col, Z_STRVAL_P(v), Z_STRLEN_P(v)); } else if (col->type == SW_TABLE_FLOAT) { convert_to_double(v); swTableRow_set_value(row, col, &Z_DVAL_P(v), 0); } else { convert_to_long(v); swTableRow_set_value(row, col, &Z_LVAL_P(v), 0); } }
static void php_swoole_aio_onDNSCompleted(swAio_event *event) { int64_t ret; zval *retval = NULL, *zcallback = NULL; zval **args[2]; dns_request *dns_req = NULL; zval _zcontent; dns_req = (dns_request *) event->req; zcallback = dns_req->callback; ret = event->ret; if (ret < 0) { SwooleG.error = event->error; swoole_php_error(E_WARNING, "Aio Error: %s[%d]", strerror(event->error), event->error); } args[0] = &dns_req->domain; zval *zcontent = &_zcontent; if (ret < 0) { SW_ZVAL_STRING(zcontent, "", 1); } else { SW_ZVAL_STRING(zcontent, event->buf, 1); } args[1] = &zcontent; if (sw_call_user_function_ex(EG(function_table), NULL, zcallback, &retval, 2, args, 0, NULL) == FAILURE) { swoole_php_fatal_error(E_WARNING, "swoole_async: onAsyncComplete handler error"); return; } if (EG(exception)) { zend_exception_error(EG(exception), E_ERROR); } sw_zval_ptr_dtor(&dns_req->callback); sw_zval_ptr_dtor(&dns_req->domain); efree(dns_req); efree(event->buf); if (zcontent) { sw_zval_ptr_dtor(&zcontent); } if (retval) { sw_zval_ptr_dtor(&retval); } }
PHP_METHOD(swoole_async, exec) { char *command; zend_size_t command_len; zval *callback; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &command, &command_len, &callback) == FAILURE) { return; } php_swoole_check_reactor(); if (!swReactor_handle_isset(SwooleG.main_reactor, PHP_SWOOLE_FD_PROCESS_STREAM)) { SwooleG.main_reactor->setHandle(SwooleG.main_reactor, PHP_SWOOLE_FD_PROCESS_STREAM | SW_EVENT_READ, process_stream_onRead); SwooleG.main_reactor->setHandle(SwooleG.main_reactor, PHP_SWOOLE_FD_PROCESS_STREAM | SW_EVENT_ERROR, process_stream_onRead); } pid_t pid; int fd = swoole_shell_exec(command, &pid); if (fd < 0) { swoole_php_error(E_WARNING, "Unable to execute '%s'", command); RETURN_FALSE; } swString *buffer = swString_new(1024); if (buffer == NULL) { RETURN_FALSE; } process_stream *ps = emalloc(sizeof(process_stream)); ps->callback = sw_zval_dup(callback); #ifdef SW_COROUTINE ps->context = NULL; #endif sw_zval_add_ref(&ps->callback); ps->fd = fd; ps->pid = pid; ps->buffer = buffer; if (SwooleG.main_reactor->add(SwooleG.main_reactor, ps->fd, PHP_SWOOLE_FD_PROCESS_STREAM | SW_EVENT_READ) < 0) { sw_zval_free(ps->callback); efree(ps); RETURN_FALSE; } else { swConnection *_socket = swReactor_get(SwooleG.main_reactor, ps->fd); _socket->object = ps; RETURN_LONG(pid); } }
static PHP_METHOD(swoole_server_port, on) { char *ha_name = NULL; zend_size_t len, i; int ret = -1; zval *cb; if (SwooleGS->start > 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Server is running. Unable to set event callback now."); RETURN_FALSE; } if (zend_parse_parameters(ZEND_NUM_ARGS()TSRMLS_CC, "sz", &ha_name, &len, &cb) == FAILURE) { return; } swoole_port_callbacks *callbacks = swoole_get_property(getThis(), 0); swListenPort *port = swoole_get_object(getThis()); if (!port->ptr) { port->ptr = callbacks; } char *callback[PHP_SERVER_PORT_CALLBACK_NUM] = { "connect", "receive", "close", "packet", }; for (i = 0; i < PHP_SERVER_PORT_CALLBACK_NUM; i++) { if (strncasecmp(callback[i], ha_name, len) == 0) { ret = php_swoole_set_callback(callbacks->array, i, cb TSRMLS_CC); if (i == SW_SERVER_CB_onConnect && SwooleG.serv->onConnect == NULL) { SwooleG.serv->onConnect = php_swoole_onConnect; } else if (i == SW_SERVER_CB_onClose && SwooleG.serv->onClose == NULL) { SwooleG.serv->onClose = php_swoole_onClose; } break; } } if (ret < 0) { swoole_php_error(E_WARNING, "Unknown event types[%s]", ha_name); } SW_CHECK_RETURN(ret); }
static int swoole_redis_send_command(zval *object, zval *callback, char *format, ...) { #if PHP_MAJOR_VERSION < 7 TSRMLS_FETCH_FROM_CTX(sw_thread_ctx ? sw_thread_ctx : NULL); #endif swRedisClient *redis = swoole_get_object(object); switch (redis->state) { case SWOOLE_REDIS_STATE_CONNECT: swoole_php_error(E_WARNING, "redis client is not connected."); return SW_ERR; case SWOOLE_REDIS_STATE_WAIT: swoole_php_error(E_WARNING, "redis client is waiting for response."); return SW_ERR; case SWOOLE_REDIS_STATE_CLOSED: swoole_php_error(E_WARNING, "redis client connection is closed."); return SW_ERR; default: break; } #if PHP_MAJOR_VERSION < 7 redis->result_callback = callback; #else redis->result_callback = &redis->_result_callback; memcpy(redis->result_callback, callback, sizeof(zval)); #endif sw_zval_add_ref(&redis->result_callback); va_list ap; va_start(ap, format); int ret = redisvAsyncCommand(redis->context, swoole_redis_onResult, NULL, format, ap); va_end(ap); if (ret < 0) { swoole_php_error(E_WARNING, "redisAsyncCommandArgv() failed."); return SW_ERR; } redis->state = SWOOLE_REDIS_STATE_WAIT; return SW_OK; }
long php_swoole_add_timer(int ms, zval *callback, zval *param, int is_tick TSRMLS_DC) { if (ms > 86400000) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "The given parameters is too big."); return SW_ERR; } char *func_name = NULL; if (!sw_zend_is_callable(callback, 0, &func_name TSRMLS_CC)) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Function '%s' is not callable", func_name); efree(func_name); return SW_ERR; } efree(func_name); if (SwooleGS->start > 0 && swIsTaskWorker()) { swoole_php_error(E_WARNING, "cannot use swoole_server->after in task worker."); } swTimer_callback *cb = emalloc(sizeof(swTimer_callback)); cb->data = param; cb->callback = callback; if (is_tick) { cb->type = SW_TIMER_TICK; } else { cb->type = SW_TIMER_AFTER; } php_swoole_check_reactor(); php_swoole_check_timer(ms); sw_zval_add_ref(&cb->callback); if (cb->data) { sw_zval_add_ref(&cb->data); } return SwooleG.timer.add(&SwooleG.timer, ms, is_tick, cb); }
static PHP_METHOD(swoole_process, kill) { long pid; long sig = SIGTERM; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|l", &pid, &sig) == FAILURE) { RETURN_FALSE; } int ret = kill((int) pid, (int) sig); if (ret < 0) { if (!(sig == 0 && errno == ESRCH)) { swoole_php_error(E_WARNING, "kill(%d, %d) failed. Error: %s[%d]", (int) pid, (int) sig, strerror(errno), errno); } RETURN_FALSE; } RETURN_TRUE; }
static PHP_METHOD(swoole_redis, on) { char *name; zend_size_t len; zval *cb; if (zend_parse_parameters(ZEND_NUM_ARGS()TSRMLS_CC, "sz", &name, &len, &cb) == FAILURE) { return; } swRedisClient *redis = swoole_get_object(getThis()); if (redis->context != NULL) { swoole_php_fatal_error(E_WARNING, "Must be called before connect."); RETURN_FALSE; } if (strncasecmp("close", name, len) == 0) { zend_update_property(swoole_redis_class_entry_ptr, getThis(), ZEND_STRL("onClose"), cb TSRMLS_CC); redis->close_callback = sw_zend_read_property(swoole_redis_class_entry_ptr, getThis(), ZEND_STRL("onClose"), 0 TSRMLS_CC); sw_copy_to_stack(redis->close_callback, redis->_close_callback); } else if (strncasecmp("message", name, len) == 0) { zend_update_property(swoole_redis_class_entry_ptr, getThis(), ZEND_STRL("onMessage"), cb TSRMLS_CC); redis->message_callback = sw_zend_read_property(swoole_redis_class_entry_ptr, getThis(), ZEND_STRL("onMessage"), 0 TSRMLS_CC); sw_copy_to_stack(redis->message_callback, redis->_message_callback); redis->subscribe = 1; } else { swoole_php_error(E_WARNING, "Unknown event type[%s]", name); RETURN_FALSE; } RETURN_TRUE; }
static PHP_METHOD(swoole_redis, connect) { char *host; zend_size_t host_len; long port; zval *callback; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "slz", &host, &host_len, &port, &callback) == FAILURE) { RETURN_FALSE; } if (host_len <= 0) { swoole_php_error(E_WARNING, "redis server host is empty."); RETURN_FALSE; } swRedisClient *redis = swoole_get_object(getThis()); redisAsyncContext *context; if (strncasecmp(host, ZEND_STRL("unix:/")) == 0) { context = redisAsyncConnectUnix(host + 5); } else { if (port <= 1 || port > 65535) { swoole_php_error(E_WARNING, "redis server port is invalid."); RETURN_FALSE; } context = redisAsyncConnect(host, (int) port); } if (context->err) { swoole_php_error(E_WARNING, "failed to connect to the redis-server[%s:%d], Erorr: %s[%d]", host, (int) port, context->errstr, context->err); RETURN_FALSE; } php_swoole_check_reactor(); if (!swReactor_handle_isset(SwooleG.main_reactor, PHP_SWOOLE_FD_REDIS)) { SwooleG.main_reactor->setHandle(SwooleG.main_reactor, PHP_SWOOLE_FD_REDIS | SW_EVENT_READ, swoole_redis_onRead); SwooleG.main_reactor->setHandle(SwooleG.main_reactor, PHP_SWOOLE_FD_REDIS | SW_EVENT_WRITE, swoole_redis_onWrite); SwooleG.main_reactor->setHandle(SwooleG.main_reactor, PHP_SWOOLE_FD_REDIS | SW_EVENT_ERROR, swoole_redis_onError); } redisAsyncSetConnectCallback(context, swoole_redis_onConnect); redisAsyncSetDisconnectCallback(context, swoole_redis_onClose); zend_update_property_long(swoole_redis_class_entry_ptr, getThis(), ZEND_STRL("sock"), context->c.fd TSRMLS_CC); zend_update_property(swoole_redis_class_entry_ptr, getThis(), ZEND_STRL("onConnect"), callback TSRMLS_CC); redis->context = context; context->ev.addRead = swoole_redis_event_AddRead; context->ev.delRead = swoole_redis_event_DelRead; context->ev.addWrite = swoole_redis_event_AddWrite; context->ev.delWrite = swoole_redis_event_DelWrite; context->ev.cleanup = swoole_redis_event_Cleanup; context->ev.data = redis; zend_update_property_string(swoole_redis_class_entry_ptr, getThis(), ZEND_STRL("host"), host TSRMLS_CC); zend_update_property_long(swoole_redis_class_entry_ptr, getThis(), ZEND_STRL("port"), port TSRMLS_CC); if (SwooleG.main_reactor->add(SwooleG.main_reactor, redis->context->c.fd, PHP_SWOOLE_FD_REDIS | SW_EVENT_WRITE) < 0) { swoole_php_fatal_error(E_WARNING, "swoole_event_add failed. Erorr: %s[%d].", redis->context->errstr, redis->context->err); RETURN_FALSE; } if (redis->timeout > 0) { php_swoole_check_timer((int) (redis->timeout * 1000)); redis->timer = SwooleG.timer.add(&SwooleG.timer, (int) (redis->timeout * 1000), 0, redis, swoole_redis_onTimeout); } sw_zval_add_ref(&redis->object); swConnection *conn = swReactor_get(SwooleG.main_reactor, redis->context->c.fd); conn->object = redis; }
static PHP_METHOD(swoole_process, signal) { zval *callback = NULL; long signo = 0; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz", &signo, &callback) == FAILURE) { return; } if (!SWOOLE_G(cli)) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "cannot use swoole_process::signal here."); RETURN_FALSE; } if (SwooleGS->start) { if (signo == SIGTERM || signo == SIGALRM) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot use swoole_process::signal in swoole_server."); RETURN_FALSE; } } if (callback == NULL || ZVAL_IS_NULL(callback)) { callback = signal_callback[signo]; if (callback) { sw_zval_ptr_dtor(&callback); swSignal_add(signo, NULL); RETURN_TRUE; } else { swoole_php_error(E_WARNING, "no callback."); RETURN_FALSE; } } char *func_name; if (!sw_zend_is_callable(callback, 0, &func_name TSRMLS_CC)) { swoole_php_error(E_WARNING, "function '%s' is not callable", func_name); efree(func_name); RETURN_FALSE; } efree(func_name); sw_zval_add_ref(&callback); if (signal_callback[signo]) { sw_zval_ptr_dtor(&callback); } signal_callback[signo] = callback; #if PHP_MAJOR_VERSION >= 7 || (PHP_MAJOR_VERSION >= 5 && PHP_MINOR_VERSION >= 4) SwooleG.use_signalfd = 1; #else SwooleG.use_signalfd = 0; #endif php_swoole_check_reactor(); /** * for swSignalfd_setup */ SwooleG.main_reactor->check_signalfd = 1; swSignal_add(signo, php_swoole_onSignal); RETURN_TRUE; }
static void php_swoole_aio_onFileCompleted(swAio_event *event) { int isEOF = SW_FALSE; int64_t ret; zval *retval = NULL, *zcallback = NULL, *zwriten = NULL; zval *zcontent = NULL; zval **args[2]; zval _zcontent; zval _zwriten; bzero(&_zcontent, sizeof(zval)); bzero(&_zwriten, sizeof(zval)); file_request *file_req = event->object; zcallback = file_req->callback; ret = event->ret; if (ret < 0) { SwooleG.error = event->error; swoole_php_error(E_WARNING, "Aio Error: %s[%d]", strerror(event->error), event->error); } else { if (ret == 0) { bzero(event->buf, event->nbytes); isEOF = SW_TRUE; } else if (file_req->once == 1 && ret < file_req->length) { swoole_php_fatal_error(E_WARNING, "ret_length[%d] < req->length[%d].", (int ) ret, file_req->length); } else if (event->type == SW_AIO_READ) { file_req->offset += event->ret; } } if (event->type == SW_AIO_READ) { args[0] = &file_req->filename; args[1] = &zcontent; zcontent = &_zcontent; if (ret < 0) { SW_ZVAL_STRING(zcontent, "", 1); } else { SW_ZVAL_STRINGL(zcontent, event->buf, ret, 1); } } else if (event->type == SW_AIO_WRITE) { zwriten = &_zwriten; args[0] = &file_req->filename; args[1] = &zwriten; ZVAL_LONG(zwriten, ret); } else { swoole_php_fatal_error(E_WARNING, "swoole_async: onFileCompleted unknown event type[%d].", event->type); return; } if (zcallback) { if (sw_call_user_function_ex(EG(function_table), NULL, zcallback, &retval, 2, args, 0, NULL TSRMLS_CC) == FAILURE) { swoole_php_fatal_error(E_WARNING, "swoole_async: onAsyncComplete handler error"); return; } if (EG(exception)) { zend_exception_error(EG(exception), E_ERROR TSRMLS_CC); } } //file io if (file_req->once == 1) { close_file: close(event->fd); php_swoole_file_request_free(file_req); } else if(file_req->type == SW_AIO_WRITE) { if (retval != NULL && !ZVAL_IS_NULL(retval) && !Z_BVAL_P(retval)) { swHashMap_del(php_swoole_open_files, Z_STRVAL_P(file_req->filename), Z_STRLEN_P(file_req->filename)); goto close_file; } else { php_swoole_file_request_free(file_req); } } else { if ((retval != NULL && !ZVAL_IS_NULL(retval) && !Z_BVAL_P(retval)) || isEOF) { goto close_file; } //Less than expected, at the end of the file else if (event->ret < event->nbytes) { event->ret = 0; php_swoole_aio_onFileCompleted(event); } //continue to read else { swAio_event ev; ev.fd = event->fd; ev.buf = event->buf; ev.type = SW_AIO_READ; ev.nbytes = event->nbytes; ev.offset = file_req->offset; ev.flags = 0; ev.object = file_req; ev.handler = swAio_handler_read; ev.callback = php_swoole_aio_onFileCompleted; int ret = swAio_dispatch(&ev); if (ret < 0) { swoole_php_fatal_error(E_WARNING, "swoole_async: continue to read failed. Error: %s[%d]", strerror(event->error), event->error); goto close_file; } } } if (zcontent) { sw_zval_ptr_dtor(&zcontent); } if (zwriten) { sw_zval_ptr_dtor(&zwriten); } if (retval) { sw_zval_ptr_dtor(&retval); } }
void swoole_websocket_onOpen(http_context *ctx) { #if PHP_MAJOR_VERSION < 7 TSRMLS_FETCH_FROM_CTX(sw_thread_ctx ? sw_thread_ctx : NULL); #endif int fd = ctx->fd; swConnection *conn = swWorker_get_connection(SwooleG.serv, fd); if (!conn) { swoole_error_log(SW_LOG_NOTICE, SW_ERROR_SESSION_CLOSED, "session[%d] is closed.", fd); return; } conn->websocket_status = WEBSOCKET_STATUS_ACTIVE; zend_fcall_info_cache *cache = php_swoole_server_get_cache(SwooleG.serv, conn->from_fd, SW_SERVER_CB_onOpen); if (cache) { swServer *serv = SwooleG.serv; zval *zserv = (zval *) serv->ptr2; zval *zrequest_object = ctx->request.zobject; zval *retval = NULL; #ifndef SW_COROUTINE zval **args[2]; args[0] = &zserv; args[1] = &zrequest_object; #else zval *args[2]; args[0] = zserv; args[1] = zrequest_object; #endif #ifndef SW_COROUTINE zval *zcallback = php_swoole_server_get_callback(SwooleG.serv, conn->from_fd, SW_SERVER_CB_onOpen); if (sw_call_user_function_fast(zcallback, cache, &retval, 2, args TSRMLS_CC) == FAILURE) { swoole_php_error(E_WARNING, "onOpen handler error"); } #else int ret = coro_create(cache, args, 2, &retval, NULL, NULL); if (ret != 0) { if (ret == CORO_LIMIT) { SwooleG.serv->factory.end(&SwooleG.serv->factory, fd); } return; } #endif if (EG(exception)) { zend_exception_error(EG(exception), E_ERROR TSRMLS_CC); } if (retval) { sw_zval_ptr_dtor(&retval); } } }
static PHP_METHOD(swoole_redis, __call) { zval *params; char *command; zend_size_t command_len; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &command, &command_len, ¶ms) == FAILURE) { return; } if (Z_TYPE_P(params) != IS_ARRAY) { swoole_php_fatal_error(E_WARNING, "invalid params."); RETURN_FALSE; } swRedisClient *redis = swoole_get_object(getThis()); if (!redis) { swoole_php_fatal_error(E_WARNING, "the object is not an instance of swoole_redis."); RETURN_FALSE; } switch (redis->state) { case SWOOLE_REDIS_STATE_CONNECT: swoole_php_error(E_WARNING, "redis client is not connected."); RETURN_FALSE; break; case SWOOLE_REDIS_STATE_WAIT_RESULT: if (swoole_redis_is_message_command(command, command_len)) { swoole_php_error(E_WARNING, "redis client is waiting for response."); RETURN_FALSE; } break; case SWOOLE_REDIS_STATE_SUBSCRIBE: if (!swoole_redis_is_message_command(command, command_len)) { swoole_php_error(E_WARNING, "redis client is waiting for subscribed messages."); RETURN_FALSE; } break; case SWOOLE_REDIS_STATE_CLOSED: swoole_php_error(E_WARNING, "redis client connection is closed."); RETURN_FALSE; break; default: break; } int argc = zend_hash_num_elements(Z_ARRVAL_P(params)); size_t stack_argvlen[SW_REDIS_COMMAND_BUFFER_SIZE]; char *stack_argv[SW_REDIS_COMMAND_BUFFER_SIZE]; size_t *argvlen; char **argv; zend_bool free_mm = 0; if (argc > SW_REDIS_COMMAND_BUFFER_SIZE) { argvlen = emalloc(sizeof(size_t) * argc); argv = emalloc(sizeof(char*) * argc); free_mm = 1; } else { argvlen = stack_argvlen; argv = stack_argv; } #define FREE_MEM() do { \ for (i = 1; i < argc; i++) \ { \ efree((void* )argv[i]); \ } \ \ if (redis->state == SWOOLE_REDIS_STATE_SUBSCRIBE) \ { \ efree(argv[argc]); \ } \ \ if (free_mm) \ { \ efree(argvlen); \ efree(argv); \ } \ } while (0) assert(command_len < SW_REDIS_COMMAND_KEY_SIZE - 1); char command_name[SW_REDIS_COMMAND_KEY_SIZE]; memcpy(command_name, command, command_len); command_name[command_len] = '\0'; argv[0] = command_name; argvlen[0] = command_len; zval *value; int i = 1; /** * subscribe command */ if (redis->state == SWOOLE_REDIS_STATE_SUBSCRIBE || (redis->subscribe && swoole_redis_is_message_command(command, command_len))) { redis->state = SWOOLE_REDIS_STATE_SUBSCRIBE; SW_HASHTABLE_FOREACH_START(Z_ARRVAL_P(params), value) convert_to_string(value); argvlen[i] = (size_t) Z_STRLEN_P(value); argv[i] = estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value)); if (i == argc) { break; } i++; SW_HASHTABLE_FOREACH_END(); if (redisAsyncCommandArgv(redis->context, swoole_redis_onResult, NULL, argc + 1, (const char **) argv, (const size_t *) argvlen) < 0) { swoole_php_error(E_WARNING, "redisAsyncCommandArgv() failed."); FREE_MEM(); RETURN_FALSE; } } /** * storage command */ else { redis->state = SWOOLE_REDIS_STATE_WAIT_RESULT; redis->reqnum++; #if PHP_MAJOR_VERSION < 7 zval *callback; zval **cb_tmp; if (zend_hash_index_find(Z_ARRVAL_P(params), zend_hash_num_elements(Z_ARRVAL_P(params)) - 1, (void **) &cb_tmp) == FAILURE) { swoole_php_error(E_WARNING, "index out of array bounds."); FREE_MEM(); RETURN_FALSE; } callback = *cb_tmp; #else zval *callback = zend_hash_index_find(Z_ARRVAL_P(params), zend_hash_num_elements(Z_ARRVAL_P(params)) - 1); if (callback == NULL) { swoole_php_error(E_WARNING, "index out of array bounds."); FREE_MEM(); RETURN_FALSE; } #endif sw_zval_add_ref(&callback); callback = sw_zval_dup(callback); SW_HASHTABLE_FOREACH_START(Z_ARRVAL_P(params), value) if (i == argc) { break; } convert_to_string(value); argvlen[i] = (size_t) Z_STRLEN_P(value); argv[i] = estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value)); i++; SW_HASHTABLE_FOREACH_END(); if (redisAsyncCommandArgv(redis->context, swoole_redis_onResult, callback, argc, (const char **) argv, (const size_t *) argvlen) < 0) { swoole_php_error(E_WARNING, "redisAsyncCommandArgv() failed."); FREE_MEM(); RETURN_FALSE; } } FREE_MEM(); RETURN_TRUE; }
static PHP_METHOD(swoole_redis, connect) { char *host; zend_size_t host_len; long port; zval *callback; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "slz", &host, &host_len, &port, &callback) == FAILURE) { RETURN_FALSE; } if (host_len <= 0) { swoole_php_error(E_WARNING, "host is empty."); RETURN_FALSE; } if (port <= 1 || port > 65535) { swoole_php_error(E_WARNING, "port is invalid."); RETURN_FALSE; } swRedisClient *redis = emalloc(sizeof(swRedisClient)); bzero(redis, sizeof(swRedisClient)); #if PHP_MAJOR_VERSION < 7 redis->object = getThis(); #else redis->object = &redis->_object; memcpy(redis->object, getThis(), sizeof(zval)); #endif sw_zval_add_ref(&redis->object); swoole_set_object(getThis(), redis); redisAsyncContext *context = redisAsyncConnect(host, (int) port); if (context->err) { swoole_php_error(E_WARNING, "connect to redis-server[%s:%d] failed, Erorr: %s[%d]", host, (int) port, context->errstr, context->err); RETURN_FALSE; } php_swoole_check_reactor(); if (!isset_event_callback) { SwooleG.main_reactor->setHandle(SwooleG.main_reactor, PHP_SWOOLE_FD_REDIS | SW_EVENT_READ, swoole_redis_onRead); SwooleG.main_reactor->setHandle(SwooleG.main_reactor, PHP_SWOOLE_FD_REDIS | SW_EVENT_WRITE, swoole_redis_onWrite); isset_event_callback = 1; } redisAsyncSetConnectCallback(context, swoole_redis_onConnect); redisAsyncSetDisconnectCallback(context, swoole_redis_onClose); #if PHP_MAJOR_VERSION < 7 redis->connect_callback = callback; #else redis->connect_callback = &redis->_connect_callback; memcpy(redis->connect_callback, callback, sizeof(zval)); #endif sw_zval_add_ref(&redis->connect_callback); redis->context = context; context->ev.addRead = swoole_redis_event_AddRead; context->ev.delRead = swoole_redis_event_DelRead; context->ev.addWrite = swoole_redis_event_AddWrite; context->ev.delWrite = swoole_redis_event_DelWrite; context->ev.cleanup = swoole_redis_event_Cleanup; context->ev.data = redis; zend_update_property_string(swoole_redis_class_entry_ptr, getThis(), ZEND_STRL("host"), host TSRMLS_CC); zend_update_property_long(swoole_redis_class_entry_ptr, getThis(), ZEND_STRL("port"), port TSRMLS_CC); if (SwooleG.main_reactor->add(SwooleG.main_reactor, redis->context->c.fd, PHP_SWOOLE_FD_REDIS | SW_EVENT_WRITE) < 0) { swoole_php_fatal_error(E_WARNING, "swoole_event_add failed. Erorr: %s[%d].", redis->context->errstr, redis->context->err); RETURN_FALSE; } swConnection *conn = swReactor_get(SwooleG.main_reactor, redis->context->c.fd); conn->object = redis; }
static PHP_METHOD(swoole_redis, __call) { zval *params; char *command; zend_size_t command_len; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &command, &command_len, ¶ms) == FAILURE) { return; } swRedisClient *redis = swoole_get_object(getThis()); switch (redis->state) { case SWOOLE_REDIS_STATE_CONNECT: swoole_php_error(E_WARNING, "redis client is not connected."); RETURN_FALSE; break; case SWOOLE_REDIS_STATE_WAIT: swoole_php_error(E_WARNING, "redis client is waiting for response."); RETURN_FALSE; break; case SWOOLE_REDIS_STATE_CLOSED: swoole_php_error(E_WARNING, "redis client connection is closed."); RETURN_FALSE; break; default: break; } #if PHP_MAJOR_VERSION < 7 zval *callback; zval **cb_tmp; if (zend_hash_index_find(Z_ARRVAL_P(params), zend_hash_num_elements(Z_ARRVAL_P(params)) - 1, (void **) &cb_tmp) == FAILURE) { swoole_php_error(E_WARNING, "index out of array."); RETURN_FALSE; } callback = *cb_tmp; redis->result_callback = callback; #else zval *callback = zend_hash_index_find(Z_ARRVAL_P(params), zend_hash_num_elements(Z_ARRVAL_P(params)) - 1); if (callback == NULL) { swoole_php_error(E_WARNING, "index out of array."); RETURN_FALSE; } redis->result_callback = &redis->_result_callback; memcpy(redis->result_callback, callback, sizeof(zval)); #endif sw_zval_add_ref(&redis->result_callback); redis->state = SWOOLE_REDIS_STATE_WAIT; int argc = zend_hash_num_elements(Z_ARRVAL_P(params)); size_t stack_argvlen[SW_REDIS_COMMAND_BUFFER_SIZE]; char *stack_argv[SW_REDIS_COMMAND_BUFFER_SIZE]; size_t *argvlen; char **argv; zend_bool free_mm = 0; if (argc > SW_REDIS_COMMAND_BUFFER_SIZE) { argvlen = emalloc(sizeof(size_t) * argc); argv = emalloc(sizeof(char*) * argc); free_mm = 1; } else { argvlen = stack_argvlen; argv = stack_argv; } assert(command_len < SW_REDIS_COMMAND_KEY_SIZE - 1); char command_name[SW_REDIS_COMMAND_KEY_SIZE]; memcpy(command_name, command, command_len); command_name[command_len] = '\0'; argv[0] = command_name; argvlen[0] = command_len; zval *value; int i = 1; SW_HASHTABLE_FOREACH_START(Z_ARRVAL_P(params), value) convert_to_string(value); argvlen[i] = (size_t) Z_STRLEN_P(value); argv[i] = estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value)); if (i == argc - 1) { break; } i++; SW_HASHTABLE_FOREACH_END(); if (redisAsyncCommandArgv(redis->context, swoole_redis_onResult, NULL, argc, (const char **) argv, (const size_t *) argvlen) < 0) { swoole_php_error(E_WARNING, "redisAsyncCommandArgv() failed."); RETURN_FALSE; } for (i = 1; i < argc; i++) { efree((void* )argv[i]); } if (free_mm) { efree(argvlen); efree(argv); } redis->state = SWOOLE_REDIS_STATE_WAIT; RETURN_TRUE; }
static void php_swoole_aio_onComplete(swAio_event *event) { int isEOF = SW_FALSE; int64_t ret; zval *retval = NULL, *zcallback = NULL, *zwriten = NULL; zval *zcontent = NULL; zval **args[2]; file_request *file_req = NULL; dns_request *dns_req = NULL; #if PHP_MAJOR_VERSION < 7 TSRMLS_FETCH_FROM_CTX(sw_thread_ctx ? sw_thread_ctx : NULL); #else zval _zcontent; zval _zwriten; bzero(&_zcontent, sizeof(zval)); bzero(&_zwriten, sizeof(zval)); #endif if (event->type == SW_AIO_GETHOSTBYNAME) { dns_req = (dns_request *) event->req; if (dns_req->callback == NULL) { swoole_php_error(E_WARNING, "swoole_async: onAsyncComplete callback not found[0]"); return; } zcallback = dns_req->callback; } else { file_req = swHashMap_find_int(php_swoole_aio_request, event->task_id); if (!file_req) { swoole_php_fatal_error(E_WARNING, "swoole_async: onAsyncComplete callback not found[1]"); return; } if (file_req->callback == NULL && file_req->type == SW_AIO_READ) { swoole_php_fatal_error(E_WARNING, "swoole_async: onAsyncComplete callback not found[2]"); return; } zcallback = file_req->callback; } ret = event->ret; if (ret < 0) { SwooleG.error = event->error; swoole_php_error(E_WARNING, "Aio Error: %s[%d]", strerror(event->error), event->error); } else if (file_req != NULL) { if (ret == 0) { bzero(event->buf, event->nbytes); isEOF = SW_TRUE; } else if (file_req->once == 1 && ret < file_req->length) { swoole_php_fatal_error(E_WARNING, "ret_length[%d] < req->length[%d].", (int ) ret, file_req->length); } else if (event->type == SW_AIO_READ) { file_req->offset += event->ret; } } if (event->type == SW_AIO_READ) { args[0] = &file_req->filename; args[1] = &zcontent; #if PHP_MAJOR_VERSION < 7 SW_MAKE_STD_ZVAL(zcontent); #else zcontent = &_zcontent; #endif if (ret < 0) { SW_ZVAL_STRING(zcontent, "", 1); } else { SW_ZVAL_STRINGL(zcontent, event->buf, ret, 1); } } else if (event->type == SW_AIO_WRITE) { #if PHP_MAJOR_VERSION < 7 SW_MAKE_STD_ZVAL(zwriten); #else zwriten = &_zwriten; #endif args[0] = &file_req->filename; args[1] = &zwriten; ZVAL_LONG(zwriten, ret); } else if(event->type == SW_AIO_GETHOSTBYNAME) { args[0] = &dns_req->domain; #if PHP_MAJOR_VERSION < 7 SW_MAKE_STD_ZVAL(zcontent); #else zcontent = &_zcontent; #endif if (ret < 0) { SW_ZVAL_STRING(zcontent, "", 1); } else { SW_ZVAL_STRING(zcontent, event->buf, 1); } args[1] = &zcontent; } else { swoole_php_fatal_error(E_WARNING, "swoole_async: onAsyncComplete unknown event type[%d].", event->type); return; } if (zcallback) { if (sw_call_user_function_ex(EG(function_table), NULL, zcallback, &retval, 2, args, 0, NULL TSRMLS_CC) == FAILURE) { swoole_php_fatal_error(E_WARNING, "swoole_async: onAsyncComplete handler error"); return; } if (EG(exception)) { zend_exception_error(EG(exception), E_ERROR TSRMLS_CC); } } //file io if (file_req) { if (file_req->once == 1) { close_file: close(event->fd); swHashMap_del_int(php_swoole_aio_request, event->task_id); } else if(file_req->type == SW_AIO_WRITE) { if (retval != NULL && !ZVAL_IS_NULL(retval) && !Z_BVAL_P(retval)) { swHashMap_del(php_swoole_open_files, Z_STRVAL_P(file_req->filename), Z_STRLEN_P(file_req->filename)); goto close_file; } else { swHashMap_del_int(php_swoole_aio_request, event->task_id); } } else { if ((retval != NULL && !ZVAL_IS_NULL(retval) && !Z_BVAL_P(retval)) || isEOF) { goto close_file; } //Less than expected, at the end of the file else if (event->ret < event->nbytes) { event->ret = 0; php_swoole_aio_onComplete(event); } //continue to read else { int ret = SwooleAIO.read(event->fd, event->buf, event->nbytes, file_req->offset); if (ret < 0) { swoole_php_fatal_error(E_WARNING, "swoole_async: continue to read failed. Error: %s[%d]", strerror(event->error), event->error); goto close_file; } else { swHashMap_move_int(php_swoole_aio_request, event->task_id, ret); } } } } else if (dns_req) { sw_zval_ptr_dtor(&dns_req->callback); sw_zval_ptr_dtor(&dns_req->domain); efree(dns_req); efree(event->buf); } if (zcontent) { sw_zval_ptr_dtor(&zcontent); } if (zwriten) { sw_zval_ptr_dtor(&zwriten); } if (retval) { sw_zval_ptr_dtor(&retval); } }
static PHP_METHOD(swoole_server_port, on) { char *name = NULL; zend_size_t len, i; zval *cb; if (SwooleGS->start > 0) { swoole_php_fatal_error(E_WARNING, "Server is running. Unable to set event callback now."); RETURN_FALSE; } if (zend_parse_parameters(ZEND_NUM_ARGS()TSRMLS_CC, "sz", &name, &len, &cb) == FAILURE) { return; } #ifdef PHP_SWOOLE_CHECK_CALLBACK char *func_name = NULL; if (!sw_zend_is_callable(cb, 0, &func_name TSRMLS_CC)) { swoole_php_fatal_error(E_ERROR, "Function '%s' is not callable", func_name); efree(func_name); return; } efree(func_name); #endif swoole_server_port_property *property = swoole_get_property(getThis(), 0); swListenPort *port = swoole_get_object(getThis()); if (!port->ptr) { port->ptr = property; } char *callback_name[PHP_SERVER_CALLBACK_NUM] = { "Connect", "Receive", "Close", "Packet", "Start", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Request", "HandShake", "Open", "Message", }; char property_name[128]; int l_property_name = 0; memcpy(property_name, "on", 2); for (i = 0; i < PHP_SERVER_CALLBACK_NUM; i++) { if (callback_name[i] == NULL) { continue; } if (strncasecmp(callback_name[i], name, len) == 0) { memcpy(property_name + 2, callback_name[i], len); l_property_name = len + 2; property_name[l_property_name] = '\0'; zend_update_property(swoole_server_port_class_entry_ptr, getThis(), property_name, l_property_name, cb TSRMLS_CC); property->callbacks[i] = sw_zend_read_property(swoole_server_port_class_entry_ptr, getThis(), property_name, l_property_name, 0 TSRMLS_CC); sw_copy_to_stack(property->callbacks[i], property->_callbacks[i]); if (i == SW_SERVER_CB_onConnect && SwooleG.serv->onConnect == NULL) { SwooleG.serv->onConnect = php_swoole_onConnect; } else if (i == SW_SERVER_CB_onClose && SwooleG.serv->onClose == NULL) { SwooleG.serv->onClose = php_swoole_onClose; } break; } } if (l_property_name == 0) { swoole_php_error(E_WARNING, "Unknown event types[%s]", name); RETURN_FALSE; } RETURN_TRUE; }
int swoole_websocket_onMessage(swEventData *req) { #if PHP_MAJOR_VERSION < 7 TSRMLS_FETCH_FROM_CTX(sw_thread_ctx ? sw_thread_ctx : NULL); #endif int fd = req->info.fd; zval *zdata; SW_MAKE_STD_ZVAL(zdata); char frame_header[2]; php_swoole_get_recv_data(zdata, req, frame_header, 2); long finish = frame_header[0] ? 1 : 0; long opcode = frame_header[1]; zval *zframe; SW_MAKE_STD_ZVAL(zframe); object_init_ex(zframe, swoole_websocket_frame_class_entry_ptr); zend_update_property_long(swoole_websocket_frame_class_entry_ptr, zframe, ZEND_STRL("fd"), fd TSRMLS_CC); zend_update_property_bool(swoole_websocket_frame_class_entry_ptr, zframe, ZEND_STRL("finish"), finish TSRMLS_CC); zend_update_property_long(swoole_websocket_frame_class_entry_ptr, zframe, ZEND_STRL("opcode"), opcode TSRMLS_CC); zend_update_property(swoole_websocket_frame_class_entry_ptr, zframe, ZEND_STRL("data"), zdata TSRMLS_CC); swServer *serv = SwooleG.serv; zval *zserv = (zval *) serv->ptr2; #ifndef SW_COROUTINE zval **args[2]; args[0] = &zserv; args[1] = &zframe; #else zval *args[2]; args[0] = zserv; args[1] = zframe; #endif zval *retval = NULL; #ifndef SW_COROUTINE zend_fcall_info_cache *fci_cache = php_swoole_server_get_cache(serv, req->info.from_fd, SW_SERVER_CB_onMessage); zval *zcallback = php_swoole_server_get_callback(SwooleG.serv, req->info.from_fd, SW_SERVER_CB_onMessage); if (sw_call_user_function_fast(zcallback, fci_cache, &retval, 2, args TSRMLS_CC) == FAILURE) { swoole_php_error(E_WARNING, "onMessage handler error"); } #else zend_fcall_info_cache *cache = php_swoole_server_get_cache(serv, req->info.from_fd, SW_SERVER_CB_onMessage); int ret = coro_create(cache, args, 2, &retval, NULL, NULL); if (ret != 0) { sw_zval_ptr_dtor(&zdata); sw_zval_ptr_dtor(&zframe); if (ret == CORO_LIMIT) { SwooleG.serv->factory.end(&SwooleG.serv->factory, fd); } return SW_OK; } #endif if (EG(exception)) { zend_exception_error(EG(exception), E_ERROR TSRMLS_CC); } if (retval) { sw_zval_ptr_dtor(&retval); } sw_zval_ptr_dtor(&zdata); sw_zval_ptr_dtor(&zframe); return SW_OK; }