Compare commits

..

23 Commits

Author SHA1 Message Date
Cloud Wu
0298997d23 release alpha 4 2015-04-13 13:04:39 +08:00
Cloud Wu
678a94bf71 update license 2015-04-10 11:35:47 +08:00
Cloud Wu
03399e86a9 udp api changed, callback recv the string 2015-04-09 12:49:40 +08:00
Cloud Wu
22364bac89 bugfix: memory leak 2015-04-09 12:14:28 +08:00
Cloud Wu
9188b5451c bugfix 1 , from http://www.lua.org/bugs.html#5.3.0-1 2015-04-09 11:55:07 +08:00
Cloud Wu
c7ed527911 add const to sproto C api 2015-04-08 11:42:06 +08:00
Cloud Wu
5a1132101b share sproto C struct 2015-04-08 11:23:52 +08:00
Cloud Wu
ca33bf8b3e bugfix sproto : support empty string 2015-04-05 20:19:30 +08:00
Cloud Wu
7d8c80c9a0 fix Issue #256 2015-04-03 11:07:11 +08:00
Cloud Wu
c6f993428e bugfix #257 2015-04-03 11:03:37 +08:00
云风
f6118b858d Merge pull request #255 from flashjay/patch-1
fix: httpc.post
2015-04-03 09:35:41 +08:00
HuaYang Huang
ec1bca238e fix: httpc.post
调用httpc.post时,如果没有在header里面设置host时有问题
2015-04-01 17:54:22 +08:00
Cloud Wu
6b87f159b4 more type check 2015-04-01 13:22:09 +08:00
Cloud Wu
41b447d41a update sproto: check table 2015-04-01 12:18:49 +08:00
Cloud Wu
c512b5f59a release alpha 3 2015-03-30 11:00:51 +08:00
云风
fc9b32b4bd Merge pull request #254 from cloudwu/dev
release alpha 3
2015-03-30 11:00:18 +08:00
Cloud Wu
36ed8679b8 you can set host in httpc header 2015-03-30 09:29:22 +08:00
Cloud Wu
a9b1993686 Add async dns query 2015-03-29 14:41:28 +08:00
Cloud Wu
05b458ddb2 update sproto 2015-03-20 09:51:00 +08:00
Cloud Wu
8d8add3710 update sproto 2015-03-18 12:17:01 +08:00
Cloud Wu
65e7da9793 more sproto error message 2015-03-18 11:50:47 +08:00
Cloud Wu
7e5d9b7399 bugfix Issue #249 2015-03-18 11:07:34 +08:00
Cloud Wu
92b7b7beff use table for multi header key 2015-03-16 20:15:57 +08:00
21 changed files with 517 additions and 109 deletions

View File

