diff --git a/lualib/snax/gateserver.lua b/lualib/snax/gateserver.lua index dfce2fa9..68f77b58 100644 --- a/lualib/snax/gateserver.lua +++ b/lualib/snax/gateserver.lua @@ -101,17 +101,24 @@ function gateserver.start(handler) end function MSG.close(fd) - if handler.disconnect then - handler.disconnect(fd) + if fd ~= socket then + if handler.disconnect then + handler.disconnect(fd) + end + close_fd(fd) end - close_fd(fd) end function MSG.error(fd, msg) - if handler.error then - handler.error(fd, msg) + if fd == socket then + socketdriver.close(fd) + skynet.error(msg) + else + if handler.error then + handler.error(fd, msg) + end + close_fd(fd) end - close_fd(fd) end function MSG.warning(fd, size) diff --git a/lualib/socket.lua b/lualib/socket.lua index c5fe7858..7f1d603b 100644 --- a/lualib/socket.lua +++ b/lualib/socket.lua @@ -106,16 +106,17 @@ socket_message[4] = function(id, newid, addr) end -- SKYNET_SOCKET_TYPE_ERROR = 5 -socket_message[5] = function(id) +socket_message[5] = function(id, _, err) local s = socket_pool[id] if s == nil then - skynet.error("socket: error on unknown", id) + skynet.error("socket: error on unknown", id, err) return end - if s.connected then - skynet.error("socket: error on", id) + if s.connected or s.connecting then + skynet.error("socket: error on", id, err) end s.connected = false + driver.close(id) wakeup(s) end @@ -170,6 +171,7 @@ local function connect(id, func) id = id, buffer = newbuffer, connected = false, + connecting = true, read_required = false, co = false, callback = func, @@ -177,6 +179,7 @@ local function connect(id, func) } socket_pool[id] = s suspend(s) + s.connecting = nil if s.connected then return id else @@ -221,7 +224,7 @@ function socket.close(id) return end if s.connected then - driver.close(s.id) + driver.close(id) -- notice: call socket.close in __gc should be carefully, -- because skynet.wait never return in __gc, so driver.clear may not be called if s.co then diff --git a/skynet-src/skynet_socket.c b/skynet-src/skynet_socket.c index 9301419f..f6f8ec56 100644 --- a/skynet-src/skynet_socket.c +++ b/skynet-src/skynet_socket.c @@ -36,7 +36,11 @@ forward_message(int type, bool padding, struct socket_message * result) { size_t sz = sizeof(*sm); if (padding) { 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 { result->data = ""; } @@ -86,7 +90,7 @@ skynet_socket_poll() { forward_message(SKYNET_SOCKET_TYPE_CONNECT, true, &result); break; case SOCKET_ERROR: - forward_message(SKYNET_SOCKET_TYPE_ERROR, false, &result); + forward_message(SKYNET_SOCKET_TYPE_ERROR, true, &result); break; case SOCKET_ACCEPT: forward_message(SKYNET_SOCKET_TYPE_ACCEPT, true, &result); diff --git a/skynet-src/socket_server.c b/skynet-src/socket_server.c index b2454d2e..7724a3c5 100644 --- a/skynet-src/socket_server.c +++ b/skynet-src/socket_server.c @@ -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 ); if ( status != 0 ) { + result->data = (void *)gai_strerror(status); goto _failed; } int sock= -1; @@ -428,12 +429,14 @@ open_socket(struct socket_server *ss, struct request_open * request, struct sock } if (sock < 0) { + result->data = strerror(errno); goto _failed; } ns = new_fd(ss, id, sock, PROTOCOL_TCP, request->opaque, true); if (ns == NULL) { close(sock); + result->data = "reach skynet socket number limit"; goto _failed; } @@ -762,7 +765,7 @@ _failed: result->opaque = request->opaque; result->id = id; result->ud = 0; - result->data = NULL; + result->data = "reach skynet socket number limit"; ss->slot[HASH_ID(id)].type = SOCKET_TYPE_INVALID; return SOCKET_ERROR; @@ -803,7 +806,7 @@ bind_socket(struct socket_server *ss, struct request_bind *request, struct socke result->ud = 0; struct socket *s = new_fd(ss, id, request->fd, PROTOCOL_TCP, request->opaque, true); if (s == NULL) { - result->data = NULL; + result->data = "reach skynet socket number limit"; return SOCKET_ERROR; } sp_nonblocking(request->fd); @@ -821,11 +824,13 @@ start_socket(struct socket_server *ss, struct request_start *request, struct soc result->data = NULL; struct socket *s = &ss->slot[HASH_ID(id)]; if (s->type == SOCKET_TYPE_INVALID || s->id !=id) { + result->data = "invalid socket"; return SOCKET_ERROR; } if (s->type == SOCKET_TYPE_PACCEPT || s->type == SOCKET_TYPE_PLISTEN) { if (sp_add(ss->event_fd, s->fd, s)) { s->type = SOCKET_TYPE_INVALID; + result->data = strerror(errno); return SOCKET_ERROR; } 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->id = s->id; result->ud = 0; - result->data = NULL; + result->data = "protocol mismatch"; return SOCKET_ERROR; } @@ -995,6 +1000,7 @@ forward_message_tcp(struct socket_server *ss, struct socket *s, struct socket_me default: // close when error force_close(ss, s, result); + result->data = strerror(errno); return SOCKET_ERROR; } return -1; @@ -1055,6 +1061,7 @@ forward_message_udp(struct socket_server *ss, struct socket *s, struct socket_me default: // close when error force_close(ss, s, result); + result->data = strerror(errno); return SOCKET_ERROR; } 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); if (code < 0 || error) { force_close(ss,s, result); + result->data = strerror(errno); return SOCKET_ERROR; } else { 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 report_accept(struct socket_server *ss, struct socket *s, struct socket_message *result) { union sockaddr_all u; socklen_t len = sizeof(u); int client_fd = accept(s->fd, &u.s, &len); 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); if (id < 0) { @@ -1203,11 +1219,16 @@ socket_server_poll(struct socket_server *ss, struct socket_message * result, int switch (s->type) { case SOCKET_TYPE_CONNECTING: return report_connect(ss, s, result); - case SOCKET_TYPE_LISTEN: - if (report_accept(ss, s, result)) { + case SOCKET_TYPE_LISTEN: { + int ok = report_accept(ss, s, result); + if (ok > 0) { return SOCKET_ACCEPT; - } + } if (ok < 0 ) { + return SOCKET_ERROR; + } + // when ok == 0, retry break; + } case SOCKET_TYPE_INVALID: fprintf(stderr, "socket-server: invalid socket\n"); break;