static int swReactorKqueue_del(swReactor *reactor, int fd) { swReactorKqueue *this = reactor->object; struct kevent e; int ret; swConnection *socket = swReactor_get(reactor, fd); if (socket->events & SW_EVENT_READ) { EV_SET(&e, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL); ret = kevent(this->epfd, &e, 1, NULL, 0, NULL); if (ret < 0) { swSysError("kqueue->del(%d, SW_EVENT_READ) failed.", fd); return SW_ERR; } } if (socket->events & SW_EVENT_WRITE) { EV_SET(&e, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); ret = kevent(this->epfd, &e, 1, NULL, 0, NULL); if (ret < 0) { swSysError("kqueue->del(%d, SW_EVENT_WRITE) failed.", fd); return SW_ERR; } } swTrace("[THREAD #%d]EP=%d|FD=%d", SwooleTG.id, this->epfd, fd); reactor->event_num = reactor->event_num <= 0 ? 0 : reactor->event_num - 1; swReactor_del(reactor, fd); return SW_OK; }
int swReactor_close(swReactor *reactor, int fd) { swConnection *socket = swReactor_get(reactor, fd); if (socket->out_buffer) { swBuffer_free(socket->out_buffer); socket->out_buffer = NULL; } if (socket->in_buffer) { swBuffer_free(socket->in_buffer); socket->in_buffer = NULL; } #ifdef SW_USE_OPENSSL if (socket->ssl) { swSSL_close(socket); } #endif bzero(socket, sizeof(swConnection)); return close(fd); }
static void co_socket_read(int fd, zend_long length, INTERNAL_FUNCTION_PARAMETERS) { php_swoole_check_reactor(); if (!swReactor_handle_isset(SwooleG.main_reactor, PHP_SWOOLE_FD_SOCKET)) { SwooleG.main_reactor->setHandle(SwooleG.main_reactor, PHP_SWOOLE_FD_CO_UTIL | SW_EVENT_READ, co_socket_onReadable); SwooleG.main_reactor->setHandle(SwooleG.main_reactor, PHP_SWOOLE_FD_CO_UTIL | SW_EVENT_WRITE, co_socket_onWritable); } if (SwooleG.main_reactor->add(SwooleG.main_reactor, fd, PHP_SWOOLE_FD_CO_UTIL | SW_EVENT_READ) < 0) { SwooleG.error = errno; RETURN_FALSE; } swConnection *_socket = swReactor_get(SwooleG.main_reactor, fd); util_socket *sock = emalloc(sizeof(util_socket)); bzero(sock, sizeof(util_socket)); _socket->object = sock; sock->fd = fd; sock->buf = zend_string_alloc(length + 1, 0); sock->nbytes = length <= 0 ? SW_BUFFER_SIZE_STD : length; sock->context.state = SW_CORO_CONTEXT_RUNNING; coro_save(&sock->context); coro_yield(); }
void swWorker_signal_handler(int signo) { switch (signo) { case SIGTERM: if (SwooleG.main_reactor) { SwooleG.main_reactor->running = 0; } else { SwooleG.running = 0; } break; case SIGALRM: swSystemTimer_signal_handler(SIGALRM); break; /** * for test */ case SIGVTALRM: swWarn("SIGVTALRM coming"); break; case SIGUSR1: if (SwooleG.main_reactor) { swWorker *worker = SwooleWG.worker; swWarn(" the worker %d get the signo", worker->pid); SwooleWG.reload = 1; SwooleWG.reload_count = 0; //删掉read管道 swConnection *socket = swReactor_get(SwooleG.main_reactor, worker->pipe_worker); if (socket->events & SW_EVENT_WRITE) { socket->events &= (~SW_EVENT_READ); if (SwooleG.main_reactor->set(SwooleG.main_reactor, worker->pipe_worker, socket->fdtype | socket->events) < 0) { swSysError("reactor->set(%d, SW_EVENT_READ) failed.", worker->pipe_worker); } } else { if (SwooleG.main_reactor->del(SwooleG.main_reactor, worker->pipe_worker) < 0) { swSysError("reactor->del(%d) failed.", worker->pipe_worker); } } } else { SwooleG.running = 0; } break; case SIGUSR2: break; default: break; } }
int swReactor_del(swReactor *reactor, int fd) { swConnection *socket = swReactor_get(reactor, fd); socket->events = 0; socket->removed = 1; return SW_OK; }
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_mysql, close) { 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; } zend_update_property_bool(swoole_mysql_class_entry_ptr, getThis(), ZEND_STRL("connected"), 0 TSRMLS_CC); SwooleG.main_reactor->del(SwooleG.main_reactor, client->fd); swConnection *socket = swReactor_get(SwooleG.main_reactor, client->fd); socket->object = NULL; zend_bool is_destroyed = client->cli->destroyed; //close the connection client->cli->close(client->cli); //release client object memory swClient_free(client->cli); efree(client->cli); client->cli = NULL; zval *retval = NULL; zval **args[1]; zval *object = getThis(); if (client->onClose) { args[0] = &object; if (sw_call_user_function_ex(EG(function_table), NULL, client->onClose, &retval, 1, args, 0, NULL TSRMLS_CC) != SUCCESS) { swoole_php_fatal_error(E_WARNING, "swoole_mysql onClose callback error."); } if (retval) { sw_zval_ptr_dtor(&retval); } } if (!is_destroyed) { sw_zval_ptr_dtor(&object); } }
int swReactor_add(swReactor *reactor, int fd, int fdtype) { assert (fd <= SwooleG.max_sockets); swConnection *socket = swReactor_get(reactor, fd); socket->fdtype = swReactor_fdtype(fdtype); socket->events = swReactor_events(fdtype); socket->removed = 0; swTraceLog(SW_TRACE_REACTOR, "fd=%d, type=%d, events=%d", fd, socket->socket_type, socket->events); return SW_OK; }
static void co_socket_write(int fd, char* str, size_t l_str, INTERNAL_FUNCTION_PARAMETERS) { int ret = write(fd, str, l_str); if (ret < 0) { if (errno == EAGAIN) { goto _yield; } SwooleG.error = errno; RETURN_FALSE; } else { RETURN_LONG(ret); } _yield: if (SwooleG.main_reactor->add(SwooleG.main_reactor, fd, PHP_SWOOLE_FD_SOCKET | SW_EVENT_WRITE) < 0) { SwooleG.error = errno; RETURN_FALSE; } swConnection *_socket = swReactor_get(SwooleG.main_reactor, fd); util_socket *sock = emalloc(sizeof(util_socket)); bzero(sock, sizeof(util_socket)); _socket->object = sock; php_context *context = &sock->context; context->state = SW_CORO_CONTEXT_RUNNING; context->private_data = str; sock->nbytes = l_str; coro_save(context); coro_yield(); }
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; }
/** * worker: send to client */ static int swFactoryProcess_finish(swFactory *factory, swSendData *resp) { int ret, sendn; swServer *serv = factory->ptr; int session_id = resp->info.fd; swConnection *conn; if (resp->info.type != SW_EVENT_CLOSE) { conn = swServer_connection_verify(serv, session_id); } else { conn = swServer_connection_verify_no_ssl(serv, session_id); } if (!conn) { swoole_error_log(SW_LOG_NOTICE, SW_ERROR_SESSION_NOT_EXIST, "connection[fd=%d] does not exists.", session_id); return SW_ERR; } else if ((conn->closed || conn->removed) && resp->info.type != SW_EVENT_CLOSE) { int _len = resp->length > 0 ? resp->length : resp->info.len; swoole_error_log(SW_LOG_NOTICE, SW_ERROR_SESSION_CLOSED, "send %d byte failed, because connection[fd=%d] is closed.", _len, session_id); return SW_ERR; } else if (conn->overflow) { swoole_error_log(SW_LOG_WARNING, SW_ERROR_OUTPUT_BUFFER_OVERFLOW, "send failed, connection[fd=%d] output buffer has been overflowed.", session_id); return SW_ERR; } swEventData ev_data; ev_data.info.fd = session_id; ev_data.info.type = resp->info.type; swWorker *worker = swServer_get_worker(serv, SwooleWG.id); /** * Big response, use shared memory */ if (resp->length > 0) { if (worker == NULL || worker->send_shm == NULL) { goto pack_data; } //worker process if (SwooleG.main_reactor) { int _pipe_fd = swWorker_get_send_pipe(serv, session_id, conn->from_id); swConnection *_pipe_socket = swReactor_get(SwooleG.main_reactor, _pipe_fd); //cannot use send_shm if (!swBuffer_empty(_pipe_socket->out_buffer)) { pack_data: if (swTaskWorker_large_pack(&ev_data, resp->data, resp->length) < 0) { return SW_ERR; } ev_data.info.from_fd = SW_RESPONSE_TMPFILE; goto send_to_reactor_thread; } } swPackage_response response; response.length = resp->length; response.worker_id = SwooleWG.id; ev_data.info.from_fd = SW_RESPONSE_SHM; ev_data.info.len = sizeof(response); memcpy(ev_data.data, &response, sizeof(response)); swTrace("[Worker] big response, length=%d|worker_id=%d", response.length, response.worker_id); worker->lock.lock(&worker->lock); memcpy(worker->send_shm, resp->data, resp->length); } else { //copy data memcpy(ev_data.data, resp->data, resp->info.len); ev_data.info.len = resp->info.len; ev_data.info.from_fd = SW_RESPONSE_SMALL; } send_to_reactor_thread: ev_data.info.from_id = conn->from_id; sendn = ev_data.info.len + sizeof(resp->info); swTrace("[Worker] send: sendn=%d|type=%d|content=%s", sendn, resp->info.type, resp->data); ret = swWorker_send2reactor(&ev_data, sendn, session_id); if (ret < 0) { swWarn("sendto to reactor failed. Error: %s [%d]", strerror(errno), errno); } return ret; }
static PHP_METHOD(swoole_mysql, __construct) { if (!mysql_request_buffer) { mysql_request_buffer = swString_new(SW_MYSQL_QUERY_INIT_SIZE); if (!mysql_request_buffer) { swoole_php_fatal_error(E_ERROR, "[1] swString_new(%d) failed.", SW_HTTP_RESPONSE_INIT_SIZE); RETURN_FALSE; } } char *unixsocket = NULL; zend_size_t unixsocket_len = 0; mysql_connector connector; connector.port = SW_MYSQL_DEFAULT_PORT; if (zend_parse_parameters(ZEND_NUM_ARGS()TSRMLS_CC, "ssss|ls", &connector.host, &connector.host_len, &connector.user, &connector.user_len, &connector.password, &connector.password_len, &connector.database, &connector.database_len, &connector.port, &unixsocket, &unixsocket_len) == FAILURE) { RETURN_FALSE; } swClient *cli = emalloc(sizeof(swClient)); int type = SW_SOCK_TCP; if (unixsocket) { type = SW_SOCK_UNIX_STREAM; connector.host = unixsocket; connector.host_len = unixsocket_len; } if (swClient_create(cli, type, 0) < 0) { zend_throw_exception(swoole_mysql_exception_class_entry, "swClient_create failed.", 1 TSRMLS_CC); RETURN_FALSE; } if (cli->connect(cli, connector.host, connector.port, SW_MYSQL_CONNECT_TIMEOUT, 0) < 0) { zend_throw_exception(swoole_mysql_exception_class_entry, "connect to mysql server[%s:%d] failed.", 2 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); } char buf[2048]; int n = cli->recv(cli, buf, sizeof(buf), 0); if (n < 0) { zend_throw_exception(swoole_mysql_exception_class_entry, "recvfrom mysql server failed.", 3 TSRMLS_CC); RETURN_FALSE; } if (mysql_handshake(&connector, buf, n) == SW_ERR) { zend_throw_exception(swoole_mysql_exception_class_entry, "handshake with mysql server failed.", 4 TSRMLS_CC); RETURN_FALSE; } if (cli->send(cli, connector.buf, connector.packet_length + 4, 0) < 0) { zend_throw_exception(swoole_mysql_exception_class_entry, "sendto mysql server failed.", 5 TSRMLS_CC); RETURN_FALSE; } if (cli->recv(cli, buf, sizeof(buf), 0) < 0) { zend_throw_exception(swoole_mysql_exception_class_entry, "recvfrom mysql server failed.", 6 TSRMLS_CC); RETURN_FALSE; } mysql_client *client = emalloc(sizeof(mysql_client)); bzero(client, sizeof(mysql_client)); 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); zend_update_property_bool(swoole_mysql_class_entry_ptr, getThis(), ZEND_STRL("connected"), 1 TSRMLS_CC); swoole_set_object(getThis(), client); php_swoole_check_reactor(); swSetNonBlock(cli->socket->fd); 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_ERROR, swoole_mysql_onError); } swConnection *socket = swReactor_get(SwooleG.main_reactor, cli->socket->fd); socket->active = 1; socket->object = client; }
int swReactor_write(swReactor *reactor, int fd, void *buf, int n) { int ret; swConnection *socket = swReactor_get(reactor, fd); swBuffer *buffer = socket->out_buffer; assert(fd > 2); if (socket->fd == 0) { socket->fd = fd; } if (swBuffer_empty(buffer)) { do_send: ret = swConnection_send(socket, buf, n, 0); if (ret > 0) { if (n == ret) { return ret; } else { buf += ret; n -= ret; goto do_buffer; } } #ifdef HAVE_KQUEUE else if (errno == EAGAIN || errno == ENOBUFS) #else else if (errno == EAGAIN) #endif { do_buffer: if (!socket->out_buffer) { buffer = swBuffer_new(sizeof(swEventData)); if (!buffer) { swWarn("create worker buffer failed."); return SW_ERR; } socket->out_buffer = buffer; } socket->events |= SW_EVENT_WRITE; if (socket->events & SW_EVENT_READ) { if (reactor->set(reactor, fd, socket->fdtype | socket->events) < 0) { swSysError("reactor->set(%d, SW_EVENT_WRITE) failed.", fd); } } else { if (reactor->add(reactor, fd, socket->fdtype | SW_EVENT_WRITE) < 0) { swSysError("reactor->add(%d, SW_EVENT_WRITE) failed.", fd); } } goto append_buffer; } else if (errno == EINTR) { goto do_send; } else { return SW_ERR; } } else {
static int swReactorPoll_wait(swReactor *reactor, struct timeval *timeo) { swReactorPoll *object = reactor->object; swEvent event; swReactor_handle handle; int ret, msec, i; if (reactor->timeout_msec == 0) { if (timeo == NULL) { reactor->timeout_msec = -1; } else { reactor->timeout_msec = timeo->tv_sec * 1000 + timeo->tv_usec / 1000; } } while (reactor->running > 0) { msec = reactor->timeout_msec; ret = poll(object->events, reactor->event_num, msec); if (ret < 0) { if (swReactor_error(reactor) < 0) { swWarn("poll error. Error: %s[%d]", strerror(errno), errno); } continue; } else if (ret == 0) { if (reactor->onTimeout != NULL) { reactor->onTimeout(reactor); } continue; } else { for (i = 0; i < reactor->event_num; i++) { event.fd = object->events[i].fd; event.from_id = reactor->id; event.type = object->fds[i].fdtype; event.socket = swReactor_get(reactor, event.fd); swTrace("Event: fd=%d|from_id=%d|type=%d", event.fd, reactor->id, object->fds[i].fdtype); //in if ((object->events[i].revents & POLLIN) && !event.socket->removed) { handle = swReactor_getHandle(reactor, SW_EVENT_READ, event.type); ret = handle(reactor, &event); if (ret < 0) { swWarn("poll[POLLIN] handler failed. fd=%d. Error: %s[%d]", event.fd, strerror(errno), errno); } } //out if ((object->events[i].revents & POLLOUT) && !event.socket->removed) { handle = swReactor_getHandle(reactor, SW_EVENT_WRITE, event.type); ret = handle(reactor, &event); if (ret < 0) { swWarn("poll[POLLOUT] handler failed. fd=%d. Error: %s[%d]", event.fd, strerror(errno), errno); } } //error if ((object->events[i].revents & (POLLHUP | POLLERR)) && !event.socket->removed) { //ignore ERR and HUP, because event is already processed at IN and OUT handler. if ((object->events[i].revents & POLLIN) || (object->events[i].revents & POLLOUT)) { continue; } handle = swReactor_getHandle(reactor, SW_EVENT_ERROR, event.type); ret = handle(reactor, &event); if (ret < 0) { swWarn("poll[POLLERR] handler failed. fd=%d. Error: %s[%d]", event.fd, strerror(errno), errno); } } } if (reactor->onFinish != NULL) { reactor->onFinish(reactor); } } } 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; }
/** * worker main loop */ int swWorker_loop(swFactory *factory, int worker_id) { swServer *serv = factory->ptr; #ifndef SW_WORKER_USE_SIGNALFD SwooleG.use_signalfd = 0; #elif defined(HAVE_SIGNALFD) SwooleG.use_signalfd = 1; #endif //timerfd #ifdef HAVE_TIMERFD SwooleG.use_timerfd = 1; #endif //worker_id SwooleWG.id = worker_id; SwooleWG.request_count = 0; SwooleG.pid = getpid(); //signal init swWorker_signal_init(); swWorker *worker = swServer_get_worker(serv, worker_id); swServer_worker_init(serv, worker); SwooleG.main_reactor = sw_malloc(sizeof(swReactor)); if (SwooleG.main_reactor == NULL) { swError("[Worker] malloc for reactor failed."); return SW_ERR; } if (swReactor_create(SwooleG.main_reactor, SW_REACTOR_MAXEVENTS) < 0) { swError("[Worker] create worker_reactor failed."); return SW_ERR; } serv->workers[worker_id].status = SW_WORKER_IDLE; int pipe_worker = serv->workers[worker_id].pipe_worker; swSetNonBlock(pipe_worker); SwooleG.main_reactor->ptr = serv; SwooleG.main_reactor->add(SwooleG.main_reactor, pipe_worker, SW_FD_PIPE | SW_EVENT_READ); SwooleG.main_reactor->setHandle(SwooleG.main_reactor, SW_FD_PIPE, swWorker_onPipeReceive); SwooleG.main_reactor->setHandle(SwooleG.main_reactor, SW_FD_PIPE | SW_FD_WRITE, swReactor_onWrite); /** * set pipe buffer size */ int i; swConnection *pipe_socket; for (i = 0; i < serv->worker_num + SwooleG.task_worker_num; i++) { worker = swServer_get_worker(serv, i); pipe_socket = swReactor_get(SwooleG.main_reactor, worker->pipe_master); pipe_socket->buffer_size = serv->pipe_buffer_size; pipe_socket = swReactor_get(SwooleG.main_reactor, worker->pipe_worker); pipe_socket->buffer_size = serv->pipe_buffer_size; } swWorker_onStart(serv); #ifdef HAVE_SIGNALFD if (SwooleG.use_signalfd) { swSignalfd_setup(SwooleG.main_reactor); } #endif //main loop SwooleG.main_reactor->wait(SwooleG.main_reactor, NULL); //clear pipe buffer swWorker_clean(); //worker shutdown swWorker_onStop(serv); return SW_OK; }
int swClient_create(swClient *cli, int type, int async) { int _domain; int _type; bzero(cli, sizeof(*cli)); switch (type) { case SW_SOCK_TCP: _domain = AF_INET; _type = SOCK_STREAM; break; case SW_SOCK_TCP6: _domain = AF_INET6; _type = SOCK_STREAM; break; case SW_SOCK_UNIX_STREAM: _domain = AF_UNIX; _type = SOCK_STREAM; break; case SW_SOCK_UDP: _domain = AF_INET; _type = SOCK_DGRAM; break; case SW_SOCK_UDP6: _domain = AF_INET6; _type = SOCK_DGRAM; break; case SW_SOCK_UNIX_DGRAM: _domain = AF_UNIX; _type = SOCK_DGRAM; break; default: return SW_ERR; } int sockfd = socket(_domain, _type, 0); if (sockfd < 0) { swWarn("socket() failed. Error: %s[%d]", strerror(errno), errno); return SW_ERR; } if (async) { cli->socket = swReactor_get(SwooleG.main_reactor, sockfd); } else { cli->socket = sw_malloc(sizeof(swConnection)); } if (!cli->socket) { swWarn("malloc(%d) failed.", (int ) sizeof(swConnection)); return SW_ERR; } bzero(cli->socket, sizeof(swConnection)); cli->socket->fd = sockfd; if (type == SW_SOCK_TCP || type == SW_SOCK_TCP6 || type == SW_SOCK_UNIX_STREAM) { cli->connect = swClient_tcp_connect; cli->recv = swClient_tcp_recv_no_buffer; if (async) { cli->send = swClient_tcp_send_async; cli->sendfile = swClient_tcp_sendfile_async; } else { cli->send = swClient_tcp_send_sync; cli->sendfile = swClient_tcp_sendfile_sync; } } else { cli->connect = swClient_udp_connect; cli->recv = swClient_udp_recv; cli->send = swClient_udp_send; } cli->close = swClient_close; cli->sock_domain = _domain; cli->sock_type = SOCK_DGRAM; cli->type = type; cli->async = async; 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, "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 swReactorKqueue_wait(swReactor *reactor, struct timeval *timeo) { swEvent event; swFd fd_; swReactorKqueue *object = reactor->object; swReactor_handle handle; int i, n, ret; struct timespec t; struct timespec *t_ptr; bzero(&t, sizeof(t)); if (reactor->timeout_msec == 0) { if (timeo == NULL) { reactor->timeout_msec = -1; } else { reactor->timeout_msec = timeo->tv_sec * 1000 + timeo->tv_usec / 1000; } } reactor->start = 1; while (reactor->running > 0) { if (reactor->onBegin != NULL) { reactor->onBegin(reactor); } if (reactor->timeout_msec > 0) { t.tv_sec = reactor->timeout_msec / 1000; t.tv_nsec = (reactor->timeout_msec - t.tv_sec * 1000) * 1000; t_ptr = &t; } else { t_ptr = NULL; } n = kevent(object->epfd, NULL, 0, object->events, object->event_max, t_ptr); if (n < 0) { swTrace("kqueue error.EP=%d | Errno=%d\n", object->epfd, errno); if (swReactor_error(reactor) < 0) { swWarn("Kqueue[#%d] Error: %s[%d]", reactor->id, strerror(errno), errno); return SW_ERR; } else { continue; } } else if (n == 0) { if (reactor->onTimeout != NULL) { reactor->onTimeout(reactor); } continue; } for (i = 0; i < n; i++) { swTrace("n %d events.", n); if (object->events[i].udata) { memcpy(&fd_, &(object->events[i].udata), sizeof(fd_)); event.fd = fd_.fd; event.from_id = reactor->id; event.type = fd_.fdtype; event.socket = swReactor_get(reactor, event.fd); //read if (object->events[i].filter == EVFILT_READ) { if (event.socket->removed) { continue; } handle = swReactor_getHandle(reactor, SW_EVENT_READ, event.type); ret = handle(reactor, &event); if (ret < 0) { swSysError("kqueue event read socket#%d handler failed.", event.fd); } } //write else if (object->events[i].filter == EVFILT_WRITE) { if (event.socket->removed) { continue; } handle = swReactor_getHandle(reactor, SW_EVENT_WRITE, event.type); ret = handle(reactor, &event); if (ret < 0) { swSysError("kqueue event write socket#%d handler failed.", event.fd); } } else { swWarn("unknown event filter[%d].", object->events[i].filter); } } } if (reactor->onFinish != NULL) { reactor->onFinish(reactor); } if (reactor->once) { break; } } return 0; }
void swReactor_set(swReactor *reactor, int fd, int fdtype) { swConnection *socket = swReactor_get(reactor, fd); socket->events = swReactor_events(fdtype); }
int swClient_create(swClient *cli, int type, int async) { int _domain; int _type; bzero(cli, sizeof(*cli)); switch (type) { case SW_SOCK_TCP: _domain = AF_INET; _type = SOCK_STREAM; break; case SW_SOCK_TCP6: _domain = AF_INET6; _type = SOCK_STREAM; break; case SW_SOCK_UNIX_STREAM: _domain = AF_UNIX; _type = SOCK_STREAM; break; case SW_SOCK_UDP: _domain = AF_INET; _type = SOCK_DGRAM; break; case SW_SOCK_UDP6: _domain = AF_INET6; _type = SOCK_DGRAM; break; case SW_SOCK_UNIX_DGRAM: _domain = AF_UNIX; _type = SOCK_DGRAM; break; default: return SW_ERR; } int sockfd = socket(_domain, _type, 0); if (sockfd < 0) { swWarn("socket() failed. Error: %s[%d]", strerror(errno), errno); return SW_ERR; } if (async) { cli->socket = swReactor_get(SwooleG.main_reactor, sockfd); } else { cli->socket = sw_malloc(sizeof(swConnection)); } cli->buffer_input_size = SW_CLIENT_BUFFER_SIZE; if (!cli->socket) { swWarn("malloc(%d) failed.", (int ) sizeof(swConnection)); return SW_ERR; } bzero(cli->socket, sizeof(swConnection)); cli->socket->fd = sockfd; cli->socket->object = cli; if (async) { swSetNonBlock(cli->socket->fd); if (isset_event_handle == 0) { SwooleG.main_reactor->setHandle(SwooleG.main_reactor, SW_FD_STREAM_CLIENT | SW_EVENT_READ, swClient_onStreamRead); SwooleG.main_reactor->setHandle(SwooleG.main_reactor, SW_FD_DGRAM_CLIENT | SW_EVENT_READ, swClient_onDgramRead); SwooleG.main_reactor->setHandle(SwooleG.main_reactor, SW_FD_STREAM_CLIENT | SW_EVENT_WRITE, swClient_onWrite); isset_event_handle = 1; } } if (swSocket_is_stream(type)) { cli->recv = swClient_tcp_recv_no_buffer; if (async) { cli->connect = swClient_tcp_connect_async; cli->send = swClient_tcp_send_async; cli->sendfile = swClient_tcp_sendfile_async; } else { cli->connect = swClient_tcp_connect_sync; cli->send = swClient_tcp_send_sync; cli->sendfile = swClient_tcp_sendfile_sync; } } else { cli->connect = swClient_udp_connect; cli->recv = swClient_udp_recv; cli->send = swClient_udp_send; } cli->_sock_domain = _domain; cli->_sock_type = _type; cli->close = swClient_close; cli->type = type; cli->async = async; return SW_OK; }
static int swReactorEpoll_wait(swReactor *reactor, struct timeval *timeo) { swEvent event; swReactorEpoll *object = reactor->object; swReactor_handle handle; int i, n, ret, msec; int reactor_id = reactor->id; int epoll_fd = object->epfd; int max_event_num = reactor->max_event_num; struct epoll_event *events = object->events; if (reactor->timeout_msec == 0) { if (timeo == NULL) { reactor->timeout_msec = -1; } else { reactor->timeout_msec = timeo->tv_sec * 1000 + timeo->tv_usec / 1000; } } while (SwooleG.running > 0) { msec = reactor->timeout_msec; n = epoll_wait(epoll_fd, events, max_event_num, msec); if (n < 0) { if (swReactor_error(reactor) < 0) { swWarn("[Reactor#%d] epoll_wait failed. Error: %s[%d]", reactor_id, strerror(errno), errno); return SW_ERR; } else { continue; } } else if (n == 0) { if (reactor->onTimeout != NULL) { reactor->onTimeout(reactor); } continue; } for (i = 0; i < n; i++) { event.fd = events[i].data.u64; event.from_id = reactor_id; event.type = events[i].data.u64 >> 32; event.socket = swReactor_get(reactor, event.fd); //read if (events[i].events & EPOLLIN) { //read handle = swReactor_getHandle(reactor, SW_EVENT_READ, event.type); ret = handle(reactor, &event); if (ret < 0) { swWarn("[Reactor#%d] epoll [EPOLLIN] handle failed. fd=%d. Error: %s[%d]", reactor_id, event.fd, strerror(errno), errno); } } //write if ((events[i].events & EPOLLOUT) && !event.socket->removed) { handle = swReactor_getHandle(reactor, SW_EVENT_WRITE, event.type); ret = handle(reactor, &event); if (ret < 0) { swWarn("[Reactor#%d] epoll [EPOLLOUT] handle failed. fd=%d. Error: %s[%d]", reactor_id, event.fd, strerror(errno), errno); } } //error #ifndef NO_EPOLLRDHUP if ((events[i].events & (EPOLLRDHUP | EPOLLERR | EPOLLHUP)) && !event.socket->removed) #else if ((events[i].events & (EPOLLERR | EPOLLHUP)) && !event.socket->removed) #endif { handle = swReactor_getHandle(reactor, SW_EVENT_ERROR, event.type); ret = handle(reactor, &event); if (ret < 0) { swWarn("[Reactor#%d] epoll [EPOLLERR] handle failed. fd=%d. Error: %s[%d]", reactor_id, event.fd, strerror(errno), errno); } } } if (reactor->onFinish != NULL) { reactor->onFinish(reactor); } } return 0; }