Skip to content

Implemented UserFile file descriptor casting. #4320

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

Closed
wants to merge 4 commits into from
Closed
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
2 changes: 1 addition & 1 deletion hphp/runtime/base/file.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ struct File : SweepableResourceData {
const String& o_getResourceName() const { return s_resource_name; }
virtual bool isInvalid() const { return m_closed; }

int fd() const { return m_fd;}
virtual int fd() const { return m_fd;}
bool valid() const { return m_fd >= 0;}
const std::string getName() const { return m_name;}

Expand Down
66 changes: 66 additions & 0 deletions hphp/runtime/base/user-file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ namespace HPHP {
#define PHP_LOCK_UN 3
#define PHP_LOCK_NB 4

/* coerce the stream into some other form */
/* cast as a stdio FILE * */
#define PHP_STREAM_AS_STDIO 0
/* cast as a POSIX fd or socketd */
#define PHP_STREAM_AS_FD 1
/* cast as a socketd */
#define PHP_STREAM_AS_SOCKETD 2
/* cast as fd/socket for select purposes */
#define PHP_STREAM_AS_FD_FOR_SELECT 3

StaticString s_stream_open("stream_open");
StaticString s_stream_close("stream_close");
StaticString s_stream_read("stream_read");
Expand All @@ -50,6 +60,7 @@ StaticString s_stream_truncate("stream_truncate");
StaticString s_stream_lock("stream_lock");
StaticString s_stream_stat("stream_stat");
StaticString s_stream_metadata("stream_metadata");
StaticString s_stream_cast("stream_cast");
StaticString s_url_stat("url_stat");
StaticString s_unlink("unlink");
StaticString s_rename("rename");
Expand All @@ -76,6 +87,7 @@ UserFile::UserFile(Class *cls, const Variant& context /*= null */) : UserFSNode(
m_Mkdir = lookupMethod(s_mkdir.get());
m_Rmdir = lookupMethod(s_rmdir.get());
m_StreamMetadata = lookupMethod(s_stream_metadata.get());
m_StreamCast = lookupMethod(s_stream_cast.get());

m_isLocal = true;

Expand All @@ -98,6 +110,60 @@ void UserFile::sweep() {

///////////////////////////////////////////////////////////////////////////////

Resource UserFile::invokeCast(int castas) {
bool invoked = false;
Variant ret = invoke(
m_StreamCast,
s_stream_cast,
PackedArrayInit(1)
.append(castas)
.toArray(),
invoked
);

if (!invoked) {
raise_warning(
"%s::stream_cast is not implemented!",
m_cls->name()->data()
);
return Resource();
}
if (ret.toBoolean() == false) {
return Resource();
}
Resource handle = ret.toResource();
File *f = handle.getTyped<File>(true, true);
if (!f) {
raise_warning(
"%s::stream_cast must return a stream resource",
m_cls->name()->data()
);
return Resource();
}
if (f == this) {
raise_warning(
"%s::stream_cast must not return itself",
m_cls->name()->data()
);
return Resource();
}

return handle;
}

int UserFile::fd() const {
Resource handle = const_cast<UserFile*>(this)->invokeCast(
PHP_STREAM_AS_FD_FOR_SELECT);
if (handle.isNull()) {
raise_warning(
"cannot represent a stream of type user-space as a file descriptor"
);
return -1;
}
File *f = handle.getTyped<File>();
return f->fd();
}

///////////////////////////////////////////////////////////////////////////////

bool UserFile::openImpl(const String& filename, const String& mode,
Expand Down
4 changes: 4 additions & 0 deletions hphp/runtime/base/user-file.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ class UserFile : public File, public UserFSNode {
// overriding ResourceData
const String& o_getClassNameHook() const { return classnameof(); }

virtual int fd() const;

virtual bool open(const String& filename, const String& mode) {
return openImpl(filename, mode, 0);
}
Expand Down Expand Up @@ -74,6 +76,7 @@ class UserFile : public File, public UserFSNode {
int urlStat(const String& path, struct stat* stat_sb, int flags = 0);
bool flushImpl(bool strict);
bool invokeMetadata(const Array& args, const char* funcName);
Resource invokeCast(int castas);

protected:
const Func* m_StreamOpen;
Expand All @@ -88,6 +91,7 @@ class UserFile : public File, public UserFSNode {
const Func* m_StreamLock;
const Func* m_StreamStat;
const Func* m_StreamMetadata;
const Func* m_StreamCast;
const Func* m_UrlStat;
const Func* m_Unlink;
const Func* m_Rename;
Expand Down
11 changes: 10 additions & 1 deletion hphp/runtime/ext/sockets/ext_sockets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,12 @@ static void sock_array_to_fd_set(const Array& sockets, pollfd *fds, int &nfds,
assert(fds);
for (ArrayIter iter(sockets); iter; ++iter) {
File *sock = iter.second().toResource().getTyped<File>();
int intfd = sock->fd();
if (intfd < 0) {
continue;
}
pollfd &fd = fds[nfds++];
fd.fd = sock->fd();
fd.fd = intfd;
fd.events = flag;
fd.revents = 0;
}
Expand Down Expand Up @@ -849,6 +853,11 @@ Variant HHVM_FUNCTION(socket_select,
if (!except.isNull()) {
sock_array_to_fd_set(except.toArray(), fds, count, POLLPRI);
}
if (!count) {
raise_warning("no resource arrays were passed to select");
free(fds);
return false;
}

IOStatusHelper io("socket_select");
int timeout_ms = -1;
Expand Down
2 changes: 1 addition & 1 deletion hphp/test/frameworks/results/vfsstream.expect
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,7 @@ org\bovigo\vfs\vfsStreamWrapperQuotaTestCase::writeMoreThanQotaWritesOnlyUpToQuo
org\bovigo\vfs\vfsStreamWrapperQuotaTestCase::writeUpToQotaWritesEverything
.
org\bovigo\vfs\vfsStreamWrapperSelectStreamTestCase::selectStream
F
.
org\bovigo\vfs\vfsStreamWrapperSetOptionTestCase::removeBlockingDoesNotWork
.
org\bovigo\vfs\vfsStreamWrapperSetOptionTestCase::setBlockingDoesNotWork
Expand Down
2 changes: 0 additions & 2 deletions hphp/test/slow/streams/stream_wrapper_register.php
Original file line number Diff line number Diff line change
Expand Up @@ -159,12 +159,10 @@ public function url_stat($path, $flags) {
feof($fp);
fread($fp, 1);

/** We don't have anything like stream_cast
$r = array($fp);
$w = null;
$e = null;
stream_select($r, $w, $e, 0);
*/

fflush($fp);
flock($fp, LOCK_SH);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@ array(1) {
[0]=>
int(8192)
}
string(11) "stream_cast"
array(1) {
[0]=>
int(3)
}

Warning: cannot represent a stream of type user-space as a file descriptor in %s/test/slow/streams/stream_wrapper_register.php on line %d

Warning: no resource arrays were passed to select in %s/test/slow/streams/stream_wrapper_register.php on line %d
string(12) "stream_flush"
array(0) {
}
Expand Down