libuv学习笔记(21)
DNS相关功能
数据结构
typedef struct uv_getaddrinfo_s uv_getaddrinfo_t;
struct uv_getaddrinfo_s {
UV_REQ_FIELDS//uv_req_t的成员
uv_loop_t* loop;
//UV_GETADDRINFO_PRIVATE_FIELDS展开:
struct uv__work work_req;//线程池任务
uv_getaddrinfo_cb getaddrinfo_cb;
void* alloc;//分配的内存的指针,方便释放
WCHAR* node;
WCHAR* service;
struct addrinfoW* addrinfow;
struct addrinfo* addrinfo;//结果,需要通过uv_freeaddrinfo()释放
int retcode;
};
typedef struct uv_getnameinfo_s uv_getnameinfo_t;
struct uv_getnameinfo_s {
UV_REQ_FIELDS//uv_req_t的成员
uv_loop_t* loop;
//UV_GETNAMEINFO_PRIVATE_FIELDS展开:
struct uv__work work_req; //线程池任务
uv_getnameinfo_cb getnameinfo_cb;
struct sockaddr_storage storage;//保存询问的地址
int flags;
char host[NI_MAXHOST];
char service[NI_MAXSERV];
int retcode;
};
相关函数
`uv_getaddrinfo,获取地址信息
int uv_getaddrinfo(uv_loop_t* loop,
uv_getaddrinfo_t* req,
uv_getaddrinfo_cb getaddrinfo_cb,
const char* node,//主机名或ip地址
const char* service,//服务名或者端口
const struct addrinfo* hints) {
int nodesize = 0;
int servicesize = 0;
int hintssize = 0;
char* alloc_ptr = NULL;
int err;
if (req == NULL || (node == NULL && service == NULL)) {
err = WSAEINVAL;
goto error;
}
uv_req_init(loop, (uv_req_t*)req);//初始化请求
req->getaddrinfo_cb = getaddrinfo_cb;
req->addrinfo = NULL;
req->type = UV_GETADDRINFO;
req->loop = loop;
req->retcode = 0;
//获取node与service的长度
//此处省略
//
if (hints != NULL) {
hintssize = ALIGNED_SIZE(sizeof(struct addrinfoW));
}
//申请内存
alloc_ptr = (char*)uv__malloc(nodesize + servicesize + hintssize);
if (!alloc_ptr) {
err = WSAENOBUFS;
goto error;
}
req->alloc = (void*)alloc_ptr;
//将node和service utf8转换为unicode
//都存储在alloc_ptr指向的内存中
//此处省略
//此处省略
//将hints 的内容复制到req->addrinfow
//此处省略
uv__req_register(loop, req);
if (getaddrinfo_cb) {//有回调函数,那么走loop流程
uv__work_submit(loop,
&req->work_req,
uv__getaddrinfo_work,//调用GetAddrInfoW(req->node, req->service, hints, &req->addrinfow);
uv__getaddrinfo_done);//
return 0;
} else {//没有回调函数,直接调用
uv__getaddrinfo_work(&req->work_req);
uv__getaddrinfo_done(&req->work_req, 0);
return req->retcode;
}
error:
if (req != NULL) {
uv__free(req->alloc);
req->alloc = NULL;
}
return uv_translate_sys_error(err);
}
获取信息之后loop调用的回调
static void uv__getaddrinfo_done(struct uv__work* w, int status) {
uv_getaddrinfo_t* req;
int addrinfo_len = 0;
int name_len = 0;
size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo));
struct addrinfoW* addrinfow_ptr;
struct addrinfo* addrinfo_ptr;
char* alloc_ptr = NULL;
char* cur_ptr = NULL;
req = container_of(w, uv_getaddrinfo_t, work_req);
uv__free(req->alloc);//释放之前申请的内存
req->alloc = NULL;
if (status == UV_ECANCELED) {//被取消的请求
assert(req->retcode == 0);
req->retcode = UV_EAI_CANCELED;
goto complete;
}
if (req->retcode == 0) {
// 将addrinfoW转换为addrinfo
//此处省略
//将名字转换为utf8
//此处省略
//释放req->addrinfow
if (req->addrinfow != NULL) {
FreeAddrInfoW(req->addrinfow);
req->addrinfow = NULL;
}
complete:
uv__req_unregister(req->loop, req);
/* finally do callback with converted result */
if (req->getaddrinfo_cb)//调用用户的回调函数
req->getaddrinfo_cb(req, req->retcode, req->addrinfo);
}
释放地址内存
void uv_freeaddrinfo(struct addrinfo* ai) {
char* alloc_ptr = (char*)ai;
uv__free(alloc_ptr);
}
通过地址获取主机名
int uv_getnameinfo(uv_loop_t* loop,
uv_getnameinfo_t* req,
uv_getnameinfo_cb getnameinfo_cb,
const struct sockaddr* addr,//地址
int flags) {
if (req == NULL || addr == NULL)
return UV_EINVAL;
if (addr->sa_family == AF_INET) {
memcpy(&req->storage,
addr,
sizeof(struct sockaddr_in));
} else if (addr->sa_family == AF_INET6) {
memcpy(&req->storage,
addr,
sizeof(struct sockaddr_in6));
} else {
return UV_EINVAL;
}
uv_req_init(loop, (uv_req_t*)req);
uv__req_register(loop, req);
req->getnameinfo_cb = getnameinfo_cb;
req->flags = flags;
req->type = UV_GETNAMEINFO;
req->loop = loop;
req->retcode = 0;
if (getnameinfo_cb) {
uv__work_submit(loop,
&req->work_req,
uv__getnameinfo_work,//调用GetNameInfoW
uv__getnameinfo_done);
return 0;
} else {
uv__getnameinfo_work(&req->work_req);
uv__getnameinfo_done(&req->work_req, 0);
return req->retcode;
}
}
loop回调
static void uv__getnameinfo_done(struct uv__work* w, int status) {
uv_getnameinfo_t* req;
char* host;
char* service;
req = container_of(w, uv_getnameinfo_t, work_req);
uv__req_unregister(req->loop, req);
host = service = NULL;
if (status == UV_ECANCELED) {
assert(req->retcode == 0);
req->retcode = UV_EAI_CANCELED;
} else if (req->retcode == 0) {
host = req->host;
service = req->service;
}
if (req->getnameinfo_cb)//回调用户回调函数
req->getnameinfo_cb(req, req->retcode, host, service);
}