├── .cproject ├── .gitignore ├── .project ├── .settings └── org.eclipse.core.resources.prefs ├── Makefile ├── README ├── example ├── Makefile ├── ares_dns.cpp ├── client.cpp ├── client2.cpp └── server.cpp ├── lib ├── c-ares-1.10.0.tar.gz ├── c-ares-1.10.0_auxten.patch ├── jemalloc-3.0.0.tar.bz2 ├── libev-4.11.tar.gz ├── libev_auxten.patch ├── patch_build_all.sh ├── patch_build_c-ares.sh ├── patch_build_jemalloc.sh └── patch_build_libev.sh └── src ├── AUTHORS ├── COPYING ├── ChangeLog ├── Makefile.am ├── NEWS ├── README ├── TODO ├── async_clnt.cpp ├── async_conn.cpp ├── async_dns.cpp ├── async_pool.h ├── async_threads.cpp ├── autogen.sh ├── configure.in ├── dict.c ├── dict.h ├── gingko.h ├── gingko_base.cpp ├── gko.h ├── gko_errno.h ├── hash ├── gko_zip.cpp ├── gko_zip.h ├── lz4.cpp ├── lz4.h ├── md5.cpp ├── md5.h ├── xor_hash.cpp └── xor_hash.h ├── hermes_errno.h ├── libgko.pc.in ├── limit.cpp ├── limit.h ├── log.cpp ├── log.h ├── memory.cpp ├── memory.h ├── path.cpp ├── path.h ├── socket.cpp └── socket.h /.cproject: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 36 | 41 | 42 | 43 | 44 | 53 | 58 | 59 | 60 | 61 | 67 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | configure 2 | example/ares_dns 3 | lib/jemalloc 4 | lib/jemalloc-3.0.0/ 5 | lib/jemalloc-3.0.0built/ 6 | lib/libjemalloc/ 7 | lib/c-ares-1.10.0.patched/ 8 | lib/c-ares-1.10.0 9 | lib/c-ares-1.10.0built 10 | lib/c-ares-1.8.0.patched/ 11 | lib/c-ares 12 | lib/c-ares-1.8.0 13 | lib/c-ares-1.8.0built 14 | lib/libgko/ 15 | src/libgko.pc 16 | example/async_dns 17 | example/client2 18 | *.dSYM 19 | example/client 20 | example/log 21 | example/server 22 | lib/libev-4.04fixed 23 | lib/libev 24 | lib/libev-4.04 25 | lib/libev-4.11/ 26 | lib/libev-4.11built/ 27 | lib/libzdb 28 | lib/libzdb-2.10.3/ 29 | lib/libzdb-2.10.3built/ 30 | svn-commit.* 31 | .deps/ 32 | clnt_unittest 33 | serv_unittest 34 | config.h 35 | config.log 36 | config.status 37 | *.tar.gz 38 | src/hash/Makefile 39 | src/Makefile 40 | *.dmg 41 | .DS_Store 42 | autom4te* 43 | gingko_clnt 44 | gingko_serv 45 | stamp-h1 46 | *.orig 47 | kfp_docs* 48 | server.log 49 | client.log 50 | *.[ao] 51 | build/ 52 | *~ 53 | .svn/ 54 | test 55 | output* 56 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | gko_pool 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 10 | clean,full,incremental, 11 | 12 | 13 | ?name? 14 | 15 | 16 | 17 | org.eclipse.cdt.make.core.append_environment 18 | true 19 | 20 | 21 | org.eclipse.cdt.make.core.autoBuildTarget 22 | all 23 | 24 | 25 | org.eclipse.cdt.make.core.buildArguments 26 | 27 | 28 | 29 | org.eclipse.cdt.make.core.buildCommand 30 | make 31 | 32 | 33 | org.eclipse.cdt.make.core.cleanBuildTarget 34 | clean 35 | 36 | 37 | org.eclipse.cdt.make.core.contents 38 | org.eclipse.cdt.make.core.activeConfigSettings 39 | 40 | 41 | org.eclipse.cdt.make.core.enableAutoBuild 42 | false 43 | 44 | 45 | org.eclipse.cdt.make.core.enableCleanBuild 46 | true 47 | 48 | 49 | org.eclipse.cdt.make.core.enableFullBuild 50 | true 51 | 52 | 53 | org.eclipse.cdt.make.core.fullBuildTarget 54 | all 55 | 56 | 57 | org.eclipse.cdt.make.core.stopOnError 58 | true 59 | 60 | 61 | org.eclipse.cdt.make.core.useDefaultBuildCmd 62 | true 63 | 64 | 65 | 66 | 67 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder 68 | full,incremental, 69 | 70 | 71 | 72 | 73 | 74 | org.eclipse.cdt.core.cnature 75 | org.eclipse.cdt.core.ccnature 76 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 77 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 78 | 79 | 80 | -------------------------------------------------------------------------------- /.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding//src/async_clnt.cpp=UTF-8 3 | encoding/=UTF-8 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | -include version_scmpf.env 2 | 3 | .PHONY: all makelib check_configure compile rm_config clean move check 4 | all: check_configure makelib compile 5 | 6 | check_configure: 7 | if [ ! -x src/configure ];then ( cd src && ./autogen.sh );fi 8 | 9 | makelib: 10 | cd lib && bash -x patch_build_all.sh && cd .. 11 | 12 | compile: 13 | cd src && ./autogen.sh && ./configure --enable-debug --prefix=$(shell pwd)/lib/libgko CXXFLAGS='-DNDEBUG -ggdb -D_GKO_VERSION=\"$(subst VERSION:,,$(VERSION_SCMPF))\"' && make clean ;sleep 1 &&\ 14 | make -j 4 && make install && cd .. 15 | 16 | rm_config: 17 | rm ./src/config.h 18 | rm -rf ./lib/libev/include 19 | 20 | clean: 21 | pwd 22 | #cd src && make clean && cd .. && rm -rf output 23 | #find ./../../../../../../.. -type f -name "event.h" 24 | 25 | move: 26 | if [ ! -d output ];then mkdir output;fi 27 | cd output && if [ ! -d bin ];then mkdir bin; fi && if [ ! -d testbin ];then mkdir testbin; fi 28 | cp ./src/gingko_serv ./output/bin/gkod 29 | cp ./src/gingko_clnt ./output/bin/gkocp 30 | cp ./src/serv_unittest ./output/testbin/ 31 | cp ./src/clnt_unittest ./output/testbin/ 32 | cp -r ./output/testbin ./test 33 | #cp ./bin/* ./output/bin/ 34 | #cp ./src/erase_job.py ./output/bin/ 35 | #cp ./src/run2.sh ./output/bin/gkod_ctl 36 | cp deploy ./output/ && chmod +x ./output/deploy 37 | cd output && md5sum deploy bin/* > md5sum 38 | #cd output/bin && cp gkocp{,.new} 39 | #cd output/bin && cp gkod{,.new} 40 | #cd output/bin && cp gkod_ctl{,.new} 41 | chmod +x ./output/bin/* 42 | cd output && tar czvf gingko.tgz bin md5sum deploy 43 | 44 | check: 45 | cd test && ./clnt_unittest && ./serv_unittest 46 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | _ _ 2 | __ _| | _____ _ __ ___ ___ | | 3 | / _` | |/ / _ \ | '_ \ / _ \ / _ \| | 4 | | (_| | < (_) | | |_) | (_) | (_) | | 5 | \__, |_|\_\___/____| .__/ \___/ \___/|_| 6 | |___/ |_____|_| 7 | 8 | # gko_pool: 9 | * an async multithread server client framework 10 | 11 | # author: 12 | * auxten 13 | 14 | # site: 15 | * http://blog.51reboot.com/gko_pool 16 | -------------------------------------------------------------------------------- /example/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: clean all client server ares_dns stress_confAgent 2 | 3 | LIBS= $(shell PKG_CONFIG_PATH=../lib/libgko/lib/pkgconfig pkg-config libgko --libs) 4 | CFLAGS= -g -O2 $(shell PKG_CONFIG_PATH=../lib/libgko/lib/pkgconfig pkg-config libgko --cflags) 5 | BINS = server client client2 ares_dns stress_confAgent 6 | all: $(BINS) 7 | 8 | server: 9 | g++ $@.cpp -g -O0 $(CFLAGS) $(LIBS) -o $@ 10 | 11 | client: 12 | g++ $@.cpp -g -O0 $(CFLAGS) $(LIBS) -o $@ 13 | 14 | client2: 15 | g++ $@.cpp -g -O0 $(CFLAGS) $(LIBS) -o $@ 16 | 17 | ares_dns: 18 | g++ $@.cpp -g -O0 $(CFLAGS) $(LIBS) -o $@ 19 | 20 | stress_confAgent: 21 | g++ $@.cpp -g -O0 $(CFLAGS) $(LIBS) -o $@ 22 | 23 | clean: 24 | -rm -rf *.dSYM 25 | -rm -f *.o 26 | -rm -f $(BINS) 27 | -------------------------------------------------------------------------------- /example/ares_dns.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * async_dns.cpp 3 | * 4 | * Created on: May 22, 2012 5 | * Author: auxten 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "event.h" 14 | #include "ares.h" 15 | #include "gko.h" 16 | 17 | struct event_base* ev_base; 18 | struct event ev_dns; 19 | 20 | void dns_callback(void* arg, int status, int timeouts, struct hostent* host) 21 | { 22 | if (status == ARES_SUCCESS) 23 | { 24 | u_int32_t addr = *(in_addr_t *) host->h_addr; 25 | printf("%u.%u.%u.%u\n", (addr) % 256, (addr >> 8) % 256, (addr >> 16) % 256, (addr >> 24) % 256); 26 | } 27 | else 28 | { 29 | std::cout << "lookup failed: " << status << '\n'; 30 | } 31 | event_del(&ev_dns); 32 | // event_base_loopexit(ev_base, &t); 33 | } 34 | 35 | void dns_ev_callback(int fd, short ev, void *arg) 36 | { 37 | if (ev & EV_READ) 38 | ares_process_fd((ares_channel) arg, fd, ARES_SOCKET_BAD); 39 | else if (ev & EV_WRITE) 40 | ares_process_fd((ares_channel) arg, ARES_SOCKET_BAD, fd); 41 | } 42 | 43 | void main_loop(ares_channel channel) 44 | { 45 | int nfds, count; 46 | fd_set readers, writers; 47 | ev_base = (struct event_base*) event_init(); 48 | 49 | ares_socket_t *read_fds; 50 | ares_socket_t *write_fds; 51 | // FD_ZERO(&readers); 52 | // FD_ZERO(&writers); 53 | //// ares_ 54 | // nfds = ares_fds(channel, &readers, &writers); 55 | // for (int i = 0; i < readers.fd_count; i++) 56 | // { 57 | // if (FD_ISSET(readers.fd_array[i], readers)) 58 | // event_set(&ev_dns, 1, EV_READ, ev_callback, 59 | // (void *) (&channel)); 60 | // } 61 | // for (int i = 0; i < writers.fd_count; i++) 62 | // { 63 | // if (FD_ISSET(writers.fd_array[i], writers)) 64 | // event_set(&ev_dns, 1, EV_WRITE, ev_callback, 65 | // (void *) (&channel)); 66 | // } 67 | 68 | //////////////////// 69 | // struct server_state *server; 70 | // 71 | // /* Are there any active queries? */ 72 | // int active_queries = !ares__is_list_empty(&(channel->all_queries)); 73 | // 74 | // for (int i = 0; i < channel->nservers; i++) 75 | // { 76 | // server = &channel->servers[i]; 77 | // /* We only need to register interest in UDP sockets if we have 78 | // * outstanding queries. 79 | // */ 80 | // if (active_queries && server->udp_socket != ARES_SOCKET_BAD) 81 | // { 82 | //// FD_SET(server->udp_socket, read_fds); 83 | // event_set(&ev_dns, server->udp_socket, EV_READ, ev_callback, 84 | // (void *) (&channel)); 85 | // } 86 | // /* We always register for TCP events, because we want to know 87 | // * when the other side closes the connection, so we don't waste 88 | // * time trying to use a broken connection. 89 | // */ 90 | // if (server->tcp_socket != ARES_SOCKET_BAD) 91 | // { 92 | //// FD_SET(server->tcp_socket, read_fds); 93 | // event_set(&ev_dns, server->tcp_socket, EV_READ, ev_callback, 94 | // (void *) (&channel)); 95 | // if (server->qhead) 96 | //// FD_SET(server->tcp_socket, write_fds); 97 | // event_set(&ev_dns, server->tcp_socket, EV_WRITE, ev_callback, 98 | // (void *) (&channel)); 99 | // } 100 | // } 101 | //////////////////// 102 | ares_fds_array(channel, &read_fds, &write_fds); 103 | 104 | for (int i = 0; *(read_fds + i) != ARES_SOCKET_BAD; i++) 105 | { 106 | // printf( "read %d\n", *(read_fds + i)); 107 | event_set(&ev_dns, *(read_fds + i), EV_READ | EV_PERSIST, dns_ev_callback, 108 | (void *) (channel)); 109 | } 110 | for (int i = 0; *(write_fds + i) != ARES_SOCKET_BAD; i++) 111 | { 112 | // printf("write %d\n", *(write_fds + i)); 113 | event_set(&ev_dns, *(write_fds + i), EV_WRITE | EV_PERSIST, dns_ev_callback, 114 | (void *) (channel)); 115 | } 116 | 117 | free(read_fds); 118 | free(write_fds); 119 | event_base_set(ev_base, &ev_dns); 120 | event_add(&ev_dns, 0); 121 | event_base_loop(ev_base, 0); 122 | 123 | // timeval tv, *tvp; 124 | // while (1) 125 | // { 126 | // FD_ZERO(&readers); 127 | // FD_ZERO(&writers); 128 | //// ares_ 129 | // nfds = ares_fds(channel, &readers, &writers); 130 | // if (nfds == 0) 131 | // break; 132 | // tvp = ares_timeout(channel, NULL, &tv); 133 | // count = select(nfds, &readers, &writers, NULL, tvp); 134 | // ares_process(channel, &readers, &writers); 135 | // } 136 | 137 | } 138 | int main(int argc, char **argv) 139 | { 140 | struct in_addr ip; 141 | int res; 142 | if (argc < 2) 143 | { 144 | std::cout << "usage: " << argv[0] << " ip.address\n"; 145 | return 1; 146 | } 147 | // inet_aton(argv[1], &ip); 148 | ares_library_init(ARES_LIB_INIT_ALL); 149 | ares_channel channel; 150 | if ((res = ares_init(&channel)) != ARES_SUCCESS) 151 | { 152 | std::cout << "ares feiled: " << res << '\n'; 153 | return 1; 154 | } 155 | 156 | ares_gethostbyname(channel, argv[1], AF_INET, dns_callback, NULL); 157 | main_loop(channel); 158 | return 0; 159 | } 160 | 161 | -------------------------------------------------------------------------------- /example/client.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * server.cpp 3 | * 4 | * Created on: May 18, 2012 5 | * Author: auxten 6 | */ 7 | #include "gko.h" 8 | #include 9 | /// gingko global stuff 10 | s_gingko_global_t gko; 11 | 12 | pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; 13 | int cnt = 3; 14 | int counter = 0; 15 | void report_result(void * c, const char * msg) 16 | { 17 | GKOLOG(NOTICE, "%s", msg); 18 | pthread_mutex_lock(&lock); 19 | if (++counter == cnt) 20 | { 21 | printf("finished\n"); 22 | exit(0); 23 | } 24 | pthread_mutex_unlock(&lock); 25 | } 26 | 27 | int main(int argc, char** argv) 28 | { 29 | char cmd[2048]; 30 | 31 | gko.opt.to_debug = 0; 32 | gko.ready_to_serv = 1; 33 | gko.sig_flag = 0; 34 | gko.opt.worker_thread = 8; 35 | gko.opt.connlimit = SERV_POOL_SIZE; 36 | // gko.opt.to_debug = 1; 37 | gko_pool * gingko = gko_pool::getInstance(); 38 | gingko->setPort(-1); 39 | gingko->setOption(&gko.opt); 40 | // gingko->setProcessHandler(conn_send_data); 41 | gingko->setReportHandler(report_result); 42 | gingko->gko_run(); 43 | 44 | char ua[56][256] = 45 | { 46 | "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:15.0) Gecko/20100101 Firefox/15.0.1", 47 | "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.79 Safari/537.4", 48 | "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4", 49 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/536.26.14 (KHTML, like Gecko) Version/6.0.1 Safari/536.26.14", 50 | "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1", 51 | "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)", 52 | "Mozilla/5.0 (Windows NT 5.1; rv:15.0) Gecko/20100101 Firefox/15.0.1", 53 | "Mozilla/5.0 (Windows NT 6.1; rv:15.0) Gecko/20100101 Firefox/15.0.1", 54 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.79 Safari/537.4", 55 | "Mozilla/5.0 (Linux; U; Android 2.2; fr-fr; Desire_A8181 Build/FRF91) App3leWebKit/53.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1", 56 | "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.79 Safari/537.4", 57 | "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4", 58 | "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:5.0) Gecko/20100101 Firefox/5.0", 59 | "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 Safari/535.1", 60 | "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:16.0) Gecko/20100101 Firefox/16.0", 61 | "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows NT 5.0) Opera 7.02 Bork-edition [en]", 62 | "Mozilla/5.0 (Windows NT 6.1; rv:5.0) Gecko/20100101 Firefox/5.02", 63 | "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 Safari/535.1", 64 | "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.79 Safari/537.4", 65 | "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; .NET CLR 3.5.30729)", 66 | "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322)", 67 | "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; .NET CLR 1.1.4322; PeoplePal 6.2)", 68 | "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MRA 5.8 (build 4157); .NET CLR 2.0.50727; AskTbPTV/5.11.3.15590)", 69 | "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727)", 70 | "Mozilla/5.0 (Windows NT 6.1; rv:2.0b7pre) Gecko/20100921 Firefox/4.0b7pre", 71 | "Mozilla/5.0 (Windows NT 5.1; rv:5.0.1) Gecko/20100101 Firefox/5.0.1", 72 | "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)", 73 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4", 74 | "Opera/9.80 (Windows NT 5.1; U; en) Presto/2.10.289 Version/12.01", 75 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1", 76 | "Mozilla/5.0 (iPhone; CPU iPhone OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A403 Safari/8536.25", 77 | "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1", 78 | "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)", 79 | "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4", 80 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:15.0) Gecko/20100101 Firefox/15.0.1", 81 | "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1", 82 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2", 83 | "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.92 Safari/537.4", 84 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/536.26.14 (KHTML, like Gecko) Version/6.0.1 Safari/536.26.14", 85 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.79 Safari/537.4", 86 | "Mozilla/5.0 (Windows NT 5.1; rv:13.0) Gecko/20100101 Firefox/13.0.1", 87 | "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:15.0) Gecko/20100101 Firefox/15.0.1", 88 | "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2) Gecko/20100115 Firefox/3.6", 89 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1", 90 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:15.0) Gecko/20100101 Firefox/15.0.1", 91 | "Mozilla/5.0 (iPad; CPU OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A403 Safari/8536.25", 92 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/536.25 (KHTML, like Gecko) Version/6.0 Safari/536.25", 93 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.79 Safari/537.4", 94 | "Mozilla/5.0 (Windows NT 5.1; rv:16.0) Gecko/20100101 Firefox/16.0", 95 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.79 Safari/537.4", 96 | "Mozilla/5.0 (iPad; CPU OS 5_1_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9B206 Safari/7534.48.3", 97 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4", 98 | "Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:15.0) Gecko/20100101 Firefox/15.0.1", 99 | "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534+ (KHTML, like Gecko) BingPreview/1.0b", 100 | "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:14.0) Gecko/20100101 Firefox/14.0.1", 101 | "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:14.0) Gecko/20100101 Firefox/14.0.1", 102 | }; 103 | 104 | char srv[3][32] = 105 | { 106 | "202.108.43.189", 107 | "202.106.182.237", 108 | "home" 109 | }; 110 | 111 | int i = cnt; 112 | while (i--) 113 | { 114 | struct timeval tv; 115 | gettimeofday(&tv, NULL); 116 | long t = tv.tv_usec; 117 | sprintf(cmd, 118 | "GET /Poll.php?project_id=5168&id=49 HTTP/1.%ld\r\n" 119 | // "GET /Poll.php?project_id=5168&id=80 HTTP/1.%ld\r\n" 120 | "Host: hi.video.sina.com.cn\r\n" 121 | "User-Agent: %s\r\n" 122 | "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" 123 | "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n" 124 | "DNT: 1\r\n" 125 | "Client-IP: %ld.%ld.%ld.%ld\r\n" 126 | "Connection: keep-alive\r\n" 127 | "Referer: http://hi.video.sina.com.cn/you/2012banjiti/ph.php?dpc=1\r\n\r\n" 128 | , t % 2,ua[t % 56], 122 + t % 20, 121 + (i + t) % 128, 24 + (i + t) % 135, 24 + (i + t) % 213); 129 | gingko->make_active_connect(srv[i%3], 80, strlen(cmd), cmd, -1, -1, 0, 10); 130 | // gingko->make_active_connect("61.30.127.2", 80, strlen(cmd), cmd, -1, -1, 0, 10); 131 | } 132 | sleep(10); 133 | return 0; 134 | } 135 | 136 | 137 | -------------------------------------------------------------------------------- /example/client2.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * client.cpp 3 | * 4 | * Created on: Feb 27, 2012 5 | * Author: auxten 6 | */ 7 | 8 | #include "gko.h" 9 | 10 | /// gingko global stuff 11 | s_gingko_global_t gko; 12 | const int T_NUM = 100; 13 | const int CMD_CNT = 100; 14 | 15 | const s_host_t server = 16 | { 17 | "127.0.0.1", 18 | 2120 19 | }; 20 | 21 | void * send_test(void *) 22 | { 23 | char msg[MSG_LEN] = 24 | "TEST\tdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"; 25 | for (int i = 0; i < CMD_CNT; i++) 26 | { 27 | if (chat_with_host(&server, msg, 2, 2) < 0) 28 | { 29 | GKOLOG(FATAL, "sending test message failed"); 30 | } 31 | } 32 | // GKOLOG(DEBUG, "%s", msg); 33 | pthread_exit(NULL); 34 | } 35 | 36 | void * send_scmd(void *) 37 | { 38 | char msg[MSG_LEN] = 39 | "SCMD\tlocalhost\tdf -h"; 40 | for (int i = 0; i < CMD_CNT; i++) 41 | { 42 | if (chat_with_host(&server, msg, 2, 2) < 0) 43 | { 44 | GKOLOG(FATAL, "sending test message failed"); 45 | } 46 | } 47 | // GKOLOG(DEBUG, "%s", msg); 48 | pthread_exit(NULL); 49 | } 50 | 51 | int main(int argc, char** argv) 52 | { 53 | gko.opt.to_debug = 1; 54 | pthread_attr_t g_attr; 55 | pthread_t vnode_pthread[T_NUM]; 56 | void *status; 57 | unsigned short proto_ver; 58 | int msg_len; 59 | 60 | // char buf[20] = 61 | // { '\0' }; 62 | // fill_cmd_head(buf, INT32_MAX); 63 | // parse_cmd_head(buf, &proto_ver, &msg_len); 64 | // GKOLOG(DEBUG, "%s %d", buf, msg_len); 65 | // std::vector conn_vec; 66 | // std::vector srv_vec(1000, server); 67 | // connect_hosts(srv_vec, &conn_vec); 68 | // sleep(10); 69 | // disconnect_hosts(conn_vec); 70 | 71 | // char * array[5] = {NULL, NULL, NULL, NULL, NULL}; 72 | // char t1[100] = "aa\t\t\tddd\tbbb\t\tccc\trrr\tyyy"; 73 | // sep_arg(t1, array, 5); 74 | // GKOLOG(DEBUG, "%s, %s, %s, %s, %s", array[0], array[1], array[2], array[3], array[4]); 75 | // GKOLOG(DEBUG, "for test %s %d", "ddd", 10); 76 | // return 0; 77 | 78 | if (pthread_attr_init(&g_attr) != 0) 79 | { 80 | GKOLOG(FATAL, FLF("pthread_mutex_destroy error")); 81 | return -1; 82 | } 83 | if (pthread_attr_setdetachstate(&g_attr, PTHREAD_CREATE_JOINABLE) != 0) 84 | { 85 | GKOLOG(FATAL, FLF("pthread_mutex_destroy error")); 86 | return -1; 87 | } 88 | 89 | for (int i = 0; i < T_NUM; i++) 90 | { 91 | if (pthread_create(&vnode_pthread[i], &g_attr, send_scmd, NULL)) 92 | { 93 | GKOLOG(FATAL, "download thread %d create error", i); 94 | return -1; 95 | } 96 | } 97 | for (int i = 0; i < T_NUM; i++) 98 | { 99 | if (pthread_join(vnode_pthread[i], &status)) 100 | { 101 | GKOLOG(FATAL, "download thread %d join error", i); 102 | return -1; 103 | } 104 | if (status != (void *) 0) 105 | { 106 | GKOLOG(FATAL, "thread %d joined with error num %lld", i, 107 | (long long) status); 108 | return -1; 109 | } 110 | } 111 | 112 | return 0; 113 | } 114 | 115 | -------------------------------------------------------------------------------- /example/server.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * server.cpp 3 | * 4 | * Created on: May 18, 2012 5 | * Author: auxten 6 | */ 7 | #include "gko.h" 8 | /// gingko global stuff 9 | s_gingko_global_t gko; 10 | 11 | 12 | void * conn_send_data(void * arg) 13 | { 14 | int process_ret; 15 | struct conn_client *client = (struct conn_client *) arg; 16 | char * p = ((char *) client->read_buffer) + CMD_PREFIX_BYTE; 17 | GKOLOG(DEBUG, "conn_send_data %s", p); 18 | 19 | client->need_write = snprintf(client->write_buffer, 20 | client->wbuf_size, 21 | "{\"errno\":\"%d\",\"message\":\"%s\"}", 22 | 0, 23 | "Hello World"); 24 | 25 | return NULL; 26 | } 27 | 28 | int main(int argc, char** argv) 29 | { 30 | gko.opt.to_debug = 1; 31 | gko.ready_to_serv = 1; 32 | gko.sig_flag = 0; 33 | gko.opt.worker_thread = 8; 34 | gko.opt.connlimit = SERV_POOL_SIZE; 35 | gko.opt.bind_ip = htons(INADDR_ANY); 36 | // gko.opt.to_debug = 1; 37 | gko_pool * gingko = gko_pool::getInstance(); 38 | gingko->setPort(2121); 39 | gingko->setOption(&gko.opt); 40 | gingko->setProcessHandler(conn_send_data); 41 | // gingko->setReportHandler(report_result); 42 | 43 | 44 | GKOLOG(DEBUG, "Debug mode start, i will print tons of log :p!"); 45 | 46 | return gingko->gko_run(); 47 | } 48 | 49 | -------------------------------------------------------------------------------- /lib/c-ares-1.10.0.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/auxten/gko_pool/aa23c545a1f1e9a8dc1c2be18d0912fa77864d61/lib/c-ares-1.10.0.tar.gz -------------------------------------------------------------------------------- /lib/c-ares-1.10.0_auxten.patch: -------------------------------------------------------------------------------- 1 | diff -u c-ares-1.10.0/ares.h c-ares-1.10.0.patched/ares.h 2 | --- c-ares-1.10.0/ares.h 2013-04-09 04:16:48.000000000 +0800 3 | +++ c-ares-1.10.0.patched/ares.h 2013-06-26 15:35:37.000000000 +0800 4 | @@ -386,6 +386,10 @@ 5 | fd_set *read_fds, 6 | fd_set *write_fds); 7 | 8 | +CARES_EXTERN int ares_fds_array(ares_channel channel, 9 | + ares_socket_t **read_fds, 10 | + ares_socket_t **write_fds); 11 | + 12 | CARES_EXTERN int ares_getsock(ares_channel channel, 13 | ares_socket_t *socks, 14 | int numsocks); 15 | diff -u c-ares-1.10.0/ares_fds.c c-ares-1.10.0.patched/ares_fds.c 16 | --- c-ares-1.10.0/ares_fds.c 2013-02-13 18:01:50.000000000 +0800 17 | +++ c-ares-1.10.0.patched/ares_fds.c 2013-06-26 15:36:32.000000000 +0800 18 | @@ -53,7 +53,64 @@ 19 | FD_SET(server->tcp_socket, write_fds); 20 | if (server->tcp_socket >= nfds) 21 | nfds = server->tcp_socket + 1; 22 | - } 23 | + } 24 | } 25 | return (int)nfds; 26 | } 27 | + 28 | +int ares_fds_array(ares_channel channel, ares_socket_t **read_fds, ares_socket_t **write_fds) 29 | +{ 30 | + struct server_state *server; 31 | + int i; 32 | + int r_cnt = 0; 33 | + int w_cnt = 0; 34 | + int r_size = 128; 35 | + int w_size = 128; 36 | + 37 | + *read_fds = (ares_socket_t *)malloc(r_size * sizeof(ares_socket_t)); 38 | + *write_fds = (ares_socket_t *)malloc(w_size * sizeof(ares_socket_t)); 39 | + 40 | + /* Are there any active queries? */ 41 | + int active_queries = !ares__is_list_empty(&(channel->all_queries)); 42 | + 43 | + for (i = 0; i < channel->nservers; i++) 44 | + { 45 | + server = &channel->servers[i]; 46 | + /* We only need to register interest in UDP sockets if we have 47 | + * outstanding queries. 48 | + */ 49 | + if (active_queries && server->udp_socket != ARES_SOCKET_BAD) 50 | + { 51 | + *(*read_fds + r_cnt++) = server->udp_socket; 52 | + } 53 | + /* We always register for TCP events, because we want to know 54 | + * when the other side closes the connection, so we don't waste 55 | + * time trying to use a broken connection. 56 | + */ 57 | + if (server->tcp_socket != ARES_SOCKET_BAD) 58 | + { 59 | + *(*read_fds + r_cnt++) = server->tcp_socket; 60 | + if (server->qhead) 61 | + { 62 | + *(*write_fds + w_cnt++) = server->tcp_socket; 63 | + } 64 | + } 65 | + if (r_cnt >= r_size - 2) 66 | + { 67 | + r_size *= 2; 68 | + *read_fds = (ares_socket_t *)realloc(*read_fds, r_size * sizeof(ares_socket_t)); 69 | + } 70 | + 71 | + if (w_cnt >= w_size - 2) 72 | + { 73 | + w_size *= 2; 74 | + *write_fds = (ares_socket_t *)realloc(*write_fds, w_size * sizeof(ares_socket_t)); 75 | + } 76 | + 77 | + } 78 | + 79 | + *(*read_fds + r_cnt) = ARES_SOCKET_BAD; 80 | + *(*write_fds + w_cnt) = ARES_SOCKET_BAD; 81 | + 82 | + return r_cnt + w_cnt; 83 | +} 84 | Common subdirectories: c-ares-1.10.0/m4 and c-ares-1.10.0.patched/m4 85 | Common subdirectories: c-ares-1.10.0/vc and c-ares-1.10.0.patched/vc 86 | -------------------------------------------------------------------------------- /lib/jemalloc-3.0.0.tar.bz2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/auxten/gko_pool/aa23c545a1f1e9a8dc1c2be18d0912fa77864d61/lib/jemalloc-3.0.0.tar.bz2 -------------------------------------------------------------------------------- /lib/libev-4.11.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/auxten/gko_pool/aa23c545a1f1e9a8dc1c2be18d0912fa77864d61/lib/libev-4.11.tar.gz -------------------------------------------------------------------------------- /lib/libev_auxten.patch: -------------------------------------------------------------------------------- 1 | diff -upNr libev-4.04/ev.c libev-4.04-fixed/ev.c 2 | --- libev-4.04/ev.c 2011-02-09 07:17:37.000000000 +0800 3 | +++ libev-4.04-fixed/ev.c 2011-09-07 15:29:55.000000000 +0800 4 | @@ -948,6 +948,8 @@ fd_event_nocheck (EV_P_ int fd, int reve 5 | 6 | if (ev) 7 | ev_feed_event (EV_A_ (W)w, ev); 8 | + if (w == (ev_io *)((WL)w)->next) 9 | + break; 10 | } 11 | } 12 | 13 | @@ -1017,7 +1019,11 @@ fd_reify (EV_P) 14 | anfd->events = 0; 15 | 16 | for (w = (ev_io *)anfd->head; w; w = (ev_io *)((WL)w)->next) 17 | - anfd->events |= (unsigned char)w->events; 18 | + { 19 | + anfd->events |= (unsigned char)w->events; 20 | + if (w == (ev_io *)((WL)w)->next) 21 | + break; 22 | + } 23 | 24 | if (o_events != anfd->events) 25 | o_reify = EV__IOFDSET; /* actually |= */ 26 | @@ -1495,6 +1501,8 @@ child_reap (EV_P_ int chain, int pid, in 27 | w->rstatus = status; 28 | ev_feed_event (EV_A_ (W)w, EV_CHILD); 29 | } 30 | + if (w == (ev_child *)((WL)w)->next) 31 | + break; 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /lib/patch_build_all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | sh patch_build_libev.sh 4 | sh patch_build_c-ares.sh 5 | #sh patch_build_jemalloc.sh 6 | 7 | #which mysql_config || echo "can't find mysql_config" 8 | #which mysql_config || exit 1 9 | #sh patch_build_libzdb.sh 10 | 11 | 12 | echo "done!" 13 | 14 | 15 | -------------------------------------------------------------------------------- /lib/patch_build_c-ares.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | NAME='c-ares' 4 | VER='1.10.0' 5 | TYPE='tar.gz' 6 | CONFIGURE_FLAGS='' 7 | 8 | #specify where to install by PREFIX or COMMAND-LINE ARG1 9 | if [ -n "$1" ]; then 10 | PREFIX=$1 11 | else 12 | PREFIX="$PWD/${NAME}-${VER}built" 13 | fi 14 | SRCDIR=${NAME}-${VER} 15 | LIBNAME="${NAME}-${VER}" 16 | if [ -d "${SRCDIR}" ]; then 17 | rm -rf ${SRCDIR} 18 | fi 19 | FILE=${LIBNAME}.${TYPE} 20 | if [ ! -f "${FILE}" ]; then 21 | echo "error: no ${FILE}" 22 | exit 1 23 | fi 24 | tar xvzf ${FILE} 25 | if [ ! -d "${SRCDIR}" ]; then 26 | echo "error: no ${SRCDIR}" 27 | exit 1 28 | fi 29 | 30 | 31 | cp ${LIBNAME}_auxten.patch ${SRCDIR}/ 32 | cd ${SRCDIR} 33 | patch -p1 < ${LIBNAME}_auxten.patch 34 | 35 | ./configure --prefix=${PREFIX} --enable-shared=no --enable-static ${CONFIGURE_FLAGS} 36 | 37 | make; make install 38 | #cp *.h ../c-ares/include/ 39 | cd .. 40 | 41 | rm -rf ${NAME} 42 | ln -s ${NAME}-${VER}built ${NAME} 43 | #rm -rf ${SRCDIR} 44 | 45 | echo "done!" 46 | 47 | 48 | -------------------------------------------------------------------------------- /lib/patch_build_jemalloc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | NAME='jemalloc' 4 | VER='3.0.0' 5 | TYPE='tar.bz2' 6 | CONFIGURE_FLAGS='' 7 | 8 | #specify where to install by PREFIX or COMMAND-LINE ARG1 9 | if [ -n "$1" ]; then 10 | PREFIX=$1 11 | else 12 | PREFIX="$PWD/${NAME}-${VER}built" 13 | fi 14 | SRCDIR=${NAME}-${VER} 15 | LIBNAME="${NAME}-${VER}" 16 | if [ -d "${SRCDIR}" ]; then 17 | rm -rf ${SRCDIR} 18 | fi 19 | FILE=${LIBNAME}.${TYPE} 20 | if [ ! -f "${FILE}" ]; then 21 | echo "error: no ${FILE}" 22 | exit 1 23 | fi 24 | tar xvjf ${FILE} 25 | if [ ! -d "${SRCDIR}" ]; then 26 | echo "error: no ${SRCDIR}" 27 | exit 1 28 | fi 29 | 30 | #cp ${NAME}_auxten.patch ${SRCDIR}/${NAME}_auxten.patch 31 | cd ${SRCDIR} 32 | #patch -p1 < ${NAME}_auxten.patch 33 | 34 | ./configure --prefix=${PREFIX} --enable-shared=no --enable-static ${CONFIGURE_FLAGS} 35 | 36 | make; make install 37 | cd .. 38 | 39 | rm -rf ${NAME} 40 | ln -s ${NAME}-${VER}built ${NAME} 41 | #rm -rf ${SRCDIR} 42 | 43 | echo "done!" 44 | 45 | 46 | -------------------------------------------------------------------------------- /lib/patch_build_libev.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | NAME='libev' 4 | VER='4.11' 5 | TYPE='tar.gz' 6 | CONFIGURE_FLAGS='' 7 | 8 | #specify where to install by PREFIX or COMMAND-LINE ARG1 9 | if [ -n "$1" ]; then 10 | PREFIX=$1 11 | else 12 | PREFIX="$PWD/${NAME}-${VER}built" 13 | fi 14 | SRCDIR=${NAME}-${VER} 15 | LIBNAME="${NAME}-${VER}" 16 | if [ -d "${SRCDIR}" ]; then 17 | rm -rf ${SRCDIR} 18 | fi 19 | FILE=${LIBNAME}.${TYPE} 20 | if [ ! -f "${FILE}" ]; then 21 | echo "error: no ${FILE}" 22 | exit 1 23 | fi 24 | tar xvzf ${FILE} 25 | if [ ! -d "${SRCDIR}" ]; then 26 | echo "error: no ${SRCDIR}" 27 | exit 1 28 | fi 29 | 30 | #cp ${NAME}_auxten.patch ${SRCDIR}/${NAME}_auxten.patch 31 | cd ${SRCDIR} 32 | #patch -p1 < ${NAME}_auxten.patch 33 | 34 | ./configure --prefix=${PREFIX} --enable-shared=no --enable-static ${CONFIGURE_FLAGS} 35 | 36 | make; make install 37 | cd .. 38 | 39 | rm -rf ${NAME} 40 | ln -s ${NAME}-${VER}built ${NAME} 41 | #rm -rf ${SRCDIR} 42 | 43 | echo "done!" 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/AUTHORS: -------------------------------------------------------------------------------- 1 | Wang Pengcheng 2 | -------------------------------------------------------------------------------- /src/ChangeLog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/auxten/gko_pool/aa23c545a1f1e9a8dc1c2be18d0912fa77864d61/src/ChangeLog -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | INCLUDES = \ 2 | -I$(srcdir)/src\ 3 | -include config.h 4 | # -I$(srcdir)/../lib/libev/include \ 5 | # -I$(srcdir)/../lib/c-ares/include 6 | # -I$(srcdir)/../../../../../../third-64/libev/include 7 | # -I$(srcdir)/../../../../../../../third-64/libev/include 8 | export INCLUDES 9 | 10 | #noinst_PROGRAMS=gingko_serv gingko_clnt serv_unittest clnt_unittest 11 | lib_LIBRARIES=libgko.a 12 | 13 | libgko_a_includedir=$(includedir)/ 14 | libgko_a_include_HEADERS = \ 15 | $(srcdir)/gko.h \ 16 | $(srcdir)/gingko.h \ 17 | $(srcdir)/async_pool.h \ 18 | $(srcdir)/log.h \ 19 | $(srcdir)/socket.h \ 20 | $(srcdir)/memory.h \ 21 | $(srcdir)/dict.h \ 22 | $(srcdir)/path.h \ 23 | $(srcdir)/hash/gko_zip.h \ 24 | $(srcdir)/hash/lz4.h \ 25 | $(srcdir)/hash/md5.h \ 26 | $(srcdir)/hash/xor_hash.h \ 27 | $(srcdir)/gko_errno.h 28 | 29 | pkgconfigdir = $(libdir)/pkgconfig 30 | pkgconfig_DATA = libgko.pc 31 | 32 | 33 | DEFS+=-D_GNU_SOURCE -ggdb -funsigned-char -fPIC -DPIC -pipe 34 | libgko_a_SOURCES=async_threads.cpp async_conn.cpp async_clnt.cpp async_dns.cpp \ 35 | gingko_base.cpp log.cpp socket.cpp limit.cpp memory.cpp dict.c path.cpp \ 36 | hash/gko_zip.cpp hash/lz4.cpp hash/md5.cpp hash/xor_hash.cpp 37 | #libgko_a_LDFLAGS=-D_GNU_SOURCE -ggdb -funsigned-char -------------------------------------------------------------------------------- /src/NEWS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/auxten/gko_pool/aa23c545a1f1e9a8dc1c2be18d0912fa77864d61/src/NEWS -------------------------------------------------------------------------------- /src/README: -------------------------------------------------------------------------------- 1 | currently p2p algorithm is complete, could be used for data transfer 2 | usage see --help 3 | ____ _ _ 4 | / ___(_)_ __ __ _| | _____ 5 | | | _| | '_ \ / _` | |/ / _ \ 6 | | |_| | | | | | (_| | < (_) | 7 | \____|_|_| |_|\__, |_|\_\___/ 8 | |___/ 9 | 10 | # Start project gingko 11 | # Gingko is a point to point rsync rolling checksum proto- 12 | # col implemented file synchronize application. Instead 13 | # of original rsync builds, we want to make it able to 14 | # sync files from a large mesh computer network so-called 15 | # the cloud and pushing files from computers to computers, 16 | # the P2P protocol will make it more efficient. 17 | # Hope it success! 18 | 19 | #define Rolling_checksum_algorithm http://samba.anu.edu.au/rsync/tech_report/node3.html 20 | 21 | BUILD: 22 | make 23 | 24 | NOTE: 25 | For reusing some code between clnt and serv, I write some funcs in gingko_common.h 26 | with some MACRO, I know this is ugly, but the bins compiled out work well...so, let it 27 | be. 28 | 29 | DEPS: 30 | libevent 31 | gtest (when ./configure --enable-unittest) 32 | 33 | auxtenwpc@gmail.com 34 | -EOF- 35 | 36 | -------------------------------------------------------------------------------- /src/TODO: -------------------------------------------------------------------------------- 1 | #connection timeout 2 | #connection error update_state() 3 | #r/w transform update time 4 | #nonblocking DNS resolve 5 | make a replacement of my_getaddr 6 | long connection support 7 | mem pool 8 | -------------------------------------------------------------------------------- /src/async_clnt.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * async_clnt.cpp 3 | * 4 | * Created on: May 4, 2012 5 | * Author: auxten 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "config.h" 14 | #include "gingko.h" 15 | #include "log.h" 16 | #include "socket.h" 17 | #ifdef __APPLE__ 18 | #include 19 | #else 20 | #include 21 | #endif /** __APPLE__ **/ 22 | 23 | #include "async_pool.h" 24 | #include "socket.h" 25 | 26 | /** 27 | * @brief non-blocking version connect 28 | * 29 | * @see 30 | * @note 31 | * @author auxten 32 | * @date Apr 22, 2012 33 | **/ 34 | int gko_pool::nb_connect(struct conn_client* conn) 35 | { 36 | int sock = -1; 37 | struct sockaddr_in channel; 38 | 39 | sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 40 | if (FAIL_CHECK(sock < 0)) 41 | { 42 | GKOLOG(FATAL, "get socket error"); 43 | goto NB_CONNECT_END; 44 | } 45 | 46 | memset(&channel, 0, sizeof(channel)); 47 | channel.sin_family = AF_INET; 48 | channel.sin_addr.s_addr = conn->client_addr; 49 | channel.sin_port = htons(conn->client_port); 50 | 51 | /** set the connect non-blocking then blocking for add timeout on connect **/ 52 | if (FAIL_CHECK(setnonblock(sock) < 0)) 53 | { 54 | GKOLOG(FATAL, "set socket non-blocking error"); 55 | goto NB_CONNECT_END; 56 | } 57 | 58 | // GKOLOG(DEBUG, "before connect"); 59 | char ip[16]; 60 | /** connect and send the msg **/ 61 | if (FAIL_CHECK(connect(sock, (struct sockaddr *) &channel, sizeof(channel)) && 62 | errno != EINPROGRESS)) 63 | { 64 | GKOLOG(WARNING, "connect error %s:%d", addr_itoa(conn->client_addr, ip), conn->client_port); 65 | } 66 | // GKOLOG(DEBUG, "after connect"); 67 | 68 | NB_CONNECT_END: 69 | 70 | conn->client_fd = sock; 71 | /// 72 | // ret = sock; 73 | // if (ret < 0 && sock >= 0) 74 | // { 75 | // close_socket(sock); 76 | // } 77 | return sock; 78 | } 79 | 80 | int gko_pool::make_active_connect(const char * host, const int port, int len, const char * cmd, 81 | const long task_id, const long sub_task_id, const u_int8_t flag, const int wrote) 82 | { 83 | struct conn_client * conn; 84 | 85 | conn = add_new_conn_client(FD_BEFORE_CONNECT); 86 | if (!conn) 87 | { 88 | ///close socket and further receives will be disallowed 89 | GKOLOG(FATAL, "Server limited: I cannot serve more clients"); 90 | return SERVER_INTERNAL_ERROR; 91 | } 92 | 93 | int worker_id; 94 | worker_id = thread_list_find_next(); 95 | if (worker_id < 0) 96 | { 97 | GKOLOG(WARNING, "can't find available thread"); 98 | return FAIL; 99 | } 100 | else 101 | { 102 | conn->worker_id = worker_id; 103 | } 104 | 105 | // GKOLOG(DEBUG, "conn_buffer_init"); 106 | conn_buffer_init(conn); 107 | 108 | strncpy(conn->client_hostname, host, sizeof(conn->client_hostname) - 1); 109 | conn->client_hostname[sizeof(conn->client_hostname) - 1] = '\0'; 110 | conn->client_port = port; 111 | 112 | conn->type = active_conn; 113 | conn->task_id = task_id; 114 | conn->sub_task_id = sub_task_id; 115 | 116 | conn->need_write = len; 117 | conn->have_write = wrote; 118 | memcpy(conn->write_buffer, cmd, len); 119 | if (wrote) 120 | { 121 | fill_cmd_head(conn->__write_buffer, len); 122 | // conn->need_read = 1500; 123 | } 124 | thread_worker_dispatch(conn->id, conn->worker_id); 125 | return SUCC; 126 | } 127 | 128 | 129 | -------------------------------------------------------------------------------- /src/async_conn.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * async_conn.cpp 3 | * gingko 4 | * 5 | * Created on: Mar 9, 2012 6 | * Author: auxten 7 | * 8 | **/ 9 | 10 | #include "gingko.h" 11 | #include "async_pool.h" 12 | #include "log.h" 13 | #include "socket.h" 14 | #include "memory.h" 15 | 16 | gko_pool * gko_pool::_instance = NULL; 17 | /// init global lock 18 | pthread_mutex_t gko_pool::instance_lock = PTHREAD_MUTEX_INITIALIZER; 19 | /// init global connecting list lock 20 | pthread_mutex_t gko_pool::conn_list_lock = PTHREAD_MUTEX_INITIALIZER; 21 | /// init global thread list lock 22 | pthread_mutex_t gko_pool::thread_list_lock = PTHREAD_MUTEX_INITIALIZER; 23 | /// init global thread list lock 24 | pthread_mutex_t gko_pool::DNS_cache_lock = PTHREAD_MUTEX_INITIALIZER; 25 | /// init gko_pool::gko_serv 26 | s_host_t gko_pool::gko_serv = {"\0", 0}; 27 | 28 | /** 29 | * @brief Initialization of client list 30 | * 31 | * @see 32 | * @note 33 | * @author wangpengcheng01 34 | * @date 2011-8-1 35 | **/ 36 | int gko_pool::conn_client_list_init() 37 | { 38 | g_client_list = new conn_client *[option->connlimit]; 39 | memset(g_client_list, 0, option->connlimit * sizeof(struct conn_client *)); 40 | g_total_clients = 0; 41 | g_total_connect = 0; 42 | 43 | GKOLOG(NOTICE, "Client pool initialized as %d", option->connlimit); 44 | 45 | return option->connlimit; 46 | } 47 | 48 | /** 49 | * @brief Init for gingko_clnt 50 | * 51 | * @see 52 | * @note 53 | * @author auxten 54 | * @date 2011-8-1 55 | **/ 56 | int gko_pool::gko_async_server_base_init() 57 | { 58 | g_server = new conn_server; 59 | memset(g_server, 0, sizeof(struct conn_server)); 60 | 61 | g_server->srv_addr = option->bind_ip; 62 | if (this->port < 0) 63 | { 64 | unsigned int randseed = (unsigned int)getpid(); 65 | int pt = MAX_LIS_PORT - rand_r(&randseed) % 500; 66 | g_server->srv_port = pt; 67 | } 68 | else 69 | { 70 | g_server->srv_port = this->port; 71 | } 72 | g_server->listen_queue_length = REQ_QUE_LEN; 73 | g_server->nonblock = 1; 74 | g_server->tcp_nodelay = 1; 75 | g_server->tcp_reuse = 1; 76 | g_server->tcp_send_buffer_size = TCP_BUF_SZ; 77 | g_server->tcp_recv_buffer_size = TCP_BUF_SZ; 78 | g_server->send_timeout = SND_TIMEOUT; 79 | g_server->on_data_callback = pHandler; 80 | g_server->is_server = this->port < 0 ? 0 : 1; 81 | /// A new TCP server 82 | int ret; 83 | while ((ret = conn_tcp_server(g_server)) < 0) 84 | { 85 | if (ret == BIND_FAIL) 86 | { 87 | if (g_server->srv_port < MIN_PORT || this->port >= 0) 88 | { 89 | GKOLOG(FATAL, "bind port failed, last try is %d", port); 90 | return -1; 91 | } 92 | g_server->srv_port --; 93 | usleep(BIND_INTERVAL); 94 | } 95 | else 96 | { 97 | GKOLOG(FATAL, "conn_tcp_server start error"); 98 | return -1; 99 | } 100 | } 101 | 102 | set_sig(int_handler); 103 | 104 | ares_library_init(ARES_LIB_INIT_ALL);/// not thread safe 105 | 106 | gko_serv.port = g_server->srv_port; 107 | return g_server->srv_port; 108 | } 109 | 110 | /** 111 | * @brief Generate a TCP server by given struct 112 | * 113 | * @see 114 | * @note 115 | * @author auxten 116 | * @date 2011-8-1 117 | **/ 118 | int gko_pool::conn_tcp_server(struct conn_server *c) 119 | { 120 | int flags; 121 | 122 | if (g_server->srv_port > MAX_PORT) 123 | { 124 | GKOLOG(FATAL, "serv port %d > %d", g_server->srv_port, MAX_PORT); 125 | return -1; 126 | } 127 | 128 | /// If port number below 1024, root privilege needed 129 | if (g_server->srv_port < MIN_PORT) 130 | { 131 | /// CHECK ROOT PRIVILEGE 132 | if (ROOT != geteuid()) 133 | { 134 | GKOLOG(FATAL, "Port %d number below 1024, root privilege needed", 135 | g_server->srv_port); 136 | return -1; 137 | } 138 | } 139 | 140 | /// Create new socket 141 | g_server->listen_fd = socket(AF_INET, SOCK_STREAM, 0); 142 | if (g_server->listen_fd < 0) 143 | { 144 | GKOLOG(WARNING, "Socket creation failed"); 145 | return -1; 146 | } 147 | 148 | if ((flags = fcntl(g_server->listen_fd, F_GETFD)) != -1) 149 | { 150 | fcntl(g_server->listen_fd, F_SETFD, flags | FD_CLOEXEC); 151 | } 152 | 153 | g_server->listen_addr.sin_family = AF_INET; 154 | g_server->listen_addr.sin_addr.s_addr = g_server->srv_addr; 155 | g_server->listen_addr.sin_port = htons(g_server->srv_port); 156 | 157 | setsockopt(g_server->listen_fd, SOL_SOCKET, SO_REUSEADDR, &g_server->tcp_reuse, 158 | sizeof(g_server->tcp_reuse)); 159 | 160 | /// Bind socket 161 | if (bind(g_server->listen_fd, (struct sockaddr *) &g_server->listen_addr, 162 | sizeof(g_server->listen_addr)) < 0) 163 | { 164 | if (g_server->is_server) 165 | { 166 | GKOLOG(FATAL, "Socket bind failed on port"); 167 | return -1; 168 | } 169 | else 170 | { 171 | return BIND_FAIL; 172 | } 173 | } 174 | GKOLOG(NOTICE, "Upload port bind on port %d", g_server->srv_port); 175 | 176 | /// Listen socket 177 | if (listen(g_server->listen_fd, g_server->listen_queue_length) < 0) 178 | { 179 | GKOLOG(FATAL, "Socket listen failed"); 180 | return -1; 181 | } 182 | 183 | /// Set socket options 184 | struct timeval send_timeout; 185 | send_timeout.tv_sec = g_server->send_timeout; 186 | send_timeout.tv_usec = 0; 187 | 188 | setsockopt(g_server->listen_fd, SOL_SOCKET, SO_SNDTIMEO, 189 | (char *) &send_timeout, sizeof(struct timeval)); 190 | setsockopt(g_server->listen_fd, SOL_SOCKET, SO_SNDBUF, 191 | &g_server->tcp_send_buffer_size, sizeof(g_server->tcp_send_buffer_size)); 192 | setsockopt(g_server->listen_fd, SOL_SOCKET, SO_RCVBUF, 193 | &g_server->tcp_recv_buffer_size, sizeof(g_server->tcp_recv_buffer_size)); 194 | setsockopt(g_server->listen_fd, IPPROTO_TCP, TCP_NODELAY, 195 | (char *) &g_server->tcp_nodelay, sizeof(g_server->tcp_nodelay)); 196 | 197 | /// Set socket non-blocking 198 | if (g_server->nonblock && setnonblock(g_server->listen_fd) < 0) 199 | { 200 | GKOLOG(WARNING, "Socket set non-blocking failed"); 201 | return -1; 202 | } 203 | 204 | g_server->start_time = time(NULL); 205 | 206 | ///GKOLOG(WARNING, "Socket server created on port %d", server->srv_port); 207 | ///g_ev_base = event_init(); 208 | /// Add data handler 209 | event_set(&g_server->ev_accept, g_server->listen_fd, EV_READ | EV_PERSIST, 210 | conn_tcp_server_accept, (void *) c); 211 | event_base_set(g_ev_base, &g_server->ev_accept); 212 | event_add(&g_server->ev_accept, NULL); 213 | ///event_base_loop(g_ev_base, 0); 214 | return g_server->listen_fd; 215 | } 216 | 217 | /** 218 | * @brief Accept new connection 219 | * 220 | * @see 221 | * @note 222 | * @author auxten 223 | * @date 2011-8-1 224 | **/ 225 | void gko_pool::conn_tcp_server_accept(int fd, short ev, void *arg) 226 | { 227 | int client_fd; 228 | struct sockaddr_in client_addr; 229 | socklen_t client_len = sizeof(client_addr); 230 | struct conn_client *client; 231 | char ip[16]; 232 | ///struct conn_server *server = (struct conn_server *) arg; 233 | /// Accept new connection 234 | client_fd = accept(fd, (struct sockaddr *) &client_addr, &client_len); 235 | if (-1 == client_fd) 236 | { 237 | GKOLOG(WARNING, "Accept error"); 238 | return; 239 | } 240 | /// Add connection to event queue 241 | client = gko_pool::getInstance()->add_new_conn_client(client_fd); 242 | if (!client) 243 | { 244 | ///close socket and further receives will be disallowed 245 | // shutdown(client_fd, SHUT_RD); 246 | close(client_fd); 247 | GKOLOG(WARNING, "Server limited: I cannot serve more clients"); 248 | return; 249 | } 250 | 251 | /// set blocking 252 | ///fcntl(fd, F_SETFL, fcntl(fd, F_GETFL)& ~O_NONBLOCK); 253 | 254 | /// Try to set non-blocking 255 | if (setnonblock(client_fd) < 0) 256 | { 257 | gko_pool::getInstance()->conn_client_free(client); 258 | GKOLOG(FATAL, "Client socket set non-blocking error"); 259 | return; 260 | } 261 | 262 | /// Client initialize 263 | client->client_addr = inet_addr(inet_ntoa(client_addr.sin_addr)); 264 | client->client_port = ntohs(client_addr.sin_port); 265 | client->type = coming_conn; 266 | 267 | GKOLOG(DEBUG, "coming conn %s:%d", 268 | addr_itoa(client->client_addr, ip), client->client_port); 269 | 270 | gko_pool::getInstance()->thread_worker_dispatch(client->id); 271 | 272 | return; 273 | } 274 | 275 | /** 276 | * @brief ADD New connection client 277 | * 278 | * @see 279 | * @note 280 | * @author auxten 281 | * @date 2011-8-1 282 | **/ 283 | struct conn_client * gko_pool::add_new_conn_client(int client_fd) 284 | { 285 | int id; 286 | struct conn_client *tmp = (struct conn_client *) NULL; 287 | /// Find a free slot 288 | id = conn_client_list_find_free(); 289 | // GKOLOG(DEBUG, "add_new_conn_client id %d",id);///test 290 | if (id >= 0) 291 | { 292 | tmp = conn_client_list_get(id); 293 | } 294 | else 295 | { 296 | /// FIXME 297 | /// Client list pool full, if you want to enlarge it, 298 | /// modify async_pool.h source please 299 | GKOLOG(FATAL, "Client list full"); 300 | return tmp; 301 | } 302 | 303 | if (tmp) 304 | { 305 | tmp->id = id; 306 | tmp->client_fd = client_fd; 307 | g_client_list[id] = tmp; 308 | if (client_fd == FD_BEFORE_CONNECT) 309 | { 310 | g_total_connect++; 311 | } 312 | else 313 | { 314 | g_total_clients++; 315 | } 316 | } 317 | return tmp; 318 | } 319 | 320 | /** 321 | * @brief Find a free slot from client pool 322 | * 323 | * @see 324 | * @note 325 | * @author auxten 326 | * @date 2011-8-1 327 | **/ 328 | int gko_pool::conn_client_list_find_free() 329 | { 330 | int i; 331 | int tmp = -1; 332 | 333 | pthread_mutex_lock(&conn_list_lock); 334 | for (i = 0; i < option->connlimit; i++) 335 | { 336 | tmp = (i + g_curr_conn + 1) % option->connlimit; 337 | if (!g_client_list[tmp] || 0 == g_client_list[tmp]->conn_time) 338 | { 339 | if (!g_client_list[tmp]) 340 | { 341 | g_client_list[tmp] = new conn_client; 342 | memset(g_client_list[tmp], 0, sizeof(conn_client)); 343 | } 344 | 345 | conn_client_clear(g_client_list[tmp]); 346 | g_client_list[tmp]->conn_time = time(NULL); 347 | 348 | g_curr_conn = tmp; 349 | break; 350 | } 351 | } 352 | pthread_mutex_unlock(&conn_list_lock); 353 | 354 | if (i == option->connlimit) 355 | tmp = -1; 356 | return tmp; 357 | } 358 | 359 | /** 360 | * @brief Close a client and free all data 361 | * 362 | * @see 363 | * @note 364 | * @author auxten 365 | * @date 2011-8-1 366 | **/ 367 | int gko_pool::conn_client_free(struct conn_client *client) 368 | { 369 | if (!client || !client->client_fd) 370 | { 371 | return -1; 372 | } 373 | ///close socket and further receives will be disallowed 374 | // shutdown(client->client_fd, SHUT_RD); 375 | close(client->client_fd); 376 | conn_client_clear(client); 377 | g_total_clients--; 378 | 379 | return 0; 380 | } 381 | 382 | void gko_pool::conn_buffer_init(conn_client *client) 383 | { 384 | gko_pool * Pool = gko_pool::getInstance(); 385 | thread_worker * worker = *(Pool->g_worker_list + client->worker_id); 386 | 387 | client->err_no = INVILID; 388 | #if defined (USE_GKO_MEMORY_POOL) 389 | /// todo calloc every connection comes? 390 | client->r_buf_arena_id = worker->mem.get_block(); 391 | client->w_buf_arena_id = worker->mem.get_block(); 392 | assert(client->r_buf_arena_id >= 0); 393 | assert(client->w_buf_arena_id >= 0); 394 | #endif 395 | 396 | #if defined (USE_GKO_MEMORY_POOL) 397 | client->read_buffer = (char *)worker->mem.id2addr(client->r_buf_arena_id); 398 | #else 399 | client->read_buffer = (char *)malloc(RBUF_SZ); 400 | #endif 401 | client->rbuf_size = RBUF_SZ; 402 | client->have_read = 0; 403 | client->need_read = CMD_PREFIX_BYTE; 404 | 405 | /// todo calloc every connection comes? 406 | #if defined (USE_GKO_MEMORY_POOL) 407 | client->__write_buffer = (char *)worker->mem.id2addr(client->w_buf_arena_id); 408 | #else 409 | client->__write_buffer = (char *)malloc(WBUF_SZ); 410 | #endif 411 | client->write_buffer = client->__write_buffer + CMD_PREFIX_BYTE; 412 | client->wbuf_size = WBUF_SZ - CMD_PREFIX_BYTE; 413 | client->have_write = 0; 414 | client->__need_write = CMD_PREFIX_BYTE; 415 | client->need_write = 0; 416 | } 417 | 418 | /** 419 | * @brief Empty client struct data 420 | * 421 | * @see 422 | * @note 423 | * @author auxten 424 | * @date 2011-8-1 425 | **/ 426 | int gko_pool::conn_client_clear(struct conn_client *client) 427 | { 428 | if (client) 429 | { 430 | /// Clear all data 431 | client->client_fd = 0; 432 | client->client_addr = 0; 433 | client->client_port = 0; 434 | client->err_no = SUCC; 435 | thread_worker * worker = *(g_worker_list + client->worker_id); 436 | 437 | /// todo free every connection comes? 438 | if (client->read_buffer) 439 | { 440 | #if defined (USE_GKO_MEMORY_POOL) 441 | if(client->r_buf_arena_id >= 0) 442 | { 443 | worker->mem.free_block(client->r_buf_arena_id); 444 | client->r_buf_arena_id = INVILID_BLOCK; 445 | client->read_buffer = NULL; 446 | } 447 | else 448 | { 449 | #endif 450 | 451 | free(client->read_buffer); 452 | client->read_buffer = NULL; 453 | #if defined (USE_GKO_MEMORY_POOL) 454 | } 455 | #endif 456 | } 457 | client->rbuf_size = RBUF_SZ; 458 | client->have_read = 0; 459 | client->need_read = CMD_PREFIX_BYTE; 460 | 461 | /// todo free every connection comes? 462 | if (client->__write_buffer) 463 | { 464 | #if defined (USE_GKO_MEMORY_POOL) 465 | if(client->w_buf_arena_id >= 0) 466 | { 467 | worker->mem.free_block(client->w_buf_arena_id); 468 | client->w_buf_arena_id = INVILID_BLOCK; 469 | client->__write_buffer = NULL; 470 | } 471 | else 472 | { 473 | #endif 474 | free(client->__write_buffer); 475 | client->__write_buffer = NULL; 476 | #if defined (USE_GKO_MEMORY_POOL) 477 | } 478 | #endif 479 | } 480 | client->wbuf_size = WBUF_SZ - CMD_PREFIX_BYTE; 481 | client->have_write = 0; 482 | client->__need_write = CMD_PREFIX_BYTE; 483 | client->need_write = 0; 484 | 485 | /// Delete event 486 | event_del(&client->event); 487 | 488 | /// Delete DNS event 489 | del_dns_event(client); 490 | /** 491 | * this is the flag of client usage, 492 | * we must put it in the last place 493 | */ 494 | client->conn_time = 0; 495 | return 0; 496 | } 497 | return -1; 498 | } 499 | 500 | int gko_pool::conn_renew(struct conn_client *client) 501 | { 502 | if (client) 503 | { 504 | /** 505 | * this is the flag of client usage, 506 | * we must put it in the last place 507 | */ 508 | client->conn_time = time(NULL); 509 | /// Clear all data 510 | client->err_no = SUCC; 511 | client->task_id = -1; 512 | client->sub_task_id = -1; 513 | thread_worker * worker = *(g_worker_list + client->worker_id); 514 | 515 | if (client->read_buffer) 516 | { 517 | #if defined (USE_GKO_MEMORY_POOL) 518 | if(client->r_buf_arena_id >= 0) 519 | { 520 | worker->mem.free_block(client->r_buf_arena_id); 521 | client->r_buf_arena_id = INVILID_BLOCK; 522 | client->read_buffer = NULL; 523 | } 524 | else 525 | { 526 | #endif 527 | free(client->read_buffer); 528 | client->read_buffer = NULL; 529 | #if defined (USE_GKO_MEMORY_POOL) 530 | } 531 | #endif 532 | } 533 | 534 | #if defined (USE_GKO_MEMORY_POOL) 535 | client->r_buf_arena_id = worker->mem.get_block(); 536 | client->read_buffer = (char *)worker->mem.id2addr(client->r_buf_arena_id); 537 | #else 538 | client->read_buffer = (char *)malloc(RBUF_SZ); 539 | #endif 540 | 541 | client->rbuf_size = RBUF_SZ; 542 | client->have_read = 0; 543 | client->need_read = CMD_PREFIX_BYTE; 544 | 545 | /// todo free every connection comes? 546 | if (client->__write_buffer) 547 | { 548 | #if defined (USE_GKO_MEMORY_POOL) 549 | if(client->w_buf_arena_id >= 0) 550 | { 551 | worker->mem.free_block(client->w_buf_arena_id); 552 | client->w_buf_arena_id = INVILID_BLOCK; 553 | client->__write_buffer = NULL; 554 | } 555 | else 556 | { 557 | #endif 558 | free(client->__write_buffer); 559 | client->__write_buffer = NULL; 560 | #if defined (USE_GKO_MEMORY_POOL) 561 | } 562 | #endif 563 | } 564 | 565 | #if defined (USE_GKO_MEMORY_POOL) 566 | client->w_buf_arena_id = worker->mem.get_block(); 567 | client->__write_buffer = (char *)worker->mem.id2addr(client->w_buf_arena_id); 568 | #else 569 | client->__write_buffer = (char *)malloc(WBUF_SZ); 570 | #endif 571 | client->write_buffer = client->__write_buffer + CMD_PREFIX_BYTE; 572 | 573 | client->wbuf_size = WBUF_SZ - CMD_PREFIX_BYTE; 574 | client->have_write = 0; 575 | client->__need_write = CMD_PREFIX_BYTE; 576 | client->need_write = 0; 577 | 578 | 579 | return 0; 580 | } 581 | 582 | return -1; 583 | } 584 | /** 585 | * @brief Get client object from pool by given client_id 586 | * 587 | * @see 588 | * @note 589 | * @author auxten 590 | * @date 2011-8-1 591 | **/ 592 | struct conn_client * gko_pool::conn_client_list_get(int id) 593 | { 594 | return g_client_list[id]; 595 | } 596 | 597 | 598 | gko_pool::gko_pool(const int pt) 599 | : 600 | g_curr_thread(0), 601 | g_curr_conn(0), 602 | g_server(NULL), 603 | port(pt), 604 | pHandler(NULL), 605 | reportHandler(NULL), 606 | HMTRHandler(defaultHMTRHandler) 607 | { 608 | DNSDict = init_dns_cache(); 609 | g_ev_base = (struct event_base*)event_init(); 610 | if (!g_ev_base) 611 | { 612 | GKOLOG(FATAL, "event init failed"); 613 | } 614 | } 615 | 616 | gko_pool::gko_pool() 617 | : 618 | g_curr_thread(0), 619 | g_curr_conn(0), 620 | g_server(NULL), 621 | port(-1), 622 | pHandler(NULL), 623 | reportHandler(NULL), 624 | HMTRHandler(defaultHMTRHandler) 625 | { 626 | DNSDict = init_dns_cache(); 627 | g_ev_base = (struct event_base*)event_init(); 628 | if (!g_ev_base) 629 | { 630 | GKOLOG(FATAL, "event init failed"); 631 | } 632 | } 633 | 634 | int gko_pool::getPort() const 635 | { 636 | return port; 637 | } 638 | 639 | void gko_pool::setPort(int port) 640 | { 641 | this->port = port; 642 | } 643 | 644 | s_option_t *gko_pool::getOption() const 645 | { 646 | return option; 647 | } 648 | 649 | void gko_pool::setOption(s_option_t *option) 650 | { 651 | this->option = option; 652 | } 653 | 654 | void gko_pool::setProcessHandler(ProcessHandler_t process_func) 655 | { 656 | this->pHandler = process_func; 657 | } 658 | 659 | void gko_pool::setReportHandler(ReportHandler_t report_func) 660 | { 661 | this->reportHandler = report_func; 662 | } 663 | 664 | /** 665 | * @brief 666 | * set "How Many To Read" handler 667 | * 668 | * @see 669 | * @note 670 | * the handler prototype is as: 671 | * int (*HMTRHandler_t)(void *, const char *, const int); 672 | * 673 | * @ret: 674 | * n == 0 --> need read more 675 | * n > 0 --> need read n byte(s) in total, NOT n byte(s) more!! 676 | * n < 0 --> an error in the message 677 | * 678 | * @args: 679 | * void * --> for the specified connection 680 | * const char * --> the data already read 681 | * const int --> the data count already read, in byte 682 | * 683 | * @author auxten 684 | * @date 2012-9-29 685 | **/ 686 | void gko_pool::setHMTRHandler(HMTRHandler_t HMTR_func) 687 | { 688 | this->HMTRHandler = HMTR_func; 689 | } 690 | 691 | gko_pool *gko_pool::getInstance() 692 | { if (! _instance) 693 | { 694 | pthread_mutex_lock(&instance_lock); 695 | if (!_instance) 696 | { 697 | _instance = new gko_pool(); 698 | } 699 | pthread_mutex_unlock(&instance_lock); 700 | } 701 | return _instance; 702 | } 703 | 704 | int gko_pool::gko_run() 705 | { 706 | 707 | if (port >= 0 && gko_async_server_base_init() < 0) 708 | { 709 | GKOLOG(FATAL, "gko_async_server_base_init failed"); 710 | return -2; 711 | } 712 | 713 | if (conn_client_list_init() < 1) 714 | { 715 | GKOLOG(FATAL, "conn_client_list_init failed"); 716 | return -3; 717 | } 718 | if (thread_init() != 0) 719 | { 720 | GKOLOG(FATAL, FLF("thread_init failed")); 721 | return -4; 722 | } 723 | 724 | if (sig_watcher(int_worker) != 0) 725 | { 726 | GKOLOG(FATAL, "signal watcher start error");//todo 727 | gko_quit(1); 728 | } 729 | 730 | return event_base_loop(g_ev_base, 0); 731 | } 732 | -------------------------------------------------------------------------------- /src/async_dns.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * async_dns.cpp 3 | * 4 | * Created on: May 22, 2012 5 | * Author: auxten 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include "event.h" 15 | #include "ares.h" 16 | #include "dict.h" 17 | #include "gko.h" 18 | 19 | static const time_t DNS_EXPIRE_TIME = -1; 20 | 21 | typedef struct DNSCacheVal 22 | { 23 | time_t expire_time; 24 | in_addr_t addr; 25 | } DNSCacheVal; 26 | 27 | /* And a case insensitive str hash function (based on dictGenCaseHashFunction hash) */ 28 | unsigned int dictGenStrCaseHashFunction(const void *p) 29 | { 30 | unsigned char *buf = (unsigned char *) p; 31 | unsigned int hash = (unsigned int) DICT_HASH_FUNCTION_SEED; 32 | 33 | while (*buf != '\0') 34 | hash = ((hash << 5) + hash) + (tolower(*buf++)); /* hash * 33 + c */ 35 | return hash; 36 | } 37 | 38 | int dictStrCaseKeyCompare(void *privdata, const void *key1, const void *key2) 39 | { 40 | DICT_NOTUSED(privdata); 41 | return strcasecmp((const char *) key1, (const char *) key2) == 0; 42 | } 43 | 44 | void * strKeyDup(void *privdata, const void *key) 45 | { 46 | DICT_NOTUSED(privdata); 47 | return (void *) strdup((const char *) key); 48 | } 49 | 50 | void strKeyDestructor(void *privdata, void *key) 51 | { 52 | DICT_NOTUSED(privdata); 53 | free(key); 54 | } 55 | 56 | void strValDestructor(void *privdata, void *key) 57 | { 58 | DICT_NOTUSED(privdata); 59 | free(key); 60 | } 61 | 62 | dictType DNSDictType = 63 | { 64 | dictGenStrCaseHashFunction, /* hash function */ 65 | strKeyDup, /* key dup */ 66 | NULL, /* val dup */ 67 | dictStrCaseKeyCompare, /* key compare */ 68 | strKeyDestructor, /* key destructor */ 69 | strValDestructor /* val destructor */ 70 | }; 71 | 72 | dict * gko_pool::init_dns_cache(void) 73 | { 74 | return dictCreate(&DNSDictType, NULL); 75 | } 76 | 77 | /** 78 | * try if hostname hit the cache, so we save a query 79 | * @param conn_client * 80 | * @return if hit cache return 0, elsewise -1 81 | */ 82 | int gko_pool::try_dns_cache(conn_client *c) 83 | { 84 | int ret; 85 | if (DNS_EXPIRE_TIME <= 0) 86 | { 87 | ret = -1; 88 | return ret; 89 | } 90 | 91 | DNSCacheVal *val; 92 | time_t now = time(NULL); 93 | 94 | pthread_mutex_lock(&DNS_cache_lock); 95 | val = (DNSCacheVal *)dictFetchValue(DNSDict, c->client_hostname); 96 | if (val != NULL) 97 | { 98 | /// hit ! 99 | if (val->expire_time < now) 100 | { 101 | /// TTL expire 102 | dictDelete(DNSDict, c->client_hostname); 103 | ret = -1; 104 | } 105 | else 106 | { 107 | /// within TTL 108 | c->client_addr = val->addr; 109 | ret = 0; 110 | } 111 | } 112 | else 113 | { 114 | /// not hit 115 | ret = -1; 116 | } 117 | pthread_mutex_unlock(&DNS_cache_lock); 118 | return ret; 119 | } 120 | 121 | void gko_pool::update_dns_cache(conn_client *c, in_addr_t addr) 122 | { 123 | if (DNS_EXPIRE_TIME <= 0) 124 | { 125 | return; 126 | } 127 | pthread_mutex_lock(&DNS_cache_lock); 128 | DNSCacheVal * val = (DNSCacheVal *)malloc(sizeof (DNSCacheVal)); 129 | val->addr = addr; 130 | val->expire_time = time(NULL) + DNS_EXPIRE_TIME; /// 131 | dictReplace(DNSDict, c->client_hostname, val); 132 | pthread_mutex_unlock(&DNS_cache_lock); 133 | } 134 | 135 | int gko_pool::del_dns_event(conn_client *c) 136 | { 137 | for (std::vector::iterator it = c->ev_dns_vec.begin(); 138 | it != c->ev_dns_vec.end(); 139 | ++it) 140 | { 141 | event_del(*it); 142 | free(*it); 143 | } 144 | c->ev_dns_vec.clear(); 145 | return 0; 146 | } 147 | 148 | void gko_pool::dns_callback(void* arg, int status, int timeouts, struct hostent* host) 149 | { 150 | conn_client *c = (conn_client *) arg; 151 | 152 | if (status == ARES_SUCCESS) 153 | { 154 | u_int32_t addr = *(in_addr_t *) host->h_addr; 155 | c->client_addr = addr; 156 | gko_pool::getInstance()->update_dns_cache(c, addr); 157 | conn_set_state(c, conn_connecting); 158 | GKOLOG(DEBUG, "DNS OK %s ==> %u.%u.%u.%u", 159 | host->h_name, 160 | (addr) % 256, (addr >> 8) % 256, (addr >> 16) % 256, (addr >> 24) % 256); 161 | } 162 | else 163 | { 164 | c->err_no = DNS_RESOLVE_FAIL; 165 | conn_set_state(c, conn_closing); 166 | GKOLOG(WARNING, "lookup failed: %s", ares_strerror(status)); 167 | } 168 | del_dns_event(c); 169 | 170 | /// call my lovly state_machine~~~ mua~ 171 | state_machine(c); 172 | } 173 | 174 | void gko_pool::dns_ev_callback(int fd, short ev, void *arg) 175 | { 176 | gko_pool * Pool = gko_pool::getInstance(); 177 | conn_client *c = (conn_client *) arg; 178 | thread_worker * w = *(Pool->g_worker_list + c->worker_id); 179 | 180 | if (c->state == conn_closing) 181 | { 182 | GKOLOG(FATAL, "closing socket have DNS event"); 183 | del_dns_event(c); 184 | state_machine(c); 185 | return; 186 | } 187 | ares_channel ch = w->dns_channel; 188 | if (ev & EV_READ) 189 | ares_process_fd(ch, fd, ARES_SOCKET_BAD); 190 | if (ev & EV_WRITE) 191 | ares_process_fd(ch, ARES_SOCKET_BAD, fd); 192 | if (ev & EV_TIMEOUT) 193 | { 194 | ares_process_fd(ch, fd, fd); 195 | c->err_no = DNS_RESOLVE_FAIL; 196 | conn_set_state(c, conn_closing); 197 | GKOLOG(FATAL, "dns timeout"); 198 | del_dns_event(c); 199 | state_machine(c); 200 | } 201 | } 202 | 203 | void gko_pool::nb_gethostbyname(conn_client *c) 204 | { 205 | ares_socket_t *read_fds; 206 | ares_socket_t *write_fds; 207 | // struct timeval timeout = {5, 0}; 208 | 209 | // gko_pool * Pool = gko_pool::getInstance(); 210 | thread_worker * worker = *(g_worker_list + c->worker_id); 211 | 212 | ares_gethostbyname(worker->dns_channel, c->client_hostname, AF_INET, dns_callback, (void *) c); 213 | ares_fds_array(worker->dns_channel, &read_fds, &write_fds); 214 | 215 | if ((*read_fds == *write_fds) && (*write_fds == ARES_SOCKET_BAD)) 216 | { 217 | // GKOLOG(DEBUG, "error no fd"); 218 | del_dns_event(c); 219 | free(read_fds); 220 | free(write_fds); 221 | return; 222 | } 223 | 224 | for (int i = 0; *(read_fds + i) != ARES_SOCKET_BAD; i++) 225 | { 226 | struct event * ev_tmp = (struct event *) malloc(sizeof(struct event)); 227 | event_set(ev_tmp, *(read_fds + i), EV_READ | EV_PERSIST, dns_ev_callback, 228 | (void *) (c)); 229 | event_base_set(worker->ev_base, ev_tmp); 230 | event_add(ev_tmp, NULL); 231 | 232 | c->ev_dns_vec.push_back(ev_tmp); 233 | } 234 | for (int i = 0; *(write_fds + i) != ARES_SOCKET_BAD; i++) 235 | { 236 | struct event * ev_tmp = (struct event *) malloc(sizeof(struct event)); 237 | event_set(ev_tmp, *(write_fds + i), EV_WRITE | EV_PERSIST, dns_ev_callback, 238 | (void *) (c)); 239 | event_base_set(worker->ev_base, ev_tmp); 240 | event_add(ev_tmp, NULL); 241 | 242 | c->ev_dns_vec.push_back(ev_tmp); 243 | } 244 | 245 | free(read_fds); 246 | free(write_fds); 247 | } 248 | -------------------------------------------------------------------------------- /src/async_pool.h: -------------------------------------------------------------------------------- 1 | /** 2 | * async_pool.h 3 | * gingko 4 | * 5 | * Created on: Mar 9, 2012 6 | * Author: auxten 7 | * 8 | **/ 9 | #ifndef ASYNC_POOL_H_ 10 | #define ASYNC_POOL_H_ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | #include "ares.h" 31 | #include "event.h" 32 | #include "memory.h" 33 | #include "dict.h" 34 | 35 | #include "gko_errno.h" 36 | 37 | static const int RBUF_SZ = SLOT_SIZE; 38 | static const int WBUF_SZ = SLOT_SIZE; 39 | static const u_int8_t F_KEEPALIVE = 0x01; 40 | static const u_int8_t F_CONN_REUSE = 0x02; 41 | 42 | /// Thread worker 43 | class thread_worker 44 | { 45 | public: 46 | int id; 47 | pthread_t tid; 48 | struct event_base *ev_base; 49 | struct event ev_notify; 50 | struct event ev_cleantimeout; 51 | int notify_recv_fd; 52 | int notify_send_fd; 53 | std::set conn_set; 54 | ares_channel dns_channel; 55 | gkoAlloc mem; 56 | void * userData; 57 | 58 | /// put conn into current thread conn_set 59 | void add_conn(int c_id); 60 | /// del conn from current thread conn_set 61 | void del_conn(int c_id); 62 | }; 63 | 64 | enum conn_states { 65 | conn_nouse = 0, 66 | conn_listening, /**< now the main schedule thread do the accept */ 67 | conn_waiting, /**< waiting for a readable socket */ 68 | conn_read, /**< reading the cmd header */ 69 | conn_nread, /**< reading in a fixed number of bytes */ 70 | conn_parse_header, /**< try to parse the cmd header */ 71 | conn_parse_cmd, /**< try to parse a command from the input buffer */ 72 | conn_write, /**< writing out a simple response */ 73 | conn_mwrite, /**< writing out many items sequentially */ 74 | conn_state_renew, /**< reset conn for following requests(long connection) */ 75 | conn_closing, /**< closing this connection */ 76 | 77 | /// for client side 78 | conn_connecting = 101, 79 | conn_dns_cache, /**< try internal DNS cache */ 80 | conn_resolving, /**< resoving DNS */ 81 | 82 | conn_max_state /**< Max state value (used for assertion) */ 83 | }; 84 | 85 | enum conn_type { 86 | coming_conn = 0, /// this is default 87 | active_conn = 1 88 | }; 89 | 90 | /// Connection client 91 | struct conn_client 92 | { 93 | int id; 94 | int worker_id; 95 | int client_fd; 96 | long task_id; 97 | long sub_task_id; 98 | in_addr_t client_addr; 99 | int client_port; 100 | time_t conn_time; 101 | func_t handle_client; 102 | struct event event; 103 | std::vector ev_dns_vec; 104 | enum conn_states state; 105 | enum error_no err_no; 106 | enum conn_type type; 107 | int ev_flags; 108 | 109 | void * userData; 110 | 111 | int r_buf_arena_id; 112 | char *read_buffer; 113 | unsigned int rbuf_size; 114 | unsigned int need_read; 115 | unsigned int have_read; 116 | 117 | int w_buf_arena_id; 118 | char *__write_buffer; 119 | char *write_buffer; 120 | unsigned int wbuf_size; 121 | unsigned int __need_write; 122 | unsigned int need_write; 123 | unsigned int have_write; 124 | char client_hostname[MAX_HOST_NAME + 1]; 125 | 126 | }; 127 | 128 | /// Connection server struct 129 | struct conn_server 130 | { 131 | char is_server; 132 | int listen_fd; 133 | struct sockaddr_in listen_addr; 134 | in_addr_t srv_addr; 135 | int srv_port; 136 | unsigned int start_time; 137 | int nonblock; 138 | int listen_queue_length; 139 | int tcp_send_buffer_size; 140 | int tcp_recv_buffer_size; 141 | int send_timeout; 142 | int tcp_reuse; 143 | int tcp_nodelay; 144 | struct event ev_accept; 145 | //void *(* on_data_callback)(void *); 146 | ProcessHandler_t on_data_callback; 147 | }; 148 | 149 | enum aread_result { 150 | READ_DATA_RECEIVED, 151 | READ_HEADER_RECEIVED, 152 | READ_NEED_MORE, 153 | READ_NO_DATA_RECEIVED, 154 | READ_ERROR, /** an error occured (on the socket) (or client closed connection) */ 155 | READ_MEMORY_ERROR /** failed to allocate more memory */ 156 | }; 157 | 158 | enum awrite_result { 159 | WRITE_DATA_SENT, 160 | WRITE_HEADER_SENT, 161 | WRITE_SENT_MORE, 162 | WRITE_NO_DATA_SENT, 163 | WRITE_ERROR /** an error occured (on the socket) (or client closed connection) */ 164 | }; 165 | 166 | /// default HMTR handler for "0000000005HELLO" style msg 167 | int defaultHMTRHandler(void * p, const char * buf, const int len); 168 | 169 | 170 | class gko_pool 171 | { 172 | private: 173 | static gko_pool * _instance; 174 | /// global lock 175 | static pthread_mutex_t instance_lock; 176 | static pthread_mutex_t conn_list_lock; 177 | static pthread_mutex_t thread_list_lock; 178 | static pthread_mutex_t DNS_cache_lock; 179 | 180 | int g_curr_thread; 181 | int g_curr_conn; 182 | 183 | thread_worker ** g_worker_list; 184 | struct event_base *g_ev_base; 185 | int g_total_clients; 186 | int g_total_connect; 187 | struct conn_client **g_client_list; 188 | struct conn_server *g_server; 189 | int port; 190 | s_option_t * option; 191 | ProcessHandler_t pHandler; 192 | ReportHandler_t reportHandler; 193 | HMTRHandler_t HMTRHandler; 194 | dict * DNSDict; 195 | 196 | static void conn_send_data(void *c); 197 | /// Accept new connection 198 | static void conn_tcp_server_accept(int fd, short ev, void *arg); 199 | /// Close conn, shutdown && close 200 | static void * thread_worker_init(void *arg); 201 | /// Close conn, shutdown && close 202 | static void thread_worker_process(int fd, short ev, void *arg); 203 | /// Connection buffer init 204 | static void conn_buffer_init(conn_client *client); 205 | /// ReAdd the event 206 | static bool update_event(conn_client *c, const int new_flags); 207 | /// State updater 208 | static void conn_set_state(conn_client *c, enum conn_states state); 209 | /// Event handler for worker thread 210 | static void worker_event_handler(const int fd, const short which, void *arg); 211 | /// Event handler for clean up timeout conn 212 | static void clean_handler(const int fd, const short which, void *arg); 213 | /// Async read 214 | static enum aread_result aread(conn_client *c); 215 | /// Async write 216 | static enum awrite_result awrite(conn_client *c); 217 | /// The drive machine of memcached 218 | static void state_machine(conn_client *c); 219 | 220 | /// non-blocking version connect 221 | int nb_connect(struct conn_client* conn); 222 | int connect_hosts(const std::vector & host_vec, 223 | std::vector * conn_vec); 224 | int disconnect_hosts(std::vector & conn_vec); 225 | 226 | /// DNS cache 227 | dict * init_dns_cache(void); 228 | int try_dns_cache(conn_client *c); 229 | void update_dns_cache(conn_client *c, in_addr_t addr); 230 | 231 | 232 | /// non-blocking DNS 233 | static int del_dns_event(conn_client *c); 234 | static void dns_callback(void* arg, int status, int timeouts, struct hostent* host); 235 | static void dns_ev_callback(int fd, short ev, void *arg); 236 | void nb_gethostbyname(conn_client *c); 237 | 238 | int clean_conn_timeout(thread_worker *worker, time_t now); 239 | int thread_worker_new(int id); 240 | int thread_list_find_next(void); 241 | int conn_client_list_init(void); 242 | int gko_async_server_base_init(void); 243 | /// Accept new connection, start listen etc. 244 | int conn_tcp_server(struct conn_server *c); 245 | /// Accept new connection 246 | struct conn_client * add_new_conn_client(int client_fd); 247 | /// Event on data from client 248 | int conn_client_list_find_free(); 249 | /// reset conn for following requests(long connection) 250 | int conn_renew(struct conn_client *client); 251 | /// clear client struct 252 | int conn_client_clear(struct conn_client *client); 253 | /// clear the "session" 254 | int conn_client_free(struct conn_client *client); 255 | /// Get client object from pool by given client_id 256 | struct conn_client * conn_client_list_get(int id); 257 | /// Dispatch to worker to a thread 258 | void thread_worker_dispatch(int c_id); 259 | /// Dispatch to worker to the thread 260 | void thread_worker_dispatch(int c_id, int worker_id); 261 | /// init the whole thread pool 262 | int thread_init(); 263 | /// construct func 264 | gko_pool(const int pt); 265 | /// another construct func 266 | gko_pool(); 267 | 268 | public: 269 | static s_host_t gko_serv; 270 | 271 | static gko_pool *getInstance(); 272 | 273 | void setProcessHandler(ProcessHandler_t func_list); 274 | void setReportHandler(ReportHandler_t report_func); 275 | void setHMTRHandler(HMTRHandler_t HMTR_func); 276 | int getPort() const; 277 | void setPort(int port); 278 | s_option_t *getOption() const; 279 | void setOption(s_option_t *option); 280 | 281 | thread_worker * getWorker(const struct conn_client *); 282 | /// global run func 283 | int gko_run(); 284 | int gko_loopexit(int timeout); 285 | 286 | int make_active_connect(const char * host, const int port, int len, const char * cmd, 287 | const long task_id = -1, const long sub_task_id = -1, 288 | const u_int8_t flag = 0, const int wrote = 0); 289 | 290 | }; 291 | 292 | #endif /** ASYNC_POOL_H_ **/ 293 | -------------------------------------------------------------------------------- /src/autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | if [ -x "`which autoreconf 2>/dev/null`" ] ; then 3 | exec autoreconf --verbose --force -i 4 | fi 5 | 6 | LIBTOOLIZE=libtoolize 7 | SYSNAME=`uname` 8 | if [ "x$SYSNAME" = "xDarwin" ] ; then 9 | LIBTOOLIZE=glibtoolize 10 | fi 11 | aclocal && \ 12 | autoheader && \ 13 | autoconf && \ 14 | automake --add-missing --force-missing --copy 15 | -------------------------------------------------------------------------------- /src/configure.in: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | 4 | AC_PREREQ([1.68]) 5 | AC_INIT([libgko.a], [3.14], [blog.optool.net]) 6 | AC_CONFIG_SRCDIR([config.h.in]) 7 | AM_CONFIG_HEADER([config.h]) 8 | #AC_CONFIG_HEADERS([config.h]) 9 | AM_INIT_AUTOMAKE([libgko.a],3.14) 10 | 11 | ########################################################################## 12 | # debug compilation support 13 | ########################################################################## 14 | 15 | AC_MSG_CHECKING([whether to build with debug information]) 16 | AC_ARG_ENABLE([debug], 17 | [AS_HELP_STRING([--enable-debug], 18 | [enable debug data generation (def=no)])], 19 | [debugit="$enableval"], 20 | [debugit=no]) 21 | AC_MSG_RESULT([$debugit]) 22 | 23 | if test x"$debugit" = x"yes"; then 24 | AC_DEFINE([GKO_DEBUG],[],[Debug Mode]) 25 | AM_CXXFLAGS="-ggdb -Wall -O0" 26 | CXXFLAGS="-ggdb -Wall -O0" 27 | else 28 | AC_DEFINE([NGKO_DEBUG],[],[No-debug Mode]) 29 | AM_CXXFLAGS="-ggdb -Wall -O2 -march=nocona" 30 | CXXFLAGS="-ggdb -Wall -O2 -march=nocona" 31 | fi 32 | 33 | AC_SUBST([AM_CXXFLAGS]) 34 | ########################################################################## 35 | 36 | ########################################################################## 37 | # unittest compilation support 38 | ########################################################################## 39 | 40 | AC_MSG_CHECKING([whether to build unittest version]) 41 | AC_ARG_ENABLE([unittest], 42 | [AS_HELP_STRING([--enable-unittest], 43 | [enable unittest code generation (def=no)])], 44 | [unittestit="$enableval"], 45 | [unittestit=no]) 46 | AC_MSG_RESULT([$unittestit]) 47 | 48 | if test x"$unittestit" = x"yes"; then 49 | AC_DEFINE([UNITTEST],[],[Unittest Mode]) 50 | AM_CXXFLAGS="-ggdb -Wall" 51 | CXXFLAGS="-ggdb -Wall" 52 | else 53 | AC_DEFINE([NUNITTEST],[],[No-unittest Mode]) 54 | AM_CXXFLAGS="$AM_CXXFLAGS" 55 | fi 56 | 57 | AC_SUBST([AM_CXXFLAGS]) 58 | ########################################################################## 59 | 60 | ########################################################################## 61 | # profile compilation support 62 | ########################################################################## 63 | 64 | AC_MSG_CHECKING([whether to build with profile information]) 65 | AC_ARG_ENABLE([profile], 66 | [AS_HELP_STRING([--enable-profile], 67 | [enable profile code generation (def=no)])], 68 | [profileit="$enableval"], 69 | [profileit=no]) 70 | AC_MSG_RESULT([$profileit]) 71 | 72 | if test x"$profileit" = x"yes"; then 73 | AC_DEFINE([PROFILE],[],[Profile Mode]) 74 | AM_CXXFLAGS="-ggdb -Wall -lprofiler" 75 | else 76 | AC_DEFINE([NPROFILE],[],[No-profile Mode]) 77 | AM_CXXFLAGS="$AM_CXXFLAGS" 78 | fi 79 | 80 | AC_SUBST([AM_CXXFLAGS]) 81 | ########################################################################## 82 | 83 | ########################################################################## 84 | # gprofile compilation support 85 | ########################################################################## 86 | 87 | AC_MSG_CHECKING([whether to build with gprofile information]) 88 | AC_ARG_ENABLE([gprofile], 89 | [AS_HELP_STRING([--enable-gprofile], 90 | [enable gprofile code generation (def=no)])], 91 | [gprofileit="$enableval"], 92 | [gprofileit=no]) 93 | AC_MSG_RESULT([$gprofileit]) 94 | 95 | if test x"$gprofileit" = x"yes"; then 96 | AC_DEFINE([GPROFILE],[],[Profile Mode]) 97 | AM_CXXFLAGS="-ggdb -Wall -pg" 98 | else 99 | AC_DEFINE([NGPROFILE],[],[No-gprofile Mode]) 100 | AM_CXXFLAGS="$AM_CXXFLAGS" 101 | fi 102 | 103 | AC_SUBST([AM_CXXFLAGS]) 104 | ########################################################################## 105 | 106 | ########################################################################## 107 | # O3 optimize compilation support 108 | ########################################################################## 109 | 110 | AC_MSG_CHECKING([whether to build with O3 optimization]) 111 | AC_ARG_ENABLE([o3], 112 | [AS_HELP_STRING([--enable-o3], 113 | [enable O3 code generation (def=no)])], 114 | [o3it="$enableval"], 115 | [o3it=no]) 116 | AC_MSG_RESULT([$o3it]) 117 | 118 | if test x"$o3it" = x"yes"; then 119 | AC_DEFINE([O3],[],[O3 Mode]) 120 | AM_CXXFLAGS="-ggdb -Wall -O3 -march=nocona" 121 | CXXFLAGS="-ggdb -Wall -O3 -march=nocona" 122 | else 123 | AC_DEFINE([NO3],[],[No-O3 Mode]) 124 | AM_CXXFLAGS="$AM_CXXFLAGS" 125 | fi 126 | 127 | AC_SUBST([AM_CXXFLAGS]) 128 | ########################################################################## 129 | 130 | # Checks for programs. 131 | AC_PROG_CXX 132 | AC_PROG_CC 133 | AC_PROG_MAKE_SET 134 | 135 | # Checks for libraries. 136 | AC_SEARCH_LIBS([pthread_rwlock_init], [pthread]) 137 | AC_SEARCH_LIBS([clock_gettime], [rt]) # macos do not hava librt? 138 | AC_PROG_RANLIB 139 | 140 | # Checks for header files. 141 | AC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h netinet/in.h stdlib.h string.h sys/socket.h unistd.h]) 142 | 143 | # Checks for typedefs, structures, and compiler characteristics. 144 | AC_TYPE_MODE_T 145 | AC_TYPE_SIZE_T 146 | 147 | # Checks for library functions. 148 | AC_FUNC_FORK 149 | AC_CHECK_FUNCS([gethostbyname memset select socket strerror gettimeofday inet_ntoa poll]) 150 | 151 | ########################################################################### 152 | ## Use jemalloc on Linux 153 | ########################################################################### 154 | #JEMALLOC_SUBDIR= 155 | #JEMALLOC_LDADD= 156 | #AC_ARG_WITH([jemalloc], 157 | # [AS_HELP_STRING([--with-jemalloc], 158 | # [use jemalloc memory allocator. Default is yes on Linux, no elsewhere])], 159 | # [], 160 | # [with_jemalloc=check]) 161 | # 162 | #case $target in 163 | # *-*-linux*) 164 | # if test "x$with_jemalloc" != xno; then 165 | # AC_CHECK_LIB([jemalloc], [malloc_conf], 166 | # [JEMALLOC_LDADD=" -Wl,-ljemalloc"], 167 | # [AC_MSG_NOTICE([No system jemalloc found, using bundled version]) 168 | # JEMALLOC_SUBDIR=libjemalloc 169 | # JEMALLOC_LDADD=" -Wl,`pwd`/../lib/libjemalloc/libjemalloc_mt.a"]) 170 | # fi 171 | # ;; 172 | #esac 173 | #venderlibsinc=${JEMALLOC_LDADD}" "${venderlibsinc} 174 | #AC_SUBST(JEMALLOC_SUBDIR) 175 | #AC_SUBST(JEMALLOC_LDADD) 176 | ########################################################################### 177 | 178 | ########################################################################## 179 | # check if libev exist 180 | ########################################################################## 181 | libev="yes" 182 | libevprefix="`pwd`/../lib/libev" 183 | AC_ARG_WITH(libev,[ --with-libev Compile with given libev library.],[libevprefix=$withval libev="yes"],[]) 184 | # if there is no value given, it appears that libevprefix is set to "yes" 185 | if test $libev = 'yes'; then 186 | libevincs=" -I"${libevprefix}"/include" 187 | venderlibsinc=${venderlibsinc}" -Wl,-L"${libevprefix}"/lib -Wl,-lev" 188 | venderincs=${venderincs}" "${libevincs} 189 | AC_CHECK_HEADERS([${libevprefix}/include/event.h],,[AC_MSG_ERROR([Cannot find event.h, We NEED libev or libevent])]) 190 | else 191 | AC_CHECK_HEADERS([event.h],,[AC_MSG_ERROR([Cannot find event.h])]) 192 | fi 193 | ########################################################################## 194 | 195 | ########################################################################## 196 | # check if c-ares exist 197 | ########################################################################## 198 | libcares="yes" 199 | libcaresprefix="`pwd`/../lib/c-ares" 200 | AC_ARG_WITH(libcares,[ --with-libcares Compile with given libcares library for thread safe and async DNS. BETTER NOT],[libcaresprefix=$withval libcares="yes"],[]) 201 | # if there is no value given, it appears that libcaresprefix is set to "yes" 202 | if test $libcares = 'yes'; then 203 | libcaresincs=" -I"${libcaresprefix}"/include" 204 | venderlibsinc=${venderlibsinc}" -Wl,-L"${libcaresprefix}"/lib -Wl,-lcares" 205 | venderincs=${venderincs}" "${libcaresincs} 206 | AC_CHECK_HEADERS([${libcaresprefix}/include/ares.h],,[AC_MSG_ERROR([Cannot find ares.h, We NEED libcares for async DNS])]) 207 | else 208 | AC_CHECK_HEADERS([ares.h],,[AC_MSG_ERROR([Cannot find ares.h])]) 209 | fi 210 | 211 | AC_SEARCH_LIBS([clock_gettime], [rt], [venderlibsinc=${venderlibsinc}" -Wl,-lrt"]) 212 | ########################################################################## 213 | 214 | AC_SUBST(venderlibsinc) 215 | AC_SUBST(venderincs) 216 | 217 | AM_CXXFLAGS=${libevincs}" "${libcaresincs}" "${AM_CXXFLAGS} 218 | #AC_CONFIG_SUBDIRS([hash]) 219 | #AC_CONFIG_FILES([Makefile hash/Makefile]) 220 | AC_CONFIG_FILES([Makefile libgko.pc]) 221 | AC_OUTPUT 222 | -------------------------------------------------------------------------------- /src/dict.h: -------------------------------------------------------------------------------- 1 | /* Hash Tables Implementation. 2 | * 3 | * This file implements in-memory hash tables with insert/del/replace/find/ 4 | * get-random-element operations. Hash tables will auto-resize if needed 5 | * tables of power of two in size are used, collisions are handled by 6 | * chaining. See the source code for more information... :) 7 | * 8 | * Copyright (c) 2006-2012, Salvatore Sanfilippo 9 | * All rights reserved. 10 | * 11 | * Redistribution and use in source and binary forms, with or without 12 | * modification, are permitted provided that the following conditions are met: 13 | * 14 | * * Redistributions of source code must retain the above copyright notice, 15 | * this list of conditions and the following disclaimer. 16 | * * Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the distribution. 19 | * * Neither the name of Redis nor the names of its contributors may be used 20 | * to endorse or promote products derived from this software without 21 | * specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 27 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 | * POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #include 37 | 38 | #ifndef __DICT_H 39 | #define __DICT_H 40 | 41 | #ifdef __cplusplus 42 | extern "C" { 43 | #endif 44 | 45 | #define DICT_OK 0 46 | #define DICT_ERR 1 47 | 48 | /* Unused arguments generate annoying warnings... */ 49 | #define DICT_NOTUSED(V) ((void) V) 50 | 51 | #define DICT_HASH_FUNCTION_SEED 5381; 52 | 53 | typedef struct dictEntry 54 | { 55 | void *key; 56 | union 57 | { 58 | void *val; 59 | uint64_t u64; 60 | int64_t s64; 61 | } v; 62 | struct dictEntry *next; 63 | } dictEntry; 64 | 65 | typedef struct dictType 66 | { 67 | unsigned int (*hashFunction)(const void *key); 68 | void *(*keyDup)(void *privdata, const void *key); 69 | void *(*valDup)(void *privdata, const void *obj); 70 | int (*keyCompare)(void *privdata, const void *key1, const void *key2); 71 | void (*keyDestructor)(void *privdata, void *key); 72 | void (*valDestructor)(void *privdata, void *obj); 73 | } dictType; 74 | 75 | /* This is our hash table structure. Every dictionary has two of this as we 76 | * implement incremental rehashing, for the old to the new table. */ 77 | typedef struct dictht 78 | { 79 | dictEntry **table; 80 | unsigned long size; 81 | unsigned long sizemask; 82 | unsigned long used; 83 | } dictht; 84 | 85 | typedef struct dict 86 | { 87 | dictType *type; 88 | void *privdata; 89 | dictht ht[2]; 90 | int rehashidx; /* rehashing not in progress if rehashidx == -1 */ 91 | int iterators; /* number of iterators currently running */ 92 | } dict; 93 | 94 | /* If safe is set to 1 this is a safe iterator, that means, you can call 95 | * dictAdd, dictFind, and other functions against the dictionary even while 96 | * iterating. Otherwise it is a non safe iterator, and only dictNext() 97 | * should be called while iterating. */ 98 | typedef struct dictIterator 99 | { 100 | dict *d; 101 | int table, index, safe; 102 | dictEntry *entry, *nextEntry; 103 | } dictIterator; 104 | 105 | /* This is the initial size of every hash table */ 106 | #define DICT_HT_INITIAL_SIZE 4 107 | 108 | /* ------------------------------- Macros ------------------------------------*/ 109 | #define dictFreeVal(d, entry) \ 110 | if ((d)->type->valDestructor) \ 111 | (d)->type->valDestructor((d)->privdata, (entry)->v.val) 112 | 113 | #define dictSetVal(d, entry, _val_) do { \ 114 | if ((d)->type->valDup) \ 115 | entry->v.val = (d)->type->valDup((d)->privdata, _val_); \ 116 | else \ 117 | entry->v.val = (_val_); \ 118 | } while(0) 119 | 120 | #define dictSetSignedIntegerVal(entry, _val_) \ 121 | do { entry->v.s64 = _val_; } while(0) 122 | 123 | #define dictSetUnsignedIntegerVal(entry, _val_) \ 124 | do { entry->v.u64 = _val_; } while(0) 125 | 126 | #define dictFreeKey(d, entry) \ 127 | if ((d)->type->keyDestructor) \ 128 | (d)->type->keyDestructor((d)->privdata, (entry)->key) 129 | 130 | #define dictSetKey(d, entry, _key_) do { \ 131 | if ((d)->type->keyDup) \ 132 | entry->key = (d)->type->keyDup((d)->privdata, _key_); \ 133 | else \ 134 | entry->key = (_key_); \ 135 | } while(0) 136 | 137 | #define dictCompareKeys(d, key1, key2) \ 138 | (((d)->type->keyCompare) ? \ 139 | (d)->type->keyCompare((d)->privdata, key1, key2) : \ 140 | (key1) == (key2)) 141 | 142 | #define dictHashKey(d, key) (d)->type->hashFunction(key) 143 | #define dictGetKey(he) ((he)->key) 144 | #define dictGetVal(he) ((he)->v.val) 145 | #define dictGetSignedIntegerVal(he) ((he)->v.s64) 146 | #define dictGetUnsignedIntegerVal(he) ((he)->v.u64) 147 | #define dictSlots(d) ((d)->ht[0].size+(d)->ht[1].size) 148 | #define dictSize(d) ((d)->ht[0].used+(d)->ht[1].used) 149 | #define dictIsRehashing(ht) ((ht)->rehashidx != -1) 150 | 151 | /* API */ 152 | dict *dictCreate(dictType *type, void *privDataPtr); 153 | int dictExpand(dict *d, unsigned long size); 154 | int dictAdd(dict *d, void *key, void *val); 155 | dictEntry *dictAddRaw(dict *d, void *key); 156 | int dictReplace(dict *d, void *key, void *val); 157 | dictEntry *dictReplaceRaw(dict *d, void *key); 158 | int dictDelete(dict *d, const void *key); 159 | int dictDeleteNoFree(dict *d, const void *key); 160 | void dictRelease(dict *d); 161 | dictEntry * dictFind(dict *d, const void *key); 162 | void *dictFetchValue(dict *d, const void *key); 163 | int dictResize(dict *d); 164 | dictIterator *dictGetIterator(dict *d); 165 | dictIterator *dictGetSafeIterator(dict *d); 166 | dictEntry *dictNext(dictIterator *iter); 167 | void dictReleaseIterator(dictIterator *iter); 168 | dictEntry *dictGetRandomKey(dict *d); 169 | void dictPrintStats(dict *d); 170 | unsigned int dictGenHashFunction(const void *key, int len); 171 | unsigned int dictGenCaseHashFunction(const unsigned char *buf, int len); 172 | void dictEmpty(dict *d); 173 | void dictEnableResize(void); 174 | void dictDisableResize(void); 175 | int dictRehash(dict *d, int n); 176 | int dictRehashMilliseconds(dict *d, int ms); 177 | void dictSetHashFunctionSeed(unsigned int initval); 178 | unsigned int dictGetHashFunctionSeed(void); 179 | 180 | /* Hash table types */ 181 | extern dictType dictTypeHeapStringCopyKey; 182 | extern dictType dictTypeHeapStrings; 183 | extern dictType dictTypeHeapStringCopyKeyValue; 184 | 185 | #ifdef __cplusplus 186 | } 187 | # endif 188 | 189 | #endif /* __DICT_H */ 190 | -------------------------------------------------------------------------------- /src/gko.h: -------------------------------------------------------------------------------- 1 | /* 2 | * gko.h 3 | * 4 | * Created on: Feb 27, 2012 5 | * Author: auxten 6 | */ 7 | 8 | #ifndef GKO_H_ 9 | #define GKO_H_ 10 | 11 | #include "gingko.h" 12 | #include "async_pool.h" 13 | #include "log.h" 14 | #include "socket.h" 15 | 16 | 17 | 18 | #endif /* GKO_H_ */ 19 | -------------------------------------------------------------------------------- /src/gko_errno.h: -------------------------------------------------------------------------------- 1 | hermes_errno.h -------------------------------------------------------------------------------- /src/hash/gko_zip.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * gko_zip.cpp 3 | * 4 | * Created on: Jan 11, 2012 5 | * Author: auxten 6 | */ 7 | 8 | 9 | #include "lz4.h" 10 | #include "gko_zip.h" 11 | 12 | int gko_zip(char* source, char* dest, int isize) 13 | { 14 | return LZ4_compress(source, dest, isize); 15 | } 16 | 17 | int gko_unzip(char* source, char* dest, int osize) 18 | { 19 | return LZ4_uncompress(source, dest, osize); 20 | } 21 | -------------------------------------------------------------------------------- /src/hash/gko_zip.h: -------------------------------------------------------------------------------- 1 | /* 2 | * gko_zip.h 3 | * 4 | * Created on: Jan 11, 2012 5 | * Author: auxten 6 | */ 7 | 8 | #ifndef GKO_ZIP_H_ 9 | #define GKO_ZIP_H_ 10 | 11 | int gko_zip(char* source, char* dest, int isize); 12 | int gko_unzip(char* source, char* dest, int osize); 13 | 14 | #endif /* GKO_ZIP_H_ */ 15 | -------------------------------------------------------------------------------- /src/hash/lz4.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | LZ4 - Fast LZ compression algorithm 3 | Copyright (C) 2011-2012, Yann Collet. 4 | BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are 8 | met: 9 | 10 | * Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above 13 | copyright notice, this list of conditions and the following disclaimer 14 | in the documentation and/or other materials provided with the 15 | distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | //************************************** 31 | // Compilation Directives 32 | //************************************** 33 | #if __STDC_VERSION__ >= 199901L 34 | /* "restrict" is a known keyword */ 35 | #else 36 | #define restrict // Disable restrict 37 | #endif 38 | 39 | #ifdef _MSC_VER 40 | #define inline __forceinline 41 | #endif 42 | 43 | #ifdef __GNUC__ 44 | #define _PACKED __attribute__ ((packed)) 45 | #else 46 | #define _PACKED 47 | #endif 48 | 49 | #define ARCH64 (__x86_64__ || __ppc64__ || _WIN64 || __LP64__) // Detect 64 bits mode 50 | 51 | 52 | //************************************** 53 | // Includes 54 | //************************************** 55 | #include // for malloc 56 | #include // for memset 57 | #include "lz4.h" 58 | 59 | 60 | //************************************** 61 | // Performance parameter 62 | //************************************** 63 | // Increasing this value improves compression ratio 64 | // Lowering this value reduces memory usage 65 | // Lowering may also improve speed, typically on reaching cache size limits (L1 32KB for Intel, 64KB for AMD) 66 | // Memory usage formula for 32 bits systems : N->2^(N+2) Bytes (examples : 17 -> 512KB ; 12 -> 16KB) 67 | #define HASH_LOG 12 68 | 69 | //#define _FORCE_SW_BITCOUNT // Uncomment for better performance if target platform has no hardware support for LowBitCount 70 | 71 | 72 | //************************************** 73 | // Basic Types 74 | //************************************** 75 | #if defined(_MSC_VER) // Visual Studio does not support 'stdint' natively 76 | #define BYTE unsigned __int8 77 | #define U16 unsigned __int16 78 | #define U32 unsigned __int32 79 | #define S32 __int32 80 | #define U64 unsigned __int64 81 | #else 82 | #include 83 | #define BYTE uint8_t 84 | #define U16 uint16_t 85 | #define U32 uint32_t 86 | #define S32 int32_t 87 | #define U64 uint64_t 88 | #endif 89 | 90 | 91 | //************************************** 92 | // Constants 93 | //************************************** 94 | #define MINMATCH 4 95 | #define SKIPSTRENGTH 6 96 | #define STACKLIMIT 13 97 | #define HEAPMODE (HASH_LOG>STACKLIMIT) // Defines if memory is allocated into the stack (local variable), or into the heap (malloc()). 98 | #define COPYLENGTH 8 99 | #define LASTLITERALS 5 100 | #define MFLIMIT (COPYLENGTH+MINMATCH) 101 | #define MINLENGTH (MFLIMIT+1) 102 | 103 | #define MAXD_LOG 16 104 | #define MAX_DISTANCE ((1 << MAXD_LOG) - 1) 105 | 106 | #define HASHTABLESIZE (1 << HASH_LOG) 107 | #define HASH_MASK (HASHTABLESIZE - 1) 108 | 109 | #define ML_BITS 4 110 | #define ML_MASK ((1U<v) 139 | #define A32(x) (((U32_S *)(x))->v) 140 | #define A16(x) (((U16_S *)(x))->v) 141 | 142 | 143 | //************************************** 144 | // Architecture-specific macros 145 | //************************************** 146 | #if ARCH64 // 64-bit 147 | #define COPYSTEP 8 148 | #define LZ4_COPYSTEP(s,d) A64(d) = A64(s); d+=8; s+=8; 149 | #define LZ4_COPYPACKET(s,d) LZ4_COPYSTEP(s,d) 150 | #else // 32-bit 151 | #define COPYSTEP 4 152 | #define LZ4_COPYSTEP(s,d) A32(d) = A32(s); d+=4; s+=4; 153 | #define LZ4_COPYPACKET(s,d) LZ4_COPYSTEP(s,d); LZ4_COPYSTEP(s,d); 154 | #endif 155 | 156 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 157 | #define LZ4_READ_LITTLEENDIAN_16(d,s,p) { d = s - A16(p); } 158 | #define LZ4_WRITE_LITTLEENDIAN_16(p,v) { A16(p) = v; p+=2; } 159 | #define LZ4_NbCommonBytes LZ4_NbCommonBytes_LittleEndian 160 | #else // Big Endian 161 | #define LZ4_READ_LITTLEENDIAN_16(d,s,p) { int delta = p[0]; delta += p[1] << 8; d = s - delta; } 162 | #define LZ4_WRITE_LITTLEENDIAN_16(p,v) { int delta = v; *p++ = delta; *op++ = delta>>8; } 163 | #define LZ4_NbCommonBytes LZ4_NbCommonBytes_BigEndian 164 | #endif 165 | 166 | 167 | //************************************** 168 | // Macros 169 | //************************************** 170 | #define LZ4_HASH_FUNCTION(i) (((i) * 2654435761U) >> ((MINMATCH*8)-HASH_LOG)) 171 | #define LZ4_HASH_VALUE(p) LZ4_HASH_FUNCTION(A32(p)) 172 | #define LZ4_WILDCOPY(s,d,e) do { LZ4_COPYPACKET(s,d) } while (d>3); 185 | #elif defined(__GNUC__) && !defined(_FORCE_SW_BITCOUNT) 186 | return (__builtin_ctz(val) >> 3); 187 | #else 188 | static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 }; 189 | return DeBruijnBytePos[((U32)((val & -val) * 0x077CB531U)) >> 27]; 190 | #endif 191 | } 192 | 193 | inline static int LZ4_NbCommonBytes_BigEndian (register U32 val) 194 | { 195 | #if defined(_MSC_VER) && !defined(_FORCE_SW_BITCOUNT) 196 | unsigned long r = 0; 197 | _BitScanReverse( &r, val ); 198 | return (int)(r>>3); 199 | #elif defined(__GNUC__) && !defined(_FORCE_SW_BITCOUNT) 200 | return (__builtin_clz(val) >> 3); 201 | #else 202 | int r; 203 | if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; } 204 | r += (!val); 205 | return r; 206 | #endif 207 | } 208 | 209 | 210 | //****************************** 211 | // Public Compression functions 212 | //****************************** 213 | int LZ4_compressCtx(void** ctx, 214 | char* source, 215 | char* dest, 216 | int isize) 217 | { 218 | #if HEAPMODE 219 | struct refTables *srt = (struct refTables *) (*ctx); 220 | const BYTE** HashTable; 221 | #else 222 | const BYTE* HashTable[HASHTABLESIZE] = {0}; 223 | #endif 224 | 225 | const BYTE* ip = (BYTE*) source; 226 | const BYTE* anchor = ip; 227 | const BYTE* const iend = ip + isize; 228 | const BYTE* const mflimit = iend - MFLIMIT; 229 | #define matchlimit (iend - LASTLITERALS) 230 | 231 | BYTE* op = (BYTE*) dest; 232 | 233 | int len, length; 234 | const int skipStrength = SKIPSTRENGTH; 235 | U32 forwardH; 236 | 237 | 238 | // Init 239 | if (isizehashTable; 247 | memset((void*)HashTable, 0, sizeof(srt->hashTable)); 248 | #else 249 | (void) ctx; 250 | #endif 251 | 252 | 253 | // First Byte 254 | HashTable[LZ4_HASH_VALUE(ip)] = ip; 255 | ip++; forwardH = LZ4_HASH_VALUE(ip); 256 | 257 | // Main Loop 258 | for ( ; ; ) 259 | { 260 | int findMatchAttempts = (1U << skipStrength) + 3; 261 | const BYTE* forwardIp = ip; 262 | const BYTE* ref; 263 | BYTE* token; 264 | 265 | // Find a match 266 | do { 267 | U32 h = forwardH; 268 | int step = findMatchAttempts++ >> skipStrength; 269 | ip = forwardIp; 270 | forwardIp = ip + step; 271 | 272 | if (forwardIp > mflimit) { goto _last_literals; } 273 | 274 | forwardH = LZ4_HASH_VALUE(forwardIp); 275 | ref = HashTable[h]; 276 | HashTable[h] = ip; 277 | 278 | } while ((ref < ip - MAX_DISTANCE) || (A32(ref) != A32(ip))); 279 | 280 | // Catch up 281 | while ((ip>anchor) && (ref>(BYTE*)source) && (ip[-1]==ref[-1])) { ip--; ref--; } 282 | 283 | // Encode Literal length 284 | length = ip - anchor; 285 | token = op++; 286 | if (length>=(int)RUN_MASK) { *token=(RUN_MASK< 254 ; len-=255) *op++ = 255; *op++ = (BYTE)len; } 287 | else *token = (length<=(int)ML_MASK) { *token+=ML_MASK; len-=ML_MASK; for(; len > 509 ; len-=510) { *op++ = 255; *op++ = 255; } if (len > 254) { len-=255; *op++ = 255; } *op++ = (BYTE)len; } 314 | else *token += len; 315 | 316 | // Test end of chunk 317 | if (ip > mflimit) { anchor = ip; break; } 318 | 319 | // Fill table 320 | HashTable[LZ4_HASH_VALUE(ip-2)] = ip-2; 321 | 322 | // Test next position 323 | ref = HashTable[LZ4_HASH_VALUE(ip)]; 324 | HashTable[LZ4_HASH_VALUE(ip)] = ip; 325 | if ((ref > ip - (MAX_DISTANCE + 1)) && (A32(ref) == A32(ip))) { token = op++; *token=0; goto _next_match; } 326 | 327 | // Prepare next loop 328 | anchor = ip++; 329 | forwardH = LZ4_HASH_VALUE(ip); 330 | } 331 | 332 | _last_literals: 333 | // Encode Last Literals 334 | { 335 | int lastRun = iend - anchor; 336 | if (lastRun>=(int)RUN_MASK) { *op++=(RUN_MASK< 254 ; lastRun-=255) *op++ = 255; *op++ = (BYTE) lastRun; } 337 | else *op++ = (lastRun<> ((MINMATCH*8)-HASHLOG64K)) 352 | #define LZ4_HASH64K_VALUE(p) LZ4_HASH64K_FUNCTION(A32(p)) 353 | int LZ4_compress64kCtx(void** ctx, 354 | char* source, 355 | char* dest, 356 | int isize) 357 | { 358 | #if HEAPMODE 359 | struct refTables *srt = (struct refTables *) (*ctx); 360 | U16* HashTable; 361 | #else 362 | U16 HashTable[HASHTABLESIZE<<1] = {0}; 363 | #endif 364 | 365 | const BYTE* ip = (BYTE*) source; 366 | const BYTE* anchor = ip; 367 | const BYTE* const base = ip; 368 | const BYTE* const iend = ip + isize; 369 | const BYTE* const mflimit = iend - MFLIMIT; 370 | #define matchlimit (iend - LASTLITERALS) 371 | 372 | BYTE* op = (BYTE*) dest; 373 | 374 | int len, length; 375 | const int skipStrength = SKIPSTRENGTH; 376 | U32 forwardH; 377 | 378 | 379 | // Init 380 | if (isizehashTable); 388 | memset((void*)HashTable, 0, sizeof(srt->hashTable)); 389 | #else 390 | (void) ctx; 391 | #endif 392 | 393 | 394 | // First Byte 395 | ip++; forwardH = LZ4_HASH64K_VALUE(ip); 396 | 397 | // Main Loop 398 | for ( ; ; ) 399 | { 400 | int findMatchAttempts = (1U << skipStrength) + 3; 401 | const BYTE* forwardIp = ip; 402 | const BYTE* ref; 403 | BYTE* token; 404 | 405 | // Find a match 406 | do { 407 | U32 h = forwardH; 408 | int step = findMatchAttempts++ >> skipStrength; 409 | ip = forwardIp; 410 | forwardIp = ip + step; 411 | 412 | if (forwardIp > mflimit) { goto _last_literals; } 413 | 414 | forwardH = LZ4_HASH64K_VALUE(forwardIp); 415 | ref = base + HashTable[h]; 416 | HashTable[h] = ip - base; 417 | 418 | } while (A32(ref) != A32(ip)); 419 | 420 | // Catch up 421 | while ((ip>anchor) && (ref>(BYTE*)source) && (ip[-1]==ref[-1])) { ip--; ref--; } 422 | 423 | // Encode Literal length 424 | length = ip - anchor; 425 | token = op++; 426 | if (length>=(int)RUN_MASK) { *token=(RUN_MASK< 254 ; len-=255) *op++ = 255; *op++ = (BYTE)len; } 427 | else *token = (length<=(int)ML_MASK) { *token+=ML_MASK; len-=ML_MASK; for(; len > 509 ; len-=510) { *op++ = 255; *op++ = 255; } if (len > 254) { len-=255; *op++ = 255; } *op++ = (BYTE)len; } 454 | else *token += len; 455 | 456 | // Test end of chunk 457 | if (ip > mflimit) { anchor = ip; break; } 458 | 459 | // Fill table 460 | HashTable[LZ4_HASH64K_VALUE(ip-2)] = ip - 2 - base; 461 | 462 | // Test next position 463 | ref = base + HashTable[LZ4_HASH64K_VALUE(ip)]; 464 | HashTable[LZ4_HASH64K_VALUE(ip)] = ip - base; 465 | if (A32(ref) == A32(ip)) { token = op++; *token=0; goto _next_match; } 466 | 467 | // Prepare next loop 468 | anchor = ip++; 469 | forwardH = LZ4_HASH64K_VALUE(ip); 470 | } 471 | 472 | _last_literals: 473 | // Encode Last Literals 474 | { 475 | int lastRun = iend - anchor; 476 | if (lastRun>=(int)RUN_MASK) { *op++=(RUN_MASK< 254 ; lastRun-=255) *op++ = 255; *op++ = (BYTE) lastRun; } 477 | else *op++ = (lastRun<>ML_BITS)) == RUN_MASK) { for (;(len=*ip++)==255;length+=255){} length += len; } 542 | 543 | // copy literals 544 | cpy = op+length; 545 | if (cpy>oend-COPYLENGTH) 546 | { 547 | if (cpy > oend) goto _output_error; 548 | memcpy(op, ip, length); 549 | ip += length; 550 | break; // Necessarily EOF 551 | } 552 | LZ4_WILDCOPY(ip, op, cpy); ip -= (op-cpy); op = cpy; 553 | 554 | // get offset 555 | LZ4_READ_LITTLEENDIAN_16(ref,cpy,ip); ip+=2; 556 | if (ref < (BYTE* const)dest) goto _output_error; 557 | 558 | // get matchlength 559 | if ((length=(token&ML_MASK)) == ML_MASK) { for (;*ip==255;length+=255) {ip++;} length += *ip++; } 560 | 561 | // copy repeated sequence 562 | if (op-refoend-COPYLENGTH) 580 | { 581 | if (cpy > oend) goto _output_error; 582 | LZ4_WILDCOPY(ref, op, (oend-COPYLENGTH)); 583 | while(op>ML_BITS)) == RUN_MASK) { for (;(len=*ip++)==255;length+=255){} length += len; } 628 | 629 | // copy literals 630 | cpy = op+length; 631 | if (cpy>oend-COPYLENGTH) 632 | { 633 | if (cpy > oend) goto _output_error; 634 | memcpy(op, ip, length); 635 | op += length; 636 | break; // Necessarily EOF 637 | } 638 | LZ4_WILDCOPY(ip, op, cpy); ip -= (op-cpy); op = cpy; 639 | if (ip>=iend) break; // check EOF 640 | 641 | // get offset 642 | LZ4_READ_LITTLEENDIAN_16(ref,cpy,ip); ip+=2; 643 | if (ref < (BYTE* const)dest) goto _output_error; 644 | 645 | // get matchlength 646 | if ((length=(token&ML_MASK)) == ML_MASK) { for (;(len=*ip++)==255;length+=255){} length += len; } 647 | 648 | // copy repeated sequence 649 | if (op-refoend-COPYLENGTH) 667 | { 668 | if (cpy > oend) goto _output_error; 669 | LZ4_WILDCOPY(ref, op, (oend-COPYLENGTH)); 670 | while(op 8 | * 9 | * All rights reserved. 10 | * 11 | * This program is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation; either version 2 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License along 22 | * with this program; if not, write to the Free Software Foundation, Inc., 23 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 24 | */ 25 | /* 26 | * The MD5 algorithm was designed by Ron Rivest in 1991. 27 | * 28 | * http://www.ietf.org/rfc/rfc1321.txt 29 | */ 30 | 31 | #define POLARSSL_MD5_C 32 | #if defined(POLARSSL_MD5_C) 33 | 34 | #include "md5.h" 35 | 36 | #if defined(POLARSSL_FS_IO) || defined(POLARSSL_SELF_TEST) 37 | #include 38 | #endif 39 | 40 | /* 41 | * 32-bit integer manipulation macros (little endian) 42 | */ 43 | #ifndef GET_ULONG_LE 44 | #define GET_ULONG_LE(n,b,i) \ 45 | { \ 46 | (n) = ( (unsigned long) (b)[(i) ] ) \ 47 | | ( (unsigned long) (b)[(i) + 1] << 8 ) \ 48 | | ( (unsigned long) (b)[(i) + 2] << 16 ) \ 49 | | ( (unsigned long) (b)[(i) + 3] << 24 ); \ 50 | } 51 | #endif 52 | 53 | #ifndef PUT_ULONG_LE 54 | #define PUT_ULONG_LE(n,b,i) \ 55 | { \ 56 | (b)[(i) ] = (unsigned char) ( (n) ); \ 57 | (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \ 58 | (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \ 59 | (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \ 60 | } 61 | #endif 62 | 63 | /* 64 | * MD5 context setup 65 | */ 66 | void md5_starts( md5_context *ctx ) 67 | { 68 | ctx->total[0] = 0; 69 | ctx->total[1] = 0; 70 | 71 | ctx->state[0] = 0x67452301; 72 | ctx->state[1] = 0xEFCDAB89; 73 | ctx->state[2] = 0x98BADCFE; 74 | ctx->state[3] = 0x10325476; 75 | } 76 | 77 | static void md5_process( md5_context *ctx, const unsigned char data[64] ) 78 | { 79 | unsigned long X[16], A, B, C, D; 80 | 81 | GET_ULONG_LE( X[ 0], data, 0 ); 82 | GET_ULONG_LE( X[ 1], data, 4 ); 83 | GET_ULONG_LE( X[ 2], data, 8 ); 84 | GET_ULONG_LE( X[ 3], data, 12 ); 85 | GET_ULONG_LE( X[ 4], data, 16 ); 86 | GET_ULONG_LE( X[ 5], data, 20 ); 87 | GET_ULONG_LE( X[ 6], data, 24 ); 88 | GET_ULONG_LE( X[ 7], data, 28 ); 89 | GET_ULONG_LE( X[ 8], data, 32 ); 90 | GET_ULONG_LE( X[ 9], data, 36 ); 91 | GET_ULONG_LE( X[10], data, 40 ); 92 | GET_ULONG_LE( X[11], data, 44 ); 93 | GET_ULONG_LE( X[12], data, 48 ); 94 | GET_ULONG_LE( X[13], data, 52 ); 95 | GET_ULONG_LE( X[14], data, 56 ); 96 | GET_ULONG_LE( X[15], data, 60 ); 97 | 98 | #define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) 99 | 100 | #define P(a,b,c,d,k,s,t) \ 101 | { \ 102 | a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \ 103 | } 104 | 105 | A = ctx->state[0]; 106 | B = ctx->state[1]; 107 | C = ctx->state[2]; 108 | D = ctx->state[3]; 109 | 110 | #define F(x,y,z) (z ^ (x & (y ^ z))) 111 | 112 | P( A, B, C, D, 0, 7, 0xD76AA478 ); 113 | P( D, A, B, C, 1, 12, 0xE8C7B756 ); 114 | P( C, D, A, B, 2, 17, 0x242070DB ); 115 | P( B, C, D, A, 3, 22, 0xC1BDCEEE ); 116 | P( A, B, C, D, 4, 7, 0xF57C0FAF ); 117 | P( D, A, B, C, 5, 12, 0x4787C62A ); 118 | P( C, D, A, B, 6, 17, 0xA8304613 ); 119 | P( B, C, D, A, 7, 22, 0xFD469501 ); 120 | P( A, B, C, D, 8, 7, 0x698098D8 ); 121 | P( D, A, B, C, 9, 12, 0x8B44F7AF ); 122 | P( C, D, A, B, 10, 17, 0xFFFF5BB1 ); 123 | P( B, C, D, A, 11, 22, 0x895CD7BE ); 124 | P( A, B, C, D, 12, 7, 0x6B901122 ); 125 | P( D, A, B, C, 13, 12, 0xFD987193 ); 126 | P( C, D, A, B, 14, 17, 0xA679438E ); 127 | P( B, C, D, A, 15, 22, 0x49B40821 ); 128 | 129 | #undef F 130 | 131 | #define F(x,y,z) (y ^ (z & (x ^ y))) 132 | 133 | P( A, B, C, D, 1, 5, 0xF61E2562 ); 134 | P( D, A, B, C, 6, 9, 0xC040B340 ); 135 | P( C, D, A, B, 11, 14, 0x265E5A51 ); 136 | P( B, C, D, A, 0, 20, 0xE9B6C7AA ); 137 | P( A, B, C, D, 5, 5, 0xD62F105D ); 138 | P( D, A, B, C, 10, 9, 0x02441453 ); 139 | P( C, D, A, B, 15, 14, 0xD8A1E681 ); 140 | P( B, C, D, A, 4, 20, 0xE7D3FBC8 ); 141 | P( A, B, C, D, 9, 5, 0x21E1CDE6 ); 142 | P( D, A, B, C, 14, 9, 0xC33707D6 ); 143 | P( C, D, A, B, 3, 14, 0xF4D50D87 ); 144 | P( B, C, D, A, 8, 20, 0x455A14ED ); 145 | P( A, B, C, D, 13, 5, 0xA9E3E905 ); 146 | P( D, A, B, C, 2, 9, 0xFCEFA3F8 ); 147 | P( C, D, A, B, 7, 14, 0x676F02D9 ); 148 | P( B, C, D, A, 12, 20, 0x8D2A4C8A ); 149 | 150 | #undef F 151 | 152 | #define F(x,y,z) (x ^ y ^ z) 153 | 154 | P( A, B, C, D, 5, 4, 0xFFFA3942 ); 155 | P( D, A, B, C, 8, 11, 0x8771F681 ); 156 | P( C, D, A, B, 11, 16, 0x6D9D6122 ); 157 | P( B, C, D, A, 14, 23, 0xFDE5380C ); 158 | P( A, B, C, D, 1, 4, 0xA4BEEA44 ); 159 | P( D, A, B, C, 4, 11, 0x4BDECFA9 ); 160 | P( C, D, A, B, 7, 16, 0xF6BB4B60 ); 161 | P( B, C, D, A, 10, 23, 0xBEBFBC70 ); 162 | P( A, B, C, D, 13, 4, 0x289B7EC6 ); 163 | P( D, A, B, C, 0, 11, 0xEAA127FA ); 164 | P( C, D, A, B, 3, 16, 0xD4EF3085 ); 165 | P( B, C, D, A, 6, 23, 0x04881D05 ); 166 | P( A, B, C, D, 9, 4, 0xD9D4D039 ); 167 | P( D, A, B, C, 12, 11, 0xE6DB99E5 ); 168 | P( C, D, A, B, 15, 16, 0x1FA27CF8 ); 169 | P( B, C, D, A, 2, 23, 0xC4AC5665 ); 170 | 171 | #undef F 172 | 173 | #define F(x,y,z) (y ^ (x | ~z)) 174 | 175 | P( A, B, C, D, 0, 6, 0xF4292244 ); 176 | P( D, A, B, C, 7, 10, 0x432AFF97 ); 177 | P( C, D, A, B, 14, 15, 0xAB9423A7 ); 178 | P( B, C, D, A, 5, 21, 0xFC93A039 ); 179 | P( A, B, C, D, 12, 6, 0x655B59C3 ); 180 | P( D, A, B, C, 3, 10, 0x8F0CCC92 ); 181 | P( C, D, A, B, 10, 15, 0xFFEFF47D ); 182 | P( B, C, D, A, 1, 21, 0x85845DD1 ); 183 | P( A, B, C, D, 8, 6, 0x6FA87E4F ); 184 | P( D, A, B, C, 15, 10, 0xFE2CE6E0 ); 185 | P( C, D, A, B, 6, 15, 0xA3014314 ); 186 | P( B, C, D, A, 13, 21, 0x4E0811A1 ); 187 | P( A, B, C, D, 4, 6, 0xF7537E82 ); 188 | P( D, A, B, C, 11, 10, 0xBD3AF235 ); 189 | P( C, D, A, B, 2, 15, 0x2AD7D2BB ); 190 | P( B, C, D, A, 9, 21, 0xEB86D391 ); 191 | 192 | #undef F 193 | 194 | ctx->state[0] += A; 195 | ctx->state[1] += B; 196 | ctx->state[2] += C; 197 | ctx->state[3] += D; 198 | } 199 | 200 | /* 201 | * MD5 process buffer 202 | */ 203 | void md5_update( md5_context *ctx, const unsigned char *input, size_t ilen ) 204 | { 205 | size_t fill; 206 | unsigned long left; 207 | 208 | if( ilen <= 0 ) 209 | return; 210 | 211 | left = ctx->total[0] & 0x3F; 212 | fill = 64 - left; 213 | 214 | ctx->total[0] += (unsigned long) ilen; 215 | ctx->total[0] &= 0xFFFFFFFF; 216 | 217 | if( ctx->total[0] < (unsigned long) ilen ) 218 | ctx->total[1]++; 219 | 220 | if( left && ilen >= fill ) 221 | { 222 | memcpy( (void *) (ctx->buffer + left), 223 | (void *) input, fill ); 224 | md5_process( ctx, ctx->buffer ); 225 | input += fill; 226 | ilen -= fill; 227 | left = 0; 228 | } 229 | 230 | while( ilen >= 64 ) 231 | { 232 | md5_process( ctx, input ); 233 | input += 64; 234 | ilen -= 64; 235 | } 236 | 237 | if( ilen > 0 ) 238 | { 239 | memcpy( (void *) (ctx->buffer + left), 240 | (void *) input, ilen ); 241 | } 242 | } 243 | 244 | static const unsigned char md5_padding[64] = 245 | { 246 | 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 247 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 248 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 249 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 250 | }; 251 | 252 | /* 253 | * MD5 final digest 254 | */ 255 | void md5_finish( md5_context *ctx, unsigned char output[16] ) 256 | { 257 | unsigned long last, padn; 258 | unsigned long high, low; 259 | unsigned char msglen[8]; 260 | 261 | high = ( ctx->total[0] >> 29 ) 262 | | ( ctx->total[1] << 3 ); 263 | low = ( ctx->total[0] << 3 ); 264 | 265 | PUT_ULONG_LE( low, msglen, 0 ); 266 | PUT_ULONG_LE( high, msglen, 4 ); 267 | 268 | last = ctx->total[0] & 0x3F; 269 | padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); 270 | 271 | md5_update( ctx, (unsigned char *) md5_padding, padn ); 272 | md5_update( ctx, msglen, 8 ); 273 | 274 | PUT_ULONG_LE( ctx->state[0], output, 0 ); 275 | PUT_ULONG_LE( ctx->state[1], output, 4 ); 276 | PUT_ULONG_LE( ctx->state[2], output, 8 ); 277 | PUT_ULONG_LE( ctx->state[3], output, 12 ); 278 | } 279 | 280 | /* 281 | * output = MD5( input buffer ) 282 | */ 283 | void md5( const unsigned char *input, size_t ilen, unsigned char output[16] ) 284 | { 285 | md5_context ctx; 286 | 287 | md5_starts( &ctx ); 288 | md5_update( &ctx, input, ilen ); 289 | md5_finish( &ctx, output ); 290 | 291 | memset( &ctx, 0, sizeof( md5_context ) ); 292 | } 293 | 294 | #if defined(POLARSSL_FS_IO) 295 | /* 296 | * output = MD5( file contents ) 297 | */ 298 | int md5_file( const char *path, unsigned char output[16] ) 299 | { 300 | FILE *f; 301 | size_t n; 302 | md5_context ctx; 303 | unsigned char buf[1024]; 304 | 305 | if( ( f = fopen( path, "rb" ) ) == NULL ) 306 | return( 1 ); 307 | 308 | md5_starts( &ctx ); 309 | 310 | while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 ) 311 | md5_update( &ctx, buf, n ); 312 | 313 | md5_finish( &ctx, output ); 314 | 315 | memset( &ctx, 0, sizeof( md5_context ) ); 316 | 317 | if( ferror( f ) != 0 ) 318 | { 319 | fclose( f ); 320 | return( 2 ); 321 | } 322 | 323 | fclose( f ); 324 | return( 0 ); 325 | } 326 | #endif /* POLARSSL_FS_IO */ 327 | 328 | /* 329 | * MD5 HMAC context setup 330 | */ 331 | void md5_hmac_starts( md5_context *ctx, const unsigned char *key, size_t keylen ) 332 | { 333 | size_t i; 334 | unsigned char sum[16]; 335 | 336 | if( keylen > 64 ) 337 | { 338 | md5( key, keylen, sum ); 339 | keylen = 16; 340 | key = sum; 341 | } 342 | 343 | memset( ctx->ipad, 0x36, 64 ); 344 | memset( ctx->opad, 0x5C, 64 ); 345 | 346 | for( i = 0; i < keylen; i++ ) 347 | { 348 | ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] ); 349 | ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] ); 350 | } 351 | 352 | md5_starts( ctx ); 353 | md5_update( ctx, ctx->ipad, 64 ); 354 | 355 | memset( sum, 0, sizeof( sum ) ); 356 | } 357 | 358 | /* 359 | * MD5 HMAC process buffer 360 | */ 361 | void md5_hmac_update( md5_context *ctx, const unsigned char *input, size_t ilen ) 362 | { 363 | md5_update( ctx, input, ilen ); 364 | } 365 | 366 | /* 367 | * MD5 HMAC final digest 368 | */ 369 | void md5_hmac_finish( md5_context *ctx, unsigned char output[16] ) 370 | { 371 | unsigned char tmpbuf[16]; 372 | 373 | md5_finish( ctx, tmpbuf ); 374 | md5_starts( ctx ); 375 | md5_update( ctx, ctx->opad, 64 ); 376 | md5_update( ctx, tmpbuf, 16 ); 377 | md5_finish( ctx, output ); 378 | 379 | memset( tmpbuf, 0, sizeof( tmpbuf ) ); 380 | } 381 | 382 | /* 383 | * MD5 HMAC context reset 384 | */ 385 | void md5_hmac_reset( md5_context *ctx ) 386 | { 387 | md5_starts( ctx ); 388 | md5_update( ctx, ctx->ipad, 64 ); 389 | } 390 | 391 | /* 392 | * output = HMAC-MD5( hmac key, input buffer ) 393 | */ 394 | void md5_hmac( const unsigned char *key, size_t keylen, 395 | const unsigned char *input, size_t ilen, 396 | unsigned char output[16] ) 397 | { 398 | md5_context ctx; 399 | 400 | md5_hmac_starts( &ctx, key, keylen ); 401 | md5_hmac_update( &ctx, input, ilen ); 402 | md5_hmac_finish( &ctx, output ); 403 | 404 | memset( &ctx, 0, sizeof( md5_context ) ); 405 | } 406 | 407 | #if defined(POLARSSL_SELF_TEST) 408 | /* 409 | * RFC 1321 test vectors 410 | */ 411 | static unsigned char md5_test_buf[7][81] = 412 | { 413 | { "" }, 414 | { "a" }, 415 | { "abc" }, 416 | { "message digest" }, 417 | { "abcdefghijklmnopqrstuvwxyz" }, 418 | { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" }, 419 | { "12345678901234567890123456789012345678901234567890123456789012" \ 420 | "345678901234567890" } 421 | }; 422 | 423 | static const int md5_test_buflen[7] = 424 | { 425 | 0, 1, 3, 14, 26, 62, 80 426 | }; 427 | 428 | static const unsigned char md5_test_sum[7][16] = 429 | { 430 | { 0xD4, 0x1D, 0x8C, 0xD9, 0x8F, 0x00, 0xB2, 0x04, 431 | 0xE9, 0x80, 0x09, 0x98, 0xEC, 0xF8, 0x42, 0x7E }, 432 | { 0x0C, 0xC1, 0x75, 0xB9, 0xC0, 0xF1, 0xB6, 0xA8, 433 | 0x31, 0xC3, 0x99, 0xE2, 0x69, 0x77, 0x26, 0x61 }, 434 | { 0x90, 0x01, 0x50, 0x98, 0x3C, 0xD2, 0x4F, 0xB0, 435 | 0xD6, 0x96, 0x3F, 0x7D, 0x28, 0xE1, 0x7F, 0x72 }, 436 | { 0xF9, 0x6B, 0x69, 0x7D, 0x7C, 0xB7, 0x93, 0x8D, 437 | 0x52, 0x5A, 0x2F, 0x31, 0xAA, 0xF1, 0x61, 0xD0 }, 438 | { 0xC3, 0xFC, 0xD3, 0xD7, 0x61, 0x92, 0xE4, 0x00, 439 | 0x7D, 0xFB, 0x49, 0x6C, 0xCA, 0x67, 0xE1, 0x3B }, 440 | { 0xD1, 0x74, 0xAB, 0x98, 0xD2, 0x77, 0xD9, 0xF5, 441 | 0xA5, 0x61, 0x1C, 0x2C, 0x9F, 0x41, 0x9D, 0x9F }, 442 | { 0x57, 0xED, 0xF4, 0xA2, 0x2B, 0xE3, 0xC9, 0x55, 443 | 0xAC, 0x49, 0xDA, 0x2E, 0x21, 0x07, 0xB6, 0x7A } 444 | }; 445 | 446 | /* 447 | * RFC 2202 test vectors 448 | */ 449 | static unsigned char md5_hmac_test_key[7][26] = 450 | { 451 | { "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B" }, 452 | { "Jefe" }, 453 | { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" }, 454 | { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10" 455 | "\x11\x12\x13\x14\x15\x16\x17\x18\x19" }, 456 | { "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C" }, 457 | { "" }, /* 0xAA 80 times */ 458 | { "" } 459 | }; 460 | 461 | static const int md5_hmac_test_keylen[7] = 462 | { 463 | 16, 4, 16, 25, 16, 80, 80 464 | }; 465 | 466 | static unsigned char md5_hmac_test_buf[7][74] = 467 | { 468 | { "Hi There" }, 469 | { "what do ya want for nothing?" }, 470 | { "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" 471 | "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" 472 | "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" 473 | "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" 474 | "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" }, 475 | { "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" 476 | "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" 477 | "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" 478 | "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" 479 | "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" }, 480 | { "Test With Truncation" }, 481 | { "Test Using Larger Than Block-Size Key - Hash Key First" }, 482 | { "Test Using Larger Than Block-Size Key and Larger" 483 | " Than One Block-Size Data" } 484 | }; 485 | 486 | static const int md5_hmac_test_buflen[7] = 487 | { 488 | 8, 28, 50, 50, 20, 54, 73 489 | }; 490 | 491 | static const unsigned char md5_hmac_test_sum[7][16] = 492 | { 493 | { 0x92, 0x94, 0x72, 0x7A, 0x36, 0x38, 0xBB, 0x1C, 494 | 0x13, 0xF4, 0x8E, 0xF8, 0x15, 0x8B, 0xFC, 0x9D }, 495 | { 0x75, 0x0C, 0x78, 0x3E, 0x6A, 0xB0, 0xB5, 0x03, 496 | 0xEA, 0xA8, 0x6E, 0x31, 0x0A, 0x5D, 0xB7, 0x38 }, 497 | { 0x56, 0xBE, 0x34, 0x52, 0x1D, 0x14, 0x4C, 0x88, 498 | 0xDB, 0xB8, 0xC7, 0x33, 0xF0, 0xE8, 0xB3, 0xF6 }, 499 | { 0x69, 0x7E, 0xAF, 0x0A, 0xCA, 0x3A, 0x3A, 0xEA, 500 | 0x3A, 0x75, 0x16, 0x47, 0x46, 0xFF, 0xAA, 0x79 }, 501 | { 0x56, 0x46, 0x1E, 0xF2, 0x34, 0x2E, 0xDC, 0x00, 502 | 0xF9, 0xBA, 0xB9, 0x95 }, 503 | { 0x6B, 0x1A, 0xB7, 0xFE, 0x4B, 0xD7, 0xBF, 0x8F, 504 | 0x0B, 0x62, 0xE6, 0xCE, 0x61, 0xB9, 0xD0, 0xCD }, 505 | { 0x6F, 0x63, 0x0F, 0xAD, 0x67, 0xCD, 0xA0, 0xEE, 506 | 0x1F, 0xB1, 0xF5, 0x62, 0xDB, 0x3A, 0xA5, 0x3E } 507 | }; 508 | 509 | /* 510 | * Checkup routine 511 | */ 512 | int md5_self_test( int verbose ) 513 | { 514 | int i, buflen; 515 | unsigned char buf[1024]; 516 | unsigned char md5sum[16]; 517 | md5_context ctx; 518 | 519 | for( i = 0; i < 7; i++ ) 520 | { 521 | if( verbose != 0 ) 522 | printf( " MD5 test #%d: ", i + 1 ); 523 | 524 | md5( md5_test_buf[i], md5_test_buflen[i], md5sum ); 525 | 526 | if( memcmp( md5sum, md5_test_sum[i], 16 ) != 0 ) 527 | { 528 | if( verbose != 0 ) 529 | printf( "failed\n" ); 530 | 531 | return( 1 ); 532 | } 533 | 534 | if( verbose != 0 ) 535 | printf( "passed\n" ); 536 | } 537 | 538 | if( verbose != 0 ) 539 | printf( "\n" ); 540 | 541 | for( i = 0; i < 7; i++ ) 542 | { 543 | if( verbose != 0 ) 544 | printf( " HMAC-MD5 test #%d: ", i + 1 ); 545 | 546 | if( i == 5 || i == 6 ) 547 | { 548 | memset( buf, '\xAA', buflen = 80 ); 549 | md5_hmac_starts( &ctx, buf, buflen ); 550 | } 551 | else 552 | md5_hmac_starts( &ctx, md5_hmac_test_key[i], 553 | md5_hmac_test_keylen[i] ); 554 | 555 | md5_hmac_update( &ctx, md5_hmac_test_buf[i], 556 | md5_hmac_test_buflen[i] ); 557 | 558 | md5_hmac_finish( &ctx, md5sum ); 559 | 560 | buflen = ( i == 4 ) ? 12 : 16; 561 | 562 | if( memcmp( md5sum, md5_hmac_test_sum[i], buflen ) != 0 ) 563 | { 564 | if( verbose != 0 ) 565 | printf( "failed\n" ); 566 | 567 | return( 1 ); 568 | } 569 | 570 | if( verbose != 0 ) 571 | printf( "passed\n" ); 572 | } 573 | 574 | if( verbose != 0 ) 575 | printf( "\n" ); 576 | 577 | return( 0 ); 578 | } 579 | 580 | #endif 581 | 582 | #endif 583 | -------------------------------------------------------------------------------- /src/hash/md5.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file md5.h 3 | * 4 | * \brief MD5 message digest algorithm (hash function) 5 | * 6 | * Copyright (C) 2006-2010, Brainspark B.V. 7 | * 8 | * This file is part of PolarSSL (http://www.polarssl.org) 9 | * Lead Maintainer: Paul Bakker 10 | * 11 | * All rights reserved. 12 | * 13 | * This program is free software; you can redistribute it and/or modify 14 | * it under the terms of the GNU General Public License as published by 15 | * the Free Software Foundation; either version 2 of the License, or 16 | * (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | * GNU General Public License for more details. 22 | * 23 | * You should have received a copy of the GNU General Public License along 24 | * with this program; if not, write to the Free Software Foundation, Inc., 25 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 26 | */ 27 | #ifndef POLARSSL_MD5_H 28 | #define POLARSSL_MD5_H 29 | 30 | #include 31 | 32 | /** 33 | * \brief MD5 context structure 34 | */ 35 | typedef struct 36 | { 37 | unsigned long total[2]; /*!< number of bytes processed */ 38 | unsigned long state[4]; /*!< intermediate digest state */ 39 | unsigned char buffer[64]; /*!< data block being processed */ 40 | 41 | unsigned char ipad[64]; /*!< HMAC: inner padding */ 42 | unsigned char opad[64]; /*!< HMAC: outer padding */ 43 | } 44 | md5_context; 45 | 46 | #ifdef __cplusplus 47 | extern "C" { 48 | #endif 49 | 50 | /** 51 | * \brief MD5 context setup 52 | * 53 | * \param ctx context to be initialized 54 | */ 55 | void md5_starts( md5_context *ctx ); 56 | 57 | /** 58 | * \brief MD5 process buffer 59 | * 60 | * \param ctx MD5 context 61 | * \param input buffer holding the data 62 | * \param ilen length of the input data 63 | */ 64 | void md5_update( md5_context *ctx, const unsigned char *input, size_t ilen ); 65 | 66 | /** 67 | * \brief MD5 final digest 68 | * 69 | * \param ctx MD5 context 70 | * \param output MD5 checksum result 71 | */ 72 | void md5_finish( md5_context *ctx, unsigned char output[16] ); 73 | 74 | /** 75 | * \brief Output = MD5( input buffer ) 76 | * 77 | * \param input buffer holding the data 78 | * \param ilen length of the input data 79 | * \param output MD5 checksum result 80 | */ 81 | void md5( const unsigned char *input, size_t ilen, unsigned char output[16] ); 82 | 83 | /** 84 | * \brief Output = MD5( file contents ) 85 | * 86 | * \param path input file name 87 | * \param output MD5 checksum result 88 | * 89 | * \return 0 if successful, 1 if fopen failed, 90 | * or 2 if fread failed 91 | */ 92 | int md5_file( const char *path, unsigned char output[16] ); 93 | 94 | /** 95 | * \brief MD5 HMAC context setup 96 | * 97 | * \param ctx HMAC context to be initialized 98 | * \param key HMAC secret key 99 | * \param keylen length of the HMAC key 100 | */ 101 | void md5_hmac_starts( md5_context *ctx, 102 | const unsigned char *key, size_t keylen ); 103 | 104 | /** 105 | * \brief MD5 HMAC process buffer 106 | * 107 | * \param ctx HMAC context 108 | * \param input buffer holding the data 109 | * \param ilen length of the input data 110 | */ 111 | void md5_hmac_update( md5_context *ctx, 112 | const unsigned char *input, size_t ilen ); 113 | 114 | /** 115 | * \brief MD5 HMAC final digest 116 | * 117 | * \param ctx HMAC context 118 | * \param output MD5 HMAC checksum result 119 | */ 120 | void md5_hmac_finish( md5_context *ctx, unsigned char output[16] ); 121 | 122 | /** 123 | * \brief MD5 HMAC context reset 124 | * 125 | * \param ctx HMAC context to be reset 126 | */ 127 | void md5_hmac_reset( md5_context *ctx ); 128 | 129 | /** 130 | * \brief Output = HMAC-MD5( hmac key, input buffer ) 131 | * 132 | * \param key HMAC secret key 133 | * \param keylen length of the HMAC key 134 | * \param input buffer holding the data 135 | * \param ilen length of the input data 136 | * \param output HMAC-MD5 result 137 | */ 138 | void md5_hmac( const unsigned char *key, size_t keylen, 139 | const unsigned char *input, size_t ilen, 140 | unsigned char output[16] ); 141 | 142 | /** 143 | * \brief Checkup routine 144 | * 145 | * \return 0 if successful, or 1 if the test failed 146 | */ 147 | int md5_self_test( int verbose ); 148 | 149 | #ifdef __cplusplus 150 | } 151 | #endif 152 | 153 | #endif /* md5.h */ 154 | -------------------------------------------------------------------------------- /src/hash/xor_hash.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * xor_hash.cpp 3 | * 4 | * Created on: 2011-5-9 5 | * Author: auxten 6 | **/ 7 | #include 8 | #include "xor_hash.h" 9 | #include "../gingko.h" 10 | #include "../log.h" 11 | 12 | /** 13 | * @brief xor hash a given length buf 14 | * 15 | * @see 16 | * @note 17 | * if hval is not 0, use it as the init hash value 18 | * @author auxten 19 | * @date 2011-8-1 20 | **/ 21 | unsigned xor_hash(const void *key, int len, unsigned hval) 22 | { 23 | #if defined(ROT_XOR_HASH) 24 | u_char *p = (u_char *) key; 25 | hval = hval ? hval : 2166136261; 26 | #if defined(HASH_BYTE_NUM_ONCE) 27 | for (int i = 0; i <= len - HASH_BYTE_NUM_ONCE; i += HASH_BYTE_NUM_ONCE) 28 | { 29 | hval = ROLL(hval) ^ p[i]; 30 | hval = ROLL(hval) ^ p[i + 1]; 31 | hval = ROLL(hval) ^ p[i + 2]; 32 | hval = ROLL(hval) ^ p[i + 3]; 33 | #if HASH_BYTE_NUM_ONCE == 8 34 | hval = ROLL(hval) ^ p[i + 4]; 35 | hval = ROLL(hval) ^ p[i + 5]; 36 | hval = ROLL(hval) ^ p[i + 6]; 37 | hval = ROLL(hval) ^ p[i + 7]; 38 | #endif /** HASH_BYTE_NUM_ONCE == 8 **/ 39 | } 40 | /** 41 | * hash the remained bytes 42 | **/ 43 | for (int i = len - len % HASH_BYTE_NUM_ONCE; i < len; i++) 44 | { 45 | hval = ROLL(hval) ^ p[i]; 46 | } 47 | #else 48 | for (int i = 0; i < len; i++) 49 | { 50 | hval = ROLL(hval) ^ p[i]; 51 | } 52 | #endif 53 | 54 | #elif defined(FNV_XOR_HASH) 55 | u_char *p = (u_char *) key; 56 | hval = hval ? hval : 2166136261; 57 | 58 | for (int i = 0; i < len; i++) 59 | { 60 | #if defined(NO_SO_CALLED_FNV_OPTIMIZE) 61 | hval = (hval * 16777619) ^ p[i]; 62 | #else 63 | hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval 64 | << 24); 65 | hval ^= p[i]; 66 | #endif 67 | } 68 | 69 | return hval; 70 | #endif /** ROT_XOR_HASH **/ 71 | return hval; 72 | } 73 | 74 | /** 75 | * @brief check if the fnv check sum is OK 76 | * 77 | * @see 78 | * @note 79 | * @author auxten 80 | * @date 2011-8-1 81 | **/ 82 | char digest_ok(void * buf, s_block_t * b) 83 | { 84 | return (xor_hash(buf, b->size, 0) == b->digest); 85 | } 86 | 87 | /** 88 | * @brief xor hash specified block 89 | * 90 | * @see 91 | * @note 92 | * @author auxten 93 | * @date 2011-8-1 94 | **/ 95 | unsigned xor_hash_block(s_job_t * jo, GKO_INT64 block_id, u_char * buf) 96 | { 97 | s_file_t * files = jo->files; 98 | s_block_t * blocks = jo->blocks; 99 | GKO_INT64 read_counter = 0; 100 | GKO_INT64 file_i = (blocks + block_id)->start_f; 101 | GKO_INT64 offset = 0; 102 | int fd; 103 | unsigned tmp_hash = 0; 104 | 105 | if (FAIL_CHECK(-1 == (fd = open((files + ((blocks + block_id)->start_f))->name, 106 | O_RDONLY | O_NOFOLLOW)))) 107 | { 108 | GKOLOG(WARNING, "file open() error!"); 109 | } 110 | memset(buf, 0, BLOCK_SIZE); 111 | offset = (blocks + block_id)->start_off; 112 | while (read_counter < (blocks + block_id)->size) 113 | { 114 | GKO_INT64 tmp = pread(fd, buf + read_counter, 115 | (blocks + block_id)->size - read_counter, offset); 116 | if (FAIL_CHECK(tmp < 0)) 117 | { 118 | GKOLOG(WARNING, "pread failed"); 119 | } 120 | if (LIKELY(tmp)) 121 | { 122 | ///printf("read: %ld\n", tmp); 123 | tmp_hash = xor_hash(buf + read_counter, (int) tmp, tmp_hash); 124 | read_counter += tmp; 125 | offset += tmp; 126 | } 127 | else 128 | { 129 | close(fd); 130 | ///if the next if a nonfile then next 131 | file_i = next_f(jo, file_i); 132 | if (FAIL_CHECK(-1 133 | == (fd = open( 134 | (files + ((blocks + block_id)->start_f) 135 | + file_i)->name, O_RDONLY | O_NOFOLLOW)))) 136 | { 137 | fprintf(stderr, "filename: %s\n", 138 | (files + ((blocks + block_id)->start_f) + file_i)->name); 139 | GKOLOG(WARNING, "filename: %s", 140 | (files + ((blocks + block_id)->start_f) + file_i)->name); 141 | } 142 | offset = 0; 143 | 144 | } 145 | } 146 | (blocks + block_id)->digest = tmp_hash; 147 | /// printf("buf: %d\n", sizeof(buf)); 148 | /// memset(buf, 0, sizeof(buf)); 149 | /// printf("buf: %d\n", sizeof(buf)); 150 | close(fd); 151 | return tmp_hash; 152 | } 153 | 154 | /** 155 | * @brief xor hash the file given 156 | * 157 | * @see 158 | * @note 159 | * @author auxten 160 | * @date 2011-8-1 161 | **/ 162 | unsigned xor_hash_file(unsigned value, FILE * fd, off_t * off, size_t * count, 163 | u_char * buf) 164 | { 165 | fseeko(fd, *off, SEEK_SET); 166 | if (FAIL_CHECK(*count != fread(buf, sizeof(char), *count, fd))) 167 | { 168 | GKOLOG(FATAL, "fread error"); 169 | } 170 | ///fprintf(stderr, "#######################buf: %s\n", buf); 171 | return xor_hash(buf, *count, value); 172 | } 173 | 174 | -------------------------------------------------------------------------------- /src/hash/xor_hash.h: -------------------------------------------------------------------------------- 1 | /** 2 | * xor_hash.h 3 | * 4 | * Created on: 2011-5-9 5 | * Author: auxten 6 | **/ 7 | #include "../gingko.h" 8 | 9 | #ifndef XOR_HASH_H_ 10 | #define XOR_HASH_H_ 11 | 12 | /// shift Macro 13 | //#define ROLL(h) (((h) << 7) ^ ((h) >> 25)) 14 | #define ROLL(h) (h * 16777619) 15 | 16 | /// xor hash a given length buf 17 | unsigned xor_hash(const void *key, int len, unsigned hval); 18 | /// check if the fnv check sum is OK 19 | char digest_ok(void * buf, s_block_t * b); 20 | /// xor hash all blocks for a job given 21 | int xor_hash_all(s_job_t * jo, hash_worker_thread_arg arg[]); 22 | #endif /** XOR_HASH_H_ **/ 23 | -------------------------------------------------------------------------------- /src/hermes_errno.h: -------------------------------------------------------------------------------- 1 | /* 2 | * gko_errno.h 3 | * 4 | * Created on: May 17, 2012 5 | * Author: auxten 6 | */ 7 | 8 | #ifndef GKO_ERRNO_H_ 9 | #define GKO_ERRNO_H_ 10 | 11 | enum error_no { 12 | //////////////////// DO NOT USE DIRECTLY below ////////////////////// 13 | /// succ or fail 14 | INVILID = -1, 15 | SUCC = 0, 16 | FAIL = 1, 17 | ING = 2, /// doing something. 18 | RESUME = 3, 19 | PAUSE = 4, 20 | DELETED = 5, 21 | STOP = 6, 22 | FINISHED = 7, 23 | 24 | /// 失败原因 25 | ERROR = 10, /// 其它各种失败 26 | RECV_TIMEOUT = 20, 27 | SEND_TIMEOUT = 30, 28 | RESETED = 40, 29 | RECV_ERROR = 50, 30 | SEND_ERROR = 60, 31 | AGENT_ERROR = 70, 32 | 33 | /// 任务阶段 34 | TODO = 100, 35 | DISPATCH = 200, 36 | EXECUTE = 300, 37 | GKO_MYSQL = 400, 38 | SERVER_INTERNAL = 500, 39 | DNS_RESOLVE = 600, 40 | //////////////////// DO NOT USE DIRECTLY above ////////////////////// 41 | ////以上不要直接使用 42 | 43 | /// 任务分发结果 44 | DISPATCH_ING = DISPATCH + ING, /// 正在分发任务 45 | DISPATCH_SUCC = DISPATCH + SUCC, 46 | DISPATCH_SEND_TIMEOUT = DISPATCH + SEND_TIMEOUT + FAIL, /// 网络发送超时 47 | DISPATCH_RECV_TIMEOUT = DISPATCH + RECV_TIMEOUT + FAIL, /// 发送任务获取agent收到确认超时 48 | DISPATCH_SEND_ERROR = DISPATCH + SEND_ERROR + FAIL, /// 网络连接错误,eg. reset 49 | DISPATCH_RECV_ERROR = DISPATCH + RECV_ERROR + FAIL, /// 网络连接错误,eg. reset 50 | DISPATCH_AGENT_FAIL = DISPATCH + AGENT_ERROR + FAIL, /// agent接受任务后立刻返回失败 51 | 52 | /// 任务执行结果 53 | EXECUTE_SUCC = EXECUTE + SUCC, /// 54 | EXECUTE_FAIL = EXECUTE + FAIL, /// agent执行失败 55 | 56 | /// 服务器内部状态 57 | SERVER_INTERNAL_ERROR = SERVER_INTERNAL + ERROR + FAIL, 58 | 59 | /// DNS解析错误 60 | DNS_RESOLVE_FAIL = DNS_RESOLVE + ERROR + FAIL, 61 | 62 | }; 63 | #endif /* GKO_ERRNO_H_ */ 64 | -------------------------------------------------------------------------------- /src/libgko.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | venderlibsinc=@venderlibsinc@ 6 | venderincs=@venderincs@ 7 | 8 | Name: gko_pool 9 | Description: Async server and client framework 10 | URL: http://optool.net 11 | Version: 0.8 12 | Requires: 13 | Libs: -L${libdir} -Wl,-lgko @venderlibsinc@ -lpthread 14 | Cflags: -I${includedir} @venderincs@ 15 | -------------------------------------------------------------------------------- /src/limit.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * limit.cpp 3 | * 4 | * Created on: Mar 9, 2012 5 | * Author: auxten 6 | **/ 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "gingko.h" 17 | 18 | 19 | ///mutex for up bandwidth limit 20 | static pthread_mutex_t g_bw_up_mutex = PTHREAD_MUTEX_INITIALIZER; 21 | ///mutex for down bandwidth limit 22 | static pthread_mutex_t g_bw_down_mutex = PTHREAD_MUTEX_INITIALIZER; 23 | ///mutex for up bandwidth limit 24 | static pthread_mutex_t g_disk_r_mutex = PTHREAD_MUTEX_INITIALIZER; 25 | ///mutex for down bandwidth limit 26 | static pthread_mutex_t g_disk_w_mutex = PTHREAD_MUTEX_INITIALIZER; 27 | ///mutex for make seed limit 28 | static pthread_mutex_t g_mk_seed_mutex = PTHREAD_MUTEX_INITIALIZER; 29 | 30 | /** 31 | * @brief limit down rate 32 | * 33 | * @see 34 | * @note bwlimit modified from scp 35 | * @author auxten 36 | * @date 2011-8-1 37 | **/ 38 | void bw_down_limit(int amount, int limit_rate) 39 | { 40 | static struct timeval bw_down_start; 41 | static struct timeval bw_down_end; 42 | static int down_lamt; 43 | static int down_thresh = 16384; 44 | GKO_UINT64 waitlen; 45 | struct timespec ts; 46 | struct timespec rm; 47 | 48 | if (amount <= 0 || limit_rate <= 0) 49 | { 50 | return; 51 | } 52 | pthread_mutex_lock(&g_bw_down_mutex); 53 | 54 | if (UNLIKELY(!timerisset(&bw_down_start))) 55 | { 56 | gettimeofday(&bw_down_start, NULL); 57 | goto DISK_W_UNLOCK_RET; 58 | } 59 | 60 | down_lamt += amount; 61 | if (down_lamt < down_thresh) 62 | { 63 | goto DISK_W_UNLOCK_RET; 64 | } 65 | 66 | gettimeofday(&bw_down_end, NULL); 67 | timersub(&bw_down_end, &bw_down_start, &bw_down_end); 68 | if (!timerisset(&bw_down_end)) 69 | { 70 | goto DISK_W_UNLOCK_RET; 71 | } 72 | 73 | waitlen = (GKO_UINT64) 1000000L * down_lamt / limit_rate; 74 | 75 | bw_down_start.tv_sec = waitlen / 1000000L; 76 | bw_down_start.tv_usec = waitlen % 1000000L; 77 | 78 | if (timercmp(&bw_down_start, &bw_down_end, >)) 79 | { 80 | timersub(&bw_down_start, &bw_down_end, &bw_down_end); 81 | 82 | /** Adjust the wait time **/ 83 | if (bw_down_end.tv_sec) 84 | { 85 | down_thresh /= 2; 86 | if (down_thresh < 2048) 87 | { 88 | down_thresh = 2048; 89 | } 90 | } 91 | else if (bw_down_end.tv_usec < 100) 92 | { 93 | down_thresh *= 2; 94 | if (down_thresh > 32768) 95 | { 96 | down_thresh = 32768; 97 | } 98 | } 99 | 100 | TIMEVAL_TO_TIMESPEC(&bw_down_end, &ts); 101 | ///GKOLOG(WARNING, "sleep for: %d usec", (&bw_down_end)->tv_usec); 102 | while (nanosleep(&ts, &rm) == -1) 103 | { 104 | if (errno != EINTR) 105 | { 106 | break; 107 | } 108 | ts = rm; 109 | } 110 | } 111 | 112 | down_lamt = 0; 113 | gettimeofday(&bw_down_start, NULL); 114 | 115 | DISK_W_UNLOCK_RET: 116 | pthread_mutex_unlock(&g_bw_down_mutex); 117 | return; 118 | } 119 | 120 | /** 121 | * @brief limit up rate 122 | * 123 | * @see 124 | * @note bwlimit modified from scp 125 | * @author auxten 126 | * @date 2011-8-1 127 | **/ 128 | void bw_up_limit(int amount, int limit_rate) 129 | { 130 | static struct timeval bw_up_start; 131 | static struct timeval bw_up_end; 132 | static int up_lamt; 133 | static int up_thresh = 16384; 134 | GKO_UINT64 waitlen; 135 | struct timespec ts; 136 | struct timespec rm; 137 | 138 | if (amount <= 0 || limit_rate <= 0) 139 | { 140 | return; 141 | } 142 | pthread_mutex_lock(&g_bw_up_mutex); 143 | 144 | if (UNLIKELY(!timerisset(&bw_up_start))) 145 | { 146 | gettimeofday(&bw_up_start, NULL); 147 | goto UP_UNLOCK_RET; 148 | } 149 | 150 | up_lamt += amount; 151 | if (up_lamt < up_thresh) 152 | { 153 | goto UP_UNLOCK_RET; 154 | } 155 | 156 | gettimeofday(&bw_up_end, NULL); 157 | timersub(&bw_up_end, &bw_up_start, &bw_up_end); 158 | if (!timerisset(&bw_up_end)) 159 | { 160 | goto UP_UNLOCK_RET; 161 | } 162 | 163 | waitlen = (GKO_UINT64) 1000000L * up_lamt / limit_rate; 164 | 165 | bw_up_start.tv_sec = waitlen / 1000000L; 166 | bw_up_start.tv_usec = waitlen % 1000000L; 167 | 168 | if (timercmp(&bw_up_start, &bw_up_end, >)) 169 | { 170 | timersub(&bw_up_start, &bw_up_end, &bw_up_end); 171 | 172 | /** Adjust the wait time **/ 173 | if (bw_up_end.tv_sec) 174 | { 175 | up_thresh /= 2; 176 | if (up_thresh < 2048) 177 | { 178 | up_thresh = 2048; 179 | } 180 | } 181 | else if (bw_up_end.tv_usec < 100) 182 | { 183 | up_thresh *= 2; 184 | if (up_thresh > 32768) 185 | { 186 | up_thresh = 32768; 187 | } 188 | } 189 | 190 | TIMEVAL_TO_TIMESPEC(&bw_up_end, &ts); 191 | ///GKOLOG(WARNING, "sleep for: %d usec", (&bw_up_end)->tv_usec); 192 | while (nanosleep(&ts, &rm) == -1) 193 | { 194 | if (errno != EINTR) 195 | { 196 | break; 197 | } 198 | ts = rm; 199 | } 200 | } 201 | 202 | up_lamt = 0; 203 | gettimeofday(&bw_up_start, NULL); 204 | 205 | UP_UNLOCK_RET: 206 | pthread_mutex_unlock(&g_bw_up_mutex); 207 | return; 208 | } 209 | 210 | /** 211 | * @brief limit disk write rate 212 | * 213 | * @see 214 | * @note bwlimit modified from scp 215 | * @author auxten 216 | * @date 2011-8-1 217 | **/ 218 | void disk_w_limit(int amount, int limit_rate) 219 | { 220 | static struct timeval disk_w_start; 221 | static struct timeval disk_w_end; 222 | static int write_lamt; 223 | static int write_thresh = 16384; 224 | GKO_UINT64 waitlen; 225 | struct timespec ts; 226 | struct timespec rm; 227 | 228 | if (amount <= 0 || limit_rate <= 0) 229 | { 230 | return; 231 | } 232 | pthread_mutex_lock(&g_disk_w_mutex); 233 | 234 | if (UNLIKELY(!timerisset(&disk_w_start))) 235 | { 236 | gettimeofday(&disk_w_start, NULL); 237 | goto DISK_W_UNLOCK_RET; 238 | } 239 | 240 | write_lamt += amount; 241 | if (write_lamt < write_thresh) 242 | { 243 | goto DISK_W_UNLOCK_RET; 244 | } 245 | 246 | gettimeofday(&disk_w_end, NULL); 247 | timersub(&disk_w_end, &disk_w_start, &disk_w_end); 248 | if (!timerisset(&disk_w_end)) 249 | { 250 | goto DISK_W_UNLOCK_RET; 251 | } 252 | 253 | waitlen = (GKO_UINT64) 1000000L * write_lamt / limit_rate; 254 | 255 | disk_w_start.tv_sec = waitlen / 1000000L; 256 | disk_w_start.tv_usec = waitlen % 1000000L; 257 | 258 | if (timercmp(&disk_w_start, &disk_w_end, >)) 259 | { 260 | timersub(&disk_w_start, &disk_w_end, &disk_w_end); 261 | 262 | /** Adjust the wait time **/ 263 | if (disk_w_end.tv_sec) 264 | { 265 | write_thresh /= 2; 266 | if (write_thresh < 2048) 267 | { 268 | write_thresh = 2048; 269 | } 270 | } 271 | else if (disk_w_end.tv_usec < 100) 272 | { 273 | write_thresh *= 2; 274 | if (write_thresh > 32768) 275 | { 276 | write_thresh = 32768; 277 | } 278 | } 279 | 280 | TIMEVAL_TO_TIMESPEC(&disk_w_end, &ts); 281 | ///GKOLOG(WARNING, "sleep for: %d usec", (&disk_w_end)->tv_usec); 282 | while (nanosleep(&ts, &rm) == -1) 283 | { 284 | if (errno != EINTR) 285 | { 286 | break; 287 | } 288 | ts = rm; 289 | } 290 | } 291 | 292 | write_lamt = 0; 293 | gettimeofday(&disk_w_start, NULL); 294 | 295 | DISK_W_UNLOCK_RET: 296 | pthread_mutex_unlock(&g_disk_w_mutex); 297 | return; 298 | } 299 | 300 | /** 301 | * @brief limit disk read rate 302 | * 303 | * @see 304 | * @note bwlimit modified from scp 305 | * @author auxten 306 | * @date 2011-8-1 307 | **/ 308 | void disk_r_limit(int amount, int limit_rate) 309 | { 310 | static struct timeval disk_r_start; 311 | static struct timeval disk_r_end; 312 | static int read_lamt; 313 | static int read_thresh = 16384; 314 | GKO_UINT64 waitlen; 315 | struct timespec ts; 316 | struct timespec rm; 317 | 318 | if (amount <= 0 || limit_rate <= 0) 319 | { 320 | return; 321 | } 322 | pthread_mutex_lock(&g_disk_r_mutex); 323 | 324 | if (UNLIKELY(!timerisset(&disk_r_start))) 325 | { 326 | gettimeofday(&disk_r_start, NULL); 327 | goto DISK_R_UNLOCK_RET; 328 | } 329 | 330 | read_lamt += amount; 331 | if (read_lamt < read_thresh) 332 | { 333 | goto DISK_R_UNLOCK_RET; 334 | } 335 | 336 | gettimeofday(&disk_r_end, NULL); 337 | timersub(&disk_r_end, &disk_r_start, &disk_r_end); 338 | if (!timerisset(&disk_r_end)) 339 | { 340 | goto DISK_R_UNLOCK_RET; 341 | } 342 | 343 | waitlen = (GKO_UINT64) 1000000L * read_lamt / limit_rate; 344 | 345 | disk_r_start.tv_sec = waitlen / 1000000L; 346 | disk_r_start.tv_usec = waitlen % 1000000L; 347 | 348 | if (timercmp(&disk_r_start, &disk_r_end, >)) 349 | { 350 | timersub(&disk_r_start, &disk_r_end, &disk_r_end); 351 | 352 | /** Adjust the wait time **/ 353 | if (disk_r_end.tv_sec) 354 | { 355 | read_thresh /= 2; 356 | if (read_thresh < 2048) 357 | { 358 | read_thresh = 2048; 359 | } 360 | } 361 | else if (disk_r_end.tv_usec < 100) 362 | { 363 | read_thresh *= 2; 364 | if (read_thresh > 32768) 365 | { 366 | read_thresh = 32768; 367 | } 368 | } 369 | 370 | TIMEVAL_TO_TIMESPEC(&disk_r_end, &ts); 371 | ///GKOLOG(WARNING, "sleep for: %d usec", (&disk_r_end)->tv_usec); 372 | while (nanosleep(&ts, &rm) == -1) 373 | { 374 | if (errno != EINTR) 375 | { 376 | break; 377 | } 378 | ts = rm; 379 | } 380 | } 381 | 382 | read_lamt = 0; 383 | gettimeofday(&disk_r_start, NULL); 384 | 385 | DISK_R_UNLOCK_RET: 386 | pthread_mutex_unlock(&g_disk_r_mutex); 387 | return; 388 | } 389 | 390 | 391 | /** 392 | * @brief limit make seed rate 393 | * 394 | * @see 395 | * @note bwlimit modified from scp 396 | * @author auxten 397 | * @date 2011-8-1 398 | **/ 399 | void mk_seed_limit(int amount, int limit_rate) 400 | { 401 | static struct timeval mk_seed_start; 402 | static struct timeval mk_seed_end; 403 | static int mk_seed_lamt; 404 | static int mk_seed_thresh = 16384; 405 | GKO_UINT64 waitlen; 406 | struct timespec ts; 407 | struct timespec rm; 408 | if (amount <= 0 || limit_rate <= 0) 409 | { 410 | return; 411 | } 412 | pthread_mutex_lock(&g_mk_seed_mutex); 413 | 414 | if (UNLIKELY(!timerisset(&mk_seed_start))) 415 | { 416 | gettimeofday(&mk_seed_start, NULL); 417 | goto MK_SEED_UNLOCK_RET; 418 | } 419 | 420 | mk_seed_lamt += amount; 421 | if (mk_seed_lamt < mk_seed_thresh) 422 | { 423 | goto MK_SEED_UNLOCK_RET; 424 | } 425 | 426 | gettimeofday(&mk_seed_end, NULL); 427 | timersub(&mk_seed_end, &mk_seed_start, &mk_seed_end); 428 | if (!timerisset(&mk_seed_end)) 429 | { 430 | goto MK_SEED_UNLOCK_RET; 431 | } 432 | 433 | waitlen = (GKO_UINT64) 1000000L * mk_seed_lamt / limit_rate; 434 | 435 | mk_seed_start.tv_sec = waitlen / 1000000L; 436 | mk_seed_start.tv_usec = waitlen % 1000000L; 437 | 438 | if (timercmp(&mk_seed_start, &mk_seed_end, >)) 439 | { 440 | timersub(&mk_seed_start, &mk_seed_end, &mk_seed_end); 441 | 442 | /** Adjust the wait time **/ 443 | if (mk_seed_end.tv_sec) 444 | { 445 | mk_seed_thresh /= 2; 446 | if (mk_seed_thresh < 2048) 447 | { 448 | mk_seed_thresh = 2048; 449 | } 450 | } 451 | else if (mk_seed_end.tv_usec < 100) 452 | { 453 | mk_seed_thresh *= 2; 454 | if (mk_seed_thresh > 32768) 455 | { 456 | mk_seed_thresh = 32768; 457 | } 458 | } 459 | 460 | TIMEVAL_TO_TIMESPEC(&mk_seed_end, &ts); 461 | ///GKOLOG(WARNING, "sleep for: %d usec", (&mk_seed_end)->tv_usec); 462 | while (nanosleep(&ts, &rm) == -1) 463 | { 464 | if (errno != EINTR) 465 | { 466 | break; 467 | } 468 | ts = rm; 469 | } 470 | } 471 | 472 | mk_seed_lamt = 0; 473 | gettimeofday(&mk_seed_start, NULL); 474 | 475 | MK_SEED_UNLOCK_RET: 476 | pthread_mutex_unlock(&g_mk_seed_mutex); 477 | return; 478 | } 479 | 480 | -------------------------------------------------------------------------------- /src/limit.h: -------------------------------------------------------------------------------- 1 | /** 2 | * limit.h 3 | * 4 | * Created on: Mar 9, 2012 5 | * Author: auxten 6 | **/ 7 | 8 | #ifndef LIMIT_H_ 9 | #define LIMIT_H_ 10 | 11 | /// limit download rate 12 | void bw_down_limit(int amount, int limit_rate); 13 | /// limit upload rate 14 | void bw_up_limit(int amount, int limit_rate); 15 | /// limit disk write rate 16 | void disk_w_limit(int amount, int limit_rate); 17 | /// limit disk read rate 18 | void disk_r_limit(int amount, int limit_rate); 19 | /// limit make seed rate 20 | void mk_seed_limit(int amount, int limit_rate); 21 | 22 | #endif /** LIMIT_H_ **/ 23 | -------------------------------------------------------------------------------- /src/log.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * log.cpp 3 | * 4 | * Created on: 2011-7-13 5 | * Author: auxten 6 | **/ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "gingko.h" 17 | #include "log.h" 18 | 19 | extern s_gingko_global_t gko; 20 | pthread_mutex_t g_logcut_lock = PTHREAD_MUTEX_INITIALIZER; 21 | /// TLS, for print proformance time in log 22 | static pthread_key_t g_proformace_timer_key; 23 | static pthread_once_t key_once = PTHREAD_ONCE_INIT; 24 | 25 | /** 26 | * @brief loglevel 27 | * 28 | * @see 29 | * @note 30 | * @author auxten 31 | * @date 2011-8-1 32 | **/ 33 | static const char * LOG_DIC[] = 34 | { "FATAL", "WARN ", "NOTIC", "TRACE", "DEBUG", }; 35 | 36 | /** 37 | * @brief generate the time string according to the TIME_FORMAT 38 | * 39 | * @see 40 | * @note 41 | * @author auxten 42 | * @date 2011-8-1 43 | **/ 44 | size_t gettimestr(char * time, const char * format, struct timeval * tv) 45 | { 46 | struct tm ltime; 47 | time_t curtime; 48 | gettimeofday(tv, NULL); 49 | curtime = tv->tv_sec; 50 | ///Format time 51 | return strftime(time, 25, format, localtime_r(&curtime, <ime)); 52 | } 53 | 54 | static void make_key() 55 | { 56 | pthread_key_create(&g_proformace_timer_key, NULL); 57 | } 58 | 59 | static struct timeval * get_timer(void) 60 | { 61 | void *p = NULL; 62 | 63 | pthread_once(&key_once, make_key); 64 | p = pthread_getspecific(g_proformace_timer_key); 65 | if (p == NULL) 66 | { 67 | p = calloc(1, sizeof(struct timeval)); 68 | pthread_setspecific(g_proformace_timer_key, p); 69 | } 70 | 71 | return (struct timeval *) p; 72 | } 73 | 74 | /** 75 | * @brief log handler 76 | * 77 | * @see 78 | * @note 79 | * @author auxten 80 | * @date 2011-8-1 81 | **/ 82 | void gko_log_flf(const u_int8_t log_level, const char *file, const int line, const char *func, const char *fmt, ...) 83 | { 84 | if (gko.opt.to_debug || log_level < DEBUG ) 85 | { 86 | int errnum = errno; 87 | va_list args; 88 | va_start(args, fmt); 89 | char logstr[MAX_LOG_BYTE]; 90 | char oldlogpath[MAX_PATH_LEN]; 91 | char rmOldLogs[MAX_PATH_LEN]; 92 | static FILE * lastfp = NULL; 93 | static GKO_INT64 counter = 1; 94 | struct timeval last_timeval; 95 | struct timeval time_diff; 96 | struct timeval * time_p = get_timer(); 97 | long usec_diff; 98 | int len = 0; 99 | int rm_cmd_len; 100 | 101 | memcpy(&last_timeval, time_p, sizeof(last_timeval)); 102 | 103 | len += snprintf(logstr, sizeof(logstr), "%s: [%u]", LOG_DIC[log_level], gko_gettid()); 104 | len += gettimestr(logstr + len, TIME_FORMAT, time_p); 105 | timersub(time_p, &last_timeval, &time_diff); 106 | usec_diff = time_diff.tv_sec * 1000000 + time_diff.tv_usec; 107 | if (usec_diff < 0) 108 | usec_diff = 0; 109 | 110 | len += snprintf(logstr + len, sizeof(logstr) - len, "[%s:%d @%s][%ldus]\t", file, line, func, usec_diff); 111 | len += vsnprintf(logstr + len, sizeof(logstr) - len, fmt, args); 112 | 113 | logstr[sizeof(logstr) - 3] = '\0'; 114 | len = MIN(sizeof(logstr) - 3, len); 115 | 116 | if (log_level < NOTICE) 117 | { 118 | len += snprintf(logstr + len, sizeof(logstr) - len, "; "); 119 | strerror_r(errnum, logstr + len, 120 | sizeof(logstr) - len); 121 | } 122 | 123 | pthread_mutex_lock(&g_logcut_lock); 124 | if (gko.opt.logpath[0] == '\0') 125 | { 126 | gko.log_fp = stdout; 127 | } 128 | else 129 | { 130 | counter ++; 131 | if (counter % MAX_LOG_REOPEN_LINE == 0) 132 | { 133 | if (lastfp) 134 | { 135 | fclose(lastfp); 136 | } 137 | lastfp = gko.log_fp; 138 | if (counter % MAX_LOG_LINE == 0) 139 | { 140 | strncpy(oldlogpath, gko.opt.logpath, MAX_PATH_LEN - 1); 141 | gettimestr(oldlogpath + strlen(oldlogpath), OLD_LOG_TIME, time_p); 142 | rename(gko.opt.logpath, oldlogpath); 143 | rm_cmd_len = snprintf(rmOldLogs, MAX_PATH_LEN - 1, 144 | "/bin/ls -t %s.201* | /usr/bin/tail -n +%u | /usr/bin/xargs /bin/rm -f", 145 | gko.opt.logpath, MAX_LOG_KEEPED); 146 | if (strlen(gko.opt.logpath) > 0 && 147 | rm_cmd_len < MAX_PATH_LEN && 148 | rm_cmd_len > 0) 149 | { 150 | rmOldLogs[rm_cmd_len] = '\0'; 151 | system(rmOldLogs); 152 | } 153 | 154 | } 155 | gko.log_fp = fopen(gko.opt.logpath, "a+"); 156 | } 157 | if(UNLIKELY(! gko.log_fp)) 158 | { 159 | gko.log_fp = fopen(gko.opt.logpath, "a+"); 160 | if(! gko.log_fp) 161 | { 162 | perror("Cann't open log file"); 163 | _exit(1); 164 | } 165 | } 166 | } 167 | fprintf(gko.log_fp, "%s\n", logstr); 168 | if (usec_diff >= 1000000 || 169 | (counter % MAX_LOG_FLUSH_LINE == 0)) 170 | { 171 | fflush(gko.log_fp); 172 | } 173 | pthread_mutex_unlock(&g_logcut_lock); 174 | 175 | va_end(args); 176 | } 177 | return; 178 | 179 | } 180 | 181 | int lock_log(void) 182 | { 183 | return pthread_mutex_lock(&g_logcut_lock); 184 | } 185 | 186 | int unlock_log(void) 187 | { 188 | return pthread_mutex_unlock(&g_logcut_lock); 189 | } 190 | 191 | int reinit_log_lock(void) 192 | { 193 | return pthread_mutex_init(&g_logcut_lock, NULL); 194 | } 195 | -------------------------------------------------------------------------------- /src/log.h: -------------------------------------------------------------------------------- 1 | /** 2 | * log.h 3 | * 4 | * Created on: Mar 9, 2012 5 | * Author: auxten 6 | * 7 | **/ 8 | 9 | #ifndef LOG_H_ 10 | #define LOG_H_ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | ///fatal 22 | static const u_int8_t FATAL = 0; 23 | ///warning 24 | static const u_int8_t WARNING = 1; 25 | ///notice 26 | static const u_int8_t NOTICE = 2; 27 | ///trace 28 | static const u_int8_t TRACE = 3; 29 | ///debug 30 | static const u_int8_t DEBUG = 4; 31 | 32 | /// to print the file line func 33 | /// MUST NOT use it in "const char *fmt, ..." type func 34 | //#define FLF(a) "{%s:%d %s} %s",__FILE__,__LINE__,__func__,#a 35 | #define FLF(a) a 36 | 37 | #define GKOLOG(level, args...) gko_log_flf(level, __FILE__, __LINE__, __func__, args) 38 | 39 | /// log handler 40 | void gko_log_flf(const u_int8_t log_level, const char *file, const int line, const char *func, const char *fmt, ...); 41 | int lock_log(void); 42 | int unlock_log(void); 43 | int reinit_log_lock(void); 44 | 45 | #endif /** LOG_H_ **/ 46 | -------------------------------------------------------------------------------- /src/memory.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * memory.cpp 3 | * 4 | * Created on: Jun 8, 2012 5 | * Author: auxten 6 | * 7 | * only support little endian : x86 8 | */ 9 | 10 | //#define MEM_TEST 11 | #define _XOPEN_SOURCE 600 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "memory.h" 19 | 20 | #include "log.h" 21 | 22 | 23 | gkoAlloc::gkoAlloc(void) 24 | { 25 | pthread_mutex_init(&alloc_lock, NULL); 26 | memset((void *) m_map, 0, M_MAP_SIZE * sizeof(u_int8_t)); 27 | memset((void *) bucket_s, 0, BUCKET_COUNT * sizeof(void *)); 28 | memset((void *) bucket_used, 0, BUCKET_COUNT * sizeof(int16_t)); 29 | latest_bucket = 0; 30 | } 31 | 32 | void * gkoAlloc::id2addr(int block_id) 33 | { 34 | if (block_id < 0) 35 | return NULL; 36 | 37 | int bucket_no = block_id / BUCKET_CAPACITY; 38 | int bucket_offset = SLOT_SIZE * (block_id % BUCKET_CAPACITY); 39 | 40 | return ((char *)bucket_s[bucket_no]) + bucket_offset; 41 | } 42 | 43 | int gkoAlloc::get_bit(u_int8_t * b) 44 | { 45 | /** 46 | * idx 01234567 47 | * byte 11111010 48 | * 49 | * return 5 and 50 | * byte 11111110 51 | */ 52 | 53 | int i; 54 | for (i = 0; i < 8; i++) 55 | { 56 | if ((u_int8_t)((*b >> 7 - i) << 7) == (u_int8_t)0u) 57 | break; 58 | } 59 | 60 | *b |= (u_int8_t)( 1u << 7 - i); 61 | 62 | return i; 63 | } 64 | 65 | int gkoAlloc::free_bit(u_int8_t * b, int index) 66 | { 67 | /** 68 | * idx 01234567 69 | * byte 11111110 70 | * 71 | * return 5 and 72 | * byte 11111010 73 | */ 74 | 75 | *b ^= (u_int8_t)( 1u << 7 - index); 76 | 77 | return index; 78 | } 79 | 80 | int gkoAlloc::get_block(void) 81 | { 82 | int i; 83 | int the_bucket; 84 | int idx = INVILID_BLOCK; 85 | u_int8_t * p_idx; 86 | u_int64_t * bucket_start_idx; 87 | u_int64_t * bucket_end_idx; 88 | u_int64_t * bucket_idx; 89 | 90 | pthread_mutex_lock(&alloc_lock); 91 | for (i = 0; i < BUCKET_COUNT; i++) 92 | { 93 | the_bucket = (latest_bucket + i) % BUCKET_COUNT; 94 | if (bucket_used[the_bucket] < BUCKET_CAPACITY) 95 | { 96 | // latest_bucket = the_bucket; 97 | break; 98 | } 99 | } 100 | 101 | if (i == BUCKET_COUNT) 102 | { 103 | fprintf(stderr, "out of memory in pool\n"); 104 | GKOLOG(FATAL, "out of memory in pool"); 105 | idx = INVILID_BLOCK; 106 | goto GET_BLOCK_RET; 107 | } 108 | 109 | if (!bucket_s[the_bucket]) 110 | { 111 | void * ptr; 112 | if (!posix_memalign(&ptr, SLOT_SIZE, BUCKET_SIZE)) 113 | { 114 | bucket_s[the_bucket] = ptr; 115 | bucket_used[the_bucket] = 0; 116 | } 117 | else 118 | { 119 | fprintf(stderr, "posix_memalign fail\n"); 120 | // GKOLOG(FATAL, "posix_memalign fail"); 121 | idx = INVILID_BLOCK; 122 | goto GET_BLOCK_RET; 123 | } 124 | } 125 | 126 | bucket_start_idx = (u_int64_t *) &(this->m_map[the_bucket * BUCKET_CAPACITY / 8]); 127 | bucket_end_idx = (u_int64_t *) &(this->m_map[(the_bucket + 1) * BUCKET_CAPACITY / 8]); 128 | for (bucket_idx = bucket_start_idx; 129 | bucket_idx < bucket_end_idx; 130 | bucket_idx++) 131 | { 132 | if (*(u_int64_t *) bucket_idx != ~0uLL) 133 | { 134 | if (*(u_int32_t *) bucket_idx != ~0u) 135 | { 136 | if (*((u_int16_t *) bucket_idx) != (u_int16_t) ~0u) 137 | { 138 | if (*(u_int8_t *) bucket_idx != (u_int8_t) ~0u) 139 | { 140 | p_idx = (u_int8_t *) bucket_idx + 0; 141 | } 142 | else 143 | { 144 | p_idx = (u_int8_t *) bucket_idx + 1; 145 | } 146 | } 147 | else 148 | { 149 | if (*((u_int8_t *) bucket_idx + 2) != (u_int8_t) ~0u) 150 | { 151 | p_idx = (u_int8_t *) bucket_idx + 2; 152 | } 153 | else 154 | { 155 | p_idx = (u_int8_t *) bucket_idx + 3; 156 | } 157 | 158 | } 159 | } 160 | else 161 | { 162 | if (*((u_int16_t *) bucket_idx + 2) != (u_int16_t) ~0u) 163 | { 164 | if (*((u_int8_t *) bucket_idx + 4) != (u_int8_t) ~0u) 165 | { 166 | p_idx = (u_int8_t *) bucket_idx + 4; 167 | } 168 | else 169 | { 170 | p_idx = (u_int8_t *) bucket_idx + 5; 171 | } 172 | } 173 | else 174 | { 175 | if (*((u_int8_t *) bucket_idx + 6) != (u_int8_t) ~0u) 176 | { 177 | p_idx = (u_int8_t *) bucket_idx + 6; 178 | } 179 | else 180 | { 181 | p_idx = (u_int8_t *) bucket_idx + 7; 182 | } 183 | 184 | } 185 | } 186 | idx = get_bit(p_idx) + 187 | 8 * (p_idx - (u_int8_t *) bucket_start_idx) + 188 | the_bucket * BUCKET_CAPACITY; 189 | bucket_used[the_bucket] ++; 190 | break; 191 | } 192 | else 193 | { 194 | continue; 195 | } 196 | } 197 | 198 | GET_BLOCK_RET: 199 | pthread_mutex_unlock(&alloc_lock); 200 | return idx; 201 | } 202 | 203 | void gkoAlloc::free_block(int block_id) 204 | { 205 | if (block_id < 0) 206 | return; 207 | 208 | int bucket_no = block_id / BUCKET_CAPACITY; 209 | 210 | pthread_mutex_lock(&alloc_lock); 211 | free_bit(&m_map[block_id / 8], block_id % 8); 212 | 213 | if(--bucket_used[bucket_no] == 0 && bucket_no) 214 | { 215 | free(bucket_s[bucket_no]); 216 | bucket_s[bucket_no] = NULL; 217 | } 218 | else 219 | { 220 | latest_bucket = bucket_no; 221 | } 222 | pthread_mutex_unlock(&alloc_lock); 223 | 224 | } 225 | 226 | #ifdef MEM_TEST 227 | int main() 228 | { 229 | gkoAlloc mem; 230 | for (int i = 0; i < BUCKET_CAPACITY - 1; i++) 231 | { 232 | int k = mem.get_block(); 233 | printf("%d, %d\n", i, k); 234 | if (i != k) 235 | { 236 | break; 237 | } 238 | } 239 | int blk1 = mem.get_block(); 240 | int blk2 = mem.get_block(); 241 | int blk3 = mem.get_block(); 242 | printf("%p\n", mem.id2addr(blk1)); 243 | printf("%p\n", mem.id2addr(blk2)); 244 | printf("%p\n", mem.id2addr(blk3)); 245 | mem.free_block(blk1); 246 | mem.free_block(blk2); 247 | mem.free_block(blk3); 248 | return 0; 249 | } 250 | #endif 251 | -------------------------------------------------------------------------------- /src/memory.h: -------------------------------------------------------------------------------- 1 | /* 2 | * memory.h 3 | * 4 | * Created on: Jun 8, 2012 5 | * Author: auxten 6 | */ 7 | 8 | #ifndef GKO_MEMORY_H_ 9 | #define GKO_MEMORY_H_ 10 | 11 | #include 12 | #include 13 | 14 | static const u_int32_t SLOT_SIZE = 4 * 1024; /// one page is good 15 | static const u_int32_t SLOT_COUNT = 1 * 1024 * 1024; 16 | static const u_int32_t M_MAP_SIZE = SLOT_COUNT / sizeof(u_int8_t); /// bitmap 17 | static const u_int32_t BUCKET_SIZE = 16 * 1024 * 1024; 18 | static const int32_t BUCKET_CAPACITY = BUCKET_SIZE / SLOT_SIZE; /// capacity, 4096 19 | static const int32_t BUCKET_COUNT = SLOT_COUNT / BUCKET_CAPACITY; /// 256 20 | static const int INVILID_BLOCK = -1; 21 | 22 | 23 | class gkoAlloc 24 | { 25 | private: 26 | pthread_mutex_t alloc_lock; 27 | u_int8_t m_map[M_MAP_SIZE]; /// 1MB can fit L2 cache 28 | void * bucket_s[BUCKET_COUNT]; 29 | int16_t bucket_used[BUCKET_COUNT]; 30 | int latest_bucket; 31 | int get_bit(u_int8_t * b); 32 | int free_bit(u_int8_t * b, int index); 33 | 34 | public: 35 | gkoAlloc(void); 36 | int get_block(void); 37 | int get_clear_block(void); 38 | int get2x_block(int block_id); 39 | void free_block(int block_id); 40 | int clear_block(void *block, int c, size_t size); 41 | void * id2addr(int block_id); 42 | }; 43 | 44 | #endif /* GKO_MEMORY_H_ */ 45 | -------------------------------------------------------------------------------- /src/path.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * path.cpp 3 | * 4 | * Created on: 2011-5-11 5 | * Author: auxten 6 | **/ 7 | #include 8 | #include 9 | #include "gingko.h" 10 | #include "hash/xor_hash.h" 11 | #include "log.h" 12 | #include "path.h" 13 | 14 | /** 15 | * @brief ../path//// TO ../path 16 | * @brief ../path/ TO ../path 17 | * @brief ../path TO ../path 18 | * 19 | * @see 20 | * @note 21 | * @author auxten 22 | * @date 2011-8-1 23 | **/ 24 | int inplace_strip_tailing_slash(char * path) 25 | { 26 | if (path == NULL) 27 | { 28 | GKOLOG(WARNING, "passed NULL p"); 29 | return -1; 30 | } 31 | char * p = path; 32 | for (int i = strlen(path) - 1; i > 0; i--) 33 | { 34 | if (*(p + i) == '/') 35 | { 36 | *(p + i) = '\0'; 37 | } 38 | else 39 | { 40 | break; 41 | } 42 | } 43 | return 0; 44 | } 45 | 46 | /** 47 | * @brief ../path/// TO ../path/ 48 | * @brief ../path/ TO ../path/ 49 | * @brief ../path TO ../path/ 50 | * 51 | * @see 52 | * @note 53 | * @author auxten 54 | * @date 2011-8-1 55 | **/ 56 | int inplace_add_tailing_slash(char * path) 57 | { 58 | if (path == NULL) 59 | { 60 | GKOLOG(WARNING, "passed NULL p"); 61 | return -1; 62 | } 63 | char * p = path; 64 | for (int i = strlen(path) - 1; i > 0; i--) 65 | { 66 | if (*(p + i) == '/') 67 | { 68 | *(p + i) = '\0'; 69 | } 70 | else 71 | { 72 | break; 73 | } 74 | } 75 | strncat(path, "/", MAX_PATH_LEN - strlen(path)); 76 | return 0; 77 | } 78 | 79 | /** 80 | * @brief get the base name of a string, 81 | * @brief if out not NULL, cp the base path to out 82 | * @brief return the base path len 83 | * 84 | * @see 85 | * @note 86 | * for example: 87 | * /home/work/opdir -> 11 88 | * ^ 89 | * ./dir -> 2 90 | * ^ 91 | * dir -> 0 92 | * ^ 93 | * ../file -> 3 94 | * ^ 95 | * @author auxten 96 | * @date 2011-8-1 97 | **/ 98 | int get_base_name_index(char * out, const char * in) 99 | { 100 | if (in == NULL) 101 | { 102 | GKOLOG(WARNING, FLF("passed NULL p at get_base_name_index")); 103 | return -1; 104 | } 105 | char * p = (char *) in; 106 | int i; 107 | int len = strlen(in); 108 | if (!len) 109 | { 110 | GKOLOG(WARNING, FLF("input string len == 0")); 111 | return -1; 112 | } 113 | for (i = len; i > 0; i--) 114 | { 115 | if (*(p + i) == '/') 116 | { 117 | i++; 118 | break; 119 | } 120 | } 121 | if (out) 122 | { 123 | strncpy(out, p + i, MAX_PATH_LEN); 124 | } 125 | return i; 126 | } 127 | 128 | /** 129 | * @brief in : const char * dir_name, const char * base_name 130 | * @brief out : dir_name/base_name 131 | * 132 | * @see 133 | * @note 134 | * @author auxten 135 | * @date 2011-8-1 136 | **/ 137 | int merge_path(char * out, const char * dir_name, const char * base_name) 138 | { 139 | if (!out || !dir_name || !base_name) 140 | { 141 | GKOLOG(WARNING, "passed NULL p"); 142 | return -1; 143 | } 144 | strncpy(out, dir_name, MAX_PATH_LEN); 145 | inplace_strip_tailing_slash(out); 146 | strncat(out, "/", MAX_PATH_LEN - strlen(out)); 147 | strncat(out, base_name, MAX_PATH_LEN - strlen(out)); 148 | if (strlen(out) == MAX_PATH_LEN) 149 | { 150 | GKOLOG(WARNING, "path too long"); 151 | return -1; 152 | } 153 | return 0; 154 | } 155 | 156 | /** 157 | * @brief change remote path to local path, store it in path 158 | * 159 | * @see 160 | * @note 161 | * path: ../test/.DS_Store 162 | * req_path: ../test 163 | * local_path: ../output2/ 164 | * if (dst_path_exist) 165 | * path output: ../output2/test/.DS_Store 166 | * else 167 | * path output: ../output2/.DS_Store 168 | * @author auxten 169 | * @date 2011-8-1 170 | **/ 171 | int change_to_local_path(char * path, const char * req_path, 172 | const char * local_path, char dst_path_exist) 173 | { 174 | if (!path || !req_path || !local_path) 175 | { 176 | GKOLOG(FATAL, "%s %s passed NULL p", __FILE__, __func__); 177 | return -1; 178 | } 179 | char base_name[MAX_PATH_LEN] = "\0"; 180 | char tmp_req_path[MAX_PATH_LEN] = "\0"; 181 | strncpy(tmp_req_path, req_path, MAX_PATH_LEN); /// ../test 182 | ///printf("tmp2: %s", tmp2); 183 | inplace_strip_tailing_slash(tmp_req_path); /// ../test 184 | ///printf("tmp2: %s", tmp2); 185 | int d; 186 | if (dst_path_exist) 187 | { 188 | d = get_base_name_index(NULL, tmp_req_path); 189 | } 190 | else 191 | { 192 | d = strlen(tmp_req_path) + 1; 193 | } 194 | 195 | if (d < 0) 196 | { 197 | GKOLOG(FATAL, FLF("change_to_local_path failed")); 198 | return -1; 199 | } 200 | ///printf("d: %d,path+d: %s", d, tmp2+d); 201 | strncpy(base_name, path + d, MAX_PATH_LEN); /// test/.DS_Store 202 | merge_path(path, local_path, base_name); /// ../output2/ + test/.DS_Store 203 | inplace_strip_tailing_slash(path); /// ../test 204 | return 0; 205 | } 206 | 207 | /** 208 | * @brief change current working dir path to absolute path 209 | * 210 | * @see 211 | * @note 212 | * result is stored in abs_path 213 | * return abs_path on succeed else NULL 214 | * @author auxten 215 | * @date 2011-8-1 216 | **/ 217 | GKO_STATIC_FUNC char * cwd_path_to_abs_path(char * abs_path, const char * oldpath) 218 | { 219 | if (!abs_path || !oldpath) 220 | { 221 | GKOLOG(FATAL, "%s %s passed NULL p", __FILE__, __func__); 222 | return NULL; 223 | } 224 | if ((strlen(oldpath) < 1)) 225 | { 226 | GKOLOG(WARNING, "invalid oldpath"); 227 | return NULL; 228 | } 229 | else 230 | { 231 | if (*oldpath == '/') ///already a abs path 232 | { 233 | strncpy(abs_path, oldpath, MAX_PATH_LEN); 234 | } 235 | else 236 | { 237 | if (!(getcwd(abs_path, MAX_PATH_LEN))) 238 | { 239 | GKOLOG(WARNING, "getcwd error"); 240 | return NULL; 241 | } 242 | inplace_add_tailing_slash(abs_path); 243 | strncat(abs_path, oldpath, MAX_PATH_LEN - strlen(abs_path)); 244 | } 245 | return abs_path; 246 | } 247 | } 248 | 249 | /** 250 | * @brief get the symlink dest's absolute path, store it in abs_path 251 | * 252 | * @see 253 | * @note 254 | * @author auxten 255 | * @date 2011-8-1 256 | **/ 257 | char * symlink_dest_to_abs_path(char * abs_path, const char * symlink) 258 | { 259 | if (!abs_path || !symlink) 260 | { 261 | GKOLOG(FATAL, "%s %s passed NULL p", __FILE__, __func__); 262 | return NULL; 263 | } 264 | 265 | memset(abs_path, 0, MAX_PATH_LEN); 266 | /** read the symlink first **/ 267 | if (readlink(symlink, abs_path, MAX_PATH_LEN) < 0) 268 | { 269 | GKOLOG(WARNING, "read synlink '%s' dest failed", symlink); 270 | return NULL; 271 | } 272 | 273 | /** if starts with a '/', that's it!! **/ 274 | if (*abs_path == '/') 275 | {/** symlink to a abs path **/ 276 | GKOLOG(NOTICE, "symlink to a abs path:)"); 277 | return abs_path; 278 | } 279 | else 280 | {/** symlink to a relative path, need convert **/ 281 | char tmp_sympath[MAX_PATH_LEN]; 282 | strncpy(tmp_sympath, abs_path, MAX_PATH_LEN); 283 | if (!cwd_path_to_abs_path(abs_path, symlink)) 284 | { 285 | GKOLOG(WARNING, "cwd_path_to_abs_path failed '%s' '%s'", abs_path, 286 | symlink); 287 | return NULL; 288 | } 289 | int idx = get_base_name_index(NULL, abs_path); 290 | if (idx < 0) 291 | { 292 | GKOLOG(FATAL, "get_base_name_index failed: '%s'", abs_path); 293 | return NULL; 294 | } 295 | *(abs_path + idx) = '\0'; 296 | strncat(abs_path, tmp_sympath, MAX_PATH_LEN); 297 | return abs_path; 298 | } 299 | 300 | } 301 | 302 | /** 303 | * @brief generate snap file path with requested localpath and requested remote uri 304 | * 305 | * @see 306 | * @note 307 | * return the hash result from xor_hash(uri, strlen(uri), 0) 308 | * the snap file path is stored in snap_fpath 309 | * @return 0 for error 310 | * uri_hash for succ 311 | * @author auxten 312 | * @date 2011-8-1 313 | **/ 314 | unsigned gen_snap_fpath(char *snap_fpath, const char * localpath, 315 | const char * uri) 316 | { 317 | if (!snap_fpath || !localpath || !uri) 318 | { 319 | GKOLOG(FATAL, "%s %s passed NULL p", __FILE__, __func__); 320 | return 0; 321 | } 322 | 323 | char out_path[MAX_PATH_LEN] = {'\0'}; 324 | strncpy(out_path, localpath, MAX_PATH_LEN); 325 | inplace_strip_tailing_slash(out_path); 326 | 327 | if (!cwd_path_to_abs_path(snap_fpath, out_path)) 328 | { 329 | GKOLOG(WARNING, "cwd_path_to_abs_path failed '%s' '%s'", snap_fpath, 330 | out_path); 331 | return 0; 332 | } 333 | /** cut the tailing file in path **/ 334 | if (!(path_type(snap_fpath) & GKO_DIR)) 335 | { 336 | int idx; 337 | if ((idx = get_base_name_index(NULL, snap_fpath)) < 0) 338 | { 339 | GKOLOG(WARNING, "gen_snap_fpath failed '%s' '%s' '%s'", snap_fpath, 340 | out_path, uri); 341 | return 0; 342 | } 343 | *(snap_fpath + idx) = '\0'; 344 | } 345 | 346 | int snap_fpath_len = strlen(snap_fpath); 347 | unsigned uri_hash = xor_hash(uri, strlen(uri), 0); 348 | snprintf(snap_fpath + snap_fpath_len, MAX_PATH_LEN - snap_fpath_len, 349 | "/%s%u", GKO_SNAP_FILE, uri_hash); 350 | 351 | GKOLOG(NOTICE, "gko.snap_fpath: '%s'", snap_fpath); 352 | return uri_hash; 353 | } 354 | 355 | /** 356 | * @brief get the dest type, return: 357 | * 358 | * @see 359 | * @note 360 | * GKO_FILE = 0001; ///file and for file test.eg: flag & GKO_FILE 361 | * GKO_DIR = 0002; ///dir and for dir test 362 | * GKO_NONE = 0004; ///nonexisted and for nonexisted test 363 | * GKO_OTHR = 0000; ///other 364 | * GKO_LFILE = 0011; ///symlink to file 365 | * GKO_LDIR = 0012; ///symlink to dir 366 | * GKO_LNONE = 0014; ///symlink to nonexist 367 | * GKO_LOTHR = 0010; ///symlink to other 368 | * GKO_LINK = 0010; ///for symlink test 369 | * GKO_ERR = 0100; ///error 370 | * @author auxten 371 | * @date 2011-8-1 372 | **/ 373 | int path_type(const char * p) 374 | { 375 | if (!p) 376 | { 377 | GKOLOG(FATAL, FLF("null passed to path_type")); 378 | return GKO_ERR; 379 | } 380 | struct stat dest_stat; 381 | char path[MAX_PATH_LEN]; 382 | strncpy(path, p, MAX_PATH_LEN); 383 | inplace_strip_tailing_slash(path); 384 | if (lstat(path, &dest_stat) < 0) 385 | { 386 | if (errno == ENOENT) 387 | { 388 | GKOLOG(NOTICE, "non existed path '%s'", path); 389 | return GKO_NONE; 390 | } 391 | GKOLOG(WARNING, "stat dest_stat failed %d", errno); 392 | return GKO_ERR; 393 | } 394 | else 395 | { 396 | switch (dest_stat.st_mode & S_IFMT) 397 | { 398 | case S_IFREG: 399 | return GKO_FILE; 400 | 401 | case S_IFDIR: 402 | return GKO_DIR; 403 | 404 | case S_IFLNK: 405 | { 406 | struct stat symstat; 407 | if (stat(path, &symstat) < 0) 408 | { 409 | if (errno == ENOENT) 410 | { 411 | GKOLOG(WARNING, "non existed sympath '%s'", path); 412 | return GKO_LNONE; 413 | } 414 | GKOLOG(WARNING, "stat symstat failed %d", errno); 415 | return GKO_ERR; 416 | } 417 | else 418 | { 419 | switch (symstat.st_mode & S_IFMT) 420 | { 421 | case S_IFREG: 422 | return GKO_LFILE; 423 | 424 | case S_IFDIR: 425 | return GKO_LDIR; 426 | 427 | default: 428 | GKOLOG(WARNING, 429 | "symbol path '%s' not a regular file or dir", 430 | path); 431 | return GKO_LOTHR; 432 | } 433 | } 434 | break; 435 | } 436 | 437 | default: 438 | GKOLOG(WARNING, "'%s' not a regular file or dir", path); 439 | return GKO_OTHR; 440 | } 441 | } 442 | } 443 | 444 | /** 445 | * @brief make dir and symlink, create the file and check the size 446 | * 447 | * @see 448 | * @note 449 | * if size not matched, continue flag is canceled. all file 450 | * will be truncate to the expected size. 451 | * if the symlink is already exist, unlink it and create a 452 | * new one 453 | * if the dir is already exist, leave it there 454 | * @author auxten 455 | * @date 2011-8-1 456 | **/ 457 | int mk_dir_symlink_file(s_job_t * jo, char * to_continue) 458 | { 459 | if (!jo || !to_continue) 460 | { 461 | GKOLOG(FATAL, FLF("null pointer")); 462 | return -1; 463 | } 464 | s_file_t * tmp; 465 | for (GKO_INT64 i = 0; i < jo->file_count; i++) 466 | { 467 | tmp = jo->files + i; 468 | int fd = -1; 469 | GKOLOG(NOTICE, "0%3o\t%lld\t%s\t%s", tmp->mode & 0777, tmp->size, 470 | (jo->files + i)->name, tmp->sympath); 471 | switch (tmp->size) 472 | { 473 | /** 474 | * to make sure client can write to every file transfered, 475 | * we create the dir and file with mode |= S_IWUSR 476 | * we will correct file, dir mode after transfer is over. 477 | **/ 478 | case -1: /// dir 479 | if (mkdir(tmp->name, tmp->mode|S_IWUSR) && errno != EEXIST) 480 | { 481 | GKOLOG(FATAL, "mkdir error"); 482 | return -1; 483 | } 484 | break; 485 | 486 | case -2: /// symbol link 487 | if (symlink(tmp->sympath, tmp->name)) 488 | { 489 | if (errno == EEXIST) 490 | { 491 | if (unlink(tmp->name)) 492 | { 493 | GKOLOG(FATAL, "unlink existed symlink '%s' error", 494 | tmp->name); 495 | } 496 | if (symlink(tmp->sympath, tmp->name)) 497 | { 498 | GKOLOG(FATAL, "re-create symlink '%s' to '%s' error", 499 | tmp->name, tmp->sympath); 500 | } 501 | } 502 | else 503 | { 504 | GKOLOG(FATAL, "symlink error"); 505 | return -1; 506 | } 507 | } 508 | break; 509 | 510 | default: ///regular file 511 | if (-1 == (fd = open(tmp->name, CREATE_OPEN_FLAG, tmp->mode|S_IWUSR))) 512 | { 513 | GKOLOG(FATAL, "make or open new file error"); 514 | return -1; 515 | } 516 | else 517 | { 518 | struct stat f_stat; 519 | /// if to_continue flag is on, but the file size existed 520 | /// doesn't match the one in seed. cancel the to_continue 521 | /// flag. 522 | if (*to_continue) 523 | { 524 | if (fstat(fd, &f_stat)) 525 | { 526 | GKOLOG( 527 | WARNING, 528 | "fstat file '%s' error, continue flag canceled", 529 | tmp->name); 530 | *to_continue = 0; 531 | } 532 | if (f_stat.st_size != tmp->size) 533 | { 534 | GKOLOG( 535 | WARNING, 536 | "file '%s' size not matched, continue flag canceled", 537 | tmp->name); 538 | *to_continue = 0; 539 | } 540 | } 541 | if (ftruncate(fd, tmp->size)) 542 | { 543 | GKOLOG(FATAL, "truncate file error"); 544 | close(fd); 545 | return -1; 546 | } 547 | close(fd); 548 | } 549 | break; 550 | } 551 | } 552 | return 0; 553 | } 554 | 555 | /** 556 | * @brief correct the file and dir mode, cause for write in we create them with mode|S_IWUSR 557 | * and take care of the setgit of dir 558 | * 559 | * @see http://www.gnu.org/software/coreutils/manual/html_node/Directory-Setuid-and-Setgid.html 560 | * @note 561 | * @author auxten 562 | * @date 2011-8-10 563 | **/ 564 | int correct_mode(s_job_t * jo) 565 | { 566 | s_file_t * f_p; 567 | for (GKO_INT64 i = 0; i < jo->file_count; i++) 568 | { 569 | f_p = jo->files + i; 570 | if ((f_p->size == -1) || (!(f_p->mode & S_IWUSR))) 571 | { 572 | if (chmod(f_p->name, f_p->mode)) 573 | { 574 | GKOLOG(FATAL, "chmod for '%s' to 0%3o failed!!!", f_p->name, 575 | f_p->mode & 0777); 576 | return -1; 577 | } 578 | GKOLOG(TRACE, "chmod for '%s' to 0%3o succeed", f_p->name, 579 | f_p->mode & 0777); 580 | } 581 | } 582 | 583 | return 0; 584 | } 585 | /** 586 | * @brief convert the remote path recv from JOIN to local path 587 | * 588 | * @see 589 | * @note 590 | * @author auxten 591 | * @date 2011-8-1 592 | **/ 593 | int process_path(s_job_t * jo) 594 | { 595 | char out_path[MAX_PATH_LEN] = {'\0'}; 596 | strncpy(out_path, jo->path, MAX_PATH_LEN); 597 | inplace_strip_tailing_slash(out_path); 598 | int out_type = path_type(out_path); 599 | if (out_type & GKO_NONE) 600 | {/** non-existed dest or dest is symlink to non-existed **/ 601 | if (out_type & GKO_LINK) 602 | {/** dest is symlink to non-existed **/ 603 | GKOLOG(FATAL, "destination: '%s' is a symlink to non-exist", 604 | out_path); 605 | return -1; 606 | } 607 | else if ((jo->file_count == 1 && jo->files->size >= 0) && 608 | (jo->path)[strlen(jo->path) - 1] == '/') 609 | {/** dest is a non existed dir path like './non/' but job is a singal file **/ 610 | GKOLOG(FATAL, "downloading a file to non existed path '%s'", 611 | jo->path); 612 | return -1; 613 | } 614 | else 615 | { /** non-existed dest **/ 616 | /** determine if the base dir is existed **/ 617 | char out_base_path[MAX_PATH_LEN]; 618 | //strncpy(out_base_path, out_path, MAX_PATH_LEN); 619 | cwd_path_to_abs_path(out_base_path, out_path); 620 | 621 | int base_idx = get_base_name_index(NULL, out_base_path); 622 | if (base_idx < 0) 623 | { 624 | GKOLOG(FATAL, "process_path failed"); 625 | return -1; 626 | } 627 | out_base_path[base_idx] = '\0'; 628 | int out_base_type = path_type(out_base_path); 629 | if (out_base_type & GKO_DIR) 630 | {/** out base path is a dir or symlink to dir **/ 631 | for (int i = 0; i < jo->file_count; i++) 632 | { 633 | if (FAIL_CHECK( 634 | change_to_local_path((jo->files + i)->name, jo->uri, out_path, 0))) 635 | { 636 | GKOLOG( 637 | FATAL, 638 | "change to local path error, name: '%s', uri: '%s', path: '%s'", 639 | (jo->files + i)->name, jo->uri, out_path); 640 | return -1; 641 | } 642 | //GKOLOG(NOTICE, "path: '%s'", (jo->files + i)->name); 643 | } 644 | return 0; 645 | } 646 | else 647 | {/** out base path is not dir, nor symlink to dir **/ 648 | GKOLOG(FATAL, "base path: '%s' is non-dir", out_base_path); 649 | return -1; 650 | } 651 | } 652 | } 653 | else 654 | {/** dest path existed **/ 655 | if (out_type & GKO_FILE) 656 | {/** dest path is file or symlink to file **/ 657 | if (jo->file_count == 1) 658 | { 659 | if ((jo->files)->size == -1) 660 | {/** dest path is dir **/ 661 | GKOLOG(FATAL, "can't overwrite dir: '%s' on file: '%s'", 662 | (jo->files)->name, out_path); 663 | return -1; 664 | } 665 | else if ((jo->files)->size == -2) 666 | {/** dest path is symlink **/ 667 | GKOLOG(FATAL, "can't overwrite symlink: '%s' on file: '%s'", 668 | (jo->files)->name, out_path); 669 | return -1; 670 | } 671 | else 672 | {/** dest path is file **/ 673 | strncpy((jo->files)->name, out_path, MAX_PATH_LEN); 674 | return 0; 675 | } 676 | } 677 | else 678 | { /** file count != 1, 679 | indicating that job is a dir, dest is a existed file **/ 680 | GKOLOG(FATAL, "can't overwrite dir: '%s' on file: '%s'", 681 | (jo->files)->name, out_path); 682 | return -1; 683 | } 684 | } 685 | else if (out_type & GKO_DIR) 686 | {/** dest is a existed dir **/ 687 | for (int i = 0; i < jo->file_count; i++) 688 | { 689 | if (FAIL_CHECK(change_to_local_path((jo->files + i)->name, jo->uri, out_path, 1))) 690 | { 691 | GKOLOG( 692 | FATAL, 693 | "change to local path error, name: '%s', uri: '%s', path: '%s'", 694 | (jo->files + i)->name, jo->uri, out_path); 695 | return -1; 696 | } 697 | } 698 | return 0; 699 | } 700 | else 701 | {/** dest is non-regular file or dir **/ 702 | GKOLOG(FATAL, "the dest: '%s' is non-regular file or dir", out_path); 703 | return -1; 704 | } 705 | } 706 | return 0; 707 | } 708 | 709 | -------------------------------------------------------------------------------- /src/path.h: -------------------------------------------------------------------------------- 1 | /** 2 | * path.h 3 | * 4 | * Created on: 2011-5-11 5 | * Author: auxten 6 | **/ 7 | 8 | #ifndef PATH_H_ 9 | #define PATH_H_ 10 | 11 | ///file and for file test.eg: flag & GKO_FILE 12 | static const int GKO_FILE = 0001; 13 | ///dir and for dir test 14 | static const int GKO_DIR = 0002; 15 | ///nonexisted and for nonexisted test 16 | static const int GKO_NONE = 0004; 17 | ///other 18 | static const int GKO_OTHR = 0000; 19 | ///symlink to file 20 | static const int GKO_LFILE = 0011; 21 | ///symlink to dir 22 | static const int GKO_LDIR = 0012; 23 | ///symlink to nonexist 24 | static const int GKO_LNONE = 0014; 25 | ///symlink to other 26 | static const int GKO_LOTHR = 0010; 27 | ///for symlink test 28 | static const int GKO_LINK = 0010; 29 | ///error 30 | static const int GKO_ERR = 0100; 31 | 32 | 33 | /// ../path//// TO ../path 34 | int inplace_strip_tailing_slash(char * path); 35 | /// ../path TO ../path/ 36 | int inplace_add_tailing_slash(char * path); 37 | /// get the base name of a string 38 | int get_base_name_index(char * in, const char * out); 39 | /// merge into dir_name/base_name 40 | int merge_path(char * out, const char * dir_name, const char * base_name); 41 | /// change remote path to local path, store it in path 42 | int change_to_local_path(char * path, const char * req_path, 43 | const char * local_path, char dst_path_exist); 44 | /// get the symlink dest's absolute path, store it in abs_path 45 | char * symlink_dest_to_abs_path(char * abs_path, const char * symlink); 46 | /// generate snap file path with requested localpath and requested remote uri 47 | unsigned gen_snap_fpath(char *snap_fpath, const char * localpath, 48 | const char * uri); 49 | /// generate snap file path with requested localpath and requested remote uri 50 | int path_type(const char * path); 51 | /// generate snap file path with requested localpath and requested remote uri 52 | int mk_dir_symlink_file(s_job_t * jo, char * to_continue); 53 | /// correct the file and dir mode, cause for write in we create them with mode|S_IWUSR 54 | int correct_mode(s_job_t * jo); 55 | /// convert the remote path recv from JOIN to local path 56 | int process_path(s_job_t * jo); 57 | 58 | #endif /** PATH_H_ **/ 59 | -------------------------------------------------------------------------------- /src/socket.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * socket.cpp 3 | * 4 | * Created on: Mar 9, 2012 5 | * Author: auxten 6 | **/ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "config.h" 14 | #include "gingko.h" 15 | #include "log.h" 16 | #include "socket.h" 17 | #ifdef __APPLE__ 18 | #include 19 | #else 20 | #include 21 | #endif /** __APPLE__ **/ 22 | 23 | char * addr_itoa(in_addr_t address, char * str) 24 | { 25 | u_int32_t addr = (u_int32_t) address; 26 | snprintf(str, 16, "%u.%u.%u.%u", (addr) & 255u, (addr >> 8) & 255u, (addr >> 16) & 255u, (addr >> 24) & 255u); 27 | return str; 28 | } 29 | 30 | /** 31 | * @brief Set non-blocking 32 | * 33 | * @see 34 | * @note 35 | * @author auxten 36 | * @date 2011-8-1 37 | **/ 38 | int setnonblock(int fd) 39 | { 40 | int flags; 41 | 42 | flags = fcntl(fd, F_GETFL); 43 | if (flags < 0) 44 | { 45 | return flags; 46 | } 47 | 48 | if (!(flags & O_NONBLOCK)) 49 | { 50 | flags |= O_NONBLOCK; 51 | if (fcntl(fd, F_SETFL, flags) < 0) 52 | { 53 | return -1; 54 | } 55 | } 56 | return 0; 57 | } 58 | 59 | /** 60 | * @brief Set blocking 61 | * 62 | * @see 63 | * @note 64 | * @author auxten 65 | * @date 2011-8-1 66 | **/ 67 | int setblock(int fd) 68 | { 69 | int flags; 70 | 71 | flags = fcntl(fd, F_GETFL); 72 | if (flags < 0) 73 | { 74 | return flags; 75 | } 76 | 77 | if (flags & O_NONBLOCK) 78 | { 79 | flags &= ~O_NONBLOCK; 80 | if (fcntl(fd, F_SETFL, flags) < 0) 81 | { 82 | return -1; 83 | } 84 | } 85 | return 0; 86 | } 87 | 88 | /** 89 | * @brief connect to a host 90 | * 91 | * @see 92 | * @note 93 | * h: pointer to s_host_t 94 | * recv_sec: receive timeout seconds, 0 for never timeout 95 | * return the socket when succ 96 | * return < 0 when error, specially HOST_DOWN_FAIL indicate host dead 97 | * @author auxten 98 | * @date 2011-8-1 99 | **/ 100 | int connect_host(const s_host_t * h, const int recv_sec, const int send_sec) 101 | { 102 | int sock = -1; 103 | int ret; 104 | int select_ret; 105 | int res; 106 | socklen_t res_size = sizeof res; 107 | struct sockaddr_in channel; 108 | in_addr_t host; 109 | int addr_len; 110 | struct timeval recv_timeout; 111 | struct timeval send_timeout; 112 | #if HAVE_POLL 113 | #else 114 | fd_set wset; 115 | #endif /* HAVE_POLL */ 116 | 117 | addr_len = getaddr_my(h->addr, &host); 118 | if (FAIL_CHECK(!addr_len)) 119 | { 120 | GKOLOG(WARNING, "gethostbyname %s error", h->addr); 121 | ret = -1; 122 | goto CONNECT_END; 123 | } 124 | sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 125 | if (FAIL_CHECK(sock < 0)) 126 | { 127 | GKOLOG(WARNING, "get socket error"); 128 | ret = -1; 129 | goto CONNECT_END; 130 | } 131 | 132 | recv_timeout.tv_usec = 0; 133 | recv_timeout.tv_sec = recv_sec ? recv_sec : RCV_TIMEOUT; 134 | send_timeout.tv_usec = 0; 135 | send_timeout.tv_sec = send_sec ? send_sec : SND_TIMEOUT; 136 | 137 | memset(&channel, 0, sizeof(channel)); 138 | channel.sin_family = AF_INET; 139 | memcpy(&channel.sin_addr.s_addr, &host, addr_len); 140 | channel.sin_port = htons(h->port); 141 | 142 | /** set the connect non-blocking then blocking for add timeout on connect **/ 143 | if (FAIL_CHECK(setnonblock(sock) < 0)) 144 | { 145 | GKOLOG(WARNING, "set socket non-blocking error"); 146 | ret = -1; 147 | goto CONNECT_END; 148 | } 149 | 150 | /** connect and send the msg **/ 151 | if (FAIL_CHECK(connect(sock, (struct sockaddr *) &channel, sizeof(channel)) && 152 | errno != EINPROGRESS)) 153 | { 154 | GKOLOG(WARNING, "connect error"); 155 | ret = HOST_DOWN_FAIL; 156 | goto CONNECT_END; 157 | } 158 | 159 | /** Wait for write bit to be set **/ 160 | #if HAVE_POLL 161 | { 162 | struct pollfd pollfd; 163 | 164 | pollfd.fd = sock; 165 | pollfd.events = POLLOUT; 166 | 167 | /* send_sec is in seconds, timeout in ms */ 168 | select_ret = poll(&pollfd, 1, (int)(send_sec * 1000 + 1)); 169 | } 170 | #else 171 | { 172 | FD_ZERO(&wset); 173 | FD_SET(sock, &wset); 174 | select_ret = select(sock + 1, 0, &wset, 0, &send_timeout); 175 | } 176 | #endif /* HAVE_POLL */ 177 | if (select_ret < 0) 178 | { 179 | GKOLOG(WARNING, "select/poll error on connect"); 180 | ret = HOST_DOWN_FAIL; 181 | goto CONNECT_END; 182 | } 183 | if (!select_ret) 184 | { 185 | GKOLOG(WARNING, "connect timeout on connect"); 186 | ret = HOST_DOWN_FAIL; 187 | goto CONNECT_END; 188 | } 189 | 190 | /** 191 | * check if connection is RESETed, maybe this is the 192 | * best way to do that 193 | * SEE: http://cr.yp.to/docs/connect.html 194 | **/ 195 | (void) getsockopt(sock, SOL_SOCKET, SO_ERROR, &res, &res_size); 196 | if (CONNECT_DEST_DOWN(res)) 197 | { 198 | // GKOLOG(NOTICE, "connect dest is down errno: %d", res); 199 | ret = HOST_DOWN_FAIL; 200 | goto CONNECT_END; 201 | } 202 | 203 | ///GKOLOG(WARNING, "selected %d ret %d, time %d", sock, select_ret, send_timeout.tv_sec); 204 | /** set back blocking **/ 205 | if (FAIL_CHECK(setblock(sock) < 0)) 206 | { 207 | GKOLOG(WARNING, "set socket non-blocking error"); 208 | ret = -1; 209 | goto CONNECT_END; 210 | } 211 | 212 | /** set recv & send timeout **/ 213 | if (FAIL_CHECK(setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *) &recv_timeout, 214 | sizeof(struct timeval)))) 215 | { 216 | GKOLOG(WARNING, "setsockopt SO_RCVTIMEO error"); 217 | ret = -1; 218 | goto CONNECT_END; 219 | } 220 | if (FAIL_CHECK(setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *) &send_timeout, 221 | sizeof(struct timeval)))) 222 | { 223 | GKOLOG(WARNING, "setsockopt SO_SNDTIMEO error"); 224 | ret = -1; 225 | goto CONNECT_END; 226 | } 227 | 228 | ret = sock; 229 | 230 | CONNECT_END: 231 | /// 232 | if (ret < 0 && sock >= 0) 233 | { 234 | close_socket(sock); 235 | } 236 | return ret; 237 | } 238 | 239 | /** 240 | * @brief gracefully close a socket, for client side 241 | * 242 | * @see 243 | * @note 244 | * @author auxten 245 | * @date 2011-8-1 246 | **/ 247 | int close_socket(int sock) 248 | { 249 | /// if (shutdown(sock, 2)) { 250 | /// GKOLOG(WARNING, "shutdown sock error"); 251 | /// return -1; 252 | /// } 253 | // struct linger so_linger; 254 | // so_linger.l_onoff = 1; /// close right now, no time_wait at serv 255 | // so_linger.l_linger = 0; /// at most wait for 1s 256 | // if (FAIL_CHECK(setsockopt(sock, SOL_SOCKET, SO_LINGER, &so_linger, sizeof(so_linger)))) 257 | // { 258 | // GKOLOG(WARNING, "set so_linger failed"); 259 | // } 260 | if (sock < 0) 261 | return 0; 262 | if (FAIL_CHECK(close(sock))) 263 | { 264 | GKOLOG(WARNING, "close sock error"); 265 | return -1; 266 | } 267 | return 0; 268 | } 269 | 270 | -------------------------------------------------------------------------------- /src/socket.h: -------------------------------------------------------------------------------- 1 | /** 2 | * socket.h 3 | * 4 | * Created on: Mar 9, 2012 5 | * Author: auxten 6 | **/ 7 | 8 | #ifndef SOCKET_H_ 9 | #define SOCKET_H_ 10 | 11 | /// in_addr_t to ascii 12 | char * addr_itoa(in_addr_t address, char * str); 13 | /// Set non-blocking 14 | int setnonblock(int fd); 15 | /// Set blocking 16 | int setblock(int fd); 17 | /// gracefully close a socket, for client side 18 | int close_socket(int sock); 19 | /// connect to a host 20 | int connect_host(const s_host_t * h, const int recv_sec, const int send_sec); 21 | 22 | #endif /** SOCKET_H_ **/ 23 | --------------------------------------------------------------------------------