static PHP_METHOD(swoole_coroutine_util, readFile) { coro_check(TSRMLS_C); char *filename = NULL; size_t l_filename = 0; #ifdef FAST_ZPP ZEND_PARSE_PARAMETERS_START(1, 2) Z_PARAM_STRING(filename, l_filename) ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); #else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &l_filename) == FAILURE) { return; } #endif swAio_event ev; bzero(&ev, sizeof(swAio_event)); php_context *context = emalloc(sizeof(php_context)); ev.type = SW_AIO_READ_FILE; ev.object = context; ev.handler = swAio_handler_read_file; ev.callback = aio_onReadFileCompleted; ev.req = estrndup(filename, l_filename); if (!SwooleAIO.init) { php_swoole_check_reactor(); swAio_init(); } swTrace("readFile(%s)", filename); int ret = swAio_dispatch(&ev); if (ret < 0) { efree(context); RETURN_FALSE; } context->state = SW_CORO_CONTEXT_RUNNING; coro_save(context); coro_yield(); }
static PHP_METHOD(swoole_coroutine_util, fgets) { coro_check(TSRMLS_C); zval *handle; php_stream *stream; #ifdef FAST_ZPP ZEND_PARSE_PARAMETERS_START(1, 2) Z_PARAM_RESOURCE(handle) ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); #else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &handle) == FAILURE) { return; } #endif int async; int fd = swoole_convert_to_fd_ex(handle, &async); if (fd < 0) { RETURN_FALSE; } if (async == 1) { swoole_php_fatal_error(E_WARNING, "only support file resources."); RETURN_FALSE; } swAio_event ev; bzero(&ev, sizeof(swAio_event)); php_stream_from_res(stream, Z_RES_P(handle)); if (stream->readbuf == NULL) { stream->readbuflen = stream->chunk_size; stream->readbuf = emalloc(stream->chunk_size); } ev.nbytes = stream->readbuflen; ev.buf = stream->readbuf; if (!ev.buf) { RETURN_FALSE; } php_context *context = emalloc(sizeof(php_context)); ev.flags = 0; ev.type = SW_AIO_STREAM_GET_LINE; ev.object = context; ev.callback = aio_onStreamGetLineCompleted; ev.handler = swAio_handler_stream_get_line; ev.fd = fd; ev.offset = stream->readpos; ev.req = (void *) (long) stream->writepos; if (!SwooleAIO.init) { php_swoole_check_reactor(); swAio_init(); } swTrace("fd=%d, offset=%jd, length=%ld", fd, (intmax_t) ev.offset, ev.nbytes); int ret = swAio_dispatch(&ev); if (ret < 0) { efree(context); RETURN_FALSE; } context->coro_params = *handle; context->state = SW_CORO_CONTEXT_RUNNING; coro_save(context); coro_yield(); }
static PHP_METHOD(swoole_coroutine_util, fread) { coro_check(TSRMLS_C); zval *handle; zend_long length = 0; #ifdef FAST_ZPP ZEND_PARSE_PARAMETERS_START(1, 2) Z_PARAM_RESOURCE(handle) Z_PARAM_OPTIONAL Z_PARAM_LONG(length) ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); #else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &handle, &length) == FAILURE) { return; } #endif int async; int fd = swoole_convert_to_fd_ex(handle, &async TSRMLS_CC); if (fd < 0) { RETURN_FALSE; } if (async) { co_socket_read(fd, length, INTERNAL_FUNCTION_PARAM_PASSTHRU); return; } struct stat file_stat; if (fstat(fd, &file_stat) < 0) { SwooleG.error = errno; RETURN_FALSE; } off_t _seek = lseek(fd, 0, SEEK_CUR); if (_seek < 0) { SwooleG.error = errno; RETURN_FALSE; } if (length <= 0 || file_stat.st_size - _seek < length) { length = file_stat.st_size - _seek; } swAio_event ev; bzero(&ev, sizeof(swAio_event)); ev.nbytes = length + 1; ev.buf = emalloc(ev.nbytes); if (!ev.buf) { RETURN_FALSE; } php_context *context = emalloc(sizeof(php_context)); ((char *) ev.buf)[length] = 0; ev.flags = 0; ev.type = SW_AIO_READ; ev.object = context; ev.handler = swAio_handler_read; ev.callback = aio_onReadCompleted; ev.fd = fd; ev.offset = _seek; if (!SwooleAIO.init) { php_swoole_check_reactor(); swAio_init(); } swTrace("fd=%d, offset=%jd, length=%ld", fd, (intmax_t) ev.offset, ev.nbytes); int ret = swAio_dispatch(&ev); if (ret < 0) { efree(context); RETURN_FALSE; } context->state = SW_CORO_CONTEXT_RUNNING; coro_save(context); coro_yield(); }
static PHP_METHOD(swoole_coroutine_util, getaddrinfo) { coro_check(TSRMLS_C); char *hostname; zend_size_t l_hostname; long family = AF_INET; long socktype = SOCK_STREAM; long protocol = IPPROTO_TCP; char *service = NULL; zend_size_t l_service = 0; if (zend_parse_parameters(ZEND_NUM_ARGS()TSRMLS_CC, "s|llls", &hostname, &l_hostname, &family, socktype, &protocol, &hostname, &l_hostname) == FAILURE) { RETURN_FALSE; } if (l_hostname <= 0) { swoole_php_fatal_error(E_WARNING, "hostname is empty."); RETURN_FALSE; } if (family != AF_INET && family != AF_INET6) { swoole_php_fatal_error(E_WARNING, "unknown protocol family, must be AF_INET or AF_INET6."); RETURN_FALSE; } swAio_event ev; bzero(&ev, sizeof(swAio_event)); swRequest_getaddrinfo *req = emalloc(sizeof(swRequest_getaddrinfo)); bzero(req, sizeof(swRequest_getaddrinfo)); php_context *sw_current_context = emalloc(sizeof(php_context)); ev.type = SW_AIO_GETADDRINFO; ev.object = sw_current_context; ev.handler = swAio_handler_getaddrinfo; ev.callback = coro_dns_onGetaddrinfoCompleted; ev.req = req; req->hostname = estrndup(hostname, l_hostname); req->family = family; req->socktype = socktype; req->protocol = protocol; if (service) { req->service = estrndup(service, l_service); } if (family == AF_INET) { req->result = ecalloc(SW_DNS_HOST_BUFFER_SIZE, sizeof(struct sockaddr_in)); } else { req->result = ecalloc(SW_DNS_HOST_BUFFER_SIZE, sizeof(struct sockaddr_in6)); } php_swoole_check_aio(); if (swAio_dispatch(&ev) < 0) { efree(ev.buf); RETURN_FALSE; } coro_save(sw_current_context); coro_yield(); }
static PHP_METHOD(swoole_coroutine_util, gethostbyname) { coro_check(TSRMLS_C); char *domain_name; zend_size_t l_domain_name; long family = AF_INET; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &domain_name, &l_domain_name, &family) == FAILURE) { RETURN_FALSE; } if (l_domain_name <= 0) { swoole_php_fatal_error(E_WARNING, "domain name is empty."); RETURN_FALSE; } if (family != AF_INET && family != AF_INET6) { swoole_php_fatal_error(E_WARNING, "unknown protocol family, must be AF_INET or AF_INET6."); RETURN_FALSE; } swAio_event ev; bzero(&ev, sizeof(swAio_event)); if (l_domain_name < SW_IP_MAX_LENGTH) { ev.nbytes = SW_IP_MAX_LENGTH; } else { ev.nbytes = l_domain_name + 1; } ev.buf = emalloc(ev.nbytes); if (!ev.buf) { swWarn("malloc failed."); RETURN_FALSE; } php_context *sw_current_context = emalloc(sizeof(php_context)); memcpy(ev.buf, domain_name, l_domain_name); ((char *) ev.buf)[l_domain_name] = 0; ev.flags = family; ev.type = SW_AIO_GETHOSTBYNAME; ev.object = sw_current_context; ev.handler = swAio_handler_gethostbyname; ev.callback = coro_dns_onResolveCompleted; php_swoole_check_aio(); if (swAio_dispatch(&ev) < 0) { efree(ev.buf); RETURN_FALSE; } coro_save(sw_current_context); coro_yield(); }
static PHP_METHOD(swoole_coroutine_util, writeFile) { coro_check(TSRMLS_C); char *filename = NULL; size_t l_filename = 0; char *data = NULL; size_t l_data = 0; zend_long flags = 0; #ifdef FAST_ZPP ZEND_PARSE_PARAMETERS_START(2, 3) Z_PARAM_STRING(filename, l_filename) Z_PARAM_STRING(data, l_data) Z_PARAM_OPTIONAL Z_PARAM_LONG(flags) ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); #else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|l", &filename, &l_filename, &data, &l_data, &flags) == FAILURE) { return; } #endif swAio_event ev; bzero(&ev, sizeof(swAio_event)); ev.nbytes = l_data; ev.buf = data; php_context *context = emalloc(sizeof(php_context)); ev.type = SW_AIO_WRITE_FILE; ev.object = context; ev.handler = swAio_handler_write_file; ev.callback = aio_onWriteFileCompleted; ev.req = estrndup(filename, l_filename); ev.flags = O_CREAT | O_WRONLY; if (flags & PHP_FILE_APPEND) { ev.flags |= O_APPEND; } else { ev.flags |= O_TRUNC; } if (!SwooleAIO.init) { php_swoole_check_reactor(); swAio_init(); } swTrace("writeFile(%s, %ld)", filename, ev.nbytes); int ret = swAio_dispatch(&ev); if (ret < 0) { efree(context); RETURN_FALSE; } context->state = SW_CORO_CONTEXT_RUNNING; coro_save(context); coro_yield(); }
static PHP_METHOD(swoole_coroutine_util, fwrite) { coro_check(TSRMLS_C); zval *handle; char *str; zend_size_t l_str; zend_long length = 0; #ifdef FAST_ZPP ZEND_PARSE_PARAMETERS_START(2, 3) Z_PARAM_RESOURCE(handle) Z_PARAM_STRING(str, l_str) Z_PARAM_OPTIONAL Z_PARAM_LONG(length) ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); #else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|l", &handle, &str, &l_str, &length) == FAILURE) { return; } #endif int async; int fd = swoole_convert_to_fd_ex(handle, &async TSRMLS_CC); if (fd < 0) { RETURN_FALSE; } if (async) { co_socket_write(fd, str, (length < 0 && length < l_str) ? length : l_str, INTERNAL_FUNCTION_PARAM_PASSTHRU); return; } off_t _seek = lseek(fd, 0, SEEK_CUR); if (_seek < 0) { SwooleG.error = errno; RETURN_FALSE; } if (length <= 0 || length > l_str) { length = l_str; } swAio_event ev; bzero(&ev, sizeof(swAio_event)); ev.nbytes = length; ev.buf = estrndup(str, length); if (!ev.buf) { RETURN_FALSE; } php_context *context = emalloc(sizeof(php_context)); ev.flags = 0; ev.type = SW_AIO_WRITE; ev.object = context; ev.handler = swAio_handler_write; ev.callback = aio_onWriteCompleted; ev.fd = fd; ev.offset = _seek; php_swoole_check_aio(); swTrace("fd=%d, offset=%jd, length=%ld", fd, (intmax_t) ev.offset, ev.nbytes); int ret = swAio_dispatch(&ev); if (ret < 0) { efree(context); RETURN_FALSE; } context->state = SW_CORO_CONTEXT_RUNNING; coro_save(context); coro_yield(); }
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); } }
static int swClient_tcp_connect_async(swClient *cli, char *host, int port, double timeout, int nonblock) { int ret; cli->timeout = timeout; if (!cli->buffer) { //alloc input memory buffer cli->buffer = swString_new(cli->buffer_input_size); if (!cli->buffer) { return SW_ERR; } } if (!(cli->onConnect && cli->onError && cli->onClose)) { swWarn("onConnect/onError/onClose callback have not set."); return SW_ERR; } if (cli->onBufferFull && cli->buffer_high_watermark == 0) { cli->buffer_high_watermark = cli->socket->buffer_size * 0.8; } if (swClient_inet_addr(cli, host, port) < 0) { return SW_ERR; } if (cli->wait_dns) { swAio_event ev; bzero(&ev, sizeof(swAio_event)); int len = strlen(cli->server_host); if (strlen(cli->server_host) < SW_IP_MAX_LENGTH) { ev.nbytes = SW_IP_MAX_LENGTH; } else { ev.nbytes = len + 1; } ev.buf = sw_malloc(ev.nbytes); if (!ev.buf) { swWarn("malloc failed."); return SW_ERR; } memcpy(ev.buf, cli->server_host, len); ((char *) ev.buf)[len] = 0; ev.flags = cli->_sock_domain; ev.type = SW_AIO_DNS_LOOKUP; ev.object = cli; ev.callback = swClient_onResolveCompleted; return swAio_dispatch(&ev); } while (1) { ret = connect(cli->socket->fd, (struct sockaddr *) &cli->server_addr.addr, cli->server_addr.len); if (ret < 0) { if (errno == EINTR) { continue; } SwooleG.error = errno; } break; } if ((ret < 0 && errno == EINPROGRESS) || ret == 0) { if (SwooleG.main_reactor->add(SwooleG.main_reactor, cli->socket->fd, cli->reactor_fdtype | SW_EVENT_WRITE) < 0) { return SW_ERR; } if (timeout > 0) { if (SwooleG.timer.fd == 0) { swTimer_init((int) (timeout * 1000)); } cli->timer = SwooleG.timer.add(&SwooleG.timer, (int) (timeout * 1000), 0, cli, swClient_onTimeout); } return SW_OK; } return ret; }