static PHP_METHOD( swoole_websocket_server, on) { zval *callback; zval *event_name; 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, "zz", &event_name, &callback) == FAILURE) { return; } swServer *serv = swoole_get_object(getThis()); 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_FALSE; } efree(func_name); #if PHP_MAJOR_VERSION >= 7 zval *callback_copy = emalloc(sizeof(zval)); memcpy(callback_copy, callback, sizeof(zval)); callback = callback_copy; #endif serv->open_websocket_protocol = 1; if (strncasecmp("open", Z_STRVAL_P(event_name), Z_STRLEN_P(event_name)) == 0) { sw_zval_add_ref(&callback); websocket_callbacks[0] = callback; } else if (strncasecmp("message", Z_STRVAL_P(event_name), Z_STRLEN_P(event_name)) == 0) { sw_zval_add_ref(&callback); websocket_callbacks[1] = callback; } else { zval *obj = getThis(); sw_zend_call_method_with_2_params(&obj, swoole_http_server_class_entry_ptr, NULL, "on", &return_value, event_name, callback); } }
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, 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)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "no callback."); RETURN_FALSE; } char *func_name; 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_FALSE; } efree(func_name); sw_zval_add_ref(&callback); signal_callback[signo] = callback; #if 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; }
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, getSocket) { swListenPort *port = swoole_get_object(getThis()); php_socket *socket_object = swoole_convert_to_socket(port->sock); if (!socket_object) { RETURN_FALSE; } SW_ZEND_REGISTER_RESOURCE(return_value, (void *) socket_object, php_sockets_le_socket()); zval *zsocket = sw_zval_dup(return_value); sw_zval_add_ref(&zsocket); }
static void php_swoole_onTimerInterval(swTimer *timer, swTimer_node *event) { #if PHP_MAJOR_VERSION < 7 TSRMLS_FETCH_FROM_CTX(sw_thread_ctx ? sw_thread_ctx : NULL); #endif zval *retval = NULL; zval **args[2]; int argc = 1; zval *ztimer_id; swTimer_callback *cb = event->data; //server->addtimer if (cb == NULL && SwooleG.serv) { SwooleG.serv->onTimer(SwooleG.serv, event->interval); return; } if (cb->type == SW_TIMER_TICK) { SW_MAKE_STD_ZVAL(ztimer_id); ZVAL_LONG(ztimer_id, event->id); if (cb->data) { argc = 2; sw_zval_add_ref(&cb->data); args[1] = &cb->data; } } else { SW_MAKE_STD_ZVAL(ztimer_id); ZVAL_LONG(ztimer_id, event->interval); } args[0] = &ztimer_id; if (sw_call_user_function_ex(EG(function_table), NULL, cb->callback, &retval, argc, args, 0, NULL TSRMLS_CC) == FAILURE) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "swoole_timer: onTimerCallback handler error"); return; } if (retval != NULL) { sw_zval_ptr_dtor(&retval); } sw_zval_ptr_dtor(&ztimer_id); }
void swoole_websocket_onOpen(swoole_http_client *client) { #if PHP_MAJOR_VERSION < 7 TSRMLS_FETCH_FROM_CTX(sw_thread_ctx ? sw_thread_ctx : NULL); #endif int fd = client->fd; swConnection *conn = swWorker_get_connection(SwooleG.serv, fd); if (!conn) { swWarn("connection[%d] is closed.", fd); return; } conn->websocket_status = WEBSOCKET_STATUS_HANDSHAKE; swTrace("\n\n\n\nconn ws status:%d, fd=%d\n\n\n", conn->websocket_status, fd); if (websocket_callbacks[WEBSOCKET_CALLBACK_onOpen]) { swTrace("\n\n\n\nhandshake success\n\n\n"); zval **args[2]; swServer *serv = SwooleG.serv; zval *zserv = (zval *) serv->ptr2; zval *zrequest_object = client->request.zrequest_object; zval *retval = NULL; #ifdef __CYGWIN__ //TODO: memory error on cygwin. sw_zval_add_ref(&zrequest_object); #endif args[0] = &zserv; args[1] = &zrequest_object; if (sw_call_user_function_ex(EG(function_table), NULL, websocket_callbacks[WEBSOCKET_CALLBACK_onOpen], &retval, 2, args, 0, NULL TSRMLS_CC) == FAILURE) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "onOpen handler error"); } if (EG(exception)) { zend_exception_error(EG(exception), E_ERROR TSRMLS_CC); } if (retval) { sw_zval_ptr_dtor(&retval); } } }
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; }
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_mysql, query) { zval *callback; swString sql; bzero(&sql, sizeof(sql)); if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &sql.str, &sql.length, &callback) == FAILURE) { return; } if (sql.length <= 0) { swoole_php_fatal_error(E_WARNING, "Query is empty."); RETURN_FALSE; } mysql_client *client = swoole_get_object(getThis()); if (!client) { swoole_php_fatal_error(E_WARNING, "object is not instanceof swoole_mysql."); RETURN_FALSE; } if (!client->cli) { swoole_php_fatal_error(E_WARNING, "mysql connection#%d is closed.", client->fd); RETURN_FALSE; } if (client->state != SW_MYSQL_STATE_QUERY) { swoole_php_fatal_error(E_WARNING, "mysql client is waiting response, cannot send new sql query."); RETURN_FALSE; } sw_zval_add_ref(&callback); client->callback = sw_zval_dup(callback); swString_clear(mysql_request_buffer); if (mysql_request(&sql, mysql_request_buffer) < 0) { RETURN_FALSE; } //send query if (SwooleG.main_reactor->write(SwooleG.main_reactor, client->fd, mysql_request_buffer->str, mysql_request_buffer->length) < 0) { //connection is closed if (swConnection_error(errno) == SW_CLOSE) { zend_update_property_bool(swoole_mysql_class_entry_ptr, getThis(), ZEND_STRL("connected"), 0 TSRMLS_CC); zend_update_property_bool(swoole_mysql_class_entry_ptr, getThis(), ZEND_STRL("errno"), 2006 TSRMLS_CC); } RETURN_FALSE; } else { client->state = SW_MYSQL_STATE_READ_START; RETURN_TRUE; } }
static PHP_METHOD(swoole_mysql, connect) { zval *server_info; zval *callback; char buf[2048]; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "az", &server_info, &callback) == FAILURE) { RETURN_FALSE; } HashTable *_ht = Z_ARRVAL_P(server_info); zval *value; mysql_client *client = swoole_get_object(getThis()); mysql_connector *connector = &client->connector; if (php_swoole_array_get_value(_ht, "host", value)) { convert_to_string(value); connector->host = Z_STRVAL_P(value); connector->host_len = Z_STRLEN_P(value); } else { zend_throw_exception(swoole_mysql_exception_class_entry, "HOST parameter is required.", 11 TSRMLS_CC); RETURN_FALSE; } if (php_swoole_array_get_value(_ht, "port", value)) { convert_to_long(value); connector->port = Z_LVAL_P(value); } else { connector->port = SW_MYSQL_DEFAULT_PORT; } if (php_swoole_array_get_value(_ht, "user", value)) { convert_to_string(value); connector->user = Z_STRVAL_P(value); connector->user_len = Z_STRLEN_P(value); } else { zend_throw_exception(swoole_mysql_exception_class_entry, "USER parameter is required.", 11 TSRMLS_CC); RETURN_FALSE; } if (php_swoole_array_get_value(_ht, "password", value)) { convert_to_string(value); connector->password = Z_STRVAL_P(value); connector->password_len = Z_STRLEN_P(value); } else { zend_throw_exception(swoole_mysql_exception_class_entry, "PASSWORD parameter is required.", 11 TSRMLS_CC); RETURN_FALSE; } if (php_swoole_array_get_value(_ht, "database", value)) { convert_to_string(value); connector->database = Z_STRVAL_P(value); connector->database_len = Z_STRLEN_P(value); } else { zend_throw_exception(swoole_mysql_exception_class_entry, "DATABASE parameter is required.", 11 TSRMLS_CC); RETURN_FALSE; } if (php_swoole_array_get_value(_ht, "timeout", value)) { convert_to_double(value); connector->timeout = Z_DVAL_P(value); } else { connector->timeout = SW_MYSQL_CONNECT_TIMEOUT; } if (php_swoole_array_get_value(_ht, "charset", value)) { convert_to_string(value); connector->character_set = mysql_get_charset(Z_STRVAL_P(value)); if (connector->character_set < 0) { snprintf(buf, sizeof(buf), "unknown charset [%s].", Z_STRVAL_P(value)); zend_throw_exception(swoole_mysql_exception_class_entry, buf, 11 TSRMLS_CC); RETURN_FALSE; } } else { connector->character_set = SW_MYSQL_DEFAULT_CHARSET; } swClient *cli = emalloc(sizeof(swClient)); int type = SW_SOCK_TCP; if (strncasecmp(connector->host, ZEND_STRL("unix:/")) == 0) { connector->host = connector->host + 5; connector->host_len = connector->host_len - 5; type = SW_SOCK_UNIX_STREAM; } else if (strchr(connector->host, ':')) { type = SW_SOCK_TCP6; } php_swoole_check_reactor(); if (!isset_event_callback) { SwooleG.main_reactor->setHandle(SwooleG.main_reactor, PHP_SWOOLE_FD_MYSQL | SW_EVENT_READ, swoole_mysql_onRead); SwooleG.main_reactor->setHandle(SwooleG.main_reactor, PHP_SWOOLE_FD_MYSQL | SW_EVENT_WRITE, swoole_mysql_onWrite); SwooleG.main_reactor->setHandle(SwooleG.main_reactor, PHP_SWOOLE_FD_MYSQL | SW_EVENT_ERROR, swoole_mysql_onError); } if (swClient_create(cli, type, 0) < 0) { zend_throw_exception(swoole_mysql_exception_class_entry, "swClient_create failed.", 1 TSRMLS_CC); RETURN_FALSE; } int tcp_nodelay = 1; if (setsockopt(cli->socket->fd, IPPROTO_TCP, TCP_NODELAY, (const void *) &tcp_nodelay, sizeof(int)) == -1) { swoole_php_sys_error(E_WARNING, "setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) failed.", cli->socket->fd); } int ret = cli->connect(cli, connector->host, connector->port, connector->timeout, 1); if ((ret < 0 && errno == EINPROGRESS) || ret == 0) { if (SwooleG.main_reactor->add(SwooleG.main_reactor, cli->socket->fd, PHP_SWOOLE_FD_MYSQL | SW_EVENT_WRITE) < 0) { RETURN_FALSE; } } else { snprintf(buf, sizeof(buf), "connect to mysql server[%s:%d] failed.", connector->host, connector->port); zend_throw_exception(swoole_mysql_exception_class_entry, buf, 2 TSRMLS_CC); RETURN_FALSE; } zend_update_property(swoole_mysql_class_entry_ptr, getThis(), ZEND_STRL("onConnect"), callback TSRMLS_CC); zend_update_property(swoole_mysql_class_entry_ptr, getThis(), ZEND_STRL("serverInfo"), server_info TSRMLS_CC); zend_update_property_long(swoole_mysql_class_entry_ptr, getThis(), ZEND_STRL("sock"), cli->socket->fd TSRMLS_CC); client->buffer = swString_new(SW_BUFFER_SIZE_BIG); client->fd = cli->socket->fd; client->object = getThis(); client->cli = cli; sw_copy_to_stack(client->object, client->_object); sw_zval_add_ref(&client->object); swConnection *_socket = swReactor_get(SwooleG.main_reactor, cli->socket->fd); _socket->object = client; _socket->active = 0; RETURN_TRUE; }
long php_swoole_add_timer(int ms, zval *callback, zval *param, int persistent TSRMLS_DC) { if (ms > SW_TIMER_MAX_VALUE) { swoole_php_fatal_error(E_WARNING, "The given parameters is too big."); return SW_ERR; } if (ms <= 0) { swoole_php_fatal_error(E_WARNING, "Timer must be greater than 0"); return SW_ERR; } char *func_name = NULL; zend_fcall_info_cache *func_cache = emalloc(sizeof(zend_fcall_info_cache)); if (!sw_zend_is_callable_ex(callback, NULL, 0, &func_name, NULL, func_cache, NULL TSRMLS_CC)) { efree(func_cache); efree(func_name); swoole_php_fatal_error(E_ERROR, "Function '%s' is not callable", func_name); return SW_ERR; } efree(func_name); if (!swIsTaskWorker()) { php_swoole_check_reactor(); } php_swoole_check_timer(ms); swTimer_callback *cb = emalloc(sizeof(swTimer_callback)); cb->data = &cb->_data; cb->callback = &cb->_callback; memcpy(cb->callback, callback, sizeof(zval)); if (param) { memcpy(cb->data, param, sizeof(zval)); } else { cb->data = NULL; } if (SwooleG.enable_coroutine) { cb->func_cache = func_cache; } else { efree(func_cache); } swTimerCallback timer_func; if (persistent) { cb->type = SW_TIMER_TICK; timer_func = php_swoole_onInterval; } else { cb->type = SW_TIMER_AFTER; timer_func = php_swoole_onTimeout; } sw_zval_add_ref(&cb->callback); if (cb->data) { sw_zval_add_ref(&cb->data); } swTimer_node *tnode = SwooleG.timer.add(&SwooleG.timer, ms, persistent, cb, timer_func); if (tnode == NULL) { swoole_php_fatal_error(E_WARNING, "add timer failed."); return SW_ERR; } else { tnode->type = SW_TIMER_TYPE_PHP; return tnode->id; } }
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 int http_client_coro_execute(zval *zobject, char *uri, zend_size_t uri_len TSRMLS_DC) { if (uri_len <= 0) { swoole_php_fatal_error(E_WARNING, "path is empty."); return SW_ERR; } http_client *http = swoole_get_object(zobject); //http is not null when keeping alive if (http) { //http not ready if (http->state != HTTP_CLIENT_STATE_READY) { //swWarn("fd=%d, state=%d, active=%d, keep_alive=%d", http->cli->socket->fd, http->state, http->cli->socket->active, http->keep_alive); swoole_php_fatal_error(E_WARNING, "Operation now in progress phase %d.", http->state); return SW_ERR; } else if (!http->cli->socket->active) { swoole_php_fatal_error(E_WARNING, "connection#%d is closed.", http->cli->socket->fd); return SW_ERR; } } else { php_swoole_check_reactor(); http = http_client_create(zobject TSRMLS_CC); } if (http == NULL) { return SW_ERR; } if (http->body == NULL) { http->body = swString_new(SW_HTTP_RESPONSE_INIT_SIZE); if (http->body == NULL) { swoole_php_fatal_error(E_ERROR, "[1] swString_new(%d) failed.", SW_HTTP_RESPONSE_INIT_SIZE); return SW_ERR; } } else { swString_clear(http->body); } if (http->uri) { efree(http->uri); } http->uri = estrdup(uri); http->uri_len = uri_len; //if connection exists if (http->cli) { http_client_coro_send_http_request(zobject TSRMLS_CC); return SW_OK; } swClient *cli = php_swoole_client_new(zobject, http->host, http->host_len, http->port); if (cli == NULL) { return SW_ERR; } http->cli = cli; zval *ztmp; HashTable *vht; zval *zset = sw_zend_read_property(swoole_http_client_coro_class_entry_ptr, zobject, ZEND_STRL("setting"), 1 TSRMLS_CC); if (zset && !ZVAL_IS_NULL(zset)) { vht = Z_ARRVAL_P(zset); /** * timeout */ if (php_swoole_array_get_value(vht, "timeout", ztmp)) { convert_to_double(ztmp); http->timeout = (double) Z_DVAL_P(ztmp); } /** * keep_alive */ if (php_swoole_array_get_value(vht, "keep_alive", ztmp)) { convert_to_boolean(ztmp); http->keep_alive = (int) Z_LVAL_P(ztmp); } //client settings php_swoole_client_check_setting(http->cli, zset TSRMLS_CC); } if (cli->socket->active == 1) { swoole_php_fatal_error(E_WARNING, "swoole_http_client is already connected."); return SW_ERR; } #if PHP_MAJOR_VERSION < 7 sw_zval_add_ref(&zobject); #endif cli->object = zobject; //sw_copy_to_stack(cli->object, hcc->_object); cli->open_eof_check = 0; cli->open_length_check = 0; cli->reactor_fdtype = PHP_SWOOLE_FD_STREAM_CLIENT; cli->onReceive = http_client_coro_onReceive; cli->onConnect = http_client_coro_onConnect; cli->onClose = http_client_coro_onClose; cli->onError = http_client_coro_onError; return cli->connect(cli, http->host, http->port, http->timeout, 0); }
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 int process_stream_onRead(swReactor *reactor, swEvent *event) { SWOOLE_GET_TSRMLS; process_stream *ps = event->socket->object; char *buf = ps->buffer->str + ps->buffer->length; size_t len = ps->buffer->size - ps->buffer->length; int ret = read(event->fd, buf, len); if (ret > 0) { ps->buffer->length += ret; if (ps->buffer->length == ps->buffer->size) { swString_extend(ps->buffer, ps->buffer->size * 2); } return SW_OK; } else if (ret < 0) { swSysError("read() failed."); return SW_OK; } zval *retval = NULL; zval **args[2]; zval *zdata; SW_MAKE_STD_ZVAL(zdata); SW_ZVAL_STRINGL(zdata, ps->buffer->str, ps->buffer->length, 1); SwooleG.main_reactor->del(SwooleG.main_reactor, ps->fd); swString_free(ps->buffer); args[0] = &zdata; int status; zval *zstatus; SW_MAKE_STD_ZVAL(zstatus); pid_t pid = swWaitpid(ps->pid, &status, WNOHANG); if (pid > 0) { array_init(zstatus); add_assoc_long(zstatus, "code", WEXITSTATUS(status)); add_assoc_long(zstatus, "signal", WTERMSIG(status)); } else { ZVAL_FALSE(zstatus); } args[1] = &zstatus; zval *zcallback = ps->callback; 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"); } sw_zval_free(zcallback); } else { #ifdef SW_COROUTINE php_context *context = ps->context; sw_zval_add_ref(&zdata); add_assoc_zval(zstatus, "output", zdata); int ret = coro_resume(context, zstatus, &retval); if (ret == CORO_END && retval) { sw_zval_ptr_dtor(&retval); } efree(context); #else return SW_OK; #endif } if (EG(exception)) { zend_exception_error(EG(exception), E_ERROR TSRMLS_CC); } if (retval != NULL) { sw_zval_ptr_dtor(&retval); } sw_zval_ptr_dtor(&zdata); sw_zval_ptr_dtor(&zstatus); close(ps->fd); efree(ps); return SW_OK; }
static PHP_METHOD(swoole_coroutine_util, create) { zval *callback; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &callback) == FAILURE) { return; } sw_zval_add_ref(&callback); callback = sw_zval_dup(callback); char *func_name = NULL; zend_fcall_info_cache *func_cache = emalloc(sizeof(zend_fcall_info_cache)); if (!sw_zend_is_callable_ex(callback, NULL, 0, &func_name, NULL, func_cache, NULL TSRMLS_CC)) { swoole_php_fatal_error(E_ERROR, "Function '%s' is not callable", func_name); sw_zval_free(callback); efree(func_name); return; } efree(func_name); php_swoole_check_reactor(); if (swReactorCheckPoint == NULL) { coro_init(TSRMLS_C); } zval *retval = NULL; zval *args[1]; jmp_buf *prev_checkpoint = swReactorCheckPoint; swReactorCheckPoint = emalloc(sizeof(jmp_buf)); php_context *cxt = emalloc(sizeof(php_context)); coro_save(cxt); int ret = coro_create(func_cache, args, 0, &retval, NULL, NULL); efree(func_cache); efree(swReactorCheckPoint); if (ret < 0) { sw_zval_free(callback); RETURN_FALSE; } //save callback COROG.current_coro->function = callback; swReactorCheckPoint = prev_checkpoint; coro_resume_parent(cxt, retval, retval); efree(cxt); if (EG(exception)) { zend_exception_error(EG(exception), E_ERROR TSRMLS_CC); } if (retval != NULL) { sw_zval_ptr_dtor(&retval); } RETURN_TRUE; }
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 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)) { swoole_php_fatal_error(E_ERROR, "cannot use swoole_process::signal here."); RETURN_FALSE; } if (SwooleGS->start && (swIsWorker() || swIsMaster() || swIsManager() || swIsTaskWorker())) { if (signo == SIGTERM || signo == SIGALRM) { swoole_php_fatal_error(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); #if PHP_MAJOR_VERSION >= 7 zval *tmp = emalloc(sizeof(zval)); memcpy(tmp, callback, sizeof(zval)); callback = tmp; #endif 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; }