add a close wait state

Wait for clients to close the connection, then:

- create redirection.
- activate pending clients.

Do no refresh timeout while in close wait state.
master
tiptorrent development team 2021-09-10 17:06:35 +02:00
parent b7b410ddc2
commit d6dbb6c979
3 changed files with 27 additions and 9 deletions

View File

@ -107,6 +107,8 @@ static int tip_client_recv(struct tip_client *cli, int events)
return ret; return ret;
} }
static int tip_client_redirect_create(const struct tip_client *cli);
static void tip_client_read_cb(struct ev_loop *loop, struct ev_io *io, int events) static void tip_client_read_cb(struct ev_loop *loop, struct ev_io *io, int events)
{ {
struct tip_client *cli; struct tip_client *cli;
@ -115,9 +117,10 @@ static void tip_client_read_cb(struct ev_loop *loop, struct ev_io *io, int event
cli = container_of(io, struct tip_client, io); cli = container_of(io, struct tip_client, io);
ret = tip_client_recv(cli, events); ret = tip_client_recv(cli, events);
if (ret <= 0) if (ret < 0)
goto close; goto close;
if (cli->state != TIP_CLIENT_CLOSE_WAIT)
ev_timer_again(loop, &cli->timer); ev_timer_again(loop, &cli->timer);
cli->buf_len += ret; cli->buf_len += ret;
@ -167,12 +170,24 @@ static void tip_client_read_cb(struct ev_loop *loop, struct ev_io *io, int event
ev_io_set(&cli->io, tip_client_socket(cli), EV_READ | EV_WRITE); ev_io_set(&cli->io, tip_client_socket(cli), EV_READ | EV_WRITE);
ev_io_start(loop, &cli->io); ev_io_start(loop, &cli->io);
break; break;
case TIP_CLIENT_CLOSE_WAIT:
if (ret == 0) {
syslog(LOG_INFO, "client %s:%hu has closed the connection with us\n",
inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
goto shutdown;
}
syslog(LOG_ERR, "unexpected data from client %s:%hu while waiting to close\n",
inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
goto close;
default: default:
syslog(LOG_ERR, "unknown read state, critical internal error for %s:%hu\n", syslog(LOG_ERR, "unknown read state, critical internal error for %s:%hu\n",
inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port)); inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
goto close; goto close;
} }
return; return;
shutdown:
if (cli->size > FILE_SIZE_THRESHOLD)
tip_client_redirect_create(cli);
close: close:
ev_timer_stop(loop, &cli->timer); ev_timer_stop(loop, &cli->timer);
tip_client_release(loop, cli); tip_client_release(loop, cli);
@ -259,9 +274,12 @@ static void tip_client_write_cb(struct ev_loop *loop, struct ev_io *io, int even
break; break;
case TIP_CLIENT_PROCESSING_REQUEST_3: case TIP_CLIENT_PROCESSING_REQUEST_3:
ret = tip_client_state_process_payload_bulk(cli); ret = tip_client_state_process_payload_bulk(cli);
if (ret > 0) if (ret > 0) {
goto shutdown; /* entering TIP_CLIENT_CLOSE_WAIT state. */
else if (ret < 0) { ev_io_stop(loop, &cli->io);
ev_io_set(&cli->io, tip_client_socket(cli), EV_READ);
ev_io_start(loop, &cli->io);
} else if (ret < 0) {
syslog(LOG_ERR, "Failed to process HTTP request from %s:%hu\n", syslog(LOG_ERR, "Failed to process HTTP request from %s:%hu\n",
inet_ntoa(cli->addr.sin_addr), inet_ntoa(cli->addr.sin_addr),
ntohs(cli->addr.sin_port)); ntohs(cli->addr.sin_port));
@ -274,9 +292,6 @@ static void tip_client_write_cb(struct ev_loop *loop, struct ev_io *io, int even
goto close; goto close;
} }
return; return;
shutdown:
if (cli->size > FILE_SIZE_THRESHOLD)
tip_client_redirect_create(cli);
close: close:
ev_timer_stop(loop, &cli->timer); ev_timer_stop(loop, &cli->timer);
tip_client_release(loop, cli); tip_client_release(loop, cli);

View File

@ -23,6 +23,7 @@ enum tip_client_state {
TIP_CLIENT_PROCESSING_REQUEST, TIP_CLIENT_PROCESSING_REQUEST,
TIP_CLIENT_PROCESSING_REQUEST_2, TIP_CLIENT_PROCESSING_REQUEST_2,
TIP_CLIENT_PROCESSING_REQUEST_3, TIP_CLIENT_PROCESSING_REQUEST_3,
TIP_CLIENT_CLOSE_WAIT,
}; };
struct tip_client { struct tip_client {

View File

@ -148,8 +148,10 @@ int tip_client_state_process_payload_bulk(struct tip_client *cli)
{ {
sendfile(tip_client_socket(cli), cli->fd, &cli->offset, BLOCK); sendfile(tip_client_socket(cli), cli->fd, &cli->offset, BLOCK);
if (cli->offset >= cli->size) if (cli->offset >= cli->size) {
cli->state = TIP_CLIENT_CLOSE_WAIT;
return 1; return 1;
}
return 0; return 0;
} }