From 839570ce3f6025ec088798e8a227d54aa406a718 Mon Sep 17 00:00:00 2001 From: huojicha <4695954+huojicha@users.noreply.github.com> Date: Thu, 8 Aug 2024 02:34:15 +0800 Subject: [PATCH] =?UTF-8?q?1.=E6=8F=90=E4=BE=9B=E6=94=AF=E6=8C=81ipv6?= =?UTF-8?q?=E7=9A=84udp=20client=E5=92=8Cserver=E6=8E=A5=E5=8F=A3,=20?= =?UTF-8?q?=E5=8F=AF=E6=94=AF=E6=8C=81ipv6=20(#1967)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 1.提供支持ipv6的udp client和server接口, 可支持ipv6 * remove chinese comments --- lualib-src/lua-socket.c | 40 ++++++++++++ lualib/skynet/socket.lua | 12 ++++ skynet-src/skynet_socket.c | 12 ++++ skynet-src/skynet_socket.h | 2 + skynet-src/socket_server.c | 122 ++++++++++++++++++++++++++++++++++++- skynet-src/socket_server.h | 6 ++ test/testudp.lua | 27 +++++++- 7 files changed, 218 insertions(+), 3 deletions(-) diff --git a/lualib-src/lua-socket.c b/lualib-src/lua-socket.c index c9527372..7e22d2ed 100644 --- a/lualib-src/lua-socket.c +++ b/lualib-src/lua-socket.c @@ -675,6 +675,44 @@ ludp_connect(lua_State *L) { return 0; } +static int +ludp_dial(lua_State *L){ + struct skynet_context * ctx = lua_touserdata(L, lua_upvalueindex(1)); + size_t sz = 0; + const char * addr = luaL_checklstring(L, 1, &sz); + char tmp[sz]; + int port = 0; + const char * host = address_port(L, tmp, addr, 2, &port); + + int id = skynet_socket_udp_dial(ctx, host, port); + if (id < 0){ + return luaL_error(L, "udp dial host failed"); + } + + lua_pushinteger(L, id); + return 1; +} + +static int +ludp_listen(lua_State *L){ + struct skynet_context * ctx = lua_touserdata(L, lua_upvalueindex(1)); + size_t sz = 0; + const char * addr = luaL_checklstring(L, 1, &sz); + char tmp[sz]; + + int port = 0; + const char * host = address_port(L, tmp, addr, 2, &port); + + int id = skynet_socket_udp_listen(ctx, host, port); + if (id < 0){ + return luaL_error(L, "udp listen host failed"); + } + + lua_pushinteger(L, id); + return 1; +} + + static int ludp_send(lua_State *L) { struct skynet_context * ctx = lua_touserdata(L, lua_upvalueindex(1)); @@ -849,6 +887,8 @@ luaopen_skynet_socketdriver(lua_State *L) { { "nodelay", lnodelay }, { "udp", ludp }, { "udp_connect", ludp_connect }, + { "udp_dial", ludp_dial}, + { "udp_listen", ludp_listen}, { "udp_send", ludp_send }, { "udp_address", ludp_address }, { "resolve", lresolve }, diff --git a/lualib/skynet/socket.lua b/lualib/skynet/socket.lua index e047ffff..b4c0fb27 100644 --- a/lualib/skynet/socket.lua +++ b/lualib/skynet/socket.lua @@ -471,6 +471,18 @@ function socket.udp_connect(id, addr, port, callback) driver.udp_connect(id, addr, port) end +function socket.udp_listen(addr, port, callback) + local id = driver.udp_listen(addr, port) + create_udp_object(id, callback) + return id +end + +function socket.udp_dial(addr, port, callback) + local id = driver.udp_dial(addr, port) + create_udp_object(id, callback) + return id +end + socket.sendto = assert(driver.udp_send) socket.udp_address = assert(driver.udp_address) socket.netstat = assert(driver.info) diff --git a/skynet-src/skynet_socket.c b/skynet-src/skynet_socket.c index 7ba7a683..d7edc51e 100644 --- a/skynet-src/skynet_socket.c +++ b/skynet-src/skynet_socket.c @@ -180,6 +180,18 @@ skynet_socket_udp(struct skynet_context *ctx, const char * addr, int port) { return socket_server_udp(SOCKET_SERVER, source, addr, port); } +int +skynet_socket_udp_dial(struct skynet_context *ctx, const char * addr, int port){ + uint32_t source = skynet_context_handle(ctx); + return socket_server_udp_dial(SOCKET_SERVER, source, addr, port); +} + +int +skynet_socket_udp_listen(struct skynet_context *ctx, const char * addr, int port){ + uint32_t source = skynet_context_handle(ctx); + return socket_server_udp_listen(SOCKET_SERVER, source, addr, port); +} + int skynet_socket_udp_connect(struct skynet_context *ctx, int id, const char * addr, int port) { return socket_server_udp_connect(SOCKET_SERVER, id, addr, port); diff --git a/skynet-src/skynet_socket.h b/skynet-src/skynet_socket.h index dd66f834..40d7e380 100644 --- a/skynet-src/skynet_socket.h +++ b/skynet-src/skynet_socket.h @@ -40,6 +40,8 @@ void skynet_socket_nodelay(struct skynet_context *ctx, int id); int skynet_socket_udp(struct skynet_context *ctx, const char * addr, int port); int skynet_socket_udp_connect(struct skynet_context *ctx, int id, const char * addr, int port); +int skynet_socket_udp_dial(struct skynet_context *ctx, const char * addr, int port); +int skynet_socket_udp_listen(struct skynet_context *ctx, const char * addr, int port); int skynet_socket_udp_sendbuffer(struct skynet_context *ctx, const char * address, struct socket_sendbuffer *buffer); const char * skynet_socket_udp_address(struct skynet_socket_message *, int *addrsz); diff --git a/skynet-src/socket_server.c b/skynet-src/socket_server.c index a3cf9633..72f2f96b 100644 --- a/skynet-src/socket_server.c +++ b/skynet-src/socket_server.c @@ -190,6 +190,13 @@ struct request_udp { uintptr_t opaque; }; +struct request_dial_udp { + int id; + int fd; + uintptr_t opaque; + uint8_t address[UDP_ADDRESS_SIZE]; +}; + /* The first byte is TYPE R Resume socket @@ -204,6 +211,7 @@ struct request_udp { P Send package (low) A Send UDP package C set udp address + N client dial to UDP host port T Set opt U Create UDP socket */ @@ -222,6 +230,7 @@ struct request_package { struct request_setopt setopt; struct request_udp udp; struct request_setudp set_udp; + struct request_dial_udp dial_udp; } u; uint8_t dummy[256]; }; @@ -1329,6 +1338,30 @@ set_udp_address(struct socket_server *ss, struct request_setudp *request, struct return -1; } +static int +dial_udp_socket(struct socket_server *ss, struct request_dial_udp *request, struct socket_message *result){ + int id = request->id; + int protocol = request->address[0]; + + struct socket *ns = new_fd(ss, id, request->fd, protocol, request->opaque, true); + if (ns == NULL){ + close(request->fd); + ss->slot[HASH_ID(id)].type = SOCKET_TYPE_INVALID; + return -1; + } + + if (protocol == PROTOCOL_UDP){ + memcpy(ns->p.udp_address, request->address, 1 + 2 + 4); + } else { + memcpy(ns->p.udp_address, request->address, 1 + 2 + 16); + } + + ATOM_STORE(&ns->type , SOCKET_TYPE_CONNECTED); + + ATOM_FDEC(&ns->udpconnecting); + return -1; +} + static inline void inc_sending_ref(struct socket *s, int id) { if (s->protocol != PROTOCOL_TCP) @@ -1372,7 +1405,6 @@ ctrl_cmd(struct socket_server *ss, struct socket_message *result) { int type = header[0]; int len = header[1]; block_readpipe(fd, buffer, len); - // ctrl command only exist in local fd, so don't worry about endian. switch (type) { case 'R': @@ -1409,6 +1441,8 @@ ctrl_cmd(struct socket_server *ss, struct socket_message *result) { } case 'C': return set_udp_address(ss, (struct request_setudp *)buffer, result); + case 'N': + return dial_udp_socket(ss, (struct request_dial_udp *)buffer, result); case 'T': setopt_socket(ss, (struct request_setopt *)buffer); return -1; @@ -2116,6 +2150,92 @@ socket_server_udp(struct socket_server *ss, uintptr_t opaque, const char * addr, return id; } +int +socket_server_udp_listen(struct socket_server *ss, uintptr_t opaque, const char* addr, int port){ + int fd; + if (port == 0){ + return -1; + } + + int family; + // bind + fd = do_bind(addr, port, IPPROTO_UDP, &family); + if (fd < 0) { + return -1; + } + + sp_nonblocking(fd); + + int id = reserve_id(ss); + if (id < 0) { + close(fd); + return -1; + } + struct request_package request; + request.u.udp.id = id; + request.u.udp.fd = fd; + request.u.udp.opaque = opaque; + request.u.udp.family = family; + + send_request(ss, &request, 'U', sizeof(request.u.udp)); + return id; +} + +int +socket_server_udp_dial(struct socket_server *ss, uintptr_t opaque, const char* addr, int port){ + int status; + struct addrinfo ai_hints; + struct addrinfo *ai_list = NULL; + char portstr[16]; + sprintf(portstr, "%d", port); + memset( &ai_hints, 0, sizeof( ai_hints ) ); + ai_hints.ai_family = AF_UNSPEC; + ai_hints.ai_socktype = SOCK_DGRAM; + ai_hints.ai_protocol = IPPROTO_UDP; + + + status = getaddrinfo(addr, portstr, &ai_hints, &ai_list ); + if ( status != 0 ) { + return -1; + } + + int protocol; + + if (ai_list->ai_family == AF_INET) { + protocol = PROTOCOL_UDP; + } else if (ai_list->ai_family == AF_INET6) { + protocol = PROTOCOL_UDPv6; + } else { + freeaddrinfo( ai_list ); + return -1; + } + + int fd = socket(ai_list->ai_family, SOCK_DGRAM, 0); + if (fd < 0){ + return -1; + } + + sp_nonblocking(fd); + int id = reserve_id(ss); + if (id < 0){ + close(fd); + return -1; + } + + struct request_package request; + request.u.dial_udp.id = id; + request.u.dial_udp.fd = fd; + request.u.dial_udp.opaque = opaque; + + + int addrsz = gen_udp_address(protocol, (union sockaddr_all *)ai_list->ai_addr, request.u.dial_udp.address); + + freeaddrinfo( ai_list ); + + send_request(ss, &request, 'N', sizeof(request.u.dial_udp) - sizeof(request.u.dial_udp.address) + addrsz); + return id; +} + int socket_server_udp_send(struct socket_server *ss, const struct socket_udp_address *addr, struct socket_sendbuffer *buf) { int id = buf->id; diff --git a/skynet-src/socket_server.h b/skynet-src/socket_server.h index beb628ca..4167cb25 100644 --- a/skynet-src/socket_server.h +++ b/skynet-src/socket_server.h @@ -57,6 +57,12 @@ struct socket_udp_address; int socket_server_udp(struct socket_server *, uintptr_t opaque, const char * addr, int port); // set default dest address, return 0 when success int socket_server_udp_connect(struct socket_server *, int id, const char * addr, int port); + +// create an udp client socket handle, and connect to server addr, return id when success +int socket_server_udp_dial(struct socket_server *ss, uintptr_t opaque, const char* addr, int port); +// create an udp server socket handle, and bind the host port, return id when success +int socket_server_udp_listen(struct socket_server *ss, uintptr_t opaque, const char* addr, int port); + // If the socket_udp_address is NULL, use last call socket_server_udp_connect address instead // You can also use socket_server_send int socket_server_udp_send(struct socket_server *, const struct socket_udp_address *, struct socket_sendbuffer *buffer); diff --git a/test/testudp.lua b/test/testudp.lua index e62f4067..e49121ea 100644 --- a/test/testudp.lua +++ b/test/testudp.lua @@ -4,14 +4,14 @@ local socket = require "skynet.socket" local function server() local host host = socket.udp(function(str, from) - print("server recv", str, socket.udp_address(from)) + print("server v4 recv", str, socket.udp_address(from)) socket.sendto(host, from, "OK " .. str) end , "127.0.0.1", 8765) -- bind an address end local function client() local c = socket.udp(function(str, from) - print("client recv", str, socket.udp_address(from)) + print("client v4 recv", str, socket.udp_address(from)) end) socket.udp_connect(c, "127.0.0.1", 8765) for i=1,20 do @@ -19,7 +19,30 @@ local function client() end end +local function server_v6() + local server + server = socket.udp_listen("::1", 8766, function(str, from) + print(string.format("server_v6 recv str:%s from:%s", str, socket.udp_address(from))) + socket.sendto(server, from, "OK " .. str) + end) -- bind an address + print("create server succeed. "..server) + return server +end + +local function client_v6() + local c = socket.udp_dial("::1", 8766, function(str, from) + print(string.format("client recv v6 response str:%s from:%s", str, socket.udp_address(from))) + end) + + print("create client succeed. "..c) + for i=1,20 do + socket.write(c, "hello " .. i) -- write to the address by udp_connect binding + end +end + skynet.start(function() skynet.fork(server) skynet.fork(client) + skynet.fork(server_v6) + skynet.fork(client_v6) end)