[BUG] Handle badly lagging client conns decently.
This commit is contained in:
parent
fa0c70539b
commit
7546daa276
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue