Skip to content
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

C++ Client implementation CRASHING in iOS #1766

Open
pedroalfonsoo opened this issue Apr 28, 2024 · 0 comments
Open

C++ Client implementation CRASHING in iOS #1766

pedroalfonsoo opened this issue Apr 28, 2024 · 0 comments

Comments

@pedroalfonsoo
Copy link

pedroalfonsoo commented Apr 28, 2024

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant