Closed fredemmott closed 4 years ago
Can't land without getsockopt; unable to detect socket errors after await. This is showing up on linux test runs as the following code (attempting to connect to port 0):
#include <fcntl.h>
#include <unistd.h>
#include <stddef.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/errno.h>
int main() {
int sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = 0;
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
int opts = fcntl(sock, F_GETFL);
fcntl(sock, F_SETFL, opts | O_NONBLOCK);
if (connect(sock, (struct sockaddr*) &addr, sizeof(addr)) == -1) {
perror(NULL);
}
return 0;
}
#include <fcntl.h>
#include <unistd.h>
#include <stddef.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/errno.h>
#include <poll.h>
int main() {
int sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = 0;
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
int opts = fcntl(sock, F_GETFL);
fcntl(sock, F_SETFL, opts | O_NONBLOCK);
if (connect(sock, (struct sockaddr*) &addr, sizeof(addr)) == -1) {
perror("connect() failed");
}
// O_NONBLOCK are ready for write when connect succeeds
struct pollfd pollfd;
pollfd.fd = sock;
pollfd.events = POLLOUT;
poll(&pollfd, 1, 1000);
int sock_error;
socklen_t sock_error_size = sizeof(sock_error);
if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &sock_error, &sock_error_size) == -1) {
perror("getsockopt() failed");
}
errno = sock_error;
perror("socket error after poll");
return 0;
}
Linux:
connect() failed: Operation now in progress
socket error after poll: Connection refused
MacOS:
connect() failed: Can't assign requested address
socket error after poll: Undefined error: 0
Regressions to be fixed in later diffs:
Other changes:
OS\
Unix\
if there is no path, instead of empty string.Design decisions:
OS\
structs, e.g.sockaddr_un
, notUnixSocketAddress
, orSockAddrUn
UnixSocketAddress
would make the most sense for Hack best practices, but would be poor for discoverabilityOS\
already feels like writing C, but with Hack syntax. Every place where this differs feels jarring already.Future work (in follow-up diffs):
FIXME
s. This is all "add new native functions":OS\socket(OS\SocketDomain::PF_UNIX, OS\SocketType::SOCK_STREAM, 0)
; this also feels bad for discoverability. I plan on keeping the enums, but also addingconst MyEnum PF_UNIX = SocketDomain::PF_UNIX
to allowOS\socket(OS\PF_UNIX, OS\SOCK_STREAM, 0)
without losing the type safety