aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2008-10-15 18:21:45 +0200
committerMax Kellermann <max@duempel.org>2008-10-15 18:21:45 +0200
commit6eb62e476195db373c3c1ac05de4fa2adc6ff661 (patch)
tree3ac21994e8b37aed946a2bf8de7b6e71568452a8 /src
parent0031eaaff50ee3b9e9c9e59a7d72743d6674e0ae (diff)
downloadmpd-6eb62e476195db373c3c1ac05de4fa2adc6ff661.tar.gz
mpd-6eb62e476195db373c3c1ac05de4fa2adc6ff661.tar.xz
mpd-6eb62e476195db373c3c1ac05de4fa2adc6ff661.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/client.c82
1 files changed, 44 insertions, 38 deletions
diff --git a/src/client.c b/src/client.c
index 1dcec5af2..48189992c 100644
--- a/src/client.c
+++ b/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;