C++ Client implementation CRASHING in iOS
pedroalfonsoo opened this issue · comments
pedroalfonsoo commented
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);
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.