├── log └── logedhere.txt ├── records.z ├── benchmark.png ├── next ├── Makefile ├── storage.h └── storage.c ├── tool ├── README ├── Makefile └── client.c ├── Makefile ├── src ├── config.h ├── update.h ├── control.h ├── Makefile ├── datas.h ├── io.h ├── event.h ├── control.c ├── net.h ├── memory.h ├── memory.c ├── storage.h ├── author.h ├── utils.h ├── update.c ├── net.c ├── event.c ├── dns.h ├── datas.c ├── init.c ├── io.c ├── utils.c └── storage.c ├── .gitignore ├── sr.conf ├── INSTALL.md ├── README.md └── LICENSE /log/logedhere.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /records.z: -------------------------------------------------------------------------------- 1 | www.google.com. 172800 IN A 8.8.8.8 2 | 3 | -------------------------------------------------------------------------------- /benchmark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DNSPod/dnspod-sr/HEAD/benchmark.png -------------------------------------------------------------------------------- /next/Makefile: -------------------------------------------------------------------------------- 1 | storage:storage.c 2 | gcc -g -o storage storage.c 3 | clean: 4 | rm -f storage.o storage 5 | -------------------------------------------------------------------------------- /tool/README: -------------------------------------------------------------------------------- 1 | use this to hijack/(cache flush) 2 | 3 | ./client "hijack" 4 | ./client "hijack example.com" 5 | ./client "cache flush: example.com" 6 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 'steal' from redis Makefile 2 | 3 | default: all 4 | 5 | .DEFAULT: 6 | cd src && $(MAKE) $@ 7 | 8 | install: 9 | cd src && $(MAKE) $@ 10 | 11 | .PHONY: install 12 | -------------------------------------------------------------------------------- /src/config.h: -------------------------------------------------------------------------------- 1 | #ifndef __CONFIG_H__ 2 | #define __CONFIG_H__ 3 | 4 | #define SR_CONFIG_FILE "../sr.conf" 5 | #define SR_ROOT_FILE "../root.z" 6 | #define SR_RECORDS_FILE "../records.z" 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/update.h: -------------------------------------------------------------------------------- 1 | #ifndef __RECV_UPDATE_H__ 2 | #define __RECV_UPDATE_H__ 3 | #include "control.h" 4 | 5 | #define CACHE_FLUSH 1 6 | #define HIJACK 2 7 | int start_local_server(); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /tool/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -Wall 3 | 4 | all: CFLAGS += -g 5 | all: client 6 | 7 | client: client.o 8 | $(CC) $^ -o $@ $(CFLAGS) 9 | 10 | .PHONY: clean 11 | clean: 12 | rm -fr *.o client 13 | 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .* 2 | !.gitignore 3 | *~ 4 | 5 | .*.sw[a-z] 6 | *.un~ 7 | Session.vim 8 | 9 | # Object files 10 | *.o 11 | 12 | # Libraries 13 | *.lib 14 | 15 | # Shared objects 16 | *.so 17 | 18 | # Executables 19 | *.out 20 | 21 | # log 22 | *.log 23 | 24 | -------------------------------------------------------------------------------- /src/control.h: -------------------------------------------------------------------------------- 1 | #ifndef __CONTROL_H__ 2 | #define __CONTROL_H__ 3 | #include "utils.h" 4 | #include "storage.h" 5 | #include "datas.h" 6 | int cache_flush(uchar *domain, uint16_t type, struct htable* ht, struct rbtree *ttlexp); 7 | int hijack(uchar *domain, uint16_t type, struct htable *ht, struct rbtree *ttlexp); 8 | #endif 9 | -------------------------------------------------------------------------------- /sr.conf: -------------------------------------------------------------------------------- 1 | xfer: 2 | googleusercontent.com.:8.8.8.8 3 | google.com.:8.8.8.8 4 | itil.com.:10.6.18.41 5 | facebook.com.:8.8.8.8 6 | twitter.com.:8.8.8.8 7 | flickr.com.:8.8.8.8 8 | akamaiedge.net.:202.106.0.20 9 | edgekey.net.:202.106.0.20 10 | youtube.com.:8.8.8.8 11 | s-static.ak.facebook.com.edgekey.net.:8.8.8.8 12 | : 13 | log_path: 14 | ../log/ 15 | -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | # 如何安装 2 | 3 | ## 编译 4 | ./src目录下执行 make 即可编译出可执行文件 5 | 6 | make 7 | 8 | ## 配置文件 9 | 默认配置文件为当前目录下的 sr.conf,也可以在命令行参数中指定 10 | 11 | ./dnspod-sr /path/of/sr.conf 12 | 13 | 当前配置文件中支持为特定域名指定外部递归 DNS,以 xfer 开头,如下: 14 | 15 | xfer: 16 | googleusercontent.com.:8.8.8.8 17 | google.com.:8.8.8.8 18 | youtube.com.:8.8.8.8 19 | s-static.ak.facebook.com.edgekey.net.:8.8.8.8 20 | : 21 | 22 | 最后一行以`:`结束。 23 | 24 | 配置日志文件目录(可选) 25 | 26 | log_path: 27 | ./log/ 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DNSPod Security Recursive DNS Server 2 | 3 | 4 | ## 关于 5 | dnspod-sr 是一个运行在 Linux 平台上的高性能的递归 DNS 服务器软件,具备高性能、高负载、易扩展的优势,非 BIND 等软件可以比拟。 6 | 7 | ## 特性 8 | 1. 高性能,比所有流行的开源 DNS 软件性能高出2倍以上 9 | 2. 安全,能抵御一般攻击 10 | 3. 稳定,有效降低解析失败率 11 | 4. 主动刷新缓存,响应速度更快 12 | 5. 易于扩展,非常容易部署 13 | 6. 防污染,能够正确解析被污染域名 14 | 15 | 16 | ## 性能 17 | dnspod-sr 依托于 DNSPod 多年运营和优化 DNS 服务的经验,针对国内复杂的网络情况,对递归 DNS 进行了一系列的优化,比较其他开源软件,性能得到大幅提升。 18 | 19 | #### 测试环境 20 | 千兆网卡,4核 CPU,4G 内存,Linux 64位系统。 21 | 22 | #### 性能测试 23 | - dnspod-sr: 15万 qps 24 | - BIND 9.9: 7万 qps 25 | - unbound 4.7: 8万 qps 26 | 27 | ![Benchmark](https://github.com/DNSPod/dnspod-sr/raw/master/benchmark.png) 28 | 29 | ## 解决方案 30 | 1. 架设 dnspod-sr 集群,替换各大运营商目前基于 BIND 的陈旧方案,减少运营成本 31 | 2. 公司、学校、政府等组织内部 DNS,解析外部不可见的私有域名,提高上网速度 32 | 33 | ## 快速开始 34 | 下载源码: 35 | 36 | git clone https://github.com/DNSPod/dnspod-sr.git 37 | cd dnspod-sr 38 | 39 | 或者下载压缩包: 40 | 41 | https://github.com/DNSPod/dnspod-sr/zipball/master 42 | 43 | 编译源码: 44 | 45 | cd src 46 | make 47 | 48 | 运行 49 | 50 | ./dnspod-sr 51 | 52 | 53 | ## Roadmap 54 | - 支持集群式部署 55 | 56 | ## 文档 & 反馈 57 | - Wiki: 58 | - FAQ: 59 | - Issues: 60 | - [提交反馈](https://github.com/DNSPod/dnspod-sr/issues/new) 61 | 62 | ## 开源协议 63 | dnspod-sr 在 BSD License 下发布。 64 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | # @author dilfish (zhangpu@dnspod.com) 2 | # @version 0.1 3 | PREFIX?=/usr/local/services/dnspod-sr 4 | INSTALL_BIN=$(PREFIX)/bin 5 | INSTALL_ETC=$(PREFIX)/etc 6 | OBJS=utils.o datas.o net.o storage.o dns.o io.o event.o author.o init.o update.o control.o memory.o 7 | LD=-lm -lc 8 | CC = gcc 9 | SERVER_NAME=dnspod-sr 10 | 11 | 12 | # ifeq (${T},g) 13 | CFLAGS=-g -Wall# -O3 14 | # else 15 | # CFLAGS= 16 | # endif 17 | 18 | all:$(OBJS) 19 | gcc -o $(SERVER_NAME) $(LD) $(OBJS) -lpthread -g# -O3 20 | #ltcmalloc 21 | 22 | #base 3 23 | #misc,data,net 24 | utils.o:utils.h utils.c 25 | datas.o:utils.o datas.h datas.c 26 | net.o:utils.o net.h net.c 27 | storage.o:utils.o storage.h storage.c 28 | control.o:control.c 29 | memory.o:memory.c 30 | #dns protocal,read from/write to config/log file 31 | dns.o:datas.o net.o storage.o dns.h dns.c 32 | io.o:dns.o io.h io.c 33 | #event driven 34 | event.o:net.o event.h event.c 35 | author.o:io.o event.o author.c author.h 36 | update.o:control.o update.c 37 | #start 38 | init.o:author.o init.c 39 | 40 | 41 | .PHONY : install 42 | install: 43 | @mkdir -p $(INSTALL_BIN) 44 | cp -f $(SERVER_NAME) $(INSTALL_BIN) 45 | @mkdir -p $(INSTALL_ETC) 46 | cp -f ../sr.conf $(INSTALL_ETC) 47 | cp -f ../root.z $(INSTALL_ETC) 48 | cp -f ../records.z $(INSTALL_ETC) 49 | 50 | .PHONY : uninstall 51 | uninstall: 52 | rm -f $(INSTALL_BIN)/$(SERVER_NAME) 53 | rm -f $(INSTALL_ETC)/sr.conf 54 | rm -f $(INSTALL_ETC)/records.z 55 | rm -f $(INSTALL_ETC)/root.z 56 | 57 | .PHONY : clean 58 | clean: 59 | rm -f $(OBJS) dnspod-sr 60 | 61 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2006-2012, DNSPod Inc. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | The views and conclusions contained in the software and documentation are those 25 | of the authors and should not be interpreted as representing official policies, 26 | either expressed or implied, of the FreeBSD Project. 27 | -------------------------------------------------------------------------------- /src/datas.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2006-2012, DNSPod Inc. 2 | * All rights reserved. 3 | 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright notice, 10 | * this list of conditions and the following disclaimer in the documentation 11 | * and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | * The views and conclusions contained in the software and documentation are those 25 | * of the authors and should not be interpreted as representing official policies, 26 | * either expressed or implied, of the FreeBSD Project. 27 | */ 28 | 29 | 30 | //infrastructure memory manager 31 | //0.red black tree 32 | 33 | #ifndef _DATAS_H 34 | #define _DATAS_H 35 | 36 | #include "utils.h" 37 | #include "dns.h" 38 | 39 | // struct rbnode; 40 | // struct entry; 41 | // typedef int (comprbt) (void *, void *, void *); 42 | // 43 | // #define RED (1) 44 | // #define BLACK (0) 45 | // 46 | // struct rbnode { 47 | // struct rbnode *parent; 48 | // struct rbnode *left; 49 | // struct rbnode *right; 50 | // int color; 51 | // void *key; 52 | // }; 53 | // 54 | // struct rbtree { 55 | // struct rbnode *root, nil; 56 | // pthread_mutex_t lock; 57 | // uint size; 58 | // comprbt *c; 59 | // void *argv; 60 | // }; 61 | 62 | 63 | struct rbtree *create_rbtree(comprbt * c, void *argv); 64 | void *delete_node(struct rbtree *rbt, struct rbnode *nd); 65 | int insert_node(struct rbtree *rbt, struct rbnode *nd); 66 | struct rbnode *find_node(struct rbtree *rbt, void *key); 67 | struct rbnode *min_node(struct rbtree *rbt); 68 | uint get_rbt_size(struct rbtree *rbt); 69 | 70 | //test only. 71 | int rbtree_test(void); 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /src/io.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2006-2012, DNSPod Inc. 2 | * All rights reserved. 3 | 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright notice, 10 | * this list of conditions and the following disclaimer in the documentation 11 | * and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | * The views and conclusions contained in the software and documentation are those 25 | * of the authors and should not be interpreted as representing official policies, 26 | * either expressed or implied, of the FreeBSD Project. 27 | */ 28 | 29 | 30 | 31 | //write log 32 | //write data file 33 | //read data file 34 | 35 | #ifndef _IO_H 36 | #define _IO_H 37 | 38 | #include "dns.h" 39 | #include //read and write files 40 | #include 41 | 42 | 43 | int read_config(const char *, char *, struct htable *, char **); 44 | 45 | 46 | #define LOG_INTERVAL (900) 47 | 48 | #define TYPE_FETCHER (112) 49 | #define TYPE_QUIZZER (233) 50 | 51 | 52 | enum { 53 | NEVER_EXPIRED1 = 172800, 54 | NEVER_EXPIRED2 = 518400, 55 | }; 56 | 57 | #define LOG_CACHE_SIZE (1024 * 1024) 58 | 59 | struct log_info { 60 | int logfd; 61 | time_t lastlog; 62 | int log_type; 63 | uchar log_cache[LOG_CACHE_SIZE]; 64 | int log_cache_cursor; 65 | }; 66 | //idx and lastlog and logfd 67 | //first argu 68 | int create_new_log(uchar * prefix, int idx, int type); 69 | int write_log(struct log_info *, int, const uchar *, int, int, 70 | struct sockaddr_in *); 71 | int read_root(struct htable *, struct rbtree *); 72 | int refresh_records(struct htable *, struct rbtree *); 73 | 74 | uchar * jump_space(uchar * itor); 75 | #endif 76 | -------------------------------------------------------------------------------- /tool/client.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define CLI_PATH "/tmp/" 11 | const char *local_socket_name = "/tmp/foo.socket"; 12 | 13 | int create_local_client(const char *name) 14 | { 15 | int sock, len, ret; 16 | struct sockaddr_un addr; 17 | sock = socket(AF_UNIX, SOCK_STREAM, 0); 18 | if (sock < 0) { 19 | perror("socket error"); 20 | return -1; 21 | } 22 | memset(&addr, 0, sizeof(addr)); 23 | addr.sun_family = AF_UNIX; 24 | sprintf(addr.sun_path, "%s%05d", CLI_PATH, getpid()); 25 | len = offsetof(struct sockaddr_un, sun_path) + strlen(addr.sun_path); 26 | 27 | unlink(addr.sun_path); 28 | 29 | ret = bind(sock, (struct sockaddr *)&addr, len); 30 | if (ret < 0) { 31 | perror("bind error"); 32 | close(sock); 33 | return -2; 34 | } 35 | memset(&addr, 0, sizeof(addr)); 36 | addr.sun_family = AF_UNIX; 37 | strcpy(addr.sun_path, name); 38 | len = offsetof(struct sockaddr_un, sun_path) + strlen(name); 39 | ret = connect(sock, (struct sockaddr *)&addr, len); 40 | if (ret < 0) { 41 | perror("connect error"); 42 | close(sock); 43 | return -3; 44 | } 45 | return sock; 46 | } 47 | 48 | void set_signal_catcher() 49 | { 50 | struct sigaction action; 51 | memset(&action, 0, sizeof(struct sigaction)); 52 | action.sa_handler = SIG_IGN; 53 | sigemptyset(&action.sa_mask); 54 | action.sa_flags = 0; 55 | 56 | sigaction(SIGPIPE, &action, NULL); 57 | } 58 | 59 | int main(int argc, char const* argv[]) 60 | { 61 | int sock, ret; 62 | char send_buf[BUFSIZ] = {0}; 63 | char recv_buf[BUFSIZ]; 64 | /* char *line = NULL; */ 65 | sock = create_local_client(local_socket_name); 66 | if (sock < 0) { 67 | fprintf(stderr, "connect to server failed\n"); 68 | return -1; 69 | } 70 | set_signal_catcher(); 71 | 72 | while (1) { 73 | /* memset(send_buf, 0, BUFSIZ); */ 74 | /* line = fgets(send_buf, BUFSIZ - 1, stdin); */ 75 | /* if (!line) { */ 76 | /* break; */ 77 | /* } */ 78 | /* if (strcmp(send_buf, "quit") == 0) { */ 79 | /* break; */ 80 | /* } */ 81 | strcpy(send_buf, argv[1]); 82 | ret = send(sock, send_buf, strlen(send_buf), 0); 83 | if (ret > 0) { 84 | memset(recv_buf, 0, BUFSIZ); 85 | recv(sock, recv_buf, BUFSIZ - 1, 0); 86 | if (recv_buf[0] != '\0') { 87 | printf("%s\n", recv_buf); 88 | } 89 | break; 90 | } else { 91 | printf("disconnect with server\n"); 92 | break; 93 | } 94 | } 95 | close(sock); 96 | return 0; 97 | } 98 | 99 | -------------------------------------------------------------------------------- /src/event.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2006-2012, DNSPod Inc. 2 | * All rights reserved. 3 | 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright notice, 10 | * this list of conditions and the following disclaimer in the documentation 11 | * and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | * The views and conclusions contained in the software and documentation are those 25 | * of the authors and should not be interpreted as representing official policies, 26 | * either expressed or implied, of the FreeBSD Project. 27 | */ 28 | 29 | 30 | #ifndef _EVENT_H 31 | #define _EVENT_H 32 | 33 | #include "author.h" 34 | #include "memory.h" 35 | 36 | #ifndef CPU_SET_S 37 | #define CPU_SET_S(cpu, setsize, cpusetp) CPU_SET(cpu, cpusetp) 38 | #endif 39 | 40 | #define SENTINEL_EVENT (1000) 41 | 42 | struct event_data; 43 | struct worker; 44 | struct baseinfo; 45 | struct sockinfo; 46 | typedef int (*noti_chain_callback) (struct event_data *, void *, int); 47 | 48 | 49 | struct event_data { 50 | int fd; 51 | noti_chain_callback cb; 52 | void *ext; 53 | }; 54 | 55 | 56 | struct iner_event; 57 | struct event { 58 | int size; 59 | int onexit; 60 | struct iner_event *ie; 61 | struct event_data data[0]; 62 | }; 63 | 64 | 65 | enum event_type { 66 | ET_READ = 1, 67 | ET_WRITE = 2, 68 | ET_ALL = 3, 69 | }; 70 | 71 | 72 | struct event_help { 73 | int fd; 74 | int spfd; 75 | int num; 76 | enum event_type type; 77 | struct timeval *to; 78 | noti_chain_callback cb; 79 | void *ext; 80 | }; 81 | 82 | 83 | int run_sentinel(struct server *s); 84 | int run_fetcher(struct fetcher *w); 85 | 86 | 87 | struct event *create_event(int); 88 | int add_event(struct event *, struct event_help *); 89 | int del_event(struct event *, struct event_help *); 90 | int deinit_event(struct event *, struct event_help *); 91 | int wait_event(struct event *, struct event_help *); 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /next/storage.h: -------------------------------------------------------------------------------- 1 | //dilfish @ dnspod 2 | //double data structure 3 | //hash for records 4 | //rbtree for ttl 5 | 6 | #ifndef _STORAGE_H 7 | #define _STORAGE_H 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | 18 | #define DEBUG_TIMES (100) 19 | #define HASH_TABLE_SIZE (65536) 20 | #define MULTI_HASH (8) 21 | #define MAX_RECORD_SIZE (3000) 22 | 23 | #define RED (1) 24 | #define BLACK (0) 25 | 26 | 27 | typedef unsigned char uchar; 28 | typedef unsigned int uint; 29 | typedef uint64_t hashval_t; 30 | 31 | typedef hashval_t(hashfunc) (const void *data, int len); 32 | typedef int (comparefunc) (const void *, const void *); 33 | typedef int (comprbt) (void *, void *); 34 | 35 | 36 | struct rbnode { 37 | struct rbnode *parent; 38 | struct rbnode *left; 39 | struct rbnode *right; 40 | int color; 41 | void *key; 42 | }; 43 | 44 | 45 | struct hlp { 46 | uchar *key; 47 | int len; 48 | uint32_t *ttl; 49 | uchar *val; 50 | int vlen; //used by record_find 51 | }; 52 | 53 | 54 | struct hentry { 55 | struct rbnode ttl; 56 | uchar *val; //has a header of struct mvalue entry 57 | struct hentry *next; 58 | uchar key[0]; 59 | }; 60 | 61 | 62 | struct hdata { 63 | struct hentry *list; 64 | pthread_mutex_t lock; 65 | }; 66 | 67 | 68 | //header in value segment 69 | struct mvalue { 70 | uint32_t len; 71 | uint32_t val; 72 | uchar data[0]; 73 | }; 74 | 75 | 76 | struct htable { 77 | pthread_mutex_t lock; //protect now 78 | struct hdata *table; 79 | uint size, mask, now; 80 | hashfunc *h; 81 | comparefunc *c; 82 | }; 83 | 84 | 85 | struct rbtree { 86 | struct rbnode *root, nil; 87 | pthread_mutex_t lock; 88 | uint size; 89 | comprbt *c; 90 | }; 91 | 92 | 93 | //hash function,compare fucntion,hash slots size 94 | struct htable *htable_create(hashfunc * h, comparefunc * c, int); 95 | //htable, key,len of key,val,replace 96 | int htable_insert(struct htable *, struct hentry *, int, int); 97 | //htable,key,keylen 98 | struct hentry *htable_delete(struct htable *ht, uchar *, int); 99 | //htable,key,keylen,val,maxvallen 100 | int htable_find(struct htable *, uchar *, int, uchar *, int); 101 | 102 | 103 | //create new tree 104 | struct rbtree *create_rbtree(comprbt * c); 105 | //delete one node, return the key pointer 106 | //if node don't exists, return NULL 107 | void *delete_node(struct rbtree *rbt, void *); 108 | //insert node, if node has existed, return -1 109 | int insert_node(struct rbtree *rbt, struct rbnode *nd); 110 | //find one node, return NULL or that node 111 | struct rbnode *find_node(struct rbtree *rbt, void *key); 112 | //minimum value node in tree 113 | struct rbnode *min_node(struct rbtree *rbt); 114 | 115 | 116 | struct records { 117 | struct rbtree *rbt; 118 | struct htable *ht; 119 | pthread_mutex_t lock; 120 | }; 121 | 122 | 123 | #endif 124 | -------------------------------------------------------------------------------- /src/control.c: -------------------------------------------------------------------------------- 1 | #define _POSIX_SOURCE 2 | #include "author.h" 3 | #include "datas.h" 4 | #include "dns.h" 5 | #include "control.h" 6 | #include 7 | #include 8 | #include 9 | 10 | int refresh_ttl_with_td(uchar *key, int len, int type, struct htable *ht, struct rbtree *ttlexp, packet_type *lowerdomain) 11 | { 12 | pthread_spin_lock(&ttlexp->lock); 13 | printf("after delete, before insert, rbt size: %d\n", get_rbt_size(ttlexp)); 14 | insert_into_ttltree(ttlexp, key, len, type, 0, lowerdomain); 15 | printf("after insert, rbt size: %d\n", get_rbt_size(ttlexp)); 16 | pthread_spin_unlock(&ttlexp->lock); 17 | return 0; 18 | } 19 | 20 | int hijack(uchar *domain, uint16_t type, struct htable *ht, struct rbtree *ttlexp) 21 | { 22 | if (!domain || domain[0] == '\0' || type <= 0 || type > 255) { 23 | kill(getpid(), SIGUSR1); 24 | } else { 25 | cache_flush(domain, type, ht, ttlexp); 26 | } 27 | 28 | /* struct mvalue *mv = (struct mvalue *)vbuffer; */ 29 | /* mv->num = 0; */ 30 | /* mv->ttl = 0; */ 31 | /* mv->len = 0; */ 32 | /* mv->seg = 0; */ 33 | // get record content from 'cnt', cp to vitor, and insert k,v to ds 34 | // uchar *vitor = vbuffer + sizeof(struct mvalue); 35 | return 0; 36 | } 37 | 38 | int cache_flush(uchar *domain, uint16_t type, struct htable* ht, struct rbtree *ttlexp) 39 | { 40 | printf("cache flush domain %s\n", domain); 41 | // uchar kbuffer[256] = { 0 }; 42 | int dlen = strlen((const char *)domain) + 1; 43 | hashval_t hash = 0; 44 | packet_type lowerdomain; 45 | 46 | str_to_len_label(domain, dlen); 47 | check_dns_name(domain, &lowerdomain); 48 | domain = lowerdomain.domain; 49 | // make_type_domain(domain, dlen, type, kbuffer); 50 | int idx = get_pre_mem_hash(domain, dlen, &hash); 51 | uchar *val = htable_delete(ht + idx, domain, dlen, type, hash); 52 | if (val) { 53 | struct mvalue *tmp = (struct mvalue *)val; 54 | struct ttlnode tn = {0}, *tmp_tn = NULL; 55 | pthread_spin_lock(&ttlexp->lock); 56 | tn.dlen = dlen; 57 | tn.exp = tmp->ttl; 58 | tn.type = type; 59 | tn.data = domain; 60 | tn.lowerdomain = NULL; 61 | struct rbnode *pn = find_node(ttlexp, &tn); 62 | //if update, we had delete tn in rbt 63 | //else update tn in rbt 64 | if (pn != NULL) { 65 | tmp_tn = delete_node(ttlexp, pn); 66 | if (tmp_tn) { 67 | free(tmp_tn->lowerdomain); 68 | free(tmp_tn); 69 | } else { 70 | assert(0); 71 | } 72 | } 73 | pthread_spin_unlock(&ttlexp->lock); 74 | free(val); 75 | refresh_ttl_with_td(domain, dlen, type, ht, ttlexp, &lowerdomain); 76 | } 77 | /* uchar kbuffer[256] = {0}; */ 78 | /* fix_tail((char*)domain); */ 79 | /* int dlen = strlen((const char *)domain); */ 80 | /* str_to_len_label(domain, dlen + 1); */ 81 | /* make_type_domain(domain, dlen, type, kbuffer); */ 82 | /* refresh_ttl_with_td(kbuffer, ht, ttlexp); */ 83 | return 0; 84 | } 85 | 86 | -------------------------------------------------------------------------------- /src/net.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2006-2012, DNSPod Inc. 2 | * All rights reserved. 3 | 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright notice, 10 | * this list of conditions and the following disclaimer in the documentation 11 | * and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | * The views and conclusions contained in the software and documentation are those 25 | * of the authors and should not be interpreted as representing official policies, 26 | * either expressed or implied, of the FreeBSD Project. 27 | */ 28 | 29 | 30 | #ifndef _NET_H 31 | #define _NET_H 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #include "utils.h" 40 | #include "memory.h" 41 | 42 | typedef struct sockaddr SA; 43 | 44 | #define MAX_TCP_SIZE (2048) 45 | #define MAX_UDP_SIZE (512) 46 | 47 | #define TCP (SOCK_STREAM) 48 | #define UDP (SOCK_DGRAM) 49 | 50 | 51 | #define BACK_EVENT (1000) 52 | 53 | 54 | //the socket information 55 | //use to identify client and auth server 56 | struct sockinfo { 57 | struct sockaddr_in addr; 58 | int fd, buflen, socktype; 59 | uchar *buf; 60 | packet_type *lowerdomain; 61 | mbuf_type *mbuf; 62 | }; 63 | 64 | 65 | int create_socket(int, int, uchar *); 66 | 67 | int add_backdoor(int fd); 68 | int udp_write_info(mbuf_type *mbuf, int); 69 | int udp_read_msg(mbuf_type *mbuf, int); 70 | int tcp_write_info(mbuf_type *mbuf, int); 71 | int tcp_read_dns_msg(mbuf_type *mbuf, uint, int); //len_msg. 72 | int connect_to(struct sockinfo *); 73 | 74 | struct fds *create_fds(int fd, int type); 75 | int set_time_out(int fd, int sec, int usec); 76 | int set_recv_timeout(int fd, int sec, int usec); 77 | int set_non_block(int fd); 78 | int set_sock_buff(int fd, int m); 79 | 80 | int check_client_addr(struct sockaddr_in *); 81 | int dbg_print_addr(struct sockaddr_in *); 82 | 83 | 84 | int make_bin_from_str(uchar * bin, const char * str); 85 | int make_addr_from_bin(struct sockaddr_in *addr, uchar * data); 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /src/memory.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2006-2012, DNSPod Inc. 2 | * All rights reserved. 3 | 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright notice, 10 | * this list of conditions and the following disclaimer in the documentation 11 | * and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | * The views and conclusions contained in the software and documentation are those 25 | * of the authors and should not be interpreted as representing official policies, 26 | * either expressed or implied, of the FreeBSD Project. 27 | */ 28 | 29 | 30 | 31 | #ifndef _MEMORY_H 32 | #define _MEMORY_H 33 | 34 | // #include "author.h" 35 | // #include "net.h" 36 | // #include "dns.h" 37 | // #include "storage.h" 38 | #include "utils.h" 39 | 40 | #include 41 | #include 42 | 43 | #define MEMPOOL_SIZE (65536) //(262144) 44 | 45 | #define RING_SP_ENQ 0x0001 46 | #define RING_SC_DEQ 0x0002 47 | 48 | struct mbuf_ring { 49 | /** Ring producer status. */ 50 | struct prod { 51 | uint32_t watermark; 52 | uint32_t sp_enqueue; 53 | uint32_t size; 54 | uint32_t mask; 55 | volatile uint32_t head; 56 | volatile uint32_t tail; 57 | } prod __attribute__((__aligned__(64))); 58 | 59 | /** Ring consumer status. */ 60 | struct cons { 61 | uint32_t sc_dequeue; 62 | uint32_t size; 63 | uint32_t mask; 64 | volatile uint32_t head; 65 | volatile uint32_t tail; 66 | } cons __attribute__((__aligned__(64))); 67 | void *ring[0] __attribute__((__aligned__(64))); 68 | }; 69 | 70 | #define MBUF_DATA_LEN (4096) 71 | typedef struct _mem_buf { 72 | struct mbuf_ring *mbuf; 73 | uint fetch_len; 74 | uint socktype; 75 | int fd; 76 | struct sockaddr_in *addr, caddr, aaddr; 77 | uchar data[MBUF_DATA_LEN]; 78 | 79 | enum rrtype qtype; 80 | int err; 81 | int dlen; 82 | ushort id; 83 | packet_type lowerdomain; 84 | uchar *origindomain; 85 | 86 | int buflen; 87 | uchar *buf; 88 | 89 | uchar *td; //type and domain 90 | ushort cid, qlen; //include 0 91 | ushort lables; 92 | //query info 93 | uchar *qing; 94 | hashval_t *qhash; 95 | ushort backid; 96 | ushort aid, mask; //auth id,domain mask 97 | ushort qname; //type 98 | //status info 99 | ushort sq; //send query flag 100 | ushort qtimes; //ns,cname,domain 101 | ushort auth_socktype, stat; //this may be diffefrent from client's socktype 102 | uchar qbuffer[256]; 103 | hashval_t qbuffer_hash; 104 | uchar *tdbuffer; 105 | uchar *tempbuffer; 106 | uchar *dmbuffer; 107 | uchar *ipbuffer; 108 | ushort hascname; 109 | int tcpfd; 110 | int tcpnums; 111 | int mxtry; 112 | int qns; 113 | uint64_t stime; 114 | 115 | // union { 116 | // uchar *vals[SUPPORT_TYPE_NUM]; 117 | // type_value val; 118 | // }; 119 | // struct hentry *next; 120 | // int count; 121 | // uchar key[256]; 122 | 123 | // union { 124 | // struct baseinfo bi; 125 | // struct sockinfo si; 126 | // struct qoutinfo qi; 127 | // struct hentry he; 128 | // } info; 129 | 130 | } mbuf_type; 131 | 132 | int mempool_create(uint32_t num); 133 | mbuf_type *mbuf_alloc(); 134 | int mbuf_free(mbuf_type *mbuf); 135 | 136 | #endif -------------------------------------------------------------------------------- /src/memory.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2006-2012, DNSPod Inc. 2 | * All rights reserved. 3 | 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright notice, 10 | * this list of conditions and the following disclaimer in the documentation 11 | * and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | * The views and conclusions contained in the software and documentation are those 25 | * of the authors and should not be interpreted as representing official policies, 26 | * either expressed or implied, of the FreeBSD Project. 27 | */ 28 | 29 | 30 | 31 | #include "memory.h" 32 | 33 | struct mbuf_ring *mbuf_ring = NULL; 34 | 35 | /* create the ring */ 36 | struct mbuf_ring * 37 | mbuf_ring_create(uint32_t count) 38 | { 39 | struct mbuf_ring *r; 40 | uint64_t ring_size; 41 | 42 | ring_size = count * sizeof(void *) + sizeof(struct mbuf_ring); 43 | 44 | r = (struct mbuf_ring *)malloc(ring_size); 45 | if (r != NULL) { 46 | memset(r, 0, sizeof(struct mbuf_ring)); 47 | r->prod.watermark = count; 48 | r->prod.size = r->cons.size = count; 49 | r->prod.mask = r->cons.mask = count - 1; 50 | r->prod.head = r->cons.head = 0; 51 | r->prod.tail = r->cons.tail = 0; 52 | } 53 | 54 | return r; 55 | } 56 | 57 | int 58 | mempool_create(uint32_t num) 59 | { 60 | mbuf_type *tmp; 61 | int i; 62 | 63 | mbuf_ring = mbuf_ring_create(num); 64 | if (NULL == mbuf_ring) 65 | return -1; 66 | 67 | for (i = 0; i < num; i++) 68 | { 69 | tmp = (mbuf_type *)malloc(sizeof(mbuf_type)); 70 | if (NULL == tmp) 71 | return -1; 72 | 73 | tmp->mbuf = mbuf_ring; 74 | mbuf_ring->ring[i] = tmp; 75 | } 76 | mbuf_ring->prod.head = mbuf_ring->prod.tail = num - 1; 77 | 78 | return 0; 79 | } 80 | 81 | #define mbuf_compiler_barrier() do { \ 82 | asm volatile ("" : : : "memory"); \ 83 | } while(0) 84 | 85 | static inline int 86 | rte_atomic32_cmpset(volatile uint32_t *dst, uint32_t exp, uint32_t src) 87 | { 88 | uint8_t res; 89 | 90 | asm volatile( 91 | "lock ; " 92 | "cmpxchgl %[src], %[dst];" 93 | "sete %[res];" 94 | : [res] "=a" (res), /* output */ 95 | [dst] "=m" (*dst) 96 | : [src] "r" (src), /* input */ 97 | "a" (exp), 98 | "m" (*dst) 99 | : "memory"); /* no-clobber list */ 100 | return res; 101 | } 102 | 103 | mbuf_type * 104 | mbuf_alloc() 105 | { 106 | uint32_t cons_head, prod_tail; 107 | uint32_t cons_next, entries; 108 | int success; 109 | uint32_t mask = mbuf_ring->prod.mask; 110 | mbuf_type *mbuf; 111 | 112 | cons_head = mbuf_ring->cons.head; 113 | prod_tail = mbuf_ring->prod.tail; 114 | 115 | entries = (prod_tail - cons_head); 116 | if (0 == entries) 117 | { 118 | dns_error(1, "out of mbuf ring(memory pool)"); 119 | return NULL; 120 | } 121 | 122 | cons_next = cons_head + 1; 123 | success = rte_atomic32_cmpset(&mbuf_ring->cons.head, cons_head, cons_next); 124 | if (success != 1) 125 | return NULL; 126 | 127 | /* copy in table */ 128 | mbuf = mbuf_ring->ring[cons_head & mask]; 129 | assert(mbuf != NULL); 130 | mbuf_compiler_barrier(); 131 | while (mbuf_ring->cons.tail != cons_head); 132 | 133 | mbuf_ring->cons.tail = cons_next; 134 | 135 | return mbuf; 136 | } 137 | 138 | int 139 | mbuf_free(mbuf_type *mbuf) 140 | { 141 | uint32_t prod_head, prod_next; 142 | uint32_t cons_tail, free_entries; 143 | int success; 144 | uint32_t mask = mbuf_ring->prod.mask; 145 | 146 | if (NULL == mbuf) 147 | return 0; 148 | 149 | /* move prod.head atomically */ 150 | do { 151 | prod_head = mbuf_ring->prod.head; 152 | cons_tail = mbuf_ring->cons.tail; 153 | 154 | free_entries = (mask + 1 + cons_tail - prod_head); 155 | assert(free_entries > 0); 156 | 157 | prod_next = prod_head + 1; 158 | success = rte_atomic32_cmpset(&mbuf_ring->prod.head, prod_head, prod_next); 159 | } while (0 == success); 160 | 161 | /* write entries in ring */ 162 | mbuf_ring->ring[prod_head & mask] = mbuf; 163 | mbuf_compiler_barrier(); 164 | 165 | while (mbuf_ring->prod.tail != prod_head); 166 | mbuf_ring->prod.tail = prod_next; 167 | 168 | return 0; 169 | } -------------------------------------------------------------------------------- /src/storage.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2006-2012, DNSPod Inc. 2 | * All rights reserved. 3 | 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright notice, 10 | * this list of conditions and the following disclaimer in the documentation 11 | * and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | * The views and conclusions contained in the software and documentation are those 25 | * of the authors and should not be interpreted as representing official policies, 26 | * either expressed or implied, of the FreeBSD Project. 27 | */ 28 | 29 | 30 | 31 | #ifndef _STORAGE_H 32 | #define _STORAGE_H 33 | 34 | #include "utils.h" 35 | #include "datas.h" 36 | #include "memory.h" 37 | #include 38 | #include 39 | 40 | //rfc 2817 41 | #define MAX_TTL (7 * 86400) 42 | //no rfc 43 | #define MIN_TTL (10) 44 | 45 | 46 | ////////////////////////memory chunk///////////////////////// 47 | struct msgcache { 48 | uint64_t head, tail; 49 | uint32_t size, pkt; 50 | pthread_spinlock_t lock; //protect head and tail 51 | uchar data[0]; 52 | }; 53 | 54 | 55 | struct msgcache *init_msgcache(int n); 56 | void free_msgcache(struct msgcache *); 57 | ///////////////////////////////////////////////////////////// 58 | 59 | 60 | enum { 61 | MAX_MSG_SEG = 32, 62 | MAX_MSG_SIZE = 2048, 63 | }; 64 | 65 | 66 | enum htable_insert_ret{ 67 | HTABLE_INSERT_RET_INVALID_TYPE = -1, 68 | HTABLE_INSERT_RET_NORMAL = 0, 69 | HTABLE_INSERT_RET_REPLACE, 70 | HTABLE_INSERT_RET_NEVER_EXPIRE, 71 | HTABLE_INSERT_RET_NO_REPLACE, 72 | }; 73 | 74 | //used by memory hash and disk db 75 | struct mvalue { 76 | uint16_t len; 77 | uint16_t num; 78 | uint32_t ttl; 79 | uint32_t hits; 80 | uint16_t seg; //when there is no memory segment, seg == 0 81 | //uint16_t off. 82 | //something... 83 | }; 84 | 85 | 86 | ///////////////////////memory hash/////////////////////////// 87 | typedef hashval_t(hashfunc) (void *data, int); 88 | typedef int (comparefunc) (void *, void *); 89 | typedef int (delkeyfunc) (void *); 90 | typedef int (delvalfunc) (void *); 91 | 92 | 93 | //we can hold at least HASH_TABLE_SIZE * MULTI_HASH elements 94 | //slot size 95 | #define HASH_TABLE_SIZE (65536) 96 | #define MULTI_HASH (10) 97 | extern const uint MAX_ELE_NUM; 98 | //MAX_RECORD_SIZE bytes at most 99 | #define MAX_RECORD_SIZE (4096) 100 | 101 | #define QLIST_MAX_ELE_NUM (200000) 102 | #define QLIST_TABLE_SIZE (4095) 103 | #define GET_AID(i, typeoff) (i | (typeoff << 12)) 104 | #define GET_IDX(i) (i & 0x0FFF) 105 | #define GET_TYPE(i) (i >> 12) 106 | 107 | //types we support at the moment 108 | extern const enum rrtype support_type[]; 109 | // #define SUPPORT_TYPE_NUM (9) 110 | // typedef struct _type_value 111 | // { 112 | // uchar *A; 113 | // uchar *NS; 114 | // uchar *CNAME; 115 | // uchar *SOA; 116 | // uchar *MX; 117 | // uchar *TXT; 118 | // uchar *AAAA; 119 | // uchar *SRV; 120 | // uchar *PTR; 121 | // }type_value; 122 | 123 | struct hentry { 124 | union { 125 | uchar *vals[SUPPORT_TYPE_NUM]; 126 | type_value val; 127 | }; 128 | struct hentry *next; 129 | int count; 130 | uchar key[0]; 131 | }; 132 | 133 | 134 | struct hdata { 135 | struct hentry *list; 136 | uint64_t now; 137 | pthread_spinlock_t lock; 138 | }; 139 | 140 | 141 | struct htable { 142 | pthread_spinlock_t lock; //protect now 143 | struct hdata *table; 144 | uchar *edata; 145 | hashfunc *h; 146 | uint size, mask, now; 147 | comparefunc *c; 148 | }; 149 | 150 | struct htable *htable_create(hashfunc * h, comparefunc * c, int, int); 151 | int htable_insert(struct htable *, uchar *, int, int, uchar *, int, struct mvalue *, hashval_t *hashd); 152 | uchar *htable_delete(struct htable *ht, uchar * key, int klen, int type, hashval_t hashd); 153 | int htable_find(struct htable *ht, uchar * key, int klen, int type, uchar * buffer, int vlen, 154 | struct mvalue *metadata, hashval_t *hashd); 155 | int htable_find_io(struct htable *ht, int idx,/* int off, uchar * buffer, 156 | uchar * key, int *klen, int vlen,*/ uint32_t limit, 157 | struct rbtree *rbt, int ttl_update); 158 | uint get_pre_mem_hash(void *, int klen, hashval_t *hashd); 159 | int find_record_with_ttl(struct htable *, uchar *, int, int, uchar *, int, 160 | struct mvalue *metadata, hashval_t *hash); 161 | 162 | int htable_find_list_io(struct htable *ht, int idx, int off, int *typeoff, uchar **buffer); 163 | int htable_find_list(struct htable *ht, uchar *key, int typeoff, int idx, uchar **buffer); 164 | uchar *htable_delete_list_io(struct htable *ht, int typeoff, int idx, int off); 165 | uchar *htable_delete_list(struct htable *ht, uchar *key, int typeoff, int idx); 166 | int htable_insert_list(struct htable *, uchar *, int, int, uchar *, int, struct mvalue *, hashval_t *hashd); 167 | 168 | 169 | int check_support_type(ushort type); 170 | 171 | #endif 172 | -------------------------------------------------------------------------------- /src/author.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2006-2012, DNSPod Inc. 2 | * All rights reserved. 3 | 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright notice, 10 | * this list of conditions and the following disclaimer in the documentation 11 | * and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | * The views and conclusions contained in the software and documentation are those 25 | * of the authors and should not be interpreted as representing official policies, 26 | * either expressed or implied, of the FreeBSD Project. 27 | */ 28 | 29 | 30 | #ifndef _AUTHOR_H 31 | #define _AUTHOR_H 32 | 33 | #define _GNU_SOURCE 34 | 35 | #include "io.h" 36 | #include 37 | #include 38 | 39 | enum { 40 | FETCHER_NUM = 2, 41 | SERVER_PORT = 53, 42 | }; 43 | 44 | 45 | enum { 46 | QUIZZER_NUM = 2, 47 | }; 48 | 49 | 50 | enum { 51 | NEW_QUERY = 0, 52 | PROCESS_QUERY = 1, 53 | TTL_UPDATE = 3, 54 | SHM_KEY = 38899, 55 | }; 56 | 57 | 58 | #define SRV_ADDR ("0.0.0.0") 59 | 60 | enum { 61 | //MAX_TRY_TIMES = 15, 62 | REFRESH_INTERVAL = 10, 63 | AUTH_DB_NUM = 101, 64 | BIG_MEM_STEP = 2000, 65 | RANDOM_SIZE = 3000, 66 | ID_SPACE = 60000, 67 | AUTH_DATA_LEN = 65528, //for meta data 68 | EP_TCP_FDS = 65530, 69 | }; 70 | 71 | 72 | enum { 73 | LIST_SPACE = 10000, 74 | }; 75 | 76 | #define OPT_LEN 9U /* Length of the NSD EDNS response record minus 2 */ 77 | #define OPT_RDATA 2 /* holds the rdata length comes after OPT_LEN */ 78 | #define OPT_HDR 4U /* NSID opt header length */ 79 | #define NSID_CODE 3 /* nsid option code */ 80 | #define DNSSEC_OK_MASK 0x8000U /* do bit mask */ 81 | 82 | struct eptcpfds { 83 | int ret; 84 | uchar domain[256]; 85 | }; 86 | 87 | struct author { 88 | int audp, //read and send auth server, private 89 | cudp, //send to client, share with other author 90 | idx; 91 | struct server *s; 92 | pthread_spinlock_t lock; //protect list above 93 | struct qoutinfo *list[LIST_SPACE]; 94 | //statis 95 | int qnum; 96 | int response; 97 | int qidx; 98 | int timex; 99 | //// 100 | struct list *el; 101 | int bdepfd; 102 | struct log_info *loginfo; 103 | pthread_spinlock_t dblock[AUTH_DB_NUM]; //protect db in disk 104 | uchar databuffer[AUTH_DATA_LEN]; 105 | uchar randombuffer[RANDOM_SIZE]; 106 | uchar tmpbuffer[BIG_MEM_STEP]; 107 | uchar tdbuffer[256]; 108 | uchar tempbuffer[IP_DATA_LEN]; 109 | uchar dmbuffer[512]; 110 | uchar ipbuffer[512]; 111 | struct epoll_event e[BACK_EVENT]; 112 | int rndidx; //no lock 113 | int dataidx; //no lock 114 | uchar ip[IP_DATA_LEN]; //shared by all qoutinfos 115 | struct eptcpfds eptcpfds[EP_TCP_FDS]; 116 | uint rdb; //records in db 117 | int ddbefore; 118 | int underattack; 119 | int tcpinuse; 120 | struct htable *fwd; 121 | struct htable *ds; 122 | int dupbefore; //only used in main thread 123 | int limits; //only used in main thread 124 | int hsidx; 125 | //statistics 126 | uint quizz; 127 | uint drop; 128 | uint timeout; 129 | int start, end; 130 | }; 131 | 132 | 133 | struct fetcher { 134 | int idx; 135 | struct server *s; 136 | struct msgcache *mc; 137 | struct list *el; 138 | struct log_info *loginfo; 139 | uchar originbuffer[AUTH_DATA_LEN]; 140 | uchar tdbuffer[256]; 141 | uchar databuffer[AUTH_DATA_LEN]; 142 | uchar cbbuffer[512]; 143 | int dataidx; 144 | int qidx; 145 | //statistics 146 | uint64_t pkg; 147 | uint64_t send; 148 | uint64_t miss; 149 | }; 150 | 151 | struct server { 152 | ushort nquizzer, nfetcher; 153 | int ludp, ltcp; //out udp 154 | struct fetcher *fetchers; 155 | struct author *authors; 156 | struct list eventlist; 157 | struct htable *datasets; 158 | struct htable *forward; 159 | //struct htable *rootz; 160 | struct htable *qlist; //same domain same type only query once. 161 | ulong pkg; 162 | uchar logpath[255]; 163 | ulong recordsindb; 164 | struct rbtree *ttlexp; 165 | //pthread_mutex_t lock;//protect ttlexp 166 | uint16_t refreshflag; 167 | time_t lastrefresh; 168 | int is_forward; 169 | }; 170 | 171 | struct server *global_serv; 172 | char *g_nameservers[2]; 173 | 174 | #define MAX_CPU_NUM 65 175 | struct thread_query_info { 176 | unsigned long query_num[9]; 177 | }; 178 | 179 | 180 | struct global_query_info { 181 | int thread_num; 182 | int log_flag; 183 | struct thread_query_info query_info[MAX_CPU_NUM]; 184 | }; 185 | 186 | struct global_query_info *global_out_info; 187 | int query_type_map[256]; 188 | 189 | struct seninfo { 190 | uint len; 191 | uint type; 192 | union { 193 | int fd; 194 | struct sockaddr_in addr; 195 | }; 196 | }; 197 | 198 | 199 | void *run_quizzer(void *); 200 | int run_fetcher(struct fetcher *f); 201 | int write_back_to_client(mbuf_type *mbuf, uchar *, int); 202 | int global_cron(struct server *); 203 | int find_from_db(struct baseinfo *qi, struct fetcher *f); 204 | 205 | #endif 206 | -------------------------------------------------------------------------------- /src/utils.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2006-2012, DNSPod Inc. 2 | * All rights reserved. 3 | 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright notice, 10 | * this list of conditions and the following disclaimer in the documentation 11 | * and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | * The views and conclusions contained in the software and documentation are those 25 | * of the authors and should not be interpreted as representing official policies, 26 | * either expressed or implied, of the FreeBSD Project. 27 | */ 28 | 29 | 30 | #ifndef _UTILS_H 31 | #define _UTILS_H 32 | 33 | //standard c headers 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include //for uint32_t 39 | 40 | //unix system headers 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | typedef unsigned int uint; 49 | typedef unsigned char uchar; 50 | typedef unsigned short ushort; 51 | typedef unsigned long ulong; 52 | typedef uint32_t hashval_t; 53 | 54 | 55 | extern time_t global_now; //defined in init.c 56 | 57 | 58 | enum utils_numberic { 59 | DEBUG_TIMES = 500, 60 | }; 61 | 62 | typedef struct _packet_type{ 63 | uint8_t label_count ; 64 | uchar domain[256]; 65 | uint8_t *label[64]; 66 | uint8_t label_offsets[64]; 67 | uint8_t label_len[64]; 68 | hashval_t hash[64]; 69 | // uchar origindomain[256]; 70 | } packet_type; 71 | 72 | 73 | struct list_node { 74 | void *data; 75 | struct list_node *next; 76 | }; 77 | 78 | 79 | //list header 80 | struct list { 81 | pthread_spinlock_t lock; 82 | struct list_node *head; 83 | }; 84 | 85 | 86 | struct ttlnode { 87 | uint exp; //expired time 88 | ushort dlen; //data len 89 | ushort type; 90 | hashval_t *hash; 91 | packet_type *lowerdomain; 92 | uchar *data; // 93 | }; 94 | 95 | enum rrtype { 96 | BEGIN_TYPE = 0, A = 1, NS = 2, 97 | MD = 3, MF = 4, CNAME = 5, SOA = 6, 98 | MB = 7, MG = 8, MR = 9, NUL = 10, 99 | WKS = 11, PTR = 12, HINFO = 13, 100 | MINFO = 14, MX = 15, TXT = 16, RP = 17, //rfc1183 101 | AFSDB = 18, //rfc1183 102 | /*gap */ SIG = 24, KEY = 25, 103 | //rfc2065 104 | /*gap */ AAAA = 28, /*gap */ NXT = 30, //rfc2065 105 | /*gap */ SRV = 33, 106 | //rfc2782 107 | CERT = 37, //rfc4398 108 | /*gap */ A6 = 38, DNAME = 39, /*rfc2672 *//*gap */ OPT = 41, //for edns0 109 | APL = 42, /*rfc3123 */ DS = 43, //rfc3658 110 | /*gap */ RRSIG = 46, 111 | //rfc4034 112 | NSEC = 47, DNSKEY = 48, DHCID = 49, /*rfc4701 *//*gap */ TKEY = 249, 113 | /*gap */ AXFR = 252, MAILB = 253, 114 | MAILA = 254, //obsolete 115 | ANY = 255, //*,a request for all records 116 | }; 117 | 118 | #define SUPPORT_TYPE_NUM (9) 119 | typedef struct _type_value 120 | { 121 | uchar *A; 122 | uchar *NS; 123 | uchar *CNAME; 124 | uchar *SOA; 125 | uchar *MX; 126 | uchar *TXT; 127 | uchar *AAAA; 128 | uchar *SRV; 129 | uchar *PTR; 130 | }type_value; 131 | 132 | typedef int (comprbt) (void *, void *, void *); 133 | 134 | #define RED (1) 135 | #define BLACK (0) 136 | 137 | struct rbnode { 138 | struct rbnode *parent; 139 | struct rbnode *left; 140 | struct rbnode *right; 141 | int color; 142 | void *key; 143 | }; 144 | 145 | struct rbtree { 146 | struct rbnode *root, nil; 147 | pthread_spinlock_t lock; 148 | uint size; 149 | comprbt *c; 150 | void *argv; 151 | }; 152 | 153 | int trig_signals(int); 154 | void drop_privilege(char *); 155 | 156 | uchar *get_str(uchar * str, int len); 157 | void put_str(uchar *); 158 | 159 | int dict_comp_uint_equ(void *a, void *b); 160 | int dict_comp_str_equ(void *a, void *b); 161 | int rbt_comp_uint_gt(void *v1, void *v2, void *argv); 162 | int rbt_comp_ttl_gt(void *v1, void *v2, void *argv); 163 | 164 | void dns_error(int, char *); 165 | int dbg(const char *format, ...); 166 | void print_hex(uchar * val, int n); 167 | 168 | int str_to_uchar4(const char *addr, uchar * val); 169 | int str_to_uchar6(uchar * addr, uchar * val); 170 | int to_uppercase(uchar * buf, int n); 171 | int to_lowercase(uchar * buf, int n); 172 | int fix_tail(char *domain); 173 | 174 | int empty_function(int); 175 | void insert_mem_bar(void); 176 | int test_lock(pthread_spinlock_t * lock); 177 | 178 | int set_bit(ushort *, int); 179 | int clr_bit(ushort *, int); 180 | int tst_bit(const ushort, int); 181 | 182 | 183 | int get_random_data(uchar *, int); 184 | 185 | int get_time_usage(struct timeval *tv, int isbegin); 186 | int is_uppercase(int c); 187 | int is_lowercase(int c); 188 | 189 | hashval_t uint_hash_function(void *ptr); 190 | hashval_t nocase_char_hash_function(void *argv, int klen); 191 | 192 | int slog(uchar * msg, int fd, pthread_spinlock_t * lock); 193 | 194 | extern unsigned char LowerTable[256]; 195 | extern unsigned char UpperTable[256]; 196 | #define TOLOWER(_ch) LowerTable[((unsigned char)_ch)] 197 | #define TOUPPER(_ch) UpperTable[((unsigned char)_ch)] 198 | 199 | #define DNS_GET16(num) ((((uint16_t)(num))>>8) | ((uint16_t)((num)<<8))) 200 | #define DNS_GET32(num) ((num >> 24)|((num >>8)&0x0000ff00)|((num << 8)&0x00ff0000)|(num << 24)); 201 | 202 | #endif 203 | -------------------------------------------------------------------------------- /src/update.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "update.h" 13 | #include "author.h" 14 | #include "control.h" 15 | 16 | #define USELESS 1 17 | #define MAX_CONN 1024 18 | 19 | const char *local_socket_name = "/tmp/foo.socket"; 20 | 21 | int create_local_server(const char *path) 22 | { 23 | int sock, size, ret; 24 | struct sockaddr_un addr; 25 | sock = socket(AF_UNIX, SOCK_STREAM, 0); 26 | if (sock < 0) { 27 | perror("socket error"); 28 | return -1; 29 | } 30 | memset(&addr, 0, sizeof(struct sockaddr_un)); 31 | addr.sun_family = AF_UNIX; 32 | strcpy(addr.sun_path, path); 33 | size = offsetof(struct sockaddr_un, sun_path) + strlen(path); 34 | 35 | unlink(addr.sun_path); 36 | ret = bind(sock, (struct sockaddr *)&addr, size); 37 | if (ret < 0) { 38 | perror("bind error"); 39 | close(sock); 40 | return -2; 41 | } 42 | 43 | ret = listen(sock, 10); 44 | if (ret < 0) { 45 | perror("listen error"); 46 | close(sock); 47 | return -3; 48 | } 49 | return sock; 50 | } 51 | 52 | int ctl_fd(int epfd, int fd, int ctl, uint32_t events) 53 | { 54 | int ret; 55 | struct epoll_event ev; 56 | memset(&ev, 0, sizeof(struct epoll_event)); 57 | ev.data.fd = fd; 58 | if (ctl == EPOLL_CTL_ADD) { 59 | ev.events = events; 60 | } 61 | 62 | if ((ret = epoll_ctl(epfd, ctl, fd, &ev)) < 0) { 63 | perror("epoll_ctl"); 64 | fprintf(stderr, "ctl fd %d error\n", fd); 65 | return -1; 66 | } 67 | return 0; 68 | } 69 | 70 | int accept_client(int epfd, int sock) 71 | { 72 | int clifd; 73 | socklen_t len; 74 | struct sockaddr_un cli_addr; 75 | struct stat statbuf; 76 | struct timeval tv; 77 | char *tmp = NULL; 78 | len = sizeof(cli_addr); 79 | clifd = accept(sock, (struct sockaddr *)&cli_addr, &len); 80 | if (clifd < 0) { 81 | fprintf(stderr, "accept error\n"); 82 | close(clifd); 83 | return -1; 84 | } 85 | len -= offsetof(struct sockaddr_un, sun_path); 86 | if (len > 0) { 87 | cli_addr.sun_path[len] = '\0'; 88 | if (stat(cli_addr.sun_path, &statbuf) < 0) { 89 | fprintf(stderr, "no this socket\n"); 90 | close(clifd); 91 | return -2; 92 | } 93 | if (S_ISSOCK(statbuf.st_mode) == 0) { 94 | fprintf(stderr, "not a socket\n"); 95 | close(clifd); 96 | return -3; 97 | } 98 | unlink(cli_addr.sun_path); 99 | tmp = strrchr(cli_addr.sun_path, '/'); 100 | if (tmp) { 101 | printf("client pid: %s connected: %d\n", tmp + 1, clifd); 102 | } 103 | } else { 104 | printf("new client (unknown pid) connected: %d\n", clifd); 105 | } 106 | 107 | if (ctl_fd(epfd, clifd, EPOLL_CTL_ADD, EPOLLIN)) { 108 | close(clifd); 109 | return -1; 110 | } 111 | tv.tv_sec = 3; 112 | tv.tv_usec = 0; 113 | setsockopt(clifd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); 114 | 115 | return clifd; 116 | } 117 | 118 | void disconnect_client(int epfd, int client) 119 | { 120 | ctl_fd(epfd, client, EPOLL_CTL_DEL, 0); 121 | close(client); 122 | printf("disconnect with client %d\n", client); 123 | } 124 | 125 | uint16_t get_type_from_str(const char *str_type) 126 | { 127 | uint16_t type = 0; 128 | if (!str_type || str_type[0] == '\0') { 129 | type = A; 130 | } else if (strcmp(str_type, "A") == 0) { 131 | type = A; 132 | } else if (strcmp(str_type, "CNAME") == 0) { 133 | type = CNAME; 134 | } else if (strcmp(str_type, "AAAA") == 0) { 135 | type = AAAA; 136 | } else if (strcmp(str_type, "MX") == 0) { 137 | type = MX; 138 | } else if (strcmp(str_type, "TXT") == 0) { 139 | type = TXT; 140 | } else if (strcmp(str_type, "SRV") == 0) { 141 | type = SRV; 142 | } else if (strcmp(str_type, "NS") == 0) { 143 | type = NS; 144 | } else if (strcmp(str_type, "SOA") == 0) { 145 | type = SOA; 146 | } else if (strcmp(str_type, "PTR") == 0) { 147 | type = PTR; 148 | } else { 149 | dns_error(1, "invalid cache flush type"); 150 | } 151 | return type; 152 | } 153 | 154 | int cmd_analyze(char *str, uchar *domain, uint16_t *type) 155 | { 156 | uchar *p = (uchar *)strchr(str, ':'); 157 | uchar *temp = NULL; 158 | uchar str_type[32] = {0}; 159 | size_t len; 160 | int cmd_type = -1; 161 | if (!p) { 162 | if (strcmp(str, "hijack") == 0) { 163 | cmd_type = HIJACK; 164 | } 165 | } else { 166 | if (strncmp(str, "cache flush", 11) == 0) { 167 | cmd_type = CACHE_FLUSH; 168 | } else if (strncmp(str, "hijack", 6) == 0) { 169 | cmd_type = HIJACK; 170 | } 171 | p++; 172 | temp = jump_space((uchar *)p); 173 | fix_tail((char *)temp); 174 | sscanf((const char *)temp, "%s %s", domain, str_type); 175 | *type = get_type_from_str((const char *)str_type); 176 | len = strlen((const char *)domain); 177 | if (domain[len - 1] != '.') { 178 | domain[len] = '.'; 179 | domain[len + 1] = '\0'; 180 | } 181 | } 182 | return cmd_type; 183 | } 184 | 185 | int talk_with_client(int epfd, int client, struct server *s) 186 | { 187 | /* 188 | * struct htable *ds = s->datasets; 189 | * struct rbtree *rbt = s->ttlexp; 190 | */ 191 | char buffer[BUFSIZ] = {0}; 192 | int ret; 193 | ret = recv(client, buffer, BUFSIZ - 1, 0); 194 | if (ret == 0) { 195 | disconnect_client(epfd, client); 196 | } 197 | if (ret > 0) { 198 | printf("recv from client [%d] %d bytes: %s\n", client, ret, buffer); 199 | uchar domain[512] = {0}; 200 | uint16_t type = 0; 201 | int ret = cmd_analyze(buffer, domain, &type); 202 | if (ret == HIJACK) { 203 | hijack(domain, type, s->datasets, s->ttlexp); 204 | } else if (ret == CACHE_FLUSH) { 205 | if (type != 0 && strlen((char *)domain) > 3) { 206 | cache_flush(domain, type, s->datasets, s->ttlexp); 207 | } 208 | } 209 | send(client, buffer, strlen(buffer), 0); 210 | } 211 | return 0; 212 | } 213 | 214 | int start_local_server(struct server *s) 215 | { 216 | int server, ret, epfd, i, fd; 217 | struct epoll_event e[MAX_CONN]; 218 | server = create_local_server(local_socket_name); 219 | if (server < 0) { 220 | return -1; 221 | } 222 | 223 | epfd = epoll_create(USELESS); 224 | if (epfd < 0) { 225 | perror("epoll_create error"); 226 | close(server); 227 | return -1; 228 | } 229 | if (ctl_fd(epfd, server, EPOLL_CTL_ADD, EPOLLIN) != 0) { 230 | close(server); 231 | return -1; 232 | } 233 | 234 | while (1) { 235 | ret = epoll_wait(epfd, e, MAX_CONN, 1000); 236 | if (ret < 0) { 237 | /* perror("epoll_wait error"); */ 238 | } else { 239 | for (i = 0; i < ret; i++) { 240 | fd = e[i].data.fd; 241 | if (fd == server) { 242 | accept_client(epfd, server); 243 | } else { 244 | if (e[i].events & EPOLLHUP || e[i].events & EPOLLERR) { 245 | disconnect_client(epfd, fd); 246 | } else if (e[i].events & EPOLLIN) { 247 | talk_with_client(epfd, fd, s); 248 | } 249 | } 250 | } 251 | } 252 | } 253 | } 254 | 255 | -------------------------------------------------------------------------------- /src/net.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2006-2012, DNSPod Inc. 2 | * All rights reserved. 3 | 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright notice, 10 | * this list of conditions and the following disclaimer in the documentation 11 | * and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | * The views and conclusions contained in the software and documentation are those 25 | * of the authors and should not be interpreted as representing official policies, 26 | * either expressed or implied, of the FreeBSD Project. 27 | */ 28 | 29 | 30 | #include "net.h" 31 | 32 | 33 | //reserved ip 34 | //10.0.0.0:8 35 | //172.16.0.0:12 36 | //192.168.0.0:16 37 | //0.0.0.0 38 | //255.255.255.255 39 | //127.0.0.0:8 40 | //224.0.0.0:18 41 | int 42 | check_client_addr(struct sockaddr_in *addr) 43 | { 44 | return 0; 45 | } 46 | 47 | 48 | //add fd to backdoor 49 | //only 1 udp fd at first 50 | int 51 | add_backdoor(int fd) 52 | { 53 | int epfd, ret; 54 | struct epoll_event ev = {0}; 55 | epfd = epoll_create(BACK_EVENT); 56 | if (epfd < 0) 57 | dns_error(0, "epoll bd"); 58 | ev.data.fd = fd; 59 | ev.events = EPOLLIN; //with out EPOLLET 60 | ret = epoll_ctl(epfd, EPOLL_CTL_ADD, ev.data.fd, &ev); 61 | if (ret < 0) 62 | dns_error(0, "epoll add udp backdoor"); 63 | return epfd; 64 | } 65 | 66 | 67 | int 68 | set_recv_timeout(int fd, int sec, int usec) 69 | { 70 | int ret; 71 | struct timeval tv; 72 | tv.tv_sec = sec; 73 | tv.tv_usec = usec; 74 | ret = 75 | setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *) &tv, 76 | sizeof(struct timeval)); 77 | return ret; 78 | } 79 | 80 | 81 | int 82 | create_socket(int port, int proto, uchar * addr) 83 | { 84 | int fd = -1, pt = -1; 85 | struct sockaddr_in srv; 86 | if (proto == UDP) 87 | pt = SOCK_DGRAM; 88 | else if (proto == TCP) 89 | pt = SOCK_STREAM; 90 | fd = socket(AF_INET, pt, 0); 91 | if (fd <= 0) 92 | return -1; 93 | srv.sin_family = AF_INET; 94 | if (addr == NULL) 95 | srv.sin_addr.s_addr = htonl(INADDR_ANY); 96 | else 97 | /* inet_aton(addr, &srv.sin_addr); */ 98 | inet_pton(AF_INET, (const char *)addr, &srv.sin_addr); 99 | srv.sin_port = htons(port); 100 | if (bind(fd, (SA *) & srv, sizeof(srv)) < 0) { 101 | perror("bind:"); 102 | return -1; 103 | } 104 | if (proto == SOCK_STREAM) 105 | listen(fd, 512); 106 | return fd; 107 | } 108 | 109 | 110 | int 111 | connect_to(struct sockinfo *si) 112 | { 113 | int ret = 0; 114 | //printf("CONN!!!\n"); 115 | socklen_t len = sizeof(struct sockaddr_in); 116 | ret = connect(si->fd, (SA *) & si->addr, len); 117 | if (ret < 0) { 118 | if (errno == EINPROGRESS) 119 | return 0; 120 | printf("%d,%d,", si->fd, errno); 121 | perror("conn"); 122 | return -1; 123 | } 124 | return 0; 125 | } 126 | 127 | 128 | int 129 | tcp_write_info(mbuf_type *mbuf, int vi) //for dns only 130 | { 131 | int i, ret; 132 | ret = send(mbuf->fd, mbuf->buf, mbuf->buflen, MSG_NOSIGNAL); 133 | if (ret < 0) { 134 | printf("%d,", errno); 135 | perror("tcp send"); 136 | } 137 | if (vi == 1) { 138 | printf("fd is %d\n", mbuf->fd); 139 | for (i = 0; i < mbuf->buflen; i++) 140 | printf("%x,", mbuf->buf[i]); 141 | printf("\n"); 142 | } 143 | return ret; 144 | } 145 | 146 | 147 | int 148 | udp_write_info(mbuf_type *mbuf, int vi) 149 | { 150 | int i, ret; 151 | socklen_t len; 152 | if (vi) { 153 | dbg_print_addr((struct sockaddr_in *) (mbuf->addr)); 154 | for (i = 0; i < mbuf->buflen; i++) 155 | { 156 | if (i % 16 == 0) 157 | printf("\n"); 158 | printf("%02x,", mbuf->buf[i]); 159 | } 160 | printf("\n"); 161 | } 162 | len = sizeof(struct sockaddr_in); 163 | ((struct sockaddr_in *) (mbuf->addr))->sin_family = AF_INET; 164 | ret = sendto(mbuf->fd, mbuf->buf, mbuf->buflen, 0, (SA *) (mbuf->addr), len); 165 | /* if (ret < 0) { */ 166 | /* perror("write udp"); */ 167 | /* printf("len %u,fd %d\n", len, ri->fd); */ 168 | /* dbg_print_addr((struct sockaddr_in *) &(ri->addr)); */ 169 | /* for (i = 0; i < ri->buflen; i++) */ 170 | /* printf("%x,", ri->buf[i]); */ 171 | /* printf("\n"); */ 172 | /* } */ 173 | return ret; 174 | } 175 | 176 | 177 | int 178 | tcp_read_dns_msg(mbuf_type *mbuf, uint max, int vi) //for dns only. 179 | { 180 | int ret = 0, tp, rcvnum; 181 | uchar buf[4] = { 0 }; 182 | ushort le = 0; 183 | tp = recv(mbuf->fd, buf, 2, 0); 184 | if (tp < 0) { 185 | printf("%d,", mbuf->fd); 186 | perror("tp"); 187 | return -1; 188 | } 189 | if (tp == 0) //peer closed 190 | return 0; 191 | memcpy(&le, buf, sizeof(ushort)); 192 | le = ntohs(le); 193 | if (le > max) { 194 | printf("too large %d,%u,%d\n", mbuf->fd, le, max); 195 | return -1; 196 | } 197 | while (ret < le) //should set time out here 198 | { 199 | rcvnum = recv(mbuf->fd, mbuf->buf + ret, mbuf->buflen - ret, 0); 200 | if (rcvnum < 0) { 201 | if (errno == EAGAIN || errno == EWOULDBLOCK) 202 | continue; 203 | printf("tcp data %d,%d,%d", mbuf->fd, le, ret); 204 | perror("tcp read"); 205 | return -1; 206 | } 207 | if (rcvnum == 0) { 208 | ret = -1; 209 | break; 210 | } 211 | ret += rcvnum; 212 | } 213 | return ret; 214 | } 215 | 216 | 217 | int 218 | udp_read_msg(mbuf_type *mbuf, int visible) 219 | { 220 | int ret, i; 221 | socklen_t len = sizeof(struct sockaddr_in); 222 | ret = 223 | recvfrom(mbuf->fd, mbuf->buf, mbuf->buflen, 0, (SA *)(mbuf->addr), 224 | &len); 225 | if (ret < 0) { 226 | //perror("read udp"); 227 | return ret; 228 | } 229 | //printf("%d,",ret); 230 | //dbg_print_addr(&si->addr); 231 | if (visible) { 232 | for (i = 0; i < ret; i++) 233 | printf("%x,", mbuf->buf[i]); 234 | printf("\n"); 235 | } 236 | return ret; 237 | } 238 | 239 | 240 | int 241 | set_sock_buff(int fd, int m) 242 | { 243 | int ret; 244 | int bufsize = m * 1024 * 1024; //1m 245 | if (fd <= 0) 246 | return -1; 247 | ret = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, 248 | (const uchar *) &bufsize, sizeof(int)); 249 | return ret; 250 | } 251 | 252 | 253 | int 254 | set_non_block(int fd) 255 | { 256 | int opt = fcntl(fd, F_GETFL, 0); 257 | if (opt < 0) 258 | return -1; 259 | opt |= O_NONBLOCK; 260 | return (fcntl(fd, F_SETFL, opt)); 261 | } 262 | 263 | 264 | int 265 | make_bin_from_str(uchar * bin, const char * str) 266 | { 267 | int i; 268 | uchar val = 0; 269 | for (i = 0; i < 4; i++) { 270 | while ((str[0] != '.') && (str[0] != 0)) { 271 | val = val * 10 + str[0] - '0'; 272 | str++; 273 | } 274 | str++; //jump '.' 275 | bin[0] = val; 276 | val = 0; 277 | bin++; //next digit 278 | } 279 | return 0; 280 | } 281 | 282 | 283 | int 284 | make_addr_from_bin(struct sockaddr_in *addr, uchar * data) 285 | { 286 | uchar ipv4[16] = { 0 }; 287 | int idx = 0; 288 | int i; 289 | ushort val = 0; 290 | if (data[0] == 0 && data[1] == 0 && data[2] == 0 && data[3] == 0) 291 | return -1; 292 | for (i = 0; i < 4; i++) { 293 | val = (ushort) data[i]; 294 | if (val > 99) { 295 | ipv4[idx] = val / 100 + '0'; 296 | idx++; 297 | } 298 | if (val > 9) { 299 | ipv4[idx] = (val % 100) / 10 + '0'; 300 | idx++; 301 | } 302 | ipv4[idx] = val % 10 + '0'; 303 | idx++; 304 | ipv4[idx] = '.'; 305 | idx++; 306 | } 307 | ipv4[idx - 1] = 0; 308 | i = inet_pton(AF_INET, (const char *)ipv4, &addr->sin_addr); 309 | return 0; 310 | } 311 | 312 | 313 | //---------------------debug------------------------------- 314 | int 315 | dbg_print_addr(struct sockaddr_in *addr) 316 | { 317 | uint i; 318 | if (addr == NULL) { 319 | printf("null addr\n"); 320 | return 0; 321 | } 322 | i = addr->sin_addr.s_addr; 323 | printf("%u.%u.%u.%u\n", i % (256), i / 256 % 256, i / 256 / 256 % 256, 324 | i / 256 / 256 / 256); 325 | return 0; 326 | } 327 | -------------------------------------------------------------------------------- /src/event.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2006-2012, DNSPod Inc. 2 | * All rights reserved. 3 | 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright notice, 10 | * this list of conditions and the following disclaimer in the documentation 11 | * and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | * The views and conclusions contained in the software and documentation are those 25 | * of the authors and should not be interpreted as representing official policies, 26 | * either expressed or implied, of the FreeBSD Project. 27 | */ 28 | 29 | 30 | 31 | #include "event.h" 32 | #include 33 | 34 | 35 | struct iner_event { 36 | int epfd; 37 | char *buf; 38 | struct epoll_event e[0]; 39 | }; 40 | 41 | 42 | struct event * 43 | create_event(int size) 44 | { 45 | struct event *ev = 46 | malloc(sizeof(struct event) + sizeof(struct event_data) * size); 47 | int epfd = epoll_create(size); 48 | if (epfd == 0) 49 | dns_error(0, "epoll create"); 50 | ev->size = size; 51 | ev->ie = 52 | malloc(sizeof(struct iner_event) + 53 | sizeof(struct epoll_event) * (ev->size)); 54 | if (ev->ie == NULL) 55 | dns_error(0, "alloc iner event"); 56 | memset(ev->ie, 0, 57 | sizeof(struct iner_event) + 58 | sizeof(struct epoll_event) * (ev->size)); 59 | ev->ie->epfd = epfd; 60 | return ev; 61 | } 62 | 63 | 64 | int 65 | add_event(struct event *ev, struct event_help *help) 66 | { 67 | struct epoll_event e = {0}; 68 | int ret = 0; 69 | int epfd = ev->ie->epfd; 70 | e.data.fd = help->fd; 71 | if (e.data.fd < 0) 72 | return -1; 73 | if (help->type == ET_READ) 74 | e.events = EPOLLIN; // | EPOLLET; 75 | if (help->type == ET_WRITE) 76 | e.events = EPOLLOUT; // | EPOLLET; 77 | ev->data[help->fd].cb = help->cb; 78 | if (help->ext != NULL) 79 | ev->data[help->fd].ext = help->ext; 80 | ret = epoll_ctl(epfd, EPOLL_CTL_ADD, help->fd, &e); 81 | if (ret < 0) { 82 | printf("fd is %d\n", help->fd); 83 | perror("epoll_ctl"); 84 | } 85 | return ret; 86 | } 87 | 88 | 89 | int 90 | del_event(struct event *ev, struct event_help *help) 91 | { 92 | struct epoll_event e; 93 | struct iner_event *ie = ev->ie; 94 | int ret = 0; 95 | e.data.fd = help->fd; 96 | ret = epoll_ctl(ie->epfd, EPOLL_CTL_DEL, help->fd, &e); 97 | return ret; 98 | } 99 | 100 | 101 | int 102 | handle_event(struct event *ev, int to) 103 | { 104 | int num = 0; 105 | /* static ulong fake_count = 0; */ 106 | /* static int tm = 0; */ 107 | struct iner_event *ie = ev->ie; 108 | if (to == 0) 109 | to = -1; 110 | else 111 | to = to * 100; 112 | ev->size = 100; 113 | while (1) { 114 | num = epoll_wait(ie->epfd, ie->e, ev->size, to); 115 | if (num >= 0) 116 | break; 117 | if (num < 0 && errno == EINTR) 118 | continue; 119 | } 120 | return num; 121 | } 122 | 123 | 124 | int 125 | cb_get_tcp_msg(struct event_data *data, void *v, int idx) 126 | { 127 | int ret, szhdr = sizeof(dnsheader); 128 | struct msgcache *mc; 129 | struct fetcher *f = (struct fetcher *) v; 130 | mbuf_type *mbuf; 131 | mbuf = mbuf_alloc(); 132 | if (NULL == mbuf) { 133 | return 0; 134 | } 135 | memset(mbuf, 0, sizeof(mbuf_type)); 136 | 137 | mc = f[idx].mc; 138 | pthread_spin_lock(&mc->lock); 139 | if (mc->tail + 8 > mc->size) 140 | mc->tail = 0; 141 | if ((mc->tail + 8 > mc->head && mc->tail < mc->head) || 142 | (mc->tail == mc->head && mc->pkt != 0)) //query msg should small than 300 bytes 143 | { 144 | close(data->fd); //we should return a SERVER_ERROR. 145 | f[idx].miss++; 146 | pthread_spin_unlock(&mc->lock); 147 | mbuf_free(mbuf); 148 | return 0; 149 | } 150 | f[idx].pkg++; 151 | mbuf->socktype = TCP; 152 | mbuf->fd = data->fd; 153 | mbuf->buf = mbuf->data; 154 | mbuf->buflen = MBUF_DATA_LEN; 155 | ret = tcp_read_dns_msg(mbuf, MBUF_DATA_LEN, 0); //epoll return and no blocked here 156 | if (ret < szhdr) { 157 | pthread_spin_unlock(&mc->lock); 158 | mbuf_free(mbuf); 159 | return -1; 160 | } 161 | mbuf->fetch_len = ret; 162 | memcpy(mc->data + mc->tail, &mbuf, sizeof(void *)); 163 | mc->tail = mc->tail + sizeof(void *); 164 | if (mc->tail + 8 > mc->size) 165 | mc->tail = 0; 166 | mc->pkt++; 167 | pthread_spin_unlock(&mc->lock); 168 | return 0; 169 | } 170 | 171 | 172 | int 173 | fake_recv(struct event_data *data, void *v, int idx) 174 | { 175 | struct fetcher *f = (struct fetcher *) v; 176 | struct sockaddr_in addr; 177 | uchar buffer[512] = { 0 }; 178 | int ret; 179 | idx = 0; 180 | socklen_t len = sizeof(struct sockaddr_in); 181 | while (1) { 182 | ret = recvfrom(data->fd, buffer, 512, 0, (SA *) & addr, &len); 183 | if (ret > 0) 184 | f[idx].pkg++; 185 | else 186 | return 0; 187 | } 188 | return 0; 189 | } 190 | 191 | 192 | int 193 | cb_get_udp_msg(struct event_data *data, void *v, int idx) 194 | { 195 | int ret, szhdr = sizeof(dnsheader); 196 | struct msgcache *mc = NULL; 197 | struct fetcher *f = (struct fetcher *) v; 198 | mbuf_type *mbuf; 199 | //printf("call back\n"); 200 | while (1) //we use epoll et and non-block mode. 201 | { 202 | mbuf = mbuf_alloc(); 203 | if (NULL == mbuf) { 204 | return 0; 205 | } 206 | memset(mbuf, 0, sizeof(mbuf_type)); 207 | mc = f[idx].mc; 208 | pthread_spin_lock(&mc->lock); 209 | if ((mc->tail + 8 > mc->head && mc->tail < mc->head) || 210 | (mc->tail == mc->head && mc->pkt != 0)) { 211 | f[idx].miss++; 212 | pthread_spin_unlock(&mc->lock); 213 | mbuf_free(mbuf); 214 | return 0; 215 | } 216 | f[idx].pkg++; 217 | mbuf->socktype = UDP; 218 | mbuf->fd = data->fd; 219 | mbuf->buf = mbuf->data + 2; 220 | mbuf->buflen = MBUF_DATA_LEN - 2; 221 | mbuf->addr = &(mbuf->caddr); 222 | ret = udp_read_msg(mbuf, 0); //epoll return and no blocking here 223 | if (ret < szhdr) { 224 | pthread_spin_unlock(&mc->lock); 225 | mbuf_free(mbuf); 226 | return -1; 227 | } 228 | mbuf->fetch_len = ret; 229 | memcpy(mc->data + mc->tail, &mbuf, sizeof(void *)); 230 | mc->tail = mc->tail + sizeof(void *);//ret + sizeof(struct seninfo); 231 | if (mc->tail + 8 > mc->size) 232 | mc->tail = 0; 233 | mc->pkt++; 234 | pthread_spin_unlock(&mc->lock); 235 | } 236 | return 0; 237 | } 238 | 239 | 240 | int 241 | insert_events(struct event *ev, int fd, int type) 242 | { 243 | struct event_help h; 244 | if (fd > 0) { 245 | memset(&h, 0, sizeof(struct event_help)); 246 | h.type = ET_READ; 247 | h.fd = fd; 248 | if (type == UDP) 249 | h.cb = cb_get_udp_msg; 250 | else 251 | h.cb = cb_get_tcp_msg; 252 | if (add_event(ev, &h) < 0) 253 | dns_error(1, "add event notify"); 254 | } 255 | return 0; 256 | } 257 | 258 | 259 | int 260 | run_sentinel(struct server *s) 261 | { 262 | int num, i, ls, connfd, ret, fidx = 0; 263 | struct sockaddr_in addr; 264 | struct event_help h; 265 | socklen_t len = sizeof(addr); 266 | struct fetcher *f = s->fetchers; 267 | struct event *ev = create_event(SENTINEL_EVENT); // 1 for udp,999 for tcp. 268 | cpu_set_t cpuinfo; 269 | pthread_t pt = pthread_self();; 270 | 271 | CPU_ZERO(&cpuinfo); 272 | CPU_SET_S(0, sizeof(cpuinfo), &cpuinfo); 273 | if(0 != pthread_setaffinity_np(pt, sizeof(cpu_set_t), &cpuinfo)) 274 | { 275 | printf("set affinity fetcher\n"); 276 | exit(0); 277 | } 278 | 279 | if (ev == NULL) 280 | dns_error(0, "create event st"); 281 | insert_events(ev, s->ludp, UDP); 282 | insert_events(ev, s->ltcp, TCP); 283 | ls = s->ltcp; 284 | while (1) { 285 | num = handle_event(ev, 1); 286 | global_cron(s); 287 | for (i = 0; i < num; i++) { 288 | int fd = ev->ie->e[i].data.fd; 289 | noti_chain_callback cb = ev->data[fd].cb; 290 | ev->data[fd].fd = fd; 291 | if (fd == ls) { 292 | connfd = accept(fd, (SA *) & addr, &len); 293 | set_non_block(connfd); 294 | insert_events(ev, connfd, TCP); 295 | continue; 296 | } else //udp or connected tcp 297 | if (cb != NULL) { 298 | //s->pkg ++; 299 | fidx++; 300 | //printf("packet\n"); 301 | fidx = fidx % FETCHER_NUM; 302 | if (fidx >= FETCHER_NUM) 303 | fidx = FETCHER_NUM - 1; 304 | //fake_recv(ev->data + fd,f,fidx); 305 | ret = (*cb) (ev->data + fd, f, fidx); 306 | if (cb == cb_get_tcp_msg) { 307 | if (ret == -1) //read data error 308 | close(fd); 309 | h.fd = fd; 310 | del_event(ev, &h); //not listen this socket 311 | } 312 | } else 313 | dns_error(1, "call back func is null"); 314 | } 315 | } 316 | return 0; 317 | } 318 | -------------------------------------------------------------------------------- /src/dns.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2006-2012, DNSPod Inc. 2 | * All rights reserved. 3 | 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright notice, 10 | * this list of conditions and the following disclaimer in the documentation 11 | * and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | * The views and conclusions contained in the software and documentation are those 25 | * of the authors and should not be interpreted as representing official policies, 26 | * either expressed or implied, of the FreeBSD Project. 27 | */ 28 | 29 | 30 | #ifndef _DNS_H 31 | #define _DNS_H 32 | 33 | #include "storage.h" 34 | #include "net.h" 35 | #include "datas.h" 36 | 37 | 38 | //-------------SYSTEM LIMIT---------------------- 39 | #define MAX_LABEL_LEN (63) 40 | #define MAX_DOMAIN_LEN (255) 41 | #define MIN_MSG_LEN (sizeof(dnsheader) + sizeof(qdns)) 42 | //a.b.c.d...15 43 | #define MAX_NS_LVL (16) 44 | #define MAX_UDP_SIZE (512) 45 | //addr to auth. 46 | #define MAX_PAR (7) 47 | #define MAX_RR_NUM (1000) 48 | //query to para_num auth servers 49 | #define PARA_NUM (3) 50 | //----------------------------------------------- 51 | 52 | 53 | 54 | // header 55 | // question 56 | // answer 57 | // authority 58 | // additional 59 | 60 | //header format 61 | ///////////// 62 | //id 63 | //flag(qr:1,opcode:4,aa:1,tc:1,rd:1,ra:1,z:3,rcode:4) 64 | //qdcount 65 | //ancount 66 | //nscount 67 | //arcount 68 | ///////////// 69 | 70 | //question format 71 | //////////// 72 | //name //digit,char,hyphen 73 | //type 74 | //class 75 | //////////// 76 | 77 | //rr format 78 | //////////// 79 | //name 80 | //type 81 | //class 82 | //ttl 83 | //rdlength 84 | //data 85 | //////////// 86 | 87 | 88 | enum { 89 | NO_ERROR = 0, 90 | FORMAT_ERROR = 1, 91 | SERVER_FAIL = 2, 92 | NAME_ERROR = 3, 93 | NOT_IMPL = 4, 94 | REFUSED = 5, 95 | }; 96 | 97 | 98 | enum { 99 | MAX_TRY_TIMES = 15, 100 | IP_DATA_LEN = 2000, 101 | }; 102 | 103 | 104 | //0 is q,1 is r 105 | #define QR_Q (0) 106 | #define QR_R (1) 107 | #define GET_QR(flag) ((flag & 0x8000) / 0x8000) 108 | #define SET_QR_R(flag) (flag | 0x8000) 109 | #define SET_QR_Q(flag) (flag & 0x7fff) 110 | #define GET_OPCODE(flag) ((flag & 0x7800) >> 11) 111 | //we always set opcode 0 at current veserion. 112 | #define QUERY (0) 113 | #define IQUERY (1) 114 | #define STATUS (2) 115 | #define GET_AA(flag) ((flag & 0x0400) / 0x0400) 116 | #define SET_AA(flag) (flag | 0x0400) 117 | #define GET_TC(flag) ((flag & 0x0200) / 0x0200) 118 | #define SET_TC(flag) (flag | 0x0200) 119 | #define GET_RD(flag) ((flag & 0x0100) / 0x0100) 120 | #define SET_RA(flag) (flag | 0x0080) 121 | #define GET_ERROR(flag) (flag & 0x7) 122 | #define SET_ERROR(flag,errcode) (flag & 0xfff0 + errcode) 123 | #define IS_PTR(os) (os >= 0xc000 && os <= 0xcfff) //in reply msg 124 | #define GET_OFFSET(offset) (offset & 0x3fff) //the 2 higher bits set to 0 125 | #define SET_OFFSET(offset) (offset | 0xc000) 126 | #define IS_EDNS0(flag) (flag > 0x4000 && flag < 0x4fff) 127 | 128 | 129 | //only IN support 130 | enum { 131 | CLASS_IN = 1, 132 | }; 133 | 134 | 135 | struct setheader { 136 | ushort an; 137 | ushort ns; 138 | ushort id; 139 | ushort dlen; 140 | uchar *od; 141 | uchar *itor; 142 | ushort type; 143 | }; 144 | 145 | 146 | 147 | enum { 148 | AN_SECTION = 2, 149 | NS_SECTION = 5, 150 | AR_SECTION = 7, 151 | DMS_SIZE = 256, 152 | }; 153 | 154 | 155 | struct hlpp { 156 | int *stype; 157 | struct htable *ds; 158 | struct rbtree *rbt; 159 | uchar *buf; 160 | int datalen; 161 | uchar *dms; 162 | int dmsidx; 163 | int section; 164 | uchar *tmpbuf; 165 | uchar *domainbuf; 166 | uchar *dmbuf; 167 | }; 168 | 169 | 170 | // enum rrtype { 171 | // BEGIN_TYPE = 0, A = 1, NS = 2, 172 | // MD = 3, MF = 4, CNAME = 5, SOA = 6, 173 | // MB = 7, MG = 8, MR = 9, NUL = 10, 174 | // WKS = 11, PTR = 12, HINFO = 13, 175 | // MINFO = 14, MX = 15, TXT = 16, RP = 17, //rfc1183 176 | // AFSDB = 18, //rfc1183 177 | // /*gap */ SIG = 24, KEY = 25, 178 | // //rfc2065 179 | // /*gap */ AAAA = 28, /*gap */ NXT = 30, //rfc2065 180 | // /*gap */ SRV = 33, 181 | // //rfc2782 182 | // CERT = 37, //rfc4398 183 | // /*gap */ A6 = 38, DNAME = 39, /*rfc2672 *//*gap */ OPT = 41, //for edns0 184 | // APL = 42, /*rfc3123 */ DS = 43, //rfc3658 185 | // /*gap */ RRSIG = 46, 186 | // //rfc4034 187 | // NSEC = 47, DNSKEY = 48, DHCID = 49, /*rfc4701 *//*gap */ TKEY = 249, 188 | // /*gap */ AXFR = 252, MAILB = 253, 189 | // MAILA = 254, //obsolete 190 | // ANY = 255, //*,a request for all records 191 | // }; 192 | // 193 | // //types we support at the moment 194 | // const enum rrtype support_type[] = 195 | // { A, NS, CNAME, SOA, MX, TXT, AAAA, SRV, PTR }; 196 | 197 | 198 | struct hlpc { 199 | uchar *name; 200 | short off, level, ref, mt, len; 201 | }; 202 | 203 | 204 | struct hlpf { 205 | ushort type; 206 | ushort len; 207 | uint ttl; 208 | uchar *hdr; 209 | uchar *from; 210 | uchar *to; 211 | }; 212 | 213 | 214 | #pragma pack (1) 215 | struct fillmsg { 216 | uint16_t type; 217 | uint16_t dclass; 218 | uint32_t ttl; 219 | uint16_t len; 220 | }; 221 | #pragma pack() 222 | 223 | 224 | #define TYPE_RECORD (7) 225 | #define TYPE_MSG_LINE (1000) 226 | #define TYPE_TCP_MSG (1007) 227 | #define TYPE_UDP_MSG (1009) 228 | 229 | #pragma pack (1) 230 | typedef struct tag_dnsheader { 231 | uint16_t id, flags; 232 | uint16_t qdcount, ancount, nscount, arcount; 233 | } dnsheader; 234 | #pragma pack () 235 | 236 | 237 | #pragma pack (1) 238 | typedef struct tag_dq { 239 | uint16_t type, dclass; 240 | } qdns; 241 | #pragma pack () 242 | 243 | //some base information about dns msg 244 | struct baseinfo { 245 | enum rrtype type; 246 | int err; 247 | int dlen; 248 | ushort id; 249 | packet_type *lowerdomain; 250 | uchar *origindomain; 251 | }; 252 | 253 | #pragma pack (1) 254 | struct soa { 255 | uchar *mname; 256 | uchar *rname; 257 | uint32_t serial; //201102022222, 12334545 258 | uint32_t refresh, retry, expire, minimum; 259 | }; 260 | #pragma pack () 261 | 262 | #pragma pack(1) 263 | //_service._proto.name 264 | //in struct record.data. 265 | //uchar *service 266 | //uchar *proto; 267 | //service and proto are NOT case sensitive. 268 | struct srv { 269 | uint16_t pri, wei, port; 270 | //uchar *target; 271 | //name compression is not to be used for this field 272 | }; 273 | #pragma pack() 274 | 275 | 276 | enum { 277 | MOST_TRY_PER_QUERY = 3, 278 | }; 279 | 280 | 281 | //query from auth server 282 | #define QBUFFER_SIZE (256) 283 | struct qoutinfo { 284 | //client info 285 | uchar *td, type; //type and domain 286 | packet_type *lowerdomain; 287 | struct sockinfo *cli; //sock info 288 | ushort cid, dlen, qlen; //include 0 289 | ushort lables; 290 | //query info 291 | uchar *qing; 292 | hashval_t *qhash; 293 | ushort backid; 294 | ushort aid, mask; //auth id,domain mask 295 | ushort qname; //type 296 | //status info 297 | ushort sq; //send query flag 298 | ushort qtimes; //ns,cname,domain 299 | ushort socktype, stat; //this may be diffefrent from client's socktype 300 | uchar qbuffer[QBUFFER_SIZE]; 301 | hashval_t qbuffer_hash; 302 | uchar *tdbuffer; 303 | uchar *tempbuffer; 304 | uchar *dmbuffer; 305 | uchar *ipbuffer; 306 | ushort hascname; 307 | int tcpfd; 308 | int tcpnums; 309 | int mxtry; 310 | int qns; 311 | uint64_t stime; 312 | }; 313 | 314 | 315 | enum { 316 | Q_CNAME = 3, 317 | Q_DOMAIN = 4, 318 | Q_NS = 6, 319 | }; 320 | 321 | int find_addr(struct htable *fwd, struct htable *, mbuf_type *mbuf, 322 | uchar *, int); 323 | 324 | 325 | uchar *fill_header_in_msg(struct setheader *); 326 | uchar *fill_rrset_in_msg(struct hlpc *, uchar *, uchar *, int *, uchar *); 327 | 328 | uint dname_hash(void *); 329 | 330 | int check_out_msg(ushort, uchar *, int); 331 | int check_an_msg(ushort, uchar *, int *); 332 | int check_dns_name(uchar * domain, packet_type *lowerdomain); 333 | int check_domain_mask(uchar *, uchar *, int); 334 | 335 | int make_dns_msg_for_new(uchar *, ushort, uchar *, int, ushort); 336 | int send_tc_to_client(mbuf_type *mbuf); 337 | 338 | uchar *str_to_len_label(uchar * domain, int len); 339 | 340 | int get_domain_from_msg(uchar * label, uchar * b, uchar * tmpd, int *tmplen); 341 | int get_dns_info(uchar *, ushort *, ushort *, uint *, ushort *); 342 | int get_level(uchar *); 343 | int make_type_domain(uchar * domain, int dlen, int type, uchar * buffer); 344 | int insert_kv_mem(struct rbtree *, struct htable *ds, uchar * k, int klen, 345 | int type, uchar * v, int vlen, int hijack, packet_type *lowerdomain); 346 | 347 | uchar *fill_a_record_in_msg(struct hlpc *h, uchar * from, uchar * to, 348 | uint ttl); 349 | uchar *fill_name_in_msg(struct hlpc *h, uchar * to, int idx); 350 | uchar *fill_header_in_msg(struct setheader *sh); 351 | int fill_rrset_in_buffer(uchar *, uchar *, uchar *, int, int, 352 | struct hlpp *); 353 | int transfer_record_to_msg(uchar *, uchar * td, uchar * buf, int buflen, 354 | uint16_t *); 355 | 356 | void passer_dns_data(mbuf_type *mbuf); 357 | uchar *process_rdata(struct hlpp *, uchar *, int); 358 | 359 | int check_qo(struct qoutinfo *qo); 360 | uchar *dbg_print_label(uchar * label, int visible); 361 | uchar *dbg_print_domain(uchar * hdr, uchar * itor); 362 | void dbg_print_ip(uchar * ip, enum rrtype type); 363 | int dbg_print_td(uchar * td); 364 | 365 | int insert_into_ttltree(struct rbtree *rbt, uchar * td, int len, int type, uint ttl, packet_type *lowerdomain); 366 | #endif 367 | -------------------------------------------------------------------------------- /src/datas.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2006-2012, DNSPod Inc. 2 | * All rights reserved. 3 | 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright notice, 10 | * this list of conditions and the following disclaimer in the documentation 11 | * and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | * The views and conclusions contained in the software and documentation are those 25 | * of the authors and should not be interpreted as representing official policies, 26 | * either expressed or implied, of the FreeBSD Project. 27 | */ 28 | 29 | 30 | #include "datas.h" 31 | 32 | 33 | //!!!!!!!!!!!!!could NOT used in multithread env!!!!!!!!!!!!!!!!!! 34 | 35 | 36 | //--------------------red black tree--------- 37 | static void 38 | left_rotate(struct rbtree *rbt, struct rbnode *node) 39 | { 40 | struct rbnode *tmp = node->right; 41 | node->right = tmp->left; 42 | if (tmp->left != &rbt->nil) 43 | tmp->left->parent = node; 44 | tmp->parent = node->parent; 45 | if (node->parent == &rbt->nil) 46 | rbt->root = tmp; 47 | else if (node == node->parent->left) 48 | node->parent->left = tmp; 49 | else 50 | node->parent->right = tmp; 51 | tmp->left = node; 52 | node->parent = tmp; 53 | } 54 | 55 | 56 | static void 57 | right_rotate(struct rbtree *rbt, struct rbnode *node) 58 | { 59 | struct rbnode *tmp = node->left; 60 | node->left = tmp->right; 61 | if (tmp->right != &rbt->nil) 62 | tmp->right->parent = node; 63 | tmp->parent = node->parent; 64 | if (node->parent == &rbt->nil) 65 | rbt->root = tmp; 66 | else if (node == node->parent->left) 67 | node->parent->left = tmp; 68 | else 69 | node->parent->right = tmp; 70 | tmp->right = node; 71 | node->parent = tmp; 72 | } 73 | 74 | 75 | static void 76 | insert_fixup(struct rbtree *rbt, struct rbnode *nd) 77 | { 78 | struct rbnode *tmp; 79 | while (nd->parent->color == RED) { 80 | if (nd->parent == nd->parent->parent->left) { 81 | tmp = nd->parent->parent->right; 82 | if (tmp->color == RED) { 83 | nd->parent->color = tmp->color = BLACK; 84 | nd->parent->parent->color = RED; 85 | nd = nd->parent->parent; 86 | } else { 87 | if (nd == nd->parent->right) { 88 | nd = nd->parent; 89 | left_rotate(rbt, nd); 90 | } 91 | nd->parent->color = BLACK; 92 | nd->parent->parent->color = RED; 93 | right_rotate(rbt, nd->parent->parent); 94 | } 95 | } else { 96 | tmp = nd->parent->parent->left; 97 | if (tmp->color == RED) { 98 | nd->parent->color = tmp->color = BLACK; 99 | nd->parent->parent->color = RED; 100 | nd = nd->parent->parent; 101 | } else { 102 | if (nd == nd->parent->left) { 103 | nd = nd->parent; 104 | right_rotate(rbt, nd); 105 | } 106 | nd->parent->color = BLACK; 107 | nd->parent->parent->color = RED; 108 | left_rotate(rbt, nd->parent->parent); 109 | } 110 | } 111 | } 112 | rbt->root->color = BLACK; 113 | } 114 | 115 | 116 | //find_node and delete_node are not safe 117 | //delete node may return NULL. 118 | struct rbnode * 119 | find_node(struct rbtree *rbt, void *key) 120 | { 121 | struct rbnode *nd = &rbt->nil; 122 | int i; 123 | //pthread_mutex_lock(&(rbt->lock)); 124 | nd = rbt->root; 125 | while (nd != &rbt->nil) { 126 | i = (rbt->c) (nd->key, key, rbt->argv); 127 | if (i > 0) 128 | nd = nd->left; 129 | if (i < 0) 130 | nd = nd->right; 131 | if (nd == &rbt->nil) 132 | break; //return null 133 | if (i == 0) { 134 | //pthread_mutex_unlock(&(rbt->lock)); 135 | return nd; 136 | } 137 | } 138 | //pthread_mutex_unlock(&(rbt->lock)); 139 | return NULL; 140 | } 141 | 142 | 143 | int 144 | insert_node(struct rbtree *rbt, struct rbnode *pnd) 145 | { 146 | struct rbnode *tmp = &rbt->nil, *itor = rbt->root; 147 | struct rbnode *nd = malloc(sizeof(struct rbnode)); 148 | if (nd == NULL) 149 | return -1; 150 | *nd = *pnd; 151 | //pthread_mutex_lock(&(rbt->lock)); 152 | while (itor != &rbt->nil) { 153 | tmp = itor; 154 | if ((rbt->c) (itor->key, nd->key, rbt->argv) > 0) 155 | itor = itor->left; 156 | else 157 | itor = itor->right; 158 | } 159 | nd->parent = tmp; 160 | if (tmp == &rbt->nil) 161 | rbt->root = nd; 162 | else { 163 | if ((rbt->c) (tmp->key, nd->key, rbt->argv) > 0) 164 | tmp->left = nd; 165 | else 166 | tmp->right = nd; 167 | } 168 | nd->left = nd->right = &rbt->nil; 169 | nd->color = RED; 170 | insert_fixup(rbt, nd); 171 | rbt->size++; 172 | //pthread_mutex_unlock(&(rbt->lock)); 173 | /* printf("\t\t\t\t\t\t\tafter insert, rbt size: %d\n", get_rbt_size(rbt)); */ 174 | return 0; 175 | } 176 | 177 | 178 | static struct rbnode * 179 | rbt_successor(struct rbtree *rbt, struct rbnode *nd) 180 | { 181 | struct rbnode *min = &rbt->nil; 182 | if (nd->right != &rbt->nil) { 183 | min = nd->right; 184 | while (min->left != &rbt->nil) 185 | min = min->left; 186 | return min; 187 | } 188 | min = nd->parent; 189 | while ((min != &rbt->nil) && (nd == min->right)) { 190 | nd = min; 191 | min = min->parent; 192 | } 193 | return min; 194 | } 195 | 196 | 197 | static void 198 | delete_fixup(struct rbtree *rbt, struct rbnode *nd) 199 | { 200 | struct rbnode *tmp = &rbt->nil; 201 | while (nd != rbt->root && nd->color == BLACK) 202 | if (nd == nd->parent->left) { 203 | tmp = nd->parent->right; 204 | if (tmp->color == RED) { 205 | tmp->color = BLACK; 206 | nd->parent->color = RED; 207 | left_rotate(rbt, nd->parent); 208 | tmp = nd->parent->right; 209 | } 210 | if (tmp->left->color == BLACK && tmp->right->color == BLACK) { 211 | tmp->color = RED; 212 | nd = nd->parent; 213 | } else { 214 | if (tmp->right->color == BLACK) { 215 | tmp->left->color = BLACK; 216 | tmp->color = RED; 217 | right_rotate(rbt, tmp); 218 | tmp = nd->parent->right; 219 | } 220 | tmp->color = nd->parent->color; 221 | nd->parent->color = BLACK; 222 | tmp->right->color = BLACK; 223 | left_rotate(rbt, nd->parent); 224 | nd = rbt->root; //end while 225 | } 226 | } else { 227 | tmp = nd->parent->left; 228 | if (tmp->color == RED) { 229 | tmp->color = BLACK; 230 | nd->parent->color = RED; 231 | right_rotate(rbt, nd->parent); 232 | tmp = nd->parent->left; 233 | } 234 | if (tmp->right->color == BLACK && tmp->left->color == BLACK) { 235 | tmp->color = RED; 236 | nd = nd->parent; 237 | } else { 238 | if (tmp->left->color == BLACK) { 239 | tmp->right->color = BLACK; 240 | tmp->color = RED; 241 | left_rotate(rbt, tmp); 242 | tmp = nd->parent->left; 243 | } 244 | tmp->color = nd->parent->color; 245 | nd->parent->color = BLACK; 246 | tmp->left->color = BLACK; 247 | right_rotate(rbt, nd->parent); 248 | nd = rbt->root; //end while 249 | } 250 | } 251 | nd->color = BLACK; 252 | } 253 | 254 | 255 | struct rbnode * 256 | min_node(struct rbtree *rbt) 257 | { 258 | struct rbnode *tmp, *ret; 259 | //pthread_mutex_lock(&(rbt->lock)); 260 | tmp = rbt->root; 261 | ret = &rbt->nil; 262 | if (tmp == &rbt->nil) { 263 | //pthread_mutex_unlock(&(rbt->lock)); 264 | return NULL; 265 | } 266 | while (tmp != &rbt->nil) { 267 | ret = tmp; 268 | tmp = tmp->left; 269 | } 270 | if (ret == &rbt->nil) { 271 | //pthread_mutex_unlock(&(rbt->lock)); 272 | return NULL; 273 | } 274 | //pthread_mutex_unlock(&(rbt->lock)); 275 | return ret; 276 | } 277 | 278 | 279 | //free node, return val 280 | void * 281 | delete_node(struct rbtree *rbt, struct rbnode *nd) 282 | { 283 | struct ttlnode *val = NULL; 284 | struct rbnode *ret = nd; 285 | struct rbnode *tmp, *itor; 286 | if (nd == NULL || rbt == NULL) 287 | return NULL; 288 | val = nd->key; 289 | /* printf("delete node ttl: %d ", val->exp); */ 290 | /* dbg_print_td(val->data); */ 291 | //pthread_mutex_lock(&(rbt->lock)); 292 | if (nd->left == &rbt->nil || nd->right == &rbt->nil) 293 | tmp = nd; 294 | else 295 | tmp = rbt_successor(rbt, nd); 296 | if (tmp->left != &rbt->nil) 297 | itor = tmp->left; 298 | else 299 | itor = tmp->right; 300 | itor->parent = tmp->parent; 301 | if (tmp->parent == &rbt->nil) 302 | rbt->root = itor; 303 | else { 304 | if (tmp == tmp->parent->left) 305 | tmp->parent->left = itor; 306 | else 307 | tmp->parent->right = itor; 308 | } 309 | if (tmp != itor) 310 | nd->key = tmp->key; 311 | if (tmp->color == BLACK) 312 | delete_fixup(rbt, itor); 313 | if (ret == NULL) 314 | printf("ret is null\n"); 315 | free(tmp); 316 | rbt->size--; 317 | //pthread_mutex_unlock(&(rbt->lock)); 318 | /* printf("\t\t\t\t\t\t\tafter delete, rbt size: %d\n", get_rbt_size(rbt)); */ 319 | return val; 320 | } 321 | 322 | 323 | struct rbtree * 324 | create_rbtree(comprbt * c, void *argv) 325 | { 326 | struct rbtree *rbt = malloc(sizeof(struct rbtree)); 327 | if (rbt == NULL) 328 | return NULL; 329 | rbt->argv = argv; 330 | rbt->c = c; 331 | rbt->size = 0; 332 | pthread_spin_init(&rbt->lock, 0); 333 | rbt->nil.parent = &(rbt->nil); 334 | rbt->nil.left = &(rbt->nil); 335 | rbt->nil.right = &(rbt->nil); 336 | rbt->nil.color = BLACK; 337 | rbt->nil.key = NULL; 338 | rbt->root = &rbt->nil; 339 | return rbt; 340 | } 341 | 342 | 343 | uint 344 | get_rbt_size(struct rbtree * rbt) 345 | { 346 | return rbt->size; 347 | } 348 | 349 | 350 | int 351 | free_rbtree(struct rbtree *rbt) 352 | { 353 | if (get_rbt_size(rbt) > 0) 354 | return -1; 355 | free(rbt); 356 | return 0; 357 | } 358 | 359 | 360 | //---------------rbtree debug------------------------------------// 361 | int 362 | rbtree_test(void) 363 | { 364 | int i, j, len, slice, ret; 365 | struct rbnode node, *pn = NULL; 366 | struct ttlnode *tn = NULL; 367 | struct rbtree *rbt = NULL; 368 | rbt = create_rbtree(rbt_comp_ttl_gt, NULL); 369 | if (rbt == NULL) 370 | dns_error(0, "create rbtree"); 371 | node = rbt->nil; //nil 372 | slice = 8000000; 373 | //for(i = 0;i < n;i ++) 374 | //{ 375 | for (j = 0; j < slice; j++) { 376 | len = random() % 30; 377 | tn = malloc(sizeof(struct ttlnode) + len); 378 | if (tn == NULL) 379 | printf("oom\n"); 380 | tn->exp = j; 381 | for (i = 0; i < len; i++) 382 | tn->data[i] = 'a' + i; 383 | node.key = tn; 384 | ret = insert_node(rbt, &node); 385 | if (ret != 0) 386 | printf("insert error\n"); 387 | } 388 | printf("insert all\n"); 389 | sleep(2); 390 | for (j = 0; j < slice; j++) { 391 | pn = min_node(rbt); 392 | if (pn != NULL) { 393 | tn = delete_node(rbt, pn); 394 | free(tn); 395 | } else 396 | printf("error\n"); 397 | } 398 | printf("delete all\n"); 399 | sleep(5); 400 | //} 401 | if (free_rbtree(rbt) != 0) 402 | dns_error(0, "free"); 403 | //get_time_usage(&tv,0); 404 | return 0; 405 | } 406 | -------------------------------------------------------------------------------- /src/init.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2006-2012, DNSPod Inc. 2 | * All rights reserved. 3 | 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright notice, 10 | * this list of conditions and the following disclaimer in the documentation 11 | * and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | * The views and conclusions contained in the software and documentation are those 25 | * of the authors and should not be interpreted as representing official policies, 26 | * either expressed or implied, of the FreeBSD Project. 27 | */ 28 | 29 | 30 | 31 | #include "event.h" 32 | #include "update.h" 33 | #include "config.h" 34 | #include "memory.h" 35 | #include 36 | #include 37 | #include 38 | 39 | //---------------------------------------------- 40 | time_t global_now = 0; 41 | pthread_mutex_t gnlock; 42 | volatile sig_atomic_t refresh_record = 0; 43 | //---------------------------------------------- 44 | 45 | 46 | extern int daemon(int, int); 47 | struct entry; 48 | 49 | 50 | static int 51 | daemonrize(int dm) 52 | { 53 | if (dm == 1) { 54 | if (daemon(1, 0) == -1) 55 | dns_error(0, "daemonrize"); 56 | else 57 | printf("daemon!!!\n"); //we will never see this 58 | } 59 | return 0; 60 | } 61 | 62 | 63 | static int 64 | create_listen_ports(int port, int proto, uchar * addr) 65 | { 66 | int fd = -1; 67 | fd = create_socket(port, proto, addr); 68 | if (fd < 0 || set_non_block(fd) < 0) { 69 | printf("port:%d,proto:%d\n", port, proto); 70 | dns_error(0, "fd < 0"); 71 | } 72 | return fd; 73 | } 74 | 75 | 76 | int 77 | create_author(struct server *s, int n) 78 | { 79 | int i, j; 80 | struct author *authors = NULL; 81 | cpu_set_t cpuinfo; 82 | pthread_t apt[QUIZZER_NUM]; 83 | if (n < 1 || n > 50) 84 | dns_error(0, "quizzer bad range"); 85 | if ((authors = malloc(sizeof(struct author) * n)) == NULL) 86 | dns_error(0, "out of memory in quizzer"); 87 | memset(authors, 0, sizeof(struct author) * n); 88 | s->authors = authors; 89 | for (i = 0; i < n; i++) { 90 | authors[i].idx = i; 91 | authors[i].cudp = s->ludp; 92 | authors[i].audp = create_listen_ports(i * 1000 + 998, UDP, NULL); 93 | if (authors[i].audp < 0) 94 | dns_error(0, "auth fd error"); 95 | set_sock_buff(authors[i].audp, 1); 96 | authors[i].el = &s->eventlist; 97 | authors[i].s = s; 98 | get_random_data(authors[i].randombuffer, RANDOM_SIZE); 99 | authors[i].rndidx = 0; 100 | authors[i].dupbefore = 0; 101 | authors[i].limits = 10; 102 | authors[i].bdepfd = 0; 103 | authors[i].fwd = s->forward; 104 | authors[i].ds = s->datasets; 105 | authors[i].qnum = 0; 106 | authors[i].underattack = 0; 107 | authors[i].timex = 0; 108 | authors[i].response = 0; 109 | authors[i].tcpinuse = 0; 110 | authors[i].rdb = 0; 111 | authors[i].quizz = 0; 112 | authors[i].drop = 0; 113 | authors[i].timeout = 0; 114 | authors[i].qidx = 0; //start idx in qoutinfo list 115 | authors[i].start = QLIST_TABLE_SIZE / QUIZZER_NUM * i; 116 | if (i == (QUIZZER_NUM - 1)) 117 | authors[i].end = QLIST_TABLE_SIZE; 118 | else 119 | authors[i].end = QLIST_TABLE_SIZE / QUIZZER_NUM * (i + 1); 120 | memset(authors[i].ip, 0, IP_DATA_LEN); 121 | authors[i].loginfo = malloc(sizeof(struct log_info)); 122 | memset(authors[i].loginfo, 0, sizeof(struct log_info)); 123 | authors[i].loginfo->log_type = TYPE_QUIZZER; 124 | authors[i].loginfo->logfd = create_new_log(s->logpath, i, TYPE_QUIZZER); 125 | for (j = 0; j < AUTH_DB_NUM; j++) 126 | pthread_spin_init(&(authors[i].dblock[j]), 0); 127 | for (j = 0; j < LIST_SPACE; j++) 128 | authors[i].list[j] = NULL; 129 | for (j = 0; j < EP_TCP_FDS; j++) 130 | authors[i].eptcpfds[j].ret = -1; 131 | pthread_spin_init(&authors[i].lock, 0); 132 | authors[i].loginfo->lastlog = global_now; 133 | if (authors[i].cudp < 0 || authors[i].audp < 0) 134 | dns_error(0, "create quizzer2"); 135 | if (pthread_create(apt + i, NULL, run_quizzer, (void *) &(authors[i])) 136 | != 0) 137 | dns_error(0, "create quizzer"); 138 | } 139 | global_out_info->thread_num += i; 140 | 141 | for(i = 0;i < QUIZZER_NUM ;i ++) 142 | { 143 | CPU_ZERO(&cpuinfo); 144 | CPU_SET_S(i + FETCHER_NUM + 1, sizeof(cpuinfo), &cpuinfo); 145 | if(0 != pthread_setaffinity_np(apt[i], sizeof(cpu_set_t), &cpuinfo)) 146 | { 147 | printf("set affinity quizzer failed, may be the cpu cores num less than (FETCHER_NUM + QUIZZER_NUM + 1)\n"); 148 | // exit(0); 149 | } 150 | } 151 | 152 | return 0; 153 | } 154 | 155 | 156 | static int 157 | create_fetcher(struct server *s, int n) 158 | { 159 | int i; 160 | struct fetcher *ws, *tmp; 161 | cpu_set_t cpuinfo; 162 | pthread_t fpt[FETCHER_NUM]; 163 | if (n < 1) 164 | return -1; 165 | ws = malloc(sizeof(struct fetcher) * n); //associated a worker with main thread 166 | if (ws == NULL) 167 | return -1; 168 | memset(ws, 0, sizeof(struct fetcher) * n); 169 | s->fetchers = ws; 170 | for (i = 0; i < n; i++) { 171 | tmp = ws + i; 172 | tmp->s = s; 173 | tmp->idx = i; 174 | tmp->pkg = 0; 175 | tmp->send = 0; 176 | tmp->miss = 0; 177 | tmp->el = &s->eventlist; 178 | tmp->qidx = i % QUIZZER_NUM; 179 | tmp->mc = init_msgcache(100); 180 | if (tmp->mc == NULL) 181 | dns_error(0, "get msgcache"); 182 | tmp->loginfo = malloc(sizeof(struct log_info)); 183 | memset(tmp->loginfo, 0, sizeof(struct log_info)); 184 | tmp->loginfo->lastlog = global_now; 185 | tmp->loginfo->log_type = TYPE_FETCHER; 186 | tmp->loginfo->logfd = create_new_log(s->logpath, i, TYPE_FETCHER); 187 | if (tmp->loginfo->logfd < 0) 188 | dns_error(0, "log file error"); 189 | if (pthread_create(fpt + i, NULL, (void *) run_fetcher, tmp) != 0) 190 | dns_error(0, "init worker"); 191 | } 192 | global_out_info->thread_num += i; 193 | 194 | for(i = 0;i < FETCHER_NUM ;i ++) 195 | { 196 | CPU_ZERO(&cpuinfo); 197 | CPU_SET_S(i + 1, sizeof(cpuinfo), &cpuinfo); 198 | if(0 != pthread_setaffinity_np(fpt[i], sizeof(cpu_set_t), &cpuinfo)) 199 | { 200 | printf("set affinity fetcher failed, may be the cpu cores num less than (FETCHER_NUM + QUIZZER_NUM + 1)\n"); 201 | // exit(0); 202 | } 203 | } 204 | 205 | return 0; 206 | } 207 | 208 | 209 | static struct server * 210 | server_init(void) 211 | { 212 | struct server *s = malloc(sizeof(struct server)); 213 | if (s == NULL) 214 | dns_error(0, "out of memory in server_init"); 215 | s->nfetcher = FETCHER_NUM; 216 | s->nquizzer = QUIZZER_NUM; 217 | s->authors = NULL; 218 | s->fetchers = NULL; 219 | s->pkg = 0; 220 | pthread_spin_init(&s->eventlist.lock, 0); 221 | //pthread_mutex_init(&s->lock,NULL); 222 | s->eventlist.head = NULL; 223 | if ((s->ludp = create_listen_ports(SERVER_PORT, UDP, (uchar *)SRV_ADDR)) < 0) 224 | dns_error(0, "can not open udp"); 225 | set_sock_buff(s->ludp, 10); 226 | if ((s->ltcp = create_listen_ports(SERVER_PORT, TCP, (uchar *)SRV_ADDR)) < 0) 227 | dns_error(0, "can not open tcp"); 228 | s->datasets = 229 | htable_create(NULL, dict_comp_str_equ, HASH_TABLE_SIZE, 230 | MULTI_HASH); 231 | if (s->datasets == NULL) 232 | dns_error(0, "htable create"); 233 | s->forward = htable_create(NULL, dict_comp_str_equ, 1024, 1); 234 | if (s->forward == NULL) 235 | dns_error(0, "create forward"); 236 | s->qlist = 237 | htable_create(NULL, dict_comp_str_equ, 238 | QLIST_TABLE_SIZE, 1); 239 | if (s->qlist == NULL) 240 | dns_error(0, "create qlist"); 241 | s->ttlexp = create_rbtree(rbt_comp_ttl_gt, NULL); 242 | if (s->ttlexp == NULL) 243 | dns_error(0, "create ttl tree"); 244 | s->recordsindb = 0; 245 | s->refreshflag = 0; 246 | s->lastrefresh = global_now; 247 | s->is_forward = 0; 248 | return s; 249 | } 250 | 251 | 252 | void * 253 | time_cron(void *arg) 254 | { 255 | struct server *s = (struct server *) arg; 256 | struct timespec tv = { 0 }; 257 | sigset_t waitset; 258 | siginfo_t info; 259 | int ret; 260 | sigemptyset(&waitset); 261 | sigaddset(&waitset, SIGUSR1); 262 | // pthread_mutex_init(&gnlock, NULL); 263 | global_now = time(NULL); 264 | while (1) { 265 | tv.tv_sec = 1; 266 | tv.tv_nsec = 0; 267 | ret = sigtimedwait(&waitset, &info, &tv); 268 | if (ret > 0) 269 | s->refreshflag = 1; 270 | // pthread_mutex_lock(&gnlock); 271 | // global_now++; 272 | // pthread_mutex_unlock(&gnlock); 273 | //printf("time %lu\n",global_now); 274 | // if ((global_now % 100) == 0) { 275 | // pthread_mutex_lock(&gnlock); 276 | global_now = time(NULL); 277 | // pthread_mutex_unlock(&gnlock); 278 | // } 279 | } 280 | return NULL; 281 | } 282 | 283 | void * 284 | recv_update(void *arg) 285 | { 286 | struct server *s = (struct server *)arg; 287 | start_local_server(s); 288 | return NULL; 289 | } 290 | 291 | int 292 | sanity_test(int exi) 293 | { 294 | //rbtree_test(); 295 | if (exi) 296 | exit(0); 297 | return 0; 298 | } 299 | 300 | 301 | int 302 | print_basic_debug(void) 303 | { 304 | printf("[DBG:] dnspod-sr is successfully running now!!\n"); 305 | printf("[DBG:] max_ele_size is %u - 1808\n", MAX_ELE_NUM); 306 | printf("[DBG:] server may contain %u useful records\n", 307 | (MAX_ELE_NUM - 1808) / 3); 308 | printf("[DBG:] hash_table_size is %u\n", HASH_TABLE_SIZE); 309 | printf("[DBG:] we have %u hash tables\n", MULTI_HASH); 310 | printf("[DBG:] we have %u fetchers,%u quizzers\n", FETCHER_NUM, 311 | QUIZZER_NUM); 312 | return 0; 313 | } 314 | 315 | 316 | void 317 | help(const char *progname) 318 | { 319 | printf("DNSPod recursive dns server\n"); 320 | printf("version 0.01\n"); 321 | printf("Usage: %s [-c config]\n", progname); 322 | } 323 | 324 | int init_globe() 325 | { 326 | int shmid; 327 | shmid = shmget(SHM_KEY, sizeof(struct global_query_info), IPC_CREAT|0600|IPC_PRIVATE); 328 | if (shmid < 0) { 329 | printf("%lu\n", SHM_KEY + sizeof(struct global_query_info)); 330 | perror("shmget"); 331 | dns_error(0, "shmget error"); 332 | } 333 | global_out_info = (struct global_query_info *)shmat(shmid, NULL, 0); 334 | memset(global_out_info, 0, sizeof(struct global_query_info)); 335 | global_out_info->thread_num = 0; 336 | int i; 337 | for (i = 0; i < sizeof(query_type_map) / sizeof(int); ++i) 338 | { 339 | query_type_map[i] = -1; 340 | } 341 | query_type_map[A] = 0; 342 | query_type_map[NS] = 1; 343 | query_type_map[CNAME] = 2; 344 | query_type_map[SOA] = 3; 345 | query_type_map[MX] = 4; 346 | query_type_map[TXT] = 5; 347 | query_type_map[AAAA] = 6; 348 | query_type_map[SRV] = 7; 349 | query_type_map[ANY] = 8; 350 | return 0; 351 | } 352 | 353 | void init_mempool() 354 | { 355 | int ret; 356 | ret = mempool_create(MEMPOOL_SIZE); 357 | if (ret < 0) 358 | dns_error(0, "create mempool failed"); 359 | } 360 | 361 | int 362 | main(int argc, char **argv) 363 | { 364 | struct server *s = NULL; 365 | pthread_t pt, ctl; 366 | int c, is_forward = 0; 367 | const char *config = SR_CONFIG_FILE; 368 | int daemon = 0; 369 | while ((c = getopt(argc,argv,"c:vhfd")) != -1) 370 | { 371 | switch(c) 372 | { 373 | case 'c': 374 | config = optarg; 375 | break; 376 | case 'h': 377 | help(argv[0]); 378 | exit(0); 379 | break; 380 | case 'f': 381 | is_forward = 1; 382 | break; 383 | case 'd': 384 | daemon = 1; 385 | break; 386 | case '?': 387 | printf("Try -h please\n"); 388 | exit(0); 389 | break; 390 | case 'v': 391 | printf("dnspod-sr 0.01\n"); 392 | exit(0); 393 | break; 394 | default: 395 | exit(0); 396 | break; 397 | } 398 | } 399 | sanity_test(0); 400 | drop_privilege("./"); 401 | daemonrize(daemon); 402 | trig_signals(1); 403 | global_now = time(NULL); //for read root.z 404 | g_nameservers[0] = g_nameservers[1] = NULL; 405 | init_globe(); 406 | init_mempool(); 407 | s = server_init(); 408 | s->is_forward = is_forward; 409 | read_config(config, (char *)s->logpath, s->forward, g_nameservers); 410 | // add default dns server 8.8.8.8, 114.114.114.114 411 | if (g_nameservers[0] == NULL) { 412 | assert(g_nameservers[1] == NULL); 413 | g_nameservers[0] = strdup("119.29.29.29"); 414 | g_nameservers[1] = strdup("8.8.4.4"); 415 | } 416 | if (g_nameservers[1] == NULL) { 417 | if (strcmp(g_nameservers[0], "119.29.29.29") == 0) { 418 | g_nameservers[1] = strdup("8.8.4.4"); 419 | } else { 420 | g_nameservers[1] = strdup("119.29.29.29"); 421 | } 422 | } 423 | // 424 | if (create_fetcher(s, s->nfetcher) < 0) 425 | dns_error(0, "create worker"); 426 | if (create_author(s, s->nquizzer) < 0) 427 | dns_error(0, "create author"); 428 | if (pthread_create(&pt, NULL, (void *) time_cron, s) != 0) 429 | dns_error(0, "time cron error"); 430 | if (pthread_create(&ctl, NULL, (void *)recv_update, s) != 0) { 431 | dns_error(0, "recv update thread error"); 432 | } 433 | read_root(s->datasets, s->ttlexp); 434 | print_basic_debug(); 435 | global_serv = s; 436 | run_sentinel(s); 437 | return 0; 438 | } 439 | -------------------------------------------------------------------------------- /src/io.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2006-2012, DNSPod Inc. 2 | * All rights reserved. 3 | 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright notice, 10 | * this list of conditions and the following disclaimer in the documentation 11 | * and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | * The views and conclusions contained in the software and documentation are those 25 | * of the authors and should not be interpreted as representing official policies, 26 | * either expressed or implied, of the FreeBSD Project. 27 | */ 28 | 29 | 30 | #include "io.h" 31 | #include "config.h" 32 | 33 | //standard format support only 34 | //name,ttl,type,data 35 | 36 | 37 | extern int add_query_info(int log_type, int idx, uint16_t type); 38 | 39 | uchar * 40 | jump_space(uchar * itor) 41 | { 42 | //close current string and jump to begin of next string 43 | int t = 100; 44 | while (itor[0] != ' ' && itor[0] != '\t' && t--) 45 | itor++; 46 | itor[0] = 0; // close the string. 47 | itor++; 48 | while (itor[0] == ' ' || itor[0] == '\t') { 49 | itor++; 50 | if (t-- == 0) { 51 | printf("error line in file\n"); 52 | return NULL; 53 | } 54 | } 55 | return itor; 56 | } 57 | 58 | 59 | //ftp://ftp.internic.net/domain/root.zone 60 | //support type 61 | //A, 62 | //NS, 63 | //CNAME, 64 | //SOA, 65 | //MX, 66 | //TXT, 67 | //AAAA, 68 | //SRV 69 | int 70 | read_records_from_file(const char * fn, struct htable *ds, 71 | struct rbtree *rbt, int hijack) 72 | { 73 | FILE *fd = NULL; 74 | uchar vbuffer[5000] = { 0 }, ipv4[4], ipv6[16]; 75 | uchar rbuffer[1024] = { 0 }; 76 | uchar tmpdomain[256] = ".", tmptype[10] = "NS"; 77 | uchar *ps[5] = { 0 }; 78 | uchar *ritor = NULL; 79 | uchar *vitor = vbuffer; 80 | int tmplen = 0, type = 0, i/*, seg = 0*/; 81 | uchar *kbuffer;//[256] = { 0 }; 82 | uint ttl = 0, tmpttl = 0; 83 | int dlen; 84 | struct mvalue *mv = (struct mvalue *) vbuffer; 85 | //uint vallen = sizeof(struct mvalue); 86 | packet_type lowerdomain, lowerns; 87 | 88 | if (ds == NULL) 89 | dns_error(0, "datasets null"); 90 | if ((fd = fopen(fn, "r")) == NULL) { 91 | fprintf(stderr, "open file %s error\n", fn); 92 | perror("fopen"); 93 | dns_error(0, "open file root.z"); 94 | } 95 | kbuffer = lowerdomain.domain; 96 | mv->num = 0; 97 | mv->ttl = 0; 98 | mv->len = 0; 99 | mv->seg = 0; 100 | vitor = vbuffer + sizeof(struct mvalue); 101 | 102 | while (fgets((char *)rbuffer, 1024, fd) != NULL) { 103 | ritor = rbuffer; 104 | ps[0] = ritor; 105 | for (i = 1; i < 5; i++) { 106 | ritor = jump_space(ritor); 107 | ps[i] = ritor; 108 | } 109 | to_lowercase(ps[0], strlen((const char *)ps[0]) + 1); 110 | fix_tail((char *)ps[4]); //drop the \n and \r 111 | tmpttl = atoi((const char *)ps[1]); 112 | ttl = tmpttl + global_now; // 600 + now 113 | if (tmpttl >= MAX_TTL + 1) // > max + 1,already added now 114 | ttl = tmpttl; // == max + 1,never expired 115 | if (tmpttl == NEVER_EXPIRED1) //special value in root.z, never expired. 116 | ttl = MAX_TTL + 1; 117 | if (tmpttl == NEVER_EXPIRED2) 118 | ttl = MAX_TTL + 1; 119 | if ((strcmp((const char *)ps[0], (const char *)tmpdomain) != 0) 120 | || (strcmp((const char *)ps[3], (const char *)tmptype) != 0)) { 121 | if (strcmp((const char *)tmptype, "NS") == 0) 122 | type = NS; 123 | else if (strcmp((const char *)tmptype, "A") == 0) 124 | type = A; 125 | else if (strcmp((const char *)tmptype, "AAAA") == 0) 126 | type = AAAA; 127 | if (strcmp((const char *)tmptype, "CNAME") == 0) 128 | type = CNAME; 129 | dlen = strlen((const char *)tmpdomain) + 1; 130 | if (dlen > 1) { 131 | str_to_len_label(tmpdomain, dlen); 132 | // make_type_domain((uchar *)tmpdomain, dlen, type, 133 | // kbuffer); 134 | // memcpy(kbuffer, tmpdomain, dlen); 135 | check_dns_name(tmpdomain, &lowerdomain); 136 | insert_kv_mem(rbt, ds, kbuffer, dlen, type, vbuffer, 137 | mv->len + sizeof(struct mvalue), hijack, &lowerdomain); //key value 138 | } 139 | memcpy(tmptype, ps[3], strlen((const char *)ps[3]) + 1); 140 | memcpy(tmpdomain, ps[0], strlen((const char *)ps[0]) + 1); 141 | vitor = vbuffer + sizeof(struct mvalue); 142 | mv->num = 0; 143 | mv->ttl = 0; 144 | mv->len = 0; 145 | mv->seg = 0; 146 | } 147 | if (ttl > mv->ttl) 148 | mv->ttl = ttl; 149 | if (strcmp((const char *)ps[3], "NS") == 0 || strcmp((const char *)ps[3], "CNAME") == 0) { 150 | // to_lowercase((uchar *)ps[4], strlen(ps[4]) + 1); 151 | str_to_len_label(ps[4], strlen((const char *)ps[4]) + 1); 152 | tmplen = check_dns_name(ps[4], &lowerns); 153 | if (tmplen > 0) { 154 | memcpy(vitor, lowerns.domain, tmplen); 155 | vitor += tmplen; 156 | mv->len += tmplen; 157 | mv->num++; 158 | } 159 | } else if (strcmp((const char *)ps[3], "A") == 0) { 160 | str_to_uchar4((const char *)ps[4], ipv4); 161 | memcpy(vitor, ipv4, 4); 162 | vitor += 4; 163 | mv->len += 4; 164 | mv->num++; 165 | } else if (strcmp((const char *)ps[3], "AAAA") == 0) { 166 | str_to_uchar6(ps[4], ipv6); 167 | memcpy(vitor, ipv6, 16); 168 | vitor += 16; 169 | mv->len += 16; 170 | mv->num++; 171 | } 172 | //else 173 | //printf("error type %s\n",ps[3]); 174 | } 175 | if (strcmp((const char *)tmptype, "NS") == 0) 176 | type = NS; 177 | if (strcmp((const char *)tmptype, "A") == 0) 178 | type = A; 179 | if (strcmp((const char *)tmptype, "AAAA") == 0) 180 | type = AAAA; 181 | dlen = strlen((const char *)tmpdomain) + 1; 182 | if (dlen > 1) { 183 | str_to_len_label(tmpdomain, dlen); 184 | // make_type_domain((uchar *)tmpdomain, dlen, type, 185 | // kbuffer); 186 | check_dns_name(tmpdomain, &lowerdomain); 187 | insert_kv_mem(rbt, ds, kbuffer, dlen, type, vbuffer, 188 | mv->len + sizeof(struct mvalue), hijack, &lowerdomain); //key value 189 | } 190 | fclose(fd); 191 | return 0; 192 | } 193 | 194 | 195 | int 196 | read_root(struct htable *ds, struct rbtree *rbt) 197 | { 198 | return read_records_from_file(SR_ROOT_FILE, ds, rbt, 0); 199 | } 200 | 201 | 202 | int 203 | refresh_records(struct htable *ds, struct rbtree *rbt) 204 | { 205 | printf("read from records.z\n"); 206 | return read_records_from_file(SR_RECORDS_FILE, ds, rbt, 1); 207 | } 208 | 209 | 210 | int 211 | create_transfer_point(uchar * name, struct htable *fwd, int n) 212 | { 213 | int i = -1, dlen, ret; 214 | uchar ipv4[4] = { 0 }, *addr = NULL, *itor; 215 | // uchar kbuffer[256] = { 0 }; 216 | uchar vbuffer[1000] = { 0 }; 217 | uchar *v = NULL; 218 | hashval_t hash = 0; 219 | dlen = strlen((const char *)name) + 1; 220 | str_to_len_label(name, dlen); 221 | // make_type_domain(name, dlen, A, kbuffer); //forward ip 222 | addr = name + dlen; 223 | struct mvalue *mv = (struct mvalue *) vbuffer; 224 | mv->num = 0; 225 | mv->ttl = MAX_TTL + 1; 226 | mv->len = 0; //not include the struct itself 227 | itor = vbuffer + sizeof(struct mvalue); 228 | for (i = 0; i < n; i++) { 229 | str_to_uchar4((const char *)addr, ipv4); 230 | memcpy(itor, ipv4, 4); 231 | addr = addr + strlen((const char *)addr) + 1; 232 | itor += 4; 233 | mv->len += 4; 234 | mv->num++; 235 | if (addr[0] == 0) 236 | break; 237 | } 238 | v = malloc(mv->len + sizeof(struct mvalue)); 239 | memcpy(v, vbuffer, mv->len + sizeof(struct mvalue)); 240 | ret = htable_insert(fwd, name, dlen, A, v, 0, NULL, &hash); 241 | assert(ret == HTABLE_INSERT_RET_NORMAL); 242 | return 0; 243 | } 244 | 245 | 246 | int read_resolve(FILE * fd, char **nameservers, int n) 247 | { 248 | char buf[1024] = {0}, *tmp = NULL; 249 | int i = 0; 250 | char placeholder[128] = {0}; 251 | char temp[32] = {0}; 252 | if (fd == NULL || n <= 0) { 253 | return -1; 254 | } 255 | i = 0; 256 | 257 | while (fgets(buf, 1024, fd) != NULL) { 258 | fix_tail(buf); 259 | if (buf[0] == ':') { 260 | break; 261 | } 262 | tmp = strstr(buf, "nameserver"); 263 | if (!tmp) { 264 | continue; 265 | } 266 | if (i + 1 > n) { 267 | continue; 268 | } 269 | memset(placeholder, 0, 128); 270 | memset(temp, 0, 32); 271 | sscanf(buf, "%s %s", placeholder, temp); 272 | // 255.255.255.255 15 273 | // 1.1.1.1 7 274 | if (strlen(temp) > 15 || strlen(temp) < 7) { 275 | continue; 276 | } 277 | nameservers[i++] = strdup(temp); 278 | } 279 | return i; 280 | } 281 | 282 | int 283 | read_logpath(FILE * fd, char * path) 284 | { 285 | if (fgets(path, 512, fd) == NULL) 286 | memcpy(path, "/var/dnspod-sr/log/", 20); // if open failed, set ./ again 287 | fix_tail(path); 288 | if (mkdir(path, 0755) != 0) { 289 | if (errno == EEXIST) { 290 | return 0; 291 | } else { 292 | dns_error(0, "create log parent dir failed"); 293 | } 294 | } 295 | 296 | return 0; 297 | } 298 | 299 | 300 | int 301 | read_transfer(FILE * fd, struct htable *fwd) 302 | { 303 | char buf[1024] = { 0 }, *tmp = NULL; 304 | int i, n; 305 | if (fd == NULL || fwd == NULL) 306 | return -1; 307 | while (fgets(buf, 1024, fd) != NULL) { 308 | fix_tail(buf); 309 | if (buf[0] == ':') 310 | break; //end 311 | tmp = strstr(buf, ":"); 312 | if (tmp != NULL) { 313 | tmp[0] = 0; // drop : 314 | tmp++; 315 | n = 1; 316 | for (i = 0; i < 8; i++) { 317 | tmp = strstr(tmp, ","); 318 | if (tmp == NULL) 319 | break; 320 | else { 321 | n++; 322 | tmp[0] = 0; //drop , 323 | tmp++; 324 | } 325 | } 326 | if (i != 8) //too more ips 327 | create_transfer_point((uchar *)buf, fwd, n); 328 | } 329 | } 330 | return 0; 331 | } 332 | 333 | 334 | int 335 | read_config(const char *fn, char * logpath, struct htable *forward, char **nameservers) 336 | { 337 | FILE *fd = NULL; 338 | char buf[1024] = {0}; 339 | if (fn == NULL) { 340 | return -1; 341 | } 342 | if ((fd = fopen(fn, "r")) == NULL) { 343 | return -1; 344 | } 345 | while (fgets(buf, 1024, fd) != NULL) { 346 | fix_tail(buf); 347 | if (strcmp(buf, "xfer:") == 0) { 348 | read_transfer(fd, forward); 349 | continue; 350 | } 351 | if (strcmp(buf, "log_path:") == 0) { 352 | read_logpath(fd, logpath); 353 | continue; 354 | } 355 | if (strcmp(buf, "resolve:") == 0) { 356 | read_resolve(fd, nameservers, 2); 357 | continue; 358 | } 359 | } 360 | fclose(fd); 361 | return 0; 362 | } 363 | 364 | 365 | int 366 | fill_domain_to_len_label(const char *from, char *to) 367 | { 368 | int len = 0; 369 | const char *itor = from; 370 | if (itor[0] == 0) { 371 | to[0] = '.'; 372 | return 1; 373 | } 374 | while (itor[0] != 0) { 375 | memcpy(to, itor + 1, itor[0]); 376 | to += itor[0]; 377 | len += itor[0]; 378 | itor = itor + itor[0] + 1; 379 | to[0] = '.'; 380 | to++; 381 | len++; 382 | } 383 | return len; 384 | } 385 | 386 | 387 | //domain, query domain 388 | //type, query type 389 | //addr, client addr 390 | int 391 | write_loginfo_into_file(struct log_info *log, const uchar * domain, int dlen, int type, 392 | struct sockaddr_in *addr) 393 | { 394 | /* char buffer[600] = { 0 }; */ 395 | /* char *itor; */ 396 | uchar tp = type % 256; 397 | /* itor = buffer; */ 398 | int fd = log->logfd; 399 | int tmplen = 0; 400 | int ret = 0; 401 | if (fd <= 0) 402 | return -1; 403 | if (domain != NULL) { 404 | tmplen = 8 + dlen; 405 | if (log->log_cache_cursor + tmplen >= LOG_CACHE_SIZE) { 406 | ret = write(log->logfd, log->log_cache, log->log_cache_cursor); 407 | if (ret == -1) { 408 | perror("write"); 409 | } 410 | log->log_cache_cursor = 0; 411 | } 412 | if (tmplen >= LOG_CACHE_SIZE) { 413 | return 0; 414 | } else { 415 | log->log_cache[log->log_cache_cursor] = 255; 416 | log->log_cache[log->log_cache_cursor + 1] = tp; 417 | log->log_cache[log->log_cache_cursor + 2] = 2; /* default label_start_num: 2 */ 418 | memcpy(log->log_cache + log->log_cache_cursor + 3, 419 | &(addr->sin_addr.s_addr), sizeof(addr->sin_addr.s_addr)); 420 | memcpy(log->log_cache + log->log_cache_cursor + 3 + sizeof(addr->sin_addr.s_addr), 421 | domain, dlen); 422 | log->log_cache_cursor = log->log_cache_cursor + tmplen; 423 | log->log_cache[log->log_cache_cursor - 1] = '#'; 424 | } 425 | 426 | 427 | /* 428 | * len = fill_domain_to_len_label((const char *)domain, itor); 429 | * itor += len; 430 | * memcpy(itor, &tp, sizeof(uchar)); 431 | * itor += sizeof(uchar); 432 | * if (addr != NULL) { 433 | * //127.0.0.1 would be 0x 7f 00 00 01 434 | * memcpy(itor, &(addr->sin_addr.s_addr), sizeof(ulong)); 435 | * itor += sizeof(struct in_addr); 436 | * } 437 | * write(fd, buffer, itor - buffer); 438 | */ 439 | } 440 | /* write(fd, "\n", 2); */ 441 | return 0; 442 | } 443 | 444 | 445 | //0001111111.log 446 | //1221111111.log 447 | //first bit 0 or 1 means fetcher or quizzer 448 | //second and third bits means idx 449 | //last bits means time 450 | int 451 | create_new_log(uchar * prefix, int idx, int type) 452 | { 453 | static char pf[50] = { 0 }; 454 | char filename[80] = { 0 }; 455 | char final[130] = { 0 }; 456 | int fd = -1, bit, len; 457 | mode_t mode; 458 | time_t prev; 459 | mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; 460 | if (pf[0] == 0) 461 | memcpy(pf, prefix, strlen((const char *)prefix) + 1); 462 | filename[0] = 'f'; 463 | if ((type != TYPE_QUIZZER) && (type != TYPE_FETCHER)) 464 | return -1; 465 | if (type == TYPE_QUIZZER) 466 | filename[0] = 'q'; 467 | bit = idx / 100; 468 | filename[1] = bit + '0'; 469 | bit = (idx % 100) / 10; 470 | filename[2] = bit + '0'; 471 | bit = idx % 10; 472 | filename[3] = bit + '0'; 473 | prev = global_now - (global_now % LOG_INTERVAL); 474 | sprintf(filename + 4, "%lu", prev); 475 | memcpy(filename + strlen(filename), ".log", 5); 476 | len = strlen(pf); 477 | memcpy(final, pf, len); 478 | memcpy(final + len, filename, strlen(filename) + 1); 479 | fd = open(final, O_WRONLY | O_CREAT, mode); 480 | return fd; 481 | } 482 | 483 | 484 | //fetcher 485 | //1.TIME# 486 | //0.name.type.clientip# 487 | //add speed/flow info to the shared mem, in order to looked up by other process 488 | int 489 | write_log(struct log_info *log, int idx, const uchar * domain, int dlen, 490 | int type, struct sockaddr_in *addr) 491 | { 492 | add_query_info(log->log_type, idx, type); 493 | int lfd = log->logfd; 494 | if (((global_now % LOG_INTERVAL) == 0) && (global_now > (log->lastlog))) { 495 | close(lfd); 496 | lfd = create_new_log(NULL, idx, log->log_type); 497 | log->logfd = lfd; 498 | } 499 | write_loginfo_into_file(log, domain, dlen, type, addr); 500 | log->lastlog = global_now; 501 | return 0; 502 | } 503 | -------------------------------------------------------------------------------- /src/utils.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2006-2012, DNSPod Inc. 2 | * All rights reserved. 3 | 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright notice, 10 | * this list of conditions and the following disclaimer in the documentation 11 | * and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | * The views and conclusions contained in the software and documentation are those 25 | * of the authors and should not be interpreted as representing official policies, 26 | * either expressed or implied, of the FreeBSD Project. 27 | */ 28 | 29 | 30 | #include "utils.h" 31 | #include "author.h" 32 | 33 | int 34 | slog(uchar * msg, int fd, pthread_spinlock_t * lock) 35 | { 36 | return 0; 37 | } 38 | 39 | 40 | //get random things 41 | int 42 | get_random_data(uchar * buffer, int len) 43 | { 44 | int fd = -1, ret = 0; 45 | if ((buffer == NULL) || (len < 0)) 46 | return -1; 47 | fd = open("/dev/urandom", O_RDONLY); 48 | if (fd <= 0) 49 | return fd; 50 | ret = read(fd, buffer, len); 51 | if (ret == -1) { 52 | perror("read"); 53 | } 54 | close(fd); 55 | return 0; 56 | } 57 | 58 | 59 | //get a c string 60 | //little function,will be replaced by mm sonn. 61 | //-----------------------begin-----------------// 62 | uchar * 63 | get_str(uchar * str, int len) 64 | { 65 | uchar *ret = malloc(len + 1); 66 | strncpy((char *)ret, (char *)str, len + 1); 67 | ret[len] = 0; 68 | return ret; 69 | } 70 | 71 | 72 | //free it 73 | void 74 | put_str(uchar * str) 75 | { 76 | free((void *) str); 77 | } 78 | 79 | //----------------------end---------------------// 80 | 81 | int flush_all_to_disk(struct server *s) 82 | { 83 | int i, ret; 84 | struct log_info *log = NULL; 85 | for (i = 0; i < s->nfetcher; i++) { 86 | /* write(log->logfd, log->log_cache, log->log_cache_cursor); */ 87 | /* s->fetchers[i] */ 88 | log = s->fetchers[i].loginfo; 89 | ret = write(log->logfd, log->log_cache, log->log_cache_cursor); 90 | if (ret == -1) { 91 | perror("write"); 92 | } 93 | log->log_cache_cursor = 0; 94 | close(log->logfd); 95 | } 96 | for (i = 0; i < s->nquizzer; i++) { 97 | log = s->authors[i].loginfo; 98 | ret = write(log->logfd, log->log_cache, log->log_cache_cursor); 99 | if (ret == -1) { 100 | perror("write"); 101 | } 102 | log->log_cache_cursor = 0; 103 | close(log->logfd); 104 | } 105 | 106 | return 0; 107 | } 108 | 109 | 110 | //signal handler,be enhenced soon. 111 | //---------------------system func begin---------------// 112 | static void 113 | sig_segment_fault(int signo) 114 | { 115 | printf("sig number is %d\n", signo); 116 | flush_all_to_disk(global_serv); 117 | exit(0); 118 | } 119 | 120 | 121 | //spider and author and 122 | //main thread may have 123 | //different handlers 124 | int 125 | trig_signals(int sig) 126 | { 127 | sigset_t bset, oset; 128 | int sigs[] = { SIGINT, SIGBUS, SIGSEGV, SIGPIPE, }, i, sig_num; 129 | struct sigaction sa, oa; 130 | memset(&sa, 0, sizeof(sa)); 131 | sa.sa_handler = sig_segment_fault; 132 | sa.sa_flags = SA_RESTART; 133 | for (i = 0; i < sizeof(sigs) / sizeof(sigs[0]); i++) { 134 | sig_num = sigs[i]; 135 | sigaction(sig_num, &sa, &oa); 136 | } 137 | sigemptyset(&bset); 138 | sigaddset(&bset, SIGUSR1); 139 | if (pthread_sigmask(SIG_BLOCK, &bset, &oset) != 0) 140 | dns_error(0, "sig error"); 141 | return 0; 142 | } 143 | 144 | 145 | void 146 | drop_privilege(char * root) 147 | { 148 | if (root == NULL) 149 | return; 150 | //chroot(root); 151 | } 152 | 153 | //------------------system func end--------------------------// 154 | 155 | 156 | //for dict 157 | //-------------------compare func begin---------------------// 158 | int 159 | dict_comp_uint_equ(void *a, void *b) 160 | { 161 | uint *u1 = a; 162 | uint *u2 = b; 163 | if (u1 == NULL) 164 | return -1; 165 | if (u2 == NULL) 166 | return 1; 167 | if (*u1 == *u2) 168 | return 0; 169 | return u1 > u2 ? 1 : -1; 170 | } 171 | 172 | 173 | int 174 | dict_comp_str_equ(void *a, void *b) 175 | { 176 | uchar *d1 = a; 177 | uchar *d2 = b; 178 | int to = 256; 179 | if (d1 == NULL) 180 | return -1; 181 | if (d2 == NULL) 182 | return 1; 183 | while (*d1 != 0 && *d2 != 0) { 184 | if (*d1 > *d2) 185 | return 1; 186 | if (*d1 < *d2) 187 | return -1; 188 | d1++; 189 | d2++; 190 | if (to-- == 0) //maybe an invalid string 191 | { 192 | printf("str compare error\n"); 193 | exit(0); 194 | } 195 | } 196 | if (*d1 == 0 && *d2 == 0) 197 | return 0; 198 | if (*d1 == 0) 199 | return -1; 200 | return 1; 201 | } 202 | 203 | 204 | //if elems put in the same time 205 | //the one who has bigger idx will be bigger. 206 | int 207 | rbt_comp_ttl_gt(void *v1, void *v2, void *argv) 208 | { 209 | int ret; 210 | //argv not used 211 | struct ttlnode *n1, *n2; 212 | //if v1=v2=null. v1 > v2 by default. 213 | if (v2 == NULL) 214 | return 1; 215 | if (v1 == NULL) //v1 is null,v2 not null. 216 | return -1; 217 | n1 = (struct ttlnode *) v1; 218 | n2 = (struct ttlnode *) v2; 219 | if (n1->exp > n2->exp) 220 | return 1; 221 | if (n1->exp < n2->exp) 222 | return -1; 223 | if (n1->type > n2->type) 224 | return 1; 225 | if (n1->type < n2->type) 226 | return -1; 227 | ret = dict_comp_str_equ(n1->data, n2->data); 228 | if (ret > 0) 229 | return 1; 230 | if (ret < 0) 231 | return -1; 232 | return 0; 233 | } 234 | 235 | 236 | int 237 | rbt_comp_uint_gt(void *v1, void *v2, void *argv) 238 | { 239 | //argv not used 240 | uint n1, n2; 241 | //if v1=v2=null. v1 > v2 by default. 242 | if (v2 == NULL) 243 | return 1; 244 | if (v1 == NULL) //v1 is null,v2 not null. 245 | return -1; 246 | n1 = *(uint *) v1; 247 | n2 = *(uint *) v2; 248 | if (n1 == n2) 249 | return 0; 250 | return n1 > n2 ? 1 : -1; 251 | } 252 | 253 | //-----------------compare func end---------------------// 254 | 255 | 256 | //str functions,no error check,no test 257 | //-----------------------str begin----------------------// 258 | 259 | //大小写转换表 260 | unsigned char LowerTable[256] = { 261 | 0X00,0X01,0X02,0X03,0X04,0X05,0X06,0X07,0X08,0X09,0X0A,0X0B,0X0C,0X0D,0X0E,0X0F, 262 | 0X10,0X11,0X12,0X13,0X14,0X15,0X16,0X17,0X18,0X19,0X1A,0X1B,0X1C,0X1D,0X1E,0X1F, 263 | 0X20,0X21,0X22,0X23,0X24,0X25,0X26,0X27,0X28,0X29,0X2A,0X2B,0X2C,0X2D,0X2E,0X2F, 264 | 0X30,0X31,0X32,0X33,0X34,0X35,0X36,0X37,0X38,0X39,0X3A,0X3B,0X3C,0X3D,0X3E,0X3F, 265 | 0X40,0X61,0X62,0X63,0X64,0X65,0X66,0X67,0X68,0X69,0X6A,0X6B,0X6C,0X6D,0X6E,0X6F, 266 | 0X70,0X71,0X72,0X73,0X74,0X75,0X76,0X77,0X78,0X79,0X7A,0X5B,0X5C,0X5D,0X5E,0X5F, 267 | 0X60,0X61,0X62,0X63,0X64,0X65,0X66,0X67,0X68,0X69,0X6A,0X6B,0X6C,0X6D,0X6E,0X6F, 268 | 0X70,0X71,0X72,0X73,0X74,0X75,0X76,0X77,0X78,0X79,0X7A,0X7B,0X7C,0X7D,0X7E,0X7F, 269 | 0X80,0X81,0X82,0X83,0X84,0X85,0X86,0X87,0X88,0X89,0X8A,0X8B,0X8C,0X8D,0X8E,0X8F, 270 | 0X90,0X91,0X92,0X93,0X94,0X95,0X96,0X97,0X98,0X99,0X9A,0X9B,0X9C,0X9D,0X9E,0X9F, 271 | 0XA0,0XA1,0XA2,0XA3,0XA4,0XA5,0XA6,0XA7,0XA8,0XA9,0XAA,0XAB,0XAC,0XAD,0XAE,0XAF, 272 | 0XB0,0XB1,0XB2,0XB3,0XB4,0XB5,0XB6,0XB7,0XB8,0XB9,0XBA,0XBB,0XBC,0XBD,0XBE,0XBF, 273 | 0XC0,0XC1,0XC2,0XC3,0XC4,0XC5,0XC6,0XC7,0XC8,0XC9,0XCA,0XCB,0XCC,0XCD,0XCE,0XCF, 274 | 0XD0,0XD1,0XD2,0XD3,0XD4,0XD5,0XD6,0XD7,0XD8,0XD9,0XDA,0XDB,0XDC,0XDD,0XDE,0XDF, 275 | 0XE0,0XE1,0XE2,0XE3,0XE4,0XE5,0XE6,0XE7,0XE8,0XE9,0XEA,0XEB,0XEC,0XED,0XEE,0XEF, 276 | 0XF0,0XF1,0XF2,0XF3,0XF4,0XF5,0XF6,0XF7,0XF8,0XF9,0XFA,0XFB,0XFC,0XFD,0XFE,0XFF 277 | }; 278 | unsigned char UpperTable[256] = { 279 | 0X00,0X01,0X02,0X03,0X04,0X05,0X06,0X07,0X08,0X09,0X0A,0X0B,0X0C,0X0D,0X0E,0X0F, 280 | 0X10,0X11,0X12,0X13,0X14,0X15,0X16,0X17,0X18,0X19,0X1A,0X1B,0X1C,0X1D,0X1E,0X1F, 281 | 0X20,0X21,0X22,0X23,0X24,0X25,0X26,0X27,0X28,0X29,0X2A,0X2B,0X2C,0X2D,0X2E,0X2F, 282 | 0X30,0X31,0X32,0X33,0X34,0X35,0X36,0X37,0X38,0X39,0X3A,0X3B,0X3C,0X3D,0X3E,0X3F, 283 | 0X40,0X41,0X42,0X43,0X44,0X45,0X46,0X47,0X48,0X49,0X4A,0X4B,0X4C,0X4D,0X4E,0X4F, 284 | 0X50,0X51,0X52,0X53,0X54,0X55,0X56,0X57,0X58,0X59,0X5A,0X5B,0X5C,0X5D,0X5E,0X5F, 285 | 0X60,0X41,0X42,0X43,0X44,0X45,0X46,0X47,0X48,0X49,0X4A,0X4B,0X4C,0X4D,0X4E,0X4F, 286 | 0X50,0X51,0X52,0X53,0X54,0X55,0X56,0X57,0X58,0X59,0X5A,0X7B,0X7C,0X7D,0X7E,0X7F, 287 | 0X80,0X81,0X82,0X83,0X84,0X85,0X86,0X87,0X88,0X89,0X8A,0X8B,0X8C,0X8D,0X8E,0X8F, 288 | 0X90,0X91,0X92,0X93,0X94,0X95,0X96,0X97,0X98,0X99,0X9A,0X9B,0X9C,0X9D,0X9E,0X9F, 289 | 0XA0,0XA1,0XA2,0XA3,0XA4,0XA5,0XA6,0XA7,0XA8,0XA9,0XAA,0XAB,0XAC,0XAD,0XAE,0XAF, 290 | 0XB0,0XB1,0XB2,0XB3,0XB4,0XB5,0XB6,0XB7,0XB8,0XB9,0XBA,0XBB,0XBC,0XBD,0XBE,0XBF, 291 | 0XC0,0XC1,0XC2,0XC3,0XC4,0XC5,0XC6,0XC7,0XC8,0XC9,0XCA,0XCB,0XCC,0XCD,0XCE,0XCF, 292 | 0XD0,0XD1,0XD2,0XD3,0XD4,0XD5,0XD6,0XD7,0XD8,0XD9,0XDA,0XDB,0XDC,0XDD,0XDE,0XDF, 293 | 0XE0,0XE1,0XE2,0XE3,0XE4,0XE5,0XE6,0XE7,0XE8,0XE9,0XEA,0XEB,0XEC,0XED,0XEE,0XEF, 294 | 0XF0,0XF1,0XF2,0XF3,0XF4,0XF5,0XF6,0XF7,0XF8,0XF9,0XFA,0XFB,0XFC,0XFD,0XFE,0XFF 295 | }; 296 | 297 | // extern unsigned char LowerTable[256]; 298 | // extern unsigned char UpperTable[256]; 299 | // #define TOLOWER(_ch) LowerTable[((unsigned char)_ch)] 300 | // #define TOUPPER(_ch) UpperTable[((unsigned char)_ch)] 301 | 302 | int 303 | to_lowercase(uchar * msg, int len) 304 | { 305 | int i; 306 | for (i = 0; i < len; i++) 307 | msg[i] = TOLOWER(msg[i]); 308 | // if (msg[i] >= 'A' && msg[i] <= 'Z') 309 | // msg[i] = msg[i] + 'a' - 'A'; 310 | return 0; 311 | } 312 | 313 | int 314 | to_uppercase(uchar * buf, int n) 315 | { 316 | int i; 317 | for (i = 0; i < n; i++) { 318 | buf[i] = TOUPPER(buf[i]); 319 | // if (buf[i] >= 'a' && buf[i] <= 'z') 320 | // buf[i] = buf[i] + 'A' - 'a'; 321 | } 322 | return 0; 323 | } 324 | 325 | 326 | int 327 | str_to_uchar4(const char *addr, uchar * val) 328 | { 329 | uint tv[4] = { 0 }, idx = 0; 330 | int i, n = strlen(addr); 331 | for (i = 0; i < n; i++) { 332 | if (addr[i] >= '0' && addr[i] <= '9') 333 | tv[idx] = tv[idx] * 10 + addr[i] - '0'; 334 | else { 335 | idx++; 336 | if (addr[i] != '.' || idx == 4) //format error 337 | { 338 | *val = 0; 339 | return -1; 340 | } 341 | } 342 | } 343 | for (i = 0; i < 4; i++) 344 | val[i] = tv[i]; 345 | return 0; 346 | } 347 | 348 | 349 | int 350 | str_to_uchar6(uchar * addr, uchar * val) 351 | { 352 | ushort tv[8] = { 0 }; 353 | int idx = 0, gap = 0, gapidx = -1, hasgap = 0; 354 | int i, n = strlen((const char *)addr); 355 | char tmp; 356 | to_lowercase(addr, n); 357 | memset(val, 0, 16); 358 | for (i = 0; i < n; i++) { 359 | tmp = addr[i]; 360 | if (tmp >= '0' && tmp <= '9') { 361 | gap = 0; 362 | tv[idx] = tv[idx] * 16 + tmp - '0'; 363 | } else if (tmp >= 'a' && tmp <= 'z') { 364 | gap = 0; 365 | tv[idx] = tv[idx] * 16 + tmp - 'a' + 10; 366 | } else { 367 | idx++; 368 | if (gap == 1) { 369 | if (hasgap == 1) //format error 370 | return -1; 371 | hasgap = 1; 372 | gapidx = idx - 1; 373 | } 374 | if (gap == 0) 375 | gap = 1; 376 | if (tmp != ':' || idx == 8) { 377 | val[0] = val[1] = val[2] = val[3] = 0; 378 | return 0; 379 | } 380 | } 381 | } 382 | if (hasgap == 1) //we have an gap 383 | { 384 | for (i = 0; i < gapidx; i++) { 385 | val[i * 2] = tv[i] / 256; 386 | val[i * 2 + 1] = tv[i] % 256; 387 | } 388 | for (i = idx - 1; i >= gapidx; i--) { 389 | val[(i + 7 - idx + 1) * 2] = tv[i + 1] / 256; 390 | val[(i + 7 - idx + 1) * 2 + 1] = tv[i + 1] % 256; 391 | } 392 | } else { 393 | for (i = 0; i < 8; i++) { 394 | val[i * 2] = tv[i] / 256; 395 | val[i * 2 + 1] = tv[i] % 256; 396 | } 397 | } 398 | return 0; 399 | } 400 | 401 | 402 | int 403 | fix_tail(char *domain) 404 | { 405 | int len = strlen(domain); 406 | uchar c; 407 | len--; 408 | c = domain[len]; 409 | if (c == '\r' || c == '\n') { 410 | domain[len] = 0; 411 | len--; 412 | } 413 | c = domain[len]; 414 | if (c == '\r' || c == '\n') { 415 | domain[len] = 0; 416 | len--; 417 | } 418 | return 0; 419 | } 420 | 421 | //-------------------str end--------------------------// 422 | 423 | 424 | //offset [0,15] 425 | //tested by rbtree_test() in datas.c. 426 | //-------------------bit functions begin-------- 427 | int 428 | opr_bit(unsigned short *bit, int off, int set) 429 | { 430 | unsigned short mask = 1; 431 | if (off > 15 || off < 0) 432 | return -1; 433 | mask <<= off; 434 | if (set == 0) //clear 435 | mask = ~mask; 436 | if (set == 0) 437 | *bit = *bit & mask; 438 | else 439 | *bit = *bit | mask; 440 | return 0; 441 | } 442 | 443 | 444 | int 445 | set_bit(unsigned short *bit, int off) 446 | { 447 | opr_bit(bit, off, 1); 448 | return 0; 449 | } 450 | 451 | 452 | int 453 | clr_bit(unsigned short *bit, int off) 454 | { 455 | opr_bit(bit, off, 0); 456 | return 0; 457 | } 458 | 459 | int 460 | tst_bit(const unsigned short bit, int off) 461 | { 462 | unsigned short mask = 1; 463 | if (off > 15 || off < 0) 464 | return -1; 465 | mask <<= off; 466 | if ((bit & mask) == 0) 467 | return 0; 468 | return 1; 469 | } 470 | 471 | //----------------bit functions end--------------------- 472 | 473 | 474 | //multi threads safe 475 | //test by rbtree_test() in datas.c 476 | int 477 | get_time_usage(struct timeval *tv, int start) 478 | { 479 | ulong msec = 0; 480 | struct timeval tmp; 481 | if (tv == NULL) 482 | return -1; 483 | if (start == 1) //start 484 | gettimeofday(tv, NULL); 485 | else //end 486 | { 487 | tmp = *tv; 488 | gettimeofday(tv, NULL); 489 | if (tv->tv_usec < tmp.tv_usec) { 490 | msec = (tv->tv_usec - tmp.tv_usec + 1000000) / 1000; 491 | tv->tv_sec--; 492 | } 493 | printf("%lu s,%lu ms\n", tv->tv_sec - tmp.tv_sec, msec); 494 | } 495 | return 0; 496 | } 497 | 498 | 499 | //------------trivial function begin--------------------------- 500 | //for debug 501 | 502 | 503 | int 504 | is_uppercase(int c) 505 | { 506 | if (c >= 'A' && c <= 'Z') 507 | return 1; 508 | return 0; 509 | } 510 | 511 | 512 | int 513 | is_lowercase(int c) 514 | { 515 | if (c >= 'a' && c <= 'z') 516 | return 1; 517 | return 0; 518 | } 519 | 520 | 521 | int 522 | empty_function(int i) 523 | { 524 | /* int j; */ 525 | /* j = i; */ 526 | return 0; 527 | } 528 | 529 | 530 | void 531 | insert_mem_bar(void) 532 | { 533 | int i, size = random() % 99 + 10000; 534 | uchar *ptr = malloc(size); 535 | if (ptr == NULL) 536 | return; 537 | for (i = 0; i < size; i++) 538 | ptr[i] = i; 539 | free(ptr); 540 | } 541 | 542 | 543 | int 544 | test_lock(pthread_spinlock_t * l) 545 | { 546 | if (pthread_spin_trylock(l) < 0) 547 | return -1; 548 | pthread_spin_unlock(l); 549 | return 0; 550 | } 551 | 552 | //------------trivial function end------------------------------ 553 | 554 | 555 | //-------------------debug print begin------------------------- 556 | void 557 | dbg_print_bit(unsigned short bit) 558 | { 559 | int i; 560 | unsigned short val = 1 << 15; 561 | for (i = 0; i < 16; i++) { 562 | if ((bit & val) == 0) 563 | printf("0"); 564 | else 565 | printf("1"); 566 | if (((i + 1) % 4) == 0 && (i != 15)) 567 | printf(","); 568 | val = val >> 1; 569 | } 570 | printf("\n"); 571 | } 572 | 573 | 574 | void 575 | print_hex(uchar * val, int n) 576 | { 577 | int i; 578 | for (i = 0; i < n; i++) 579 | printf("%x,", val[i]); 580 | printf("\n"); 581 | } 582 | 583 | 584 | //global error function 585 | void 586 | dns_error(int level, char *msg) 587 | { 588 | dbg("Error:%s\n", msg); 589 | fflush(stdout); 590 | if (level == 0) 591 | exit(-1); 592 | } 593 | 594 | 595 | //output debug infomartion 596 | int 597 | dbg(const char *format, ...) 598 | { 599 | int ret; 600 | va_list ap; 601 | va_start(ap, format); 602 | printf("dbg:"); 603 | ret = vprintf(format, ap); 604 | va_end(ap); 605 | return ret; 606 | } 607 | 608 | //-----------------------debug print end-------------------- 609 | 610 | 611 | hashval_t 612 | uint_hash_function(void *ptr) 613 | { 614 | uint key = *(uint *) ptr; 615 | key += ~(key << 15); 616 | key ^= (key >> 10); 617 | key += (key << 3); 618 | key ^= (key >> 6); 619 | key += ~(key << 11); 620 | key ^= (key >> 16); 621 | return key; 622 | } 623 | 624 | 625 | hashval_t 626 | nocase_char_hash_function(void *argv, int klen) 627 | { 628 | int len = (klen == 2) ? 1 : klen; 629 | uchar *buf = argv; 630 | hashval_t hash = 5381; 631 | // to_lowercase(buf, len); 632 | while (len--) 633 | { 634 | // *buf = TOLOWER(*buf); 635 | hash = (((hash << 5) + hash) + *buf++); 636 | } 637 | return hash; 638 | } 639 | 640 | -------------------------------------------------------------------------------- /next/storage.c: -------------------------------------------------------------------------------- 1 | //dilfish @ dnspod 2 | //20120305 3 | 4 | #include "storage.h" 5 | 6 | //--------------------red black tree--------- 7 | static void 8 | left_rotate(struct rbtree *rbt, struct rbnode *node) 9 | { 10 | struct rbnode *tmp = node->right; 11 | node->right = tmp->left; 12 | if (tmp->left != &rbt->nil) 13 | tmp->left->parent = node; 14 | tmp->parent = node->parent; 15 | if (node->parent == &rbt->nil) 16 | rbt->root = tmp; 17 | else if (node == node->parent->left) 18 | node->parent->left = tmp; 19 | else 20 | node->parent->right = tmp; 21 | tmp->left = node; 22 | node->parent = tmp; 23 | } 24 | 25 | 26 | static void 27 | right_rotate(struct rbtree *rbt, struct rbnode *node) 28 | { 29 | struct rbnode *tmp = node->left; 30 | node->left = tmp->right; 31 | if (tmp->right != &rbt->nil) 32 | tmp->right->parent = node; 33 | tmp->parent = node->parent; 34 | if (node->parent == &rbt->nil) 35 | rbt->root = tmp; 36 | else if (node == node->parent->left) 37 | node->parent->left = tmp; 38 | else 39 | node->parent->right = tmp; 40 | tmp->right = node; 41 | node->parent = tmp; 42 | } 43 | 44 | 45 | static void 46 | insert_fixup(struct rbtree *rbt, struct rbnode *nd) 47 | { 48 | struct rbnode *tmp; 49 | while (nd->parent->color == RED) { 50 | if (nd->parent == nd->parent->parent->left) { 51 | tmp = nd->parent->parent->right; 52 | if (tmp->color == RED) { 53 | nd->parent->color = tmp->color = BLACK; 54 | nd->parent->parent->color = RED; 55 | nd = nd->parent->parent; 56 | } else { 57 | if (nd == nd->parent->right) { 58 | nd = nd->parent; 59 | left_rotate(rbt, nd); 60 | } 61 | nd->parent->color = BLACK; 62 | nd->parent->parent->color = RED; 63 | right_rotate(rbt, nd->parent->parent); 64 | } 65 | } else { 66 | tmp = nd->parent->parent->left; 67 | if (tmp->color == RED) { 68 | nd->parent->color = tmp->color = BLACK; 69 | nd->parent->parent->color = RED; 70 | nd = nd->parent->parent; 71 | } else { 72 | if (nd == nd->parent->left) { 73 | nd = nd->parent; 74 | right_rotate(rbt, nd); 75 | } 76 | nd->parent->color = BLACK; 77 | nd->parent->parent->color = RED; 78 | left_rotate(rbt, nd->parent->parent); 79 | } 80 | } 81 | } 82 | rbt->root->color = BLACK; 83 | } 84 | 85 | 86 | //find_node and delete_node are not safe 87 | //delete node may return NULL. 88 | struct rbnode * 89 | find_node(struct rbtree *rbt, void *key) 90 | { 91 | struct rbnode *nd = &rbt->nil; 92 | int i; 93 | nd = rbt->root; 94 | while (nd != &rbt->nil) { 95 | i = (rbt->c) (nd->key, key); 96 | if (i > 0) 97 | nd = nd->left; 98 | if (i < 0) 99 | nd = nd->right; 100 | if (nd == &rbt->nil) 101 | break; //return null 102 | if (i == 0) 103 | return nd; 104 | } 105 | return NULL; 106 | } 107 | 108 | 109 | int 110 | insert_node(struct rbtree *rbt, struct rbnode *nd) 111 | { 112 | struct rbnode *tmp = &rbt->nil, *itor = rbt->root; 113 | //struct rbnode *nd = malloc(sizeof(struct rbnode)); 114 | nd->left = nd->right = nd->parent = NULL; 115 | //nd->key = key; 116 | while (itor != &rbt->nil) { 117 | tmp = itor; 118 | if ((rbt->c) (itor->key, nd->key) > 0) 119 | itor = itor->left; 120 | else 121 | itor = itor->right; 122 | } 123 | nd->parent = tmp; 124 | if (tmp == &rbt->nil) 125 | rbt->root = nd; 126 | else { 127 | if ((rbt->c) (tmp->key, nd->key) > 0) 128 | tmp->left = nd; 129 | else 130 | tmp->right = nd; 131 | } 132 | nd->left = nd->right = &rbt->nil; 133 | nd->color = RED; 134 | insert_fixup(rbt, nd); 135 | rbt->size++; 136 | return 0; 137 | } 138 | 139 | 140 | static struct rbnode * 141 | rbt_successor(struct rbtree *rbt, struct rbnode *nd) 142 | { 143 | struct rbnode *min = &rbt->nil; 144 | if (nd->right != &rbt->nil) { 145 | min = nd->right; 146 | while (min->left != &rbt->nil) 147 | min = min->left; 148 | return min; 149 | } 150 | min = nd->parent; 151 | while ((min != &rbt->nil) && (nd == min->right)) { 152 | nd = min; 153 | min = min->parent; 154 | } 155 | return min; 156 | } 157 | 158 | 159 | static void 160 | delete_fixup(struct rbtree *rbt, struct rbnode *nd) 161 | { 162 | struct rbnode *tmp = &rbt->nil; 163 | while (nd != rbt->root && nd->color == BLACK) 164 | if (nd == nd->parent->left) { 165 | tmp = nd->parent->right; 166 | if (tmp->color == RED) { 167 | tmp->color = BLACK; 168 | nd->parent->color = RED; 169 | left_rotate(rbt, nd->parent); 170 | tmp = nd->parent->right; 171 | } 172 | if (tmp->left->color == BLACK && tmp->right->color == BLACK) { 173 | tmp->color = RED; 174 | nd = nd->parent; 175 | } else { 176 | if (tmp->right->color == BLACK) { 177 | tmp->left->color = BLACK; 178 | tmp->color = RED; 179 | right_rotate(rbt, tmp); 180 | tmp = nd->parent->right; 181 | } 182 | tmp->color = nd->parent->color; 183 | nd->parent->color = BLACK; 184 | tmp->right->color = BLACK; 185 | left_rotate(rbt, nd->parent); 186 | nd = rbt->root; //end while 187 | } 188 | } else { 189 | tmp = nd->parent->left; 190 | if (tmp->color == RED) { 191 | tmp->color = BLACK; 192 | nd->parent->color = RED; 193 | right_rotate(rbt, nd->parent); 194 | tmp = nd->parent->left; 195 | } 196 | if (tmp->right->color == BLACK && tmp->left->color == BLACK) { 197 | tmp->color = RED; 198 | nd = nd->parent; 199 | } else { 200 | if (tmp->left->color == BLACK) { 201 | tmp->right->color = BLACK; 202 | tmp->color = RED; 203 | left_rotate(rbt, tmp); 204 | tmp = nd->parent->left; 205 | } 206 | tmp->color = nd->parent->color; 207 | nd->parent->color = BLACK; 208 | tmp->left->color = BLACK; 209 | right_rotate(rbt, nd->parent); 210 | nd = rbt->root; //end while 211 | } 212 | } 213 | nd->color = BLACK; 214 | } 215 | 216 | 217 | struct rbnode * 218 | min_node(struct rbtree *rbt) 219 | { 220 | struct rbnode *tmp, *ret; 221 | tmp = rbt->root; 222 | ret = &rbt->nil; 223 | if (tmp == &rbt->nil) 224 | return NULL; 225 | while (tmp != &rbt->nil) { 226 | ret = tmp; 227 | tmp = tmp->left; 228 | } 229 | if (ret == &rbt->nil) 230 | return NULL; 231 | return ret; 232 | } 233 | 234 | 235 | //free node, return val 236 | void * 237 | delete_node(struct rbtree *rbt, void *key) 238 | { 239 | void *val = NULL; 240 | struct rbnode *nd = NULL; 241 | struct rbnode *tmp, *itor; 242 | nd = find_node(rbt, key); 243 | if (nd == NULL || rbt == NULL) { 244 | printf("find node error\n"); 245 | return NULL; 246 | } 247 | val = nd->key; 248 | if (nd->left == &rbt->nil || nd->right == &rbt->nil) 249 | tmp = nd; 250 | else 251 | tmp = rbt_successor(rbt, nd); 252 | if (tmp->left != &rbt->nil) 253 | itor = tmp->left; 254 | else 255 | itor = tmp->right; 256 | itor->parent = tmp->parent; 257 | if (tmp->parent == &rbt->nil) 258 | rbt->root = itor; 259 | else { 260 | if (tmp == tmp->parent->left) 261 | tmp->parent->left = itor; 262 | else 263 | tmp->parent->right = itor; 264 | } 265 | if (tmp != itor) 266 | nd->key = tmp->key; 267 | if (tmp->color == BLACK) 268 | delete_fixup(rbt, itor); 269 | //free(tmp); 270 | rbt->size--; 271 | return tmp; 272 | } 273 | 274 | 275 | struct rbtree * 276 | create_rbtree(comprbt * c) 277 | { 278 | struct rbtree *rbt = malloc(sizeof(struct rbtree)); 279 | if (rbt == NULL) 280 | return NULL; 281 | rbt->c = c; 282 | rbt->size = 0; 283 | rbt->nil.parent = &(rbt->nil); 284 | rbt->nil.left = &(rbt->nil); 285 | rbt->nil.right = &(rbt->nil); 286 | rbt->nil.color = BLACK; 287 | rbt->nil.key = NULL; 288 | rbt->root = &rbt->nil; 289 | return rbt; 290 | } 291 | 292 | 293 | static int 294 | deep_copy(uchar * from, uchar * to, int tlen) //*to is big enough 295 | { 296 | struct mvalue *mv = (struct mvalue *) from; 297 | int sz = mv->len + sizeof(struct mvalue); 298 | if (sz >= tlen) 299 | return -1; 300 | memcpy(to, from, sz); 301 | return sz; 302 | } 303 | 304 | 305 | //murmurhash 306 | hashval_t 307 | murmur(const void *key, int len) 308 | { 309 | uint seed = 0x19871016; 310 | const uint m = 0x5bd1e995, r = 24; 311 | uint h1 = seed ^ len, h2 = 0; 312 | const uint *data = (const uint *) key; 313 | 314 | while (len >= 8) { 315 | uint k1 = *data++; 316 | k1 *= m; 317 | k1 ^= k1 >> r; 318 | k1 *= m; 319 | h1 *= m; 320 | h1 ^= k1; 321 | len -= 4; 322 | 323 | uint k2 = *data++; 324 | k2 *= m; 325 | k2 ^= k2 >> r; 326 | k2 *= m; 327 | h2 *= m; 328 | h2 ^= k2; 329 | len -= 4; 330 | } 331 | 332 | if (len >= 4) { 333 | uint k1 = *data++; 334 | k1 *= m; 335 | k1 ^= k1 >> r; 336 | k1 *= m; 337 | h1 *= m; 338 | h1 ^= k1; 339 | len -= 4; 340 | } 341 | 342 | switch (len) { 343 | case 3: 344 | h2 ^= ((uchar *) data)[2] << 16; 345 | //to through, no break 346 | case 2: 347 | h2 ^= ((uchar *) data)[1] << 8; 348 | case 1: 349 | h2 ^= ((uchar *) data)[0]; 350 | h2 *= m; 351 | } 352 | h1 ^= h2 >> 18; 353 | h1 *= m; 354 | h2 ^= h1 >> 22; 355 | h2 *= m; 356 | h1 ^= h2 >> 17; 357 | h1 *= m; 358 | h2 ^= h1 >> 19; 359 | h2 *= m; 360 | 361 | uint64_t h = h1; 362 | h = (h << 32) | h2; 363 | return h; 364 | } 365 | 366 | 367 | /////////////////////////memory hash///////////////////////////// 368 | struct htable * 369 | htable_create(hashfunc * h, comparefunc * c, int size) 370 | { 371 | int i, j; 372 | struct htable *ht = NULL; 373 | if (c == NULL) 374 | return NULL; 375 | if ((ht = malloc(sizeof(struct htable) * MULTI_HASH)) == NULL) 376 | return NULL; 377 | for (i = 0; i < MULTI_HASH; i++) { 378 | ht[i].h = h; 379 | if (h == NULL) 380 | ht[i].h = murmur; 381 | ht[i].c = c; 382 | ht[i].size = size; 383 | ht[i].now = 0; //no need lock 384 | ht[i].mask = size - 1; 385 | pthread_mutex_init(&(ht[i].lock), NULL); 386 | if ((ht[i].table = 387 | malloc(sizeof(struct hdata) * ht[i].size)) == NULL) { 388 | for (j = 0; j < i; j++) 389 | free(ht[j].table); 390 | free(ht); 391 | return NULL; 392 | } 393 | for (j = 0; j < size; j++) { 394 | ht[i].table[j].list = NULL; 395 | pthread_mutex_init(&(ht[i].table[j].lock), NULL); 396 | } 397 | } 398 | return ht; 399 | } 400 | 401 | 402 | int 403 | htable_find(struct htable *ht, uchar * key, int klen, uchar * buffer, 404 | int vlen) 405 | { 406 | int idx, debug = DEBUG_TIMES, ret, off; 407 | struct hdata *hd = NULL; 408 | struct hentry *he = NULL; 409 | struct mvalue *mx = NULL; 410 | hashval_t h = (ht->h) (key, klen); 411 | idx = h & ht->mask; 412 | off = (h >> 32) & (MULTI_HASH - 1); 413 | ht = ht + off; 414 | hd = ht->table + idx; 415 | pthread_mutex_lock(&hd->lock); 416 | if (hd->list == NULL) { 417 | printf("empty error\n"); 418 | pthread_mutex_unlock(&hd->lock); 419 | return -1; 420 | } 421 | he = hd->list; 422 | while (he != NULL) { 423 | if ((ht->c) (key, he->key) == 0) { 424 | if (buffer != NULL) 425 | ret = deep_copy(he->val, buffer, vlen); 426 | else 427 | ret = 1; //successed 428 | pthread_mutex_unlock(&hd->lock); 429 | if (ret < 0) 430 | printf("copy error\n"); 431 | return ret; 432 | } 433 | he = he->next; 434 | if (debug-- == 0) { 435 | printf("error in htable find\n"); 436 | exit(0); 437 | } 438 | } 439 | pthread_mutex_unlock(&hd->lock); 440 | printf("find nothing\n"); 441 | return -1; 442 | } 443 | 444 | 445 | struct hentry * 446 | htable_delete(struct htable *ht, uchar * key, int klen) 447 | { 448 | hashval_t h = (ht->h) (key, klen); 449 | int debug = DEBUG_TIMES; 450 | uint idx, off; 451 | struct hdata *hd = NULL; 452 | struct hentry *he = NULL, *prev = NULL; 453 | idx = h & ht->mask; 454 | off = (h >> 32) & (MULTI_HASH - 1); 455 | ht = ht + off; 456 | hd = ht->table + idx; 457 | pthread_mutex_lock(&hd->lock); 458 | if (hd->list == NULL) { 459 | pthread_mutex_unlock(&hd->lock); 460 | return NULL; 461 | } 462 | he = hd->list; 463 | if ((ht->c) (key, he->key) == 0) { 464 | hd->list = he->next; 465 | pthread_mutex_unlock(&hd->lock); 466 | pthread_mutex_lock(&ht->lock); 467 | ht->now--; 468 | pthread_mutex_unlock(&ht->lock); 469 | return he; 470 | } 471 | prev = he; 472 | he = he->next; 473 | while (he != NULL) { 474 | if ((ht->c) (key, he->key) == 0) { 475 | prev->next = he->next; 476 | pthread_mutex_unlock(&hd->lock); 477 | pthread_mutex_lock(&ht->lock); 478 | ht->now--; 479 | pthread_mutex_unlock(&ht->lock); 480 | return he; 481 | } 482 | prev = he; 483 | he = he->next; 484 | debug--; 485 | if (debug == 0) { 486 | printf("error in storage\n"); 487 | exit(0); 488 | } 489 | } 490 | pthread_mutex_unlock(&hd->lock); 491 | return NULL; 492 | } 493 | 494 | 495 | //if conllision, replace old element by default. 496 | //if replace is 1, replace it, return 1 497 | //if replace is 0, drop it, return -1 498 | //else return 0 499 | int 500 | htable_insert(struct htable *ht, struct hentry *he, int klen, int rpl) 501 | { 502 | uchar *key = he->key; 503 | uchar *val = he->val; 504 | hashval_t hash; 505 | int ret, debug = DEBUG_TIMES; 506 | uint idx, off; 507 | struct hentry *cl = NULL; 508 | struct hdata *hd = NULL; //slot header 509 | struct mvalue *pt = NULL; //protect root and gtld 510 | pt = (struct mvalue *) val; 511 | if (pt->len > MAX_RECORD_SIZE) 512 | return -1; 513 | hash = ht->h(key, klen); 514 | idx = hash & ht->mask; 515 | off = (hash >> 32) & (MULTI_HASH - 1); 516 | ht = ht + off; 517 | hd = ht->table + idx; 518 | pthread_mutex_lock(&hd->lock); 519 | he->next = NULL; 520 | if (hd->list == NULL) 521 | hd->list = he; 522 | else { 523 | cl = hd->list; 524 | while (cl != NULL) { 525 | if ((ht->c) (cl->key, he->key) == 0) //the exactly same elements 526 | { 527 | printf("dup\n"); 528 | ret = -1; //drop 529 | pthread_mutex_unlock(&hd->lock); 530 | //free(he); 531 | //rbt del 532 | return ret; //replace 533 | } 534 | cl = cl->next; 535 | debug--; 536 | if (debug == 0) { 537 | printf("error in storage2\n"); 538 | exit(0); 539 | } 540 | } 541 | he->next = hd->list; 542 | hd->list = he; 543 | } 544 | pthread_mutex_unlock(&hd->lock); 545 | pthread_mutex_lock(&ht->lock); 546 | ht->now++; 547 | pthread_mutex_unlock(&ht->lock); 548 | return 0; 549 | } 550 | 551 | 552 | int 553 | domain_compare(const void *k1, const void *k2) 554 | { 555 | uchar *itor1 = NULL, *itor2 = NULL; 556 | if (k1 == NULL) 557 | return -1; 558 | if (k2 == NULL) 559 | return 1; 560 | itor1 = (uchar *) k1; 561 | itor2 = (uchar *) k2; 562 | while (itor1[0] != 0) { 563 | if (itor1[0] > itor2[0]) 564 | return 1; 565 | if (itor1[0] < itor2[0]) 566 | return -1; 567 | itor1++; 568 | itor2++; 569 | } 570 | if (itor2[0] != 0) 571 | return -1; 572 | return 0; 573 | } 574 | 575 | 576 | int 577 | compare_ttl(void *t1, void *t2) 578 | { 579 | uint32_t tx1, tx2; 580 | if (t1 == NULL || t2 == NULL) { 581 | printf("fatal error in compare ttl\n"); 582 | exit(0); 583 | } 584 | tx1 = *(uint32_t *) t1; 585 | tx2 = *(uint32_t *) t2; 586 | //printf("tx %u,%u\n",tx1,tx2); 587 | if (t1 > t2) 588 | return 1; 589 | if (t1 == t2) 590 | return 0; 591 | return -1; 592 | } 593 | 594 | 595 | int 596 | record_insert(struct records *r, struct hlp *h) 597 | { 598 | int ret; 599 | struct rbnode *node; 600 | struct hentry *he = NULL; 601 | if (r == NULL || h == NULL) 602 | return -1; 603 | he = malloc(sizeof(struct hentry) + h->len); 604 | if (he == NULL) 605 | return -1; 606 | he->ttl.key = h->ttl; 607 | h->ttl = NULL; 608 | pthread_mutex_lock(&r->lock); //protect rbtree 609 | //printf("insert %d\n",*(uint32_t*)he->ttl.key); 610 | ret = insert_node(r->rbt, &he->ttl); 611 | if (ret < 0) { 612 | free(he); 613 | pthread_mutex_unlock(&r->lock); 614 | return -1; 615 | } 616 | he->val = h->val; 617 | memcpy(he->key, h->key, h->len); 618 | ret = htable_insert(r->ht, he, h->len, 0); 619 | if (ret < 0) { 620 | node = delete_node(r->rbt, &h->ttl); 621 | if (node == NULL) { 622 | printf("fatal error\n"); 623 | exit(0); 624 | } 625 | free(he); 626 | } 627 | pthread_mutex_unlock(&r->lock); 628 | return 0; 629 | } 630 | 631 | 632 | int 633 | record_find(struct records *r, struct hlp *h) 634 | { 635 | return htable_find(r->ht, h->key, h->len, h->val, h->vlen); 636 | } 637 | 638 | 639 | int 640 | record_delete(struct records *r, struct hlp *h) 641 | { 642 | int ret; 643 | struct rbnode *nd, *node; 644 | struct hentry *he = NULL; 645 | pthread_mutex_lock(&r->lock); 646 | he = htable_delete(r->ht, h->key, h->len); 647 | if (he == NULL) { 648 | pthread_mutex_unlock(&r->lock); 649 | return -1; 650 | } 651 | nd = (struct rbnode *) he; 652 | node = delete_node(r->rbt, nd->key); 653 | if (node == NULL) { 654 | printf("fatal error delete node\n"); 655 | exit(0); 656 | } 657 | //printf("node %d\n",*(uint32_t*)node->key); 658 | pthread_mutex_unlock(&r->lock); 659 | free(node->key); 660 | free(he->val); 661 | free(he); 662 | return 0; 663 | } 664 | 665 | 666 | int 667 | ttl_find_and_delete(struct records *r, struct hlp *h) 668 | { 669 | struct rbnode *node = NULL; 670 | struct hentry *he = NULL, *entry = NULL; 671 | node = min_node(r->rbt); 672 | if (node == NULL) 673 | return 0; 674 | entry = (struct hentry *) node; 675 | he = htable_delete(r->ht, entry->key, strlen(entry->key) + 1); 676 | if (he == NULL) { 677 | printf("fatal error\n"); 678 | exit(0); 679 | } 680 | free(he); 681 | free(node->key); 682 | return 0; 683 | } 684 | 685 | 686 | int 687 | main(int argc, char **argv) 688 | { 689 | #define INSERT_NUM (1000000) 690 | struct records rds; 691 | uchar key[50] = "test"; 692 | int i, ret; 693 | struct hlp hlp; 694 | pthread_mutex_init(&rds.lock, NULL); 695 | rds.rbt = create_rbtree(compare_ttl); 696 | if (rds.rbt == NULL) 697 | printf("create rbtree error\n"); 698 | rds.ht = htable_create(murmur, domain_compare, HASH_TABLE_SIZE); 699 | if (rds.ht == NULL) 700 | printf("create htable error\n"); 701 | for (i = 0; i < INSERT_NUM; i++) { 702 | key[0] = i / 1000000 + '0'; 703 | key[1] = ((i / 100000) % 10) + '0'; 704 | key[2] = ((i / 10000) % 10) + '0'; 705 | key[3] = ((i / 1000) % 10) + '0'; 706 | key[4] = ((i / 100) % 10) + '0'; 707 | key[5] = ((i / 10) % 10) + '0'; 708 | key[6] = (i % 10) + '0'; 709 | key[7] = 0; 710 | //printf("key is %s\n",key); 711 | hlp.key = key; 712 | hlp.len = strlen(key) + 1; 713 | hlp.ttl = malloc(sizeof(uint32_t)); 714 | if (hlp.ttl == NULL) { 715 | printf("malloc ttl error\n"); 716 | return -1; 717 | } 718 | *(hlp.ttl) = i * 3; 719 | hlp.val = malloc(200); 720 | if (hlp.val == NULL) { 721 | printf("alloc val error\n"); 722 | return -1; 723 | } 724 | ret = record_insert(&rds, &hlp); 725 | if (ret < 0) { 726 | printf("insert error\n"); 727 | return -1; 728 | } 729 | } 730 | sleep(5); 731 | for (i = 0; i < INSERT_NUM; i++) { 732 | key[0] = i / 1000000 + '0'; 733 | key[1] = ((i / 100000) % 10) + '0'; 734 | key[2] = ((i / 10000) % 10) + '0'; 735 | key[3] = ((i / 1000) % 10) + '0'; 736 | key[4] = ((i / 100) % 10) + '0'; 737 | key[5] = ((i / 10) % 10) + '0'; 738 | key[6] = (i % 10) + '0'; 739 | key[7] = 0; 740 | hlp.key = key; 741 | hlp.len = strlen(key) + 1; 742 | record_delete(&rds, &hlp); 743 | } 744 | return 0; 745 | } 746 | -------------------------------------------------------------------------------- /src/storage.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2006-2012, DNSPod Inc. 2 | * All rights reserved. 3 | 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright notice, 10 | * this list of conditions and the following disclaimer in the documentation 11 | * and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | * The views and conclusions contained in the software and documentation are those 25 | * of the authors and should not be interpreted as representing official policies, 26 | * either expressed or implied, of the FreeBSD Project. 27 | */ 28 | 29 | 30 | #include "storage.h" 31 | 32 | 33 | const uint MAX_ELE_NUM = 1000000; 34 | 35 | 36 | //////////////////////////memory chunk/////////////////////////// 37 | //push to tail 38 | //pop from head 39 | struct msgcache * 40 | init_msgcache(int n) 41 | { 42 | struct msgcache *mc = NULL; 43 | int pgsz; 44 | if (n < 1 || n > 5000) //page size == 4k. 5000*4k == 20m 45 | return NULL; 46 | pgsz = getpagesize(); 47 | if ((mc = malloc(sizeof(struct msgcache) + pgsz * n)) == NULL) 48 | return NULL; 49 | mc->size = pgsz * n; 50 | pthread_spin_init(&mc->lock, 0); 51 | mc->head = mc->tail = 0; 52 | mc->pkt = 0; 53 | return mc; 54 | } 55 | 56 | 57 | void 58 | free_msgcache(struct msgcache *mc) 59 | { 60 | if (mc != NULL) 61 | free(mc); 62 | } 63 | 64 | ///////////////////////////////////////////////////////////////// 65 | 66 | 67 | int 68 | get_mvalue_len(uchar * val) 69 | { 70 | struct mvalue *mv = (struct mvalue *) val; 71 | return mv->len; 72 | } 73 | 74 | 75 | //this should be defined in upper files 76 | int 77 | ttl_expired(uchar * val) 78 | { 79 | struct mvalue *mv = (struct mvalue *) val; 80 | uint tx = global_now; 81 | if (mv->ttl == (MAX_TTL + 1)) //never expired 82 | return 0; 83 | if (mv->ttl < tx) 84 | return 1; 85 | return 0; 86 | } 87 | 88 | 89 | //use by memory hash and disk db 90 | //copy data from storage to buffer 91 | //after this, operate data will not need 92 | //to lock database any more 93 | static int 94 | deep_copy(uchar * from, uchar * to, int tlen) //*to is big enough 95 | { 96 | struct mvalue *mv = (struct mvalue *) from; 97 | int sz = mv->len + sizeof(struct mvalue) + mv->seg * sizeof(uint16_t); 98 | if (sz >= tlen) 99 | return -1; 100 | mv->hits++; 101 | //printf("sz is %d\n",sz); 102 | memcpy(to, from, sz); 103 | return sz; 104 | } 105 | 106 | 107 | /////////////////////////memory hash///////////////////////////// 108 | uint 109 | get_pre_mem_hash(void *argv, int klen, hashval_t *hash) 110 | { 111 | uint ret = 0; 112 | if (*hash == 0) 113 | *hash = nocase_char_hash_function(argv, klen); 114 | ret = (*hash / MULTI_HASH) % MULTI_HASH; 115 | return ret; 116 | } 117 | 118 | 119 | struct htable * 120 | htable_create(hashfunc * h, comparefunc * c, int size, int num) 121 | { 122 | int i, j; 123 | struct htable *ht = NULL; 124 | if (c == NULL) 125 | return NULL; 126 | if ((ht = malloc(sizeof(struct htable) * num)) == NULL) 127 | return NULL; 128 | for (i = 0; i < num; i++) { 129 | ht[i].h = h; 130 | if (h == NULL) 131 | ht[i].h = nocase_char_hash_function; 132 | ht[i].c = c; 133 | ht[i].size = size; 134 | ht[i].edata = NULL; 135 | ht[i].now = 0; //no need lock 136 | ht[i].mask = size - 1; 137 | pthread_spin_init(&(ht[i].lock), 0); 138 | if ((ht[i].table = 139 | malloc(sizeof(struct hdata) * ht[i].size)) == NULL) { 140 | for (j = 0; j < i; j++) 141 | free(ht[j].table); 142 | free(ht); 143 | return NULL; 144 | } 145 | for (j = 0; j < size; j++) { 146 | ht[i].table[j].list = NULL; 147 | pthread_spin_init(&(ht[i].table[j].lock), 0); 148 | } 149 | } 150 | return ht; 151 | } 152 | 153 | void find_io_from_he(struct hentry *he, uint32_t limit, struct rbtree *rbt, int ttl_update) 154 | { 155 | struct mvalue *mv; 156 | int i, val_num = SUPPORT_TYPE_NUM; 157 | uchar *val; 158 | time_t now = global_now; 159 | struct ttlnode tn, *ptn; 160 | struct rbnode *pn; 161 | 162 | assert(he->count > 0); 163 | 164 | for (i = 0; i< val_num; i++) 165 | { 166 | val = he->vals[i]; 167 | if (val == NULL) 168 | continue; 169 | 170 | mv = (struct mvalue *)val; 171 | if ((mv->ttl > (now + ttl_update + 1)) && (mv->hits < limit)) 172 | { 173 | tn.data = he->key; 174 | tn.type = support_type[i]; 175 | tn.exp = mv->ttl; 176 | tn.dlen = strlen((const char *)he->key) + 1; 177 | tn.lowerdomain = NULL; 178 | pthread_spin_lock(&rbt->lock); 179 | pn = find_node(rbt, &tn); 180 | if (pn != NULL) 181 | { 182 | ptn = delete_node(rbt, pn); 183 | if (ptn != NULL) 184 | { 185 | //printf("delete true\n"); 186 | free(ptn->lowerdomain); 187 | free(ptn); 188 | } else 189 | printf("delete error\n"); 190 | } 191 | else 192 | { 193 | /* printf("find error\n"); */ 194 | /* dbg_print_td(key); */ 195 | } 196 | pthread_spin_unlock(&rbt->lock); 197 | 198 | free(val); 199 | he->vals[i] = NULL; 200 | he->count--; 201 | } 202 | 203 | if (0 == he->count) 204 | break; 205 | } 206 | 207 | return; 208 | } 209 | 210 | int 211 | htable_find_io(struct htable *ht, int idx,/* int off, uchar * buffer, 212 | uchar * key, int *klen, int vlen,*/ uint32_t limit, 213 | struct rbtree *rbt, int ttl_update) 214 | { 215 | int /*ret,*/ debug = DEBUG_TIMES; 216 | struct hdata *hd; 217 | struct hentry *he, *prev = NULL, *tmp; 218 | 219 | if (idx > HASH_TABLE_SIZE) 220 | return -1; 221 | hd = ht->table + idx; 222 | pthread_spin_lock(&hd->lock); 223 | if (hd->list == NULL) { 224 | pthread_spin_unlock(&hd->lock); 225 | return -1; 226 | } 227 | he = hd->list; 228 | while (he != NULL) { 229 | find_io_from_he(he, limit, rbt, ttl_update); 230 | if (0 == he->count) 231 | { 232 | tmp = he; 233 | if (NULL == prev) 234 | hd->list = he->next; 235 | else 236 | prev->next = he->next; 237 | he = he->next; 238 | free(tmp); 239 | hd->now--; 240 | pthread_spin_lock(&ht->lock); 241 | ht->now--; 242 | pthread_spin_unlock(&ht->lock); 243 | } 244 | else 245 | { 246 | prev = he; 247 | he = he->next; 248 | } 249 | debug--; 250 | if (debug == 0) { 251 | printf("error in storage...\n"); 252 | exit(0); 253 | } 254 | } 255 | pthread_spin_unlock(&hd->lock); 256 | return -1; 257 | } 258 | 259 | uchar *get_val_from_he(struct hentry *he, int type) 260 | { 261 | uchar *val; 262 | 263 | assert(he->count > 0); 264 | 265 | switch (type) 266 | { 267 | case A: 268 | val = he->val.A; 269 | break; 270 | case NS: 271 | val = he->val.NS; 272 | break; 273 | case CNAME: 274 | val = he->val.CNAME; 275 | break; 276 | case SOA: 277 | val = he->val.SOA; 278 | break; 279 | case MX: 280 | val = he->val.MX; 281 | break; 282 | case TXT: 283 | val = he->val.TXT; 284 | break; 285 | case AAAA: 286 | val = he->val.AAAA; 287 | break; 288 | case SRV: 289 | val = he->val.SRV; 290 | break; 291 | case PTR: 292 | val = he->val.PTR; 293 | break; 294 | default: 295 | val = NULL; 296 | break; 297 | } 298 | 299 | return val; 300 | } 301 | 302 | // read dirty 303 | int 304 | htable_find(struct htable *ht, uchar * key, int klen, int type, uchar * buffer, int vlen, 305 | struct mvalue *md, hashval_t *hashd) 306 | { 307 | int idx, debug = DEBUG_TIMES, ret; 308 | struct hdata *hd = NULL; 309 | struct hentry *he = NULL; 310 | struct mvalue *mx = NULL; 311 | uchar *val; 312 | 313 | if (*hashd == 0) 314 | *hashd = (ht->h) (key, klen); 315 | idx = *hashd & ht->mask; 316 | hd = ht->table + idx; 317 | pthread_spin_lock(&hd->lock); 318 | if (hd->list == NULL) { 319 | pthread_spin_unlock(&hd->lock); 320 | return -1; 321 | } 322 | he = hd->list; 323 | while (he != NULL) { 324 | if ((ht->c) (key, he->key) == 0) { 325 | val = get_val_from_he(he, type); 326 | if (NULL == val) 327 | ret = -1; 328 | else if (buffer != NULL) 329 | ret = deep_copy(val, buffer, vlen); 330 | else { 331 | if (md != NULL) { 332 | mx = (struct mvalue *)val; 333 | *md = *mx; //meta data 334 | } 335 | ret = 1; //successed 336 | } 337 | pthread_spin_unlock(&hd->lock); 338 | return ret; 339 | } 340 | he = he->next; 341 | if (debug-- == 0) { 342 | printf("error in htable find\n"); 343 | exit(0); 344 | } 345 | } 346 | pthread_spin_unlock(&hd->lock); 347 | return -1; 348 | } 349 | 350 | int 351 | find_list_io_from_he(struct hentry *he, int *typeoff, uchar **buffer) 352 | { 353 | int i, val_num = SUPPORT_TYPE_NUM; 354 | uchar *val; 355 | 356 | assert(he->count > 0); 357 | 358 | for (i = *typeoff; i < val_num; i++) 359 | { 360 | val = he->vals[i]; 361 | if (val == NULL) 362 | continue; 363 | 364 | *buffer = val; 365 | *typeoff = i; 366 | return 1; 367 | } 368 | 369 | return 0; 370 | } 371 | 372 | int 373 | htable_find_list_io(struct htable *ht, int idx, int off, int *typeoff, uchar **buffer) 374 | { 375 | int debug = DEBUG_TIMES, ret; 376 | struct hdata *hd = NULL; 377 | struct hentry *he = NULL; 378 | 379 | hd = ht->table + idx; 380 | pthread_spin_lock(&hd->lock); 381 | if (hd->list == NULL) { 382 | pthread_spin_unlock(&hd->lock); 383 | return -1; 384 | } 385 | he = hd->list; 386 | while (he != NULL) { 387 | if (off == 0) { 388 | ret = find_list_io_from_he(he, typeoff, buffer); 389 | pthread_spin_unlock(&hd->lock); 390 | return ret; 391 | } 392 | off--; 393 | he = he->next; 394 | if (debug-- == 0) { 395 | printf("error in htable find list io\n"); 396 | exit(0); 397 | } 398 | } 399 | pthread_spin_unlock(&hd->lock); 400 | return -1; 401 | } 402 | 403 | int 404 | get_list_val_from_he(struct hentry *he, int typeoff, uchar **buffer) 405 | { 406 | uchar *val; 407 | 408 | assert(he->count > 0); 409 | 410 | val = he->vals[typeoff]; 411 | *buffer = val; 412 | if (NULL == val) 413 | return -1; 414 | return 1; 415 | } 416 | 417 | int 418 | htable_find_list(struct htable *ht, uchar *key, int typeoff, int idx, uchar **buffer) 419 | { 420 | int debug = DEBUG_TIMES/*, ret*/; 421 | struct hdata *hd = NULL; 422 | struct hentry *he = NULL; 423 | mbuf_type *mbuf; 424 | 425 | hd = ht->table + idx; 426 | pthread_spin_lock(&hd->lock); 427 | if (hd->list == NULL) { 428 | pthread_spin_unlock(&hd->lock); 429 | return -1; 430 | } 431 | he = hd->list; 432 | while (he != NULL) { 433 | mbuf = (mbuf_type *)(he->vals[typeoff]); 434 | if ((mbuf != NULL) && ((ht->c) (key, mbuf->qing) == 0)) { 435 | *buffer = (uchar *)mbuf; 436 | pthread_spin_unlock(&hd->lock); 437 | return 1; 438 | } 439 | he = he->next; 440 | if (debug-- == 0) { 441 | printf("error in htable find\n"); 442 | exit(0); 443 | } 444 | } 445 | pthread_spin_unlock(&hd->lock); 446 | return -1; 447 | } 448 | 449 | uchar *delete_val_from_he(struct hentry *he, int type) 450 | { 451 | uchar **oval, *val = NULL; 452 | 453 | assert(he->count > 0); 454 | 455 | switch (type) 456 | { 457 | case A: 458 | oval = &(he->val.A); 459 | break; 460 | case NS: 461 | oval = &(he->val.NS); 462 | break; 463 | case CNAME: 464 | oval = &(he->val.CNAME); 465 | break; 466 | case SOA: 467 | oval = &(he->val.SOA); 468 | break; 469 | case MX: 470 | oval = &(he->val.MX); 471 | break; 472 | case TXT: 473 | oval = &(he->val.TXT); 474 | break; 475 | case AAAA: 476 | oval = &(he->val.AAAA); 477 | break; 478 | case SRV: 479 | oval = &(he->val.SRV); 480 | break; 481 | case PTR: 482 | oval = &(he->val.PTR); 483 | break; 484 | default: 485 | return NULL; 486 | break; 487 | } 488 | 489 | if (*oval != NULL) 490 | { 491 | val = *oval; 492 | *oval = NULL; 493 | he->count--; 494 | } 495 | 496 | return val; 497 | } 498 | 499 | uchar * 500 | htable_delete(struct htable *ht, uchar * key, int klen, int type, hashval_t hashd) 501 | { 502 | hashval_t h = (hashd) ? (hashd) : ((ht->h) (key, klen)); 503 | int idx = h & ht->mask, debug = DEBUG_TIMES; 504 | struct hdata *hd = NULL; 505 | struct hentry *he = NULL, *prev = NULL; 506 | hd = ht->table + idx; 507 | uchar *val; 508 | 509 | pthread_spin_lock(&hd->lock); 510 | if (hd->list == NULL) { 511 | pthread_spin_unlock(&hd->lock); 512 | return NULL; 513 | } 514 | he = hd->list; 515 | while (he != NULL) { 516 | if ((ht->c) (key, he->key) == 0) { 517 | val = delete_val_from_he(he, type); 518 | if (0 == he->count) 519 | { 520 | if (NULL == prev) 521 | hd->list = he->next; 522 | else 523 | prev->next = he->next; 524 | free(he); 525 | hd->now--; 526 | pthread_spin_lock(&ht->lock); 527 | ht->now--; 528 | pthread_spin_unlock(&ht->lock); 529 | } 530 | pthread_spin_unlock(&hd->lock); 531 | return val; 532 | } 533 | prev = he; 534 | he = he->next; 535 | debug--; 536 | if (debug == 0) { 537 | printf("error in storage\n"); 538 | exit(0); 539 | } 540 | } 541 | pthread_spin_unlock(&hd->lock); 542 | return NULL; 543 | } 544 | 545 | uchar *delete_list_val_from_he(struct hentry *he, int typeoff) 546 | { 547 | uchar **oval, *val = NULL; 548 | 549 | assert(he->count > 0); 550 | 551 | oval = &(he->vals[typeoff]); 552 | 553 | if (*oval != NULL) 554 | { 555 | val = *oval; 556 | *oval = NULL; 557 | he->count--; 558 | } 559 | 560 | return val; 561 | } 562 | 563 | uchar * 564 | htable_delete_list_io(struct htable *ht, int typeoff, int idx, int off) 565 | { 566 | int debug = DEBUG_TIMES; 567 | struct hdata *hd = NULL; 568 | struct hentry *he = NULL, *prev = NULL; 569 | uchar *val; 570 | 571 | hd = ht->table + idx; 572 | pthread_spin_lock(&hd->lock); 573 | if (hd->list == NULL) { 574 | pthread_spin_unlock(&hd->lock); 575 | return NULL; 576 | } 577 | he = hd->list; 578 | while (he != NULL) { 579 | if (off == 0) { 580 | val = delete_list_val_from_he(he, typeoff); 581 | if (0 == he->count) 582 | { 583 | if (NULL == prev) 584 | hd->list = he->next; 585 | else 586 | prev->next = he->next; 587 | free(he); 588 | hd->now--; 589 | pthread_spin_lock(&ht->lock); 590 | ht->now--; 591 | pthread_spin_unlock(&ht->lock); 592 | } 593 | pthread_spin_unlock(&hd->lock); 594 | return val; 595 | } 596 | off--; 597 | prev = he; 598 | he = he->next; 599 | if (debug-- == 0) { 600 | printf("error in htable find list io\n"); 601 | exit(0); 602 | } 603 | } 604 | pthread_spin_unlock(&hd->lock); 605 | return NULL; 606 | } 607 | 608 | uchar * 609 | htable_delete_list(struct htable *ht, uchar *key, int typeoff, int idx) 610 | { 611 | int debug = DEBUG_TIMES; 612 | struct hdata *hd = NULL; 613 | struct hentry *he = NULL, *prev = NULL; 614 | uchar *val; 615 | 616 | hd = ht->table + idx; 617 | pthread_spin_lock(&hd->lock); 618 | if (hd->list == NULL) { 619 | pthread_spin_unlock(&hd->lock); 620 | return NULL; 621 | } 622 | he = hd->list; 623 | while (he != NULL) { 624 | if ((ht->c) (key, he->key) == 0) { 625 | val = delete_list_val_from_he(he, typeoff); 626 | if (0 == he->count) 627 | { 628 | if (NULL == prev) 629 | hd->list = he->next; 630 | else 631 | prev->next = he->next; 632 | free(he); 633 | hd->now--; 634 | pthread_spin_lock(&ht->lock); 635 | ht->now--; 636 | pthread_spin_unlock(&ht->lock); 637 | } 638 | pthread_spin_unlock(&hd->lock); 639 | return val; 640 | } 641 | prev = he; 642 | he = he->next; 643 | if (debug-- == 0) { 644 | printf("error in htable find list io\n"); 645 | exit(0); 646 | } 647 | } 648 | pthread_spin_unlock(&hd->lock); 649 | return NULL; 650 | } 651 | 652 | 653 | // A, NS, CNAME, SOA, MX, TXT, AAAA, SRV, PTR 654 | int append_value_to_he(struct hentry *he, uchar *val, int type, int replace, 655 | struct mvalue *mv) 656 | { 657 | int ret; 658 | uchar **oval; 659 | 660 | switch (type) 661 | { 662 | case A: 663 | oval = &(he->val.A); 664 | break; 665 | case NS: 666 | oval = &(he->val.NS); 667 | break; 668 | case CNAME: 669 | oval = &(he->val.CNAME); 670 | break; 671 | case SOA: 672 | oval = &(he->val.SOA); 673 | break; 674 | case MX: 675 | oval = &(he->val.MX); 676 | break; 677 | case TXT: 678 | oval = &(he->val.TXT); 679 | break; 680 | case AAAA: 681 | oval = &(he->val.AAAA); 682 | break; 683 | case SRV: 684 | oval = &(he->val.SRV); 685 | break; 686 | case PTR: 687 | oval = &(he->val.PTR); 688 | break; 689 | default: 690 | return HTABLE_INSERT_RET_INVALID_TYPE; 691 | break; 692 | } 693 | 694 | if (*oval != NULL) 695 | { 696 | if (replace) 697 | { 698 | if (mv != NULL) //get old meta data 699 | *mv = *(struct mvalue *) (*oval); 700 | if ((mv != NULL) && (mv->ttl != (MAX_TTL + 1))) 701 | { 702 | /* 703 | * 如果替换的为NS类型,则TTL使用原有NS记录的TTL 704 | * 否则授权与根返回的NS不一致时,会无法刷新NS 705 | */ 706 | if (NS == type) 707 | { 708 | ((struct mvalue *)val)->ttl = mv->ttl; 709 | } 710 | free(*oval); 711 | *oval = val; 712 | ret = HTABLE_INSERT_RET_REPLACE; 713 | } 714 | else 715 | { 716 | ret = HTABLE_INSERT_RET_NEVER_EXPIRE; 717 | } 718 | } 719 | else 720 | { 721 | ret = HTABLE_INSERT_RET_NO_REPLACE; 722 | } 723 | } 724 | else 725 | { 726 | he->count++; 727 | *oval = val; 728 | ret = HTABLE_INSERT_RET_NORMAL; 729 | } 730 | return ret; 731 | } 732 | 733 | //if conllision, replace old element by default. 734 | //if replace is 1, replace it, return 1 735 | //if replace is 0, drop it, return -1 736 | //else return 0 737 | int 738 | htable_insert(struct htable *ht, uchar * key, int klen, int type, uchar * val, int replace, 739 | struct mvalue *mv, hashval_t *hashd) 740 | { 741 | int idx, ret, debug = DEBUG_TIMES; 742 | struct hentry *he = NULL, *cl = NULL; 743 | struct hdata *hd = NULL; 744 | /* struct mvalue *pt = NULL; //protect root and gtld */ 745 | uchar dlen = klen; 746 | 747 | if (check_support_type(type) == -1) 748 | { 749 | printf("invalud type:%d, key:[%s]\n", type, key); 750 | return -1; 751 | } 752 | 753 | he = malloc(sizeof(struct hentry) + dlen); 754 | if (he == NULL) { 755 | printf("oom\n"); 756 | return -1; 757 | } 758 | memset(he, 0, sizeof(struct hentry)); 759 | memcpy(he->key, key, dlen); 760 | if (*hashd == 0) { 761 | *hashd = ht->h(key, klen); 762 | } 763 | idx = *hashd & ht->mask; 764 | //printf("hash %u,idx is %d\n",hash,idx); 765 | hd = ht->table + idx; 766 | pthread_spin_lock(&hd->lock); 767 | if (hd->list == NULL) 768 | { 769 | ret = append_value_to_he(he, val, type, replace, NULL); 770 | hd->now = 1; 771 | hd->list = he; 772 | } 773 | else { 774 | cl = hd->list; 775 | while (cl != NULL) { 776 | if ((ht->c) (cl->key, he->key) == 0) //the exactly same elements 777 | { 778 | ret = append_value_to_he(cl, val, type, replace, mv); 779 | pthread_spin_unlock(&hd->lock); 780 | free(he); 781 | return ret; //replace 782 | } 783 | cl = cl->next; 784 | debug--; 785 | if (debug == 0) { 786 | printf("error in storage2\n"); 787 | exit(0); 788 | } 789 | } 790 | ret = append_value_to_he(he, val, type, replace, NULL); 791 | he->next = hd->list; 792 | hd->list = he; 793 | hd->now++; 794 | } 795 | pthread_spin_unlock(&hd->lock); 796 | pthread_spin_lock(&ht->lock); 797 | ht->now++; 798 | pthread_spin_unlock(&ht->lock); 799 | return HTABLE_INSERT_RET_NORMAL; 800 | } 801 | 802 | int 803 | htable_insert_list(struct htable *ht, uchar * key, int klen, int type, uchar * val, int replace, 804 | struct mvalue *mv, hashval_t *hashd) 805 | { 806 | int idx, ret, debug = DEBUG_TIMES; 807 | struct hentry *he = NULL, *cl = NULL, *prev = NULL; 808 | struct hdata *hd = NULL; 809 | /* struct mvalue *pt = NULL; //protect root and gtld */ 810 | uchar dlen = klen; 811 | 812 | if (check_support_type(type) == -1) 813 | { 814 | printf("invalud type:%d, key:[%s]\n", type, key); 815 | return -1; 816 | } 817 | 818 | he = malloc(sizeof(struct hentry) + dlen); 819 | if (he == NULL) { 820 | printf("oom\n"); 821 | return -1; 822 | } 823 | memset(he, 0, sizeof(struct hentry)); 824 | memcpy(he->key, key, dlen); 825 | if (*hashd == 0) { 826 | *hashd = ht->h(key, klen); 827 | } 828 | idx = *hashd & ht->mask; 829 | //printf("hash %u,idx is %d\n",hash,idx); 830 | hd = ht->table + idx; 831 | pthread_spin_lock(&hd->lock); 832 | if (hd->list == NULL) 833 | { 834 | ret = append_value_to_he(he, val, type, replace, NULL); 835 | hd->now = 1; 836 | hd->list = he; 837 | } 838 | else { 839 | cl = hd->list; 840 | while (cl != NULL) { 841 | if ((ht->c) (cl->key, he->key) == 0) //the exactly same elements 842 | { 843 | ret = append_value_to_he(cl, val, type, replace, mv); 844 | pthread_spin_unlock(&hd->lock); 845 | free(he); 846 | return ret; //replace 847 | } 848 | prev = cl; 849 | cl = cl->next; 850 | debug--; 851 | if (debug == 0) { 852 | printf("error in storage3\n"); 853 | exit(0); 854 | } 855 | } 856 | ret = append_value_to_he(he, val, type, replace, NULL); 857 | prev->next = he; 858 | hd->now++; 859 | } 860 | pthread_spin_unlock(&hd->lock); 861 | pthread_spin_lock(&ht->lock); 862 | ht->now++; 863 | pthread_spin_unlock(&ht->lock); 864 | return 0; 865 | } 866 | 867 | 868 | int 869 | find_record_with_ttl(struct htable *ht, uchar * key, int klen, int type, uchar *val, int vlen, 870 | struct mvalue *md, hashval_t *hash) 871 | { 872 | int idx, ret; 873 | uchar *oval; 874 | idx = get_pre_mem_hash(key, klen, hash); 875 | ret = htable_find(ht + idx, key, klen, type, val, vlen, md, hash); 876 | if (ret > 0) { 877 | if (ttl_expired(val) == 1) { 878 | oval = htable_delete(ht + idx, key, klen, type, *hash); 879 | if (oval != NULL) 880 | free(oval); 881 | } else { 882 | return ret; 883 | } 884 | } 885 | return -1; 886 | } 887 | 888 | 889 | ///////////////////////////////////////////////////////////////// 890 | ////////////////////////////////dbg////////////////////////////// 891 | #define THREADX (5) 892 | #define NUMX (10000) 893 | struct st_hlp { 894 | struct htable *ht; 895 | int idx; 896 | }; 897 | 898 | 899 | void * 900 | st_th(void *arg) 901 | { 902 | int i, idx; 903 | uchar key[50] = { 0 }; 904 | int klen; 905 | uchar *val = NULL; 906 | int pre = 0; 907 | // struct hentry *he = NULL; 908 | uchar *oval; 909 | struct htable *ht; 910 | struct st_hlp *sh = (struct st_hlp *) arg; 911 | hashval_t hash; 912 | idx = sh->idx; 913 | ht = sh->ht; 914 | for (i = idx * NUMX; i < (idx + 1) * NUMX; i++) { 915 | hash = 0; 916 | sprintf((char *)key, "%dkey", i); 917 | val = malloc(50); 918 | sprintf((char *)val, "%dval", i); 919 | //printf("%d,%s,%s\n",idx,key,val); 920 | klen = strlen((const char *)key) + 1; 921 | pre = get_pre_mem_hash(key, klen, &hash); 922 | htable_insert(ht + pre, key, klen, A, val, 0, NULL, &hash); 923 | } 924 | if (idx == (THREADX - 1)) 925 | idx = -1; 926 | sleep(2); 927 | for (i = (idx + 1) * NUMX; i < (idx + 2) * NUMX; i++) { 928 | hash = 0; 929 | sprintf((char *)key, "%dkey", i); 930 | klen = strlen((const char *)key) + 1; 931 | pre = get_pre_mem_hash(key, klen, &hash); 932 | oval = htable_delete(ht + pre, key, klen, A, hash); 933 | if (oval == NULL) { 934 | printf("error in test %s,%d,%d\n", key, idx, i); 935 | } 936 | else 937 | free(oval); 938 | } 939 | sleep(5); 940 | return NULL; 941 | } 942 | 943 | 944 | int 945 | storage_test(void) 946 | { 947 | struct htable *ht = NULL; 948 | pthread_t pt[THREADX]; 949 | int i; 950 | struct st_hlp sh[THREADX]; 951 | //ht = htable_create(NULL,dict_comp_str_equ,HASH_TABLE_SIZE,MULTI_HASH); 952 | if (ht == NULL) 953 | dns_error(0, "create htable error"); 954 | for (i = 0; i < THREADX; i++) { 955 | sh[i].ht = ht; 956 | sh[i].idx = i; 957 | if (pthread_create(pt + i, NULL, st_th, sh + i)) 958 | dns_error(0, "create pthread"); 959 | } 960 | for (i = 0; i < THREADX; i++) 961 | pthread_join(pt[i], NULL); 962 | sleep(2); 963 | return 0; 964 | } 965 | --------------------------------------------------------------------------------