cloudflare / quiche

🥧 Savoury implementation of the QUIC transport protocol and HTTP/3

Home Page:https://docs.quic.tech/quiche/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

C++ Client implementation CRASHING in iOS

pedroalfonsoo opened this issue · comments

Hi quiche team:

We are trying to implement a simple client logic in iOS, but we are getting a crash when the configuration line is being executed (using Xcode 15.3):

quiche_config *config = quiche_config_new(0xbabababa);

Screenshot 2024-04-28 at 10 11 18 AM

Please have the entire client logic:

- (int)startStreaming {
    const char *host = "192.168.1.65";
    const char *port = "8085";

    const struct addrinfo hints = {.ai_family = PF_UNSPEC,
                                   .ai_socktype = SOCK_DGRAM,
                                   .ai_protocol = IPPROTO_UDP};

    quiche_enable_debug_logging(Helper::debug_log, NULL);

    struct addrinfo *peer;
    if (getaddrinfo(host, port, &hints, &peer) != 0) {
      perror("failed to resolve host");
      return -1;
    }

    int sock = socket(peer->ai_family, SOCK_DGRAM, 0);
    if (sock < 0) {
      perror("failed to create socket");
      return -1;
    }

    if (fcntl(sock, F_SETFL, O_NONBLOCK) != 0) {
      perror("failed to make socket non-blocking");
      return -1;
    }

    quiche_config *config = quiche_config_new(0xbabababa);
    if (config == NULL) {
      fprintf(stderr, "failed to create config\n");
      return -1;
    }

    quiche_config_set_application_protos(
        config, (uint8_t *)QUICHE_H3_APPLICATION_PROTOCOL,
        sizeof(QUICHE_H3_APPLICATION_PROTOCOL) - 1);

    quiche_config_set_max_idle_timeout(config, 5000);
    quiche_config_set_max_recv_udp_payload_size(config, MAX_DATAGRAM_SIZE);
    quiche_config_set_max_send_udp_payload_size(config, MAX_DATAGRAM_SIZE);
    quiche_config_set_initial_max_data(config, INT_MAX);
    quiche_config_set_initial_max_stream_data_bidi_local(config, INT_MAX);
    quiche_config_set_initial_max_stream_data_bidi_remote(config, INT_MAX);
    quiche_config_set_initial_max_stream_data_uni(config, INT_MAX);
    quiche_config_set_initial_max_streams_bidi(config, 100);
    quiche_config_set_initial_max_streams_uni(config, 100);
    quiche_config_set_disable_active_migration(config, true);
    quiche_config_set_initial_congestion_window_packets(config, 5000000);
    quiche_config_set_cc_algorithm(config, CC_ALGO);
    quiche_config_grease(config, true);

    if (getenv("SSLKEYLOGFILE")) {
      quiche_config_log_keys(config);
    }

    // ABC: old config creation here

    uint8_t scid[LOCAL_CONN_ID_LEN];
    int rng = open("/dev/urandom", O_RDONLY);
    if (rng < 0) {
      perror("failed to open /dev/urandom");
      return -1;
    }

    ssize_t rand_len = read(rng, &scid, sizeof(scid));
    if (rand_len < 0) {
      perror("failed to create connection ID");
      return -1;
    }

    struct client_conn_io *conn_io =
        (struct client_conn_io *)malloc(sizeof(*conn_io));
    if (conn_io == NULL) {
      fprintf(stderr, "failed to allocate connection IO\n");
      return -1;
    }

    conn_io->local_addr_len = sizeof(conn_io->local_addr);
    if (getsockname(sock, (struct sockaddr *)&conn_io->local_addr,
                    &conn_io->local_addr_len) != 0) {
      perror("failed to get local address of socket");
      return -1;
    };

    quiche_conn *conn = quiche_connect(host, (const uint8_t *)scid, sizeof(scid),
                                       (struct sockaddr *)&conn_io->local_addr,
                                       conn_io->local_addr_len, peer->ai_addr,
                                       peer->ai_addrlen, config);

    if (conn == NULL) {
      fprintf(stderr, "failed to create connection\n");
      return -1;
    }

    conn_io->sock = sock;
    conn_io->conn = conn;
    conn_io->host = host;

    while (true) {
        fd_set read_fds;
        FD_ZERO(&read_fds);
        FD_SET(sock, &read_fds);

        struct timeval timeout = {0, 0}; // No timeout

        int ready_fds = select(sock + 1, &read_fds, NULL, NULL, &timeout);
        if (ready_fds == -1) {
            perror("select");
            return -1;
        } else if (ready_fds > 0) {
            if (FD_ISSET(sock, &read_fds)) {
                printf("");
               // handle_receive(&conn_io);
            }
        }
    }

    freeaddrinfo(peer);
    close(sock);

    return 0;
}

