[BUG] Handle badly lagging client conns decently.

This commit is contained in:
Arnaud Cornet 2009-08-19 02:09:16 +02:00
parent fa0c70539b
commit 7546daa276
2 changed files with 46 additions and 33 deletions

View File

@ -232,46 +232,42 @@ static int _write_socket(connection_t *cn, char *message)
{ {
size_t size; size_t size;
size_t tcount = 0; size_t tcount = 0;
size_t p_tcount = 0;
ssize_t count; ssize_t count;
size = strlen(message); size = strlen(message);
do { do {
while ((count = write(cn->handle, count = write(cn->handle, ((const char *)message) + tcount,
((const char *)message) + tcount, size - tcount);
size - tcount)) > 0) { if (count > 0) {
tcount += count; tcount += count;
if (tcount == size) if (tcount == size)
break; break;
if (tcount - p_tcount == 0) {
/* no write at all, we give up */
cn->connected = CONN_ERROR;
return WRITE_ERROR;
}
p_tcount = tcount;
} }
} while (count < 0 && } while (count < 0 && errno == EINTR);
(errno == EAGAIN || errno == EINTR || errno == EINPROGRESS));
#if 0 #if 0
if (count <= 0 && tcount > 0) if (count <= 0 && tcount > 0)
fatal("shit happens errno:%d count:%d tcount:%d (%s)\n", errno, fatal("shit happens errno:%d count:%d tcount:%d (%s)\n", errno,
count, tcount, message); count, tcount, message);
#endif #endif
if (count <= 0) { if (tcount < size) {
/* /*
* if no fatal error, return WRITE_KEEP, which makes caller * if no fatal error, return WRITE_KEEP, which makes caller
* keep line in its FIFO * keep line in its FIFO
* *
* Cannot do: we might have written a partial line * Shitty: we might have written a partial line, so we hack the
* * line...
if (errno == EAGAIN || errno == EINTR || errno == EINPROGRESS) * callers of _write_socket muse provide a writable memspace
return WRITE_KEEP;
*/ */
if (count < 0 && (errno == EAGAIN || errno == EINPROGRESS)) {
memmove(message, message + tcount, size - tcount + 1);
return WRITE_KEEP;
}
if (cn_is_connected(cn)) { if (cn_is_connected(cn)) {
mylog(LOG_DEBUGVERB, "write(fd %d) : %s", cn->handle, mylog(LOG_DEBUGVERB, "write(fd %d) : %s", cn->handle,
strerror(errno)); strerror(errno));
connection_close(cn);
cn->connected = CONN_ERROR; cn->connected = CONN_ERROR;
} }
mylog(LOG_DEBUGVERB, "write : %s", strerror(errno)); mylog(LOG_DEBUGVERB, "write : %s", strerror(errno));
@ -301,7 +297,14 @@ static int real_write_all(connection_t *cn)
if (cn == NULL) if (cn == NULL)
fatal("real_write_all: wrong arguments"); fatal("real_write_all: wrong arguments");
while ((line = list_remove_first(cn->outgoing))) { if (cn->partial) {
line = cn->partial;
cn->partial = NULL;
} else {
line = list_remove_first(cn->outgoing);
}
do {
ret = write_socket(cn, line); ret = write_socket(cn, line);
switch (ret) { switch (ret) {
@ -311,7 +314,8 @@ static int real_write_all(connection_t *cn)
return 1; return 1;
case WRITE_KEEP: case WRITE_KEEP:
/* interrupted or not ready */ /* interrupted or not ready */
list_add_first(cn->outgoing, line); assert(cn->partial == NULL);
cn->partial = line;
return 0; return 0;
case WRITE_OK: case WRITE_OK:
free(line); free(line);
@ -324,26 +328,34 @@ static int real_write_all(connection_t *cn)
if (cn->anti_flood) if (cn->anti_flood)
/* one line at a time */ /* one line at a time */
break; break;
} } while ((line = list_remove_first(cn->outgoing)));
return 0; return 0;
} }
void write_line_fast(connection_t *cn, char *line) void write_line_fast(connection_t *cn, char *line)
{ {
int r; int r;
r = write_socket(cn, line); char *nline = bip_strdup(line);
switch (r) {
case WRITE_KEEP: if (cn->partial) {
list_add_first(cn->outgoing, bip_strdup(line)); list_add_first(cn->outgoing, nline);
break; } else {
case WRITE_ERROR: r = write_socket(cn, nline);
cn->connected = CONN_ERROR; switch (r) {
break; case WRITE_KEEP:
case WRITE_OK: list_add_first(cn->outgoing, nline);
break; break;
default: case WRITE_ERROR:
fatal("internal error 7"); cn->connected = CONN_ERROR;
break; free(nline);
break;
case WRITE_OK:
free(nline);
break;
default:
fatal("internal error 7");
break;
}
} }
} }

View File

@ -76,6 +76,7 @@ typedef struct connection {
char *incoming; char *incoming;
unsigned incoming_end; unsigned incoming_end;
list_t *outgoing; list_t *outgoing;
char *partial;
list_t *incoming_lines; list_t *incoming_lines;
void *user_data; void *user_data;
list_t *ip_list; list_t *ip_list;