more error message for socket, and close listen socket when reach limit of open files. See Issue #339

This commit is contained in:
Cloud Wu
2015-09-15 14:52:30 +08:00
parent 6c33f7bc44
commit b8f419eb69
4 changed files with 56 additions and 21 deletions

View File

@@ -101,17 +101,24 @@ function gateserver.start(handler)
end end
function MSG.close(fd) function MSG.close(fd)
if handler.disconnect then if fd ~= socket then
handler.disconnect(fd) if handler.disconnect then
handler.disconnect(fd)
end
close_fd(fd)
end end
close_fd(fd)
end end
function MSG.error(fd, msg) function MSG.error(fd, msg)
if handler.error then if fd == socket then
handler.error(fd, msg) socketdriver.close(fd)
skynet.error(msg)
else
if handler.error then
handler.error(fd, msg)
end
close_fd(fd)
end end
close_fd(fd)
end end
function MSG.warning(fd, size) function MSG.warning(fd, size)

View File

@@ -106,16 +106,17 @@ socket_message[4] = function(id, newid, addr)
end end
-- SKYNET_SOCKET_TYPE_ERROR = 5 -- SKYNET_SOCKET_TYPE_ERROR = 5
socket_message[5] = function(id) socket_message[5] = function(id, _, err)
local s = socket_pool[id] local s = socket_pool[id]
if s == nil then if s == nil then
skynet.error("socket: error on unknown", id) skynet.error("socket: error on unknown", id, err)
return return
end end
if s.connected then if s.connected or s.connecting then
skynet.error("socket: error on", id) skynet.error("socket: error on", id, err)
end end
s.connected = false s.connected = false
driver.close(id)
wakeup(s) wakeup(s)
end end
@@ -170,6 +171,7 @@ local function connect(id, func)
id = id, id = id,
buffer = newbuffer, buffer = newbuffer,
connected = false, connected = false,
connecting = true,
read_required = false, read_required = false,
co = false, co = false,
callback = func, callback = func,
@@ -177,6 +179,7 @@ local function connect(id, func)
} }
socket_pool[id] = s socket_pool[id] = s
suspend(s) suspend(s)
s.connecting = nil
if s.connected then if s.connected then
return id return id
else else
@@ -221,7 +224,7 @@ function socket.close(id)
return return
end end
if s.connected then if s.connected then
driver.close(s.id) driver.close(id)
-- notice: call socket.close in __gc should be carefully, -- notice: call socket.close in __gc should be carefully,
-- because skynet.wait never return in __gc, so driver.clear may not be called -- because skynet.wait never return in __gc, so driver.clear may not be called
if s.co then if s.co then

View File

