Skip to content

[6.1] Accessing the same file descriptor from multiple coroutines is prohibited #5807

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 51 additions & 22 deletions ext-src/swoole_http_client_coro.cc
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ class Client {
bool in_callback = false;
bool has_upload_files = false;

std::shared_ptr<File> download_file; // save http response to file
zend::String download_file_name; // unlink the file on error
int download_file = 0; // save http response to file
zend::String download_file_name; // unlink the file on error
zend_long download_offset = 0;

/* safety zval */
Expand Down Expand Up @@ -366,6 +366,42 @@ static const zend_function_entry swoole_http_client_coro_methods[] =

// clang-format on

static inline int http_client_open_file(const char *pathname, int flags, mode_t mode) {
#ifdef SW_USE_IOURING
return swoole_coroutine_iouring_open(pathname, flags, mode);
#else
return swoole_coroutine_open(pathname, flags, mode);
#endif
}

static inline int http_client_close_file(int fd) {
#ifdef SW_USE_IOURING
return swoole_coroutine_iouring_close_file(fd);
#else
return swoole_coroutine_close_file(fd);
#endif
}

static inline int http_client_truncate_file(int fd, off_t length) {
return swoole_coroutine_ftruncate(fd, length);
}

static inline int http_client_lseek_file(int fd, off_t offset) {
#ifdef SW_USE_IOURING
return swoole_coroutine_iouring_lseek(fd, offset, SEEK_SET);
#else
return swoole_coroutine_lseek(fd, offset, SEEK_SET);
#endif
}

static inline ssize_t http_client_co_write(int sockfd, const void *buf, size_t count) {
#ifdef SW_USE_IOURING
return swoole_coroutine_iouring_write(sockfd, buf, count);
#else
return swoole_coroutine_write(sockfd, buf, count);
#endif
}

void php_swoole_http_parse_set_cookies(const char *at, size_t length, zval *zcookies, zval *zset_cookie_headers) {
const char *p, *eof = at + length;
size_t key_len = 0, value_len = 0;
Expand Down Expand Up @@ -486,14 +522,6 @@ static int http_parser_on_headers_complete(llhttp_t *parser) {
return 0;
}

static inline ssize_t http_client_co_write(int sockfd, const void *buf, size_t count) {
#ifdef SW_USE_IOURING
return swoole_coroutine_iouring_write(sockfd, buf, count);
#else
return swoole_coroutine_write(sockfd, buf, count);
#endif
}

static int http_parser_on_body(llhttp_t *parser, const char *at, size_t length) {
auto *http = static_cast<Client *>(parser->data);
if (http->write_func) {
Expand Down Expand Up @@ -523,28 +551,28 @@ static int http_parser_on_body(llhttp_t *parser, const char *at, size_t length)
}
}
if (http->download_file_name.get() && http->body->length > 0) {
if (http->download_file == nullptr) {
char *download_file_name = http->download_file_name.val();
std::shared_ptr<File> fp = std::make_shared<File>(download_file_name, O_CREAT | O_WRONLY, 0664);
if (!fp->ready()) {
if (http->download_file == 0) {
const char *download_file_name = http->download_file_name.val();
int fd = http_client_open_file(download_file_name, O_CREAT | O_WRONLY, 0664);
if (sw_unlikely(fd == -1)) {
swoole_sys_warning("open(%s, O_CREAT | O_WRONLY) failed", download_file_name);
return -1;
}

if (http->download_offset == 0) {
if (!fp->truncate(0)) {
if (http_client_truncate_file(fd, 0) < 0) {
swoole_sys_warning("ftruncate(%s) failed", download_file_name);
return -1;
}
} else {
if (!fp->set_offset(http->download_offset)) {
if (http_client_lseek_file(fd, http->download_offset) < 0) {
swoole_sys_warning("fseek(%s, %jd) failed", download_file_name, (intmax_t) http->download_offset);
return -1;
}
}
http->download_file = fp;
http->download_file = fd;
}
if (http_client_co_write(http->download_file->get_fd(), SW_STRINGL(http->body)) !=
(ssize_t) http->body->length) {
if (http_client_co_write(http->download_file, SW_STRINGL(http->body)) != (ssize_t) http->body->length) {
return -1;
}
http->body->clear();
Expand All @@ -564,7 +592,7 @@ static int http_parser_on_message_complete(llhttp_t *parser) {

zend_update_property_long(
swoole_http_client_coro_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("statusCode"), parser->status_code);
if (http->download_file == nullptr) {
if (http->download_file == 0) {
zend_update_property_stringl(
swoole_http_client_coro_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("body"), SW_STRINGL(http->body));
} else {
Expand Down Expand Up @@ -1651,8 +1679,9 @@ void Client::reset() {
if (has_upload_files) {
zend_update_property_null(swoole_http_client_coro_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("uploadFiles"));
}
if (download_file != nullptr) {
download_file.reset();
if (download_file != 0) {
http_client_close_file(download_file);
download_file = 0;
download_file_name.release();
download_offset = 0;
zend_update_property_null(swoole_http_client_coro_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("downloadFile"));
Expand Down
2 changes: 2 additions & 0 deletions include/swoole_coroutine_c_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ int swoole_coroutine_statvfs(const char *path, struct statvfs *buf);
int swoole_coroutine_close_file(int fd);
int swoole_coroutine_fsync(int fd);
int swoole_coroutine_fdatasync(int fd);
int swoole_coroutine_ftruncate(int fd, off_t length);
/**
* io_uring
*/
Expand All @@ -72,6 +73,7 @@ int swoole_coroutine_iouring_open(const char *pathname, int flags, mode_t mode);
int swoole_coroutine_iouring_close_file(int fd);
ssize_t swoole_coroutine_iouring_read(int sockfd, void *buf, size_t count);
ssize_t swoole_coroutine_iouring_write(int sockfd, const void *buf, size_t count);
off_t swoole_coroutine_iouring_lseek(int fd, off_t offset, int whence);
int swoole_coroutine_iouring_rename(const char *oldpath, const char *newpath);
int swoole_coroutine_iouring_mkdir(const char *pathname, mode_t mode);
int swoole_coroutine_iouring_unlink(const char *pathname);
Expand Down
4 changes: 3 additions & 1 deletion include/swoole_file_hook.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#define close_file(fd) swoole_coroutine_iouring_close_file(fd)
#define read(fd, buf, count) swoole_coroutine_iouring_read(fd, buf, count)
#define write(fd, buf, count) swoole_coroutine_iouring_write(fd, buf, count)
#define lseek(fd, offset, whence) swoole_coroutine_iouring_lseek(fd, offset, whence)
#define rename(oldpath, newpath) swoole_coroutine_iouring_rename(oldpath, newpath)
#define mkdir(pathname, mode) swoole_coroutine_iouring_mkdir(pathname, mode)
#define unlink(pathname) swoole_coroutine_iouring_unlink(pathname)
Expand All @@ -36,13 +37,14 @@
#define read(fd, buf, count) swoole_coroutine_read(fd, buf, count)
#define write(fd, buf, count) swoole_coroutine_write(fd, buf, count)
#define lseek(fd, offset, whence) swoole_coroutine_lseek(fd, offset, whence)
#define readlink(fd, buf, size) swoole_coroutine_readlink(fd, buf, size)
#define readlink(pathname, buf, size) swoole_coroutine_readlink(pathname, buf, size)
#define unlink(pathname) swoole_coroutine_unlink(pathname)
#define mkdir(pathname, mode) swoole_coroutine_mkdir(pathname, mode)
#define rmdir(pathname) swoole_coroutine_rmdir(pathname)
#define rename(oldpath, newpath) swoole_coroutine_rename(oldpath, newpath)
#define fsync(fd) swoole_coroutine_fsync(fd)
#define fdatasync(fd) swoole_coroutine_fdatasync(fd)
#define ftruncate(fd, length) swoole_coroutine_ftruncate(fd, length)
#endif

#ifdef HAVE_IOURING_STATX
Expand Down
Loading
Loading