mirror of
https://github.com/cloudwu/skynet.git
synced 2026-07-23 19:43:09 +00:00
shutdown write when write error, See #1346
This commit is contained in:
@@ -681,9 +681,21 @@ static int
|
||||
close_write(struct socket_server *ss, struct socket *s, struct socket_lock *l, struct socket_message *result) {
|
||||
if (s->closing) {
|
||||
force_close(ss,s,l,result);
|
||||
return SOCKET_CLOSE;
|
||||
return SOCKET_RST;
|
||||
} else {
|
||||
int t = ATOM_LOAD(&s->type);
|
||||
if (t == SOCKET_TYPE_HALFCLOSE_READ) {
|
||||
// recv 0 before, ignore the error and close fd
|
||||
force_close(ss,s,l,result);
|
||||
return SOCKET_RST;
|
||||
}
|
||||
if (t == SOCKET_TYPE_HALFCLOSE_WRITE) {
|
||||
// already raise SOCKET_ERR
|
||||
return SOCKET_RST;
|
||||
}
|
||||
ATOM_STORE(&s->type, SOCKET_TYPE_HALFCLOSE_WRITE);
|
||||
shutdown(s->fd, SHUT_WR);
|
||||
enable_write(ss, s, false);
|
||||
result->id = s->id;
|
||||
result->ud = 0;
|
||||
result->opaque = s->opaque;
|
||||
@@ -847,7 +859,7 @@ send_buffer_(struct socket_server *ss, struct socket *s, struct socket_lock *l,
|
||||
// HALFCLOSE_WRITE
|
||||
return SOCKET_ERR;
|
||||
}
|
||||
// SOCKET_CLOSE
|
||||
// SOCKET_RST (ignore)
|
||||
return -1;
|
||||
}
|
||||
if (s->high.head == NULL) {
|
||||
@@ -859,6 +871,7 @@ send_buffer_(struct socket_server *ss, struct socket *s, struct socket_lock *l,
|
||||
// HALFCLOSE_WRITE
|
||||
return SOCKET_ERR;
|
||||
}
|
||||
// SOCKET_RST (ignore)
|
||||
return -1;
|
||||
}
|
||||
// step 3
|
||||
@@ -873,6 +886,7 @@ send_buffer_(struct socket_server *ss, struct socket *s, struct socket_lock *l,
|
||||
assert(send_buffer_empty(s) && s->wb_size == 0);
|
||||
|
||||
if (s->closing) {
|
||||
// finish writing
|
||||
force_close(ss, s, l, result);
|
||||
return -1;
|
||||
}
|
||||
@@ -1111,6 +1125,11 @@ halfclose_read(struct socket *s) {
|
||||
return ATOM_LOAD(&s->type) == SOCKET_TYPE_HALFCLOSE_READ;
|
||||
}
|
||||
|
||||
// SOCKET_CLOSE can be raised (only once) in one of two conditions.
|
||||
// See https://github.com/cloudwu/skynet/issues/1346 for more discussion.
|
||||
// 1. close socket by self, See close_socket()
|
||||
// 2. recv 0 or eof event (close socket by remote), See forward_message_tcp()
|
||||
// It's able to write data after SOCKET_CLOSE (In condition 2), but if remote is closed, SOCKET_ERR may raised.
|
||||
static int
|
||||
close_socket(struct socket_server *ss, struct request_close *request, struct socket_message *result) {
|
||||
int id = request->id;
|
||||
@@ -1122,13 +1141,21 @@ close_socket(struct socket_server *ss, struct request_close *request, struct soc
|
||||
struct socket_lock l;
|
||||
socket_lock_init(s, &l);
|
||||
|
||||
int shutdown_read = halfclose_read(s);
|
||||
|
||||
if (request->shutdown || nomore_sending_data(s)) {
|
||||
// If socket is SOCKET_TYPE_HALFCLOSE_READ, Do not raise SOCKET_CLOSE again.
|
||||
int r = shutdown_read ? -1 : SOCKET_CLOSE;
|
||||
force_close(ss,s,&l,result);
|
||||
} else {
|
||||
return r;
|
||||
} else if (!shutdown_read) {
|
||||
s->closing = true;
|
||||
// don't read socket after socket.close()
|
||||
close_read(ss, s, result);
|
||||
return SOCKET_CLOSE;
|
||||
}
|
||||
return SOCKET_CLOSE;
|
||||
// recv 0 before (socket is SOCKET_TYPE_HALFCLOSE_READ) and waiting for sending data out.
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1459,20 +1486,28 @@ forward_message_tcp(struct socket_server *ss, struct socket *s, struct socket_lo
|
||||
}
|
||||
if (n==0) {
|
||||
if (s->closing) {
|
||||
// Rare case : if s->closing is true, reading event is disable, and SOCKET_CLOSE is raised.
|
||||
if (nomore_sending_data(s)) {
|
||||
force_close(ss,s,l,result);
|
||||
return SOCKET_CLOSE;
|
||||
} else {
|
||||
// Already returned SOCKET_CLOSE
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
int t = ATOM_LOAD(&s->type);
|
||||
if (t == SOCKET_TYPE_HALFCLOSE_READ) {
|
||||
// Rare case : Already shutdown read.
|
||||
return -1;
|
||||
}
|
||||
if (t == SOCKET_TYPE_HALFCLOSE_WRITE) {
|
||||
// Remote shutdown read (write error) before.
|
||||
force_close(ss,s,l,result);
|
||||
} else {
|
||||
close_read(ss, s, result);
|
||||
}
|
||||
close_read(ss, s, result);
|
||||
return SOCKET_CLOSE;
|
||||
}
|
||||
|
||||
if (halfclose_read(s)) {
|
||||
// discard recv data
|
||||
// discard recv data (Rare case : if socket is HALFCLOSE_READ, reading event is disable.)
|
||||
FREE(buf.buf);
|
||||
return -1;
|
||||
}
|
||||
@@ -1765,8 +1800,8 @@ socket_server_poll(struct socket_server *ss, struct socket_message * result, int
|
||||
// For epoll (at least), FIN packets are exchanged both ways.
|
||||
// See: https://stackoverflow.com/questions/52976152/tcp-when-is-epollhup-generated
|
||||
force_close(ss, s, &l, result);
|
||||
if (s->closing) {
|
||||
// Already returned SOCKET_CLOSE
|
||||
if (halfclose_read(s)) {
|
||||
// Already rasied SOCKET_CLOSE
|
||||
return -1;
|
||||
} else {
|
||||
return SOCKET_CLOSE;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#define SOCKET_EXIT 5
|
||||
#define SOCKET_UDP 6
|
||||
#define SOCKET_WARNING 7
|
||||
#define SOCKET_RST 8 // Only for internal use
|
||||
|
||||
struct socket_server;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user