mirror of
https://github.com/cloudwu/skynet.git
synced 2026-07-22 02:53:09 +00:00
1.提供支持ipv6的udp client和server接口, 可支持ipv6 (#1967)
* 1.提供支持ipv6的udp client和server接口, 可支持ipv6 * remove chinese comments
This commit is contained in:
@@ -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 },
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user