client: optimized client_input_received()
Use memchr() instead of manually traversing the input buffer. Update the client's properties after all commands have been processed. Check for buffer overflow once.
This commit is contained in:
		
							
								
								
									
										82
									
								
								src/client.c
									
									
									
									
									
								
							
							
						
						
									
										82
									
								
								src/client.c
									
									
									
									
									
								
							| @@ -341,10 +341,9 @@ void client_new(int fd, const struct sockaddr *addr) | ||||
| 	       sockaddr_to_tmp_string(addr)); | ||||
| } | ||||
|  | ||||
| static int client_process_line(struct client *client) | ||||
| static int client_process_line(struct client *client, char *line) | ||||
| { | ||||
| 	int ret = 1; | ||||
| 	char *line = client->buffer + client->bufferPos; | ||||
|  | ||||
| 	if (client->cmd_list_OK >= 0) { | ||||
| 		if (strcmp(line, CLIENT_LIST_MODE_END) == 0) { | ||||
| @@ -414,49 +413,56 @@ static int client_process_line(struct client *client) | ||||
|  | ||||
| static int client_input_received(struct client *client, int bytesRead) | ||||
| { | ||||
| 	char *start = client->buffer + client->bufferLength; | ||||
| 	char *end = start + bytesRead; | ||||
| 	char *newline, *next; | ||||
| 	int ret; | ||||
| 	char *buf_tail = &(client->buffer[client->bufferLength - 1]); | ||||
|  | ||||
| 	/* any input from the client makes it leave "idle" mode */ | ||||
| 	client->idle_waiting = false; | ||||
|  | ||||
| 	while (bytesRead > 0) { | ||||
| 		client->bufferLength++; | ||||
| 		bytesRead--; | ||||
| 		buf_tail++; | ||||
| 		if (*buf_tail == '\n') { | ||||
| 			*buf_tail = '\0'; | ||||
| 			if (client->bufferLength > client->bufferPos) { | ||||
| 				if (*(buf_tail - 1) == '\r') | ||||
| 					*(buf_tail - 1) = '\0'; | ||||
| 			} | ||||
| 			ret = client_process_line(client); | ||||
| 			if (ret == COMMAND_RETURN_KILL || | ||||
| 			    ret == COMMAND_RETURN_CLOSE) | ||||
| 				return ret; | ||||
| 			if (client_is_expired(client)) | ||||
| 				return COMMAND_RETURN_CLOSE; | ||||
| 	client->bufferLength += bytesRead; | ||||
|  | ||||
| 			client->bufferPos = client->bufferLength; | ||||
| 		} | ||||
| 		if (client->bufferLength == CLIENT_MAX_BUFFER_LENGTH) { | ||||
| 			if (client->bufferPos == 0) { | ||||
| 				ERROR("client %i: buffer overflow\n", | ||||
| 				      client->num); | ||||
| 				return COMMAND_RETURN_CLOSE; | ||||
| 			} | ||||
| 			if (client->cmd_list_OK >= 0 && | ||||
| 			    client->cmd_list && | ||||
| 			    !client->cmd_list_dup) | ||||
| 				cmd_list_clone(client); | ||||
| 			assert(client->bufferLength >= client->bufferPos | ||||
| 			       && "bufferLength >= bufferPos"); | ||||
| 			client->bufferLength -= client->bufferPos; | ||||
| 			memmove(client->buffer, | ||||
| 				client->buffer + client->bufferPos, | ||||
| 				client->bufferLength); | ||||
| 			client->bufferPos = 0; | ||||
| 	/* process all lines */ | ||||
| 	while ((newline = memchr(start, '\n', end - start)) != NULL) { | ||||
| 		next = newline + 1; | ||||
|  | ||||
| 		if (newline > start && newline[-1] == '\r') | ||||
| 			--newline; | ||||
| 		*newline = 0; | ||||
|  | ||||
| 		ret = client_process_line(client, start); | ||||
| 		if (ret == COMMAND_RETURN_KILL || | ||||
| 		    ret == COMMAND_RETURN_CLOSE) | ||||
| 			return ret; | ||||
| 		if (client_is_expired(client)) | ||||
| 			return COMMAND_RETURN_CLOSE; | ||||
|  | ||||
| 		start = next; | ||||
| 	} | ||||
|  | ||||
| 	/* mark consumed lines */ | ||||
| 	client->bufferPos = start - client->buffer; | ||||
|  | ||||
| 	/* if we're have reached the buffer's end, close the gab at | ||||
| 	   the beginning */ | ||||
| 	if (client->bufferLength == sizeof(client->buffer)) { | ||||
| 		if (client->bufferPos == 0) { | ||||
| 			ERROR("client %i: buffer overflow\n", | ||||
| 			      client->num); | ||||
| 			return COMMAND_RETURN_CLOSE; | ||||
| 		} | ||||
| 		if (client->cmd_list_OK >= 0 && | ||||
| 		    client->cmd_list && | ||||
| 		    !client->cmd_list_dup) | ||||
| 			cmd_list_clone(client); | ||||
| 		assert(client->bufferLength >= client->bufferPos | ||||
| 		       && "bufferLength >= bufferPos"); | ||||
| 		client->bufferLength -= client->bufferPos; | ||||
| 		memmove(client->buffer, | ||||
| 			client->buffer + client->bufferPos, | ||||
| 			client->bufferLength); | ||||
| 		client->bufferPos = 0; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Max Kellermann
					Max Kellermann