- 论坛徽章:
- 0
|
怀疑Lighttpd1.4.18一个bug
在connections.c文件中connection_handle_fdevent函数的line 3有这么一行:
joblist_append(srv, con);把该链接加入joblist中。
在该函数中还有这么一段:
if (con->state == CON_STATE_WRITE &&
!chunkqueue_is_empty(con->write_queue) &&
con->is_writable) {
if (-1 == connection_handle_write(srv, con)) {
connection_set_state(srv, con, CON_STATE_ERROR);
log_error_write(srv, __FILE__, __LINE__, "ds",
con->fd,
"handle write failed.");
} else if (con->state == CON_STATE_WRITE) {
con->write_request_ts = srv->cur_ts;
}
}
当当前状态为CON_STATE_WRITE并且输出队列非空,套接字可写时调用connection_handle_write,该函数代码:
static int connection_handle_write(server *srv, connection *con) {
switch(network_write_chunkqueue(srv, con, con->write_queue)) {
case 0:
if (con->file_finished) {
connection_set_state(srv, con, CON_STATE_RESPONSE_END);
joblist_append(srv, con);
}
break;
case -1: /* error on our side */
log_error_write(srv, __FILE__, __LINE__, "sd",
"connection closed: write failed on fd", con->fd);
connection_set_state(srv, con, CON_STATE_ERROR);
joblist_append(srv, con);
break;
case -2: /* remote close */
connection_set_state(srv, con, CON_STATE_ERROR);
joblist_append(srv, con);
break;
case 1:
con->is_writable = 0;
/* not finished yet -> WRITE */
break;
}
return 0;
}
再次调用joblist_append(srv, con);
int joblist_append(server *srv, connection *con) {
if (con->in_joblist) return 0;
if (srv->joblist->size == 0) {
srv->joblist->size = 16;
srv->joblist->ptr = malloc(sizeof(*srv->joblist->ptr) * srv->joblist->size);
} else if (srv->joblist->used == srv->joblist->size) {
srv->joblist->size += 16;
srv->joblist->ptr = realloc(srv->joblist->ptr, sizeof(*srv->joblist->ptr) * srv->joblist->size);
}
srv->joblist->ptr[srv->joblist->used++] = con;
return 0;
}
注意if (con->in_joblist) return 0; 整个项目源代码中并没有对con->in_joblist赋值为非0的地方,所以这个条件一直成立。也就是会有相同的con同时在joblist中。
导致下面这段代码,重复处理了相同的con。
for (ndx = 0; ndx < srv->joblist->used; ndx++) {
connection *con = srv->joblist->ptr[ndx];
handler_t r;
connection_state_machine(srv, con);
switch(r = plugins_call_handle_joblist(srv, con)) {
case HANDLER_FINISHED:
case HANDLER_GO_ON:
break;
default:
log_error_write(srv, __FILE__, __LINE__, "d", r);
break;
}
con->in_joblist = 0;
} |
|