diff --git a/.ycm_extra_conf.py b/.ycm_extra_conf.py
new file mode 100644
index 000000000..dc2334945
--- /dev/null
+++ b/.ycm_extra_conf.py
@@ -0,0 +1,187 @@
+# Generated by YCM Generator at 2021-11-18 20:34:43.424020
+
+# This file is NOT licensed under the GPLv3, which is the license for the rest
+# of YouCompleteMe.
+#
+# Here's the license text for this file:
+#
+# This is free and unencumbered software released into the public domain.
+#
+# Anyone is free to copy, modify, publish, use, compile, sell, or
+# distribute this software, either in source code form or as a compiled
+# binary, for any purpose, commercial or non-commercial, and by any
+# means.
+#
+# In jurisdictions that recognize copyright laws, the author or authors
+# of this software dedicate any and all copyright interest in the
+# software to the public domain. We make this dedication for the benefit
+# of the public at large and to the detriment of our heirs and
+# successors. We intend this dedication to be an overt act of
+# relinquishment in perpetuity of all present and future rights to this
+# software under copyright law.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+# For more information, please refer to
+
+import os
+import ycm_core
+
+flags = [
+ '-isystem'
+ './lib_acl/include',
+ '-isystem'
+ './lib_protocol/include',
+ '-isystem'
+ './lib_acl_cpp/include',
+ '-isystem'
+ './lib_fiber/c/include',
+ '-isystem'
+ './lib_fiber/cpp/include',
+
+ '-x',
+ 'c++',
+ '-I.',
+ '-I./lib_acl/include',
+ '-I./lib_acl/src',
+ '-I./lib_protocol/include',
+ '-I./lib_protocol/src',
+ '-I./lib_acl_cpp/include',
+ '-I./lib_acl_cpp/src',
+ '-I./lib_fiber/c/include',
+ '-I./lib_fiber/c/src',
+ '-I./lib_fiber/cpp/include',
+ '-I./lib_fiber/cpp/src',
+ '-DACL_PREPARE_COMPILE',
+ '-DACL_WRITEABLE_CHECK',
+ '-DHAVE_CONFIG_H',
+ '-DNO_TCMALLOC_SAMPLES',
+ '-DUSE_BOOST_JMP',
+ '-DUSE_FAST_RING',
+ '-D_FILE_OFFSET_BITS=64',
+ '-D_POSIX_PTHREAD_SEMANTICS',
+ '-D_REENTRANT',
+ '-D_USE_FAST_MACRO',
+ '-D__CLASSIC_C__',
+ '-W',
+ '-Wall',
+ '-Wdeclaration-after-statement',
+ '-Werror',
+ '-Wno-long-long',
+ '-Wpointer-arith',
+ '-Wshadow',
+ '-Wuninitialized',
+ '-std=c++11',
+]
+
+
+# Set this to the absolute path to the folder (NOT the file!) containing the
+# compile_commands.json file to use that instead of 'flags'. See here for
+# more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html
+#
+# You can get CMake to generate this file for you by adding:
+# set( CMAKE_EXPORT_COMPILE_COMMANDS 1 )
+# to your CMakeLists.txt file.
+#
+# Most projects will NOT need to set this to anything; you can just change the
+# 'flags' list of compilation flags. Notice that YCM itself uses that approach.
+compilation_database_folder = ''
+
+if os.path.exists( compilation_database_folder ):
+ database = ycm_core.CompilationDatabase( compilation_database_folder )
+else:
+ database = None
+
+SOURCE_EXTENSIONS = ['.cpp', '.cxx', '.cc', '.c' ]
+
+def DirectoryOfThisScript():
+ return os.path.dirname( os.path.abspath( __file__ ) )
+
+
+def MakeRelativePathsInFlagsAbsolute( flags, working_directory ):
+ if not working_directory:
+ return list( flags )
+ new_flags = []
+ make_next_absolute = False
+ path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ]
+ for flag in flags:
+ new_flag = flag
+
+ if make_next_absolute:
+ make_next_absolute = False
+ if not flag.startswith( '/' ):
+ new_flag = os.path.join( working_directory, flag )
+
+ for path_flag in path_flags:
+ if flag == path_flag:
+ make_next_absolute = True
+ break
+
+ if flag.startswith( path_flag ):
+ path = flag[ len( path_flag ): ]
+ new_flag = path_flag + os.path.join( working_directory, path )
+ break
+
+ if new_flag:
+ new_flags.append( new_flag )
+ return new_flags
+
+
+def IsHeaderFile( filename ):
+ extension = os.path.splitext( filename )[ 1 ]
+ return extension in [ '.H', '.h', '.hxx', '.hpp', '.hh' ]
+
+
+def GetCompilationInfoForFile( filename ):
+ # The compilation_commands.json file generated by CMake does not have entries
+ # for header files. So we do our best by asking the db for flags for a
+ # corresponding source file, if any. If one exists, the flags for that file
+ # should be good enough.
+ if IsHeaderFile( filename ):
+ basename = os.path.splitext( filename )[ 0 ]
+ for extension in SOURCE_EXTENSIONS:
+ replacement_file = basename + extension
+ if os.path.exists( replacement_file ):
+ compilation_info = database.GetCompilationInfoForFile(
+ replacement_file )
+ if compilation_info.compiler_flags_:
+ return compilation_info
+ return None
+ return database.GetCompilationInfoForFile( filename )
+
+
+def FlagsForFile( filename, **kwargs ):
+ if database:
+ # Bear in mind that compilation_info.compiler_flags_ does NOT return a
+ # python list, but a "list-like" StringVec object
+ compilation_info = GetCompilationInfoForFile( filename )
+ if not compilation_info:
+ return None
+
+ final_flags = MakeRelativePathsInFlagsAbsolute(
+ compilation_info.compiler_flags_,
+ compilation_info.compiler_working_dir_ )
+
+ else:
+ relative_to = DirectoryOfThisScript()
+ final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to )
+
+ return {
+ 'flags': final_flags,
+ 'do_cache': True
+ }
+
+def Settings( **kwargs ):
+ language = kwargs[ 'language' ]
+ if language == 'cfamily':
+ return {
+ 'flags': flags
+ }
+
+ return {}
diff --git a/app/master/daemon/main.cpp b/app/master/daemon/main.cpp
index f84e57e09..8fac35f07 100644
--- a/app/master/daemon/main.cpp
+++ b/app/master/daemon/main.cpp
@@ -185,7 +185,7 @@ int main(int argc, char **argv)
}
if (setsid() == -1 && getsid(0) != getpid())
- acl_msg_fatal("unable to set session %s", acl_last_serror());
+ acl_msg_warn("unable to set session %s", acl_last_serror());
/*
* Make some room for plumbing with file descriptors. XXX This breaks
diff --git a/app/wizard/tmpl/http/master_fiber.cf b/app/wizard/tmpl/http/master_fiber.cf
index 30317fc47..200551b10 100644
--- a/app/wizard/tmpl/http/master_fiber.cf
+++ b/app/wizard/tmpl/http/master_fiber.cf
@@ -99,6 +99,9 @@ service $
# 当 acl_master 退出时,如果该值置1则该程序不等所有连接处理完毕便立即退出
fiber_quick_abort = 1
+# 是否启用协程共享栈模式
+ fiber_share_stack = 0
+
# 当 fiber_quick_abort 为 0 且本配置项大于 0 时,该配置项才有效,指定了
# 本进程在所有连接退出前的最大等待时间(秒)
fiber_wait_limit = 0
diff --git a/app/wizard/tmpl/master/master_fiber.cf b/app/wizard/tmpl/master/master_fiber.cf
index 3df3986aa..712e1c01f 100644
--- a/app/wizard/tmpl/master/master_fiber.cf
+++ b/app/wizard/tmpl/master/master_fiber.cf
@@ -99,6 +99,9 @@ service $
# 当 acl_master 退出时,如果该值置1则该程序不等所有连接处理完毕便立即退出
fiber_quick_abort = 1
+# 是否启用协程共享栈模式
+ fiber_share_stack = 0
+
# 当 fiber_quick_abort 为 0 且本配置项大于 0 时,该配置项才有效,指定了
# 本进程在所有连接退出前的最大等待时间(秒)
fiber_wait_limit = 0
diff --git a/app/wizard_demo/httpd_proxy/http_servlet.cpp b/app/wizard_demo/httpd_proxy/http_servlet.cpp
index dffe68b7f..b93414b6b 100644
--- a/app/wizard_demo/httpd_proxy/http_servlet.cpp
+++ b/app/wizard_demo/httpd_proxy/http_servlet.cpp
@@ -81,8 +81,7 @@ bool http_servlet::on_hello(request_t& req, response_t& res)
return false;
}
- if (i % 10000 == 0)
- {
+ if (i % 10000 == 0) {
sleep(1);
printf("i=%d\n", (int) i);
}
@@ -96,22 +95,27 @@ bool http_servlet::on_hello(request_t& req, response_t& res)
bool http_servlet::transfer_get(request_t& req, response_t& res)
{
- http_transfer fiber_peer(acl::HTTP_METHOD_GET, req, res, port_);
- fiber_peer.start();
+ http_transfer* fiber_peer = new
+ http_transfer(acl::HTTP_METHOD_GET, req, res, port_);
+ fiber_peer->start();
bool keep_alive;
- fiber_peer.wait(&keep_alive);
+ fiber_peer->wait(&keep_alive);
+
+ delete fiber_peer;
return keep_alive && req.isKeepAlive();
}
bool http_servlet::transfer_post(request_t& req, response_t& res)
{
- http_transfer fiber_peer(acl::HTTP_METHOD_POST, req, res, port_);
- fiber_peer.start();
+ http_transfer* fiber_peer = new
+ http_transfer(acl::HTTP_METHOD_POST, req, res, port_);
+ fiber_peer->start();
bool keep_alive;
- fiber_peer.wait(&keep_alive);
+ fiber_peer->wait(&keep_alive);
+ delete fiber_peer;
printf("transfer_post finished\r\n");
return keep_alive && req.isKeepAlive();
}
@@ -136,17 +140,25 @@ bool http_servlet::doConnect(request_t& req, response_t&)
} else {
host = phost;
}
+
printf("remote host=%s, current fiber=%p\r\n", host.c_str(), acl_fiber_running());
- acl::socket_stream peer;
- if (!peer.open(host, 5, 5, acl::time_unit_s)) {
+ acl::socket_stream* peer = new acl::socket_stream;
+ if (!peer->open(host, 5, 5, acl::time_unit_s)) {
logger_error("connect %s error %s", host.c_str(), acl::last_serror());
+ delete peer;
return false;
}
- printf("connect %s ok, fd=%d\r\n", host.c_str(), peer.sock_handle());
+ printf("connect %s ok, fd=%d\r\n", host.c_str(), peer->sock_handle());
- acl::socket_stream& local = req.getSocketStream();
- local.set_rw_timeout(3);
+#define USE_REFER
+
+#ifdef USE_REFER
+ acl::socket_stream* local = &req.getSocketStream();
+#else
+ acl::socket_stream* local = new acl::socket_stream;
+ local->open(req.getSocketStream().sock_handle());
+#endif
#if 0
const char* ok = "";
@@ -159,43 +171,68 @@ bool http_servlet::doConnect(request_t& req, response_t&)
const char* ok = "HTTP/1.1 200 Connection Established\r\n\r\n";
size_t n = strlen(ok);
- if (local.write(ok, n) != (int) n) {
+ if (local->write(ok, n) != (int) n) {
logger_error("write connect response error");
+ delete peer;
+
+ local->unbind_sock();
+ delete local;
return false;
}
#endif
- transfer_tcp(local, peer);
+ transfer_tcp(*local, *peer);
+
+#ifndef USE_REFER
+ int fd = local->unbind_sock();
+ if (fd == -1) {
+ acl::socket_stream& ss = req.getSocketStream();
+ logger_warn("The socket=%d has been closed before!",
+ ss.sock_handle());
+ ss.unbind_sock();
+ }
+ delete local;
+#endif
+ delete peer;
return false;
}
-bool http_servlet::transfer_tcp(acl::socket_stream& local, acl::socket_stream& peer)
+bool http_servlet::transfer_tcp(acl::socket_stream& local,
+ acl::socket_stream& peer)
{
- local.set_rw_timeout(5);
- peer.set_rw_timeout(5);
+ local.set_rw_timeout(20);
+ peer.set_rw_timeout(20);
- tcp_transfer fiber_local(acl_fiber_running(), local, peer, false);
- tcp_transfer fiber_peer(acl_fiber_running(), peer, local, false);
+ tcp_transfer* fiber_local = new
+ tcp_transfer(acl_fiber_running(), local, peer, false);
+ tcp_transfer* fiber_peer = new
+ tcp_transfer(acl_fiber_running(), peer, local, false);
- fiber_local.set_peer(fiber_peer);
- fiber_peer.set_peer(fiber_local);
+ fiber_local->set_peer(fiber_peer);
+ fiber_local->set_local(true);
- fiber_peer.start();
- fiber_local.start();
+ fiber_peer->set_peer(fiber_local);
+ fiber_peer->set_local(false);
+
+ fiber_peer->start();
+ fiber_local->start();
//int fd_local = local.sock_handle();
//int fd_peer = peer.sock_handle();
//printf("wait local fiber, local fd=%d, peer fd=%d\r\n", fd_local, fd_peer);
- fiber_local.wait();
+ fiber_local->wait();
//printf("local fiber done, local fd=%d, peer fd=%d\r\n", fd_local, fd_peer);
//printf("wait peer fiber, local fd=%d, peer fd=%d\r\n", fd_local, fd_peer);
- fiber_peer.wait();
+ fiber_peer->wait();
//printf("peer fiber done, local fd=%d, peer fd=%d\r\n", fd_local, fd_peer);
//printf("transfer_tcp finished, local fd=%d, %d, peer fd=%d, %d\r\n",
// fiber_local.get_input().sock_handle(), fd_local,
// fiber_local.get_output().sock_handle(), fd_peer);
+
+ delete fiber_peer;
+ delete fiber_local;
return true;
}
diff --git a/app/wizard_demo/httpd_proxy/http_transfer.cpp b/app/wizard_demo/httpd_proxy/http_transfer.cpp
index 01d1e1324..8537306f0 100644
--- a/app/wizard_demo/httpd_proxy/http_transfer.cpp
+++ b/app/wizard_demo/httpd_proxy/http_transfer.cpp
@@ -8,14 +8,27 @@ http_transfer::http_transfer(acl::http_method_t method, request_t& req,
, req_(req)
, res_(res)
, client_(NULL)
-{}
+{
+ box_ = new acl::fiber_tbox;
+
+ acl::socket_stream& sin = req_.getSocketStream();
+ req_in_.open(sin.sock_handle());
+
+ acl::socket_stream& sout = res_.getSocketStream();
+ res_out_.open(sout.sock_handle());
+ res_client_ = res_.getClient();
+}
http_transfer::~http_transfer(void) {
+ req_in_.unbind_sock();
+ res_out_.unbind_sock();
+
delete client_;
+ delete box_;
}
void http_transfer::wait(bool* keep_alive) {
- bool* res = box_.pop();
+ bool* res = box_->pop();
assert(res);
*keep_alive = *res;
delete res;
@@ -36,7 +49,7 @@ void http_transfer::run(void) {
break;
}
- box_.push(res);
+ box_->push(res);
}
bool http_transfer::open_peer(request_t& req, acl::socket_stream& conn)
@@ -61,13 +74,17 @@ bool http_transfer::open_peer(request_t& req, acl::socket_stream& conn)
acl::string addr;
addr.format("%s|%d", buf.c_str(), port_);
- if (conn.open(addr, 0, 0)) {
- logger("connect %s ok", addr.c_str());
- return true;
+ if (!conn.open(addr, 0, 0)) {
+ logger_error("connect %s error %s",
+ addr.c_str(), acl::last_serror());
+ return false;
}
- logger_error("connect %s error %s", addr.c_str(), acl::last_serror());
- return false;
+ logger("connect %s ok", addr.c_str());
+
+ bool is_request = true, unzip = false, fixed_stream = true;
+ client_ = new acl::http_client(&conn, is_request, unzip, fixed_stream);
+ return true;
}
bool http_transfer::transfer_request_head(acl::socket_stream& conn) {
@@ -85,8 +102,7 @@ bool http_transfer::transfer_request_head(acl::socket_stream& conn) {
return false;
}
- //printf(">>>send head: [%s]\r\n", header.c_str());
- client_ = new acl::http_client(&conn, true);
+ printf(">>>send head: [%s]\r\n", header.c_str());
return true;
}
@@ -96,12 +112,11 @@ bool http_transfer::transfer_request_body(acl::socket_stream& conn) {
return true;
}
- acl::istream& in = req_.getInputStream();
long long n = 0;
char buf[8192];
while (n < length) {
- int ret = in.read(buf, sizeof(buf), false);
+ int ret = req_in_.read(buf, sizeof(buf), false);
if (ret == -1) {
logger_error("read request body error");
return false;
@@ -156,6 +171,9 @@ bool http_transfer::transfer_response(void) {
return false;
}
+ bool keep_alive = false; // xxxx
+ client_->header_update("Connection", "Close");
+
acl::string header;
client_->sprint_header(header, NULL);
if (header.empty()) {
@@ -167,32 +185,47 @@ bool http_transfer::transfer_response(void) {
printf("response head:\r\n[%s]\r\n", header.c_str());
- acl::ostream& out = res_.getOutputStream();
- if (out.write(header) == -1) {
+ //acl::ostream* out = &res_->getOutputStream();
+ if (res_out_.write(header) == -1) {
logger_error("send response head error");
return false;
}
+ //acl::http_client* out_client = res_->getClient();
+ //assert(out_client);
+
long long length = client_->body_length();
if (length == 0) {
- return client_->is_server_keep_alive();
+ return client_->is_server_keep_alive() && keep_alive;
}
+ HTTP_HDR_RES* hdr_res = client_->get_respond_head(NULL);
+ assert(hdr_res);
+ bool chunked = hdr_res->hdr.chunked ? true : false;
+
char buf[8192];
+
while (true) {
int ret = client_->read_body(buf, sizeof(buf));
if (ret <= 0) {
break;
- } else if (out.write(buf, ret) == -1) {
+ } else if (chunked) {
+ if (!res_client_->write_chunk(res_out_, buf, ret)) {
+ logger_error("send response body error");
+ return false;
+ }
+ } else if (res_out_.write(buf, ret) == -1) {
logger_error("send response body error");
return false;
}
}
-
- if (length < 0) {
- return false;
+ if (chunked) {
+ if (!res_client_->write_chunk_trailer(res_out_)) {
+ logger_error("write chunked trailer error");
+ return false;
+ }
}
- return client_->is_server_keep_alive();
+ return client_->is_server_keep_alive() && false;
}
diff --git a/app/wizard_demo/httpd_proxy/http_transfer.h b/app/wizard_demo/httpd_proxy/http_transfer.h
index fe34b3acc..635a81142 100644
--- a/app/wizard_demo/httpd_proxy/http_transfer.h
+++ b/app/wizard_demo/httpd_proxy/http_transfer.h
@@ -14,7 +14,7 @@ protected:
void run(void);
private:
- acl::fiber_tbox box_;
+ acl::fiber_tbox* box_;
int port_;
acl::http_method_t method_;
@@ -23,6 +23,10 @@ private:
acl::socket_stream conn_;
acl::http_client* client_;
+ acl::socket_stream req_in_;
+ acl::socket_stream res_out_;
+ acl::http_client* res_client_;
+
bool open_peer(request_t& req, acl::socket_stream& conn);
bool transfer_get(void);
diff --git a/app/wizard_demo/httpd_proxy/httpd_proxy_vc2019.vcxproj b/app/wizard_demo/httpd_proxy/httpd_proxy_vc2019.vcxproj
index 3dfbffced..9fb1dfa5d 100644
--- a/app/wizard_demo/httpd_proxy/httpd_proxy_vc2019.vcxproj
+++ b/app/wizard_demo/httpd_proxy/httpd_proxy_vc2019.vcxproj
@@ -155,7 +155,7 @@
Disabled
- ..\..\..\lib_acl_cpp\include;..\..\..\lib_acl\include;..\..\..\lib_fiber\c\include;..\..\..\lib_fiber\cpp\include;%(AdditionalIncludeDirectories)
+ ..\..\..\lib_acl_cpp\include;..\..\..\lib_acl\include;..\..\..\lib_fiber\c\include;..\..\..\lib_fiber\cpp\include;..\..\..\lib_protocol\include;%(AdditionalIncludeDirectories)
WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
false
EnableFastChecks
@@ -199,7 +199,7 @@
- ..\..\..\lib_acl_cpp\include;..\..\..\lib_acl\include;..\..\..\lib_fiber\c\include;..\..\..\lib_fiber\cpp\include;%(AdditionalIncludeDirectories)
+ ..\..\..\lib_acl_cpp\include;..\..\..\lib_acl\include;..\..\..\lib_fiber\c\include;..\..\..\lib_fiber\cpp\include;..\..\..\lib_protocol\include;%(AdditionalIncludeDirectories)
WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
MultiThreadedDLL
Use
diff --git a/app/wizard_demo/httpd_proxy/master_service.cpp b/app/wizard_demo/httpd_proxy/master_service.cpp
index 46f679141..22cdafc56 100644
--- a/app/wizard_demo/httpd_proxy/master_service.cpp
+++ b/app/wizard_demo/httpd_proxy/master_service.cpp
@@ -47,15 +47,18 @@ void master_service::on_accept(acl::socket_stream& conn)
conn.set_rw_timeout(120);
- acl::memcache_session session("127.0.0.1:11211");
- http_servlet servlet(&conn, &session);
+ acl::memcache_session* session = new acl::memcache_session("127.0.0.1:11211");
+ http_servlet* servlet = new http_servlet(&conn, session);
// charset: big5, gb2312, gb18030, gbk, utf-8
- servlet.setLocalCharset("utf-8");
+ servlet->setLocalCharset("utf-8");
+ servlet->setParseBody(false);
- while(servlet.doRun()) {}
+ while(servlet->doRun()) {}
logger("disconnect from %s, fd %d", conn.get_peer(), conn.sock_handle());
+ delete session;
+ delete servlet;
}
void master_service::proc_pre_jail(void)
@@ -70,7 +73,8 @@ void master_service::proc_on_listen(acl::server_socket& ss)
void master_service::proc_on_init(void)
{
- logger(">>>proc_on_init<<<");
+ logger(">>>proc_on_init: shared stack size=%zd<<<",
+ acl::fiber::get_shared_stack_size());
}
void master_service::proc_on_exit(void)
diff --git a/app/wizard_demo/httpd_proxy/stdafx.h b/app/wizard_demo/httpd_proxy/stdafx.h
index cfb5b4e11..a127ef2d8 100644
--- a/app/wizard_demo/httpd_proxy/stdafx.h
+++ b/app/wizard_demo/httpd_proxy/stdafx.h
@@ -11,6 +11,7 @@
// TODO: ڴ˴óҪĸͷļ
#include "lib_acl.h"
+#include "lib_protocol.h"
#include "acl_cpp/lib_acl.hpp"
#include "fiber/lib_fiber.h"
#include "fiber/lib_fiber.hpp"
diff --git a/app/wizard_demo/httpd_proxy/tcp_transfer.cpp b/app/wizard_demo/httpd_proxy/tcp_transfer.cpp
index 7acc0490e..97236b6bd 100644
--- a/app/wizard_demo/httpd_proxy/tcp_transfer.cpp
+++ b/app/wizard_demo/httpd_proxy/tcp_transfer.cpp
@@ -9,6 +9,7 @@ tcp_transfer::tcp_transfer(ACL_FIBER* parent, acl::socket_stream& in,
, in_(in)
, out_(out)
, peer_(NULL)
+, is_local_(false)
{
}
@@ -16,9 +17,14 @@ tcp_transfer::~tcp_transfer(void)
{
}
-void tcp_transfer::set_peer(tcp_transfer& peer)
+void tcp_transfer::set_peer(tcp_transfer* peer)
{
- peer_ = &peer;
+ peer_ = peer;
+}
+
+void tcp_transfer::set_local(bool yes)
+{
+ is_local_ = yes;
}
void tcp_transfer::unset_peer(void)
@@ -45,7 +51,9 @@ void tcp_transfer::wait(void)
void tcp_transfer::run(void)
{
me_ = acl_fiber_running();
+
char buf[8192];
+
while (true) {
int fd = in_.sock_handle();
int ret = in_.read(buf, sizeof(buf) - 1, false);
@@ -57,9 +65,24 @@ void tcp_transfer::run(void)
break;
}
+ buf[ret] = 0;
+
+#if 0
+ printf("send from %s data, in=%d, out=%d\r\n",
+ is_local_ ? "local" : "remote",
+ in_->sock_handle(), out_->sock_handle());
+#endif
+
if (out_.write(buf, ret) == -1) {
+ printf(">>>write error\n");
break;
}
+
+#if 0
+ printf("send to %s data, in=%d, out=%d ok\r\n",
+ is_local_ ? "local" : "remote",
+ in_->sock_handle(), out_->sock_handle());
+#endif
}
if (peer_) {
diff --git a/app/wizard_demo/httpd_proxy/tcp_transfer.h b/app/wizard_demo/httpd_proxy/tcp_transfer.h
index aad85ce12..a27fd0d1d 100644
--- a/app/wizard_demo/httpd_proxy/tcp_transfer.h
+++ b/app/wizard_demo/httpd_proxy/tcp_transfer.h
@@ -3,23 +3,16 @@
class tcp_transfer : public acl::fiber
{
public:
- tcp_transfer(ACL_FIBER* parent, acl::socket_stream& in, acl::socket_stream& out, bool running);
+ tcp_transfer(ACL_FIBER* parent, acl::socket_stream& in,
+ acl::socket_stream& out, bool running);
~tcp_transfer(void);
- void set_peer(tcp_transfer& peer);
+ void set_peer(tcp_transfer* peer);
void unset_peer(void);
void close(void);
void wait(void);
- acl::socket_stream& get_input(void) const
- {
- return in_;
- }
-
- acl::socket_stream& get_output(void) const
- {
- return out_;
- }
+ void set_local(bool yes);
ACL_FIBER* peer_fiber(void) const {
return me_;
@@ -36,5 +29,6 @@ private:
acl::socket_stream& in_;
acl::socket_stream& out_;
tcp_transfer* peer_;
+ bool is_local_;
};
diff --git a/lib_acl/samples/dgate/dgate.cf b/lib_acl/samples/dgate/dgate.cf
index 685d8a3a4..83807017e 100644
--- a/lib_acl/samples/dgate/dgate.cf
+++ b/lib_acl/samples/dgate/dgate.cf
@@ -28,7 +28,7 @@ service server {
# DNS IP
# dns_neighbor_ip = 211.157.131.7
# dns_neighbor_ip = 192.168.198.47
- dns_neighbor_ip = 8.8.8.8
+ dns_neighbor_ip = 114.114.114.114
# DNS PORT
dns_neighbor_port = 53
}
diff --git a/lib_acl/samples/dgate/service_udp.cpp b/lib_acl/samples/dgate/service_udp.cpp
index c758bf9d7..5c2f92553 100644
--- a/lib_acl/samples/dgate/service_udp.cpp
+++ b/lib_acl/samples/dgate/service_udp.cpp
@@ -149,7 +149,8 @@ static ACL_VSTREAM *stream_udp_bind(struct sockaddr_in addr)
stream = stream_udp_open();
fd = ACL_VSTREAM_SOCK(stream);
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
- acl_msg_fatal("%s(%d): can't bind", myname, __LINE__);
+ acl_msg_fatal("%s(%d): bind, error: %s", myname,
+ __LINE__, acl_last_serror());
return stream;
}
@@ -456,7 +457,7 @@ void service_udp_init(SERVICE *service, const char *local_ip,
ACL_SAFE_STRNCPY(ctx->local_ip, local_ip, sizeof(ctx->local_ip));
ctx->local_port = local_port;
ctx->local_addr.sin_addr.s_addr = inet_addr(local_ip);
- ctx->local_addr.sin_port = htons(local_port);
+ ctx->local_addr.sin_port = htons(local_port + 1);
ctx->local_addr.sin_family = AF_INET;
ACL_SAFE_STRNCPY(ctx->remote_ip, remote_ip, sizeof(ctx->remote_ip));
@@ -465,6 +466,8 @@ void service_udp_init(SERVICE *service, const char *local_ip,
ctx->remote_addr.sin_port = htons(remote_port);
ctx->remote_addr.sin_family = AF_INET;
+ printf("begin bind %s:%d\r\n", local_ip, local_port);
+
// տͻ
stream = stream_udp_bind(ctx->local_addr);
acl_vstream_ctl(stream,
diff --git a/lib_acl/src/stdlib/iostuff/acl_read_wait.c b/lib_acl/src/stdlib/iostuff/acl_read_wait.c
index cb25d944c..a034e1738 100644
--- a/lib_acl/src/stdlib/iostuff/acl_read_wait.c
+++ b/lib_acl/src/stdlib/iostuff/acl_read_wait.c
@@ -539,6 +539,8 @@ int acl_read_wait(ACL_SOCKET fd, int timeout)
return acl_read_wait_ms(fd, timeout * 1000);
}
+/* #define USE_EPOLL */
+
int acl_read_wait_ms(ACL_SOCKET fd, int timeout)
{
#if defined(ACL_LINUX) && !defined(MINGW) && defined(USE_EPOLL)
diff --git a/lib_acl_cpp/include/acl_cpp/http/HttpServlet.hpp b/lib_acl_cpp/include/acl_cpp/http/HttpServlet.hpp
index e2efa097e..9c8444517 100644
--- a/lib_acl_cpp/include/acl_cpp/http/HttpServlet.hpp
+++ b/lib_acl_cpp/include/acl_cpp/http/HttpServlet.hpp
@@ -69,14 +69,13 @@ public:
HttpServlet& setRwTimeout(int rw_timeout);
/**
- * POST ÷ǷҪݣĬΪú
- * doRun ֮ǰòЧΪ MIME ʽʹ
- * ñ˽ݣҲн
- * @param on {bool} ǷҪ
+ * POST ÷ǷҪ Form ݣĬΪ
+ * ú doRun ֮ǰòЧΪ MIME ʽ
+ * ʹñ˽ݣҲн
+ * @param yes {bool} ǷҪ
* @return {HttpServlet&}
- * xxxx: ÷Ѿ
*/
- HttpServlet& setParseBody(bool on);
+ HttpServlet& setParseBody(bool yes);
/**
* POST ÷ýȣ壬ú
@@ -207,6 +206,7 @@ protected:
protected:
HttpServletRequest* req_;
HttpServletResponse* res_;
+ bool parse_body_;
private:
session* session_;
diff --git a/lib_acl_cpp/include/acl_cpp/http/HttpServletRequest.hpp b/lib_acl_cpp/include/acl_cpp/http/HttpServletRequest.hpp
index ee978bf19..06466c6a3 100644
--- a/lib_acl_cpp/include/acl_cpp/http/HttpServletRequest.hpp
+++ b/lib_acl_cpp/include/acl_cpp/http/HttpServletRequest.hpp
@@ -47,6 +47,14 @@ public:
int body_limit = 102400);
~HttpServletRequest(void);
+ /**
+ * POST ÷ǷҪ Form ݣĬΪ
+ * ú doRun ֮ǰòЧΪ MIME ʽ
+ * ʹñ˽ݣҲн
+ * @param yes {bool} ǷҪ
+ */
+ void setParseBody(bool yes);
+
/**
* HTTP ͻGET, POST, PUT, CONNECT, PURGE
* @param method_s {string*} ǿʱ洢ַʽ
@@ -413,6 +421,7 @@ private:
int rw_timeout_;
std::vector params_;
http_request_t request_type_;
+ bool parse_body_;
http_mime* mime_;
string* body_;
json* json_;
diff --git a/lib_acl_cpp/include/acl_cpp/redis/redis_client_pipeline.hpp b/lib_acl_cpp/include/acl_cpp/redis/redis_client_pipeline.hpp
index 1d38fc778..ad6aa03f4 100644
--- a/lib_acl_cpp/include/acl_cpp/redis/redis_client_pipeline.hpp
+++ b/lib_acl_cpp/include/acl_cpp/redis/redis_client_pipeline.hpp
@@ -54,11 +54,18 @@ public:
tbox_ = new tbox(false);
mbox_ = NULL;
}
+
+ size_ = 10;
+ argc_ = 0;
+ argv_ = new const char* [size_];
+ lens_ = new size_t [size_];
}
~redis_pipeline_message(void) {
delete mbox_;
delete tbox_;
+ delete [] argv_;
+ delete [] lens_;
}
redis_pipeline_message& set_type(redis_pipeline_type_t type) {
@@ -83,9 +90,25 @@ public:
}
void set_request(size_t argc, const char** argv, size_t* lens) {
+#if 0
argc_ = argc;
argv_ = argv;
lens_ = lens;
+#else
+ if (argc_ > size_) {
+ delete [] argv_;
+ delete [] lens_;
+ size_ = argc;
+ argv_ = new const char* [size_];
+ lens_ = new size_t [size_];
+ }
+
+ argc_ = argc;
+ for (size_t i = 0; i < size_; i++) {
+ argv_[i] = argv[i];
+ lens_[i] = lens[i];
+ }
+#endif
}
void set_addr(const char* addr) {
@@ -142,6 +165,7 @@ private:
size_t redirect_count_;
public:
+ size_t size_;
size_t argc_;
const char** argv_;
size_t* lens_;
diff --git a/lib_acl_cpp/src/http/HttpServlet.cpp b/lib_acl_cpp/src/http/HttpServlet.cpp
index 55e7f5cee..9d18e35a5 100644
--- a/lib_acl_cpp/src/http/HttpServlet.cpp
+++ b/lib_acl_cpp/src/http/HttpServlet.cpp
@@ -19,6 +19,7 @@ namespace acl
HttpServlet::HttpServlet(socket_stream* stream, session* session)
: req_(NULL)
, res_(NULL)
+, parse_body_(true)
, stream_(stream)
{
init();
@@ -88,8 +89,9 @@ HttpServlet& HttpServlet::setRwTimeout(int rw_timeout)
return *this;
}
-HttpServlet& HttpServlet::setParseBody(bool)
+HttpServlet& HttpServlet::setParseBody(bool yes)
{
+ parse_body_ = yes;
return *this;
}
@@ -161,6 +163,7 @@ bool HttpServlet::start(void)
res_ = NEW HttpServletResponse(*out);
req_ = NEW HttpServletRequest(*res_, *session_, *in, local_charset_,
parse_body_limit_);
+ req_->setParseBody(parse_body_);
// HttpServletRequest
res_->setHttpServletRequest(req_);
diff --git a/lib_acl_cpp/src/http/HttpServletRequest.cpp b/lib_acl_cpp/src/http/HttpServletRequest.cpp
index bf68cd9e8..6eb6aad00 100644
--- a/lib_acl_cpp/src/http/HttpServletRequest.cpp
+++ b/lib_acl_cpp/src/http/HttpServletRequest.cpp
@@ -43,6 +43,7 @@ HttpServletRequest::HttpServletRequest(HttpServletResponse& res,
, client_(NULL)
, method_(HTTP_METHOD_UNKNOWN)
, request_type_(HTTP_REQUEST_NORMAL)
+, parse_body_(true)
, mime_(NULL)
, body_(NULL)
, json_(NULL)
@@ -90,6 +91,11 @@ http_method_t HttpServletRequest::getMethod(string* method_s /* = NULL */) const
return method_;
}
+void HttpServletRequest::setParseBody(bool yes)
+{
+ parse_body_ = yes;
+}
+
void HttpServletRequest::add_cookie(char* data)
{
SKIP_SPACE(data);
@@ -826,6 +832,10 @@ bool HttpServletRequest::readHeader(string* method_s)
// Ϊ form ʽʱ
if (EQ(ctype, "application") && EQ(stype, "x-www-form-urlencoded")) {
request_type_ = HTTP_REQUEST_NORMAL;
+ if (!parse_body_) {
+ return true;
+ }
+
char* query = (char*) dbuf_->dbuf_alloc((size_t) len + 1);
int ret = getInputStream().read(query, (size_t) len);
if (ret > 0) {
diff --git a/lib_acl_cpp/src/redis/redis_client_cluster.cpp b/lib_acl_cpp/src/redis/redis_client_cluster.cpp
index 433f7b748..c0bc47351 100644
--- a/lib_acl_cpp/src/redis/redis_client_cluster.cpp
+++ b/lib_acl_cpp/src/redis/redis_client_cluster.cpp
@@ -164,11 +164,13 @@ void redis_client_cluster::set_all_slot(const char* addr, size_t max_conns,
char buf[128];
safe_snprintf(buf, sizeof(buf), "%s:%d", ip, port);
redis_client_pool* conns = (redis_client_pool*) get(buf);
- if (conns == NULL)
+ if (conns == NULL) {
set(buf, max_conns, conn_timeout, rw_timeout);
+ }
- for (size_t i = slot_min; i <= slot_max; i++)
+ for (size_t i = slot_min; i <= slot_max; i++) {
set_slot((int) i, buf);
+ }
}
}
diff --git a/lib_acl_cpp/src/redis/redis_cluster.cpp b/lib_acl_cpp/src/redis/redis_cluster.cpp
index 647327ff7..942e1955a 100644
--- a/lib_acl_cpp/src/redis/redis_cluster.cpp
+++ b/lib_acl_cpp/src/redis/redis_cluster.cpp
@@ -112,13 +112,13 @@ int redis_cluster::cluster_getkeysinslot(size_t slot, size_t max,
argv[1] = "GETKEYSINSLOT";
lens[1] = sizeof("GETKEYSINSLOT") - 1;
- char slot_s[LONG_LEN];
- safe_snprintf(slot_s, sizeof(slot_s), "%lu", (unsigned long) slot);
+ char* slot_s = (char*) dbuf_->dbuf_alloc(LONG_LEN);
+ safe_snprintf(slot_s, LONG_LEN, "%lu", (unsigned long) slot);
argv[2] = slot_s;
lens[2] = strlen(slot_s);
- char max_s[LONG_LEN];
- safe_snprintf(max_s, sizeof(max_s), "%lu", (unsigned long) max);
+ char* max_s = (char*) dbuf_->dbuf_alloc(LONG_LEN);
+ safe_snprintf(max_s, LONG_LEN, "%lu", (unsigned long) max);
argv[3] = max_s;
lens[3] = strlen(max_s);
@@ -140,8 +140,8 @@ bool redis_cluster::cluster_meet(const char* ip, int port)
argv[2] = ip;
lens[2] = strlen(ip);
- char port_s[INT_LEN];
- safe_snprintf(port_s, sizeof(port_s), "%d", port);
+ char* port_s = (char*) dbuf_->dbuf_alloc(INT_LEN);
+ safe_snprintf(port_s, INT_LEN, "%d", port);
argv[3] = port_s;
lens[3] = strlen(port_s);
@@ -212,8 +212,8 @@ bool redis_cluster::cluster_setslot_importing(size_t slot, const char* src_node)
argv[1] = "SETSLOT";
lens[1] = sizeof("SETSLOT") - 1;
- char slot_s[LONG_LEN];
- safe_snprintf(slot_s, sizeof(slot_s), "%lu", (unsigned long) slot);
+ char* slot_s = (char*) dbuf_->dbuf_alloc(LONG_LEN);
+ safe_snprintf(slot_s, LONG_LEN, "%lu", (unsigned long) slot);
argv[2] = slot_s;
lens[2] = strlen(slot_s);
@@ -238,8 +238,8 @@ bool redis_cluster::cluster_setslot_migrating(size_t slot, const char* dst_node)
argv[1] = "SETSLOT";
lens[1] = sizeof("SETSLOT") - 1;
- char slot_s[LONG_LEN];
- safe_snprintf(slot_s, sizeof(slot_s), "%lu", (unsigned long) slot);
+ char* slot_s = (char*) dbuf_->dbuf_alloc(LONG_LEN);
+ safe_snprintf(slot_s, LONG_LEN, "%lu", (unsigned long) slot);
argv[2] = slot_s;
lens[2] = strlen(slot_s);
@@ -264,8 +264,8 @@ bool redis_cluster::cluster_setslot_stable(size_t slot)
argv[1] = "SETSLOT";
lens[1] = sizeof("SETSLOT") - 1;
- char slot_s[LONG_LEN];
- safe_snprintf(slot_s, sizeof(slot_s), "%lu", (unsigned long) slot);
+ char* slot_s = (char*) dbuf_->dbuf_alloc(LONG_LEN);
+ safe_snprintf(slot_s, LONG_LEN, "%lu", (unsigned long) slot);
argv[2] = slot_s;
lens[2] = strlen(slot_s);
@@ -287,8 +287,8 @@ bool redis_cluster::cluster_setslot_node(size_t slot, const char* node)
argv[1] = "SETSLOT";
lens[1] = sizeof("SETSLOT") - 1;
- char slot_s[LONG_LEN];
- safe_snprintf(slot_s, sizeof(slot_s), "%lu", (unsigned long) slot);
+ char* slot_s = (char*) dbuf_->dbuf_alloc(LONG_LEN);
+ safe_snprintf(slot_s, LONG_LEN, "%lu", (unsigned long) slot);
argv[2] = slot_s;
lens[2] = strlen(slot_s);
@@ -432,8 +432,8 @@ int redis_cluster::cluster_countkeysinslot(size_t slot)
argv[1] = "COUNTKEYSINSLOT";
lens[1] = sizeof("COUNTKEYSINSLOT") - 1;
- char slot_s[LONG_LEN];
- safe_snprintf(slot_s, sizeof(slot_s), "%lu", (unsigned long) slot);
+ char* slot_s = (char*) dbuf_->dbuf_alloc(LONG_LEN);
+ safe_snprintf(slot_s, LONG_LEN, "%lu", (unsigned long) slot);
argv[2] = slot_s;
lens[2] = strlen(slot_s);
diff --git a/lib_acl_cpp/src/redis/redis_command.cpp b/lib_acl_cpp/src/redis/redis_command.cpp
index 8f4a00772..2714a1c59 100644
--- a/lib_acl_cpp/src/redis/redis_command.cpp
+++ b/lib_acl_cpp/src/redis/redis_command.cpp
@@ -859,8 +859,8 @@ const redis_result** redis_command::scan_keys(const char* cmd, const char* key,
argc++;
}
- char cursor_s[INT_LEN];
- safe_snprintf(cursor_s, sizeof(cursor_s), "%d", cursor);
+ char* cursor_s = (char*) dbuf_->dbuf_alloc(INT_LEN);
+ safe_snprintf(cursor_s, INT_LEN, "%d", cursor);
argv[argc] = cursor_s;
lens[argc] = strlen(cursor_s);
argc++;
@@ -880,8 +880,8 @@ const redis_result** redis_command::scan_keys(const char* cmd, const char* key,
lens[argc] = sizeof("COUNT") - 1;
argc++;
- char count_s[LONG_LEN];
- safe_snprintf(count_s, sizeof(count_s), "%lu",
+ char* count_s = (char*) dbuf_->dbuf_alloc(LONG_LEN);
+ safe_snprintf(count_s, LONG_LEN, "%lu",
(unsigned long) (*count));
argv[argc] = count_s;
lens[argc] = strlen(count_s);
diff --git a/lib_acl_cpp/src/redis/redis_connection.cpp b/lib_acl_cpp/src/redis/redis_connection.cpp
index 9ac03d1ef..aeaa51207 100644
--- a/lib_acl_cpp/src/redis/redis_connection.cpp
+++ b/lib_acl_cpp/src/redis/redis_connection.cpp
@@ -62,8 +62,8 @@ bool redis_connection::select(int dbnum)
argv[0] = "SELECT";
lens[0] = strlen(argv[0]);
- char buf[21];
- safe_snprintf(buf, sizeof(buf), "%d", dbnum);
+ char* buf = (char*) dbuf_->dbuf_alloc(21);
+ safe_snprintf(buf, 21, "%d", dbnum);
argv[1] = buf;
lens[1] = strlen(argv[1]);
diff --git a/lib_acl_cpp/src/redis/redis_hash.cpp b/lib_acl_cpp/src/redis/redis_hash.cpp
index ea08148ce..285861ea2 100644
--- a/lib_acl_cpp/src/redis/redis_hash.cpp
+++ b/lib_acl_cpp/src/redis/redis_hash.cpp
@@ -440,8 +440,8 @@ bool redis_hash::hincrbyfloat(const char* key, const char* name,
const char* values[1];
names[0] = name;
- char buf[FLOAT_LEN];
- (void) safe_snprintf(buf, sizeof(buf), "%f", inc);
+ char* buf = (char*) dbuf_->dbuf_alloc(FLOAT_LEN);
+ (void) safe_snprintf(buf, FLOAT_LEN, "%f", inc);
values[0] = buf;
hash_slot(key);
diff --git a/lib_acl_cpp/src/redis/redis_key.cpp b/lib_acl_cpp/src/redis/redis_key.cpp
index ded0d76b7..4b2809a52 100644
--- a/lib_acl_cpp/src/redis/redis_key.cpp
+++ b/lib_acl_cpp/src/redis/redis_key.cpp
@@ -195,7 +195,7 @@ int redis_key::expire(const char* key, size_t len, int n)
argv[1] = key;
lens[1] = len;
- char buf[INT_LEN];
+ char* buf = (char*) dbuf_->dbuf_alloc(INT_LEN);
(void) safe_snprintf(buf, INT_LEN, "%d", n);
argv[2] = buf;
lens[2] = strlen(buf);
@@ -221,8 +221,8 @@ int redis_key::expireat(const char* key, size_t len, time_t stamp)
argv[1] = key;
lens[1] = len;
- char stamp_s[LONG_LEN];
- safe_snprintf(stamp_s, sizeof(stamp_s), "%lu", (unsigned long) stamp);
+ char* stamp_s = (char*) dbuf_->dbuf_alloc(LONG_LEN);
+ safe_snprintf(stamp_s, LONG_LEN, "%lu", (unsigned long) stamp);
argv[2] = stamp_s;
lens[2] = strlen(stamp_s);
@@ -284,7 +284,7 @@ int redis_key::pexpire(const char* key, size_t len, int n)
argv[1] = key;
lens[1] = len;
- char buf[INT_LEN];
+ char* buf = (char*) dbuf_->dbuf_alloc(INT_LEN);
(void) safe_snprintf(buf, INT_LEN, "%d", n);
argv[2] = buf;
lens[2] = strlen(buf);
@@ -422,8 +422,8 @@ bool redis_key::restore(const char* key, const char* value, size_t len,
argv[1] = key;
lens[1] = strlen(key);
- char ttl_s[INT_LEN];
- safe_snprintf(ttl_s, sizeof(ttl_s), "%d", nttl);
+ char* ttl_s = (char*) dbuf_->dbuf_alloc(INT_LEN);
+ safe_snprintf(ttl_s, INT_LEN, "%d", nttl);
argv[2] = ttl_s;
lens[2] = strlen(ttl_s);
@@ -517,8 +517,8 @@ bool redis_key::migrate(const char* key, const char* addr, unsigned dest_db,
bool redis_key::migrate(const char* key, size_t len, const char* addr,
unsigned dest_db, unsigned timeout, const char* option /* = NULL */)
{
- char addrbuf[64];
- safe_snprintf(addrbuf, sizeof(addrbuf), "%s", addr);
+ char* addrbuf = (char*) dbuf_->dbuf_alloc(64);
+ safe_snprintf(addrbuf, 64, "%s", addr);
char* at = strchr(addrbuf, ':');
if (at == NULL || *(at + 1) == 0)
return false;
@@ -540,13 +540,13 @@ bool redis_key::migrate(const char* key, size_t len, const char* addr,
argv[3] = key;
lens[3] = len;
- char db_s[11];
- safe_snprintf(db_s, sizeof(db_s), "%u", dest_db);
+ char* db_s = (char*) dbuf_->dbuf_alloc(11);
+ safe_snprintf(db_s, 11, "%u", dest_db);
argv[4] = db_s;
lens[4] = strlen(db_s);
- char timeout_s[11];
- safe_snprintf(timeout_s, sizeof(timeout_s), "%u", timeout);
+ char* timeout_s = (char*) dbuf_->dbuf_alloc(11);
+ safe_snprintf(timeout_s, 11, "%u", timeout);
argv[5] = timeout_s;
lens[5] = strlen(timeout_s);
@@ -575,8 +575,8 @@ int redis_key::move(const char* key, size_t len, unsigned dest_db)
argv[1] = key;
lens[1] = len;
- char db_s[11];
- safe_snprintf(db_s, sizeof(db_s), "%u", dest_db);
+ char* db_s = (char*) dbuf_->dbuf_alloc(11);
+ safe_snprintf(db_s, 11, "%u", dest_db);
argv[2] = db_s;
lens[2] = strlen(db_s);
diff --git a/lib_acl_cpp/src/redis/redis_list.cpp b/lib_acl_cpp/src/redis/redis_list.cpp
index 98ded9852..20a79b432 100644
--- a/lib_acl_cpp/src/redis/redis_list.cpp
+++ b/lib_acl_cpp/src/redis/redis_list.cpp
@@ -71,8 +71,8 @@ bool redis_list::lindex(const char* key, size_t idx, string& buf)
argv[1] = key;
lens[1] = strlen(key);
- char tmp[LONG_LEN];
- (void) safe_snprintf(tmp, sizeof(tmp), "%lu", (unsigned long) idx);
+ char* tmp = (char*) dbuf_->dbuf_alloc(LONG_LEN);
+ (void) safe_snprintf(tmp, LONG_LEN, "%lu", (unsigned long) idx);
argv[2] = tmp;
lens[2] = strlen(tmp);
@@ -96,8 +96,8 @@ bool redis_list::lset(const char* key, int idx, const char* value, size_t len)
argv[1] = key;
lens[1] = strlen(key);
- char tmp[LONG_LEN];
- (void) safe_snprintf(tmp, sizeof(tmp), "%lu", (unsigned long) idx);
+ char* tmp = (char*) dbuf_->dbuf_alloc(LONG_LEN);
+ (void) safe_snprintf(tmp, LONG_LEN, "%lu", (unsigned long) idx);
argv[2] = tmp;
lens[2] = strlen(tmp);
@@ -388,8 +388,8 @@ bool redis_list::bpop(const char* cmd, const std::vector& keys,
i++;
}
- char buf[LONG_LEN];
- safe_snprintf(buf, sizeof(buf), "%lu", (unsigned long) timeout);
+ char* buf = (char*) dbuf_->dbuf_alloc(LONG_LEN);
+ safe_snprintf(buf, LONG_LEN, "%lu", (unsigned long) timeout);
args[i] = buf;
lens[i] = strlen(args[i]);
@@ -415,8 +415,8 @@ bool redis_list::bpop(const char* cmd, const std::vector& keys,
i++;
}
- char buf[LONG_LEN];
- safe_snprintf(buf, sizeof(buf), "%lu", (unsigned long) timeout);
+ char* buf = (char*) dbuf_->dbuf_alloc(LONG_LEN);
+ safe_snprintf(buf, LONG_LEN, "%lu", (unsigned long) timeout);
args[i] = buf;
lens[i] = strlen(args[i]);
@@ -486,8 +486,8 @@ bool redis_list::brpoplpush(const char* src, const char* dst,
argv[2] = dst;
lens[2] = strlen(dst);
- char tmp[LONG_LEN];
- safe_snprintf(tmp, sizeof(tmp), "%lu", (unsigned long) timeout);
+ char* tmp = (char*) dbuf_->dbuf_alloc(LONG_LEN);
+ safe_snprintf(tmp, LONG_LEN, "%lu", (unsigned long) timeout);
argv[3] = tmp;
lens[3] = strlen(argv[3]);
@@ -506,9 +506,10 @@ bool redis_list::lrange(const char* key, int start, int end,
argv[1] = key;
lens[1] = strlen(key);
- char start_s[LONG_LEN], end_s[LONG_LEN];
- safe_snprintf(start_s, sizeof(start_s), "%d", start);
- safe_snprintf(end_s, sizeof(end_s), "%d", end);
+ char* start_s = (char*) dbuf_->dbuf_alloc(LONG_LEN);
+ char* end_s = (char*) dbuf_->dbuf_alloc(LONG_LEN);
+ safe_snprintf(start_s, LONG_LEN, "%d", start);
+ safe_snprintf(end_s, LONG_LEN, "%d", end);
argv[2] = start_s;
lens[2] = strlen(start_s);
@@ -535,8 +536,8 @@ int redis_list::lrem(const char* key, int count, const char* value, size_t len)
argv[1] = key;
lens[1] = strlen(key);
- char buf[INT_LEN];
- safe_snprintf(buf, sizeof(buf), "%d", count);
+ char* buf = (char*) dbuf_->dbuf_alloc(INT_LEN);
+ safe_snprintf(buf, INT_LEN, "%d", count);
argv[2] = buf;
lens[2] = strlen(buf);
@@ -558,9 +559,10 @@ bool redis_list::ltrim(const char* key, int start, int end)
argv[1] = key;
lens[1] = strlen(key);
- char start_s[LONG_LEN], end_s[LONG_LEN];
- safe_snprintf(start_s, sizeof(start_s), "%d", start);
- safe_snprintf(end_s, sizeof(end_s), "%d", end);
+ char* start_s = (char*) dbuf_->dbuf_alloc(LONG_LEN);
+ char* end_s = (char*) dbuf_->dbuf_alloc(LONG_LEN);
+ safe_snprintf(start_s, LONG_LEN, "%d", start);
+ safe_snprintf(end_s, LONG_LEN, "%d", end);
argv[2] = start_s;
lens[2] = strlen(start_s);
diff --git a/lib_acl_cpp/src/redis/redis_role.cpp b/lib_acl_cpp/src/redis/redis_role.cpp
index 5a81941e8..c2718ecfe 100644
--- a/lib_acl_cpp/src/redis/redis_role.cpp
+++ b/lib_acl_cpp/src/redis/redis_role.cpp
@@ -1,6 +1,5 @@
#include "acl_stdafx.hpp"
#ifndef ACL_PREPARE_COMPILE
-#include "acl_cpp/stdlib/snprintf.hpp"
#include "acl_cpp/stdlib/dbuf_pool.hpp"
#include "acl_cpp/stdlib/string.hpp"
#include "acl_cpp/redis/redis_client.hpp"
diff --git a/lib_acl_cpp/src/redis/redis_script.cpp b/lib_acl_cpp/src/redis/redis_script.cpp
index 06752c5cc..2bd4f71bb 100644
--- a/lib_acl_cpp/src/redis/redis_script.cpp
+++ b/lib_acl_cpp/src/redis/redis_script.cpp
@@ -392,8 +392,8 @@ const redis_result* redis_script::eval_cmd(const char* cmd,
argv[1] = script;
lens[1] = strlen(script);
- char buf[LONG_LEN];
- safe_snprintf(buf, sizeof(buf), "%lu", (unsigned long) keys.size());
+ char* buf = (char*) dbuf_->dbuf_alloc(LONG_LEN);
+ safe_snprintf(buf, LONG_LEN, "%lu", (unsigned long) keys.size());
argv[2] = buf;
lens[2] = strlen(buf);
@@ -437,8 +437,8 @@ const redis_result* redis_script::eval_cmd(const char* cmd,
argv[1] = script;
lens[1] = strlen(script);
- char buf[LONG_LEN];
- safe_snprintf(buf, sizeof(buf), "%lu", (unsigned long) keys.size());
+ char* buf = (char*) dbuf_->dbuf_alloc(LONG_LEN);
+ safe_snprintf(buf, LONG_LEN, "%lu", (unsigned long) keys.size());
argv[2] = buf;
lens[2] = strlen(buf);
diff --git a/lib_acl_cpp/src/redis/redis_sentinel.cpp b/lib_acl_cpp/src/redis/redis_sentinel.cpp
index 399ad0442..baa8b681a 100644
--- a/lib_acl_cpp/src/redis/redis_sentinel.cpp
+++ b/lib_acl_cpp/src/redis/redis_sentinel.cpp
@@ -399,13 +399,13 @@ bool redis_sentinel::sentinel_monitor(const char* master_name, const char* ip,
argv[3] = ip;
lens[3] = strlen(ip);
- char port_s[64];
- safe_snprintf(port_s, sizeof(port_s), "%d", port);
+ char* port_s = (char*) dbuf_->dbuf_alloc(64);
+ safe_snprintf(port_s, 64, "%d", port);
argv[4] = port_s;
lens[4] = strlen(argv[4]);
- char quorum_s[64];
- safe_snprintf(quorum_s, sizeof(quorum_s), "%d", quorum);
+ char* quorum_s = (char*) dbuf_->dbuf_alloc(64);
+ safe_snprintf(quorum_s, 64, "%d", quorum);
argv[5] = quorum_s;
lens[5] = strlen(argv[5]);
@@ -441,8 +441,8 @@ bool redis_sentinel::sentinel_set(const char* master_name, const char* name,
bool redis_sentinel::sentinel_set(const char* master_name, const char* name,
unsigned value)
{
- char buf[64];
- safe_snprintf(buf, sizeof(buf), "%u", value);
+ char* buf = (char*) dbuf_->dbuf_alloc(64);
+ safe_snprintf(buf, 64, "%u", value);
return sentinel_set(master_name, name, buf);
}
diff --git a/lib_acl_cpp/src/redis/redis_server.cpp b/lib_acl_cpp/src/redis/redis_server.cpp
index 1237efcfa..ae35e81d0 100644
--- a/lib_acl_cpp/src/redis/redis_server.cpp
+++ b/lib_acl_cpp/src/redis/redis_server.cpp
@@ -358,8 +358,8 @@ bool redis_server::slaveof(const char* ip, int port)
argv[1] = ip;
lens[1] = strlen(ip);
- char port_s[INT_LEN];
- safe_snprintf(port_s, sizeof(port_s), "%d", port);
+ char* port_s= (char*) dbuf_->dbuf_alloc(INT_LEN);
+ safe_snprintf(port_s, INT_LEN, "%d", port);
argv[2] = port_s;
lens[2] = strlen(port_s);
@@ -380,9 +380,9 @@ const redis_result* redis_server::slowlog_get(int number /* = 0 */)
size_t argc = 2;
- char buf[INT_LEN];
if (number > 0) {
- safe_snprintf(buf, sizeof(buf), "%d", number);
+ char* buf = (char*) dbuf_->dbuf_alloc(INT_LEN);
+ safe_snprintf(buf, INT_LEN, "%d", number);
argv[2] = buf;
lens[2] = strlen(buf);
argc++;
diff --git a/lib_acl_cpp/src/redis/redis_set.cpp b/lib_acl_cpp/src/redis/redis_set.cpp
index 806d50717..4c35c0ab6 100644
--- a/lib_acl_cpp/src/redis/redis_set.cpp
+++ b/lib_acl_cpp/src/redis/redis_set.cpp
@@ -380,8 +380,8 @@ int redis_set::srandmember(const char* key, size_t n, std::vector& out)
argv[1] = key;
lens[1] = strlen(key);
- char buf[LONG_LEN];
- safe_snprintf(buf, sizeof(buf), "%lu", (unsigned long) n);
+ char* buf= (char*) dbuf_->dbuf_alloc(LONG_LEN);
+ safe_snprintf(buf, LONG_LEN, "%lu", (unsigned long) n);
argv[2] = buf;
lens[2] = strlen(buf);
diff --git a/lib_acl_cpp/src/redis/redis_stream.cpp b/lib_acl_cpp/src/redis/redis_stream.cpp
index 5e4ebea56..e53e6eb09 100644
--- a/lib_acl_cpp/src/redis/redis_stream.cpp
+++ b/lib_acl_cpp/src/redis/redis_stream.cpp
@@ -149,8 +149,8 @@ bool redis_stream::xadd_with_maxlen(const char* key, size_t maxlen,
argv_lens_[i] = 1;
i++;
- char buf[LONG_LEN];
- safe_snprintf(buf, sizeof(buf), "%ld", (long) maxlen);
+ char* buf= (char*) dbuf_->dbuf_alloc(LONG_LEN);
+ safe_snprintf(buf, LONG_LEN, "%ld", (long) maxlen);
argv_[i] = buf;
argv_lens_[i] = strlen(buf);
i++;
@@ -196,26 +196,25 @@ int redis_stream::xlen(const char* key)
void redis_stream::build(const std::map& streams, size_t i,
size_t count, ssize_t block, bool noack /* = false */)
{
- char count_s[LONG_LEN];
if (count > 0) {
argv_[i] = "COUNT";
argv_lens_[i] = sizeof("COUNT") - 1;
i++;
- safe_snprintf(count_s, sizeof(count_s), "%lu",
- (unsigned long) count);
+ char* count_s= (char*) dbuf_->dbuf_alloc(LONG_LEN);
+ safe_snprintf(count_s, LONG_LEN, "%lu", (unsigned long) count);
argv_[i] = count_s;
argv_lens_[i] = strlen(count_s);
i++;
}
- char block_s[LONG_LEN];
if (block >= 0) {
argv_[i] = "BLOCK";
argv_lens_[i] = sizeof("BLOCK") - 1;
i++;
- safe_snprintf(block_s, sizeof(block_s), "%ld", (long) block);
+ char* block_s= (char*) dbuf_->dbuf_alloc(LONG_LEN);
+ safe_snprintf(block_s, LONG_LEN, "%ld", (long) block);
argv_[i] = block_s;
argv_lens_[i] = strlen(block_s);
i++;
@@ -359,14 +358,13 @@ bool redis_stream::range(redis_stream_messages& messages, const char* cmd,
lens[i] = strlen(end);
i++;
- char count_s[LONG_LEN];
if (count > 0) {
argv[i] = "COUNT";
lens[i] = sizeof("COUNT") - 1;
i++;
- safe_snprintf(count_s, sizeof(count_s), "%lu",
- (unsigned long) count);
+ char* count_s= (char*) dbuf_->dbuf_alloc(LONG_LEN);
+ safe_snprintf(count_s, LONG_LEN, "%lu", (unsigned long) count);
argv[i] = count_s;
lens[i] = strlen(count_s);
i++;
@@ -545,8 +543,8 @@ void redis_stream::xclaim_build(const char* key, const char* group,
argv_lens_[i] = strlen(consumer);
i++;
- char min_idle_s[LONG_LEN];
- safe_snprintf(min_idle_s, sizeof(min_idle_s), "%lu", min_idle_time);
+ char* min_idle_s= (char*) dbuf_->dbuf_alloc(LONG_LEN);
+ safe_snprintf(min_idle_s, LONG_LEN, "%lu", min_idle_time);
argv_[i] = min_idle_s;
argv_lens_[i] = strlen(min_idle_s);
i++;
@@ -559,22 +557,23 @@ void redis_stream::xclaim_build(const char* key, const char* group,
i++;
}
- char tbuf[LONG_LEN];
if (idle > 0) {
- safe_snprintf(tbuf, sizeof(tbuf), "%lu", (unsigned long) idle);
+ char* tbuf= (char*) dbuf_->dbuf_alloc(LONG_LEN);
+ safe_snprintf(tbuf, LONG_LEN, "%lu", (unsigned long) idle);
argv_[i] = tbuf;
argv_lens_[i] = strlen(tbuf);
i++;
} else if (time_ms > 0) {
- safe_snprintf(tbuf, sizeof(tbuf), "%lld", time_ms);
+ char* tbuf= (char*) dbuf_->dbuf_alloc(LONG_LEN);
+ safe_snprintf(tbuf, LONG_LEN, "%lld", time_ms);
argv_[i] = tbuf;
argv_lens_[i] = strlen(tbuf);
i++;
}
- char retry_buf[INT_LEN];
if (retry_count > 0) {
- safe_snprintf(retry_buf, sizeof(retry_buf), "%d", retry_count);
+ char* retry_buf= (char*) dbuf_->dbuf_alloc(INT_LEN);
+ safe_snprintf(retry_buf, INT_LEN, "%d", retry_count);
argv_[i] = retry_buf;
argv_lens_[i] = strlen(retry_buf);
i++;
@@ -968,8 +967,8 @@ bool redis_stream::xpending_detail(redis_pending_detail& result,
lens[i] = strlen(end_id);
i++;
- char count_s[LONG_LEN];
- safe_snprintf(count_s, sizeof(count_s), "%lu", (unsigned long) count);
+ char* count_s= (char*) dbuf_->dbuf_alloc(LONG_LEN);
+ safe_snprintf(count_s, LONG_LEN, "%lu", (unsigned long) count);
argv[i] = count_s;
lens[i] = strlen(count_s);
i++;
@@ -1105,8 +1104,8 @@ int redis_stream::xtrim(const char* key, size_t maxlen, bool tilde)
i++;
}
- char buf[LONG_LEN];
- safe_snprintf(buf, sizeof(buf), "%lu", (unsigned long) maxlen);
+ char* buf= (char*) dbuf_->dbuf_alloc(LONG_LEN);
+ safe_snprintf(buf, LONG_LEN, "%lu", (unsigned long) maxlen);
argv[i] = buf;
lens[i] = strlen(buf);
i++;
diff --git a/lib_acl_cpp/src/redis/redis_string.cpp b/lib_acl_cpp/src/redis/redis_string.cpp
index 66182fa2f..00c904aa6 100644
--- a/lib_acl_cpp/src/redis/redis_string.cpp
+++ b/lib_acl_cpp/src/redis/redis_string.cpp
@@ -104,8 +104,8 @@ bool redis_string::set(const char* key, size_t key_len, const char* value,
goto NEXT_X;
}
- char buf[INT_LEN];
- (void) safe_snprintf(buf, sizeof(buf), "%d", timeout);
+ char* buf= (char*) dbuf_->dbuf_alloc(INT_LEN);
+ (void) safe_snprintf(buf, INT_LEN, "%d", timeout);
argv[n] = buf;
lens[n] = strlen(buf);
n++;
@@ -144,8 +144,8 @@ bool redis_string::setex(const char* key, size_t key_len, const char* value,
argv[1] = key;
lens[1] = key_len;
- char buf[INT_LEN];
- (void) safe_snprintf(buf, sizeof(buf), "%d", timeout);
+ char* buf= (char*) dbuf_->dbuf_alloc(INT_LEN);
+ (void) safe_snprintf(buf, INT_LEN, "%d", timeout);
argv[2] = buf;
lens[2] = strlen(buf);
@@ -174,8 +174,8 @@ bool redis_string::psetex(const char* key, size_t key_len, const char* value,
argv[1] = key;
lens[1] = key_len;
- char buf[INT_LEN];
- (void) safe_snprintf(buf, sizeof(buf), "%d", timeout);
+ char* buf= (char*) dbuf_->dbuf_alloc(INT_LEN);
+ (void) safe_snprintf(buf, INT_LEN, "%d", timeout);
argv[2] = buf;
lens[2] = strlen(buf);
@@ -378,12 +378,13 @@ bool redis_string::getrange(const char* key, size_t key_len,
argv[1] = key;
lens[1] = key_len;
- char start_buf[INT_LEN], end_buf[INT_LEN];
- (void) safe_snprintf(start_buf, sizeof(start_buf), "%d", start);
+ char* start_buf= (char*) dbuf_->dbuf_alloc(INT_LEN);
+ (void) safe_snprintf(start_buf, INT_LEN, "%d", start);
argv[2] = start_buf;
lens[2] = strlen(start_buf);
- (void) safe_snprintf(end_buf, sizeof(end_buf), "%d", end);
+ char* end_buf= (char*) dbuf_->dbuf_alloc(INT_LEN);
+ (void) safe_snprintf(end_buf, INT_LEN, "%d", end);
argv[3] = end_buf;
lens[3] = strlen(end_buf);
@@ -411,8 +412,8 @@ bool redis_string::setbit_(const char* key, size_t len,
argv[1] = key;
lens[1] = len;
- char buf4off[INT_LEN];
- (void) safe_snprintf(buf4off, sizeof(buf4off), "%d", offset);
+ char* buf4off= (char*) dbuf_->dbuf_alloc(INT_LEN);
+ (void) safe_snprintf(buf4off, INT_LEN, "%d", offset);
argv[2] = buf4off;
lens[2] = strlen(buf4off);
@@ -441,8 +442,8 @@ bool redis_string::getbit(const char* key, size_t len,
argv[1] = key;
lens[1] = len;
- char buf4off[INT_LEN];
- (void) safe_snprintf(buf4off, sizeof(buf4off), "%d", offset);
+ char* buf4off= (char*) dbuf_->dbuf_alloc(INT_LEN);
+ (void) safe_snprintf(buf4off, INT_LEN, "%d", offset);
argv[2] = buf4off;
lens[2] = strlen(buf4off);
@@ -492,13 +493,13 @@ int redis_string::bitcount(const char* key, size_t len, int start, int end)
argv[1] = key;
lens[1] = len;
- char buf4start[INT_LEN];
- (void) safe_snprintf(buf4start, sizeof(buf4start), "%d", start);
+ char* buf4start= (char*) dbuf_->dbuf_alloc(INT_LEN);
+ (void) safe_snprintf(buf4start, INT_LEN, "%d", start);
argv[2] = buf4start;
lens[2] = strlen(buf4start);
- char buf4end[INT_LEN];
- (void) safe_snprintf(buf4end, sizeof(buf4end), "%d", end);
+ char* buf4end= (char*) dbuf_->dbuf_alloc(INT_LEN);
+ (void) safe_snprintf(buf4end, INT_LEN, "%d", end);
argv[3] = buf4end;
lens[3] = strlen(buf4end);
@@ -800,8 +801,8 @@ bool redis_string::incrbyfloat(const char* key, double inc,
argv[1] = key;
lens[1] = strlen(key);
- char buf[FLOAT_LEN];
- (void) safe_snprintf(buf, sizeof(buf), "%f", inc);
+ char* buf= (char*) dbuf_->dbuf_alloc(FLOAT_LEN);
+ (void) safe_snprintf(buf, FLOAT_LEN, "%f", inc);
argv[2] = buf;
lens[2] = strlen(buf);
diff --git a/lib_acl_cpp/src/redis/redis_zset.cpp b/lib_acl_cpp/src/redis/redis_zset.cpp
index 7be242a69..c5ae24d6b 100644
--- a/lib_acl_cpp/src/redis/redis_zset.cpp
+++ b/lib_acl_cpp/src/redis/redis_zset.cpp
@@ -344,8 +344,8 @@ bool redis_zset::zadd_with_incr(const char* key, const char* member,
i++;
}
- char score_s[BUFLEN];
- safe_snprintf(score_s, sizeof(score_s), "%.8f", score);
+ char* score_s= (char*) dbuf_->dbuf_alloc(BUFLEN);
+ safe_snprintf(score_s, BUFLEN, "%.8f", score);
argv[i] = score_s;
lens[i] = strlen(score_s);
i++;
@@ -410,9 +410,10 @@ int redis_zset::zcount(const char* key, double min, double max)
argv[1] = key;
lens[1] = strlen(key);
- char min_buf[BUFLEN], max_buf[BUFLEN];
- safe_snprintf(min_buf, sizeof(min_buf), "%.8f", min);
- safe_snprintf(max_buf, sizeof(max_buf), "%.8f", max);
+ char* min_buf= (char*) dbuf_->dbuf_alloc(BUFLEN);
+ char* max_buf= (char*) dbuf_->dbuf_alloc(BUFLEN);
+ safe_snprintf(min_buf, BUFLEN, "%.8f", min);
+ safe_snprintf(max_buf, BUFLEN, "%.8f", max);
argv[2] = min_buf;
lens[2] = strlen(min_buf);
@@ -443,8 +444,8 @@ bool redis_zset::zincrby(const char* key, double inc,
argv[1] = key;
lens[1] = strlen(key);
- char score[BUFLEN];
- safe_snprintf(score, sizeof(score), "%.8f", inc);
+ char* score= (char*) dbuf_->dbuf_alloc(BUFLEN);
+ safe_snprintf(score, BUFLEN, "%.8f", inc);
argv[2] = score;
lens[2] = strlen(score);
@@ -474,9 +475,10 @@ int redis_zset::zrange_get(const char* cmd, const char* key, int start,
argv[1] = key;
lens[1] = strlen(key);
- char start_s[INTLEN], stop_s[INTLEN];
- safe_snprintf(start_s, sizeof(start_s), "%d", start);
- safe_snprintf(stop_s, sizeof(stop_s), "%d", stop);
+ char* start_s= (char*) dbuf_->dbuf_alloc(INTLEN);
+ char* stop_s= (char*) dbuf_->dbuf_alloc(INTLEN);
+ safe_snprintf(start_s, INTLEN, "%d", start);
+ safe_snprintf(stop_s, INTLEN, "%d", stop);
argv[2] = start_s;
lens[2] = strlen(start_s);
@@ -550,9 +552,10 @@ int redis_zset::zrange_get_with_scores(const char* cmd, const char* key,
argv[1] = key;
lens[1] = strlen(key);
- char start_s[INTLEN], stop_s[INTLEN];
- safe_snprintf(start_s, sizeof(start_s), "%d", start);
- safe_snprintf(stop_s, sizeof(stop_s), "%d", stop);
+ char* start_s= (char*) dbuf_->dbuf_alloc(INTLEN);
+ char* stop_s= (char*) dbuf_->dbuf_alloc(INTLEN);
+ safe_snprintf(start_s, INTLEN, "%d", start);
+ safe_snprintf(stop_s, INTLEN, "%d", stop);
argv[2] = start_s;
lens[2] = strlen(start_s);
@@ -595,10 +598,11 @@ int redis_zset::zrangebyscore_get(const char* cmd, const char* key,
argv[3] = max;
lens[3] = strlen(max);
- char offset_s[INTLEN], count_s[INTLEN];
if (offset && count) {
- safe_snprintf(offset_s, sizeof(offset_s), "%d", *offset);
- safe_snprintf(count_s, sizeof(count_s), "%d", *count);
+ char* offset_s= (char*) dbuf_->dbuf_alloc(INTLEN);
+ char* count_s= (char*) dbuf_->dbuf_alloc(INTLEN);
+ safe_snprintf(offset_s, INTLEN, "%d", *offset);
+ safe_snprintf(count_s, INTLEN, "%d", *count);
argv[4] = "LIMIT";
lens[4] = sizeof("LIMIT") - 1;
@@ -629,9 +633,10 @@ int redis_zset::zrangebyscore(const char* key, double min,
double max, std::vector* out,
const int* offset /* = NULL */, const int* count /* = NULL */)
{
- char min_s[BUFLEN], max_s[BUFLEN];
- safe_snprintf(min_s, sizeof(min_s), "%.8f", min);
- safe_snprintf(max_s, sizeof(max_s), "%.8f", max);
+ char* min_s= (char*) dbuf_->dbuf_alloc(BUFLEN);
+ char* max_s= (char*) dbuf_->dbuf_alloc(BUFLEN);
+ safe_snprintf(min_s, BUFLEN, "%.8f", min);
+ safe_snprintf(max_s, BUFLEN, "%.8f", max);
return zrangebyscore(key, min_s, max_s, out, offset, count);
}
@@ -660,10 +665,11 @@ int redis_zset::zrangebyscore_get_with_scores(const char* cmd,
argv[4] = "WITHSCORES";
lens[4] = sizeof("WITHSCORES") - 1;
- char offset_s[INTLEN], count_s[INTLEN];
if (offset && count) {
- safe_snprintf(offset_s, sizeof(offset_s), "%d", *offset);
- safe_snprintf(count_s, sizeof(count_s), "%d", *count);
+ char* offset_s = (char*) dbuf_->dbuf_alloc(INTLEN);
+ char* count_s = (char*) dbuf_->dbuf_alloc(INTLEN);
+ safe_snprintf(offset_s, INTLEN, "%d", *offset);
+ safe_snprintf(count_s, INTLEN, "%d", *count);
argv[5] = "LIMIT";
lens[5] = sizeof("LIMIT") - 1;
@@ -695,9 +701,10 @@ int redis_zset::zrangebyscore_with_scores(const char* key, double min,
double max, std::vector >& out,
const int* offset /* = NULL */, const int* count /* = NULL */)
{
- char min_s[BUFLEN], max_s[BUFLEN];
- safe_snprintf(min_s, sizeof(min_s), "%.8f", min);
- safe_snprintf(max_s, sizeof(max_s), "%.8f", max);
+ char* min_s = (char*) dbuf_->dbuf_alloc(BUFLEN);
+ char* max_s = (char*) dbuf_->dbuf_alloc(BUFLEN);
+ safe_snprintf(min_s, BUFLEN, "%.8f", min);
+ safe_snprintf(max_s, BUFLEN, "%.8f", max);
return zrangebyscore_with_scores(key, min_s, max_s, out, offset, count);
}
@@ -772,9 +779,10 @@ int redis_zset::zremrangebyrank(const char* key, int start, int stop)
argv[1] = key;
lens[1] = strlen(key);
- char start_s[INTLEN], stop_s[INTLEN];
- safe_snprintf(start_s, sizeof(start_s), "%d", start);
- safe_snprintf(stop_s, sizeof(stop_s), "%d", stop);
+ char* start_s = (char*) dbuf_->dbuf_alloc(INTLEN);
+ char*stop_s = (char*) dbuf_->dbuf_alloc(INTLEN);
+ safe_snprintf(start_s, INTLEN, "%d", start);
+ safe_snprintf(stop_s, INTLEN, "%d", stop);
argv[2] = start_s;
lens[2] = strlen(start_s);
@@ -789,9 +797,10 @@ int redis_zset::zremrangebyrank(const char* key, int start, int stop)
int redis_zset::zremrangebyscore(const char* key, double min, double max)
{
- char min_s[BUFLEN], max_s[BUFLEN];
- safe_snprintf(min_s, sizeof(min_s), "%.8f", min);
- safe_snprintf(max_s, sizeof(max_s), "%.8f", max);
+ char* min_s = (char*) dbuf_->dbuf_alloc(BUFLEN);
+ char* max_s = (char*) dbuf_->dbuf_alloc(BUFLEN);
+ safe_snprintf(min_s, BUFLEN, "%.8f", min);
+ safe_snprintf(max_s, BUFLEN, "%.8f", max);
return zremrangebyscore(key, min_s, max_s);
}
@@ -843,9 +852,10 @@ int redis_zset::zrevrangebyscore_with_scores(const char* key, double min,
double max, std::vector >& out,
const int* offset /* = NULL */, const int* count /* = NULL */)
{
- char min_s[BUFLEN], max_s[BUFLEN];
- safe_snprintf(min_s, sizeof(min_s), "%.8f", min);
- safe_snprintf(max_s, sizeof(max_s), "%.8f", max);
+ char* min_s = (char*) dbuf_->dbuf_alloc(BUFLEN);
+ char* max_s = (char*) dbuf_->dbuf_alloc(BUFLEN);
+ safe_snprintf(min_s, BUFLEN, "%.8f", min);
+ safe_snprintf(max_s, BUFLEN, "%.8f", max);
return zrevrangebyscore_with_scores(key, min_s, max_s,
out, offset, count);
@@ -925,8 +935,8 @@ int redis_zset::zstore(const char* cmd, const char* dst,
argv[1] = dst;
lens[1] = strlen(dst);
- char num_s[BUFLEN];
- safe_snprintf(num_s, sizeof(num_s), "%d", (int) num);
+ char* num_s = (char*) dbuf_->dbuf_alloc(INTLEN);
+ safe_snprintf(num_s, INTLEN, "%d", (int) num);
argv[2] = num_s;
lens[2] = strlen(num_s);
@@ -1002,8 +1012,8 @@ int redis_zset::zstore(const char* cmd, const char* dst,
argv[1] = dst;
lens[1] = strlen(dst);
- char num_s[INTLEN];
- safe_snprintf(num_s, sizeof(num_s), "%d", (int) keys.size());
+ char* num_s = (char*) dbuf_->dbuf_alloc(INTLEN);
+ safe_snprintf(num_s, INTLEN, "%d", (int) keys.size());
argv[2] = num_s;
lens[2] = strlen(num_s);
@@ -1201,8 +1211,8 @@ int redis_zset::zpop(const char* cmd, const char* key,
argv[1] = key;
lens[1] = strlen(key);
- char count_s[BUFLEN];
- safe_snprintf(count_s, sizeof(count_s), "%lu", (unsigned long) count);
+ char* count_s = (char*) dbuf_->dbuf_alloc(BUFLEN);
+ safe_snprintf(count_s, BUFLEN, "%lu", (unsigned long) count);
argv[2] = count_s;
lens[2] = strlen(count_s);
argc = 3;
@@ -1251,8 +1261,8 @@ int redis_zset::bzpop(const char* cmd, const char* key, size_t timeout,
argv[1] = key;
lens[1] = strlen(key);
- char buf[BUFLEN];
- safe_snprintf(buf, sizeof(buf), "%lu", (unsigned long) timeout);
+ char* buf = (char*) dbuf_->dbuf_alloc(BUFLEN);
+ safe_snprintf(buf, BUFLEN, "%lu", (unsigned long) timeout);
argv[2] = buf;
lens[2] = strlen(buf);
@@ -1278,8 +1288,8 @@ int redis_zset::bzpop(const char* cmd, const std::vector& keys,
i++;
}
- char buf[BUFLEN];
- safe_snprintf(buf, sizeof(buf), "%lu", (unsigned long) timeout);
+ char* buf = (char*) dbuf_->dbuf_alloc(BUFLEN);
+ safe_snprintf(buf, BUFLEN, "%lu", (unsigned long) timeout);
argv_[i] = buf;
argv_lens_[i] = strlen(buf);
build_request(argc_, argv_, argv_lens_);
diff --git a/lib_acl_cpp/src/stream/server_socket.cpp b/lib_acl_cpp/src/stream/server_socket.cpp
index df5048cc5..b152db952 100644
--- a/lib_acl_cpp/src/stream/server_socket.cpp
+++ b/lib_acl_cpp/src/stream/server_socket.cpp
@@ -89,7 +89,7 @@ bool server_socket::opened(void) const
bool server_socket::open(const char* addr)
{
if (fd_ != ACL_SOCKET_INVALID) {
- logger_error("listen fd already opened");
+ logger_error("listen fd already opened, fd_=%d", (int) fd_);
return true;
}
diff --git a/lib_fiber/c/CMakeLists.txt b/lib_fiber/c/CMakeLists.txt
index 49ccb9dfa..ee20a4d28 100644
--- a/lib_fiber/c/CMakeLists.txt
+++ b/lib_fiber/c/CMakeLists.txt
@@ -57,6 +57,7 @@ add_definitions(
"-Wno-long-long"
"-Wuninitialized"
# "-DUSE_JMP"
+# "-DSHARE_STACK"
"-DUSE_FAST_RING"
"-D_POSIX_PTHREAD_SEMANTICS"
"-DACL_PREPARE_COMPILE"
diff --git a/lib_fiber/c/Makefile b/lib_fiber/c/Makefile
index ede1692af..7ad94aae4 100644
--- a/lib_fiber/c/Makefile
+++ b/lib_fiber/c/Makefile
@@ -7,7 +7,9 @@ ARFL = rv
#ARFL = cru
RANLIB = ${ENV_RANLIB}
+#JMP_CTX = DUMMY
JMP_CTX = USE_JMP_DEF
+#JMP_CTX = USE_BOOST_JMP
CFLAGS = -c -g -W \
-std=gnu99 \
@@ -22,8 +24,7 @@ CFLAGS = -c -g -W \
-Wmissing-prototypes \
-Wcast-qual \
-DUSE_FAST_RING \
-#-DUSE_JMP_DEF \
-#-DUSE_BOOST_JMP \
+#-DSHARE_STACK \
#-DUSE_VALGRIND \
#-DUSE_FAST_TIME \
#-Waggregate-return \
@@ -70,10 +71,10 @@ ifeq ($(findstring gcc, $(CC)), gcc)
GCC_MINOR:=$(shell echo "$(GCC_VERSION)" | cut -d'.' -f2)
GCC_SUB:=$(shell echo "$(GCC_VERSION)" | cut -d'.' -f3)
GCC_VER:=$(shell [ $(GCC_MAJOR) -gt 4 -o \( $(GCC_MAJOR) -eq 4 -a $(GCC_MINOR) -gt 4 \) ] && echo true)
- ifeq ($(GCC_VER), true)
- CFLAGS += -Wno-implicit-fallthrough
- CFLAGS += -Wno-absolute-value
- endif
+# ifeq ($(GCC_VER), true)
+# CFLAGS += -Wno-implicit-fallthrough
+# CFLAGS += -Wno-absolute-value
+# endif
endif
ifeq ($(findstring clang, $(CC)), clang)
diff --git a/lib_fiber/c/include/fiber/fiber_base.h b/lib_fiber/c/include/fiber/fiber_base.h
index fc0e58be6..ae88230b8 100644
--- a/lib_fiber/c/include/fiber/fiber_base.h
+++ b/lib_fiber/c/include/fiber/fiber_base.h
@@ -8,7 +8,18 @@
extern "C" {
#endif
-typedef ACL_FIBER *((*FIBER_ALLOC_FN)(void (*)(ACL_FIBER *), size_t));
+typedef struct ACL_FIBER_ATTR {
+ unsigned int oflag;
+#define ACL_FIBER_ATTR_SHARE_STACK (unsigned) 1 << 0
+
+ size_t stack_size;
+} ACL_FIBER_ATTR;
+
+void acl_fiber_attr_init(ACL_FIBER_ATTR *attr);
+void acl_fiber_attr_setstacksize(ACL_FIBER_ATTR *attr, size_t size);
+void acl_fiber_attr_setsharestack(ACL_FIBER_ATTR *attr, int on);
+
+typedef ACL_FIBER *((*FIBER_ALLOC_FN)(void (*)(ACL_FIBER *), const ACL_FIBER_ATTR *));
typedef ACL_FIBER *((*FIBER_ORIGIN_FN)(void));
FIBER_API void acl_fiber_register(FIBER_ALLOC_FN alloc_fn,
@@ -17,19 +28,31 @@ FIBER_API void acl_fiber_register(FIBER_ALLOC_FN alloc_fn,
FIBER_API ACL_FIBER *acl_fiber_alloc(size_t size, void **pptr);
/**
- * set flag if the system API should be hooked, default value is 1 internal
+ * Set flag if the system API should be hooked, default value is 1 internal
* @param onoff {int} if need to hook the system API
*/
FIBER_API void acl_fiber_hook_api(int onoff);
/**
- * set the global flag that if in non-blocking status, just for windows
+ * Set the global flag that if in non-blocking status, just for windows
* @param yes {int} set in non-blocking status global if yes not 0
*/
FIBER_API void acl_fiber_set_non_blocking(int yes);
/**
- * create and start one fiber
+ * Set the shared stack's memory size in shared stack mode
+ * @param size {size_t} must more than 1024 for shared stack mode.
+ */
+FIBER_API void acl_fiber_set_shared_stack_size(size_t size);
+
+/**
+ * Get the shared stack's memory size if shared stack was enabled
+ * @return {size_t} return > 0 if shared stack was enabled, or return 0.
+ */
+FIBER_API size_t acl_fiber_get_shared_stack_size(void);
+
+/**
+ * Create and start one fiber
* @param fn {void (*)(ACL_FIBER*, void*)} the callback of fiber running
* @param arg {void*} the second parameter of the callback fn
* @param size {size_t} the virual memory size of the fiber created
@@ -38,46 +61,56 @@ FIBER_API void acl_fiber_set_non_blocking(int yes);
FIBER_API ACL_FIBER* acl_fiber_create(void (*fn)(ACL_FIBER*, void*),
void* arg, size_t size);
+FIBER_API ACL_FIBER* acl_fiber_create2(const ACL_FIBER_ATTR *attr,
+ void (*fn)(ACL_FIBER*, void*), void* arg);
+
/**
- * get the fibers count in deading status
+ * Get the fibers count in deading status
* @return {unsigned}
*/
FIBER_API unsigned acl_fiber_ndead(void);
/**
- * get the fibers count in aliving status
+ * Get the fibers count in aliving status
* @return {unsigned}
*/
FIBER_API unsigned acl_fiber_number(void);
/**
- * create one fiber in background for freeing the dead fibers, specify the
+ * Create one fiber in background for freeing the dead fibers, specify the
* maximum fibers in every recyling process
* @param max {size_t} the maximum fibers to freed in every recyling process
*/
FIBER_API void acl_fiber_check_timer(size_t max);
/**
- * get the current running fiber
+ * Get the current running fiber
* @retur {ACL_FIBER*} if no running fiber NULL will be returned
*/
FIBER_API ACL_FIBER* acl_fiber_running(void);
/**
- * get the fiber ID of the specified fiber
+ * If the fiber using shared stack?
+ * @param fiber {const ACL_FIBER*}
+ * @return {int} return 0 if using private stack, or the shared stack was used
+ */
+FIBER_API int acl_fiber_use_share_stack(const ACL_FIBER *fiber);
+
+/**
+ * Get the fiber ID of the specified fiber
* @param fiber {const ACL_FIBER*} the specified fiber object
* @return {unsigned int} return the fiber ID
*/
FIBER_API unsigned int acl_fiber_id(const ACL_FIBER* fiber);
/**
- * get the current running fiber's ID
+ * Get the current running fiber's ID
* @return {unsigned int} the current fiber's ID
*/
FIBER_API unsigned int acl_fiber_self(void);
/**
- * set the error number to the specified fiber object
+ * Set the error number to the specified fiber object
* @param fiber {ACL_FIBER*} the specified fiber, if NULL the current running
* fiber will be used
* @param errnum {int} the error number
@@ -85,7 +118,7 @@ FIBER_API unsigned int acl_fiber_self(void);
FIBER_API void acl_fiber_set_errno(ACL_FIBER* fiber, int errnum);
/**
- * get the error number of assosiated fiber
+ * Get the error number of assosiated fiber
* @param fiber {ACL_FIBER*} the specified fiber, if NULL the current running
* @return {int} get the error number of assosiated fiber
*/
@@ -99,79 +132,79 @@ FIBER_API int acl_fiber_errno(ACL_FIBER* fiber);
FIBER_API void acl_fiber_keep_errno(ACL_FIBER* fiber, int yesno);
/**
- * get the assosiated fiber's status
+ * Get the assosiated fiber's status
* @param fiber {ACL_FIBER*} the specified fiber, if NULL the current running
* @return {int}
*/
FIBER_API int acl_fiber_status(const ACL_FIBER* fiber);
/**
- * kill the suspended fiber and notify it to exit
+ * Kill the suspended fiber and notify it to exit
* @param fiber {const ACL_FIBER*} the specified fiber, NOT NULL
*/
FIBER_API void acl_fiber_kill(ACL_FIBER* fiber);
/**
- * check if the specified fiber has been killed
+ * Check if the specified fiber has been killed
* @param fiber {ACL_FIBER*} the specified fiber, if NULL the current running
* @return {int} non zero returned if been killed
*/
FIBER_API int acl_fiber_killed(ACL_FIBER* fiber);
/**
- * check if the specified fiber has been signaled
+ * Check if the specified fiber has been signaled
* @param fiber {ACL_FIBER*} the specified fiber, if NULL the current running
* @return {int} non zero returned if been signed
*/
FIBER_API int acl_fiber_signaled(ACL_FIBER* fiber);
/**
- * check if the specified fiber's socket has been closed by another fiber
+ * Check if the specified fiber's socket has been closed by another fiber
* @param fiber {ACL_FIBER*} the specified fiber, if NULL the current running
* @return {int} non zero returned if been closed
*/
FIBER_API int acl_fiber_closed(ACL_FIBER* fiber);
/**
- * check if the specified fiber has been canceled
+ * Check if the specified fiber has been canceled
* @param fiber {ACL_FIBER*} the specified fiber, if NULL the current running
* @return {int} non zero returned if been canceled
*/
FIBER_API int acl_fiber_canceled(ACL_FIBER* fiber);
/**
- * wakeup the suspended fiber with the assosiated signal number
+ * Wakeup the suspended fiber with the assosiated signal number
* @param fiber {const ACL_FIBER*} the specified fiber, NOT NULL
* @param signum {int} SIGINT, SIGKILL, SIGTERM ... refer to bits/signum.h
*/
FIBER_API void acl_fiber_signal(ACL_FIBER* fiber, int signum);
/**
- * get the signal number got from other fiber
+ * Get the signal number got from other fiber
* @param fiber {ACL_FIBER*} the specified fiber, if NULL the current running
* @retur {int} the signal number got
*/
FIBER_API int acl_fiber_signum(ACL_FIBER* fiber);
/**
- * suspend the current running fiber
+ * Suspend the current running fiber
* @return {int}
*/
FIBER_API int acl_fiber_yield(void);
/**
- * add the suspended fiber into resuming queue
+ * Add the suspended fiber into resuming queue
* @param fiber {ACL_FIBER*} the fiber, NOT NULL
*/
FIBER_API void acl_fiber_ready(ACL_FIBER* fiber);
/**
- * suspend the current fiber and switch to run the next ready fiber
+ * Suspend the current fiber and switch to run the next ready fiber
*/
FIBER_API void acl_fiber_switch(void);
/**
- * set the fiber schedule process with automatically, in this way, when one
+ * Set the fiber schedule process with automatically, in this way, when one
* fiber was created, the schedule process will start automatically, but only
* the first fiber was started, so you can create the other fibers in this
* fiber. The default schedule mode is non-automatically, you should call the
@@ -180,13 +213,13 @@ FIBER_API void acl_fiber_switch(void);
FIBER_API void acl_fiber_schedule_init(int on);
/**
- * start the fiber schedule process, the fibers in the ready quque will be
+ * Start the fiber schedule process, the fibers in the ready quque will be
* started in sequence.
*/
FIBER_API void acl_fiber_schedule(void);
/**
- * start the fiber schedule process with the specified event type, the default
+ * Start the fiber schedule process with the specified event type, the default
* event type is FIBER_EVENT_KERNEL. acl_fiber_schedule using the default
* event type. FIBER_EVENT_KERNEL is diffrent for diffrent OS platform:
* Linux: epoll; BSD: kqueue; Windows: iocp.
@@ -199,39 +232,39 @@ FIBER_API void acl_fiber_schedule(void);
FIBER_API void acl_fiber_schedule_with(int event_mode);
/**
- * set the event type, the default type is FIBER_EVENT_KERNEL, this function
+ * Set the event type, the default type is FIBER_EVENT_KERNEL, this function
* must be called before acl_fiber_schedule.
* @param event_mode {int} the event type, defined as FIBER_EVENT_XXX
*/
FIBER_API void acl_fiber_schedule_set_event(int event_mode);
/**
- * check if the current thread is in fiber schedule status
+ * Check if the current thread is in fiber schedule status
* @return {int} non zero returned if in fiber schedule status
*/
FIBER_API int acl_fiber_scheduled(void);
/**
- * stop the fiber schedule process, all fibers will be stopped
+ * Stop the fiber schedule process, all fibers will be stopped
*/
FIBER_API void acl_fiber_schedule_stop(void);
/**
- * let the current fiber sleep for a while
+ * Let the current fiber sleep for a while
* @param milliseconds {unsigned int} the milliseconds to sleep
* @return {unsigned int} the rest milliseconds returned after wakeup
*/
FIBER_API unsigned int acl_fiber_delay(unsigned int milliseconds);
/**
- * let the current fiber sleep for a while
+ * Let the current fiber sleep for a while
* @param seconds {unsigned int} the seconds to sleep
* @return {unsigned int} the rest seconds returned after wakeup
*/
FIBER_API unsigned int acl_fiber_sleep(unsigned int seconds);
/**
- * create one fiber timer
+ * Create one fiber timer
* @param milliseconds {unsigned int} the timer wakeup milliseconds
* @param size {size_t} the virtual memory of the created fiber
* @param fn {void (*)(ACL_FIBER*, void*)} the callback when fiber wakeup
@@ -242,23 +275,23 @@ FIBER_API ACL_FIBER* acl_fiber_create_timer(unsigned int milliseconds,
size_t size, void (*fn)(ACL_FIBER*, void*), void* ctx);
/**
- * reset the timer milliseconds time before the timer fiber wakeup
+ * Reset the timer milliseconds time before the timer fiber wakeup
* @param timer {ACL_FIBER*} the fiber created by acl_fiber_create_timer
* @param milliseconds {unsigned int} the new timer wakeup milliseconds
*/
FIBER_API void acl_fiber_reset_timer(ACL_FIBER* timer, unsigned int milliseconds);
/**
- * set the DNS service addr
+ * Set the DNS service addr
* @param ip {const char*} ip of the DNS service
* @param port {int} port of the DNS service
*/
FIBER_API void acl_fiber_set_dns(const char* ip, int port);
-/* for fiber specific */
+/* For fiber specific */
/**
- * set the current fiber's local object
+ * Set the current fiber's local object
* @param key {int*} the addr of indexed key, its initial value should <= 0,
* and one integer which > 0 will be set for it; the fiber local object will
* be assosiated with the indexed key.
@@ -271,7 +304,7 @@ FIBER_API void acl_fiber_set_dns(const char* ip, int port);
FIBER_API int acl_fiber_set_specific(int* key, void* ctx, void (*free_fn)(void*));
/**
- * get the current fiber's local object assosiated with the specified indexed key
+ * Get the current fiber's local object assosiated with the specified indexed key
* @param key {int} the integer value returned by acl_fiber_set_specific
* @retur {void*} NULL returned if no fiber local object with the specified key
*/
@@ -280,7 +313,7 @@ FIBER_API void* acl_fiber_get_specific(int key);
/****************************************************************************/
/**
- * log function type used in fiber logging process, should be set by the
+ * Log function type used in fiber logging process, should be set by the
* function acl_fiber_msg_pre_write
* @param ctx {void*} the user's context
* @param fmt {const char*} format of parameters
@@ -289,7 +322,7 @@ FIBER_API void* acl_fiber_get_specific(int key);
typedef void (*FIBER_MSG_PRE_WRITE_FN)(void *ctx, const char *fmt, va_list ap);
/**
- * log function type used in fiber logging process, should be set by the
+ * Log function type used in fiber logging process, should be set by the
* function acl_fiber_msg_register. This can be used by user for get the
* logging information of fiber
* @param ctx {void*} the user's context
@@ -299,44 +332,44 @@ typedef void (*FIBER_MSG_PRE_WRITE_FN)(void *ctx, const char *fmt, va_list ap);
typedef void (*FIBER_MSG_WRITE_FN) (void *ctx, const char *fmt, va_list ap);
/**
- * set the user's log saving function when process started
+ * Set the user's log saving function when process started
* @param write_fn {MSG_WRITE_FN} log function defined by the user
* @param ctx {void*} parameter will be transfered to write_fn
*/
FIBER_API void acl_fiber_msg_register(FIBER_MSG_WRITE_FN write_fn, void *ctx);
/**
- * cleanup the registered log callback by acl_fiber_msg_register
+ * Cleanup the registered log callback by acl_fiber_msg_register
*/
FIBER_API void acl_fiber_msg_unregister(void);
/**
- * register the user's callback
+ * Register the user's callback
* @param pre_write {MSG_PRE_WRITE_FN}
* @param ctx {void*}
*/
FIBER_API void acl_fiber_msg_pre_write(FIBER_MSG_PRE_WRITE_FN pre_write, void *ctx);
/**
- * if showing the fiber schedule process's log to stdout
+ * If showing the fiber schedule process's log to stdout
* @param onoff {int} log will be showed to stdout if onoff isn't 0
*/
FIBER_API void acl_fiber_msg_stdout_enable(int onoff);
/**
- * get the system error number of last system API calling
+ * Get the system error number of last system API calling
* @return {int} error number
*/
FIBER_API int acl_fiber_last_error(void);
/**
- * get the error information of last system API calling
+ * Get the error information of last system API calling
* @return {const char*}
*/
FIBER_API const char *acl_fiber_last_serror(void);
/**
- * convert errno to string
+ * Convert errno to string
* @param errnum {int}
* @param buf {char*} hold the result
* @param size {size_t} buf's size
@@ -345,13 +378,13 @@ FIBER_API const char *acl_fiber_last_serror(void);
FIBER_API const char *acl_fiber_strerror(int errnum, char *buf, size_t size);
/**
- * set the system error number
+ * Set the system error number
* @param errnum {int} the error number
*/
FIBER_API void acl_fiber_set_error(int errnum);
/**
- * set the fd limit for the current process
+ * Set the fd limit for the current process
* @param limit {int} the fd limit to be set
* @return {int} the real fd limit will be returned
*/
diff --git a/lib_fiber/c/include/fiber/fiber_channel.h b/lib_fiber/c/include/fiber/fiber_channel.h
index de8cc961f..08ecf004d 100644
--- a/lib_fiber/c/include/fiber/fiber_channel.h
+++ b/lib_fiber/c/include/fiber/fiber_channel.h
@@ -7,15 +7,15 @@
extern "C" {
#endif
-/* channel communication */
+/* Channel communication */
/**
- * the fiber channel type definition
+ * The fiber channel type definition
*/
typedef struct ACL_CHANNEL ACL_CHANNEL;
/**
- * create one fiber channel
+ * Create one fiber channel
* @param elemsize {int} the fixed object size transfered in fiber channel
* @param bufsize {int} the buffered of objects in fiber channel
* @return {ACL_CHANNNEL*}
@@ -23,13 +23,13 @@ typedef struct ACL_CHANNEL ACL_CHANNEL;
FIBER_API ACL_CHANNEL* acl_channel_create(int elemsize, int bufsize);
/**
- * free fiber channel created by acl_channel_create
+ * Free fiber channel created by acl_channel_create
* @param c {ACL_CHANNEL*} created by acl_channel_create
*/
FIBER_API void acl_channel_free(ACL_CHANNEL* c);
/**
- * send object to specified fiber channel in block mode
+ * Send object to specified fiber channel in block mode
* @param c {ACL_CHANNEL*} created by acl_channel_create
* @param v {void*} the object to be transfered
* @return {int} value (>= 0) returned
@@ -37,7 +37,7 @@ FIBER_API void acl_channel_free(ACL_CHANNEL* c);
FIBER_API int acl_channel_send(ACL_CHANNEL* c, void* v);
/**
- * send object to specified fiber channel in non-block mode, one new object
+ * Send object to specified fiber channel in non-block mode, one new object
* copied from which will be created internal
* @param c {ACL_CHANNEL*} created by acl_channel_create
* @param v {void*} the object to be transfered
@@ -46,7 +46,7 @@ FIBER_API int acl_channel_send(ACL_CHANNEL* c, void* v);
FIBER_API int acl_channel_send_nb(ACL_CHANNEL* c, void* v);
/**
- * read one object from specified channel in block mode
+ * Read one object from specified channel in block mode
* @param c {ACL_CHANNEL*} created by acl_channel_create
* @param v {void*} will store the result
* @return {int} value(>= 0) returned if get one object
@@ -54,7 +54,7 @@ FIBER_API int acl_channel_send_nb(ACL_CHANNEL* c, void* v);
FIBER_API int acl_channel_recv(ACL_CHANNEL* c, void* v);
/**
- * read one object from specified channel in non-block ode
+ * Read one object from specified channel in non-block ode
* @param c {ACL_CHANNEL*} created by acl_channel_create
* @param v {void*} will store the result
* @return {int} value(>= 0) returned if get one object, or NULL returned if
@@ -63,7 +63,7 @@ FIBER_API int acl_channel_recv(ACL_CHANNEL* c, void* v);
FIBER_API int acl_channel_recv_nb(ACL_CHANNEL* c, void* v);
/**
- * send object's addr to specified channel in block mode
+ * Send object's addr to specified channel in block mode
* @param c {ACL_CHANNEL*} created by acl_channel_create
* @param v {void*} the addr of the object to be transfered
* @return {int} value (>= 0) returned
@@ -71,14 +71,14 @@ FIBER_API int acl_channel_recv_nb(ACL_CHANNEL* c, void* v);
FIBER_API int acl_channel_sendp(ACL_CHANNEL* c, void* v);
/**
- * get object's addr from specified channel in block mode
+ * Get object's addr from specified channel in block mode
* @param c {ACL_CHANNEL*} created by acl_channel_create
* @return {void*} non-NULL addr returned
*/
FIBER_API void *acl_channel_recvp(ACL_CHANNEL* c);
/**
- * send the object's addr to specified channel in non-block mode
+ * Send the object's addr to specified channel in non-block mode
* @param c {ACL_CHANNEL*} created by acl_channel_create
* @param v {void*} the addr of the object to be transfered
* @return {int} value which is >= 0 returned
@@ -86,14 +86,14 @@ FIBER_API void *acl_channel_recvp(ACL_CHANNEL* c);
FIBER_API int acl_channel_sendp_nb(ACL_CHANNEL* c, void* v);
/**
- * get the object's addr form specified channel in non-block mode
+ * Get the object's addr form specified channel in non-block mode
* @param c {ACL_CHANNEL*} created by acl_channel_create
* @return {void*} * non-NULL returned when got one, or NULL returned
*/
FIBER_API void *acl_channel_recvp_nb(ACL_CHANNEL* c);
/**
- * send unsigned integer to specified channel in block mode
+ * Send unsigned integer to specified channel in block mode
* @param c {ACL_CHANNEL*} created by acl_channel_create
* @param val {unsigned long} the integer to be sent
* @return {int} value (>= 0) returned
@@ -101,14 +101,14 @@ FIBER_API void *acl_channel_recvp_nb(ACL_CHANNEL* c);
FIBER_API int acl_channel_sendul(ACL_CHANNEL* c, unsigned long val);
/**
- * get unsigned integer from specified channel in block mode
+ * Get unsigned integer from specified channel in block mode
* @param c {ACL_CHANNEL*} created by acl_channel_create
* @return {unsigned long}
*/
FIBER_API unsigned long acl_channel_recvul(ACL_CHANNEL* c);
/**
- * sent unsigned integer to specified channel in non-block mode
+ * Sent unsigned integer to specified channel in non-block mode
* @param c {ACL_CHANNEL*} created by acl_channel_create
* @param val {unsigned long} integer to be sent
* @return {int} value(>= 0) returned
@@ -116,7 +116,7 @@ FIBER_API unsigned long acl_channel_recvul(ACL_CHANNEL* c);
FIBER_API int acl_channel_sendul_nb(ACL_CHANNEL* c, unsigned long val);
/**
- * get one unsigned integer from specified channel in non-block mode
+ * Get one unsigned integer from specified channel in non-block mode
* @param c {ACL_CHANNEL*} created by acl_channel_create
* @return {unsigned long}
*/
diff --git a/lib_fiber/c/include/fiber/fiber_cond.h b/lib_fiber/c/include/fiber/fiber_cond.h
index 95d541bad..053b72b3d 100644
--- a/lib_fiber/c/include/fiber/fiber_cond.h
+++ b/lib_fiber/c/include/fiber/fiber_cond.h
@@ -11,26 +11,26 @@ extern "C" {
/* fiber_cond.h */
/**
- * fiber_cond object look like pthread_cond_t which is used between threads
+ * Fiber_cond object look like pthread_cond_t which is used between threads
* and fibers
*/
typedef struct ACL_FIBER_COND ACL_FIBER_COND;
/**
- * create fiber cond which can be used in fibers more or threads mode
+ * Create fiber cond which can be used in fibers more or threads mode
* @param flag {unsigned} current not used, just for the future extend
* @return {ACL_FIBER_COND *}
*/
FIBER_API ACL_FIBER_COND *acl_fiber_cond_create(unsigned flag);
/**
- * free cond created by acl_fiber_cond_create
+ * Free cond created by acl_fiber_cond_create
* @param cond {ACL_FIBER_COND *}
*/
FIBER_API void acl_fiber_cond_free(ACL_FIBER_COND *cond);
/**
- * wait for cond event to be signaled
+ * Wait for cond event to be signaled
* @param cond {ACL_FIBER_COND *}
* @param event {ACL_FIBER_EVENT *} must be owned by the current caller
* @return {int} return 0 if ok or return error value
@@ -38,7 +38,7 @@ FIBER_API void acl_fiber_cond_free(ACL_FIBER_COND *cond);
FIBER_API int acl_fiber_cond_wait(ACL_FIBER_COND *cond, ACL_FIBER_EVENT *event);
/**
- * wait for cond event to be signaled with the specified timeout
+ * Wait for cond event to be signaled with the specified timeout
* @param cond {ACL_FIBER_COND *}
* @return {int} return 0 if ok or return error value, when timedout ETIMEDOUT
* will be returned
@@ -47,7 +47,7 @@ FIBER_API int acl_fiber_cond_timedwait(ACL_FIBER_COND *cond,
ACL_FIBER_EVENT *event, int delay_ms);
/**
- * signle the cond which will wakeup one waiter for the cond to be signaled
+ * Signal the cond which will wakeup one waiter for the cond to be signaled
* @param cond {ACL_FIBER_COND *}
* @return {int} return 0 if ok or return error value
*/
diff --git a/lib_fiber/c/include/fiber/fiber_define.h b/lib_fiber/c/include/fiber/fiber_define.h
index 08e8cac6f..a7d6ee454 100644
--- a/lib_fiber/c/include/fiber/fiber_define.h
+++ b/lib_fiber/c/include/fiber/fiber_define.h
@@ -95,7 +95,7 @@ typedef int socket_t;
#endif
/**
- * the fiber struct type definition
+ * The fiber struct type definition
*/
typedef struct ACL_FIBER ACL_FIBER;
diff --git a/lib_fiber/c/include/fiber/fiber_event.h b/lib_fiber/c/include/fiber/fiber_event.h
index 8e0e0e872..25cbe0647 100644
--- a/lib_fiber/c/include/fiber/fiber_event.h
+++ b/lib_fiber/c/include/fiber/fiber_event.h
@@ -10,13 +10,13 @@ extern "C" {
/* fiber_event.c */
/**
- * fiber event mutex object based on IO event, which is thread safety. That's
+ * Fiber event mutex object based on IO event, which is thread safety. That's
* to say one event object can used in different threads
*/
typedef struct ACL_FIBER_EVENT ACL_FIBER_EVENT;
/**
- * when the fiber_event is used in multiple threads for sync, if there're
+ * When the fiber_event is used in multiple threads for sync, if there're
* many threads, the flag FIBER_FLAG_USE_MUTEX should be set to avoid internal
* thundering herd which maybe happen by using atomic; if the threads' number
* is less than one hundred, the flag FIBER_FLAG_USE_MUTEX needn't be set
@@ -24,40 +24,40 @@ typedef struct ACL_FIBER_EVENT ACL_FIBER_EVENT;
#define FIBER_FLAG_USE_MUTEX (1 << 0)
/**
- * if this flag is set, msg_fatal will be used other msg_error when error
+ * If this flag is set, msg_fatal will be used other msg_error when error
* happened, this flag is optional for users
*/
#define FIBER_FLAG_USE_FATAL (1 << 1)
/**
- * create fiber event mutex which can be used in fibers mode or threads mode
+ * Create fiber event mutex which can be used in fibers mode or threads mode
* @param flag {unsigned} define as FIBER_FLAG_XXX above
* @return {ACL_FIBER_EVENT *}
*/
FIBER_API ACL_FIBER_EVENT *acl_fiber_event_create(unsigned flag);
/**
- * free event mutex returned by acl_fiber_event_create
+ * Free event mutex returned by acl_fiber_event_create
* @param {ACL_FIBER_EVENT *}
*/
FIBER_API void acl_fiber_event_free(ACL_FIBER_EVENT *event);
/**
- * wait for event can be available
+ * Wait for event can be available
* @param {ACL_FIBER_EVENT *}
* @return {int} 0 returned if successful, or -1 if error happened
*/
FIBER_API int acl_fiber_event_wait(ACL_FIBER_EVENT *event);
/**
- * try to wait for event can be available
+ * Try to wait for event can be available
* @param {ACL_FIBER_EVENT *}
* @return {int} 0 returned if successful, or -1 if the event been locked
*/
FIBER_API int acl_fiber_event_trywait(ACL_FIBER_EVENT *event);
/**
- * the event's owner notify the waiters that the event mutex can be available,
+ * The event's owner notify the waiters that the event mutex can be available,
* and the waiter will get the event mutex
* @param {ACL_FIBER_EVENT *}
* @return {int} 0 returned if successful, or -1 if error happened
diff --git a/lib_fiber/c/include/fiber/fiber_lock.h b/lib_fiber/c/include/fiber/fiber_lock.h
index 4c69cd7b3..dd6884bfb 100644
--- a/lib_fiber/c/include/fiber/fiber_lock.h
+++ b/lib_fiber/c/include/fiber/fiber_lock.h
@@ -7,40 +7,40 @@
extern "C" {
#endif
-/* fiber locking */
+/* Fiber locking */
/**
- * fiber mutex, thread unsafety, one fiber mutex can only be used in the
+ * Fiber mutex, thread unsafety, one fiber mutex can only be used in the
* same thread, otherwise the result is unpredictable
*/
typedef struct ACL_FIBER_MUTEX ACL_FIBER_MUTEX;
/**
- * fiber read/write mutex, thread unsafety, can only be used in the sampe thread
+ * Fiber read/write mutex, thread unsafety, can only be used in the sampe thread
*/
typedef struct ACL_FIBER_RWLOCK ACL_FIBER_RWLOCK;
/**
- * create one fiber mutex, can only be used in the same thread
+ * Create one fiber mutex, can only be used in the same thread
* @return {ACL_FIBER_MUTEX*} fiber mutex returned
*/
FIBER_API ACL_FIBER_MUTEX* acl_fiber_mutex_create(void);
/**
- * free fiber mutex created by acl_fiber_mutex_create
+ * Free fiber mutex created by acl_fiber_mutex_create
* @param l {ACL_FIBER_MUTEX*} created by acl_fiber_mutex_create
*/
FIBER_API void acl_fiber_mutex_free(ACL_FIBER_MUTEX* l);
/**
- * lock the specified fiber mutex, return immediately when locked, or will
+ * Lock the specified fiber mutex, return immediately when locked, or will
* wait until the mutex can be used
* @param l {ACL_FIBER_MUTEX*} created by acl_fiber_mutex_create
*/
FIBER_API void acl_fiber_mutex_lock(ACL_FIBER_MUTEX* l);
/**
- * try lock the specified fiber mutex, return immediately no matter the mutex
+ * Try lock the specified fiber mutex, return immediately no matter the mutex
* can be locked.
* @param l {ACL_FIBER_MUTEX*} created by acl_fiber_mutex_create
* @return {int} 0 returned when locking successfully, -1 when locking failed
@@ -48,7 +48,7 @@ FIBER_API void acl_fiber_mutex_lock(ACL_FIBER_MUTEX* l);
FIBER_API int acl_fiber_mutex_trylock(ACL_FIBER_MUTEX* l);
/**
- * the fiber mutex be unlock by its owner fiber, fatal will happen when others
+ * The fiber mutex be unlock by its owner fiber, fatal will happen when others
* release the fiber mutex
* @param l {ACL_FIBER_MUTEX*} created by acl_fiber_mutex_create
*/
@@ -57,19 +57,19 @@ FIBER_API void acl_fiber_mutex_unlock(ACL_FIBER_MUTEX* l);
/****************************************************************************/
/**
- * create one fiber rwlock, can only be operated in the sampe thread
+ * Create one fiber rwlock, can only be operated in the sampe thread
* @return {ACL_FIBER_RWLOCK*}
*/
FIBER_API ACL_FIBER_RWLOCK* acl_fiber_rwlock_create(void);
/**
- * free rw mutex created by acl_fiber_rwlock_create
+ * Free rw mutex created by acl_fiber_rwlock_create
* @param l {ACL_FIBER_RWLOCK*} created by acl_fiber_rwlock_create
*/
FIBER_API void acl_fiber_rwlock_free(ACL_FIBER_RWLOCK* l);
/**
- * lock the rwlock, if there is no any write locking on it, the
+ * Lock the rwlock, if there is no any write locking on it, the
* function will return immediately; otherwise, the caller will wait for all
* write locking be released. Read lock on it will successful when returning
* @param l {ACL_FIBER_RWLOCK*} created by acl_fiber_rwlock_create
@@ -77,7 +77,7 @@ FIBER_API void acl_fiber_rwlock_free(ACL_FIBER_RWLOCK* l);
FIBER_API void acl_fiber_rwlock_rlock(ACL_FIBER_RWLOCK* l);
/**
- * try to locking the Readonly lock, return immediately no matter locking
+ * Try to locking the Readonly lock, return immediately no matter locking
* is successful.
* @param l {ACL_FIBER_RWLOCK*} crated by acl_fiber_rwlock_create
* @retur {int} 1 returned when successfully locked, or 0 returned if locking
@@ -86,13 +86,13 @@ FIBER_API void acl_fiber_rwlock_rlock(ACL_FIBER_RWLOCK* l);
FIBER_API int acl_fiber_rwlock_tryrlock(ACL_FIBER_RWLOCK* l);
/**
- * lock the rwlock in Write Lock mode, return until no any one locking it
+ * Lock the rwlock in Write Lock mode, return until no any one locking it
* @param l {ACL_FIBER_RWLOCK*} created by acl_fiber_rwlock_create
*/
FIBER_API void acl_fiber_rwlock_wlock(ACL_FIBER_RWLOCK* l);
/**
- * try to lock the rwlock in Write Lock mode. return immediately no matter
+ * Try to lock the rwlock in Write Lock mode. return immediately no matter
* locking is successful.
* @param l {ACL_FIBER_RWLOCK*} created by acl_fiber_rwlock_create
* @return {int} 1 returned when locking successfully, or 0 returned when
@@ -101,13 +101,13 @@ FIBER_API void acl_fiber_rwlock_wlock(ACL_FIBER_RWLOCK* l);
FIBER_API int acl_fiber_rwlock_trywlock(ACL_FIBER_RWLOCK* l);
/**
- * the rwlock's Read-Lock owner unlock the rwlock
+ * The rwlock's Read-Lock owner unlock the rwlock
* @param l {ACL_FIBER_RWLOCK*} crated by acl_fiber_rwlock_create
*/
FIBER_API void acl_fiber_rwlock_runlock(ACL_FIBER_RWLOCK* l);
/**
- * the rwlock's Write-Lock owner unlock the rwlock
+ * The rwlock's Write-Lock owner unlock the rwlock
* @param l {ACL_FIBER_RWLOCK*} created by acl_fiber_rwlock_create
*/
FIBER_API void acl_fiber_rwlock_wunlock(ACL_FIBER_RWLOCK* l);
diff --git a/lib_fiber/c/include/fiber/fiber_sem.h b/lib_fiber/c/include/fiber/fiber_sem.h
index a79116bb4..ae4842a0a 100644
--- a/lib_fiber/c/include/fiber/fiber_sem.h
+++ b/lib_fiber/c/include/fiber/fiber_sem.h
@@ -7,26 +7,26 @@
extern "C" {
#endif
-/* fiber semaphore, thread unsafety, one semaphore can only be used in one
+/* Fiber semaphore, thread unsafety, one semaphore can only be used in one
* thread, if used in different threads, result is unpredictable */
typedef struct ACL_FIBER_SEM ACL_FIBER_SEM;
/**
- * create one fiber semaphore, and binding it with the current thread
+ * Create one fiber semaphore, and binding it with the current thread
* @param num {int} the initial value of the semaphore, must >= 0
* @return {ACL_FIBER_SEM *}
*/
FIBER_API ACL_FIBER_SEM* acl_fiber_sem_create(int num);
/**
- * free fiber semaphore
+ * Free fiber semaphore
* @param {ACL_FIBER_SEM *}
*/
FIBER_API void acl_fiber_sem_free(ACL_FIBER_SEM* sem);
/**
- * get the thread binding the specificed fiber sem
+ * Get the thread binding the specificed fiber sem
* @param sem {ACL_FIBER_SEM*} created by acl_fiber_sem_create
* @return {unsigned long} thread ID of the thread binding the semaphore
*/
@@ -35,7 +35,7 @@ FIBER_API unsigned long acl_fiber_sem_get_tid(ACL_FIBER_SEM* sem);
#endif
/**
- * set the thread ID the semaphore belongs to, changing the owner of the fiber
+ * Set the thread ID the semaphore belongs to, changing the owner of the fiber
* semaphore, when this function was called, the value of the semaphore must
* be zero, otherwise fatal will happen.
* @param sem {ACL_FIBER_SEM*} created by acl_fiber_sem_create
@@ -44,7 +44,7 @@ FIBER_API unsigned long acl_fiber_sem_get_tid(ACL_FIBER_SEM* sem);
FIBER_API void acl_fiber_sem_set_tid(ACL_FIBER_SEM* sem, unsigned long tid);
/**
- * wait for semaphore until > 0, semaphore will be -1 when returned
+ * Wait for semaphore until > 0, semaphore will be -1 when returned
* @param sem {ACL_FIBER_SEM *} created by acl_fiber_sem_create
* @return {int} the semaphore value returned, if the caller's thread isn't
* same as the semaphore owner's thread, -1 will be returned
@@ -52,7 +52,7 @@ FIBER_API void acl_fiber_sem_set_tid(ACL_FIBER_SEM* sem, unsigned long tid);
FIBER_API int acl_fiber_sem_wait(ACL_FIBER_SEM* sem);
/**
- * try to wait semaphore until > 0, if semaphore is 0, -1 returned immediately,
+ * Try to wait semaphore until > 0, if semaphore is 0, -1 returned immediately,
* otherwise semaphore will be decreased 1 and the semaphore's value is returned
* @param sem {ACL_FIBER_SEM *} created by acl_fiber_sem_create
* @return {int} value(>=0) returned when waiting ok, otherwise -1 will be
@@ -62,7 +62,7 @@ FIBER_API int acl_fiber_sem_wait(ACL_FIBER_SEM* sem);
FIBER_API int acl_fiber_sem_trywait(ACL_FIBER_SEM* sem);
/**
- * add 1 to the semaphore, if there are other fibers waiting for semaphore,
+ * Add 1 to the semaphore, if there are other fibers waiting for semaphore,
* one waiter will be wakeuped
* @param sem {ACL_FIBER_SEM *} created by acl_fiber_sem_create
* @return {int} the current semaphore value returned, -1 returned if the
@@ -71,7 +71,7 @@ FIBER_API int acl_fiber_sem_trywait(ACL_FIBER_SEM* sem);
FIBER_API int acl_fiber_sem_post(ACL_FIBER_SEM* sem);
/**
- * get the specificed semaphore's value
+ * Get the specificed semaphore's value
* @param sem {ACL_FIBER_SEM*} created by acl_fiber_sem_create
* @retur {int} current semaphore's value returned
*/
diff --git a/lib_fiber/c/src/common/msg.c b/lib_fiber/c/src/common/msg.c
index 44fde8c55..01baa8f09 100644
--- a/lib_fiber/c/src/common/msg.c
+++ b/lib_fiber/c/src/common/msg.c
@@ -49,19 +49,23 @@ void msg_info(const char *fmt,...)
va_start (ap, fmt);
if (__pre_write_fn) {
- __pre_write_fn(__pre_write_ctx, fmt, ap);
+ va_list ap_tmp;
+ va_copy(ap_tmp, ap);
+ __pre_write_fn(__pre_write_ctx, fmt, ap_tmp);
+ }
+
+ if (__stdout_enable) {
+ va_list ap_tmp;
+ va_copy(ap_tmp, ap);
+ printf("msg_info->pid(%d), ", GETPID());
+ vprintf(fmt, ap_tmp);
+ printf("\r\n");
}
if (__write_fn != NULL) {
__write_fn(__msg_ctx, fmt, ap);
}
- if (__stdout_enable) {
- printf("msg_info->pid(%d), ", GETPID());
- vprintf(fmt, ap);
- printf("\r\n");
- }
-
va_end (ap);
}
@@ -72,18 +76,22 @@ void msg_warn(const char *fmt,...)
va_start (ap, fmt);
if (__pre_write_fn) {
- __pre_write_fn(__pre_write_ctx, fmt, ap);
+ va_list ap_tmp;
+ va_copy(ap_tmp, ap);
+ __pre_write_fn(__pre_write_ctx, fmt, ap_tmp);
+ }
+
+ if (__stdout_enable) {
+ va_list ap_tmp;
+ va_copy(ap_tmp, ap);
+ printf("msg_warn->pid(%d), ", GETPID());
+ vprintf(fmt, ap_tmp);
+ printf("\r\n");
}
if (__write_fn != NULL) {
__write_fn(__msg_ctx, fmt, ap);
}
-
- if (__stdout_enable) {
- printf("msg_warn->pid(%d), ", GETPID());
- vprintf(fmt, ap);
- printf("\r\n");
- }
va_end (ap);
}
@@ -95,18 +103,22 @@ void msg_error(const char *fmt,...)
va_start (ap, fmt);
if (__pre_write_fn) {
- __pre_write_fn(__pre_write_ctx, fmt, ap);
+ va_list ap_tmp;
+ va_copy(ap_tmp, ap);
+ __pre_write_fn(__pre_write_ctx, fmt, ap_tmp);
+ }
+
+ if (__stdout_enable) {
+ va_list ap_tmp;
+ va_copy(ap_tmp, ap);
+ printf("msg_error->pid(%d), ", GETPID());
+ vprintf(fmt, ap_tmp);
+ printf("\r\n");
}
if (__write_fn != NULL) {
__write_fn(__msg_ctx, fmt, ap);
}
-
- if (__stdout_enable) {
- printf("msg_error->pid(%d), ", GETPID());
- vprintf(fmt, ap);
- printf("\r\n");
- }
va_end (ap);
}
@@ -118,19 +130,23 @@ void msg_fatal(const char *fmt,...)
va_start (ap, fmt);
if (__pre_write_fn) {
- __pre_write_fn(__pre_write_ctx, fmt, ap);
+ va_list ap_tmp;
+ va_copy(ap_tmp, ap);
+ __pre_write_fn(__pre_write_ctx, fmt, ap_tmp);
+ }
+
+ if (__stdout_enable) {
+ va_list ap_tmp;
+ va_copy(ap_tmp, ap);
+ printf("msg_fatal->pid(%d), ", GETPID());
+ printf("fatal:");
+ vprintf(fmt, ap_tmp);
+ printf("\r\n");
}
if (__write_fn != NULL) {
__write_fn(__msg_ctx, fmt, ap);
}
-
- if (__stdout_enable) {
- printf("msg_fatal->pid(%d), ", GETPID());
- printf("fatal:");
- vprintf(fmt, ap);
- printf("\r\n");
- }
va_end (ap);
abort();
diff --git a/lib_fiber/c/src/dns/dns.c.bak b/lib_fiber/c/src/dns/dns.c.bak
deleted file mode 100644
index 274131b53..000000000
--- a/lib_fiber/c/src/dns/dns.c.bak
+++ /dev/null
@@ -1,10129 +0,0 @@
-/* ==========================================================================
- * dns.c - Recursive, Reentrant DNS Resolver.
- * --------------------------------------------------------------------------
- * Copyright (c) 2008, 2009, 2010, 2012-2016 William Ahern
- *
- * 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 the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to permit
- * persons to whom the Software is furnished to do so, subject to the
- * following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
- * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
- * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
- * USE OR OTHER DEALINGS IN THE SOFTWARE.
- * ==========================================================================
- */
-#include "stdafx.h"
-
-#ifdef SYS_UNIX
-
-#include "fiber/libfiber.h"
-#include "common.h"
-
-#if !defined(__FreeBSD__) && !defined(__sun)
-#ifndef _XOPEN_SOURCE
-#define _XOPEN_SOURCE 600
-#endif
-
-#undef _DEFAULT_SOURCE
-#define _DEFAULT_SOURCE
-
-#undef _BSD_SOURCE
-#define _BSD_SOURCE
-
-#undef _DARWIN_C_SOURCE
-#define _DARWIN_C_SOURCE
-
-#undef _NETBSD_SOURCE
-#define _NETBSD_SOURCE
-#endif
-
-#include /* INT_MAX */
-#include /* offsetof() */
-#ifdef _WIN32
-#define uint32_t unsigned int
-#else
-#include /* uint32_t */
-#endif
-#include /* malloc(3) realloc(3) free(3) rand(3) random(3) arc4random(3) */
-#include /* FILE fopen(3) fclose(3) getc(3) rewind(3) */
-#include /* memcpy(3) strlen(3) memmove(3) memchr(3) memcmp(3) strchr(3) strsep(3) strcspn(3) */
-#include /* strcasecmp(3) strncasecmp(3) */
-#include /* isspace(3) isdigit(3) */
-#include /* time_t time(2) difftime(3) */
-#include /* SIGPIPE sigemptyset(3) sigaddset(3) sigpending(2) sigprocmask(2) pthread_sigmask(3) sigtimedwait(2) */
-#include /* errno EINVAL ENOENT */
-#undef NDEBUG
-#include /* assert(3) */
-
-#if _WIN32
-#ifndef FD_SETSIZE
-#define FD_SETSIZE 256
-#endif
-#include
-#include
-#else
-#include /* FD_SETSIZE socklen_t */
-#include /* FD_ZERO FD_SET fd_set select(2) */
-#include /* AF_INET AF_INET6 AF_UNIX struct sockaddr struct sockaddr_in struct sockaddr_in6 socket(2) */
-#if defined(AF_UNIX)
-#include /* struct sockaddr_un */
-#endif
-#include /* F_SETFD F_GETFL F_SETFL O_NONBLOCK fcntl(2) */
-#include /* _POSIX_THREADS gethostname(3) close(2) */
-#include /* POLLIN POLLOUT */
-#include /* struct sockaddr_in struct sockaddr_in6 */
-#include /* inet_pton(3) inet_ntop(3) htons(3) ntohs(3) */
-#include /* struct addrinfo */
-#endif
-
-#include "dns.h"
-
-
-/*
- * C O M P I L E R V E R S I O N & F E A T U R E D E T E C T I O N
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-#define DNS_GNUC_2VER(M, m, p) (((M) * 10000) + ((m) * 100) + (p))
-#define DNS_GNUC_PREREQ(M, m, p) (__GNUC__ > 0 && DNS_GNUC_2VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) >= DNS_GNUC_2VER((M), (m), (p)))
-
-#define DNS_MSC_2VER(M, m, p) ((((M) + 6) * 10000000) + ((m) * 1000000) + (p))
-#define DNS_MSC_PREREQ(M, m, p) (_MSC_VER_FULL > 0 && _MSC_VER_FULL >= DNS_MSC_2VER((M), (m), (p)))
-
-#define DNS_SUNPRO_PREREQ(M, m, p) (__SUNPRO_C > 0 && __SUNPRO_C >= 0x ## M ## m ## p)
-
-#if defined __has_builtin
-#define dns_has_builtin(x) __has_builtin(x)
-#else
-#define dns_has_builtin(x) 0
-#endif
-
-#if defined __has_extension
-#define dns_has_extension(x) __has_extension(x)
-#else
-#define dns_has_extension(x) 0
-#endif
-
-#ifndef HAVE___ASSUME
-#define HAVE___ASSUME DNS_MSC_PREREQ(8,0,0)
-#endif
-
-#ifndef HAVE___BUILTIN_TYPES_COMPATIBLE_P
-#define HAVE___BUILTIN_TYPES_COMPATIBLE_P (DNS_GNUC_PREREQ(3,1,1) || __clang__)
-#endif
-
-#ifndef HAVE___BUILTIN_UNREACHABLE
-#define HAVE___BUILTIN_UNREACHABLE (DNS_GNUC_PREREQ(4,5,0) || dns_has_builtin(__builtin_unreachable))
-#endif
-
-#ifndef HAVE_PRAGMA_MESSAGE
-#define HAVE_PRAGMA_MESSAGE (DNS_GNUC_PREREQ(4,4,0) || __clang__ || _MSC_VER)
-#endif
-
-
-/*
- * C O M P I L E R A N N O T A T I O N S
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-#if __GNUC__
-#define DNS_NOTUSED __attribute__((unused))
-#define DNS_NORETURN __attribute__((noreturn))
-#else
-#define DNS_NOTUSED
-#define DNS_NORETURN
-#endif
-
-#if __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunused-parameter"
-#pragma clang diagnostic ignored "-Wmissing-field-initializers"
-#elif DNS_GNUC_PREREQ(4,6,0)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunused-parameter"
-#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
-#endif
-
-
-/*
- * S T A N D A R D M A C R O S
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-#if HAVE___BUILTIN_TYPES_COMPATIBLE_P
-#define dns_same_type(a, b, def) __builtin_types_compatible_p(__typeof__ (a), __typeof__ (b))
-#else
-#define dns_same_type(a, b, def) (def)
-#endif
-#define dns_isarray(a) (!dns_same_type((a), (&(a)[0]), 0))
-/* NB: "_" field silences Sun Studio "zero-sized struct/union" error diagnostic */
-#define dns_inline_assert(cond) ((void)(sizeof (struct { int:-!(cond); int _; })))
-
-#if HAVE___ASSUME
-#define dns_assume(cond) __assume(cond)
-#elif HAVE___BUILTIN_UNREACHABLE
-#define dns_assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0)
-#else
-#define dns_assume(cond) do { (void)(cond); } while (0)
-#endif
-
-#ifndef lengthof
-#define lengthof(a) (dns_inline_assert(dns_isarray(a)), (sizeof (a) / sizeof (a)[0]))
-#endif
-
-#ifndef endof
-#define endof(a) (dns_inline_assert(dns_isarray(a)), &(a)[lengthof((a))])
-#endif
-
-
-/*
- * M I S C E L L A N E O U S C O M P A T
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-#if _WIN32 || _WIN64
-#define PRIuZ "Iu"
-#else
-#define PRIuZ "zu"
-#endif
-
-#ifndef DNS_THREAD_SAFE
-#if (defined _REENTRANT || defined _THREAD_SAFE) && _POSIX_THREADS > 0
-#define DNS_THREAD_SAFE 1
-#else
-#define DNS_THREAD_SAFE 0
-#endif
-#endif
-
-#ifndef HAVE__STATIC_ASSERT
-#define HAVE__STATIC_ASSERT \
- (dns_has_extension(c_static_assert) || DNS_GNUC_PREREQ(4,6,0) || \
- __C11FEATURES__ || __STDC_VERSION__ >= 201112L)
-#endif
-
-#ifndef HAVE_STATIC_ASSERT
-#if (defined static_assert) && \
- (!DNS_GNUC_PREREQ(0,0,0) || DNS_GNUC_PREREQ(4,6,0)) /* glibc doesn't check GCC version */
-#define HAVE_STATIC_ASSERT 1
-#else
-#define HAVE_STATIC_ASSERT 0
-#endif
-#endif
-
-#if HAVE_STATIC_ASSERT
-#define dns_static_assert(cond, msg) static_assert(cond, msg)
-#elif HAVE__STATIC_ASSERT
-#define dns_static_assert(cond, msg) _Static_assert(cond, msg)
-#else
-#define dns_static_assert(cond, msg) extern char DNS_PP_XPASTE(dns_assert_, __LINE__)[sizeof (int[1 - 2*!(cond)])]
-#endif
-
-
-/*
- * D E B U G M A C R O S
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-int *dns_debug_p(void) {
- static int debug;
-
- return &debug;
-} /* dns_debug_p() */
-
-#if DNS_DEBUG
-
-#undef DNS_DEBUG
-#define DNS_DEBUG dns_debug
-
-#define DNS_SAY_(fmt, ...) \
- do { if (DNS_DEBUG > 0) fprintf(stderr, fmt "%.1s", __func__, __LINE__, __VA_ARGS__); } while (0)
-#define DNS_SAY(...) DNS_SAY_("@@ (%s:%d) " __VA_ARGS__, "\n")
-#define DNS_HAI DNS_SAY("HAI")
-
-#define DNS_SHOW_(P, fmt, ...) do { \
- if (DNS_DEBUG > 1) { \
- fprintf(stderr, "@@ BEGIN * * * * * * * * * * * *\n"); \
- fprintf(stderr, "@@ " fmt "%.0s\n", __VA_ARGS__); \
- dns_p_dump((P), stderr); \
- fprintf(stderr, "@@ END * * * * * * * * * * * * *\n\n"); \
- } \
-} while (0)
-
-#define DNS_SHOW(...) DNS_SHOW_(__VA_ARGS__, "")
-
-#else /* !DNS_DEBUG */
-
-#undef DNS_DEBUG
-#define DNS_DEBUG 0
-
-#define DNS_SAY(...)
-#define DNS_HAI
-#define DNS_SHOW(...)
-
-#endif /* DNS_DEBUG */
-
-#define DNS_CARP(...) DNS_SAY(__VA_ARGS__)
-
-
-/*
- * V E R S I O N R O U T I N E S
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-const char *dns_vendor(void) {
- return DNS_VENDOR;
-} /* dns_vendor() */
-
-
-int dns_v_rel(void) {
- return DNS_V_REL;
-} /* dns_v_rel() */
-
-
-int dns_v_abi(void) {
- return DNS_V_ABI;
-} /* dns_v_abi() */
-
-
-int dns_v_api(void) {
- return DNS_V_API;
-} /* dns_v_api() */
-
-
-/*
- * E R R O R R O U T I N E S
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-#if _WIN32
-
-#define DNS_EINTR WSAEINTR
-#define DNS_EINPROGRESS WSAEINPROGRESS
-#define DNS_EISCONN WSAEISCONN
-#define DNS_EWOULDBLOCK WSAEWOULDBLOCK
-#define DNS_EALREADY WSAEALREADY
-#define DNS_EAGAIN EAGAIN
-#define DNS_ETIMEDOUT WSAETIMEDOUT
-
-#define dns_syerr() ((int)GetLastError())
-#define dns_soerr() ((int)WSAGetLastError())
-
-#else
-
-#define DNS_EINTR EINTR
-#define DNS_EINPROGRESS EINPROGRESS
-#define DNS_EISCONN EISCONN
-#define DNS_EWOULDBLOCK EWOULDBLOCK
-#define DNS_EALREADY EALREADY
-#define DNS_EAGAIN EAGAIN
-#define DNS_ETIMEDOUT ETIMEDOUT
-
-#define dns_syerr() errno
-#define dns_soerr() errno
-
-#endif
-
-
-const char *dns_strerror(int error) {
- switch (error) {
- case DNS_ENOBUFS:
- return "DNS packet buffer too small";
- case DNS_EILLEGAL:
- return "Illegal DNS RR name or data";
- case DNS_EORDER:
- return "Attempt to push RR out of section order";
- case DNS_ESECTION:
- return "Invalid section specified";
- case DNS_EUNKNOWN:
- return "Unknown DNS error";
- case DNS_EADDRESS:
- return "Invalid textual address form";
- case DNS_ENOQUERY:
- return "Bad execution state (missing query packet)";
- case DNS_ENOANSWER:
- return "Bad execution state (missing answer packet)";
- case DNS_EFETCHED:
- return "Answer already fetched";
- case DNS_ESERVICE:
- return "The service passed was not recognized for the specified socket type";
- case DNS_ENONAME:
- return "The name does not resolve for the supplied parameters";
- case DNS_EFAIL:
- return "A non-recoverable error occurred when attempting to resolve the name";
- default:
- return strerror(error);
- } /* switch() */
-} /* dns_strerror() */
-
-
-/*
- * A T O M I C R O U T I N E S
- *
- * Use GCC's __atomic built-ins if possible. Unlike the __sync built-ins, we
- * can use the preprocessor to detect API and, more importantly, ISA
- * support. We want to avoid linking headaches where the API depends on an
- * external library if the ISA (e.g. i386) doesn't support lockless
- * operation.
- *
- * TODO: Support C11's atomic API. Although that may require some finesse
- * with how we define some public types, such as dns_atomic_t and struct
- * dns_resolv_conf.
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-#ifndef HAVE___ATOMIC_FETCH_ADD
-#ifdef __ATOMIC_RELAXED
-#define HAVE___ATOMIC_FETCH_ADD 1
-#else
-#define HAVE___ATOMIC_FETCH_ADD 0
-#endif
-#endif
-
-#ifndef HAVE___ATOMIC_FETCH_SUB
-#define HAVE___ATOMIC_FETCH_SUB HAVE___ATOMIC_FETCH_ADD
-#endif
-
-#ifndef DNS_ATOMIC_FETCH_ADD
-#if HAVE___ATOMIC_FETCH_ADD && __GCC_ATOMIC_LONG_LOCK_FREE == 2
-#define DNS_ATOMIC_FETCH_ADD(i) __atomic_fetch_add((i), 1, __ATOMIC_RELAXED)
-#else
-#pragma message("no atomic_fetch_add available")
-#define DNS_ATOMIC_FETCH_ADD(i) ((*(i))++)
-#endif
-#endif
-
-#ifndef DNS_ATOMIC_FETCH_SUB
-#if HAVE___ATOMIC_FETCH_SUB && __GCC_ATOMIC_LONG_LOCK_FREE == 2
-#define DNS_ATOMIC_FETCH_SUB(i) __atomic_fetch_sub((i), 1, __ATOMIC_RELAXED)
-#else
-#pragma message("no atomic_fetch_sub available")
-#define DNS_ATOMIC_FETCH_SUB(i) ((*(i))--)
-#endif
-#endif
-
-static inline unsigned dns_atomic_fetch_add(dns_atomic_t *i) {
- return DNS_ATOMIC_FETCH_ADD(i);
-} /* dns_atomic_fetch_add() */
-
-
-static inline unsigned dns_atomic_fetch_sub(dns_atomic_t *i) {
- return DNS_ATOMIC_FETCH_SUB(i);
-} /* dns_atomic_fetch_sub() */
-
-
-/*
- * C R Y P T O R O U T I N E S
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-/*
- * P R N G
- */
-
-#ifndef DNS_RANDOM
-#if defined(HAVE_ARC4RANDOM) \
- || defined(__OpenBSD__) \
- || defined(__FreeBSD__) \
- || defined(__NetBSD__) \
- || defined(__APPLE__)
-#define DNS_RANDOM arc4random
-#elif __linux
-#define DNS_RANDOM random
-#else
-#define DNS_RANDOM rand
-#endif
-#endif
-
-#define DNS_RANDOM_arc4random 1
-#define DNS_RANDOM_random 2
-#define DNS_RANDOM_rand 3
-#define DNS_RANDOM_RAND_bytes 4
-
-#define DNS_RANDOM_OPENSSL (DNS_RANDOM_RAND_bytes == DNS_PP_XPASTE(DNS_RANDOM_, DNS_RANDOM))
-
-#if DNS_RANDOM_OPENSSL
-#include
-#endif
-
-static unsigned dns_random_(void) {
-#if DNS_RANDOM_OPENSSL
- unsigned r;
- _Bool ok;
-
- ok = (1 == RAND_bytes((unsigned char *)&r, sizeof r));
- assert(ok && "1 == RAND_bytes()");
-
- return r;
-#else
- return DNS_RANDOM();
-#endif
-} /* dns_random_() */
-
-dns_random_f **dns_random_p(void) {
- static dns_random_f *random_f = &dns_random_;
-
- return &random_f;
-} /* dns_random_p() */
-
-
-/*
- * P E R M U T A T I O N G E N E R A T O R
- */
-
-#define DNS_K_TEA_KEY_SIZE 16
-#define DNS_K_TEA_BLOCK_SIZE 8
-#define DNS_K_TEA_CYCLES 32
-#define DNS_K_TEA_MAGIC 0x9E3779B9U
-
-struct dns_k_tea {
- uint32_t key[DNS_K_TEA_KEY_SIZE / sizeof (uint32_t)];
- unsigned cycles;
-}; /* struct dns_k_tea */
-
-
-static void dns_k_tea_init(struct dns_k_tea *tea, uint32_t key[], unsigned cycles) {
- memcpy(tea->key, key, sizeof tea->key);
-
- tea->cycles = (cycles)? cycles : DNS_K_TEA_CYCLES;
-} /* dns_k_tea_init() */
-
-
-static void dns_k_tea_encrypt(struct dns_k_tea *tea, uint32_t v[], uint32_t *w) {
- uint32_t y, z, sum, n;
-
- y = v[0];
- z = v[1];
- sum = 0;
-
- for (n = 0; n < tea->cycles; n++) {
- sum += DNS_K_TEA_MAGIC;
- y += ((z << 4) + tea->key[0]) ^ (z + sum) ^ ((z >> 5) + tea->key[1]);
- z += ((y << 4) + tea->key[2]) ^ (y + sum) ^ ((y >> 5) + tea->key[3]);
- }
-
- w[0] = y;
- w[1] = z;
-
- return /* void */;
-} /* dns_k_tea_encrypt() */
-
-
-/*
- * Permutation generator, based on a Luby-Rackoff Feistel construction.
- *
- * Specifically, this is a generic balanced Feistel block cipher using TEA
- * (another block cipher) as the pseudo-random function, F. At best it's as
- * strong as F (TEA), notwithstanding the seeding. F could be AES, SHA-1, or
- * perhaps Bernstein's Salsa20 core; I am naively trying to keep things
- * simple.
- *
- * The generator can create a permutation of any set of numbers, as long as
- * the size of the set is an even power of 2. This limitation arises either
- * out of an inherent property of balanced Feistel constructions, or by my
- * own ignorance. I'll tackle an unbalanced construction after I wrap my
- * head around Schneier and Kelsey's paper.
- *
- * CAVEAT EMPTOR. IANAC.
- */
-#define DNS_K_PERMUTOR_ROUNDS 8
-
-struct dns_k_permutor {
- unsigned stepi, length, limit;
- unsigned shift, mask, rounds;
-
- struct dns_k_tea tea;
-}; /* struct dns_k_permutor */
-
-
-static inline unsigned dns_k_permutor_powof(unsigned n) {
- unsigned m, i = 0;
-
- for (m = 1; m < n; m <<= 1, i++)
- ;;
-
- return i;
-} /* dns_k_permutor_powof() */
-
-static void dns_k_permutor_init(struct dns_k_permutor *p, unsigned low, unsigned high) {
- uint32_t key[DNS_K_TEA_KEY_SIZE / sizeof (uint32_t)];
- unsigned width, i;
-
- p->stepi = 0;
-
- p->length = (high - low) + 1;
- p->limit = high;
-
- width = dns_k_permutor_powof(p->length);
- width += width % 2;
-
- p->shift = width / 2;
- p->mask = (1U << p->shift) - 1;
- p->rounds = DNS_K_PERMUTOR_ROUNDS;
-
- for (i = 0; i < lengthof(key); i++)
- key[i] = dns_random();
-
- dns_k_tea_init(&p->tea, key, 0);
-
- return /* void */;
-} /* dns_k_permutor_init() */
-
-
-static unsigned dns_k_permutor_F(struct dns_k_permutor *p, unsigned k, unsigned x) {
- uint32_t in[DNS_K_TEA_BLOCK_SIZE / sizeof (uint32_t)], out[DNS_K_TEA_BLOCK_SIZE / sizeof (uint32_t)];
-
- memset(in, '\0', sizeof in);
-
- in[0] = k;
- in[1] = x;
-
- dns_k_tea_encrypt(&p->tea, in, out);
-
- return p->mask & out[0];
-} /* dns_k_permutor_F() */
-
-
-static unsigned dns_k_permutor_E(struct dns_k_permutor *p, unsigned n) {
- unsigned l[2], r[2];
- unsigned i;
-
- i = 0;
- l[i] = p->mask & (n >> p->shift);
- r[i] = p->mask & (n >> 0);
-
- do {
- l[(i + 1) % 2] = r[i % 2];
- r[(i + 1) % 2] = l[i % 2] ^ dns_k_permutor_F(p, i, r[i % 2]);
-
- i++;
- } while (i < p->rounds - 1);
-
- return ((l[i % 2] & p->mask) << p->shift) | ((r[i % 2] & p->mask) << 0);
-} /* dns_k_permutor_E() */
-
-
-DNS_NOTUSED static unsigned dns_k_permutor_D(struct dns_k_permutor *p, unsigned n) {
- unsigned l[2], r[2];
- unsigned i;
-
- i = p->rounds - 1;
- l[i % 2] = p->mask & (n >> p->shift);
- r[i % 2] = p->mask & (n >> 0);
-
- do {
- i--;
-
- r[i % 2] = l[(i + 1) % 2];
- l[i % 2] = r[(i + 1) % 2] ^ dns_k_permutor_F(p, i, l[(i + 1) % 2]);
- } while (i > 0);
-
- return ((l[i % 2] & p->mask) << p->shift) | ((r[i % 2] & p->mask) << 0);
-} /* dns_k_permutor_D() */
-
-
-static unsigned dns_k_permutor_step(struct dns_k_permutor *p) {
- unsigned n;
-
- do {
- n = dns_k_permutor_E(p, p->stepi++);
- } while (n >= p->length);
-
- return n + (p->limit + 1 - p->length);
-} /* dns_k_permutor_step() */
-
-
-/*
- * Simple permutation box. Useful for shuffling rrsets from an iterator.
- * Uses AES s-box to provide good diffusion.
- *
- * Seems to pass muster under runs test.
- *
- * $ for i in 0 1 2 3 4 5 6 7 8 9; do ./dns shuffle-16 > /tmp/out; done
- * $ R -q -f /dev/stdin 2>/dev/null <<-EOF | awk '/p-value/{ print $8 }'
- * library(lawstat)
- * runs.test(scan(file="/tmp/out"))
- * EOF
- */
-static unsigned short dns_k_shuffle16(unsigned short n, unsigned s) {
- static const unsigned char sbox[256] =
- { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
- 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
- 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
- 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
- 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
- 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
- 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
- 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
- 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
- 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
- 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
- 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
- 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
- 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
- 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
- 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
- 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
- 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
- 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
- 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
- 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
- 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
- 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
- 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
- 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
- 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
- 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
- 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
- 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
- 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
- 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
- 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };
- unsigned char a, b;
- unsigned i;
-
- a = 0xff & (n >> 0);
- b = 0xff & (n >> 8);
-
- for (i = 0; i < 4; i++) {
- a ^= 0xff & s;
- a = sbox[a] ^ b;
- b = sbox[b] ^ a;
- s >>= 8;
- }
-
- return ((0xff00 & (a << 8)) | (0x00ff & (b << 0)));
-} /* dns_k_shuffle16() */
-
-/*
- * S T A T E M A C H I N E R O U T I N E S
- *
- * Application code should define DNS_SM_RESTORE and DNS_SM_SAVE, and the
- * local variable pc.
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-#define DNS_SM_ENTER \
- do { \
- static const int pc0 = __LINE__; \
- DNS_SM_RESTORE; \
- switch (pc0 + pc) { \
- case __LINE__: (void)0
-
-#define DNS_SM_SAVE_AND_DO(do_statement) \
- do { \
- pc = __LINE__ - pc0; \
- DNS_SM_SAVE; \
- do_statement; \
- case __LINE__: (void)0; \
- } while (0)
-
-#define DNS_SM_YIELD(rv) \
- DNS_SM_SAVE_AND_DO(return (rv))
-
-#define DNS_SM_EXIT \
- do { goto leave; } while (0)
-
-#define DNS_SM_LEAVE \
- leave: (void)0; \
- DNS_SM_SAVE_AND_DO(break); \
- } \
- } while (0)
-
-/*
- * U T I L I T Y R O U T I N E S
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-#define DNS_MAXINTERVAL 300
-
-struct dns_clock {
- time_t sample, elapsed;
-}; /* struct dns_clock */
-
-static void dns_begin(struct dns_clock *clk) {
- clk->sample = time(0);
- clk->elapsed = 0;
-} /* dns_begin() */
-
-static time_t dns_elapsed(struct dns_clock *clk) {
- time_t curtime;
-
- if ((time_t)-1 == time(&curtime))
- return clk->elapsed;
-
- if (curtime > clk->sample)
- clk->elapsed += (time_t)DNS_PP_MIN(difftime(curtime, clk->sample), DNS_MAXINTERVAL);
-
- clk->sample = curtime;
-
- return clk->elapsed;
-} /* dns_elapsed() */
-
-
-DNS_NOTUSED static size_t dns_strnlen(const char *src, size_t m) {
- size_t n = 0;
-
- while (*src++ && n < m)
- ++n;
-
- return n;
-} /* dns_strnlen() */
-
-
-DNS_NOTUSED static size_t dns_strnlcpy(char *dst, size_t lim, const char *src, size_t max) {
- size_t len = dns_strnlen(src, max), n;
-
- if (lim > 0) {
- n = DNS_PP_MIN(lim - 1, len);
- memcpy(dst, src, n);
- dst[n] = '\0';
- }
-
- return len;
-} /* dns_strnlcpy() */
-
-
-#if (defined AF_UNIX && !defined _WIN32)
-#define DNS_HAVE_SOCKADDR_UN 1
-#else
-#define DNS_HAVE_SOCKADDR_UN 0
-#endif
-
-static size_t dns_af_len(int af) {
- static const size_t table[AF_MAX] = {
- [AF_INET6] = sizeof (struct sockaddr_in6),
- [AF_INET] = sizeof (struct sockaddr_in),
-#if DNS_HAVE_SOCKADDR_UN
- [AF_UNIX] = sizeof (struct sockaddr_un),
-#endif
- };
-
- return table[af];
-} /* dns_af_len() */
-
-#define c_dns_sa_family(sa) (((const struct sockaddr *)(sa))->sa_family)
-#define dns_sa_family(sa) (((struct sockaddr *)(sa))->sa_family)
-
-#define dns_sa_len(sa) dns_af_len(c_dns_sa_family(sa))
-
-
-#define DNS_SA_NOPORT &dns_sa_noport
-static unsigned short dns_sa_noport;
-
-static unsigned short *dns_sa_port(int af, void *sa) {
- switch (af) {
- case AF_INET6:
- return &((struct sockaddr_in6 *)sa)->sin6_port;
- case AF_INET:
- return &((struct sockaddr_in *)sa)->sin_port;
- default:
- return DNS_SA_NOPORT;
- }
-} /* dns_sa_port() */
-
-
-static void *dns_sa_addr(int af, void *sa, socklen_t *size) {
- switch (af) {
- case AF_INET6: {
- struct in6_addr *in6 = &((struct sockaddr_in6 *)sa)->sin6_addr;
-
- if (size)
- *size = sizeof *in6;
-
- return in6;
- }
- case AF_INET: {
- struct in_addr *in = &((struct sockaddr_in *)sa)->sin_addr;
-
- if (size)
- *size = sizeof *in;
-
- return in;
- }
- default:
- if (size)
- *size = 0;
-
- return 0;
- }
-} /* dns_sa_addr() */
-
-
-#if DNS_HAVE_SOCKADDR_UN
-#define DNS_SUNPATHMAX (sizeof ((struct sockaddr_un *)0)->sun_path)
-#endif
-
-DNS_NOTUSED static void *dns_sa_path(void *sa, socklen_t *size) {
- switch (dns_sa_family(sa)) {
-#if DNS_HAVE_SOCKADDR_UN
- case AF_UNIX: {
- char *path = ((struct sockaddr_un *)sa)->sun_path;
-
- if (size)
- *size = dns_strnlen(path, DNS_SUNPATHMAX);
-
- return path;
- }
-#endif
- default:
- if (size)
- *size = 0;
-
- return NULL;
- }
-} /* dns_sa_path() */
-
-
-static int dns_sa_cmp(void *a, void *b) {
- int cmp, af;
-
- if ((cmp = dns_sa_family(a) - dns_sa_family(b)))
- return cmp;
-
- switch ((af = dns_sa_family(a))) {
- case AF_INET: {
- const struct in_addr *a4, *b4;
-
- if ((cmp = htons(*dns_sa_port(af, a)) - htons(*dns_sa_port(af, b))))
- return cmp;
-
- a4 = dns_sa_addr(af, a, NULL);
- b4 = dns_sa_addr(af, b, NULL);
-
- if (ntohl(a4->s_addr) < ntohl(b4->s_addr))
- return -1;
- if (ntohl(a4->s_addr) > ntohl(b4->s_addr))
- return 1;
-
- return 0;
- }
- case AF_INET6: {
- const struct in6_addr *a6, *b6;
- size_t i;
-
- if ((cmp = htons(*dns_sa_port(af, a)) - htons(*dns_sa_port(af, b))))
- return cmp;
-
- a6 = dns_sa_addr(af, a, NULL);
- b6 = dns_sa_addr(af, b, NULL);
-
- /* XXX: do we need to use in6_clearscope()? */
- for (i = 0; i < sizeof a6->s6_addr; i++) {
- if ((cmp = a6->s6_addr[i] - b6->s6_addr[i]))
- return cmp;
- }
-
- return 0;
- }
-#if DNS_HAVE_SOCKADDR_UN
- case AF_UNIX: {
- char a_path[DNS_SUNPATHMAX + 1], b_path[sizeof a_path];
-
- dns_strnlcpy(a_path, sizeof a_path, dns_sa_path(a, NULL), DNS_SUNPATHMAX);
- dns_strnlcpy(b_path, sizeof b_path, dns_sa_path(b, NULL), DNS_SUNPATHMAX);
-
- return strcmp(a_path, b_path);
- }
-#endif
- default:
- return -1;
- }
-} /* dns_sa_cmp() */
-
-
-#if _WIN32
-static int dns_inet_pton(int af, const void *src, void *dst) {
- union { struct sockaddr_in sin; struct sockaddr_in6 sin6; } u;
-
- u.sin.sin_family = af;
-
- if (0 != WSAStringToAddressA((void *)src, af, (void *)0, (struct sockaddr *)&u, &(int){ sizeof u }))
- return -1;
-
- switch (af) {
- case AF_INET6:
- *(struct in6_addr *)dst = u.sin6.sin6_addr;
-
- return 1;
- case AF_INET:
- *(struct in_addr *)dst = u.sin.sin_addr;
-
- return 1;
- default:
- return 0;
- }
-} /* dns_inet_pton() */
-
-static const char *dns_inet_ntop(int af, const void *src, void *dst, unsigned long lim) {
- union { struct sockaddr_in sin; struct sockaddr_in6 sin6; } u;
-
- /* NOTE: WSAAddressToString will print .sin_port unless zeroed. */
- memset(&u, 0, sizeof u);
-
- u.sin.sin_family = af;
-
- switch (af) {
- case AF_INET6:
- u.sin6.sin6_addr = *(struct in6_addr *)src;
- break;
- case AF_INET:
- u.sin.sin_addr = *(struct in_addr *)src;
-
- break;
- default:
- return 0;
- }
-
- if (0 != WSAAddressToStringA((struct sockaddr *)&u, dns_sa_len(&u), (void *)0, dst, &lim))
- return 0;
-
- return dst;
-} /* dns_inet_ntop() */
-#else
-#define dns_inet_pton(...) inet_pton(__VA_ARGS__)
-#define dns_inet_ntop(...) inet_ntop(__VA_ARGS__)
-#endif
-
-
-static dns_error_t dns_pton(int af, const void *src, void *dst) {
- switch (dns_inet_pton(af, src, dst)) {
- case 1:
- return 0;
- case -1:
- return dns_soerr();
- default:
- return DNS_EADDRESS;
- }
-} /* dns_pton() */
-
-
-static dns_error_t dns_ntop(int af, const void *src, void *dst, unsigned long lim) {
- return (dns_inet_ntop(af, src, dst, lim))? 0 : dns_soerr();
-} /* dns_ntop() */
-
-
-size_t dns_strlcpy(char *dst, const char *src, size_t lim) {
- char *d = dst;
- char *e = &dst[lim];
- const char *s = src;
-
- if (d < e) {
- do {
- if ('\0' == (*d++ = *s++))
- return s - src - 1;
- } while (d < e);
-
- d[-1] = '\0';
- }
-
- while (*s++ != '\0')
- ;;
-
- return s - src - 1;
-} /* dns_strlcpy() */
-
-
-size_t dns_strlcat(char *dst, const char *src, size_t lim) {
- char *d = memchr(dst, '\0', lim);
- char *e = &dst[lim];
- const char *s = src;
- const char *p;
-
- if (d && d < e) {
- do {
- if ('\0' == (*d++ = *s++))
- return d - dst - 1;
- } while (d < e);
-
- d[-1] = '\0';
- }
-
- p = s;
-
- while (*s++ != '\0')
- ;;
-
- return lim + (s - p - 1);
-} /* dns_strlcat() */
-
-
-#if _WIN32
-
-static char *dns_strsep(char **sp, const char *delim) {
- char *p;
-
- if (!(p = *sp))
- return 0;
-
- *sp += strcspn(p, delim);
-
- if (**sp != '\0') {
- **sp = '\0';
- ++*sp;
- } else
- *sp = NULL;
-
- return p;
-} /* dns_strsep() */
-
-#else
-#define dns_strsep(...) strsep(__VA_ARGS__)
-#endif
-
-
-#if _WIN32
-#define strcasecmp(...) _stricmp(__VA_ARGS__)
-#define strncasecmp(...) _strnicmp(__VA_ARGS__)
-#endif
-
-
-static inline _Bool dns_isalpha(unsigned char c) {
- return isalpha(c);
-} /* dns_isalpha() */
-
-static inline _Bool dns_isdigit(unsigned char c) {
- return isdigit(c);
-} /* dns_isdigit() */
-
-static inline _Bool dns_isalnum(unsigned char c) {
- return isalnum(c);
-} /* dns_isalnum() */
-
-static inline _Bool dns_isspace(unsigned char c) {
- return isspace(c);
-} /* dns_isspace() */
-
-/* changed by zsx--2017.12.20 */
-#if defined(_WIN32) || defined(_WIN64)
-static int dns_poll(int fd, short events, int timeout) {
- fd_set rset, wset;
- struct timeval tv, *tp;
-
- if (!events)
- return 0;
-
- assert(fd >= 0 && (unsigned)fd < FD_SETSIZE);
-
- FD_ZERO(&rset);
- FD_ZERO(&wset);
-
- if (events & DNS_POLLIN)
- FD_SET(fd, &rset);
-
- if (events & DNS_POLLOUT)
- FD_SET(fd, &wset);
-
- if (timeout > 0) {
- tv.tv_sec = timeout;
- tv.tv_usec = 0;
- tp = &tv;
- } else {
- tp = NULL;
- }
- select(fd + 1, &rset, &wset, 0, tp);
-
- return 0;
-}
-#else
-static int dns_poll(int fd, short events, int timeout) {
- struct pollfd fds;
-
- if (!events) {
- acl_fiber_set_error(EINVAL);
- return EINVAL;
- }
-
- fds.fd = fd;
- fds.events = 0; /* POLLHUP | POLLERR */
- if (events & DNS_POLLIN)
- fds.events |= POLLIN;
- if (events & DNS_POLLOUT)
- fds.events |= POLLOUT;
- for (;;) {
- switch (poll(&fds, 1, timeout)) {
- case -1:
- if (acl_fiber_last_error() == EINTR)
- continue;
- return EEXIST;
- case 0:
- return ETIMEDOUT;
- default:
- if ((fds.revents & POLLIN))
- return 0;
- return EEXIST;
- }
- }
-} /* dns_poll() */
-#endif
-
-/* add by zsx--2017.12.20 */
-#ifdef SYS_WIN
-static int read_wait(int fd, int timeout) {
- struct timeval tv;
- struct timeval *tp;
- fd_set rset, xset;
- int err;
-
- FD_ZERO(&rset);
- FD_SET(fd, &rset);
- FD_ZERO(&xset);
- FD_SET(fd, &xset);
-
- if (timeout > 0) {
- tv.tv_sec = timeout / 1000;
- tv.tv_usec = (timeout % 1000) * 1000;
- tp = &tv;
- } else {
- tp = NULL;
- }
-
-TAG_AGAIN:
- switch (select(1, &rset, (fd_set *) 0, &xset, tp)) {
- case -1:
- err = acl_fiber_last_error();
- if (err == EINTR || err == WSAEINPROGRESS
- || err == WSAEWOULDBLOCK) {
-
- goto TAG_AGAIN;
- }
- return -1;
- case 0:
- acl_fiber_set_error(ETIMEDOUT);
- return 0;
- default:
- return 1;
- }
-}
-#else
-static int read_wait(int fd, int timeout) {
- struct pollfd fds;
- int err;
-
- fds.fd = fd;
- //fds.events = POLLHUP | POLLERR;
- fds.events = POLLIN;
-
- for (;;) {
- switch (poll(&fds, 1, timeout)) {
- case -1:
- err = acl_fiber_last_error();
- if (err == EINTR)
- continue;
- acl_fiber_set_error(EEXIST);
- return -1;
- case 0:
- acl_fiber_set_error(ETIMEDOUT);
- return 0;
- default:
- if ((fds.revents & POLLIN))
- return 1;
- acl_fiber_set_error(EEXIST);
- return -1;
- }
- }
-}
-#endif
-
-static int __timeout = 5000;
-
-static int read_wait0(int fd) {
- return read_wait(fd, __timeout);
-}
-
-void set_read_timeout(int timeo) {
- if (timeo > 0)
- __timeout = timeo * 1000;
-}
-
-int get_read_timeout(void) {
- return __timeout / 1000;
-}
-
-// end add by zsx
-
-
-#if !_WIN32
-DNS_NOTUSED static int dns_sigmask(int how, const sigset_t *set, sigset_t *oset) {
-#if DNS_THREAD_SAFE
- return pthread_sigmask(how, set, oset);
-#else
- return (0 == sigprocmask(how, set, oset))? 0 : errno;
-#endif
-} /* dns_sigmask() */
-#endif
-
-
-static long dns_send(int fd, const void *src, size_t lim, int flags) {
-#if _WIN32 || !defined SIGPIPE || defined SO_NOSIGPIPE
- return send(fd, src, lim, flags);
-#elif defined MSG_NOSIGNAL
- return send(fd, src, lim, flags|MSG_NOSIGNAL);
-#elif _POSIX_REALTIME_SIGNALS > 0 /* require sigtimedwait */
- /*
- * SIGPIPE handling similar to the approach described in
- * http://krokisplace.blogspot.com/2010/02/suppressing-sigpipe-in-library.html
- */
- sigset_t pending, blocked, piped;
- long count;
- int saved, error;
-
- sigemptyset(&pending);
- sigpending(&pending);
-
- if (!sigismember(&pending, SIGPIPE)) {
- sigemptyset(&piped);
- sigaddset(&piped, SIGPIPE);
- sigemptyset(&blocked);
-
- if ((error = dns_sigmask(SIG_BLOCK, &piped, &blocked)))
- goto error;
- }
-
- count = send(fd, src, lim, flags);
-
- if (!sigismember(&pending, SIGPIPE)) {
- saved = errno;
-
- if (count == -1 && errno == EPIPE) {
- while (-1 == sigtimedwait(&piped, NULL, &(struct timespec){ 0, 0 }) && errno == EINTR)
- ;;
- }
-
- if ((error = dns_sigmask(SIG_SETMASK, &blocked, NULL)))
- goto error;
-
- errno = saved;
- }
-
- return count;
-error:
- errno = error;
-
- return -1;
-#else
-#error "unable to suppress SIGPIPE"
- return send(fd, src, lim, flags);
-#endif
-} /* dns_send() */
-
-
-#define DNS_FOPEN_STDFLAGS "rwabt+"
-
-static dns_error_t dns_fopen_addflag(char *dst, const char *src, size_t lim, int fc) {
- char *p = dst, *pe = dst + lim;
-
- /* copy standard flags */
- while (*src && strchr(DNS_FOPEN_STDFLAGS, *src)) {
- if (!(p < pe))
- return ENOMEM;
- *p++ = *src++;
- }
-
- /* append flag to standard flags */
- if (!(p < pe))
- return ENOMEM;
- *p++ = fc;
-
- /* copy remaining mode string, including '\0' */
- do {
- if (!(p < pe))
- return ENOMEM;
- } while ((*p++ = *src++));
-
- return 0;
-} /* dns_fopen_addflag() */
-
-static FILE *dns_fopen(const char *path, const char *mode, dns_error_t *_error) {
- FILE *fp;
- char mode_cloexec[32];
- int error;
-
- assert(path && mode && *mode);
- if (!*path) {
- error = EINVAL;
- goto error;
- }
-
-#if _WIN32 || _WIN64
- if ((error = dns_fopen_addflag(mode_cloexec, mode, sizeof mode_cloexec, 'N')))
- goto error;
- if (!(fp = fopen(path, mode_cloexec)))
- goto syerr;
-#else
- if ((error = dns_fopen_addflag(mode_cloexec, mode, sizeof mode_cloexec, 'e')))
- goto error;
- if (!(fp = fopen(path, mode_cloexec))) {
- if (errno != EINVAL)
- goto syerr;
- if (!(fp = fopen(path, mode)))
- goto syerr;
- }
-#endif
-
- return fp;
-syerr:
- error = dns_syerr();
-error:
- *_error = error;
-
- return NULL;
-} /* dns_fopen() */
-
-
-/*
- * F I X E D - S I Z E D B U F F E R R O U T I N E S
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-#define DNS_B_INIT(src, n) { \
- (unsigned char *)(src), \
- (unsigned char *)(src), \
- (unsigned char *)(src) + (n), \
- DNS_EUNKNOWN, 0 \
-}
-
-#define DNS_B_FROM(src, n) DNS_B_INIT((src), (n))
-#define DNS_B_INTO(src, n) DNS_B_INIT((src), (n))
-
-struct dns_buf {
- unsigned char *base;
- unsigned char *p;
- const unsigned char *pe;
- dns_error_t error;
- size_t overflow;
-}; /* struct dns_buf */
-
-static inline size_t
-dns_b_tell(struct dns_buf *b)
-{
- return b->p - b->base;
-}
-
-static inline dns_error_t
-dns_b_setoverflow(struct dns_buf *b, size_t n, dns_error_t error)
-{
- b->overflow += n;
- return b->error = error;
-}
-
-DNS_NOTUSED static struct dns_buf *
-dns_b_into(struct dns_buf *b, void *src, size_t n)
-{
- *b = (struct dns_buf)DNS_B_INTO(src, n);
-
- return b;
-}
-
-static dns_error_t
-dns_b_putc(struct dns_buf *b, unsigned char uc)
-{
- if (!(b->p < b->pe))
- return dns_b_setoverflow(b, 1, DNS_ENOBUFS);
-
- *b->p++ = uc;
-
- return 0;
-}
-
-static dns_error_t
-dns_b_pputc(struct dns_buf *b, unsigned char uc, size_t p)
-{
- size_t pe = b->pe - b->base;
- if (pe <= p)
- return dns_b_setoverflow(b, p - pe + 1, DNS_ENOBUFS);
-
- *((unsigned char *)b->base + p) = uc;
-
- return 0;
-}
-
-static inline dns_error_t
-dns_b_put16(struct dns_buf *b, uint16_t u)
-{
- return dns_b_putc(b, u >> 8), dns_b_putc(b, u >> 0);
-}
-
-static inline dns_error_t
-dns_b_pput16(struct dns_buf *b, uint16_t u, size_t p)
-{
- if (dns_b_pputc(b, u >> 8, p) || dns_b_pputc(b, u >> 0, p + 1))
- return b->error;
-
- return 0;
-}
-
-DNS_NOTUSED static inline dns_error_t
-dns_b_put32(struct dns_buf *b, uint32_t u)
-{
- return dns_b_putc(b, u >> 24), dns_b_putc(b, u >> 16),
- dns_b_putc(b, u >> 8), dns_b_putc(b, u >> 0);
-}
-
-static dns_error_t
-dns_b_put(struct dns_buf *b, const void *src, size_t len)
-{
- size_t n = DNS_PP_MIN((size_t)(b->pe - b->p), len);
-
- memcpy(b->p, src, n);
- b->p += n;
-
- if (n < len)
- return dns_b_setoverflow(b, len - n, DNS_ENOBUFS);
-
- return 0;
-}
-
-static dns_error_t
-dns_b_puts(struct dns_buf *b, const void *src)
-{
- return dns_b_put(b, src, strlen(src));
-}
-
-DNS_NOTUSED static inline dns_error_t
-dns_b_fmtju(struct dns_buf *b, const uintmax_t u, const unsigned width)
-{
- size_t digits, padding, overflow;
- uintmax_t r;
- unsigned char *tp, *te, tc;
-
- digits = 0;
- r = u;
- do {
- digits++;
- r /= 10;
- } while (r);
-
- padding = width - DNS_PP_MIN(digits, width);
- overflow = (digits + padding) - DNS_PP_MIN((size_t)(b->pe - b->p), (digits + padding));
-
- while (padding--) {
- dns_b_putc(b, '0');
- }
-
- digits = 0;
- tp = b->p;
- r = u;
- do {
- if (overflow < ++digits)
- dns_b_putc(b, '0' + (r % 10));
- r /= 10;
- } while (r);
-
- te = b->p;
- while (tp < te) {
- tc = *--te;
- *te = *tp;
- *tp++ = tc;
- }
-
- return b->error;
-}
-
-static void
-dns_b_popc(struct dns_buf *b)
-{
- if (b->overflow && !--b->overflow)
- b->error = 0;
- if (b->p > b->base)
- b->p--;
-}
-
-static inline const char *
-dns_b_tolstring(struct dns_buf *b, size_t *n)
-{
- if (b->p < b->pe) {
- *b->p = '\0';
- *n = b->p - b->base;
-
- return (const char *)b->base;
- } else if (b->p > b->base) {
- if (b->p[-1] != '\0') {
- dns_b_setoverflow(b, 1, DNS_ENOBUFS);
- b->p[-1] = '\0';
- }
- *n = &b->p[-1] - b->base;
-
- return (const char *)b->base;
- } else {
- *n = 0;
-
- return "";
- }
-}
-
-static inline const char *
-dns_b_tostring(struct dns_buf *b)
-{
- size_t n;
- return dns_b_tolstring(b, &n);
-}
-
-static inline size_t
-dns_b_strlen(struct dns_buf *b)
-{
- size_t n;
- dns_b_tolstring(b, &n);
- return n;
-}
-
-static inline size_t
-dns_b_strllen(struct dns_buf *b)
-{
- size_t n = dns_b_strlen(b);
- return n + b->overflow;
-}
-
-DNS_NOTUSED static const struct dns_buf *
-dns_b_from(struct dns_buf *b, void *src, size_t n)
-{
- *(struct dns_buf *)b = (struct dns_buf)DNS_B_FROM(src, n);
-
- return b;
-}
-
-static inline int
-dns_b_getc(struct dns_buf *_b, int eof)
-{
- struct dns_buf *b = (struct dns_buf *)_b;
-
- if (!(b->p < b->pe))
- return dns_b_setoverflow(b, 1, DNS_EILLEGAL), eof;
-
- return *b->p++;
-}
-
-static inline intmax_t
-dns_b_get16(struct dns_buf *b, intmax_t eof)
-{
- intmax_t n;
-
- n = (dns_b_getc(b, 0) << 8);
- n |= (dns_b_getc(b, 0) << 0);
-
- return (!b->overflow)? n : eof;
-}
-
-DNS_NOTUSED static inline intmax_t
-dns_b_get32(struct dns_buf *b, intmax_t eof)
-{
- intmax_t n;
-
- n = (dns_b_get16(b, 0) << 16);
- n |= (dns_b_get16(b, 0) << 0);
-
- return (!b->overflow)? n : eof;
-}
-
-static inline dns_error_t
-dns_b_move(struct dns_buf *dst, struct dns_buf *_src, size_t n)
-{
- struct dns_buf *src = (struct dns_buf *)_src;
- size_t src_n = DNS_PP_MIN((size_t)(src->pe - src->p), n);
- size_t src_r = n - src_n;
-
- dns_b_put(dst, src->p, src_n);
- src->p += src_n;
-
- if (src_r)
- return dns_b_setoverflow(src, src_r, DNS_EILLEGAL);
-
- return dst->error;
-}
-
-
-/*
- * P A C K E T R O U T I N E S
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-unsigned dns_p_count(struct dns_packet *P, enum dns_section section) {
- unsigned count;
-
- switch (section) {
- case DNS_S_QD:
- return ntohs(DNS_HEADER(P)->qdcount);
- case DNS_S_AN:
- return ntohs(DNS_HEADER(P)->ancount);
- case DNS_S_NS:
- return ntohs(DNS_HEADER(P)->nscount);
- case DNS_S_AR:
- return ntohs(DNS_HEADER(P)->arcount);
- default:
- count = 0;
-
- if (section & DNS_S_QD)
- count += ntohs(DNS_HEADER(P)->qdcount);
- if (section & DNS_S_AN)
- count += ntohs(DNS_HEADER(P)->ancount);
- if (section & DNS_S_NS)
- count += ntohs(DNS_HEADER(P)->nscount);
- if (section & DNS_S_AR)
- count += ntohs(DNS_HEADER(P)->arcount);
-
- return count;
- }
-} /* dns_p_count() */
-
-
-struct dns_packet *dns_p_init(struct dns_packet *P, size_t size) {
- if (!P)
- return 0;
-
- assert(size >= offsetof(struct dns_packet, data) + 12);
-
- memset(P, 0, sizeof *P);
- P->size = size - offsetof(struct dns_packet, data);
- P->end = 12;
-
- memset(P->data, '\0', 12);
-
- return P;
-} /* dns_p_init() */
-
-
-static struct dns_packet *dns_p_reset(struct dns_packet *P) {
- return dns_p_init(P, offsetof(struct dns_packet, data) + P->size);
-} /* dns_p_reset() */
-
-
-static unsigned short dns_p_qend(struct dns_packet *P) {
- unsigned short qend = 12;
- unsigned i, count = dns_p_count(P, DNS_S_QD);
-
- for (i = 0; i < count && qend < P->end; i++) {
- if (P->end == (qend = dns_d_skip(qend, P)))
- goto invalid;
-
- if (P->end - qend < 4)
- goto invalid;
-
- qend += 4;
- }
-
- return DNS_PP_MIN(qend, P->end);
-invalid:
- return P->end;
-} /* dns_p_qend() */
-
-
-struct dns_packet *dns_p_make(size_t len, int *error) {
- struct dns_packet *P;
- size_t size = dns_p_calcsize(len);
-
- if (!(P = dns_p_init(malloc(size), size)))
- *error = dns_syerr();
-
- return P;
-} /* dns_p_make() */
-
-
-static void dns_p_free(struct dns_packet *P) {
- free(P);
-} /* dns_p_free() */
-
-
-/* convience routine to free any existing packet before storing new packet */
-static struct dns_packet *dns_p_setptr(struct dns_packet **dst, struct dns_packet *src) {
- dns_p_free(*dst);
-
- *dst = src;
-
- return src;
-} /* dns_p_setptr() */
-
-
-static struct dns_packet *dns_p_movptr(struct dns_packet **dst, struct dns_packet **src) {
- dns_p_setptr(dst, *src);
-
- *src = NULL;
-
- return *dst;
-} /* dns_p_movptr() */
-
-
-int dns_p_grow(struct dns_packet **P) {
- struct dns_packet *tmp;
- size_t size;
- int error;
-
- if (!*P) {
- if (!(*P = dns_p_make(DNS_P_QBUFSIZ, &error)))
- return error;
-
- return 0;
- }
-
- size = dns_p_sizeof(*P);
- size |= size >> 1;
- size |= size >> 2;
- size |= size >> 4;
- size |= size >> 8;
- size++;
-
- if (size > 65536)
- return DNS_ENOBUFS;
-
- if (!(tmp = realloc(*P, dns_p_calcsize(size))))
- return dns_syerr();
-
- tmp->size = size;
- *P = tmp;
-
- return 0;
-} /* dns_p_grow() */
-
-
-struct dns_packet *dns_p_copy(struct dns_packet *P, const struct dns_packet *P0) {
- if (!P)
- return 0;
-
- P->end = DNS_PP_MIN(P->size, P0->end);
-
- memcpy(P->data, P0->data, P->end);
-
- return P;
-} /* dns_p_copy() */
-
-
-struct dns_packet *dns_p_merge(struct dns_packet *A, enum dns_section Amask, struct dns_packet *B, enum dns_section Bmask, int *error_) {
- size_t bufsiz = DNS_PP_MIN(65535, ((A)? A->end : 0) + ((B)? B->end : 0));
- struct dns_packet *M;
- enum dns_section section;
- struct dns_rr rr, mr;
- int error, copy;
-
- if (!A && B) {
- A = B;
- Amask = Bmask;
- B = 0;
- }
-
-merge:
- if (!(M = dns_p_make(bufsiz, &error)))
- goto error;
-
- for (section = DNS_S_QD; (DNS_S_ALL & section); section <<= 1) {
- if (A && (section & Amask)) {
- dns_rr_foreach(&rr, A, .section = section) {
- if ((error = dns_rr_copy(M, &rr, A)))
- goto error;
- }
- }
-
- if (B && (section & Bmask)) {
- dns_rr_foreach(&rr, B, .section = section) {
- copy = 1;
-
- dns_rr_foreach(&mr, M, .type = rr.type, .section = DNS_S_ALL) {
- if (!(copy = dns_rr_cmp(&rr, B, &mr, M)))
- break;
- }
-
- if (copy && (error = dns_rr_copy(M, &rr, B)))
- goto error;
- }
- }
- }
-
- return M;
-error:
- dns_p_setptr(&M, NULL);
-
- if (error == DNS_ENOBUFS && bufsiz < 65535) {
- bufsiz = DNS_PP_MIN(65535, bufsiz * 2);
-
- goto merge;
- }
-
- *error_ = error;
-
- return 0;
-} /* dns_p_merge() */
-
-
-static unsigned short dns_l_skip(unsigned short, const unsigned char *, size_t);
-
-void dns_p_dictadd(struct dns_packet *P, unsigned short dn) {
- unsigned short lp, lptr, i;
-
- lp = dn;
-
- while (lp < P->end) {
- if (0xc0 == (0xc0 & P->data[lp]) && P->end - lp >= 2 && lp != dn) {
- lptr = ((0x3f & P->data[lp + 0]) << 8)
- | ((0xff & P->data[lp + 1]) << 0);
-
- for (i = 0; i < lengthof(P->dict) && P->dict[i]; i++) {
- if (P->dict[i] == lptr) {
- P->dict[i] = dn;
-
- return;
- }
- }
- }
-
- lp = dns_l_skip(lp, P->data, P->end);
- }
-
- for (i = 0; i < lengthof(P->dict); i++) {
- if (!P->dict[i]) {
- P->dict[i] = dn;
-
- break;
- }
- }
-} /* dns_p_dictadd() */
-
-
-int dns_p_push(struct dns_packet *P, enum dns_section section, void *dn,
- size_t dnlen, enum dns_type type, enum dns_class class,
- unsigned ttl, void *any) {
-
- unsigned n;
- size_t end = P->end;
- int error;
-
- if ((error = dns_d_push(P, dn, dnlen)))
- goto error;
-
- if (P->size - P->end < 4)
- goto nobufs;
-
- P->data[P->end++] = 0xff & (type >> 8);
- P->data[P->end++] = 0xff & (type >> 0);
-
- P->data[P->end++] = 0xff & (class >> 8);
- P->data[P->end++] = 0xff & (class >> 0);
-
- if (section == DNS_S_QD)
- goto update;
-
- if (P->size - P->end < 6)
- goto nobufs;
-
- if (type != DNS_T_OPT)
- ttl = DNS_PP_MIN(ttl, 0x7fffffffU);
- P->data[P->end++] = ttl >> 24;
- P->data[P->end++] = ttl >> 16;
- P->data[P->end++] = ttl >> 8;
- P->data[P->end++] = ttl >> 0;
-
- if ((error = dns_any_push(P, (union dns_any *)any, type)))
- goto error;
-
-update:
- switch (section) {
- case DNS_S_QD:
- if (dns_p_count(P, DNS_S_AN|DNS_S_NS|DNS_S_AR))
- goto order;
-
- if (!P->memo.qd.base && (error = dns_p_study(P)))
- goto error;
-
- n = ntohs(DNS_HEADER(P)->qdcount) + 1;
- DNS_HEADER(P)->qdcount = htons(n);
-
- P->memo.qd.end = P->end;
- P->memo.an.base = P->end;
- P->memo.an.end = P->end;
- P->memo.ns.base = P->end;
- P->memo.ns.end = P->end;
- P->memo.ar.base = P->end;
- P->memo.ar.end = P->end;
-
- break;
- case DNS_S_AN:
- if (dns_p_count(P, DNS_S_NS|DNS_S_AR))
- goto order;
-
- if (!P->memo.an.base && (error = dns_p_study(P)))
- goto error;
-
- n = ntohs(DNS_HEADER(P)->ancount) + 1;
- DNS_HEADER(P)->ancount = htons(n);
-
- P->memo.an.end = P->end;
- P->memo.ns.base = P->end;
- P->memo.ns.end = P->end;
- P->memo.ar.base = P->end;
- P->memo.ar.end = P->end;
-
- break;
- case DNS_S_NS:
- if (dns_p_count(P, DNS_S_AR))
- goto order;
-
- if (!P->memo.ns.base && (error = dns_p_study(P)))
- goto error;
-
- n = ntohs(DNS_HEADER(P)->nscount) + 1;
- DNS_HEADER(P)->nscount = htons(n);
-
- P->memo.ns.end = P->end;
- P->memo.ar.base = P->end;
- P->memo.ar.end = P->end;
-
- break;
- case DNS_S_AR:
- if (!P->memo.ar.base && (error = dns_p_study(P)))
- goto error;
-
- n = ntohs(DNS_HEADER(P)->arcount) + 1;
- DNS_HEADER(P)->arcount = htons(n);
-
- P->memo.ar.end = P->end;
-
- if (type == DNS_T_OPT && !P->memo.opt.p) {
- P->memo.opt.p = end;
- P->memo.opt.maxudp = class;
- P->memo.opt.ttl = ttl;
- }
-
- break;
- default:
- error = DNS_ESECTION;
-
- goto error;
- } /* switch() */
-
- return 0;
-nobufs:
- error = DNS_ENOBUFS;
-
- goto error;
-order:
- error = DNS_EORDER;
-
- goto error;
-error:
- P->end = end;
-
- return error;
-} /* dns_p_push() */
-
-
-static void dns_p_dump3(struct dns_packet *P, struct dns_rr_i *I, FILE *fp) {
- enum dns_section section;
- struct dns_rr rr;
- int error;
- union dns_any any;
- char pretty[sizeof any * 2];
- size_t len;
-
- fputs(";; [HEADER]\n", fp);
- fprintf(fp, ";; qid : %d\n", ntohs(DNS_HEADER(P)->qid));
- fprintf(fp, ";; qr : %s(%d)\n", (DNS_HEADER(P)->qr)? "RESPONSE" : "QUERY", DNS_HEADER(P)->qr);
- fprintf(fp, ";; opcode : %s(%d)\n", dns_stropcode(DNS_HEADER(P)->opcode), DNS_HEADER(P)->opcode);
- fprintf(fp, ";; aa : %s(%d)\n", (DNS_HEADER(P)->aa)? "AUTHORITATIVE" : "NON-AUTHORITATIVE", DNS_HEADER(P)->aa);
- fprintf(fp, ";; tc : %s(%d)\n", (DNS_HEADER(P)->tc)? "TRUNCATED" : "NOT-TRUNCATED", DNS_HEADER(P)->tc);
- fprintf(fp, ";; rd : %s(%d)\n", (DNS_HEADER(P)->rd)? "RECURSION-DESIRED" : "RECURSION-NOT-DESIRED", DNS_HEADER(P)->rd);
- fprintf(fp, ";; ra : %s(%d)\n", (DNS_HEADER(P)->ra)? "RECURSION-ALLOWED" : "RECURSION-NOT-ALLOWED", DNS_HEADER(P)->ra);
- fprintf(fp, ";; rcode : %s(%d)\n", dns_strrcode(dns_p_rcode(P)), dns_p_rcode(P));
-
- section = 0;
-
- while (dns_rr_grep(&rr, 1, I, P, &error)) {
- if (section != rr.section)
- fprintf(fp, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(P, rr.section));
-
- if ((len = dns_rr_print(pretty, sizeof pretty, &rr, P, &error)))
- fprintf(fp, "%s\n", pretty);
-
- section = rr.section;
- }
-} /* dns_p_dump3() */
-
-
-void dns_p_dump(struct dns_packet *P, FILE *fp) {
- dns_p_dump3(P, dns_rr_i_new(P, .section = 0), fp);
-} /* dns_p_dump() */
-
-
-static void dns_s_unstudy(struct dns_s_memo *m)
- { m->base = 0; m->end = 0; }
-
-static void dns_m_unstudy(struct dns_p_memo *m) {
- dns_s_unstudy(&m->qd);
- dns_s_unstudy(&m->an);
- dns_s_unstudy(&m->ns);
- dns_s_unstudy(&m->ar);
- m->opt.p = 0;
- m->opt.maxudp = 0;
- m->opt.ttl = 0;
-} /* dns_m_unstudy() */
-
-static int dns_s_study(struct dns_s_memo *m, enum dns_section section, unsigned short base, struct dns_packet *P) {
- unsigned short count, rp;
-
- count = dns_p_count(P, section);
-
- for (rp = base; count && rp < P->end; count--)
- rp = dns_rr_skip(rp, P);
-
- m->base = base;
- m->end = rp;
-
- return 0;
-} /* dns_s_study() */
-
-static int dns_m_study(struct dns_p_memo *m, struct dns_packet *P) {
- struct dns_rr rr;
- int error;
-
- if ((error = dns_s_study(&m->qd, DNS_S_QD, 12, P)))
- goto error;
- if ((error = dns_s_study(&m->an, DNS_S_AN, m->qd.end, P)))
- goto error;
- if ((error = dns_s_study(&m->ns, DNS_S_NS, m->an.end, P)))
- goto error;
- if ((error = dns_s_study(&m->ar, DNS_S_AR, m->ns.end, P)))
- goto error;
-
- m->opt.p = 0;
- m->opt.maxudp = 0;
- m->opt.ttl = 0;
- dns_rr_foreach(&rr, P, .type = DNS_T_OPT, .section = DNS_S_AR) {
- m->opt.p = rr.dn.p;
- m->opt.maxudp = rr.class;
- m->opt.ttl = rr.ttl;
- break;
- }
-
- return 0;
-error:
- dns_m_unstudy(m);
-
- return error;
-} /* dns_m_study() */
-
-int dns_p_study(struct dns_packet *P) {
- return dns_m_study(&P->memo, P);
-} /* dns_p_study() */
-
-
-enum dns_rcode dns_p_rcode(struct dns_packet *P) {
- return 0xfff & ((P->memo.opt.ttl >> 20) | DNS_HEADER(P)->rcode);
-} /* dns_p_rcode() */
-
-
-/*
- * Q U E R Y P A C K E T R O U T I N E S
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-#define DNS_Q_RD 0x1 /* recursion desired */
-#define DNS_Q_EDNS0 0x2 /* include OPT RR */
-
-static dns_error_t
-dns_q_make2(struct dns_packet **_Q, char *qname, size_t qlen, enum dns_type qtype, enum dns_class qclass, int qflags)
-{
- struct dns_packet *Q = NULL;
- int error;
-
- if (dns_p_movptr(&Q, _Q)) {
- dns_p_reset(Q);
- } else if (!(Q = dns_p_make(DNS_P_QBUFSIZ, &error))) {
- goto error;
- }
-
- if ((error = dns_p_push(Q, DNS_S_QD, qname, qlen, qtype, qclass, 0, 0)))
- goto error;
-
- DNS_HEADER(Q)->rd = !!(qflags & DNS_Q_RD);
-
- if (qflags & DNS_Q_EDNS0) {
- struct dns_opt opt = DNS_OPT_INIT(&opt);
-
- opt.version = 0; /* RFC 6891 version */
- opt.maxudp = 4096;
-
- if ((error = dns_p_push(Q, DNS_S_AR, ".", 1, DNS_T_OPT, dns_opt_class(&opt), dns_opt_ttl(&opt), &opt)))
- goto error;
- }
-
- *_Q = Q;
-
- return 0;
-error:
- dns_p_free(Q);
-
- return error;
-}
-
-static dns_error_t
-dns_q_make(struct dns_packet **Q, char *qname, enum dns_type qtype, enum dns_class qclass, int qflags)
-{
- return dns_q_make2(Q, qname, strlen(qname), qtype, qclass, qflags);
-}
-
-static dns_error_t
-dns_q_remake(struct dns_packet **Q, int qflags)
-{
- char qname[DNS_D_MAXNAME + 1];
- size_t qlen;
- struct dns_rr rr;
- int error;
-
- assert(Q && *Q);
- if ((error = dns_rr_parse(&rr, 12, *Q)))
- return error;
- if (!(qlen = dns_d_expand(qname, sizeof qname, rr.dn.p, *Q, &error)))
- return error;
- if (qlen >= sizeof qname)
- return DNS_EILLEGAL;
- return dns_q_make2(Q, qname, qlen, rr.type, rr.class, qflags);
-}
-
-/*
- * D O M A I N N A M E R O U T I N E S
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-#ifndef DNS_D_MAXPTRS
-#define DNS_D_MAXPTRS 127 /* Arbitrary; possible, valid depth is something like packet size / 2 + fudge. */
-#endif
-
-static size_t dns_l_expand(unsigned char *dst, size_t lim, unsigned short src, unsigned short *nxt, const unsigned char *data, size_t end) {
- unsigned short len;
- unsigned nptrs = 0;
-
-retry:
- if (src >= end)
- goto invalid;
-
- switch (0x03 & (data[src] >> 6)) {
- case 0x00:
- len = (0x3f & (data[src++]));
-
- if (end - src < len)
- goto invalid;
-
- if (lim > 0) {
- memcpy(dst, &data[src], DNS_PP_MIN(lim, len));
-
- dst[DNS_PP_MIN(lim - 1, len)] = '\0';
- }
-
- *nxt = src + len;
-
- return len;
- case 0x01:
- goto invalid;
- case 0x02:
- goto invalid;
- case 0x03:
- if (++nptrs > DNS_D_MAXPTRS)
- goto invalid;
-
- if (end - src < 2)
- goto invalid;
-
- src = ((0x3f & data[src + 0]) << 8)
- | ((0xff & data[src + 1]) << 0);
-
- goto retry;
- } /* switch() */
-
- /* NOT REACHED */
-invalid:
- *nxt = end;
-
- return 0;
-} /* dns_l_expand() */
-
-
-static unsigned short dns_l_skip(unsigned short src, const unsigned char *data, size_t end) {
- unsigned short len;
-
- if (src >= end)
- goto invalid;
-
- switch (0x03 & (data[src] >> 6)) {
- case 0x00:
- len = (0x3f & (data[src++]));
-
- if (end - src < len)
- goto invalid;
-
- return (len)? src + len : end;
- case 0x01:
- goto invalid;
- case 0x02:
- goto invalid;
- case 0x03:
- return end;
- } /* switch() */
-
- /* NOT REACHED */
-invalid:
- return end;
-} /* dns_l_skip() */
-
-
-static _Bool dns_d_isanchored(const void *_src, size_t len) {
- const unsigned char *src = _src;
- return len > 0 && src[len - 1] == '.';
-} /* dns_d_isanchored() */
-
-
-static size_t dns_d_ndots(const void *_src, size_t len) {
- const unsigned char *p = _src, *pe = p + len;
- size_t ndots = 0;
-
- while ((p = memchr(p, '.', pe - p))) {
- ndots++;
- p++;
- }
-
- return ndots;
-} /* dns_d_ndots() */
-
-
-static size_t dns_d_trim(void *dst_, size_t lim, const void *src_, size_t len, int flags) {
- unsigned char *dst = dst_;
- const unsigned char *src = src_;
- size_t dp = 0, sp = 0;
- int lc;
-
- /* trim any leading dot(s) */
- while (sp < len && src[sp] == '.')
- sp++;
-
- for (lc = 0; sp < len; lc = src[sp++]) {
- /* trim extra dot(s) */
- if (src[sp] == '.' && lc == '.')
- continue;
-
- if (dp < lim)
- dst[dp] = src[sp];
-
- dp++;
- }
-
- if ((flags & DNS_D_ANCHOR) && lc != '.') {
- if (dp < lim)
- dst[dp] = '.';
-
- dp++;
- }
-
- if (lim > 0)
- dst[DNS_PP_MIN(dp, lim - 1)] = '\0';
-
- return dp;
-} /* dns_d_trim() */
-
-
-char *dns_d_init(void *dst, size_t lim, const void *src, size_t len, int flags) {
- if (flags & DNS_D_TRIM) {
- dns_d_trim(dst, lim, src, len, flags);
- } if (flags & DNS_D_ANCHOR) {
- dns_d_anchor(dst, lim, src, len);
- } else {
- memmove(dst, src, DNS_PP_MIN(lim, len));
-
- if (lim > 0)
- ((char *)dst)[DNS_PP_MIN(len, lim - 1)] = '\0';
- }
-
- return dst;
-} /* dns_d_init() */
-
-
-size_t dns_d_anchor(void *dst, size_t lim, const void *src, size_t len) {
- if (len == 0)
- return 0;
-
- memmove(dst, src, DNS_PP_MIN(lim, len));
-
- if (((const char *)src)[len - 1] != '.') {
- if (len < lim)
- ((char *)dst)[len] = '.';
- len++;
- }
-
- if (lim > 0)
- ((char *)dst)[DNS_PP_MIN(lim - 1, len)] = '\0';
-
- return len;
-} /* dns_d_anchor() */
-
-
-size_t dns_d_cleave(void *dst, size_t lim, const void *src, size_t len) {
- const char *dot;
-
- /* XXX: Skip any leading dot. Handles cleaving root ".". */
- if (len == 0 || !(dot = memchr((const char *)src + 1, '.', len - 1)))
- return 0;
-
- len -= dot - (const char *)src;
-
- /* XXX: Unless root, skip the label's trailing dot. */
- if (len > 1) {
- src = ++dot;
- len--;
- } else
- src = dot;
-
- memmove(dst, src, DNS_PP_MIN(lim, len));
-
- if (lim > 0)
- ((char *)dst)[DNS_PP_MIN(lim - 1, len)] = '\0';
-
- return len;
-} /* dns_d_cleave() */
-
-
-size_t dns_d_comp(void *dst_, size_t lim, void *src_, size_t len, struct dns_packet *P, int *error) {
- struct { unsigned char *b; size_t p, x; } dst, src;
- unsigned char ch = '.';
-
- dst.b = dst_;
- dst.p = 0;
- dst.x = 1;
-
- src.b = (unsigned char *)src_;
- src.p = 0;
- src.x = 0;
-
- while (src.x < len) {
- ch = src.b[src.x];
-
- if (ch == '.') {
- if (dst.p < lim)
- dst.b[dst.p] = (0x3f & (src.x - src.p));
-
- dst.p = dst.x++;
- src.p = ++src.x;
- } else {
- if (dst.x < lim)
- dst.b[dst.x] = ch;
-
- dst.x++;
- src.x++;
- }
- } /* while() */
-
- if (src.x > src.p) {
- if (dst.p < lim)
- dst.b[dst.p] = (0x3f & (src.x - src.p));
-
- dst.p = dst.x;
- }
-
- if (dst.p > 1) {
- if (dst.p < lim)
- dst.b[dst.p] = 0x00;
-
- dst.p++;
- }
-
-#if 1
- if (dst.p < lim) {
- struct { unsigned char label[DNS_D_MAXLABEL + 1]; size_t len; unsigned short p, x, y; } a, b;
- unsigned i;
-
- a.p = 0;
-
- while ((a.len = dns_l_expand(a.label, sizeof a.label, a.p, &a.x, dst.b, lim))) {
- for (i = 0; i < lengthof(P->dict) && P->dict[i]; i++) {
- b.p = P->dict[i];
-
- while ((b.len = dns_l_expand(b.label, sizeof b.label, b.p, &b.x, P->data, P->end))) {
- a.y = a.x;
- b.y = b.x;
-
- while (a.len && b.len && 0 == strcasecmp((char *)a.label, (char *)b.label)) {
- a.len = dns_l_expand(a.label, sizeof a.label, a.y, &a.y, dst.b, lim);
- b.len = dns_l_expand(b.label, sizeof b.label, b.y, &b.y, P->data, P->end);
- }
-
- if (a.len == 0 && b.len == 0 && b.p <= 0x3fff) {
- dst.b[a.p++] = 0xc0
- | (0x3f & (b.p >> 8));
- dst.b[a.p++] = (0xff & (b.p >> 0));
-
- /* silence static analyzers */
- dns_assume(a.p > 0);
-
- return a.p;
- }
-
- b.p = b.x;
- } /* while() */
- } /* for() */
-
- a.p = a.x;
- } /* while() */
- } /* if () */
-#endif
-
- if (!dst.p)
- *error = DNS_EILLEGAL;
-
- return dst.p;
-} /* dns_d_comp() */
-
-
-unsigned short dns_d_skip(unsigned short src, struct dns_packet *P) {
- unsigned short len;
-
- while (src < P->end) {
- switch (0x03 & (P->data[src] >> 6)) {
- case 0x00: /* FOLLOWS */
- len = (0x3f & P->data[src++]);
-
- if (0 == len) {
-/* success ==> */ return src;
- } else if (P->end - src > len) {
- src += len;
-
- break;
- } else
- goto invalid;
-
- /* NOT REACHED */
- case 0x01: /* RESERVED */
- goto invalid;
- case 0x02: /* RESERVED */
- goto invalid;
- case 0x03: /* POINTER */
- if (P->end - src < 2)
- goto invalid;
-
- src += 2;
-
-/* success ==> */ return src;
- } /* switch() */
- } /* while() */
-
-invalid:
- return P->end;
-} /* dns_d_skip() */
-
-
-#include
-
-size_t dns_d_expand(void *dst, size_t lim, unsigned short src, struct dns_packet *P, int *error) {
- size_t dstp = 0;
- unsigned nptrs = 0;
- unsigned char len;
-
- while (src < P->end) {
- switch ((0x03 & (P->data[src] >> 6))) {
- case 0x00: /* FOLLOWS */
- len = (0x3f & P->data[src]);
-
- if (0 == len) {
- if (dstp == 0) {
- if (dstp < lim)
- ((unsigned char *)dst)[dstp] = '.';
-
- dstp++;
- }
-
- /* NUL terminate */
- if (lim > 0)
- ((unsigned char *)dst)[DNS_PP_MIN(dstp, lim - 1)] = '\0';
-
-/* success ==> */ return dstp;
- }
-
- src++;
-
- if (P->end - src < len)
- goto toolong;
-
- if (dstp < lim)
- memcpy(&((unsigned char *)dst)[dstp], &P->data[src], DNS_PP_MIN(len, lim - dstp));
-
- src += len;
- dstp += len;
-
- if (dstp < lim)
- ((unsigned char *)dst)[dstp] = '.';
-
- dstp++;
-
- nptrs = 0;
-
- continue;
- case 0x01: /* RESERVED */
- goto reserved;
- case 0x02: /* RESERVED */
- goto reserved;
- case 0x03: /* POINTER */
- if (++nptrs > DNS_D_MAXPTRS)
- goto toolong;
-
- if (P->end - src < 2)
- goto toolong;
-
- src = ((0x3f & P->data[src + 0]) << 8)
- | ((0xff & P->data[src + 1]) << 0);
-
- continue;
- } /* switch() */
- } /* while() */
-
-toolong:
- *error = DNS_EILLEGAL;
-
- if (lim > 0)
- ((unsigned char *)dst)[DNS_PP_MIN(dstp, lim - 1)] = '\0';
-
- return 0;
-reserved:
- *error = DNS_EILLEGAL;
-
- if (lim > 0)
- ((unsigned char *)dst)[DNS_PP_MIN(dstp, lim - 1)] = '\0';
-
- return 0;
-} /* dns_d_expand() */
-
-
-int dns_d_push(struct dns_packet *P, void *dn, size_t len) {
- size_t lim = P->size - P->end;
- unsigned dp = P->end;
- int error = DNS_EILLEGAL; /* silence compiler */
-
- len = dns_d_comp(&P->data[dp], lim, dn, len, P, &error);
-
- if (len == 0)
- return error;
- if (len > lim)
- return DNS_ENOBUFS;
-
- P->end += len;
-
- dns_p_dictadd(P, dp);
-
- return 0;
-} /* dns_d_push() */
-
-
-size_t dns_d_cname(void *dst, size_t lim, const void *dn, size_t len, struct dns_packet *P, int *error_) {
- char host[DNS_D_MAXNAME + 1];
- struct dns_rr_i i;
- struct dns_rr rr;
- unsigned depth;
- int error;
-
- if (sizeof host <= dns_d_anchor(host, sizeof host, dn, len))
- { error = ENAMETOOLONG; goto error; }
-
- for (depth = 0; depth < 7; depth++) {
- dns_rr_i_init(memset(&i, 0, sizeof i), P);
-
- i.section = DNS_S_ALL & ~DNS_S_QD;
- i.name = host;
- i.type = DNS_T_CNAME;
-
- if (!dns_rr_grep(&rr, 1, &i, P, &error))
- break;
-
- if ((error = dns_cname_parse((struct dns_cname *)host, &rr, P)))
- goto error;
- }
-
- return dns_strlcpy(dst, host, lim);
-error:
- *error_ = error;
-
- return 0;
-} /* dns_d_cname() */
-
-
-/*
- * R E S O U R C E R E C O R D R O U T I N E S
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-int dns_rr_copy(struct dns_packet *P, struct dns_rr *rr, struct dns_packet *Q) {
- unsigned char dn[DNS_D_MAXNAME + 1];
- union dns_any any;
- size_t len;
- int error;
-
- if (!(len = dns_d_expand(dn, sizeof dn, rr->dn.p, Q, &error)))
- return error;
- else if (len >= sizeof dn)
- return DNS_EILLEGAL;
-
- if (rr->section != DNS_S_QD && (error = dns_any_parse(dns_any_init(&any, sizeof any), rr, Q)))
- return error;
-
- return dns_p_push(P, rr->section, dn, len, rr->type, rr->class, rr->ttl, &any);
-} /* dns_rr_copy() */
-
-
-int dns_rr_parse(struct dns_rr *rr, unsigned short src, struct dns_packet *P) {
- unsigned short p = src;
-
- if (src >= P->end)
- goto invalid;
-
- rr->dn.p = p;
- rr->dn.len = (p = dns_d_skip(p, P)) - rr->dn.p;
-
- if (P->end - p < 4)
- goto invalid;
-
- rr->type = ((0xff & P->data[p + 0]) << 8)
- | ((0xff & P->data[p + 1]) << 0);
-
- rr->class = ((0xff & P->data[p + 2]) << 8)
- | ((0xff & P->data[p + 3]) << 0);
-
- p += 4;
-
- if (src < dns_p_qend(P)) {
- rr->section = DNS_S_QUESTION;
-
- rr->ttl = 0;
- rr->rd.p = 0;
- rr->rd.len = 0;
-
- return 0;
- }
-
- if (P->end - p < 4)
- goto invalid;
-
- rr->ttl = ((0xff & P->data[p + 0]) << 24)
- | ((0xff & P->data[p + 1]) << 16)
- | ((0xff & P->data[p + 2]) << 8)
- | ((0xff & P->data[p + 3]) << 0);
- if (rr->type != DNS_T_OPT)
- rr->ttl = DNS_PP_MIN(rr->ttl, 0x7fffffffU);
-
- p += 4;
-
- if (P->end - p < 2)
- goto invalid;
-
- rr->rd.len = ((0xff & P->data[p + 0]) << 8)
- | ((0xff & P->data[p + 1]) << 0);
- rr->rd.p = p + 2;
-
- p += 2;
-
- if (P->end - p < rr->rd.len)
- goto invalid;
-
- return 0;
-invalid:
- return DNS_EILLEGAL;
-} /* dns_rr_parse() */
-
-
-static unsigned short dns_rr_len(const unsigned short src, struct dns_packet *P) {
- unsigned short rp, rdlen;
-
- rp = dns_d_skip(src, P);
-
- if (P->end - rp < 4)
- return P->end - src;
-
- rp += 4; /* TYPE, CLASS */
-
- if (rp <= dns_p_qend(P))
- return rp - src;
-
- if (P->end - rp < 6)
- return P->end - src;
-
- rp += 6; /* TTL, RDLEN */
-
- rdlen = ((0xff & P->data[rp - 2]) << 8)
- | ((0xff & P->data[rp - 1]) << 0);
-
- if (P->end - rp < rdlen)
- return P->end - src;
-
- rp += rdlen;
-
- return rp - src;
-} /* dns_rr_len() */
-
-
-unsigned short dns_rr_skip(unsigned short src, struct dns_packet *P) {
- return src + dns_rr_len(src, P);
-} /* dns_rr_skip() */
-
-
-static enum dns_section dns_rr_section(unsigned short src, struct dns_packet *P) {
- enum dns_section section;
- unsigned count, index;
- unsigned short rp;
-
- if (src >= P->memo.qd.base && src < P->memo.qd.end)
- return DNS_S_QD;
- if (src >= P->memo.an.base && src < P->memo.an.end)
- return DNS_S_AN;
- if (src >= P->memo.ns.base && src < P->memo.ns.end)
- return DNS_S_NS;
- if (src >= P->memo.ar.base && src < P->memo.ar.end)
- return DNS_S_AR;
-
- /* NOTE: Possibly bad memoization. Try it the hard-way. */
-
- for (rp = 12, index = 0; rp < src && rp < P->end; index++)
- rp = dns_rr_skip(rp, P);
-
- section = DNS_S_QD;
- count = dns_p_count(P, section);
-
- while (index >= count && section <= DNS_S_AR) {
- section <<= 1;
- count += dns_p_count(P, section);
- }
-
- return DNS_S_ALL & section;
-} /* dns_rr_section() */
-
-
-static enum dns_type dns_rr_type(unsigned short src, struct dns_packet *P) {
- struct dns_rr rr;
- int error;
-
- if ((error = dns_rr_parse(&rr, src, P)))
- return 0;
-
- return rr.type;
-} /* dns_rr_type() */
-
-
-int dns_rr_cmp(struct dns_rr *r0, struct dns_packet *P0, struct dns_rr *r1, struct dns_packet *P1) {
- char host0[DNS_D_MAXNAME + 1], host1[DNS_D_MAXNAME + 1];
- union dns_any any0, any1;
- int cmp, error;
- size_t len;
-
- if ((cmp = r0->type - r1->type))
- return cmp;
-
- if ((cmp = r0->class - r1->class))
- return cmp;
-
- /*
- * FIXME: Do label-by-label comparison to handle illegally long names?
- */
-
- if (!(len = dns_d_expand(host0, sizeof host0, r0->dn.p, P0, &error))
- || len >= sizeof host0)
- return -1;
-
- if (!(len = dns_d_expand(host1, sizeof host1, r1->dn.p, P1, &error))
- || len >= sizeof host1)
- return 1;
-
- if ((cmp = strcasecmp(host0, host1)))
- return cmp;
-
- if (DNS_S_QD & (r0->section | r1->section)) {
- if (r0->section == r1->section)
- return 0;
-
- return (r0->section == DNS_S_QD)? -1 : 1;
- }
-
- if ((error = dns_any_parse(&any0, r0, P0)))
- return -1;
-
- if ((error = dns_any_parse(&any1, r1, P1)))
- return 1;
-
- return dns_any_cmp(&any0, r0->type, &any1, r1->type);
-} /* dns_rr_cmp() */
-
-
-static _Bool dns_rr_exists(struct dns_rr *rr0, struct dns_packet *P0, struct dns_packet *P1) {
- struct dns_rr rr1;
-
- dns_rr_foreach(&rr1, P1, .section = rr0->section, .type = rr0->type) {
- if (0 == dns_rr_cmp(rr0, P0, &rr1, P1))
- return 1;
- }
-
- return 0;
-} /* dns_rr_exists() */
-
-
-static unsigned short dns_rr_offset(struct dns_rr *rr) {
- return rr->dn.p;
-} /* dns_rr_offset() */
-
-
-static _Bool dns_rr_i_match(struct dns_rr *rr, struct dns_rr_i *i, struct dns_packet *P) {
- if (i->section && !(rr->section & i->section))
- return 0;
-
- if (i->type && rr->type != i->type && i->type != DNS_T_ALL)
- return 0;
-
- if (i->class && rr->class != i->class && i->class != DNS_C_ANY)
- return 0;
-
- if (i->name) {
- char dn[DNS_D_MAXNAME + 1];
- size_t len;
- int error;
-
- if (!(len = dns_d_expand(dn, sizeof dn, rr->dn.p, P, &error))
- || len >= sizeof dn)
- return 0;
-
- if (0 != strcasecmp(dn, i->name))
- return 0;
- }
-
- if (i->data && i->type && rr->section > DNS_S_QD) {
- union dns_any rd;
- int error;
-
- if ((error = dns_any_parse(&rd, rr, P)))
- return 0;
-
- if (0 != dns_any_cmp(&rd, rr->type, i->data, i->type))
- return 0;
- }
-
- return 1;
-} /* dns_rr_i_match() */
-
-
-static unsigned short dns_rr_i_start(struct dns_rr_i *i, struct dns_packet *P) {
- unsigned short rp;
- struct dns_rr r0, rr;
- int error;
-
- if ((i->section & DNS_S_QD) && P->memo.qd.base)
- rp = P->memo.qd.base;
- else if ((i->section & DNS_S_AN) && P->memo.an.base)
- rp = P->memo.an.base;
- else if ((i->section & DNS_S_NS) && P->memo.ns.base)
- rp = P->memo.ns.base;
- else if ((i->section & DNS_S_AR) && P->memo.ar.base)
- rp = P->memo.ar.base;
- else
- rp = 12;
-
- for (; rp < P->end; rp = dns_rr_skip(rp, P)) {
- if ((error = dns_rr_parse(&rr, rp, P)))
- continue;
-
- rr.section = dns_rr_section(rp, P);
-
- if (!dns_rr_i_match(&rr, i, P))
- continue;
-
- r0 = rr;
-
- goto lower;
- }
-
- return P->end;
-lower:
- if (i->sort == &dns_rr_i_packet)
- return dns_rr_offset(&r0);
-
- while ((rp = dns_rr_skip(rp, P)) < P->end) {
- if ((error = dns_rr_parse(&rr, rp, P)))
- continue;
-
- rr.section = dns_rr_section(rp, P);
-
- if (!dns_rr_i_match(&rr, i, P))
- continue;
-
- if (i->sort(&rr, &r0, i, P) < 0)
- r0 = rr;
- }
-
- return dns_rr_offset(&r0);
-} /* dns_rr_i_start() */
-
-
-static unsigned short dns_rr_i_skip(unsigned short rp, struct dns_rr_i *i, struct dns_packet *P) {
- struct dns_rr r0, r1, rr;
- int error;
-
- if ((error = dns_rr_parse(&r0, rp, P)))
- return P->end;
-
- r0.section = dns_rr_section(rp, P);
-
- rp = (i->sort == &dns_rr_i_packet)? dns_rr_skip(rp, P) : 12;
-
- for (; rp < P->end; rp = dns_rr_skip(rp, P)) {
- if ((error = dns_rr_parse(&rr, rp, P)))
- continue;
-
- rr.section = dns_rr_section(rp, P);
-
- if (!dns_rr_i_match(&rr, i, P))
- continue;
-
- if (i->sort(&rr, &r0, i, P) <= 0)
- continue;
-
- r1 = rr;
-
- goto lower;
- }
-
- return P->end;
-lower:
- if (i->sort == &dns_rr_i_packet)
- return dns_rr_offset(&r1);
-
- while ((rp = dns_rr_skip(rp, P)) < P->end) {
- if ((error = dns_rr_parse(&rr, rp, P)))
- continue;
-
- rr.section = dns_rr_section(rp, P);
-
- if (!dns_rr_i_match(&rr, i, P))
- continue;
-
- if (i->sort(&rr, &r0, i, P) <= 0)
- continue;
-
- if (i->sort(&rr, &r1, i, P) >= 0)
- continue;
-
- r1 = rr;
- }
-
- return dns_rr_offset(&r1);
-} /* dns_rr_i_skip() */
-
-
-int dns_rr_i_packet(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) {
- (void)i;
- (void)P;
-
- return (int)a->dn.p - (int)b->dn.p;
-} /* dns_rr_i_packet() */
-
-
-int dns_rr_i_order(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) {
- int cmp;
-
- (void)i;
-
- if ((cmp = a->section - b->section))
- return cmp;
-
- if (a->type != b->type)
- return (int)a->dn.p - (int)b->dn.p;
-
- return dns_rr_cmp(a, P, b, P);
-} /* dns_rr_i_order() */
-
-
-int dns_rr_i_shuffle(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) {
- int cmp;
-
- (void)i;
- (void)P;
-
- while (!i->state.regs[0])
- i->state.regs[0] = dns_random();
-
- if ((cmp = a->section - b->section))
- return cmp;
-
- return dns_k_shuffle16(a->dn.p, i->state.regs[0]) - dns_k_shuffle16(b->dn.p, i->state.regs[0]);
-} /* dns_rr_i_shuffle() */
-
-
-struct dns_rr_i *dns_rr_i_init(struct dns_rr_i *i, struct dns_packet *P) {
- static const struct dns_rr_i i_initializer;
-
- (void)P;
-
- i->state = i_initializer.state;
- i->saved = i->state;
-
- return i;
-} /* dns_rr_i_init() */
-
-
-unsigned dns_rr_grep(struct dns_rr *rr, unsigned lim, struct dns_rr_i *i, struct dns_packet *P, int *error_) {
- unsigned count = 0;
- int error;
-
- switch (i->state.exec) {
- case 0:
- if (!i->sort)
- i->sort = &dns_rr_i_packet;
-
- i->state.next = dns_rr_i_start(i, P);
- i->state.exec++;
-
- /* FALL THROUGH */
- case 1:
- while (count < lim && i->state.next < P->end) {
- if ((error = dns_rr_parse(rr, i->state.next, P)))
- goto error;
-
- rr->section = dns_rr_section(i->state.next, P);
-
- rr++;
- count++;
- i->state.count++;
-
- i->state.next = dns_rr_i_skip(i->state.next, i, P);
- } /* while() */
-
- break;
- } /* switch() */
-
- return count;
-error:
- *error_ = error;
-
- return count;
-} /* dns_rr_grep() */
-
-
-size_t dns_rr_print(void *_dst, size_t lim, struct dns_rr *rr, struct dns_packet *P, int *_error) {
- struct dns_buf dst = DNS_B_INTO(_dst, lim);
- union dns_any any;
- size_t n;
- int error;
-
- if (rr->section == DNS_S_QD)
- dns_b_putc(&dst, ';');
-
- if (!(n = dns_d_expand(any.ns.host, sizeof any.ns.host, rr->dn.p, P, &error)))
- goto error;
- dns_b_put(&dst, any.ns.host, DNS_PP_MIN(n, sizeof any.ns.host - 1));
-
- if (rr->section != DNS_S_QD) {
- dns_b_putc(&dst, ' ');
- dns_b_fmtju(&dst, rr->ttl, 0);
- }
-
- dns_b_putc(&dst, ' ');
- dns_b_puts(&dst, dns_strclass(rr->class));
- dns_b_putc(&dst, ' ');
- dns_b_puts(&dst, dns_strtype(rr->type));
-
- if (rr->section == DNS_S_QD)
- goto epilog;
-
- dns_b_putc(&dst, ' ');
-
- if ((error = dns_any_parse(dns_any_init(&any, sizeof any), rr, P)))
- goto error;
-
- n = dns_any_print(dst.p, dst.pe - dst.p, &any, rr->type);
- dst.p += DNS_PP_MIN(n, (size_t)(dst.pe - dst.p));
-epilog:
- return dns_b_strllen(&dst);
-error:
- *_error = error;
-
- return 0;
-} /* dns_rr_print() */
-
-
-int dns_a_parse(struct dns_a *a, struct dns_rr *rr, struct dns_packet *P) {
- unsigned long addr;
-
- if (rr->rd.len != 4)
- return DNS_EILLEGAL;
-
- addr = ((0xffU & P->data[rr->rd.p + 0]) << 24)
- | ((0xffU & P->data[rr->rd.p + 1]) << 16)
- | ((0xffU & P->data[rr->rd.p + 2]) << 8)
- | ((0xffU & P->data[rr->rd.p + 3]) << 0);
-
- a->addr.s_addr = htonl(addr);
-
- return 0;
-} /* dns_a_parse() */
-
-
-int dns_a_push(struct dns_packet *P, struct dns_a *a) {
- unsigned long addr;
-
- if (P->size - P->end < 6)
- return DNS_ENOBUFS;
-
- P->data[P->end++] = 0x00;
- P->data[P->end++] = 0x04;
-
- addr = ntohl(a->addr.s_addr);
-
- P->data[P->end++] = 0xffU & (addr >> 24);
- P->data[P->end++] = 0xffU & (addr >> 16);
- P->data[P->end++] = 0xffU & (addr >> 8);
- P->data[P->end++] = 0xffU & (addr >> 0);
-
- return 0;
-} /* dns_a_push() */
-
-
-size_t dns_a_arpa(void *_dst, size_t lim, const struct dns_a *a) {
- struct dns_buf dst = DNS_B_INTO(_dst, lim);
- unsigned long octets = ntohl(a->addr.s_addr);
- unsigned i;
-
- for (i = 0; i < 4; i++) {
- dns_b_fmtju(&dst, 0xff & octets, 0);
- dns_b_putc(&dst, '.');
- octets >>= 8;
- }
-
- dns_b_puts(&dst, "in-addr.arpa.");
-
- return dns_b_strllen(&dst);
-} /* dns_a_arpa() */
-
-
-int dns_a_cmp(const struct dns_a *a, const struct dns_a *b) {
- if (ntohl(a->addr.s_addr) < ntohl(b->addr.s_addr))
- return -1;
- if (ntohl(a->addr.s_addr) > ntohl(b->addr.s_addr))
- return 1;
-
- return 0;
-} /* dns_a_cmp() */
-
-
-size_t dns_a_print(void *dst, size_t lim, struct dns_a *a) {
- char addr[INET_ADDRSTRLEN + 1] = "0.0.0.0";
-
- dns_inet_ntop(AF_INET, &a->addr, addr, sizeof addr);
-
- return dns_strlcpy(dst, addr, lim);
-} /* dns_a_print() */
-
-
-int dns_aaaa_parse(struct dns_aaaa *aaaa, struct dns_rr *rr, struct dns_packet *P) {
- if (rr->rd.len != sizeof aaaa->addr.s6_addr)
- return DNS_EILLEGAL;
-
- memcpy(aaaa->addr.s6_addr, &P->data[rr->rd.p], sizeof aaaa->addr.s6_addr);
-
- return 0;
-} /* dns_aaaa_parse() */
-
-
-int dns_aaaa_push(struct dns_packet *P, struct dns_aaaa *aaaa) {
- if (P->size - P->end < 2 + sizeof aaaa->addr.s6_addr)
- return DNS_ENOBUFS;
-
- P->data[P->end++] = 0x00;
- P->data[P->end++] = 0x10;
-
- memcpy(&P->data[P->end], aaaa->addr.s6_addr, sizeof aaaa->addr.s6_addr);
-
- P->end += sizeof aaaa->addr.s6_addr;
-
- return 0;
-} /* dns_aaaa_push() */
-
-
-int dns_aaaa_cmp(const struct dns_aaaa *a, const struct dns_aaaa *b) {
- unsigned i;
- int cmp;
-
- for (i = 0; i < lengthof(a->addr.s6_addr); i++) {
- if ((cmp = (a->addr.s6_addr[i] - b->addr.s6_addr[i])))
- return cmp;
- }
-
- return 0;
-} /* dns_aaaa_cmp() */
-
-
-size_t dns_aaaa_arpa(void *_dst, size_t lim, const struct dns_aaaa *aaaa) {
- static const unsigned char hex[16] = "0123456789abcdef";
- struct dns_buf dst = DNS_B_INTO(_dst, lim);
- unsigned nyble;
- int i, j;
-
- for (i = sizeof aaaa->addr.s6_addr - 1; i >= 0; i--) {
- nyble = aaaa->addr.s6_addr[i];
-
- for (j = 0; j < 2; j++) {
- dns_b_putc(&dst, hex[0x0f & nyble]);
- dns_b_putc(&dst, '.');
- nyble >>= 4;
- }
- }
-
- dns_b_puts(&dst, "ip6.arpa.");
-
- return dns_b_strllen(&dst);
-} /* dns_aaaa_arpa() */
-
-
-size_t dns_aaaa_print(void *dst, size_t lim, struct dns_aaaa *aaaa) {
- char addr[INET6_ADDRSTRLEN + 1] = "::";
-
- dns_inet_ntop(AF_INET6, &aaaa->addr, addr, sizeof addr);
-
- return dns_strlcpy(dst, addr, lim);
-} /* dns_aaaa_print() */
-
-
-int dns_mx_parse(struct dns_mx *mx, struct dns_rr *rr, struct dns_packet *P) {
- size_t len;
- int error;
-
- if (rr->rd.len < 3)
- return DNS_EILLEGAL;
-
- mx->preference = (0xff00 & (P->data[rr->rd.p + 0] << 8))
- | (0x00ff & (P->data[rr->rd.p + 1] << 0));
-
- if (!(len = dns_d_expand(mx->host, sizeof mx->host, rr->rd.p + 2, P, &error)))
- return error;
- else if (len >= sizeof mx->host)
- return DNS_EILLEGAL;
-
- return 0;
-} /* dns_mx_parse() */
-
-
-int dns_mx_push(struct dns_packet *P, struct dns_mx *mx) {
- size_t end, len;
- int error;
-
- if (P->size - P->end < 5)
- return DNS_ENOBUFS;
-
- end = P->end;
- P->end += 2;
-
- P->data[P->end++] = 0xff & (mx->preference >> 8);
- P->data[P->end++] = 0xff & (mx->preference >> 0);
-
- if ((error = dns_d_push(P, mx->host, strlen(mx->host))))
- goto error;
-
- len = P->end - end - 2;
-
- P->data[end + 0] = 0xff & (len >> 8);
- P->data[end + 1] = 0xff & (len >> 0);
-
- return 0;
-error:
- P->end = end;
-
- return error;
-} /* dns_mx_push() */
-
-
-int dns_mx_cmp(const struct dns_mx *a, const struct dns_mx *b) {
- int cmp;
-
- if ((cmp = a->preference - b->preference))
- return cmp;
-
- return strcasecmp(a->host, b->host);
-} /* dns_mx_cmp() */
-
-
-size_t dns_mx_print(void *_dst, size_t lim, struct dns_mx *mx) {
- struct dns_buf dst = DNS_B_INTO(_dst, lim);
-
- dns_b_fmtju(&dst, mx->preference, 0);
- dns_b_putc(&dst, ' ');
- dns_b_puts(&dst, mx->host);
-
- return dns_b_strllen(&dst);
-} /* dns_mx_print() */
-
-
-size_t dns_mx_cname(void *dst, size_t lim, struct dns_mx *mx) {
- return dns_strlcpy(dst, mx->host, lim);
-} /* dns_mx_cname() */
-
-
-int dns_ns_parse(struct dns_ns *ns, struct dns_rr *rr, struct dns_packet *P) {
- size_t len;
- int error;
-
- if (!(len = dns_d_expand(ns->host, sizeof ns->host, rr->rd.p, P, &error)))
- return error;
- else if (len >= sizeof ns->host)
- return DNS_EILLEGAL;
-
- return 0;
-} /* dns_ns_parse() */
-
-
-int dns_ns_push(struct dns_packet *P, struct dns_ns *ns) {
- size_t end, len;
- int error;
-
- if (P->size - P->end < 3)
- return DNS_ENOBUFS;
-
- end = P->end;
- P->end += 2;
-
- if ((error = dns_d_push(P, ns->host, strlen(ns->host))))
- goto error;
-
- len = P->end - end - 2;
-
- P->data[end + 0] = 0xff & (len >> 8);
- P->data[end + 1] = 0xff & (len >> 0);
-
- return 0;
-error:
- P->end = end;
-
- return error;
-} /* dns_ns_push() */
-
-
-int dns_ns_cmp(const struct dns_ns *a, const struct dns_ns *b) {
- return strcasecmp(a->host, b->host);
-} /* dns_ns_cmp() */
-
-
-size_t dns_ns_print(void *dst, size_t lim, struct dns_ns *ns) {
- return dns_strlcpy(dst, ns->host, lim);
-} /* dns_ns_print() */
-
-
-size_t dns_ns_cname(void *dst, size_t lim, struct dns_ns *ns) {
- return dns_strlcpy(dst, ns->host, lim);
-} /* dns_ns_cname() */
-
-
-int dns_cname_parse(struct dns_cname *cname, struct dns_rr *rr, struct dns_packet *P) {
- return dns_ns_parse((struct dns_ns *)cname, rr, P);
-} /* dns_cname_parse() */
-
-
-int dns_cname_push(struct dns_packet *P, struct dns_cname *cname) {
- return dns_ns_push(P, (struct dns_ns *)cname);
-} /* dns_cname_push() */
-
-
-int dns_cname_cmp(const struct dns_cname *a, const struct dns_cname *b) {
- return strcasecmp(a->host, b->host);
-} /* dns_cname_cmp() */
-
-
-size_t dns_cname_print(void *dst, size_t lim, struct dns_cname *cname) {
- return dns_ns_print(dst, lim, (struct dns_ns *)cname);
-} /* dns_cname_print() */
-
-
-size_t dns_cname_cname(void *dst, size_t lim, struct dns_cname *cname) {
- return dns_strlcpy(dst, cname->host, lim);
-} /* dns_cname_cname() */
-
-
-int dns_soa_parse(struct dns_soa *soa, struct dns_rr *rr, struct dns_packet *P) {
- struct { void *dst; size_t lim; } dn[] =
- { { soa->mname, sizeof soa->mname },
- { soa->rname, sizeof soa->rname } };
- unsigned *ts[] =
- { &soa->serial, &soa->refresh, &soa->retry, &soa->expire, &soa->minimum };
- unsigned short rp;
- unsigned i, j, n;
- int error;
-
- /* MNAME / RNAME */
- if ((rp = rr->rd.p) >= P->end)
- return DNS_EILLEGAL;
-
- for (i = 0; i < lengthof(dn); i++) {
- if (!(n = dns_d_expand(dn[i].dst, dn[i].lim, rp, P, &error)))
- return error;
- else if (n >= dn[i].lim)
- return DNS_EILLEGAL;
-
- if ((rp = dns_d_skip(rp, P)) >= P->end)
- return DNS_EILLEGAL;
- }
-
- /* SERIAL / REFRESH / RETRY / EXPIRE / MINIMUM */
- for (i = 0; i < lengthof(ts); i++) {
- for (j = 0; j < 4; j++, rp++) {
- if (rp >= P->end)
- return DNS_EILLEGAL;
-
- *ts[i] <<= 8;
- *ts[i] |= (0xff & P->data[rp]);
- }
- }
-
- return 0;
-} /* dns_soa_parse() */
-
-
-int dns_soa_push(struct dns_packet *P, struct dns_soa *soa) {
- void *dn[] = { soa->mname, soa->rname };
- unsigned ts[] = { (0xffffffff & soa->serial),
- (0x7fffffff & soa->refresh),
- (0x7fffffff & soa->retry),
- (0x7fffffff & soa->expire),
- (0xffffffff & soa->minimum) };
- unsigned i, j;
- size_t end, len;
- int error;
-
- end = P->end;
-
- if ((P->end += 2) >= P->size)
- goto toolong;
-
- /* MNAME / RNAME */
- for (i = 0; i < lengthof(dn); i++) {
- if ((error = dns_d_push(P, dn[i], strlen(dn[i]))))
- goto error;
- }
-
- /* SERIAL / REFRESH / RETRY / EXPIRE / MINIMUM */
- for (i = 0; i < lengthof(ts); i++) {
- if ((P->end += 4) >= P->size)
- goto toolong;
-
- for (j = 1; j <= 4; j++) {
- P->data[P->end - j] = (0xff & ts[i]);
- ts[i] >>= 8;
- }
- }
-
- len = P->end - end - 2;
- P->data[end + 0] = (0xff & (len >> 8));
- P->data[end + 1] = (0xff & (len >> 0));
-
- return 0;
-toolong:
- error = DNS_ENOBUFS;
-
- /* FALL THROUGH */
-error:
- P->end = end;
-
- return error;
-} /* dns_soa_push() */
-
-
-int dns_soa_cmp(const struct dns_soa *a, const struct dns_soa *b) {
- int cmp;
-
- if ((cmp = strcasecmp(a->mname, b->mname)))
- return cmp;
-
- if ((cmp = strcasecmp(a->rname, b->rname)))
- return cmp;
-
- if (a->serial > b->serial)
- return -1;
- else if (a->serial < b->serial)
- return 1;
-
- if (a->refresh > b->refresh)
- return -1;
- else if (a->refresh < b->refresh)
- return 1;
-
- if (a->retry > b->retry)
- return -1;
- else if (a->retry < b->retry)
- return 1;
-
- if (a->expire > b->expire)
- return -1;
- else if (a->expire < b->expire)
- return 1;
-
- if (a->minimum > b->minimum)
- return -1;
- else if (a->minimum < b->minimum)
- return 1;
-
- return 0;
-} /* dns_soa_cmp() */
-
-
-size_t dns_soa_print(void *_dst, size_t lim, struct dns_soa *soa) {
- struct dns_buf dst = DNS_B_INTO(_dst, lim);
-
- dns_b_puts(&dst, soa->mname);
- dns_b_putc(&dst, ' ');
- dns_b_puts(&dst, soa->rname);
- dns_b_putc(&dst, ' ');
- dns_b_fmtju(&dst, soa->serial, 0);
- dns_b_putc(&dst, ' ');
- dns_b_fmtju(&dst, soa->refresh, 0);
- dns_b_putc(&dst, ' ');
- dns_b_fmtju(&dst, soa->retry, 0);
- dns_b_putc(&dst, ' ');
- dns_b_fmtju(&dst, soa->expire, 0);
- dns_b_putc(&dst, ' ');
- dns_b_fmtju(&dst, soa->minimum, 0);
-
- return dns_b_strllen(&dst);
-} /* dns_soa_print() */
-
-
-int dns_srv_parse(struct dns_srv *srv, struct dns_rr *rr, struct dns_packet *P) {
- unsigned short rp;
- unsigned i;
- size_t n;
- int error;
-
- memset(srv, '\0', sizeof *srv);
-
- rp = rr->rd.p;
-
- if (rr->rd.len < 7)
- return DNS_EILLEGAL;
-
- for (i = 0; i < 2; i++, rp++) {
- srv->priority <<= 8;
- srv->priority |= (0xff & P->data[rp]);
- }
-
- for (i = 0; i < 2; i++, rp++) {
- srv->weight <<= 8;
- srv->weight |= (0xff & P->data[rp]);
- }
-
- for (i = 0; i < 2; i++, rp++) {
- srv->port <<= 8;
- srv->port |= (0xff & P->data[rp]);
- }
-
- if (!(n = dns_d_expand(srv->target, sizeof srv->target, rp, P, &error)))
- return error;
- else if (n >= sizeof srv->target)
- return DNS_EILLEGAL;
-
- return 0;
-} /* dns_srv_parse() */
-
-
-int dns_srv_push(struct dns_packet *P, struct dns_srv *srv) {
- size_t end, len;
- int error;
-
- end = P->end;
-
- if (P->size - P->end < 2)
- goto toolong;
-
- P->end += 2;
-
- if (P->size - P->end < 6)
- goto toolong;
-
- P->data[P->end++] = 0xff & (srv->priority >> 8);
- P->data[P->end++] = 0xff & (srv->priority >> 0);
-
- P->data[P->end++] = 0xff & (srv->weight >> 8);
- P->data[P->end++] = 0xff & (srv->weight >> 0);
-
- P->data[P->end++] = 0xff & (srv->port >> 8);
- P->data[P->end++] = 0xff & (srv->port >> 0);
-
- if (0 == (len = dns_d_comp(&P->data[P->end], P->size - P->end, srv->target, strlen(srv->target), P, &error)))
- goto error;
- else if (P->size - P->end < len)
- goto toolong;
-
- P->end += len;
-
- if (P->end > 65535)
- goto toolong;
-
- len = P->end - end - 2;
-
- P->data[end + 0] = 0xff & (len >> 8);
- P->data[end + 1] = 0xff & (len >> 0);
-
- return 0;
-toolong:
- error = DNS_ENOBUFS;
-
- /* FALL THROUGH */
-error:
- P->end = end;
-
- return error;
-} /* dns_srv_push() */
-
-
-int dns_srv_cmp(const struct dns_srv *a, const struct dns_srv *b) {
- int cmp;
-
- if ((cmp = a->priority - b->priority))
- return cmp;
-
- /*
- * FIXME: We need some sort of random seed to implement the dynamic
- * weighting required by RFC 2782.
- */
- if ((cmp = a->weight - b->weight))
- return cmp;
-
- if ((cmp = a->port - b->port))
- return cmp;
-
- return strcasecmp(a->target, b->target);
-} /* dns_srv_cmp() */
-
-
-size_t dns_srv_print(void *_dst, size_t lim, struct dns_srv *srv) {
- struct dns_buf dst = DNS_B_INTO(_dst, lim);
-
- dns_b_fmtju(&dst, srv->priority, 0);
- dns_b_putc(&dst, ' ');
- dns_b_fmtju(&dst, srv->weight, 0);
- dns_b_putc(&dst, ' ');
- dns_b_fmtju(&dst, srv->port, 0);
- dns_b_putc(&dst, ' ');
- dns_b_puts(&dst, srv->target);
-
- return dns_b_strllen(&dst);
-} /* dns_srv_print() */
-
-
-size_t dns_srv_cname(void *dst, size_t lim, struct dns_srv *srv) {
- return dns_strlcpy(dst, srv->target, lim);
-} /* dns_srv_cname() */
-
-
-unsigned int dns_opt_ttl(const struct dns_opt *opt) {
- unsigned int ttl = 0;
-
- ttl |= (0xffU & opt->rcode) << 24;
- ttl |= (0xffU & opt->version) << 16;
- ttl |= (0xffffU & opt->flags) << 0;
-
- return ttl;
-} /* dns_opt_ttl() */
-
-
-unsigned short dns_opt_class(const struct dns_opt *opt) {
- return opt->maxudp;
-} /* dns_opt_class() */
-
-
-struct dns_opt *dns_opt_init(struct dns_opt *opt, size_t size) {
- assert(size >= offsetof(struct dns_opt, data));
-
- opt->size = size - offsetof(struct dns_opt, data);
- opt->len = 0;
-
- opt->rcode = 0;
- opt->version = 0;
- opt->maxudp = 0;
-
- return opt;
-} /* dns_opt_init() */
-
-
-static union dns_any *dns_opt_initany(union dns_any *any, size_t size) {
- return dns_opt_init(&any->opt, size), any;
-} /* dns_opt_initany() */
-
-
-int dns_opt_parse(struct dns_opt *opt, struct dns_rr *rr, struct dns_packet *P) {
- struct dns_buf src = DNS_B_FROM(&P->data[rr->rd.p], rr->rd.len);
- struct dns_buf dst = DNS_B_INTO(opt->data, opt->size);
- int error;
-
- opt->rcode = 0xfff & ((rr->ttl >> 20) | DNS_HEADER(P)->rcode);
- opt->version = 0xff & (rr->ttl >> 16);
- opt->flags = 0xffff & rr->ttl;
- opt->maxudp = 0xffff & rr->class;
-
- while (src.p < src.pe) {
- int code, len;
-
- if (-1 == (code = dns_b_get16(&src, -1)))
- return src.error;
- if (-1 == (len = dns_b_get16(&src, -1)))
- return src.error;
-
- switch (code) {
- default:
- dns_b_put16(&dst, code);
- dns_b_put16(&dst, len);
- if ((error = dns_b_move(&dst, &src, len)))
- return error;
- break;
- }
- }
-
- return 0;
-} /* dns_opt_parse() */
-
-
-int dns_opt_push(struct dns_packet *P, struct dns_opt *opt) {
- struct dns_buf src = DNS_B_FROM(opt->data, opt->len);
- struct dns_buf dst = DNS_B_INTO(&P->data[P->end], (P->size - P->end));
- int error;
-
- /* rdata length (see below) */
- if ((error = dns_b_put16(&dst, 0)))
- goto error;
-
- /* ... push known options here */
-
- /* push opaque option data */
- if ((error = dns_b_move(&dst, &src, (size_t)(src.pe - src.p))))
- goto error;
-
- /* rdata length */
- if ((error = dns_b_pput16(&dst, dns_b_tell(&dst) - 2, 0)))
- goto error;
-
-#if !DNS_DEBUG_OPT_FORMERR
- P->end += dns_b_tell(&dst);
-#endif
-
- return 0;
-error:
- return error;
-} /* dns_opt_push() */
-
-
-int dns_opt_cmp(const struct dns_opt *a, const struct dns_opt *b) {
- (void)a;
- (void)b;
-
- return -1;
-} /* dns_opt_cmp() */
-
-
-size_t dns_opt_print(void *_dst, size_t lim, struct dns_opt *opt) {
- struct dns_buf dst = DNS_B_INTO(_dst, lim);
- size_t p;
-
- dns_b_putc(&dst, '"');
-
- for (p = 0; p < opt->len; p++) {
- dns_b_putc(&dst, '\\');
- dns_b_fmtju(&dst, opt->data[p], 3);
- }
-
- dns_b_putc(&dst, '"');
-
- return dns_b_strllen(&dst);
-} /* dns_opt_print() */
-
-
-int dns_ptr_parse(struct dns_ptr *ptr, struct dns_rr *rr, struct dns_packet *P) {
- return dns_ns_parse((struct dns_ns *)ptr, rr, P);
-} /* dns_ptr_parse() */
-
-
-int dns_ptr_push(struct dns_packet *P, struct dns_ptr *ptr) {
- return dns_ns_push(P, (struct dns_ns *)ptr);
-} /* dns_ptr_push() */
-
-
-size_t dns_ptr_qname(void *dst, size_t lim, int af, void *addr) {
- switch (af) {
- case AF_INET6:
- return dns_aaaa_arpa(dst, lim, addr);
- case AF_INET:
- return dns_a_arpa(dst, lim, addr);
- default: {
- struct dns_a a;
- a.addr.s_addr = INADDR_NONE;
- return dns_a_arpa(dst, lim, &a);
- }
- }
-} /* dns_ptr_qname() */
-
-
-int dns_ptr_cmp(const struct dns_ptr *a, const struct dns_ptr *b) {
- return strcasecmp(a->host, b->host);
-} /* dns_ptr_cmp() */
-
-
-size_t dns_ptr_print(void *dst, size_t lim, struct dns_ptr *ptr) {
- return dns_ns_print(dst, lim, (struct dns_ns *)ptr);
-} /* dns_ptr_print() */
-
-
-size_t dns_ptr_cname(void *dst, size_t lim, struct dns_ptr *ptr) {
- return dns_strlcpy(dst, ptr->host, lim);
-} /* dns_ptr_cname() */
-
-
-int dns_sshfp_parse(struct dns_sshfp *fp, struct dns_rr *rr, struct dns_packet *P) {
- unsigned p = rr->rd.p, pe = rr->rd.p + rr->rd.len;
-
- if (pe - p < 2)
- return DNS_EILLEGAL;
-
- fp->algo = P->data[p++];
- fp->type = P->data[p++];
-
- switch (fp->type) {
- case DNS_SSHFP_SHA1:
- if (pe - p < sizeof fp->digest.sha1)
- return DNS_EILLEGAL;
-
- memcpy(fp->digest.sha1, &P->data[p], sizeof fp->digest.sha1);
-
- break;
- default:
- break;
- } /* switch() */
-
- return 0;
-} /* dns_sshfp_parse() */
-
-
-int dns_sshfp_push(struct dns_packet *P, struct dns_sshfp *fp) {
- unsigned p = P->end, pe = P->size, n;
-
- if (pe - p < 4)
- return DNS_ENOBUFS;
-
- p += 2;
- P->data[p++] = 0xff & fp->algo;
- P->data[p++] = 0xff & fp->type;
-
- switch (fp->type) {
- case DNS_SSHFP_SHA1:
- if (pe - p < sizeof fp->digest.sha1)
- return DNS_ENOBUFS;
-
- memcpy(&P->data[p], fp->digest.sha1, sizeof fp->digest.sha1);
- p += sizeof fp->digest.sha1;
-
- break;
- default:
- return DNS_EILLEGAL;
- } /* switch() */
-
- n = p - P->end - 2;
- P->data[P->end++] = 0xff & (n >> 8);
- P->data[P->end++] = 0xff & (n >> 0);
- P->end = p;
-
- return 0;
-} /* dns_sshfp_push() */
-
-
-int dns_sshfp_cmp(const struct dns_sshfp *a, const struct dns_sshfp *b) {
- int cmp;
-
- if ((cmp = a->algo - b->algo) || (cmp = a->type - b->type))
- return cmp;
-
- switch (a->type) {
- case DNS_SSHFP_SHA1:
- return memcmp(a->digest.sha1, b->digest.sha1, sizeof a->digest.sha1);
- default:
- return 0;
- } /* switch() */
-
- /* NOT REACHED */
-} /* dns_sshfp_cmp() */
-
-
-size_t dns_sshfp_print(void *_dst, size_t lim, struct dns_sshfp *fp) {
- static const unsigned char hex[16] = "0123456789abcdef";
- struct dns_buf dst = DNS_B_INTO(_dst, lim);
- size_t i;
-
- dns_b_fmtju(&dst, fp->algo, 0);
- dns_b_putc(&dst, ' ');
- dns_b_fmtju(&dst, fp->type, 0);
- dns_b_putc(&dst, ' ');
-
- switch (fp->type) {
- case DNS_SSHFP_SHA1:
- for (i = 0; i < sizeof fp->digest.sha1; i++) {
- dns_b_putc(&dst, hex[0x0f & (fp->digest.sha1[i] >> 4)]);
- dns_b_putc(&dst, hex[0x0f & (fp->digest.sha1[i] >> 0)]);
- }
-
- break;
- default:
- dns_b_putc(&dst, '0');
-
- break;
- } /* switch() */
-
- return dns_b_strllen(&dst);
-} /* dns_sshfp_print() */
-
-
-struct dns_txt *dns_txt_init(struct dns_txt *txt, size_t size) {
- assert(size > offsetof(struct dns_txt, data));
-
- txt->size = size - offsetof(struct dns_txt, data);
- txt->len = 0;
-
- return txt;
-} /* dns_txt_init() */
-
-
-static union dns_any *dns_txt_initany(union dns_any *any, size_t size) {
- /* NB: union dns_any is already initialized as struct dns_txt */
- (void)size;
- return any;
-} /* dns_txt_initany() */
-
-
-int dns_txt_parse(struct dns_txt *txt, struct dns_rr *rr, struct dns_packet *P) {
- struct { unsigned char *b; size_t p, end; } dst, src;
- unsigned n;
-
- dst.b = txt->data;
- dst.p = 0;
- dst.end = txt->size;
-
- src.b = P->data;
- src.p = rr->rd.p;
- src.end = src.p + rr->rd.len;
-
- while (src.p < src.end) {
- n = 0xff & P->data[src.p++];
-
- if (src.end - src.p < n || dst.end - dst.p < n)
- return DNS_EILLEGAL;
-
- memcpy(&dst.b[dst.p], &src.b[src.p], n);
-
- dst.p += n;
- src.p += n;
- }
-
- txt->len = dst.p;
-
- return 0;
-} /* dns_txt_parse() */
-
-
-int dns_txt_push(struct dns_packet *P, struct dns_txt *txt) {
- struct { unsigned char *b; size_t p, end; } dst, src;
- unsigned n;
-
- dst.b = P->data;
- dst.p = P->end;
- dst.end = P->size;
-
- src.b = txt->data;
- src.p = 0;
- src.end = txt->len;
-
- if (dst.end - dst.p < 2)
- return DNS_ENOBUFS;
-
- n = txt->len + ((txt->len + 254) / 255);
-
- dst.b[dst.p++] = 0xff & (n >> 8);
- dst.b[dst.p++] = 0xff & (n >> 0);
-
- while (src.p < src.end) {
- n = DNS_PP_MIN(255, src.end - src.p);
-
- if (dst.p >= dst.end)
- return DNS_ENOBUFS;
-
- dst.b[dst.p++] = n;
-
- if (dst.end - dst.p < n)
- return DNS_ENOBUFS;
-
- memcpy(&dst.b[dst.p], &src.b[src.p], n);
-
- dst.p += n;
- src.p += n;
- }
-
- P->end = dst.p;
-
- return 0;
-} /* dns_txt_push() */
-
-
-int dns_txt_cmp(const struct dns_txt *a, const struct dns_txt *b) {
- (void)a;
- (void)b;
-
- return -1;
-} /* dns_txt_cmp() */
-
-
-size_t dns_txt_print(void *_dst, size_t lim, struct dns_txt *txt) {
- struct dns_buf src = DNS_B_FROM(txt->data, txt->len);
- struct dns_buf dst = DNS_B_INTO(_dst, lim);
- unsigned i;
-
- if (src.p < src.pe) {
- do {
- dns_b_putc(&dst, '"');
-
- for (i = 0; i < 256 && src.p < src.pe; i++, src.p++) {
- if (*src.p < 32 || *src.p > 126 || *src.p == '"' || *src.p == '\\') {
- dns_b_putc(&dst, '\\');
- dns_b_fmtju(&dst, *src.p, 3);
- } else {
- dns_b_putc(&dst, *src.p);
- }
- }
-
- dns_b_putc(&dst, '"');
- dns_b_putc(&dst, ' ');
- } while (src.p < src.pe);
-
- dns_b_popc(&dst);
- } else {
- dns_b_putc(&dst, '"');
- dns_b_putc(&dst, '"');
- }
-
- return dns_b_strllen(&dst);
-} /* dns_txt_print() */
-
-
-static const struct dns_rrtype {
- enum dns_type type;
- const char *name;
- union dns_any *(*init)(union dns_any *, size_t);
- int (*parse)();
- int (*push)();
- int (*cmp)();
- size_t (*print)();
- size_t (*cname)();
-} dns_rrtypes[] = {
- { DNS_T_A, "A", 0, &dns_a_parse, &dns_a_push, &dns_a_cmp, &dns_a_print, 0, },
- { DNS_T_AAAA, "AAAA", 0, &dns_aaaa_parse, &dns_aaaa_push, &dns_aaaa_cmp, &dns_aaaa_print, 0, },
- { DNS_T_MX, "MX", 0, &dns_mx_parse, &dns_mx_push, &dns_mx_cmp, &dns_mx_print, &dns_mx_cname, },
- { DNS_T_NS, "NS", 0, &dns_ns_parse, &dns_ns_push, &dns_ns_cmp, &dns_ns_print, &dns_ns_cname, },
- { DNS_T_CNAME, "CNAME", 0, &dns_cname_parse, &dns_cname_push, &dns_cname_cmp, &dns_cname_print, &dns_cname_cname, },
- { DNS_T_SOA, "SOA", 0, &dns_soa_parse, &dns_soa_push, &dns_soa_cmp, &dns_soa_print, 0, },
- { DNS_T_SRV, "SRV", 0, &dns_srv_parse, &dns_srv_push, &dns_srv_cmp, &dns_srv_print, &dns_srv_cname, },
- { DNS_T_OPT, "OPT", &dns_opt_initany, &dns_opt_parse, &dns_opt_push, &dns_opt_cmp, &dns_opt_print, 0, },
- { DNS_T_PTR, "PTR", 0, &dns_ptr_parse, &dns_ptr_push, &dns_ptr_cmp, &dns_ptr_print, &dns_ptr_cname, },
- { DNS_T_TXT, "TXT", &dns_txt_initany, &dns_txt_parse, &dns_txt_push, &dns_txt_cmp, &dns_txt_print, 0, },
- { DNS_T_SPF, "SPF", &dns_txt_initany, &dns_txt_parse, &dns_txt_push, &dns_txt_cmp, &dns_txt_print, 0, },
- { DNS_T_SSHFP, "SSHFP", 0, &dns_sshfp_parse, &dns_sshfp_push, &dns_sshfp_cmp, &dns_sshfp_print, 0, },
- { DNS_T_AXFR, "AXFR", 0, 0, 0, 0, 0, 0, },
-}; /* dns_rrtypes[] */
-
-static const struct dns_rrtype *dns_rrtype(enum dns_type type) {
- const struct dns_rrtype *t;
-
- for (t = dns_rrtypes; t < endof(dns_rrtypes); t++) {
- if (t->type == type && t->parse) {
- return t;
- }
- }
-
- return NULL;
-} /* dns_rrtype() */
-
-
-union dns_any *dns_any_init(union dns_any *any, size_t size) {
- dns_static_assert(dns_same_type(any->txt, any->rdata, 1), "unexpected rdata type");
- return (union dns_any *)dns_txt_init(&any->rdata, size);
-} /* dns_any_init() */
-
-
-static size_t dns_any_sizeof(union dns_any *any) {
- dns_static_assert(dns_same_type(any->txt, any->rdata, 1), "unexpected rdata type");
- return offsetof(struct dns_txt, data) + any->rdata.size;
-} /* dns_any_sizeof() */
-
-static union dns_any *dns_any_reinit(union dns_any *any, const struct dns_rrtype *t) {
- return (t->init)? t->init(any, dns_any_sizeof(any)) : any;
-} /* dns_any_reinit() */
-
-int dns_any_parse(union dns_any *any, struct dns_rr *rr, struct dns_packet *P) {
- const struct dns_rrtype *t;
-
- if ((t = dns_rrtype(rr->type)))
- return t->parse(dns_any_reinit(any, t), rr, P);
-
- if (rr->rd.len > any->rdata.size)
- return DNS_EILLEGAL;
-
- memcpy(any->rdata.data, &P->data[rr->rd.p], rr->rd.len);
- any->rdata.len = rr->rd.len;
-
- return 0;
-} /* dns_any_parse() */
-
-
-int dns_any_push(struct dns_packet *P, union dns_any *any, enum dns_type type) {
- const struct dns_rrtype *t;
-
- if ((t = dns_rrtype(type)))
- return t->push(P, any);
-
- if (P->size - P->end < any->rdata.len + 2)
- return DNS_ENOBUFS;
-
- P->data[P->end++] = 0xff & (any->rdata.len >> 8);
- P->data[P->end++] = 0xff & (any->rdata.len >> 0);
-
- memcpy(&P->data[P->end], any->rdata.data, any->rdata.len);
- P->end += any->rdata.len;
-
- return 0;
-} /* dns_any_push() */
-
-
-int dns_any_cmp(const union dns_any *a, enum dns_type x, const union dns_any *b, enum dns_type y) {
- const struct dns_rrtype *t;
- int cmp;
-
- if ((cmp = x - y))
- return cmp;
-
- if ((t = dns_rrtype(x)))
- return t->cmp(a, b);
-
- return -1;
-} /* dns_any_cmp() */
-
-
-size_t dns_any_print(void *_dst, size_t lim, union dns_any *any, enum dns_type type) {
- const struct dns_rrtype *t;
- struct dns_buf src, dst;
-
- if ((t = dns_rrtype(type)))
- return t->print(_dst, lim, any);
-
- dns_b_from(&src, any->rdata.data, any->rdata.len);
- dns_b_into(&dst, _dst, lim);
-
- dns_b_putc(&dst, '"');
-
- while (src.p < src.pe) {
- dns_b_putc(&dst, '\\');
- dns_b_fmtju(&dst, *src.p++, 3);
- }
-
- dns_b_putc(&dst, '"');
-
- return dns_b_strllen(&dst);
-} /* dns_any_print() */
-
-
-size_t dns_any_cname(void *dst, size_t lim, union dns_any *any, enum dns_type type) {
- const struct dns_rrtype *t;
-
- if ((t = dns_rrtype(type)) && t->cname)
- return t->cname(dst, lim, any);
-
- return 0;
-} /* dns_any_cname() */
-
-
-/*
- * H O S T S R O U T I N E S
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-struct dns_hosts {
- struct dns_hosts_entry {
- char host[DNS_D_MAXNAME + 1];
- char arpa[73 + 1];
-
- int af;
-
- union {
- struct in_addr a4;
- struct in6_addr a6;
- } addr;
-
- _Bool alias;
-
- struct dns_hosts_entry *next;
- } *head, **tail;
-
- dns_atomic_t refcount;
-}; /* struct dns_hosts */
-
-
-struct dns_hosts *dns_hosts_open(int *error) {
- static const struct dns_hosts hosts_initializer = { .refcount = 1 };
- struct dns_hosts *hosts;
-
- if (!(hosts = malloc(sizeof *hosts)))
- goto syerr;
-
- *hosts = hosts_initializer;
-
- hosts->tail = &hosts->head;
-
- return hosts;
-syerr:
- *error = dns_syerr();
-
- free(hosts);
-
- return 0;
-} /* dns_hosts_open() */
-
-
-void dns_hosts_close(struct dns_hosts *hosts) {
- struct dns_hosts_entry *ent, *xnt;
-
- if (!hosts || 1 != dns_hosts_release(hosts))
- return;
-
- for (ent = hosts->head; ent; ent = xnt) {
- xnt = ent->next;
-
- free(ent);
- }
-
- free(hosts);
-
- return;
-} /* dns_hosts_close() */
-
-
-dns_refcount_t dns_hosts_acquire(struct dns_hosts *hosts) {
- return dns_atomic_fetch_add(&hosts->refcount);
-} /* dns_hosts_acquire() */
-
-
-dns_refcount_t dns_hosts_release(struct dns_hosts *hosts) {
- return dns_atomic_fetch_sub(&hosts->refcount);
-} /* dns_hosts_release() */
-
-
-struct dns_hosts *dns_hosts_mortal(struct dns_hosts *hosts) {
- if (hosts)
- dns_hosts_release(hosts);
-
- return hosts;
-} /* dns_hosts_mortal() */
-
-
-struct dns_hosts *dns_hosts_local(int *error_) {
- struct dns_hosts *hosts;
- int error;
-
- if (!(hosts = dns_hosts_open(&error)))
- goto error;
-
- if ((error = dns_hosts_loadpath(hosts, "/etc/hosts")))
- goto error;
-
- return hosts;
-error:
- *error_ = error;
-
- dns_hosts_close(hosts);
-
- return 0;
-} /* dns_hosts_local() */
-
-
-#define dns_hosts_issep(ch) (dns_isspace(ch))
-#define dns_hosts_iscom(ch) ((ch) == '#' || (ch) == ';')
-
-int dns_hosts_loadfile(struct dns_hosts *hosts, FILE *fp) {
- struct dns_hosts_entry ent;
- char word[DNS_PP_MAX(INET6_ADDRSTRLEN, DNS_D_MAXNAME) + 1];
- unsigned wp, wc, skip;
- int ch, error;
-
- rewind(fp);
-
- do {
- memset(&ent, '\0', sizeof ent);
- wc = 0;
- skip = 0;
-
- do {
- memset(word, '\0', sizeof word);
- wp = 0;
-
- while (EOF != (ch = fgetc(fp)) && ch != '\n') {
- skip |= !!dns_hosts_iscom(ch);
-
- if (skip)
- continue;
-
- if (dns_hosts_issep(ch))
- break;
-
- if (wp < sizeof word - 1)
- word[wp] = ch;
- wp++;
- }
-
- if (!wp)
- continue;
-
- wc++;
-
- switch (wc) {
- case 0:
- break;
- case 1:
- ent.af = (strchr(word, ':'))? AF_INET6 : AF_INET;
- skip = (1 != dns_inet_pton(ent.af, word, &ent.addr));
-
- break;
- default:
- if (!wp)
- break;
-
- dns_d_anchor(ent.host, sizeof ent.host, word, wp);
-
- if ((error = dns_hosts_insert(hosts, ent.af, &ent.addr, ent.host, (wc > 2))))
- return error;
-
- break;
- } /* switch() */
- } while (ch != EOF && ch != '\n');
- } while (ch != EOF);
-
- return 0;
-} /* dns_hosts_loadfile() */
-
-
-int dns_hosts_loadpath(struct dns_hosts *hosts, const char *path) {
- FILE *fp;
- int error;
-
- if (!(fp = dns_fopen(path, "rt", &error)))
- return error;
-
- error = dns_hosts_loadfile(hosts, fp);
-
- fclose(fp);
-
- return error;
-} /* dns_hosts_loadpath() */
-
-
-int dns_hosts_dump(struct dns_hosts *hosts, FILE *fp) {
- struct dns_hosts_entry *ent, *xnt;
- char addr[INET6_ADDRSTRLEN + 1];
- unsigned i;
-
- for (ent = hosts->head; ent; ent = xnt) {
- xnt = ent->next;
-
- dns_inet_ntop(ent->af, &ent->addr, addr, sizeof addr);
-
- fputs(addr, fp);
-
- for (i = strlen(addr); i < INET_ADDRSTRLEN; i++)
- fputc(' ', fp);
-
- fputc(' ', fp);
-
- fputs(ent->host, fp);
- fputc('\n', fp);
- }
-
- return 0;
-} /* dns_hosts_dump() */
-
-
-int dns_hosts_insert(struct dns_hosts *hosts, int af, const void *addr, const void *host, _Bool alias) {
- struct dns_hosts_entry *ent;
- int error;
-
- if (!(ent = malloc(sizeof *ent)))
- goto syerr;
-
- dns_d_anchor(ent->host, sizeof ent->host, host, strlen(host));
-
- switch ((ent->af = af)) {
- case AF_INET6:
- memcpy(&ent->addr.a6, addr, sizeof ent->addr.a6);
-
- dns_aaaa_arpa(ent->arpa, sizeof ent->arpa, addr);
-
- break;
- case AF_INET:
- memcpy(&ent->addr.a4, addr, sizeof ent->addr.a4);
-
- dns_a_arpa(ent->arpa, sizeof ent->arpa, addr);
-
- break;
- default:
- error = EINVAL;
-
- goto error;
- } /* switch() */
-
- ent->alias = alias;
-
- ent->next = 0;
- *hosts->tail = ent;
- hosts->tail = &ent->next;
-
- return 0;
-syerr:
- error = dns_syerr();
-error:
- free(ent);
-
- return error;
-} /* dns_hosts_insert() */
-
-
-struct dns_packet *dns_hosts_query(struct dns_hosts *hosts, struct dns_packet *Q, int *error_) {
- struct dns_packet *P = dns_p_new(512);
- struct dns_packet *A = 0;
- struct dns_rr rr;
- struct dns_hosts_entry *ent;
- int error, af;
- char qname[DNS_D_MAXNAME + 1];
- size_t qlen;
-
- if ((error = dns_rr_parse(&rr, 12, Q)))
- goto error;
-
- if (!(qlen = dns_d_expand(qname, sizeof qname, rr.dn.p, Q, &error)))
- goto error;
- else if (qlen >= sizeof qname)
- goto toolong;
-
- if ((error = dns_p_push(P, DNS_S_QD, qname, qlen, rr.type, rr.class, 0, 0)))
- goto error;
-
- switch (rr.type) {
- case DNS_T_PTR:
- for (ent = hosts->head; ent; ent = ent->next) {
- if (ent->alias || 0 != strcasecmp(qname, ent->arpa))
- continue;
-
- if ((error = dns_p_push(P, DNS_S_AN, qname, qlen, rr.type, rr.class, 0, ent->host)))
- goto error;
- }
-
- break;
- case DNS_T_AAAA:
- af = AF_INET6;
-
- goto loop;
- case DNS_T_A:
- af = AF_INET;
-
-loop: for (ent = hosts->head; ent; ent = ent->next) {
- if (ent->af != af || 0 != strcasecmp(qname, ent->host))
- continue;
-
- if ((error = dns_p_push(P, DNS_S_AN, qname, qlen, rr.type, rr.class, 0, &ent->addr)))
- goto error;
- }
-
- break;
- default:
- break;
- } /* switch() */
-
-
- if (!(A = dns_p_copy(dns_p_make(P->end, &error), P)))
- goto error;
-
- return A;
-toolong:
- error = DNS_EILLEGAL;
-error:
- *error_ = error;
-
- dns_p_free(A);
-
- return 0;
-} /* dns_hosts_query() */
-
-
-/*
- * R E S O L V . C O N F R O U T I N E S
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-struct dns_resolv_conf *dns_resconf_open(int *error) {
- static const struct dns_resolv_conf resconf_initializer = {
- .lookup = "bf",
- .family = { AF_INET, AF_INET6 },
- .options = { .ndots = 1, .timeout = 5, .attempts = 2, .tcp = DNS_RESCONF_TCP_ENABLE, },
- .iface = { .ss_family = AF_INET },
- };
- struct dns_resolv_conf *resconf;
- struct sockaddr_in *sin;
- size_t len;
-
- if (!(resconf = malloc(sizeof *resconf)))
- goto syerr;
-
- *resconf = resconf_initializer;
-
- sin = (struct sockaddr_in *)&resconf->nameserver[0];
- sin->sin_family = AF_INET;
- sin->sin_addr.s_addr = INADDR_ANY;
- sin->sin_port = htons(53);
-#if defined(SA_LEN)
- sin->sin_len = sizeof *sin;
-#endif
-
- if (0 != gethostname(resconf->search[0], sizeof resconf->search[0]))
- goto syerr;
-
- len = strlen(resconf->search[0]);
- len = dns_d_anchor(resconf->search[0], sizeof resconf->search[0], resconf->search[0], len);
- len = dns_d_cleave(resconf->search[0], sizeof resconf->search[0], resconf->search[0], len);
- if (1 == len) /* gethostname() returned a string without any label */
- resconf->search[0][0] = '\0';
-
- dns_resconf_acquire(resconf);
-
- return resconf;
-syerr:
- *error = dns_syerr();
-
- free(resconf);
-
- return 0;
-} /* dns_resconf_open() */
-
-
-void dns_resconf_close(struct dns_resolv_conf *resconf) {
- if (!resconf || 1 != dns_resconf_release(resconf))
- return /* void */;
-
- free(resconf);
-} /* dns_resconf_close() */
-
-
-dns_refcount_t dns_resconf_acquire(struct dns_resolv_conf *resconf) {
- return dns_atomic_fetch_add(&resconf->_.refcount);
-} /* dns_resconf_acquire() */
-
-
-dns_refcount_t dns_resconf_release(struct dns_resolv_conf *resconf) {
- return dns_atomic_fetch_sub(&resconf->_.refcount);
-} /* dns_resconf_release() */
-
-
-struct dns_resolv_conf *dns_resconf_mortal(struct dns_resolv_conf *resconf) {
- if (resconf)
- dns_resconf_release(resconf);
-
- return resconf;
-} /* dns_resconf_mortal() */
-
-
-struct dns_resolv_conf *dns_resconf_local(int *error_) {
- struct dns_resolv_conf *resconf;
- int error;
-
- if (!(resconf = dns_resconf_open(&error)))
- goto error;
-
- if ((error = dns_resconf_loadpath(resconf, "/etc/resolv.conf"))) {
- /*
- * NOTE: Both the glibc and BIND9 resolvers ignore a missing
- * /etc/resolv.conf, defaulting to a nameserver of
- * 127.0.0.1. See also dns_hints_insert_resconf, and the
- * default initialization of nameserver[0] in
- * dns_resconf_open.
- */
- if (error != ENOENT)
- goto error;
- }
-
- if ((error = dns_nssconf_loadpath(resconf, "/etc/nsswitch.conf"))) {
- if (error != ENOENT)
- goto error;
- }
-
- return resconf;
-error:
- *error_ = error;
-
- dns_resconf_close(resconf);
-
- return 0;
-} /* dns_resconf_local() */
-
-
-struct dns_resolv_conf *dns_resconf_root(int *error) {
- struct dns_resolv_conf *resconf;
-
- if ((resconf = dns_resconf_local(error)))
- resconf->options.recurse = 1;
-
- return resconf;
-} /* dns_resconf_root() */
-
-
-static time_t dns_resconf_timeout(const struct dns_resolv_conf *resconf) {
- return (time_t)DNS_PP_MIN(INT_MAX, resconf->options.timeout);
-} /* dns_resconf_timeout() */
-
-
-enum dns_resconf_keyword {
- DNS_RESCONF_NAMESERVER,
- DNS_RESCONF_DOMAIN,
- DNS_RESCONF_SEARCH,
- DNS_RESCONF_LOOKUP,
- DNS_RESCONF_FILE,
- DNS_RESCONF_BIND,
- DNS_RESCONF_CACHE,
- DNS_RESCONF_FAMILY,
- DNS_RESCONF_INET4,
- DNS_RESCONF_INET6,
- DNS_RESCONF_OPTIONS,
- DNS_RESCONF_EDNS0,
- DNS_RESCONF_NDOTS,
- DNS_RESCONF_TIMEOUT,
- DNS_RESCONF_ATTEMPTS,
- DNS_RESCONF_ROTATE,
- DNS_RESCONF_RECURSE,
- DNS_RESCONF_SMART,
- DNS_RESCONF_TCP,
- DNS_RESCONF_TCPx,
- DNS_RESCONF_INTERFACE,
- DNS_RESCONF_ZERO,
- DNS_RESCONF_ONE,
- DNS_RESCONF_ENABLE,
- DNS_RESCONF_ONLY,
- DNS_RESCONF_DISABLE,
-}; /* enum dns_resconf_keyword */
-
-static enum dns_resconf_keyword dns_resconf_keyword(const char *word) {
- static const char *words[] = {
- [DNS_RESCONF_NAMESERVER] = "nameserver",
- [DNS_RESCONF_DOMAIN] = "domain",
- [DNS_RESCONF_SEARCH] = "search",
- [DNS_RESCONF_LOOKUP] = "lookup",
- [DNS_RESCONF_FILE] = "file",
- [DNS_RESCONF_BIND] = "bind",
- [DNS_RESCONF_CACHE] = "cache",
- [DNS_RESCONF_FAMILY] = "family",
- [DNS_RESCONF_INET4] = "inet4",
- [DNS_RESCONF_INET6] = "inet6",
- [DNS_RESCONF_OPTIONS] = "options",
- [DNS_RESCONF_EDNS0] = "edns0",
- [DNS_RESCONF_ROTATE] = "rotate",
- [DNS_RESCONF_RECURSE] = "recurse",
- [DNS_RESCONF_SMART] = "smart",
- [DNS_RESCONF_TCP] = "tcp",
- [DNS_RESCONF_INTERFACE] = "interface",
- [DNS_RESCONF_ZERO] = "0",
- [DNS_RESCONF_ONE] = "1",
- [DNS_RESCONF_ENABLE] = "enable",
- [DNS_RESCONF_ONLY] = "only",
- [DNS_RESCONF_DISABLE] = "disable",
- };
- unsigned i;
-
- for (i = 0; i < lengthof(words); i++) {
- if (words[i] && 0 == strcasecmp(words[i], word))
- return i;
- }
-
- if (0 == strncasecmp(word, "ndots:", sizeof "ndots:" - 1))
- return DNS_RESCONF_NDOTS;
-
- if (0 == strncasecmp(word, "timeout:", sizeof "timeout:" - 1))
- return DNS_RESCONF_TIMEOUT;
-
- if (0 == strncasecmp(word, "attempts:", sizeof "attempts:" - 1))
- return DNS_RESCONF_ATTEMPTS;
-
- if (0 == strncasecmp(word, "tcp:", sizeof "tcp:" - 1))
- return DNS_RESCONF_TCPx;
-
- return -1;
-} /* dns_resconf_keyword() */
-
-
-/** OpenBSD-style "[1.2.3.4]:53" nameserver syntax */
-int dns_resconf_pton(struct sockaddr_storage *ss, const char *src) {
- struct { char buf[128], *p; } addr = { "", addr.buf };
- unsigned short port = 0;
- int ch, af = AF_INET, error;
-
- while ((ch = *src++)) {
- switch (ch) {
- case ' ':
- /* FALL THROUGH */
- case '\t':
- break;
- case '[':
- break;
- case ']':
- while ((ch = *src++)) {
- if (dns_isdigit(ch)) {
- port *= 10;
- port += ch - '0';
- }
- }
-
- goto inet;
- case ':':
- af = AF_INET6;
-
- /* FALL THROUGH */
- default:
- if (addr.p < endof(addr.buf) - 1)
- *addr.p++ = ch;
-
- break;
- } /* switch() */
- } /* while() */
-inet:
-
- if ((error = dns_pton(af, addr.buf, dns_sa_addr(af, ss, NULL))))
- return error;
-
- port = (!port)? 53 : port;
- *dns_sa_port(af, ss) = htons(port);
- dns_sa_family(ss) = af;
-
- return 0;
-} /* dns_resconf_pton() */
-
-#define dns_resconf_issep(ch) (dns_isspace(ch) || (ch) == ',')
-#define dns_resconf_iscom(ch) ((ch) == '#' || (ch) == ';')
-
-int dns_resconf_loadfile(struct dns_resolv_conf *resconf, FILE *fp) {
- unsigned sa_count = 0;
- char words[6][DNS_D_MAXNAME + 1];
- unsigned wp, wc, i, j, n;
- int ch, error;
-
- rewind(fp);
-
- do {
- memset(words, '\0', sizeof words);
- wp = 0;
- wc = 0;
-
- while (EOF != (ch = getc(fp)) && ch != '\n') {
- if (dns_resconf_issep(ch)) {
- if (wp > 0) {
- wp = 0;
-
- if (++wc >= lengthof(words))
- goto skip;
- }
- } else if (dns_resconf_iscom(ch)) {
-skip:
- do {
- ch = getc(fp);
- } while (ch != EOF && ch != '\n');
-
- break;
- } else if (wp < sizeof words[wc] - 1) {
- words[wc][wp++] = ch;
- } else {
- wp = 0; /* drop word */
- goto skip;
- }
- }
-
- if (wp > 0)
- wc++;
-
- if (wc < 2)
- continue;
-
- switch (dns_resconf_keyword(words[0])) {
- case DNS_RESCONF_NAMESERVER:
- if (sa_count >= lengthof(resconf->nameserver))
- continue;
-
- if ((error = dns_resconf_pton(&resconf->nameserver[sa_count], words[1])))
- continue;
-
- sa_count++;
-
- break;
- case DNS_RESCONF_DOMAIN:
- case DNS_RESCONF_SEARCH:
- memset(resconf->search, '\0', sizeof resconf->search);
-
- for (i = 1, j = 0; i < wc && j < lengthof(resconf->search); i++, j++)
- dns_d_anchor(resconf->search[j], sizeof resconf->search[j], words[i], strlen(words[i]));
-
- break;
- case DNS_RESCONF_LOOKUP:
- for (i = 1, j = 0; i < wc && j < lengthof(resconf->lookup); i++) {
- switch (dns_resconf_keyword(words[i])) {
- case DNS_RESCONF_FILE:
- resconf->lookup[j++] = 'f';
-
- break;
- case DNS_RESCONF_BIND:
- resconf->lookup[j++] = 'b';
-
- break;
- case DNS_RESCONF_CACHE:
- resconf->lookup[j++] = 'c';
-
- break;
- default:
- break;
- } /* switch() */
- } /* for() */
-
- break;
- case DNS_RESCONF_FAMILY:
- for (i = 1, j = 0; i < wc && j < lengthof(resconf->family); i++) {
- switch (dns_resconf_keyword(words[i])) {
- case DNS_RESCONF_INET4:
- resconf->family[j++] = AF_INET;
-
- break;
- case DNS_RESCONF_INET6:
- resconf->family[j++] = AF_INET6;
-
- break;
- default:
- break;
- }
- }
-
- break;
- case DNS_RESCONF_OPTIONS:
- for (i = 1; i < wc; i++) {
- switch (dns_resconf_keyword(words[i])) {
- case DNS_RESCONF_EDNS0:
- resconf->options.edns0 = 1;
-
- break;
- case DNS_RESCONF_NDOTS:
- for (j = sizeof "ndots:" - 1, n = 0; dns_isdigit(words[i][j]); j++) {
- n *= 10;
- n += words[i][j] - '0';
- } /* for() */
-
- resconf->options.ndots = n;
-
- break;
- case DNS_RESCONF_TIMEOUT:
- for (j = sizeof "timeout:" - 1, n = 0; dns_isdigit(words[i][j]); j++) {
- n *= 10;
- n += words[i][j] - '0';
- } /* for() */
-
- resconf->options.timeout = n;
-
- break;
- case DNS_RESCONF_ATTEMPTS:
- for (j = sizeof "attempts:" - 1, n = 0; dns_isdigit(words[i][j]); j++) {
- n *= 10;
- n += words[i][j] - '0';
- } /* for() */
-
- resconf->options.attempts = n;
-
- break;
- case DNS_RESCONF_ROTATE:
- resconf->options.rotate = 1;
-
- break;
- case DNS_RESCONF_RECURSE:
- resconf->options.recurse = 1;
-
- break;
- case DNS_RESCONF_SMART:
- resconf->options.smart = 1;
-
- break;
- case DNS_RESCONF_TCP:
- resconf->options.tcp = DNS_RESCONF_TCP_ONLY;
-
- break;
- case DNS_RESCONF_TCPx:
- switch (dns_resconf_keyword(&words[i][sizeof "tcp:" - 1])) {
- case DNS_RESCONF_ENABLE:
- resconf->options.tcp = DNS_RESCONF_TCP_ENABLE;
-
- break;
- case DNS_RESCONF_ONE:
- case DNS_RESCONF_ONLY:
- resconf->options.tcp = DNS_RESCONF_TCP_ONLY;
-
- break;
- case DNS_RESCONF_ZERO:
- case DNS_RESCONF_DISABLE:
- resconf->options.tcp = DNS_RESCONF_TCP_DISABLE;
-
- break;
- default:
- break;
- } /* switch() */
-
- break;
- default:
- break;
- } /* switch() */
- } /* for() */
-
- break;
- case DNS_RESCONF_INTERFACE:
- for (i = 0, n = 0; dns_isdigit(words[2][i]); i++) {
- n *= 10;
- n += words[2][i] - '0';
- }
-
- dns_resconf_setiface(resconf, words[1], n);
-
- break;
- default:
- break;
- } /* switch() */
- } while (ch != EOF);
-
- return 0;
-} /* dns_resconf_loadfile() */
-
-
-int dns_resconf_loadpath(struct dns_resolv_conf *resconf, const char *path) {
- FILE *fp;
- int error;
-
- if (!(fp = dns_fopen(path, "rt", &error)))
- return error;
-
- error = dns_resconf_loadfile(resconf, fp);
-
- fclose(fp);
-
- return error;
-} /* dns_resconf_loadpath() */
-
-
-struct dns_anyconf {
- char *token[16];
- unsigned count;
- char buffer[1024], *tp, *cp;
-}; /* struct dns_anyconf */
-
-
-static void dns_anyconf_reset(struct dns_anyconf *cf) {
- cf->count = 0;
- cf->tp = cf->cp = cf->buffer;
-} /* dns_anyconf_reset() */
-
-
-static int dns_anyconf_push(struct dns_anyconf *cf) {
- if (!(cf->cp < endof(cf->buffer) && cf->count < lengthof(cf->token)))
- return ENOMEM;
-
- *cf->cp++ = '\0';
- cf->token[cf->count++] = cf->tp;
- cf->tp = cf->cp;
-
- return 0;
-} /* dns_anyconf_push() */
-
-
-static void dns_anyconf_pop(struct dns_anyconf *cf) {
- if (cf->count > 0) {
- --cf->count;
- cf->tp = cf->cp = cf->token[cf->count];
- cf->token[cf->count] = 0;
- }
-} /* dns_anyconf_pop() */
-
-
-static int dns_anyconf_addc(struct dns_anyconf *cf, int ch) {
- if (!(cf->cp < endof(cf->buffer)))
- return ENOMEM;
-
- *cf->cp++ = ch;
-
- return 0;
-} /* dns_anyconf_addc() */
-
-
-static _Bool dns_anyconf_match(const char *pat, int mc) {
- _Bool match;
- int pc;
-
- if (*pat == '^') {
- match = 0;
- ++pat;
- } else {
- match = 1;
- }
-
- while ((pc = *(const unsigned char *)pat++)) {
- switch (pc) {
- case '%':
- if (!(pc = *(const unsigned char *)pat++))
- return !match;
-
- switch (pc) {
- case 'a':
- if (dns_isalpha(mc))
- return match;
- break;
- case 'd':
- if (dns_isdigit(mc))
- return match;
- break;
- case 'w':
- if (dns_isalnum(mc))
- return match;
- break;
- case 's':
- if (dns_isspace(mc))
- return match;
- break;
- default:
- if (mc == pc)
- return match;
- break;
- } /* switch() */
-
- break;
- default:
- if (mc == pc)
- return match;
- break;
- } /* switch() */
- } /* while() */
-
- return !match;
-} /* dns_anyconf_match() */
-
-
-static int dns_anyconf_peek(FILE *fp) {
- int ch;
- ch = getc(fp);
- ungetc(ch, fp);
- return ch;
-} /* dns_anyconf_peek() */
-
-
-static size_t dns_anyconf_skip(const char *pat, FILE *fp) {
- size_t count = 0;
- int ch;
-
- while (EOF != (ch = getc(fp))) {
- if (dns_anyconf_match(pat, ch)) {
- count++;
- continue;
- }
-
- ungetc(ch, fp);
-
- break;
- }
-
- return count;
-} /* dns_anyconf_skip() */
-
-
-static size_t dns_anyconf_scan(struct dns_anyconf *cf, const char *pat, FILE *fp, int *error) {
- size_t len;
- int ch;
-
- while (EOF != (ch = getc(fp))) {
- if (dns_anyconf_match(pat, ch)) {
- if ((*error = dns_anyconf_addc(cf, ch)))
- return 0;
-
- continue;
- } else {
- ungetc(ch, fp);
-
- break;
- }
- }
-
- if ((len = cf->cp - cf->tp)) {
- if ((*error = dns_anyconf_push(cf)))
- return 0;
-
- return len;
- } else {
- *error = 0;
-
- return 0;
- }
-} /* dns_anyconf_scan() */
-
-
-DNS_NOTUSED static void dns_anyconf_dump(struct dns_anyconf *cf, FILE *fp) {
- unsigned i;
-
- fprintf(fp, "tokens:");
-
- for (i = 0; i < cf->count; i++) {
- fprintf(fp, " %s", cf->token[i]);
- }
-
- fputc('\n', fp);
-} /* dns_anyconf_dump() */
-
-
-enum dns_nssconf_keyword {
- DNS_NSSCONF_INVALID = 0,
- DNS_NSSCONF_HOSTS = 1,
- DNS_NSSCONF_SUCCESS,
- DNS_NSSCONF_NOTFOUND,
- DNS_NSSCONF_UNAVAIL,
- DNS_NSSCONF_TRYAGAIN,
- DNS_NSSCONF_CONTINUE,
- DNS_NSSCONF_RETURN,
- DNS_NSSCONF_FILES,
- DNS_NSSCONF_DNS,
- DNS_NSSCONF_MDNS,
-
- DNS_NSSCONF_LAST,
-}; /* enum dns_nssconf_keyword */
-
-static enum dns_nssconf_keyword dns_nssconf_keyword(const char *word) {
- static const char *list[] = {
- [DNS_NSSCONF_HOSTS] = "hosts",
- [DNS_NSSCONF_SUCCESS] = "success",
- [DNS_NSSCONF_NOTFOUND] = "notfound",
- [DNS_NSSCONF_UNAVAIL] = "unavail",
- [DNS_NSSCONF_TRYAGAIN] = "tryagain",
- [DNS_NSSCONF_CONTINUE] = "continue",
- [DNS_NSSCONF_RETURN] = "return",
- [DNS_NSSCONF_FILES] = "files",
- [DNS_NSSCONF_DNS] = "dns",
- [DNS_NSSCONF_MDNS] = "mdns",
- };
- unsigned i;
-
- for (i = 1; i < lengthof(list); i++) {
- if (list[i] && 0 == strcasecmp(list[i], word))
- return i;
- }
-
- return DNS_NSSCONF_INVALID;
-} /* dns_nssconf_keyword() */
-
-
-static enum dns_nssconf_keyword dns_nssconf_c2k(int ch) {
- static const char map[] = {
- ['S'] = DNS_NSSCONF_SUCCESS,
- ['N'] = DNS_NSSCONF_NOTFOUND,
- ['U'] = DNS_NSSCONF_UNAVAIL,
- ['T'] = DNS_NSSCONF_TRYAGAIN,
- ['C'] = DNS_NSSCONF_CONTINUE,
- ['R'] = DNS_NSSCONF_RETURN,
- ['f'] = DNS_NSSCONF_FILES,
- ['F'] = DNS_NSSCONF_FILES,
- ['d'] = DNS_NSSCONF_DNS,
- ['D'] = DNS_NSSCONF_DNS,
- ['b'] = DNS_NSSCONF_DNS,
- ['B'] = DNS_NSSCONF_DNS,
- ['m'] = DNS_NSSCONF_MDNS,
- ['M'] = DNS_NSSCONF_MDNS,
- };
-
- return (ch >= 0 && ch < (int)lengthof(map))? map[ch] : DNS_NSSCONF_INVALID;
-} /* dns_nssconf_c2k() */
-
-
-DNS_PRAGMA_PUSH
-DNS_PRAGMA_QUIET
-
-static int dns_nssconf_k2c(int k) {
- static const char map[DNS_NSSCONF_LAST] = {
- [DNS_NSSCONF_SUCCESS] = 'S',
- [DNS_NSSCONF_NOTFOUND] = 'N',
- [DNS_NSSCONF_UNAVAIL] = 'U',
- [DNS_NSSCONF_TRYAGAIN] = 'T',
- [DNS_NSSCONF_CONTINUE] = 'C',
- [DNS_NSSCONF_RETURN] = 'R',
- [DNS_NSSCONF_FILES] = 'f',
- [DNS_NSSCONF_DNS] = 'b',
- [DNS_NSSCONF_MDNS] = 'm',
- };
-
- return (k >= 0 && k < (int)lengthof(map))? (map[k]? map[k] : '?') : '?';
-} /* dns_nssconf_k2c() */
-
-static const char *dns_nssconf_k2s(int k) {
- static const char *const map[DNS_NSSCONF_LAST] = {
- [DNS_NSSCONF_SUCCESS] = "SUCCESS",
- [DNS_NSSCONF_NOTFOUND] = "NOTFOUND",
- [DNS_NSSCONF_UNAVAIL] = "UNAVAIL",
- [DNS_NSSCONF_TRYAGAIN] = "TRYAGAIN",
- [DNS_NSSCONF_CONTINUE] = "continue",
- [DNS_NSSCONF_RETURN] = "return",
- [DNS_NSSCONF_FILES] = "files",
- [DNS_NSSCONF_DNS] = "dns",
- [DNS_NSSCONF_MDNS] = "mdns",
- };
-
- return (k >= 0 && k < (int)lengthof(map))? (map[k]? map[k] : "") : "";
-} /* dns_nssconf_k2s() */
-
-DNS_PRAGMA_POP
-
-
-int dns_nssconf_loadfile(struct dns_resolv_conf *resconf, FILE *fp) {
- enum dns_nssconf_keyword source, status, action;
- char lookup[sizeof resconf->lookup] = "", *lp;
- struct dns_anyconf cf;
- size_t i;
- int error;
-
- while (!feof(fp) && !ferror(fp)) {
- dns_anyconf_reset(&cf);
-
- dns_anyconf_skip("%s", fp);
-
- if (!dns_anyconf_scan(&cf, "%w_", fp, &error))
- goto nextent;
-
- if (DNS_NSSCONF_HOSTS != dns_nssconf_keyword(cf.token[0]))
- goto nextent;
-
- dns_anyconf_pop(&cf);
-
- if (!dns_anyconf_skip(": \t", fp))
- goto nextent;
-
- *(lp = lookup) = '\0';
-
- while (dns_anyconf_scan(&cf, "%w_", fp, &error)) {
- dns_anyconf_skip(" \t", fp);
-
- if ('[' == dns_anyconf_peek(fp)) {
- dns_anyconf_skip("[! \t", fp);
-
- while (dns_anyconf_scan(&cf, "%w_", fp, &error)) {
- dns_anyconf_skip("= \t", fp);
- if (!dns_anyconf_scan(&cf, "%w_", fp, &error)) {
- dns_anyconf_pop(&cf); /* discard status */
- dns_anyconf_skip("^#;]\n", fp); /* skip to end of criteria */
- break;
- }
- dns_anyconf_skip(" \t", fp);
- }
-
- dns_anyconf_skip("] \t", fp);
- }
-
- if ((size_t)(endof(lookup) - lp) < cf.count + 1) /* +1 for '\0' */
- goto nextsrc;
-
- source = dns_nssconf_keyword(cf.token[0]);
-
- switch (source) {
- case DNS_NSSCONF_DNS:
- case DNS_NSSCONF_MDNS:
- case DNS_NSSCONF_FILES:
- *lp++ = dns_nssconf_k2c(source);
- break;
- default:
- goto nextsrc;
- }
-
- for (i = 1; i + 1 < cf.count; i += 2) {
- status = dns_nssconf_keyword(cf.token[i]);
- action = dns_nssconf_keyword(cf.token[i + 1]);
-
- switch (status) {
- case DNS_NSSCONF_SUCCESS:
- case DNS_NSSCONF_NOTFOUND:
- case DNS_NSSCONF_UNAVAIL:
- case DNS_NSSCONF_TRYAGAIN:
- *lp++ = dns_nssconf_k2c(status);
- break;
- default:
- continue;
- }
-
- switch (action) {
- case DNS_NSSCONF_CONTINUE:
- case DNS_NSSCONF_RETURN:
- break;
- default:
- action = (status == DNS_NSSCONF_SUCCESS)
- ? DNS_NSSCONF_RETURN
- : DNS_NSSCONF_CONTINUE;
- break;
- }
-
- *lp++ = dns_nssconf_k2c(action);
- }
-nextsrc:
- *lp = '\0';
- dns_anyconf_reset(&cf);
- }
-nextent:
- dns_anyconf_skip("^\n", fp);
- }
-
- if (*lookup)
- strncpy(resconf->lookup, lookup, sizeof resconf->lookup);
-
- return 0;
-} /* dns_nssconf_loadfile() */
-
-
-int dns_nssconf_loadpath(struct dns_resolv_conf *resconf, const char *path) {
- FILE *fp;
- int error;
-
- if (!(fp = dns_fopen(path, "rt", &error)))
- return error;
-
- error = dns_nssconf_loadfile(resconf, fp);
-
- fclose(fp);
-
- return error;
-} /* dns_nssconf_loadpath() */
-
-
-struct dns_nssconf_source {
- enum dns_nssconf_keyword source, success, notfound, unavail, tryagain;
-}; /* struct dns_nssconf_source */
-
-typedef unsigned dns_nssconf_i;
-
-static inline int dns_nssconf_peek(const struct dns_resolv_conf *resconf, dns_nssconf_i state) {
- return (state < lengthof(resconf->lookup) && resconf->lookup[state])? resconf->lookup[state] : 0;
-} /* dns_nssconf_peek() */
-
-static _Bool dns_nssconf_next(struct dns_nssconf_source *src, const struct dns_resolv_conf *resconf, dns_nssconf_i *state) {
- int source, status, action;
-
- src->source = DNS_NSSCONF_INVALID;
- src->success = DNS_NSSCONF_RETURN;
- src->notfound = DNS_NSSCONF_CONTINUE;
- src->unavail = DNS_NSSCONF_CONTINUE;
- src->tryagain = DNS_NSSCONF_CONTINUE;
-
- while ((source = dns_nssconf_peek(resconf, *state))) {
- source = dns_nssconf_c2k(source);
- ++*state;
-
- switch (source) {
- case DNS_NSSCONF_FILES:
- case DNS_NSSCONF_DNS:
- case DNS_NSSCONF_MDNS:
- src->source = source;
- break;
- default:
- continue;
- }
-
- while ((status = dns_nssconf_peek(resconf, *state)) && (action = dns_nssconf_peek(resconf, *state + 1))) {
- status = dns_nssconf_c2k(status);
- action = dns_nssconf_c2k(action);
-
- switch (action) {
- case DNS_NSSCONF_RETURN:
- case DNS_NSSCONF_CONTINUE:
- break;
- default:
- goto done;
- }
-
- switch (status) {
- case DNS_NSSCONF_SUCCESS:
- src->success = action;
- break;
- case DNS_NSSCONF_NOTFOUND:
- src->notfound = action;
- break;
- case DNS_NSSCONF_UNAVAIL:
- src->unavail = action;
- break;
- case DNS_NSSCONF_TRYAGAIN:
- src->tryagain = action;
- break;
- default:
- goto done;
- }
-
- *state += 2;
- }
-
- break;
- }
-done:
- return src->source != DNS_NSSCONF_INVALID;
-} /* dns_nssconf_next() */
-
-
-static int dns_nssconf_dump_status(int status, int action, unsigned *count, FILE *fp) {
- switch (status) {
- case DNS_NSSCONF_SUCCESS:
- if (action == DNS_NSSCONF_RETURN)
- return 0;
- break;
- default:
- if (action == DNS_NSSCONF_CONTINUE)
- return 0;
- break;
- }
-
- fputc(' ', fp);
-
- if (!*count)
- fputc('[', fp);
-
- fprintf(fp, "%s=%s", dns_nssconf_k2s(status), dns_nssconf_k2s(action));
-
- ++*count;
-
- return 0;
-} /* dns_nssconf_dump_status() */
-
-
-int dns_nssconf_dump(struct dns_resolv_conf *resconf, FILE *fp) {
- struct dns_nssconf_source src;
- dns_nssconf_i i = 0;
-
- fputs("hosts:", fp);
-
- while (dns_nssconf_next(&src, resconf, &i)) {
- unsigned n = 0;
-
- fprintf(fp, " %s", dns_nssconf_k2s(src.source));
-
- dns_nssconf_dump_status(DNS_NSSCONF_SUCCESS, src.success, &n, fp);
- dns_nssconf_dump_status(DNS_NSSCONF_NOTFOUND, src.notfound, &n, fp);
- dns_nssconf_dump_status(DNS_NSSCONF_UNAVAIL, src.unavail, &n, fp);
- dns_nssconf_dump_status(DNS_NSSCONF_TRYAGAIN, src.tryagain, &n, fp);
-
- if (n)
- fputc(']', fp);
- }
-
- fputc('\n', fp);
-
- return 0;
-} /* dns_nssconf_dump() */
-
-
-int dns_resconf_setiface(struct dns_resolv_conf *resconf, const char *addr, unsigned short port) {
- int af = (strchr(addr, ':'))? AF_INET6 : AF_INET;
- int error;
-
- if ((error = dns_pton(af, addr, dns_sa_addr(af, &resconf->iface, NULL))))
- return error;
-
- *dns_sa_port(af, &resconf->iface) = htons(port);
- resconf->iface.ss_family = af;
-
- return 0;
-} /* dns_resconf_setiface() */
-
-
-#define DNS_SM_RESTORE \
- do { \
- pc = 0xff & (*state >> 0); \
- srchi = 0xff & (*state >> 8); \
- ndots = 0xff & (*state >> 16); \
- } while (0)
-
-#define DNS_SM_SAVE \
- do { \
- *state = ((0xff & pc) << 0) \
- | ((0xff & srchi) << 8) \
- | ((0xff & ndots) << 16); \
- } while (0)
-
-size_t dns_resconf_search(void *dst, size_t lim, const void *qname, size_t qlen, struct dns_resolv_conf *resconf, dns_resconf_i_t *state) {
- unsigned pc, srchi, ndots, len;
-
- DNS_SM_ENTER;
-
- /* if FQDN then return as-is and finish */
- if (dns_d_isanchored(qname, qlen)) {
- len = dns_d_anchor(dst, lim, qname, qlen);
- DNS_SM_YIELD(len);
- DNS_SM_EXIT;
- }
-
- ndots = dns_d_ndots(qname, qlen);
-
- if (ndots >= resconf->options.ndots) {
- len = dns_d_anchor(dst, lim, qname, qlen);
- DNS_SM_YIELD(len);
- }
-
- while (srchi < lengthof(resconf->search) && resconf->search[srchi][0]) {
- struct dns_buf buf = DNS_B_INTO(dst, lim);
- const char *dn = resconf->search[srchi++];
-
- dns_b_put(&buf, qname, qlen);
- dns_b_putc(&buf, '.');
- dns_b_puts(&buf, dn);
- if (!dns_d_isanchored(dn, strlen(dn)))
- dns_b_putc(&buf, '.');
- len = dns_b_strllen(&buf);
- DNS_SM_YIELD(len);
- }
-
- if (ndots < resconf->options.ndots) {
- len = dns_d_anchor(dst, lim, qname, qlen);
- DNS_SM_YIELD(len);
- }
-
- DNS_SM_LEAVE;
-
- return dns_strlcpy(dst, "", lim);
-} /* dns_resconf_search() */
-
-#undef DNS_SM_SAVE
-#undef DNS_SM_RESTORE
-
-
-int dns_resconf_dump(struct dns_resolv_conf *resconf, FILE *fp) {
- unsigned i;
- int af;
-
- for (i = 0; i < lengthof(resconf->nameserver) && (af = resconf->nameserver[i].ss_family) != AF_UNSPEC; i++) {
- char addr[INET6_ADDRSTRLEN + 1] = "[INVALID]";
- unsigned short port;
-
- dns_inet_ntop(af, dns_sa_addr(af, &resconf->nameserver[i], NULL), addr, sizeof addr);
- port = ntohs(*dns_sa_port(af, &resconf->nameserver[i]));
-
- if (port == 53)
- fprintf(fp, "nameserver %s\n", addr);
- else
- fprintf(fp, "nameserver [%s]:%hu\n", addr, port);
- }
-
-
- fprintf(fp, "search");
-
- for (i = 0; i < lengthof(resconf->search) && resconf->search[i][0]; i++)
- fprintf(fp, " %s", resconf->search[i]);
-
- fputc('\n', fp);
-
-
- fputs("; ", fp);
- dns_nssconf_dump(resconf, fp);
-
- fprintf(fp, "lookup");
-
- for (i = 0; i < lengthof(resconf->lookup) && resconf->lookup[i]; i++) {
- switch (resconf->lookup[i]) {
- case 'b':
- fprintf(fp, " bind"); break;
- case 'f':
- fprintf(fp, " file"); break;
- case 'c':
- fprintf(fp, " cache"); break;
- }
- }
-
- fputc('\n', fp);
-
-
- fprintf(fp, "options ndots:%u timeout:%u attempts:%u", resconf->options.ndots, resconf->options.timeout, resconf->options.attempts);
-
- if (resconf->options.edns0)
- fprintf(fp, " edns0");
- if (resconf->options.rotate)
- fprintf(fp, " rotate");
- if (resconf->options.recurse)
- fprintf(fp, " recurse");
- if (resconf->options.smart)
- fprintf(fp, " smart");
-
- switch (resconf->options.tcp) {
- case DNS_RESCONF_TCP_ENABLE:
- break;
- case DNS_RESCONF_TCP_ONLY:
- fprintf(fp, " tcp");
- break;
- case DNS_RESCONF_TCP_DISABLE:
- fprintf(fp, " tcp:disable");
- break;
- }
-
- fputc('\n', fp);
-
-
- if ((af = resconf->iface.ss_family) != AF_UNSPEC) {
- char addr[INET6_ADDRSTRLEN + 1] = "[INVALID]";
-
- dns_inet_ntop(af, dns_sa_addr(af, &resconf->iface, NULL), addr, sizeof addr);
-
- fprintf(fp, "interface %s %hu\n", addr, ntohs(*dns_sa_port(af, &resconf->iface)));
- }
-
- return 0;
-} /* dns_resconf_dump() */
-
-
-/*
- * H I N T S E R V E R R O U T I N E S
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-struct dns_hints_soa {
- unsigned char zone[DNS_D_MAXNAME + 1];
-
- struct {
- struct sockaddr_storage ss;
- unsigned priority;
- } addrs[16];
-
- unsigned count;
-
- struct dns_hints_soa *next;
-}; /* struct dns_hints_soa */
-
-
-struct dns_hints {
- dns_atomic_t refcount;
-
- struct dns_hints_soa *head;
-}; /* struct dns_hints */
-
-
-struct dns_hints *dns_hints_open(struct dns_resolv_conf *resconf, int *error) {
- static const struct dns_hints H_initializer;
- struct dns_hints *H;
-
- (void)resconf;
-
- if (!(H = malloc(sizeof *H)))
- goto syerr;
-
- *H = H_initializer;
-
- dns_hints_acquire(H);
-
- return H;
-syerr:
- *error = dns_syerr();
-
- free(H);
-
- return 0;
-} /* dns_hints_open() */
-
-
-void dns_hints_close(struct dns_hints *H) {
- struct dns_hints_soa *soa, *nxt;
-
- if (!H || 1 != dns_hints_release(H))
- return /* void */;
-
- for (soa = H->head; soa; soa = nxt) {
- nxt = soa->next;
-
- free(soa);
- }
-
- free(H);
-
- return /* void */;
-} /* dns_hints_close() */
-
-
-dns_refcount_t dns_hints_acquire(struct dns_hints *H) {
- return dns_atomic_fetch_add(&H->refcount);
-} /* dns_hints_acquire() */
-
-
-dns_refcount_t dns_hints_release(struct dns_hints *H) {
- return dns_atomic_fetch_sub(&H->refcount);
-} /* dns_hints_release() */
-
-
-struct dns_hints *dns_hints_mortal(struct dns_hints *hints) {
- if (hints)
- dns_hints_release(hints);
-
- return hints;
-} /* dns_hints_mortal() */
-
-
-struct dns_hints *dns_hints_local(struct dns_resolv_conf *resconf, int *error_) {
- struct dns_hints *hints = 0;
- int error;
-
- if (resconf)
- dns_resconf_acquire(resconf);
- else if (!(resconf = dns_resconf_local(&error)))
- goto error;
-
- if (!(hints = dns_hints_open(resconf, &error)))
- goto error;
-
- error = 0;
-
- if (0 == dns_hints_insert_resconf(hints, ".", resconf, &error) && error)
- goto error;
-
- dns_resconf_close(resconf);
-
- return hints;
-error:
- *error_ = error;
-
- dns_resconf_close(resconf);
- dns_hints_close(hints);
-
- return 0;
-} /* dns_hints_local() */
-
-
-struct dns_hints *dns_hints_root(struct dns_resolv_conf *resconf, int *error_) {
- static const struct {
- int af;
- char addr[INET6_ADDRSTRLEN];
- } root_hints[] = {
- { AF_INET, "198.41.0.4" }, /* A.ROOT-SERVERS.NET. */
- { AF_INET6, "2001:503:ba3e::2:30" }, /* A.ROOT-SERVERS.NET. */
- { AF_INET, "192.228.79.201" }, /* B.ROOT-SERVERS.NET. */
- { AF_INET6, "2001:500:84::b" }, /* B.ROOT-SERVERS.NET. */
- { AF_INET, "192.33.4.12" }, /* C.ROOT-SERVERS.NET. */
- { AF_INET6, "2001:500:2::c" }, /* C.ROOT-SERVERS.NET. */
- { AF_INET, "199.7.91.13" }, /* D.ROOT-SERVERS.NET. */
- { AF_INET6, "2001:500:2d::d" }, /* D.ROOT-SERVERS.NET. */
- { AF_INET, "192.203.230.10" }, /* E.ROOT-SERVERS.NET. */
- { AF_INET, "192.5.5.241" }, /* F.ROOT-SERVERS.NET. */
- { AF_INET6, "2001:500:2f::f" }, /* F.ROOT-SERVERS.NET. */
- { AF_INET, "192.112.36.4" }, /* G.ROOT-SERVERS.NET. */
- { AF_INET, "128.63.2.53" }, /* H.ROOT-SERVERS.NET. */
- { AF_INET6, "2001:500:1::803f:235" }, /* H.ROOT-SERVERS.NET. */
- { AF_INET, "192.36.148.17" }, /* I.ROOT-SERVERS.NET. */
- { AF_INET6, "2001:7FE::53" }, /* I.ROOT-SERVERS.NET. */
- { AF_INET, "192.58.128.30" }, /* J.ROOT-SERVERS.NET. */
- { AF_INET6, "2001:503:c27::2:30" }, /* J.ROOT-SERVERS.NET. */
- { AF_INET, "193.0.14.129" }, /* K.ROOT-SERVERS.NET. */
- { AF_INET6, "2001:7FD::1" }, /* K.ROOT-SERVERS.NET. */
- { AF_INET, "199.7.83.42" }, /* L.ROOT-SERVERS.NET. */
- { AF_INET6, "2001:500:3::42" }, /* L.ROOT-SERVERS.NET. */
- { AF_INET, "202.12.27.33" }, /* M.ROOT-SERVERS.NET. */
- { AF_INET6, "2001:DC3::35" }, /* M.ROOT-SERVERS.NET. */
- };
- struct dns_hints *hints = 0;
- struct sockaddr_storage ss;
- unsigned i;
- int error, af;
-
- if (!(hints = dns_hints_open(resconf, &error)))
- goto error;
-
- for (i = 0; i < lengthof(root_hints); i++) {
- af = root_hints[i].af;
-
- if ((error = dns_pton(af, root_hints[i].addr, dns_sa_addr(af, &ss, NULL))))
- goto error;
-
- *dns_sa_port(af, &ss) = htons(53);
- ss.ss_family = af;
-
- if ((error = dns_hints_insert(hints, ".", (struct sockaddr *)&ss, 1)))
- goto error;
- }
-
- return hints;
-error:
- *error_ = error;
-
- dns_hints_close(hints);
-
- return 0;
-} /* dns_hints_root() */
-
-
-static struct dns_hints_soa *dns_hints_fetch(struct dns_hints *H, const char *zone) {
- struct dns_hints_soa *soa;
-
- for (soa = H->head; soa; soa = soa->next) {
- if (0 == strcasecmp(zone, (char *)soa->zone))
- return soa;
- }
-
- return 0;
-} /* dns_hints_fetch() */
-
-
-int dns_hints_insert(struct dns_hints *H, const char *zone, const struct sockaddr *sa, unsigned priority) {
- static const struct dns_hints_soa soa_initializer;
- struct dns_hints_soa *soa;
- unsigned i;
-
- if (!(soa = dns_hints_fetch(H, zone))) {
- if (!(soa = malloc(sizeof *soa)))
- return dns_syerr();
- *soa = soa_initializer;
- dns_strlcpy((char *)soa->zone, zone, sizeof soa->zone);
-
- soa->next = H->head;
- H->head = soa;
- }
-
- i = soa->count % lengthof(soa->addrs);
-
- memcpy(&soa->addrs[i].ss, sa, dns_sa_len(sa));
-
- soa->addrs[i].priority = DNS_PP_MAX(1, priority);
-
- if (soa->count < lengthof(soa->addrs))
- soa->count++;
-
- return 0;
-} /* dns_hints_insert() */
-
-
-static _Bool dns_hints_isinaddr_any(void *sa) {
- struct in_addr *addr;
-
- if (dns_sa_family(sa) != AF_INET)
- return 0;
-
- addr = dns_sa_addr(AF_INET, sa, NULL);
- return addr->s_addr == htonl(INADDR_ANY);
-}
-
-unsigned dns_hints_insert_resconf(struct dns_hints *H, const char *zone, struct dns_resolv_conf *resconf, int *error_) {
- unsigned i, n, p;
- int error;
-
- for (i = 0, n = 0, p = 1; i < lengthof(resconf->nameserver) && resconf->nameserver[i].ss_family != AF_UNSPEC; i++, n++) {
- union { struct sockaddr_in sin; } tmp;
- struct sockaddr *ns;
-
- /*
- * dns_resconf_open initializes nameserver[0] to INADDR_ANY.
- *
- * Traditionally the semantics of 0.0.0.0 meant the default
- * interface, which evolved to mean the loopback interface.
- * See comment block preceding resolv/res_init.c:res_init in
- * glibc 2.23. As of 2.23, glibc no longer translates
- * 0.0.0.0 despite the code comment, but it does default to
- * 127.0.0.1 when no nameservers are present.
- *
- * BIND9 as of 9.10.3 still translates 0.0.0.0 to 127.0.0.1.
- * See lib/lwres/lwconfig.c:lwres_create_addr and the
- * convert_zero flag. 127.0.0.1 is also the default when no
- * nameservers are present.
- */
- if (dns_hints_isinaddr_any(&resconf->nameserver[i])) {
- memcpy(&tmp.sin, &resconf->nameserver[i], sizeof tmp.sin);
- tmp.sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- ns = (struct sockaddr *)&tmp.sin;
- } else {
- ns = (struct sockaddr *)&resconf->nameserver[i];
- }
-
- if ((error = dns_hints_insert(H, zone, ns, p)))
- goto error;
-
- p += !resconf->options.rotate;
- }
-
- return n;
-error:
- *error_ = error;
-
- return n;
-} /* dns_hints_insert_resconf() */
-
-
-static int dns_hints_i_cmp(unsigned a, unsigned b, struct dns_hints_i *i, struct dns_hints_soa *soa) {
- int cmp;
-
- if ((cmp = soa->addrs[a].priority - soa->addrs[b].priority))
- return cmp;
-
- return dns_k_shuffle16(a, i->state.seed) - dns_k_shuffle16(b, i->state.seed);
-} /* dns_hints_i_cmp() */
-
-
-static unsigned dns_hints_i_start(struct dns_hints_i *i, struct dns_hints_soa *soa) {
- unsigned p0, p;
-
- p0 = 0;
-
- for (p = 1; p < soa->count; p++) {
- if (dns_hints_i_cmp(p, p0, i, soa) < 0)
- p0 = p;
- }
-
- return p0;
-} /* dns_hints_i_start() */
-
-
-static unsigned dns_hints_i_skip(unsigned p0, struct dns_hints_i *i, struct dns_hints_soa *soa) {
- unsigned pZ, p;
-
- for (pZ = 0; pZ < soa->count; pZ++) {
- if (dns_hints_i_cmp(pZ, p0, i, soa) > 0)
- goto cont;
- }
-
- return soa->count;
-cont:
- for (p = pZ + 1; p < soa->count; p++) {
- if (dns_hints_i_cmp(p, p0, i, soa) <= 0)
- continue;
-
- if (dns_hints_i_cmp(p, pZ, i, soa) >= 0)
- continue;
-
- pZ = p;
- }
-
-
- return pZ;
-} /* dns_hints_i_skip() */
-
-
-static struct dns_hints_i *dns_hints_i_init(struct dns_hints_i *i, struct dns_hints *hints) {
- static const struct dns_hints_i i_initializer;
- struct dns_hints_soa *soa;
-
- i->state = i_initializer.state;
-
- do {
- i->state.seed = dns_random();
- } while (0 == i->state.seed);
-
- if ((soa = dns_hints_fetch(hints, i->zone))) {
- i->state.next = dns_hints_i_start(i, soa);
- }
-
- return i;
-} /* dns_hints_i_init() */
-
-
-unsigned dns_hints_grep(struct sockaddr **sa, socklen_t *sa_len, unsigned lim, struct dns_hints_i *i, struct dns_hints *H) {
- struct dns_hints_soa *soa;
- unsigned n;
-
- if (!(soa = dns_hints_fetch(H, i->zone)))
- return 0;
-
- n = 0;
-
- while (i->state.next < soa->count && n < lim) {
- *sa = (struct sockaddr *)&soa->addrs[i->state.next].ss;
- *sa_len = dns_sa_len(*sa);
-
- sa++;
- sa_len++;
- n++;
-
- i->state.next = dns_hints_i_skip(i->state.next, i, soa);
- }
-
- return n;
-} /* dns_hints_grep() */
-
-
-struct dns_packet *dns_hints_query(struct dns_hints *hints, struct dns_packet *Q, int *error_) {
- struct dns_packet *A, *P;
- struct dns_rr rr;
- char zone[DNS_D_MAXNAME + 1];
- size_t zlen;
- struct dns_hints_i i;
- struct sockaddr *sa;
- socklen_t slen;
- int error;
-
- if (!dns_rr_grep(&rr, 1, dns_rr_i_new(Q, .section = DNS_S_QUESTION), Q, &error))
- goto error;
-
- if (!(zlen = dns_d_expand(zone, sizeof zone, rr.dn.p, Q, &error)))
- goto error;
- else if (zlen >= sizeof zone)
- goto toolong;
-
- P = dns_p_new(512);
- DNS_HEADER(P)->qr = 1;
-
- if ((error = dns_rr_copy(P, &rr, Q)))
- goto error;
-
- if ((error = dns_p_push(P, DNS_S_AUTHORITY, ".", strlen("."), DNS_T_NS, DNS_C_IN, 0, "hints.local.")))
- goto error;
-
- do {
- i.zone = zone;
-
- dns_hints_i_init(&i, hints);
-
- while (dns_hints_grep(&sa, &slen, 1, &i, hints)) {
- int af = sa->sa_family;
- int rtype = (af == AF_INET6)? DNS_T_AAAA : DNS_T_A;
-
- if ((error = dns_p_push(P, DNS_S_ADDITIONAL, "hints.local.", strlen("hints.local."), rtype, DNS_C_IN, 0, dns_sa_addr(af, sa, NULL))))
- goto error;
- }
- } while ((zlen = dns_d_cleave(zone, sizeof zone, zone, zlen)));
-
- if (!(A = dns_p_copy(dns_p_make(P->end, &error), P)))
- goto error;
-
- return A;
-toolong:
- error = DNS_EILLEGAL;
-error:
- *error_ = error;
-
- return 0;
-} /* dns_hints_query() */
-
-
-/** ugly hack to support specifying ports other than 53 in resolv.conf. */
-static unsigned short dns_hints_port(struct dns_hints *hints, int af, void *addr) {
- struct dns_hints_soa *soa;
- void *addrsoa;
- socklen_t addrlen;
- unsigned short port;
- unsigned i;
-
- for (soa = hints->head; soa; soa = soa->next) {
- for (i = 0; i < soa->count; i++) {
- if (af != soa->addrs[i].ss.ss_family)
- continue;
-
- if (!(addrsoa = dns_sa_addr(af, &soa->addrs[i].ss, &addrlen)))
- continue;
-
- if (memcmp(addr, addrsoa, addrlen))
- continue;
-
- port = *dns_sa_port(af, &soa->addrs[i].ss);
-
- return (port)? port : htons(53);
- }
- }
-
- return htons(53);
-} /* dns_hints_port() */
-
-
-int dns_hints_dump(struct dns_hints *hints, FILE *fp) {
- struct dns_hints_soa *soa;
- char addr[INET6_ADDRSTRLEN];
- unsigned i;
- int af, error;
-
- for (soa = hints->head; soa; soa = soa->next) {
- fprintf(fp, "ZONE \"%s\"\n", soa->zone);
-
- for (i = 0; i < soa->count; i++) {
- af = soa->addrs[i].ss.ss_family;
-
- if ((error = dns_ntop(af, dns_sa_addr(af, &soa->addrs[i].ss, NULL), addr, sizeof addr)))
- return error;
-
- fprintf(fp, "\t(%d) [%s]:%hu\n", (int)soa->addrs[i].priority, addr, ntohs(*dns_sa_port(af, &soa->addrs[i].ss)));
- }
- }
-
- return 0;
-} /* dns_hints_dump() */
-
-
-/*
- * C A C H E R O U T I N E S
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-static dns_refcount_t dns_cache_acquire(struct dns_cache *cache) {
- return dns_atomic_fetch_add(&cache->_.refcount);
-} /* dns_cache_acquire() */
-
-
-static dns_refcount_t dns_cache_release(struct dns_cache *cache) {
- return dns_atomic_fetch_sub(&cache->_.refcount);
-} /* dns_cache_release() */
-
-
-static struct dns_packet *dns_cache_query(struct dns_packet *query, struct dns_cache *cache, int *error) {
- (void)query;
- (void)cache;
- (void)error;
-
- return NULL;
-} /* dns_cache_query() */
-
-
-static int dns_cache_submit(struct dns_packet *query, struct dns_cache *cache) {
- (void)query;
- (void)cache;
-
- return 0;
-} /* dns_cache_submit() */
-
-
-static int dns_cache_check(struct dns_cache *cache) {
- (void)cache;
-
- return 0;
-} /* dns_cache_check() */
-
-
-static struct dns_packet *dns_cache_fetch(struct dns_cache *cache, int *error) {
- (void)cache;
- (void)error;
-
- return NULL;
-} /* dns_cache_fetch() */
-
-
-static int dns_cache_pollfd(struct dns_cache *cache) {
- (void)cache;
-
- return -1;
-} /* dns_cache_pollfd() */
-
-
-static short dns_cache_events(struct dns_cache *cache) {
- (void)cache;
-
- return 0;
-} /* dns_cache_events() */
-
-
-static void dns_cache_clear(struct dns_cache *cache) {
- (void)cache;
-
- return;
-} /* dns_cache_clear() */
-
-
-struct dns_cache *dns_cache_init(struct dns_cache *cache) {
- static const struct dns_cache c_init = {
- .acquire = &dns_cache_acquire,
- .release = &dns_cache_release,
- .query = &dns_cache_query,
- .submit = &dns_cache_submit,
- .check = &dns_cache_check,
- .fetch = &dns_cache_fetch,
- .pollfd = &dns_cache_pollfd,
- .events = &dns_cache_events,
- .clear = &dns_cache_clear,
- ._ = { .refcount = 1, },
- };
-
- *cache = c_init;
-
- return cache;
-} /* dns_cache_init() */
-
-
-void dns_cache_close(struct dns_cache *cache) {
- if (cache)
- cache->release(cache);
-} /* dns_cache_close() */
-
-
-/*
- * S O C K E T R O U T I N E S
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-static void dns_socketclose(int *fd, const struct dns_options *opts) {
- if (opts && opts->closefd.cb)
- opts->closefd.cb(fd, opts->closefd.arg);
-
- if (*fd != -1) {
-#if _WIN32
- closesocket(*fd);
-#else
- close(*fd);
-#endif
- *fd = -1;
- }
-} /* dns_socketclose() */
-
-
-#ifndef HAVE_IOCTLSOCKET
-#define HAVE_IOCTLSOCKET (_WIN32 || _WIN64)
-#endif
-
-#ifndef HAVE_SOCK_CLOEXEC
-#ifdef SOCK_CLOEXEC
-#define HAVE_SOCK_CLOEXEC 1
-#else
-#define HAVE_SOCK_CLOEXEC 0
-#endif
-#endif
-
-#ifndef HAVE_SOCK_NONBLOCK
-#ifdef SOCK_NONBLOCK
-#define HAVE_SOCK_NONBLOCK 1
-#else
-#define HAVE_SOCK_NONBLOCK 0
-#endif
-#endif
-
-#define DNS_SO_MAXTRY 7
-
-static int dns_socket(struct sockaddr *local, int type, int *error_) {
- int fd = -1, flags, error;
-#if defined FIONBIO
- unsigned long opt;
-#endif
-
- flags = 0;
-#if HAVE_SOCK_CLOEXEC
- flags |= SOCK_CLOEXEC;
-#endif
-#if HAVE_SOCK_NONBLOCK
- flags |= SOCK_NONBLOCK;
-#endif
- if (-1 == (fd = socket(local->sa_family, type|flags, 0)))
- goto soerr;
-
-#if defined F_SETFD && !HAVE_SOCK_CLOEXEC
- if (-1 == fcntl(fd, F_SETFD, 1))
- goto syerr;
-#endif
-
-#if defined O_NONBLOCK && !HAVE_SOCK_NONBLOCK
- if (-1 == (flags = fcntl(fd, F_GETFL)))
- goto syerr;
- if (-1 == fcntl(fd, F_SETFL, flags | O_NONBLOCK))
- goto syerr;
-#elif defined FIONBIO && HAVE_IOCTLSOCKET
- opt = 1;
- if (0 != ioctlsocket(fd, FIONBIO, &opt))
- goto soerr;
-#endif
-
-#if defined SO_NOSIGPIPE
- if (type != SOCK_DGRAM) {
- if (0 != setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &(int){ 1 }, sizeof (int)))
- goto soerr;
- }
-#endif
-
- if (local->sa_family != AF_INET && local->sa_family != AF_INET6)
- return fd;
-
- if (type != SOCK_DGRAM)
- return fd;
-
- /*
- * FreeBSD, Linux, OpenBSD, OS X, and Solaris use random ports by
- * default. Though the ephemeral range is quite small on OS X
- * (49152-65535 on 10.10) and Linux (32768-60999 on 4.4.0, Ubuntu
- * Xenial). See also RFC 6056.
- *
- * TODO: Optionally rely on the kernel to select a random port.
- */
- if (*dns_sa_port(local->sa_family, local) == 0) {
- struct sockaddr_storage tmp;
- unsigned i, port;
-
- memcpy(&tmp, local, dns_sa_len(local));
-
- for (i = 0; i < DNS_SO_MAXTRY; i++) {
- port = 1025 + (dns_random() % 64510);
-
- *dns_sa_port(tmp.ss_family, &tmp) = htons(port);
-
- if (0 == bind(fd, (struct sockaddr *)&tmp, dns_sa_len(&tmp)))
- return fd;
- }
-
- /* NB: continue to next bind statement */
- }
-
- if (0 == bind(fd, local, dns_sa_len(local)))
- return fd;
-
- /* FALL THROUGH */
-soerr:
- error = dns_soerr();
-
- goto error;
-#if (defined F_SETFD && !HAVE_SOCK_CLOEXEC) || (defined O_NONBLOCK && !HAVE_SOCK_NONBLOCK)
-syerr:
- error = dns_syerr();
-
- goto error;
-#endif
-error:
- *error_ = error;
-
- dns_socketclose(&fd, NULL);
-
- return -1;
-} /* dns_socket() */
-
-
-enum {
- DNS_SO_UDP_INIT = 1,
- DNS_SO_UDP_CONN,
- DNS_SO_UDP_SEND,
- DNS_SO_UDP_RECV,
- DNS_SO_UDP_DONE,
-
- DNS_SO_TCP_INIT,
- DNS_SO_TCP_CONN,
- DNS_SO_TCP_SEND,
- DNS_SO_TCP_RECV,
- DNS_SO_TCP_DONE,
-};
-
-struct dns_socket {
- struct dns_options opts;
-
- int udp;
- int tcp;
-
- int *old;
- unsigned onum, olim;
-
- int type;
-
- struct sockaddr_storage local, remote;
-
- struct dns_k_permutor qids;
-
- struct dns_stat stat;
-
- /*
- * NOTE: dns_so_reset() zeroes everything from here down.
- */
- int state;
-
- unsigned short qid;
- char qname[DNS_D_MAXNAME + 1];
- size_t qlen;
- enum dns_type qtype;
- enum dns_class qclass;
-
- struct dns_packet *query;
- size_t qout;
-
- struct dns_clock elapsed;
-
- struct dns_packet *answer;
- size_t alen, apos;
-}; /* struct dns_socket */
-
-
-/*
- * NOTE: Actual closure delayed so that kqueue(2) and epoll(2) callers have
- * a chance to recognize a state change after installing a persistent event
- * and where sequential descriptors with the same integer value returned
- * from _pollfd() would be ambiguous. See dns_so_closefds().
- */
-static int dns_so_closefd(struct dns_socket *so, int *fd) {
- int error;
-
- if (*fd == -1)
- return 0;
-
- if (so->opts.closefd.cb) {
- if ((error = so->opts.closefd.cb(fd, so->opts.closefd.arg))) {
- return error;
- } else if (*fd == -1)
- return 0;
- }
-
- if (!(so->onum < so->olim)) {
- unsigned olim = DNS_PP_MAX(4, so->olim * 2);
- void *old;
-
- if (!(old = realloc(so->old, sizeof so->old[0] * olim)))
- return dns_syerr();
-
- so->old = old;
- so->olim = olim;
- }
-
- so->old[so->onum++] = *fd;
- *fd = -1;
-
- return 0;
-} /* dns_so_closefd() */
-
-
-#define DNS_SO_CLOSE_UDP 0x01
-#define DNS_SO_CLOSE_TCP 0x02
-#define DNS_SO_CLOSE_OLD 0x04
-#define DNS_SO_CLOSE_ALL (DNS_SO_CLOSE_UDP|DNS_SO_CLOSE_TCP|DNS_SO_CLOSE_OLD)
-
-static void dns_so_closefds(struct dns_socket *so, int which) {
- if (DNS_SO_CLOSE_UDP & which)
- dns_socketclose(&so->udp, &so->opts);
- if (DNS_SO_CLOSE_TCP & which)
- dns_socketclose(&so->tcp, &so->opts);
- if (DNS_SO_CLOSE_OLD & which) {
- unsigned i;
- for (i = 0; i < so->onum; i++)
- dns_socketclose(&so->old[i], &so->opts);
- so->onum = 0;
- free(so->old);
- so->old = 0;
- so->olim = 0;
- }
-} /* dns_so_closefds() */
-
-
-static void dns_so_destroy(struct dns_socket *);
-
-static struct dns_socket *dns_so_init(struct dns_socket *so, const struct sockaddr *local, int type, const struct dns_options *opts, int *error) {
- static const struct dns_socket so_initializer = { .opts = DNS_OPTS_INITIALIZER, .udp = -1, .tcp = -1, };
-
- *so = so_initializer;
- so->type = type;
-
- if (opts)
- so->opts = *opts;
-
- if (local)
- memcpy(&so->local, local, dns_sa_len(local));
-
- if (-1 == (so->udp = dns_socket((struct sockaddr *)&so->local, SOCK_DGRAM, error)))
- goto error;
-
- dns_k_permutor_init(&so->qids, 1, 65535);
-
- return so;
-error:
- dns_so_destroy(so);
-
- return 0;
-} /* dns_so_init() */
-
-
-struct dns_socket *dns_so_open(const struct sockaddr *local, int type, const struct dns_options *opts, int *error) {
- struct dns_socket *so;
-
- if (!(so = malloc(sizeof *so)))
- goto syerr;
-
- if (!dns_so_init(so, local, type, opts, error))
- goto error;
-
- return so;
-syerr:
- *error = dns_syerr();
-error:
- dns_so_close(so);
-
- return 0;
-} /* dns_so_open() */
-
-
-static void dns_so_destroy(struct dns_socket *so) {
- dns_so_reset(so);
- dns_so_closefds(so, DNS_SO_CLOSE_ALL);
-} /* dns_so_destroy() */
-
-
-void dns_so_close(struct dns_socket *so) {
- if (!so)
- return;
-
- dns_so_destroy(so);
-
- free(so);
-} /* dns_so_close() */
-
-
-void dns_so_reset(struct dns_socket *so) {
- dns_p_setptr(&so->answer, NULL);
-
- memset(&so->state, '\0', sizeof *so - offsetof(struct dns_socket, state));
-} /* dns_so_reset() */
-
-
-unsigned short dns_so_mkqid(struct dns_socket *so) {
- return dns_k_permutor_step(&so->qids);
-} /* dns_so_mkqid() */
-
-
-#define DNS_SO_MINBUF 768
-
-static int dns_so_newanswer(struct dns_socket *so, size_t len) {
- size_t size = offsetof(struct dns_packet, data) + DNS_PP_MAX(len, DNS_SO_MINBUF);
- void *p;
-
- if (!(p = realloc(so->answer, size)))
- return dns_syerr();
-
- so->answer = dns_p_init(p, size);
-
- return 0;
-} /* dns_so_newanswer() */
-
-
-int dns_so_submit(struct dns_socket *so, struct dns_packet *Q, struct sockaddr *host) {
- struct dns_rr rr;
- int error = DNS_EUNKNOWN;
-
- dns_so_reset(so);
-
- if ((error = dns_rr_parse(&rr, 12, Q)))
- goto error;
-
- if (!(so->qlen = dns_d_expand(so->qname, sizeof so->qname, rr.dn.p, Q, &error)))
- goto error;
- /*
- * NOTE: Don't bail if expansion is too long; caller may be
- * intentionally sending long names. However, we won't be able to
- * verify it on return.
- */
-
- so->qtype = rr.type;
- so->qclass = rr.class;
-
- if ((error = dns_so_newanswer(so, (Q->memo.opt.maxudp)? Q->memo.opt.maxudp : DNS_SO_MINBUF)))
- goto syerr;
-
- memcpy(&so->remote, host, dns_sa_len(host));
-
- so->query = Q;
- so->qout = 0;
-
- dns_begin(&so->elapsed);
-
- if (DNS_HEADER(so->query)->qid == 0)
- DNS_HEADER(so->query)->qid = dns_so_mkqid(so);
-
- so->qid = DNS_HEADER(so->query)->qid;
- so->state = (so->type == SOCK_STREAM)? DNS_SO_TCP_INIT : DNS_SO_UDP_INIT;
-
- so->stat.queries++;
-
- return 0;
-syerr:
- error = dns_syerr();
-error:
- dns_so_reset(so);
-
- return error;
-} /* dns_so_submit() */
-
-
-static int dns_so_verify(struct dns_socket *so, struct dns_packet *P) {
- char qname[DNS_D_MAXNAME + 1];
- size_t qlen;
- struct dns_rr rr;
- int error = -1;
-
- if (so->qid != DNS_HEADER(so->answer)->qid)
- goto reject;
-
- if (!dns_p_count(so->answer, DNS_S_QD))
- goto reject;
-
- if (0 != dns_rr_parse(&rr, 12, so->answer))
- goto reject;
-
- if (rr.type != so->qtype || rr.class != so->qclass)
- goto reject;
-
- if (!(qlen = dns_d_expand(qname, sizeof qname, rr.dn.p, P, &error)))
- goto error;
- else if (qlen >= sizeof qname || qlen != so->qlen)
- goto reject;
-
- if (0 != strcasecmp(so->qname, qname))
- goto reject;
-
- return 0;
-reject:
- error = DNS_EUNKNOWN;
-error:
- DNS_SHOW(P, "rejecting packet (%s)", dns_strerror(error));
-
- return error;
-} /* dns_so_verify() */
-
-
-static _Bool dns_so_tcp_keep(struct dns_socket *so) {
- struct sockaddr_storage remote;
-
- if (so->tcp == -1)
- return 0;
-
- if (0 != getpeername(so->tcp, (struct sockaddr *)&remote, &(socklen_t){ sizeof remote }))
- return 0;
-
- return 0 == dns_sa_cmp(&remote, &so->remote);
-} /* dns_so_tcp_keep() */
-
-
-#if defined __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Warray-bounds"
-#endif
-
-static int dns_so_tcp_send(struct dns_socket *so) {
- unsigned char *qsrc;
- size_t qend;
- long n;
-
- so->query->data[-2] = 0xff & (so->query->end >> 8);
- so->query->data[-1] = 0xff & (so->query->end >> 0);
-
- qsrc = &so->query->data[-2] + so->qout;
- qend = so->query->end + 2;
-
- while (so->qout < qend) {
- if (0 > (n = dns_send(so->tcp, (void *)&qsrc[so->qout], qend - so->qout, 0)))
- return dns_soerr();
-
- so->qout += n;
- so->stat.tcp.sent.bytes += n;
- }
-
- so->stat.tcp.sent.count++;
-
- return 0;
-} /* dns_so_tcp_send() */
-
-
-static int dns_so_tcp_recv(struct dns_socket *so) {
- unsigned char *asrc;
- size_t aend, alen;
- int error;
- long n;
-
- aend = so->alen + 2;
-
- while (so->apos < aend) {
- if (read_wait0(so->udp) <= 0) // add by zsx
- return dns_soerr();
-
- asrc = &so->answer->data[-2];
-
- if (0 > (n = recv(so->tcp, (void *)&asrc[so->apos], aend - so->apos, 0)))
- return dns_soerr();
- else if (n == 0)
- return DNS_EUNKNOWN; /* FIXME */
-
- so->apos += n;
- so->stat.tcp.rcvd.bytes += n;
-
- if (so->alen == 0 && so->apos >= 2) {
- alen = ((0xff & so->answer->data[-2]) << 8)
- | ((0xff & so->answer->data[-1]) << 0);
-
- if ((error = dns_so_newanswer(so, alen)))
- return error;
-
- so->alen = alen;
- aend = alen + 2;
- }
- }
-
- so->answer->end = so->alen;
- so->stat.tcp.rcvd.count++;
-
- return 0;
-} /* dns_so_tcp_recv() */
-
-#if __clang__
-#pragma clang diagnostic pop
-#endif
-
-
-int dns_so_check(struct dns_socket *so) {
- int error;
- long n;
-
-retry:
- switch (so->state) {
- case DNS_SO_UDP_INIT:
- so->state++;
- /* FALL THROUGH */
- case DNS_SO_UDP_CONN:
- if (0 != connect(so->udp, (struct sockaddr *)&so->remote, dns_sa_len(&so->remote)))
- goto soerr;
-
- so->state++;
- /* FALL THROUGH */
- case DNS_SO_UDP_SEND:
- if (0 > (n = send(so->udp, (void *)so->query->data, so->query->end, 0)))
- goto soerr;
-
- so->stat.udp.sent.bytes += n;
- so->stat.udp.sent.count++;
-
- so->state++;
- /* FALL THROUGH */
- case DNS_SO_UDP_RECV:
- if (read_wait0(so->udp) <= 0) // add by zsx
- goto soerr;
-
- if (0 > (n = recv(so->udp, (void *)so->answer->data, so->answer->size, 0)))
- goto soerr;
-
- so->stat.udp.rcvd.bytes += n;
- so->stat.udp.rcvd.count++;
-
- if ((so->answer->end = n) < 12)
- goto trash;
-
- if ((error = dns_so_verify(so, so->answer)))
- goto trash;
-
- so->state++;
- /* FALL THROUGH */
- case DNS_SO_UDP_DONE:
- if (!DNS_HEADER(so->answer)->tc || so->type == SOCK_DGRAM)
- return 0;
-
- so->state++;
- /* FALL THROUGH */
- case DNS_SO_TCP_INIT:
- if (dns_so_tcp_keep(so)) {
- so->state = DNS_SO_TCP_SEND;
-
- goto retry;
- }
-
- if ((error = dns_so_closefd(so, &so->tcp)))
- goto error;
-
- if (-1 == (so->tcp = dns_socket((struct sockaddr *)&so->local, SOCK_STREAM, &error)))
- goto error;
-
- so->state++;
- /* FALL THROUGH */
- case DNS_SO_TCP_CONN:
- if (0 != connect(so->tcp, (struct sockaddr *)&so->remote, dns_sa_len(&so->remote))) {
- if (dns_soerr() != DNS_EISCONN)
- goto soerr;
- }
-
- so->state++;
- /* FALL THROUGH */
- case DNS_SO_TCP_SEND:
- if ((error = dns_so_tcp_send(so)))
- goto error;
-
- so->state++;
- /* FALL THROUGH */
- case DNS_SO_TCP_RECV:
- if ((error = dns_so_tcp_recv(so)))
- goto error;
-
- so->state++;
- /* FALL THROUGH */
- case DNS_SO_TCP_DONE:
- /* close unless DNS_RESCONF_TCP_ONLY (see dns_res_tcp2type) */
- if (so->type != SOCK_STREAM) {
- if ((error = dns_so_closefd(so, &so->tcp)))
- goto error;
- }
-
- if (so->answer->end < 12)
- return DNS_EILLEGAL;
-
- if ((error = dns_so_verify(so, so->answer)))
- goto error;
-
- return 0;
- default:
- error = DNS_EUNKNOWN;
-
- goto error;
- } /* switch() */
-
-trash:
- DNS_CARP("discarding packet");
- goto retry;
-soerr:
- error = dns_soerr();
-
- goto error;
-error:
- switch (error) {
- case DNS_EINTR:
- goto retry;
- case DNS_EINPROGRESS:
- /* FALL THROUGH */
- case DNS_EALREADY:
- /* FALL THROUGH */
-#if DNS_EWOULDBLOCK != DNS_EAGAIN
- case DNS_EWOULDBLOCK:
- /* FALL THROUGH */
-#endif
- error = DNS_EAGAIN;
-
- break;
- } /* switch() */
-
- return error;
-} /* dns_so_check() */
-
-
-struct dns_packet *dns_so_fetch(struct dns_socket *so, int *error) {
- struct dns_packet *answer;
-
- switch (so->state) {
- case DNS_SO_UDP_DONE:
- case DNS_SO_TCP_DONE:
- answer = so->answer;
- so->answer = 0;
-
- return answer;
- default:
- *error = DNS_EUNKNOWN;
-
- return 0;
- }
-} /* dns_so_fetch() */
-
-
-struct dns_packet *dns_so_query(struct dns_socket *so, struct dns_packet *Q, struct sockaddr *host, int *error_) {
- struct dns_packet *A;
- int error;
-
- if (!so->state) {
- if ((error = dns_so_submit(so, Q, host)))
- goto error;
- }
-
- if ((error = dns_so_check(so)))
- goto error;
-
- if (!(A = dns_so_fetch(so, &error)))
- goto error;
-
- dns_so_reset(so);
-
- return A;
-error:
- *error_ = error;
-
- return 0;
-} /* dns_so_query() */
-
-
-time_t dns_so_elapsed(struct dns_socket *so) {
- return dns_elapsed(&so->elapsed);
-} /* dns_so_elapsed() */
-
-
-void dns_so_clear(struct dns_socket *so) {
- dns_so_closefds(so, DNS_SO_CLOSE_OLD);
-} /* dns_so_clear() */
-
-
-static int dns_so_events2(struct dns_socket *so, enum dns_events type) {
- int events = 0;
-
- switch (so->state) {
- case DNS_SO_UDP_CONN:
- case DNS_SO_UDP_SEND:
- events |= DNS_POLLOUT;
-
- break;
- case DNS_SO_UDP_RECV:
- events |= DNS_POLLIN;
-
- break;
- case DNS_SO_TCP_CONN:
- case DNS_SO_TCP_SEND:
- events |= DNS_POLLOUT;
-
- break;
- case DNS_SO_TCP_RECV:
- events |= DNS_POLLIN;
-
- break;
- } /* switch() */
-
- switch (type) {
- case DNS_LIBEVENT:
- return DNS_POLL2EV(events);
- default:
- return events;
- } /* switch() */
-} /* dns_so_events2() */
-
-
-int dns_so_events(struct dns_socket *so) {
- return dns_so_events2(so, so->opts.events);
-} /* dns_so_events() */
-
-
-int dns_so_pollfd(struct dns_socket *so) {
- switch (so->state) {
- case DNS_SO_UDP_CONN:
- case DNS_SO_UDP_SEND:
- case DNS_SO_UDP_RECV:
- return so->udp;
- case DNS_SO_TCP_CONN:
- case DNS_SO_TCP_SEND:
- case DNS_SO_TCP_RECV:
- return so->tcp;
- } /* switch() */
-
- return -1;
-} /* dns_so_pollfd() */
-
-
-int dns_so_poll(struct dns_socket *so, int timeout) {
- return dns_poll(dns_so_pollfd(so), dns_so_events2(so, DNS_SYSPOLL), timeout);
-} /* dns_so_poll() */
-
-
-const struct dns_stat *dns_so_stat(struct dns_socket *so) {
- return &so->stat;
-} /* dns_so_stat() */
-
-
-/*
- * R E S O L V E R R O U T I N E S
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-enum dns_res_state {
- DNS_R_INIT,
- DNS_R_GLUE,
- DNS_R_SWITCH, /* (B)IND, (F)ILE, (C)ACHE */
-
- DNS_R_FILE, /* Lookup in local hosts database */
-
- DNS_R_CACHE, /* Lookup in application cache */
- DNS_R_SUBMIT,
- DNS_R_CHECK,
- DNS_R_FETCH,
-
- DNS_R_BIND, /* Lookup in the network */
- DNS_R_SEARCH,
- DNS_R_HINTS,
- DNS_R_ITERATE,
- DNS_R_FOREACH_NS,
- DNS_R_RESOLV0_NS, /* Prologue: Setup next frame and recurse */
- DNS_R_RESOLV1_NS, /* Epilog: Inspect answer */
- DNS_R_FOREACH_A,
- DNS_R_QUERY_A,
- DNS_R_CNAME0_A,
- DNS_R_CNAME1_A,
-
- DNS_R_FINISH,
- DNS_R_SMART0_A,
- DNS_R_SMART1_A,
- DNS_R_DONE,
- DNS_R_SERVFAIL,
-}; /* enum dns_res_state */
-
-
-#define DNS_R_MAXDEPTH 8
-#define DNS_R_ENDFRAME (DNS_R_MAXDEPTH - 1)
-
-struct dns_resolver {
- struct dns_socket so;
-
- struct dns_resolv_conf *resconf;
- struct dns_hosts *hosts;
- struct dns_hints *hints;
- struct dns_cache *cache;
-
- dns_atomic_t refcount;
-
- /* Reset zeroes everything below here. */
-
- char qname[DNS_D_MAXNAME + 1];
- size_t qlen;
-
- enum dns_type qtype;
- enum dns_class qclass;
-
- struct dns_clock elapsed;
-
- dns_resconf_i_t search;
-
- struct dns_rr_i smart;
-
- struct dns_packet *nodata; /* answer if nothing better */
-
- unsigned sp;
-
- struct dns_res_frame {
- enum dns_res_state state;
-
- int error;
- int which; /* (B)IND, (F)ILE; index into resconf->lookup */
- int qflags;
-
- unsigned attempts;
-
- struct dns_packet *query, *answer, *hints;
-
- struct dns_rr_i hints_i, hints_j;
- struct dns_rr hints_ns, ans_cname;
- } stack[DNS_R_MAXDEPTH];
-}; /* struct dns_resolver */
-
-
-static int dns_res_tcp2type(int tcp) {
- switch (tcp) {
- case DNS_RESCONF_TCP_ONLY:
- return SOCK_STREAM;
- case DNS_RESCONF_TCP_DISABLE:
- return SOCK_DGRAM;
- default:
- return 0;
- }
-} /* dns_res_tcp2type() */
-
-struct dns_resolver *dns_res_open(struct dns_resolv_conf *resconf, struct dns_hosts *hosts, struct dns_hints *hints, struct dns_cache *cache, const struct dns_options *opts, int *_error) {
- static const struct dns_resolver R_initializer
- = { .refcount = 1, };
- struct dns_resolver *R = 0;
- int type, error;
-
- /*
- * Grab ref count early because the caller may have passed us a mortal
- * reference, and we want to do the right thing if we return early
- * from an error.
- */
- if (resconf)
- dns_resconf_acquire(resconf);
- if (hosts)
- dns_hosts_acquire(hosts);
- if (hints)
- dns_hints_acquire(hints);
- if (cache)
- dns_cache_acquire(cache);
-
- /*
- * Don't try to load it ourselves because a NULL object might be an
- * error from, say, dns_resconf_root(), and loading
- * dns_resconf_local() by default would create undesirable surpises.
- */
- if (!resconf || !hosts || !hints) {
- if (!*_error)
- *_error = EINVAL;
- goto _error;
- }
-
- if (!(R = malloc(sizeof *R)))
- goto syerr;
-
- *R = R_initializer;
- type = dns_res_tcp2type(resconf->options.tcp);
-
- if (!dns_so_init(&R->so, (struct sockaddr *)&resconf->iface, type, opts, &error))
- goto error;
-
- R->resconf = resconf;
- R->hosts = hosts;
- R->hints = hints;
- R->cache = cache;
-
- return R;
-syerr:
- error = dns_syerr();
-error:
- *_error = error;
-_error:
- dns_res_close(R);
-
- dns_resconf_close(resconf);
- dns_hosts_close(hosts);
- dns_hints_close(hints);
- dns_cache_close(cache);
-
- return 0;
-} /* dns_res_open() */
-
-
-struct dns_resolver *dns_res_stub(const struct dns_options *opts, int *error) {
- struct dns_resolv_conf *resconf = 0;
- struct dns_hosts *hosts = 0;
- struct dns_hints *hints = 0;
- struct dns_resolver *res = 0;
-
- if (!(resconf = dns_resconf_local(error)))
- goto epilog;
-
- if (!(hosts = dns_hosts_local(error)))
- goto epilog;
-
- if (!(hints = dns_hints_local(resconf, error)))
- goto epilog;
-
- if (!(res = dns_res_open(resconf, hosts, hints, NULL, opts, error)))
- goto epilog;
-
-epilog:
- dns_resconf_close(resconf);
- dns_hosts_close(hosts);
- dns_hints_close(hints);
-
- return res;
-} /* dns_res_stub() */
-
-
-static void dns_res_frame_destroy(struct dns_resolver *R, struct dns_res_frame *frame) {
- (void)R;
-
- dns_p_setptr(&frame->query, NULL);
- dns_p_setptr(&frame->answer, NULL);
- dns_p_setptr(&frame->hints, NULL);
-} /* dns_res_frame_destroy() */
-
-
-static void dns_res_frame_init(struct dns_resolver *R, struct dns_res_frame *frame) {
- memset(frame, '\0', sizeof *frame);
-
- /*
- * NB: Can be invoked from dns_res_open, before R->resconf has been
- * initialized.
- */
- if (R->resconf) {
- if (!R->resconf->options.recurse)
- frame->qflags |= DNS_Q_RD;
- if (R->resconf->options.edns0)
- frame->qflags |= DNS_Q_EDNS0;
- }
-} /* dns_res_frame_init() */
-
-
-static void dns_res_frame_reset(struct dns_resolver *R, struct dns_res_frame *frame) {
- dns_res_frame_destroy(R, frame);
- dns_res_frame_init(R, frame);
-} /* dns_res_frame_reset() */
-
-
-static dns_error_t dns_res_frame_prepare(struct dns_resolver *R, struct dns_res_frame *F, char *qname, enum dns_type qtype, enum dns_class qclass) {
- struct dns_packet *P = NULL;
-
- if (!(F < endof(R->stack)))
- return DNS_EUNKNOWN;
-
- dns_p_movptr(&P, &F->query);
- dns_res_frame_reset(R, F);
- dns_p_movptr(&F->query, &P);
-
- return dns_q_make(&F->query, qname, qtype, qclass, F->qflags);
-} /* dns_res_frame_prepare() */
-
-
-void dns_res_reset(struct dns_resolver *R) {
- unsigned i;
-
- dns_so_reset(&R->so);
- dns_p_setptr(&R->nodata, NULL);
-
- for (i = 0; i < lengthof(R->stack); i++)
- dns_res_frame_destroy(R, &R->stack[i]);
-
- memset(&R->qname, '\0', sizeof *R - offsetof(struct dns_resolver, qname));
-
- for (i = 0; i < lengthof(R->stack); i++)
- dns_res_frame_init(R, &R->stack[i]);
-} /* dns_res_reset() */
-
-
-void dns_res_close(struct dns_resolver *R) {
- if (!R || 1 < dns_res_release(R))
- return;
-
- dns_res_reset(R);
-
- dns_so_destroy(&R->so);
-
- dns_hints_close(R->hints);
- dns_hosts_close(R->hosts);
- dns_resconf_close(R->resconf);
- dns_cache_close(R->cache);
-
- free(R);
-} /* dns_res_close() */
-
-
-dns_refcount_t dns_res_acquire(struct dns_resolver *R) {
- return dns_atomic_fetch_add(&R->refcount);
-} /* dns_res_acquire() */
-
-
-dns_refcount_t dns_res_release(struct dns_resolver *R) {
- return dns_atomic_fetch_sub(&R->refcount);
-} /* dns_res_release() */
-
-
-struct dns_resolver *dns_res_mortal(struct dns_resolver *res) {
- if (res)
- dns_res_release(res);
- return res;
-} /* dns_res_mortal() */
-
-
-static struct dns_packet *dns_res_merge(struct dns_packet *P0, struct dns_packet *P1, int *error_) {
- size_t bufsiz = P0->end + P1->end;
- struct dns_packet *P[3] = { P0, P1, 0 };
- struct dns_rr rr[3];
- int error, copy, i;
- enum dns_section section;
-
-retry:
- if (!(P[2] = dns_p_make(bufsiz, &error)))
- goto error;
-
- dns_rr_foreach(&rr[0], P[0], .section = DNS_S_QD) {
- if ((error = dns_rr_copy(P[2], &rr[0], P[0])))
- goto error;
- }
-
- for (section = DNS_S_AN; (DNS_S_ALL & section); section <<= 1) {
- for (i = 0; i < 2; i++) {
- dns_rr_foreach(&rr[i], P[i], .section = section) {
- copy = 1;
-
- dns_rr_foreach(&rr[2], P[2], .type = rr[i].type, .section = (DNS_S_ALL & ~DNS_S_QD)) {
- if (0 == dns_rr_cmp(&rr[i], P[i], &rr[2], P[2])) {
- copy = 0;
-
- break;
- }
- }
-
- if (copy && (error = dns_rr_copy(P[2], &rr[i], P[i]))) {
- if (error == DNS_ENOBUFS && bufsiz < 65535) {
- dns_p_setptr(&P[2], NULL);
-
- bufsiz = DNS_PP_MAX(65535, bufsiz * 2);
-
- goto retry;
- }
-
- goto error;
- }
- } /* foreach(rr) */
- } /* foreach(packet) */
- } /* foreach(section) */
-
- return P[2];
-error:
- *error_ = error;
-
- dns_p_free(P[2]);
-
- return 0;
-} /* dns_res_merge() */
-
-
-static struct dns_packet *dns_res_glue(struct dns_resolver *R, struct dns_packet *Q) {
- struct dns_packet *P = dns_p_new(512);
- char qname[DNS_D_MAXNAME + 1];
- size_t qlen;
- enum dns_type qtype;
- struct dns_rr rr;
- unsigned sp;
- int error;
-
- if (!(qlen = dns_d_expand(qname, sizeof qname, 12, Q, &error))
- || qlen >= sizeof qname)
- return 0;
-
- if (!(qtype = dns_rr_type(12, Q)))
- return 0;
-
- if ((error = dns_p_push(P, DNS_S_QD, qname, strlen(qname), qtype, DNS_C_IN, 0, 0)))
- return 0;
-
- for (sp = 0; sp <= R->sp; sp++) {
- if (!R->stack[sp].answer)
- continue;
-
- dns_rr_foreach(&rr, R->stack[sp].answer, .name = qname, .type = qtype, .section = (DNS_S_ALL & ~DNS_S_QD)) {
- rr.section = DNS_S_AN;
-
- if ((error = dns_rr_copy(P, &rr, R->stack[sp].answer)))
- return 0;
- }
- }
-
- if (dns_p_count(P, DNS_S_AN) > 0)
- goto copy;
-
- /* Otherwise, look for a CNAME */
- for (sp = 0; sp <= R->sp; sp++) {
- if (!R->stack[sp].answer)
- continue;
-
- dns_rr_foreach(&rr, R->stack[sp].answer, .name = qname, .type = DNS_T_CNAME, .section = (DNS_S_ALL & ~DNS_S_QD)) {
- rr.section = DNS_S_AN;
-
- if ((error = dns_rr_copy(P, &rr, R->stack[sp].answer)))
- return 0;
- }
- }
-
- if (!dns_p_count(P, DNS_S_AN))
- return 0;
-
-copy:
- return dns_p_copy(dns_p_make(P->end, &error), P);
-} /* dns_res_glue() */
-
-
-/*
- * Sort NS records by three criteria:
- *
- * 1) Whether glue is present.
- * 2) Whether glue record is original or of recursive lookup.
- * 3) Randomly shuffle records which share the above criteria.
- *
- * NOTE: Assumes only NS records passed, AND ASSUMES no new NS records will
- * be added during an iteration.
- *
- * FIXME: Only groks A glue, not AAAA glue.
- */
-static int dns_res_nameserv_cmp(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) {
- _Bool glued[2] = { 0 };
- struct dns_rr x, y;
- struct dns_ns ns;
- int cmp, error;
-
- memset(&x, 0, sizeof(x));
- memset(&y, 0, sizeof(y));
-
- if (!(error = dns_ns_parse(&ns, a, P)))
- glued[0] = !!dns_rr_grep(&x, 1, dns_rr_i_new(P, .section = (DNS_S_ALL & ~DNS_S_QD), .name = ns.host, .type = DNS_T_A), P, &error);
-
- if (!(error = dns_ns_parse(&ns, b, P)))
- glued[1] = !!dns_rr_grep(&y, 1, dns_rr_i_new(P, .section = (DNS_S_ALL & ~DNS_S_QD), .name = ns.host, .type = DNS_T_A), P, &error);
-
- if ((cmp = glued[1] - glued[0])) {
- return cmp;
- } else if ((cmp = (dns_rr_offset(&y) < i->args[0]) - (dns_rr_offset(&x) < i->args[0]))) {
- return cmp;
- } else {
- return dns_rr_i_shuffle(a, b, i, P);
- }
-} /* dns_res_nameserv_cmp() */
-
-
-#define dgoto(sp, i) \
- do { R->stack[(sp)].state = (i); goto exec; } while (0)
-
-static int dns_res_exec(struct dns_resolver *R) {
- struct dns_res_frame *F;
- struct dns_packet *P;
- union {
- char host[DNS_D_MAXNAME + 1];
- char name[DNS_D_MAXNAME + 1];
- struct dns_ns ns;
- struct dns_cname cname;
- } u;
- size_t len;
- struct dns_rr rr;
- int error;
-
-exec:
-
- F = &R->stack[R->sp];
-
- switch (F->state) {
- case DNS_R_INIT:
- F->state++;
- /* FALL THROUGH */
- case DNS_R_GLUE:
- if (R->sp == 0)
- dgoto(R->sp, DNS_R_SWITCH);
-
- if (!F->query)
- goto noquery;
-
- if (!(F->answer = dns_res_glue(R, F->query)))
- dgoto(R->sp, DNS_R_SWITCH);
-
- if (!(len = dns_d_expand(u.name, sizeof u.name, 12, F->query, &error)))
- goto error;
- else if (len >= sizeof u.name)
- goto toolong;
-
- dns_rr_foreach(&rr, F->answer, .name = u.name, .type = dns_rr_type(12, F->query), .section = DNS_S_AN) {
- dgoto(R->sp, DNS_R_FINISH);
- }
-
- dns_rr_foreach(&rr, F->answer, .name = u.name, .type = DNS_T_CNAME, .section = DNS_S_AN) {
- F->ans_cname = rr;
-
- dgoto(R->sp, DNS_R_CNAME0_A);
- }
-
- F->state++;
- /* FALL THROUGH */
- case DNS_R_SWITCH:
- while (F->which < (int)sizeof R->resconf->lookup && R->resconf->lookup[F->which]) {
- switch (R->resconf->lookup[F->which++]) {
- case 'b': case 'B':
- dgoto(R->sp, DNS_R_BIND);
- case 'f': case 'F':
- dgoto(R->sp, DNS_R_FILE);
- case 'c': case 'C':
- if (R->cache)
- dgoto(R->sp, DNS_R_CACHE);
-
- break;
- default:
- break;
- }
- }
-
- /*
- * FIXME: Examine more closely whether our logic is correct
- * and DNS_R_SERVFAIL is the correct default response.
- *
- * Case 1: We got here because we never got an answer on the
- * wire. All queries timed-out and we reached maximum
- * attempts count. See DNS_R_FOREACH_NS. In that case
- * DNS_R_SERVFAIL is the correct state, unless we want to
- * return DNS_ETIMEDOUT.
- *
- * Case 2: We were a stub resolver and got an unsatisfactory
- * answer (empty ANSWER section) which caused us to jump
- * back to DNS_R_SEARCH and ultimately to DNS_R_SWITCH. We
- * return the answer returned from the wire, which we
- * stashed in R->nodata.
- *
- * Case 3: We reached maximum attempts count as in case #1,
- * but never got an authoritative response which caused us
- * to short-circuit. See end of DNS_R_QUERY_A case. We
- * should probably prepare R->nodata as in case #2.
- */
- if (R->sp == 0 && R->nodata) { /* XXX: can we just return nodata regardless? */
- dns_p_movptr(&F->answer, &R->nodata);
- dgoto(R->sp, DNS_R_FINISH);
- }
-
- dgoto(R->sp, DNS_R_SERVFAIL);
- case DNS_R_FILE:
- if (R->sp > 0) {
- if (!dns_p_setptr(&F->answer, dns_hosts_query(R->hosts, F->query, &error)))
- goto error;
-
- if (dns_p_count(F->answer, DNS_S_AN) > 0)
- dgoto(R->sp, DNS_R_FINISH);
-
- dns_p_setptr(&F->answer, NULL);
- } else {
- R->search = 0;
-
- while ((len = dns_resconf_search(u.name, sizeof u.name, R->qname, R->qlen, R->resconf, &R->search))) {
- if ((error = dns_q_make2(&F->query, u.name, len, R->qtype, R->qclass, F->qflags)))
- goto error;
-
- if (!dns_p_setptr(&F->answer, dns_hosts_query(R->hosts, F->query, &error)))
- goto error;
-
- if (dns_p_count(F->answer, DNS_S_AN) > 0)
- dgoto(R->sp, DNS_R_FINISH);
-
- dns_p_setptr(&F->answer, NULL);
- }
- }
-
- dgoto(R->sp, DNS_R_SWITCH);
- case DNS_R_CACHE:
- error = 0;
-
- if (!F->query && (error = dns_q_make(&F->query, R->qname, R->qtype, R->qclass, F->qflags)))
- goto error;
-
- if (dns_p_setptr(&F->answer, R->cache->query(F->query, R->cache, &error))) {
- if (dns_p_count(F->answer, DNS_S_AN) > 0)
- dgoto(R->sp, DNS_R_FINISH);
-
- dns_p_setptr(&F->answer, NULL);
-
- dgoto(R->sp, DNS_R_SWITCH);
- } else if (error)
- goto error;
-
- F->state++;
- /* FALL THROUGH */
- case DNS_R_SUBMIT:
- if ((error = R->cache->submit(F->query, R->cache)))
- goto error;
-
- F->state++;
- /* FALL THROUGH */
- case DNS_R_CHECK:
- if ((error = R->cache->check(R->cache)))
- goto error;
-
- F->state++;
- /* FALL THROUGH */
- case DNS_R_FETCH:
- error = 0;
-
- if (dns_p_setptr(&F->answer, R->cache->fetch(R->cache, &error))) {
- if (dns_p_count(F->answer, DNS_S_AN) > 0)
- dgoto(R->sp, DNS_R_FINISH);
-
- dns_p_setptr(&F->answer, NULL);
-
- dgoto(R->sp, DNS_R_SWITCH);
- } else if (error)
- goto error;
-
- dgoto(R->sp, DNS_R_SWITCH);
- case DNS_R_BIND:
- if (R->sp > 0) {
- if (!F->query)
- goto noquery;
-
- dgoto(R->sp, DNS_R_HINTS);
- }
-
- R->search = 0;
-
- F->state++;
- /* FALL THROUGH */
- case DNS_R_SEARCH:
- /*
- * XXX: We probably should only apply the domain search
- * algorithm if R->sp == 0.
- */
- if (!(len = dns_resconf_search(u.name, sizeof u.name, R->qname, R->qlen, R->resconf, &R->search)))
- dgoto(R->sp, DNS_R_SWITCH);
-
- if ((error = dns_q_make2(&F->query, u.name, len, R->qtype, R->qclass, F->qflags)))
- goto error;
-
- F->state++;
- /* FALL THROUGH */
- case DNS_R_HINTS:
- if (!dns_p_setptr(&F->hints, dns_hints_query(R->hints, F->query, &error)))
- goto error;
-
- F->state++;
- /* FALL THROUGH */
- case DNS_R_ITERATE:
- dns_rr_i_init(&F->hints_i, F->hints);
-
- F->hints_i.section = DNS_S_AUTHORITY;
- F->hints_i.type = DNS_T_NS;
- F->hints_i.sort = &dns_res_nameserv_cmp;
- F->hints_i.args[0] = F->hints->end;
-
- F->state++;
- /* FALL THROUGH */
- case DNS_R_FOREACH_NS:
- dns_rr_i_save(&F->hints_i);
-
- /* Load our next nameserver host. */
- if (!dns_rr_grep(&F->hints_ns, 1, &F->hints_i, F->hints, &error)) {
- if (++F->attempts < R->resconf->options.attempts)
- dgoto(R->sp, DNS_R_ITERATE);
-
- dgoto(R->sp, DNS_R_SWITCH);
- }
-
- dns_rr_i_init(&F->hints_j, F->hints);
-
- /* Assume there are glue records */
- dgoto(R->sp, DNS_R_FOREACH_A);
- case DNS_R_RESOLV0_NS:
- /* Have we reached our max depth? */
- if (&F[1] >= endof(R->stack))
- dgoto(R->sp, DNS_R_FOREACH_NS);
-
- if ((error = dns_ns_parse(&u.ns, &F->hints_ns, F->hints)))
- goto error;
- if ((error = dns_res_frame_prepare(R, &F[1], u.ns.host, DNS_T_A, DNS_C_IN)))
- goto error;
-
- F->state++;
-
- dgoto(++R->sp, DNS_R_INIT);
- case DNS_R_RESOLV1_NS:
- if (!(len = dns_d_expand(u.host, sizeof u.host, 12, F[1].query, &error)))
- goto error;
- else if (len >= sizeof u.host)
- goto toolong;
-
- dns_rr_foreach(&rr, F[1].answer, .name = u.host, .type = DNS_T_A, .section = (DNS_S_ALL & ~DNS_S_QD)) {
- rr.section = DNS_S_AR;
-
- if ((error = dns_rr_copy(F->hints, &rr, F[1].answer)))
- goto error;
-
- dns_rr_i_rewind(&F->hints_i); /* Now there's glue. */
- }
-
- dgoto(R->sp, DNS_R_FOREACH_NS);
- case DNS_R_FOREACH_A: {
- struct dns_a a;
- struct sockaddr_in sin;
-
- /*
- * NOTE: Iterator initialized in DNS_R_FOREACH_NS because
- * this state is re-entrant, but we need to reset
- * .name to a valid pointer each time.
- */
- if ((error = dns_ns_parse(&u.ns, &F->hints_ns, F->hints)))
- goto error;
-
- F->hints_j.name = u.ns.host;
- F->hints_j.type = DNS_T_A;
- F->hints_j.section = DNS_S_ALL & ~DNS_S_QD;
-
- if (!dns_rr_grep(&rr, 1, &F->hints_j, F->hints, &error)) {
- if (!dns_rr_i_count(&F->hints_j))
- dgoto(R->sp, DNS_R_RESOLV0_NS);
-
- dgoto(R->sp, DNS_R_FOREACH_NS);
- }
-
- if ((error = dns_a_parse(&a, &rr, F->hints)))
- goto error;
-
- sin.sin_family = AF_INET;
- sin.sin_addr = a.addr;
- if (R->sp == 0)
- sin.sin_port = dns_hints_port(R->hints, AF_INET, &sin.sin_addr);
- else
- sin.sin_port = htons(53);
-
- if (DNS_DEBUG) {
- char addr[INET_ADDRSTRLEN + 1];
- dns_a_print(addr, sizeof addr, &a);
- DNS_HEADER(F->query)->qid = dns_so_mkqid(&R->so);
- DNS_SHOW(F->query, "ASKING: %s/%s @ DEPTH: %u)", u.ns.host, addr, R->sp);
- }
-
- if ((error = dns_so_submit(&R->so, F->query, (struct sockaddr *)&sin)))
- goto error;
-
- F->state++;
- }
- /* FALL THROUGH */
- case DNS_R_QUERY_A:
- if (dns_so_elapsed(&R->so) >= dns_resconf_timeout(R->resconf))
- dgoto(R->sp, DNS_R_FOREACH_A);
-
- if ((error = dns_so_check(&R->so)))
- goto error;
-
- if (!dns_p_setptr(&F->answer, dns_so_fetch(&R->so, &error)))
- goto error;
-
- if (DNS_DEBUG) {
- DNS_SHOW(F->answer, "ANSWER @ DEPTH: %u)", R->sp);
- }
-
- if (dns_p_rcode(F->answer) == DNS_RC_FORMERR ||
- dns_p_rcode(F->answer) == DNS_RC_NOTIMP ||
- dns_p_rcode(F->answer) == DNS_RC_BADVERS) {
- /* Temporarily disable EDNS0 and try again. */
- if (F->qflags & DNS_Q_EDNS0) {
- F->qflags &= ~DNS_Q_EDNS0;
- if ((error = dns_q_remake(&F->query, F->qflags)))
- goto error;
-
- dgoto(R->sp, DNS_R_FOREACH_A);
- }
- }
-
- if ((error = dns_rr_parse(&rr, 12, F->query)))
- goto error;
-
- if (!(len = dns_d_expand(u.name, sizeof u.name, rr.dn.p, F->query, &error)))
- goto error;
- else if (len >= sizeof u.name)
- goto toolong;
-
- dns_rr_foreach(&rr, F->answer, .section = DNS_S_AN, .name = u.name, .type = rr.type) {
- dgoto(R->sp, DNS_R_FINISH); /* Found */
- }
-
- dns_rr_foreach(&rr, F->answer, .section = DNS_S_AN, .name = u.name, .type = DNS_T_CNAME) {
- F->ans_cname = rr;
-
- dgoto(R->sp, DNS_R_CNAME0_A);
- }
-
- /*
- * XXX: The condition here should probably check whether
- * R->sp == 0, because DNS_R_SEARCH runs regardless of
- * options.recurse. See DNS_R_BIND.
- */
- if (!R->resconf->options.recurse) {
- /* Make first answer our tentative answer */
- if (!R->nodata)
- dns_p_movptr(&R->nodata, &F->answer);
-
- dgoto(R->sp, DNS_R_SEARCH);
- }
-
- dns_rr_foreach(&rr, F->answer, .section = DNS_S_NS, .type = DNS_T_NS) {
- dns_p_movptr(&F->hints, &F->answer);
-
- dgoto(R->sp, DNS_R_ITERATE);
- }
-
- /* XXX: Should this go further up? */
- if (DNS_HEADER(F->answer)->aa)
- dgoto(R->sp, DNS_R_FINISH);
-
- /* XXX: Should we copy F->answer to R->nodata? */
-
- dgoto(R->sp, DNS_R_FOREACH_A);
- case DNS_R_CNAME0_A:
- if (&F[1] >= endof(R->stack))
- dgoto(R->sp, DNS_R_FINISH);
-
- if ((error = dns_cname_parse(&u.cname, &F->ans_cname, F->answer)))
- goto error;
- if ((error = dns_res_frame_prepare(R, &F[1], u.cname.host, dns_rr_type(12, F->query), DNS_C_IN)))
- goto error;
-
- F->state++;
-
- dgoto(++R->sp, DNS_R_INIT);
- case DNS_R_CNAME1_A:
- if (!(P = dns_res_merge(F->answer, F[1].answer, &error)))
- goto error;
-
- dns_p_setptr(&F->answer, P);
-
- dgoto(R->sp, DNS_R_FINISH);
- case DNS_R_FINISH:
- if (!F->answer)
- goto noanswer;
-
- if (!R->resconf->options.smart || R->sp > 0)
- dgoto(R->sp, DNS_R_DONE);
-
- R->smart.section = DNS_S_AN;
- R->smart.type = R->qtype;
-
- dns_rr_i_init(&R->smart, F->answer);
-
- F->state++;
- /* FALL THROUGH */
- case DNS_R_SMART0_A:
- if (&F[1] >= endof(R->stack))
- dgoto(R->sp, DNS_R_DONE);
-
- while (dns_rr_grep(&rr, 1, &R->smart, F->answer, &error)) {
- union {
- struct dns_ns ns;
- struct dns_mx mx;
- struct dns_srv srv;
- } rd;
- char *qname;
- enum dns_type qtype;
- enum dns_class qclass;
-
- switch (rr.type) {
- case DNS_T_NS:
- if ((error = dns_ns_parse(&rd.ns, &rr, F->answer)))
- goto error;
-
- qname = rd.ns.host;
- qtype = DNS_T_A;
- qclass = DNS_C_IN;
-
- break;
- case DNS_T_MX:
- if ((error = dns_mx_parse(&rd.mx, &rr, F->answer)))
- goto error;
-
- qname = rd.mx.host;
- qtype = DNS_T_A;
- qclass = DNS_C_IN;
-
- break;
- case DNS_T_SRV:
- if ((error = dns_srv_parse(&rd.srv, &rr, F->answer)))
- goto error;
-
- qname = rd.srv.target;
- qtype = DNS_T_A;
- qclass = DNS_C_IN;
-
- break;
- default:
- continue;
- } /* switch() */
-
- if ((error = dns_res_frame_prepare(R, &F[1], qname, qtype, qclass)))
- goto error;
-
- F->state++;
-
- dgoto(++R->sp, DNS_R_INIT);
- } /* while() */
-
- /*
- * NOTE: SMTP specification says to fallback to A record.
- *
- * XXX: Should we add a mock MX answer?
- */
- if (R->qtype == DNS_T_MX && R->smart.state.count == 0) {
- if ((error = dns_res_frame_prepare(R, &F[1], R->qname, DNS_T_A, DNS_C_IN)))
- goto error;
-
- R->smart.state.count++;
- F->state++;
-
- dgoto(++R->sp, DNS_R_INIT);
- }
-
- dgoto(R->sp, DNS_R_DONE);
- case DNS_R_SMART1_A:
- if (!F[1].answer)
- goto noanswer;
-
- /*
- * FIXME: For CNAME chains (which are typically illegal in
- * this context), we should rewrite the record host name
- * to the original smart qname. All the user cares about
- * is locating that A/AAAA record.
- */
- dns_rr_foreach(&rr, F[1].answer, .section = DNS_S_AN, .type = DNS_T_A) {
- rr.section = DNS_S_AR;
-
- if (dns_rr_exists(&rr, F[1].answer, F->answer))
- continue;
-
- while ((error = dns_rr_copy(F->answer, &rr, F[1].answer))) {
- if (error != DNS_ENOBUFS)
- goto error;
- if ((error = dns_p_grow(&F->answer)))
- goto error;
- }
- }
-
- dgoto(R->sp, DNS_R_SMART0_A);
- case DNS_R_DONE:
- if (!F->answer)
- goto noanswer;
-
- if (R->sp > 0)
- dgoto(--R->sp, F[-1].state);
-
- break;
- case DNS_R_SERVFAIL:
- if (!dns_p_setptr(&F->answer, dns_p_make(DNS_P_QBUFSIZ, &error)))
- goto error;
-
- DNS_HEADER(F->answer)->qr = 1;
- DNS_HEADER(F->answer)->rcode = DNS_RC_SERVFAIL;
-
- if ((error = dns_p_push(F->answer, DNS_S_QD, R->qname, strlen(R->qname), R->qtype, R->qclass, 0, 0)))
- goto error;
-
- dgoto(R->sp, DNS_R_DONE);
- default:
- error = EINVAL;
-
- goto error;
- } /* switch () */
-
- return 0;
-noquery:
- error = DNS_ENOQUERY;
-
- goto error;
-noanswer:
- error = DNS_ENOANSWER;
-
- goto error;
-toolong:
- error = DNS_EILLEGAL;
-
- /* FALL THROUGH */
-error:
- return error;
-} /* dns_res_exec() */
-
-#undef goto
-
-
-void dns_res_clear(struct dns_resolver *R) {
- switch (R->stack[R->sp].state) {
- case DNS_R_CHECK:
- R->cache->clear(R->cache);
- break;
- default:
- dns_so_clear(&R->so);
- break;
- }
-} /* dns_res_clear() */
-
-
-static int dns_res_events2(struct dns_resolver *R, enum dns_events type) {
- int events;
-
- switch (R->stack[R->sp].state) {
- case DNS_R_CHECK:
- events = R->cache->events(R->cache);
-
- return (type == DNS_LIBEVENT)? DNS_POLL2EV(events) : events;
- default:
- return dns_so_events2(&R->so, type);
- }
-} /* dns_res_events2() */
-
-
-int dns_res_events(struct dns_resolver *R) {
- return dns_res_events2(R, R->so.opts.events);
-} /* dns_res_events() */
-
-
-int dns_res_pollfd(struct dns_resolver *R) {
- switch (R->stack[R->sp].state) {
- case DNS_R_CHECK:
- return R->cache->pollfd(R->cache);
- default:
- return dns_so_pollfd(&R->so);
- }
-} /* dns_res_pollfd() */
-
-
-time_t dns_res_timeout(struct dns_resolver *R) {
- time_t elapsed;
-
- switch (R->stack[R->sp].state) {
-#if 0
- case DNS_R_QUERY_AAAA:
-#endif
- case DNS_R_QUERY_A:
- elapsed = dns_so_elapsed(&R->so);
-
- if (elapsed <= dns_resconf_timeout(R->resconf))
- return R->resconf->options.timeout - elapsed;
-
- break;
- default:
- break;
- } /* switch() */
-
- /*
- * NOTE: We're not in a pollable state, or the user code hasn't
- * called dns_res_check properly. The calling code is probably
- * broken. Put them into a slow-burn pattern.
- */
- return 1;
-} /* dns_res_timeout() */
-
-
-time_t dns_res_elapsed(struct dns_resolver *R) {
- return dns_elapsed(&R->elapsed);
-} /* dns_res_elapsed() */
-
-
-int dns_res_poll(struct dns_resolver *R, int timeout) {
- return dns_poll(dns_res_pollfd(R), dns_res_events2(R, DNS_SYSPOLL), timeout);
-} /* dns_res_poll() */
-
-
-int dns_res_submit2(struct dns_resolver *R, const char *qname, size_t qlen, enum dns_type qtype, enum dns_class qclass) {
- dns_res_reset(R);
-
- /* Don't anchor; that can conflict with searchlist generation. */
- dns_d_init(R->qname, sizeof R->qname, qname, (R->qlen = qlen), 0);
-
- R->qtype = qtype;
- R->qclass = qclass;
-
- dns_begin(&R->elapsed);
-
- return 0;
-} /* dns_res_submit2() */
-
-
-int dns_res_submit(struct dns_resolver *R, const char *qname, enum dns_type qtype, enum dns_class qclass) {
- return dns_res_submit2(R, qname, strlen(qname), qtype, qclass);
-} /* dns_res_submit() */
-
-
-int dns_res_check(struct dns_resolver *R) {
- int error;
-
- if (R->stack[0].state != DNS_R_DONE) {
- if ((error = dns_res_exec(R)))
- return error;
- }
-
- return 0;
-} /* dns_res_check() */
-
-
-struct dns_packet *dns_res_fetch(struct dns_resolver *R, int *error) {
- struct dns_packet *P = NULL;
-
- if (R->stack[0].state != DNS_R_DONE)
- return *error = DNS_EUNKNOWN, (void *)0;
-
- if (!dns_p_movptr(&P, &R->stack[0].answer))
- return *error = DNS_EFETCHED, (void *)0;
-
- return P;
-} /* dns_res_fetch() */
-
-
-static struct dns_packet *dns_res_fetch_and_study(struct dns_resolver *R, int *_error) {
- struct dns_packet *P = NULL;
- int error;
-
- if (!(P = dns_res_fetch(R, &error)))
- goto error;
- if ((error = dns_p_study(P)))
- goto error;
-
- return P;
-error:
- *_error = error;
-
- dns_p_free(P);
-
- return NULL;
-} /* dns_res_fetch_and_study() */
-
-
-struct dns_packet *dns_res_query(struct dns_resolver *res, const char *qname, enum dns_type qtype, enum dns_class qclass, int timeout, int *error_) {
- int error;
-
- if ((error = dns_res_submit(res, qname, qtype, qclass)))
- goto error;
-
- while ((error = dns_res_check(res))) {
- if (dns_res_elapsed(res) > timeout)
- error = DNS_ETIMEDOUT;
-
- if (error != DNS_EAGAIN)
- goto error;
-
- if ((error = dns_res_poll(res, 1)))
- goto error;
- }
-
- return dns_res_fetch(res, error_);
-error:
- *error_ = error;
-
- return 0;
-} /* dns_res_query() */
-
-
-const struct dns_stat *dns_res_stat(struct dns_resolver *res) {
- return dns_so_stat(&res->so);
-} /* dns_res_stat() */
-
-
-void dns_res_sethints(struct dns_resolver *res, struct dns_hints *hints) {
- dns_hints_acquire(hints); /* acquire first in case same hints object */
- dns_hints_close(res->hints);
- res->hints = hints;
-} /* dns_res_sethints() */
-
-
-/*
- * A D D R I N F O R O U T I N E S
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-struct dns_addrinfo {
- struct addrinfo hints;
- struct dns_resolver *res;
-
- char qname[DNS_D_MAXNAME + 1];
- enum dns_type qtype;
- unsigned short qport, port;
-
- struct {
- unsigned long todo;
- int state;
- int atype;
- enum dns_type qtype;
- } af;
-
- struct dns_packet *answer;
- struct dns_packet *glue;
-
- struct dns_rr_i i, g;
- struct dns_rr rr;
-
- char cname[DNS_D_MAXNAME + 1];
- char i_cname[DNS_D_MAXNAME + 1], g_cname[DNS_D_MAXNAME + 1];
-
- int g_depth;
-
- int state;
- int found;
-
- struct dns_stat st;
-}; /* struct dns_addrinfo */
-
-
-#define DNS_AI_AFMAX 32
-#define DNS_AI_AF2INDEX(af) (1UL << ((af) - 1))
-
-static inline unsigned long dns_ai_af2index(int af) {
- dns_static_assert(dns_same_type(unsigned long, DNS_AI_AF2INDEX(1), 1), "internal type mismatch");
- dns_static_assert(dns_same_type(unsigned long, ((struct dns_addrinfo *)0)->af.todo, 1), "internal type mismatch");
-
- return (af > 0 && af <= DNS_AI_AFMAX)? DNS_AI_AF2INDEX(af) : 0;
-}
-
-static int dns_ai_setaf(struct dns_addrinfo *ai, int af, int qtype) {
- ai->af.atype = af;
- ai->af.qtype = qtype;
-
- ai->af.todo &= ~dns_ai_af2index(af);
-
- return af;
-} /* dns_ai_setaf() */
-
-#define DNS_SM_RESTORE \
- do { pc = 0xff & (ai->af.state >> 0); i = 0xff & (ai->af.state >> 8); } while (0)
-#define DNS_SM_SAVE \
- do { ai->af.state = ((0xff & pc) << 0) | ((0xff & i) << 8); } while (0)
-
-static int dns_ai_nextaf(struct dns_addrinfo *ai) {
- int i, pc;
-
- dns_static_assert(AF_UNSPEC == 0, "AF_UNSPEC constant not 0");
- dns_static_assert(AF_INET <= DNS_AI_AFMAX, "AF_INET constant too large");
- dns_static_assert(AF_INET6 <= DNS_AI_AFMAX, "AF_INET6 constant too large");
-
- DNS_SM_ENTER;
-
- if (ai->res) {
- /*
- * NB: On OpenBSD, at least, the types of entries resolved
- * is the intersection of the /etc/resolv.conf families and
- * the families permitted by the .ai_type hint. So if
- * /etc/resolv.conf has "family inet4" and .ai_type
- * is AF_INET6, then the address ::1 will return 0 entries
- * even if AI_NUMERICHOST is specified in .ai_flags.
- */
- while (i < (int)lengthof(ai->res->resconf->family)) {
- int af = ai->res->resconf->family[i++];
-
- if (af == AF_UNSPEC) {
- DNS_SM_EXIT;
- } else if (af < 0 || af > DNS_AI_AFMAX) {
- continue;
- } else if (!(DNS_AI_AF2INDEX(af) & ai->af.todo)) {
- continue;
- } else if (af == AF_INET) {
- DNS_SM_YIELD(dns_ai_setaf(ai, AF_INET, DNS_T_A));
- } else if (af == AF_INET6) {
- DNS_SM_YIELD(dns_ai_setaf(ai, AF_INET6, DNS_T_AAAA));
- }
- }
- } else {
- /*
- * NB: If we get here than AI_NUMERICFLAGS should be set and
- * order shouldn't matter.
- */
- if (DNS_AI_AF2INDEX(AF_INET) & ai->af.todo)
- DNS_SM_YIELD(dns_ai_setaf(ai, AF_INET, DNS_T_A));
- if (DNS_AI_AF2INDEX(AF_INET6) & ai->af.todo)
- DNS_SM_YIELD(dns_ai_setaf(ai, AF_INET6, DNS_T_AAAA));
- }
-
- DNS_SM_LEAVE;
-
- return dns_ai_setaf(ai, AF_UNSPEC, 0);
-} /* dns_ai_nextaf() */
-
-#undef DNS_SM_RESTORE
-#undef DNS_SM_SAVE
-
-static enum dns_type dns_ai_qtype(struct dns_addrinfo *ai) {
- return (ai->qtype)? ai->qtype : ai->af.qtype;
-} /* dns_ai_qtype() */
-
-
-static dns_error_t dns_ai_parseport(unsigned short *port, const char *serv, const struct addrinfo *hints) {
- const char *cp = serv;
- unsigned long n = 0;
-
- while (*cp >= '0' && *cp <= '9' && n < 65536) {
- n *= 10;
- n += *cp++ - '0';
- }
-
- if (*cp == '\0') {
- if (cp == serv || n >= 65536)
- return DNS_ESERVICE;
-
- *port = n;
-
- return 0;
- }
-
- if (hints->ai_flags & AI_NUMERICSERV)
- return DNS_ESERVICE;
-
- /* TODO: try getaddrinfo(NULL, serv, { .ai_flags = AI_NUMERICSERV }) */
-
- return DNS_ESERVICE;
-} /* dns_ai_parseport() */
-
-
-struct dns_addrinfo *dns_ai_open(const char *host, const char *serv, enum dns_type qtype, const struct addrinfo *hints, struct dns_resolver *res, int *_error) {
- static const struct dns_addrinfo ai_initializer;
- struct dns_addrinfo *ai;
- int error;
-
- if (res) {
- dns_res_acquire(res);
- } else if (!(hints->ai_flags & AI_NUMERICHOST)) {
- /*
- * NOTE: it's assumed that *_error is set from a previous
- * API function call, such as dns_res_stub(). Should change
- * this semantic, but it's applied elsewhere, too.
- */
- if (!*_error)
- *_error = EINVAL;
- return NULL;
- }
-
- if (!(ai = malloc(sizeof *ai)))
- goto syerr;
-
- *ai = ai_initializer;
- ai->hints = *hints;
-
- ai->res = res;
- res = NULL;
-
- if (sizeof ai->qname <= dns_strlcpy(ai->qname, host, sizeof ai->qname))
- { error = ENAMETOOLONG; goto error; }
-
- ai->qtype = qtype;
- ai->qport = 0;
-
- if (serv && (error = dns_ai_parseport(&ai->qport, serv, hints)))
- goto error;
- ai->port = ai->qport;
-
- /*
- * FIXME: If an explicit A or AAAA record type conflicts with
- * .ai_family or with resconf.family (i.e. AAAA specified but
- * AF_INET6 not in interection of .ai_family and resconf.family),
- * then what?
- */
- switch (ai->qtype) {
- case DNS_T_A:
- ai->af.todo = DNS_AI_AF2INDEX(AF_INET);
- break;
- case DNS_T_AAAA:
- ai->af.todo = DNS_AI_AF2INDEX(AF_INET6);
- break;
- default: /* 0, MX, SRV, etc */
- switch (ai->hints.ai_family) {
- case AF_UNSPEC:
- ai->af.todo = DNS_AI_AF2INDEX(AF_INET) | DNS_AI_AF2INDEX(AF_INET6);
- break;
- case AF_INET:
- ai->af.todo = DNS_AI_AF2INDEX(AF_INET);
- break;
- case AF_INET6:
- ai->af.todo = DNS_AI_AF2INDEX(AF_INET6);
- break;
- default:
- break;
- }
- }
-
- return ai;
-syerr:
- error = dns_syerr();
-error:
- *_error = error;
-
- dns_ai_close(ai);
- dns_res_close(res);
-
- return NULL;
-} /* dns_ai_open() */
-
-
-void dns_ai_close(struct dns_addrinfo *ai) {
- if (!ai)
- return;
-
- dns_res_close(ai->res);
-
- if (ai->answer != ai->glue)
- dns_p_free(ai->glue);
-
- dns_p_free(ai->answer);
- free(ai);
-} /* dns_ai_close() */
-
-
-static int dns_ai_setent(struct addrinfo **ent, union dns_any *any, enum dns_type type, struct dns_addrinfo *ai) {
- union { struct sockaddr saddr; struct sockaddr_in sin; struct sockaddr_in6 sin6; } saddr;
- memset(&saddr, 0, sizeof(saddr));
- const char *cname;
- size_t clen;
-
- switch (type) {
- case DNS_T_A:
- saddr.sin.sin_family = AF_INET;
- saddr.sin.sin_port = htons(ai->port);
-
- memcpy(&saddr.sin.sin_addr, any, sizeof saddr.sin.sin_addr);
-
- break;
- case DNS_T_AAAA:
- saddr.sin6.sin6_family = AF_INET6;
- saddr.sin6.sin6_port = htons(ai->port);
-
- memcpy(&saddr.sin6.sin6_addr, any, sizeof saddr.sin6.sin6_addr);
-
- break;
- default:
- return EINVAL;
- } /* switch() */
-
- if (ai->hints.ai_flags & AI_CANONNAME) {
- cname = (*ai->cname)? ai->cname : ai->qname;
- clen = strlen(cname);
- } else {
- cname = NULL;
- clen = 0;
- }
-
- if (!(*ent = malloc(sizeof **ent + dns_sa_len(&saddr) + ((ai->hints.ai_flags & AI_CANONNAME)? clen + 1 : 0))))
- return dns_syerr();
-
- memset(*ent, '\0', sizeof **ent);
-
- (*ent)->ai_family = saddr.saddr.sa_family;
- (*ent)->ai_socktype = ai->hints.ai_socktype;
- (*ent)->ai_protocol = ai->hints.ai_protocol;
-
- (*ent)->ai_addr = memcpy((unsigned char *)*ent + sizeof **ent, &saddr, dns_sa_len(&saddr));
- (*ent)->ai_addrlen = dns_sa_len(&saddr);
-
- if (ai->hints.ai_flags & AI_CANONNAME)
- (*ent)->ai_canonname = memcpy((unsigned char *)*ent + sizeof **ent + dns_sa_len(&saddr), cname, clen + 1);
-
- ai->found++;
-
- return 0;
-} /* dns_ai_setent() */
-
-
-enum dns_ai_state {
- DNS_AI_S_INIT,
- DNS_AI_S_NEXTAF,
- DNS_AI_S_NUMERIC,
- DNS_AI_S_SUBMIT,
- DNS_AI_S_CHECK,
- DNS_AI_S_FETCH,
- DNS_AI_S_FOREACH_I,
- DNS_AI_S_INIT_G,
- DNS_AI_S_ITERATE_G,
- DNS_AI_S_FOREACH_G,
- DNS_AI_S_SUBMIT_G,
- DNS_AI_S_CHECK_G,
- DNS_AI_S_FETCH_G,
- DNS_AI_S_DONE,
-}; /* enum dns_ai_state */
-
-#define dns_ai_goto(which) do { ai->state = (which); goto exec; } while (0)
-
-int dns_ai_nextent(struct addrinfo **ent, struct dns_addrinfo *ai) {
- struct dns_packet *ans, *glue;
- struct dns_rr rr;
- char qname[DNS_D_MAXNAME + 1];
- union dns_any any;
- size_t qlen, clen;
- int error;
-
- *ent = 0;
-
-exec:
-
- switch (ai->state) {
- case DNS_AI_S_INIT:
- ai->state++;
- /* FALL THROUGH */
- case DNS_AI_S_NEXTAF:
- if (!dns_ai_nextaf(ai))
- dns_ai_goto(DNS_AI_S_DONE);
-
- ai->state++;
- /* FALL THROUGH */
- case DNS_AI_S_NUMERIC:
- if (1 == dns_inet_pton(AF_INET, ai->qname, &any.a)) {
- if (ai->af.atype == AF_INET) {
- ai->state = DNS_AI_S_NEXTAF;
- return dns_ai_setent(ent, &any, DNS_T_A, ai);
- } else {
- dns_ai_goto(DNS_AI_S_NEXTAF);
- }
- }
-
- if (1 == dns_inet_pton(AF_INET6, ai->qname, &any.aaaa)) {
- if (ai->af.atype == AF_INET6) {
- ai->state = DNS_AI_S_NEXTAF;
- return dns_ai_setent(ent, &any, DNS_T_AAAA, ai);
- } else {
- dns_ai_goto(DNS_AI_S_NEXTAF);
- }
- }
-
- if (ai->hints.ai_flags & AI_NUMERICHOST)
- dns_ai_goto(DNS_AI_S_NEXTAF);
-
- ai->state++;
- /* FALL THROUGH */
- case DNS_AI_S_SUBMIT:
- assert(ai->res);
-
- if ((error = dns_res_submit(ai->res, ai->qname, dns_ai_qtype(ai), DNS_C_IN)))
- return error;
-
- ai->state++;
- /* FALL THROUGH */
- case DNS_AI_S_CHECK:
- if ((error = dns_res_check(ai->res)))
- return error;
-
- ai->state++;
- /* FALL THROUGH */
- case DNS_AI_S_FETCH:
- if (!(ans = dns_res_fetch_and_study(ai->res, &error)))
- return error;
- if (ai->glue != ai->answer)
- dns_p_free(ai->glue);
- ai->glue = dns_p_movptr(&ai->answer, &ans);
-
- /* Search generator may have changed the qname. */
- if (!(qlen = dns_d_expand(qname, sizeof qname, 12, ai->answer, &error)))
- return error;
- else if (qlen >= sizeof qname)
- return DNS_EILLEGAL;
- if (!dns_d_cname(ai->cname, sizeof ai->cname, qname, qlen, ai->answer, &error))
- return error;
-
- dns_strlcpy(ai->i_cname, ai->cname, sizeof ai->i_cname);
- dns_rr_i_init(&ai->i, ai->answer);
- ai->i.section = DNS_S_AN;
- ai->i.name = ai->i_cname;
- ai->i.type = dns_ai_qtype(ai);
- ai->i.sort = &dns_rr_i_order;
-
- ai->state++;
- /* FALL THROUGH */
- case DNS_AI_S_FOREACH_I:
- if (!dns_rr_grep(&rr, 1, &ai->i, ai->answer, &error))
- dns_ai_goto(DNS_AI_S_NEXTAF);
-
- if ((error = dns_any_parse(&any, &rr, ai->answer)))
- return error;
-
- ai->port = ai->qport;
-
- switch (rr.type) {
- case DNS_T_A:
- case DNS_T_AAAA:
- return dns_ai_setent(ent, &any, rr.type, ai);
- default:
- if (!(clen = dns_any_cname(ai->cname, sizeof ai->cname, &any, rr.type)))
- dns_ai_goto(DNS_AI_S_FOREACH_I);
-
- /*
- * Find the "real" canonical name. Some authorities
- * publish aliases where an RFC defines a canonical
- * name. We trust that the resolver followed any
- * CNAME chains on it's own, regardless of whether
- * the "smart" option is enabled.
- */
- if (!dns_d_cname(ai->cname, sizeof ai->cname, ai->cname, clen, ai->answer, &error))
- return error;
-
- if (rr.type == DNS_T_SRV)
- ai->port = any.srv.port;
-
- break;
- } /* switch() */
-
- ai->state++;
- /* FALL THROUGH */
- case DNS_AI_S_INIT_G:
- ai->g_depth = 0;
-
- ai->state++;
- /* FALL THROUGH */
- case DNS_AI_S_ITERATE_G:
- dns_strlcpy(ai->g_cname, ai->cname, sizeof ai->g_cname);
- dns_rr_i_init(&ai->g, ai->glue);
- ai->g.section = DNS_S_ALL & ~DNS_S_QD;
- ai->g.name = ai->g_cname;
- ai->g.type = ai->af.qtype;
-
- ai->state++;
- /* FALL THROUGH */
- case DNS_AI_S_FOREACH_G:
- if (!dns_rr_grep(&rr, 1, &ai->g, ai->glue, &error)) {
- if (dns_rr_i_count(&ai->g) > 0)
- dns_ai_goto(DNS_AI_S_FOREACH_I);
- else
- dns_ai_goto(DNS_AI_S_SUBMIT_G);
- }
-
- if ((error = dns_any_parse(&any, &rr, ai->glue)))
- return error;
-
- return dns_ai_setent(ent, &any, rr.type, ai);
- case DNS_AI_S_SUBMIT_G:
- /* skip if already queried */
- if (dns_rr_grep(&rr, 1, dns_rr_i_new(ai->glue, .section = DNS_S_QD, .name = ai->g.name, .type = ai->g.type), ai->glue, &error))
- dns_ai_goto(DNS_AI_S_FOREACH_I);
- /* skip if we recursed (CNAME chains should have been handled in the resolver) */
- if (++ai->g_depth > 1)
- dns_ai_goto(DNS_AI_S_FOREACH_I);
-
- if ((error = dns_res_submit(ai->res, ai->g.name, ai->g.type, DNS_C_IN)))
- return error;
-
- ai->state++;
- /* FALL THROUGH */
- case DNS_AI_S_CHECK_G:
- if ((error = dns_res_check(ai->res)))
- return error;
-
- ai->state++;
- /* FALL THROUGH */
- case DNS_AI_S_FETCH_G:
- if (!(ans = dns_res_fetch_and_study(ai->res, &error)))
- return error;
-
- glue = dns_p_merge(ai->glue, DNS_S_ALL, ans, DNS_S_ALL, &error);
- dns_p_setptr(&ans, NULL);
- if (!glue)
- return error;
-
- if (ai->glue != ai->answer)
- dns_p_free(ai->glue);
- ai->glue = glue;
-
- if (!dns_d_cname(ai->cname, sizeof ai->cname, ai->g.name, strlen(ai->g.name), ai->glue, &error))
- dns_ai_goto(DNS_AI_S_FOREACH_I);
-
- dns_ai_goto(DNS_AI_S_ITERATE_G);
- case DNS_AI_S_DONE:
- if (ai->found) {
- return ENOENT; /* TODO: Just return 0 */
- } else if (ai->answer) {
- switch (dns_p_rcode(ai->answer)) {
- case DNS_RC_NOERROR:
- /* FALL THROUGH */
- case DNS_RC_NXDOMAIN:
- return DNS_ENONAME;
- default:
- return DNS_EFAIL;
- }
- } else {
- return DNS_EFAIL;
- }
- default:
- return EINVAL;
- } /* switch() */
-} /* dns_ai_nextent() */
-
-
-time_t dns_ai_elapsed(struct dns_addrinfo *ai) {
- return (ai->res)? dns_res_elapsed(ai->res) : 0;
-} /* dns_ai_elapsed() */
-
-
-void dns_ai_clear(struct dns_addrinfo *ai) {
- if (ai->res)
- dns_res_clear(ai->res);
-} /* dns_ai_clear() */
-
-
-int dns_ai_events(struct dns_addrinfo *ai) {
- return (ai->res)? dns_res_events(ai->res) : 0;
-} /* dns_ai_events() */
-
-
-int dns_ai_pollfd(struct dns_addrinfo *ai) {
- return (ai->res)? dns_res_pollfd(ai->res) : -1;
-} /* dns_ai_pollfd() */
-
-
-time_t dns_ai_timeout(struct dns_addrinfo *ai) {
- return (ai->res)? dns_res_timeout(ai->res) : 0;
-} /* dns_ai_timeout() */
-
-
-int dns_ai_poll(struct dns_addrinfo *ai, int timeout) {
- return (ai->res)? dns_res_poll(ai->res, timeout) : 0;
-} /* dns_ai_poll() */
-
-
-size_t dns_ai_print(void *_dst, size_t lim, struct addrinfo *ent, struct dns_addrinfo *ai) {
- struct dns_buf dst = DNS_B_INTO(_dst, lim);
- char addr[DNS_PP_MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) + 1];
-
- dns_b_puts(&dst, "[ ");
- dns_b_puts(&dst, ai->qname);
- dns_b_puts(&dst, " IN ");
- if (ai->qtype) {
- dns_b_puts(&dst, dns_strtype(ai->qtype));
- } else if (ent->ai_family == AF_INET) {
- dns_b_puts(&dst, dns_strtype(DNS_T_A));
- } else if (ent->ai_family == AF_INET6) {
- dns_b_puts(&dst, dns_strtype(DNS_T_AAAA));
- } else {
- dns_b_puts(&dst, "0");
- }
- dns_b_puts(&dst, " ]\n");
-
- dns_b_puts(&dst, ".ai_family = ");
- switch (ent->ai_family) {
- case AF_INET:
- dns_b_puts(&dst, "AF_INET");
- break;
- case AF_INET6:
- dns_b_puts(&dst, "AF_INET6");
- break;
- default:
- dns_b_fmtju(&dst, ent->ai_family, 0);
- break;
- }
- dns_b_putc(&dst, '\n');
-
- dns_b_puts(&dst, ".ai_socktype = ");
- switch (ent->ai_socktype) {
- case SOCK_STREAM:
- dns_b_puts(&dst, "SOCK_STREAM");
- break;
- case SOCK_DGRAM:
- dns_b_puts(&dst, "SOCK_DGRAM");
- break;
- default:
- dns_b_fmtju(&dst, ent->ai_socktype, 0);
- break;
- }
- dns_b_putc(&dst, '\n');
-
- dns_inet_ntop(dns_sa_family(ent->ai_addr), dns_sa_addr(dns_sa_family(ent->ai_addr), ent->ai_addr, NULL), addr, sizeof addr);
- dns_b_puts(&dst, ".ai_addr = [");
- dns_b_puts(&dst, addr);
- dns_b_puts(&dst, "]:");
- dns_b_fmtju(&dst, ntohs(*dns_sa_port(dns_sa_family(ent->ai_addr), ent->ai_addr)), 0);
- dns_b_putc(&dst, '\n');
-
- dns_b_puts(&dst, ".ai_canonname = ");
- dns_b_puts(&dst, (ent->ai_canonname)? ent->ai_canonname : "[NULL]");
- dns_b_putc(&dst, '\n');
-
- return dns_b_strllen(&dst);
-} /* dns_ai_print() */
-
-
-const struct dns_stat *dns_ai_stat(struct dns_addrinfo *ai) {
- return (ai->res)? dns_res_stat(ai->res) : &ai->st;
-} /* dns_ai_stat() */
-
-
-/*
- * M I S C E L L A N E O U S R O U T I N E S
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-static const struct {
- char name[16];
- enum dns_section type;
-} dns_sections[] = {
- { "QUESTION", DNS_S_QUESTION },
- { "QD", DNS_S_QUESTION },
- { "ANSWER", DNS_S_ANSWER },
- { "AN", DNS_S_ANSWER },
- { "AUTHORITY", DNS_S_AUTHORITY },
- { "NS", DNS_S_AUTHORITY },
- { "ADDITIONAL", DNS_S_ADDITIONAL },
- { "AR", DNS_S_ADDITIONAL },
-};
-
-const char *(dns_strsection)(enum dns_section section, void *_dst, size_t lim) {
- struct dns_buf dst = DNS_B_INTO(_dst, lim);
- unsigned i;
-
- for (i = 0; i < lengthof(dns_sections); i++) {
- if (dns_sections[i].type & section) {
- dns_b_puts(&dst, dns_sections[i].name);
- section &= ~dns_sections[i].type;
- if (section)
- dns_b_putc(&dst, '|');
- }
- }
-
- if (section || dst.p == dst.base)
- dns_b_fmtju(&dst, (0xffff & section), 0);
-
- return dns_b_tostring(&dst);
-} /* dns_strsection() */
-
-
-enum dns_section dns_isection(const char *src) {
- enum dns_section section = 0;
- char sbuf[128];
- char *name, *next;
- unsigned i;
-
- dns_strlcpy(sbuf, src, sizeof sbuf);
- next = sbuf;
-
- while ((name = dns_strsep(&next, "|+, \t"))) {
- for (i = 0; i < lengthof(dns_sections); i++) {
- if (!strcasecmp(dns_sections[i].name, name)) {
- section |= dns_sections[i].type;
- break;
- }
- }
- }
-
- return section;
-} /* dns_isection() */
-
-
-static const struct {
- char name[8];
- enum dns_class type;
-} dns_classes[] = {
- { "IN", DNS_C_IN },
-};
-
-const char *(dns_strclass)(enum dns_class type, void *_dst, size_t lim) {
- struct dns_buf dst = DNS_B_INTO(_dst, lim);
- unsigned i;
-
- for (i = 0; i < lengthof(dns_classes); i++) {
- if (dns_classes[i].type == type) {
- dns_b_puts(&dst, dns_classes[i].name);
- break;
- }
- }
-
- if (dst.p == dst.base)
- dns_b_fmtju(&dst, (0xffff & type), 0);
-
- return dns_b_tostring(&dst);
-} /* dns_strclass() */
-
-
-enum dns_class dns_iclass(const char *name) {
- unsigned i, class;
-
- for (i = 0; i < lengthof(dns_classes); i++) {
- if (!strcasecmp(dns_classes[i].name, name))
- return dns_classes[i].type;
- }
-
- class = 0;
- while (dns_isdigit(*name)) {
- class *= 10;
- class += *name++ - '0';
- }
-
- return DNS_PP_MIN(class, 0xffff);
-} /* dns_iclass() */
-
-
-const char *(dns_strtype)(enum dns_type type, void *_dst, size_t lim) {
- struct dns_buf dst = DNS_B_INTO(_dst, lim);
- unsigned i;
-
- for (i = 0; i < lengthof(dns_rrtypes); i++) {
- if (dns_rrtypes[i].type == type) {
- dns_b_puts(&dst, dns_rrtypes[i].name);
- break;
- }
- }
-
- if (dst.p == dst.base)
- dns_b_fmtju(&dst, (0xffff & type), 0);
-
- return dns_b_tostring(&dst);
-} /* dns_strtype() */
-
-
-enum dns_type dns_itype(const char *name) {
- unsigned i, type;
-
- for (i = 0; i < lengthof(dns_rrtypes); i++) {
- if (!strcasecmp(dns_rrtypes[i].name, name))
- return dns_rrtypes[i].type;
- }
-
- type = 0;
- while (dns_isdigit(*name)) {
- type *= 10;
- type += *name++ - '0';
- }
-
- return DNS_PP_MIN(type, 0xffff);
-} /* dns_itype() */
-
-
-static char dns_opcodes[16][16] = {
- [DNS_OP_QUERY] = "QUERY",
- [DNS_OP_IQUERY] = "IQUERY",
- [DNS_OP_STATUS] = "STATUS",
- [DNS_OP_NOTIFY] = "NOTIFY",
- [DNS_OP_UPDATE] = "UPDATE",
-};
-
-static char *dns__strcode(int code, char *dst, size_t lim) {
- char _tmp[48] = "";
- struct dns_buf tmp;
- size_t p;
-
- assert(lim > 0);
- dns_b_fmtju(dns_b_into(&tmp, _tmp, DNS_PP_MIN(sizeof _tmp, lim - 1)), code, 0);
-
- /* copy downwards so first byte is copied last (see below) */
- p = (size_t)(tmp.p - tmp.base);
- dst[p] = '\0';
- while (p--)
- dst[p] = _tmp[p];
-
- return (char *)dst;
-}
-
-const char *dns_stropcode(enum dns_opcode opcode) {
- opcode = (unsigned)opcode % lengthof(dns_opcodes);
-
- if ('\0' == dns_opcodes[opcode][0])
- return dns__strcode(opcode, dns_opcodes[opcode], sizeof dns_opcodes[opcode]);
-
- return dns_opcodes[opcode];
-} /* dns_stropcode() */
-
-
-enum dns_opcode dns_iopcode(const char *name) {
- unsigned opcode;
-
- for (opcode = 0; opcode < lengthof(dns_opcodes); opcode++) {
- if (!strcasecmp(name, dns_opcodes[opcode]))
- return opcode;
- }
-
- opcode = 0;
- while (dns_isdigit(*name)) {
- opcode *= 10;
- opcode += *name++ - '0';
- }
-
- return DNS_PP_MIN(opcode, 0x0f);
-} /* dns_iopcode() */
-
-
-static char dns_rcodes[32][16] = {
- [DNS_RC_NOERROR] = "NOERROR",
- [DNS_RC_FORMERR] = "FORMERR",
- [DNS_RC_SERVFAIL] = "SERVFAIL",
- [DNS_RC_NXDOMAIN] = "NXDOMAIN",
- [DNS_RC_NOTIMP] = "NOTIMP",
- [DNS_RC_REFUSED] = "REFUSED",
- [DNS_RC_YXDOMAIN] = "YXDOMAIN",
- [DNS_RC_YXRRSET] = "YXRRSET",
- [DNS_RC_NXRRSET] = "NXRRSET",
- [DNS_RC_NOTAUTH] = "NOTAUTH",
- [DNS_RC_NOTZONE] = "NOTZONE",
- /* EDNS(0) extended RCODEs ... */
- [DNS_RC_BADVERS] = "BADVERS",
-};
-
-const char *dns_strrcode(enum dns_rcode rcode) {
- rcode = (unsigned)rcode % lengthof(dns_rcodes);
-
- if ('\0' == dns_rcodes[rcode][0])
- return dns__strcode(rcode, dns_rcodes[rcode], sizeof dns_rcodes[rcode]);
-
- return dns_rcodes[rcode];
-} /* dns_strrcode() */
-
-
-enum dns_rcode dns_ircode(const char *name) {
- unsigned rcode;
-
- for (rcode = 0; rcode < lengthof(dns_rcodes); rcode++) {
- if (!strcasecmp(name, dns_rcodes[rcode]))
- return rcode;
- }
-
- rcode = 0;
- while (dns_isdigit(*name)) {
- rcode *= 10;
- rcode += *name++ - '0';
- }
-
- return DNS_PP_MIN(rcode, 0xfff);
-} /* dns_ircode() */
-
-
-
-/*
- * C O M M A N D - L I N E / R E G R E S S I O N R O U T I N E S
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-#if DNS_MAIN
-
-#include
-#include
-#include
-
-#include
-
-#if _WIN32
-#include
-#endif
-
-#if !_WIN32
-#include
-#endif
-
-
-struct {
- struct {
- const char *path[8];
- unsigned count;
- } resconf, nssconf, hosts, cache;
-
- const char *qname;
- enum dns_type qtype;
-
- int (*sort)();
-
- int verbose;
-} MAIN = {
- .sort = &dns_rr_i_packet,
-};
-
-
-static void hexdump(const unsigned char *src, size_t len, FILE *fp) {
- static const unsigned char hex[] = "0123456789abcdef";
- static const unsigned char tmpl[] = " | |\n";
- unsigned char ln[sizeof tmpl];
- const unsigned char *sp, *se;
- unsigned char *h, *g;
- unsigned i, n;
-
- sp = src;
- se = sp + len;
-
- while (sp < se) {
- memcpy(ln, tmpl, sizeof ln);
-
- h = &ln[2];
- g = &ln[53];
-
- for (n = 0; n < 2; n++) {
- for (i = 0; i < 8 && se - sp > 0; i++, sp++) {
- h[0] = hex[0x0f & (*sp >> 4)];
- h[1] = hex[0x0f & (*sp >> 0)];
- h += 3;
-
- *g++ = (isgraph(*sp))? *sp : '.';
- }
-
- h++;
- }
-
- fputs((char *)ln, fp);
- }
-
- return /* void */;
-} /* hexdump() */
-
-
-DNS_NORETURN static void panic(const char *fmt, ...) {
- va_list ap;
-
- va_start(ap, fmt);
-
-#if _WIN32
- vfprintf(stderr, fmt, ap);
-
- exit(EXIT_FAILURE);
-#else
- verrx(EXIT_FAILURE, fmt, ap);
-#endif
-} /* panic() */
-
-#define panic_(fn, ln, fmt, ...) \
- panic(fmt "%0s", (fn), (ln), __VA_ARGS__)
-#define panic(...) \
- panic_(__func__, __LINE__, "(%s:%d) " __VA_ARGS__, "")
-
-
-static void *grow(unsigned char *p, size_t size) {
- void *tmp;
-
- if (!(tmp = realloc(p, size)))
- panic("realloc(%"PRIuZ"): %s", size, dns_strerror(errno));
-
- return tmp;
-} /* grow() */
-
-
-static size_t add(size_t a, size_t b) {
- if (~a < b)
- panic("%"PRIuZ" + %"PRIuZ": integer overflow", a, b);
-
- return a + b;
-} /* add() */
-
-
-static size_t append(unsigned char **dst, size_t osize, const void *src, size_t len) {
- size_t size = add(osize, len);
-
- *dst = grow(*dst, size);
- memcpy(*dst + osize, src, len);
-
- return size;
-} /* append() */
-
-
-static size_t slurp(unsigned char **dst, size_t osize, FILE *fp, const char *path) {
- size_t size = osize;
- unsigned char buf[1024];
- size_t count;
-
- while ((count = fread(buf, 1, sizeof buf, fp)))
- size = append(dst, size, buf, count);
-
- if (ferror(fp))
- panic("%s: %s", path, dns_strerror(errno));
-
- return size;
-} /* slurp() */
-
-
-static struct dns_resolv_conf *resconf(void) {
- static struct dns_resolv_conf *resconf;
- const char *path;
- unsigned i;
- int error;
-
- if (resconf)
- return resconf;
-
- if (!(resconf = dns_resconf_open(&error)))
- panic("dns_resconf_open: %s", dns_strerror(error));
-
- if (!MAIN.resconf.count)
- MAIN.resconf.path[MAIN.resconf.count++] = "/etc/resolv.conf";
-
- for (i = 0; i < MAIN.resconf.count; i++) {
- path = MAIN.resconf.path[i];
-
- if (0 == strcmp(path, "-"))
- error = dns_resconf_loadfile(resconf, stdin);
- else
- error = dns_resconf_loadpath(resconf, path);
-
- if (error)
- panic("%s: %s", path, dns_strerror(error));
- }
-
- for (i = 0; i < MAIN.nssconf.count; i++) {
- path = MAIN.nssconf.path[i];
-
- if (0 == strcmp(path, "-"))
- error = dns_nssconf_loadfile(resconf, stdin);
- else
- error = dns_nssconf_loadpath(resconf, path);
-
- if (error)
- panic("%s: %s", path, dns_strerror(error));
- }
-
- if (!MAIN.nssconf.count) {
- path = "/etc/nsswitch.conf";
-
- if (!(error = dns_nssconf_loadpath(resconf, path)))
- MAIN.nssconf.path[MAIN.nssconf.count++] = path;
- else if (error != ENOENT)
- panic("%s: %s", path, dns_strerror(error));
- }
-
- return resconf;
-} /* resconf() */
-
-
-static struct dns_hosts *hosts(void) {
- static struct dns_hosts *hosts;
- const char *path;
- unsigned i;
- int error;
-
- if (hosts)
- return hosts;
-
- if (!MAIN.hosts.count) {
- MAIN.hosts.path[MAIN.hosts.count++] = "/etc/hosts";
-
- /* Explicitly test dns_hosts_local() */
- if (!(hosts = dns_hosts_local(&error)))
- panic("%s: %s", "/etc/hosts", dns_strerror(error));
-
- return hosts;
- }
-
- if (!(hosts = dns_hosts_open(&error)))
- panic("dns_hosts_open: %s", dns_strerror(error));
-
- for (i = 0; i < MAIN.hosts.count; i++) {
- path = MAIN.hosts.path[i];
-
- if (0 == strcmp(path, "-"))
- error = dns_hosts_loadfile(hosts, stdin);
- else
- error = dns_hosts_loadpath(hosts, path);
-
- if (error)
- panic("%s: %s", path, dns_strerror(error));
- }
-
- return hosts;
-} /* hosts() */
-
-
-#if DNS_CACHE
-#include "cache.h"
-
-static struct dns_cache *cache(void) {
- static struct cache *cache;
- const char *path;
- unsigned i;
- int error;
-
- if (cache)
- return cache_resi(cache);
- if (!MAIN.cache.count)
- return NULL;
-
- if (!(cache = cache_open(&error)))
- panic("%s: %s", MAIN.cache.path[0], dns_strerror(error));
-
- for (i = 0; i < MAIN.cache.count; i++) {
- path = MAIN.cache.path[i];
-
- if (!strcmp(path, "-")) {
- if ((error = cache_loadfile(cache, stdin, NULL, 0)))
- panic("%s: %s", path, dns_strerror(error));
- } else if ((error = cache_loadpath(cache, path, NULL, 0)))
- panic("%s: %s", path, dns_strerror(error));
- }
-
- return cache_resi(cache);
-} /* cache() */
-#else
-static struct dns_cache *cache(void) { return NULL; }
-#endif
-
-
-static void print_packet(struct dns_packet *P, FILE *fp) {
- dns_p_dump3(P, dns_rr_i_new(P, .sort = MAIN.sort), fp);
-
- if (MAIN.verbose > 2)
- hexdump(P->data, P->end, fp);
-} /* print_packet() */
-
-
-static int parse_packet(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
- struct dns_packet *P = dns_p_new(512);
- struct dns_packet *Q = dns_p_new(512);
- enum dns_section section;
- struct dns_rr rr;
- int error;
- union dns_any any;
- char pretty[sizeof any * 2];
- size_t len;
-
- P->end = fread(P->data, 1, P->size, stdin);
-
- fputs(";; [HEADER]\n", stdout);
- fprintf(stdout, ";; qr : %s(%d)\n", (DNS_HEADER(P)->qr)? "RESPONSE" : "QUERY", DNS_HEADER(P)->qr);
- fprintf(stdout, ";; opcode : %s(%d)\n", dns_stropcode(DNS_HEADER(P)->opcode), DNS_HEADER(P)->opcode);
- fprintf(stdout, ";; aa : %s(%d)\n", (DNS_HEADER(P)->aa)? "AUTHORITATIVE" : "NON-AUTHORITATIVE", DNS_HEADER(P)->aa);
- fprintf(stdout, ";; tc : %s(%d)\n", (DNS_HEADER(P)->tc)? "TRUNCATED" : "NOT-TRUNCATED", DNS_HEADER(P)->tc);
- fprintf(stdout, ";; rd : %s(%d)\n", (DNS_HEADER(P)->rd)? "RECURSION-DESIRED" : "RECURSION-NOT-DESIRED", DNS_HEADER(P)->rd);
- fprintf(stdout, ";; ra : %s(%d)\n", (DNS_HEADER(P)->ra)? "RECURSION-ALLOWED" : "RECURSION-NOT-ALLOWED", DNS_HEADER(P)->ra);
- fprintf(stdout, ";; rcode : %s(%d)\n", dns_strrcode(dns_p_rcode(P)), dns_p_rcode(P));
-
- section = 0;
-
- dns_rr_foreach(&rr, P, .sort = MAIN.sort) {
- if (section != rr.section)
- fprintf(stdout, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(P, rr.section));
-
- if ((len = dns_rr_print(pretty, sizeof pretty, &rr, P, &error)))
- fprintf(stdout, "%s\n", pretty);
-
- dns_rr_copy(Q, &rr, P);
-
- section = rr.section;
- }
-
- fputs("; ; ; ; ; ; ; ;\n\n", stdout);
-
- section = 0;
-
-#if 0
- dns_rr_foreach(&rr, Q, .name = "ns8.yahoo.com.") {
-#else
- struct dns_rr rrset[32];
- struct dns_rr_i *rri = dns_rr_i_new(Q, .name = dns_d_new("ns8.yahoo.com", DNS_D_ANCHOR), .sort = MAIN.sort);
- unsigned rrcount = dns_rr_grep(rrset, lengthof(rrset), rri, Q, &error);
-
- for (unsigned i = 0; i < rrcount; i++) {
- rr = rrset[i];
-#endif
- if (section != rr.section)
- fprintf(stdout, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(Q, rr.section));
-
- if ((len = dns_rr_print(pretty, sizeof pretty, &rr, Q, &error)))
- fprintf(stdout, "%s\n", pretty);
-
- section = rr.section;
- }
-
- if (MAIN.verbose > 1) {
- fprintf(stderr, "orig:%"PRIuZ"\n", P->end);
- hexdump(P->data, P->end, stdout);
-
- fprintf(stderr, "copy:%"PRIuZ"\n", Q->end);
- hexdump(Q->data, Q->end, stdout);
- }
-
- return 0;
-} /* parse_packet() */
-
-
-static int parse_domain(int argc, char *argv[]) {
- char *dn;
-
- dn = (argc > 1)? argv[1] : "f.l.google.com";
-
- printf("[%s]\n", dn);
-
- dn = dns_d_new(dn);
-
- do {
- puts(dn);
- } while (dns_d_cleave(dn, strlen(dn) + 1, dn, strlen(dn)));
-
- return 0;
-} /* parse_domain() */
-
-
-static int trim_domain(int argc, char **argv) {
- for (argc--, argv++; argc > 0; argc--, argv++) {
- char name[DNS_D_MAXNAME + 1];
-
- dns_d_trim(name, sizeof name, *argv, strlen(*argv), DNS_D_ANCHOR);
-
- puts(name);
- }
-
- return 0;
-} /* trim_domain() */
-
-
-static int expand_domain(int argc, char *argv[]) {
- unsigned short rp = 0;
- unsigned char *src = NULL;
- unsigned char *dst;
- struct dns_packet *pkt;
- size_t lim = 0, len;
- int error;
-
- if (argc > 1)
- rp = atoi(argv[1]);
-
- len = slurp(&src, 0, stdin, "-");
-
- if (!(pkt = dns_p_make(len, &error)))
- panic("malloc(%"PRIuZ"): %s", len, dns_strerror(error));
-
- memcpy(pkt->data, src, len);
- pkt->end = len;
-
- lim = 1;
- dst = grow(NULL, lim);
-
- while (lim <= (len = dns_d_expand(dst, lim, rp, pkt, &error))) {
- lim = add(len, 1);
- dst = grow(dst, lim);
- }
-
- if (!len)
- panic("expand: %s", dns_strerror(error));
-
- fwrite(dst, 1, len, stdout);
- fflush(stdout);
-
- free(src);
- free(dst);
- free(pkt);
-
- return 0;
-} /* expand_domain() */
-
-
-static int show_resconf(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
- unsigned i;
-
- resconf(); /* load it */
-
- fputs("; SOURCES\n", stdout);
-
- for (i = 0; i < MAIN.resconf.count; i++)
- fprintf(stdout, "; %s\n", MAIN.resconf.path[i]);
-
- for (i = 0; i < MAIN.nssconf.count; i++)
- fprintf(stdout, "; %s\n", MAIN.nssconf.path[i]);
-
- fputs(";\n", stdout);
-
- dns_resconf_dump(resconf(), stdout);
-
- return 0;
-} /* show_resconf() */
-
-
-static int show_nssconf(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
- unsigned i;
-
- resconf();
-
- fputs("# SOURCES\n", stdout);
-
- for (i = 0; i < MAIN.resconf.count; i++)
- fprintf(stdout, "# %s\n", MAIN.resconf.path[i]);
-
- for (i = 0; i < MAIN.nssconf.count; i++)
- fprintf(stdout, "# %s\n", MAIN.nssconf.path[i]);
-
- fputs("#\n", stdout);
-
- dns_nssconf_dump(resconf(), stdout);
-
- return 0;
-} /* show_nssconf() */
-
-
-static int show_hosts(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
- unsigned i;
-
- hosts();
-
- fputs("# SOURCES\n", stdout);
-
- for (i = 0; i < MAIN.hosts.count; i++)
- fprintf(stdout, "# %s\n", MAIN.hosts.path[i]);
-
- fputs("#\n", stdout);
-
- dns_hosts_dump(hosts(), stdout);
-
- return 0;
-} /* show_hosts() */
-
-
-static int query_hosts(int argc, char *argv[]) {
- struct dns_packet *Q = dns_p_new(512);
- struct dns_packet *A;
- char qname[DNS_D_MAXNAME + 1];
- size_t qlen;
- int error;
-
- if (!MAIN.qname)
- MAIN.qname = (argc > 1)? argv[1] : "localhost";
- if (!MAIN.qtype)
- MAIN.qtype = DNS_T_A;
-
- hosts();
-
- if (MAIN.qtype == DNS_T_PTR && !strstr(MAIN.qname, "arpa")) {
- union { struct in_addr a; struct in6_addr a6; } addr;
- int af = (strchr(MAIN.qname, ':'))? AF_INET6 : AF_INET;
-
- if ((error = dns_pton(af, MAIN.qname, &addr)))
- panic("%s: %s", MAIN.qname, dns_strerror(error));
-
- qlen = dns_ptr_qname(qname, sizeof qname, af, &addr);
- } else
- qlen = dns_strlcpy(qname, MAIN.qname, sizeof qname);
-
- if ((error = dns_p_push(Q, DNS_S_QD, qname, qlen, MAIN.qtype, DNS_C_IN, 0, 0)))
- panic("%s: %s", qname, dns_strerror(error));
-
- if (!(A = dns_hosts_query(hosts(), Q, &error)))
- panic("%s: %s", qname, dns_strerror(error));
-
- print_packet(A, stdout);
-
- free(A);
-
- return 0;
-} /* query_hosts() */
-
-
-static int search_list(int argc, char *argv[]) {
- const char *qname = (argc > 1)? argv[1] : "f.l.google.com";
- unsigned long i = 0;
- char name[DNS_D_MAXNAME + 1];
-
- printf("[%s]\n", qname);
-
- while (dns_resconf_search(name, sizeof name, qname, strlen(qname), resconf(), &i))
- puts(name);
-
- return 0;
-} /* search_list() */
-
-
-static int permute_set(int argc, char *argv[]) {
- unsigned lo, hi, i;
- struct dns_k_permutor p;
-
- hi = (--argc > 0)? atoi(argv[argc]) : 8;
- lo = (--argc > 0)? atoi(argv[argc]) : 0;
-
- fprintf(stderr, "[%u .. %u]\n", lo, hi);
-
- dns_k_permutor_init(&p, lo, hi);
-
- for (i = lo; i <= hi; i++)
- fprintf(stdout, "%u\n", dns_k_permutor_step(&p));
-// printf("%u -> %u -> %u\n", i, dns_k_permutor_E(&p, i), dns_k_permutor_D(&p, dns_k_permutor_E(&p, i)));
-
- return 0;
-} /* permute_set() */
-
-
-static int shuffle_16(int argc, char *argv[]) {
- unsigned n, r;
-
- if (--argc > 0) {
- n = 0xffff & atoi(argv[argc]);
- r = (--argc > 0)? (unsigned)atoi(argv[argc]) : dns_random();
-
- fprintf(stdout, "%hu\n", dns_k_shuffle16(n, r));
- } else {
- r = dns_random();
-
- for (n = 0; n < 65536; n++)
- fprintf(stdout, "%hu\n", dns_k_shuffle16(n, r));
- }
-
- return 0;
-} /* shuffle_16() */
-
-
-static int dump_random(int argc, char *argv[]) {
- unsigned char b[32];
- unsigned i, j, n, r;
-
- n = (argc > 1)? atoi(argv[1]) : 32;
-
- while (n) {
- i = 0;
-
- do {
- r = dns_random();
-
- for (j = 0; j < sizeof r && i < n && i < sizeof b; i++, j++) {
- b[i] = 0xff & r;
- r >>= 8;
- }
- } while (i < n && i < sizeof b);
-
- hexdump(b, i, stdout);
-
- n -= i;
- }
-
- return 0;
-} /* dump_random() */
-
-
-static int send_query(int argc, char *argv[]) {
- struct dns_packet *A, *Q = dns_p_new(512);
- char host[INET6_ADDRSTRLEN + 1];
- struct sockaddr_storage ss;
- struct dns_socket *so;
- int error, type;
-
- if (argc > 1) {
- ss.ss_family = (strchr(argv[1], ':'))? AF_INET6 : AF_INET;
-
- if ((error = dns_pton(ss.ss_family, argv[1], dns_sa_addr(ss.ss_family, &ss, NULL))))
- panic("%s: %s", argv[1], dns_strerror(error));
-
- *dns_sa_port(ss.ss_family, &ss) = htons(53);
- } else
- memcpy(&ss, &resconf()->nameserver[0], dns_sa_len(&resconf()->nameserver[0]));
-
- if (!dns_inet_ntop(ss.ss_family, dns_sa_addr(ss.ss_family, &ss, NULL), host, sizeof host))
- panic("bad host address, or none provided");
-
- if (!MAIN.qname)
- MAIN.qname = "ipv6.google.com";
- if (!MAIN.qtype)
- MAIN.qtype = DNS_T_AAAA;
-
- if ((error = dns_p_push(Q, DNS_S_QD, MAIN.qname, strlen(MAIN.qname), MAIN.qtype, DNS_C_IN, 0, 0)))
- panic("dns_p_push: %s", dns_strerror(error));
-
- DNS_HEADER(Q)->rd = 1;
-
- if (strstr(argv[0], "udp"))
- type = SOCK_DGRAM;
- else if (strstr(argv[0], "tcp"))
- type = SOCK_STREAM;
- else
- type = dns_res_tcp2type(resconf()->options.tcp);
-
- fprintf(stderr, "querying %s for %s IN %s\n", host, MAIN.qname, dns_strtype(MAIN.qtype));
-
- if (!(so = dns_so_open((struct sockaddr *)&resconf()->iface, type, dns_opts(), &error)))
- panic("dns_so_open: %s", dns_strerror(error));
-
- while (!(A = dns_so_query(so, Q, (struct sockaddr *)&ss, &error))) {
- if (error != DNS_EAGAIN)
- panic("dns_so_query: %s (%d)", dns_strerror(error), error);
- if (dns_so_elapsed(so) > 10)
- panic("query timed-out");
-
- dns_so_poll(so, 1);
- }
-
- print_packet(A, stdout);
-
- dns_so_close(so);
-
- return 0;
-} /* send_query() */
-
-
-static int print_arpa(int argc, char *argv[]) {
- const char *ip = (argc > 1)? argv[1] : "::1";
- int af = (strchr(ip, ':'))? AF_INET6 : AF_INET;
- union { struct in_addr a4; struct in6_addr a6; } addr;
- char host[DNS_D_MAXNAME + 1];
-
- if (1 != dns_inet_pton(af, ip, &addr) || 0 == dns_ptr_qname(host, sizeof host, af, &addr))
- panic("%s: invalid address", ip);
-
- fprintf(stdout, "%s\n", host);
-
- return 0;
-} /* print_arpa() */
-
-
-static int show_hints(int argc, char *argv[]) {
- struct dns_hints *(*load)(struct dns_resolv_conf *, int *);
- const char *which, *how, *who;
- struct dns_hints *hints;
- int error;
-
- which = (argc > 1)? argv[1] : "local";
- how = (argc > 2)? argv[2] : "plain";
- who = (argc > 3)? argv[3] : "google.com";
-
- load = (0 == strcmp(which, "local"))
- ? &dns_hints_local
- : &dns_hints_root;
-
- if (!(hints = load(resconf(), &error)))
- panic("%s: %s", argv[0], dns_strerror(error));
-
- if (0 == strcmp(how, "plain")) {
- dns_hints_dump(hints, stdout);
- } else {
- struct dns_packet *query, *answer;
-
- query = dns_p_new(512);
-
- if ((error = dns_p_push(query, DNS_S_QUESTION, who, strlen(who), DNS_T_A, DNS_C_IN, 0, 0)))
- panic("%s: %s", who, dns_strerror(error));
-
- if (!(answer = dns_hints_query(hints, query, &error)))
- panic("%s: %s", who, dns_strerror(error));
-
- print_packet(answer, stdout);
-
- free(answer);
- }
-
- dns_hints_close(hints);
-
- return 0;
-} /* show_hints() */
-
-
-static int resolve_query(int argc DNS_NOTUSED, char *argv[]) {
- _Bool recurse = !!strstr(argv[0], "recurse");
- struct dns_hints *(*hints)() = (recurse)? &dns_hints_root : &dns_hints_local;
- struct dns_resolver *R;
- struct dns_packet *ans;
- const struct dns_stat *st;
- int error;
-
- if (!MAIN.qname)
- MAIN.qname = "www.google.com";
- if (!MAIN.qtype)
- MAIN.qtype = DNS_T_A;
-
- resconf()->options.recurse = recurse;
-
- if (!(R = dns_res_open(resconf(), hosts(), dns_hints_mortal(hints(resconf(), &error)), cache(), dns_opts(), &error)))
- panic("%s: %s", MAIN.qname, dns_strerror(error));
-
- if ((error = dns_res_submit(R, MAIN.qname, MAIN.qtype, DNS_C_IN)))
- panic("%s: %s", MAIN.qname, dns_strerror(error));
-
- while ((error = dns_res_check(R))) {
- if (error != DNS_EAGAIN)
- panic("dns_res_check: %s (%d)", dns_strerror(error), error);
- if (dns_res_elapsed(R) > 30)
- panic("query timed-out");
-
- dns_res_poll(R, 1);
- }
-
- ans = dns_res_fetch(R, &error);
- print_packet(ans, stdout);
- free(ans);
-
- st = dns_res_stat(R);
- putchar('\n');
- printf(";; queries: %"PRIuZ"\n", st->queries);
- printf(";; udp sent: %"PRIuZ" in %"PRIuZ" bytes\n", st->udp.sent.count, st->udp.sent.bytes);
- printf(";; udp rcvd: %"PRIuZ" in %"PRIuZ" bytes\n", st->udp.rcvd.count, st->udp.rcvd.bytes);
- printf(";; tcp sent: %"PRIuZ" in %"PRIuZ" bytes\n", st->tcp.sent.count, st->tcp.sent.bytes);
- printf(";; tcp rcvd: %"PRIuZ" in %"PRIuZ" bytes\n", st->tcp.rcvd.count, st->tcp.rcvd.bytes);
-
- dns_res_close(R);
-
- return 0;
-} /* resolve_query() */
-
-
-static int resolve_addrinfo(int argc DNS_NOTUSED, char *argv[]) {
- _Bool recurse = !!strstr(argv[0], "recurse");
- struct dns_hints *(*hints)() = (recurse)? &dns_hints_root : &dns_hints_local;
- struct dns_resolver *res = NULL;
- struct dns_addrinfo *ai = NULL;
- struct addrinfo ai_hints = { .ai_family = PF_UNSPEC, .ai_socktype = SOCK_STREAM, .ai_flags = AI_CANONNAME };
- struct addrinfo *ent;
- char pretty[512];
- int error;
-
- if (!MAIN.qname)
- MAIN.qname = "www.google.com";
- /* NB: MAIN.qtype of 0 means obey hints.ai_family */
-
- resconf()->options.recurse = recurse;
-
- if (!(res = dns_res_open(resconf(), hosts(), dns_hints_mortal(hints(resconf(), &error)), cache(), dns_opts(), &error)))
- panic("%s: %s", MAIN.qname, dns_strerror(error));
-
- if (!(ai = dns_ai_open(MAIN.qname, "80", MAIN.qtype, &ai_hints, res, &error)))
- panic("%s: %s", MAIN.qname, dns_strerror(error));
-
- do {
- switch (error = dns_ai_nextent(&ent, ai)) {
- case 0:
- dns_ai_print(pretty, sizeof pretty, ent, ai);
-
- fputs(pretty, stdout);
-
- free(ent);
-
- break;
- case ENOENT:
- break;
- case DNS_EAGAIN:
- if (dns_ai_elapsed(ai) > 30)
- panic("query timed-out");
-
- dns_ai_poll(ai, 1);
-
- break;
- default:
- panic("dns_ai_nextent: %s (%d)", dns_strerror(error), error);
- }
- } while (error != ENOENT);
-
- dns_res_close(res);
- dns_ai_close(ai);
-
- return 0;
-} /* resolve_addrinfo() */
-
-
-static int echo_port(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
- union {
- struct sockaddr sa;
- struct sockaddr_in sin;
- } port;
- int fd;
-
- memset(&port, 0, sizeof port);
- port.sin.sin_family = AF_INET;
- port.sin.sin_port = htons(5354);
- port.sin.sin_addr.s_addr = inet_addr("127.0.0.1");
-
- if (-1 == (fd = socket(PF_INET, SOCK_DGRAM, 0)))
- panic("socket: %s", strerror(errno));
-
- if (0 != bind(fd, &port.sa, sizeof port.sa))
- panic("127.0.0.1:5353: %s", dns_strerror(errno));
-
- for (;;) {
- struct dns_packet *pkt = dns_p_new(512);
- struct sockaddr_storage ss;
- socklen_t slen = sizeof ss;
- ssize_t count;
-#if defined(MSG_WAITALL) /* MinGW issue */
- int rflags = MSG_WAITALL;
-#else
- int rflags = 0;
-#endif
-
- count = recvfrom(fd, (char *)pkt->data, pkt->size, rflags, (struct sockaddr *)&ss, &slen);
-
- if (!count || count < 0)
- panic("recvfrom: %s", strerror(errno));
-
- pkt->end = count;
-
- dns_p_dump(pkt, stdout);
-
- (void)sendto(fd, (char *)pkt->data, pkt->end, 0, (struct sockaddr *)&ss, slen);
- }
-
- return 0;
-} /* echo_port() */
-
-
-static int isection(int argc, char *argv[]) {
- const char *name = (argc > 1)? argv[1] : "";
- int type;
-
- type = dns_isection(name);
- name = dns_strsection(type);
-
- printf("%s (%d)\n", name, type);
-
- return 0;
-} /* isection() */
-
-
-static int iclass(int argc, char *argv[]) {
- const char *name = (argc > 1)? argv[1] : "";
- int type;
-
- type = dns_iclass(name);
- name = dns_strclass(type);
-
- printf("%s (%d)\n", name, type);
-
- return 0;
-} /* iclass() */
-
-
-static int itype(int argc, char *argv[]) {
- const char *name = (argc > 1)? argv[1] : "";
- int type;
-
- type = dns_itype(name);
- name = dns_strtype(type);
-
- printf("%s (%d)\n", name, type);
-
- return 0;
-} /* itype() */
-
-
-static int iopcode(int argc, char *argv[]) {
- const char *name = (argc > 1)? argv[1] : "";
- int type;
-
- type = dns_iopcode(name);
- name = dns_stropcode(type);
-
- printf("%s (%d)\n", name, type);
-
- return 0;
-} /* iopcode() */
-
-
-static int ircode(int argc, char *argv[]) {
- const char *name = (argc > 1)? argv[1] : "";
- int type;
-
- type = dns_ircode(name);
- name = dns_strrcode(type);
-
- printf("%s (%d)\n", name, type);
-
- return 0;
-} /* ircode() */
-
-
-#define SIZE1(x) { DNS_PP_STRINGIFY(x), sizeof (x) }
-#define SIZE2(x, ...) SIZE1(x), SIZE1(__VA_ARGS__)
-#define SIZE3(x, ...) SIZE1(x), SIZE2(__VA_ARGS__)
-#define SIZE4(x, ...) SIZE1(x), SIZE3(__VA_ARGS__)
-#define SIZE(...) DNS_PP_CALL(DNS_PP_XPASTE(SIZE, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__)
-
-static int sizes(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
- static const struct { const char *name; size_t size; } type[] = {
- SIZE(struct dns_header, struct dns_packet, struct dns_rr, struct dns_rr_i),
- SIZE(struct dns_a, struct dns_aaaa, struct dns_mx, struct dns_ns),
- SIZE(struct dns_cname, struct dns_soa, struct dns_ptr, struct dns_srv),
- SIZE(struct dns_sshfp, struct dns_txt, union dns_any),
- SIZE(struct dns_resolv_conf, struct dns_hosts, struct dns_hints, struct dns_hints_i),
- SIZE(struct dns_options, struct dns_socket, struct dns_resolver, struct dns_addrinfo),
- SIZE(struct dns_cache), SIZE(size_t), SIZE(void *), SIZE(long)
- };
- unsigned i, max;
-
- for (i = 0, max = 0; i < lengthof(type); i++)
- max = DNS_PP_MAX(max, strlen(type[i].name));
-
- for (i = 0; i < lengthof(type); i++)
- printf("%*s : %"PRIuZ"\n", max, type[i].name, type[i].size);
-
- return 0;
-} /* sizes() */
-
-
-static const struct { const char *cmd; int (*run)(); const char *help; } cmds[] = {
- { "parse-packet", &parse_packet, "parse binary packet from stdin" },
- { "parse-domain", &parse_domain, "anchor and iteratively cleave domain" },
- { "trim-domain", &trim_domain, "trim and anchor domain name" },
- { "expand-domain", &expand_domain, "expand domain at offset NN in packet from stdin" },
- { "show-resconf", &show_resconf, "show resolv.conf data" },
- { "show-hosts", &show_hosts, "show hosts data" },
- { "show-nssconf", &show_nssconf, "show nsswitch.conf data" },
- { "query-hosts", &query_hosts, "query A, AAAA or PTR in hosts data" },
- { "search-list", &search_list, "generate query search list from domain" },
- { "permute-set", &permute_set, "generate random permutation -> (0 .. N or N .. M)" },
- { "shuffle-16", &shuffle_16, "simple 16-bit permutation" },
- { "dump-random", &dump_random, "generate random bytes" },
- { "send-query", &send_query, "send query to host" },
- { "send-query-udp", &send_query, "send udp query to host" },
- { "send-query-tcp", &send_query, "send tcp query to host" },
- { "print-arpa", &print_arpa, "print arpa. zone name of address" },
- { "show-hints", &show_hints, "print hints: show-hints [local|root] [plain|packet]" },
- { "resolve-stub", &resolve_query, "resolve as stub resolver" },
- { "resolve-recurse", &resolve_query, "resolve as recursive resolver" },
- { "addrinfo-stub", &resolve_addrinfo, "resolve through getaddrinfo clone" },
- { "addrinfo-recurse", &resolve_addrinfo, "resolve through getaddrinfo clone" },
-/* { "resolve-nameinfo", &resolve_query, "resolve as recursive resolver" }, */
- { "echo", &echo_port, "server echo mode, for nmap fuzzing" },
- { "isection", &isection, "parse section string" },
- { "iclass", &iclass, "parse class string" },
- { "itype", &itype, "parse type string" },
- { "iopcode", &iopcode, "parse opcode string" },
- { "ircode", &ircode, "parse rcode string" },
- { "sizes", &sizes, "print data structure sizes" },
-};
-
-
-static void print_usage(const char *progname, FILE *fp) {
- static const char *usage =
- " [OPTIONS] COMMAND [ARGS]\n"
- " -c PATH Path to resolv.conf\n"
- " -n PATH Path to nsswitch.conf\n"
- " -l PATH Path to local hosts\n"
- " -z PATH Path to zone cache\n"
- " -q QNAME Query name\n"
- " -t QTYPE Query type\n"
- " -s HOW Sort records\n"
- " -v Be more verbose (-vv show packets; -vvv hexdump packets)\n"
- " -V Print version info\n"
- " -h Print this usage message\n"
- "\n";
- unsigned i, n, m;
-
- fputs(progname, fp);
- fputs(usage, fp);
-
- for (i = 0, m = 0; i < lengthof(cmds); i++) {
- if (strlen(cmds[i].cmd) > m)
- m = strlen(cmds[i].cmd);
- }
-
- for (i = 0; i < lengthof(cmds); i++) {
- fprintf(fp, " %s ", cmds[i].cmd);
-
- for (n = strlen(cmds[i].cmd); n < m; n++)
- putc(' ', fp);
-
- fputs(cmds[i].help, fp);
- putc('\n', fp);
- }
-
- fputs("\nReport bugs to William Ahern \n", fp);
-} /* print_usage() */
-
-
-static void print_version(const char *progname, FILE *fp) {
- fprintf(fp, "%s (dns.c) %.8X\n", progname, dns_v_rel());
- fprintf(fp, "vendor %s\n", dns_vendor());
- fprintf(fp, "release %.8X\n", dns_v_rel());
- fprintf(fp, "abi %.8X\n", dns_v_abi());
- fprintf(fp, "api %.8X\n", dns_v_api());
-} /* print_version() */
-
-
-int main(int argc, char **argv) {
- extern int optind;
- extern char *optarg;
- const char *progname = argv[0];
- unsigned i;
- int ch;
-
- while (-1 != (ch = getopt(argc, argv, "q:t:c:n:l:z:s:vVh"))) {
- switch (ch) {
- case 'c':
- assert(MAIN.resconf.count < lengthof(MAIN.resconf.path));
-
- MAIN.resconf.path[MAIN.resconf.count++] = optarg;
-
- break;
- case 'n':
- assert(MAIN.nssconf.count < lengthof(MAIN.nssconf.path));
-
- MAIN.nssconf.path[MAIN.nssconf.count++] = optarg;
-
- break;
- case 'l':
- assert(MAIN.hosts.count < lengthof(MAIN.hosts.path));
-
- MAIN.hosts.path[MAIN.hosts.count++] = optarg;
-
- break;
- case 'z':
- assert(MAIN.cache.count < lengthof(MAIN.cache.path));
-
- MAIN.cache.path[MAIN.cache.count++] = optarg;
-
- break;
- case 'q':
- MAIN.qname = optarg;
-
- break;
- case 't':
- for (i = 0; i < lengthof(dns_rrtypes); i++) {
- if (0 == strcasecmp(dns_rrtypes[i].name, optarg))
- { MAIN.qtype = dns_rrtypes[i].type; break; }
- }
-
- if (MAIN.qtype)
- break;
-
- for (i = 0; dns_isdigit(optarg[i]); i++) {
- MAIN.qtype *= 10;
- MAIN.qtype += optarg[i] - '0';
- }
-
- if (!MAIN.qtype)
- panic("%s: invalid query type", optarg);
-
- break;
- case 's':
- if (0 == strcasecmp(optarg, "packet"))
- MAIN.sort = &dns_rr_i_packet;
- else if (0 == strcasecmp(optarg, "shuffle"))
- MAIN.sort = &dns_rr_i_shuffle;
- else if (0 == strcasecmp(optarg, "order"))
- MAIN.sort = &dns_rr_i_order;
- else
- panic("%s: invalid sort method", optarg);
-
- break;
- case 'v':
- dns_debug = ++MAIN.verbose;
-
- break;
- case 'V':
- print_version(progname, stdout);
-
- return 0;
- case 'h':
- print_usage(progname, stdout);
-
- return 0;
- default:
- print_usage(progname, stderr);
-
- return EXIT_FAILURE;
- } /* switch() */
- } /* while() */
-
- argc -= optind;
- argv += optind;
-
- for (i = 0; i < lengthof(cmds) && argv[0]; i++) {
- if (0 == strcmp(cmds[i].cmd, argv[0]))
- return cmds[i].run(argc, argv);
- }
-
- print_usage(progname, stderr);
-
- return EXIT_FAILURE;
-} /* main() */
-
-
-#endif /* DNS_MAIN */
-
-/*
- * pop file-scoped compiler annotations
- */
-#if __clang__
-#pragma clang diagnostic pop
-#elif DNS_GNUC_PREREQ(4,6,0)
-#pragma GCC diagnostic pop
-#endif
-
-#endif /* SYS_UNIX */
diff --git a/lib_fiber/c/src/dns/dns.h.bak b/lib_fiber/c/src/dns/dns.h.bak
deleted file mode 100644
index cd41322e9..000000000
--- a/lib_fiber/c/src/dns/dns.h.bak
+++ /dev/null
@@ -1,1261 +0,0 @@
-/* ==========================================================================
- * dns.h - Recursive, Reentrant DNS Resolver.
- * --------------------------------------------------------------------------
- * Copyright (c) 2009, 2010, 2012-2015 William Ahern
- *
- * 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 the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to permit
- * persons to whom the Software is furnished to do so, subject to the
- * following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
- * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
- * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
- * USE OR OTHER DEALINGS IN THE SOFTWARE.
- * ==========================================================================
- */
-#ifndef DNS_H
-#define DNS_H
-
-#include "define.h"
-
-#ifdef SYS_UNIX
-
-#include /* size_t offsetof() */
-#include /* FILE */
-
-#include /* strlen(3) */
-
-#include /* time_t */
-
-#if _WIN32
-#include
-#include
-#else
-#include /* BYTE_ORDER BIG_ENDIAN _BIG_ENDIAN */
-#include /* socklen_t */
-#include /* struct socket */
-
-#include /* POLLIN POLLOUT */
-
-#include /* struct in_addr struct in6_addr */
-
-#include /* struct addrinfo */
-#endif
-
-
-/*
- * V I S I B I L I T Y
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-#ifndef DNS_PUBLIC
-#define DNS_PUBLIC
-#endif
-
-
-/*
- * V E R S I O N
- *
- * Vendor: Entity for which versions numbers are relevant. (If forking
- * change DNS_VENDOR to avoid confusion.)
- *
- * Three versions:
- *
- * REL Official "release"--bug fixes, new features, etc.
- * ABI Changes to existing object sizes or parameter types.
- * API Changes that might effect application source.
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-#define DNS_VENDOR "william@25thandClement.com"
-
-#define DNS_V_REL 0x20161214
-#define DNS_V_ABI 0x20160608
-#define DNS_V_API 0x20160608
-
-
-DNS_PUBLIC const char *dns_vendor(void);
-
-DNS_PUBLIC int dns_v_rel(void);
-DNS_PUBLIC int dns_v_abi(void);
-DNS_PUBLIC int dns_v_api(void);
-
-
-/*
- * E R R O R S
- *
- * Errors and exceptions are always returned through an int. This should
- * hopefully make integration easier in the majority of circumstances, and
- * also cut down on useless compiler warnings.
- *
- * System and library errors are returned together. POSIX guarantees that
- * all system errors are positive integers. Library errors are always
- * negative integers in the range DNS_EBASE to DNS_ELAST, with the high bits
- * set to the three magic ASCII characters "dns".
- *
- * dns_strerror() returns static English string descriptions of all known
- * errors, and punts the remainder to strerror(3).
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-#define DNS_EBASE -(('d' << 24) | ('n' << 16) | ('s' << 8) | 64)
-
-#define dns_error_t int /* for documentation only */
-
-enum dns_errno {
- DNS_ENOBUFS = DNS_EBASE,
- DNS_EILLEGAL,
- DNS_EORDER,
- DNS_ESECTION,
- DNS_EUNKNOWN,
- DNS_EADDRESS,
- DNS_ENOQUERY,
- DNS_ENOANSWER,
- DNS_EFETCHED,
- DNS_ESERVICE, /* EAI_SERVICE */
- DNS_ENONAME, /* EAI_NONAME */
- DNS_EFAIL, /* EAI_FAIL */
- DNS_ELAST,
-}; /* dns_errno */
-
-DNS_PUBLIC const char *dns_strerror(dns_error_t);
-
-DNS_PUBLIC int *dns_debug_p(void);
-
-#define dns_debug (*dns_debug_p()) /* was extern int dns_debug before 20160523 API */
-
-
-/*
- * C O M P I L E R A N N O T A T I O N S
- *
- * GCC with -Wextra, and clang by default, complain about overrides in
- * initializer lists. Overriding previous member initializers is well
- * defined behavior in C. dns.c relies on this behavior to define default,
- * overrideable member values when instantiating configuration objects.
- *
- * dns_quietinit() guards a compound literal expression with pragmas to
- * silence these shrill warnings. This alleviates the burden of requiring
- * third-party projects to adjust their compiler flags.
- *
- * NOTE: If you take the address of the compound literal, take the address
- * of the transformed expression, otherwise the compound literal lifetime is
- * tied to the scope of the GCC statement expression.
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-#if defined __clang__
-#define DNS_PRAGMA_PUSH _Pragma("clang diagnostic push")
-#define DNS_PRAGMA_QUIET _Pragma("clang diagnostic ignored \"-Winitializer-overrides\"")
-#define DNS_PRAGMA_POP _Pragma("clang diagnostic pop")
-
-#define dns_quietinit(...) \
- DNS_PRAGMA_PUSH DNS_PRAGMA_QUIET __VA_ARGS__ DNS_PRAGMA_POP
-#elif (__GNUC__ < 9) && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
-#define DNS_PRAGMA_PUSH _Pragma("GCC diagnostic push")
-#define DNS_PRAGMA_QUIET _Pragma("GCC diagnostic ignored \"-Woverride-init\"")
-#define DNS_PRAGMA_POP _Pragma("GCC diagnostic pop")
-
-/*
- * GCC parses the _Pragma operator less elegantly than clang.
- * This only works up to GCC 9
- */
-#define dns_quietinit(...) \
- __extension__ ({ DNS_PRAGMA_PUSH DNS_PRAGMA_QUIET __VA_ARGS__; DNS_PRAGMA_POP })
-#else
-#define DNS_PRAGMA_PUSH
-#define DNS_PRAGMA_QUIET
-#define DNS_PRAGMA_POP
-#define dns_quietinit(...) __VA_ARGS__
-#endif
-
-#if defined __GNUC__
-#define DNS_PRAGMA_EXTENSION __extension__
-#pragma GCC diagnostic ignored "-Wstrict-prototypes"
-#else
-#define DNS_PRAGMA_EXTENSION
-#endif
-
-
-/*
- * E V E N T S I N T E R F A C E S
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-#if defined(POLLIN)
-#define DNS_POLLIN POLLIN
-#else
-#define DNS_POLLIN 1
-#endif
-
-#if defined(POLLOUT)
-#define DNS_POLLOUT POLLOUT
-#else
-#define DNS_POLLOUT 2
-#endif
-
-
-/*
- * See Application Interface below for configuring libevent bitmasks instead
- * of poll(2) bitmasks.
- */
-#define DNS_EVREAD 2
-#define DNS_EVWRITE 4
-
-
-#define DNS_POLL2EV(set) \
- (((set) & DNS_POLLIN)? DNS_EVREAD : 0) | (((set) & DNS_POLLOUT)? DNS_EVWRITE : 0)
-
-#define DNS_EV2POLL(set) \
- (((set) & DNS_EVREAD)? DNS_POLLIN : 0) | (((set) & DNS_EVWRITE)? DNS_POLLOUT : 0)
-
-
-/*
- * E N U M E R A T I O N I N T E R F A C E S
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-enum dns_section {
- DNS_S_QD = 0x01,
-#define DNS_S_QUESTION DNS_S_QD
-
- DNS_S_AN = 0x02,
-#define DNS_S_ANSWER DNS_S_AN
-
- DNS_S_NS = 0x04,
-#define DNS_S_AUTHORITY DNS_S_NS
-
- DNS_S_AR = 0x08,
-#define DNS_S_ADDITIONAL DNS_S_AR
-
- DNS_S_ALL = 0x0f
-}; /* enum dns_section */
-
-
-enum dns_class {
- DNS_C_IN = 1,
-
- DNS_C_ANY = 255
-}; /* enum dns_class */
-
-
-enum dns_type {
- DNS_T_A = 1,
- DNS_T_NS = 2,
- DNS_T_CNAME = 5,
- DNS_T_SOA = 6,
- DNS_T_PTR = 12,
- DNS_T_MX = 15,
- DNS_T_TXT = 16,
- DNS_T_AAAA = 28,
- DNS_T_SRV = 33,
- DNS_T_OPT = 41,
- DNS_T_SSHFP = 44,
- DNS_T_SPF = 99,
- DNS_T_AXFR = 252,
-
- DNS_T_ALL = 255
-}; /* enum dns_type */
-
-
-enum dns_opcode {
- DNS_OP_QUERY = 0,
- DNS_OP_IQUERY = 1,
- DNS_OP_STATUS = 2,
- DNS_OP_NOTIFY = 4,
- DNS_OP_UPDATE = 5,
-}; /* dns_opcode */
-
-
-enum dns_rcode {
- DNS_RC_NOERROR = 0,
- DNS_RC_FORMERR = 1,
- DNS_RC_SERVFAIL = 2,
- DNS_RC_NXDOMAIN = 3,
- DNS_RC_NOTIMP = 4,
- DNS_RC_REFUSED = 5,
- DNS_RC_YXDOMAIN = 6,
- DNS_RC_YXRRSET = 7,
- DNS_RC_NXRRSET = 8,
- DNS_RC_NOTAUTH = 9,
- DNS_RC_NOTZONE = 10,
-
- /* EDNS(0) extended RCODEs */
- DNS_RC_BADVERS = 16,
-}; /* dns_rcode */
-
-
-/*
- * NOTE: These string functions need a small buffer in case the literal
- * integer value needs to be printed and returned. UNLESS this buffer is
- * SPECIFIED, the returned string has ONLY BLOCK SCOPE.
- */
-#define DNS_STRMAXLEN 47 /* "QUESTION|ANSWER|AUTHORITY|ADDITIONAL" */
-
-DNS_PUBLIC const char *dns_strsection(enum dns_section, void *, size_t);
-#define dns_strsection3(a, b, c) \
- dns_strsection((a), (b), (c))
-#define dns_strsection1(a) dns_strsection((a), (char [DNS_STRMAXLEN + 1]){ 0 }, DNS_STRMAXLEN + 1)
-#define dns_strsection(...) DNS_PP_CALL(DNS_PP_XPASTE(dns_strsection, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__)
-
-DNS_PUBLIC enum dns_section dns_isection(const char *);
-
-DNS_PUBLIC const char *dns_strclass(enum dns_class, void *, size_t);
-#define dns_strclass3(a, b, c) dns_strclass((a), (b), (c))
-#define dns_strclass1(a) dns_strclass((a), (char [DNS_STRMAXLEN + 1]){ 0 }, DNS_STRMAXLEN + 1)
-#define dns_strclass(...) DNS_PP_CALL(DNS_PP_XPASTE(dns_strclass, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__)
-
-DNS_PUBLIC enum dns_class dns_iclass(const char *);
-
-DNS_PUBLIC const char *dns_strtype(enum dns_type, void *, size_t);
-#define dns_strtype3(a, b, c) dns_strtype((a), (b), (c))
-#define dns_strtype1(a) dns_strtype((a), (char [DNS_STRMAXLEN + 1]){ 0 }, DNS_STRMAXLEN + 1)
-#define dns_strtype(...) DNS_PP_CALL(DNS_PP_XPASTE(dns_strtype, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__)
-
-DNS_PUBLIC enum dns_type dns_itype(const char *);
-
-DNS_PUBLIC const char *dns_stropcode(enum dns_opcode);
-
-DNS_PUBLIC enum dns_opcode dns_iopcode(const char *);
-
-DNS_PUBLIC const char *dns_strrcode(enum dns_rcode);
-
-DNS_PUBLIC enum dns_rcode dns_ircode(const char *);
-
-
-/*
- * A T O M I C I N T E R F A C E S
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-typedef unsigned long dns_atomic_t;
-
-typedef unsigned long dns_refcount_t; /* must be same value type as dns_atomic_t */
-
-
-/*
- * C R Y P T O I N T E R F A C E S
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-typedef unsigned dns_random_f(void);
-
-DNS_PUBLIC dns_random_f **dns_random_p(void);
-
-#define dns_random (*dns_random_p()) /* was extern unsigned (*dns_random)(void) before 20160523 API */
-
-
-/*
- * P A C K E T I N T E R F A C E
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-struct dns_header {
- unsigned qid:16;
-
-#if (defined BYTE_ORDER && BYTE_ORDER == BIG_ENDIAN) || (defined __sun && defined _BIG_ENDIAN)
- unsigned qr:1;
- unsigned opcode:4;
- unsigned aa:1;
- unsigned tc:1;
- unsigned rd:1;
-
- unsigned ra:1;
- unsigned unused:3;
- unsigned rcode:4;
-#else
- unsigned rd:1;
- unsigned tc:1;
- unsigned aa:1;
- unsigned opcode:4;
- unsigned qr:1;
-
- unsigned rcode:4;
- unsigned unused:3;
- unsigned ra:1;
-#endif
-
- unsigned qdcount:16;
- unsigned ancount:16;
- unsigned nscount:16;
- unsigned arcount:16;
-}; /* struct dns_header */
-
-#define DNS_HEADER(_p_) (&(_p_)->header)
-
-
-#ifndef DNS_P_QBUFSIZ
-#define DNS_P_QBUFSIZ dns_p_calcsize(256 + 4)
-#endif
-
-#ifndef DNS_P_DICTSIZE
-#define DNS_P_DICTSIZE 16
-#endif
-
-struct dns_packet {
- unsigned short dict[DNS_P_DICTSIZE];
-
- struct dns_p_memo {
- struct dns_s_memo {
- unsigned short base, end;
- } qd, an, ns, ar;
-
- struct {
- unsigned short p;
- unsigned short maxudp;
- unsigned ttl;
- } opt;
- } memo;
-
- struct { struct dns_packet *cqe_next, *cqe_prev; } cqe;
-
- size_t size, end;
-
- int:16; /* tcp padding */
-
- DNS_PRAGMA_EXTENSION union {
- struct dns_header header;
- unsigned char data[1];
- };
-}; /* struct dns_packet */
-
-#define dns_p_calcsize(n) (offsetof(struct dns_packet, data) + DNS_PP_MAX(12, (n)))
-
-#define dns_p_sizeof(P) dns_p_calcsize((P)->end)
-
-/** takes size of maximum desired payload */
-#define dns_p_new(n) (dns_p_init((struct dns_packet *)&(union { unsigned char b[dns_p_calcsize((n))]; struct dns_packet p; }){ { 0 } }, dns_p_calcsize((n))))
-
-/** takes size of entire packet structure as allocated */
-DNS_PUBLIC struct dns_packet *dns_p_init(struct dns_packet *, size_t);
-
-/** takes size of maximum desired payload */
-DNS_PUBLIC struct dns_packet *dns_p_make(size_t, int *);
-
-DNS_PUBLIC int dns_p_grow(struct dns_packet **);
-
-DNS_PUBLIC struct dns_packet *dns_p_copy(struct dns_packet *, const struct dns_packet *);
-
-#define dns_p_opcode(P) (dns_header(P)->opcode)
-
-DNS_PUBLIC enum dns_rcode dns_p_rcode(struct dns_packet *);
-
-DNS_PUBLIC unsigned dns_p_count(struct dns_packet *, enum dns_section);
-
-DNS_PUBLIC int dns_p_push(struct dns_packet *, enum dns_section, void *, size_t, enum dns_type, enum dns_class, unsigned, void *);
-
-DNS_PUBLIC void dns_p_dictadd(struct dns_packet *, unsigned short);
-
-DNS_PUBLIC struct dns_packet *dns_p_merge(struct dns_packet *, enum dns_section, struct dns_packet *, enum dns_section, int *);
-
-DNS_PUBLIC void dns_p_dump(struct dns_packet *, FILE *);
-
-DNS_PUBLIC int dns_p_study(struct dns_packet *);
-
-
-/*
- * D O M A I N N A M E I N T E R F A C E S
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-#define DNS_D_MAXLABEL 63 /* + 1 '\0' */
-#define DNS_D_MAXNAME 255 /* + 1 '\0' */
-
-#define DNS_D_ANCHOR 1 /* anchor domain w/ root "." */
-#define DNS_D_CLEAVE 2 /* cleave sub-domain */
-#define DNS_D_TRIM 4 /* remove superfluous dots */
-
-#define dns_d_new3(a, b, f) dns_d_init(&(char[DNS_D_MAXNAME + 1]){ 0 }, DNS_D_MAXNAME + 1, (a), (b), (f))
-#define dns_d_new2(a, f) dns_d_new3((a), strlen((a)), (f))
-#define dns_d_new1(a) dns_d_new3((a), strlen((a)), DNS_D_ANCHOR)
-#define dns_d_new(...) DNS_PP_CALL(DNS_PP_XPASTE(dns_d_new, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__)
-
-DNS_PUBLIC char *dns_d_init(void *, size_t, const void *, size_t, int);
-
-DNS_PUBLIC size_t dns_d_anchor(void *, size_t, const void *, size_t);
-
-DNS_PUBLIC size_t dns_d_cleave(void *, size_t, const void *, size_t);
-
-DNS_PUBLIC size_t dns_d_comp(void *, size_t, void *, size_t, struct dns_packet *, int *);
-
-DNS_PUBLIC size_t dns_d_expand(void *, size_t, unsigned short, struct dns_packet *, int *);
-
-DNS_PUBLIC unsigned short dns_d_skip(unsigned short, struct dns_packet *);
-
-DNS_PUBLIC int dns_d_push(struct dns_packet *, void *, size_t);
-
-DNS_PUBLIC size_t dns_d_cname(void *, size_t, const void *, size_t, struct dns_packet *, int *error);
-
-
-/*
- * R E S O U R C E R E C O R D I N T E R F A C E S
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-struct dns_rr {
- enum dns_section section;
-
- struct {
- unsigned short p;
- unsigned short len;
- } dn;
-
- enum dns_type type;
- enum dns_class class;
- unsigned ttl;
-
- struct {
- unsigned short p;
- unsigned short len;
- } rd;
-}; /* struct dns_rr */
-
-
-DNS_PUBLIC int dns_rr_copy(struct dns_packet *, struct dns_rr *, struct dns_packet *);
-
-DNS_PUBLIC int dns_rr_parse(struct dns_rr *, unsigned short, struct dns_packet *);
-
-DNS_PUBLIC unsigned short dns_rr_skip(unsigned short, struct dns_packet *);
-
-DNS_PUBLIC int dns_rr_cmp(struct dns_rr *, struct dns_packet *, struct dns_rr *, struct dns_packet *);
-
-DNS_PUBLIC size_t dns_rr_print(void *, size_t, struct dns_rr *, struct dns_packet *, int *);
-
-
-#define dns_rr_i_new(P, ...) \
- dns_rr_i_init(&dns_quietinit((struct dns_rr_i){ 0, __VA_ARGS__ }), (P))
-
-struct dns_rr_i {
- enum dns_section section;
- const void *name;
- enum dns_type type;
- enum dns_class class;
- const void *data;
-
- int follow;
-
- int (*sort)();
- unsigned args[2];
-
- struct {
- unsigned short next;
- unsigned short count;
-
- unsigned exec;
- unsigned regs[2];
- } state, saved;
-}; /* struct dns_rr_i */
-
-DNS_PUBLIC int dns_rr_i_packet(struct dns_rr *, struct dns_rr *, struct dns_rr_i *, struct dns_packet *);
-
-DNS_PUBLIC int dns_rr_i_order(struct dns_rr *, struct dns_rr *, struct dns_rr_i *, struct dns_packet *);
-
-DNS_PUBLIC int dns_rr_i_shuffle(struct dns_rr *, struct dns_rr *, struct dns_rr_i *, struct dns_packet *);
-
-DNS_PUBLIC struct dns_rr_i *dns_rr_i_init(struct dns_rr_i *, struct dns_packet *);
-
-#define dns_rr_i_save(i) ((i)->saved = (i)->state)
-#define dns_rr_i_rewind(i) ((i)->state = (i)->saved)
-#define dns_rr_i_count(i) ((i)->state.count)
-
-DNS_PUBLIC unsigned dns_rr_grep(struct dns_rr *, unsigned, struct dns_rr_i *, struct dns_packet *, int *);
-
-#define dns_rr_foreach_(rr, P, ...) \
- for (struct dns_rr_i DNS_PP_XPASTE(i, __LINE__) = *dns_rr_i_new((P), __VA_ARGS__); dns_rr_grep((rr), 1, &DNS_PP_XPASTE(i, __LINE__), (P), &(int){ 0 }); )
-
-#define dns_rr_foreach(...) dns_rr_foreach_(__VA_ARGS__)
-
-
-/*
- * A R E S O U R C E R E C O R D
- */
-
-struct dns_a {
- struct in_addr addr;
-}; /* struct dns_a */
-
-DNS_PUBLIC int dns_a_parse(struct dns_a *, struct dns_rr *, struct dns_packet *);
-
-DNS_PUBLIC int dns_a_push(struct dns_packet *, struct dns_a *);
-
-DNS_PUBLIC int dns_a_cmp(const struct dns_a *, const struct dns_a *);
-
-DNS_PUBLIC size_t dns_a_print(void *, size_t, struct dns_a *);
-
-DNS_PUBLIC size_t dns_a_arpa(void *, size_t, const struct dns_a *);
-
-
-/*
- * AAAA R E S O U R C E R E C O R D
- */
-
-struct dns_aaaa {
- struct in6_addr addr;
-}; /* struct dns_aaaa */
-
-DNS_PUBLIC int dns_aaaa_parse(struct dns_aaaa *, struct dns_rr *, struct dns_packet *);
-
-DNS_PUBLIC int dns_aaaa_push(struct dns_packet *, struct dns_aaaa *);
-
-DNS_PUBLIC int dns_aaaa_cmp(const struct dns_aaaa *, const struct dns_aaaa *);
-
-DNS_PUBLIC size_t dns_aaaa_print(void *, size_t, struct dns_aaaa *);
-
-DNS_PUBLIC size_t dns_aaaa_arpa(void *, size_t, const struct dns_aaaa *);
-
-
-/*
- * MX R E S O U R C E R E C O R D
- */
-
-struct dns_mx {
- unsigned short preference;
- char host[DNS_D_MAXNAME + 1];
-}; /* struct dns_mx */
-
-DNS_PUBLIC int dns_mx_parse(struct dns_mx *, struct dns_rr *, struct dns_packet *);
-
-DNS_PUBLIC int dns_mx_push(struct dns_packet *, struct dns_mx *);
-
-DNS_PUBLIC int dns_mx_cmp(const struct dns_mx *, const struct dns_mx *);
-
-DNS_PUBLIC size_t dns_mx_print(void *, size_t, struct dns_mx *);
-
-DNS_PUBLIC size_t dns_mx_cname(void *, size_t, struct dns_mx *);
-
-
-/*
- * NS R E S O U R C E R E C O R D
- */
-
-struct dns_ns {
- char host[DNS_D_MAXNAME + 1];
-}; /* struct dns_ns */
-
-DNS_PUBLIC int dns_ns_parse(struct dns_ns *, struct dns_rr *, struct dns_packet *);
-
-DNS_PUBLIC int dns_ns_push(struct dns_packet *, struct dns_ns *);
-
-DNS_PUBLIC int dns_ns_cmp(const struct dns_ns *, const struct dns_ns *);
-
-DNS_PUBLIC size_t dns_ns_print(void *, size_t, struct dns_ns *);
-
-DNS_PUBLIC size_t dns_ns_cname(void *, size_t, struct dns_ns *);
-
-
-/*
- * CNAME R E S O U R C E R E C O R D
- */
-
-struct dns_cname {
- char host[DNS_D_MAXNAME + 1];
-}; /* struct dns_cname */
-
-DNS_PUBLIC int dns_cname_parse(struct dns_cname *, struct dns_rr *, struct dns_packet *);
-
-DNS_PUBLIC int dns_cname_push(struct dns_packet *, struct dns_cname *);
-
-DNS_PUBLIC int dns_cname_cmp(const struct dns_cname *, const struct dns_cname *);
-
-DNS_PUBLIC size_t dns_cname_print(void *, size_t, struct dns_cname *);
-
-DNS_PUBLIC size_t dns_cname_cname(void *, size_t, struct dns_cname *);
-
-
-/*
- * SOA R E S O U R C E R E C O R D
- */
-
-struct dns_soa {
- char mname[DNS_D_MAXNAME + 1];
- char rname[DNS_D_MAXNAME + 1];
- unsigned serial, refresh, retry, expire, minimum;
-}; /* struct dns_soa */
-
-DNS_PUBLIC int dns_soa_parse(struct dns_soa *, struct dns_rr *, struct dns_packet *);
-
-DNS_PUBLIC int dns_soa_push(struct dns_packet *, struct dns_soa *);
-
-DNS_PUBLIC int dns_soa_cmp(const struct dns_soa *, const struct dns_soa *);
-
-DNS_PUBLIC size_t dns_soa_print(void *, size_t, struct dns_soa *);
-
-
-/*
- * PTR R E S O U R C E R E C O R D
- */
-
-struct dns_ptr {
- char host[DNS_D_MAXNAME + 1];
-}; /* struct dns_ptr */
-
-DNS_PUBLIC int dns_ptr_parse(struct dns_ptr *, struct dns_rr *, struct dns_packet *);
-
-DNS_PUBLIC int dns_ptr_push(struct dns_packet *, struct dns_ptr *);
-
-DNS_PUBLIC int dns_ptr_cmp(const struct dns_ptr *, const struct dns_ptr *);
-
-DNS_PUBLIC size_t dns_ptr_print(void *, size_t, struct dns_ptr *);
-
-DNS_PUBLIC size_t dns_ptr_cname(void *, size_t, struct dns_ptr *);
-
-DNS_PUBLIC size_t dns_ptr_qname(void *, size_t, int, void *);
-
-
-/*
- * SRV R E S O U R C E R E C O R D
- */
-
-struct dns_srv {
- unsigned short priority;
- unsigned short weight;
- unsigned short port;
- char target[DNS_D_MAXNAME + 1];
-}; /* struct dns_srv */
-
-DNS_PUBLIC int dns_srv_parse(struct dns_srv *, struct dns_rr *, struct dns_packet *);
-
-DNS_PUBLIC int dns_srv_push(struct dns_packet *, struct dns_srv *);
-
-DNS_PUBLIC int dns_srv_cmp(const struct dns_srv *, const struct dns_srv *);
-
-DNS_PUBLIC size_t dns_srv_print(void *, size_t, struct dns_srv *);
-
-DNS_PUBLIC size_t dns_srv_cname(void *, size_t, struct dns_srv *);
-
-
-/*
- * OPT R E S O U R C E R E C O R D
- */
-
-#ifndef DNS_OPT_MINDATA
-#define DNS_OPT_MINDATA 256
-#endif
-
-#define DNS_OPT_DNSSEC 0x8000
-
-struct dns_opt {
- enum dns_rcode rcode;
- unsigned char version;
- unsigned short flags;
-
- union {
- unsigned short maxsize; /* deprecated as confusing */
- unsigned short maxudp; /* maximum UDP payload size */
- };
-
- size_t size, len;
- unsigned char data[DNS_OPT_MINDATA];
-}; /* struct dns_opt */
-
-#define DNS_OPT_INIT(opt) { .size = sizeof (*opt) - offsetof(struct dns_opt, data) }
-
-DNS_PUBLIC struct dns_opt *dns_opt_init(struct dns_opt *, size_t);
-
-DNS_PUBLIC int dns_opt_parse(struct dns_opt *, struct dns_rr *, struct dns_packet *);
-
-DNS_PUBLIC int dns_opt_push(struct dns_packet *, struct dns_opt *);
-
-DNS_PUBLIC int dns_opt_cmp(const struct dns_opt *, const struct dns_opt *);
-
-DNS_PUBLIC size_t dns_opt_print(void *, size_t, struct dns_opt *);
-
-DNS_PUBLIC unsigned int dns_opt_ttl(const struct dns_opt *);
-
-DNS_PUBLIC unsigned short dns_opt_class(const struct dns_opt *);
-
-DNS_PUBLIC dns_error_t dns_opt_data_push(struct dns_opt *, unsigned char, unsigned short, const void *);
-
-
-/*
- * SSHFP R E S O U R C E R E C O R D
- */
-
-struct dns_sshfp {
- enum dns_sshfp_key {
- DNS_SSHFP_RSA = 1,
- DNS_SSHFP_DSA = 2,
- } algo;
-
- enum dns_sshfp_digest {
- DNS_SSHFP_SHA1 = 1,
- } type;
-
- union {
- unsigned char sha1[20];
- } digest;
-}; /* struct dns_sshfp */
-
-DNS_PUBLIC int dns_sshfp_parse(struct dns_sshfp *, struct dns_rr *, struct dns_packet *);
-
-DNS_PUBLIC int dns_sshfp_push(struct dns_packet *, struct dns_sshfp *);
-
-DNS_PUBLIC int dns_sshfp_cmp(const struct dns_sshfp *, const struct dns_sshfp *);
-
-DNS_PUBLIC size_t dns_sshfp_print(void *, size_t, struct dns_sshfp *);
-
-
-/*
- * TXT R E S O U R C E R E C O R D
- */
-
-#ifndef DNS_TXT_MINDATA
-#define DNS_TXT_MINDATA 1024
-#endif
-
-struct dns_txt {
- size_t size, len;
- unsigned char data[DNS_TXT_MINDATA];
-}; /* struct dns_txt */
-
-DNS_PUBLIC struct dns_txt *dns_txt_init(struct dns_txt *, size_t);
-
-DNS_PUBLIC int dns_txt_parse(struct dns_txt *, struct dns_rr *, struct dns_packet *);
-
-DNS_PUBLIC int dns_txt_push(struct dns_packet *, struct dns_txt *);
-
-DNS_PUBLIC int dns_txt_cmp(const struct dns_txt *, const struct dns_txt *);
-
-DNS_PUBLIC size_t dns_txt_print(void *, size_t, struct dns_txt *);
-
-
-/*
- * ANY R E S O U R C E R E C O R D
- */
-
-union dns_any {
- struct dns_a a;
- struct dns_aaaa aaaa;
- struct dns_mx mx;
- struct dns_ns ns;
- struct dns_cname cname;
- struct dns_soa soa;
- struct dns_ptr ptr;
- struct dns_srv srv;
- struct dns_opt opt;
- struct dns_sshfp sshfp;
- struct dns_txt txt, spf, rdata;
-}; /* union dns_any */
-
-#define DNS_ANY_INIT(any) { .rdata = { .size = sizeof *(any) - offsetof(struct dns_txt, data) } }
-
-DNS_PUBLIC union dns_any *dns_any_init(union dns_any *, size_t);
-
-DNS_PUBLIC int dns_any_parse(union dns_any *, struct dns_rr *, struct dns_packet *);
-
-DNS_PUBLIC int dns_any_push(struct dns_packet *, union dns_any *, enum dns_type);
-
-DNS_PUBLIC int dns_any_cmp(const union dns_any *, enum dns_type, const union dns_any *, enum dns_type);
-
-DNS_PUBLIC size_t dns_any_print(void *, size_t, union dns_any *, enum dns_type);
-
-DNS_PUBLIC size_t dns_any_cname(void *, size_t, union dns_any *, enum dns_type);
-
-
-/*
- * H O S T S I N T E R F A C E
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-struct dns_hosts;
-
-DNS_PUBLIC struct dns_hosts *dns_hosts_open(int *);
-
-DNS_PUBLIC void dns_hosts_close(struct dns_hosts *);
-
-DNS_PUBLIC dns_refcount_t dns_hosts_acquire(struct dns_hosts *);
-
-DNS_PUBLIC dns_refcount_t dns_hosts_release(struct dns_hosts *);
-
-DNS_PUBLIC struct dns_hosts *dns_hosts_mortal(struct dns_hosts *);
-
-DNS_PUBLIC struct dns_hosts *dns_hosts_local(int *);
-
-DNS_PUBLIC int dns_hosts_loadfile(struct dns_hosts *, FILE *);
-
-DNS_PUBLIC int dns_hosts_loadpath(struct dns_hosts *, const char *);
-
-DNS_PUBLIC int dns_hosts_dump(struct dns_hosts *, FILE *);
-
-DNS_PUBLIC int dns_hosts_insert(struct dns_hosts *, int, const void *, const void *, _Bool);
-
-DNS_PUBLIC struct dns_packet *dns_hosts_query(struct dns_hosts *, struct dns_packet *, int *);
-
-
-/*
- * R E S O L V . C O N F I N T E R F A C E
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-struct dns_resolv_conf {
- struct sockaddr_storage nameserver[3];
-
- char search[4][DNS_D_MAXNAME + 1];
-
- /* (f)ile, (b)ind, (c)ache */
- char lookup[4 * (1 + (4 * 2))];
-
- /* getaddrinfo family by preference order ("inet4", "inet6") */
- int family[3];
-
- struct {
- _Bool edns0;
-
- unsigned ndots;
-
- unsigned timeout;
-
- unsigned attempts;
-
- _Bool rotate;
-
- _Bool recurse;
-
- _Bool smart;
-
- enum {
- DNS_RESCONF_TCP_ENABLE,
- DNS_RESCONF_TCP_ONLY,
- DNS_RESCONF_TCP_DISABLE,
- } tcp;
- } options;
-
- struct sockaddr_storage iface;
-
- struct { /* PRIVATE */
- dns_atomic_t refcount;
- } _;
-}; /* struct dns_resolv_conf */
-
-DNS_PUBLIC struct dns_resolv_conf *dns_resconf_open(int *);
-
-DNS_PUBLIC void dns_resconf_close(struct dns_resolv_conf *);
-
-DNS_PUBLIC dns_refcount_t dns_resconf_acquire(struct dns_resolv_conf *);
-
-DNS_PUBLIC dns_refcount_t dns_resconf_release(struct dns_resolv_conf *);
-
-DNS_PUBLIC struct dns_resolv_conf *dns_resconf_mortal(struct dns_resolv_conf *);
-
-DNS_PUBLIC struct dns_resolv_conf *dns_resconf_local(int *);
-
-DNS_PUBLIC struct dns_resolv_conf *dns_resconf_root(int *);
-
-DNS_PUBLIC int dns_resconf_pton(struct sockaddr_storage *, const char *);
-
-DNS_PUBLIC int dns_resconf_loadfile(struct dns_resolv_conf *, FILE *);
-
-DNS_PUBLIC int dns_resconf_loadpath(struct dns_resolv_conf *, const char *);
-
-DNS_PUBLIC int dns_nssconf_loadfile(struct dns_resolv_conf *, FILE *);
-
-DNS_PUBLIC int dns_nssconf_loadpath(struct dns_resolv_conf *, const char *);
-
-DNS_PUBLIC int dns_resconf_dump(struct dns_resolv_conf *, FILE *);
-
-DNS_PUBLIC int dns_nssconf_dump(struct dns_resolv_conf *, FILE *);
-
-DNS_PUBLIC int dns_resconf_setiface(struct dns_resolv_conf *, const char *, unsigned short);
-
-typedef unsigned long dns_resconf_i_t;
-
-DNS_PUBLIC size_t dns_resconf_search(void *, size_t, const void *, size_t, struct dns_resolv_conf *, dns_resconf_i_t *);
-
-
-/*
- * H I N T S E R V E R I N T E R F A C E
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-struct dns_hints;
-
-DNS_PUBLIC struct dns_hints *dns_hints_open(struct dns_resolv_conf *, int *);
-
-DNS_PUBLIC void dns_hints_close(struct dns_hints *);
-
-DNS_PUBLIC dns_refcount_t dns_hints_acquire(struct dns_hints *);
-
-DNS_PUBLIC dns_refcount_t dns_hints_release(struct dns_hints *);
-
-DNS_PUBLIC struct dns_hints *dns_hints_mortal(struct dns_hints *);
-
-DNS_PUBLIC int dns_hints_insert(struct dns_hints *, const char *, const struct sockaddr *, unsigned);
-
-DNS_PUBLIC unsigned dns_hints_insert_resconf(struct dns_hints *, const char *, struct dns_resolv_conf *, int *);
-
-DNS_PUBLIC struct dns_hints *dns_hints_local(struct dns_resolv_conf *, int *);
-
-DNS_PUBLIC struct dns_hints *dns_hints_root(struct dns_resolv_conf *, int *);
-
-DNS_PUBLIC struct dns_packet *dns_hints_query(struct dns_hints *, struct dns_packet *, int *);
-
-DNS_PUBLIC int dns_hints_dump(struct dns_hints *, FILE *);
-
-
-struct dns_hints_i {
- const char *zone;
-
- struct {
- unsigned next;
- unsigned seed;
- } state;
-}; /* struct dns_hints_i */
-
-#define dns_hints_i_new(...) (&(struct dns_hints_i){ __VA_ARGS__ })
-
-DNS_PUBLIC unsigned dns_hints_grep(struct sockaddr **, socklen_t *, unsigned, struct dns_hints_i *, struct dns_hints *);
-
-
-/*
- * C A C H E I N T E R F A C E
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-struct dns_cache {
- void *state;
-
- dns_refcount_t (*acquire)(struct dns_cache *);
- dns_refcount_t (*release)(struct dns_cache *);
-
- struct dns_packet *(*query)(struct dns_packet *, struct dns_cache *, int *);
-
- int (*submit)(struct dns_packet *, struct dns_cache *);
- int (*check)(struct dns_cache *);
- struct dns_packet *(*fetch)(struct dns_cache *, int *);
-
- int (*pollfd)(struct dns_cache *);
- short (*events)(struct dns_cache *);
- void (*clear)(struct dns_cache *);
-
- union {
- long i;
- void *p;
- } arg[3];
-
- struct { /* PRIVATE */
- dns_atomic_t refcount;
- } _;
-}; /* struct dns_cache */
-
-
-DNS_PUBLIC struct dns_cache *dns_cache_init(struct dns_cache *);
-
-DNS_PUBLIC void dns_cache_close(struct dns_cache *);
-
-
-/*
- * A P P L I C A T I O N I N T E R F A C E
- *
- * Options to change the behavior of the API. Applies across all the
- * different components.
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-#define DNS_OPTS_INITIALIZER_ { 0, 0 }, 0
-#define DNS_OPTS_INITIALIZER { DNS_OPTS_INITIALIZER_ }
-#define DNS_OPTS_INIT(...) { DNS_OPTS_INITIALIZER_, __VA_ARGS__ }
-
-#define dns_opts(...) (&dns_quietinit((struct dns_options)DNS_OPTS_INIT(__VA_ARGS__)))
-
-struct dns_options {
- /*
- * If the callback closes *fd, it must set it to -1. Otherwise, the
- * descriptor is queued and lazily closed at object destruction or
- * by an explicit call to _clear(). This allows safe use of
- * kqueue(2), epoll(2), et al -style persistent events.
- */
- struct {
- void *arg;
- int (*cb)(int *fd, void *arg);
- } closefd;
-
- /* bitmask for _events() routines */
- enum dns_events {
- DNS_SYSPOLL,
- DNS_LIBEVENT,
- } events;
-}; /* struct dns_options */
-
-
-/*
- * S T A T S I N T E R F A C E S
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-struct dns_stat {
- size_t queries;
-
- struct {
- struct {
- size_t count, bytes;
- } sent, rcvd;
- } udp, tcp;
-}; /* struct dns_stat */
-
-
-/*
- * S O C K E T I N T E R F A C E
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-struct dns_socket;
-
-DNS_PUBLIC struct dns_socket *dns_so_open(const struct sockaddr *, int, const struct dns_options *, int *error);
-
-DNS_PUBLIC void dns_so_close(struct dns_socket *);
-
-DNS_PUBLIC void dns_so_reset(struct dns_socket *);
-
-DNS_PUBLIC unsigned short dns_so_mkqid(struct dns_socket *so);
-
-DNS_PUBLIC struct dns_packet *dns_so_query(struct dns_socket *, struct dns_packet *, struct sockaddr *, int *);
-
-DNS_PUBLIC int dns_so_submit(struct dns_socket *, struct dns_packet *, struct sockaddr *);
-
-DNS_PUBLIC int dns_so_check(struct dns_socket *);
-
-DNS_PUBLIC struct dns_packet *dns_so_fetch(struct dns_socket *, int *);
-
-DNS_PUBLIC time_t dns_so_elapsed(struct dns_socket *);
-
-DNS_PUBLIC void dns_so_clear(struct dns_socket *);
-
-DNS_PUBLIC int dns_so_events(struct dns_socket *);
-
-DNS_PUBLIC int dns_so_pollfd(struct dns_socket *);
-
-DNS_PUBLIC int dns_so_poll(struct dns_socket *, int);
-
-DNS_PUBLIC const struct dns_stat *dns_so_stat(struct dns_socket *);
-
-
-/*
- * R E S O L V E R I N T E R F A C E
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-struct dns_resolver;
-
-DNS_PUBLIC struct dns_resolver *dns_res_open(struct dns_resolv_conf *, struct dns_hosts *hosts, struct dns_hints *, struct dns_cache *, const struct dns_options *, int *);
-
-DNS_PUBLIC struct dns_resolver *dns_res_stub(const struct dns_options *, int *);
-
-DNS_PUBLIC void dns_res_reset(struct dns_resolver *);
-
-DNS_PUBLIC void dns_res_close(struct dns_resolver *);
-
-DNS_PUBLIC dns_refcount_t dns_res_acquire(struct dns_resolver *);
-
-DNS_PUBLIC dns_refcount_t dns_res_release(struct dns_resolver *);
-
-DNS_PUBLIC struct dns_resolver *dns_res_mortal(struct dns_resolver *);
-
-DNS_PUBLIC int dns_res_submit(struct dns_resolver *, const char *, enum dns_type, enum dns_class);
-
-DNS_PUBLIC int dns_res_submit2(struct dns_resolver *, const char *, size_t, enum dns_type, enum dns_class);
-
-DNS_PUBLIC int dns_res_check(struct dns_resolver *);
-
-DNS_PUBLIC struct dns_packet *dns_res_fetch(struct dns_resolver *, int *);
-
-DNS_PUBLIC time_t dns_res_elapsed(struct dns_resolver *);
-
-DNS_PUBLIC void dns_res_clear(struct dns_resolver *);
-
-DNS_PUBLIC int dns_res_events(struct dns_resolver *);
-
-DNS_PUBLIC int dns_res_pollfd(struct dns_resolver *);
-
-DNS_PUBLIC time_t dns_res_timeout(struct dns_resolver *);
-
-DNS_PUBLIC int dns_res_poll(struct dns_resolver *, int);
-
-DNS_PUBLIC struct dns_packet *dns_res_query(struct dns_resolver *, const char *, enum dns_type, enum dns_class, int, int *);
-
-DNS_PUBLIC const struct dns_stat *dns_res_stat(struct dns_resolver *);
-
-DNS_PUBLIC void dns_res_sethints(struct dns_resolver *, struct dns_hints *);
-
-
-/*
- * A D D R I N F O I N T E R F A C E
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-struct dns_addrinfo;
-
-DNS_PUBLIC struct dns_addrinfo *dns_ai_open(const char *, const char *, enum dns_type, const struct addrinfo *, struct dns_resolver *, int *);
-
-DNS_PUBLIC void dns_ai_close(struct dns_addrinfo *);
-
-DNS_PUBLIC int dns_ai_nextent(struct addrinfo **, struct dns_addrinfo *);
-
-DNS_PUBLIC size_t dns_ai_print(void *, size_t, struct addrinfo *, struct dns_addrinfo *);
-
-DNS_PUBLIC time_t dns_ai_elapsed(struct dns_addrinfo *);
-
-DNS_PUBLIC void dns_ai_clear(struct dns_addrinfo *);
-
-DNS_PUBLIC int dns_ai_events(struct dns_addrinfo *);
-
-DNS_PUBLIC int dns_ai_pollfd(struct dns_addrinfo *);
-
-DNS_PUBLIC time_t dns_ai_timeout(struct dns_addrinfo *);
-
-DNS_PUBLIC int dns_ai_poll(struct dns_addrinfo *, int);
-
-DNS_PUBLIC const struct dns_stat *dns_ai_stat(struct dns_addrinfo *);
-
-
-/*
- * U T I L I T Y I N T E R F A C E S
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-DNS_PUBLIC size_t dns_strlcpy(char *, const char *, size_t);
-
-DNS_PUBLIC size_t dns_strlcat(char *, const char *, size_t);
-
-// add by zsx, 2017.12.20
-void set_read_timeout(int timeo);
-int get_read_timeout(void);
-// end add by zsx
-
-/*
- * M A C R O M A G I C S
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-#define DNS_PP_MIN(a, b) (((a) < (b))? (a) : (b))
-#define DNS_PP_MAX(a, b) (((a) > (b))? (a) : (b))
-#define DNS_PP_NARG_(a, b, c, d, e, f, g, h, i, j, k, N,...) N
-#define DNS_PP_NARG(...) DNS_PP_NARG_(__VA_ARGS__, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
-#define DNS_PP_CALL(F, ...) F(__VA_ARGS__)
-#define DNS_PP_PASTE(x, y) x##y
-#define DNS_PP_XPASTE(x, y) DNS_PP_PASTE(x, y)
-#define DNS_PP_STRINGIFY_(s) #s
-#define DNS_PP_STRINGIFY(s) DNS_PP_STRINGIFY_(s)
-#define DNS_PP_D1 0
-#define DNS_PP_D2 1
-#define DNS_PP_D3 2
-#define DNS_PP_D4 3
-#define DNS_PP_D5 4
-#define DNS_PP_D6 5
-#define DNS_PP_D7 6
-#define DNS_PP_D8 7
-#define DNS_PP_D9 8
-#define DNS_PP_D10 9
-#define DNS_PP_D11 10
-#define DNS_PP_DEC(N) DNS_PP_XPASTE(DNS_PP_D, N)
-
-#endif /* SYS_UNIX */
-#endif /* DNS_H */
diff --git a/lib_fiber/c/src/event.c b/lib_fiber/c/src/event.c
index f0d889cbc..1f7911e1d 100644
--- a/lib_fiber/c/src/event.c
+++ b/lib_fiber/c/src/event.c
@@ -74,7 +74,8 @@ EVENT *event_create(int size)
#endif
#ifdef HAS_EPOLL
- ring_init(&ev->epoll_list);
+ ev->epoll_list = timer_cache_create();
+ ring_init(&ev->epoll_ready);
#endif
return ev;
}
@@ -89,14 +90,13 @@ acl_handle_t event_handle(EVENT *ev)
return ev->handle(ev);
}
-ssize_t event_size(EVENT *ev)
-{
- return ev->setsize;
-}
-
void event_free(EVENT *ev)
{
timer_cache_free(ev->poll_list);
+#ifdef HAS_EPOLL
+ timer_cache_free(ev->epoll_list);
+#endif
+
ev->free(ev);
}
@@ -253,7 +253,8 @@ int event_add_read(EVENT *ev, FILE_EVENT *fe, event_proc *proc)
}
if (fe->fd >= (socket_t) ev->setsize) {
- msg_error("fd: %d >= setsize: %d", fe->fd, (int) ev->setsize);
+ msg_error("%s(%d): fd=%d >= setsize=%d", __FUNCTION__,
+ __LINE__, fe->fd, (int) ev->setsize);
acl_fiber_set_error(ERANGE);
return 0;
}
@@ -296,7 +297,8 @@ int event_add_write(EVENT *ev, FILE_EVENT *fe, event_proc *proc)
}
if (fe->fd >= (socket_t) ev->setsize) {
- msg_error("fd: %d >= setsize: %d", fe->fd, (int) ev->setsize);
+ msg_error("%s(%d): fd=%d >= setsize=%d", __FUNCTION__,
+ __LINE__, fe->fd, (int) ev->setsize);
acl_fiber_set_error(ERANGE);
return 0;
}
@@ -410,7 +412,7 @@ static void event_process_poll(EVENT *ev)
RING_ITER iter;
RING *head;
POLL_EVENT *pe;
- long long now = event_get_stamp(ev);
+ long long now = event_get_stamp(ev);
TIMER_CACHE_NODE *node = avl_first(&ev->poll_list->tree), *next;
/* Check and call all the pe's callback which was timeout except the
@@ -442,35 +444,29 @@ static void event_process_poll(EVENT *ev)
#ifdef HAS_EPOLL
static void event_process_epoll(EVENT *ev)
{
-#if 0
- while (1) {
- EPOLL_EVENT *ee;
- RING *head = ring_pop_head(&ev->epoll_list);
- if (head == NULL) {
- break;
+ RING_ITER iter;
+ RING *head;
+ EPOLL_EVENT *ee;
+ long long now = event_get_stamp(ev);
+ TIMER_CACHE_NODE *node = avl_first(&ev->epoll_list->tree), *next;
+
+ while (node && node->expire >= 0 && node->expire <= now) {
+ next = AVL_NEXT(&ev->epoll_list->tree, node);
+
+ ring_foreach(iter, &node->ring) {
+ ee = TO_APPL(iter.ptr, EPOLL_EVENT, me);
+ ee->proc(ev, ee);
}
+
+ node = next;
+ }
+
+ while ((head = ring_pop_head(&ev->epoll_ready)) != NULL) {
ee = TO_APPL(head, EPOLL_EVENT, me);
ee->proc(ev, ee);
}
-#else
- EPOLL_EVENT *ee;
- RING *next, *curr;
- long long now;
- now = event_get_stamp(ev);
-
- for (next = ring_succ(&ev->epoll_list); next != &ev->epoll_list;) {
- ee = ring_to_appl(next, EPOLL_EVENT, me);
- if (ee->nready != 0 || (ee->expire >= 0 && now >= ee->expire)) {
- curr = next;
- next = ring_succ(next);
- ring_detach(curr);
- ee->proc(ev, ee);
- } else {
- next = ring_succ(next);
- }
- }
-#endif
+ ring_init(&ev->epoll_ready);
}
#endif
diff --git a/lib_fiber/c/src/event.h b/lib_fiber/c/src/event.h
index ac055dc4b..15cc2899d 100644
--- a/lib_fiber/c/src/event.h
+++ b/lib_fiber/c/src/event.h
@@ -150,12 +150,6 @@ struct FILE_EVENT {
};
#ifdef HAS_POLL
-struct POLLFD {
- FILE_EVENT *fe;
- POLL_EVENT *pe;
- struct pollfd *pfd;
-};
-
struct POLL_EVENT {
RING me;
@@ -169,24 +163,16 @@ struct POLL_EVENT {
#endif
#ifdef HAS_EPOLL
-struct EPOLL_CTX {
- int fd;
- int op;
- int mask;
- int rmask;
- FILE_EVENT *fe;
- EPOLL_EVENT *ee;
- epoll_data_t data;
-};
+
+typedef struct EPOLL EPOLL;
struct EPOLL_EVENT {
RING me;
ACL_FIBER *fiber;
+ EPOLL *epoll;
+
epoll_proc *proc;
- size_t nfds;
long long expire;
- EPOLL_CTX **fds;
- int epfd;
struct epoll_event *events;
int maxevents;
@@ -212,7 +198,8 @@ struct EVENT {
#endif
#ifdef HAS_EPOLL
- RING epoll_list;
+ TIMER_CACHE *epoll_list;
+ RING epoll_ready;
#endif
unsigned waiter;
@@ -242,7 +229,6 @@ void event_set(int event_mode);
EVENT *event_create(int size);
const char *event_name(EVENT *ev);
acl_handle_t event_handle(EVENT *ev);
-ssize_t event_size(EVENT *ev);
void event_free(EVENT *ev);
void event_close(EVENT *ev, FILE_EVENT *fe);
long long event_set_stamp(EVENT *ev);
diff --git a/lib_fiber/c/src/event/event_epoll.c b/lib_fiber/c/src/event/event_epoll.c
index 50ce35c5c..cae0f1734 100644
--- a/lib_fiber/c/src/event/event_epoll.c
+++ b/lib_fiber/c/src/event/event_epoll.c
@@ -316,6 +316,14 @@ EVENT *event_epoll_create(int size)
hook_init();
}
+ // Limit the max events buff maybe a good idea to impromve performance
+ // for handling large fds. Because epoll uses robin round to handle
+ // all the ready fds, so we needn't worry about the starvation of the
+ // left ready fds.
+ if (size <= 0 || size > 100) {
+ size = 100;
+ }
+
ep->events = (struct epoll_event *)
mem_malloc(sizeof(struct epoll_event) * size);
ep->size = size;
@@ -325,7 +333,7 @@ EVENT *event_epoll_create(int size)
ep->w_ready = array_create(100);
#endif
- ep->epfd = __sys_epoll_create(1024);
+ ep->epfd = __sys_epoll_create(size);
assert(ep->epfd >= 0);
ep->event.name = epoll_name;
diff --git a/lib_fiber/c/src/fiber.c b/lib_fiber/c/src/fiber.c
index 6a8dc9c91..f6621f6e8 100644
--- a/lib_fiber/c/src/fiber.c
+++ b/lib_fiber/c/src/fiber.c
@@ -36,7 +36,14 @@ typedef struct THREAD {
unsigned idgen;
int count;
size_t switched;
+ size_t switched_old;
int nlocal;
+
+#ifdef SHARE_STACK
+ char *stack_buff;
+ size_t stack_size;
+ size_t stack_dlen;
+#endif
} THREAD;
static THREAD *__main_fiber = NULL;
@@ -45,6 +52,10 @@ static __thread int __scheduled = 0;
static __thread int __schedule_auto = 0;
__thread int var_hook_sys_api = 0;
+#ifdef SHARE_STACK
+static size_t __shared_stack_size = 1024000;
+#endif
+
#ifdef SYS_UNIX
static FIBER_ALLOC_FN __fiber_alloc_fn = fiber_unix_alloc;
static FIBER_ORIGIN_FN __fiber_origin_fn = fiber_unix_origin;
@@ -52,8 +63,8 @@ static FIBER_ORIGIN_FN __fiber_origin_fn = fiber_unix_origin;
static FIBER_ALLOC_FN __fiber_alloc_fn = fiber_win_alloc;
static FIBER_ORIGIN_FN __fiber_origin_fn = fiber_win_origin;
#else
-static ACL_FIBER *fiber_dummy_alloc(void(*start_fn)(ACL_FIBER*) fiber_unused,
- size_t size fiber_unused)
+static ACL_FIBER *fiber_dummy_alloc(ACL_FIBER_ATTR *attr fiber_unused,
+ void(*start_fn)(ACL_FIBER*) fiber_unused, size_t size fiber_unused)
{
msg_fatal("unknown OS");
return NULL;
@@ -98,13 +109,13 @@ static void thread_free(void *ctx)
return;
}
- /* free fiber object in the dead fibers link */
+ /* Free fiber object in the dead fibers link */
while ((head = ring_pop_head(&__thread_fiber->dead))) {
fiber = RING_TO_APPL(head, ACL_FIBER, me);
fiber_free(fiber);
}
- /* free all possible aliving fiber object */
+ /* Free all possible aliving fiber object */
for (i = 0; i < __thread_fiber->slot; i++) {
fiber_free(__thread_fiber->fibers[i]);
}
@@ -113,6 +124,10 @@ static void thread_free(void *ctx)
mem_free(tf->fibers);
}
+#ifdef SHARE_STACK
+ mem_free(tf->stack_buff);
+#endif
+
tf->original->free_fn(tf->original);
mem_free(tf);
@@ -165,6 +180,12 @@ static void fiber_check(void)
__thread_fiber->count = 0;
__thread_fiber->nlocal = 0;
+#ifdef SHARE_STACK
+ __thread_fiber->stack_size = __shared_stack_size;
+ __thread_fiber->stack_buff = mem_malloc(__thread_fiber->stack_size);
+ __thread_fiber->stack_dlen = 0;
+#endif
+
ring_init(&__thread_fiber->ready);
ring_init(&__thread_fiber->dead);
@@ -176,6 +197,40 @@ static void fiber_check(void)
}
}
+ACL_FIBER *fiber_origin(void)
+{
+ return __thread_fiber->original;
+}
+
+#ifdef SHARE_STACK
+
+char *fiber_share_stack_addr(void)
+{
+ return __thread_fiber->stack_buff;
+}
+
+char *fiber_share_stack_bottom(void)
+{
+ return __thread_fiber->stack_buff + __thread_fiber->stack_size;
+}
+
+size_t fiber_share_stack_size(void)
+{
+ return __thread_fiber->stack_size;
+}
+
+size_t fiber_share_stack_dlen(void)
+{
+ return __thread_fiber->stack_dlen;
+}
+
+void fiber_share_stack_set_dlen(size_t dlen)
+{
+ __thread_fiber->stack_dlen = dlen;
+}
+
+#endif
+
#ifdef HOOK_ERRNO
static void fiber_init(void)
@@ -205,7 +260,7 @@ static void fiber_init(void)
#endif
}
-/* see /usr/include/bits/errno.h for __errno_location */
+/* See /usr/include/bits/errno.h for __errno_location */
#ifdef ANDROID
volatile int* __errno(void)
#else
@@ -356,7 +411,7 @@ static void fiber_swap(ACL_FIBER *from, ACL_FIBER *to)
size_t slot = from->slot;
int n = ring_size(&__thread_fiber->dead);
- /* if the cached dead fibers reached the limit,
+ /* If the cached dead fibers reached the limit,
* some will be freed
*/
if (n > MAX_CACHE) {
@@ -474,14 +529,14 @@ void acl_fiber_signal(ACL_FIBER *fiber, int signum)
fiber->signum = signum;
- if (fiber == curr) { // just return if kill myself
+ if (fiber == curr) { // Just return if kill myself
return;
}
ring_detach(&curr->me);
ring_detach(&fiber->me);
- /* add the current fiber and signed fiber in the head of the ready */
+ /* Add the current fiber and signed fiber in the head of the ready */
#if 0
fiber_ready(fiber);
fiber_yield();
@@ -537,25 +592,32 @@ void acl_fiber_ready(ACL_FIBER *fiber)
int acl_fiber_yield(void)
{
- size_t n;
-
if (ring_size(&__thread_fiber->ready) == 0) {
return 0;
}
- n = __thread_fiber->switched;
+ __thread_fiber->switched_old = __thread_fiber->switched;
__thread_fiber->running->status = FIBER_STATUS_NONE;
acl_fiber_ready(__thread_fiber->running);
acl_fiber_switch();
- // when switched overflows, it will be set to 0, then n saved last
+ // When switched overflows, it will be set to 0, then n saved last
// switched's value will larger than switched, so we need to use
// abs function to avoiding this problem
+ if (__thread_fiber->switched == 0) {
+ return (int) (__thread_fiber->switched -
+ __thread_fiber->switched_old - 1);
+ } else {
+ return (int) (__thread_fiber->switched_old -
+ __thread_fiber->switched - 1);
+ }
+/*
#if defined(__APPLE__) || defined(SYS_WIN) || defined(ANDROID)
- return (int) (__thread_fiber->switched - n - 1);
+ return (int) (__thread_fiber->switched - __thread_fiber->switched_old - 1);
#else
- return (int) abs(__thread_fiber->switched - n - 1);
+ return (int) abs(__thread_fiber->switched - __thread_fiber->switched_old - 1);
#endif
+*/
}
unsigned acl_fiber_ndead(void)
@@ -647,7 +709,7 @@ ACL_FIBER *acl_fiber_alloc(size_t size, void **pptr)
}
static ACL_FIBER *fiber_alloc(void (*fn)(ACL_FIBER *, void *),
- void *arg, size_t size)
+ void *arg, const ACL_FIBER_ATTR *attr)
{
ACL_FIBER *fiber = NULL;
RING *head;
@@ -656,17 +718,17 @@ static ACL_FIBER *fiber_alloc(void (*fn)(ACL_FIBER *, void *),
#define APPL RING_TO_APPL
- /* try to reuse the fiber memory in dead queue */
+ /* Try to reuse the fiber memory in dead queue */
head = ring_pop_head(&__thread_fiber->dead);
if (head == NULL) {
- fiber = __fiber_alloc_fn(fiber_start, size);
+ fiber = __fiber_alloc_fn(fiber_start, attr);
fbase_init(&fiber->base, FBASE_F_FIBER);
} else {
fiber = APPL(head, ACL_FIBER, me);
}
__thread_fiber->idgen++;
- if (__thread_fiber->idgen == 0) { /* overflow ? */
+ if (__thread_fiber->idgen == 0) { /* Overflow ? */
__thread_fiber->idgen++;
}
@@ -675,12 +737,13 @@ static ACL_FIBER *fiber_alloc(void (*fn)(ACL_FIBER *, void *),
fiber->signum = 0;
fiber->fn = fn;
fiber->arg = arg;
+ fiber->oflag = attr ? attr->oflag : 0;
fiber->flag = 0;
fiber->status = FIBER_STATUS_NONE;
fiber->waiting = NULL;
ring_init(&fiber->holding);
- fiber->init_fn(fiber, size);
+ fiber->init_fn(fiber, attr ? attr->stack_size : 128000);
return fiber;
}
@@ -690,10 +753,40 @@ void acl_fiber_schedule_init(int on)
__schedule_auto = on;
}
+void acl_fiber_attr_init(ACL_FIBER_ATTR *attr)
+{
+ attr->oflag = 0;
+ attr->stack_size = 128000;
+}
+
+void acl_fiber_attr_setstacksize(ACL_FIBER_ATTR *attr, size_t size)
+{
+ attr->stack_size = size;
+}
+
+void acl_fiber_attr_setsharestack(ACL_FIBER_ATTR *attr, int on)
+{
+ if (on) {
+ attr->oflag |= ACL_FIBER_ATTR_SHARE_STACK;
+ } else {
+ attr->oflag &= ~ACL_FIBER_ATTR_SHARE_STACK;
+ }
+}
+
ACL_FIBER *acl_fiber_create(void (*fn)(ACL_FIBER *, void *),
void *arg, size_t size)
{
- ACL_FIBER *fiber = fiber_alloc(fn, arg, size);
+ ACL_FIBER_ATTR attr;
+
+ acl_fiber_attr_init(&attr);
+ attr.stack_size = size;
+ return acl_fiber_create2(&attr, fn, arg);
+}
+
+ACL_FIBER *acl_fiber_create2(const ACL_FIBER_ATTR *attr,
+ void (*fn)(ACL_FIBER *, void *), void *arg)
+{
+ ACL_FIBER *fiber = fiber_alloc(fn, arg, attr);
__thread_fiber->count++;
@@ -714,6 +807,11 @@ ACL_FIBER *acl_fiber_create(void (*fn)(ACL_FIBER *, void *),
return fiber;
}
+int acl_fiber_use_share_stack(const ACL_FIBER *fiber)
+{
+ return fiber->oflag & ACL_FIBER_ATTR_SHARE_STACK ? 1 : 0;
+}
+
unsigned int acl_fiber_id(const ACL_FIBER *fiber)
{
return fiber ? fiber->id : 0;
@@ -733,6 +831,25 @@ int acl_fiber_status(const ACL_FIBER *fiber)
return fiber ? fiber->status : 0;
}
+void acl_fiber_set_shared_stack_size(size_t size)
+{
+ if (size >= 1024) {
+#ifdef SHARE_STACK
+ __shared_stack_size = size;
+#endif
+ }
+}
+
+size_t acl_fiber_get_shared_stack_size(void)
+{
+#if defined(SHARE_STACK)
+ return __shared_stack_size;
+#else
+ return 0;
+#endif
+}
+
+
void acl_fiber_schedule_set_event(int event_mode)
{
event_set(event_mode);
@@ -778,7 +895,7 @@ void acl_fiber_schedule(void)
__thread_fiber->running = NULL;
}
- /* release dead fiber */
+ /* Release dead fiber */
while ((head = ring_pop_head(&__thread_fiber->dead)) != NULL) {
fiber = RING_TO_APPL(head, ACL_FIBER, me);
fiber_free(fiber);
diff --git a/lib_fiber/c/src/fiber.h b/lib_fiber/c/src/fiber.h
index 0edab398f..ebed99668 100644
--- a/lib_fiber/c/src/fiber.h
+++ b/lib_fiber/c/src/fiber.h
@@ -50,17 +50,18 @@ struct ACL_FIBER {
int errnum;
int sys;
int signum;
+ unsigned int oflag;
unsigned int flag;
- RING holding;
- ACL_FIBER_MUTEX *waiting;
-
#define FIBER_F_SAVE_ERRNO (unsigned) 1 << 0
#define FIBER_F_KILLED (unsigned) 1 << 1
#define FIBER_F_CLOSED (unsigned) 1 << 2
#define FIBER_F_SIGNALED (unsigned) 1 << 3
#define FIBER_F_CANCELED (FIBER_F_KILLED | FIBER_F_CLOSED | FIBER_F_SIGNALED)
+ RING holding;
+ ACL_FIBER_MUTEX *waiting;
+
FIBER_LOCAL **locals;
int nlocal;
@@ -76,9 +77,19 @@ struct ACL_FIBER {
/* in fiber.c */
extern __thread int var_hook_sys_api;
+
FIBER_BASE *fbase_alloc(void);
void fbase_free(FIBER_BASE *fbase);
void fiber_free(ACL_FIBER *fiber);
+ACL_FIBER *fiber_origin(void);
+
+#ifdef SHARE_STACK
+char *fiber_share_stack_addr(void);
+char *fiber_share_stack_bottom(void);
+size_t fiber_share_stack_size(void);
+size_t fiber_share_stack_dlen(void);
+void fiber_share_stack_set_dlen(size_t dlen);
+#endif
/* in fbase.c */
void fbase_event_open(FIBER_BASE *fbase);
@@ -124,13 +135,15 @@ int epoll_event_close(int epfd);
/* in fiber/fiber_unix.c */
#ifdef SYS_UNIX
ACL_FIBER *fiber_unix_origin(void);
-ACL_FIBER *fiber_unix_alloc(void (*start_fn)(ACL_FIBER *), size_t size);
+ACL_FIBER *fiber_unix_alloc(void (*start_fn)(ACL_FIBER *),
+ const ACL_FIBER_ATTR *attr);
#endif
/* in fiber/fiber_win.c */
#ifdef SYS_WIN
ACL_FIBER *fiber_win_origin(void);
-ACL_FIBER *fiber_win_alloc(void (*start_fn)(ACL_FIBER *), size_t size);
+ACL_FIBER *fiber_win_alloc(void (*start_fn)(ACL_FIBER *),
+ const ACL_FIBER_ATTR *attr);
#endif
#endif
diff --git a/lib_fiber/c/src/fiber/fiber_unix.c b/lib_fiber/c/src/fiber/fiber_unix.c
index 51bab1029..f1b30cdf7 100644
--- a/lib_fiber/c/src/fiber/fiber_unix.c
+++ b/lib_fiber/c/src/fiber/fiber_unix.c
@@ -45,9 +45,14 @@ typedef struct FIBER_UNIX {
# endif
size_t size;
char *buff;
+ size_t dlen;
} FIBER_UNIX;
#if defined(USE_BOOST_JMP)
+# if defined(SHARE_STACK)
+# error "Not support shared stack when using boost jmp!"
+# endif
+
typedef struct {
FIBER_UNIX *from;
FIBER_UNIX *to;
@@ -64,18 +69,64 @@ static void swap_fcontext(FIBER_UNIX *from, FIBER_UNIX *to)
jmp = (s_jump_t*) trans.data;
jmp->from->fcontext = trans.fctx;
}
+
+#endif
+
+#if defined(SHARE_STACK)
+
+static void fiber_stack_save(FIBER_UNIX *curr, const char *stack_top)
+{
+ curr->dlen = fiber_share_stack_bottom() - stack_top;
+ if (curr->dlen > curr->size) {
+ stack_free(curr->buff);
+ curr->buff = (char *) stack_alloc(curr->dlen);
+ curr->size = curr->dlen;
+ }
+ memcpy(curr->buff, stack_top, curr->dlen);
+}
+
+static void fiber_stack_restore(FIBER_UNIX *curr)
+{
+ // After coming back, the current fiber's stack should be
+ // restored and copied from its private memory to the shared
+ // stack running memory.
+ if (curr->dlen > 0) {
+ char *bottom = fiber_share_stack_bottom();
+ memcpy(bottom - curr->dlen, curr->buff, curr->dlen);
+ fiber_share_stack_set_dlen(curr->dlen);
+ }
+ // else if from->dlen == 0, the fiber must be the origin fiber
+ // that its fiber id should be 0.
+}
+
#endif
static void fiber_unix_swap(FIBER_UNIX *from, FIBER_UNIX *to)
{
+ // The shared stack mode isn't supported in USE_BOOST_JMP current,
+ // which may be supported in future.
+ // If the fiber isn't in exiting status, and not the origin fiber,
+ // the fiber's running stack should be copied from the shared running
+ // stack to the fiber's private memory.
+#if defined(SHARE_STACK)
+ if (from->fiber.oflag & ACL_FIBER_ATTR_SHARE_STACK
+ && from->fiber.status != FIBER_STATUS_EXITING
+ && from->fiber.id > 0) {
+
+ char stack_top = 0;
+ fiber_stack_save(from, &stack_top);
+ }
+#endif
+
#if defined(USE_BOOST_JMP)
swap_fcontext(from, to);
#elif defined(USE_JMP)
- /* use setcontext() for the initial jump, as it allows us to set up
+
+ /* Use setcontext() for the initial jump, as it allows us to set up
* a stack, but continue with longjmp() as it's much faster.
*/
if (SETJMP(&from->env) == 0) {
- /* context just be used once for set up a stack, which will
+ /* Context just be used once for set up a stack, which will
* be freed in fiber_start. The context in __thread_fiber
* was set NULL.
*/
@@ -85,12 +136,24 @@ static void fiber_unix_swap(FIBER_UNIX *from, FIBER_UNIX *to)
LONGJMP(&to->env);
}
}
-#else
+#else // Use the default context swap API
if (swapcontext(from->context, to->context) < 0) {
msg_fatal("%s(%d), %s: swapcontext error %s",
__FILE__, __LINE__, __FUNCTION__, last_serror());
}
#endif
+
+#if defined(SHARE_STACK)
+ {
+ FIBER_UNIX *curr = (FIBER_UNIX *) acl_fiber_running();
+
+ if (curr->fiber.oflag & ACL_FIBER_ATTR_SHARE_STACK
+ && curr->fiber.status != FIBER_STATUS_EXITING) {
+
+ fiber_stack_restore(curr);
+ }
+ }
+#endif
}
static void fiber_unix_free(ACL_FIBER *fiber)
@@ -111,13 +174,16 @@ static void fiber_unix_free(ACL_FIBER *fiber)
}
#if defined(USE_BOOST_JMP)
+
static void fiber_unix_start(transfer_t arg)
{
s_jump_t *jmp = (s_jump_t*) arg.data;
jmp->from->fcontext = arg.fctx;
jmp->to->fiber.start_fn(&jmp->to->fiber);
}
+
#else
+
union cc_arg
{
void *p;
@@ -135,7 +201,7 @@ static void fiber_unix_start(unsigned int x, unsigned int y)
fb = (FIBER_UNIX *)arg.p;
#ifdef USE_JMP
- /* when using setjmp/longjmp, the context just be used only once */
+ /* When using setjmp/longjmp, the context just be used only once */
if (fb->context != NULL) {
stack_free(fb->context);
fb->context = NULL;
@@ -143,18 +209,20 @@ static void fiber_unix_start(unsigned int x, unsigned int y)
#endif
fb->fiber.start_fn(&fb->fiber);
}
-#endif // USE_BOOST_JMP
+
+#endif // !USE_BOOST_JMP
static void fiber_unix_init(ACL_FIBER *fiber, size_t size)
{
FIBER_UNIX *fb = (FIBER_UNIX *) fiber;
#if !defined(USE_BOOST_JMP)
+ FIBER_UNIX *origin;
union cc_arg carg;
sigset_t zero;
#endif
if (fb->size < size) {
- /* if using realloc, real memory will be used, when we first
+ /* If using realloc, real memory will be used, when we first
* free and malloc again, then we'll just use virtual memory,
* because memcpy will be called in realloc.
*/
@@ -164,9 +232,22 @@ static void fiber_unix_init(ACL_FIBER *fiber, size_t size)
}
#if defined(USE_BOOST_JMP)
+# if defined(SHARE_STACK)
+ if (fb->fiber.oflag & ACL_FIBER_ATTR_SHARE_STACK) {
+ fb->stack = fiber_share_stack_bottom();
+ fb->fcontext = make_fcontext(fb->stack,
+ fiber_share_stack_size(),
+ (void(*)(transfer_t)) fiber_unix_start);
+ } else {
+ fb->stack = fb->buff + fb->size;
+ fb->fcontext = make_fcontext(fb->stack, fb->size,
+ (void(*)(transfer_t)) fiber_unix_start);
+ }
+# else
fb->stack = fb->buff + fb->size;
fb->fcontext = make_fcontext(fb->stack, fb->size,
(void(*)(transfer_t)) fiber_unix_start);
+# endif
#else
carg.p = fiber;
@@ -189,15 +270,28 @@ static void fiber_unix_init(ACL_FIBER *fiber, size_t size)
__FILE__, __LINE__, __FUNCTION__, last_serror());
}
- fb->context->uc_stack.ss_sp = fb->buff + 8;
- fb->context->uc_stack.ss_size = fb->size - 64;
- fb->context->uc_link = NULL;
+#if defined(SHARE_STACK)
+ if (fb->fiber.oflag & ACL_FIBER_ATTR_SHARE_STACK) {
+ fb->context->uc_stack.ss_sp = fiber_share_stack_addr();
+ fb->context->uc_stack.ss_size = fiber_share_stack_size();
+ } else {
+ fb->context->uc_stack.ss_sp = fb->buff;
+ fb->context->uc_stack.ss_size = fb->size;
+ }
+#else
+ fb->context->uc_stack.ss_sp = fb->buff;
+ fb->context->uc_stack.ss_size = fb->size;
+#endif
+
+ origin = (FIBER_UNIX*) fiber_origin();
+ fb->context->uc_link = origin->context;
+
makecontext(fb->context, (void(*)(void)) fiber_unix_start,
2, carg.i[0], carg.i[1]);
#endif
#ifdef USE_VALGRIND
- /* avoid the valgrind warning */
+ /* Avoid the valgrind warning */
# if defined(USE_BOOST_JMP)
fb->vid = VALGRIND_STACK_REGISTER(fb->buff, fb->stack);
# else
@@ -208,13 +302,16 @@ static void fiber_unix_init(ACL_FIBER *fiber, size_t size)
#endif
}
-ACL_FIBER *fiber_unix_alloc(void (*start_fn)(ACL_FIBER *), size_t size)
+ACL_FIBER *fiber_unix_alloc(void (*start_fn)(ACL_FIBER *),
+ const ACL_FIBER_ATTR *attr)
{
FIBER_UNIX *fb = (FIBER_UNIX *) mem_calloc(1, sizeof(*fb));
+ size_t size = attr ? attr->stack_size : 128000;
- /* no using calloc just avoiding using real memory */
+ /* No using calloc just avoiding using real memory */
fb->buff = (char *) stack_alloc(size);
fb->size = size;
+ fb->fiber.oflag = attr ? attr->oflag : 0;
fb->fiber.init_fn = fiber_unix_init;
fb->fiber.free_fn = fiber_unix_free;
fb->fiber.swap_fn = (void (*)(ACL_FIBER*, ACL_FIBER*))fiber_unix_swap;
@@ -236,12 +333,12 @@ ACL_FIBER *fiber_unix_origin(void)
fb->fiber.start_fn = NULL;
#elif defined(USE_JMP)
- /* set context NULL when using setjmp that setcontext will not be
+ /* Set context NULL when using setjmp that setcontext will not be
* called in fiber_swap.
*/
fb->context = NULL;
#else
- fb->context = (ucontext_t *) stack_calloc(sizeof(ucontext_t));
+ fb->context = (ucontext_t *) stack_alloc(sizeof(ucontext_t));
#endif
fb->fiber.free_fn = fiber_unix_free;
fb->fiber.swap_fn = (void (*)(ACL_FIBER*, ACL_FIBER*)) fiber_unix_swap;
diff --git a/lib_fiber/c/src/fiber/fiber_win.c b/lib_fiber/c/src/fiber/fiber_win.c
index e424ce63e..1418300b4 100644
--- a/lib_fiber/c/src/fiber/fiber_win.c
+++ b/lib_fiber/c/src/fiber/fiber_win.c
@@ -62,9 +62,11 @@ static void fiber_win_init(FIBER_WIN *fb, size_t size)
}
}
-ACL_FIBER *fiber_win_alloc(void (*start_fn)(ACL_FIBER *), size_t size)
+ACL_FIBER *fiber_win_alloc(void (*start_fn)(ACL_FIBER *),
+ const ACL_FIBER_ATTR *attr)
{
FIBER_WIN *fb = (FIBER_WIN *) mem_calloc(1, sizeof(*fb));
+ size_t size = attr ? attr->stack_size : 128000;
fb->fiber.init_fn = (void (*)(ACL_FIBER*, size_t)) fiber_win_init;
fb->fiber.free_fn = fiber_win_free;
diff --git a/lib_fiber/c/src/fiber_io.c b/lib_fiber/c/src/fiber_io.c
index 9ef5c6ac2..39b894f01 100644
--- a/lib_fiber/c/src/fiber_io.c
+++ b/lib_fiber/c/src/fiber_io.c
@@ -94,6 +94,8 @@ static void thread_init(void)
static pthread_once_t __once_control = PTHREAD_ONCE_INIT;
+// Notice: don't write log here to avoid recursive calling when user call
+// acl_fiber_msg_register() to hook the log process.
void fiber_io_check(void)
{
if (__thread_fiber != NULL) {
@@ -109,8 +111,9 @@ void fiber_io_check(void)
}
if (pthread_once(&__once_control, thread_init) != 0) {
- msg_fatal("%s(%d), %s: pthread_once error %s",
+ printf("%s(%d), %s: pthread_once error %s\r\n",
__FILE__, __LINE__, __FUNCTION__, last_serror());
+ abort();
}
var_maxfd = open_limit(0);
@@ -118,8 +121,6 @@ void fiber_io_check(void)
var_maxfd = MAXFD;
}
- msg_info("%s(%d): maxfd=%d", __FUNCTION__, __LINE__, var_maxfd);
-
__thread_fiber = (FIBER_TLS *) mem_malloc(sizeof(FIBER_TLS));
__thread_fiber->event = event_create(var_maxfd);
__thread_fiber->ev_fiber = acl_fiber_create(fiber_io_loop,
@@ -140,7 +141,8 @@ void fiber_io_check(void)
__main_fiber = __thread_fiber;
atexit(fiber_io_main_free);
} else if (pthread_setspecific(__fiber_key, __thread_fiber) != 0) {
- msg_fatal("pthread_setspecific error!");
+ printf("pthread_setspecific error!\r\n");
+ abort();
}
}
@@ -568,8 +570,12 @@ static int fiber_file_del(FILE_EVENT *fe)
void fiber_file_free(FILE_EVENT *fe)
{
- fiber_file_del(fe);
- file_event_free(fe);
+ if (fiber_file_del(fe) == 0) {
+ file_event_free(fe);
+ } else {
+ // xxx: What happened?
+ msg_error("Some error happened for fe=%p, fd=%d", fe, fe->fd);
+ }
}
void fiber_file_close(FILE_EVENT *fe)
diff --git a/lib_fiber/c/src/hook/dns_init.c.bak b/lib_fiber/c/src/hook/dns_init.c.bak
deleted file mode 100644
index 9d58c2f60..000000000
--- a/lib_fiber/c/src/hook/dns_init.c.bak
+++ /dev/null
@@ -1,70 +0,0 @@
-#include "stdafx.h"
-#include "dns/dns.h"
-#include "common/pthread_patch.h"
-#include "hook.h"
-
-#ifdef SYS_UNIX
-
-struct dns_resolv_conf *var_dns_conf = NULL;
-struct dns_hosts *var_dns_hosts = NULL;
-struct dns_hints *var_dns_hints = NULL;
-
-void fiber_dns_set_read_wait(int timeout)
-{
- set_read_timeout(timeout);
-}
-
-static void dns_on_exit(void)
-{
- if (var_dns_conf) {
- dns_resconf_close(var_dns_conf);
- var_dns_conf = NULL;
- }
-
- if (var_dns_hosts) {
- dns_hosts_close(var_dns_hosts);
- var_dns_hosts = NULL;
- }
-
- if (var_dns_hints) {
- dns_hints_close(var_dns_hints);
- var_dns_hints = NULL;
- }
-}
-
-void fiber_dns_init(void)
-{
-#ifdef SYS_WIN
- static pthread_mutex_t __lock;
-#elif defined(SYS_UNIX)
- static pthread_mutex_t __lock = PTHREAD_MUTEX_INITIALIZER;
-#endif
- static int __called = 0;
- int err;
-
- (void) pthread_mutex_lock(&__lock);
-
- if (__called) {
- (void) pthread_mutex_unlock(&__lock);
- return;
- }
-
- __called++;
-
- err = 0;
- var_dns_conf = dns_resconf_local(&err);
- assert(var_dns_conf && err == 0);
- var_dns_conf->options.timeout = 1000;
-
- var_dns_hosts = dns_hosts_local(&err);
- assert(var_dns_hosts && err == 0);
-
- var_dns_hints = dns_hints_local(var_dns_conf, &err);
- assert(var_dns_hints && err == 0);
-
- atexit(dns_on_exit);
-
- (void) pthread_mutex_unlock(&__lock);
-}
-
-#endif
diff --git a/lib_fiber/c/src/hook/epoll.c b/lib_fiber/c/src/hook/epoll.c
index 44683c765..1d68a3716 100644
--- a/lib_fiber/c/src/hook/epoll.c
+++ b/lib_fiber/c/src/hook/epoll.c
@@ -10,32 +10,115 @@
/****************************************************************************/
-static EPOLL_EVENT *epfd_alloc(void)
-{
- EPOLL_EVENT *ee = mem_calloc(1, sizeof(EPOLL_EVENT));
- int maxfd = open_limit(0);
+struct EPOLL_CTX {
+ int fd;
+ int op;
+ int mask;
+ int rmask;
+ FILE_EVENT *fe;
+ EPOLL_EVENT *ee;
+ epoll_data_t data;
+};
- if (maxfd <= 0) {
- msg_fatal("%s(%d), %s: open_limit error %s",
- __FILE__, __LINE__, __FUNCTION__, last_serror());
+/**
+ * All EPOLL_EVENT owned by its fiber are assosiate with the same one epoll fd.
+ * one epoll fd -|- one EPOLL -|- fiber EPOLL_EVENT
+ * |- fiber EPOLL_EVENT
+ * |- ...
+ * |- fiber EPOLL_EVENT -|- socket EPOLL_CTX
+ * |- socket EPOLL_CTX
+ * |- socket EPOLL_CTX
+ * |- ...
+ */
+struct EPOLL {
+ int epfd;
+ EPOLL_CTX **fds;
+ size_t nfds;
+
+ // Store all EPOLL_EVENT, every fiber should use its own EPOLL_EVENT,
+ // Because in some case, one thread maybe have many fibers but it maybe
+ // use only one epoll fd to handle IO events, see acl_read_epoll_wait()
+ // in lib_acl/src/stdlib/iostuff/acl_read_wait.c.
+ HTABLE *ep_events;
+};
+
+/****************************************************************************/
+
+#ifdef SYS_WIN
+# define SNPRINTF _snprintf
+#else
+# define SNPRINTF snprintf
+#endif
+
+static void epoll_event_free(EPOLL_EVENT *ee)
+{
+ mem_free(ee);
+}
+
+static void fiber_on_exit(void *ctx)
+{
+ EPOLL_EVENT *ee = (EPOLL_EVENT*) ctx, *tmp;
+ ACL_FIBER *curr = acl_fiber_running();
+ char key[32];
+
+ assert(curr);
+
+ // If the epoll in ee has been set NULL in epoll_free(), the EPOLL
+ // must have been freed and the associated epoll fd must also have
+ // been closed, so we just only free the ee here.
+ if (ee->epoll == NULL) {
+ epoll_event_free(ee);
+ return;
}
- ++maxfd;
- ee->fds = (EPOLL_CTX **) mem_malloc(maxfd * sizeof(EPOLL_CTX *));
- ee->nfds = maxfd;
+ SNPRINTF(key, sizeof(key), "%u", curr->id);
+ tmp = (EPOLL_EVENT *) htable_find(ee->epoll->ep_events, key);
+
+ if (tmp == NULL) {
+ msg_fatal("%s(%d), %s: not found ee=%p, curr fiber=%d,"
+ " ee fiber=%d", __FILE__, __LINE__, __FUNCTION__,
+ ee, acl_fiber_id(curr), acl_fiber_id(ee->fiber));
+ }
+
+ assert(tmp == ee);
+ htable_delete(ee->epoll->ep_events, key, NULL);
+ epoll_event_free(ee);
+}
+
+static __thread int __local_key;
+
+static EPOLL_EVENT *epoll_event_alloc(void)
+{
+ // One EPOLL_EVENT can be owned by one fiber and be stored in the
+ // fiber's local store, so the EPOLL_EVENT can be used repeated by
+ // its owner fiber, and can be freed when the fiber is exiting.
+
+ EPOLL_EVENT *ee = (EPOLL_EVENT*) acl_fiber_get_specific(__local_key);
+ if (ee) {
+ return ee;
+ }
+
+ ee = mem_calloc(1, sizeof(EPOLL_EVENT));
+ acl_fiber_set_specific(&__local_key, ee, fiber_on_exit);
+
+ ring_init(&ee->me);
+ ee->fiber = acl_fiber_running();
return ee;
}
+/****************************************************************************/
+
static ARRAY *__main_epfds = NULL;
static __thread ARRAY *__epfds = NULL;
static pthread_key_t __once_key;
static pthread_once_t __once_control = PTHREAD_ONCE_INIT;
+static void epoll_free(EPOLL *ep);
+
static void thread_free(void *ctx fiber_unused)
{
- size_t j;
ITER iter;
if (__epfds == NULL) {
@@ -47,20 +130,13 @@ static void thread_free(void *ctx fiber_unused)
}
foreach(iter, __epfds) {
- EPOLL_EVENT *ee = (EPOLL_EVENT *) iter.data;
+ EPOLL *ep = (EPOLL *) iter.data;
- for (j = 0; j < ee->nfds; j++) {
- if (ee->fds[j] != NULL) {
- mem_free(ee->fds[j]);
- }
- }
-
- if (ee->epfd >= 0 && (*sys_close)(ee->epfd) < 0) {
+ if (ep->epfd >= 0 && (*sys_close)(ep->epfd) < 0) {
fiber_save_errno(acl_fiber_last_error());
}
- mem_free(ee->fds);
- mem_free(ee);
+ epoll_free(ep);
}
array_free(__epfds, NULL);
@@ -83,17 +159,21 @@ static void thread_init(void)
}
}
-static EPOLL_EVENT *epoll_event_create(int epfd)
+static EPOLL *epoll_alloc(int epfd)
{
- EPOLL_EVENT *ee = NULL;
- size_t i;
+ EPOLL *ep;
+ int maxfd = open_limit(0), i;
- /* using thread specific to store the epoll handles for each thread*/
+ if (maxfd <= 0) {
+ msg_fatal("%s(%d), %s: open_limit error %s",
+ __FILE__, __LINE__, __FUNCTION__, last_serror());
+ }
+
+ /* Using thread local to store the epoll handles for each thread. */
if (__epfds == NULL) {
if (pthread_once(&__once_control, thread_init) != 0) {
msg_fatal("%s(%d), %s: pthread_once error %s",
- __FILE__, __LINE__, __FUNCTION__,
- last_serror());
+ __FILE__, __LINE__, __FUNCTION__, last_serror());
}
__epfds = array_create(5);
@@ -105,25 +185,106 @@ static EPOLL_EVENT *epoll_event_create(int epfd)
}
}
- ee = epfd_alloc();
- array_append(__epfds, ee);
+ ep = mem_malloc(sizeof(EPOLL));
+ array_append(__epfds, ep);
- /* duplicate the current thread's epoll fd, so we can assosiate the
+ /* Duplicate the current thread's epoll fd, so we can assosiate the
* connection handles with one epoll fd for the current thread, and
- * use one epoll fd for each thread to handle all fds
+ * use one epoll fd for each thread to handle all fds.
*/
- ee->epfd = dup(epfd);
+ ep->epfd = dup(epfd);
- for (i = 0; i < ee->nfds; i++) {
- ee->fds[i] = NULL;
+ ep->nfds = maxfd;
+ ep->fds = (EPOLL_CTX **) mem_malloc(maxfd * sizeof(EPOLL_CTX *));
+ for (i = 0; i < maxfd; i++) {
+ ep->fds[i] = NULL;
}
- return ee;
+ ep->ep_events = htable_create(100);
+ return ep;
}
-static EPOLL_EVENT *epoll_event_find(int epfd)
+static void epoll_free(EPOLL *ep)
{
ITER iter;
+ size_t i;
+
+ // Walk through all EPOLL_EVENT stored in ep_events, and just set their
+ // epoll variable to NULL, because they will be freed in fiber_on_exit()
+ // when the fiber the EPOLL_EVENT belonging to is exiting.
+
+ foreach(iter, ep->ep_events) {
+ EPOLL_EVENT *ee = (EPOLL_EVENT *) iter.data;
+ ee->epoll = NULL;
+ }
+
+ htable_free(ep->ep_events, NULL);
+
+ for (i = 0; i < ep->nfds; i++) {
+ if (ep->fds[i] != NULL) {
+ mem_free(ep->fds[i]);
+ }
+ }
+
+ mem_free(ep->fds);
+ mem_free(ep);
+}
+
+int epoll_event_close(int epfd)
+{
+ EVENT *ev;
+ int sys_epfd;
+ EPOLL *ep = NULL;
+ int pos = -1;
+ ITER iter;
+
+ if (__epfds == NULL || epfd < 0) {
+ return -1;
+ }
+
+ foreach(iter, __epfds) {
+ EPOLL *tmp = (EPOLL *) iter.data;
+ if (tmp->epfd == epfd) {
+ ep = tmp;
+ pos = iter.i;
+ break;
+ }
+ }
+
+ if (ep == NULL) {
+ return -1;
+ }
+
+ ev = fiber_io_event();
+ assert(ev);
+
+ sys_epfd = event_handle(ev);
+ assert(sys_epfd >= 0);
+
+ // We can't close the epfd same as the internal fiber event's fd.
+ // Because we've alloced a new fd as a duplication of internal epfd
+ // in epoll_alloc by calling sys API dup(), the epfd here shouldn't
+ // be same as the internal epfd.
+
+ if (epfd == sys_epfd) {
+ msg_error("%s(%d): can't close the event sys_epfd=%d",
+ __FUNCTION__, __LINE__, epfd);
+ return -1;
+ }
+
+ epoll_free(ep);
+ array_delete(__epfds, pos, NULL);
+
+ return (*sys_close)(epfd);
+}
+
+static EPOLL_EVENT *epoll_event_find(int epfd, int create)
+{
+ ACL_FIBER *curr = acl_fiber_running();
+ EPOLL *ep = NULL;
+ EPOLL_EVENT *ee;
+ char key[32];
+ ITER iter;
if (__epfds == NULL) {
msg_error("%s(%d), %s: __epfds NULL",
@@ -132,58 +293,43 @@ static EPOLL_EVENT *epoll_event_find(int epfd)
}
foreach(iter, __epfds) {
- EPOLL_EVENT *ee = (EPOLL_EVENT *) iter.data;
- if (ee->epfd == epfd) {
- return ee;
- }
- }
-
- return NULL;
-}
-
-int epoll_event_close(int epfd)
-{
- ITER iter;
- EPOLL_EVENT *ee = NULL;
- int pos = -1;
- size_t i;
-
- if (__epfds == NULL || epfd < 0) {
- return -1;
- }
-
- foreach(iter, __epfds) {
- EPOLL_EVENT *e = (EPOLL_EVENT *) iter.data;
- if (e->epfd == epfd) {
- ee = e;
- pos = iter.i;
+ EPOLL *tmp = (EPOLL *) iter.data;
+ if (tmp->epfd == epfd) {
+ ep = tmp;
break;
}
}
- if (ee == NULL) {
- return -1;
+ if (ep == NULL) {
+ msg_error("%s(%d, %s: not found epfd=%d",
+ __FILE__, __LINE__, __FUNCTION__, epfd);
+ return NULL;
}
- for (i = 0; i < ee->nfds; i++) {
- if (ee->fds[i] != NULL) {
- mem_free(ee->fds[i]);
- }
+ SNPRINTF(key, sizeof(key), "%u", curr->id);
+ ee = (EPOLL_EVENT *) htable_find(ep->ep_events, key);
+ if (ee != NULL) {
+ ee->epoll = ep;
+ return ee;
}
- mem_free(ee->fds);
- mem_free(ee);
- array_delete(__epfds, pos, NULL);
+ if (create) {
+ ee = epoll_event_alloc();
+ ee->epoll = ep;
+ htable_enter(ep->ep_events, key, ee);
- return (*sys_close)(epfd);
+ return ee;
+ } else {
+ return NULL;
+ }
}
/****************************************************************************/
int epoll_create(int size fiber_unused)
{
- EPOLL_EVENT *ee;
EVENT *ev;
+ EPOLL *ep;
int epfd;
if (sys_epoll_create == NULL) {
@@ -195,9 +341,9 @@ int epoll_create(int size fiber_unused)
}
ev = fiber_io_event();
+ assert(ev);
- /* get the current thread's epoll fd */
-
+ // Get the current thread's epoll fd.
epfd = event_handle(ev);
if (epfd < 0) {
msg_error("%s(%d), %s: invalid event_handle %d",
@@ -205,8 +351,10 @@ int epoll_create(int size fiber_unused)
return epfd;
}
- ee = epoll_event_create(epfd);
- return ee->epfd;
+ // The epoll fd will be duplicated in the below function, and the new
+ // fd will be returned to the caller.
+ ep = epoll_alloc(epfd);
+ return ep->epfd;
}
#ifdef EPOLL_CLOEXEC
@@ -224,104 +372,146 @@ int epoll_create1(int flags)
}
#endif
-static void read_callback(EVENT *ev fiber_unused, FILE_EVENT *fe)
+static void read_callback(EVENT *ev, FILE_EVENT *fe)
{
- EPOLL_CTX *epx = fe->epx;
- EPOLL_EVENT *ee = epx->ee;
+ EPOLL_CTX *epx = fe->epx;
+ EPOLL_EVENT *ee;
+ EPOLL *ep;
- assert(ee);
+ assert(epx);
assert(epx->mask & EVENT_READ);
+ ee = epx->ee;
+ assert(ee);
+
+ ep = ee->epoll;
+ assert(ep);
+
+ // If the ready count exceeds the maxevents been set which limits the
+ // the buffer space to hold the the ready fds, we just return to let
+ // the left ready fds keeped in system buffer, and hope they'll be
+ // handled in the next epoll_wait().
if (ee->nready >= ee->maxevents) {
return;
}
ee->events[ee->nready].events |= EPOLLIN;
- memcpy(&ee->events[ee->nready].data, &ee->fds[epx->fd]->data,
- sizeof(ee->fds[epx->fd]->data));
+ memcpy(&ee->events[ee->nready].data, &ep->fds[epx->fd]->data,
+ sizeof(ep->fds[epx->fd]->data));
+
+ if (ee->nready == 0) {
+ timer_cache_remove(ev->epoll_list, ee->expire, &ee->me);
+ ring_prepend(&ev->epoll_ready, &ee->me);
+ }
+
if (!(ee->events[ee->nready].events & EPOLLOUT)) {
ee->nready++;
}
+
SET_READABLE(fe);
}
static void write_callback(EVENT *ev fiber_unused, FILE_EVENT *fe)
{
- EPOLL_CTX *epx = fe->epx;
- EPOLL_EVENT *ee = epx->ee;
+ EPOLL_CTX *epx = fe->epx;
+ EPOLL_EVENT *ee;
+ EPOLL *ep;
- assert(ee);
+ assert(epx);
assert(epx->mask & EVENT_WRITE);
+
+ ee = epx->ee;
+ assert(ee);
+
+ ep = ee->epoll;
+ assert(ep);
+
if (ee->nready >= ee->maxevents) {
return;
}
ee->events[ee->nready].events |= EPOLLOUT;
- memcpy(&ee->events[ee->nready].data, &ee->fds[epx->fd]->data,
- sizeof(ee->fds[epx->fd]->data));
+ memcpy(&ee->events[ee->nready].data, &ep->fds[epx->fd]->data,
+ sizeof(ep->fds[epx->fd]->data));
+
+ if (ee->nready == 0) {
+ timer_cache_remove(ev->epoll_list, ee->expire, &ee->me);
+ ring_prepend(&ev->epoll_ready, &ee->me);
+ }
+
if (!(ee->events[ee->nready].events & EPOLLIN)) {
ee->nready++;
}
+
SET_WRITABLE(fe);
}
static void epoll_ctl_add(EVENT *ev, EPOLL_EVENT *ee,
struct epoll_event *event, int fd, int op)
{
- if (ee->fds[fd] == NULL) {
- ee->fds[fd] = (EPOLL_CTX *) mem_malloc(sizeof(EPOLL_CTX));
+ EPOLL *ep = ee->epoll;
+
+ if (ep->fds[fd] == NULL) {
+ ep->fds[fd] = (EPOLL_CTX *) mem_malloc(sizeof(EPOLL_CTX));
}
- ee->fds[fd]->fd = fd;
- ee->fds[fd]->op = op;
- ee->fds[fd]->mask = EVENT_NONE;
- ee->fds[fd]->rmask = EVENT_NONE;
- ee->fds[fd]->ee = ee;
- ee->fds[fd]->fe->epx = ee->fds[fd];
+ ep->fds[fd]->fd = fd;
+ ep->fds[fd]->op = op;
+ ep->fds[fd]->mask = EVENT_NONE;
+ ep->fds[fd]->rmask = EVENT_NONE;
+ ep->fds[fd]->ee = ee;
- memcpy(&ee->fds[fd]->data, &event->data, sizeof(event->data));
+ memcpy(&ep->fds[fd]->data, &event->data, sizeof(event->data));
if (event->events & EPOLLIN) {
- ee->fds[fd]->mask |= EVENT_READ;
- ee->fds[fd]->fe = fiber_file_open_read(fd);
- event_add_read(ev, ee->fds[fd]->fe, read_callback);
- SET_READWAIT(ee->fds[fd]->fe);
+ ep->fds[fd]->mask |= EVENT_READ;
+ ep->fds[fd]->fe = fiber_file_open_read(fd);
+ ep->fds[fd]->fe->epx = ep->fds[fd];
+
+ event_add_read(ev, ep->fds[fd]->fe, read_callback);
+ SET_READWAIT(ep->fds[fd]->fe);
}
+
if (event->events & EPOLLOUT) {
- ee->fds[fd]->mask |= EVENT_WRITE;
- ee->fds[fd]->fe = fiber_file_open_write(fd);
- event_add_write(ev, ee->fds[fd]->fe, write_callback);
- SET_WRITEWAIT(ee->fds[fd]->fe);
+ ep->fds[fd]->mask |= EVENT_WRITE;
+ ep->fds[fd]->fe = fiber_file_open_write(fd);
+ ep->fds[fd]->fe->epx = ep->fds[fd];
+
+ event_add_write(ev, ep->fds[fd]->fe, write_callback);
+ SET_WRITEWAIT(ep->fds[fd]->fe);
}
}
static void epoll_ctl_del(EVENT *ev, EPOLL_EVENT *ee, int fd)
{
- if (ee->fds[fd]->mask & EVENT_READ) {
- event_del_read(ev, ee->fds[fd]->fe);
- CLR_READWAIT(ee->fds[fd]->fe);
- }
- if (ee->fds[fd]->mask & EVENT_WRITE) {
- event_del_write(ev, ee->fds[fd]->fe);
- CLR_WRITEWAIT(ee->fds[fd]->fe);
+ EPOLL *ep = ee->epoll;
+
+ if (ep->fds[fd]->mask & EVENT_READ) {
+ event_del_read(ev, ep->fds[fd]->fe);
+ CLR_READWAIT(ep->fds[fd]->fe);
}
- ee->fds[fd]->fd = -1;
- ee->fds[fd]->op = 0;
- ee->fds[fd]->mask = EVENT_NONE;
- ee->fds[fd]->rmask = EVENT_NONE;
- ee->fds[fd]->fe->epx = NULL;
- ee->fds[fd]->fe = NULL;
- memset(&ee->fds[fd]->data, 0, sizeof(ee->fds[fd]->data));
+ if (ep->fds[fd]->mask & EVENT_WRITE) {
+ event_del_write(ev, ep->fds[fd]->fe);
+ CLR_WRITEWAIT(ep->fds[fd]->fe);
+ }
- mem_free(ee->fds[fd]);
- ee->fds[fd] = NULL;
+ ep->fds[fd]->fd = -1;
+ ep->fds[fd]->op = 0;
+ ep->fds[fd]->mask = EVENT_NONE;
+ ep->fds[fd]->rmask = EVENT_NONE;
+ ep->fds[fd]->fe->epx = NULL;
+ ep->fds[fd]->fe = NULL;
+ memset(&ep->fds[fd]->data, 0, sizeof(ep->fds[fd]->data));
+
+ mem_free(ep->fds[fd]);
+ ep->fds[fd] = NULL;
}
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
{
- EPOLL_EVENT *ee;
EVENT *ev;
+ EPOLL_EVENT *ee;
if (sys_epoll_ctl == NULL) {
hook_once();
@@ -331,13 +521,15 @@ int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
return sys_epoll_ctl ? (*sys_epoll_ctl)(epfd, op, fd, event) : -1;
}
- ee = epoll_event_find(epfd);
+ ee = epoll_event_find(epfd, 1);
if (ee == NULL) {
msg_error("%s(%d), %s: not exist epfd=%d",
__FILE__, __LINE__, __FUNCTION__, epfd);
return -1;
}
+ assert(ee->epoll);
+
ev = fiber_io_event();
if (op == EPOLL_CTL_ADD || op == EPOLL_CTL_MOD) {
@@ -346,10 +538,8 @@ int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
msg_error("%s(%d), %s: invalid op %d, fd %d",
__FILE__, __LINE__, __FUNCTION__, op, fd);
return -1;
- } else if (ee->fds[fd] != NULL) {
+ } else if (ee->epoll->fds[fd] != NULL) {
epoll_ctl_del(ev, ee, fd);
- CLR_READWAIT(ee->fds[fd]->fe);
- CLR_WRITEWAIT(ee->fds[fd]->fe);
} else {
msg_error("%s(%d), %s: invalid fd=%d",
__FILE__, __LINE__, __FUNCTION__, fd);
@@ -398,7 +588,8 @@ int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)
}
if (!var_hook_sys_api) {
- return sys_epoll_wait ? (*sys_epoll_wait)(epfd, events, maxevents, timeout) : -1;
+ return sys_epoll_wait ? (*sys_epoll_wait)
+ (epfd, events, maxevents, timeout) : -1;
}
ev = fiber_io_event();
@@ -408,7 +599,7 @@ int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)
return -1;
}
- ee = epoll_event_find(epfd);
+ ee = epoll_event_find(epfd, 0);
if (ee == NULL) {
msg_error("%s(%d), %s: not exist epfd %d",
__FILE__, __LINE__, __FUNCTION__, epfd);
@@ -417,37 +608,51 @@ int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)
ee->events = events;
ee->maxevents = maxevents;
- ee->nready = 0;
ee->fiber = acl_fiber_running();
ee->proc = epoll_callback;
+ ee->nready = 0;
old_timeout = ev->timeout;
event_epoll_set(ev, ee, timeout);
ev->waiter++;
while (1) {
- ring_prepend(&ev->epoll_list, &ee->me);
+ timer_cache_add(ev->epoll_list, ee->expire, &ee->me);
fiber_io_inc();
ee->fiber->status = FIBER_STATUS_EPOLL_WAIT;
acl_fiber_switch();
+
+ if (ee->nready == 0) {
+ timer_cache_remove(ev->epoll_list, ee->expire, &ee->me);
+ }
+
ev->timeout = old_timeout;
- ev->timeout = -1;
if (acl_fiber_killed(ee->fiber)) {
- ring_detach(&ee->me);
+ acl_fiber_set_error(ee->fiber->errnum);
+ if (ee->nready == 0) {
+ ee->nready = -1;
+ }
+
msg_info("%s(%d), %s: fiber-%u was killed",
__FILE__, __LINE__, __FUNCTION__,
acl_fiber_id(ee->fiber));
break;
}
+
+ if (timer_cache_size(ev->epoll_list) == 0) {
+ ev->timeout = -1;
+ }
+
if (ee->nready != 0 || timeout == 0) {
break;
}
now = event_get_stamp(ev);
if (ee->expire > 0 && now >= ee->expire) {
+ acl_fiber_set_error(FIBER_ETIMEDOUT);
break;
}
}
diff --git a/lib_fiber/c/src/hook/poll.c b/lib_fiber/c/src/hook/poll.c
index 2583db7cb..9d5db949c 100644
--- a/lib_fiber/c/src/hook/poll.c
+++ b/lib_fiber/c/src/hook/poll.c
@@ -7,6 +7,12 @@
#ifdef HAS_POLL
+struct POLLFD {
+ FILE_EVENT *fe;
+ POLL_EVENT *pe;
+ struct pollfd *pfd;
+};
+
/****************************************************************************/
#define TO_APPL ring_to_appl
@@ -49,8 +55,6 @@ static void read_callback(EVENT *ev, FILE_EVENT *fe)
pfd->fe = NULL;
}
- assert(timer_cache_size(ev->poll_list) > 0);
-
/*
* If any fe has been ready, the pe holding fe should be removed from
* ev->poll_list to avoid to be called in timeout process.
@@ -63,6 +67,7 @@ static void read_callback(EVENT *ev, FILE_EVENT *fe)
timer_cache_remove(ev->poll_list, pfd->pe->expire, &pfd->pe->me);
ring_prepend(&ev->poll_ready, &pfd->pe->me);
}
+
pfd->pe->nready++;
SET_READABLE(fe);
}
@@ -99,12 +104,11 @@ static void write_callback(EVENT *ev, FILE_EVENT *fe)
pfd->fe = NULL;
}
- assert(timer_cache_size(ev->poll_list) > 0);
-
if (pfd->pe->nready == 0) {
timer_cache_remove(ev->poll_list, pfd->pe->expire, &pfd->pe->me);
ring_prepend(&ev->poll_ready, &pfd->pe->me);
}
+
pfd->pe->nready++;
SET_WRITABLE(fe);
}
@@ -201,6 +205,7 @@ static POLLFD *pollfd_alloc(POLL_EVENT *pe, struct pollfd *fds, nfds_t nfds)
#endif
pfds[i].pe = pe;
pfds[i].pfd = &fds[i];
+ pfds[i].pfd->revents = 0;
SET_POLLING(pfds[i].fe);
}
@@ -212,14 +217,74 @@ static void pollfd_free(POLLFD *pfds)
mem_free(pfds);
}
+#ifdef SHARE_STACK
+
+typedef struct pollfds {
+ struct pollfd *fds;
+ nfds_t nfds;
+ size_t size;
+} pollfds;
+
+static void fiber_on_exit(void *ctx)
+{
+ pollfds *pfds = (pollfds *) ctx;
+
+ mem_free(pfds->fds);
+ mem_free(pfds);
+}
+
+static __thread int __local_key;
+
+static pollfds *pollfds_save(const struct pollfd *fds, nfds_t nfds)
+{
+ pollfds *pfds = (pollfds *) acl_fiber_get_specific(__local_key);
+
+ if (pfds == NULL) {
+ pfds = (pollfds *) mem_malloc(sizeof(pollfds));
+ pfds->size = nfds + 1;
+ pfds->fds = mem_malloc(sizeof(struct pollfds) * pfds->size);
+ acl_fiber_set_specific(&__local_key, pfds, fiber_on_exit);
+ } else if (pfds->size < (size_t) nfds) {
+ mem_free(pfds->fds);
+ pfds->size = nfds + 1;
+ pfds->fds = mem_malloc(sizeof(struct pollfd) * pfds->size);
+ } else {
+ pfds->nfds = nfds;
+ }
+
+ pfds->nfds = nfds;
+ memcpy(pfds->fds, fds, sizeof(struct pollfd) * nfds);
+ return pfds;
+}
+
+static void pollfds_copy(const pollfds *pfds, struct pollfd *fds)
+{
+ memcpy(fds, pfds->fds, sizeof(struct pollfd) * pfds->nfds);
+}
+
+#endif // SHARE_STACK
+
#define MAX_TIMEOUT 200000000
int WINAPI acl_fiber_poll(struct pollfd *fds, nfds_t nfds, int timeout)
{
long long now;
- POLL_EVENT pe;
EVENT *ev;
- int old_timeout;
+ int old_timeout, nready;
+ ACL_FIBER *curr;
+
+#ifdef SHARE_STACK
+ // In shared stack mode, we should use heap memory for pe to hold
+ // all the fds, because the pe will be operated by the event fiber,
+ // but the shared stack can be used by only one fiber, the stack
+ // memory of the current fiber will be occupied by the other fiber
+ // after switching the other fiber. So, we use heap memory to hold
+ // pe to avoid stack memory collision.
+ pollfds *pfds;
+ POLL_EVENT pevent, *pe;
+#else
+ POLL_EVENT pevent, *pe;
+#endif
if (sys_poll == NULL) {
hook_once();
@@ -229,65 +294,93 @@ int WINAPI acl_fiber_poll(struct pollfd *fds, nfds_t nfds, int timeout)
return sys_poll ? (*sys_poll)(fds, nfds, timeout) : -1;
}
+ curr = acl_fiber_running();
+
if (timeout < 0) {
timeout = MAX_TIMEOUT;
}
- ev = fiber_io_event();
- pe.fds = pollfd_alloc(&pe, fds, nfds);
- pe.nfds = nfds;
- pe.fiber = acl_fiber_running();
- pe.proc = poll_callback;
- pe.nready = 0;
-
+ ev = fiber_io_event();
old_timeout = ev->timeout;
- poll_event_set(ev, &pe, timeout);
+
+#ifdef SHARE_STACK
+ if (curr->oflag & ACL_FIBER_ATTR_SHARE_STACK) {
+ pfds = pollfds_save(fds, nfds);
+ pe = (POLL_EVENT *) mem_malloc(sizeof(POLL_EVENT));
+ pe->fds = pollfd_alloc(pe, pfds->fds, nfds);
+ } else {
+ pfds = NULL;
+ pe = &pevent;
+ pe->fds = pollfd_alloc(pe, fds, nfds);
+ }
+#else
+ pe = &pevent;
+ pe->fds = pollfd_alloc(pe, fds, nfds);
+#endif
+
+ pe->nfds = nfds;
+ pe->fiber = curr;
+ pe->proc = poll_callback;
+
+ poll_event_set(ev, pe, timeout);
ev->waiter++;
while (1) {
- timer_cache_add(ev->poll_list, pe.expire, &pe.me);
- pe.nready = 0;
+ timer_cache_add(ev->poll_list, pe->expire, &pe->me);
+ pe->nready = 0;
fiber_io_inc();
- pe.fiber->status = FIBER_STATUS_POLL_WAIT;
+ pe->fiber->status = FIBER_STATUS_POLL_WAIT;
acl_fiber_switch();
- if (pe.nready == 0) {
- timer_cache_remove(ev->poll_list, pe.expire, &pe.me);
+ if (pe->nready == 0) {
+ timer_cache_remove(ev->poll_list, pe->expire, &pe->me);
}
ev->timeout = old_timeout;
- if (acl_fiber_killed(pe.fiber)) {
- acl_fiber_set_error(pe.fiber->errnum);
- pe.nready = -1;
+ if (acl_fiber_killed(pe->fiber)) {
+ acl_fiber_set_error(pe->fiber->errnum);
+ if (pe->nready == 0) {
+ pe->nready = -1;
+ }
msg_info("%s(%d), %s: fiber-%u was killed, %s, timeout=%d",
__FILE__, __LINE__, __FUNCTION__,
- acl_fiber_id(pe.fiber), last_serror(), timeout);
+ acl_fiber_id(pe->fiber), last_serror(), timeout);
break;
}
if (timer_cache_size(ev->poll_list) == 0) {
ev->timeout = -1;
}
- if (pe.nready != 0 || timeout == 0) {
+
+ if (pe->nready != 0 || timeout == 0) {
break;
}
now = event_get_stamp(ev);
- if (pe.expire > 0 && now >= pe.expire) {
+ if (pe->expire > 0 && now >= pe->expire) {
acl_fiber_set_error(FIBER_ETIMEDOUT);
break;
}
}
- poll_event_clean(ev, &pe);
- pollfd_free(pe.fds);
+ poll_event_clean(ev, pe);
+ pollfd_free(pe->fds);
ev->waiter--;
- return pe.nready;
+ nready = pe->nready;
+
+#ifdef SHARE_STACK
+ if (curr->oflag & ACL_FIBER_ATTR_SHARE_STACK) {
+ mem_free(pe);
+ pollfds_copy(pfds, fds);
+ }
+#endif
+
+ return nready;
}
#ifdef SYS_UNIX
diff --git a/lib_fiber/cpp/include/fiber/fiber.hpp b/lib_fiber/cpp/include/fiber/fiber.hpp
index d30a1cee2..8ab38d2af 100644
--- a/lib_fiber/cpp/include/fiber/fiber.hpp
+++ b/lib_fiber/cpp/include/fiber/fiber.hpp
@@ -35,8 +35,10 @@ public:
* Э̣Ȼص run ص running Ϊ true ʱ
* ֹ start
* @param stack_size {size_t} Э̶ջС
+ * @param Ƿùջʽ(Ҫùջʽڱ libfiber.a
+ * ʱ뿪 SHARE_STACK )
*/
- void start(size_t stack_size = 320000);
+ void start(size_t stack_size = 320000, bool share_stack = false);
/**
* ڱЭʱô˺֪ͨЭ˳
@@ -194,6 +196,18 @@ public:
*/
static void set_non_blocking(bool yes);
+ /**
+ * ùջģʽùջĴС,ڲȱʡֵΪ 1024000 ֽ
+ * @param size {size_t} ջڴС
+ */
+ static void set_shared_stack_size(size_t size);
+
+ /**
+ * ùջģʽ»ùջС
+ * @return {size_t} 0 ʾδùջʽ
+ */
+ static size_t get_shared_stack_size(void);
+
/**
* ʽñʹ acl IO Э̻ UNIX ƽ̨²ʽ
* ñΪڲԶ HOOK IO API
@@ -238,6 +252,7 @@ public:
*/
static void fiber_create(void (*fn)(ACL_FIBER*, void*),
void* ctx, size_t size);
+
protected:
/**
* 麯ʵֱͨ start Э̺
diff --git a/lib_fiber/cpp/src/fiber.cpp b/lib_fiber/cpp/src/fiber.cpp
index a3c5ba865..4bb0ab7aa 100644
--- a/lib_fiber/cpp/src/fiber.cpp
+++ b/lib_fiber/cpp/src/fiber.cpp
@@ -102,6 +102,16 @@ void fiber::set_non_blocking(bool yes)
acl_fiber_set_non_blocking(yes ? 1 : 0);
}
+void fiber::set_shared_stack_size(size_t size)
+{
+ acl_fiber_set_shared_stack_size(size);
+}
+
+size_t fiber::get_shared_stack_size(void)
+{
+ return acl_fiber_get_shared_stack_size();
+}
+
ACL_FIBER *fiber::get_fiber(void) const
{
return f_;
@@ -150,13 +160,18 @@ void fiber::run(void)
__FILE__, __LINE__, __FUNCTION__);
}
-void fiber::start(size_t stack_size /* = 64000 */)
+void fiber::start(size_t stack_size /* 64000 */, bool share_stack /* false */)
{
if (f_ != NULL) {
acl_msg_fatal("%s(%d), %s: fiber-%u, already running!",
__FILE__, __LINE__, __FUNCTION__, self());
}
- acl_fiber_create(fiber_callback, this, stack_size);
+ ACL_FIBER_ATTR attr;
+ acl_fiber_attr_init(&attr);
+ acl_fiber_attr_setstacksize(&attr, stack_size);
+ acl_fiber_attr_setsharestack(&attr, share_stack ? 1 : 0);
+
+ acl_fiber_create2(&attr, fiber_callback, this);
}
void fiber::fiber_callback(ACL_FIBER *f, void *ctx)
diff --git a/lib_fiber/cpp/src/fiber_server.cpp b/lib_fiber/cpp/src/fiber_server.cpp
index a6ce64492..31a0413d8 100644
--- a/lib_fiber/cpp/src/fiber_server.cpp
+++ b/lib_fiber/cpp/src/fiber_server.cpp
@@ -67,8 +67,10 @@ static ACL_CONFIG_STR_TABLE __conf_str_tab[] = {
};
static int acl_var_fiber_quick_abort;
+static int acl_var_fiber_share_stack;
static ACL_CONFIG_BOOL_TABLE __conf_bool_tab[] = {
{ "fiber_quick_abort", 1, &acl_var_fiber_quick_abort },
+ { "fiber_share_stack", 0, &acl_var_fiber_share_stack },
{ 0, 0, 0 },
};
@@ -141,6 +143,11 @@ static void thread_fiber_accept(ACL_FIBER *fiber, void *ctx)
static socket_t __max_fd = 0, __last_fd = 0;
ACL_VSTREAM *sstream = (ACL_VSTREAM *) ctx, *cstream;
char ip[64];
+ ACL_FIBER_ATTR attr;
+
+ acl_fiber_attr_init(&attr);
+ acl_fiber_attr_setstacksize(&attr, acl_var_fiber_stack_size);
+ acl_fiber_attr_setsharestack(&attr, acl_var_fiber_share_stack ? 1 : 0);
while (1) {
cstream = acl_vstream_accept(sstream, ip, sizeof(ip));
@@ -150,8 +157,7 @@ static void thread_fiber_accept(ACL_FIBER *fiber, void *ctx)
__max_fd = __last_fd;
}
- acl_fiber_create(fiber_client, cstream,
- acl_var_fiber_stack_size);
+ acl_fiber_create2(&attr, fiber_client, cstream);
continue;
}
@@ -401,6 +407,11 @@ static int main_dispatch_receive(int dispatch_fd)
char buf[256], remote[256], local[256];
int fd = -1, ret;
ACL_VSTREAM *cstream;
+ ACL_FIBER_ATTR attr;
+
+ acl_fiber_attr_init(&attr);
+ acl_fiber_attr_setstacksize(&attr, acl_var_fiber_stack_size);
+ acl_fiber_attr_setsharestack(&attr, acl_var_fiber_share_stack ? 1 : 0);
ret = acl_read_fd(dispatch_fd, buf, sizeof(buf) - 1, &fd);
if (ret < 0 || fd < 0) {
@@ -422,7 +433,7 @@ static int main_dispatch_receive(int dispatch_fd)
acl_vstream_set_peer(cstream, remote);
}
- acl_fiber_create(fiber_client, cstream, acl_var_fiber_stack_size);
+ acl_fiber_create2(&attr, fiber_client, cstream);
return 0;
}
diff --git a/lib_fiber/cpp/src/master_fiber.cpp b/lib_fiber/cpp/src/master_fiber.cpp
index 0fa6c47b1..241d3f949 100644
--- a/lib_fiber/cpp/src/master_fiber.cpp
+++ b/lib_fiber/cpp/src/master_fiber.cpp
@@ -108,14 +108,16 @@ void master_fiber::service_on_accept(void* ctx, ACL_VSTREAM *client)
master_fiber* mf = (master_fiber *) ctx;
acl_assert(mf != NULL);
- socket_stream stream;
- if (!stream.open(client)) {
+ socket_stream* stream = new socket_stream;
+ if (!stream->open(client)) {
logger_error("open stream error(%s)", acl_last_serror());
+ delete stream;
return;
}
- mf->on_accept(stream);
- stream.unbind();
+ mf->on_accept(*stream);
+ stream->unbind();
+ delete stream;
}
void master_fiber::thread_init(void* ctx)
diff --git a/lib_fiber/samples-c++1x/fiber/main.cpp b/lib_fiber/samples-c++1x/fiber/main.cpp
index 77edd1873..8f045f8e6 100644
--- a/lib_fiber/samples-c++1x/fiber/main.cpp
+++ b/lib_fiber/samples-c++1x/fiber/main.cpp
@@ -100,6 +100,7 @@ static void usage(const char* procname)
int main(int argc, char *argv[])
{
int ch, n = 10;
+ size_t shared_size;
acl::acl_cpp_init();
acl::log::stdout_open(true);
@@ -118,8 +119,14 @@ int main(int argc, char *argv[])
}
go fiber1;
- go fiber_wait4thread;
- go fiber_wait4fiber;
+
+ shared_size = acl::fiber::get_shared_stack_size();
+ if (shared_size == 0) {
+ // These two fibers can't running in shared stack mode.
+
+ go fiber_wait4thread;
+ go fiber_wait4fiber;
+ }
go[=] {
fiber2(n, "hello world");
diff --git a/lib_fiber/samples-c++1x/fiber/valgrind.sh b/lib_fiber/samples-c++1x/fiber/valgrind.sh
new file mode 100755
index 000000000..cc8944d6c
--- /dev/null
+++ b/lib_fiber/samples-c++1x/fiber/valgrind.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+#valgrind --tool=memcheck --leak-check=yes --leak-check=full --show-reachable=yes --max-stackframe=3426305034400000 -v ./fiber -n 10 -m 20
+valgrind --tool=memcheck --leak-check=yes --leak-check=full --show-reachable=yes -v ./fiber
diff --git a/lib_fiber/samples-c++1x/fiber_tbox/Makefile b/lib_fiber/samples-c++1x/fiber_tbox/Makefile
new file mode 100644
index 000000000..023e1a738
--- /dev/null
+++ b/lib_fiber/samples-c++1x/fiber_tbox/Makefile
@@ -0,0 +1,3 @@
+include ../Makefile_cpp.in
+CFLAGS += -std=c++11
+PROG = fiber_tbox
diff --git a/lib_fiber/samples-c++1x/fiber_tbox/main.cpp b/lib_fiber/samples-c++1x/fiber_tbox/main.cpp
new file mode 100644
index 000000000..6dba33848
--- /dev/null
+++ b/lib_fiber/samples-c++1x/fiber_tbox/main.cpp
@@ -0,0 +1,249 @@
+#include "stdafx.h"
+#include
+#include
+#include
+#include "../stamp.h"
+
+static void box_wakeup(acl::fiber_tbox& box)
+{
+ box.push(NULL);
+}
+
+static void box_wait(acl::fiber_tbox& box)
+{
+ box.pop();
+}
+
+static void test_in_shared_stack(size_t cocurrent, size_t n, size_t& count,
+ bool interactive)
+{
+ go[&] {
+ size_t total = cocurrent * n;
+ acl::fiber_tbox* box = new acl::fiber_tbox;
+ acl::fiber_tbox* box1;
+ if (interactive) {
+ box1 = new acl::fiber_tbox;
+ } else {
+ box1 = NULL;
+ }
+
+ for (size_t j = 0; j < cocurrent; j++) {
+ go[=] {
+ for (size_t i = 0; i < n; i++) {
+ if (box1) {
+ box_wait(*box1);
+ }
+
+ box_wakeup(*box);
+ }
+ };
+ }
+
+ for (size_t i = 0; i < total; i++) {
+ if (box1) {
+ box_wakeup(*box1);
+ }
+
+ box_wait(*box);
+ count++;
+ }
+
+ delete box;
+ delete box1;
+ printf(">>> wait over, count=%zd\r\n", count);
+ };
+}
+
+static void test_in_shared_stack_thread(size_t cocurrent, size_t n,
+ size_t& count, bool interactive)
+{
+ go[&] {
+ size_t total = cocurrent * n;
+ acl::fiber_tbox* box = new acl::fiber_tbox;
+ acl::fiber_tbox* box1;
+
+ if (interactive) {
+ box1 = new acl::fiber_tbox;
+ } else {
+ box1 = NULL;
+ }
+
+ for (size_t j = 0; j < cocurrent; j++) {
+ std::thread thread([=] {
+ for (size_t i = 0; i < n; i++) {
+ if (box1) {
+ box_wait(*box1);
+ }
+
+ box_wakeup(*box);
+ }
+ });
+ thread.detach();
+ }
+
+ for (size_t i = 0; i < total; i++) {
+ if (box1) {
+ box_wakeup(*box1);
+ }
+
+ box_wait(*box);
+ count++;
+ }
+
+ delete box;
+ delete box1;
+
+ printf(">>> wait over, count=%zd\r\n", count);
+ };
+}
+
+static void test_in_private_stack(size_t cocurrent, size_t n, size_t& count,
+ bool interactive)
+{
+ size_t total = cocurrent * n;
+
+ go[&] {
+ acl::fiber_tbox box;
+ acl::fiber_tbox box1;
+
+ for (size_t j = 0; j < cocurrent; j++) {
+ go[&] {
+ for (size_t i = 0; i < n; i++) {
+ if (interactive) {
+ box_wait(box1);
+ }
+
+ box_wakeup(box);
+ }
+ };
+ }
+
+ for (size_t i = 0; i < total; i++) {
+ if (interactive) {
+ box_wakeup(box1);
+ }
+
+ box_wait(box);
+ count++;
+ }
+
+ printf(">>> wait over, count=%zd\r\n", count);
+ };
+}
+
+static void test_in_private_stack_thread(size_t cocurrent, size_t n,
+ size_t& count, bool interactive)
+{
+ go[&] {
+ size_t total = cocurrent * n;
+ acl::fiber_tbox box;
+ acl::fiber_tbox box1;
+
+ for (size_t j = 0; j < cocurrent; j++) {
+ std::thread thread([&] {
+ for (size_t i = 0; i < n; i++) {
+ if (interactive) {
+ box_wait(box1);
+ }
+
+ box_wakeup(box);
+ }
+ });
+ thread.detach();
+ }
+
+ for (size_t i = 0; i < total; i++) {
+ if (interactive) {
+ box_wakeup(box1);
+ }
+
+ box_wait(box);
+ count++;
+ }
+
+ printf(">>> wait over, count=%zd\r\n", count);
+ };
+}
+static void usage(const char* procname)
+{
+ printf("usage: %s -h [help]\r\n"
+ " -c cocurrent\r\n"
+ " -n loop_count\r\n"
+ " -T [if use_thread]\r\n"
+ " -B [if interactive]\r\n"
+ , procname);
+}
+
+int main(int argc, char *argv[])
+{
+ int ch, n = 1, cocurrent = 1;
+ bool use_shared_stack = false, use_thread = false, interactive = false;
+
+ acl::acl_cpp_init();
+ acl::log::stdout_open(true);
+
+ while ((ch = getopt(argc, argv, "hc:n:STB")) > 0) {
+ switch (ch) {
+ case 'h':
+ usage(argv[0]);
+ return 0;
+ case 'c':
+ cocurrent = atoi(optarg);
+ break;
+ case 'n':
+ n = atoi(optarg);
+ break;
+ case 'S':
+ use_shared_stack = true;
+ break;
+ case 'T':
+ use_thread = true;
+ break;
+ case 'B':
+ interactive = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ size_t shared_stack_size = acl::fiber::get_shared_stack_size();
+
+ printf(">>> shared_stack_size: %zd\r\n", shared_stack_size);
+
+ struct timeval begin;
+ gettimeofday(&begin, NULL);
+
+ size_t count = 0;
+
+ if (use_shared_stack > 0) {
+ if (use_thread) {
+ test_in_shared_stack_thread(cocurrent, n, count,
+ interactive);
+ } else {
+ test_in_shared_stack(cocurrent, n, count, interactive);
+ }
+ } else {
+ if (shared_stack_size > 0) {
+ printf(">>> This will be crashed in shared stack!\r\n");
+ }
+
+ if (use_thread) {
+ test_in_private_stack_thread(cocurrent, n, count,
+ interactive);
+ } else {
+ test_in_private_stack(cocurrent, n, count, interactive);
+ }
+ }
+
+ acl::fiber::schedule();
+
+ struct timeval end;
+ gettimeofday(&end, NULL);
+
+ double cost = stamp_sub(&end, &begin);
+ double speed = (count * 1000) / (cost > 0 ? cost : 0.1);
+ printf(">>> Total count=%zd, cost=%.2f ms, speed=%.2f qps\r\n",
+ count, cost, speed);
+ return 0;
+}
diff --git a/lib_fiber/samples-c++1x/fiber_tbox/stdafx.cpp b/lib_fiber/samples-c++1x/fiber_tbox/stdafx.cpp
new file mode 100644
index 000000000..a27b824da
--- /dev/null
+++ b/lib_fiber/samples-c++1x/fiber_tbox/stdafx.cpp
@@ -0,0 +1 @@
+#include "stdafx.h"
diff --git a/lib_fiber/samples-c++1x/fiber_tbox/stdafx.h b/lib_fiber/samples-c++1x/fiber_tbox/stdafx.h
new file mode 100644
index 000000000..101513001
--- /dev/null
+++ b/lib_fiber/samples-c++1x/fiber_tbox/stdafx.h
@@ -0,0 +1,19 @@
+// stdafx.h : ϵͳļİļ
+// dzõĵĿضİļ
+//
+
+#pragma once
+
+
+// TODO: ڴ˴óҪĸͷļ
+
+#include "lib_acl.h"
+#include "acl_cpp/lib_acl.hpp"
+#include "fiber/fiber.hpp"
+
+#include "fiber/go_fiber.hpp"
+
+#ifdef WIN32
+#define snprintf _snprintf
+#endif
+
diff --git a/lib_fiber/samples-c++1x/fiber_tbox/valgrind.sh b/lib_fiber/samples-c++1x/fiber_tbox/valgrind.sh
new file mode 100755
index 000000000..5372db3d2
--- /dev/null
+++ b/lib_fiber/samples-c++1x/fiber_tbox/valgrind.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+#valgrind --tool=memcheck --leak-check=yes --leak-check=full --show-reachable=yes --max-stackframe=3426305034400000 -v ./fiber -n 10 -m 20
+valgrind --tool=memcheck --leak-check=yes --leak-check=full --show-reachable=yes -v ./fiber_tbox -S -c 100 -n 100
diff --git a/lib_fiber/samples-c++1x/go_fiber/Makefile b/lib_fiber/samples-c++1x/go_fiber/Makefile
new file mode 100644
index 000000000..251550ef2
--- /dev/null
+++ b/lib_fiber/samples-c++1x/go_fiber/Makefile
@@ -0,0 +1,3 @@
+include ../Makefile_cpp.in
+CFLAGS += -std=c++11
+PROG = go_fiber
diff --git a/lib_fiber/samples-c++1x/go_fiber/main.cpp b/lib_fiber/samples-c++1x/go_fiber/main.cpp
new file mode 100644
index 000000000..f3745265e
--- /dev/null
+++ b/lib_fiber/samples-c++1x/go_fiber/main.cpp
@@ -0,0 +1,75 @@
+#include "stdafx.h"
+#include
+#include
+
+static void fiber1(void)
+{
+ printf("in fiber: %d\r\n", acl::fiber::self());
+}
+
+static void fiber2(int n, const char* s)
+{
+ printf("in fiber: %d, n: %d, s: %s\r\n", acl::fiber::self(), n, s);
+}
+
+static void fiber3(acl::string& buf)
+{
+ printf("in fiber: %d, buf: %s\r\n", acl::fiber::self(), buf.c_str());
+ buf = "world";
+}
+
+static void fiber4(const acl::string& buf)
+{
+ printf("in fiber: %d, buf: %s\r\n", acl::fiber::self(), buf.c_str());
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+static void usage(const char* procname)
+{
+ printf("usage: %s -h [help] -n fibers_count\r\n", procname);
+}
+
+int main(int argc, char *argv[])
+{
+ int ch, n = 10;
+
+ acl::acl_cpp_init();
+ acl::log::stdout_open(true);
+
+ while ((ch = getopt(argc, argv, "hn:")) > 0) {
+ switch (ch) {
+ case 'h':
+ usage(argv[0]);
+ return 0;
+ case 'n':
+ n = atoi(optarg);
+ break;
+ default:
+ break;
+ }
+ }
+
+ go fiber1;
+
+ go[=] {
+ fiber2(n, "hello world");
+ };
+
+ acl::string buf("hello");
+
+ go[&] {
+ fiber3(buf);
+ };
+
+ go[&] {
+ fiber4(buf);
+ };
+
+ go[=] {
+ fiber4(buf);
+ };
+
+ acl::fiber::schedule();
+ return 0;
+}
diff --git a/lib_fiber/samples-c++1x/go_fiber/stdafx.cpp b/lib_fiber/samples-c++1x/go_fiber/stdafx.cpp
new file mode 100644
index 000000000..a27b824da
--- /dev/null
+++ b/lib_fiber/samples-c++1x/go_fiber/stdafx.cpp
@@ -0,0 +1 @@
+#include "stdafx.h"
diff --git a/lib_fiber/samples-c++1x/go_fiber/stdafx.h b/lib_fiber/samples-c++1x/go_fiber/stdafx.h
new file mode 100644
index 000000000..101513001
--- /dev/null
+++ b/lib_fiber/samples-c++1x/go_fiber/stdafx.h
@@ -0,0 +1,19 @@
+// stdafx.h : ϵͳļİļ
+// dzõĵĿضİļ
+//
+
+#pragma once
+
+
+// TODO: ڴ˴óҪĸͷļ
+
+#include "lib_acl.h"
+#include "acl_cpp/lib_acl.hpp"
+#include "fiber/fiber.hpp"
+
+#include "fiber/go_fiber.hpp"
+
+#ifdef WIN32
+#define snprintf _snprintf
+#endif
+
diff --git a/lib_fiber/samples-c++1x/go_fiber/valgrind.sh b/lib_fiber/samples-c++1x/go_fiber/valgrind.sh
new file mode 100755
index 000000000..c4189c1fa
--- /dev/null
+++ b/lib_fiber/samples-c++1x/go_fiber/valgrind.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+#valgrind --tool=memcheck --leak-check=yes --leak-check=full --show-reachable=yes --max-stackframe=3426305034400000 -v ./fiber -n 10 -m 20
+valgrind --tool=memcheck --leak-check=yes --leak-check=full --show-reachable=yes -v ./go_fiber
diff --git a/lib_fiber/samples-c++1x/stamp.h b/lib_fiber/samples-c++1x/stamp.h
new file mode 100644
index 000000000..a35632eda
--- /dev/null
+++ b/lib_fiber/samples-c++1x/stamp.h
@@ -0,0 +1,28 @@
+#ifndef __STAMP_INCLUDE_H__
+#define __STAMP_INCLUDE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static double stamp_sub(const struct timeval *from, const struct timeval *sub)
+{
+ struct timeval res;
+
+ memcpy(&res, from, sizeof(struct timeval));
+
+ res.tv_usec -= sub->tv_usec;
+ if (res.tv_usec < 0) {
+ --res.tv_sec;
+ res.tv_usec += 1000000;
+ }
+ res.tv_sec -= sub->tv_sec;
+
+ return (res.tv_sec * 1000.0 + res.tv_usec/1000.0);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib_fiber/samples/fiber/main.c b/lib_fiber/samples/fiber/main.c
index c0944d312..c61cab8f2 100644
--- a/lib_fiber/samples/fiber/main.c
+++ b/lib_fiber/samples/fiber/main.c
@@ -11,14 +11,15 @@
static int __max_loop = 1000;
static int __max_fiber = 1000;
static int __display = 0;
-static int __stack_size = 64000;
static __thread struct timeval __begin;
-static __thread int __left_fiber = 1000;
+static __thread long long __count = 0;
+
+#define DUMMY_SIZE 512000
static void stack_dummy(ACL_FIBER *fiber acl_unused)
{
- char buf[81920];
+ char buf[DUMMY_SIZE];
memset(buf, 0, sizeof(buf));
}
@@ -26,51 +27,63 @@ static void stack_dummy(ACL_FIBER *fiber acl_unused)
static void fiber_main(ACL_FIBER *fiber, void *ctx acl_unused)
{
int i;
+ size_t shared_stack_size = acl_fiber_get_shared_stack_size();
- if (0)
+ printf("\r\nshared_stack_size=%zd\r\n\r\n", shared_stack_size);
+
+ if (acl_fiber_use_share_stack(fiber) && shared_stack_size > DUMMY_SIZE) {
stack_dummy(fiber);
+ }
errno = acl_fiber_errno(fiber);
+
for (i = 0; i < __max_loop; i++) {
+ if (__count < 10) {
+ printf("fiber-%d, run, begin to yield\r\n",
+ acl_fiber_id(fiber));
+ }
+
acl_fiber_yield();
- if (!__display)
- continue;
- if (i <= 2)
- printf("fiber-%d, errno: %d\r\n",
+ if (__count++ < 10) {
+ printf("fiber-%d, wakeup errno: %d\r\n",
acl_fiber_id(fiber), errno);
+ printf("---------------------------------------\r\n");
+ }
}
- if (--__left_fiber == 0) {
- long long count = __max_fiber * __max_loop;
- struct timeval end;
- double spent;
-
- gettimeofday(&end, NULL);
- spent = stamp_sub(&end, &__begin);
- printf("fibers: %d, count: %lld, spent: %.2f, speed: %.2f\r\n",
- __max_fiber, count, spent,
- (count * 1000) / (spent > 0 ? spent : 1));
- }
+ printf("%s: fiber-%d exiting, count=%lld ...\r\n",
+ __FUNCTION__, acl_fiber_id(fiber), __count);
}
-static void *thread_main(void *ctx acl_unused)
+static void *thread_main(void *ctx)
{
+ ACL_FIBER_ATTR *attr = (ACL_FIBER_ATTR *) ctx;
int i;
- gettimeofday(&__begin, NULL);
- __left_fiber = __max_fiber;
-
- for (i = 0; i < __max_fiber; i++)
- acl_fiber_create(fiber_main, NULL, __stack_size);
+ for (i = 0; i < __max_fiber; i++) {
+ acl_fiber_create2(attr, fiber_main, NULL);
+ }
acl_fiber_schedule();
printf("thread: %lu\r\n", (unsigned long) acl_pthread_self());
-
return NULL;
}
+static void calc_speed(void)
+{
+ long long count = __max_fiber * __max_loop;
+ struct timeval end;
+ double spent, speed;
+
+ gettimeofday(&end, NULL);
+ spent = stamp_sub(&end, &__begin);
+ speed = (count * 1000) / (spent > 0 ? spent : 1);
+ printf("\r\nfibers: %d, count: %lld, spent: %.2f, speed: %.2f\r\n",
+ __max_fiber, count, spent, speed);
+}
+
static void usage(const char *procname)
{
printf("usage: %s -h [help]\r\n"
@@ -78,7 +91,9 @@ static void usage(const char *procname)
" -c max_fiber\r\n"
" -t max_threads\r\n"
" -d stack_size\r\n"
- " -e [if display]\r\n", procname);
+ " -e [if display]\r\n"
+ " -S [if use shared stack]\r\n"
+ , procname);
}
int main(int argc, char *argv[])
@@ -86,8 +101,12 @@ int main(int argc, char *argv[])
int ch, i, nthreads = 1;
acl_pthread_attr_t attr;
acl_pthread_t *tids;
+ ACL_FIBER_ATTR fiber_attr;
+ size_t stack_size = 64000;
- while ((ch = getopt(argc, argv, "hn:c:t:d:e")) > 0) {
+ acl_fiber_attr_init(&fiber_attr);
+
+ while ((ch = getopt(argc, argv, "hn:c:t:ed:S")) > 0) {
switch (ch) {
case 'h':
usage(argv[0]);
@@ -104,7 +123,11 @@ int main(int argc, char *argv[])
nthreads = 1;
break;
case 'd':
- __stack_size = atoi(optarg);
+ stack_size = (size_t) atoi(optarg);
+ acl_fiber_attr_setstacksize(&fiber_attr, stack_size);
+ break;
+ case 'S':
+ acl_fiber_attr_setsharestack(&fiber_attr, 1);
break;
case 'e':
__display = 1;
@@ -114,14 +137,23 @@ int main(int argc, char *argv[])
}
}
+ acl_fiber_set_shared_stack_size(8000000);
+
acl_pthread_attr_init(&attr);
tids = (acl_pthread_t *) acl_mycalloc(nthreads, sizeof(acl_pthread_t));
- for (i = 0; i < nthreads; i++)
- acl_pthread_create(&tids[i], &attr, thread_main, NULL);
+ gettimeofday(&__begin, NULL);
- for (i = 0; i < nthreads; i++)
+ for (i = 0; i < nthreads; i++) {
+ acl_pthread_create(&tids[i], &attr, thread_main, &fiber_attr);
+ }
+
+ for (i = 0; i < nthreads; i++) {
acl_pthread_join(tids[i], NULL);
+ }
+
+ calc_speed();
+ printf("All fiber threads exited now ...\r\n");
acl_myfree(tids);
diff --git a/lib_fiber/samples/fiber/valgrind.sh b/lib_fiber/samples/fiber/valgrind.sh
index 696368204..bb972305d 100755
--- a/lib_fiber/samples/fiber/valgrind.sh
+++ b/lib_fiber/samples/fiber/valgrind.sh
@@ -1,4 +1,4 @@
#!/bin/sh
#valgrind --tool=memcheck --leak-check=yes --leak-check=full --show-reachable=yes --max-stackframe=3426305034400000 -v ./fiber -n 10 -m 20
-valgrind --tool=memcheck --leak-check=yes --leak-check=full --show-reachable=yes -v ./fiber -n 1 -m 2
+valgrind --tool=memcheck --leak-check=yes --leak-check=full --show-reachable=yes -v ./fiber -c 100 -n 100 -S
diff --git a/lib_fiber/samples/httpd/main.cpp b/lib_fiber/samples/httpd/main.cpp
index eac028fd5..e55b2ae48 100644
--- a/lib_fiber/samples/httpd/main.cpp
+++ b/lib_fiber/samples/httpd/main.cpp
@@ -3,7 +3,7 @@
#include
#include "http_servlet.h"
-#define STACK_SIZE 320000
+static int STACK_SIZE = 128000;
static int __rw_timeout = 0;
static int __schedule_event = FIBER_EVENT_KERNEL;
@@ -11,31 +11,31 @@ static void http_server(ACL_FIBER *, void *ctx)
{
acl::socket_stream *conn = (acl::socket_stream *) ctx;
+ acl::memcache_session *session = new acl::memcache_session("127.0.0.1:11211");
+ http_servlet *servlet = new http_servlet(conn, session);
+ servlet->setLocalCharset("gb2312");
+
//printf("start one http_server\r\n");
- acl::memcache_session session("127.0.0.1:11211");
- http_servlet servlet(conn, &session);
- servlet.setLocalCharset("gb2312");
-
- while (true)
- {
- if (servlet.doRun() == false)
+ while (true) {
+ if (servlet->doRun() == false) {
break;
+ }
}
printf("close one connection: %d, %s\r\n", conn->sock_handle(),
acl::last_serror());
+ delete session;
+ delete servlet;
delete conn;
}
static void fiber_accept(ACL_FIBER *, void *ctx)
{
acl::server_socket* server = (acl::server_socket *) ctx;
- while (true)
- {
+ while (true) {
acl::socket_stream* client = server->accept();
- if (client == NULL)
- {
+ if (client == NULL) {
printf("accept failed: %s\r\n", acl::last_serror());
break;
}
@@ -59,11 +59,10 @@ public:
thread_server(const char* addr)
{
- server_inner_ = new acl::server_socket(acl::OPEN_FLAG_REUSEPORT);
- if (server_inner_->open(addr) == false)
- {
- printf("open %s error %s\r\n",
- addr, acl::last_serror());
+ server_inner_ = new acl::server_socket(acl::OPEN_FLAG_REUSEPORT, 128);
+ if (server_inner_->open(addr) == false) {
+ printf("%s(%d): open %s error %s\r\n", __FUNCTION__,
+ __LINE__, addr, acl::last_serror());
exit (1);
}
@@ -91,6 +90,7 @@ static void usage(const char* procname)
" -e event\r\n"
" -R reuse_port\r\n"
" -t threads\r\n"
+ " -z stack_size[default: 128000]\r\n"
" -r rw_timeout\r\n", procname);
}
@@ -100,10 +100,8 @@ int main(int argc, char *argv[])
int ch, nthreads = 2;
bool reuse_port = false;
- while ((ch = getopt(argc, argv, "hs:r:t:Re:")) > 0)
- {
- switch (ch)
- {
+ while ((ch = getopt(argc, argv, "hs:r:t:Re:z:")) > 0) {
+ switch (ch) {
case 'h':
usage(argv[0]);
return 0;
@@ -120,12 +118,17 @@ int main(int argc, char *argv[])
reuse_port = true;
break;
case 'e':
- if (strcasecmp(optarg, "kernel") == 0)
+ if (strcasecmp(optarg, "kernel") == 0) {
__schedule_event = FIBER_EVENT_KERNEL;
- else if (strcasecmp(optarg, "poll") == 0)
- __schedule_event = FIBER_EVENT_SELECT;
- else if (strcasecmp(optarg, "select") == 0)
+ } else if (strcasecmp(optarg, "poll") == 0) {
__schedule_event = FIBER_EVENT_POLL;
+ } else if (strcasecmp(optarg, "select") == 0) {
+ __schedule_event = FIBER_EVENT_SELECT;
+ }
+ break;
+ case 'z':
+ STACK_SIZE = atoi(optarg);
+ break;
default:
break;
}
@@ -136,26 +139,25 @@ int main(int argc, char *argv[])
acl::server_socket server;
- if (!reuse_port)
- {
- if (server.open(addr) == false)
- {
- printf("open %s error\r\n", addr.c_str());
+ if (!reuse_port) {
+ if (server.open(addr) == false) {
+ printf("%s(%d): open %s error %s\r\n", __FUNCTION__,
+ __LINE__, addr.c_str(), acl::last_serror());
exit (1);
- }
- else
+ } else {
printf("open %s ok\r\n", addr.c_str());
+ }
}
std::vector threads;
- for (int i = 0; i < nthreads; i++)
- {
+ for (int i = 0; i < nthreads; i++) {
acl::thread* thr;
- if (reuse_port)
+ if (reuse_port) {
thr = new thread_server(addr);
- else
+ } else {
thr = new thread_server(server);
+ }
threads.push_back(thr);
thr->set_detachable(false);
thr->start();
@@ -163,8 +165,7 @@ int main(int argc, char *argv[])
}
for (std::vector::iterator it = threads.begin();
- it != threads.end(); ++it)
- {
+ it != threads.end(); ++it) {
(*it)->wait();
delete *it;
}
diff --git a/lib_fiber/samples/httpd3/main.cpp b/lib_fiber/samples/httpd3/main.cpp
index d8fe7829a..09352b50d 100644
--- a/lib_fiber/samples/httpd3/main.cpp
+++ b/lib_fiber/samples/httpd3/main.cpp
@@ -9,26 +9,46 @@
#define STACK_SIZE 320000
static void client_callback(int type, ACL_EVENT *event,
- ACL_VSTREAM *cstream, void *ctx);
+ ACL_VSTREAM *conn, void *ctx);
-static int __rw_timeout = 0;
-static int __stop = 0;
-static int __real_http = 0;
-static int __use_kernel = 0;
+static int __rw_timeout = 0;
+static int __stop = 0;
+static int __real_http = 0;
+static int __use_kernel = 0;
+static int __accept_alone = 0;
-static int http_demo(ACL_VSTREAM *cstream, const char* res, size_t len)
+static int http_demo(ACL_VSTREAM *conn, const char* res, size_t len)
{
char buf[8192];
int ret;
- cstream->rw_timeout = __rw_timeout;
+ conn->rw_timeout = __rw_timeout;
while (1) {
- ret = acl_vstream_gets_nonl(cstream, buf, sizeof(buf) - 1);
+ ret = acl_vstream_gets_nonl(conn, buf, sizeof(buf) -1);
if (ret == ACL_VSTREAM_EOF) {
printf("gets error: %s\r\n", acl_last_serror());
return -1;
}
+ if (ret > 0) {
+ buf[ret] = 0;
+ if (strcasecmp(buf, "stop") == 0) {
+ __stop = 1;
+ }
+ break;
+ }
+ }
+
+ while (1) {
+ ret = acl_vstream_gets_nonl(conn, buf, sizeof(buf) - 1);
+ if (ret == ACL_VSTREAM_EOF) {
+ printf("gets error: %s\r\n", acl_last_serror());
+ return -1;
+ }
+
+ if (ret == 0) {
+ break;
+ }
buf[ret] = 0;
if (strcasecmp(buf, "stop") == 0) {
@@ -36,12 +56,9 @@ static int http_demo(ACL_VSTREAM *cstream, const char* res, size_t len)
printf("----stop now----\r\n");
break;
}
-
- if (ret == 0)
- break;
}
- if (acl_vstream_writen(cstream, res, len) == ACL_VSTREAM_EOF) {
+ if (acl_vstream_writen(conn, res, len) == ACL_VSTREAM_EOF) {
printf("write error\r\n");
return -1;
}
@@ -51,8 +68,8 @@ static int http_demo(ACL_VSTREAM *cstream, const char* res, size_t len)
static void echo_client(ACL_FIBER *fiber acl_unused, void *ctx)
{
- ACL_VSTREAM *cstream = (ACL_VSTREAM *) ctx;
- ACL_EVENT *event = (ACL_EVENT *) cstream->context;
+ ACL_VSTREAM *conn = (ACL_VSTREAM *) ctx;
+ ACL_EVENT *event = (ACL_EVENT *) conn->context;
const char* res = "HTTP/1.1 200 OK\r\n"
"Date: Tue, 31 May 2016 14:20:28 GMT\r\n"
"Server: acl\r\n"
@@ -63,23 +80,23 @@ static void echo_client(ACL_FIBER *fiber acl_unused, void *ctx)
"hello world!";
size_t len = strlen(res);
- if (http_demo(cstream, res, len) < 0 || __stop) {
- acl_vstream_close(cstream);
+ if (http_demo(conn, res, len) < 0 || __stop) {
+ acl_vstream_close(conn);
return;
}
//printf("%s: %d: call acl_event_enable_read again, fd: %d\r\n",
- // __FUNCTION__, __LINE__, ACL_VSTREAM_SOCK(cstream));
- acl_event_enable_read(event, cstream, 120, client_callback, NULL);
+ // __FUNCTION__, __LINE__, ACL_VSTREAM_SOCK(conn));
+ acl_event_enable_read(event, conn, 120, client_callback, NULL);
}
static void http_server(ACL_FIBER *, void *ctx)
{
- ACL_VSTREAM *cstream = (ACL_VSTREAM *) ctx;
- ACL_EVENT *event = (ACL_EVENT *) cstream->context;
+ ACL_VSTREAM *client = (ACL_VSTREAM *) ctx;
+ ACL_EVENT *event = (ACL_EVENT *) client->context;
acl::socket_stream conn;
- conn.open(cstream);
+ conn.open(client);
acl::memcache_session session("127.0.0.1:11211");
http_servlet servlet(&conn, &session);
servlet.setLocalCharset("gb2312");
@@ -89,35 +106,56 @@ static void http_server(ACL_FIBER *, void *ctx)
}
conn.unbind();
- acl_event_enable_read(event, cstream, 120, client_callback, NULL);
+ acl_event_enable_read(event, client, 120, client_callback, NULL);
}
static void client_callback(int type acl_unused, ACL_EVENT *event,
- ACL_VSTREAM *cstream, void *ctx acl_unused)
+ ACL_VSTREAM *conn, void *ctx acl_unused)
{
- cstream->context = event;
- acl_event_disable_readwrite(event, cstream);
+ conn->context = event;
+ acl_event_disable_readwrite(event, conn);
- if (__real_http)
- acl_fiber_create(http_server, cstream, 320000);
- else
- acl_fiber_create(echo_client, cstream, 160000);
+ if (__real_http) {
+ acl_fiber_create(http_server, conn, 128000);
+ } else {
+ acl_fiber_create(echo_client, conn, 64000);
+ }
+}
+
+static void fiber_accept(ACL_FIBER *fiber acl_unused, void *ctx)
+{
+ ACL_VSTREAM *sstream = (ACL_VSTREAM *) ctx;
+ ACL_EVENT *event = (ACL_EVENT *) sstream->context;
+
+ while (true) {
+ char ip[64];
+ ACL_VSTREAM *conn = acl_vstream_accept(sstream, ip, sizeof(ip));
+ if (conn == NULL) {
+ printf("accept error %s\r\n", acl::last_serror());
+ break;
+ }
+
+ printf(">>>%s: accept one, fd: %d\r\n",
+ __FUNCTION__, ACL_VSTREAM_SOCK(conn));
+ acl_event_enable_read(event, conn, 120, client_callback, NULL);
+ }
+
+ acl_fiber_schedule_stop();
}
static void listen_callback(int type acl_unused, ACL_EVENT *event,
ACL_VSTREAM *sstream, void *ctx acl_unused)
{
char ip[64];
- ACL_VSTREAM *cstream = acl_vstream_accept(sstream, ip, sizeof(ip));
+ ACL_VSTREAM *conn = acl_vstream_accept(sstream, ip, sizeof(ip));
- if (cstream == NULL) {
+ if (conn== NULL) {
printf("accept error %s\r\n", acl_last_serror());
return;
}
- printf(">>>accept one, fd: %d\r\n", ACL_VSTREAM_SOCK(cstream));
-
- acl_event_enable_read(event, cstream, 120, client_callback, NULL);
+ printf(">>>accept one, fd: %d\r\n", ACL_VSTREAM_SOCK(conn));
+ acl_event_enable_read(event, conn, 120, client_callback, NULL);
}
static void fiber_event(ACL_FIBER *fiber acl_unused, void *ctx)
@@ -125,13 +163,18 @@ static void fiber_event(ACL_FIBER *fiber acl_unused, void *ctx)
ACL_VSTREAM *sstream = (ACL_VSTREAM *) ctx;
ACL_EVENT *event;
- if (__use_kernel)
+ if (__use_kernel) {
event = acl_event_new(ACL_EVENT_KERNEL, 0, 1, 0);
- else
+ } else {
event = acl_event_new(ACL_EVENT_POLL, 0, 1, 0);
+ }
- printf(">>>enable read fd: %d\r\n", ACL_VSTREAM_SOCK(sstream));
- acl_event_enable_listen(event, sstream, 0, listen_callback, NULL);
+ if (__accept_alone) {
+ sstream->context = event;
+ acl_fiber_create(fiber_accept, sstream, STACK_SIZE);
+ } else {
+ acl_event_enable_listen(event, sstream, 0, listen_callback, NULL);
+ }
while (!__stop) {
acl_event_loop(event);
@@ -146,8 +189,10 @@ static void fiber_event(ACL_FIBER *fiber acl_unused, void *ctx)
static void usage(const char *procname)
{
printf("usage: %s -h [help] -s listen_addr\r\n"
+ " -e fiber_event_type[kernel|poll|select]\r\n"
" -r rw_timeout\r\n"
" -R [use real http]\r\n"
+ " -A [use fiber to accept]\r\n"
" -k [use kernel event]\r\n", procname);
}
@@ -155,12 +200,14 @@ int main(int argc, char *argv[])
{
char addr[64];
ACL_VSTREAM *sstream;
- int ch;
+ int ch, fiber_event_type = FIBER_EVENT_KERNEL;
acl::log::stdout_open(true);
+ acl_fiber_msg_stdout_enable(1);
+
snprintf(addr, sizeof(addr), "%s", "127.0.0.1:9001");
- while ((ch = getopt(argc, argv, "hs:r:Rk")) > 0) {
+ while ((ch = getopt(argc, argv, "hs:r:RAke:")) > 0) {
switch (ch) {
case 'h':
usage(argv[0]);
@@ -174,14 +221,29 @@ int main(int argc, char *argv[])
case 'R':
__real_http = 1;
break;
+ case 'A':
+ __accept_alone = 1;
+ break;
case 'k':
__use_kernel = 1;
break;
+ case 'e':
+ if (strcasecmp(optarg, "kernel") == 0) {
+ fiber_event_type = FIBER_EVENT_KERNEL;
+ } else if (strcasecmp(optarg, "poll") == 0) {
+ fiber_event_type = FIBER_EVENT_POLL;
+ } else if (strcasecmp(optarg, "select") == 0) {
+ fiber_event_type = FIBER_EVENT_SELECT;
+ }
default:
break;
}
}
+ if (fiber_event_type != FIBER_EVENT_KERNEL) {
+ __use_kernel = 0;
+ }
+
sstream = acl_vstream_listen(addr, 128);
if (sstream == NULL) {
printf("acl_vstream_listen error %s\r\n", acl_last_serror());
@@ -194,7 +256,7 @@ int main(int argc, char *argv[])
acl_fiber_create(fiber_event, sstream, STACK_SIZE);
printf("call fiber_schedule\r\n");
- acl_fiber_schedule();
+ acl_fiber_schedule_with(fiber_event_type);
return 0;
}
diff --git a/lib_fiber/samples/redis_pipeline/redis_pipeline.cpp b/lib_fiber/samples/redis_pipeline/redis_pipeline.cpp
index 7329bce75..ca09e55f0 100644
--- a/lib_fiber/samples/redis_pipeline/redis_pipeline.cpp
+++ b/lib_fiber/samples/redis_pipeline/redis_pipeline.cpp
@@ -147,10 +147,7 @@ protected:
void run(void)
{
bool ret;
- acl::redis_key cmd_key;
cmd_key.set_pipeline(&conns_);
-
- acl::redis_string cmd_string;
cmd_string.set_pipeline(&conns_);
for (int i = 0; i < n_; i++) {
@@ -208,6 +205,9 @@ private:
acl::redis_client_pipeline& conns_;
acl::string cmd_;
int n_;
+
+ acl::redis_key cmd_key;
+ acl::redis_string cmd_string;
};
class test_thread : public acl::thread
@@ -370,6 +370,8 @@ int main(int argc, char* argv[])
// stop pipeline thread
pipeline.stop_thread();
+ printf("The pipeline thread has stopped!\r\n");
+
#ifdef WIN32
printf("enter any key to exit\r\n");
getchar();
diff --git a/lib_fiber/samples/server/main.c b/lib_fiber/samples/server/main.c
index a1deee685..5b3cee4f0 100644
--- a/lib_fiber/samples/server/main.c
+++ b/lib_fiber/samples/server/main.c
@@ -69,12 +69,26 @@ static void fiber_accept(ACL_FIBER *fiber acl_unused, void *ctx)
for (;;) {
ACL_VSTREAM *cstream = acl_vstream_accept(sstream, NULL, 0);
+ char buf[1024];
+ int ret;
+
if (cstream == NULL) {
printf("acl_vstream_accept error %s\r\n",
acl_last_serror());
break;
}
+ ret = acl_vstream_gets(cstream, buf, sizeof(buf) - 1);
+ if (ret == ACL_VSTREAM_EOF) {
+ printf("get first line error\r\n");
+ acl_vstream_close(cstream);
+ continue;
+ } else if (acl_vstream_writen(cstream, buf, ret) != ret) {
+ printf("write error\r\n");
+ acl_vstream_close(cstream);
+ continue;
+ }
+
//printf("accept one, fd: %d\r\n", ACL_VSTREAM_SOCK(cstream));
acl_fiber_create(echo_client, cstream, __stack_size);
//printf("continue to accept\r\n");
diff --git a/lib_fiber/samples/server2/main.c b/lib_fiber/samples/server2/main.c
index 4eb913979..0228b8402 100644
--- a/lib_fiber/samples/server2/main.c
+++ b/lib_fiber/samples/server2/main.c
@@ -34,7 +34,6 @@ static int __listen_port = 9001;
static int __listen_qlen = 64;
static int __rw_timeout = 0;
static int __echo_data = 1;
-static int __stack_size = 320000;
static int check_read(int fd, int timeout)
{
@@ -51,12 +50,15 @@ static int check_read(int fd, int timeout)
return -1;
}
- if (n == 0)
+ if (n == 0) {
return 0;
- if (pfd.revents & POLLIN)
+ }
+ if (pfd.revents & POLLIN) {
return 1;
- else
+ } else {
+ printf(">>>poll return n=%d read no ready,fd=%d, pfd=%p\n", n, fd, &pfd);
return 0;
+ }
}
static void echo_client(ACL_FIBER *fiber acl_unused, void *ctx)
@@ -129,12 +131,15 @@ static void echo_client(ACL_FIBER *fiber acl_unused, void *ctx)
}
}
-static void fiber_accept(ACL_FIBER *fiber acl_unused, void *ctx acl_unused)
+static void fiber_accept(ACL_FIBER *fiber acl_unused, void *ctx)
{
+ ACL_FIBER_ATTR *attr = (ACL_FIBER_ATTR*) ctx;
SOCKET lfd;
int on = 1;
struct sockaddr_in sa;
+ assert(attr);
+
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(__listen_port);
@@ -181,7 +186,7 @@ static void fiber_accept(ACL_FIBER *fiber acl_unused, void *ctx acl_unused)
__nconnect++;
printf("accept one, fd: %u, %p\r\n", cfd, pfd);
- acl_fiber_create(echo_client, pfd, __stack_size);
+ acl_fiber_create2(attr, echo_client, pfd);
}
CLOSE(lfd);
@@ -214,16 +219,20 @@ static void usage(const char *procname)
" -r rw_timeout\r\n"
" -q listen_queue\r\n"
" -z stack_size\r\n"
+ " -Z [if use shared stack]\r\n"
" -S [if using single IO, default: no]\r\n", procname);
}
int main(int argc, char *argv[])
{
int ch, event_mode = FIBER_EVENT_KERNEL;
+ ACL_FIBER_ATTR fiber_attr;
+ int stack_size = 320000;
+ acl_fiber_attr_init(&fiber_attr);
snprintf(__listen_ip, sizeof(__listen_ip), "%s", "127.0.0.1");
- while ((ch = getopt(argc, argv, "hs:p:r:q:Sz:e:")) > 0) {
+ while ((ch = getopt(argc, argv, "hs:p:r:q:Sz:Ze:")) > 0) {
switch (ch) {
case 'h':
usage(argv[0]);
@@ -244,7 +253,11 @@ int main(int argc, char *argv[])
__echo_data = 0;
break;
case 'z':
- __stack_size = atoi(optarg);
+ stack_size = atoi(optarg);
+ acl_fiber_attr_setstacksize(&fiber_attr, stack_size);
+ break;
+ case 'Z':
+ acl_fiber_attr_setsharestack(&fiber_attr, 1);
break;
case 'e':
if (strcasecmp(optarg, "select") == 0)
@@ -270,7 +283,7 @@ int main(int argc, char *argv[])
#endif
printf("%s: call fiber_creater\r\n", __FUNCTION__);
- acl_fiber_create(fiber_accept, NULL, 327680);
+ acl_fiber_create(fiber_accept, &fiber_attr, 327680);
#ifndef SCHEDULE_AUTO
acl_fiber_create(fiber_memcheck, NULL, 640000);
diff --git a/lib_fiber/samples/server2/valgrind.sh b/lib_fiber/samples/server2/valgrind.sh
index 2f5c1aab9..c714448d3 100755
--- a/lib_fiber/samples/server2/valgrind.sh
+++ b/lib_fiber/samples/server2/valgrind.sh
@@ -2,4 +2,4 @@
#valgrind --tool=memcheck --leak-check=yes --leak-check=full --show-reachable=yes --max-stackframe=3426305034400000 -v ./fiber -n 10 -m 20
#valgrind --tool=memcheck --leak-check=yes --leak-check=full --show-reachable=yes -v ./server -e poll
-valgrind --tool=memcheck --leak-check=yes --leak-check=full --show-reachable=yes -v ./server
+valgrind --tool=memcheck --leak-check=yes --leak-check=full --show-reachable=yes -v ./server -r 10
diff --git a/lib_fiber/samples/server4/main.cpp b/lib_fiber/samples/server4/main.cpp
index 10cc28671..686cebb83 100644
--- a/lib_fiber/samples/server4/main.cpp
+++ b/lib_fiber/samples/server4/main.cpp
@@ -1,31 +1,76 @@
#include "stdafx.h"
#include
#include
+#include
+
+static bool stop = false;
+
+static void echo_client(acl::socket_stream* conn, acl::fiber_tbox *box)
+{
+ printf("fiber-%d running, sock fd=%d\r\n",
+ acl::fiber::self(), conn->sock_handle());
+
+ char buf[8192];
+ while (true) {
+ int ret = conn->read(buf, sizeof(buf), false);
+ if (ret == -1) {
+ break;
+ }
+ buf[ret] = 0;
+
+ if (strncasecmp(buf, "stop", 4) == 0) {
+ stop = true;
+ break;
+ }
+ if (conn->write(buf, ret) == -1) {
+ break;
+ }
+ if (strncasecmp(buf, "bye", 3) == 0) {
+ break;
+ }
+ }
+
+ box->push(NULL);
+}
static void fiber_client(acl::socket_stream* conn)
{
- printf("fiber-%d running\r\n", acl::fiber::self());
+ acl::fiber_tbox* box = new acl::fiber_tbox;
char buf[8192];
- while (true)
- {
- int ret = conn->read(buf, sizeof(buf), false);
- if (ret == -1)
- break;
- if (conn->write(buf, ret) == -1)
- break;
+ int ret = conn->read(buf, sizeof(buf), false);
+ if (ret == -1) {
+ printf("read from fd=%d error\r\n", conn->sock_handle());
+ delete conn;
+ return;
+ }
+ if (conn->write(buf, ret) == -1) {
+ printf("write to fd=%d error\r\n", conn->sock_handle());
+ delete conn;
+ return;
}
+ go[&] {
+ echo_client(conn, box);
+ };
+
+ box->pop();
+ delete box;
+
+ printf("%s: delete fd=%d\r\n", __FUNCTION__, conn->sock_handle());
delete conn;
+
+ if (stop) {
+ printf("Stop fiber schedule now\r\n");
+ acl::fiber::schedule_stop();
+ }
}
static void fiber_server(acl::server_socket& ss)
{
- while (true)
- {
+ while (true) {
acl::socket_stream* conn = ss.accept();
- if (conn == NULL)
- {
+ if (conn == NULL) {
printf("accept error %s\r\n", acl::last_serror());
break;
}
@@ -51,10 +96,8 @@ int main(int argc, char *argv[])
acl::string addr("127.0.0.1:9006");
acl::log::stdout_open(true);
- while ((ch = getopt(argc, argv, "hs:")) > 0)
- {
- switch (ch)
- {
+ while ((ch = getopt(argc, argv, "hs:")) > 0) {
+ switch (ch) {
case 'h':
usage(argv[0]);
return 0;
@@ -67,8 +110,7 @@ int main(int argc, char *argv[])
}
acl::server_socket ss;
- if (ss.open(addr) == false)
- {
+ if (ss.open(addr) == false) {
printf("listen %s error %s\r\n", addr.c_str(), acl::last_serror());
return 1;
}
diff --git a/lib_fiber/samples/server5/main.cpp b/lib_fiber/samples/server5/main.cpp
index df7ca278b..e0a7446d4 100644
--- a/lib_fiber/samples/server5/main.cpp
+++ b/lib_fiber/samples/server5/main.cpp
@@ -1,6 +1,9 @@
#include "stdafx.h"
#include
#include
+#include
+
+static int __event_type = ACL_EVENT_KERNEL;
static bool echo(acl::socket_stream& conn)
{
@@ -71,7 +74,7 @@ static void fiber_client(acl::socket_stream* conn)
printf("fiber-%d running\r\n", acl::fiber::self());
bool stop = false;
- ACL_EVENT *event = acl_event_new(ACL_EVENT_POLL, 0, 1, 0);
+ ACL_EVENT *event = acl_event_new(__event_type, 0, 1, 0);
ACL_VSTREAM *cstream = conn->get_vstream();
cstream->context = conn;
conn->set_ctx(&stop);
@@ -105,7 +108,7 @@ static void fiber_server(acl::server_socket& ss)
static void usage(const char* procname)
{
- printf("usage: %s -h [help] -s listen_addr\r\n", procname);
+ printf("usage: %s -h [help] -s listen_addr -e event_type[kernel|poll|select]\r\n", procname);
}
int main(int argc, char *argv[])
@@ -116,7 +119,7 @@ int main(int argc, char *argv[])
acl::string addr("127.0.0.1:9006");
acl::log::stdout_open(true);
- while ((ch = getopt(argc, argv, "hs:")) > 0) {
+ while ((ch = getopt(argc, argv, "hs:e:")) > 0) {
switch (ch) {
case 'h':
usage(argv[0]);
@@ -124,6 +127,14 @@ int main(int argc, char *argv[])
case 's':
addr = optarg;
break;
+ case 'e':
+ if (strcasecmp(optarg, "poll") == 0) {
+ __event_type = ACL_EVENT_POLL;
+ } else if (strcasecmp(optarg, "select") == 0) {
+ __event_type = ACL_EVENT_SELECT;
+ } else {
+ __event_type = ACL_EVENT_KERNEL;
+ }
default:
break;
}
diff --git a/lib_fiber/samples/server5/stdafx.h b/lib_fiber/samples/server5/stdafx.h
index cee9a8583..7dfe7cf1b 100644
--- a/lib_fiber/samples/server5/stdafx.h
+++ b/lib_fiber/samples/server5/stdafx.h
@@ -13,6 +13,7 @@
#include "lib_acl.h"
#include "acl_cpp/lib_acl.hpp"
#include "fiber/lib_fiber.hpp"
+#include "fiber/go_fiber.hpp"
#ifdef WIN32
#define snprintf _snprintf
diff --git a/lib_fiber/samples/server6/Makefile b/lib_fiber/samples/server6/Makefile
new file mode 100644
index 000000000..5ab377af6
--- /dev/null
+++ b/lib_fiber/samples/server6/Makefile
@@ -0,0 +1,2 @@
+include ../Makefile_cpp.in
+PROG = server
diff --git a/lib_fiber/samples/server6/main.cpp b/lib_fiber/samples/server6/main.cpp
new file mode 100644
index 000000000..c4ef00cb8
--- /dev/null
+++ b/lib_fiber/samples/server6/main.cpp
@@ -0,0 +1,149 @@
+#include "stdafx.h"
+#include
+#include
+
+static bool tried = false, is_sleeping = false;
+static acl::socket_stream* first = NULL, *second = NULL;
+
+static void fiber_client(acl::socket_stream* conn)
+{
+ conn->set_rw_timeout(20);
+ int fd = conn->sock_handle();
+
+ printf("fiber-%d running, fiber=%p\r\n", acl::fiber::self(), acl_fiber_running());
+
+ char buf[8192];
+ while (true) {
+ printf(">>>%s: fiber=%p, begin read, fd=%d, %d\n",
+ __FUNCTION__, acl_fiber_running(),
+ conn->sock_handle(), fd);
+
+ int ret = conn->read(buf, sizeof(buf), false);
+
+ printf(">>>%s: fiber=%p, read=%d, fd=%d, %d\n",
+ __FUNCTION__, acl_fiber_running(), ret,
+ conn->sock_handle(), fd);
+
+ if (ret == -1) {
+ printf("fiber-%d, read error %s from fd %d, %d, fiber=%p\r\n",
+ acl::fiber::self(), acl::last_serror(),
+ conn->sock_handle(), fd, acl_fiber_running());
+ break;
+ }
+
+ if (conn->write(buf, ret) == -1) {
+ printf("fiber-%d, write error %s to fd %d\r\n",
+ acl::fiber::self(), acl::last_serror(),
+ conn->sock_handle());
+ break;
+ }
+
+ if (conn == first) {
+ if (second) {
+ printf("---close another fd=%d, me fiber=%p\n",
+ second->sock_handle(), acl_fiber_running());
+ int sock = second->sock_handle();
+ if (is_sleeping) {
+ second->unbind_sock();
+ }
+ close(sock);
+ //second->close();
+ printf("---close another fd=%d ok, fiber=%p\n",
+ sock, acl_fiber_running());
+ second = NULL;
+ } else {
+ printf("---another fd closed\r\n");
+ }
+ }
+
+ //continue;
+
+ if (conn == second) {
+ time_t begin = time(NULL);
+ printf("second fiber-%d, %p, fd=%d sleep\n",
+ acl::fiber::self(), acl_fiber_running(),
+ conn->sock_handle());
+ is_sleeping = true;
+ sleep(15);
+ is_sleeping = false;
+ printf("second fiber-%d, %p, fd=%d wakeup, diff=%ld second\n",
+ acl::fiber::self(), acl_fiber_running(),
+ conn->sock_handle(), time(NULL) - begin);
+ }
+ }
+
+ printf("\r\n>>fiber=%p, delete conn, fd=%d\n",
+ acl_fiber_running(), conn->sock_handle());
+ delete conn;
+ printf(">>fiber=%p, delete conn ok: %s\n\n",
+ acl_fiber_running(), acl::last_serror());
+}
+
+static void fiber_server(acl::server_socket& ss)
+{
+ while (true) {
+ acl::socket_stream* conn = ss.accept();
+ if (conn == NULL) {
+ printf("accept error %s\r\n", acl::last_serror());
+ break;
+ }
+
+ printf("accept ok, fd: %d\r\n", conn->sock_handle());
+
+ if (first == NULL) {
+ first = conn;
+ } else if (second == NULL) {
+ if (!tried) {
+ second = conn;
+ tried = true;
+ }
+ }
+
+ go[=] {
+ fiber_client(conn);
+ };
+ }
+}
+
+static void usage(const char* procname)
+{
+ printf("usage: %s -h [help] -s listen_addr\r\n", procname);
+}
+
+int main(int argc, char *argv[])
+{
+ int ch;
+
+ acl::acl_cpp_init();
+ acl::string addr("127.0.0.1:9006");
+ acl::log::stdout_open(true);
+ acl::fiber::stdout_open(true);
+
+ while ((ch = getopt(argc, argv, "hs:")) > 0) {
+ switch (ch) {
+ case 'h':
+ usage(argv[0]);
+ return 0;
+ case 's':
+ addr = optarg;
+ break;
+ default:
+ break;
+ }
+ }
+
+ acl::server_socket ss;
+ if (!ss.open(addr)) {
+ printf("listen %s error %s\r\n", addr.c_str(), acl::last_serror());
+ return 1;
+ }
+ printf("listen %s ok\r\n", addr.c_str());
+
+ go[&] {
+ fiber_server(ss);
+ };
+
+ acl::fiber::schedule(); // start fiber schedule
+
+ return 0;
+}
diff --git a/lib_fiber/samples/server6/stdafx.cpp b/lib_fiber/samples/server6/stdafx.cpp
new file mode 100644
index 000000000..a27b824da
--- /dev/null
+++ b/lib_fiber/samples/server6/stdafx.cpp
@@ -0,0 +1 @@
+#include "stdafx.h"
diff --git a/lib_fiber/samples/server6/stdafx.h b/lib_fiber/samples/server6/stdafx.h
new file mode 100644
index 000000000..ea39dfb29
--- /dev/null
+++ b/lib_fiber/samples/server6/stdafx.h
@@ -0,0 +1,22 @@
+// stdafx.h : ϵͳļİļ
+// dzõĵĿضİļ
+//
+
+#pragma once
+
+
+//#include
+//#include
+
+// TODO: ڴ˴óҪĸͷļ
+
+#include "lib_acl.h"
+#include "acl_cpp/lib_acl.hpp"
+#include "fiber/fiber.hpp"
+#include "fiber/libfiber.h"
+#include "fiber/go_fiber.hpp"
+
+#ifdef WIN32
+#define snprintf _snprintf
+#endif
+
diff --git a/lib_fiber/samples/server6/t.sh b/lib_fiber/samples/server6/t.sh
new file mode 100755
index 000000000..6e4652794
--- /dev/null
+++ b/lib_fiber/samples/server6/t.sh
@@ -0,0 +1 @@
+valgrind --tool=memcheck --leak-check=yes --leak-check=full --show-reachable=yes -v ./server