Please also have the server logic:

int start(int argc, char *argv[]) {
  const char *host = "0.0.0.0"; // argv[1];
  const char *port = "8085";      // argv[2];

  const struct addrinfo hints = {.ai_family = PF_UNSPEC,
                                 .ai_socktype = SOCK_DGRAM,
                                 .ai_protocol = IPPROTO_UDP};

  quiche_enable_debug_logging(Helper::debug_log, NULL);

  struct addrinfo *local;
  if (getaddrinfo(host, port, &hints, &local) != 0) {
    perror("failed to resolve host");
    return -1;
  }

  int sock = socket(local->ai_family, SOCK_DGRAM, 0);
  if (sock < 0) {
    perror("failed to create socket");
    return -1;
  }

  if (fcntl(sock, F_SETFL, O_NONBLOCK) != 0) {
    perror("failed to make socket non-blocking");
    return -1;
  }

  if (bind(sock, local->ai_addr, local->ai_addrlen) < 0) {
    perror("failed to connect socket");
    return -1;
  }

  std::cout << "Socket connected to: " << &host[0] << " : " << &port[0]
            << std::endl;
  std::cout << "Local addr: " << &local->ai_addr->sa_data[0] << std::endl;
  server_info_ = new server_info();
  server_info_->config = quiche_config_new(QUICHE_PROTOCOL_VERSION);
  if (server_info_->config == NULL) {
    fprintf(stderr, "failed to create config\n");
    return -1;
  }

  quiche_config_load_cert_chain_from_pem_file(server_info_->config,
                                              "../cert.crt");
  quiche_config_load_priv_key_from_pem_file(server_info_->config,
                                            "../cert.key");

  quiche_config_set_application_protos(
      server_info_->config, (uint8_t *)QUICHE_H3_APPLICATION_PROTOCOL,
      sizeof(QUICHE_H3_APPLICATION_PROTOCOL) - 1);

  quiche_config_set_max_idle_timeout(server_info_->config, 5000);
  quiche_config_set_max_recv_udp_payload_size(server_info_->config,
                                              MAX_DATAGRAM_SIZE);
  quiche_config_set_max_send_udp_payload_size(server_info_->config,
                                              MAX_DATAGRAM_SIZE);
  quiche_config_set_initial_max_data(server_info_->config, INT_MAX);
  quiche_config_set_initial_max_stream_data_bidi_local(server_info_->config,
                                                       INT_MAX);
  quiche_config_set_initial_max_stream_data_bidi_remote(server_info_->config,
                                                        INT_MAX);
  quiche_config_set_initial_max_stream_data_uni(server_info_->config, INT_MAX);
  quiche_config_set_initial_max_streams_bidi(server_info_->config, 100);
  quiche_config_set_initial_max_streams_uni(server_info_->config, 100);
  quiche_config_set_disable_active_migration(server_info_->config, true);
  quiche_config_set_cc_algorithm(server_info_->config, QUICHE_CC_RENO);
  quiche_config_set_initial_congestion_window_packets(server_info_->config,
                                                      5000000);
  quiche_config_set_cc_algorithm(server_info_->config, CC_ALGO);
  quiche_config_grease(server_info_->config, true);

  server_info_->http3_config = quiche_h3_config_new();
  if (server_info_->http3_config == NULL) {
    fprintf(stderr, "failed to create HTTP/3 config\n");
    return -1;
  }
  std::cout << "Configuration created..." << std::endl;

  struct server_connections c;
  c.sock = sock;
  c.h = NULL;
  c.local_addr = local->ai_addr;
  c.local_addr_len = local->ai_addrlen;

  server_info_->conns = &c;
  std::cout << "Connection created..." << std::endl;

  ev_io watcher;

  struct ev_loop *loop = ev_default_loop(0);

  if (true) { // file streaming
    FileStreaming::set_server_info(*server_info_);
    ev_io_init(&watcher, FileStreaming::recv_cb, sock, EV_READ);

  } else { // sample
    ev_io_init(&watcher, recv_cb, sock, EV_READ);
  }

  ev_io_start(loop, &watcher);
  watcher.data = &c;

  ev_loop(loop, 0);

  std::cout << "Event loop exited..." << std::endl;

  freeaddrinfo(local);

  quiche_h3_config_free(server_info_->http3_config);

  quiche_config_free(server_info_->config);

  return 0;
}

Even though the debug logs are enabled, we can not see any on server/client side at all.

Also, the same logic executing from VS Code has no issues.

Thanks in advance.