@@ -798,7 +798,8 @@ static int str_gsub (lua_State *L) {
*/
/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */
#define MAX_ITEM 512
#define MAX_ITEM \
(sizeof(lua_Number) <= 4 ? 150 : sizeof(lua_Number) <= 8 ? 450 : 5050)
/* valid flags in a format specification */
#define FLAGS "-+ #0"

View File

@@ -1,3 +1,15 @@
v1.0.0-alpha4 (2015-4-13)
-----------
* sproto can share c struct between states
* udp api changed (use lua string now)
* fix memory leak in dns module
v1.0.0-alpha3 (2015-3-30)
-----------
* Update sproto (bugfix)
* Add async dns query
* improve httpc
v1.0.0-alpha2 (2015-3-16)
-----------
* Update examples client to lua 5.3

View File

@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2012-2014 codingnow.com
Copyright (c) 2012-2015 codingnow.com
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in

View File

@@ -39,17 +39,18 @@ LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
#define luaL_newlib(L,l) (luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
#endif
#if LUA_VERSION_NUM < 503
// lua_isinteger is lua 5.3 api
#define lua_isinteger lua_isnumber
#endif
static int
lnewproto(lua_State *L) {
size_t sz = 0;
void * buffer;
struct sproto * sp;
if (lua_isuserdata(L,1)) {
buffer = lua_touserdata(L,1);
sz = luaL_checkinteger(L,2);
} else {
buffer = (void *)luaL_checklstring(L,1,&sz);
}
size_t sz;
void * buffer = (void *)luaL_checklstring(L,1,&sz);
sp = sproto_create(buffer, sz);
if (sp) {
lua_pushlightuserdata(L, sp);
@@ -104,6 +105,7 @@ encode(const struct sproto_arg *args) {
return luaL_error(L, "The table is too deep");
if (args->index > 0) {
if (args->tagname != self->array_tag) {
// a new array
self->array_tag = args->tagname;
lua_getfield(L, self->tbl_index, args->tagname);
if (lua_isnil(L, -1)) {
@@ -113,6 +115,10 @@ encode(const struct sproto_arg *args) {
self->array_index = 0;
return 0;
}
if (!lua_istable(L, -1)) {
return luaL_error(L, ".*%s(%d) should be a table (Is a %s)",
args->tagname, args->index, lua_typename(L, lua_type(L, -1)));
}
if (self->array_index) {
lua_replace(L, self->array_index);
} else {
@@ -144,8 +150,14 @@ encode(const struct sproto_arg *args) {
}
switch (args->type) {
case SPROTO_TINTEGER: {
lua_Integer v = luaL_checkinteger(L, -1);
lua_Integer v;
lua_Integer vh;
if (!lua_isinteger(L, -1)) {
return luaL_error(L, ".%s[%d] is not an integer (Is a %s)",
args->tagname, args->index, lua_typename(L, lua_type(L, -1)));
} else {
v = lua_tointeger(L, -1);
}
lua_pop(L,1);
// notice: in lua 5.2, lua_Integer maybe 52bit
vh = v >> 31;
@@ -160,32 +172,47 @@ encode(const struct sproto_arg *args) {
}
case SPROTO_TBOOLEAN: {
int v = lua_toboolean(L, -1);
if (!lua_isboolean(L,-1)) {
return luaL_error(L, ".%s[%d] is not a boolean (Is a %s)",
args->tagname, args->index, lua_typename(L, lua_type(L, -1)));
}
*(int *)args->value = v;
lua_pop(L,1);
return 4;
}
case SPROTO_TSTRING: {
size_t sz = 0;
const char * str = luaL_checklstring(L, -1, &sz);
const char * str;
if (!lua_isstring(L, -1)) {
return luaL_error(L, ".%s[%d] is not a string (Is a %s)",
args->tagname, args->index, lua_typename(L, lua_type(L, -1)));
} else {
str = lua_tolstring(L, -1, &sz);
}
if (sz > args->length)
return -1;
memcpy(args->value, str, sz);
lua_pop(L,1);
return sz;
return sz + 1; // The length of empty string is 1.
}
case SPROTO_TSTRUCT: {
struct encode_ud sub;
int r;
int top = lua_gettop(L);
if (!lua_istable(L, top)) {
return luaL_error(L, ".%s[%d] is not a table (Is a %s)",
args->tagname, args->index, lua_typename(L, lua_type(L, -1)));
}
sub.L = L;
sub.st = args->subtype;
sub.tbl_index = lua_gettop(L);
sub.tbl_index = top;
sub.array_tag = NULL;
sub.array_index = 0;
sub.deep = self->deep + 1;
lua_pushnil(L); // prepare an iterator slot
sub.iter_index = sub.tbl_index + 1;
r = sproto_encode(args->subtype, args->value, args->length, encode, &sub);
lua_pop(L,2); // pop the value and the iterator slot
lua_settop(L, top-1); // pop the value
return r;
}
default:
@@ -222,29 +249,30 @@ lencode(lua_State *L) {
struct encode_ud self;
void * buffer = lua_touserdata(L, lua_upvalueindex(1));
int sz = lua_tointeger(L, lua_upvalueindex(2));
int tbl_index = 2;
struct sproto_type * st = lua_touserdata(L, 1);
if (st == NULL) {
return luaL_argerror(L, 1, "Need a sproto_type object");
}
luaL_checktype(L, 2, LUA_TTABLE);
luaL_checktype(L, tbl_index, LUA_TTABLE);
luaL_checkstack(L, ENCODE_DEEPLEVEL*2 + 8, NULL);
self.L = L;
self.st = st;
self.tbl_index = 2;
self.array_tag = NULL;
self.array_index = 0;
self.deep = 0;
lua_pushnil(L); // for iterator (stack 3)
self.iter_index = 3;
self.tbl_index = tbl_index;
for (;;) {
int r = sproto_encode(st, buffer, sz, encode, &self);
int r;
self.array_tag = NULL;
self.array_index = 0;
self.deep = 0;
lua_settop(L, tbl_index);
lua_pushnil(L); // for iterator (stack slot 3)
self.iter_index = tbl_index+1;
r = sproto_encode(st, buffer, sz, encode, &self);
if (r<0) {
buffer = expand_buffer(L, sz, sz*2);
sz *= 2;
// reset iterator slot
lua_pushnil(L);
lua_replace(L, 3);
} else {
lua_pushlstring(L, buffer, r);
return 1;
@@ -511,48 +539,38 @@ lprotocol(lua_State *L) {
return 3;
}
/* global sproto pointer for multi states */
struct sproto_bin {
void *ptr;
size_t sz;
};
static struct sproto_bin G_sproto[MAX_GLOBALSPROTO];
/* global sproto pointer for multi states
NOTICE : It is not thread safe
*/
static struct sproto * G_sproto[MAX_GLOBALSPROTO];
static int
lsaveproto(lua_State *L) {
size_t sz;
void * buffer = (void *)luaL_checklstring(L,1,&sz);
struct sproto * sp = lua_touserdata(L, 1);
int index = luaL_optinteger(L, 2, 0);
void * tmp;
struct sproto_bin * sbin = &G_sproto[index];
if (index < 0 || index >= MAX_GLOBALSPROTO) {
return luaL_error(L, "Invalid global slot index %d", index);
}
tmp = malloc(sz);
memcpy(tmp, buffer, sz);
if (sbin->ptr) {
free(sbin->ptr);
}
sbin->ptr = tmp;
sbin->sz = sz;
/* TODO : release old object (memory leak now, but thread safe)*/
G_sproto[index] = sp;
return 0;
}
static int
lloadproto(lua_State *L) {
int index = luaL_optinteger(L, 1, 0);
struct sproto_bin * sbin = &G_sproto[index];
struct sproto * sp;
if (index < 0 || index >= MAX_GLOBALSPROTO) {
return luaL_error(L, "Invalid global slot index %d", index);
}
if (sbin->ptr == NULL) {
sp = G_sproto[index];
if (sp == NULL) {
return luaL_error(L, "nil sproto at index %d", index);
}
lua_pushlightuserdata(L, sbin->ptr);
lua_pushinteger(L, sbin->sz);
return 2;
lua_pushlightuserdata(L, sp);
return 1;
}
int

View File

@@ -510,7 +510,7 @@ sproto_dump(struct sproto *s) {
// query
int
sproto_prototag(struct sproto *sp, const char * name) {
sproto_prototag(const struct sproto *sp, const char * name) {
int i;
for (i=0;i<sp->protocol_n;i++) {
if (strcmp(name, sp->proto[i].name) == 0) {
@@ -521,7 +521,7 @@ sproto_prototag(struct sproto *sp, const char * name) {
}
static struct protocol *
query_proto(struct sproto *sp, int tag) {
query_proto(const struct sproto *sp, int tag) {
int begin = 0, end = sp->protocol_n;
while(begin<end) {
int mid = (begin+end)/2;
@@ -539,7 +539,7 @@ query_proto(struct sproto *sp, int tag) {
}
struct sproto_type *
sproto_protoquery(struct sproto *sp, int proto, int what) {
sproto_protoquery(const struct sproto *sp, int proto, int what) {
struct protocol * p;
if (what <0 || what >1) {
return NULL;
@@ -552,7 +552,7 @@ sproto_protoquery(struct sproto *sp, int proto, int what) {
}
const char *
sproto_protoname(struct sproto *sp, int proto) {
sproto_protoname(const struct sproto *sp, int proto) {
struct protocol * p = query_proto(sp, proto);
if (p) {
return p->name;
@@ -561,7 +561,7 @@ sproto_protoname(struct sproto *sp, int proto) {
}
struct sproto_type *
sproto_type(struct sproto *sp, const char * type_name) {
sproto_type(const struct sproto *sp, const char * type_name) {
int i;
for (i=0;i<sp->type_n;i++) {
if (strcmp(type_name, sp->type[i].name) == 0) {
@@ -577,7 +577,7 @@ sproto_name(struct sproto_type * st) {
}
static struct field *
findtag(struct sproto_type *st, int tag) {
findtag(const struct sproto_type *st, int tag) {
int begin, end;
if (st->base >=0 ) {
tag -= st->base;
@@ -609,10 +609,6 @@ findtag(struct sproto_type *st, int tag) {
static inline int
fill_size(uint8_t * data, int sz) {
if (sz < 0)
return -1;
if (sz == 0)
return 0;
data[0] = sz & 0xff;
data[1] = (sz >> 8) & 0xff;
data[2] = (sz >> 16) & 0xff;
@@ -677,6 +673,11 @@ encode_object(sproto_callback cb, struct sproto_arg *args, uint8_t *data, int si
args->value = data+SIZEOF_LENGTH;
args->length = size-SIZEOF_LENGTH;
sz = cb(args);
if (sz <= 0)
return sz;
if (args->type == SPROTO_TSTRING) {
--sz; // the length of null string is 1
}
return fill_size(data, sz);
}
@@ -718,7 +719,7 @@ encode_integer_array(sproto_callback cb, struct sproto_arg *args, uint8_t *buffe
sz = cb(args);
if (sz < 0)
return NULL;
if (sz == 0)
if (sz == 0) // nil object, end of array
break;
if (size < sizeof(uint64_t))
return NULL;
@@ -798,7 +799,7 @@ encode_array(sproto_callback cb, struct sproto_arg *args, uint8_t *data, int siz
sz = cb(args);
if (sz < 0)
return -1;
if (sz == 0)
if (sz == 0) // nil object , end of array
break;
if (size < 1)
return -1;
@@ -817,10 +818,13 @@ encode_array(sproto_callback cb, struct sproto_arg *args, uint8_t *data, int siz
args->value = buffer+SIZEOF_LENGTH;
args->length = size;
sz = cb(args);
if (sz < 0)
return -1;
if (sz == 0)
break;
if (sz < 0)
return -1;
if (args->type == SPROTO_TSTRING) {
--sz;
}
fill_size(buffer, sz);
buffer += SIZEOF_LENGTH+sz;
size -=sz;
@@ -829,13 +833,13 @@ encode_array(sproto_callback cb, struct sproto_arg *args, uint8_t *data, int siz
break;
}
sz = buffer - (data + SIZEOF_LENGTH);
if (sz == 0)
if (sz == 0) // empty array
return 0;
return fill_size(data, sz);
}
int
sproto_encode(struct sproto_type *st, void * buffer, int size, sproto_callback cb, void *ud) {
sproto_encode(const struct sproto_type *st, void * buffer, int size, sproto_callback cb, void *ud) {
struct sproto_arg args;
uint8_t * header = buffer;
uint8_t * data;
@@ -878,7 +882,7 @@ sproto_encode(struct sproto_type *st, void * buffer, int size, sproto_callback c
sz = cb(&args);
if (sz < 0)
return -1;
if (sz == 0)
if (sz == 0) // nil object
continue;
if (sz == sizeof(uint32_t)) {
if (u.u32 < 0x7fff) {
@@ -895,11 +899,10 @@ sproto_encode(struct sproto_type *st, void * buffer, int size, sproto_callback c
break;
}
case SPROTO_TSTRUCT:
case SPROTO_TSTRING: {
case SPROTO_TSTRING:
sz = encode_object(cb, &args, data, size);
break;
}
}
}
if (sz < 0)
return -1;
@@ -1032,7 +1035,7 @@ decode_array(sproto_callback cb, struct sproto_arg *args, uint8_t * stream) {
}
int
sproto_decode(struct sproto_type *st, const void * data, int size, sproto_callback cb, void *ud) {
sproto_decode(const struct sproto_type *st, const void * data, int size, sproto_callback cb, void *ud) {
struct sproto_arg args;
int total = size;
uint8_t * stream;

View File

@@ -17,12 +17,12 @@ struct sproto_type;
struct sproto * sproto_create(const void * proto, size_t sz);
void sproto_release(struct sproto *);
int sproto_prototag(struct sproto *, const char * name);
const char * sproto_protoname(struct sproto *, int proto);
int sproto_prototag(const struct sproto *, const char * name);
const char * sproto_protoname(const struct sproto *, int proto);
// SPROTO_REQUEST(0) : request, SPROTO_RESPONSE(1): response
struct sproto_type * sproto_protoquery(struct sproto *, int proto, int what);
struct sproto_type * sproto_protoquery(const struct sproto *, int proto, int what);
struct sproto_type * sproto_type(struct sproto *, const char * type_name);
struct sproto_type * sproto_type(const struct sproto *, const char * type_name);
int sproto_pack(const void * src, int srcsz, void * buffer, int bufsz);
int sproto_unpack(const void * src, int srcsz, void * buffer, int bufsz);
@@ -41,8 +41,8 @@ struct sproto_arg {
typedef int (*sproto_callback)(const struct sproto_arg *args);
int sproto_decode(struct sproto_type *, const void * data, int size, sproto_callback cb, void *ud);
int sproto_encode(struct sproto_type *, void * buffer, int size, sproto_callback cb, void *ud);
int sproto_decode(const struct sproto_type *, const void * data, int size, sproto_callback cb, void *ud);
int sproto_encode(const struct sproto_type *, void * buffer, int size, sproto_callback cb, void *ud);
// for debug use
void sproto_dump(struct sproto *);

290
lualib/dns.lua Normal file
View File

@@ -0,0 +1,290 @@
--[[
lua dns resolver library
See https://github.com/xjdrew/levent/blob/master/levent/dns.lua for more detail
-- resource record type:
-- TYPE value and meaning
-- A 1 a host address
-- NS 2 an authoritative name server
-- MD 3 a mail destination (Obsolete - use MX)
-- MF 4 a mail forwarder (Obsolete - use MX)
-- CNAME 5 the canonical name for an alias
-- SOA 6 marks the start of a zone of authority
-- MB 7 a mailbox domain name (EXPERIMENTAL)
-- MG 8 a mail group member (EXPERIMENTAL)
-- MR 9 a mail rename domain name (EXPERIMENTAL)
-- NULL 10 a null RR (EXPERIMENTAL)
-- WKS 11 a well known service description
-- PTR 12 a domain name pointer
-- HINFO 13 host information
-- MINFO 14 mailbox or mail list information
-- MX 15 mail exchange
-- TXT 16 text strings
-- AAAA 28 a ipv6 host address
-- only appear in the question section:
-- AXFR 252 A request for a transfer of an entire zone
-- MAILB 253 A request for mailbox-related records (MB, MG or MR)
-- MAILA 254 A request for mail agent RRs (Obsolete - see MX)
-- * 255 A request for all records
--
-- resource recode class:
-- IN 1 the Internet
-- CS 2 the CSNET class (Obsolete - used only for examples in some obsolete RFCs)
-- CH 3 the CHAOS class
-- HS 4 Hesiod [Dyer 87]
-- only appear in the question section:
-- * 255 any class
-- ]]
--[[
-- struct header {
-- uint16_t tid # identifier assigned by the program that generates any kind of query.
-- uint16_t flags # flags
-- uint16_t qdcount # the number of entries in the question section.
-- uint16_t ancount # the number of resource records in the answer section.
-- uint16_t nscount # the number of name server resource records in the authority records section.
-- uint16_t arcount # the number of resource records in the additional records section.
-- }
--
-- request body:
-- struct request {
-- string name
-- uint16_t atype
-- uint16_t class
-- }
--
-- response body:
-- struct response {
-- string name
-- uint16_t atype
-- uint16_t class
-- uint16_t ttl
-- uint16_t rdlength
-- string rdata
-- }
--]]
local skynet = require "skynet"
local socket = require "socket"
local MAX_DOMAIN_LEN = 1024
local MAX_LABEL_LEN = 63
local MAX_PACKET_LEN = 2048
local DNS_HEADER_LEN = 12
local QTYPE = {
A = 1,
CNAME = 5,
AAAA = 28,
}
local QCLASS = {
IN = 1,
}
local dns = {}
local function verify_domain_name(name)
if #name > MAX_DOMAIN_LEN then
return false
end
if not name:match("^[%l%d-%.]+$") then
return false
end
for w in name:gmatch("([%w-]+)%.?") do
if #w > MAX_LABEL_LEN then
return false
end
end
return true
end
local next_tid = 1
local function gen_tid()
local tid = next_tid
next_tid = next_tid + 1
return tid
end
local function pack_header(t)
return string.pack(">HHHHHH",
t.tid, t.flags, t.qdcount, t.ancount or 0, t.nscount or 0, t.arcount or 0)
end
local function pack_question(name, qtype, qclass)
local labels = {}
for w in name:gmatch("([%w-]+)%.?") do
table.insert(labels, string.pack("s1",w))
end
table.insert(labels, '\0')
table.insert(labels, string.pack(">HH", qtype, qclass))
return table.concat(labels)
end
local function unpack_header(chunk)
local tid, flags, qdcount, ancount, nscount, arcount, left = string.unpack(">HHHHHH", chunk)
return {
tid = tid,
flags = flags,
qdcount = qdcount,
ancount = ancount,
nscount = nscount,
arcount = arcount
}, left
end
-- unpack a resource name
local function unpack_name(chunk, left)
local t = {}
local jump_pointer
local tag, offset, label
while true do
tag, left = string.unpack("B", chunk, left)
if tag & 0xc0 == 0xc0 then
-- pointer
offset,left = string.unpack(">H", chunk, left - 1)
offset = offset & 0x3fff
if not jump_pointer then
jump_pointer = left
end
-- offset is base 0, need to plus 1
left = offset + 1
elseif tag == 0 then
break
else
label, left = string.unpack("s1", chunk, left - 1)
t[#t+1] = label
end
end
return table.concat(t, "."), jump_pointer or left
end
local function unpack_question(chunk, left)
local name, left = unpack_name(chunk, left)
local atype, class, left = string.unpack(">HH", chunk, left)
return {
name = name,
atype = atype,
class = class
}, left
end
local function unpack_answer(chunk, left)
local name, left = unpack_name(chunk, left)
local atype, class, ttl, rdata, left = string.unpack(">HHI4s2", chunk, left)
return {
name = name,
atype = atype,
class = class,
ttl = ttl,
rdata = rdata
},left
end
local function unpack_rdata(qtype, chunk)
if qtype == QTYPE.A then
local a,b,c,d = string.unpack("BBBB", chunk)
return string.format("%d.%d.%d.%d", a,b,c,d)
elseif qtype == QTYPE.AAAA then
local a,b,c,d,e,f,g,h = string.unpack(">HHHHHHHH", chunk)
return string.format("%x:%x:%x:%x:%x:%x:%x:%x", a, b, c, d, e, f, g, h)
else
error("Error qtype " .. qtype)
end
end
local dns_server
local request_pool = {}
local function resolve(content)
if #content < DNS_HEADER_LEN then
-- drop
skynet.error("Recv an invalid package when dns query")
return
end
local answer_header,left = unpack_header(content)
-- verify answer
assert(answer_header.qdcount == 1, "malformed packet")
local resp = request_pool[answer_header.tid]
if not resp then
skynet.error("Recv an invalid tid when dns query")
return
end
local question,left = unpack_question(content, left)
if question.name ~= resp.name then
skynet.error("Recv an invalid name when dns query")
return
end
local ttl
local answer
local answers = {}
for i=1, answer_header.ancount do
answer, left = unpack_answer(content, left)
-- only extract qtype address
if answer.atype == resp.qtype then
local ip = unpack_rdata(resp.qtype, answer.rdata)
ttl = ttl and math.min(ttl, answer.ttl) or answer.ttl
answers[#answers+1] = ip
end
end
if #answers > 0 then
resp.answers = answers
end
skynet.wakeup(resp.co)
end
function dns.server(server, port)
if not server then
local f = assert(io.open "/etc/resolv.conf")
for line in f:lines() do
server = line:match("%s*nameserver%s+([^%s]+)")
if server then
break
end
end
assert(server, "Can't get nameserver")
end
dns_server = socket.udp(function(str, from)
resolve(str)
end)
socket.udp_connect(dns_server, server, port or 53)
return server
end
local function suspend(tid, name, qtype)
local req = {
name = name,
tid = tid,
qtype = qtype,
time = skynet.now(), -- for timeout
co = coroutine.running(),
}
request_pool[tid] = req
skynet.wait()
local answers = request_pool[tid].answers
request_pool[tid] = nil
assert(answers, "no ip")
return answers[1], answers
end
function dns.resolve(name, ipv6)
local qtype = ipv6 and QTYPE.AAAA or QTYPE.A
local name = name:lower()
assert(verify_domain_name(name) , "illegal name")
local question_header = {
tid = gen_tid(),
flags = 0x100, -- flags: 00000001 00000000, set RD
qdcount = 1,
}
local req = pack_header(question_header) .. pack_question(name, qtype, QCLASS.IN)
assert(dns_server, "Call dns.server fist")
socket.write(dns_server, req)
return suspend(question_header.tid, name, qtype)
end
return dns

View File

@@ -14,10 +14,17 @@ local function request(fd, method, host, url, recvheader, header, content)
for k,v in pairs(header) do
header_content = string.format("%s%s:%s\r\n", header_content, k, v)
end
if header.host then
host = ""
else
host = string.format("host:%s\r\n", host)
end
else
host = string.format("host:%s\r\n",host)
end
if content then
local data = string.format("%s %s HTTP/1.1\r\nhost:%s\r\ncontent-length:%d\r\n%s\r\n%s", method, url, host, #content, header_content, content)
local data = string.format("%s %s HTTP/1.1\r\n%scontent-length:%d\r\n%s\r\n%s", method, url, host, #content, header_content, content)
write(data)
else
local request_header = string.format("%s %s HTTP/1.1\r\nhost:%s\r\ncontent-length:0\r\n%s\r\n", method, url, host, header_content)

View File

@@ -2,6 +2,7 @@ local internal = require "http.internal"
local table = table
local string = string
local type = type
local httpd = {}
@@ -113,7 +114,13 @@ local function writeall(writefunc, statuscode, bodyfunc, header)
writefunc(statusline)
if header then
for k,v in pairs(header) do
writefunc(string.format("%s: %s\r\n", k,v))
if type(v) == "table" then
for _,v in ipairs(v) do
writefunc(string.format("%s: %s\r\n", k,v))
end
else
writefunc(string.format("%s: %s\r\n", k,v))
end
end
end
local t = type(bodyfunc)

View File

@@ -1,3 +1,6 @@
local table = table
local type = type
local M = {}
local LIMIT = 8192
@@ -83,7 +86,12 @@ function M.parseheader(lines, from, header)
end
name = name:lower()
if header[name] then
header[name] = header[name] .. ", " .. value
local v = header[name]
if type(v) == "table" then
table.insert(v, value)
else
header[name] = { v , value }
end
else
header[name] = value
end

View File

@@ -30,12 +30,14 @@ function sharemap.writer(typename, obj)
local sp = loadsp()
obj = obj or {}
local stmobj = stm.new(sp:encode(typename,obj))
obj.__typename = typename
obj.__obj = stmobj
obj.__data = obj
obj.commit = sharemap.commit
obj.copy = sharemap.copy
return setmetatable(obj, { __index = obj.__data, __newindex = obj.__data })
local ret = {
__typename = typename,
__obj = stmobj,
__data = obj,
commit = sharemap.commit,
copy = sharemap.copy,
}
return setmetatable(ret, { __index = obj, __newindex = obj })
end
local function decode(msg, sz, self)
@@ -63,7 +65,7 @@ function sharemap.reader(typename, stmcpy)
__data = data,
update = sharemap.update,
}
return setmetatable(obj, { __index = obj.__data, __newindex = error })
return setmetatable(obj, { __index = data, __newindex = error })
end
return sharemap

View File

@@ -398,6 +398,7 @@ skynet.pack = assert(c.pack)
skynet.packstring = assert(c.packstring)
skynet.unpack = assert(c.unpack)
skynet.tostring = assert(c.tostring)
skynet.trash = assert(c.trash)
local function yield_call(service, session)
watching_session[session] = service

View File

@@ -1,5 +1,6 @@
local driver = require "socketdriver"
local skynet = require "skynet"
local skynet_core = require "skynet.core"
local assert = assert
local socket = {} -- api
@@ -127,7 +128,9 @@ socket_message[6] = function(id, size, data, address)
driver.drop(data, size)
return
end
s.callback(data, size, address)
local str = skynet.tostring(data, size)
skynet_core.trash(data, size)
s.callback(str, address)
end
skynet.register_protocol {

View File

@@ -13,14 +13,23 @@ function sproto_mt:__gc()
core.deleteproto(self.__cobj)
end
function sproto.new(bin,sz,nogc)
local cobj = assert(core.newproto(bin,sz))
function sproto.new(bin)
local cobj = assert(core.newproto(bin))
local self = {
__cobj = cobj,
__tcache = setmetatable( {} , weak_mt ),
__pcache = setmetatable( {} , weak_mt ),
}
return setmetatable(self, nogc and sproto_nogc or sproto_mt)
return setmetatable(self, sproto_mt)
end
function sproto.sharenew(cobj)
local self = {
__cobj = cobj,
__tcache = setmetatable( {} , weak_mt ),
__pcache = setmetatable( {} , weak_mt ),
}
return setmetatable(self, sproto_nogc)
end
function sproto.parse(ptext)

View File

@@ -8,16 +8,19 @@ function loader.register(filename, index)
local f = assert(io.open(filename), "Can't open sproto file")
local data = f:read "a"
f:close()
local bin = parser.parse(data)
core.saveproto(bin, index)
local sp = core.newproto(parser.parse(data))
core.saveproto(sp, index)
end
loader.save = core.saveproto
function loader.save(bin, index)
local sp = core.newproto(bin)
core.saveproto(sp, index)
end
function loader.load(index)
local bin, sz = core.loadproto(index)
local sp = core.loadproto(index)
-- no __gc in metatable
return sproto.new(bin,sz, true)
return sproto.sharenew(sp)
end
return loader

View File

@@ -84,7 +84,7 @@ local typedef = P {
FIELD = namedpat("field", (name * blanks * tag * blank0 * ":" * blank0 * (C"*")^0 * typename * mainkey^0)),
STRUCT = P"{" * multipat(V"FIELD" + V"TYPE") * P"}",
TYPE = namedpat("type", P"." * name * blank0 * V"STRUCT" ),
SUBPROTO = Ct((C"request" + C"response") * blanks * (name + V"STRUCT")),
SUBPROTO = Ct((C"request" + C"response") * blanks * (typename + V"STRUCT")),
PROTOCOL = namedpat("protocol", name * blanks * tag * blank0 * P"{" * multipat(V"SUBPROTO") * P"}"),
ALL = multipat(V"TYPE" + V"PROTOCOL"),
}
@@ -186,6 +186,32 @@ local function checktype(types, ptype, t)
end
end
local function check_protocol(r)
local map = {}
local type = r.type
for name, v in pairs(r.protocol) do
local tag = v.tag
local request = v.request
local response = v.response
local p = map[tag]
if p then
error(string.format("redefined protocol tag %d at %s", tag, name))
end
if request and not type[request] then
error(string.format("Undefined request type %s in protocol %s", request, name))
end
if response and not type[response] then
error(string.format("Undefined response type %s in protocol %s", response, name))
end
map[tag] = v
end
return r
end
local function flattypename(r)
for typename, t in pairs(r.type) do
for _, f in pairs(t) do
@@ -204,7 +230,7 @@ end
local function parser(text,filename)
local state = { file = filename, pos = 0, line = 1 }
local r = lpeg.match(proto * -1 + exception , text , 1, state )
return flattypename(adjust(r))
return flattypename(check_protocol(adjust(r)))
end
--[[

View File

@@ -1,5 +1,5 @@
#ifndef __MALLOC_HOOK_H
#define __MALLOC_HOOK_H
#ifndef SKYNET_MALLOC_HOOK_H
#define SKYNET_MALLOC_HOOK_H
#include <stdlib.h>
@@ -10,5 +10,5 @@ extern size_t mallctl_int64(const char* name, size_t* newval);
extern int mallctl_opt(const char* name, int* newval);
extern void dump_c_mem(void);
#endif /* __MALLOC_HOOK_H */
#endif /* SKYNET_MALLOC_HOOK_H */

View File

@@ -1,5 +1,5 @@
#ifndef _RWLOCK_H_
#define _RWLOCK_H_
#ifndef SKYNET_RWLOCK_H
#define SKYNET_RWLOCK_H
struct rwlock {
int write;

11
test/testdns.lua Normal file
View File

@@ -0,0 +1,11 @@
local skynet = require "skynet"
local dns = require "dns"
skynet.start(function()
print("nameserver:", dns.server()) -- set nameserver
-- you can specify the server like dns.server("8.8.4.4", 53)
local ip, ips = dns.resolve "github.com"
for k,v in ipairs(ips) do
print("github.com",v)
end
end)

View File

@@ -1,16 +1,24 @@
local skynet = require "skynet"
local httpc = require "http.httpc"
local dns = require "dns"
skynet.start(function()
print("GET baidu.com")
local header = {}
local status, body = httpc.get("baidu.com", "/", header)
local respheader = {}
local status, body = httpc.get("baidu.com", "/", respheader)
print("[header] =====>")
for k,v in pairs(header) do
for k,v in pairs(respheader) do
print(k,v)
end
print("[body] =====>", status)
print(body)
local respheader = {}
dns.server()
local ip = dns.resolve "baidu.com"
print(string.format("GET %s (baidu.com)", ip))
local status, body = httpc.get("baidu.com", "/", respheader, { host = "baidu.com" })
print(status)
skynet.exit()
end)

View File

@@ -3,16 +3,15 @@ local socket = require "socket"
local function server()
local host
host = socket.udp(function(data, sz, from)
local str = skynet.tostring(data,sz) -- skynet.tostring should call only once, because it will free the pointer data
host = socket.udp(function(str, from)
print("server 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(data, sz, from)
print("client recv", skynet.tostring(data,sz), socket.udp_address(from))
local c = socket.udp(function(str, from)
print("client recv", str, socket.udp_address(from))
end)
socket.udp_connect(c, "127.0.0.1", 8765)
for i=1,20 do