@@ -36,7 +36,11 @@ forward_message(int type, bool padding, struct socket_message * result) {
size_t sz = sizeof(*sm); size_t sz = sizeof(*sm);
if (padding) { if (padding) {
if (result->data) { if (result->data) {
sz += strlen(result->data); size_t msg_sz = strlen(result->data);
if (msg_sz > 128) {
msg_sz = 128;
}
sz += msg_sz;
} else { } else {
result->data = ""; result->data = "";
} }
@@ -86,7 +90,7 @@ skynet_socket_poll() {
forward_message(SKYNET_SOCKET_TYPE_CONNECT, true, &result); forward_message(SKYNET_SOCKET_TYPE_CONNECT, true, &result);
break; break;
case SOCKET_ERROR: case SOCKET_ERROR:
forward_message(SKYNET_SOCKET_TYPE_ERROR, false, &result); forward_message(SKYNET_SOCKET_TYPE_ERROR, true, &result);
break; break;
case SOCKET_ACCEPT: case SOCKET_ACCEPT:
forward_message(SKYNET_SOCKET_TYPE_ACCEPT, true, &result); forward_message(SKYNET_SOCKET_TYPE_ACCEPT, true, &result);

View File

@@ -408,6 +408,7 @@ open_socket(struct socket_server *ss, struct request_open * request, struct sock
status = getaddrinfo( request->host, port, &ai_hints, &ai_list ); status = getaddrinfo( request->host, port, &ai_hints, &ai_list );
if ( status != 0 ) { if ( status != 0 ) {
result->data = (void *)gai_strerror(status);
goto _failed; goto _failed;
} }
int sock= -1; int sock= -1;
@@ -428,12 +429,14 @@ open_socket(struct socket_server *ss, struct request_open * request, struct sock
} }
if (sock < 0) { if (sock < 0) {
result->data = strerror(errno);
goto _failed; goto _failed;
} }
ns = new_fd(ss, id, sock, PROTOCOL_TCP, request->opaque, true); ns = new_fd(ss, id, sock, PROTOCOL_TCP, request->opaque, true);
if (ns == NULL) { if (ns == NULL) {
close(sock); close(sock);
result->data = "reach skynet socket number limit";
goto _failed; goto _failed;
} }
@@ -762,7 +765,7 @@ _failed:
result->opaque = request->opaque; result->opaque = request->opaque;
result->id = id; result->id = id;
result->ud = 0; result->ud = 0;
result->data = NULL; result->data = "reach skynet socket number limit";
ss->slot[HASH_ID(id)].type = SOCKET_TYPE_INVALID; ss->slot[HASH_ID(id)].type = SOCKET_TYPE_INVALID;
return SOCKET_ERROR; return SOCKET_ERROR;
@@ -803,7 +806,7 @@ bind_socket(struct socket_server *ss, struct request_bind *request, struct socke
result->ud = 0; result->ud = 0;
struct socket *s = new_fd(ss, id, request->fd, PROTOCOL_TCP, request->opaque, true); struct socket *s = new_fd(ss, id, request->fd, PROTOCOL_TCP, request->opaque, true);
if (s == NULL) { if (s == NULL) {
result->data = NULL; result->data = "reach skynet socket number limit";
return SOCKET_ERROR; return SOCKET_ERROR;
} }
sp_nonblocking(request->fd); sp_nonblocking(request->fd);
@@ -821,11 +824,13 @@ start_socket(struct socket_server *ss, struct request_start *request, struct soc
result->data = NULL; result->data = NULL;
struct socket *s = &ss->slot[HASH_ID(id)]; struct socket *s = &ss->slot[HASH_ID(id)];
if (s->type == SOCKET_TYPE_INVALID || s->id !=id) { if (s->type == SOCKET_TYPE_INVALID || s->id !=id) {
result->data = "invalid socket";
return SOCKET_ERROR; return SOCKET_ERROR;
} }
if (s->type == SOCKET_TYPE_PACCEPT || s->type == SOCKET_TYPE_PLISTEN) { if (s->type == SOCKET_TYPE_PACCEPT || s->type == SOCKET_TYPE_PLISTEN) {
if (sp_add(ss->event_fd, s->fd, s)) { if (sp_add(ss->event_fd, s->fd, s)) {
s->type = SOCKET_TYPE_INVALID; s->type = SOCKET_TYPE_INVALID;
result->data = strerror(errno);
return SOCKET_ERROR; return SOCKET_ERROR;
} }
s->type = (s->type == SOCKET_TYPE_PACCEPT) ? SOCKET_TYPE_CONNECTED : SOCKET_TYPE_LISTEN; s->type = (s->type == SOCKET_TYPE_PACCEPT) ? SOCKET_TYPE_CONNECTED : SOCKET_TYPE_LISTEN;
@@ -913,7 +918,7 @@ set_udp_address(struct socket_server *ss, struct request_setudp *request, struct
result->opaque = s->opaque; result->opaque = s->opaque;
result->id = s->id; result->id = s->id;
result->ud = 0; result->ud = 0;
result->data = NULL; result->data = "protocol mismatch";
return SOCKET_ERROR; return SOCKET_ERROR;
} }
@@ -995,6 +1000,7 @@ forward_message_tcp(struct socket_server *ss, struct socket *s, struct socket_me
default: default:
// close when error // close when error
force_close(ss, s, result); force_close(ss, s, result);
result->data = strerror(errno);
return SOCKET_ERROR; return SOCKET_ERROR;
} }
return -1; return -1;
@@ -1055,6 +1061,7 @@ forward_message_udp(struct socket_server *ss, struct socket *s, struct socket_me
default: default:
// close when error // close when error
force_close(ss, s, result); force_close(ss, s, result);
result->data = strerror(errno);
return SOCKET_ERROR; return SOCKET_ERROR;
} }
return -1; return -1;
@@ -1088,6 +1095,7 @@ report_connect(struct socket_server *ss, struct socket *s, struct socket_message
int code = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, &error, &len); int code = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, &error, &len);
if (code < 0 || error) { if (code < 0 || error) {
force_close(ss,s, result); force_close(ss,s, result);
result->data = strerror(errno);
return SOCKET_ERROR; return SOCKET_ERROR;
} else { } else {
s->type = SOCKET_TYPE_CONNECTED; s->type = SOCKET_TYPE_CONNECTED;
@@ -1111,14 +1119,22 @@ report_connect(struct socket_server *ss, struct socket *s, struct socket_message
} }
} }
// return 0 when failed // return 0 when failed, or -1 when file limit
static int static int
report_accept(struct socket_server *ss, struct socket *s, struct socket_message *result) { report_accept(struct socket_server *ss, struct socket *s, struct socket_message *result) {
union sockaddr_all u; union sockaddr_all u;
socklen_t len = sizeof(u); socklen_t len = sizeof(u);
int client_fd = accept(s->fd, &u.s, &len); int client_fd = accept(s->fd, &u.s, &len);
if (client_fd < 0) { if (client_fd < 0) {
return 0; if (errno == EMFILE || errno == ENFILE) {
result->opaque = s->opaque;
result->id = s->id;
result->ud = 0;
result->data = strerror(errno);
return -1;
} else {
return 0;
}
} }
int id = reserve_id(ss); int id = reserve_id(ss);
if (id < 0) { if (id < 0) {
@@ -1203,11 +1219,16 @@ socket_server_poll(struct socket_server *ss, struct socket_message * result, int
switch (s->type) { switch (s->type) {
case SOCKET_TYPE_CONNECTING: case SOCKET_TYPE_CONNECTING:
return report_connect(ss, s, result); return report_connect(ss, s, result);
case SOCKET_TYPE_LISTEN: case SOCKET_TYPE_LISTEN: {
if (report_accept(ss, s, result)) { int ok = report_accept(ss, s, result);
if (ok > 0) {
return SOCKET_ACCEPT; return SOCKET_ACCEPT;
} } if (ok < 0 ) {
return SOCKET_ERROR;
}
// when ok == 0, retry
break; break;
}
case SOCKET_TYPE_INVALID: case SOCKET_TYPE_INVALID:
fprintf(stderr, "socket-server: invalid socket\n"); fprintf(stderr, "socket-server: invalid socket\n");
break; break;