Concurrent Connections Don't Require Threads?

Hi All! I’m confused about Stage #EJ5.

I was able to complete the stage and get all my tests passing without using threads. I’m a bit baffled by this because I assumed threads were required. I feel like I’m getting false positives. If someone could clarify why my tests are passing and if my implementation is actually okay, I would really appreciate it!

All I did was wrap my connection logic in a while loop to continuously accept connections. Below is all my code.

void handle_connection(int client_fd)
{
	char request[1024];
	char response[1024];
	read(client_fd, request, sizeof(request));

	// passing null starts from strtok static pointer to previous token
	char *request_target = strtok(request, " ");
	request_target = strtok(NULL, " ");

	if (strcmp(request_target, "/") == 0)
	{
		send(client_fd, "HTTP/1.1 200 OK\r\n\r\n", 23, 0);
	}
	else if (strncmp(request_target, "/echo", 5) == 0)
	{
		int content_length = strlen(request_target + 6);
		sprintf(
			response,
			"HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %d\r\n\r\n%s",
			content_length,
			request_target + 6);
		send(client_fd, response, strlen(response), 0);
	}
	else if (strncmp(request_target, "/user-agent", 11) == 0)
	{
		char *token = strtok(NULL, "\r\n");
		while (strncmp(token, "User-Agent", 10) != 0)
		{
			token = strtok(NULL, "\r\n");
		}
		char *user_agent = strchr(token, ':') + 2;
		int content_length = strlen(user_agent);
		sprintf(
			response,
			"HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %d\r\n\r\n%s",
			content_length,
			user_agent);
		send(client_fd, response, strlen(response), 0);
	}
	else
	{
		send(client_fd, "HTTP/1.1 404 Not Found\r\n\r\n", 30, 0);
	}
}

int main()
{
	// Disable output buffering
	setbuf(stdout, NULL);
	setbuf(stderr, NULL);

	// You can use print statements as follows for debugging, they'll be visible when running tests.
	printf("Logs from your program will appear here!\n");

	int server_fd, client_addr_len;
	struct sockaddr_in client_addr;

	server_fd = socket(AF_INET, SOCK_STREAM, 0);
	if (server_fd == -1)
	{
		printf("Socket creation failed: %s...\n", strerror(errno));
		return 1;
	}

	// Since the tester restarts your program quite often, setting SO_REUSEADDR
	// ensures that we don't run into 'Address already in use' errors
	int reuse = 1;
	if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
	{
		printf("SO_REUSEADDR failed: %s \n", strerror(errno));
		return 1;
	}

	struct sockaddr_in serv_addr = {
		.sin_family = AF_INET,
		.sin_port = htons(4221),
		.sin_addr = {htonl(INADDR_ANY)},
	};

	if (bind(server_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) != 0)
	{
		printf("Bind failed: %s \n", strerror(errno));
		return 1;
	}

	int connection_backlog = 5;
	if (listen(server_fd, connection_backlog) != 0)
	{
		printf("Listen failed: %s \n", strerror(errno));
		return 1;
	}

	client_addr_len = sizeof(client_addr);

	for (;;)
	{
		printf("Waiting for a client to connect...\n");
		int client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_addr_len);
		printf("Client connected\n");
		handle_connection(client_fd);
		//pthread_t t;
	}
	
	close(server_fd);
	return 0;
}

Thanks so much!

While you don’t need threads to pass the stage as you could do a non blocking polling approach where you handle all connections simultaneously, that is not what you are doing so it seems strange your code passes.

Agreed! Super strange.

Weird indeed… One of us will look into this next week! We did make some changes to that test recently (CC-1306: Add test for server closure once all connections shut down by ryan-gang · Pull Request #58 · codecrafters-io/http-server-tester · GitHub), could be related.

This is now fixed!

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.