hhvm / hsl-experimental

Experimental features for the Hack Standard Library
MIT License
23 stars 10 forks source link

Implement TCP and Unix sockets without using PHP resources #125

Closed fredemmott closed 4 years ago

fredemmott commented 4 years ago

Regressions to be fixed in later diffs:

Other changes:

Design decisions:

Future work (in follow-up diffs):

fredemmott commented 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;
}
fredemmott commented 4 years ago
#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